atagen

monolith

public
Star0
Watch0
7de49c2aa70b317e35783f54619e08eff5326c7f
1
ssh://brewery@pls.lobotomise.me:33/atagen/monolith.git
crates/render-vk/src/renderer.rsRust875 lines27.5 KB
1
use crate::Error;
2
use crate::device::Shared;
3
use crate::dmabuf::{self, DmabufCaps, RENDER_USAGE, SAMPLE_USAGE, VulkanAllocator};
4
use crate::format::{BYTES_PER_PIXEL, SUPPORTED};
5
use crate::frame::{Op, VulkanFrame};
6
use crate::image::{
7
    ImageInner, Staging, VulkanImage, VulkanMapping, VulkanTarget, VulkanTexture, color_range,
8
};
9
use crate::pipeline::Pipelines;
10
use crate::sync::{FenceInner, VkFence};
11
use ash::vk;
12
use gpu_allocator::MemoryLocation;
13
use smithay::backend::allocator::Fourcc;
14
use smithay::backend::allocator::dmabuf::{Dmabuf, WeakDmabuf};
15
use smithay::backend::allocator::format::FormatSet;
16
use smithay::backend::renderer::sync::SyncPoint;
17
use smithay::backend::renderer::{
18
    Bind, ContextId, DebugFlags, ExportMem, ImportDma, ImportDmaWl, ImportMem, Offscreen, Renderer,
19
    RendererSuper, Texture, TextureFilter,
20
};
21
use smithay::utils::{Buffer, Physical, Rectangle, Size, Transform};
22
use std::collections::HashMap;
23
use std::fmt;
24
use std::marker::PhantomData;
25
use std::sync::Arc;
26
27
struct Pending {
28
    fence: Arc<FenceInner>,
29
    cmd: vk::CommandBuffer,
30
    _keep: Vec<Arc<ImageInner>>,
31
}
32
33
pub struct VulkanRenderer {
34
    pending: Vec<Pending>,
35
    dmabuf_textures: HashMap<WeakDmabuf, VulkanTexture>,
36
    dmabuf_targets: HashMap<WeakDmabuf, Arc<ImageInner>>,
37
    pipelines: Pipelines,
38
    pool: vk::CommandPool,
39
    samplers: [vk::Sampler; 4],
40
    min_filter: TextureFilter,
41
    mag_filter: TextureFilter,
42
    debug: DebugFlags,
43
    context: ContextId<VulkanTexture>,
44
    caps: Arc<DmabufCaps>,
45
    shared: Arc<Shared>,
46
}
47
48
impl fmt::Debug for VulkanRenderer {
49
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50
        f.debug_struct("VulkanRenderer")
51
            .field("device", &self.shared.device.name)
52
            .finish()
53
    }
54
}
55
56
impl VulkanRenderer {
57
    pub fn new() -> Result<Self, Error> {
58
        let shared = Arc::new(Shared::new()?);
59
        let d = &shared.device.device;
60
        let pool = unsafe {
61
            d.create_command_pool(
62
                &vk::CommandPoolCreateInfo::default()
63
                    .queue_family_index(shared.device.queue_family)
64
                    .flags(vk::CommandPoolCreateFlags::TRANSIENT),
65
                None,
66
            )?
67
        };
68
        let filter = |f: TextureFilter| match f {
69
            TextureFilter::Linear => vk::Filter::LINEAR,
70
            TextureFilter::Nearest => vk::Filter::NEAREST,
71
        };
72
        let mut samplers = [vk::Sampler::null(); 4];
73
        for (i, s) in samplers.iter_mut().enumerate() {
74
            let (min, mag) = (sampler_filter(i >> 1), sampler_filter(i & 1));
75
            *s = unsafe {
76
                d.create_sampler(
77
                    &vk::SamplerCreateInfo::default()
78
                        .min_filter(filter(min))
79
                        .mag_filter(filter(mag))
80
                        .address_mode_u(vk::SamplerAddressMode::CLAMP_TO_EDGE)
81
                        .address_mode_v(vk::SamplerAddressMode::CLAMP_TO_EDGE)
82
                        .address_mode_w(vk::SamplerAddressMode::CLAMP_TO_EDGE),
83
                    None,
84
                )?
85
            };
86
        }
87
        Ok(Self {
88
            pending: Vec::new(),
89
            dmabuf_textures: HashMap::new(),
90
            dmabuf_targets: HashMap::new(),
91
            pipelines: Pipelines::new(&shared)?,
92
            pool,
93
            samplers,
94
            min_filter: TextureFilter::Linear,
95
            mag_filter: TextureFilter::Linear,
96
            debug: DebugFlags::empty(),
97
            context: ContextId::new(),
98
            caps: Arc::new(DmabufCaps::query(&shared)),
99
            shared,
100
        })
101
    }
102
103
    /// Name of the physical device in use.
104
    pub fn device_name(&self) -> &str {
105
        &self.shared.device.name
106
    }
107
108
    /// Whether dmabufs can be imported, rendered into and allocated.
109
    pub fn supports_dmabuf(&self) -> bool {
110
        self.caps.render.iter().next().is_some()
111
    }
112
113
    /// Formats and modifiers this renderer can render into as dmabufs.
114
    pub fn render_formats(&self) -> FormatSet {
115
        self.caps.render.clone()
116
    }
117
118
    /// An allocator for render-capable dmabufs on this device.
119
    pub fn allocator(&self) -> VulkanAllocator {
120
        VulkanAllocator {
121
            shared: self.shared.clone(),
122
            caps: self.caps.clone(),
123
        }
124
    }
125
126
    pub(crate) fn shared(&self) -> &Arc<Shared> {
127
        &self.shared
128
    }
129
130
    pub(crate) fn context_id_ref(&self) -> &ContextId<VulkanTexture> {
131
        &self.context
132
    }
133
134
    fn sampler(&self) -> vk::Sampler {
135
        let idx = |f: TextureFilter| usize::from(f == TextureFilter::Nearest);
136
        self.samplers[(idx(self.min_filter) << 1) | idx(self.mag_filter)]
137
    }
138
139
    fn reap(&mut self) {
140
        let d = &self.shared.device.device;
141
        let pool = self.pool;
142
        self.pending.retain(|p| {
143
            if !p.fence.signaled() {
144
                return true;
145
            }
146
            unsafe { d.free_command_buffers(pool, &[p.cmd]) };
147
            false
148
        });
149
        self.dmabuf_textures.retain(|k, _| !k.is_gone());
150
        self.dmabuf_targets.retain(|k, _| !k.is_gone());
151
    }
152
153
    fn begin(&self) -> Result<vk::CommandBuffer, Error> {
154
        let d = &self.shared.device.device;
155
        let cmd = unsafe {
156
            d.allocate_command_buffers(
157
                &vk::CommandBufferAllocateInfo::default()
158
                    .command_pool(self.pool)
159
                    .level(vk::CommandBufferLevel::PRIMARY)
160
                    .command_buffer_count(1),
161
            )?[0]
162
        };
163
        unsafe {
164
            d.begin_command_buffer(
165
                cmd,
166
                &vk::CommandBufferBeginInfo::default()
167
                    .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT),
168
            )?
169
        };
170
        Ok(cmd)
171
    }
172
173
    fn end_and_submit(&self, cmd: vk::CommandBuffer) -> Result<Arc<FenceInner>, Error> {
174
        let d = &self.shared.device.device;
175
        unsafe { d.end_command_buffer(cmd)? };
176
        let fence = FenceInner::new(&self.shared)?;
177
        let cmds = [vk::CommandBufferSubmitInfo::default().command_buffer(cmd)];
178
        let submit = vk::SubmitInfo2::default().command_buffer_infos(&cmds);
179
        let queue = self
180
            .shared
181
            .device
182
            .queue
183
            .lock()
184
            .unwrap_or_else(|e| e.into_inner());
185
        unsafe { d.queue_submit2(*queue, &[submit], fence.fence())? };
186
        Ok(fence)
187
    }
188
189
    /// Records, submits and waits for a short command buffer.
190
    fn one_shot(
191
        &mut self,
192
        record: impl FnOnce(&ash::Device, vk::CommandBuffer, u32),
193
    ) -> Result<(), Error> {
194
        let cmd = self.begin()?;
195
        record(
196
            &self.shared.device.device,
197
            cmd,
198
            self.shared.device.queue_family,
199
        );
200
        let fence = self.end_and_submit(cmd)?;
201
        let res = fence.wait();
202
        unsafe {
203
            self.shared
204
                .device
205
                .device
206
                .free_command_buffers(self.pool, &[cmd])
207
        };
208
        Ok(res?)
209
    }
210
211
    pub(crate) fn submit(
212
        &mut self,
213
        target: &mut VulkanTarget<'_>,
214
        ops: Vec<Op>,
215
    ) -> Result<SyncPoint, Error> {
216
        self.reap();
217
        let image = target.0.clone();
218
        let mut sampled: Vec<Arc<ImageInner>> = Vec::new();
219
        for op in &ops {
220
            if let Op::Draw {
221
                texture: Some(t), ..
222
            } = op
223
                && !sampled.iter().any(|s| Arc::ptr_eq(s, &t.0))
224
            {
225
                sampled.push(t.0.clone());
226
            }
227
        }
228
        let mut pipelines = Vec::with_capacity(ops.len());
229
        for op in &ops {
230
            pipelines.push(match op {
231
                Op::Draw { kind, .. } => Some(self.pipelines.get(image.format, *kind)?),
232
                Op::Clear { .. } => None,
233
            });
234
        }
235
        let cmd = self.begin()?;
236
        let d = &self.shared.device.device;
237
        let family = self.shared.device.queue_family;
238
        let push = &self.shared.device.push_descriptor;
239
        let (w, h) = (image.width, image.height);
240
        let sampler = self.sampler();
241
        unsafe {
242
            for t in &sampled {
243
                acquire(d, cmd, family, t, vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL);
244
            }
245
            acquire(
246
                d,
247
                cmd,
248
                family,
249
                &image,
250
                vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
251
            );
252
            let attachments = [vk::RenderingAttachmentInfo::default()
253
                .image_view(image.view)
254
                .image_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
255
                .load_op(vk::AttachmentLoadOp::LOAD)
256
                .store_op(vk::AttachmentStoreOp::STORE)];
257
            let area = vk::Rect2D {
258
                offset: vk::Offset2D::default(),
259
                extent: vk::Extent2D {
260
                    width: w,
261
                    height: h,
262
                },
263
            };
264
            d.cmd_begin_rendering(
265
                cmd,
266
                &vk::RenderingInfo::default()
267
                    .render_area(area)
268
                    .layer_count(1)
269
                    .color_attachments(&attachments),
270
            );
271
            d.cmd_set_viewport(
272
                cmd,
273
                0,
274
                &[vk::Viewport {
275
                    x: 0.0,
276
                    y: 0.0,
277
                    width: w as f32,
278
                    height: h as f32,
279
                    min_depth: 0.0,
280
                    max_depth: 1.0,
281
                }],
282
            );
283
            let mut bound = vk::Pipeline::null();
284
            for (op, pipeline) in ops.iter().zip(pipelines) {
285
                match op {
286
                    Op::Clear { color, rects } => {
287
                        let clear = [vk::ClearAttachment {
288
                            aspect_mask: vk::ImageAspectFlags::COLOR,
289
                            color_attachment: 0,
290
                            clear_value: vk::ClearValue {
291
                                color: vk::ClearColorValue { float32: *color },
292
                            },
293
                        }];
294
                        let rects: Vec<_> = rects
295
                            .iter()
296
                            .map(|&rect| vk::ClearRect {
297
                                rect,
298
                                base_array_layer: 0,
299
                                layer_count: 1,
300
                            })
301
                            .collect();
302
                        d.cmd_clear_attachments(cmd, &clear, &rects);
303
                    }
304
                    Op::Draw {
305
                        texture,
306
                        push: constants,
307
                        scissors,
308
                        ..
309
                    } => {
310
                        let pipeline = pipeline.unwrap_or_default();
311
                        if pipeline != bound {
312
                            d.cmd_bind_pipeline(cmd, vk::PipelineBindPoint::GRAPHICS, pipeline);
313
                            bound = pipeline;
314
                        }
315
                        if let Some(t) = texture {
316
                            let info = [vk::DescriptorImageInfo::default()
317
                                .image_view(t.0.view)
318
                                .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
319
                                .sampler(sampler)];
320
                            let write = vk::WriteDescriptorSet::default()
321
                                .dst_binding(0)
322
                                .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
323
                                .image_info(&info);
324
                            push.cmd_push_descriptor_set(
325
                                cmd,
326
                                vk::PipelineBindPoint::GRAPHICS,
327
                                self.pipelines.layout,
328
                                0,
329
                                &[write],
330
                            );
331
                        }
332
                        d.cmd_push_constants(
333
                            cmd,
334
                            self.pipelines.layout,
335
                            vk::ShaderStageFlags::VERTEX | vk::ShaderStageFlags::FRAGMENT,
336
                            0,
337
                            constants.bytes(),
338
                        );
339
                        for s in scissors {
340
                            d.cmd_set_scissor(cmd, 0, &[*s]);
341
                            d.cmd_draw(cmd, 4, 1, 0, 0);
342
                        }
343
                    }
344
                }
345
            }
346
            d.cmd_end_rendering(cmd);
347
            release(
348
                d,
349
                cmd,
350
                family,
351
                &image,
352
                vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
353
            );
354
            for t in &sampled {
355
                release(d, cmd, family, t, vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL);
356
            }
357
        }
358
        let fence = self.end_and_submit(cmd)?;
359
        sampled.push(image);
360
        self.pending.push(Pending {
361
            fence: fence.clone(),
362
            cmd,
363
            _keep: sampled,
364
        });
365
        Ok(SyncPoint::from(VkFence(fence)))
366
    }
367
368
    fn upload(
369
        &mut self,
370
        image: &Arc<ImageInner>,
371
        data: &[u8],
372
        region: Rectangle<i32, Buffer>,
373
        flipped: bool,
374
    ) -> Result<(), Error> {
375
        if image.external {
376
            return Err(Error::ForeignTexture);
377
        }
378
        let width = image.width as usize;
379
        let needed = width * image.height as usize * BYTES_PER_PIXEL;
380
        if data.len() < needed {
381
            return Err(Error::BufferTooSmall {
382
                needed,
383
                got: data.len(),
384
            });
385
        }
386
        let mut staging = Staging::new(
387
            &self.shared,
388
            needed,
389
            vk::BufferUsageFlags::TRANSFER_SRC,
390
            MemoryLocation::CpuToGpu,
391
        )?;
392
        let row = width * BYTES_PER_PIXEL;
393
        let rows = image.height as usize;
394
        let dst = staging.bytes_mut();
395
        for y in 0..rows {
396
            let from = if flipped { rows - 1 - y } else { y };
397
            dst[y * row..(y + 1) * row].copy_from_slice(&data[from * row..(from + 1) * row]);
398
        }
399
        let copy = vk::BufferImageCopy::default()
400
            .buffer_offset(
401
                ((region.loc.y as usize * width + region.loc.x as usize) * BYTES_PER_PIXEL) as u64,
402
            )
403
            .buffer_row_length(image.width)
404
            .image_subresource(
405
                vk::ImageSubresourceLayers::default()
406
                    .aspect_mask(vk::ImageAspectFlags::COLOR)
407
                    .layer_count(1),
408
            )
409
            .image_offset(vk::Offset3D {
410
                x: region.loc.x,
411
                y: region.loc.y,
412
                z: 0,
413
            })
414
            .image_extent(vk::Extent3D {
415
                width: region.size.w as u32,
416
                height: region.size.h as u32,
417
                depth: 1,
418
            });
419
        let buffer = staging.buffer;
420
        let target = image.clone();
421
        self.one_shot(|d, cmd, family| unsafe {
422
            acquire(
423
                d,
424
                cmd,
425
                family,
426
                &target,
427
                vk::ImageLayout::TRANSFER_DST_OPTIMAL,
428
            );
429
            d.cmd_copy_buffer_to_image(
430
                cmd,
431
                buffer,
432
                target.image,
433
                vk::ImageLayout::TRANSFER_DST_OPTIMAL,
434
                &[copy],
435
            );
436
            acquire(
437
                d,
438
                cmd,
439
                family,
440
                &target,
441
                vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
442
            );
443
        })
444
    }
445
446
    fn read_back(
447
        &mut self,
448
        image: &Arc<ImageInner>,
449
        region: Rectangle<i32, Buffer>,
450
        fourcc: Fourcc,
451
    ) -> Result<VulkanMapping, Error> {
452
        let region = region
453
            .intersection(Rectangle::from_size(
454
                (image.width as i32, image.height as i32).into(),
455
            ))
456
            .unwrap_or_default();
457
        let (w, h) = (region.size.w.max(0) as u32, region.size.h.max(0) as u32);
458
        let swap = needs_swizzle(image.fourcc, fourcc)?;
459
        let len = (w as usize * h as usize * BYTES_PER_PIXEL).max(BYTES_PER_PIXEL);
460
        let staging = Staging::new(
461
            &self.shared,
462
            len,
463
            vk::BufferUsageFlags::TRANSFER_DST,
464
            MemoryLocation::GpuToCpu,
465
        )?;
466
        if w > 0 && h > 0 {
467
            let copy = vk::BufferImageCopy::default()
468
                .image_subresource(
469
                    vk::ImageSubresourceLayers::default()
470
                        .aspect_mask(vk::ImageAspectFlags::COLOR)
471
                        .layer_count(1),
472
                )
473
                .image_offset(vk::Offset3D {
474
                    x: region.loc.x,
475
                    y: region.loc.y,
476
                    z: 0,
477
                })
478
                .image_extent(vk::Extent3D {
479
                    width: w,
480
                    height: h,
481
                    depth: 1,
482
                });
483
            let buffer = staging.buffer;
484
            let source = image.clone();
485
            self.one_shot(|d, cmd, family| unsafe {
486
                acquire(
487
                    d,
488
                    cmd,
489
                    family,
490
                    &source,
491
                    vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
492
                );
493
                d.cmd_copy_image_to_buffer(
494
                    cmd,
495
                    source.image,
496
                    vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
497
                    buffer,
498
                    &[copy],
499
                );
500
                release(
501
                    d,
502
                    cmd,
503
                    family,
504
                    &source,
505
                    vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
506
                );
507
            })?;
508
        }
509
        let mut data = staging.bytes()[..w as usize * h as usize * BYTES_PER_PIXEL].to_vec();
510
        if swap {
511
            for px in data.as_chunks_mut::<BYTES_PER_PIXEL>().0 {
512
                px.swap(0, 2);
513
            }
514
        }
515
        Ok(VulkanMapping {
516
            data,
517
            width: w,
518
            height: h,
519
            fourcc,
520
        })
521
    }
522
523
    fn own(&self, image: &Arc<ImageInner>) -> Result<(), Error> {
524
        if Arc::ptr_eq(&image.shared, &self.shared) {
525
            Ok(())
526
        } else {
527
            Err(Error::ForeignTexture)
528
        }
529
    }
530
}
531
532
impl Drop for VulkanRenderer {
533
    fn drop(&mut self) {
534
        let d = &self.shared.device.device;
535
        unsafe {
536
            let _ = d.device_wait_idle();
537
            for p in self.pending.drain(..) {
538
                d.free_command_buffers(self.pool, &[p.cmd]);
539
            }
540
            for s in self.samplers {
541
                d.destroy_sampler(s, None);
542
            }
543
            d.destroy_command_pool(self.pool, None);
544
        }
545
    }
546
}
547
548
fn sampler_filter(bit: usize) -> TextureFilter {
549
    if bit == 0 {
550
        TextureFilter::Linear
551
    } else {
552
        TextureFilter::Nearest
553
    }
554
}
555
556
/// A full barrier between all earlier and later work on the image, optionally
557
/// transferring ownership between queue families. Coarse, but correct for
558
/// every transition the renderer makes.
559
unsafe fn barrier(
560
    d: &ash::Device,
561
    cmd: vk::CommandBuffer,
562
    image: vk::Image,
563
    old: vk::ImageLayout,
564
    new: vk::ImageLayout,
565
    src_family: u32,
566
    dst_family: u32,
567
) {
568
    let b = [vk::ImageMemoryBarrier2::default()
569
        .src_stage_mask(vk::PipelineStageFlags2::ALL_COMMANDS)
570
        .src_access_mask(vk::AccessFlags2::MEMORY_WRITE)
571
        .dst_stage_mask(vk::PipelineStageFlags2::ALL_COMMANDS)
572
        .dst_access_mask(vk::AccessFlags2::MEMORY_READ | vk::AccessFlags2::MEMORY_WRITE)
573
        .old_layout(old)
574
        .new_layout(new)
575
        .src_queue_family_index(src_family)
576
        .dst_queue_family_index(dst_family)
577
        .image(image)
578
        .subresource_range(color_range())];
579
    unsafe {
580
        d.cmd_pipeline_barrier2(
581
            cmd,
582
            &vk::DependencyInfo::default().image_memory_barriers(&b),
583
        )
584
    };
585
}
586
587
/// Moves an image into `layout` for use on this queue. Dmabuf images come
588
/// from the foreign queue family in the general layout, others continue from
589
/// their tracked layout.
590
unsafe fn acquire(
591
    d: &ash::Device,
592
    cmd: vk::CommandBuffer,
593
    family: u32,
594
    image: &ImageInner,
595
    layout: vk::ImageLayout,
596
) {
597
    if image.external {
598
        unsafe {
599
            barrier(
600
                d,
601
                cmd,
602
                image.image,
603
                vk::ImageLayout::GENERAL,
604
                layout,
605
                vk::QUEUE_FAMILY_FOREIGN_EXT,
606
                family,
607
            )
608
        };
609
    } else {
610
        let old = image.layout();
611
        if old != layout {
612
            unsafe {
613
                barrier(
614
                    d,
615
                    cmd,
616
                    image.image,
617
                    old,
618
                    layout,
619
                    vk::QUEUE_FAMILY_IGNORED,
620
                    vk::QUEUE_FAMILY_IGNORED,
621
                )
622
            };
623
            image.set_layout(layout);
624
        }
625
    }
626
}
627
628
/// Hands a dmabuf image back to the foreign queue family after use.
629
unsafe fn release(
630
    d: &ash::Device,
631
    cmd: vk::CommandBuffer,
632
    family: u32,
633
    image: &ImageInner,
634
    layout: vk::ImageLayout,
635
) {
636
    if image.external {
637
        unsafe {
638
            barrier(
639
                d,
640
                cmd,
641
                image.image,
642
                layout,
643
                vk::ImageLayout::GENERAL,
644
                family,
645
                vk::QUEUE_FAMILY_FOREIGN_EXT,
646
            )
647
        };
648
    }
649
}
650
651
/// Whether reading `from` as `to` needs red and blue swapped.
652
fn needs_swizzle(from: Fourcc, to: Fourcc) -> Result<bool, Error> {
653
    let bgr = |f: Fourcc| match f {
654
        Fourcc::Argb8888 | Fourcc::Xrgb8888 => Ok(true),
655
        Fourcc::Abgr8888 | Fourcc::Xbgr8888 => Ok(false),
656
        f => Err(Error::UnsupportedFormat(f)),
657
    };
658
    Ok(bgr(from)? != bgr(to)?)
659
}
660
661
impl RendererSuper for VulkanRenderer {
662
    type Error = Error;
663
    type TextureId = VulkanTexture;
664
    type Framebuffer<'buffer> = VulkanTarget<'buffer>;
665
    type Frame<'frame, 'buffer>
666
        = VulkanFrame<'frame, 'buffer>
667
    where
668
        'buffer: 'frame,
669
        Self: 'frame;
670
}
671
672
impl Renderer for VulkanRenderer {
673
    fn context_id(&self) -> ContextId<VulkanTexture> {
674
        self.context.clone()
675
    }
676
677
    fn downscale_filter(&mut self, filter: TextureFilter) -> Result<(), Error> {
678
        self.min_filter = filter;
679
        Ok(())
680
    }
681
682
    fn upscale_filter(&mut self, filter: TextureFilter) -> Result<(), Error> {
683
        self.mag_filter = filter;
684
        Ok(())
685
    }
686
687
    fn set_debug_flags(&mut self, flags: DebugFlags) {
688
        self.debug = flags;
689
    }
690
691
    fn debug_flags(&self) -> DebugFlags {
692
        self.debug
693
    }
694
695
    fn render<'frame, 'buffer>(
696
        &'frame mut self,
697
        framebuffer: &'frame mut VulkanTarget<'buffer>,
698
        output_size: Size<i32, Physical>,
699
        dst_transform: Transform,
700
    ) -> Result<VulkanFrame<'frame, 'buffer>, Error>
701
    where
702
        'buffer: 'frame,
703
    {
704
        self.own(&framebuffer.0)?;
705
        self.reap();
706
        Ok(VulkanFrame::new(
707
            self,
708
            framebuffer,
709
            output_size,
710
            dst_transform,
711
        ))
712
    }
713
714
    fn wait(&mut self, sync: &SyncPoint) -> Result<(), Error> {
715
        sync.wait().map_err(|_| Error::Interrupted)
716
    }
717
718
    fn cleanup_texture_cache(&mut self) -> Result<(), Error> {
719
        self.reap();
720
        Ok(())
721
    }
722
723
    fn invalidate_caches(&mut self) -> Result<(), Error> {
724
        self.reap();
725
        self.dmabuf_textures.clear();
726
        self.dmabuf_targets.clear();
727
        Ok(())
728
    }
729
}
730
731
impl Bind<VulkanImage> for VulkanRenderer {
732
    fn bind<'a>(&mut self, target: &'a mut VulkanImage) -> Result<VulkanTarget<'a>, Error> {
733
        self.own(&target.0)?;
734
        Ok(VulkanTarget(target.0.clone(), PhantomData))
735
    }
736
}
737
738
impl Bind<Dmabuf> for VulkanRenderer {
739
    fn bind<'a>(&mut self, target: &'a mut Dmabuf) -> Result<VulkanTarget<'a>, Error> {
740
        let key = target.weak();
741
        let image = match self.dmabuf_targets.get(&key) {
742
            Some(image) => image.clone(),
743
            None => {
744
                let image = dmabuf::import(&self.shared, &self.caps, target, RENDER_USAGE)?;
745
                self.dmabuf_targets.insert(key, image.clone());
746
                image
747
            }
748
        };
749
        Ok(VulkanTarget(image, PhantomData))
750
    }
751
752
    fn supported_formats(&self) -> Option<FormatSet> {
753
        Some(self.caps.render.clone())
754
    }
755
}
756
757
impl Offscreen<VulkanImage> for VulkanRenderer {
758
    fn create_buffer(
759
        &mut self,
760
        format: Fourcc,
761
        size: Size<i32, Buffer>,
762
    ) -> Result<VulkanImage, Error> {
763
        if size.w <= 0 || size.h <= 0 {
764
            return Err(Error::InvalidSize(size.w, size.h));
765
        }
766
        let usage = vk::ImageUsageFlags::COLOR_ATTACHMENT
767
            | vk::ImageUsageFlags::SAMPLED
768
            | vk::ImageUsageFlags::TRANSFER_SRC
769
            | vk::ImageUsageFlags::TRANSFER_DST;
770
        Ok(VulkanImage(ImageInner::create(
771
            &self.shared,
772
            format,
773
            size.w as u32,
774
            size.h as u32,
775
            usage,
776
        )?))
777
    }
778
}
779
780
impl ImportMem for VulkanRenderer {
781
    fn import_memory(
782
        &mut self,
783
        data: &[u8],
784
        format: Fourcc,
785
        size: Size<i32, Buffer>,
786
        flipped: bool,
787
    ) -> Result<VulkanTexture, Error> {
788
        if size.w <= 0 || size.h <= 0 {
789
            return Err(Error::InvalidSize(size.w, size.h));
790
        }
791
        let usage = vk::ImageUsageFlags::SAMPLED
792
            | vk::ImageUsageFlags::TRANSFER_DST
793
            | vk::ImageUsageFlags::TRANSFER_SRC;
794
        let image = ImageInner::create(&self.shared, format, size.w as u32, size.h as u32, usage)?;
795
        self.upload(&image, data, Rectangle::from_size(size), flipped)?;
796
        Ok(VulkanTexture(image))
797
    }
798
799
    fn update_memory(
800
        &mut self,
801
        texture: &VulkanTexture,
802
        data: &[u8],
803
        region: Rectangle<i32, Buffer>,
804
    ) -> Result<(), Error> {
805
        self.own(&texture.0)?;
806
        let Some(region) = region.intersection(Rectangle::from_size(texture.size())) else {
807
            return Ok(());
808
        };
809
        self.upload(&texture.0, data, region, false)
810
    }
811
812
    fn mem_formats(&self) -> Box<dyn Iterator<Item = Fourcc>> {
813
        Box::new(SUPPORTED.into_iter())
814
    }
815
}
816
817
impl ImportDma for VulkanRenderer {
818
    fn dmabuf_formats(&self) -> FormatSet {
819
        self.caps.sample.clone()
820
    }
821
822
    fn import_dmabuf(
823
        &mut self,
824
        buffer: &Dmabuf,
825
        _damage: Option<&[Rectangle<i32, Buffer>]>,
826
    ) -> Result<VulkanTexture, Error> {
827
        let key = buffer.weak();
828
        if let Some(t) = self.dmabuf_textures.get(&key) {
829
            return Ok(t.clone());
830
        }
831
        let texture = VulkanTexture(dmabuf::import(
832
            &self.shared,
833
            &self.caps,
834
            buffer,
835
            SAMPLE_USAGE,
836
        )?);
837
        self.dmabuf_textures.insert(key, texture.clone());
838
        Ok(texture)
839
    }
840
}
841
842
impl ImportDmaWl for VulkanRenderer {}
843
844
impl ExportMem for VulkanRenderer {
845
    type TextureMapping = VulkanMapping;
846
847
    fn copy_framebuffer(
848
        &mut self,
849
        target: &VulkanTarget<'_>,
850
        region: Rectangle<i32, Buffer>,
851
        format: Fourcc,
852
    ) -> Result<VulkanMapping, Error> {
853
        self.own(&target.0)?;
854
        let image = target.0.clone();
855
        self.read_back(&image, region, format)
856
    }
857
858
    fn copy_texture(
859
        &mut self,
860
        texture: &VulkanTexture,
861
        region: Rectangle<i32, Buffer>,
862
        format: Fourcc,
863
    ) -> Result<VulkanMapping, Error> {
864
        self.own(&texture.0)?;
865
        self.read_back(&texture.0, region, format)
866
    }
867
868
    fn can_read_texture(&mut self, texture: &VulkanTexture) -> Result<bool, Error> {
869
        Ok(texture.0.external || texture.0.layout() != vk::ImageLayout::UNDEFINED)
870
    }
871
872
    fn map_texture<'a>(&mut self, mapping: &'a VulkanMapping) -> Result<&'a [u8], Error> {
873
        Ok(&mapping.data)
874
    }
875
}