atagen

monolith

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