atagen

monolith

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