Merge pull request #248 from mahkoh/jorth/vulkan-allocator
vulkan: create a vulkan allocator
This commit is contained in:
commit
940aecab96
15 changed files with 984 additions and 101 deletions
|
|
@ -1,8 +1,9 @@
|
|||
use {
|
||||
crate::{
|
||||
allocator::{Allocator, AllocatorError, BO_USE_LINEAR, BO_USE_RENDERING},
|
||||
allocator::{Allocator, AllocatorError, BufferUsage, MappedBuffer},
|
||||
cli::{GlobalArgs, ScreenshotArgs, ScreenshotFormat},
|
||||
format::XRGB8888,
|
||||
gfx_apis,
|
||||
tools::tool_client::{with_tool_client, Handle, ToolClient},
|
||||
udmabuf::{Udmabuf, UdmabufError},
|
||||
utils::{errorfmt::ErrorFmt, queue::AsyncQueue, windows::WindowsExt},
|
||||
|
|
@ -138,6 +139,21 @@ pub enum ScreenshotError {
|
|||
ImportDmabuf(#[source] AllocatorError),
|
||||
#[error("Could not map a dmabuf")]
|
||||
MapDmabuf(#[source] AllocatorError),
|
||||
#[error("Could not create a vulkan allocator")]
|
||||
CreateVulkanAllocator(#[source] AllocatorError),
|
||||
#[error("Could not map the dmabuf with any allocator")]
|
||||
MapDmabufAny,
|
||||
}
|
||||
|
||||
fn map(
|
||||
allocator: Rc<dyn Allocator>,
|
||||
buf: &DmaBuf,
|
||||
) -> Result<Box<dyn MappedBuffer>, ScreenshotError> {
|
||||
let bo = allocator
|
||||
.import_dmabuf(buf, BufferUsage::none())
|
||||
.map_err(ScreenshotError::ImportDmabuf)?;
|
||||
let bo_map = bo.map_read().map_err(ScreenshotError::MapDmabuf)?;
|
||||
Ok(bo_map)
|
||||
}
|
||||
|
||||
pub fn buf_to_bytes(
|
||||
|
|
@ -145,21 +161,55 @@ pub fn buf_to_bytes(
|
|||
buf: &DmaBuf,
|
||||
format: ScreenshotFormat,
|
||||
) -> Result<Vec<u8>, ScreenshotError> {
|
||||
let allocator: Rc<dyn Allocator> = match drm_dev {
|
||||
match drm_dev {
|
||||
None => {}
|
||||
Some(_) => {}
|
||||
}
|
||||
let mut allocators =
|
||||
Vec::<Box<dyn FnOnce() -> Result<Rc<dyn Allocator>, ScreenshotError>>>::new();
|
||||
match drm_dev {
|
||||
Some(drm_dev) => {
|
||||
let drm = Drm::reopen(drm_dev.raw(), false).map_err(ScreenshotError::OpenDrmDevice)?;
|
||||
GbmDevice::new(&drm)
|
||||
.map(Rc::new)
|
||||
.map_err(ScreenshotError::CreateGbmDevice)?
|
||||
let drm = || Drm::reopen(drm_dev.raw(), false).map_err(ScreenshotError::OpenDrmDevice);
|
||||
let gbm = Box::new(move || {
|
||||
GbmDevice::new(&drm()?)
|
||||
.map(|d| Rc::new(d) as _)
|
||||
.map_err(ScreenshotError::CreateGbmDevice)
|
||||
});
|
||||
let vulkan = Box::new(move || {
|
||||
gfx_apis::create_vulkan_allocator(&drm()?)
|
||||
.map_err(ScreenshotError::CreateVulkanAllocator)
|
||||
});
|
||||
allocators.push(vulkan);
|
||||
allocators.push(gbm);
|
||||
}
|
||||
None => Udmabuf::new()
|
||||
.map(Rc::new)
|
||||
.map_err(ScreenshotError::CreateUdmabuf)?,
|
||||
None => {
|
||||
let udmabuf = Box::new(|| {
|
||||
Udmabuf::new()
|
||||
.map(|u| Rc::new(u) as _)
|
||||
.map_err(ScreenshotError::CreateUdmabuf)
|
||||
});
|
||||
allocators.push(udmabuf);
|
||||
}
|
||||
}
|
||||
let bo_map = 'create_bo_map: {
|
||||
for allocator in allocators {
|
||||
let allocator = match allocator() {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
log::error!("Could not create allocator: {}", ErrorFmt(e));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
match map(allocator, buf) {
|
||||
Ok(m) => break 'create_bo_map m,
|
||||
Err(e) => {
|
||||
log::error!("Could not map dmabuf: {}", ErrorFmt(e));
|
||||
continue;
|
||||
}
|
||||
};
|
||||
}
|
||||
return Err(ScreenshotError::MapDmabufAny);
|
||||
};
|
||||
let bo = allocator
|
||||
.import_dmabuf(buf, BO_USE_LINEAR | BO_USE_RENDERING)
|
||||
.map_err(ScreenshotError::ImportDmabuf)?;
|
||||
let bo_map = bo.map_read().map_err(ScreenshotError::MapDmabuf)?;
|
||||
let data = unsafe { bo_map.data() };
|
||||
if format == ScreenshotFormat::Qoi {
|
||||
return Ok(xrgb8888_encode_qoi(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
pub use vulkan::create_vulkan_allocator;
|
||||
use {
|
||||
crate::{
|
||||
async_engine::AsyncEngine,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
mod allocator;
|
||||
mod bo_allocator;
|
||||
mod command;
|
||||
mod descriptor;
|
||||
mod device;
|
||||
|
|
@ -17,7 +18,7 @@ mod util;
|
|||
|
||||
use {
|
||||
crate::{
|
||||
allocator::Allocator,
|
||||
allocator::{Allocator, AllocatorError},
|
||||
async_engine::AsyncEngine,
|
||||
format::Format,
|
||||
gfx_api::{
|
||||
|
|
@ -39,6 +40,7 @@ use {
|
|||
ash::{vk, LoadingError},
|
||||
gpu_alloc::{AllocationError, MapError},
|
||||
jay_config::video::GfxApi,
|
||||
log::Level,
|
||||
once_cell::sync::Lazy,
|
||||
std::{
|
||||
cell::Cell,
|
||||
|
|
@ -180,6 +182,20 @@ pub enum VulkanError {
|
|||
GfxError(GfxError),
|
||||
#[error("Buffer format {0} is not supported for shm buffers in Vulkan context")]
|
||||
UnsupportedShmFormat(&'static str),
|
||||
#[error("Only BO_USE_RENDERING and BO_USE_WRITE are supported")]
|
||||
UnsupportedBufferUsage,
|
||||
#[error("None of the supplied modifiers are supported")]
|
||||
NoSupportedModifiers,
|
||||
#[error("Could not retrieve the image modifier")]
|
||||
GetModifier(#[source] vk::Result),
|
||||
#[error("Vulkan allocated the image with an invalid modifier")]
|
||||
InvalidModifier,
|
||||
#[error("Could not export the DmaBuf")]
|
||||
GetDmaBuf(#[source] vk::Result),
|
||||
#[error("Could not wait for the device to become idle")]
|
||||
WaitIdle(#[source] vk::Result),
|
||||
#[error("Could not dup a DRM device")]
|
||||
DupDrm(#[source] DrmError),
|
||||
}
|
||||
|
||||
impl From<VulkanError> for GfxError {
|
||||
|
|
@ -196,12 +212,19 @@ pub fn create_graphics_context(
|
|||
ring: &Rc<IoUring>,
|
||||
drm: &Drm,
|
||||
) -> Result<Rc<dyn GfxContext>, GfxError> {
|
||||
let instance = VulkanInstance::new(eng, ring, *VULKAN_VALIDATION)?;
|
||||
let instance = VulkanInstance::new(Level::Info, *VULKAN_VALIDATION)?;
|
||||
let device = instance.create_device(drm)?;
|
||||
let renderer = device.create_renderer()?;
|
||||
let renderer = device.create_renderer(eng, ring)?;
|
||||
Ok(Rc::new(Context(renderer)))
|
||||
}
|
||||
|
||||
pub fn create_vulkan_allocator(drm: &Drm) -> Result<Rc<dyn Allocator>, AllocatorError> {
|
||||
let instance = VulkanInstance::new(Level::Debug, *VULKAN_VALIDATION)?;
|
||||
let device = instance.create_device(drm)?;
|
||||
let allocator = device.create_bo_allocator(drm)?;
|
||||
Ok(Rc::new(allocator))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Context(Rc<VulkanRenderer>);
|
||||
|
||||
|
|
|
|||
761
src/gfx_apis/vulkan/bo_allocator.rs
Normal file
761
src/gfx_apis/vulkan/bo_allocator.rs
Normal file
|
|
@ -0,0 +1,761 @@
|
|||
use {
|
||||
crate::{
|
||||
allocator::{
|
||||
Allocator, AllocatorError, BufferObject, BufferUsage, MappedBuffer, BO_USE_RENDERING,
|
||||
BO_USE_WRITE,
|
||||
},
|
||||
format::Format,
|
||||
gfx_apis::vulkan::{
|
||||
allocator::VulkanAllocator, command::VulkanCommandBuffer, device::VulkanDevice,
|
||||
format::VulkanFormat, renderer::image_barrier, staging::VulkanStagingBuffer,
|
||||
util::OnDrop, VulkanError,
|
||||
},
|
||||
utils::errorfmt::ErrorFmt,
|
||||
video::{
|
||||
dmabuf::{DmaBuf, DmaBufIds, DmaBufPlane, PlaneVec},
|
||||
drm::Drm,
|
||||
Modifier,
|
||||
},
|
||||
},
|
||||
arrayvec::ArrayVec,
|
||||
ash::vk::{
|
||||
AccessFlags2, BindImageMemoryInfo, BindImagePlaneMemoryInfo, BufferImageCopy2,
|
||||
BufferMemoryBarrier2, CommandBuffer, CommandBufferBeginInfo, CommandBufferSubmitInfo,
|
||||
CommandBufferUsageFlags, CopyBufferToImageInfo2, CopyImageToBufferInfo2, DependencyInfo,
|
||||
DeviceMemory, ExportMemoryAllocateInfo, Extent3D, ExternalMemoryHandleTypeFlags,
|
||||
ExternalMemoryImageCreateInfo, Fence, FormatFeatureFlags, Image, ImageAspectFlags,
|
||||
ImageCreateInfo, ImageDrmFormatModifierExplicitCreateInfoEXT,
|
||||
ImageDrmFormatModifierListCreateInfoEXT, ImageDrmFormatModifierPropertiesEXT, ImageLayout,
|
||||
ImageMemoryBarrier2, ImageMemoryRequirementsInfo2, ImagePlaneMemoryRequirementsInfo,
|
||||
ImageSubresource, ImageSubresourceLayers, ImageTiling, ImageType, ImageUsageFlags,
|
||||
ImportMemoryFdInfoKHR, MemoryAllocateInfo, MemoryDedicatedAllocateInfo,
|
||||
MemoryFdPropertiesKHR, MemoryGetFdInfoKHR, MemoryPropertyFlags, MemoryRequirements2,
|
||||
PipelineStageFlags2, SampleCountFlags, SharingMode, SubmitInfo2, SubresourceLayout,
|
||||
QUEUE_FAMILY_FOREIGN_EXT,
|
||||
},
|
||||
std::{rc::Rc, slice},
|
||||
uapi::OwnedFd,
|
||||
};
|
||||
|
||||
impl From<VulkanError> for AllocatorError {
|
||||
fn from(value: VulkanError) -> Self {
|
||||
Self(Box::new(value))
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct VulkanBoAllocator {
|
||||
data: Rc<VulkanBoAllocatorData>,
|
||||
}
|
||||
|
||||
struct VulkanBoAllocatorData {
|
||||
drm: Drm,
|
||||
device: Rc<VulkanDevice>,
|
||||
allocator: Rc<VulkanAllocator>,
|
||||
command_buffer: Rc<VulkanCommandBuffer>,
|
||||
}
|
||||
|
||||
struct VulkanBo {
|
||||
allocator: Rc<VulkanBoAllocatorData>,
|
||||
image: Image,
|
||||
memory: PlaneVec<DeviceMemory>,
|
||||
buf: DmaBuf,
|
||||
}
|
||||
|
||||
struct VulkanBoMapping {
|
||||
bo: Rc<VulkanBo>,
|
||||
upload: bool,
|
||||
stride: i32,
|
||||
staging: VulkanStagingBuffer,
|
||||
data: *mut [u8],
|
||||
}
|
||||
|
||||
impl Drop for VulkanBo {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.allocator.device.device.destroy_image(self.image, None);
|
||||
for &memory in &self.memory {
|
||||
self.allocator.device.device.free_memory(memory, None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl VulkanDevice {
|
||||
pub(super) fn create_bo_allocator(
|
||||
self: &Rc<Self>,
|
||||
drm: &Drm,
|
||||
) -> Result<VulkanBoAllocator, VulkanError> {
|
||||
let allocator = self.create_allocator()?;
|
||||
let pool = self.create_command_pool()?;
|
||||
let command_buffer = pool.allocate_buffer()?;
|
||||
let drm = drm.dup_render().map_err(VulkanError::DupDrm)?;
|
||||
Ok(VulkanBoAllocator {
|
||||
data: Rc::new(VulkanBoAllocatorData {
|
||||
drm,
|
||||
device: self.clone(),
|
||||
allocator,
|
||||
command_buffer,
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl VulkanBoAllocator {
|
||||
fn create_bo(
|
||||
&self,
|
||||
dma_buf_ids: &DmaBufIds,
|
||||
width: i32,
|
||||
height: i32,
|
||||
format: &'static Format,
|
||||
modifiers: &[Modifier],
|
||||
usage: BufferUsage,
|
||||
) -> Result<Rc<VulkanBo>, VulkanError> {
|
||||
validate_usage(usage)?;
|
||||
let data = &self.data;
|
||||
let Some(format) = data.device.formats.get(&format.drm) else {
|
||||
return Err(VulkanError::FormatNotSupported);
|
||||
};
|
||||
if width < 0 || height < 0 {
|
||||
return Err(VulkanError::NonPositiveImageSize);
|
||||
}
|
||||
let width = width as u32;
|
||||
let height = height as u32;
|
||||
let image = {
|
||||
let mut mods = vec![];
|
||||
for &modifier in modifiers {
|
||||
if validate_modifier(width, height, usage, false, None, format, modifier) {
|
||||
mods.push(modifier);
|
||||
}
|
||||
}
|
||||
if mods.is_empty() {
|
||||
return Err(VulkanError::NoSupportedModifiers);
|
||||
}
|
||||
let mut mod_list =
|
||||
ImageDrmFormatModifierListCreateInfoEXT::default().drm_format_modifiers(&mods);
|
||||
let mut memory_image_create_info = ExternalMemoryImageCreateInfo::default()
|
||||
.handle_types(ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
|
||||
let create_info = image_create_info(width, height, format.format, usage)
|
||||
.push_next(&mut memory_image_create_info)
|
||||
.push_next(&mut mod_list);
|
||||
let res = unsafe { data.device.device.create_image(&create_info, None) };
|
||||
res.map_err(VulkanError::CreateImage)?
|
||||
};
|
||||
let destroy_image = OnDrop(|| unsafe { data.device.device.destroy_image(image, None) });
|
||||
let modifier = {
|
||||
let mut props = ImageDrmFormatModifierPropertiesEXT::default();
|
||||
unsafe {
|
||||
data.device
|
||||
.image_drm_format_modifier
|
||||
.get_image_drm_format_modifier_properties(image, &mut props)
|
||||
.map_err(VulkanError::GetModifier)?
|
||||
}
|
||||
props.drm_format_modifier
|
||||
};
|
||||
let Some(modifier) = format.modifiers.get(&modifier) else {
|
||||
return Err(VulkanError::InvalidModifier)?;
|
||||
};
|
||||
let memory = {
|
||||
let image_memory_requirements_info =
|
||||
ImageMemoryRequirementsInfo2::default().image(image);
|
||||
let mut memory_requirements = MemoryRequirements2::default();
|
||||
unsafe {
|
||||
data.device.device.get_image_memory_requirements2(
|
||||
&image_memory_requirements_info,
|
||||
&mut memory_requirements,
|
||||
);
|
||||
}
|
||||
let memory_type_index = data
|
||||
.device
|
||||
.find_memory_type(
|
||||
MemoryPropertyFlags::DEVICE_LOCAL,
|
||||
memory_requirements.memory_requirements.memory_type_bits,
|
||||
)
|
||||
.ok_or(VulkanError::MemoryType)?;
|
||||
let mut memory_dedicated_allocate_info =
|
||||
MemoryDedicatedAllocateInfo::default().image(image);
|
||||
let mut export_info = ExportMemoryAllocateInfo::default()
|
||||
.handle_types(ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
|
||||
let memory_allocate_info = MemoryAllocateInfo::default()
|
||||
.allocation_size(memory_requirements.memory_requirements.size)
|
||||
.memory_type_index(memory_type_index)
|
||||
.push_next(&mut memory_dedicated_allocate_info)
|
||||
.push_next(&mut export_info);
|
||||
let memory = unsafe {
|
||||
data.device
|
||||
.device
|
||||
.allocate_memory(&memory_allocate_info, None)
|
||||
};
|
||||
memory.map_err(VulkanError::AllocateMemory)?
|
||||
};
|
||||
let destroy_memory = OnDrop(|| unsafe { data.device.device.free_memory(memory, None) });
|
||||
unsafe {
|
||||
data.device
|
||||
.device
|
||||
.bind_image_memory(image, memory, 0)
|
||||
.map_err(VulkanError::BindImageMemory)?;
|
||||
}
|
||||
let fd = {
|
||||
let get_info = MemoryGetFdInfoKHR::default()
|
||||
.handle_type(ExternalMemoryHandleTypeFlags::DMA_BUF_EXT)
|
||||
.memory(memory);
|
||||
let fd = unsafe { data.device.external_memory_fd.get_memory_fd(&get_info) };
|
||||
fd.map_err(VulkanError::GetDmaBuf)
|
||||
.map(OwnedFd::new)
|
||||
.map(Rc::new)?
|
||||
};
|
||||
let mut planes = PlaneVec::new();
|
||||
for i in 0..modifier.planes {
|
||||
let flag = [
|
||||
ImageAspectFlags::MEMORY_PLANE_0_EXT,
|
||||
ImageAspectFlags::MEMORY_PLANE_1_EXT,
|
||||
ImageAspectFlags::MEMORY_PLANE_2_EXT,
|
||||
ImageAspectFlags::MEMORY_PLANE_3_EXT,
|
||||
][i];
|
||||
let layout = unsafe {
|
||||
data.device.device.get_image_subresource_layout(
|
||||
image,
|
||||
ImageSubresource::default().aspect_mask(flag),
|
||||
)
|
||||
};
|
||||
planes.push(DmaBufPlane {
|
||||
offset: layout.offset as _,
|
||||
stride: layout.row_pitch as _,
|
||||
fd: fd.clone(),
|
||||
});
|
||||
}
|
||||
let buf = DmaBuf {
|
||||
id: dma_buf_ids.next(),
|
||||
width: width as _,
|
||||
height: height as _,
|
||||
format: format.format,
|
||||
modifier: modifier.modifier,
|
||||
planes,
|
||||
};
|
||||
unsafe {
|
||||
let cmd = data.command_buffer.buffer;
|
||||
let device = &data.device.device;
|
||||
let begin =
|
||||
CommandBufferBeginInfo::default().flags(CommandBufferUsageFlags::ONE_TIME_SUBMIT);
|
||||
let barrier = image_barrier()
|
||||
.src_queue_family_index(data.device.graphics_queue_idx)
|
||||
.dst_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT)
|
||||
.old_layout(ImageLayout::UNDEFINED)
|
||||
.new_layout(ImageLayout::GENERAL)
|
||||
.image(image);
|
||||
let dependency_info =
|
||||
DependencyInfo::default().image_memory_barriers(slice::from_ref(&barrier));
|
||||
let cmd_buffer_submit_info = CommandBufferSubmitInfo::default().command_buffer(cmd);
|
||||
let submit_info = SubmitInfo2::default()
|
||||
.command_buffer_infos(slice::from_ref(&cmd_buffer_submit_info));
|
||||
device
|
||||
.begin_command_buffer(cmd, &begin)
|
||||
.map_err(VulkanError::BeginCommandBuffer)?;
|
||||
device.cmd_pipeline_barrier2(cmd, &dependency_info);
|
||||
device
|
||||
.end_command_buffer(cmd)
|
||||
.map_err(VulkanError::EndCommandBuffer)?;
|
||||
device
|
||||
.queue_submit2(
|
||||
data.device.graphics_queue,
|
||||
slice::from_ref(&submit_info),
|
||||
Fence::null(),
|
||||
)
|
||||
.map_err(VulkanError::Submit)?;
|
||||
device.device_wait_idle().map_err(VulkanError::WaitIdle)?;
|
||||
}
|
||||
destroy_image.forget();
|
||||
destroy_memory.forget();
|
||||
Ok(Rc::new(VulkanBo {
|
||||
allocator: self.data.clone(),
|
||||
image,
|
||||
memory: [memory].into_iter().collect(),
|
||||
buf,
|
||||
}))
|
||||
}
|
||||
|
||||
fn import_dmabuf(
|
||||
&self,
|
||||
dmabuf: &DmaBuf,
|
||||
usage: BufferUsage,
|
||||
) -> Result<Rc<VulkanBo>, VulkanError> {
|
||||
validate_usage(usage)?;
|
||||
let data = &self.data;
|
||||
let Some(format) = data.device.formats.get(&dmabuf.format.drm) else {
|
||||
return Err(VulkanError::FormatNotSupported);
|
||||
};
|
||||
if dmabuf.width < 0 || dmabuf.height < 0 {
|
||||
return Err(VulkanError::NonPositiveImageSize);
|
||||
}
|
||||
let width = dmabuf.width as u32;
|
||||
let height = dmabuf.height as u32;
|
||||
let disjoint = dmabuf.is_disjoint();
|
||||
let image = {
|
||||
if !validate_modifier(
|
||||
width,
|
||||
height,
|
||||
usage,
|
||||
disjoint,
|
||||
Some(dmabuf.planes.len()),
|
||||
format,
|
||||
dmabuf.modifier,
|
||||
) {
|
||||
return Err(VulkanError::ModifierNotSupported);
|
||||
}
|
||||
let plane_layouts: PlaneVec<_> = dmabuf
|
||||
.planes
|
||||
.iter()
|
||||
.map(|p| {
|
||||
SubresourceLayout::default()
|
||||
.offset(p.offset as _)
|
||||
.row_pitch(p.stride as _)
|
||||
})
|
||||
.collect();
|
||||
let mut modifier_info = ImageDrmFormatModifierExplicitCreateInfoEXT::default()
|
||||
.plane_layouts(&plane_layouts)
|
||||
.drm_format_modifier(dmabuf.modifier);
|
||||
let mut memory_image_create_info = ExternalMemoryImageCreateInfo::default()
|
||||
.handle_types(ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
|
||||
let create_info = image_create_info(width, height, format.format, usage)
|
||||
.push_next(&mut memory_image_create_info)
|
||||
.push_next(&mut modifier_info);
|
||||
let res = unsafe { data.device.device.create_image(&create_info, None) };
|
||||
res.map_err(VulkanError::CreateImage)?
|
||||
};
|
||||
let destroy_image = OnDrop(|| unsafe { data.device.device.destroy_image(image, None) });
|
||||
let num_device_memories = match disjoint {
|
||||
true => dmabuf.planes.len(),
|
||||
false => 1,
|
||||
};
|
||||
let mut device_memories = PlaneVec::new();
|
||||
let mut free_device_memories = PlaneVec::new();
|
||||
let mut bind_image_plane_memory_infos = PlaneVec::new();
|
||||
for plane_idx in 0..num_device_memories {
|
||||
let dma_buf_plane = &dmabuf.planes[plane_idx];
|
||||
let mut memory_fd_properties = MemoryFdPropertiesKHR::default();
|
||||
unsafe {
|
||||
data.device
|
||||
.external_memory_fd
|
||||
.get_memory_fd_properties(
|
||||
ExternalMemoryHandleTypeFlags::DMA_BUF_EXT,
|
||||
dma_buf_plane.fd.raw(),
|
||||
&mut memory_fd_properties,
|
||||
)
|
||||
.map_err(VulkanError::MemoryFdProperties)?;
|
||||
}
|
||||
let mut image_memory_requirements_info =
|
||||
ImageMemoryRequirementsInfo2::default().image(image);
|
||||
let mut image_plane_memory_requirements_info;
|
||||
if disjoint {
|
||||
let plane_aspect = [
|
||||
ImageAspectFlags::MEMORY_PLANE_0_EXT,
|
||||
ImageAspectFlags::MEMORY_PLANE_1_EXT,
|
||||
ImageAspectFlags::MEMORY_PLANE_2_EXT,
|
||||
ImageAspectFlags::MEMORY_PLANE_3_EXT,
|
||||
][plane_idx];
|
||||
image_plane_memory_requirements_info =
|
||||
ImagePlaneMemoryRequirementsInfo::default().plane_aspect(plane_aspect);
|
||||
image_memory_requirements_info = image_memory_requirements_info
|
||||
.push_next(&mut image_plane_memory_requirements_info);
|
||||
bind_image_plane_memory_infos
|
||||
.push(BindImagePlaneMemoryInfo::default().plane_aspect(plane_aspect));
|
||||
}
|
||||
let mut memory_requirements = MemoryRequirements2::default();
|
||||
unsafe {
|
||||
data.device.device.get_image_memory_requirements2(
|
||||
&image_memory_requirements_info,
|
||||
&mut memory_requirements,
|
||||
);
|
||||
}
|
||||
let memory_type_bits = memory_requirements.memory_requirements.memory_type_bits
|
||||
& memory_fd_properties.memory_type_bits;
|
||||
let memory_type_index = data
|
||||
.device
|
||||
.find_memory_type(MemoryPropertyFlags::empty(), memory_type_bits)
|
||||
.ok_or(VulkanError::MemoryType)?;
|
||||
let fd = uapi::fcntl_dupfd_cloexec(dma_buf_plane.fd.raw(), 0)
|
||||
.map_err(|e| VulkanError::Dupfd(e.into()))?;
|
||||
let mut memory_dedicated_allocate_info =
|
||||
MemoryDedicatedAllocateInfo::default().image(image);
|
||||
let mut import_memory_fd_info = ImportMemoryFdInfoKHR::default()
|
||||
.fd(fd.raw())
|
||||
.handle_type(ExternalMemoryHandleTypeFlags::DMA_BUF_EXT);
|
||||
let memory_allocate_info = MemoryAllocateInfo::default()
|
||||
.allocation_size(memory_requirements.memory_requirements.size)
|
||||
.memory_type_index(memory_type_index)
|
||||
.push_next(&mut import_memory_fd_info)
|
||||
.push_next(&mut memory_dedicated_allocate_info);
|
||||
let device_memory = unsafe {
|
||||
data.device
|
||||
.device
|
||||
.allocate_memory(&memory_allocate_info, None)
|
||||
};
|
||||
let device_memory = device_memory.map_err(VulkanError::AllocateMemory)?;
|
||||
fd.unwrap();
|
||||
device_memories.push(device_memory);
|
||||
free_device_memories.push(OnDrop(move || unsafe {
|
||||
data.device.device.free_memory(device_memory, None)
|
||||
}));
|
||||
}
|
||||
let mut bind_image_memory_infos = Vec::with_capacity(num_device_memories);
|
||||
let mut bind_image_plane_memory_infos = bind_image_plane_memory_infos.iter_mut();
|
||||
for mem in device_memories.iter().copied() {
|
||||
let mut info = BindImageMemoryInfo::default().image(image).memory(mem);
|
||||
if disjoint {
|
||||
info = info.push_next(bind_image_plane_memory_infos.next().unwrap());
|
||||
}
|
||||
bind_image_memory_infos.push(info);
|
||||
}
|
||||
let res = unsafe {
|
||||
data.device
|
||||
.device
|
||||
.bind_image_memory2(&bind_image_memory_infos)
|
||||
};
|
||||
res.map_err(VulkanError::BindImageMemory)?;
|
||||
destroy_image.forget();
|
||||
free_device_memories.drain(..).for_each(|m| m.forget());
|
||||
Ok(Rc::new(VulkanBo {
|
||||
allocator: data.clone(),
|
||||
image,
|
||||
memory: device_memories,
|
||||
buf: dmabuf.clone(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl Allocator for VulkanBoAllocator {
|
||||
fn drm(&self) -> Option<&Drm> {
|
||||
Some(&self.data.drm)
|
||||
}
|
||||
|
||||
fn create_bo(
|
||||
&self,
|
||||
dma_buf_ids: &DmaBufIds,
|
||||
width: i32,
|
||||
height: i32,
|
||||
format: &'static Format,
|
||||
modifiers: &[Modifier],
|
||||
usage: BufferUsage,
|
||||
) -> Result<Rc<dyn BufferObject>, AllocatorError> {
|
||||
let bo = self.create_bo(dma_buf_ids, width, height, format, modifiers, usage)?;
|
||||
Ok(bo)
|
||||
}
|
||||
|
||||
fn import_dmabuf(
|
||||
&self,
|
||||
dmabuf: &DmaBuf,
|
||||
usage: BufferUsage,
|
||||
) -> Result<Rc<dyn BufferObject>, AllocatorError> {
|
||||
let bo = self.import_dmabuf(dmabuf, usage)?;
|
||||
Ok(bo)
|
||||
}
|
||||
}
|
||||
|
||||
impl VulkanBo {
|
||||
fn map(self: &Rc<Self>, write: bool) -> Result<VulkanBoMapping, VulkanError> {
|
||||
let format = self.buf.format;
|
||||
let Some(shm_info) = &format.shm_info else {
|
||||
return Err(VulkanError::ShmNotSupported);
|
||||
};
|
||||
let stride = self.buf.width as u32 * shm_info.bpp;
|
||||
let size = self.buf.height as u32 * stride;
|
||||
let data = &self.allocator;
|
||||
let staging =
|
||||
data.device
|
||||
.create_staging_buffer(&data.allocator, size as _, write, true, true)?;
|
||||
self.transfer(&staging, false, |cmd| {
|
||||
let region = BufferImageCopy2::default()
|
||||
.image_subresource(
|
||||
ImageSubresourceLayers::default()
|
||||
.aspect_mask(ImageAspectFlags::COLOR)
|
||||
.layer_count(1),
|
||||
)
|
||||
.image_extent(Extent3D {
|
||||
width: self.buf.width as _,
|
||||
height: self.buf.height as _,
|
||||
depth: 1,
|
||||
});
|
||||
let copy_info = CopyImageToBufferInfo2::default()
|
||||
.src_image(self.image)
|
||||
.src_image_layout(ImageLayout::TRANSFER_SRC_OPTIMAL)
|
||||
.regions(slice::from_ref(®ion))
|
||||
.dst_buffer(staging.buffer);
|
||||
unsafe {
|
||||
data.device
|
||||
.device
|
||||
.cmd_copy_image_to_buffer2(cmd, ©_info);
|
||||
}
|
||||
})?;
|
||||
staging.download(|_, _| ())?;
|
||||
let data = unsafe {
|
||||
slice::from_raw_parts_mut(
|
||||
staging.allocation.mem.unwrap(),
|
||||
staging.allocation.size as _,
|
||||
)
|
||||
};
|
||||
Ok(VulkanBoMapping {
|
||||
bo: self.clone(),
|
||||
upload: write,
|
||||
stride: stride as _,
|
||||
staging,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
fn transfer<F>(
|
||||
&self,
|
||||
staging: &VulkanStagingBuffer,
|
||||
write: bool,
|
||||
f: F,
|
||||
) -> Result<(), VulkanError>
|
||||
where
|
||||
F: FnOnce(CommandBuffer),
|
||||
{
|
||||
let data = &self.allocator;
|
||||
let cmd = data.command_buffer.buffer;
|
||||
let device = &data.device.device;
|
||||
let begin =
|
||||
CommandBufferBeginInfo::default().flags(CommandBufferUsageFlags::ONE_TIME_SUBMIT);
|
||||
let initial_image_barrier = self.initial_image_barrier(write);
|
||||
let final_image_barrier = self.final_image_barrier(write);
|
||||
let mut initial_buffer_barrier = ArrayVec::<_, 1>::new();
|
||||
let mut final_buffer_barrier = ArrayVec::<_, 1>::new();
|
||||
if write {
|
||||
initial_buffer_barrier.push(
|
||||
BufferMemoryBarrier2::default()
|
||||
.src_access_mask(AccessFlags2::HOST_WRITE)
|
||||
.src_stage_mask(PipelineStageFlags2::HOST)
|
||||
.dst_access_mask(AccessFlags2::TRANSFER_READ)
|
||||
.dst_stage_mask(PipelineStageFlags2::TRANSFER)
|
||||
.buffer(staging.buffer)
|
||||
.size(staging.size),
|
||||
);
|
||||
} else {
|
||||
final_buffer_barrier.push(
|
||||
BufferMemoryBarrier2::default()
|
||||
.src_access_mask(AccessFlags2::TRANSFER_WRITE)
|
||||
.src_stage_mask(PipelineStageFlags2::TRANSFER)
|
||||
.dst_access_mask(AccessFlags2::HOST_READ | AccessFlags2::HOST_WRITE)
|
||||
.dst_stage_mask(PipelineStageFlags2::HOST)
|
||||
.buffer(staging.buffer)
|
||||
.size(staging.size),
|
||||
);
|
||||
}
|
||||
let initial_dependency_info = DependencyInfo::default()
|
||||
.image_memory_barriers(slice::from_ref(&initial_image_barrier))
|
||||
.buffer_memory_barriers(&initial_buffer_barrier);
|
||||
let final_dependency_info = DependencyInfo::default()
|
||||
.image_memory_barriers(slice::from_ref(&final_image_barrier))
|
||||
.buffer_memory_barriers(&final_buffer_barrier);
|
||||
let cmd_buffer_submit_info = CommandBufferSubmitInfo::default().command_buffer(cmd);
|
||||
let submit_info =
|
||||
SubmitInfo2::default().command_buffer_infos(slice::from_ref(&cmd_buffer_submit_info));
|
||||
unsafe {
|
||||
device
|
||||
.begin_command_buffer(cmd, &begin)
|
||||
.map_err(VulkanError::BeginCommandBuffer)?;
|
||||
device.cmd_pipeline_barrier2(cmd, &initial_dependency_info);
|
||||
f(cmd);
|
||||
device.cmd_pipeline_barrier2(cmd, &final_dependency_info);
|
||||
device
|
||||
.end_command_buffer(cmd)
|
||||
.map_err(VulkanError::EndCommandBuffer)?;
|
||||
device
|
||||
.queue_submit2(
|
||||
data.device.graphics_queue,
|
||||
slice::from_ref(&submit_info),
|
||||
Fence::null(),
|
||||
)
|
||||
.map_err(VulkanError::Submit)?;
|
||||
device.device_wait_idle().map_err(VulkanError::WaitIdle)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_image_barrier_flags(&self, write: bool) -> (ImageLayout, AccessFlags2) {
|
||||
let layout;
|
||||
let access_mask;
|
||||
match write {
|
||||
false => {
|
||||
layout = ImageLayout::TRANSFER_SRC_OPTIMAL;
|
||||
access_mask = AccessFlags2::TRANSFER_READ;
|
||||
}
|
||||
true => {
|
||||
layout = ImageLayout::TRANSFER_DST_OPTIMAL;
|
||||
access_mask = AccessFlags2::TRANSFER_WRITE;
|
||||
}
|
||||
}
|
||||
(layout, access_mask)
|
||||
}
|
||||
|
||||
fn initial_image_barrier(&self, write: bool) -> ImageMemoryBarrier2<'static> {
|
||||
let (new_layout, dst_access_mask) = self.get_image_barrier_flags(write);
|
||||
image_barrier()
|
||||
.src_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT)
|
||||
.dst_queue_family_index(self.allocator.device.graphics_queue_idx)
|
||||
.old_layout(ImageLayout::GENERAL)
|
||||
.new_layout(new_layout)
|
||||
.dst_access_mask(dst_access_mask)
|
||||
.dst_stage_mask(PipelineStageFlags2::TRANSFER)
|
||||
.image(self.image)
|
||||
}
|
||||
|
||||
fn final_image_barrier(&self, write: bool) -> ImageMemoryBarrier2<'static> {
|
||||
let (old_layout, src_access_mask) = self.get_image_barrier_flags(write);
|
||||
image_barrier()
|
||||
.src_queue_family_index(self.allocator.device.graphics_queue_idx)
|
||||
.dst_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT)
|
||||
.old_layout(old_layout)
|
||||
.new_layout(ImageLayout::GENERAL)
|
||||
.src_access_mask(src_access_mask)
|
||||
.src_stage_mask(PipelineStageFlags2::TRANSFER)
|
||||
.image(self.image)
|
||||
}
|
||||
}
|
||||
|
||||
impl BufferObject for VulkanBo {
|
||||
fn dmabuf(&self) -> &DmaBuf {
|
||||
&self.buf
|
||||
}
|
||||
|
||||
fn map_read(self: Rc<Self>) -> Result<Box<dyn MappedBuffer>, AllocatorError> {
|
||||
let m = self.map(false)?;
|
||||
Ok(Box::new(m))
|
||||
}
|
||||
|
||||
fn map_write(self: Rc<Self>) -> Result<Box<dyn MappedBuffer>, AllocatorError> {
|
||||
let m = self.map(true)?;
|
||||
Ok(Box::new(m))
|
||||
}
|
||||
}
|
||||
|
||||
impl VulkanBoMapping {
|
||||
fn upload(&self) -> Result<(), VulkanError> {
|
||||
let data = &self.bo.allocator;
|
||||
self.staging.upload(|_, _| ())?;
|
||||
self.bo.transfer(&self.staging, true, |cmd| {
|
||||
let region = BufferImageCopy2::default()
|
||||
.image_subresource(
|
||||
ImageSubresourceLayers::default()
|
||||
.aspect_mask(ImageAspectFlags::COLOR)
|
||||
.layer_count(1),
|
||||
)
|
||||
.image_extent(Extent3D {
|
||||
width: self.bo.buf.width as _,
|
||||
height: self.bo.buf.height as _,
|
||||
depth: 1,
|
||||
});
|
||||
let copy_info = CopyBufferToImageInfo2::default()
|
||||
.dst_image(self.bo.image)
|
||||
.dst_image_layout(ImageLayout::TRANSFER_DST_OPTIMAL)
|
||||
.regions(slice::from_ref(®ion))
|
||||
.src_buffer(self.staging.buffer);
|
||||
unsafe {
|
||||
data.device
|
||||
.device
|
||||
.cmd_copy_buffer_to_image2(cmd, ©_info);
|
||||
}
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VulkanBoMapping {
|
||||
fn drop(&mut self) {
|
||||
if self.upload {
|
||||
if let Err(e) = self.upload() {
|
||||
log::error!("Could not upload to image: {}", ErrorFmt(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MappedBuffer for VulkanBoMapping {
|
||||
unsafe fn data(&self) -> &[u8] {
|
||||
&*self.data
|
||||
}
|
||||
|
||||
fn data_ptr(&self) -> *mut u8 {
|
||||
self.data as _
|
||||
}
|
||||
|
||||
fn stride(&self) -> i32 {
|
||||
self.stride
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_usage(usage: BufferUsage) -> Result<(), VulkanError> {
|
||||
if usage.contains(!(BO_USE_WRITE | BO_USE_RENDERING)) {
|
||||
return Err(VulkanError::UnsupportedBufferUsage);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn map_usage(usage: BufferUsage) -> ImageUsageFlags {
|
||||
let mut vk_usage = ImageUsageFlags::TRANSFER_SRC | ImageUsageFlags::TRANSFER_DST;
|
||||
if usage.contains(BO_USE_RENDERING) {
|
||||
vk_usage |= ImageUsageFlags::COLOR_ATTACHMENT;
|
||||
}
|
||||
vk_usage
|
||||
}
|
||||
|
||||
fn validate_modifier(
|
||||
width: u32,
|
||||
height: u32,
|
||||
usage: BufferUsage,
|
||||
disjoint: bool,
|
||||
plane_count: Option<usize>,
|
||||
format: &VulkanFormat,
|
||||
modifier: Modifier,
|
||||
) -> bool {
|
||||
let Some(modifier) = format.modifiers.get(&modifier) else {
|
||||
return false;
|
||||
};
|
||||
if disjoint && !modifier.features.contains(FormatFeatureFlags::DISJOINT) {
|
||||
return false;
|
||||
}
|
||||
if let Some(plane_count) = plane_count {
|
||||
if plane_count != modifier.planes {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let Some(max_extents) = modifier.transfer_max_extents else {
|
||||
return false;
|
||||
};
|
||||
let mut max_width = max_extents.width;
|
||||
let mut max_height = max_extents.height;
|
||||
if usage.contains(BO_USE_RENDERING) {
|
||||
let Some(max_extents) = modifier.render_max_extents else {
|
||||
return false;
|
||||
};
|
||||
max_width = max_width.min(max_extents.width);
|
||||
max_height = max_height.min(max_extents.height);
|
||||
}
|
||||
if width > max_width || height > max_height {
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn image_create_info(
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: &Format,
|
||||
usage: BufferUsage,
|
||||
) -> ImageCreateInfo {
|
||||
let usage = map_usage(usage);
|
||||
ImageCreateInfo::default()
|
||||
.image_type(ImageType::TYPE_2D)
|
||||
.format(format.vk_format)
|
||||
.mip_levels(1)
|
||||
.array_layers(1)
|
||||
.tiling(ImageTiling::DRM_FORMAT_MODIFIER_EXT)
|
||||
.samples(SampleCountFlags::TYPE_1)
|
||||
.sharing_mode(SharingMode::EXCLUSIVE)
|
||||
.initial_layout(ImageLayout::UNDEFINED)
|
||||
.extent(Extent3D {
|
||||
width,
|
||||
height,
|
||||
depth: 1,
|
||||
})
|
||||
.usage(usage)
|
||||
}
|
||||
|
|
@ -57,6 +57,7 @@ pub struct VulkanDevice {
|
|||
pub(super) external_semaphore_fd: external_semaphore_fd::Device,
|
||||
pub(super) external_fence_fd: external_fence_fd::Device,
|
||||
pub(super) push_descriptor: push_descriptor::Device,
|
||||
pub(super) image_drm_format_modifier: image_drm_format_modifier::Device,
|
||||
pub(super) formats: AHashMap<u32, VulkanFormat>,
|
||||
pub(super) memory_types: ArrayVec<MemoryType, MAX_MEMORY_TYPES>,
|
||||
pub(super) graphics_queue: Queue,
|
||||
|
|
@ -104,7 +105,8 @@ impl VulkanInstance {
|
|||
Err(e) => return Err(VulkanError::Fstat(e.into())),
|
||||
};
|
||||
let dev = stat.st_rdev;
|
||||
log::info!(
|
||||
log::log!(
|
||||
self.log_level,
|
||||
"Searching for vulkan device with devnum {}:{}",
|
||||
uapi::major(dev),
|
||||
uapi::minor(dev)
|
||||
|
|
@ -153,8 +155,13 @@ impl VulkanInstance {
|
|||
let render_dev =
|
||||
uapi::makedev(drm_props.render_major as _, drm_props.render_minor as _);
|
||||
if primary_dev == dev || render_dev == dev {
|
||||
log::info!("Device with id {} matches", props.device_id);
|
||||
log_device(&props, Some(&extensions), Some(&driver_props));
|
||||
log::log!(self.log_level, "Device with id {} matches", props.device_id);
|
||||
log_device(
|
||||
self.log_level,
|
||||
&props,
|
||||
Some(&extensions),
|
||||
Some(&driver_props),
|
||||
);
|
||||
return Ok(phy_dev);
|
||||
}
|
||||
devices.push((props, Some(extensions), Some(driver_props)));
|
||||
|
|
@ -166,7 +173,12 @@ impl VulkanInstance {
|
|||
for (props, extensions, driver_props) in devices.iter() {
|
||||
log::warn!("Found the following devices but none matches:");
|
||||
log::warn!("-----");
|
||||
log_device(props, extensions.as_ref(), driver_props.as_ref());
|
||||
log_device(
|
||||
self.log_level,
|
||||
props,
|
||||
extensions.as_ref(),
|
||||
driver_props.as_ref(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Err(VulkanError::NoDeviceFound(dev))
|
||||
|
|
@ -264,6 +276,8 @@ impl VulkanInstance {
|
|||
let external_semaphore_fd = external_semaphore_fd::Device::new(&self.instance, &device);
|
||||
let external_fence_fd = external_fence_fd::Device::new(&self.instance, &device);
|
||||
let push_descriptor = push_descriptor::Device::new(&self.instance, &device);
|
||||
let image_drm_format_modifier =
|
||||
image_drm_format_modifier::Device::new(&self.instance, &device);
|
||||
let memory_properties =
|
||||
unsafe { self.instance.get_physical_device_memory_properties(phy_dev) };
|
||||
let memory_types = memory_properties.memory_types
|
||||
|
|
@ -283,6 +297,7 @@ impl VulkanInstance {
|
|||
external_semaphore_fd,
|
||||
external_fence_fd,
|
||||
push_descriptor,
|
||||
image_drm_format_modifier,
|
||||
formats,
|
||||
memory_types,
|
||||
graphics_queue,
|
||||
|
|
@ -302,20 +317,27 @@ const REQUIRED_DEVICE_EXTENSIONS: &[&CStr] = &[
|
|||
];
|
||||
|
||||
fn log_device(
|
||||
level: log::Level,
|
||||
props: &PhysicalDeviceProperties,
|
||||
extensions: Option<&Extensions>,
|
||||
driver_props: Option<&PhysicalDeviceDriverProperties>,
|
||||
) {
|
||||
log::info!(" api version: {}", ApiVersionDisplay(props.api_version));
|
||||
log::info!(
|
||||
log::log!(
|
||||
level,
|
||||
" api version: {}",
|
||||
ApiVersionDisplay(props.api_version)
|
||||
);
|
||||
log::log!(
|
||||
level,
|
||||
" driver version: {}",
|
||||
ApiVersionDisplay(props.driver_version)
|
||||
);
|
||||
log::info!(" vendor id: {}", props.vendor_id);
|
||||
log::info!(" device id: {}", props.device_id);
|
||||
log::info!(" device type: {:?}", props.device_type);
|
||||
log::log!(level, " vendor id: {}", props.vendor_id);
|
||||
log::log!(level, " device id: {}", props.device_id);
|
||||
log::log!(level, " device type: {:?}", props.device_type);
|
||||
unsafe {
|
||||
log::info!(
|
||||
log::log!(
|
||||
level,
|
||||
" device name: {}",
|
||||
Ustr::from_ptr(props.device_name.as_ptr()).display()
|
||||
);
|
||||
|
|
@ -330,7 +352,8 @@ fn log_device(
|
|||
}
|
||||
if let Some(driver_props) = driver_props {
|
||||
unsafe {
|
||||
log::info!(
|
||||
log::log!(
|
||||
level,
|
||||
" driver: {} ({})",
|
||||
Ustr::from_ptr(driver_props.driver_name.as_ptr()).display(),
|
||||
Ustr::from_ptr(driver_props.driver_info.as_ptr()).display()
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ pub struct VulkanModifier {
|
|||
pub features: FormatFeatureFlags,
|
||||
pub render_max_extents: Option<VulkanMaxExtents>,
|
||||
pub texture_max_extents: Option<VulkanMaxExtents>,
|
||||
pub transfer_max_extents: Option<VulkanMaxExtents>,
|
||||
pub render_needs_bridge: bool,
|
||||
}
|
||||
|
||||
|
|
@ -58,24 +59,24 @@ const TEX_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw(
|
|||
| FormatFeatureFlags::TRANSFER_SRC.as_raw()
|
||||
| FormatFeatureFlags::SAMPLED_IMAGE_FILTER_LINEAR.as_raw(),
|
||||
);
|
||||
const SHM_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw(
|
||||
0 | FormatFeatureFlags::TRANSFER_SRC.as_raw()
|
||||
| FormatFeatureFlags::TRANSFER_DST.as_raw()
|
||||
| TEX_FEATURES.as_raw(),
|
||||
const TRANSFER_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw(
|
||||
FormatFeatureFlags::TRANSFER_SRC.as_raw() | FormatFeatureFlags::TRANSFER_DST.as_raw(),
|
||||
);
|
||||
const SHM_FEATURES: FormatFeatureFlags =
|
||||
FormatFeatureFlags::from_raw(TRANSFER_FEATURES.as_raw() | TEX_FEATURES.as_raw());
|
||||
|
||||
const FRAMEBUFFER_USAGE: ImageUsageFlags = ImageUsageFlags::from_raw(
|
||||
0 | ImageUsageFlags::COLOR_ATTACHMENT.as_raw() | ImageUsageFlags::TRANSFER_SRC.as_raw(),
|
||||
ImageUsageFlags::COLOR_ATTACHMENT.as_raw() | ImageUsageFlags::TRANSFER_SRC.as_raw(),
|
||||
);
|
||||
const FRAMEBUFFER_BRIDGED_USAGE: ImageUsageFlags = ImageUsageFlags::TRANSFER_DST;
|
||||
const TEX_USAGE: ImageUsageFlags = ImageUsageFlags::from_raw(
|
||||
0 | ImageUsageFlags::SAMPLED.as_raw() | ImageUsageFlags::TRANSFER_SRC.as_raw(),
|
||||
ImageUsageFlags::SAMPLED.as_raw() | ImageUsageFlags::TRANSFER_SRC.as_raw(),
|
||||
);
|
||||
const SHM_USAGE: ImageUsageFlags = ImageUsageFlags::from_raw(
|
||||
0 | ImageUsageFlags::TRANSFER_SRC.as_raw()
|
||||
| ImageUsageFlags::TRANSFER_DST.as_raw()
|
||||
| TEX_USAGE.as_raw(),
|
||||
const TRANSFER_USAGE: ImageUsageFlags = ImageUsageFlags::from_raw(
|
||||
ImageUsageFlags::TRANSFER_SRC.as_raw() | ImageUsageFlags::TRANSFER_DST.as_raw(),
|
||||
);
|
||||
const SHM_USAGE: ImageUsageFlags =
|
||||
ImageUsageFlags::from_raw(TRANSFER_USAGE.as_raw() | TEX_USAGE.as_raw());
|
||||
|
||||
impl VulkanInstance {
|
||||
pub(super) fn load_formats(
|
||||
|
|
@ -209,6 +210,13 @@ impl VulkanInstance {
|
|||
)?;
|
||||
let texture_max_extents =
|
||||
self.get_max_extents(phy_dev, format, TEX_FEATURES, TEX_USAGE, &modifier)?;
|
||||
let transfer_max_extents = self.get_max_extents(
|
||||
phy_dev,
|
||||
format,
|
||||
TRANSFER_FEATURES,
|
||||
TRANSFER_USAGE,
|
||||
&modifier,
|
||||
)?;
|
||||
let mut render_needs_bridge = false;
|
||||
if render_max_extents.is_none() && modifier.drm_format_modifier == LINEAR_MODIFIER {
|
||||
render_max_extents = self.get_fb_bridged_max_extents(
|
||||
|
|
@ -229,6 +237,7 @@ impl VulkanInstance {
|
|||
features: modifier.drm_format_modifier_tiling_features,
|
||||
render_max_extents,
|
||||
texture_max_extents,
|
||||
transfer_max_extents,
|
||||
render_needs_bridge,
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,5 @@
|
|||
use {
|
||||
crate::{
|
||||
async_engine::AsyncEngine,
|
||||
gfx_apis::vulkan::{util::OnDrop, VulkanError, VULKAN_VALIDATION},
|
||||
io_uring::IoUring,
|
||||
},
|
||||
crate::gfx_apis::vulkan::{util::OnDrop, VulkanError, VULKAN_VALIDATION},
|
||||
ahash::{AHashMap, AHashSet},
|
||||
ash::{
|
||||
ext::{debug_utils, validation_features},
|
||||
|
|
@ -35,16 +31,11 @@ pub struct VulkanInstance {
|
|||
pub(super) instance: Instance,
|
||||
pub(super) debug_utils: debug_utils::Instance,
|
||||
pub(super) messenger: DebugUtilsMessengerEXT,
|
||||
pub(super) eng: Rc<AsyncEngine>,
|
||||
pub(super) ring: Rc<IoUring>,
|
||||
pub(super) log_level: Level,
|
||||
}
|
||||
|
||||
impl VulkanInstance {
|
||||
pub fn new(
|
||||
eng: &Rc<AsyncEngine>,
|
||||
ring: &Rc<IoUring>,
|
||||
validation: bool,
|
||||
) -> Result<Rc<Self>, VulkanError> {
|
||||
pub fn new(log_level: Level, validation: bool) -> Result<Rc<Self>, VulkanError> {
|
||||
static ENTRY: Lazy<Result<Entry, Arc<LoadingError>>> =
|
||||
Lazy::new(|| unsafe { Entry::load() }.map_err(Arc::new));
|
||||
let entry = match &*ENTRY {
|
||||
|
|
@ -127,8 +118,7 @@ impl VulkanInstance {
|
|||
instance,
|
||||
debug_utils,
|
||||
messenger,
|
||||
eng: eng.clone(),
|
||||
ring: ring.clone(),
|
||||
log_level,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
async_engine::SpawnedFuture,
|
||||
async_engine::{AsyncEngine, SpawnedFuture},
|
||||
format::Format,
|
||||
gfx_api::{
|
||||
AcquireSync, BufferResv, BufferResvUser, GfxApiOpt, GfxFormat, GfxFramebuffer,
|
||||
|
|
@ -68,6 +68,8 @@ pub struct VulkanRenderer {
|
|||
pub(super) allocator: Rc<VulkanAllocator>,
|
||||
pub(super) last_point: NumCell<u64>,
|
||||
pub(super) buffer_resv_user: BufferResvUser,
|
||||
pub(super) eng: Rc<AsyncEngine>,
|
||||
pub(super) ring: Rc<IoUring>,
|
||||
}
|
||||
|
||||
pub(super) struct UsedTexture {
|
||||
|
|
@ -111,7 +113,11 @@ pub(super) struct PendingFrame {
|
|||
}
|
||||
|
||||
impl VulkanDevice {
|
||||
pub fn create_renderer(self: &Rc<Self>) -> Result<Rc<VulkanRenderer>, VulkanError> {
|
||||
pub fn create_renderer(
|
||||
self: &Rc<Self>,
|
||||
eng: &Rc<AsyncEngine>,
|
||||
ring: &Rc<IoUring>,
|
||||
) -> Result<Rc<VulkanRenderer>, VulkanError> {
|
||||
let fill_pipeline = self.create_pipeline::<FillVertPushConstants, FillFragPushConstants>(
|
||||
PipelineCreateInfo {
|
||||
vert: self.create_shader(FILL_VERT)?,
|
||||
|
|
@ -196,6 +202,8 @@ impl VulkanDevice {
|
|||
allocator,
|
||||
last_point: Default::default(),
|
||||
buffer_resv_user: Default::default(),
|
||||
eng: eng.clone(),
|
||||
ring: ring.clone(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
@ -691,9 +699,9 @@ impl VulkanRenderer {
|
|||
_release_fence: memory.release_fence.take(),
|
||||
});
|
||||
self.pending_frames.set(frame.point, frame.clone());
|
||||
let future = self.device.instance.eng.spawn(await_release(
|
||||
let future = self.eng.spawn(await_release(
|
||||
memory.release_sync_file.clone(),
|
||||
self.device.instance.ring.clone(),
|
||||
self.ring.clone(),
|
||||
frame.clone(),
|
||||
self.clone(),
|
||||
));
|
||||
|
|
@ -776,7 +784,9 @@ impl VulkanRenderer {
|
|||
height: tex.height,
|
||||
depth: 1,
|
||||
});
|
||||
let staging = self.create_staging_buffer(size, false, true, true)?;
|
||||
let staging =
|
||||
self.device
|
||||
.create_staging_buffer(&self.allocator, size, false, true, true)?;
|
||||
let initial_tex_barrier;
|
||||
let initial_buffer_barrier = BufferMemoryBarrier2::default()
|
||||
.buffer(staging.buffer)
|
||||
|
|
|
|||
|
|
@ -104,9 +104,13 @@ impl VulkanShmImage {
|
|||
cpy = slice::from_ref(&cpy_one);
|
||||
total_size = img.height * img.stride;
|
||||
}
|
||||
let staging = img
|
||||
.renderer
|
||||
.create_staging_buffer(total_size as u64, true, false, true)?;
|
||||
let staging = img.renderer.device.create_staging_buffer(
|
||||
&img.renderer.allocator,
|
||||
total_size as u64,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
)?;
|
||||
staging.upload(|mem, _| unsafe {
|
||||
let buf = buffer.as_ptr() as *const u8;
|
||||
if damage.is_some() {
|
||||
|
|
@ -215,7 +219,7 @@ impl VulkanShmImage {
|
|||
}
|
||||
};
|
||||
let point = img.renderer.allocate_point();
|
||||
let future = img.renderer.device.instance.eng.spawn(await_upload(
|
||||
let future = img.renderer.eng.spawn(await_upload(
|
||||
point,
|
||||
img.clone(),
|
||||
cmd,
|
||||
|
|
@ -236,13 +240,7 @@ async fn await_upload(
|
|||
_fence: Rc<VulkanFence>,
|
||||
_staging: VulkanStagingBuffer,
|
||||
) {
|
||||
let res = img
|
||||
.renderer
|
||||
.device
|
||||
.instance
|
||||
.ring
|
||||
.readable(&sync_file.0)
|
||||
.await;
|
||||
let res = img.renderer.ring.readable(&sync_file.0).await;
|
||||
if let Err(e) = res {
|
||||
log::error!(
|
||||
"Could not wait for sync file to become readable: {}",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use {
|
||||
crate::gfx_apis::vulkan::{
|
||||
allocator::VulkanAllocation, device::VulkanDevice, renderer::VulkanRenderer, util::OnDrop,
|
||||
allocator::{VulkanAllocation, VulkanAllocator},
|
||||
device::VulkanDevice,
|
||||
util::OnDrop,
|
||||
VulkanError,
|
||||
},
|
||||
ash::vk::{Buffer, BufferCreateInfo, BufferUsageFlags, MappedMemoryRange},
|
||||
|
|
@ -15,9 +17,10 @@ pub struct VulkanStagingBuffer {
|
|||
pub(super) size: u64,
|
||||
}
|
||||
|
||||
impl VulkanRenderer {
|
||||
impl VulkanDevice {
|
||||
pub(super) fn create_staging_buffer(
|
||||
self: &Rc<Self>,
|
||||
allocator: &Rc<VulkanAllocator>,
|
||||
size: u64,
|
||||
upload: bool,
|
||||
download: bool,
|
||||
|
|
@ -38,24 +41,22 @@ impl VulkanRenderer {
|
|||
}
|
||||
let buffer = {
|
||||
let create_info = BufferCreateInfo::default().size(size).usage(vk_usage);
|
||||
let buffer = unsafe { self.device.device.create_buffer(&create_info, None) };
|
||||
let buffer = unsafe { self.device.create_buffer(&create_info, None) };
|
||||
buffer.map_err(VulkanError::CreateBuffer)?
|
||||
};
|
||||
let destroy_buffer = OnDrop(|| unsafe { self.device.device.destroy_buffer(buffer, None) });
|
||||
let memory_requirements =
|
||||
unsafe { self.device.device.get_buffer_memory_requirements(buffer) };
|
||||
let allocation = self.allocator.alloc(&memory_requirements, usage, true)?;
|
||||
let destroy_buffer = OnDrop(|| unsafe { self.device.destroy_buffer(buffer, None) });
|
||||
let memory_requirements = unsafe { self.device.get_buffer_memory_requirements(buffer) };
|
||||
let allocation = allocator.alloc(&memory_requirements, usage, true)?;
|
||||
{
|
||||
let res = unsafe {
|
||||
self.device
|
||||
.device
|
||||
.bind_buffer_memory(buffer, allocation.memory, allocation.offset)
|
||||
};
|
||||
res.map_err(VulkanError::BindBufferMemory)?;
|
||||
}
|
||||
destroy_buffer.forget();
|
||||
Ok(VulkanStagingBuffer {
|
||||
device: self.device.clone(),
|
||||
device: self.clone(),
|
||||
allocation,
|
||||
buffer,
|
||||
size,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
allocator::Allocator,
|
||||
allocator::{Allocator, AllocatorError},
|
||||
async_engine::SpawnedFuture,
|
||||
backend::{
|
||||
AxisSource, Backend, BackendEvent, Connector, ConnectorEvent, ConnectorId,
|
||||
|
|
@ -12,6 +12,7 @@ use {
|
|||
drm_feedback::DrmFeedback,
|
||||
fixed::Fixed,
|
||||
gfx_api::GfxError,
|
||||
gfx_apis::create_vulkan_allocator,
|
||||
it::{
|
||||
test_error::TestResult, test_gfx_api::TestGfxCtx, test_utils::test_expected_event::TEEH,
|
||||
},
|
||||
|
|
@ -46,6 +47,8 @@ pub enum TestBackendError {
|
|||
CreateGbmDevice(#[source] GbmError),
|
||||
#[error("Could not create any allocator")]
|
||||
CreateAllocator,
|
||||
#[error("Could not create a vulkan allocator")]
|
||||
CreateVulkanAllocator(#[source] AllocatorError),
|
||||
}
|
||||
|
||||
pub struct TestBackend {
|
||||
|
|
@ -133,21 +136,21 @@ impl TestBackend {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn install_render_context(&self, prefer_udmabuf: bool) -> TestResult {
|
||||
pub fn install_render_context(&self, need_drm: bool) -> TestResult {
|
||||
if self.render_context_installed.get() {
|
||||
return Ok(());
|
||||
}
|
||||
self.create_render_context(prefer_udmabuf)?;
|
||||
self.create_render_context(need_drm)?;
|
||||
self.render_context_installed.set(true);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn install_default(&self) -> TestResult {
|
||||
self.install_default2(true)
|
||||
self.install_default2(false)
|
||||
}
|
||||
|
||||
pub fn install_default2(&self, prefer_udmabuf: bool) -> TestResult {
|
||||
self.install_render_context(prefer_udmabuf)?;
|
||||
pub fn install_default2(&self, need_drm: bool) -> TestResult {
|
||||
self.install_render_context(need_drm)?;
|
||||
self.state
|
||||
.backend_events
|
||||
.push(BackendEvent::NewConnector(self.default_connector.clone()));
|
||||
|
|
@ -163,20 +166,25 @@ impl TestBackend {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn create_render_context(&self, prefer_udmabuf: bool) -> Result<(), TestBackendError> {
|
||||
fn create_render_context(&self, need_drm: bool) -> Result<(), TestBackendError> {
|
||||
macro_rules! constructor {
|
||||
($c:expr) => {
|
||||
(&|| {
|
||||
$c.map(|a| Rc::new(a) as Rc<dyn Allocator>)
|
||||
.map_err(|e| Box::new(e) as Box<dyn Error>)
|
||||
}) as &dyn Fn() -> Result<Rc<dyn Allocator>, Box<dyn Error>>
|
||||
constructor!($c, |a| Rc::new(a) as Rc<dyn Allocator>)
|
||||
};
|
||||
($c:expr, nomap) => {
|
||||
constructor!($c, |a| a)
|
||||
};
|
||||
($c:expr, $map:expr) => {
|
||||
(&|| $c.map($map).map_err(|e| Box::new(e) as Box<dyn Error>))
|
||||
as &dyn Fn() -> Result<Rc<dyn Allocator>, Box<dyn Error>>
|
||||
};
|
||||
}
|
||||
let udmabuf = ("udmabuf", constructor!(Udmabuf::new()));
|
||||
let vulkan = ("Vulkan", constructor!(create_vk_allocator(), nomap));
|
||||
let gbm = ("GBM", constructor!(create_gbm_allocator()));
|
||||
let allocators = match prefer_udmabuf {
|
||||
true => [udmabuf, gbm],
|
||||
false => [gbm, udmabuf],
|
||||
let allocators = match need_drm {
|
||||
true => [vulkan, gbm, udmabuf],
|
||||
false => [udmabuf, vulkan, gbm],
|
||||
};
|
||||
let mut allocator = None::<Rc<dyn Allocator>>;
|
||||
for (name, f) in allocators {
|
||||
|
|
@ -201,6 +209,19 @@ impl TestBackend {
|
|||
}
|
||||
|
||||
fn create_gbm_allocator() -> Result<GbmDevice, TestBackendError> {
|
||||
create_drm_allocator(|drm| GbmDevice::new(&drm).map_err(TestBackendError::CreateGbmDevice))
|
||||
}
|
||||
|
||||
fn create_vk_allocator() -> Result<Rc<dyn Allocator>, TestBackendError> {
|
||||
create_drm_allocator(|drm| {
|
||||
create_vulkan_allocator(&drm).map_err(TestBackendError::CreateVulkanAllocator)
|
||||
})
|
||||
}
|
||||
|
||||
fn create_drm_allocator<T, F>(f: F) -> Result<T, TestBackendError>
|
||||
where
|
||||
F: FnOnce(Drm) -> Result<T, TestBackendError>,
|
||||
{
|
||||
let dri = match std::fs::read_dir("/dev/dri") {
|
||||
Ok(d) => d,
|
||||
Err(e) => return Err(TestBackendError::ReadDri(e)),
|
||||
|
|
@ -240,8 +261,7 @@ fn create_gbm_allocator() -> Result<GbmDevice, TestBackendError> {
|
|||
}
|
||||
};
|
||||
let drm = Drm::open_existing(file);
|
||||
let gbm = GbmDevice::new(&drm).map_err(TestBackendError::CreateGbmDevice)?;
|
||||
Ok(gbm)
|
||||
f(drm)
|
||||
}
|
||||
|
||||
impl Backend for TestBackend {
|
||||
|
|
|
|||
|
|
@ -106,14 +106,11 @@ impl TestRun {
|
|||
}
|
||||
|
||||
pub async fn create_default_setup(&self) -> Result<DefaultSetup, TestError> {
|
||||
self.create_default_setup2(true).await
|
||||
self.create_default_setup2(false).await
|
||||
}
|
||||
|
||||
pub async fn create_default_setup2(
|
||||
&self,
|
||||
prefer_udmabuf: bool,
|
||||
) -> Result<DefaultSetup, TestError> {
|
||||
self.backend.install_default2(prefer_udmabuf)?;
|
||||
pub async fn create_default_setup2(&self, need_drm: bool) -> Result<DefaultSetup, TestError> {
|
||||
self.backend.install_default2(need_drm)?;
|
||||
let seat = self.get_seat("default")?;
|
||||
self.state.eng.yield_now().await;
|
||||
let output = match self.state.root.outputs.lock().values().next() {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ async fn test(run: Rc<TestRun>) -> TestResult {
|
|||
|
||||
tassert!(!run.cfg.graphics_initialized.get());
|
||||
|
||||
run.backend.install_render_context(true)?;
|
||||
run.backend.install_render_context(false)?;
|
||||
|
||||
tassert!(run.cfg.graphics_initialized.get());
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use {
|
|||
testcase!();
|
||||
|
||||
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||
let _ds = run.create_default_setup2(false).await?;
|
||||
let _ds = run.create_default_setup2(true).await?;
|
||||
|
||||
struct Waiter(Cell<bool>);
|
||||
impl SyncObjWaiter for Waiter {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use {
|
|||
testcase!();
|
||||
|
||||
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||
let ds = run.create_default_setup2(false).await?;
|
||||
let ds = run.create_default_setup2(true).await?;
|
||||
|
||||
let scanout_feedback = {
|
||||
let Some(base_fb) = run.state.drm_feedback.get() else {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue