vulkan: create a vulkan allocator
This commit is contained in:
parent
952bd31f48
commit
766a093780
15 changed files with 984 additions and 101 deletions
|
|
@ -1,8 +1,9 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
allocator::{Allocator, AllocatorError, BO_USE_LINEAR, BO_USE_RENDERING},
|
allocator::{Allocator, AllocatorError, BufferUsage, MappedBuffer},
|
||||||
cli::{GlobalArgs, ScreenshotArgs, ScreenshotFormat},
|
cli::{GlobalArgs, ScreenshotArgs, ScreenshotFormat},
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
|
gfx_apis,
|
||||||
tools::tool_client::{with_tool_client, Handle, ToolClient},
|
tools::tool_client::{with_tool_client, Handle, ToolClient},
|
||||||
udmabuf::{Udmabuf, UdmabufError},
|
udmabuf::{Udmabuf, UdmabufError},
|
||||||
utils::{errorfmt::ErrorFmt, queue::AsyncQueue, windows::WindowsExt},
|
utils::{errorfmt::ErrorFmt, queue::AsyncQueue, windows::WindowsExt},
|
||||||
|
|
@ -138,6 +139,21 @@ pub enum ScreenshotError {
|
||||||
ImportDmabuf(#[source] AllocatorError),
|
ImportDmabuf(#[source] AllocatorError),
|
||||||
#[error("Could not map a dmabuf")]
|
#[error("Could not map a dmabuf")]
|
||||||
MapDmabuf(#[source] AllocatorError),
|
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(
|
pub fn buf_to_bytes(
|
||||||
|
|
@ -145,21 +161,55 @@ pub fn buf_to_bytes(
|
||||||
buf: &DmaBuf,
|
buf: &DmaBuf,
|
||||||
format: ScreenshotFormat,
|
format: ScreenshotFormat,
|
||||||
) -> Result<Vec<u8>, ScreenshotError> {
|
) -> 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) => {
|
Some(drm_dev) => {
|
||||||
let drm = Drm::reopen(drm_dev.raw(), false).map_err(ScreenshotError::OpenDrmDevice)?;
|
let drm = || Drm::reopen(drm_dev.raw(), false).map_err(ScreenshotError::OpenDrmDevice);
|
||||||
GbmDevice::new(&drm)
|
let gbm = Box::new(move || {
|
||||||
.map(Rc::new)
|
GbmDevice::new(&drm()?)
|
||||||
.map_err(ScreenshotError::CreateGbmDevice)?
|
.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()
|
None => {
|
||||||
.map(Rc::new)
|
let udmabuf = Box::new(|| {
|
||||||
.map_err(ScreenshotError::CreateUdmabuf)?,
|
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() };
|
let data = unsafe { bo_map.data() };
|
||||||
if format == ScreenshotFormat::Qoi {
|
if format == ScreenshotFormat::Qoi {
|
||||||
return Ok(xrgb8888_encode_qoi(
|
return Ok(xrgb8888_encode_qoi(
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub use vulkan::create_vulkan_allocator;
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::AsyncEngine,
|
async_engine::AsyncEngine,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
mod allocator;
|
mod allocator;
|
||||||
|
mod bo_allocator;
|
||||||
mod command;
|
mod command;
|
||||||
mod descriptor;
|
mod descriptor;
|
||||||
mod device;
|
mod device;
|
||||||
|
|
@ -17,7 +18,7 @@ mod util;
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
allocator::Allocator,
|
allocator::{Allocator, AllocatorError},
|
||||||
async_engine::AsyncEngine,
|
async_engine::AsyncEngine,
|
||||||
format::Format,
|
format::Format,
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
|
|
@ -39,6 +40,7 @@ use {
|
||||||
ash::{vk, LoadingError},
|
ash::{vk, LoadingError},
|
||||||
gpu_alloc::{AllocationError, MapError},
|
gpu_alloc::{AllocationError, MapError},
|
||||||
jay_config::video::GfxApi,
|
jay_config::video::GfxApi,
|
||||||
|
log::Level,
|
||||||
once_cell::sync::Lazy,
|
once_cell::sync::Lazy,
|
||||||
std::{
|
std::{
|
||||||
cell::Cell,
|
cell::Cell,
|
||||||
|
|
@ -180,6 +182,20 @@ pub enum VulkanError {
|
||||||
GfxError(GfxError),
|
GfxError(GfxError),
|
||||||
#[error("Buffer format {0} is not supported for shm buffers in Vulkan context")]
|
#[error("Buffer format {0} is not supported for shm buffers in Vulkan context")]
|
||||||
UnsupportedShmFormat(&'static str),
|
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 {
|
impl From<VulkanError> for GfxError {
|
||||||
|
|
@ -196,12 +212,19 @@ pub fn create_graphics_context(
|
||||||
ring: &Rc<IoUring>,
|
ring: &Rc<IoUring>,
|
||||||
drm: &Drm,
|
drm: &Drm,
|
||||||
) -> Result<Rc<dyn GfxContext>, GfxError> {
|
) -> 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 device = instance.create_device(drm)?;
|
||||||
let renderer = device.create_renderer()?;
|
let renderer = device.create_renderer(eng, ring)?;
|
||||||
Ok(Rc::new(Context(renderer)))
|
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)]
|
#[derive(Debug)]
|
||||||
struct Context(Rc<VulkanRenderer>);
|
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_semaphore_fd: external_semaphore_fd::Device,
|
||||||
pub(super) external_fence_fd: external_fence_fd::Device,
|
pub(super) external_fence_fd: external_fence_fd::Device,
|
||||||
pub(super) push_descriptor: push_descriptor::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) formats: AHashMap<u32, VulkanFormat>,
|
||||||
pub(super) memory_types: ArrayVec<MemoryType, MAX_MEMORY_TYPES>,
|
pub(super) memory_types: ArrayVec<MemoryType, MAX_MEMORY_TYPES>,
|
||||||
pub(super) graphics_queue: Queue,
|
pub(super) graphics_queue: Queue,
|
||||||
|
|
@ -104,7 +105,8 @@ impl VulkanInstance {
|
||||||
Err(e) => return Err(VulkanError::Fstat(e.into())),
|
Err(e) => return Err(VulkanError::Fstat(e.into())),
|
||||||
};
|
};
|
||||||
let dev = stat.st_rdev;
|
let dev = stat.st_rdev;
|
||||||
log::info!(
|
log::log!(
|
||||||
|
self.log_level,
|
||||||
"Searching for vulkan device with devnum {}:{}",
|
"Searching for vulkan device with devnum {}:{}",
|
||||||
uapi::major(dev),
|
uapi::major(dev),
|
||||||
uapi::minor(dev)
|
uapi::minor(dev)
|
||||||
|
|
@ -153,8 +155,13 @@ impl VulkanInstance {
|
||||||
let render_dev =
|
let render_dev =
|
||||||
uapi::makedev(drm_props.render_major as _, drm_props.render_minor as _);
|
uapi::makedev(drm_props.render_major as _, drm_props.render_minor as _);
|
||||||
if primary_dev == dev || render_dev == dev {
|
if primary_dev == dev || render_dev == dev {
|
||||||
log::info!("Device with id {} matches", props.device_id);
|
log::log!(self.log_level, "Device with id {} matches", props.device_id);
|
||||||
log_device(&props, Some(&extensions), Some(&driver_props));
|
log_device(
|
||||||
|
self.log_level,
|
||||||
|
&props,
|
||||||
|
Some(&extensions),
|
||||||
|
Some(&driver_props),
|
||||||
|
);
|
||||||
return Ok(phy_dev);
|
return Ok(phy_dev);
|
||||||
}
|
}
|
||||||
devices.push((props, Some(extensions), Some(driver_props)));
|
devices.push((props, Some(extensions), Some(driver_props)));
|
||||||
|
|
@ -166,7 +173,12 @@ impl VulkanInstance {
|
||||||
for (props, extensions, driver_props) in devices.iter() {
|
for (props, extensions, driver_props) in devices.iter() {
|
||||||
log::warn!("Found the following devices but none matches:");
|
log::warn!("Found the following devices but none matches:");
|
||||||
log::warn!("-----");
|
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))
|
Err(VulkanError::NoDeviceFound(dev))
|
||||||
|
|
@ -264,6 +276,8 @@ impl VulkanInstance {
|
||||||
let external_semaphore_fd = external_semaphore_fd::Device::new(&self.instance, &device);
|
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 external_fence_fd = external_fence_fd::Device::new(&self.instance, &device);
|
||||||
let push_descriptor = push_descriptor::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 =
|
let memory_properties =
|
||||||
unsafe { self.instance.get_physical_device_memory_properties(phy_dev) };
|
unsafe { self.instance.get_physical_device_memory_properties(phy_dev) };
|
||||||
let memory_types = memory_properties.memory_types
|
let memory_types = memory_properties.memory_types
|
||||||
|
|
@ -283,6 +297,7 @@ impl VulkanInstance {
|
||||||
external_semaphore_fd,
|
external_semaphore_fd,
|
||||||
external_fence_fd,
|
external_fence_fd,
|
||||||
push_descriptor,
|
push_descriptor,
|
||||||
|
image_drm_format_modifier,
|
||||||
formats,
|
formats,
|
||||||
memory_types,
|
memory_types,
|
||||||
graphics_queue,
|
graphics_queue,
|
||||||
|
|
@ -302,20 +317,27 @@ const REQUIRED_DEVICE_EXTENSIONS: &[&CStr] = &[
|
||||||
];
|
];
|
||||||
|
|
||||||
fn log_device(
|
fn log_device(
|
||||||
|
level: log::Level,
|
||||||
props: &PhysicalDeviceProperties,
|
props: &PhysicalDeviceProperties,
|
||||||
extensions: Option<&Extensions>,
|
extensions: Option<&Extensions>,
|
||||||
driver_props: Option<&PhysicalDeviceDriverProperties>,
|
driver_props: Option<&PhysicalDeviceDriverProperties>,
|
||||||
) {
|
) {
|
||||||
log::info!(" api version: {}", ApiVersionDisplay(props.api_version));
|
log::log!(
|
||||||
log::info!(
|
level,
|
||||||
|
" api version: {}",
|
||||||
|
ApiVersionDisplay(props.api_version)
|
||||||
|
);
|
||||||
|
log::log!(
|
||||||
|
level,
|
||||||
" driver version: {}",
|
" driver version: {}",
|
||||||
ApiVersionDisplay(props.driver_version)
|
ApiVersionDisplay(props.driver_version)
|
||||||
);
|
);
|
||||||
log::info!(" vendor id: {}", props.vendor_id);
|
log::log!(level, " vendor id: {}", props.vendor_id);
|
||||||
log::info!(" device id: {}", props.device_id);
|
log::log!(level, " device id: {}", props.device_id);
|
||||||
log::info!(" device type: {:?}", props.device_type);
|
log::log!(level, " device type: {:?}", props.device_type);
|
||||||
unsafe {
|
unsafe {
|
||||||
log::info!(
|
log::log!(
|
||||||
|
level,
|
||||||
" device name: {}",
|
" device name: {}",
|
||||||
Ustr::from_ptr(props.device_name.as_ptr()).display()
|
Ustr::from_ptr(props.device_name.as_ptr()).display()
|
||||||
);
|
);
|
||||||
|
|
@ -330,7 +352,8 @@ fn log_device(
|
||||||
}
|
}
|
||||||
if let Some(driver_props) = driver_props {
|
if let Some(driver_props) = driver_props {
|
||||||
unsafe {
|
unsafe {
|
||||||
log::info!(
|
log::log!(
|
||||||
|
level,
|
||||||
" driver: {} ({})",
|
" driver: {} ({})",
|
||||||
Ustr::from_ptr(driver_props.driver_name.as_ptr()).display(),
|
Ustr::from_ptr(driver_props.driver_name.as_ptr()).display(),
|
||||||
Ustr::from_ptr(driver_props.driver_info.as_ptr()).display()
|
Ustr::from_ptr(driver_props.driver_info.as_ptr()).display()
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ pub struct VulkanModifier {
|
||||||
pub features: FormatFeatureFlags,
|
pub features: FormatFeatureFlags,
|
||||||
pub render_max_extents: Option<VulkanMaxExtents>,
|
pub render_max_extents: Option<VulkanMaxExtents>,
|
||||||
pub texture_max_extents: Option<VulkanMaxExtents>,
|
pub texture_max_extents: Option<VulkanMaxExtents>,
|
||||||
|
pub transfer_max_extents: Option<VulkanMaxExtents>,
|
||||||
pub render_needs_bridge: bool,
|
pub render_needs_bridge: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,24 +59,24 @@ const TEX_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw(
|
||||||
| FormatFeatureFlags::TRANSFER_SRC.as_raw()
|
| FormatFeatureFlags::TRANSFER_SRC.as_raw()
|
||||||
| FormatFeatureFlags::SAMPLED_IMAGE_FILTER_LINEAR.as_raw(),
|
| FormatFeatureFlags::SAMPLED_IMAGE_FILTER_LINEAR.as_raw(),
|
||||||
);
|
);
|
||||||
const SHM_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw(
|
const TRANSFER_FEATURES: FormatFeatureFlags = FormatFeatureFlags::from_raw(
|
||||||
0 | FormatFeatureFlags::TRANSFER_SRC.as_raw()
|
FormatFeatureFlags::TRANSFER_SRC.as_raw() | FormatFeatureFlags::TRANSFER_DST.as_raw(),
|
||||||
| FormatFeatureFlags::TRANSFER_DST.as_raw()
|
|
||||||
| TEX_FEATURES.as_raw(),
|
|
||||||
);
|
);
|
||||||
|
const SHM_FEATURES: FormatFeatureFlags =
|
||||||
|
FormatFeatureFlags::from_raw(TRANSFER_FEATURES.as_raw() | TEX_FEATURES.as_raw());
|
||||||
|
|
||||||
const FRAMEBUFFER_USAGE: ImageUsageFlags = ImageUsageFlags::from_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 FRAMEBUFFER_BRIDGED_USAGE: ImageUsageFlags = ImageUsageFlags::TRANSFER_DST;
|
||||||
const TEX_USAGE: ImageUsageFlags = ImageUsageFlags::from_raw(
|
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(
|
const TRANSFER_USAGE: ImageUsageFlags = ImageUsageFlags::from_raw(
|
||||||
0 | ImageUsageFlags::TRANSFER_SRC.as_raw()
|
ImageUsageFlags::TRANSFER_SRC.as_raw() | ImageUsageFlags::TRANSFER_DST.as_raw(),
|
||||||
| ImageUsageFlags::TRANSFER_DST.as_raw()
|
|
||||||
| TEX_USAGE.as_raw(),
|
|
||||||
);
|
);
|
||||||
|
const SHM_USAGE: ImageUsageFlags =
|
||||||
|
ImageUsageFlags::from_raw(TRANSFER_USAGE.as_raw() | TEX_USAGE.as_raw());
|
||||||
|
|
||||||
impl VulkanInstance {
|
impl VulkanInstance {
|
||||||
pub(super) fn load_formats(
|
pub(super) fn load_formats(
|
||||||
|
|
@ -209,6 +210,13 @@ impl VulkanInstance {
|
||||||
)?;
|
)?;
|
||||||
let texture_max_extents =
|
let texture_max_extents =
|
||||||
self.get_max_extents(phy_dev, format, TEX_FEATURES, TEX_USAGE, &modifier)?;
|
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;
|
let mut render_needs_bridge = false;
|
||||||
if render_max_extents.is_none() && modifier.drm_format_modifier == LINEAR_MODIFIER {
|
if render_max_extents.is_none() && modifier.drm_format_modifier == LINEAR_MODIFIER {
|
||||||
render_max_extents = self.get_fb_bridged_max_extents(
|
render_max_extents = self.get_fb_bridged_max_extents(
|
||||||
|
|
@ -229,6 +237,7 @@ impl VulkanInstance {
|
||||||
features: modifier.drm_format_modifier_tiling_features,
|
features: modifier.drm_format_modifier_tiling_features,
|
||||||
render_max_extents,
|
render_max_extents,
|
||||||
texture_max_extents,
|
texture_max_extents,
|
||||||
|
transfer_max_extents,
|
||||||
render_needs_bridge,
|
render_needs_bridge,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::gfx_apis::vulkan::{util::OnDrop, VulkanError, VULKAN_VALIDATION},
|
||||||
async_engine::AsyncEngine,
|
|
||||||
gfx_apis::vulkan::{util::OnDrop, VulkanError, VULKAN_VALIDATION},
|
|
||||||
io_uring::IoUring,
|
|
||||||
},
|
|
||||||
ahash::{AHashMap, AHashSet},
|
ahash::{AHashMap, AHashSet},
|
||||||
ash::{
|
ash::{
|
||||||
ext::{debug_utils, validation_features},
|
ext::{debug_utils, validation_features},
|
||||||
|
|
@ -35,16 +31,11 @@ pub struct VulkanInstance {
|
||||||
pub(super) instance: Instance,
|
pub(super) instance: Instance,
|
||||||
pub(super) debug_utils: debug_utils::Instance,
|
pub(super) debug_utils: debug_utils::Instance,
|
||||||
pub(super) messenger: DebugUtilsMessengerEXT,
|
pub(super) messenger: DebugUtilsMessengerEXT,
|
||||||
pub(super) eng: Rc<AsyncEngine>,
|
pub(super) log_level: Level,
|
||||||
pub(super) ring: Rc<IoUring>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VulkanInstance {
|
impl VulkanInstance {
|
||||||
pub fn new(
|
pub fn new(log_level: Level, validation: bool) -> Result<Rc<Self>, VulkanError> {
|
||||||
eng: &Rc<AsyncEngine>,
|
|
||||||
ring: &Rc<IoUring>,
|
|
||||||
validation: bool,
|
|
||||||
) -> Result<Rc<Self>, VulkanError> {
|
|
||||||
static ENTRY: Lazy<Result<Entry, Arc<LoadingError>>> =
|
static ENTRY: Lazy<Result<Entry, Arc<LoadingError>>> =
|
||||||
Lazy::new(|| unsafe { Entry::load() }.map_err(Arc::new));
|
Lazy::new(|| unsafe { Entry::load() }.map_err(Arc::new));
|
||||||
let entry = match &*ENTRY {
|
let entry = match &*ENTRY {
|
||||||
|
|
@ -127,8 +118,7 @@ impl VulkanInstance {
|
||||||
instance,
|
instance,
|
||||||
debug_utils,
|
debug_utils,
|
||||||
messenger,
|
messenger,
|
||||||
eng: eng.clone(),
|
log_level,
|
||||||
ring: ring.clone(),
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::SpawnedFuture,
|
async_engine::{AsyncEngine, SpawnedFuture},
|
||||||
format::Format,
|
format::Format,
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
AcquireSync, BufferResv, BufferResvUser, GfxApiOpt, GfxFormat, GfxFramebuffer,
|
AcquireSync, BufferResv, BufferResvUser, GfxApiOpt, GfxFormat, GfxFramebuffer,
|
||||||
|
|
@ -68,6 +68,8 @@ pub struct VulkanRenderer {
|
||||||
pub(super) allocator: Rc<VulkanAllocator>,
|
pub(super) allocator: Rc<VulkanAllocator>,
|
||||||
pub(super) last_point: NumCell<u64>,
|
pub(super) last_point: NumCell<u64>,
|
||||||
pub(super) buffer_resv_user: BufferResvUser,
|
pub(super) buffer_resv_user: BufferResvUser,
|
||||||
|
pub(super) eng: Rc<AsyncEngine>,
|
||||||
|
pub(super) ring: Rc<IoUring>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct UsedTexture {
|
pub(super) struct UsedTexture {
|
||||||
|
|
@ -111,7 +113,11 @@ pub(super) struct PendingFrame {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VulkanDevice {
|
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>(
|
let fill_pipeline = self.create_pipeline::<FillVertPushConstants, FillFragPushConstants>(
|
||||||
PipelineCreateInfo {
|
PipelineCreateInfo {
|
||||||
vert: self.create_shader(FILL_VERT)?,
|
vert: self.create_shader(FILL_VERT)?,
|
||||||
|
|
@ -196,6 +202,8 @@ impl VulkanDevice {
|
||||||
allocator,
|
allocator,
|
||||||
last_point: Default::default(),
|
last_point: Default::default(),
|
||||||
buffer_resv_user: 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(),
|
_release_fence: memory.release_fence.take(),
|
||||||
});
|
});
|
||||||
self.pending_frames.set(frame.point, frame.clone());
|
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(),
|
memory.release_sync_file.clone(),
|
||||||
self.device.instance.ring.clone(),
|
self.ring.clone(),
|
||||||
frame.clone(),
|
frame.clone(),
|
||||||
self.clone(),
|
self.clone(),
|
||||||
));
|
));
|
||||||
|
|
@ -776,7 +784,9 @@ impl VulkanRenderer {
|
||||||
height: tex.height,
|
height: tex.height,
|
||||||
depth: 1,
|
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_tex_barrier;
|
||||||
let initial_buffer_barrier = BufferMemoryBarrier2::default()
|
let initial_buffer_barrier = BufferMemoryBarrier2::default()
|
||||||
.buffer(staging.buffer)
|
.buffer(staging.buffer)
|
||||||
|
|
|
||||||
|
|
@ -104,9 +104,13 @@ impl VulkanShmImage {
|
||||||
cpy = slice::from_ref(&cpy_one);
|
cpy = slice::from_ref(&cpy_one);
|
||||||
total_size = img.height * img.stride;
|
total_size = img.height * img.stride;
|
||||||
}
|
}
|
||||||
let staging = img
|
let staging = img.renderer.device.create_staging_buffer(
|
||||||
.renderer
|
&img.renderer.allocator,
|
||||||
.create_staging_buffer(total_size as u64, true, false, true)?;
|
total_size as u64,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
)?;
|
||||||
staging.upload(|mem, _| unsafe {
|
staging.upload(|mem, _| unsafe {
|
||||||
let buf = buffer.as_ptr() as *const u8;
|
let buf = buffer.as_ptr() as *const u8;
|
||||||
if damage.is_some() {
|
if damage.is_some() {
|
||||||
|
|
@ -215,7 +219,7 @@ impl VulkanShmImage {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let point = img.renderer.allocate_point();
|
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,
|
point,
|
||||||
img.clone(),
|
img.clone(),
|
||||||
cmd,
|
cmd,
|
||||||
|
|
@ -236,13 +240,7 @@ async fn await_upload(
|
||||||
_fence: Rc<VulkanFence>,
|
_fence: Rc<VulkanFence>,
|
||||||
_staging: VulkanStagingBuffer,
|
_staging: VulkanStagingBuffer,
|
||||||
) {
|
) {
|
||||||
let res = img
|
let res = img.renderer.ring.readable(&sync_file.0).await;
|
||||||
.renderer
|
|
||||||
.device
|
|
||||||
.instance
|
|
||||||
.ring
|
|
||||||
.readable(&sync_file.0)
|
|
||||||
.await;
|
|
||||||
if let Err(e) = res {
|
if let Err(e) = res {
|
||||||
log::error!(
|
log::error!(
|
||||||
"Could not wait for sync file to become readable: {}",
|
"Could not wait for sync file to become readable: {}",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use {
|
use {
|
||||||
crate::gfx_apis::vulkan::{
|
crate::gfx_apis::vulkan::{
|
||||||
allocator::VulkanAllocation, device::VulkanDevice, renderer::VulkanRenderer, util::OnDrop,
|
allocator::{VulkanAllocation, VulkanAllocator},
|
||||||
|
device::VulkanDevice,
|
||||||
|
util::OnDrop,
|
||||||
VulkanError,
|
VulkanError,
|
||||||
},
|
},
|
||||||
ash::vk::{Buffer, BufferCreateInfo, BufferUsageFlags, MappedMemoryRange},
|
ash::vk::{Buffer, BufferCreateInfo, BufferUsageFlags, MappedMemoryRange},
|
||||||
|
|
@ -15,9 +17,10 @@ pub struct VulkanStagingBuffer {
|
||||||
pub(super) size: u64,
|
pub(super) size: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VulkanRenderer {
|
impl VulkanDevice {
|
||||||
pub(super) fn create_staging_buffer(
|
pub(super) fn create_staging_buffer(
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
|
allocator: &Rc<VulkanAllocator>,
|
||||||
size: u64,
|
size: u64,
|
||||||
upload: bool,
|
upload: bool,
|
||||||
download: bool,
|
download: bool,
|
||||||
|
|
@ -38,24 +41,22 @@ impl VulkanRenderer {
|
||||||
}
|
}
|
||||||
let buffer = {
|
let buffer = {
|
||||||
let create_info = BufferCreateInfo::default().size(size).usage(vk_usage);
|
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)?
|
buffer.map_err(VulkanError::CreateBuffer)?
|
||||||
};
|
};
|
||||||
let destroy_buffer = OnDrop(|| unsafe { self.device.device.destroy_buffer(buffer, None) });
|
let destroy_buffer = OnDrop(|| unsafe { self.device.destroy_buffer(buffer, None) });
|
||||||
let memory_requirements =
|
let memory_requirements = unsafe { self.device.get_buffer_memory_requirements(buffer) };
|
||||||
unsafe { self.device.device.get_buffer_memory_requirements(buffer) };
|
let allocation = allocator.alloc(&memory_requirements, usage, true)?;
|
||||||
let allocation = self.allocator.alloc(&memory_requirements, usage, true)?;
|
|
||||||
{
|
{
|
||||||
let res = unsafe {
|
let res = unsafe {
|
||||||
self.device
|
self.device
|
||||||
.device
|
|
||||||
.bind_buffer_memory(buffer, allocation.memory, allocation.offset)
|
.bind_buffer_memory(buffer, allocation.memory, allocation.offset)
|
||||||
};
|
};
|
||||||
res.map_err(VulkanError::BindBufferMemory)?;
|
res.map_err(VulkanError::BindBufferMemory)?;
|
||||||
}
|
}
|
||||||
destroy_buffer.forget();
|
destroy_buffer.forget();
|
||||||
Ok(VulkanStagingBuffer {
|
Ok(VulkanStagingBuffer {
|
||||||
device: self.device.clone(),
|
device: self.clone(),
|
||||||
allocation,
|
allocation,
|
||||||
buffer,
|
buffer,
|
||||||
size,
|
size,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
allocator::Allocator,
|
allocator::{Allocator, AllocatorError},
|
||||||
async_engine::SpawnedFuture,
|
async_engine::SpawnedFuture,
|
||||||
backend::{
|
backend::{
|
||||||
AxisSource, Backend, BackendEvent, Connector, ConnectorEvent, ConnectorId,
|
AxisSource, Backend, BackendEvent, Connector, ConnectorEvent, ConnectorId,
|
||||||
|
|
@ -12,6 +12,7 @@ use {
|
||||||
drm_feedback::DrmFeedback,
|
drm_feedback::DrmFeedback,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
gfx_api::GfxError,
|
gfx_api::GfxError,
|
||||||
|
gfx_apis::create_vulkan_allocator,
|
||||||
it::{
|
it::{
|
||||||
test_error::TestResult, test_gfx_api::TestGfxCtx, test_utils::test_expected_event::TEEH,
|
test_error::TestResult, test_gfx_api::TestGfxCtx, test_utils::test_expected_event::TEEH,
|
||||||
},
|
},
|
||||||
|
|
@ -46,6 +47,8 @@ pub enum TestBackendError {
|
||||||
CreateGbmDevice(#[source] GbmError),
|
CreateGbmDevice(#[source] GbmError),
|
||||||
#[error("Could not create any allocator")]
|
#[error("Could not create any allocator")]
|
||||||
CreateAllocator,
|
CreateAllocator,
|
||||||
|
#[error("Could not create a vulkan allocator")]
|
||||||
|
CreateVulkanAllocator(#[source] AllocatorError),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestBackend {
|
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() {
|
if self.render_context_installed.get() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
self.create_render_context(prefer_udmabuf)?;
|
self.create_render_context(need_drm)?;
|
||||||
self.render_context_installed.set(true);
|
self.render_context_installed.set(true);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install_default(&self) -> TestResult {
|
pub fn install_default(&self) -> TestResult {
|
||||||
self.install_default2(true)
|
self.install_default2(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install_default2(&self, prefer_udmabuf: bool) -> TestResult {
|
pub fn install_default2(&self, need_drm: bool) -> TestResult {
|
||||||
self.install_render_context(prefer_udmabuf)?;
|
self.install_render_context(need_drm)?;
|
||||||
self.state
|
self.state
|
||||||
.backend_events
|
.backend_events
|
||||||
.push(BackendEvent::NewConnector(self.default_connector.clone()));
|
.push(BackendEvent::NewConnector(self.default_connector.clone()));
|
||||||
|
|
@ -163,20 +166,25 @@ impl TestBackend {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_render_context(&self, prefer_udmabuf: bool) -> Result<(), TestBackendError> {
|
fn create_render_context(&self, need_drm: bool) -> Result<(), TestBackendError> {
|
||||||
macro_rules! constructor {
|
macro_rules! constructor {
|
||||||
($c:expr) => {
|
($c:expr) => {
|
||||||
(&|| {
|
constructor!($c, |a| Rc::new(a) as Rc<dyn Allocator>)
|
||||||
$c.map(|a| Rc::new(a) as Rc<dyn Allocator>)
|
};
|
||||||
.map_err(|e| Box::new(e) as Box<dyn Error>)
|
($c:expr, nomap) => {
|
||||||
}) as &dyn Fn() -> Result<Rc<dyn Allocator>, Box<dyn Error>>
|
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 udmabuf = ("udmabuf", constructor!(Udmabuf::new()));
|
||||||
|
let vulkan = ("Vulkan", constructor!(create_vk_allocator(), nomap));
|
||||||
let gbm = ("GBM", constructor!(create_gbm_allocator()));
|
let gbm = ("GBM", constructor!(create_gbm_allocator()));
|
||||||
let allocators = match prefer_udmabuf {
|
let allocators = match need_drm {
|
||||||
true => [udmabuf, gbm],
|
true => [vulkan, gbm, udmabuf],
|
||||||
false => [gbm, udmabuf],
|
false => [udmabuf, vulkan, gbm],
|
||||||
};
|
};
|
||||||
let mut allocator = None::<Rc<dyn Allocator>>;
|
let mut allocator = None::<Rc<dyn Allocator>>;
|
||||||
for (name, f) in allocators {
|
for (name, f) in allocators {
|
||||||
|
|
@ -201,6 +209,19 @@ impl TestBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_gbm_allocator() -> Result<GbmDevice, TestBackendError> {
|
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") {
|
let dri = match std::fs::read_dir("/dev/dri") {
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
Err(e) => return Err(TestBackendError::ReadDri(e)),
|
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 drm = Drm::open_existing(file);
|
||||||
let gbm = GbmDevice::new(&drm).map_err(TestBackendError::CreateGbmDevice)?;
|
f(drm)
|
||||||
Ok(gbm)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend for TestBackend {
|
impl Backend for TestBackend {
|
||||||
|
|
|
||||||
|
|
@ -106,14 +106,11 @@ impl TestRun {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_default_setup(&self) -> Result<DefaultSetup, TestError> {
|
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(
|
pub async fn create_default_setup2(&self, need_drm: bool) -> Result<DefaultSetup, TestError> {
|
||||||
&self,
|
self.backend.install_default2(need_drm)?;
|
||||||
prefer_udmabuf: bool,
|
|
||||||
) -> Result<DefaultSetup, TestError> {
|
|
||||||
self.backend.install_default2(prefer_udmabuf)?;
|
|
||||||
let seat = self.get_seat("default")?;
|
let seat = self.get_seat("default")?;
|
||||||
self.state.eng.yield_now().await;
|
self.state.eng.yield_now().await;
|
||||||
let output = match self.state.root.outputs.lock().values().next() {
|
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());
|
tassert!(!run.cfg.graphics_initialized.get());
|
||||||
|
|
||||||
run.backend.install_render_context(true)?;
|
run.backend.install_render_context(false)?;
|
||||||
|
|
||||||
tassert!(run.cfg.graphics_initialized.get());
|
tassert!(run.cfg.graphics_initialized.get());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use {
|
||||||
testcase!();
|
testcase!();
|
||||||
|
|
||||||
async fn test(run: Rc<TestRun>) -> TestResult {
|
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>);
|
struct Waiter(Cell<bool>);
|
||||||
impl SyncObjWaiter for Waiter {
|
impl SyncObjWaiter for Waiter {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use {
|
||||||
testcase!();
|
testcase!();
|
||||||
|
|
||||||
async fn test(run: Rc<TestRun>) -> TestResult {
|
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 scanout_feedback = {
|
||||||
let Some(base_fb) = run.state.drm_feedback.get() else {
|
let Some(base_fb) = run.state.drm_feedback.get() else {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue