atagen

monolith

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

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

824bf02b6e55atagen2026-10-16 09:15 UTC1
use crate::Error;
824bf02b6e55atagen2026-10-16 09:15 UTC2
use crate::device::Shared;
824bf02b6e55atagen2026-10-16 09:15 UTC3
use crate::format::{components, vk_format};
824bf02b6e55atagen2026-10-16 09:15 UTC4
use ash::vk;
824bf02b6e55atagen2026-10-16 09:15 UTC5
use gpu_allocator::MemoryLocation;
824bf02b6e55atagen2026-10-16 09:15 UTC6
use gpu_allocator::vulkan::{Allocation, AllocationCreateDesc, AllocationScheme};
824bf02b6e55atagen2026-10-16 09:15 UTC7
use smithay::backend::allocator::Fourcc;
824bf02b6e55atagen2026-10-16 09:15 UTC8
use smithay::backend::renderer::{Texture, TextureMapping};
824bf02b6e55atagen2026-10-16 09:15 UTC9
use std::fmt;
7de49c2aa70batagen2026-10-16 09:27 UTC10
use std::marker::PhantomData;
824bf02b6e55atagen2026-10-16 09:15 UTC11
use std::sync::{Arc, Mutex};
824bf02b6e55atagen2026-10-16 09:15 UTC12
7de49c2aa70batagen2026-10-16 09:27 UTC13
pub(crate) enum Memory {
7de49c2aa70batagen2026-10-16 09:27 UTC14
    Allocated(Allocation),
7de49c2aa70batagen2026-10-16 09:27 UTC15
    /// Memory imported from a dmabuf, owned directly.
7de49c2aa70batagen2026-10-16 09:27 UTC16
    Imported(vk::DeviceMemory),
7de49c2aa70batagen2026-10-16 09:27 UTC17
}
7de49c2aa70batagen2026-10-16 09:27 UTC18
824bf02b6e55atagen2026-10-16 09:15 UTC19
pub(crate) struct ImageInner {
824bf02b6e55atagen2026-10-16 09:15 UTC20
    pub shared: Arc<Shared>,
824bf02b6e55atagen2026-10-16 09:15 UTC21
    pub image: vk::Image,
824bf02b6e55atagen2026-10-16 09:15 UTC22
    pub view: vk::ImageView,
7de49c2aa70batagen2026-10-16 09:27 UTC23
    pub memory: Mutex<Option<Memory>>,
824bf02b6e55atagen2026-10-16 09:15 UTC24
    pub fourcc: Fourcc,
824bf02b6e55atagen2026-10-16 09:15 UTC25
    pub format: vk::Format,
824bf02b6e55atagen2026-10-16 09:15 UTC26
    pub width: u32,
824bf02b6e55atagen2026-10-16 09:15 UTC27
    pub height: u32,
f0e45b059808atagen2026-10-19 07:34 UTC28
    pub usage: vk::ImageUsageFlags,
b03e3b32603aatagen2026-10-19 07:40 UTC29
    /// The rows are stored bottom to top, as a dmabuf flagged `Y_INVERT`.
b03e3b32603aatagen2026-10-19 07:40 UTC30
    pub y_inverted: bool,
824bf02b6e55atagen2026-10-16 09:15 UTC31
    pub layout: Mutex<vk::ImageLayout>,
7de49c2aa70batagen2026-10-16 09:27 UTC32
    /// Shared with other devices or processes through a dmabuf. Every use
7de49c2aa70batagen2026-10-16 09:27 UTC33
    /// acquires the image from the foreign queue family and releases it after.
7de49c2aa70batagen2026-10-16 09:27 UTC34
    pub external: bool,
824bf02b6e55atagen2026-10-16 09:15 UTC35
}
824bf02b6e55atagen2026-10-16 09:15 UTC36
824bf02b6e55atagen2026-10-16 09:15 UTC37
impl fmt::Debug for ImageInner {
824bf02b6e55atagen2026-10-16 09:15 UTC38
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
824bf02b6e55atagen2026-10-16 09:15 UTC39
        f.debug_struct("ImageInner")
824bf02b6e55atagen2026-10-16 09:15 UTC40
            .field("image", &self.image)
824bf02b6e55atagen2026-10-16 09:15 UTC41
            .field("fourcc", &self.fourcc)
824bf02b6e55atagen2026-10-16 09:15 UTC42
            .field("size", &(self.width, self.height))
7de49c2aa70batagen2026-10-16 09:27 UTC43
            .field("external", &self.external)
824bf02b6e55atagen2026-10-16 09:15 UTC44
            .finish()
824bf02b6e55atagen2026-10-16 09:15 UTC45
    }
824bf02b6e55atagen2026-10-16 09:15 UTC46
}
824bf02b6e55atagen2026-10-16 09:15 UTC47
824bf02b6e55atagen2026-10-16 09:15 UTC48
impl Drop for ImageInner {
824bf02b6e55atagen2026-10-16 09:15 UTC49
    fn drop(&mut self) {
824bf02b6e55atagen2026-10-16 09:15 UTC50
        let d = &self.shared.device.device;
824bf02b6e55atagen2026-10-16 09:15 UTC51
        unsafe {
824bf02b6e55atagen2026-10-16 09:15 UTC52
            d.destroy_image_view(self.view, None);
824bf02b6e55atagen2026-10-16 09:15 UTC53
            d.destroy_image(self.image, None);
824bf02b6e55atagen2026-10-16 09:15 UTC54
        }
7de49c2aa70batagen2026-10-16 09:27 UTC55
        match self.memory.lock().unwrap_or_else(|e| e.into_inner()).take() {
7de49c2aa70batagen2026-10-16 09:27 UTC56
            Some(Memory::Allocated(a)) => {
7de49c2aa70batagen2026-10-16 09:27 UTC57
                let _ = self
7de49c2aa70batagen2026-10-16 09:27 UTC58
                    .shared
7de49c2aa70batagen2026-10-16 09:27 UTC59
                    .allocator
7de49c2aa70batagen2026-10-16 09:27 UTC60
                    .lock()
7de49c2aa70batagen2026-10-16 09:27 UTC61
                    .unwrap_or_else(|e| e.into_inner())
7de49c2aa70batagen2026-10-16 09:27 UTC62
                    .free(a);
7de49c2aa70batagen2026-10-16 09:27 UTC63
            }
7de49c2aa70batagen2026-10-16 09:27 UTC64
            Some(Memory::Imported(m)) => unsafe { d.free_memory(m, None) },
7de49c2aa70batagen2026-10-16 09:27 UTC65
            None => {}
824bf02b6e55atagen2026-10-16 09:15 UTC66
        }
824bf02b6e55atagen2026-10-16 09:15 UTC67
    }
824bf02b6e55atagen2026-10-16 09:15 UTC68
}
824bf02b6e55atagen2026-10-16 09:15 UTC69
824bf02b6e55atagen2026-10-16 09:15 UTC70
impl ImageInner {
824bf02b6e55atagen2026-10-16 09:15 UTC71
    pub fn create(
824bf02b6e55atagen2026-10-16 09:15 UTC72
        shared: &Arc<Shared>,
824bf02b6e55atagen2026-10-16 09:15 UTC73
        fourcc: Fourcc,
824bf02b6e55atagen2026-10-16 09:15 UTC74
        width: u32,
824bf02b6e55atagen2026-10-16 09:15 UTC75
        height: u32,
824bf02b6e55atagen2026-10-16 09:15 UTC76
        usage: vk::ImageUsageFlags,
824bf02b6e55atagen2026-10-16 09:15 UTC77
    ) -> Result<Arc<Self>, Error> {
824bf02b6e55atagen2026-10-16 09:15 UTC78
        let fmt = vk_format(fourcc).ok_or(Error::UnsupportedFormat(fourcc))?;
824bf02b6e55atagen2026-10-16 09:15 UTC79
        if width == 0 || height == 0 {
824bf02b6e55atagen2026-10-16 09:15 UTC80
            return Err(Error::InvalidSize(width as i32, height as i32));
824bf02b6e55atagen2026-10-16 09:15 UTC81
        }
824bf02b6e55atagen2026-10-16 09:15 UTC82
        let d = &shared.device.device;
824bf02b6e55atagen2026-10-16 09:15 UTC83
        let info = vk::ImageCreateInfo::default()
824bf02b6e55atagen2026-10-16 09:15 UTC84
            .image_type(vk::ImageType::TYPE_2D)
824bf02b6e55atagen2026-10-16 09:15 UTC85
            .format(fmt.format)
824bf02b6e55atagen2026-10-16 09:15 UTC86
            .extent(vk::Extent3D {
824bf02b6e55atagen2026-10-16 09:15 UTC87
                width,
824bf02b6e55atagen2026-10-16 09:15 UTC88
                height,
824bf02b6e55atagen2026-10-16 09:15 UTC89
                depth: 1,
824bf02b6e55atagen2026-10-16 09:15 UTC90
            })
824bf02b6e55atagen2026-10-16 09:15 UTC91
            .mip_levels(1)
824bf02b6e55atagen2026-10-16 09:15 UTC92
            .array_layers(1)
824bf02b6e55atagen2026-10-16 09:15 UTC93
            .samples(vk::SampleCountFlags::TYPE_1)
824bf02b6e55atagen2026-10-16 09:15 UTC94
            .tiling(vk::ImageTiling::OPTIMAL)
824bf02b6e55atagen2026-10-16 09:15 UTC95
            .usage(usage)
824bf02b6e55atagen2026-10-16 09:15 UTC96
            .initial_layout(vk::ImageLayout::UNDEFINED);
824bf02b6e55atagen2026-10-16 09:15 UTC97
        let image = unsafe { d.create_image(&info, None)? };
824bf02b6e55atagen2026-10-16 09:15 UTC98
        let requirements = unsafe { d.get_image_memory_requirements(image) };
824bf02b6e55atagen2026-10-16 09:15 UTC99
        let allocation = shared
824bf02b6e55atagen2026-10-16 09:15 UTC100
            .allocator
824bf02b6e55atagen2026-10-16 09:15 UTC101
            .lock()
824bf02b6e55atagen2026-10-16 09:15 UTC102
            .unwrap_or_else(|e| e.into_inner())
824bf02b6e55atagen2026-10-16 09:15 UTC103
            .allocate(&AllocationCreateDesc {
824bf02b6e55atagen2026-10-16 09:15 UTC104
                name: "image",
824bf02b6e55atagen2026-10-16 09:15 UTC105
                requirements,
824bf02b6e55atagen2026-10-16 09:15 UTC106
                location: MemoryLocation::GpuOnly,
824bf02b6e55atagen2026-10-16 09:15 UTC107
                linear: false,
824bf02b6e55atagen2026-10-16 09:15 UTC108
                allocation_scheme: AllocationScheme::GpuAllocatorManaged,
824bf02b6e55atagen2026-10-16 09:15 UTC109
            });
824bf02b6e55atagen2026-10-16 09:15 UTC110
        let allocation = match allocation {
824bf02b6e55atagen2026-10-16 09:15 UTC111
            Ok(a) => a,
824bf02b6e55atagen2026-10-16 09:15 UTC112
            Err(e) => {
824bf02b6e55atagen2026-10-16 09:15 UTC113
                unsafe { d.destroy_image(image, None) };
824bf02b6e55atagen2026-10-16 09:15 UTC114
                return Err(e.into());
824bf02b6e55atagen2026-10-16 09:15 UTC115
            }
824bf02b6e55atagen2026-10-16 09:15 UTC116
        };
7de49c2aa70batagen2026-10-16 09:27 UTC117
        let memory = Memory::Allocated(allocation);
7de49c2aa70batagen2026-10-16 09:27 UTC118
        let (mem, offset) = match &memory {
7de49c2aa70batagen2026-10-16 09:27 UTC119
            Memory::Allocated(a) => (unsafe { a.memory() }, a.offset()),
7de49c2aa70batagen2026-10-16 09:27 UTC120
            Memory::Imported(m) => (*m, 0),
7de49c2aa70batagen2026-10-16 09:27 UTC121
        };
7de49c2aa70batagen2026-10-16 09:27 UTC122
        Self::finish(
b03e3b32603aatagen2026-10-19 07:40 UTC123
            shared, image, memory, mem, offset, fourcc, width, height, usage, false, false,
7de49c2aa70batagen2026-10-16 09:27 UTC124
        )
7de49c2aa70batagen2026-10-16 09:27 UTC125
    }
7de49c2aa70batagen2026-10-16 09:27 UTC126
7de49c2aa70batagen2026-10-16 09:27 UTC127
    /// Binds memory, creates the view and wraps everything up. Takes
7de49c2aa70batagen2026-10-16 09:27 UTC128
    /// ownership of `image` and `memory`, releasing both on failure.
7de49c2aa70batagen2026-10-16 09:27 UTC129
    #[expect(clippy::too_many_arguments)]
7de49c2aa70batagen2026-10-16 09:27 UTC130
    pub fn finish(
7de49c2aa70batagen2026-10-16 09:27 UTC131
        shared: &Arc<Shared>,
7de49c2aa70batagen2026-10-16 09:27 UTC132
        image: vk::Image,
7de49c2aa70batagen2026-10-16 09:27 UTC133
        memory: Memory,
7de49c2aa70batagen2026-10-16 09:27 UTC134
        mem: vk::DeviceMemory,
7de49c2aa70batagen2026-10-16 09:27 UTC135
        offset: u64,
7de49c2aa70batagen2026-10-16 09:27 UTC136
        fourcc: Fourcc,
7de49c2aa70batagen2026-10-16 09:27 UTC137
        width: u32,
7de49c2aa70batagen2026-10-16 09:27 UTC138
        height: u32,
f0e45b059808atagen2026-10-19 07:34 UTC139
        usage: vk::ImageUsageFlags,
7de49c2aa70batagen2026-10-16 09:27 UTC140
        external: bool,
b03e3b32603aatagen2026-10-19 07:40 UTC141
        y_inverted: bool,
7de49c2aa70batagen2026-10-16 09:27 UTC142
    ) -> Result<Arc<Self>, Error> {
7de49c2aa70batagen2026-10-16 09:27 UTC143
        let fmt = vk_format(fourcc).ok_or(Error::UnsupportedFormat(fourcc))?;
7de49c2aa70batagen2026-10-16 09:27 UTC144
        let d = &shared.device.device;
7de49c2aa70batagen2026-10-16 09:27 UTC145
        let mut inner = Self {
824bf02b6e55atagen2026-10-16 09:15 UTC146
            shared: shared.clone(),
824bf02b6e55atagen2026-10-16 09:15 UTC147
            image,
7de49c2aa70batagen2026-10-16 09:27 UTC148
            view: vk::ImageView::null(),
7de49c2aa70batagen2026-10-16 09:27 UTC149
            memory: Mutex::new(Some(memory)),
824bf02b6e55atagen2026-10-16 09:15 UTC150
            fourcc,
824bf02b6e55atagen2026-10-16 09:15 UTC151
            format: fmt.format,
824bf02b6e55atagen2026-10-16 09:15 UTC152
            width,
824bf02b6e55atagen2026-10-16 09:15 UTC153
            height,
f0e45b059808atagen2026-10-19 07:34 UTC154
            usage,
b03e3b32603aatagen2026-10-19 07:40 UTC155
            y_inverted,
7de49c2aa70batagen2026-10-16 09:27 UTC156
            layout: Mutex::new(if external {
7de49c2aa70batagen2026-10-16 09:27 UTC157
                vk::ImageLayout::GENERAL
7de49c2aa70batagen2026-10-16 09:27 UTC158
            } else {
7de49c2aa70batagen2026-10-16 09:27 UTC159
                vk::ImageLayout::UNDEFINED
7de49c2aa70batagen2026-10-16 09:27 UTC160
            }),
7de49c2aa70batagen2026-10-16 09:27 UTC161
            external,
7de49c2aa70batagen2026-10-16 09:27 UTC162
        };
7de49c2aa70batagen2026-10-16 09:27 UTC163
        unsafe { d.bind_image_memory(image, mem, offset)? };
7de49c2aa70batagen2026-10-16 09:27 UTC164
        let view_info = vk::ImageViewCreateInfo::default()
7de49c2aa70batagen2026-10-16 09:27 UTC165
            .image(image)
7de49c2aa70batagen2026-10-16 09:27 UTC166
            .view_type(vk::ImageViewType::TYPE_2D)
7de49c2aa70batagen2026-10-16 09:27 UTC167
            .format(fmt.format)
7de49c2aa70batagen2026-10-16 09:27 UTC168
            .components(components(fmt.opaque))
7de49c2aa70batagen2026-10-16 09:27 UTC169
            .subresource_range(color_range());
7de49c2aa70batagen2026-10-16 09:27 UTC170
        inner.view = unsafe { d.create_image_view(&view_info, None)? };
7de49c2aa70batagen2026-10-16 09:27 UTC171
        Ok(Arc::new(inner))
824bf02b6e55atagen2026-10-16 09:15 UTC172
    }
824bf02b6e55atagen2026-10-16 09:15 UTC173
c0caa658decfatagen2026-10-19 07:37 UTC174
    /// Whether sampling the image always gives alpha one.
c0caa658decfatagen2026-10-19 07:37 UTC175
    pub fn opaque(&self) -> bool {
c0caa658decfatagen2026-10-19 07:37 UTC176
        vk_format(self.fourcc).is_some_and(|f| f.opaque)
c0caa658decfatagen2026-10-19 07:37 UTC177
    }
c0caa658decfatagen2026-10-19 07:37 UTC178
824bf02b6e55atagen2026-10-16 09:15 UTC179
    pub fn layout(&self) -> vk::ImageLayout {
824bf02b6e55atagen2026-10-16 09:15 UTC180
        *self.layout.lock().unwrap_or_else(|e| e.into_inner())
824bf02b6e55atagen2026-10-16 09:15 UTC181
    }
824bf02b6e55atagen2026-10-16 09:15 UTC182
824bf02b6e55atagen2026-10-16 09:15 UTC183
    pub fn set_layout(&self, layout: vk::ImageLayout) {
824bf02b6e55atagen2026-10-16 09:15 UTC184
        *self.layout.lock().unwrap_or_else(|e| e.into_inner()) = layout;
824bf02b6e55atagen2026-10-16 09:15 UTC185
    }
824bf02b6e55atagen2026-10-16 09:15 UTC186
}
824bf02b6e55atagen2026-10-16 09:15 UTC187
824bf02b6e55atagen2026-10-16 09:15 UTC188
pub(crate) fn color_range() -> vk::ImageSubresourceRange {
824bf02b6e55atagen2026-10-16 09:15 UTC189
    vk::ImageSubresourceRange::default()
824bf02b6e55atagen2026-10-16 09:15 UTC190
        .aspect_mask(vk::ImageAspectFlags::COLOR)
824bf02b6e55atagen2026-10-16 09:15 UTC191
        .level_count(1)
824bf02b6e55atagen2026-10-16 09:15 UTC192
        .layer_count(1)
824bf02b6e55atagen2026-10-16 09:15 UTC193
}
824bf02b6e55atagen2026-10-16 09:15 UTC194
824bf02b6e55atagen2026-10-16 09:15 UTC195
/// A sampled texture.
824bf02b6e55atagen2026-10-16 09:15 UTC196
#[derive(Clone, Debug)]
824bf02b6e55atagen2026-10-16 09:15 UTC197
pub struct VulkanTexture(pub(crate) Arc<ImageInner>);
824bf02b6e55atagen2026-10-16 09:15 UTC198
824bf02b6e55atagen2026-10-16 09:15 UTC199
/// An image the renderer can draw into, from [`smithay::backend::renderer::Offscreen`].
824bf02b6e55atagen2026-10-16 09:15 UTC200
#[derive(Debug)]
824bf02b6e55atagen2026-10-16 09:15 UTC201
pub struct VulkanImage(pub(crate) Arc<ImageInner>);
824bf02b6e55atagen2026-10-16 09:15 UTC202
824bf02b6e55atagen2026-10-16 09:15 UTC203
impl VulkanImage {
824bf02b6e55atagen2026-10-16 09:15 UTC204
    /// The image's contents as a texture, for drawing it elsewhere.
824bf02b6e55atagen2026-10-16 09:15 UTC205
    pub fn texture(&self) -> VulkanTexture {
824bf02b6e55atagen2026-10-16 09:15 UTC206
        VulkanTexture(self.0.clone())
824bf02b6e55atagen2026-10-16 09:15 UTC207
    }
824bf02b6e55atagen2026-10-16 09:15 UTC208
}
824bf02b6e55atagen2026-10-16 09:15 UTC209
7de49c2aa70batagen2026-10-16 09:27 UTC210
/// A bound render target, borrowing whatever it was bound from.
824bf02b6e55atagen2026-10-16 09:15 UTC211
#[derive(Debug)]
7de49c2aa70batagen2026-10-16 09:27 UTC212
pub struct VulkanTarget<'a>(
7de49c2aa70batagen2026-10-16 09:27 UTC213
    pub(crate) Arc<ImageInner>,
7de49c2aa70batagen2026-10-16 09:27 UTC214
    pub(crate) PhantomData<&'a mut ()>,
7de49c2aa70batagen2026-10-16 09:27 UTC215
);
824bf02b6e55atagen2026-10-16 09:15 UTC216
824bf02b6e55atagen2026-10-16 09:15 UTC217
/// Pixels read back from the GPU.
824bf02b6e55atagen2026-10-16 09:15 UTC218
#[derive(Debug)]
824bf02b6e55atagen2026-10-16 09:15 UTC219
pub struct VulkanMapping {
824bf02b6e55atagen2026-10-16 09:15 UTC220
    pub(crate) data: Vec<u8>,
824bf02b6e55atagen2026-10-16 09:15 UTC221
    pub(crate) width: u32,
824bf02b6e55atagen2026-10-16 09:15 UTC222
    pub(crate) height: u32,
824bf02b6e55atagen2026-10-16 09:15 UTC223
    pub(crate) fourcc: Fourcc,
824bf02b6e55atagen2026-10-16 09:15 UTC224
}
824bf02b6e55atagen2026-10-16 09:15 UTC225
824bf02b6e55atagen2026-10-16 09:15 UTC226
macro_rules! texture_impl {
824bf02b6e55atagen2026-10-16 09:15 UTC227
    ($t:ty, |$s:ident| $inner:expr) => {
824bf02b6e55atagen2026-10-16 09:15 UTC228
        impl Texture for $t {
824bf02b6e55atagen2026-10-16 09:15 UTC229
            fn width(&self) -> u32 {
824bf02b6e55atagen2026-10-16 09:15 UTC230
                let $s = self;
824bf02b6e55atagen2026-10-16 09:15 UTC231
                $inner.width
824bf02b6e55atagen2026-10-16 09:15 UTC232
            }
824bf02b6e55atagen2026-10-16 09:15 UTC233
            fn height(&self) -> u32 {
824bf02b6e55atagen2026-10-16 09:15 UTC234
                let $s = self;
824bf02b6e55atagen2026-10-16 09:15 UTC235
                $inner.height
824bf02b6e55atagen2026-10-16 09:15 UTC236
            }
824bf02b6e55atagen2026-10-16 09:15 UTC237
            fn format(&self) -> Option<Fourcc> {
824bf02b6e55atagen2026-10-16 09:15 UTC238
                let $s = self;
824bf02b6e55atagen2026-10-16 09:15 UTC239
                Some($inner.fourcc)
824bf02b6e55atagen2026-10-16 09:15 UTC240
            }
824bf02b6e55atagen2026-10-16 09:15 UTC241
        }
824bf02b6e55atagen2026-10-16 09:15 UTC242
    };
824bf02b6e55atagen2026-10-16 09:15 UTC243
}
824bf02b6e55atagen2026-10-16 09:15 UTC244
824bf02b6e55atagen2026-10-16 09:15 UTC245
texture_impl!(VulkanTexture, |s| s.0);
824bf02b6e55atagen2026-10-16 09:15 UTC246
texture_impl!(VulkanImage, |s| s.0);
7de49c2aa70batagen2026-10-16 09:27 UTC247
texture_impl!(VulkanTarget<'_>, |s| s.0);
824bf02b6e55atagen2026-10-16 09:15 UTC248
texture_impl!(VulkanMapping, |s| s);
824bf02b6e55atagen2026-10-16 09:15 UTC249
824bf02b6e55atagen2026-10-16 09:15 UTC250
impl TextureMapping for VulkanMapping {
824bf02b6e55atagen2026-10-16 09:15 UTC251
    fn flipped(&self) -> bool {
824bf02b6e55atagen2026-10-16 09:15 UTC252
        false
824bf02b6e55atagen2026-10-16 09:15 UTC253
    }
824bf02b6e55atagen2026-10-16 09:15 UTC254
}