atagen

monolith

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

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

7de49c2aa70batagen2026-10-16 09:27 UTC1
use crate::Error;
7de49c2aa70batagen2026-10-16 09:27 UTC2
use crate::device::Shared;
7de49c2aa70batagen2026-10-16 09:27 UTC3
use crate::format::{SUPPORTED, vk_format};
7de49c2aa70batagen2026-10-16 09:27 UTC4
use crate::image::{ImageInner, Memory};
7de49c2aa70batagen2026-10-16 09:27 UTC5
use ash::vk;
7de49c2aa70batagen2026-10-16 09:27 UTC6
use smithay::backend::allocator::dmabuf::{Dmabuf, DmabufFlags};
7de49c2aa70batagen2026-10-16 09:27 UTC7
use smithay::backend::allocator::format::FormatSet;
7de49c2aa70batagen2026-10-16 09:27 UTC8
use smithay::backend::allocator::{Allocator, Buffer, Format, Fourcc, Modifier};
7de49c2aa70batagen2026-10-16 09:27 UTC9
use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd};
7de49c2aa70batagen2026-10-16 09:27 UTC10
use std::sync::Arc;
7de49c2aa70batagen2026-10-16 09:27 UTC11
7de49c2aa70batagen2026-10-16 09:27 UTC12
/// Which (format, modifier) pairs the device can import for sampling and
7de49c2aa70batagen2026-10-16 09:27 UTC13
/// render into, queried once at startup.
7de49c2aa70batagen2026-10-16 09:27 UTC14
#[derive(Debug, Default)]
7de49c2aa70batagen2026-10-16 09:27 UTC15
pub(crate) struct DmabufCaps {
7de49c2aa70batagen2026-10-16 09:27 UTC16
    pub sample: FormatSet,
7de49c2aa70batagen2026-10-16 09:27 UTC17
    pub render: FormatSet,
7de49c2aa70batagen2026-10-16 09:27 UTC18
}
7de49c2aa70batagen2026-10-16 09:27 UTC19
7de49c2aa70batagen2026-10-16 09:27 UTC20
pub(crate) const RENDER_USAGE: vk::ImageUsageFlags = vk::ImageUsageFlags::from_raw(
7de49c2aa70batagen2026-10-16 09:27 UTC21
    vk::ImageUsageFlags::COLOR_ATTACHMENT.as_raw()
7de49c2aa70batagen2026-10-16 09:27 UTC22
        | vk::ImageUsageFlags::SAMPLED.as_raw()
7de49c2aa70batagen2026-10-16 09:27 UTC23
        | vk::ImageUsageFlags::TRANSFER_SRC.as_raw(),
7de49c2aa70batagen2026-10-16 09:27 UTC24
);
7de49c2aa70batagen2026-10-16 09:27 UTC25
pub(crate) const SAMPLE_USAGE: vk::ImageUsageFlags = vk::ImageUsageFlags::SAMPLED;
7de49c2aa70batagen2026-10-16 09:27 UTC26
7de49c2aa70batagen2026-10-16 09:27 UTC27
impl DmabufCaps {
7de49c2aa70batagen2026-10-16 09:27 UTC28
    pub fn query(shared: &Shared) -> Self {
7de49c2aa70batagen2026-10-16 09:27 UTC29
        if shared.device.dmabuf.is_none() {
7de49c2aa70batagen2026-10-16 09:27 UTC30
            return Self::default();
7de49c2aa70batagen2026-10-16 09:27 UTC31
        }
7de49c2aa70batagen2026-10-16 09:27 UTC32
        let (mut sample, mut render) = (Vec::new(), Vec::new());
7de49c2aa70batagen2026-10-16 09:27 UTC33
        for fourcc in SUPPORTED {
7de49c2aa70batagen2026-10-16 09:27 UTC34
            let Some(fmt) = vk_format(fourcc) else {
7de49c2aa70batagen2026-10-16 09:27 UTC35
                continue;
7de49c2aa70batagen2026-10-16 09:27 UTC36
            };
7de49c2aa70batagen2026-10-16 09:27 UTC37
            for props in modifier_properties(shared, fmt.format) {
7de49c2aa70batagen2026-10-16 09:27 UTC38
                if props.drm_format_modifier_plane_count != 1 {
7de49c2aa70batagen2026-10-16 09:27 UTC39
                    continue;
7de49c2aa70batagen2026-10-16 09:27 UTC40
                }
7de49c2aa70batagen2026-10-16 09:27 UTC41
                let features = props.drm_format_modifier_tiling_features;
7de49c2aa70batagen2026-10-16 09:27 UTC42
                let format = Format {
7de49c2aa70batagen2026-10-16 09:27 UTC43
                    code: fourcc,
7de49c2aa70batagen2026-10-16 09:27 UTC44
                    modifier: Modifier::from(props.drm_format_modifier),
7de49c2aa70batagen2026-10-16 09:27 UTC45
                };
7de49c2aa70batagen2026-10-16 09:27 UTC46
                let supports =
7de49c2aa70batagen2026-10-16 09:27 UTC47
                    |usage| external_support(shared, fmt.format, props.drm_format_modifier, usage);
7de49c2aa70batagen2026-10-16 09:27 UTC48
                if features.contains(vk::FormatFeatureFlags::SAMPLED_IMAGE)
7de49c2aa70batagen2026-10-16 09:27 UTC49
                    && supports(SAMPLE_USAGE).importable
7de49c2aa70batagen2026-10-16 09:27 UTC50
                {
7de49c2aa70batagen2026-10-16 09:27 UTC51
                    sample.push(format);
7de49c2aa70batagen2026-10-16 09:27 UTC52
                }
7de49c2aa70batagen2026-10-16 09:27 UTC53
                let renderable = vk::FormatFeatureFlags::COLOR_ATTACHMENT
7de49c2aa70batagen2026-10-16 09:27 UTC54
                    | vk::FormatFeatureFlags::COLOR_ATTACHMENT_BLEND;
7de49c2aa70batagen2026-10-16 09:27 UTC55
                let s = supports(RENDER_USAGE);
7de49c2aa70batagen2026-10-16 09:27 UTC56
                if features.contains(renderable) && s.importable && s.exportable {
7de49c2aa70batagen2026-10-16 09:27 UTC57
                    render.push(format);
7de49c2aa70batagen2026-10-16 09:27 UTC58
                }
7de49c2aa70batagen2026-10-16 09:27 UTC59
            }
7de49c2aa70batagen2026-10-16 09:27 UTC60
        }
7de49c2aa70batagen2026-10-16 09:27 UTC61
        Self {
7de49c2aa70batagen2026-10-16 09:27 UTC62
            sample: sample.into_iter().collect(),
7de49c2aa70batagen2026-10-16 09:27 UTC63
            render: render.into_iter().collect(),
7de49c2aa70batagen2026-10-16 09:27 UTC64
        }
7de49c2aa70batagen2026-10-16 09:27 UTC65
    }
7de49c2aa70batagen2026-10-16 09:27 UTC66
}
7de49c2aa70batagen2026-10-16 09:27 UTC67
7de49c2aa70batagen2026-10-16 09:27 UTC68
fn modifier_properties(
7de49c2aa70batagen2026-10-16 09:27 UTC69
    shared: &Shared,
7de49c2aa70batagen2026-10-16 09:27 UTC70
    format: vk::Format,
7de49c2aa70batagen2026-10-16 09:27 UTC71
) -> Vec<vk::DrmFormatModifierPropertiesEXT> {
7de49c2aa70batagen2026-10-16 09:27 UTC72
    let dev = &shared.device;
7de49c2aa70batagen2026-10-16 09:27 UTC73
    let mut list = vk::DrmFormatModifierPropertiesListEXT::default();
7de49c2aa70batagen2026-10-16 09:27 UTC74
    let mut props = vk::FormatProperties2::default().push_next(&mut list);
7de49c2aa70batagen2026-10-16 09:27 UTC75
    unsafe {
7de49c2aa70batagen2026-10-16 09:27 UTC76
        dev.instance
7de49c2aa70batagen2026-10-16 09:27 UTC77
            .get_physical_device_format_properties2(dev.physical, format, &mut props)
7de49c2aa70batagen2026-10-16 09:27 UTC78
    };
7de49c2aa70batagen2026-10-16 09:27 UTC79
    let count = list.drm_format_modifier_count as usize;
7de49c2aa70batagen2026-10-16 09:27 UTC80
    let mut out = vec![vk::DrmFormatModifierPropertiesEXT::default(); count];
7de49c2aa70batagen2026-10-16 09:27 UTC81
    let mut list =
7de49c2aa70batagen2026-10-16 09:27 UTC82
        vk::DrmFormatModifierPropertiesListEXT::default().drm_format_modifier_properties(&mut out);
7de49c2aa70batagen2026-10-16 09:27 UTC83
    let mut props = vk::FormatProperties2::default().push_next(&mut list);
7de49c2aa70batagen2026-10-16 09:27 UTC84
    unsafe {
7de49c2aa70batagen2026-10-16 09:27 UTC85
        dev.instance
7de49c2aa70batagen2026-10-16 09:27 UTC86
            .get_physical_device_format_properties2(dev.physical, format, &mut props)
7de49c2aa70batagen2026-10-16 09:27 UTC87
    };
7de49c2aa70batagen2026-10-16 09:27 UTC88
    out
7de49c2aa70batagen2026-10-16 09:27 UTC89
}
7de49c2aa70batagen2026-10-16 09:27 UTC90
7de49c2aa70batagen2026-10-16 09:27 UTC91
struct External {
7de49c2aa70batagen2026-10-16 09:27 UTC92
    importable: bool,
7de49c2aa70batagen2026-10-16 09:27 UTC93
    exportable: bool,
7de49c2aa70batagen2026-10-16 09:27 UTC94
}
7de49c2aa70batagen2026-10-16 09:27 UTC95
7de49c2aa70batagen2026-10-16 09:27 UTC96
fn external_support(
7de49c2aa70batagen2026-10-16 09:27 UTC97
    shared: &Shared,
7de49c2aa70batagen2026-10-16 09:27 UTC98
    format: vk::Format,
7de49c2aa70batagen2026-10-16 09:27 UTC99
    modifier: u64,
7de49c2aa70batagen2026-10-16 09:27 UTC100
    usage: vk::ImageUsageFlags,
7de49c2aa70batagen2026-10-16 09:27 UTC101
) -> External {
7de49c2aa70batagen2026-10-16 09:27 UTC102
    let dev = &shared.device;
7de49c2aa70batagen2026-10-16 09:27 UTC103
    let mut modifier_info = vk::PhysicalDeviceImageDrmFormatModifierInfoEXT::default()
7de49c2aa70batagen2026-10-16 09:27 UTC104
        .drm_format_modifier(modifier)
7de49c2aa70batagen2026-10-16 09:27 UTC105
        .sharing_mode(vk::SharingMode::EXCLUSIVE);
7de49c2aa70batagen2026-10-16 09:27 UTC106
    let mut external_info = vk::PhysicalDeviceExternalImageFormatInfo::default()
7de49c2aa70batagen2026-10-16 09:27 UTC107
        .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
7de49c2aa70batagen2026-10-16 09:27 UTC108
    let info = vk::PhysicalDeviceImageFormatInfo2::default()
7de49c2aa70batagen2026-10-16 09:27 UTC109
        .format(format)
7de49c2aa70batagen2026-10-16 09:27 UTC110
        .ty(vk::ImageType::TYPE_2D)
7de49c2aa70batagen2026-10-16 09:27 UTC111
        .tiling(vk::ImageTiling::DRM_FORMAT_MODIFIER_EXT)
7de49c2aa70batagen2026-10-16 09:27 UTC112
        .usage(usage)
7de49c2aa70batagen2026-10-16 09:27 UTC113
        .push_next(&mut external_info)
7de49c2aa70batagen2026-10-16 09:27 UTC114
        .push_next(&mut modifier_info);
7de49c2aa70batagen2026-10-16 09:27 UTC115
    let mut external_props = vk::ExternalImageFormatProperties::default();
7de49c2aa70batagen2026-10-16 09:27 UTC116
    let mut props = vk::ImageFormatProperties2::default().push_next(&mut external_props);
7de49c2aa70batagen2026-10-16 09:27 UTC117
    let ok = unsafe {
7de49c2aa70batagen2026-10-16 09:27 UTC118
        dev.instance
7de49c2aa70batagen2026-10-16 09:27 UTC119
            .get_physical_device_image_format_properties2(dev.physical, &info, &mut props)
7de49c2aa70batagen2026-10-16 09:27 UTC120
    }
7de49c2aa70batagen2026-10-16 09:27 UTC121
    .is_ok();
7de49c2aa70batagen2026-10-16 09:27 UTC122
    let features = external_props
7de49c2aa70batagen2026-10-16 09:27 UTC123
        .external_memory_properties
7de49c2aa70batagen2026-10-16 09:27 UTC124
        .external_memory_features;
7de49c2aa70batagen2026-10-16 09:27 UTC125
    External {
7de49c2aa70batagen2026-10-16 09:27 UTC126
        importable: ok && features.contains(vk::ExternalMemoryFeatureFlags::IMPORTABLE),
7de49c2aa70batagen2026-10-16 09:27 UTC127
        exportable: ok && features.contains(vk::ExternalMemoryFeatureFlags::EXPORTABLE),
7de49c2aa70batagen2026-10-16 09:27 UTC128
    }
7de49c2aa70batagen2026-10-16 09:27 UTC129
}
7de49c2aa70batagen2026-10-16 09:27 UTC130
7de49c2aa70batagen2026-10-16 09:27 UTC131
fn memory_type(shared: &Shared, bits: u32, prefer: vk::MemoryPropertyFlags) -> Option<u32> {
7de49c2aa70batagen2026-10-16 09:27 UTC132
    let props = unsafe {
7de49c2aa70batagen2026-10-16 09:27 UTC133
        shared
7de49c2aa70batagen2026-10-16 09:27 UTC134
            .device
7de49c2aa70batagen2026-10-16 09:27 UTC135
            .instance
7de49c2aa70batagen2026-10-16 09:27 UTC136
            .get_physical_device_memory_properties(shared.device.physical)
7de49c2aa70batagen2026-10-16 09:27 UTC137
    };
7de49c2aa70batagen2026-10-16 09:27 UTC138
    let types = &props.memory_types[..props.memory_type_count as usize];
7de49c2aa70batagen2026-10-16 09:27 UTC139
    let allowed = |i: usize| bits & (1 << i) != 0;
7de49c2aa70batagen2026-10-16 09:27 UTC140
    (0..types.len())
7de49c2aa70batagen2026-10-16 09:27 UTC141
        .find(|&i| allowed(i) && types[i].property_flags.contains(prefer))
7de49c2aa70batagen2026-10-16 09:27 UTC142
        .or_else(|| (0..types.len()).find(|&i| allowed(i)))
7de49c2aa70batagen2026-10-16 09:27 UTC143
        .map(|i| i as u32)
7de49c2aa70batagen2026-10-16 09:27 UTC144
}
7de49c2aa70batagen2026-10-16 09:27 UTC145
7de49c2aa70batagen2026-10-16 09:27 UTC146
fn image_info<'a>(
7de49c2aa70batagen2026-10-16 09:27 UTC147
    fourcc: Fourcc,
7de49c2aa70batagen2026-10-16 09:27 UTC148
    size: (u32, u32),
7de49c2aa70batagen2026-10-16 09:27 UTC149
    usage: vk::ImageUsageFlags,
7de49c2aa70batagen2026-10-16 09:27 UTC150
) -> Result<vk::ImageCreateInfo<'a>, Error> {
7de49c2aa70batagen2026-10-16 09:27 UTC151
    let fmt = vk_format(fourcc).ok_or(Error::UnsupportedFormat(fourcc))?;
7de49c2aa70batagen2026-10-16 09:27 UTC152
    Ok(vk::ImageCreateInfo::default()
7de49c2aa70batagen2026-10-16 09:27 UTC153
        .image_type(vk::ImageType::TYPE_2D)
7de49c2aa70batagen2026-10-16 09:27 UTC154
        .format(fmt.format)
7de49c2aa70batagen2026-10-16 09:27 UTC155
        .extent(vk::Extent3D {
7de49c2aa70batagen2026-10-16 09:27 UTC156
            width: size.0,
7de49c2aa70batagen2026-10-16 09:27 UTC157
            height: size.1,
7de49c2aa70batagen2026-10-16 09:27 UTC158
            depth: 1,
7de49c2aa70batagen2026-10-16 09:27 UTC159
        })
7de49c2aa70batagen2026-10-16 09:27 UTC160
        .mip_levels(1)
7de49c2aa70batagen2026-10-16 09:27 UTC161
        .array_layers(1)
7de49c2aa70batagen2026-10-16 09:27 UTC162
        .samples(vk::SampleCountFlags::TYPE_1)
7de49c2aa70batagen2026-10-16 09:27 UTC163
        .tiling(vk::ImageTiling::DRM_FORMAT_MODIFIER_EXT)
7de49c2aa70batagen2026-10-16 09:27 UTC164
        .usage(usage)
7de49c2aa70batagen2026-10-16 09:27 UTC165
        .sharing_mode(vk::SharingMode::EXCLUSIVE)
7de49c2aa70batagen2026-10-16 09:27 UTC166
        .initial_layout(vk::ImageLayout::UNDEFINED))
7de49c2aa70batagen2026-10-16 09:27 UTC167
}
7de49c2aa70batagen2026-10-16 09:27 UTC168
7de49c2aa70batagen2026-10-16 09:27 UTC169
/// Imports a single-plane dmabuf as an image, without copying.
7de49c2aa70batagen2026-10-16 09:27 UTC170
pub(crate) fn import(
7de49c2aa70batagen2026-10-16 09:27 UTC171
    shared: &Arc<Shared>,
7de49c2aa70batagen2026-10-16 09:27 UTC172
    caps: &DmabufCaps,
7de49c2aa70batagen2026-10-16 09:27 UTC173
    dmabuf: &Dmabuf,
7de49c2aa70batagen2026-10-16 09:27 UTC174
    usage: vk::ImageUsageFlags,
7de49c2aa70batagen2026-10-16 09:27 UTC175
) -> Result<Arc<ImageInner>, Error> {
7de49c2aa70batagen2026-10-16 09:27 UTC176
    let ext = shared
7de49c2aa70batagen2026-10-16 09:27 UTC177
        .device
7de49c2aa70batagen2026-10-16 09:27 UTC178
        .dmabuf
7de49c2aa70batagen2026-10-16 09:27 UTC179
        .as_ref()
7de49c2aa70batagen2026-10-16 09:27 UTC180
        .ok_or(Error::DmabufUnsupported)?;
7de49c2aa70batagen2026-10-16 09:27 UTC181
    let format = dmabuf.format();
7de49c2aa70batagen2026-10-16 09:27 UTC182
    let set = if usage.contains(vk::ImageUsageFlags::COLOR_ATTACHMENT) {
7de49c2aa70batagen2026-10-16 09:27 UTC183
        &caps.render
7de49c2aa70batagen2026-10-16 09:27 UTC184
    } else {
7de49c2aa70batagen2026-10-16 09:27 UTC185
        &caps.sample
7de49c2aa70batagen2026-10-16 09:27 UTC186
    };
7de49c2aa70batagen2026-10-16 09:27 UTC187
    if dmabuf.num_planes() != 1 || !set.contains(&format) {
7de49c2aa70batagen2026-10-16 09:27 UTC188
        return Err(Error::UnsupportedDmabuf(format));
7de49c2aa70batagen2026-10-16 09:27 UTC189
    }
7de49c2aa70batagen2026-10-16 09:27 UTC190
    let (Some(fd), Some(offset), Some(stride)) = (
7de49c2aa70batagen2026-10-16 09:27 UTC191
        dmabuf.handles().next(),
7de49c2aa70batagen2026-10-16 09:27 UTC192
        dmabuf.offsets().next(),
7de49c2aa70batagen2026-10-16 09:27 UTC193
        dmabuf.strides().next(),
7de49c2aa70batagen2026-10-16 09:27 UTC194
    ) else {
7de49c2aa70batagen2026-10-16 09:27 UTC195
        return Err(Error::UnsupportedDmabuf(format));
7de49c2aa70batagen2026-10-16 09:27 UTC196
    };
7de49c2aa70batagen2026-10-16 09:27 UTC197
    let size = (dmabuf.width(), dmabuf.height());
7de49c2aa70batagen2026-10-16 09:27 UTC198
    let d = &shared.device.device;
7de49c2aa70batagen2026-10-16 09:27 UTC199
    let layouts = [vk::SubresourceLayout {
7de49c2aa70batagen2026-10-16 09:27 UTC200
        offset: u64::from(offset),
7de49c2aa70batagen2026-10-16 09:27 UTC201
        size: 0,
7de49c2aa70batagen2026-10-16 09:27 UTC202
        row_pitch: u64::from(stride),
7de49c2aa70batagen2026-10-16 09:27 UTC203
        array_pitch: 0,
7de49c2aa70batagen2026-10-16 09:27 UTC204
        depth_pitch: 0,
7de49c2aa70batagen2026-10-16 09:27 UTC205
    }];
7de49c2aa70batagen2026-10-16 09:27 UTC206
    let mut explicit = vk::ImageDrmFormatModifierExplicitCreateInfoEXT::default()
7de49c2aa70batagen2026-10-16 09:27 UTC207
        .drm_format_modifier(u64::from(format.modifier))
7de49c2aa70batagen2026-10-16 09:27 UTC208
        .plane_layouts(&layouts);
7de49c2aa70batagen2026-10-16 09:27 UTC209
    let mut external = vk::ExternalMemoryImageCreateInfo::default()
7de49c2aa70batagen2026-10-16 09:27 UTC210
        .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
7de49c2aa70batagen2026-10-16 09:27 UTC211
    let info = image_info(format.code, size, usage)?
7de49c2aa70batagen2026-10-16 09:27 UTC212
        .push_next(&mut external)
7de49c2aa70batagen2026-10-16 09:27 UTC213
        .push_next(&mut explicit);
7de49c2aa70batagen2026-10-16 09:27 UTC214
    let image = unsafe { d.create_image(&info, None)? };
7de49c2aa70batagen2026-10-16 09:27 UTC215
    let destroy = || unsafe { d.destroy_image(image, None) };
7de49c2aa70batagen2026-10-16 09:27 UTC216
    let owned = match fd.try_clone_to_owned() {
7de49c2aa70batagen2026-10-16 09:27 UTC217
        Ok(o) => o,
7de49c2aa70batagen2026-10-16 09:27 UTC218
        Err(_) => {
7de49c2aa70batagen2026-10-16 09:27 UTC219
            destroy();
7de49c2aa70batagen2026-10-16 09:27 UTC220
            return Err(Error::UnsupportedDmabuf(format));
7de49c2aa70batagen2026-10-16 09:27 UTC221
        }
7de49c2aa70batagen2026-10-16 09:27 UTC222
    };
7de49c2aa70batagen2026-10-16 09:27 UTC223
    let mut fd_props = vk::MemoryFdPropertiesKHR::default();
7de49c2aa70batagen2026-10-16 09:27 UTC224
    if let Err(e) = unsafe {
7de49c2aa70batagen2026-10-16 09:27 UTC225
        ext.memory_fd.get_memory_fd_properties(
7de49c2aa70batagen2026-10-16 09:27 UTC226
            vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT,
7de49c2aa70batagen2026-10-16 09:27 UTC227
            owned.as_raw_fd(),
7de49c2aa70batagen2026-10-16 09:27 UTC228
            &mut fd_props,
7de49c2aa70batagen2026-10-16 09:27 UTC229
        )
7de49c2aa70batagen2026-10-16 09:27 UTC230
    } {
7de49c2aa70batagen2026-10-16 09:27 UTC231
        destroy();
7de49c2aa70batagen2026-10-16 09:27 UTC232
        return Err(e.into());
7de49c2aa70batagen2026-10-16 09:27 UTC233
    }
7de49c2aa70batagen2026-10-16 09:27 UTC234
    let requirements = unsafe { d.get_image_memory_requirements(image) };
7de49c2aa70batagen2026-10-16 09:27 UTC235
    let Some(type_index) = memory_type(
7de49c2aa70batagen2026-10-16 09:27 UTC236
        shared,
7de49c2aa70batagen2026-10-16 09:27 UTC237
        requirements.memory_type_bits & fd_props.memory_type_bits,
7de49c2aa70batagen2026-10-16 09:27 UTC238
        vk::MemoryPropertyFlags::empty(),
7de49c2aa70batagen2026-10-16 09:27 UTC239
    ) else {
7de49c2aa70batagen2026-10-16 09:27 UTC240
        destroy();
7de49c2aa70batagen2026-10-16 09:27 UTC241
        return Err(Error::UnsupportedDmabuf(format));
7de49c2aa70batagen2026-10-16 09:27 UTC242
    };
7de49c2aa70batagen2026-10-16 09:27 UTC243
    let raw = owned.into_raw_fd();
7de49c2aa70batagen2026-10-16 09:27 UTC244
    let mut import = vk::ImportMemoryFdInfoKHR::default()
7de49c2aa70batagen2026-10-16 09:27 UTC245
        .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT)
7de49c2aa70batagen2026-10-16 09:27 UTC246
        .fd(raw);
7de49c2aa70batagen2026-10-16 09:27 UTC247
    let mut dedicated = vk::MemoryDedicatedAllocateInfo::default().image(image);
7de49c2aa70batagen2026-10-16 09:27 UTC248
    let alloc = vk::MemoryAllocateInfo::default()
7de49c2aa70batagen2026-10-16 09:27 UTC249
        .allocation_size(requirements.size)
7de49c2aa70batagen2026-10-16 09:27 UTC250
        .memory_type_index(type_index)
7de49c2aa70batagen2026-10-16 09:27 UTC251
        .push_next(&mut import)
7de49c2aa70batagen2026-10-16 09:27 UTC252
        .push_next(&mut dedicated);
7de49c2aa70batagen2026-10-16 09:27 UTC253
    let memory = match unsafe { d.allocate_memory(&alloc, None) } {
7de49c2aa70batagen2026-10-16 09:27 UTC254
        Ok(m) => m,
7de49c2aa70batagen2026-10-16 09:27 UTC255
        Err(e) => {
35d6f20f8eb6atagen2026-10-17 05:07 UTC256
            // SAFETY: a failed import leaves the fd with us, per
35d6f20f8eb6atagen2026-10-17 05:07 UTC257
            // VK_KHR_external_memory_fd.
7de49c2aa70batagen2026-10-16 09:27 UTC258
            drop(unsafe { OwnedFd::from_raw_fd(raw) });
7de49c2aa70batagen2026-10-16 09:27 UTC259
            destroy();
7de49c2aa70batagen2026-10-16 09:27 UTC260
            return Err(e.into());
7de49c2aa70batagen2026-10-16 09:27 UTC261
        }
7de49c2aa70batagen2026-10-16 09:27 UTC262
    };
7de49c2aa70batagen2026-10-16 09:27 UTC263
    ImageInner::finish(
7de49c2aa70batagen2026-10-16 09:27 UTC264
        shared,
7de49c2aa70batagen2026-10-16 09:27 UTC265
        image,
7de49c2aa70batagen2026-10-16 09:27 UTC266
        Memory::Imported(memory),
7de49c2aa70batagen2026-10-16 09:27 UTC267
        memory,
7de49c2aa70batagen2026-10-16 09:27 UTC268
        0,
7de49c2aa70batagen2026-10-16 09:27 UTC269
        format.code,
7de49c2aa70batagen2026-10-16 09:27 UTC270
        size.0,
7de49c2aa70batagen2026-10-16 09:27 UTC271
        size.1,
f0e45b059808atagen2026-10-19 07:34 UTC272
        usage,
7de49c2aa70batagen2026-10-16 09:27 UTC273
        true,
7de49c2aa70batagen2026-10-16 09:27 UTC274
    )
7de49c2aa70batagen2026-10-16 09:27 UTC275
}
7de49c2aa70batagen2026-10-16 09:27 UTC276
7de49c2aa70batagen2026-10-16 09:27 UTC277
/// Allocates a dmabuf the device can render into, picking among `modifiers`.
7de49c2aa70batagen2026-10-16 09:27 UTC278
pub(crate) fn export(
7de49c2aa70batagen2026-10-16 09:27 UTC279
    shared: &Arc<Shared>,
7de49c2aa70batagen2026-10-16 09:27 UTC280
    caps: &DmabufCaps,
7de49c2aa70batagen2026-10-16 09:27 UTC281
    fourcc: Fourcc,
7de49c2aa70batagen2026-10-16 09:27 UTC282
    size: (u32, u32),
7de49c2aa70batagen2026-10-16 09:27 UTC283
    modifiers: &[Modifier],
7de49c2aa70batagen2026-10-16 09:27 UTC284
) -> Result<Dmabuf, Error> {
7de49c2aa70batagen2026-10-16 09:27 UTC285
    let ext = shared
7de49c2aa70batagen2026-10-16 09:27 UTC286
        .device
7de49c2aa70batagen2026-10-16 09:27 UTC287
        .dmabuf
7de49c2aa70batagen2026-10-16 09:27 UTC288
        .as_ref()
7de49c2aa70batagen2026-10-16 09:27 UTC289
        .ok_or(Error::DmabufUnsupported)?;
7de49c2aa70batagen2026-10-16 09:27 UTC290
    let allowed: Vec<u64> = modifiers
7de49c2aa70batagen2026-10-16 09:27 UTC291
        .iter()
7de49c2aa70batagen2026-10-16 09:27 UTC292
        .filter(|&&modifier| {
7de49c2aa70batagen2026-10-16 09:27 UTC293
            caps.render.contains(&Format {
7de49c2aa70batagen2026-10-16 09:27 UTC294
                code: fourcc,
7de49c2aa70batagen2026-10-16 09:27 UTC295
                modifier,
7de49c2aa70batagen2026-10-16 09:27 UTC296
            })
7de49c2aa70batagen2026-10-16 09:27 UTC297
        })
7de49c2aa70batagen2026-10-16 09:27 UTC298
        .map(|&m| u64::from(m))
7de49c2aa70batagen2026-10-16 09:27 UTC299
        .collect();
7de49c2aa70batagen2026-10-16 09:27 UTC300
    if allowed.is_empty() {
7de49c2aa70batagen2026-10-16 09:27 UTC301
        return Err(Error::UnsupportedFormat(fourcc));
7de49c2aa70batagen2026-10-16 09:27 UTC302
    }
7de49c2aa70batagen2026-10-16 09:27 UTC303
    let d = &shared.device.device;
7de49c2aa70batagen2026-10-16 09:27 UTC304
    let mut list =
7de49c2aa70batagen2026-10-16 09:27 UTC305
        vk::ImageDrmFormatModifierListCreateInfoEXT::default().drm_format_modifiers(&allowed);
7de49c2aa70batagen2026-10-16 09:27 UTC306
    let mut external = vk::ExternalMemoryImageCreateInfo::default()
7de49c2aa70batagen2026-10-16 09:27 UTC307
        .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
7de49c2aa70batagen2026-10-16 09:27 UTC308
    let info = image_info(fourcc, size, RENDER_USAGE)?
7de49c2aa70batagen2026-10-16 09:27 UTC309
        .push_next(&mut external)
7de49c2aa70batagen2026-10-16 09:27 UTC310
        .push_next(&mut list);
7de49c2aa70batagen2026-10-16 09:27 UTC311
    let image = unsafe { d.create_image(&info, None)? };
7de49c2aa70batagen2026-10-16 09:27 UTC312
    let result = (|| -> Result<Dmabuf, Error> {
7de49c2aa70batagen2026-10-16 09:27 UTC313
        let requirements = unsafe { d.get_image_memory_requirements(image) };
7de49c2aa70batagen2026-10-16 09:27 UTC314
        let type_index = memory_type(
7de49c2aa70batagen2026-10-16 09:27 UTC315
            shared,
7de49c2aa70batagen2026-10-16 09:27 UTC316
            requirements.memory_type_bits,
7de49c2aa70batagen2026-10-16 09:27 UTC317
            vk::MemoryPropertyFlags::DEVICE_LOCAL,
7de49c2aa70batagen2026-10-16 09:27 UTC318
        )
7de49c2aa70batagen2026-10-16 09:27 UTC319
        .ok_or(Error::UnsupportedFormat(fourcc))?;
7de49c2aa70batagen2026-10-16 09:27 UTC320
        let mut export = vk::ExportMemoryAllocateInfo::default()
7de49c2aa70batagen2026-10-16 09:27 UTC321
            .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
7de49c2aa70batagen2026-10-16 09:27 UTC322
        let mut dedicated = vk::MemoryDedicatedAllocateInfo::default().image(image);
7de49c2aa70batagen2026-10-16 09:27 UTC323
        let alloc = vk::MemoryAllocateInfo::default()
7de49c2aa70batagen2026-10-16 09:27 UTC324
            .allocation_size(requirements.size)
7de49c2aa70batagen2026-10-16 09:27 UTC325
            .memory_type_index(type_index)
7de49c2aa70batagen2026-10-16 09:27 UTC326
            .push_next(&mut export)
7de49c2aa70batagen2026-10-16 09:27 UTC327
            .push_next(&mut dedicated);
7de49c2aa70batagen2026-10-16 09:27 UTC328
        let memory = unsafe { d.allocate_memory(&alloc, None)? };
7de49c2aa70batagen2026-10-16 09:27 UTC329
        let exported = (|| -> Result<Dmabuf, Error> {
7de49c2aa70batagen2026-10-16 09:27 UTC330
            unsafe { d.bind_image_memory(image, memory, 0)? };
7de49c2aa70batagen2026-10-16 09:27 UTC331
            let raw = unsafe {
7de49c2aa70batagen2026-10-16 09:27 UTC332
                ext.memory_fd.get_memory_fd(
7de49c2aa70batagen2026-10-16 09:27 UTC333
                    &vk::MemoryGetFdInfoKHR::default()
7de49c2aa70batagen2026-10-16 09:27 UTC334
                        .memory(memory)
7de49c2aa70batagen2026-10-16 09:27 UTC335
                        .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT),
7de49c2aa70batagen2026-10-16 09:27 UTC336
                )?
7de49c2aa70batagen2026-10-16 09:27 UTC337
            };
35d6f20f8eb6atagen2026-10-17 05:07 UTC338
            // SAFETY: vkGetMemoryFdKHR hands the caller a new fd to own.
7de49c2aa70batagen2026-10-16 09:27 UTC339
            let fd = unsafe { OwnedFd::from_raw_fd(raw) };
7de49c2aa70batagen2026-10-16 09:27 UTC340
            let mut props = vk::ImageDrmFormatModifierPropertiesEXT::default();
7de49c2aa70batagen2026-10-16 09:27 UTC341
            unsafe {
7de49c2aa70batagen2026-10-16 09:27 UTC342
                ext.modifier
7de49c2aa70batagen2026-10-16 09:27 UTC343
                    .get_image_drm_format_modifier_properties(image, &mut props)?
7de49c2aa70batagen2026-10-16 09:27 UTC344
            };
7de49c2aa70batagen2026-10-16 09:27 UTC345
            let layout = unsafe {
7de49c2aa70batagen2026-10-16 09:27 UTC346
                d.get_image_subresource_layout(
7de49c2aa70batagen2026-10-16 09:27 UTC347
                    image,
7de49c2aa70batagen2026-10-16 09:27 UTC348
                    vk::ImageSubresource::default()
7de49c2aa70batagen2026-10-16 09:27 UTC349
                        .aspect_mask(vk::ImageAspectFlags::MEMORY_PLANE_0_EXT),
7de49c2aa70batagen2026-10-16 09:27 UTC350
                )
7de49c2aa70batagen2026-10-16 09:27 UTC351
            };
7de49c2aa70batagen2026-10-16 09:27 UTC352
            let mut builder = Dmabuf::builder(
7de49c2aa70batagen2026-10-16 09:27 UTC353
                (size.0 as i32, size.1 as i32),
7de49c2aa70batagen2026-10-16 09:27 UTC354
                fourcc,
7de49c2aa70batagen2026-10-16 09:27 UTC355
                Modifier::from(props.drm_format_modifier),
7de49c2aa70batagen2026-10-16 09:27 UTC356
                DmabufFlags::empty(),
7de49c2aa70batagen2026-10-16 09:27 UTC357
            );
7de49c2aa70batagen2026-10-16 09:27 UTC358
            builder.add_plane(fd, layout.offset as u32, layout.row_pitch as u32);
7de49c2aa70batagen2026-10-16 09:27 UTC359
            builder.build().ok_or(Error::UnsupportedFormat(fourcc))
7de49c2aa70batagen2026-10-16 09:27 UTC360
        })();
7de49c2aa70batagen2026-10-16 09:27 UTC361
        unsafe { d.free_memory(memory, None) };
7de49c2aa70batagen2026-10-16 09:27 UTC362
        exported
7de49c2aa70batagen2026-10-16 09:27 UTC363
    })();
7de49c2aa70batagen2026-10-16 09:27 UTC364
    unsafe { d.destroy_image(image, None) };
7de49c2aa70batagen2026-10-16 09:27 UTC365
    result
7de49c2aa70batagen2026-10-16 09:27 UTC366
}
7de49c2aa70batagen2026-10-16 09:27 UTC367
7de49c2aa70batagen2026-10-16 09:27 UTC368
/// Allocates render-capable dmabufs, for swapchains.
7de49c2aa70batagen2026-10-16 09:27 UTC369
#[derive(Clone, Debug)]
7de49c2aa70batagen2026-10-16 09:27 UTC370
pub struct VulkanAllocator {
7de49c2aa70batagen2026-10-16 09:27 UTC371
    pub(crate) shared: Arc<Shared>,
7de49c2aa70batagen2026-10-16 09:27 UTC372
    pub(crate) caps: Arc<DmabufCaps>,
7de49c2aa70batagen2026-10-16 09:27 UTC373
}
7de49c2aa70batagen2026-10-16 09:27 UTC374
7de49c2aa70batagen2026-10-16 09:27 UTC375
impl Allocator for VulkanAllocator {
7de49c2aa70batagen2026-10-16 09:27 UTC376
    type Buffer = Dmabuf;
7de49c2aa70batagen2026-10-16 09:27 UTC377
    type Error = Error;
7de49c2aa70batagen2026-10-16 09:27 UTC378
7de49c2aa70batagen2026-10-16 09:27 UTC379
    fn create_buffer(
7de49c2aa70batagen2026-10-16 09:27 UTC380
        &mut self,
7de49c2aa70batagen2026-10-16 09:27 UTC381
        width: u32,
7de49c2aa70batagen2026-10-16 09:27 UTC382
        height: u32,
7de49c2aa70batagen2026-10-16 09:27 UTC383
        fourcc: Fourcc,
7de49c2aa70batagen2026-10-16 09:27 UTC384
        modifiers: &[Modifier],
7de49c2aa70batagen2026-10-16 09:27 UTC385
    ) -> Result<Dmabuf, Error> {
7de49c2aa70batagen2026-10-16 09:27 UTC386
        export(&self.shared, &self.caps, fourcc, (width, height), modifiers)
7de49c2aa70batagen2026-10-16 09:27 UTC387
    }
7de49c2aa70batagen2026-10-16 09:27 UTC388
}
7de49c2aa70batagen2026-10-16 09:27 UTC389
7de49c2aa70batagen2026-10-16 09:27 UTC390
impl std::fmt::Debug for Shared {
7de49c2aa70batagen2026-10-16 09:27 UTC391
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7de49c2aa70batagen2026-10-16 09:27 UTC392
        f.debug_struct("Shared")
7de49c2aa70batagen2026-10-16 09:27 UTC393
            .field("device", &self.device.name)
7de49c2aa70batagen2026-10-16 09:27 UTC394
            .finish()
7de49c2aa70batagen2026-10-16 09:27 UTC395
    }
7de49c2aa70batagen2026-10-16 09:27 UTC396
}