atagen

monolith

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