atagen

monolith

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