1
0
Fork 0
forked from wry/wry

vulkan: create a vulkan allocator

This commit is contained in:
Julian Orth 2024-09-02 15:56:09 +02:00
parent 952bd31f48
commit 766a093780
15 changed files with 984 additions and 101 deletions

View file

@ -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(

View file

@ -1,3 +1,4 @@
pub use vulkan::create_vulkan_allocator;
use {
crate::{
async_engine::AsyncEngine,

View file

@ -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>);

View 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(&region))
.dst_buffer(staging.buffer);
unsafe {
data.device
.device
.cmd_copy_image_to_buffer2(cmd, &copy_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(&region))
.src_buffer(self.staging.buffer);
unsafe {
data.device
.device
.cmd_copy_buffer_to_image2(cmd, &copy_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)
}

View file

@ -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()

View file

@ -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,
},
);

View file

@ -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,
}))
}
}

View file

@ -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)

View file

@ -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: {}",

View file

@ -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,

View file

@ -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 {

View file

@ -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() {

View file

@ -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());

View file

@ -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 {

View file

@ -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 {