gfx: implement async shm downloads
This commit is contained in:
parent
aca14d48dd
commit
028d0ed44c
11 changed files with 194 additions and 198 deletions
|
|
@ -5,7 +5,7 @@ use {
|
|||
format::{Format, XRGB8888},
|
||||
gfx_api::{
|
||||
AsyncShmGfxTexture, BufferResvUser, GfxContext, GfxError, GfxFormat, GfxFramebuffer,
|
||||
GfxImage, ResetStatus, ShmGfxTexture,
|
||||
GfxImage, GfxInternalFramebuffer, ResetStatus, ShmGfxTexture,
|
||||
},
|
||||
gfx_apis::gl::{
|
||||
egl::{context::EglContext, display::EglDisplay, image::EglImage},
|
||||
|
|
@ -316,13 +316,14 @@ impl GfxContext for GlRenderContext {
|
|||
GfxApi::OpenGl
|
||||
}
|
||||
|
||||
fn create_fb(
|
||||
fn create_internal_fb(
|
||||
self: Rc<Self>,
|
||||
_cpu_worker: &Rc<CpuWorker>,
|
||||
width: i32,
|
||||
height: i32,
|
||||
_stride: i32,
|
||||
format: &'static Format,
|
||||
) -> Result<Rc<dyn GfxFramebuffer>, GfxError> {
|
||||
) -> Result<Rc<dyn GfxInternalFramebuffer>, GfxError> {
|
||||
let fb = self.ctx.with_current(|| unsafe {
|
||||
GlRenderBuffer::new(&self.ctx, width, height, format)?.create_framebuffer()
|
||||
})?;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
use {
|
||||
crate::{
|
||||
format::Format,
|
||||
gfx_api::{AcquireSync, GfxApiOpt, GfxError, GfxFramebuffer, ReleaseSync, SyncFile},
|
||||
gfx_api::{
|
||||
AcquireSync, AsyncShmGfxTextureCallback, GfxApiOpt, GfxError, GfxFramebuffer,
|
||||
GfxInternalFramebuffer, GfxStagingBuffer, PendingShmTransfer, ReleaseSync, ShmMemory,
|
||||
SyncFile,
|
||||
},
|
||||
gfx_apis::gl::{
|
||||
gl::{
|
||||
frame_buffer::GlFrameBuffer,
|
||||
|
|
@ -13,6 +17,7 @@ use {
|
|||
sys::{GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
|
||||
RenderError,
|
||||
},
|
||||
rect::Region,
|
||||
theme::Color,
|
||||
},
|
||||
std::{
|
||||
|
|
@ -104,11 +109,31 @@ impl GfxFramebuffer for Framebuffer {
|
|||
self.render(acquire_sync, ops, clear).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn copy_to_shm(self: Rc<Self>, shm: &[Cell<u8>]) -> Result<(), GfxError> {
|
||||
(*self).copy_to_shm(shm).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn format(&self) -> &'static Format {
|
||||
self.gl.rb.format
|
||||
}
|
||||
}
|
||||
|
||||
impl GfxInternalFramebuffer for Framebuffer {
|
||||
fn into_fb(self: Rc<Self>) -> Rc<dyn GfxFramebuffer> {
|
||||
self
|
||||
}
|
||||
|
||||
fn staging_size(&self) -> usize {
|
||||
0
|
||||
}
|
||||
|
||||
fn download(
|
||||
self: Rc<Self>,
|
||||
_staging: &Rc<dyn GfxStagingBuffer>,
|
||||
_callback: Rc<dyn AsyncShmGfxTextureCallback>,
|
||||
mem: Rc<dyn ShmMemory>,
|
||||
_damage: Region,
|
||||
) -> Result<Option<PendingShmTransfer>, GfxError> {
|
||||
let mut res = Ok(());
|
||||
mem.access(&mut |mem| res = self.copy_to_shm(mem))
|
||||
.map_err(RenderError::AccessFailed)?;
|
||||
res?;
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ use {
|
|||
cpu_worker::{jobs::read_write::ReadWriteJobError, CpuWorker},
|
||||
format::Format,
|
||||
gfx_api::{
|
||||
AsyncShmGfxTexture, GfxContext, GfxError, GfxFormat, GfxFramebuffer, GfxImage,
|
||||
AsyncShmGfxTexture, GfxContext, GfxError, GfxFormat, GfxImage, GfxInternalFramebuffer,
|
||||
GfxStagingBuffer, ResetStatus, ShmGfxTexture, StagingBufferUsecase, STAGING_DOWNLOAD,
|
||||
STAGING_UPLOAD,
|
||||
},
|
||||
|
|
@ -316,16 +316,23 @@ impl GfxContext for Context {
|
|||
GfxApi::Vulkan
|
||||
}
|
||||
|
||||
fn create_fb(
|
||||
fn create_internal_fb(
|
||||
self: Rc<Self>,
|
||||
cpu_worker: &Rc<CpuWorker>,
|
||||
width: i32,
|
||||
height: i32,
|
||||
stride: i32,
|
||||
format: &'static Format,
|
||||
) -> Result<Rc<dyn GfxFramebuffer>, GfxError> {
|
||||
let fb = self
|
||||
.0
|
||||
.create_shm_texture(format, width, height, stride, &[], true, None)?;
|
||||
) -> Result<Rc<dyn GfxInternalFramebuffer>, GfxError> {
|
||||
let fb = self.0.create_shm_texture(
|
||||
format,
|
||||
width,
|
||||
height,
|
||||
stride,
|
||||
&[],
|
||||
true,
|
||||
Some(cpu_worker),
|
||||
)?;
|
||||
Ok(fb)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ use {
|
|||
gfx_api::{
|
||||
AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback,
|
||||
AsyncShmGfxTextureTransferCancellable, GfxApiOpt, GfxError, GfxFramebuffer, GfxImage,
|
||||
GfxStagingBuffer, GfxTexture, PendingShmTransfer, ReleaseSync, ShmGfxTexture,
|
||||
ShmMemory, SyncFile,
|
||||
GfxInternalFramebuffer, GfxStagingBuffer, GfxTexture, PendingShmTransfer, ReleaseSync,
|
||||
ShmGfxTexture, ShmMemory, SyncFile,
|
||||
},
|
||||
gfx_apis::vulkan::{
|
||||
allocator::VulkanAllocation, device::VulkanDevice, format::VulkanModifierLimits,
|
||||
|
|
@ -510,17 +510,46 @@ impl GfxFramebuffer for VulkanImage {
|
|||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn copy_to_shm(self: Rc<Self>, shm: &[Cell<u8>]) -> Result<(), GfxError> {
|
||||
self.renderer
|
||||
.read_all_pixels(&self, shm)
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn format(&self) -> &'static Format {
|
||||
self.format
|
||||
}
|
||||
}
|
||||
|
||||
impl GfxInternalFramebuffer for VulkanImage {
|
||||
fn into_fb(self: Rc<Self>) -> Rc<dyn GfxFramebuffer> {
|
||||
self
|
||||
}
|
||||
|
||||
fn staging_size(&self) -> usize {
|
||||
let VulkanImageMemory::Internal(shm) = &self.ty else {
|
||||
unreachable!();
|
||||
};
|
||||
shm.size as _
|
||||
}
|
||||
|
||||
fn download(
|
||||
self: Rc<Self>,
|
||||
staging: &Rc<dyn GfxStagingBuffer>,
|
||||
callback: Rc<dyn AsyncShmGfxTextureCallback>,
|
||||
mem: Rc<dyn ShmMemory>,
|
||||
damage: Region,
|
||||
) -> Result<Option<PendingShmTransfer>, GfxError> {
|
||||
let VulkanImageMemory::Internal(shm) = &self.ty else {
|
||||
unreachable!();
|
||||
};
|
||||
let staging = staging.clone().into_vk(&self.renderer.device.device);
|
||||
let pending = shm.async_transfer(
|
||||
&self,
|
||||
staging,
|
||||
&mem,
|
||||
damage,
|
||||
callback,
|
||||
TransferType::Download,
|
||||
)?;
|
||||
Ok(pending)
|
||||
}
|
||||
}
|
||||
|
||||
impl GfxTexture for VulkanImage {
|
||||
fn size(&self) -> (i32, i32) {
|
||||
(self.width as _, self.height as _)
|
||||
|
|
|
|||
|
|
@ -32,11 +32,10 @@ use {
|
|||
ash::{
|
||||
vk,
|
||||
vk::{
|
||||
AccessFlags2, AttachmentLoadOp, AttachmentStoreOp, BufferImageCopy,
|
||||
BufferMemoryBarrier2, ClearColorValue, ClearValue, CommandBuffer,
|
||||
CommandBufferBeginInfo, CommandBufferSubmitInfo, CommandBufferUsageFlags,
|
||||
CopyImageInfo2, DependencyInfo, DependencyInfoKHR, DescriptorImageInfo, DescriptorType,
|
||||
Extent2D, Extent3D, Fence, ImageAspectFlags, ImageCopy2, ImageLayout,
|
||||
AccessFlags2, AttachmentLoadOp, AttachmentStoreOp, ClearColorValue, ClearValue,
|
||||
CommandBuffer, CommandBufferBeginInfo, CommandBufferSubmitInfo,
|
||||
CommandBufferUsageFlags, CopyImageInfo2, DependencyInfoKHR, DescriptorImageInfo,
|
||||
DescriptorType, Extent2D, Extent3D, ImageAspectFlags, ImageCopy2, ImageLayout,
|
||||
ImageMemoryBarrier2, ImageSubresourceLayers, ImageSubresourceRange, PipelineBindPoint,
|
||||
PipelineStageFlags2, Rect2D, RenderingAttachmentInfo, RenderingInfo,
|
||||
SemaphoreSubmitInfo, SemaphoreSubmitInfoKHR, ShaderStageFlags, SubmitInfo2, Viewport,
|
||||
|
|
@ -49,7 +48,7 @@ use {
|
|||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
fmt::{Debug, Formatter},
|
||||
mem, ptr,
|
||||
mem,
|
||||
rc::Rc,
|
||||
slice,
|
||||
},
|
||||
|
|
@ -905,143 +904,6 @@ impl VulkanRenderer {
|
|||
frame.waiter.set(Some(future));
|
||||
}
|
||||
|
||||
pub(super) fn read_all_pixels(
|
||||
self: &Rc<Self>,
|
||||
tex: &VulkanImage,
|
||||
dst: &[Cell<u8>],
|
||||
) -> Result<(), VulkanError> {
|
||||
let Some(shm_info) = &tex.format.shm_info else {
|
||||
return Err(VulkanError::UnsupportedShmFormat(tex.format.name));
|
||||
};
|
||||
let size = tex.stride as u64 * tex.height as u64;
|
||||
if size != dst.len() as u64 {
|
||||
return Err(VulkanError::InvalidBufferSize);
|
||||
}
|
||||
let region = BufferImageCopy::default()
|
||||
.buffer_row_length(tex.stride / shm_info.bpp)
|
||||
.buffer_image_height(tex.height)
|
||||
.image_subresource(ImageSubresourceLayers {
|
||||
aspect_mask: ImageAspectFlags::COLOR,
|
||||
mip_level: 0,
|
||||
base_array_layer: 0,
|
||||
layer_count: 1,
|
||||
})
|
||||
.image_extent(Extent3D {
|
||||
width: tex.width,
|
||||
height: tex.height,
|
||||
depth: 1,
|
||||
});
|
||||
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)
|
||||
.offset(0)
|
||||
.size(staging.size)
|
||||
.dst_access_mask(AccessFlags2::TRANSFER_WRITE)
|
||||
.dst_stage_mask(PipelineStageFlags2::TRANSFER);
|
||||
let mut initial_barriers = DependencyInfo::default()
|
||||
.buffer_memory_barriers(slice::from_ref(&initial_buffer_barrier));
|
||||
if tex.bridge.is_none() {
|
||||
initial_tex_barrier = image_barrier()
|
||||
.src_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT)
|
||||
.dst_queue_family_index(self.device.graphics_queue_idx)
|
||||
.image(tex.image)
|
||||
.old_layout(ImageLayout::GENERAL)
|
||||
.new_layout(ImageLayout::TRANSFER_SRC_OPTIMAL)
|
||||
.dst_access_mask(AccessFlags2::TRANSFER_READ)
|
||||
.dst_stage_mask(PipelineStageFlags2::TRANSFER);
|
||||
initial_barriers =
|
||||
initial_barriers.image_memory_barriers(slice::from_ref(&initial_tex_barrier));
|
||||
}
|
||||
let final_tex_barrier;
|
||||
let final_buffer_barrier = BufferMemoryBarrier2::default()
|
||||
.buffer(staging.buffer)
|
||||
.offset(0)
|
||||
.size(staging.size)
|
||||
.src_access_mask(AccessFlags2::TRANSFER_WRITE)
|
||||
.src_stage_mask(PipelineStageFlags2::TRANSFER)
|
||||
.dst_access_mask(AccessFlags2::HOST_READ)
|
||||
.dst_stage_mask(PipelineStageFlags2::HOST);
|
||||
let mut final_barriers = DependencyInfo::default()
|
||||
.buffer_memory_barriers(slice::from_ref(&final_buffer_barrier));
|
||||
if tex.bridge.is_none() {
|
||||
final_tex_barrier = image_barrier()
|
||||
.src_queue_family_index(self.device.graphics_queue_idx)
|
||||
.dst_queue_family_index(QUEUE_FAMILY_FOREIGN_EXT)
|
||||
.image(tex.image)
|
||||
.old_layout(ImageLayout::TRANSFER_SRC_OPTIMAL)
|
||||
.new_layout(ImageLayout::GENERAL)
|
||||
.src_access_mask(AccessFlags2::TRANSFER_READ)
|
||||
.src_stage_mask(PipelineStageFlags2::TRANSFER);
|
||||
final_barriers =
|
||||
final_barriers.image_memory_barriers(slice::from_ref(&final_tex_barrier));
|
||||
}
|
||||
let buf = self.gfx_command_buffers.allocate()?;
|
||||
let mut semaphores = vec![];
|
||||
let mut semaphore_infos = vec![];
|
||||
if let VulkanImageMemory::DmaBuf(buf) = &tex.ty {
|
||||
for plane in &buf.template.dmabuf.planes {
|
||||
let fd = dma_buf_export_sync_file(&plane.fd, DMA_BUF_SYNC_READ)
|
||||
.map_err(VulkanError::IoctlExportSyncFile)?;
|
||||
let semaphore = self.allocate_semaphore()?;
|
||||
semaphore.import_sync_file(fd)?;
|
||||
let semaphore_info = SemaphoreSubmitInfo::default()
|
||||
.semaphore(semaphore.semaphore)
|
||||
.stage_mask(PipelineStageFlags2::TOP_OF_PIPE);
|
||||
semaphores.push(semaphore);
|
||||
semaphore_infos.push(semaphore_info);
|
||||
}
|
||||
}
|
||||
let command_buffer_info = CommandBufferSubmitInfo::default().command_buffer(buf.buffer);
|
||||
let submit_info = SubmitInfo2::default()
|
||||
.wait_semaphore_infos(&semaphore_infos)
|
||||
.command_buffer_infos(slice::from_ref(&command_buffer_info));
|
||||
let begin_info =
|
||||
CommandBufferBeginInfo::default().flags(CommandBufferUsageFlags::ONE_TIME_SUBMIT);
|
||||
unsafe {
|
||||
self.device
|
||||
.device
|
||||
.begin_command_buffer(buf.buffer, &begin_info)
|
||||
.map_err(VulkanError::BeginCommandBuffer)?;
|
||||
self.device
|
||||
.device
|
||||
.cmd_pipeline_barrier2(buf.buffer, &initial_barriers);
|
||||
self.device.device.cmd_copy_image_to_buffer(
|
||||
buf.buffer,
|
||||
tex.image,
|
||||
ImageLayout::TRANSFER_SRC_OPTIMAL,
|
||||
staging.buffer,
|
||||
&[region],
|
||||
);
|
||||
self.device
|
||||
.device
|
||||
.cmd_pipeline_barrier2(buf.buffer, &final_barriers);
|
||||
self.device
|
||||
.device
|
||||
.end_command_buffer(buf.buffer)
|
||||
.map_err(VulkanError::EndCommandBuffer)?;
|
||||
self.device
|
||||
.device
|
||||
.queue_submit2(
|
||||
self.device.graphics_queue,
|
||||
slice::from_ref(&submit_info),
|
||||
Fence::null(),
|
||||
)
|
||||
.map_err(VulkanError::Submit)?;
|
||||
}
|
||||
self.block();
|
||||
self.gfx_command_buffers.buffers.push(buf);
|
||||
for semaphore in semaphores {
|
||||
self.wait_semaphores.push(semaphore);
|
||||
}
|
||||
staging.download(|mem, size| unsafe {
|
||||
ptr::copy_nonoverlapping(mem, dst.as_ptr() as _, size);
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn execute(
|
||||
self: &Rc<Self>,
|
||||
fb: &VulkanImage,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue