use { crate::{ format::Format, gfx_api::GfxBuffer, gfx_apis::vulkan::{VulkanError, device::VulkanDevice}, utils::oserror::OsErrorExt2, }, ash::{ Device, vk::{ self, BufferCreateInfo, BufferUsageFlags, ExternalMemoryBufferCreateInfo, ExternalMemoryHandleTypeFlags, ImportMemoryFdInfoKHR, MemoryAllocateInfo, MemoryDedicatedAllocateInfo, MemoryFdPropertiesKHR, MemoryPropertyFlags, }, }, run_on_drop::on_drop, std::{any::Any, rc::Rc}, uapi::OwnedFd, }; pub(super) const TRANSFER_QUEUE_BUFFER_ALIGNMENT: u64 = 4; pub struct VulkanDmabufBuffer { pub(super) device: Rc, pub(super) size: u64, pub(super) offset: u64, pub(super) buffer: vk::Buffer, pub(super) memory: vk::DeviceMemory, } impl VulkanDevice { pub fn create_dmabuf_buffer( self: &Rc, dmabuf: &OwnedFd, offset: u64, size: u64, format: &'static Format, ) -> Result, VulkanError> { if offset % TRANSFER_QUEUE_BUFFER_ALIGNMENT != 0 || offset % format.bpp as u64 != 0 { return Err(VulkanError::DmaBufBufferOffsetAlignment); } let mut memory_fd_properties = MemoryFdPropertiesKHR::default(); unsafe { self.external_memory_fd .get_memory_fd_properties( ExternalMemoryHandleTypeFlags::DMA_BUF_EXT, dmabuf.raw(), &mut memory_fd_properties, ) .map_err(VulkanError::MemoryFdProperties)? } let buffer = { let mut external_info = ExternalMemoryBufferCreateInfo::default() .handle_types(ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); let create_info = BufferCreateInfo::default() .size(size) .usage(BufferUsageFlags::TRANSFER_SRC) .push_next(&mut external_info); unsafe { self.device .create_buffer(&create_info, None) .map_err(VulkanError::CreateBuffer)? } }; let destroy_buffer = on_drop(|| unsafe { self.device.destroy_buffer(buffer, None) }); let requirements = unsafe { self.device.get_buffer_memory_requirements(buffer) }; let memory_type = self.find_memory_type( MemoryPropertyFlags::HOST_VISIBLE, requirements.memory_type_bits & memory_fd_properties.memory_type_bits, ); let Some(memory_type) = memory_type else { return Err(VulkanError::MemoryType); }; let fd = uapi::fcntl_dupfd_cloexec(dmabuf.raw(), 0).map_os_err(VulkanError::Dupfd)?; let memory = { let mut dedicated = MemoryDedicatedAllocateInfo::default().buffer(buffer); let mut import_info = ImportMemoryFdInfoKHR::default() .fd(fd.raw()) .handle_type(ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); let allocate_info = MemoryAllocateInfo::default() .allocation_size(requirements.size) .memory_type_index(memory_type) .push_next(&mut import_info) .push_next(&mut dedicated); unsafe { self.device .allocate_memory(&allocate_info, None) .map_err(VulkanError::AllocateMemory)? } }; fd.unwrap(); let free_memory = on_drop(|| unsafe { self.device.free_memory(memory, None) }); unsafe { self.device .bind_buffer_memory(buffer, memory, 0) .map_err(VulkanError::BindBufferMemory)?; } free_memory.forget(); destroy_buffer.forget(); Ok(Rc::new(VulkanDmabufBuffer { device: self.clone(), size, offset, buffer, memory, })) } } impl Drop for VulkanDmabufBuffer { fn drop(&mut self) { unsafe { self.device.device.free_memory(self.memory, None); self.device.device.destroy_buffer(self.buffer, None); } } } impl VulkanDmabufBuffer { fn assert_device(&self, device: &Device) { assert_eq!( self.device.device.handle(), device.handle(), "Mixed vulkan device use" ); } } impl GfxBuffer for VulkanDmabufBuffer {} impl dyn GfxBuffer { pub(super) fn into_vk(self: Rc, device: &Device) -> Rc { let buffer: Rc = (self as Rc) .downcast() .expect("Non-vulkan buffer passed into vulkan"); buffer.assert_device(device); buffer } }