1
0
Fork 0
forked from wry/wry
wry/src/gfx_apis/vulkan/dmabuf_buffer.rs
2026-04-02 19:00:42 +02:00

139 lines
4.7 KiB
Rust

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<VulkanDevice>,
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<Self>,
dmabuf: &OwnedFd,
offset: u64,
size: u64,
format: &'static Format,
) -> Result<Rc<VulkanDmabufBuffer>, 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<Self>, device: &Device) -> Rc<VulkanDmabufBuffer> {
let buffer: Rc<VulkanDmabufBuffer> = (self as Rc<dyn Any>)
.downcast()
.expect("Non-vulkan buffer passed into vulkan");
buffer.assert_device(device);
buffer
}
}