7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 1 | use crate::Error; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 2 | use crate::device::Shared; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 3 | use crate::format::{SUPPORTED, vk_format}; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 4 | use crate::image::{ImageInner, Memory}; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 5 | use ash::vk; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 6 | use smithay::backend::allocator::dmabuf::{Dmabuf, DmabufFlags}; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 7 | use smithay::backend::allocator::format::FormatSet; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 8 | use smithay::backend::allocator::{Allocator, Buffer, Format, Fourcc, Modifier}; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 9 | use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd, OwnedFd}; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 10 | use std::sync::Arc; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 11 | |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 12 | /// Which (format, modifier) pairs the device can import for sampling and |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 13 | /// render into, queried once at startup. |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 14 | #[derive(Debug, Default)] |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 15 | pub(crate) struct DmabufCaps { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 16 | pub sample: FormatSet, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 17 | pub render: FormatSet, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 18 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 19 | |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 20 | pub(crate) const RENDER_USAGE: vk::ImageUsageFlags = vk::ImageUsageFlags::from_raw( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 21 | vk::ImageUsageFlags::COLOR_ATTACHMENT.as_raw() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 22 | | vk::ImageUsageFlags::SAMPLED.as_raw() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 23 | | vk::ImageUsageFlags::TRANSFER_SRC.as_raw(), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 24 | ); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 25 | pub(crate) const SAMPLE_USAGE: vk::ImageUsageFlags = vk::ImageUsageFlags::SAMPLED; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 26 | |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 27 | impl DmabufCaps { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 28 | pub fn query(shared: &Shared) -> Self { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 29 | if shared.device.dmabuf.is_none() { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 30 | return Self::default(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 31 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 32 | let (mut sample, mut render) = (Vec::new(), Vec::new()); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 33 | for fourcc in SUPPORTED { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 34 | let Some(fmt) = vk_format(fourcc) else { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 35 | continue; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 36 | }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 37 | for props in modifier_properties(shared, fmt.format) { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 38 | if props.drm_format_modifier_plane_count != 1 { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 39 | continue; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 40 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 41 | let features = props.drm_format_modifier_tiling_features; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 42 | let format = Format { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 43 | code: fourcc, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 44 | modifier: Modifier::from(props.drm_format_modifier), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 45 | }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 46 | let supports = |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 47 | |usage| external_support(shared, fmt.format, props.drm_format_modifier, usage); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 48 | if features.contains(vk::FormatFeatureFlags::SAMPLED_IMAGE) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 49 | && supports(SAMPLE_USAGE).importable |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 50 | { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 51 | sample.push(format); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 52 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 53 | let renderable = vk::FormatFeatureFlags::COLOR_ATTACHMENT |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 54 | | vk::FormatFeatureFlags::COLOR_ATTACHMENT_BLEND; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 55 | let s = supports(RENDER_USAGE); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 56 | if features.contains(renderable) && s.importable && s.exportable { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 57 | render.push(format); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 58 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 59 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 60 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 61 | Self { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 62 | sample: sample.into_iter().collect(), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 63 | render: render.into_iter().collect(), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 64 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 65 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 66 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 67 | |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 68 | fn modifier_properties( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 69 | shared: &Shared, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 70 | format: vk::Format, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 71 | ) -> Vec<vk::DrmFormatModifierPropertiesEXT> { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 72 | let dev = &shared.device; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 73 | let mut list = vk::DrmFormatModifierPropertiesListEXT::default(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 74 | let mut props = vk::FormatProperties2::default().push_next(&mut list); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 75 | unsafe { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 76 | dev.instance |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 77 | .get_physical_device_format_properties2(dev.physical, format, &mut props) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 78 | }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 79 | let count = list.drm_format_modifier_count as usize; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 80 | let mut out = vec![vk::DrmFormatModifierPropertiesEXT::default(); count]; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 81 | let mut list = |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 82 | vk::DrmFormatModifierPropertiesListEXT::default().drm_format_modifier_properties(&mut out); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 83 | let mut props = vk::FormatProperties2::default().push_next(&mut list); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 84 | unsafe { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 85 | dev.instance |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 86 | .get_physical_device_format_properties2(dev.physical, format, &mut props) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 87 | }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 88 | out |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 89 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 90 | |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 91 | struct External { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 92 | importable: bool, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 93 | exportable: bool, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 94 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 95 | |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 96 | fn external_support( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 97 | shared: &Shared, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 98 | format: vk::Format, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 99 | modifier: u64, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 100 | usage: vk::ImageUsageFlags, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 101 | ) -> External { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 102 | let dev = &shared.device; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 103 | let mut modifier_info = vk::PhysicalDeviceImageDrmFormatModifierInfoEXT::default() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 104 | .drm_format_modifier(modifier) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 105 | .sharing_mode(vk::SharingMode::EXCLUSIVE); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 106 | let mut external_info = vk::PhysicalDeviceExternalImageFormatInfo::default() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 107 | .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 108 | let info = vk::PhysicalDeviceImageFormatInfo2::default() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 109 | .format(format) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 110 | .ty(vk::ImageType::TYPE_2D) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 111 | .tiling(vk::ImageTiling::DRM_FORMAT_MODIFIER_EXT) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 112 | .usage(usage) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 113 | .push_next(&mut external_info) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 114 | .push_next(&mut modifier_info); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 115 | let mut external_props = vk::ExternalImageFormatProperties::default(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 116 | let mut props = vk::ImageFormatProperties2::default().push_next(&mut external_props); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 117 | let ok = unsafe { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 118 | dev.instance |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 119 | .get_physical_device_image_format_properties2(dev.physical, &info, &mut props) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 120 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 121 | .is_ok(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 122 | let features = external_props |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 123 | .external_memory_properties |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 124 | .external_memory_features; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 125 | External { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 126 | importable: ok && features.contains(vk::ExternalMemoryFeatureFlags::IMPORTABLE), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 127 | exportable: ok && features.contains(vk::ExternalMemoryFeatureFlags::EXPORTABLE), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 128 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 129 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 130 | |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 131 | fn memory_type(shared: &Shared, bits: u32, prefer: vk::MemoryPropertyFlags) -> Option<u32> { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 132 | let props = unsafe { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 133 | shared |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 134 | .device |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 135 | .instance |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 136 | .get_physical_device_memory_properties(shared.device.physical) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 137 | }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 138 | let types = &props.memory_types[..props.memory_type_count as usize]; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 139 | let allowed = |i: usize| bits & (1 << i) != 0; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 140 | (0..types.len()) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 141 | .find(|&i| allowed(i) && types[i].property_flags.contains(prefer)) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 142 | .or_else(|| (0..types.len()).find(|&i| allowed(i))) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 143 | .map(|i| i as u32) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 144 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 145 | |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 146 | fn image_info<'a>( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 147 | fourcc: Fourcc, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 148 | size: (u32, u32), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 149 | usage: vk::ImageUsageFlags, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 150 | ) -> Result<vk::ImageCreateInfo<'a>, Error> { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 151 | let fmt = vk_format(fourcc).ok_or(Error::UnsupportedFormat(fourcc))?; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 152 | Ok(vk::ImageCreateInfo::default() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 153 | .image_type(vk::ImageType::TYPE_2D) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 154 | .format(fmt.format) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 155 | .extent(vk::Extent3D { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 156 | width: size.0, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 157 | height: size.1, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 158 | depth: 1, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 159 | }) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 160 | .mip_levels(1) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 161 | .array_layers(1) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 162 | .samples(vk::SampleCountFlags::TYPE_1) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 163 | .tiling(vk::ImageTiling::DRM_FORMAT_MODIFIER_EXT) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 164 | .usage(usage) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 165 | .sharing_mode(vk::SharingMode::EXCLUSIVE) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 166 | .initial_layout(vk::ImageLayout::UNDEFINED)) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 167 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 168 | |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 169 | /// Imports a single-plane dmabuf as an image, without copying. |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 170 | pub(crate) fn import( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 171 | shared: &Arc<Shared>, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 172 | caps: &DmabufCaps, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 173 | dmabuf: &Dmabuf, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 174 | usage: vk::ImageUsageFlags, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 175 | ) -> Result<Arc<ImageInner>, Error> { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 176 | let ext = shared |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 177 | .device |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 178 | .dmabuf |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 179 | .as_ref() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 180 | .ok_or(Error::DmabufUnsupported)?; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 181 | let format = dmabuf.format(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 182 | let set = if usage.contains(vk::ImageUsageFlags::COLOR_ATTACHMENT) { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 183 | &caps.render |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 184 | } else { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 185 | &caps.sample |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 186 | }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 187 | if dmabuf.num_planes() != 1 || !set.contains(&format) { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 188 | return Err(Error::UnsupportedDmabuf(format)); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 189 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 190 | let (Some(fd), Some(offset), Some(stride)) = ( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 191 | dmabuf.handles().next(), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 192 | dmabuf.offsets().next(), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 193 | dmabuf.strides().next(), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 194 | ) else { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 195 | return Err(Error::UnsupportedDmabuf(format)); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 196 | }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 197 | let size = (dmabuf.width(), dmabuf.height()); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 198 | let d = &shared.device.device; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 199 | let layouts = [vk::SubresourceLayout { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 200 | offset: u64::from(offset), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 201 | size: 0, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 202 | row_pitch: u64::from(stride), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 203 | array_pitch: 0, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 204 | depth_pitch: 0, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 205 | }]; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 206 | let mut explicit = vk::ImageDrmFormatModifierExplicitCreateInfoEXT::default() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 207 | .drm_format_modifier(u64::from(format.modifier)) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 208 | .plane_layouts(&layouts); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 209 | let mut external = vk::ExternalMemoryImageCreateInfo::default() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 210 | .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 211 | let info = image_info(format.code, size, usage)? |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 212 | .push_next(&mut external) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 213 | .push_next(&mut explicit); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 214 | let image = unsafe { d.create_image(&info, None)? }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 215 | let destroy = || unsafe { d.destroy_image(image, None) }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 216 | let owned = match fd.try_clone_to_owned() { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 217 | Ok(o) => o, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 218 | Err(_) => { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 219 | destroy(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 220 | return Err(Error::UnsupportedDmabuf(format)); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 221 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 222 | }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 223 | let mut fd_props = vk::MemoryFdPropertiesKHR::default(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 224 | if let Err(e) = unsafe { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 225 | ext.memory_fd.get_memory_fd_properties( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 226 | vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 227 | owned.as_raw_fd(), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 228 | &mut fd_props, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 229 | ) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 230 | } { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 231 | destroy(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 232 | return Err(e.into()); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 233 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 234 | let requirements = unsafe { d.get_image_memory_requirements(image) }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 235 | let Some(type_index) = memory_type( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 236 | shared, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 237 | requirements.memory_type_bits & fd_props.memory_type_bits, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 238 | vk::MemoryPropertyFlags::empty(), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 239 | ) else { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 240 | destroy(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 241 | return Err(Error::UnsupportedDmabuf(format)); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 242 | }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 243 | let raw = owned.into_raw_fd(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 244 | let mut import = vk::ImportMemoryFdInfoKHR::default() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 245 | .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 246 | .fd(raw); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 247 | let mut dedicated = vk::MemoryDedicatedAllocateInfo::default().image(image); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 248 | let alloc = vk::MemoryAllocateInfo::default() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 249 | .allocation_size(requirements.size) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 250 | .memory_type_index(type_index) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 251 | .push_next(&mut import) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 252 | .push_next(&mut dedicated); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 253 | let memory = match unsafe { d.allocate_memory(&alloc, None) } { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 254 | Ok(m) => m, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 255 | Err(e) => { |
35d6f20f8eb6 | atagen | 2026-10-17 05:07 UTC | 256 | // SAFETY: a failed import leaves the fd with us, per |
35d6f20f8eb6 | atagen | 2026-10-17 05:07 UTC | 257 | // VK_KHR_external_memory_fd. |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 258 | drop(unsafe { OwnedFd::from_raw_fd(raw) }); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 259 | destroy(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 260 | return Err(e.into()); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 261 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 262 | }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 263 | ImageInner::finish( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 264 | shared, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 265 | image, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 266 | Memory::Imported(memory), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 267 | memory, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 268 | 0, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 269 | format.code, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 270 | size.0, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 271 | size.1, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 272 | true, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 273 | ) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 274 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 275 | |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 276 | /// Allocates a dmabuf the device can render into, picking among `modifiers`. |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 277 | pub(crate) fn export( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 278 | shared: &Arc<Shared>, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 279 | caps: &DmabufCaps, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 280 | fourcc: Fourcc, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 281 | size: (u32, u32), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 282 | modifiers: &[Modifier], |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 283 | ) -> Result<Dmabuf, Error> { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 284 | let ext = shared |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 285 | .device |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 286 | .dmabuf |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 287 | .as_ref() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 288 | .ok_or(Error::DmabufUnsupported)?; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 289 | let allowed: Vec<u64> = modifiers |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 290 | .iter() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 291 | .filter(|&&modifier| { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 292 | caps.render.contains(&Format { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 293 | code: fourcc, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 294 | modifier, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 295 | }) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 296 | }) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 297 | .map(|&m| u64::from(m)) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 298 | .collect(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 299 | if allowed.is_empty() { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 300 | return Err(Error::UnsupportedFormat(fourcc)); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 301 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 302 | let d = &shared.device.device; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 303 | let mut list = |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 304 | vk::ImageDrmFormatModifierListCreateInfoEXT::default().drm_format_modifiers(&allowed); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 305 | let mut external = vk::ExternalMemoryImageCreateInfo::default() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 306 | .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 307 | let info = image_info(fourcc, size, RENDER_USAGE)? |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 308 | .push_next(&mut external) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 309 | .push_next(&mut list); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 310 | let image = unsafe { d.create_image(&info, None)? }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 311 | let result = (|| -> Result<Dmabuf, Error> { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 312 | let requirements = unsafe { d.get_image_memory_requirements(image) }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 313 | let type_index = memory_type( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 314 | shared, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 315 | requirements.memory_type_bits, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 316 | vk::MemoryPropertyFlags::DEVICE_LOCAL, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 317 | ) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 318 | .ok_or(Error::UnsupportedFormat(fourcc))?; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 319 | let mut export = vk::ExportMemoryAllocateInfo::default() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 320 | .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 321 | let mut dedicated = vk::MemoryDedicatedAllocateInfo::default().image(image); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 322 | let alloc = vk::MemoryAllocateInfo::default() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 323 | .allocation_size(requirements.size) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 324 | .memory_type_index(type_index) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 325 | .push_next(&mut export) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 326 | .push_next(&mut dedicated); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 327 | let memory = unsafe { d.allocate_memory(&alloc, None)? }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 328 | let exported = (|| -> Result<Dmabuf, Error> { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 329 | unsafe { d.bind_image_memory(image, memory, 0)? }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 330 | let raw = unsafe { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 331 | ext.memory_fd.get_memory_fd( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 332 | &vk::MemoryGetFdInfoKHR::default() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 333 | .memory(memory) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 334 | .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 335 | )? |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 336 | }; |
35d6f20f8eb6 | atagen | 2026-10-17 05:07 UTC | 337 | // SAFETY: vkGetMemoryFdKHR hands the caller a new fd to own. |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 338 | let fd = unsafe { OwnedFd::from_raw_fd(raw) }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 339 | let mut props = vk::ImageDrmFormatModifierPropertiesEXT::default(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 340 | unsafe { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 341 | ext.modifier |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 342 | .get_image_drm_format_modifier_properties(image, &mut props)? |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 343 | }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 344 | let layout = unsafe { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 345 | d.get_image_subresource_layout( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 346 | image, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 347 | vk::ImageSubresource::default() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 348 | .aspect_mask(vk::ImageAspectFlags::MEMORY_PLANE_0_EXT), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 349 | ) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 350 | }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 351 | let mut builder = Dmabuf::builder( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 352 | (size.0 as i32, size.1 as i32), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 353 | fourcc, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 354 | Modifier::from(props.drm_format_modifier), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 355 | DmabufFlags::empty(), |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 356 | ); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 357 | builder.add_plane(fd, layout.offset as u32, layout.row_pitch as u32); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 358 | builder.build().ok_or(Error::UnsupportedFormat(fourcc)) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 359 | })(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 360 | unsafe { d.free_memory(memory, None) }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 361 | exported |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 362 | })(); |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 363 | unsafe { d.destroy_image(image, None) }; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 364 | result |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 365 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 366 | |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 367 | /// Allocates render-capable dmabufs, for swapchains. |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 368 | #[derive(Clone, Debug)] |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 369 | pub struct VulkanAllocator { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 370 | pub(crate) shared: Arc<Shared>, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 371 | pub(crate) caps: Arc<DmabufCaps>, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 372 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 373 | |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 374 | impl Allocator for VulkanAllocator { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 375 | type Buffer = Dmabuf; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 376 | type Error = Error; |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 377 | |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 378 | fn create_buffer( |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 379 | &mut self, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 380 | width: u32, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 381 | height: u32, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 382 | fourcc: Fourcc, |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 383 | modifiers: &[Modifier], |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 384 | ) -> Result<Dmabuf, Error> { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 385 | export(&self.shared, &self.caps, fourcc, (width, height), modifiers) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 386 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 387 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 388 | |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 389 | impl std::fmt::Debug for Shared { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 390 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 391 | f.debug_struct("Shared") |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 392 | .field("device", &self.device.name) |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 393 | .finish() |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 394 | } |
7de49c2aa70b | atagen | 2026-10-16 09:27 UTC | 395 | } |