atagen

monolith

public
Star0
Watch0
04f0de43684167aa07cc57462d63bf998c75756b
1
ssh://brewery@pls.lobotomise.me:33/atagen/monolith.git

Blame: crates/render-vk/src/renderer.rs

824bf02b6e55atagen2026-10-16 09:15 UTC1
use crate::Error;
824bf02b6e55atagen2026-10-16 09:15 UTC2
use crate::device::Shared;
7de49c2aa70batagen2026-10-16 09:27 UTC3
use crate::dmabuf::{self, DmabufCaps, RENDER_USAGE, SAMPLE_USAGE, VulkanAllocator};
824bf02b6e55atagen2026-10-16 09:15 UTC4
use crate::format::{BYTES_PER_PIXEL, SUPPORTED};
824bf02b6e55atagen2026-10-16 09:15 UTC5
use crate::frame::{Op, VulkanFrame};
824bf02b6e55atagen2026-10-16 09:15 UTC6
use crate::image::{
824bf02b6e55atagen2026-10-16 09:15 UTC7
    ImageInner, Staging, VulkanImage, VulkanMapping, VulkanTarget, VulkanTexture, color_range,
824bf02b6e55atagen2026-10-16 09:15 UTC8
};
824bf02b6e55atagen2026-10-16 09:15 UTC9
use crate::pipeline::Pipelines;
824bf02b6e55atagen2026-10-16 09:15 UTC10
use crate::sync::{FenceInner, VkFence};
824bf02b6e55atagen2026-10-16 09:15 UTC11
use ash::vk;
824bf02b6e55atagen2026-10-16 09:15 UTC12
use gpu_allocator::MemoryLocation;
824bf02b6e55atagen2026-10-16 09:15 UTC13
use smithay::backend::allocator::Fourcc;
7de49c2aa70batagen2026-10-16 09:27 UTC14
use smithay::backend::allocator::dmabuf::{Dmabuf, WeakDmabuf};
7de49c2aa70batagen2026-10-16 09:27 UTC15
use smithay::backend::allocator::format::FormatSet;
d4a64ce87164atagen2026-10-16 09:34 UTC16
use smithay::backend::renderer::ImportMemWl;
824bf02b6e55atagen2026-10-16 09:15 UTC17
use smithay::backend::renderer::sync::SyncPoint;
824bf02b6e55atagen2026-10-16 09:15 UTC18
use smithay::backend::renderer::{
7de49c2aa70batagen2026-10-16 09:27 UTC19
    Bind, ContextId, DebugFlags, ExportMem, ImportDma, ImportDmaWl, ImportMem, Offscreen, Renderer,
7de49c2aa70batagen2026-10-16 09:27 UTC20
    RendererSuper, Texture, TextureFilter,
824bf02b6e55atagen2026-10-16 09:15 UTC21
};
0f11410be91batagen2026-10-17 03:59 UTC22
use smithay::reexports::wayland_server::Resource;
0f11410be91batagen2026-10-17 03:59 UTC23
use smithay::reexports::wayland_server::backend::ObjectId;
d4a64ce87164atagen2026-10-16 09:34 UTC24
use smithay::reexports::wayland_server::protocol::wl_buffer::WlBuffer;
824bf02b6e55atagen2026-10-16 09:15 UTC25
use smithay::utils::{Buffer, Physical, Rectangle, Size, Transform};
d4a64ce87164atagen2026-10-16 09:34 UTC26
use smithay::wayland::compositor::SurfaceData;
d4a64ce87164atagen2026-10-16 09:34 UTC27
use smithay::wayland::shm::{shm_format_to_fourcc, with_buffer_contents};
5cd954fce34batagen2026-10-16 22:42 UTC28
use std::cell::Cell;
7de49c2aa70batagen2026-10-16 09:27 UTC29
use std::collections::HashMap;
824bf02b6e55atagen2026-10-16 09:15 UTC30
use std::fmt;
7de49c2aa70batagen2026-10-16 09:27 UTC31
use std::marker::PhantomData;
48af562d968batagen2026-10-16 12:39 UTC32
use std::sync::{Arc, Mutex};
5cd954fce34batagen2026-10-16 22:42 UTC33
use std::time::{Duration, Instant};
824bf02b6e55atagen2026-10-16 09:15 UTC34
824bf02b6e55atagen2026-10-16 09:15 UTC35
struct Pending {
824bf02b6e55atagen2026-10-16 09:15 UTC36
    fence: Arc<FenceInner>,
824bf02b6e55atagen2026-10-16 09:15 UTC37
    cmd: vk::CommandBuffer,
7de49c2aa70batagen2026-10-16 09:27 UTC38
    _keep: Vec<Arc<ImageInner>>,
48af562d968batagen2026-10-16 12:39 UTC39
    _staging: Option<Staging>,
824bf02b6e55atagen2026-10-16 09:15 UTC40
}
824bf02b6e55atagen2026-10-16 09:15 UTC41
824bf02b6e55atagen2026-10-16 09:15 UTC42
pub struct VulkanRenderer {
824bf02b6e55atagen2026-10-16 09:15 UTC43
    pending: Vec<Pending>,
7de49c2aa70batagen2026-10-16 09:27 UTC44
    dmabuf_textures: HashMap<WeakDmabuf, VulkanTexture>,
7de49c2aa70batagen2026-10-16 09:27 UTC45
    dmabuf_targets: HashMap<WeakDmabuf, Arc<ImageInner>>,
824bf02b6e55atagen2026-10-16 09:15 UTC46
    pipelines: Pipelines,
824bf02b6e55atagen2026-10-16 09:15 UTC47
    pool: vk::CommandPool,
d5eca1c82213atagen2026-10-16 13:56 UTC48
    /// Command buffers whose work finished, reset and reused by `begin`.
d5eca1c82213atagen2026-10-16 13:56 UTC49
    spare_cmds: Vec<vk::CommandBuffer>,
824bf02b6e55atagen2026-10-16 09:15 UTC50
    samplers: [vk::Sampler; 4],
824bf02b6e55atagen2026-10-16 09:15 UTC51
    min_filter: TextureFilter,
824bf02b6e55atagen2026-10-16 09:15 UTC52
    mag_filter: TextureFilter,
824bf02b6e55atagen2026-10-16 09:15 UTC53
    debug: DebugFlags,
824bf02b6e55atagen2026-10-16 09:15 UTC54
    context: ContextId<VulkanTexture>,
7de49c2aa70batagen2026-10-16 09:27 UTC55
    caps: Arc<DmabufCaps>,
824bf02b6e55atagen2026-10-16 09:15 UTC56
    shared: Arc<Shared>,
5cd954fce34batagen2026-10-16 22:42 UTC57
    submissions: Cell<u64>,
0f11410be91batagen2026-10-17 03:59 UTC58
    /// Shm uploads staged off the main thread, by buffer.
0f11410be91batagen2026-10-17 03:59 UTC59
    staged: HashMap<ObjectId, (WlBuffer, StagedShm)>,
5cd954fce34batagen2026-10-16 22:42 UTC60
    stall: Cell<StallPhase>,
824bf02b6e55atagen2026-10-16 09:15 UTC61
}
824bf02b6e55atagen2026-10-16 09:15 UTC62
5cd954fce34batagen2026-10-16 22:42 UTC63
/// Where in every 1024 submissions the driver stalls. A phase is trusted
5cd954fce34batagen2026-10-16 22:42 UTC64
/// once two stalls land on it.
5cd954fce34batagen2026-10-16 22:42 UTC65
#[derive(Clone, Copy, Default)]
5cd954fce34batagen2026-10-16 22:42 UTC66
struct StallPhase {
5cd954fce34batagen2026-10-16 22:42 UTC67
    phase: Option<u64>,
5cd954fce34batagen2026-10-16 22:42 UTC68
    seen: Option<u64>,
5cd954fce34batagen2026-10-16 22:42 UTC69
}
5cd954fce34batagen2026-10-16 22:42 UTC70
5cd954fce34batagen2026-10-16 22:42 UTC71
impl StallPhase {
5cd954fce34batagen2026-10-16 22:42 UTC72
    fn saw(self, at: u64) -> Self {
5cd954fce34batagen2026-10-16 22:42 UTC73
        if self.seen == Some(at) {
5cd954fce34batagen2026-10-16 22:42 UTC74
            if self.phase != Some(at) {
5cd954fce34batagen2026-10-16 22:42 UTC75
                tracing::debug!(phase = at, "queue submissions stall periodically");
5cd954fce34batagen2026-10-16 22:42 UTC76
            }
5cd954fce34batagen2026-10-16 22:42 UTC77
            Self {
5cd954fce34batagen2026-10-16 22:42 UTC78
                phase: Some(at),
5cd954fce34batagen2026-10-16 22:42 UTC79
                seen: Some(at),
5cd954fce34batagen2026-10-16 22:42 UTC80
            }
5cd954fce34batagen2026-10-16 22:42 UTC81
        } else {
5cd954fce34batagen2026-10-16 22:42 UTC82
            Self {
5cd954fce34batagen2026-10-16 22:42 UTC83
                seen: Some(at),
5cd954fce34batagen2026-10-16 22:42 UTC84
                ..self
5cd954fce34batagen2026-10-16 22:42 UTC85
            }
5cd954fce34batagen2026-10-16 22:42 UTC86
        }
5cd954fce34batagen2026-10-16 22:42 UTC87
    }
5cd954fce34batagen2026-10-16 22:42 UTC88
}
5cd954fce34batagen2026-10-16 22:42 UTC89
5cd954fce34batagen2026-10-16 22:42 UTC90
/// A submission this slow is a driver stall rather than work.
5cd954fce34batagen2026-10-16 22:42 UTC91
const STALL: Duration = Duration::from_micros(1500);
5cd954fce34batagen2026-10-16 22:42 UTC92
/// How many submissions early a stall is absorbed. Each empty one costs
5cd954fce34batagen2026-10-16 22:42 UTC93
/// tens of microseconds.
5cd954fce34batagen2026-10-16 22:42 UTC94
const ABSORB_AHEAD: u64 = 8;
5cd954fce34batagen2026-10-16 22:42 UTC95
824bf02b6e55atagen2026-10-16 09:15 UTC96
impl fmt::Debug for VulkanRenderer {
824bf02b6e55atagen2026-10-16 09:15 UTC97
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
824bf02b6e55atagen2026-10-16 09:15 UTC98
        f.debug_struct("VulkanRenderer")
824bf02b6e55atagen2026-10-16 09:15 UTC99
            .field("device", &self.shared.device.name)
824bf02b6e55atagen2026-10-16 09:15 UTC100
            .finish()
824bf02b6e55atagen2026-10-16 09:15 UTC101
    }
824bf02b6e55atagen2026-10-16 09:15 UTC102
}
824bf02b6e55atagen2026-10-16 09:15 UTC103
824bf02b6e55atagen2026-10-16 09:15 UTC104
impl VulkanRenderer {
824bf02b6e55atagen2026-10-16 09:15 UTC105
    pub fn new() -> Result<Self, Error> {
f27fa4c2ade9atagen2026-10-16 12:59 UTC106
        Self::with_node(None)
f27fa4c2ade9atagen2026-10-16 12:59 UTC107
    }
f27fa4c2ade9atagen2026-10-16 12:59 UTC108
f27fa4c2ade9atagen2026-10-16 12:59 UTC109
    /// A renderer on the GPU behind DRM device number `node`, so it can
f27fa4c2ade9atagen2026-10-16 12:59 UTC110
    /// render into buffers that GPU scans out.
f27fa4c2ade9atagen2026-10-16 12:59 UTC111
    pub fn for_node(node: u64) -> Result<Self, Error> {
f27fa4c2ade9atagen2026-10-16 12:59 UTC112
        Self::with_node(Some(node))
f27fa4c2ade9atagen2026-10-16 12:59 UTC113
    }
f27fa4c2ade9atagen2026-10-16 12:59 UTC114
f27fa4c2ade9atagen2026-10-16 12:59 UTC115
    fn with_node(node: Option<u64>) -> Result<Self, Error> {
f27fa4c2ade9atagen2026-10-16 12:59 UTC116
        let shared = Arc::new(Shared::new(node)?);
824bf02b6e55atagen2026-10-16 09:15 UTC117
        let d = &shared.device.device;
824bf02b6e55atagen2026-10-16 09:15 UTC118
        let pool = unsafe {
824bf02b6e55atagen2026-10-16 09:15 UTC119
            d.create_command_pool(
824bf02b6e55atagen2026-10-16 09:15 UTC120
                &vk::CommandPoolCreateInfo::default()
824bf02b6e55atagen2026-10-16 09:15 UTC121
                    .queue_family_index(shared.device.queue_family)
d5eca1c82213atagen2026-10-16 13:56 UTC122
                    .flags(
d5eca1c82213atagen2026-10-16 13:56 UTC123
                        vk::CommandPoolCreateFlags::TRANSIENT
d5eca1c82213atagen2026-10-16 13:56 UTC124
                            | vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER,
d5eca1c82213atagen2026-10-16 13:56 UTC125
                    ),
824bf02b6e55atagen2026-10-16 09:15 UTC126
                None,
824bf02b6e55atagen2026-10-16 09:15 UTC127
            )?
824bf02b6e55atagen2026-10-16 09:15 UTC128
        };
824bf02b6e55atagen2026-10-16 09:15 UTC129
        let filter = |f: TextureFilter| match f {
824bf02b6e55atagen2026-10-16 09:15 UTC130
            TextureFilter::Linear => vk::Filter::LINEAR,
824bf02b6e55atagen2026-10-16 09:15 UTC131
            TextureFilter::Nearest => vk::Filter::NEAREST,
824bf02b6e55atagen2026-10-16 09:15 UTC132
        };
824bf02b6e55atagen2026-10-16 09:15 UTC133
        let mut samplers = [vk::Sampler::null(); 4];
824bf02b6e55atagen2026-10-16 09:15 UTC134
        for (i, s) in samplers.iter_mut().enumerate() {
824bf02b6e55atagen2026-10-16 09:15 UTC135
            let (min, mag) = (sampler_filter(i >> 1), sampler_filter(i & 1));
824bf02b6e55atagen2026-10-16 09:15 UTC136
            *s = unsafe {
824bf02b6e55atagen2026-10-16 09:15 UTC137
                d.create_sampler(
824bf02b6e55atagen2026-10-16 09:15 UTC138
                    &vk::SamplerCreateInfo::default()
824bf02b6e55atagen2026-10-16 09:15 UTC139
                        .min_filter(filter(min))
824bf02b6e55atagen2026-10-16 09:15 UTC140
                        .mag_filter(filter(mag))
824bf02b6e55atagen2026-10-16 09:15 UTC141
                        .address_mode_u(vk::SamplerAddressMode::CLAMP_TO_EDGE)
824bf02b6e55atagen2026-10-16 09:15 UTC142
                        .address_mode_v(vk::SamplerAddressMode::CLAMP_TO_EDGE)
824bf02b6e55atagen2026-10-16 09:15 UTC143
                        .address_mode_w(vk::SamplerAddressMode::CLAMP_TO_EDGE),
824bf02b6e55atagen2026-10-16 09:15 UTC144
                    None,
824bf02b6e55atagen2026-10-16 09:15 UTC145
                )?
824bf02b6e55atagen2026-10-16 09:15 UTC146
            };
824bf02b6e55atagen2026-10-16 09:15 UTC147
        }
824bf02b6e55atagen2026-10-16 09:15 UTC148
        Ok(Self {
824bf02b6e55atagen2026-10-16 09:15 UTC149
            pending: Vec::new(),
7de49c2aa70batagen2026-10-16 09:27 UTC150
            dmabuf_textures: HashMap::new(),
7de49c2aa70batagen2026-10-16 09:27 UTC151
            dmabuf_targets: HashMap::new(),
824bf02b6e55atagen2026-10-16 09:15 UTC152
            pipelines: Pipelines::new(&shared)?,
824bf02b6e55atagen2026-10-16 09:15 UTC153
            pool,
d5eca1c82213atagen2026-10-16 13:56 UTC154
            spare_cmds: Vec::new(),
5cd954fce34batagen2026-10-16 22:42 UTC155
            submissions: Cell::new(0),
0f11410be91batagen2026-10-17 03:59 UTC156
            staged: HashMap::new(),
5cd954fce34batagen2026-10-16 22:42 UTC157
            stall: Cell::new(StallPhase {
5cd954fce34batagen2026-10-16 22:42 UTC158
                // Measured on an RTX 3060, see research/nvidia.md.
5cd954fce34batagen2026-10-16 22:42 UTC159
                phase: shared.device.name.contains("NVIDIA").then_some(1015),
5cd954fce34batagen2026-10-16 22:42 UTC160
                seen: None,
5cd954fce34batagen2026-10-16 22:42 UTC161
            }),
824bf02b6e55atagen2026-10-16 09:15 UTC162
            samplers,
824bf02b6e55atagen2026-10-16 09:15 UTC163
            min_filter: TextureFilter::Linear,
824bf02b6e55atagen2026-10-16 09:15 UTC164
            mag_filter: TextureFilter::Linear,
824bf02b6e55atagen2026-10-16 09:15 UTC165
            debug: DebugFlags::empty(),
824bf02b6e55atagen2026-10-16 09:15 UTC166
            context: ContextId::new(),
7de49c2aa70batagen2026-10-16 09:27 UTC167
            caps: Arc::new(DmabufCaps::query(&shared)),
824bf02b6e55atagen2026-10-16 09:15 UTC168
            shared,
824bf02b6e55atagen2026-10-16 09:15 UTC169
        })
824bf02b6e55atagen2026-10-16 09:15 UTC170
    }
824bf02b6e55atagen2026-10-16 09:15 UTC171
824bf02b6e55atagen2026-10-16 09:15 UTC172
    /// Name of the physical device in use.
824bf02b6e55atagen2026-10-16 09:15 UTC173
    pub fn device_name(&self) -> &str {
824bf02b6e55atagen2026-10-16 09:15 UTC174
        &self.shared.device.name
824bf02b6e55atagen2026-10-16 09:15 UTC175
    }
824bf02b6e55atagen2026-10-16 09:15 UTC176
7de49c2aa70batagen2026-10-16 09:27 UTC177
    /// Whether dmabufs can be imported, rendered into and allocated.
7de49c2aa70batagen2026-10-16 09:27 UTC178
    pub fn supports_dmabuf(&self) -> bool {
7de49c2aa70batagen2026-10-16 09:27 UTC179
        self.caps.render.iter().next().is_some()
7de49c2aa70batagen2026-10-16 09:27 UTC180
    }
7de49c2aa70batagen2026-10-16 09:27 UTC181
7de49c2aa70batagen2026-10-16 09:27 UTC182
    /// Formats and modifiers this renderer can render into as dmabufs.
7de49c2aa70batagen2026-10-16 09:27 UTC183
    pub fn render_formats(&self) -> FormatSet {
7de49c2aa70batagen2026-10-16 09:27 UTC184
        self.caps.render.clone()
7de49c2aa70batagen2026-10-16 09:27 UTC185
    }
7de49c2aa70batagen2026-10-16 09:27 UTC186
7de49c2aa70batagen2026-10-16 09:27 UTC187
    /// An allocator for render-capable dmabufs on this device.
7de49c2aa70batagen2026-10-16 09:27 UTC188
    pub fn allocator(&self) -> VulkanAllocator {
7de49c2aa70batagen2026-10-16 09:27 UTC189
        VulkanAllocator {
7de49c2aa70batagen2026-10-16 09:27 UTC190
            shared: self.shared.clone(),
7de49c2aa70batagen2026-10-16 09:27 UTC191
            caps: self.caps.clone(),
7de49c2aa70batagen2026-10-16 09:27 UTC192
        }
7de49c2aa70batagen2026-10-16 09:27 UTC193
    }
7de49c2aa70batagen2026-10-16 09:27 UTC194
824bf02b6e55atagen2026-10-16 09:15 UTC195
    pub(crate) fn shared(&self) -> &Arc<Shared> {
824bf02b6e55atagen2026-10-16 09:15 UTC196
        &self.shared
824bf02b6e55atagen2026-10-16 09:15 UTC197
    }
824bf02b6e55atagen2026-10-16 09:15 UTC198
824bf02b6e55atagen2026-10-16 09:15 UTC199
    pub(crate) fn context_id_ref(&self) -> &ContextId<VulkanTexture> {
824bf02b6e55atagen2026-10-16 09:15 UTC200
        &self.context
824bf02b6e55atagen2026-10-16 09:15 UTC201
    }
824bf02b6e55atagen2026-10-16 09:15 UTC202
824bf02b6e55atagen2026-10-16 09:15 UTC203
    fn sampler(&self) -> vk::Sampler {
824bf02b6e55atagen2026-10-16 09:15 UTC204
        let idx = |f: TextureFilter| usize::from(f == TextureFilter::Nearest);
824bf02b6e55atagen2026-10-16 09:15 UTC205
        self.samplers[(idx(self.min_filter) << 1) | idx(self.mag_filter)]
824bf02b6e55atagen2026-10-16 09:15 UTC206
    }
824bf02b6e55atagen2026-10-16 09:15 UTC207
824bf02b6e55atagen2026-10-16 09:15 UTC208
    fn reap(&mut self) {
d5eca1c82213atagen2026-10-16 13:56 UTC209
        let spare = &mut self.spare_cmds;
824bf02b6e55atagen2026-10-16 09:15 UTC210
        self.pending.retain(|p| {
824bf02b6e55atagen2026-10-16 09:15 UTC211
            if !p.fence.signaled() {
824bf02b6e55atagen2026-10-16 09:15 UTC212
                return true;
824bf02b6e55atagen2026-10-16 09:15 UTC213
            }
d5eca1c82213atagen2026-10-16 13:56 UTC214
            spare.push(p.cmd);
824bf02b6e55atagen2026-10-16 09:15 UTC215
            false
824bf02b6e55atagen2026-10-16 09:15 UTC216
        });
7de49c2aa70batagen2026-10-16 09:27 UTC217
        self.dmabuf_textures.retain(|k, _| !k.is_gone());
7de49c2aa70batagen2026-10-16 09:27 UTC218
        self.dmabuf_targets.retain(|k, _| !k.is_gone());
824bf02b6e55atagen2026-10-16 09:15 UTC219
    }
824bf02b6e55atagen2026-10-16 09:15 UTC220
d5eca1c82213atagen2026-10-16 13:56 UTC221
    fn begin(&mut self) -> Result<vk::CommandBuffer, Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC222
        let d = &self.shared.device.device;
d5eca1c82213atagen2026-10-16 13:56 UTC223
        let cmd = match self.spare_cmds.pop() {
d5eca1c82213atagen2026-10-16 13:56 UTC224
            Some(cmd) => {
d5eca1c82213atagen2026-10-16 13:56 UTC225
                unsafe { d.reset_command_buffer(cmd, vk::CommandBufferResetFlags::empty())? };
d5eca1c82213atagen2026-10-16 13:56 UTC226
                cmd
d5eca1c82213atagen2026-10-16 13:56 UTC227
            }
d5eca1c82213atagen2026-10-16 13:56 UTC228
            None => unsafe {
d5eca1c82213atagen2026-10-16 13:56 UTC229
                d.allocate_command_buffers(
d5eca1c82213atagen2026-10-16 13:56 UTC230
                    &vk::CommandBufferAllocateInfo::default()
d5eca1c82213atagen2026-10-16 13:56 UTC231
                        .command_pool(self.pool)
d5eca1c82213atagen2026-10-16 13:56 UTC232
                        .level(vk::CommandBufferLevel::PRIMARY)
d5eca1c82213atagen2026-10-16 13:56 UTC233
                        .command_buffer_count(1),
d5eca1c82213atagen2026-10-16 13:56 UTC234
                )?[0]
d5eca1c82213atagen2026-10-16 13:56 UTC235
            },
824bf02b6e55atagen2026-10-16 09:15 UTC236
        };
824bf02b6e55atagen2026-10-16 09:15 UTC237
        unsafe {
824bf02b6e55atagen2026-10-16 09:15 UTC238
            d.begin_command_buffer(
824bf02b6e55atagen2026-10-16 09:15 UTC239
                cmd,
824bf02b6e55atagen2026-10-16 09:15 UTC240
                &vk::CommandBufferBeginInfo::default()
824bf02b6e55atagen2026-10-16 09:15 UTC241
                    .flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT),
824bf02b6e55atagen2026-10-16 09:15 UTC242
            )?
824bf02b6e55atagen2026-10-16 09:15 UTC243
        };
824bf02b6e55atagen2026-10-16 09:15 UTC244
        Ok(cmd)
824bf02b6e55atagen2026-10-16 09:15 UTC245
    }
824bf02b6e55atagen2026-10-16 09:15 UTC246
30aece3a63ceatagen2026-10-16 13:48 UTC247
    #[profiling::function]
824bf02b6e55atagen2026-10-16 09:15 UTC248
    fn end_and_submit(&self, cmd: vk::CommandBuffer) -> Result<Arc<FenceInner>, Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC249
        let d = &self.shared.device.device;
d5eca1c82213atagen2026-10-16 13:56 UTC250
        {
d5eca1c82213atagen2026-10-16 13:56 UTC251
            profiling::scope!("end_command_buffer");
d5eca1c82213atagen2026-10-16 13:56 UTC252
            unsafe { d.end_command_buffer(cmd)? };
d5eca1c82213atagen2026-10-16 13:56 UTC253
        }
d5eca1c82213atagen2026-10-16 13:56 UTC254
        let fence = {
d5eca1c82213atagen2026-10-16 13:56 UTC255
            profiling::scope!("create_fence");
d5eca1c82213atagen2026-10-16 13:56 UTC256
            FenceInner::new(&self.shared)?
d5eca1c82213atagen2026-10-16 13:56 UTC257
        };
824bf02b6e55atagen2026-10-16 09:15 UTC258
        let cmds = [vk::CommandBufferSubmitInfo::default().command_buffer(cmd)];
824bf02b6e55atagen2026-10-16 09:15 UTC259
        let submit = vk::SubmitInfo2::default().command_buffer_infos(&cmds);
824bf02b6e55atagen2026-10-16 09:15 UTC260
        let queue = self
824bf02b6e55atagen2026-10-16 09:15 UTC261
            .shared
824bf02b6e55atagen2026-10-16 09:15 UTC262
            .device
824bf02b6e55atagen2026-10-16 09:15 UTC263
            .queue
824bf02b6e55atagen2026-10-16 09:15 UTC264
            .lock()
824bf02b6e55atagen2026-10-16 09:15 UTC265
            .unwrap_or_else(|e| e.into_inner());
5cd954fce34batagen2026-10-16 22:42 UTC266
        let began = Instant::now();
d5eca1c82213atagen2026-10-16 13:56 UTC267
        {
d5eca1c82213atagen2026-10-16 13:56 UTC268
            profiling::scope!("queue_submit");
d5eca1c82213atagen2026-10-16 13:56 UTC269
            unsafe { d.queue_submit2(*queue, &[submit], fence.fence())? };
d5eca1c82213atagen2026-10-16 13:56 UTC270
        }
5cd954fce34batagen2026-10-16 22:42 UTC271
        let n = self.submissions.get();
5cd954fce34batagen2026-10-16 22:42 UTC272
        self.submissions.set(n + 1);
5cd954fce34batagen2026-10-16 22:42 UTC273
        if began.elapsed() > STALL {
5cd954fce34batagen2026-10-16 22:42 UTC274
            self.stall.set(self.stall.get().saw(n % 1024));
5cd954fce34batagen2026-10-16 22:42 UTC275
        }
824bf02b6e55atagen2026-10-16 09:15 UTC276
        Ok(fence)
824bf02b6e55atagen2026-10-16 09:15 UTC277
    }
824bf02b6e55atagen2026-10-16 09:15 UTC278
5cd954fce34batagen2026-10-16 22:42 UTC279
    /// Spends an upcoming stalling submission on empty command buffers, so
5cd954fce34batagen2026-10-16 22:42 UTC280
    /// the stall lands now, in idle time, instead of in a frame. Call it
5cd954fce34batagen2026-10-16 22:42 UTC281
    /// right after a flip. NVIDIA stalls for milliseconds on every 1024th
5cd954fce34batagen2026-10-16 22:42 UTC282
    /// submission, see research/nvidia.md.
5cd954fce34batagen2026-10-16 22:42 UTC283
    pub fn absorb_submit_stall(&mut self) -> Result<(), Error> {
5cd954fce34batagen2026-10-16 22:42 UTC284
        self.reap();
5cd954fce34batagen2026-10-16 22:42 UTC285
        let Some(phase) = self.stall.get().phase else {
5cd954fce34batagen2026-10-16 22:42 UTC286
            return Ok(());
5cd954fce34batagen2026-10-16 22:42 UTC287
        };
5cd954fce34batagen2026-10-16 22:42 UTC288
        let ahead = (phase + 1024 - self.submissions.get() % 1024) % 1024;
5cd954fce34batagen2026-10-16 22:42 UTC289
        if ahead >= ABSORB_AHEAD {
5cd954fce34batagen2026-10-16 22:42 UTC290
            return Ok(());
5cd954fce34batagen2026-10-16 22:42 UTC291
        }
5cd954fce34batagen2026-10-16 22:42 UTC292
        for _ in 0..=ahead {
5cd954fce34batagen2026-10-16 22:42 UTC293
            let cmd = self.begin()?;
5cd954fce34batagen2026-10-16 22:42 UTC294
            let fence = self.end_and_submit(cmd)?;
5cd954fce34batagen2026-10-16 22:42 UTC295
            self.pending.push(Pending {
5cd954fce34batagen2026-10-16 22:42 UTC296
                fence,
5cd954fce34batagen2026-10-16 22:42 UTC297
                cmd,
5cd954fce34batagen2026-10-16 22:42 UTC298
                _keep: Vec::new(),
5cd954fce34batagen2026-10-16 22:42 UTC299
                _staging: None,
5cd954fce34batagen2026-10-16 22:42 UTC300
            });
5cd954fce34batagen2026-10-16 22:42 UTC301
        }
5cd954fce34batagen2026-10-16 22:42 UTC302
        Ok(())
5cd954fce34batagen2026-10-16 22:42 UTC303
    }
5cd954fce34batagen2026-10-16 22:42 UTC304
824bf02b6e55atagen2026-10-16 09:15 UTC305
    /// Records, submits and waits for a short command buffer.
824bf02b6e55atagen2026-10-16 09:15 UTC306
    fn one_shot(
824bf02b6e55atagen2026-10-16 09:15 UTC307
        &mut self,
7de49c2aa70batagen2026-10-16 09:27 UTC308
        record: impl FnOnce(&ash::Device, vk::CommandBuffer, u32),
824bf02b6e55atagen2026-10-16 09:15 UTC309
    ) -> Result<(), Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC310
        let cmd = self.begin()?;
7de49c2aa70batagen2026-10-16 09:27 UTC311
        record(
7de49c2aa70batagen2026-10-16 09:27 UTC312
            &self.shared.device.device,
7de49c2aa70batagen2026-10-16 09:27 UTC313
            cmd,
7de49c2aa70batagen2026-10-16 09:27 UTC314
            self.shared.device.queue_family,
7de49c2aa70batagen2026-10-16 09:27 UTC315
        );
824bf02b6e55atagen2026-10-16 09:15 UTC316
        let fence = self.end_and_submit(cmd)?;
824bf02b6e55atagen2026-10-16 09:15 UTC317
        let res = fence.wait();
d5eca1c82213atagen2026-10-16 13:56 UTC318
        self.spare_cmds.push(cmd);
824bf02b6e55atagen2026-10-16 09:15 UTC319
        Ok(res?)
824bf02b6e55atagen2026-10-16 09:15 UTC320
    }
824bf02b6e55atagen2026-10-16 09:15 UTC321
30aece3a63ceatagen2026-10-16 13:48 UTC322
    #[profiling::function]
824bf02b6e55atagen2026-10-16 09:15 UTC323
    pub(crate) fn submit(
824bf02b6e55atagen2026-10-16 09:15 UTC324
        &mut self,
824bf02b6e55atagen2026-10-16 09:15 UTC325
        target: &mut VulkanTarget<'_>,
824bf02b6e55atagen2026-10-16 09:15 UTC326
        ops: Vec<Op>,
824bf02b6e55atagen2026-10-16 09:15 UTC327
    ) -> Result<SyncPoint, Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC328
        self.reap();
7de49c2aa70batagen2026-10-16 09:27 UTC329
        let image = target.0.clone();
7de49c2aa70batagen2026-10-16 09:27 UTC330
        let mut sampled: Vec<Arc<ImageInner>> = Vec::new();
824bf02b6e55atagen2026-10-16 09:15 UTC331
        for op in &ops {
824bf02b6e55atagen2026-10-16 09:15 UTC332
            if let Op::Draw {
824bf02b6e55atagen2026-10-16 09:15 UTC333
                texture: Some(t), ..
824bf02b6e55atagen2026-10-16 09:15 UTC334
            } = op
7de49c2aa70batagen2026-10-16 09:27 UTC335
                && !sampled.iter().any(|s| Arc::ptr_eq(s, &t.0))
824bf02b6e55atagen2026-10-16 09:15 UTC336
            {
7de49c2aa70batagen2026-10-16 09:27 UTC337
                sampled.push(t.0.clone());
824bf02b6e55atagen2026-10-16 09:15 UTC338
            }
824bf02b6e55atagen2026-10-16 09:15 UTC339
        }
824bf02b6e55atagen2026-10-16 09:15 UTC340
        let mut pipelines = Vec::with_capacity(ops.len());
824bf02b6e55atagen2026-10-16 09:15 UTC341
        for op in &ops {
824bf02b6e55atagen2026-10-16 09:15 UTC342
            pipelines.push(match op {
824bf02b6e55atagen2026-10-16 09:15 UTC343
                Op::Draw { kind, .. } => Some(self.pipelines.get(image.format, *kind)?),
824bf02b6e55atagen2026-10-16 09:15 UTC344
                Op::Clear { .. } => None,
824bf02b6e55atagen2026-10-16 09:15 UTC345
            });
824bf02b6e55atagen2026-10-16 09:15 UTC346
        }
824bf02b6e55atagen2026-10-16 09:15 UTC347
        let cmd = self.begin()?;
824bf02b6e55atagen2026-10-16 09:15 UTC348
        let d = &self.shared.device.device;
7de49c2aa70batagen2026-10-16 09:27 UTC349
        let family = self.shared.device.queue_family;
824bf02b6e55atagen2026-10-16 09:15 UTC350
        let push = &self.shared.device.push_descriptor;
824bf02b6e55atagen2026-10-16 09:15 UTC351
        let (w, h) = (image.width, image.height);
824bf02b6e55atagen2026-10-16 09:15 UTC352
        let sampler = self.sampler();
824bf02b6e55atagen2026-10-16 09:15 UTC353
        unsafe {
7de49c2aa70batagen2026-10-16 09:27 UTC354
            for t in &sampled {
7de49c2aa70batagen2026-10-16 09:27 UTC355
                acquire(d, cmd, family, t, vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL);
824bf02b6e55atagen2026-10-16 09:15 UTC356
            }
7de49c2aa70batagen2026-10-16 09:27 UTC357
            acquire(
824bf02b6e55atagen2026-10-16 09:15 UTC358
                d,
824bf02b6e55atagen2026-10-16 09:15 UTC359
                cmd,
7de49c2aa70batagen2026-10-16 09:27 UTC360
                family,
7de49c2aa70batagen2026-10-16 09:27 UTC361
                &image,
824bf02b6e55atagen2026-10-16 09:15 UTC362
                vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
824bf02b6e55atagen2026-10-16 09:15 UTC363
            );
824bf02b6e55atagen2026-10-16 09:15 UTC364
            let attachments = [vk::RenderingAttachmentInfo::default()
824bf02b6e55atagen2026-10-16 09:15 UTC365
                .image_view(image.view)
824bf02b6e55atagen2026-10-16 09:15 UTC366
                .image_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
824bf02b6e55atagen2026-10-16 09:15 UTC367
                .load_op(vk::AttachmentLoadOp::LOAD)
824bf02b6e55atagen2026-10-16 09:15 UTC368
                .store_op(vk::AttachmentStoreOp::STORE)];
824bf02b6e55atagen2026-10-16 09:15 UTC369
            let area = vk::Rect2D {
824bf02b6e55atagen2026-10-16 09:15 UTC370
                offset: vk::Offset2D::default(),
824bf02b6e55atagen2026-10-16 09:15 UTC371
                extent: vk::Extent2D {
824bf02b6e55atagen2026-10-16 09:15 UTC372
                    width: w,
824bf02b6e55atagen2026-10-16 09:15 UTC373
                    height: h,
824bf02b6e55atagen2026-10-16 09:15 UTC374
                },
824bf02b6e55atagen2026-10-16 09:15 UTC375
            };
824bf02b6e55atagen2026-10-16 09:15 UTC376
            d.cmd_begin_rendering(
824bf02b6e55atagen2026-10-16 09:15 UTC377
                cmd,
824bf02b6e55atagen2026-10-16 09:15 UTC378
                &vk::RenderingInfo::default()
824bf02b6e55atagen2026-10-16 09:15 UTC379
                    .render_area(area)
824bf02b6e55atagen2026-10-16 09:15 UTC380
                    .layer_count(1)
824bf02b6e55atagen2026-10-16 09:15 UTC381
                    .color_attachments(&attachments),
824bf02b6e55atagen2026-10-16 09:15 UTC382
            );
824bf02b6e55atagen2026-10-16 09:15 UTC383
            d.cmd_set_viewport(
824bf02b6e55atagen2026-10-16 09:15 UTC384
                cmd,
824bf02b6e55atagen2026-10-16 09:15 UTC385
                0,
824bf02b6e55atagen2026-10-16 09:15 UTC386
                &[vk::Viewport {
824bf02b6e55atagen2026-10-16 09:15 UTC387
                    x: 0.0,
824bf02b6e55atagen2026-10-16 09:15 UTC388
                    y: 0.0,
824bf02b6e55atagen2026-10-16 09:15 UTC389
                    width: w as f32,
824bf02b6e55atagen2026-10-16 09:15 UTC390
                    height: h as f32,
824bf02b6e55atagen2026-10-16 09:15 UTC391
                    min_depth: 0.0,
824bf02b6e55atagen2026-10-16 09:15 UTC392
                    max_depth: 1.0,
824bf02b6e55atagen2026-10-16 09:15 UTC393
                }],
824bf02b6e55atagen2026-10-16 09:15 UTC394
            );
824bf02b6e55atagen2026-10-16 09:15 UTC395
            let mut bound = vk::Pipeline::null();
824bf02b6e55atagen2026-10-16 09:15 UTC396
            for (op, pipeline) in ops.iter().zip(pipelines) {
824bf02b6e55atagen2026-10-16 09:15 UTC397
                match op {
824bf02b6e55atagen2026-10-16 09:15 UTC398
                    Op::Clear { color, rects } => {
824bf02b6e55atagen2026-10-16 09:15 UTC399
                        let clear = [vk::ClearAttachment {
824bf02b6e55atagen2026-10-16 09:15 UTC400
                            aspect_mask: vk::ImageAspectFlags::COLOR,
824bf02b6e55atagen2026-10-16 09:15 UTC401
                            color_attachment: 0,
824bf02b6e55atagen2026-10-16 09:15 UTC402
                            clear_value: vk::ClearValue {
824bf02b6e55atagen2026-10-16 09:15 UTC403
                                color: vk::ClearColorValue { float32: *color },
824bf02b6e55atagen2026-10-16 09:15 UTC404
                            },
824bf02b6e55atagen2026-10-16 09:15 UTC405
                        }];
824bf02b6e55atagen2026-10-16 09:15 UTC406
                        let rects: Vec<_> = rects
824bf02b6e55atagen2026-10-16 09:15 UTC407
                            .iter()
824bf02b6e55atagen2026-10-16 09:15 UTC408
                            .map(|&rect| vk::ClearRect {
824bf02b6e55atagen2026-10-16 09:15 UTC409
                                rect,
824bf02b6e55atagen2026-10-16 09:15 UTC410
                                base_array_layer: 0,
824bf02b6e55atagen2026-10-16 09:15 UTC411
                                layer_count: 1,
824bf02b6e55atagen2026-10-16 09:15 UTC412
                            })
824bf02b6e55atagen2026-10-16 09:15 UTC413
                            .collect();
824bf02b6e55atagen2026-10-16 09:15 UTC414
                        d.cmd_clear_attachments(cmd, &clear, &rects);
824bf02b6e55atagen2026-10-16 09:15 UTC415
                    }
824bf02b6e55atagen2026-10-16 09:15 UTC416
                    Op::Draw {
824bf02b6e55atagen2026-10-16 09:15 UTC417
                        texture,
824bf02b6e55atagen2026-10-16 09:15 UTC418
                        push: constants,
824bf02b6e55atagen2026-10-16 09:15 UTC419
                        scissors,
824bf02b6e55atagen2026-10-16 09:15 UTC420
                        ..
824bf02b6e55atagen2026-10-16 09:15 UTC421
                    } => {
824bf02b6e55atagen2026-10-16 09:15 UTC422
                        let pipeline = pipeline.unwrap_or_default();
824bf02b6e55atagen2026-10-16 09:15 UTC423
                        if pipeline != bound {
824bf02b6e55atagen2026-10-16 09:15 UTC424
                            d.cmd_bind_pipeline(cmd, vk::PipelineBindPoint::GRAPHICS, pipeline);
824bf02b6e55atagen2026-10-16 09:15 UTC425
                            bound = pipeline;
824bf02b6e55atagen2026-10-16 09:15 UTC426
                        }
824bf02b6e55atagen2026-10-16 09:15 UTC427
                        if let Some(t) = texture {
824bf02b6e55atagen2026-10-16 09:15 UTC428
                            let info = [vk::DescriptorImageInfo::default()
824bf02b6e55atagen2026-10-16 09:15 UTC429
                                .image_view(t.0.view)
824bf02b6e55atagen2026-10-16 09:15 UTC430
                                .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
824bf02b6e55atagen2026-10-16 09:15 UTC431
                                .sampler(sampler)];
824bf02b6e55atagen2026-10-16 09:15 UTC432
                            let write = vk::WriteDescriptorSet::default()
824bf02b6e55atagen2026-10-16 09:15 UTC433
                                .dst_binding(0)
824bf02b6e55atagen2026-10-16 09:15 UTC434
                                .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
824bf02b6e55atagen2026-10-16 09:15 UTC435
                                .image_info(&info);
824bf02b6e55atagen2026-10-16 09:15 UTC436
                            push.cmd_push_descriptor_set(
824bf02b6e55atagen2026-10-16 09:15 UTC437
                                cmd,
824bf02b6e55atagen2026-10-16 09:15 UTC438
                                vk::PipelineBindPoint::GRAPHICS,
824bf02b6e55atagen2026-10-16 09:15 UTC439
                                self.pipelines.layout,
824bf02b6e55atagen2026-10-16 09:15 UTC440
                                0,
824bf02b6e55atagen2026-10-16 09:15 UTC441
                                &[write],
824bf02b6e55atagen2026-10-16 09:15 UTC442
                            );
824bf02b6e55atagen2026-10-16 09:15 UTC443
                        }
824bf02b6e55atagen2026-10-16 09:15 UTC444
                        d.cmd_push_constants(
824bf02b6e55atagen2026-10-16 09:15 UTC445
                            cmd,
824bf02b6e55atagen2026-10-16 09:15 UTC446
                            self.pipelines.layout,
824bf02b6e55atagen2026-10-16 09:15 UTC447
                            vk::ShaderStageFlags::VERTEX | vk::ShaderStageFlags::FRAGMENT,
824bf02b6e55atagen2026-10-16 09:15 UTC448
                            0,
824bf02b6e55atagen2026-10-16 09:15 UTC449
                            constants.bytes(),
824bf02b6e55atagen2026-10-16 09:15 UTC450
                        );
824bf02b6e55atagen2026-10-16 09:15 UTC451
                        for s in scissors {
824bf02b6e55atagen2026-10-16 09:15 UTC452
                            d.cmd_set_scissor(cmd, 0, &[*s]);
824bf02b6e55atagen2026-10-16 09:15 UTC453
                            d.cmd_draw(cmd, 4, 1, 0, 0);
824bf02b6e55atagen2026-10-16 09:15 UTC454
                        }
824bf02b6e55atagen2026-10-16 09:15 UTC455
                    }
824bf02b6e55atagen2026-10-16 09:15 UTC456
                }
824bf02b6e55atagen2026-10-16 09:15 UTC457
            }
824bf02b6e55atagen2026-10-16 09:15 UTC458
            d.cmd_end_rendering(cmd);
7de49c2aa70batagen2026-10-16 09:27 UTC459
            release(
7de49c2aa70batagen2026-10-16 09:27 UTC460
                d,
7de49c2aa70batagen2026-10-16 09:27 UTC461
                cmd,
7de49c2aa70batagen2026-10-16 09:27 UTC462
                family,
7de49c2aa70batagen2026-10-16 09:27 UTC463
                &image,
7de49c2aa70batagen2026-10-16 09:27 UTC464
                vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
7de49c2aa70batagen2026-10-16 09:27 UTC465
            );
7de49c2aa70batagen2026-10-16 09:27 UTC466
            for t in &sampled {
7de49c2aa70batagen2026-10-16 09:27 UTC467
                release(d, cmd, family, t, vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL);
7de49c2aa70batagen2026-10-16 09:27 UTC468
            }
824bf02b6e55atagen2026-10-16 09:15 UTC469
        }
824bf02b6e55atagen2026-10-16 09:15 UTC470
        let fence = self.end_and_submit(cmd)?;
7de49c2aa70batagen2026-10-16 09:27 UTC471
        sampled.push(image);
824bf02b6e55atagen2026-10-16 09:15 UTC472
        self.pending.push(Pending {
824bf02b6e55atagen2026-10-16 09:15 UTC473
            fence: fence.clone(),
824bf02b6e55atagen2026-10-16 09:15 UTC474
            cmd,
7de49c2aa70batagen2026-10-16 09:27 UTC475
            _keep: sampled,
48af562d968batagen2026-10-16 12:39 UTC476
            _staging: None,
824bf02b6e55atagen2026-10-16 09:15 UTC477
        });
824bf02b6e55atagen2026-10-16 09:15 UTC478
        Ok(SyncPoint::from(VkFence(fence)))
824bf02b6e55atagen2026-10-16 09:15 UTC479
    }
824bf02b6e55atagen2026-10-16 09:15 UTC480
48af562d968batagen2026-10-16 12:39 UTC481
    /// Copies `region` of a full-image `data` into `image`, rows top-down or
48af562d968batagen2026-10-16 12:39 UTC482
    /// flipped.
824bf02b6e55atagen2026-10-16 09:15 UTC483
    fn upload(
824bf02b6e55atagen2026-10-16 09:15 UTC484
        &mut self,
824bf02b6e55atagen2026-10-16 09:15 UTC485
        image: &Arc<ImageInner>,
824bf02b6e55atagen2026-10-16 09:15 UTC486
        data: &[u8],
824bf02b6e55atagen2026-10-16 09:15 UTC487
        region: Rectangle<i32, Buffer>,
824bf02b6e55atagen2026-10-16 09:15 UTC488
        flipped: bool,
824bf02b6e55atagen2026-10-16 09:15 UTC489
    ) -> Result<(), Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC490
        let width = image.width as usize;
48af562d968batagen2026-10-16 12:39 UTC491
        let rows = image.height as usize;
48af562d968batagen2026-10-16 12:39 UTC492
        let needed = width * rows * BYTES_PER_PIXEL;
824bf02b6e55atagen2026-10-16 09:15 UTC493
        if data.len() < needed {
824bf02b6e55atagen2026-10-16 09:15 UTC494
            return Err(Error::BufferTooSmall {
824bf02b6e55atagen2026-10-16 09:15 UTC495
                needed,
824bf02b6e55atagen2026-10-16 09:15 UTC496
                got: data.len(),
824bf02b6e55atagen2026-10-16 09:15 UTC497
            });
824bf02b6e55atagen2026-10-16 09:15 UTC498
        }
48af562d968batagen2026-10-16 12:39 UTC499
        let stride = width * BYTES_PER_PIXEL;
48af562d968batagen2026-10-16 12:39 UTC500
        self.upload_with(image, region, |y| {
48af562d968batagen2026-10-16 12:39 UTC501
            let from = if flipped { rows - 1 - y } else { y };
48af562d968batagen2026-10-16 12:39 UTC502
            let start = from * stride + region.loc.x as usize * BYTES_PER_PIXEL;
48af562d968batagen2026-10-16 12:39 UTC503
            &data[start..start + region.size.w as usize * BYTES_PER_PIXEL]
48af562d968batagen2026-10-16 12:39 UTC504
        })
48af562d968batagen2026-10-16 12:39 UTC505
    }
48af562d968batagen2026-10-16 12:39 UTC506
48af562d968batagen2026-10-16 12:39 UTC507
    /// Uploads `region` of `image`, taking each image row `y` in the region
48af562d968batagen2026-10-16 12:39 UTC508
    /// from `row(y)`. The CPU does not wait: the copy is ordered before later
48af562d968batagen2026-10-16 12:39 UTC509
    /// frames by its barrier, and its staging memory lives until its fence.
30aece3a63ceatagen2026-10-16 13:48 UTC510
    #[profiling::function]
48af562d968batagen2026-10-16 12:39 UTC511
    fn upload_with<'a>(
48af562d968batagen2026-10-16 12:39 UTC512
        &mut self,
48af562d968batagen2026-10-16 12:39 UTC513
        image: &Arc<ImageInner>,
48af562d968batagen2026-10-16 12:39 UTC514
        region: Rectangle<i32, Buffer>,
48af562d968batagen2026-10-16 12:39 UTC515
        row: impl Fn(usize) -> &'a [u8],
48af562d968batagen2026-10-16 12:39 UTC516
    ) -> Result<(), Error> {
48af562d968batagen2026-10-16 12:39 UTC517
        if image.external {
48af562d968batagen2026-10-16 12:39 UTC518
            return Err(Error::ForeignTexture);
48af562d968batagen2026-10-16 12:39 UTC519
        }
48af562d968batagen2026-10-16 12:39 UTC520
        self.reap();
0f11410be91batagen2026-10-17 03:59 UTC521
        if region.size.w <= 0 || region.size.h <= 0 {
48af562d968batagen2026-10-16 12:39 UTC522
            return Ok(());
48af562d968batagen2026-10-16 12:39 UTC523
        }
0f11410be91batagen2026-10-17 03:59 UTC524
        let staging = stage_rows(&self.shared, region, row)?;
0f11410be91batagen2026-10-17 03:59 UTC525
        self.copy_staged(image, region, staging)
0f11410be91batagen2026-10-17 03:59 UTC526
    }
0f11410be91batagen2026-10-17 03:59 UTC527
0f11410be91batagen2026-10-17 03:59 UTC528
    /// Copies staged pixels into `region` of `image` on the GPU.
0f11410be91batagen2026-10-17 03:59 UTC529
    fn copy_staged(
0f11410be91batagen2026-10-17 03:59 UTC530
        &mut self,
0f11410be91batagen2026-10-17 03:59 UTC531
        image: &Arc<ImageInner>,
0f11410be91batagen2026-10-17 03:59 UTC532
        region: Rectangle<i32, Buffer>,
0f11410be91batagen2026-10-17 03:59 UTC533
        staging: Staging,
0f11410be91batagen2026-10-17 03:59 UTC534
    ) -> Result<(), Error> {
0f11410be91batagen2026-10-17 03:59 UTC535
        let (w, h) = (region.size.w as usize, region.size.h as usize);
824bf02b6e55atagen2026-10-16 09:15 UTC536
        let copy = vk::BufferImageCopy::default()
48af562d968batagen2026-10-16 12:39 UTC537
            .buffer_row_length(w as u32)
824bf02b6e55atagen2026-10-16 09:15 UTC538
            .image_subresource(
824bf02b6e55atagen2026-10-16 09:15 UTC539
                vk::ImageSubresourceLayers::default()
824bf02b6e55atagen2026-10-16 09:15 UTC540
                    .aspect_mask(vk::ImageAspectFlags::COLOR)
824bf02b6e55atagen2026-10-16 09:15 UTC541
                    .layer_count(1),
824bf02b6e55atagen2026-10-16 09:15 UTC542
            )
824bf02b6e55atagen2026-10-16 09:15 UTC543
            .image_offset(vk::Offset3D {
824bf02b6e55atagen2026-10-16 09:15 UTC544
                x: region.loc.x,
824bf02b6e55atagen2026-10-16 09:15 UTC545
                y: region.loc.y,
824bf02b6e55atagen2026-10-16 09:15 UTC546
                z: 0,
824bf02b6e55atagen2026-10-16 09:15 UTC547
            })
824bf02b6e55atagen2026-10-16 09:15 UTC548
            .image_extent(vk::Extent3D {
48af562d968batagen2026-10-16 12:39 UTC549
                width: w as u32,
48af562d968batagen2026-10-16 12:39 UTC550
                height: h as u32,
824bf02b6e55atagen2026-10-16 09:15 UTC551
                depth: 1,
824bf02b6e55atagen2026-10-16 09:15 UTC552
            });
d5eca1c82213atagen2026-10-16 13:56 UTC553
        let cmd = self.begin()?;
48af562d968batagen2026-10-16 12:39 UTC554
        let d = &self.shared.device.device;
48af562d968batagen2026-10-16 12:39 UTC555
        let family = self.shared.device.queue_family;
48af562d968batagen2026-10-16 12:39 UTC556
        unsafe {
48af562d968batagen2026-10-16 12:39 UTC557
            acquire(d, cmd, family, image, vk::ImageLayout::TRANSFER_DST_OPTIMAL);
824bf02b6e55atagen2026-10-16 09:15 UTC558
            d.cmd_copy_buffer_to_image(
824bf02b6e55atagen2026-10-16 09:15 UTC559
                cmd,
48af562d968batagen2026-10-16 12:39 UTC560
                staging.buffer,
48af562d968batagen2026-10-16 12:39 UTC561
                image.image,
824bf02b6e55atagen2026-10-16 09:15 UTC562
                vk::ImageLayout::TRANSFER_DST_OPTIMAL,
824bf02b6e55atagen2026-10-16 09:15 UTC563
                &[copy],
824bf02b6e55atagen2026-10-16 09:15 UTC564
            );
7de49c2aa70batagen2026-10-16 09:27 UTC565
            acquire(
824bf02b6e55atagen2026-10-16 09:15 UTC566
                d,
824bf02b6e55atagen2026-10-16 09:15 UTC567
                cmd,
7de49c2aa70batagen2026-10-16 09:27 UTC568
                family,
48af562d968batagen2026-10-16 12:39 UTC569
                image,
824bf02b6e55atagen2026-10-16 09:15 UTC570
                vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
824bf02b6e55atagen2026-10-16 09:15 UTC571
            );
48af562d968batagen2026-10-16 12:39 UTC572
        }
48af562d968batagen2026-10-16 12:39 UTC573
        let fence = self.end_and_submit(cmd)?;
48af562d968batagen2026-10-16 12:39 UTC574
        self.pending.push(Pending {
48af562d968batagen2026-10-16 12:39 UTC575
            fence,
48af562d968batagen2026-10-16 12:39 UTC576
            cmd,
48af562d968batagen2026-10-16 12:39 UTC577
            _keep: vec![image.clone()],
48af562d968batagen2026-10-16 12:39 UTC578
            _staging: Some(staging),
48af562d968batagen2026-10-16 12:39 UTC579
        });
48af562d968batagen2026-10-16 12:39 UTC580
        Ok(())
824bf02b6e55atagen2026-10-16 09:15 UTC581
    }
824bf02b6e55atagen2026-10-16 09:15 UTC582
824bf02b6e55atagen2026-10-16 09:15 UTC583
    fn read_back(
824bf02b6e55atagen2026-10-16 09:15 UTC584
        &mut self,
824bf02b6e55atagen2026-10-16 09:15 UTC585
        image: &Arc<ImageInner>,
824bf02b6e55atagen2026-10-16 09:15 UTC586
        region: Rectangle<i32, Buffer>,
824bf02b6e55atagen2026-10-16 09:15 UTC587
        fourcc: Fourcc,
824bf02b6e55atagen2026-10-16 09:15 UTC588
    ) -> Result<VulkanMapping, Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC589
        let region = region
824bf02b6e55atagen2026-10-16 09:15 UTC590
            .intersection(Rectangle::from_size(
824bf02b6e55atagen2026-10-16 09:15 UTC591
                (image.width as i32, image.height as i32).into(),
824bf02b6e55atagen2026-10-16 09:15 UTC592
            ))
824bf02b6e55atagen2026-10-16 09:15 UTC593
            .unwrap_or_default();
824bf02b6e55atagen2026-10-16 09:15 UTC594
        let (w, h) = (region.size.w.max(0) as u32, region.size.h.max(0) as u32);
824bf02b6e55atagen2026-10-16 09:15 UTC595
        let swap = needs_swizzle(image.fourcc, fourcc)?;
824bf02b6e55atagen2026-10-16 09:15 UTC596
        let len = (w as usize * h as usize * BYTES_PER_PIXEL).max(BYTES_PER_PIXEL);
824bf02b6e55atagen2026-10-16 09:15 UTC597
        let staging = Staging::new(
824bf02b6e55atagen2026-10-16 09:15 UTC598
            &self.shared,
824bf02b6e55atagen2026-10-16 09:15 UTC599
            len,
824bf02b6e55atagen2026-10-16 09:15 UTC600
            vk::BufferUsageFlags::TRANSFER_DST,
824bf02b6e55atagen2026-10-16 09:15 UTC601
            MemoryLocation::GpuToCpu,
824bf02b6e55atagen2026-10-16 09:15 UTC602
        )?;
824bf02b6e55atagen2026-10-16 09:15 UTC603
        if w > 0 && h > 0 {
824bf02b6e55atagen2026-10-16 09:15 UTC604
            let copy = vk::BufferImageCopy::default()
824bf02b6e55atagen2026-10-16 09:15 UTC605
                .image_subresource(
824bf02b6e55atagen2026-10-16 09:15 UTC606
                    vk::ImageSubresourceLayers::default()
824bf02b6e55atagen2026-10-16 09:15 UTC607
                        .aspect_mask(vk::ImageAspectFlags::COLOR)
824bf02b6e55atagen2026-10-16 09:15 UTC608
                        .layer_count(1),
824bf02b6e55atagen2026-10-16 09:15 UTC609
                )
824bf02b6e55atagen2026-10-16 09:15 UTC610
                .image_offset(vk::Offset3D {
824bf02b6e55atagen2026-10-16 09:15 UTC611
                    x: region.loc.x,
824bf02b6e55atagen2026-10-16 09:15 UTC612
                    y: region.loc.y,
824bf02b6e55atagen2026-10-16 09:15 UTC613
                    z: 0,
824bf02b6e55atagen2026-10-16 09:15 UTC614
                })
824bf02b6e55atagen2026-10-16 09:15 UTC615
                .image_extent(vk::Extent3D {
824bf02b6e55atagen2026-10-16 09:15 UTC616
                    width: w,
824bf02b6e55atagen2026-10-16 09:15 UTC617
                    height: h,
824bf02b6e55atagen2026-10-16 09:15 UTC618
                    depth: 1,
824bf02b6e55atagen2026-10-16 09:15 UTC619
                });
7de49c2aa70batagen2026-10-16 09:27 UTC620
            let buffer = staging.buffer;
7de49c2aa70batagen2026-10-16 09:27 UTC621
            let source = image.clone();
7de49c2aa70batagen2026-10-16 09:27 UTC622
            self.one_shot(|d, cmd, family| unsafe {
7de49c2aa70batagen2026-10-16 09:27 UTC623
                acquire(
7de49c2aa70batagen2026-10-16 09:27 UTC624
                    d,
7de49c2aa70batagen2026-10-16 09:27 UTC625
                    cmd,
7de49c2aa70batagen2026-10-16 09:27 UTC626
                    family,
7de49c2aa70batagen2026-10-16 09:27 UTC627
                    &source,
7de49c2aa70batagen2026-10-16 09:27 UTC628
                    vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
7de49c2aa70batagen2026-10-16 09:27 UTC629
                );
824bf02b6e55atagen2026-10-16 09:15 UTC630
                d.cmd_copy_image_to_buffer(
824bf02b6e55atagen2026-10-16 09:15 UTC631
                    cmd,
7de49c2aa70batagen2026-10-16 09:27 UTC632
                    source.image,
824bf02b6e55atagen2026-10-16 09:15 UTC633
                    vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
824bf02b6e55atagen2026-10-16 09:15 UTC634
                    buffer,
824bf02b6e55atagen2026-10-16 09:15 UTC635
                    &[copy],
824bf02b6e55atagen2026-10-16 09:15 UTC636
                );
7de49c2aa70batagen2026-10-16 09:27 UTC637
                release(
7de49c2aa70batagen2026-10-16 09:27 UTC638
                    d,
7de49c2aa70batagen2026-10-16 09:27 UTC639
                    cmd,
7de49c2aa70batagen2026-10-16 09:27 UTC640
                    family,
7de49c2aa70batagen2026-10-16 09:27 UTC641
                    &source,
7de49c2aa70batagen2026-10-16 09:27 UTC642
                    vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
7de49c2aa70batagen2026-10-16 09:27 UTC643
                );
824bf02b6e55atagen2026-10-16 09:15 UTC644
            })?;
824bf02b6e55atagen2026-10-16 09:15 UTC645
        }
824bf02b6e55atagen2026-10-16 09:15 UTC646
        let mut data = staging.bytes()[..w as usize * h as usize * BYTES_PER_PIXEL].to_vec();
824bf02b6e55atagen2026-10-16 09:15 UTC647
        if swap {
824bf02b6e55atagen2026-10-16 09:15 UTC648
            for px in data.as_chunks_mut::<BYTES_PER_PIXEL>().0 {
824bf02b6e55atagen2026-10-16 09:15 UTC649
                px.swap(0, 2);
824bf02b6e55atagen2026-10-16 09:15 UTC650
            }
824bf02b6e55atagen2026-10-16 09:15 UTC651
        }
824bf02b6e55atagen2026-10-16 09:15 UTC652
        Ok(VulkanMapping {
824bf02b6e55atagen2026-10-16 09:15 UTC653
            data,
824bf02b6e55atagen2026-10-16 09:15 UTC654
            width: w,
824bf02b6e55atagen2026-10-16 09:15 UTC655
            height: h,
824bf02b6e55atagen2026-10-16 09:15 UTC656
            fourcc,
824bf02b6e55atagen2026-10-16 09:15 UTC657
        })
824bf02b6e55atagen2026-10-16 09:15 UTC658
    }
824bf02b6e55atagen2026-10-16 09:15 UTC659
824bf02b6e55atagen2026-10-16 09:15 UTC660
    fn own(&self, image: &Arc<ImageInner>) -> Result<(), Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC661
        if Arc::ptr_eq(&image.shared, &self.shared) {
824bf02b6e55atagen2026-10-16 09:15 UTC662
            Ok(())
824bf02b6e55atagen2026-10-16 09:15 UTC663
        } else {
824bf02b6e55atagen2026-10-16 09:15 UTC664
            Err(Error::ForeignTexture)
824bf02b6e55atagen2026-10-16 09:15 UTC665
        }
824bf02b6e55atagen2026-10-16 09:15 UTC666
    }
824bf02b6e55atagen2026-10-16 09:15 UTC667
}
824bf02b6e55atagen2026-10-16 09:15 UTC668
824bf02b6e55atagen2026-10-16 09:15 UTC669
impl Drop for VulkanRenderer {
824bf02b6e55atagen2026-10-16 09:15 UTC670
    fn drop(&mut self) {
824bf02b6e55atagen2026-10-16 09:15 UTC671
        let d = &self.shared.device.device;
824bf02b6e55atagen2026-10-16 09:15 UTC672
        unsafe {
824bf02b6e55atagen2026-10-16 09:15 UTC673
            let _ = d.device_wait_idle();
824bf02b6e55atagen2026-10-16 09:15 UTC674
            for p in self.pending.drain(..) {
824bf02b6e55atagen2026-10-16 09:15 UTC675
                d.free_command_buffers(self.pool, &[p.cmd]);
824bf02b6e55atagen2026-10-16 09:15 UTC676
            }
824bf02b6e55atagen2026-10-16 09:15 UTC677
            for s in self.samplers {
824bf02b6e55atagen2026-10-16 09:15 UTC678
                d.destroy_sampler(s, None);
824bf02b6e55atagen2026-10-16 09:15 UTC679
            }
824bf02b6e55atagen2026-10-16 09:15 UTC680
            d.destroy_command_pool(self.pool, None);
824bf02b6e55atagen2026-10-16 09:15 UTC681
        }
824bf02b6e55atagen2026-10-16 09:15 UTC682
    }
824bf02b6e55atagen2026-10-16 09:15 UTC683
}
824bf02b6e55atagen2026-10-16 09:15 UTC684
824bf02b6e55atagen2026-10-16 09:15 UTC685
fn sampler_filter(bit: usize) -> TextureFilter {
824bf02b6e55atagen2026-10-16 09:15 UTC686
    if bit == 0 {
824bf02b6e55atagen2026-10-16 09:15 UTC687
        TextureFilter::Linear
824bf02b6e55atagen2026-10-16 09:15 UTC688
    } else {
824bf02b6e55atagen2026-10-16 09:15 UTC689
        TextureFilter::Nearest
824bf02b6e55atagen2026-10-16 09:15 UTC690
    }
824bf02b6e55atagen2026-10-16 09:15 UTC691
}
824bf02b6e55atagen2026-10-16 09:15 UTC692
7de49c2aa70batagen2026-10-16 09:27 UTC693
/// A full barrier between all earlier and later work on the image, optionally
7de49c2aa70batagen2026-10-16 09:27 UTC694
/// transferring ownership between queue families. Coarse, but correct for
7de49c2aa70batagen2026-10-16 09:27 UTC695
/// every transition the renderer makes.
824bf02b6e55atagen2026-10-16 09:15 UTC696
unsafe fn barrier(
824bf02b6e55atagen2026-10-16 09:15 UTC697
    d: &ash::Device,
824bf02b6e55atagen2026-10-16 09:15 UTC698
    cmd: vk::CommandBuffer,
824bf02b6e55atagen2026-10-16 09:15 UTC699
    image: vk::Image,
824bf02b6e55atagen2026-10-16 09:15 UTC700
    old: vk::ImageLayout,
824bf02b6e55atagen2026-10-16 09:15 UTC701
    new: vk::ImageLayout,
7de49c2aa70batagen2026-10-16 09:27 UTC702
    src_family: u32,
7de49c2aa70batagen2026-10-16 09:27 UTC703
    dst_family: u32,
824bf02b6e55atagen2026-10-16 09:15 UTC704
) {
824bf02b6e55atagen2026-10-16 09:15 UTC705
    let b = [vk::ImageMemoryBarrier2::default()
824bf02b6e55atagen2026-10-16 09:15 UTC706
        .src_stage_mask(vk::PipelineStageFlags2::ALL_COMMANDS)
824bf02b6e55atagen2026-10-16 09:15 UTC707
        .src_access_mask(vk::AccessFlags2::MEMORY_WRITE)
824bf02b6e55atagen2026-10-16 09:15 UTC708
        .dst_stage_mask(vk::PipelineStageFlags2::ALL_COMMANDS)
824bf02b6e55atagen2026-10-16 09:15 UTC709
        .dst_access_mask(vk::AccessFlags2::MEMORY_READ | vk::AccessFlags2::MEMORY_WRITE)
824bf02b6e55atagen2026-10-16 09:15 UTC710
        .old_layout(old)
824bf02b6e55atagen2026-10-16 09:15 UTC711
        .new_layout(new)
7de49c2aa70batagen2026-10-16 09:27 UTC712
        .src_queue_family_index(src_family)
7de49c2aa70batagen2026-10-16 09:27 UTC713
        .dst_queue_family_index(dst_family)
824bf02b6e55atagen2026-10-16 09:15 UTC714
        .image(image)
824bf02b6e55atagen2026-10-16 09:15 UTC715
        .subresource_range(color_range())];
824bf02b6e55atagen2026-10-16 09:15 UTC716
    unsafe {
824bf02b6e55atagen2026-10-16 09:15 UTC717
        d.cmd_pipeline_barrier2(
824bf02b6e55atagen2026-10-16 09:15 UTC718
            cmd,
824bf02b6e55atagen2026-10-16 09:15 UTC719
            &vk::DependencyInfo::default().image_memory_barriers(&b),
824bf02b6e55atagen2026-10-16 09:15 UTC720
        )
824bf02b6e55atagen2026-10-16 09:15 UTC721
    };
824bf02b6e55atagen2026-10-16 09:15 UTC722
}
824bf02b6e55atagen2026-10-16 09:15 UTC723
7de49c2aa70batagen2026-10-16 09:27 UTC724
/// Moves an image into `layout` for use on this queue. Dmabuf images come
7de49c2aa70batagen2026-10-16 09:27 UTC725
/// from the foreign queue family in the general layout, others continue from
7de49c2aa70batagen2026-10-16 09:27 UTC726
/// their tracked layout.
7de49c2aa70batagen2026-10-16 09:27 UTC727
unsafe fn acquire(
7de49c2aa70batagen2026-10-16 09:27 UTC728
    d: &ash::Device,
7de49c2aa70batagen2026-10-16 09:27 UTC729
    cmd: vk::CommandBuffer,
7de49c2aa70batagen2026-10-16 09:27 UTC730
    family: u32,
7de49c2aa70batagen2026-10-16 09:27 UTC731
    image: &ImageInner,
7de49c2aa70batagen2026-10-16 09:27 UTC732
    layout: vk::ImageLayout,
7de49c2aa70batagen2026-10-16 09:27 UTC733
) {
7de49c2aa70batagen2026-10-16 09:27 UTC734
    if image.external {
7de49c2aa70batagen2026-10-16 09:27 UTC735
        unsafe {
7de49c2aa70batagen2026-10-16 09:27 UTC736
            barrier(
7de49c2aa70batagen2026-10-16 09:27 UTC737
                d,
7de49c2aa70batagen2026-10-16 09:27 UTC738
                cmd,
7de49c2aa70batagen2026-10-16 09:27 UTC739
                image.image,
7de49c2aa70batagen2026-10-16 09:27 UTC740
                vk::ImageLayout::GENERAL,
7de49c2aa70batagen2026-10-16 09:27 UTC741
                layout,
7de49c2aa70batagen2026-10-16 09:27 UTC742
                vk::QUEUE_FAMILY_FOREIGN_EXT,
7de49c2aa70batagen2026-10-16 09:27 UTC743
                family,
7de49c2aa70batagen2026-10-16 09:27 UTC744
            )
7de49c2aa70batagen2026-10-16 09:27 UTC745
        };
7de49c2aa70batagen2026-10-16 09:27 UTC746
    } else {
7de49c2aa70batagen2026-10-16 09:27 UTC747
        let old = image.layout();
7de49c2aa70batagen2026-10-16 09:27 UTC748
        if old != layout {
7de49c2aa70batagen2026-10-16 09:27 UTC749
            unsafe {
7de49c2aa70batagen2026-10-16 09:27 UTC750
                barrier(
7de49c2aa70batagen2026-10-16 09:27 UTC751
                    d,
7de49c2aa70batagen2026-10-16 09:27 UTC752
                    cmd,
7de49c2aa70batagen2026-10-16 09:27 UTC753
                    image.image,
7de49c2aa70batagen2026-10-16 09:27 UTC754
                    old,
7de49c2aa70batagen2026-10-16 09:27 UTC755
                    layout,
7de49c2aa70batagen2026-10-16 09:27 UTC756
                    vk::QUEUE_FAMILY_IGNORED,
7de49c2aa70batagen2026-10-16 09:27 UTC757
                    vk::QUEUE_FAMILY_IGNORED,
7de49c2aa70batagen2026-10-16 09:27 UTC758
                )
7de49c2aa70batagen2026-10-16 09:27 UTC759
            };
7de49c2aa70batagen2026-10-16 09:27 UTC760
            image.set_layout(layout);
7de49c2aa70batagen2026-10-16 09:27 UTC761
        }
7de49c2aa70batagen2026-10-16 09:27 UTC762
    }
7de49c2aa70batagen2026-10-16 09:27 UTC763
}
7de49c2aa70batagen2026-10-16 09:27 UTC764
7de49c2aa70batagen2026-10-16 09:27 UTC765
/// Hands a dmabuf image back to the foreign queue family after use.
7de49c2aa70batagen2026-10-16 09:27 UTC766
unsafe fn release(
7de49c2aa70batagen2026-10-16 09:27 UTC767
    d: &ash::Device,
7de49c2aa70batagen2026-10-16 09:27 UTC768
    cmd: vk::CommandBuffer,
7de49c2aa70batagen2026-10-16 09:27 UTC769
    family: u32,
7de49c2aa70batagen2026-10-16 09:27 UTC770
    image: &ImageInner,
7de49c2aa70batagen2026-10-16 09:27 UTC771
    layout: vk::ImageLayout,
7de49c2aa70batagen2026-10-16 09:27 UTC772
) {
7de49c2aa70batagen2026-10-16 09:27 UTC773
    if image.external {
7de49c2aa70batagen2026-10-16 09:27 UTC774
        unsafe {
7de49c2aa70batagen2026-10-16 09:27 UTC775
            barrier(
7de49c2aa70batagen2026-10-16 09:27 UTC776
                d,
7de49c2aa70batagen2026-10-16 09:27 UTC777
                cmd,
7de49c2aa70batagen2026-10-16 09:27 UTC778
                image.image,
7de49c2aa70batagen2026-10-16 09:27 UTC779
                layout,
7de49c2aa70batagen2026-10-16 09:27 UTC780
                vk::ImageLayout::GENERAL,
7de49c2aa70batagen2026-10-16 09:27 UTC781
                family,
7de49c2aa70batagen2026-10-16 09:27 UTC782
                vk::QUEUE_FAMILY_FOREIGN_EXT,
7de49c2aa70batagen2026-10-16 09:27 UTC783
            )
7de49c2aa70batagen2026-10-16 09:27 UTC784
        };
7de49c2aa70batagen2026-10-16 09:27 UTC785
    }
7de49c2aa70batagen2026-10-16 09:27 UTC786
}
7de49c2aa70batagen2026-10-16 09:27 UTC787
824bf02b6e55atagen2026-10-16 09:15 UTC788
/// Whether reading `from` as `to` needs red and blue swapped.
824bf02b6e55atagen2026-10-16 09:15 UTC789
fn needs_swizzle(from: Fourcc, to: Fourcc) -> Result<bool, Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC790
    let bgr = |f: Fourcc| match f {
824bf02b6e55atagen2026-10-16 09:15 UTC791
        Fourcc::Argb8888 | Fourcc::Xrgb8888 => Ok(true),
824bf02b6e55atagen2026-10-16 09:15 UTC792
        Fourcc::Abgr8888 | Fourcc::Xbgr8888 => Ok(false),
824bf02b6e55atagen2026-10-16 09:15 UTC793
        f => Err(Error::UnsupportedFormat(f)),
824bf02b6e55atagen2026-10-16 09:15 UTC794
    };
824bf02b6e55atagen2026-10-16 09:15 UTC795
    Ok(bgr(from)? != bgr(to)?)
824bf02b6e55atagen2026-10-16 09:15 UTC796
}
824bf02b6e55atagen2026-10-16 09:15 UTC797
824bf02b6e55atagen2026-10-16 09:15 UTC798
impl RendererSuper for VulkanRenderer {
824bf02b6e55atagen2026-10-16 09:15 UTC799
    type Error = Error;
824bf02b6e55atagen2026-10-16 09:15 UTC800
    type TextureId = VulkanTexture;
824bf02b6e55atagen2026-10-16 09:15 UTC801
    type Framebuffer<'buffer> = VulkanTarget<'buffer>;
824bf02b6e55atagen2026-10-16 09:15 UTC802
    type Frame<'frame, 'buffer>
824bf02b6e55atagen2026-10-16 09:15 UTC803
        = VulkanFrame<'frame, 'buffer>
824bf02b6e55atagen2026-10-16 09:15 UTC804
    where
824bf02b6e55atagen2026-10-16 09:15 UTC805
        'buffer: 'frame,
824bf02b6e55atagen2026-10-16 09:15 UTC806
        Self: 'frame;
824bf02b6e55atagen2026-10-16 09:15 UTC807
}
824bf02b6e55atagen2026-10-16 09:15 UTC808
824bf02b6e55atagen2026-10-16 09:15 UTC809
impl Renderer for VulkanRenderer {
824bf02b6e55atagen2026-10-16 09:15 UTC810
    fn context_id(&self) -> ContextId<VulkanTexture> {
824bf02b6e55atagen2026-10-16 09:15 UTC811
        self.context.clone()
824bf02b6e55atagen2026-10-16 09:15 UTC812
    }
824bf02b6e55atagen2026-10-16 09:15 UTC813
824bf02b6e55atagen2026-10-16 09:15 UTC814
    fn downscale_filter(&mut self, filter: TextureFilter) -> Result<(), Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC815
        self.min_filter = filter;
824bf02b6e55atagen2026-10-16 09:15 UTC816
        Ok(())
824bf02b6e55atagen2026-10-16 09:15 UTC817
    }
824bf02b6e55atagen2026-10-16 09:15 UTC818
824bf02b6e55atagen2026-10-16 09:15 UTC819
    fn upscale_filter(&mut self, filter: TextureFilter) -> Result<(), Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC820
        self.mag_filter = filter;
824bf02b6e55atagen2026-10-16 09:15 UTC821
        Ok(())
824bf02b6e55atagen2026-10-16 09:15 UTC822
    }
824bf02b6e55atagen2026-10-16 09:15 UTC823
824bf02b6e55atagen2026-10-16 09:15 UTC824
    fn set_debug_flags(&mut self, flags: DebugFlags) {
824bf02b6e55atagen2026-10-16 09:15 UTC825
        self.debug = flags;
824bf02b6e55atagen2026-10-16 09:15 UTC826
    }
824bf02b6e55atagen2026-10-16 09:15 UTC827
824bf02b6e55atagen2026-10-16 09:15 UTC828
    fn debug_flags(&self) -> DebugFlags {
824bf02b6e55atagen2026-10-16 09:15 UTC829
        self.debug
824bf02b6e55atagen2026-10-16 09:15 UTC830
    }
824bf02b6e55atagen2026-10-16 09:15 UTC831
824bf02b6e55atagen2026-10-16 09:15 UTC832
    fn render<'frame, 'buffer>(
824bf02b6e55atagen2026-10-16 09:15 UTC833
        &'frame mut self,
824bf02b6e55atagen2026-10-16 09:15 UTC834
        framebuffer: &'frame mut VulkanTarget<'buffer>,
824bf02b6e55atagen2026-10-16 09:15 UTC835
        output_size: Size<i32, Physical>,
824bf02b6e55atagen2026-10-16 09:15 UTC836
        dst_transform: Transform,
824bf02b6e55atagen2026-10-16 09:15 UTC837
    ) -> Result<VulkanFrame<'frame, 'buffer>, Error>
824bf02b6e55atagen2026-10-16 09:15 UTC838
    where
824bf02b6e55atagen2026-10-16 09:15 UTC839
        'buffer: 'frame,
824bf02b6e55atagen2026-10-16 09:15 UTC840
    {
7de49c2aa70batagen2026-10-16 09:27 UTC841
        self.own(&framebuffer.0)?;
824bf02b6e55atagen2026-10-16 09:15 UTC842
        self.reap();
824bf02b6e55atagen2026-10-16 09:15 UTC843
        Ok(VulkanFrame::new(
824bf02b6e55atagen2026-10-16 09:15 UTC844
            self,
824bf02b6e55atagen2026-10-16 09:15 UTC845
            framebuffer,
824bf02b6e55atagen2026-10-16 09:15 UTC846
            output_size,
824bf02b6e55atagen2026-10-16 09:15 UTC847
            dst_transform,
824bf02b6e55atagen2026-10-16 09:15 UTC848
        ))
824bf02b6e55atagen2026-10-16 09:15 UTC849
    }
824bf02b6e55atagen2026-10-16 09:15 UTC850
824bf02b6e55atagen2026-10-16 09:15 UTC851
    fn wait(&mut self, sync: &SyncPoint) -> Result<(), Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC852
        sync.wait().map_err(|_| Error::Interrupted)
824bf02b6e55atagen2026-10-16 09:15 UTC853
    }
824bf02b6e55atagen2026-10-16 09:15 UTC854
824bf02b6e55atagen2026-10-16 09:15 UTC855
    fn cleanup_texture_cache(&mut self) -> Result<(), Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC856
        self.reap();
824bf02b6e55atagen2026-10-16 09:15 UTC857
        Ok(())
824bf02b6e55atagen2026-10-16 09:15 UTC858
    }
7de49c2aa70batagen2026-10-16 09:27 UTC859
7de49c2aa70batagen2026-10-16 09:27 UTC860
    fn invalidate_caches(&mut self) -> Result<(), Error> {
7de49c2aa70batagen2026-10-16 09:27 UTC861
        self.reap();
7de49c2aa70batagen2026-10-16 09:27 UTC862
        self.dmabuf_textures.clear();
7de49c2aa70batagen2026-10-16 09:27 UTC863
        self.dmabuf_targets.clear();
7de49c2aa70batagen2026-10-16 09:27 UTC864
        Ok(())
7de49c2aa70batagen2026-10-16 09:27 UTC865
    }
824bf02b6e55atagen2026-10-16 09:15 UTC866
}
824bf02b6e55atagen2026-10-16 09:15 UTC867
824bf02b6e55atagen2026-10-16 09:15 UTC868
impl Bind<VulkanImage> for VulkanRenderer {
824bf02b6e55atagen2026-10-16 09:15 UTC869
    fn bind<'a>(&mut self, target: &'a mut VulkanImage) -> Result<VulkanTarget<'a>, Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC870
        self.own(&target.0)?;
7de49c2aa70batagen2026-10-16 09:27 UTC871
        Ok(VulkanTarget(target.0.clone(), PhantomData))
7de49c2aa70batagen2026-10-16 09:27 UTC872
    }
7de49c2aa70batagen2026-10-16 09:27 UTC873
}
7de49c2aa70batagen2026-10-16 09:27 UTC874
7de49c2aa70batagen2026-10-16 09:27 UTC875
impl Bind<Dmabuf> for VulkanRenderer {
30aece3a63ceatagen2026-10-16 13:48 UTC876
    #[profiling::function]
7de49c2aa70batagen2026-10-16 09:27 UTC877
    fn bind<'a>(&mut self, target: &'a mut Dmabuf) -> Result<VulkanTarget<'a>, Error> {
7de49c2aa70batagen2026-10-16 09:27 UTC878
        let key = target.weak();
7de49c2aa70batagen2026-10-16 09:27 UTC879
        let image = match self.dmabuf_targets.get(&key) {
7de49c2aa70batagen2026-10-16 09:27 UTC880
            Some(image) => image.clone(),
7de49c2aa70batagen2026-10-16 09:27 UTC881
            None => {
7de49c2aa70batagen2026-10-16 09:27 UTC882
                let image = dmabuf::import(&self.shared, &self.caps, target, RENDER_USAGE)?;
7de49c2aa70batagen2026-10-16 09:27 UTC883
                self.dmabuf_targets.insert(key, image.clone());
7de49c2aa70batagen2026-10-16 09:27 UTC884
                image
7de49c2aa70batagen2026-10-16 09:27 UTC885
            }
7de49c2aa70batagen2026-10-16 09:27 UTC886
        };
7de49c2aa70batagen2026-10-16 09:27 UTC887
        Ok(VulkanTarget(image, PhantomData))
7de49c2aa70batagen2026-10-16 09:27 UTC888
    }
7de49c2aa70batagen2026-10-16 09:27 UTC889
7de49c2aa70batagen2026-10-16 09:27 UTC890
    fn supported_formats(&self) -> Option<FormatSet> {
7de49c2aa70batagen2026-10-16 09:27 UTC891
        Some(self.caps.render.clone())
824bf02b6e55atagen2026-10-16 09:15 UTC892
    }
824bf02b6e55atagen2026-10-16 09:15 UTC893
}
824bf02b6e55atagen2026-10-16 09:15 UTC894
824bf02b6e55atagen2026-10-16 09:15 UTC895
impl Offscreen<VulkanImage> for VulkanRenderer {
824bf02b6e55atagen2026-10-16 09:15 UTC896
    fn create_buffer(
824bf02b6e55atagen2026-10-16 09:15 UTC897
        &mut self,
824bf02b6e55atagen2026-10-16 09:15 UTC898
        format: Fourcc,
824bf02b6e55atagen2026-10-16 09:15 UTC899
        size: Size<i32, Buffer>,
824bf02b6e55atagen2026-10-16 09:15 UTC900
    ) -> Result<VulkanImage, Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC901
        if size.w <= 0 || size.h <= 0 {
824bf02b6e55atagen2026-10-16 09:15 UTC902
            return Err(Error::InvalidSize(size.w, size.h));
824bf02b6e55atagen2026-10-16 09:15 UTC903
        }
824bf02b6e55atagen2026-10-16 09:15 UTC904
        let usage = vk::ImageUsageFlags::COLOR_ATTACHMENT
824bf02b6e55atagen2026-10-16 09:15 UTC905
            | vk::ImageUsageFlags::SAMPLED
824bf02b6e55atagen2026-10-16 09:15 UTC906
            | vk::ImageUsageFlags::TRANSFER_SRC
824bf02b6e55atagen2026-10-16 09:15 UTC907
            | vk::ImageUsageFlags::TRANSFER_DST;
824bf02b6e55atagen2026-10-16 09:15 UTC908
        Ok(VulkanImage(ImageInner::create(
824bf02b6e55atagen2026-10-16 09:15 UTC909
            &self.shared,
824bf02b6e55atagen2026-10-16 09:15 UTC910
            format,
824bf02b6e55atagen2026-10-16 09:15 UTC911
            size.w as u32,
824bf02b6e55atagen2026-10-16 09:15 UTC912
            size.h as u32,
824bf02b6e55atagen2026-10-16 09:15 UTC913
            usage,
824bf02b6e55atagen2026-10-16 09:15 UTC914
        )?))
824bf02b6e55atagen2026-10-16 09:15 UTC915
    }
824bf02b6e55atagen2026-10-16 09:15 UTC916
}
824bf02b6e55atagen2026-10-16 09:15 UTC917
824bf02b6e55atagen2026-10-16 09:15 UTC918
impl ImportMem for VulkanRenderer {
824bf02b6e55atagen2026-10-16 09:15 UTC919
    fn import_memory(
824bf02b6e55atagen2026-10-16 09:15 UTC920
        &mut self,
824bf02b6e55atagen2026-10-16 09:15 UTC921
        data: &[u8],
824bf02b6e55atagen2026-10-16 09:15 UTC922
        format: Fourcc,
824bf02b6e55atagen2026-10-16 09:15 UTC923
        size: Size<i32, Buffer>,
824bf02b6e55atagen2026-10-16 09:15 UTC924
        flipped: bool,
824bf02b6e55atagen2026-10-16 09:15 UTC925
    ) -> Result<VulkanTexture, Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC926
        if size.w <= 0 || size.h <= 0 {
824bf02b6e55atagen2026-10-16 09:15 UTC927
            return Err(Error::InvalidSize(size.w, size.h));
824bf02b6e55atagen2026-10-16 09:15 UTC928
        }
824bf02b6e55atagen2026-10-16 09:15 UTC929
        let usage = vk::ImageUsageFlags::SAMPLED
824bf02b6e55atagen2026-10-16 09:15 UTC930
            | vk::ImageUsageFlags::TRANSFER_DST
824bf02b6e55atagen2026-10-16 09:15 UTC931
            | vk::ImageUsageFlags::TRANSFER_SRC;
824bf02b6e55atagen2026-10-16 09:15 UTC932
        let image = ImageInner::create(&self.shared, format, size.w as u32, size.h as u32, usage)?;
824bf02b6e55atagen2026-10-16 09:15 UTC933
        self.upload(&image, data, Rectangle::from_size(size), flipped)?;
824bf02b6e55atagen2026-10-16 09:15 UTC934
        Ok(VulkanTexture(image))
824bf02b6e55atagen2026-10-16 09:15 UTC935
    }
824bf02b6e55atagen2026-10-16 09:15 UTC936
824bf02b6e55atagen2026-10-16 09:15 UTC937
    fn update_memory(
824bf02b6e55atagen2026-10-16 09:15 UTC938
        &mut self,
824bf02b6e55atagen2026-10-16 09:15 UTC939
        texture: &VulkanTexture,
824bf02b6e55atagen2026-10-16 09:15 UTC940
        data: &[u8],
824bf02b6e55atagen2026-10-16 09:15 UTC941
        region: Rectangle<i32, Buffer>,
824bf02b6e55atagen2026-10-16 09:15 UTC942
    ) -> Result<(), Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC943
        self.own(&texture.0)?;
824bf02b6e55atagen2026-10-16 09:15 UTC944
        let Some(region) = region.intersection(Rectangle::from_size(texture.size())) else {
824bf02b6e55atagen2026-10-16 09:15 UTC945
            return Ok(());
824bf02b6e55atagen2026-10-16 09:15 UTC946
        };
824bf02b6e55atagen2026-10-16 09:15 UTC947
        self.upload(&texture.0, data, region, false)
824bf02b6e55atagen2026-10-16 09:15 UTC948
    }
824bf02b6e55atagen2026-10-16 09:15 UTC949
824bf02b6e55atagen2026-10-16 09:15 UTC950
    fn mem_formats(&self) -> Box<dyn Iterator<Item = Fourcc>> {
824bf02b6e55atagen2026-10-16 09:15 UTC951
        Box::new(SUPPORTED.into_iter())
824bf02b6e55atagen2026-10-16 09:15 UTC952
    }
824bf02b6e55atagen2026-10-16 09:15 UTC953
}
824bf02b6e55atagen2026-10-16 09:15 UTC954
7de49c2aa70batagen2026-10-16 09:27 UTC955
impl ImportDma for VulkanRenderer {
7de49c2aa70batagen2026-10-16 09:27 UTC956
    fn dmabuf_formats(&self) -> FormatSet {
7de49c2aa70batagen2026-10-16 09:27 UTC957
        self.caps.sample.clone()
7de49c2aa70batagen2026-10-16 09:27 UTC958
    }
7de49c2aa70batagen2026-10-16 09:27 UTC959
30aece3a63ceatagen2026-10-16 13:48 UTC960
    #[profiling::function]
7de49c2aa70batagen2026-10-16 09:27 UTC961
    fn import_dmabuf(
7de49c2aa70batagen2026-10-16 09:27 UTC962
        &mut self,
7de49c2aa70batagen2026-10-16 09:27 UTC963
        buffer: &Dmabuf,
7de49c2aa70batagen2026-10-16 09:27 UTC964
        _damage: Option<&[Rectangle<i32, Buffer>]>,
7de49c2aa70batagen2026-10-16 09:27 UTC965
    ) -> Result<VulkanTexture, Error> {
7de49c2aa70batagen2026-10-16 09:27 UTC966
        let key = buffer.weak();
7de49c2aa70batagen2026-10-16 09:27 UTC967
        if let Some(t) = self.dmabuf_textures.get(&key) {
7de49c2aa70batagen2026-10-16 09:27 UTC968
            return Ok(t.clone());
7de49c2aa70batagen2026-10-16 09:27 UTC969
        }
7de49c2aa70batagen2026-10-16 09:27 UTC970
        let texture = VulkanTexture(dmabuf::import(
7de49c2aa70batagen2026-10-16 09:27 UTC971
            &self.shared,
7de49c2aa70batagen2026-10-16 09:27 UTC972
            &self.caps,
7de49c2aa70batagen2026-10-16 09:27 UTC973
            buffer,
7de49c2aa70batagen2026-10-16 09:27 UTC974
            SAMPLE_USAGE,
7de49c2aa70batagen2026-10-16 09:27 UTC975
        )?);
7de49c2aa70batagen2026-10-16 09:27 UTC976
        self.dmabuf_textures.insert(key, texture.clone());
7de49c2aa70batagen2026-10-16 09:27 UTC977
        Ok(texture)
7de49c2aa70batagen2026-10-16 09:27 UTC978
    }
7de49c2aa70batagen2026-10-16 09:27 UTC979
}
7de49c2aa70batagen2026-10-16 09:27 UTC980
7de49c2aa70batagen2026-10-16 09:27 UTC981
impl ImportDmaWl for VulkanRenderer {}
7de49c2aa70batagen2026-10-16 09:27 UTC982
8956d017e879atagen2026-10-16 22:50 UTC983
/// Imports dmabufs on another thread. The textures it makes belong to the
8956d017e879atagen2026-10-16 22:50 UTC984
/// renderer it came from, which takes them back with `adopt_dmabuf`.
8956d017e879atagen2026-10-16 22:50 UTC985
#[derive(Clone)]
8956d017e879atagen2026-10-16 22:50 UTC986
pub struct DmabufImporter {
8956d017e879atagen2026-10-16 22:50 UTC987
    shared: Arc<Shared>,
8956d017e879atagen2026-10-16 22:50 UTC988
    caps: Arc<DmabufCaps>,
8956d017e879atagen2026-10-16 22:50 UTC989
}
8956d017e879atagen2026-10-16 22:50 UTC990
8956d017e879atagen2026-10-16 22:50 UTC991
impl DmabufImporter {
8956d017e879atagen2026-10-16 22:50 UTC992
    pub fn import(&self, buffer: &Dmabuf) -> Result<VulkanTexture, Error> {
8956d017e879atagen2026-10-16 22:50 UTC993
        dmabuf::import(&self.shared, &self.caps, buffer, SAMPLE_USAGE).map(VulkanTexture)
8956d017e879atagen2026-10-16 22:50 UTC994
    }
8956d017e879atagen2026-10-16 22:50 UTC995
}
8956d017e879atagen2026-10-16 22:50 UTC996
8956d017e879atagen2026-10-16 22:50 UTC997
impl VulkanRenderer {
8956d017e879atagen2026-10-16 22:50 UTC998
    pub fn dmabuf_importer(&self) -> DmabufImporter {
8956d017e879atagen2026-10-16 22:50 UTC999
        DmabufImporter {
8956d017e879atagen2026-10-16 22:50 UTC1000
            shared: self.shared.clone(),
8956d017e879atagen2026-10-16 22:50 UTC1001
            caps: self.caps.clone(),
8956d017e879atagen2026-10-16 22:50 UTC1002
        }
8956d017e879atagen2026-10-16 22:50 UTC1003
    }
8956d017e879atagen2026-10-16 22:50 UTC1004
8956d017e879atagen2026-10-16 22:50 UTC1005
    pub fn has_dmabuf(&self, buffer: &Dmabuf) -> bool {
8956d017e879atagen2026-10-16 22:50 UTC1006
        self.dmabuf_textures.contains_key(&buffer.weak())
8956d017e879atagen2026-10-16 22:50 UTC1007
    }
8956d017e879atagen2026-10-16 22:50 UTC1008
8956d017e879atagen2026-10-16 22:50 UTC1009
    pub fn adopt_dmabuf(&mut self, buffer: &Dmabuf, texture: VulkanTexture) -> Result<(), Error> {
8956d017e879atagen2026-10-16 22:50 UTC1010
        self.own(&texture.0)?;
8956d017e879atagen2026-10-16 22:50 UTC1011
        self.dmabuf_textures.insert(buffer.weak(), texture);
8956d017e879atagen2026-10-16 22:50 UTC1012
        Ok(())
8956d017e879atagen2026-10-16 22:50 UTC1013
    }
8956d017e879atagen2026-10-16 22:50 UTC1014
}
8956d017e879atagen2026-10-16 22:50 UTC1015
824bf02b6e55atagen2026-10-16 09:15 UTC1016
impl ExportMem for VulkanRenderer {
824bf02b6e55atagen2026-10-16 09:15 UTC1017
    type TextureMapping = VulkanMapping;
824bf02b6e55atagen2026-10-16 09:15 UTC1018
824bf02b6e55atagen2026-10-16 09:15 UTC1019
    fn copy_framebuffer(
824bf02b6e55atagen2026-10-16 09:15 UTC1020
        &mut self,
824bf02b6e55atagen2026-10-16 09:15 UTC1021
        target: &VulkanTarget<'_>,
824bf02b6e55atagen2026-10-16 09:15 UTC1022
        region: Rectangle<i32, Buffer>,
824bf02b6e55atagen2026-10-16 09:15 UTC1023
        format: Fourcc,
824bf02b6e55atagen2026-10-16 09:15 UTC1024
    ) -> Result<VulkanMapping, Error> {
7de49c2aa70batagen2026-10-16 09:27 UTC1025
        self.own(&target.0)?;
7de49c2aa70batagen2026-10-16 09:27 UTC1026
        let image = target.0.clone();
824bf02b6e55atagen2026-10-16 09:15 UTC1027
        self.read_back(&image, region, format)
824bf02b6e55atagen2026-10-16 09:15 UTC1028
    }
824bf02b6e55atagen2026-10-16 09:15 UTC1029
824bf02b6e55atagen2026-10-16 09:15 UTC1030
    fn copy_texture(
824bf02b6e55atagen2026-10-16 09:15 UTC1031
        &mut self,
824bf02b6e55atagen2026-10-16 09:15 UTC1032
        texture: &VulkanTexture,
824bf02b6e55atagen2026-10-16 09:15 UTC1033
        region: Rectangle<i32, Buffer>,
824bf02b6e55atagen2026-10-16 09:15 UTC1034
        format: Fourcc,
824bf02b6e55atagen2026-10-16 09:15 UTC1035
    ) -> Result<VulkanMapping, Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC1036
        self.own(&texture.0)?;
824bf02b6e55atagen2026-10-16 09:15 UTC1037
        self.read_back(&texture.0, region, format)
824bf02b6e55atagen2026-10-16 09:15 UTC1038
    }
824bf02b6e55atagen2026-10-16 09:15 UTC1039
7de49c2aa70batagen2026-10-16 09:27 UTC1040
    fn can_read_texture(&mut self, texture: &VulkanTexture) -> Result<bool, Error> {
7de49c2aa70batagen2026-10-16 09:27 UTC1041
        Ok(texture.0.external || texture.0.layout() != vk::ImageLayout::UNDEFINED)
824bf02b6e55atagen2026-10-16 09:15 UTC1042
    }
824bf02b6e55atagen2026-10-16 09:15 UTC1043
824bf02b6e55atagen2026-10-16 09:15 UTC1044
    fn map_texture<'a>(&mut self, mapping: &'a VulkanMapping) -> Result<&'a [u8], Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC1045
        Ok(&mapping.data)
824bf02b6e55atagen2026-10-16 09:15 UTC1046
    }
824bf02b6e55atagen2026-10-16 09:15 UTC1047
}
d4a64ce87164atagen2026-10-16 09:34 UTC1048
d4a64ce87164atagen2026-10-16 09:34 UTC1049
impl ImportMemWl for VulkanRenderer {
48af562d968batagen2026-10-16 12:39 UTC1050
    /// Keeps one texture per surface and uploads only the damaged rows into
48af562d968batagen2026-10-16 12:39 UTC1051
    /// it, straight from the client's shm pool.
d4a64ce87164atagen2026-10-16 09:34 UTC1052
    fn import_shm_buffer(
d4a64ce87164atagen2026-10-16 09:34 UTC1053
        &mut self,
d4a64ce87164atagen2026-10-16 09:34 UTC1054
        buffer: &WlBuffer,
48af562d968batagen2026-10-16 12:39 UTC1055
        surface: Option<&SurfaceData>,
48af562d968batagen2026-10-16 12:39 UTC1056
        damage: &[Rectangle<i32, Buffer>],
d4a64ce87164atagen2026-10-16 09:34 UTC1057
    ) -> Result<VulkanTexture, Error> {
0f11410be91batagen2026-10-17 03:59 UTC1058
        self.staged.retain(|_, (b, _)| b.is_alive());
0f11410be91batagen2026-10-17 03:59 UTC1059
        let staged = self.staged.remove(&buffer.id()).map(|(_, s)| s);
48af562d968batagen2026-10-16 12:39 UTC1060
        let cache = surface.map(|s| {
48af562d968batagen2026-10-16 12:39 UTC1061
            s.data_map
48af562d968batagen2026-10-16 12:39 UTC1062
                .insert_if_missing_threadsafe(|| ShmCache(Mutex::new(None)));
48af562d968batagen2026-10-16 12:39 UTC1063
            s.data_map.get::<ShmCache>().expect("just inserted")
48af562d968batagen2026-10-16 12:39 UTC1064
        });
48af562d968batagen2026-10-16 12:39 UTC1065
        with_buffer_contents(buffer, |ptr, len, data| {
d4a64ce87164atagen2026-10-16 09:34 UTC1066
            let fourcc = shm_format_to_fourcc(data.format).ok_or(Error::ShmAccess)?;
d4a64ce87164atagen2026-10-16 09:34 UTC1067
            let (w, h, stride, offset) = (
d4a64ce87164atagen2026-10-16 09:34 UTC1068
                data.width as usize,
d4a64ce87164atagen2026-10-16 09:34 UTC1069
                data.height as usize,
d4a64ce87164atagen2026-10-16 09:34 UTC1070
                data.stride as usize,
d4a64ce87164atagen2026-10-16 09:34 UTC1071
                data.offset as usize,
d4a64ce87164atagen2026-10-16 09:34 UTC1072
            );
48af562d968batagen2026-10-16 12:39 UTC1073
            let line = w * BYTES_PER_PIXEL;
48af562d968batagen2026-10-16 12:39 UTC1074
            if w == 0 || h == 0 || stride < line || offset + stride * (h - 1) + line > len {
d4a64ce87164atagen2026-10-16 09:34 UTC1075
                return Err(Error::ShmAccess);
d4a64ce87164atagen2026-10-16 09:34 UTC1076
            }
48af562d968batagen2026-10-16 12:39 UTC1077
            let size = Size::from((data.width, data.height));
48af562d968batagen2026-10-16 12:39 UTC1078
            let full = Rectangle::from_size(size);
48af562d968batagen2026-10-16 12:39 UTC1079
            let reused = cache
48af562d968batagen2026-10-16 12:39 UTC1080
                .and_then(|c| c.0.lock().unwrap_or_else(|e| e.into_inner()).clone())
48af562d968batagen2026-10-16 12:39 UTC1081
                .filter(|t| {
48af562d968batagen2026-10-16 12:39 UTC1082
                    t.0.fourcc == fourcc
48af562d968batagen2026-10-16 12:39 UTC1083
                        && t.size() == size
48af562d968batagen2026-10-16 12:39 UTC1084
                        && Arc::ptr_eq(&t.0.shared, &self.shared)
48af562d968batagen2026-10-16 12:39 UTC1085
                });
48af562d968batagen2026-10-16 12:39 UTC1086
            let (texture, region) = match reused {
48af562d968batagen2026-10-16 12:39 UTC1087
                Some(t) => {
48af562d968batagen2026-10-16 12:39 UTC1088
                    let dirty = damage
48af562d968batagen2026-10-16 12:39 UTC1089
                        .iter()
48af562d968batagen2026-10-16 12:39 UTC1090
                        .filter_map(|d| d.intersection(full))
48af562d968batagen2026-10-16 12:39 UTC1091
                        .reduce(|a, b| a.merge(b));
48af562d968batagen2026-10-16 12:39 UTC1092
                    (t, if damage.is_empty() { Some(full) } else { dirty })
48af562d968batagen2026-10-16 12:39 UTC1093
                }
48af562d968batagen2026-10-16 12:39 UTC1094
                None => {
48af562d968batagen2026-10-16 12:39 UTC1095
                    let usage = vk::ImageUsageFlags::SAMPLED
48af562d968batagen2026-10-16 12:39 UTC1096
                        | vk::ImageUsageFlags::TRANSFER_DST
48af562d968batagen2026-10-16 12:39 UTC1097
                        | vk::ImageUsageFlags::TRANSFER_SRC;
48af562d968batagen2026-10-16 12:39 UTC1098
                    let image =
48af562d968batagen2026-10-16 12:39 UTC1099
                        ImageInner::create(&self.shared, fourcc, w as u32, h as u32, usage)?;
48af562d968batagen2026-10-16 12:39 UTC1100
                    (VulkanTexture(image), Some(full))
48af562d968batagen2026-10-16 12:39 UTC1101
                }
48af562d968batagen2026-10-16 12:39 UTC1102
            };
0f11410be91batagen2026-10-17 03:59 UTC1103
            let staged = staged.filter(|s| {
0f11410be91batagen2026-10-17 03:59 UTC1104
                s.fourcc == fourcc
0f11410be91batagen2026-10-17 03:59 UTC1105
                    && s.size == size
0f11410be91batagen2026-10-17 03:59 UTC1106
                    && region.is_some_and(|r| s.region.contains_rect(r))
0f11410be91batagen2026-10-17 03:59 UTC1107
            });
0f11410be91batagen2026-10-17 03:59 UTC1108
            if let Some(s) = staged {
0f11410be91batagen2026-10-17 03:59 UTC1109
                tracing::trace!(region = ?s.region, "uploading a staged shm copy");
0f11410be91batagen2026-10-17 03:59 UTC1110
                self.copy_staged(&texture.0, s.region, s.staging)?;
0f11410be91batagen2026-10-17 03:59 UTC1111
            } else if let Some(region) = region {
48af562d968batagen2026-10-16 12:39 UTC1112
                let x = region.loc.x as usize * BYTES_PER_PIXEL;
48af562d968batagen2026-10-16 12:39 UTC1113
                let rw = region.size.w as usize * BYTES_PER_PIXEL;
48af562d968batagen2026-10-16 12:39 UTC1114
                self.upload_with(&texture.0, region, |y| unsafe {
48af562d968batagen2026-10-16 12:39 UTC1115
                    std::slice::from_raw_parts(ptr.add(offset + y * stride + x), rw)
48af562d968batagen2026-10-16 12:39 UTC1116
                })?;
d4a64ce87164atagen2026-10-16 09:34 UTC1117
            }
48af562d968batagen2026-10-16 12:39 UTC1118
            if let Some(c) = cache {
48af562d968batagen2026-10-16 12:39 UTC1119
                *c.0.lock().unwrap_or_else(|e| e.into_inner()) = Some(texture.clone());
48af562d968batagen2026-10-16 12:39 UTC1120
            }
48af562d968batagen2026-10-16 12:39 UTC1121
            Ok(texture)
d4a64ce87164atagen2026-10-16 09:34 UTC1122
        })
48af562d968batagen2026-10-16 12:39 UTC1123
        .map_err(|_| Error::ShmAccess)?
d4a64ce87164atagen2026-10-16 09:34 UTC1124
    }
d4a64ce87164atagen2026-10-16 09:34 UTC1125
}
48af562d968batagen2026-10-16 12:39 UTC1126
48af562d968batagen2026-10-16 12:39 UTC1127
/// The texture last imported for a surface's shm buffers.
48af562d968batagen2026-10-16 12:39 UTC1128
struct ShmCache(Mutex<Option<VulkanTexture>>);
0f11410be91batagen2026-10-17 03:59 UTC1129
0f11410be91batagen2026-10-17 03:59 UTC1130
/// Copies `region` of a full-image `row` source into new staging memory.
0f11410be91batagen2026-10-17 03:59 UTC1131
fn stage_rows<'a>(
0f11410be91batagen2026-10-17 03:59 UTC1132
    shared: &Arc<Shared>,
0f11410be91batagen2026-10-17 03:59 UTC1133
    region: Rectangle<i32, Buffer>,
0f11410be91batagen2026-10-17 03:59 UTC1134
    row: impl Fn(usize) -> &'a [u8],
0f11410be91batagen2026-10-17 03:59 UTC1135
) -> Result<Staging, Error> {
0f11410be91batagen2026-10-17 03:59 UTC1136
    let (w, h) = (region.size.w as usize, region.size.h as usize);
0f11410be91batagen2026-10-17 03:59 UTC1137
    let line = w * BYTES_PER_PIXEL;
0f11410be91batagen2026-10-17 03:59 UTC1138
    let mut staging = Staging::new(
0f11410be91batagen2026-10-17 03:59 UTC1139
        shared,
0f11410be91batagen2026-10-17 03:59 UTC1140
        line * h,
0f11410be91batagen2026-10-17 03:59 UTC1141
        vk::BufferUsageFlags::TRANSFER_SRC,
0f11410be91batagen2026-10-17 03:59 UTC1142
        MemoryLocation::CpuToGpu,
0f11410be91batagen2026-10-17 03:59 UTC1143
    )?;
0f11410be91batagen2026-10-17 03:59 UTC1144
    let dst = staging.bytes_mut();
0f11410be91batagen2026-10-17 03:59 UTC1145
    for i in 0..h {
0f11410be91batagen2026-10-17 03:59 UTC1146
        dst[i * line..(i + 1) * line].copy_from_slice(row(region.loc.y as usize + i));
0f11410be91batagen2026-10-17 03:59 UTC1147
    }
0f11410be91batagen2026-10-17 03:59 UTC1148
    Ok(staging)
0f11410be91batagen2026-10-17 03:59 UTC1149
}
0f11410be91batagen2026-10-17 03:59 UTC1150
0f11410be91batagen2026-10-17 03:59 UTC1151
/// Shm pixels copied off the main thread, waiting for the import of the
0f11410be91batagen2026-10-17 03:59 UTC1152
/// commit that shows them.
0f11410be91batagen2026-10-17 03:59 UTC1153
pub struct StagedShm {
0f11410be91batagen2026-10-17 03:59 UTC1154
    staging: Staging,
0f11410be91batagen2026-10-17 03:59 UTC1155
    region: Rectangle<i32, Buffer>,
0f11410be91batagen2026-10-17 03:59 UTC1156
    fourcc: Fourcc,
0f11410be91batagen2026-10-17 03:59 UTC1157
    size: Size<i32, Buffer>,
0f11410be91batagen2026-10-17 03:59 UTC1158
}
0f11410be91batagen2026-10-17 03:59 UTC1159
0f11410be91batagen2026-10-17 03:59 UTC1160
/// Copies shm buffers into staging memory on another thread. The renderer
0f11410be91batagen2026-10-17 03:59 UTC1161
/// it came from takes the result back with `adopt_staged`.
0f11410be91batagen2026-10-17 03:59 UTC1162
#[derive(Clone)]
0f11410be91batagen2026-10-17 03:59 UTC1163
pub struct ShmStager {
0f11410be91batagen2026-10-17 03:59 UTC1164
    shared: Arc<Shared>,
0f11410be91batagen2026-10-17 03:59 UTC1165
}
0f11410be91batagen2026-10-17 03:59 UTC1166
0f11410be91batagen2026-10-17 03:59 UTC1167
impl ShmStager {
0f11410be91batagen2026-10-17 03:59 UTC1168
    /// Stages `region` of `buffer`, all of it when the region is `None`.
0f11410be91batagen2026-10-17 03:59 UTC1169
    pub fn stage(
0f11410be91batagen2026-10-17 03:59 UTC1170
        &self,
0f11410be91batagen2026-10-17 03:59 UTC1171
        buffer: &WlBuffer,
0f11410be91batagen2026-10-17 03:59 UTC1172
        region: Option<Rectangle<i32, Buffer>>,
0f11410be91batagen2026-10-17 03:59 UTC1173
    ) -> Result<StagedShm, Error> {
0f11410be91batagen2026-10-17 03:59 UTC1174
        with_buffer_contents(buffer, |ptr, len, data| {
0f11410be91batagen2026-10-17 03:59 UTC1175
            let fourcc = shm_format_to_fourcc(data.format).ok_or(Error::ShmAccess)?;
0f11410be91batagen2026-10-17 03:59 UTC1176
            let (w, h, stride, offset) = (
0f11410be91batagen2026-10-17 03:59 UTC1177
                data.width as usize,
0f11410be91batagen2026-10-17 03:59 UTC1178
                data.height as usize,
0f11410be91batagen2026-10-17 03:59 UTC1179
                data.stride as usize,
0f11410be91batagen2026-10-17 03:59 UTC1180
                data.offset as usize,
0f11410be91batagen2026-10-17 03:59 UTC1181
            );
0f11410be91batagen2026-10-17 03:59 UTC1182
            let line = w * BYTES_PER_PIXEL;
0f11410be91batagen2026-10-17 03:59 UTC1183
            if w == 0 || h == 0 || stride < line || offset + stride * (h - 1) + line > len {
0f11410be91batagen2026-10-17 03:59 UTC1184
                return Err(Error::ShmAccess);
0f11410be91batagen2026-10-17 03:59 UTC1185
            }
0f11410be91batagen2026-10-17 03:59 UTC1186
            let size = Size::from((data.width, data.height));
0f11410be91batagen2026-10-17 03:59 UTC1187
            let full = Rectangle::from_size(size);
0f11410be91batagen2026-10-17 03:59 UTC1188
            let region = region.and_then(|r| r.intersection(full)).unwrap_or(full);
0f11410be91batagen2026-10-17 03:59 UTC1189
            let x = region.loc.x as usize * BYTES_PER_PIXEL;
0f11410be91batagen2026-10-17 03:59 UTC1190
            let rw = region.size.w as usize * BYTES_PER_PIXEL;
0f11410be91batagen2026-10-17 03:59 UTC1191
            // SAFETY: the bounds check above keeps every row inside the
0f11410be91batagen2026-10-17 03:59 UTC1192
            // `len` bytes smithay mapped at `ptr`.
0f11410be91batagen2026-10-17 03:59 UTC1193
            let staging = stage_rows(&self.shared, region, |y| unsafe {
0f11410be91batagen2026-10-17 03:59 UTC1194
                std::slice::from_raw_parts(ptr.add(offset + y * stride + x), rw)
0f11410be91batagen2026-10-17 03:59 UTC1195
            })?;
0f11410be91batagen2026-10-17 03:59 UTC1196
            Ok(StagedShm {
0f11410be91batagen2026-10-17 03:59 UTC1197
                staging,
0f11410be91batagen2026-10-17 03:59 UTC1198
                region,
0f11410be91batagen2026-10-17 03:59 UTC1199
                fourcc,
0f11410be91batagen2026-10-17 03:59 UTC1200
                size,
0f11410be91batagen2026-10-17 03:59 UTC1201
            })
0f11410be91batagen2026-10-17 03:59 UTC1202
        })
0f11410be91batagen2026-10-17 03:59 UTC1203
        .map_err(|_| Error::ShmAccess)?
0f11410be91batagen2026-10-17 03:59 UTC1204
    }
0f11410be91batagen2026-10-17 03:59 UTC1205
}
0f11410be91batagen2026-10-17 03:59 UTC1206
0f11410be91batagen2026-10-17 03:59 UTC1207
impl VulkanRenderer {
0f11410be91batagen2026-10-17 03:59 UTC1208
    pub fn shm_stager(&self) -> ShmStager {
0f11410be91batagen2026-10-17 03:59 UTC1209
        ShmStager {
0f11410be91batagen2026-10-17 03:59 UTC1210
            shared: self.shared.clone(),
0f11410be91batagen2026-10-17 03:59 UTC1211
        }
0f11410be91batagen2026-10-17 03:59 UTC1212
    }
0f11410be91batagen2026-10-17 03:59 UTC1213
0f11410be91batagen2026-10-17 03:59 UTC1214
    /// Hands back pixels a stager copied, used by the next import of `buffer`.
0f11410be91batagen2026-10-17 03:59 UTC1215
    pub fn adopt_staged(&mut self, buffer: &WlBuffer, staged: StagedShm) {
0f11410be91batagen2026-10-17 03:59 UTC1216
        if Arc::ptr_eq(&staged.staging.shared, &self.shared) {
0f11410be91batagen2026-10-17 03:59 UTC1217
            self.staged.insert(buffer.id(), (buffer.clone(), staged));
0f11410be91batagen2026-10-17 03:59 UTC1218
        }
0f11410be91batagen2026-10-17 03:59 UTC1219
    }
0f11410be91batagen2026-10-17 03:59 UTC1220
}