gfx: implement async shm downloads
This commit is contained in:
parent
aca14d48dd
commit
028d0ed44c
11 changed files with 194 additions and 198 deletions
|
|
@ -265,11 +265,23 @@ pub trait GfxFramebuffer: Debug {
|
||||||
clear: Option<&Color>,
|
clear: Option<&Color>,
|
||||||
) -> Result<Option<SyncFile>, GfxError>;
|
) -> Result<Option<SyncFile>, GfxError>;
|
||||||
|
|
||||||
fn copy_to_shm(self: Rc<Self>, shm: &[Cell<u8>]) -> Result<(), GfxError>;
|
|
||||||
|
|
||||||
fn format(&self) -> &'static Format;
|
fn format(&self) -> &'static Format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait GfxInternalFramebuffer: GfxFramebuffer {
|
||||||
|
fn into_fb(self: Rc<Self>) -> Rc<dyn GfxFramebuffer>;
|
||||||
|
|
||||||
|
fn staging_size(&self) -> usize;
|
||||||
|
|
||||||
|
fn download(
|
||||||
|
self: Rc<Self>,
|
||||||
|
staging: &Rc<dyn GfxStagingBuffer>,
|
||||||
|
callback: Rc<dyn AsyncShmGfxTextureCallback>,
|
||||||
|
mem: Rc<dyn ShmMemory>,
|
||||||
|
damage: Region,
|
||||||
|
) -> Result<Option<PendingShmTransfer>, GfxError>;
|
||||||
|
}
|
||||||
|
|
||||||
impl dyn GfxFramebuffer {
|
impl dyn GfxFramebuffer {
|
||||||
pub fn clear(
|
pub fn clear(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -593,13 +605,14 @@ pub trait GfxContext: Debug {
|
||||||
|
|
||||||
fn gfx_api(&self) -> GfxApi;
|
fn gfx_api(&self) -> GfxApi;
|
||||||
|
|
||||||
fn create_fb(
|
fn create_internal_fb(
|
||||||
self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
|
cpu_worker: &Rc<CpuWorker>,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
stride: i32,
|
stride: i32,
|
||||||
format: &'static Format,
|
format: &'static Format,
|
||||||
) -> Result<Rc<dyn GfxFramebuffer>, GfxError>;
|
) -> Result<Rc<dyn GfxInternalFramebuffer>, GfxError>;
|
||||||
|
|
||||||
fn sync_obj_ctx(&self) -> Option<&Rc<SyncObjCtx>>;
|
fn sync_obj_ctx(&self) -> Option<&Rc<SyncObjCtx>>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use {
|
||||||
format::{Format, XRGB8888},
|
format::{Format, XRGB8888},
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
AsyncShmGfxTexture, BufferResvUser, GfxContext, GfxError, GfxFormat, GfxFramebuffer,
|
AsyncShmGfxTexture, BufferResvUser, GfxContext, GfxError, GfxFormat, GfxFramebuffer,
|
||||||
GfxImage, ResetStatus, ShmGfxTexture,
|
GfxImage, GfxInternalFramebuffer, ResetStatus, ShmGfxTexture,
|
||||||
},
|
},
|
||||||
gfx_apis::gl::{
|
gfx_apis::gl::{
|
||||||
egl::{context::EglContext, display::EglDisplay, image::EglImage},
|
egl::{context::EglContext, display::EglDisplay, image::EglImage},
|
||||||
|
|
@ -316,13 +316,14 @@ impl GfxContext for GlRenderContext {
|
||||||
GfxApi::OpenGl
|
GfxApi::OpenGl
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_fb(
|
fn create_internal_fb(
|
||||||
self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
|
_cpu_worker: &Rc<CpuWorker>,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
_stride: i32,
|
_stride: i32,
|
||||||
format: &'static Format,
|
format: &'static Format,
|
||||||
) -> Result<Rc<dyn GfxFramebuffer>, GfxError> {
|
) -> Result<Rc<dyn GfxInternalFramebuffer>, GfxError> {
|
||||||
let fb = self.ctx.with_current(|| unsafe {
|
let fb = self.ctx.with_current(|| unsafe {
|
||||||
GlRenderBuffer::new(&self.ctx, width, height, format)?.create_framebuffer()
|
GlRenderBuffer::new(&self.ctx, width, height, format)?.create_framebuffer()
|
||||||
})?;
|
})?;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
format::Format,
|
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::{
|
gfx_apis::gl::{
|
||||||
gl::{
|
gl::{
|
||||||
frame_buffer::GlFrameBuffer,
|
frame_buffer::GlFrameBuffer,
|
||||||
|
|
@ -13,6 +17,7 @@ use {
|
||||||
sys::{GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
|
sys::{GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
|
||||||
RenderError,
|
RenderError,
|
||||||
},
|
},
|
||||||
|
rect::Region,
|
||||||
theme::Color,
|
theme::Color,
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -104,11 +109,31 @@ impl GfxFramebuffer for Framebuffer {
|
||||||
self.render(acquire_sync, ops, clear).map_err(|e| e.into())
|
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 {
|
fn format(&self) -> &'static Format {
|
||||||
self.gl.rb.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},
|
cpu_worker::{jobs::read_write::ReadWriteJobError, CpuWorker},
|
||||||
format::Format,
|
format::Format,
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
AsyncShmGfxTexture, GfxContext, GfxError, GfxFormat, GfxFramebuffer, GfxImage,
|
AsyncShmGfxTexture, GfxContext, GfxError, GfxFormat, GfxImage, GfxInternalFramebuffer,
|
||||||
GfxStagingBuffer, ResetStatus, ShmGfxTexture, StagingBufferUsecase, STAGING_DOWNLOAD,
|
GfxStagingBuffer, ResetStatus, ShmGfxTexture, StagingBufferUsecase, STAGING_DOWNLOAD,
|
||||||
STAGING_UPLOAD,
|
STAGING_UPLOAD,
|
||||||
},
|
},
|
||||||
|
|
@ -316,16 +316,23 @@ impl GfxContext for Context {
|
||||||
GfxApi::Vulkan
|
GfxApi::Vulkan
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_fb(
|
fn create_internal_fb(
|
||||||
self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
|
cpu_worker: &Rc<CpuWorker>,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
stride: i32,
|
stride: i32,
|
||||||
format: &'static Format,
|
format: &'static Format,
|
||||||
) -> Result<Rc<dyn GfxFramebuffer>, GfxError> {
|
) -> Result<Rc<dyn GfxInternalFramebuffer>, GfxError> {
|
||||||
let fb = self
|
let fb = self.0.create_shm_texture(
|
||||||
.0
|
format,
|
||||||
.create_shm_texture(format, width, height, stride, &[], true, None)?;
|
width,
|
||||||
|
height,
|
||||||
|
stride,
|
||||||
|
&[],
|
||||||
|
true,
|
||||||
|
Some(cpu_worker),
|
||||||
|
)?;
|
||||||
Ok(fb)
|
Ok(fb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ use {
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback,
|
AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback,
|
||||||
AsyncShmGfxTextureTransferCancellable, GfxApiOpt, GfxError, GfxFramebuffer, GfxImage,
|
AsyncShmGfxTextureTransferCancellable, GfxApiOpt, GfxError, GfxFramebuffer, GfxImage,
|
||||||
GfxStagingBuffer, GfxTexture, PendingShmTransfer, ReleaseSync, ShmGfxTexture,
|
GfxInternalFramebuffer, GfxStagingBuffer, GfxTexture, PendingShmTransfer, ReleaseSync,
|
||||||
ShmMemory, SyncFile,
|
ShmGfxTexture, ShmMemory, SyncFile,
|
||||||
},
|
},
|
||||||
gfx_apis::vulkan::{
|
gfx_apis::vulkan::{
|
||||||
allocator::VulkanAllocation, device::VulkanDevice, format::VulkanModifierLimits,
|
allocator::VulkanAllocation, device::VulkanDevice, format::VulkanModifierLimits,
|
||||||
|
|
@ -510,17 +510,46 @@ impl GfxFramebuffer for VulkanImage {
|
||||||
.map_err(|e| e.into())
|
.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 {
|
fn format(&self) -> &'static Format {
|
||||||
self.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 {
|
impl GfxTexture for VulkanImage {
|
||||||
fn size(&self) -> (i32, i32) {
|
fn size(&self) -> (i32, i32) {
|
||||||
(self.width as _, self.height as _)
|
(self.width as _, self.height as _)
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,10 @@ use {
|
||||||
ash::{
|
ash::{
|
||||||
vk,
|
vk,
|
||||||
vk::{
|
vk::{
|
||||||
AccessFlags2, AttachmentLoadOp, AttachmentStoreOp, BufferImageCopy,
|
AccessFlags2, AttachmentLoadOp, AttachmentStoreOp, ClearColorValue, ClearValue,
|
||||||
BufferMemoryBarrier2, ClearColorValue, ClearValue, CommandBuffer,
|
CommandBuffer, CommandBufferBeginInfo, CommandBufferSubmitInfo,
|
||||||
CommandBufferBeginInfo, CommandBufferSubmitInfo, CommandBufferUsageFlags,
|
CommandBufferUsageFlags, CopyImageInfo2, DependencyInfoKHR, DescriptorImageInfo,
|
||||||
CopyImageInfo2, DependencyInfo, DependencyInfoKHR, DescriptorImageInfo, DescriptorType,
|
DescriptorType, Extent2D, Extent3D, ImageAspectFlags, ImageCopy2, ImageLayout,
|
||||||
Extent2D, Extent3D, Fence, ImageAspectFlags, ImageCopy2, ImageLayout,
|
|
||||||
ImageMemoryBarrier2, ImageSubresourceLayers, ImageSubresourceRange, PipelineBindPoint,
|
ImageMemoryBarrier2, ImageSubresourceLayers, ImageSubresourceRange, PipelineBindPoint,
|
||||||
PipelineStageFlags2, Rect2D, RenderingAttachmentInfo, RenderingInfo,
|
PipelineStageFlags2, Rect2D, RenderingAttachmentInfo, RenderingInfo,
|
||||||
SemaphoreSubmitInfo, SemaphoreSubmitInfoKHR, ShaderStageFlags, SubmitInfo2, Viewport,
|
SemaphoreSubmitInfo, SemaphoreSubmitInfoKHR, ShaderStageFlags, SubmitInfo2, Viewport,
|
||||||
|
|
@ -49,7 +48,7 @@ use {
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
mem, ptr,
|
mem,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
slice,
|
slice,
|
||||||
},
|
},
|
||||||
|
|
@ -905,143 +904,6 @@ impl VulkanRenderer {
|
||||||
frame.waiter.set(Some(future));
|
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(
|
pub fn execute(
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
fb: &VulkanImage,
|
fb: &VulkanImage,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{Client, ClientError},
|
client::{Client, ClientError},
|
||||||
format::XRGB8888,
|
format::XRGB8888,
|
||||||
|
gfx_api::{AsyncShmGfxTextureCallback, GfxError, PendingShmTransfer},
|
||||||
ifs::{
|
ifs::{
|
||||||
wl_buffer::{WlBuffer, WlBufferError, WlBufferStorage},
|
wl_buffer::{WlBuffer, WlBufferError, WlBufferStorage},
|
||||||
wl_output::OutputGlobalOpt,
|
wl_output::OutputGlobalOpt,
|
||||||
|
|
@ -9,6 +10,7 @@ use {
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Object, Version},
|
object::{Object, Version},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
|
utils::errorfmt::ErrorFmt,
|
||||||
wire::{zwlr_screencopy_frame_v1::*, WlBufferId, ZwlrScreencopyFrameV1Id},
|
wire::{zwlr_screencopy_frame_v1::*, WlBufferId, ZwlrScreencopyFrameV1Id},
|
||||||
},
|
},
|
||||||
std::{cell::Cell, ops::Deref, rc::Rc},
|
std::{cell::Cell, ops::Deref, rc::Rc},
|
||||||
|
|
@ -29,6 +31,7 @@ pub struct ZwlrScreencopyFrameV1 {
|
||||||
pub with_damage: Cell<bool>,
|
pub with_damage: Cell<bool>,
|
||||||
pub buffer: Cell<Option<Rc<WlBuffer>>>,
|
pub buffer: Cell<Option<Rc<WlBuffer>>>,
|
||||||
pub version: Version,
|
pub version: Version,
|
||||||
|
pub pending: Cell<Option<PendingShmTransfer>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ZwlrScreencopyFrameV1 {
|
impl ZwlrScreencopyFrameV1 {
|
||||||
|
|
@ -132,6 +135,7 @@ impl ZwlrScreencopyFrameV1 {
|
||||||
node.screencopies.remove(&(self.client.id, self.id));
|
node.screencopies.remove(&(self.client.id, self.id));
|
||||||
node.screencast_changed();
|
node.screencast_changed();
|
||||||
}
|
}
|
||||||
|
self.pending.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,6 +157,22 @@ impl ZwlrScreencopyFrameV1RequestHandler for ZwlrScreencopyFrameV1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsyncShmGfxTextureCallback for ZwlrScreencopyFrameV1 {
|
||||||
|
fn completed(self: Rc<Self>, res: Result<(), GfxError>) {
|
||||||
|
self.pending.take();
|
||||||
|
match res {
|
||||||
|
Ok(_) => {
|
||||||
|
let now = self.client.state.now();
|
||||||
|
self.send_ready(now.0.tv_sec as _, now.0.tv_nsec as _);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Could not perform shm screencopy: {}", ErrorFmt(e));
|
||||||
|
self.send_failed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object_base! {
|
object_base! {
|
||||||
self = ZwlrScreencopyFrameV1;
|
self = ZwlrScreencopyFrameV1;
|
||||||
version = self.version;
|
version = self.version;
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,7 @@ impl ZwlrScreencopyManagerV1 {
|
||||||
with_damage: Cell::new(false),
|
with_damage: Cell::new(false),
|
||||||
buffer: Cell::new(None),
|
buffer: Cell::new(None),
|
||||||
version: self.version,
|
version: self.version,
|
||||||
|
pending: Default::default(),
|
||||||
});
|
});
|
||||||
track!(self.client, frame);
|
track!(self.client, frame);
|
||||||
self.client.add_client_obj(&frame)?;
|
self.client.add_client_obj(&frame)?;
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ use {
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback, CopyTexture, FillRect,
|
AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback, CopyTexture, FillRect,
|
||||||
FramebufferRect, GfxApiOpt, GfxContext, GfxError, GfxFormat, GfxFramebuffer, GfxImage,
|
FramebufferRect, GfxApiOpt, GfxContext, GfxError, GfxFormat, GfxFramebuffer, GfxImage,
|
||||||
GfxStagingBuffer, GfxTexture, GfxWriteModifier, PendingShmTransfer, ReleaseSync,
|
GfxInternalFramebuffer, GfxStagingBuffer, GfxTexture, GfxWriteModifier,
|
||||||
ResetStatus, ShmGfxTexture, ShmMemory, SyncFile,
|
PendingShmTransfer, ReleaseSync, ResetStatus, ShmGfxTexture, ShmMemory, SyncFile,
|
||||||
},
|
},
|
||||||
rect::{Rect, Region},
|
rect::{Rect, Region},
|
||||||
theme::Color,
|
theme::Color,
|
||||||
|
|
@ -165,13 +165,14 @@ impl GfxContext for TestGfxCtx {
|
||||||
GfxApi::OpenGl
|
GfxApi::OpenGl
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_fb(
|
fn create_internal_fb(
|
||||||
self: Rc<Self>,
|
self: Rc<Self>,
|
||||||
|
_cpu_worker: &Rc<CpuWorker>,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
stride: i32,
|
stride: i32,
|
||||||
format: &'static Format,
|
format: &'static Format,
|
||||||
) -> Result<Rc<dyn GfxFramebuffer>, GfxError> {
|
) -> Result<Rc<dyn GfxInternalFramebuffer>, GfxError> {
|
||||||
assert!(stride >= width * 4);
|
assert!(stride >= width * 4);
|
||||||
Ok(Rc::new(TestGfxFb {
|
Ok(Rc::new(TestGfxFb {
|
||||||
img: Rc::new(TestGfxImage::Shm(TestShmGfxImage {
|
img: Rc::new(TestGfxImage::Shm(TestShmGfxImage {
|
||||||
|
|
@ -548,15 +549,34 @@ impl GfxFramebuffer for TestGfxFb {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_to_shm(self: Rc<Self>, shm: &[Cell<u8>]) -> Result<(), GfxError> {
|
|
||||||
self.img.deref().read_pixels(shm)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format(&self) -> &'static Format {
|
fn format(&self) -> &'static Format {
|
||||||
&ARGB8888
|
&ARGB8888
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GfxInternalFramebuffer for TestGfxFb {
|
||||||
|
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.img.deref().read_pixels(mem))
|
||||||
|
.map_err(TestGfxError::AccessFailed)?;
|
||||||
|
res.map(|_| None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl dyn GfxTexture {
|
impl dyn GfxTexture {
|
||||||
fn as_native(&self) -> &TestGfxImage {
|
fn as_native(&self) -> &TestGfxImage {
|
||||||
self.as_any()
|
self.as_any()
|
||||||
|
|
|
||||||
41
src/state.rs
41
src/state.rs
|
|
@ -27,8 +27,8 @@ use {
|
||||||
forker::ForkerProxy,
|
forker::ForkerProxy,
|
||||||
format::Format,
|
format::Format,
|
||||||
gfx_api::{
|
gfx_api::{
|
||||||
AcquireSync, BufferResv, GfxContext, GfxError, GfxFramebuffer, GfxTexture, ReleaseSync,
|
AcquireSync, BufferResv, GfxContext, GfxError, GfxFramebuffer, GfxTexture,
|
||||||
SampleRect, SyncFile,
|
PendingShmTransfer, ReleaseSync, SampleRect, SyncFile, STAGING_DOWNLOAD,
|
||||||
},
|
},
|
||||||
gfx_apis::create_gfx_context,
|
gfx_apis::create_gfx_context,
|
||||||
globals::{Globals, GlobalsError, RemovableWaylandGlobal, WaylandGlobal},
|
globals::{Globals, GlobalsError, RemovableWaylandGlobal, WaylandGlobal},
|
||||||
|
|
@ -62,7 +62,7 @@ use {
|
||||||
io_uring::IoUring,
|
io_uring::IoUring,
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
logger::Logger,
|
logger::Logger,
|
||||||
rect::Rect,
|
rect::{Rect, Region},
|
||||||
renderer::Renderer,
|
renderer::Renderer,
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
security_context_acceptor::SecurityContextAcceptors,
|
security_context_acceptor::SecurityContextAcceptors,
|
||||||
|
|
@ -1014,25 +1014,32 @@ impl State {
|
||||||
x_off: i32,
|
x_off: i32,
|
||||||
y_off: i32,
|
y_off: i32,
|
||||||
size: Option<(i32, i32)>,
|
size: Option<(i32, i32)>,
|
||||||
capture: &ZwlrScreencopyFrameV1,
|
capture: &Rc<ZwlrScreencopyFrameV1>,
|
||||||
mem: &ClientMemOffset,
|
mem: &Rc<ClientMemOffset>,
|
||||||
stride: i32,
|
stride: i32,
|
||||||
format: &'static Format,
|
format: &'static Format,
|
||||||
transform: Transform,
|
transform: Transform,
|
||||||
scale: Scale,
|
scale: Scale,
|
||||||
) -> Result<(), ShmScreencopyError> {
|
) -> Result<Option<PendingShmTransfer>, ShmScreencopyError> {
|
||||||
let Some(ctx) = self.render_ctx.get() else {
|
let Some(ctx) = self.render_ctx.get() else {
|
||||||
return Err(ShmScreencopyError::NoRenderContext);
|
return Err(ShmScreencopyError::NoRenderContext);
|
||||||
};
|
};
|
||||||
let fb = ctx
|
let fb = ctx
|
||||||
.create_fb(capture.rect.width(), capture.rect.height(), stride, format)
|
.clone()
|
||||||
|
.create_internal_fb(
|
||||||
|
&self.cpu_worker,
|
||||||
|
capture.rect.width(),
|
||||||
|
capture.rect.height(),
|
||||||
|
stride,
|
||||||
|
format,
|
||||||
|
)
|
||||||
.map_err(ShmScreencopyError::CreateTemporaryFb)?;
|
.map_err(ShmScreencopyError::CreateTemporaryFb)?;
|
||||||
self.perform_screencopy(
|
self.perform_screencopy(
|
||||||
src,
|
src,
|
||||||
None,
|
None,
|
||||||
acquire_sync,
|
acquire_sync,
|
||||||
ReleaseSync::None,
|
ReleaseSync::None,
|
||||||
&fb,
|
&fb.clone().into_fb(),
|
||||||
AcquireSync::Unnecessary,
|
AcquireSync::Unnecessary,
|
||||||
ReleaseSync::None,
|
ReleaseSync::None,
|
||||||
transform,
|
transform,
|
||||||
|
|
@ -1045,14 +1052,16 @@ impl State {
|
||||||
scale,
|
scale,
|
||||||
)
|
)
|
||||||
.map_err(ShmScreencopyError::CopyToTemporary)?;
|
.map_err(ShmScreencopyError::CopyToTemporary)?;
|
||||||
let acc = mem.access(|mem| fb.copy_to_shm(mem));
|
let staging = ctx.create_staging_buffer(fb.staging_size(), STAGING_DOWNLOAD);
|
||||||
match acc {
|
let pending = fb
|
||||||
Ok(res) => res.map_err(ShmScreencopyError::ReadPixels),
|
.download(
|
||||||
Err(e) => {
|
&staging,
|
||||||
capture.client.error(e);
|
capture.clone(),
|
||||||
Ok(())
|
mem.clone(),
|
||||||
}
|
Region::new2(capture.rect.at_point(0, 0)),
|
||||||
}
|
)
|
||||||
|
.map_err(ShmScreencopyError::ReadPixels)?;
|
||||||
|
Ok(pending)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_seat(self: &Rc<Self>, name: &str) -> Rc<WlSeatGlobal> {
|
pub fn create_seat(self: &Rc<Self>, name: &str) -> Rc<WlSeatGlobal> {
|
||||||
|
|
|
||||||
|
|
@ -267,6 +267,7 @@ impl OutputNode {
|
||||||
capture.send_failed();
|
capture.send_failed();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
let mut ready = true;
|
||||||
if let Some(storage) = wl_buffer.storage.borrow_mut().deref() {
|
if let Some(storage) = wl_buffer.storage.borrow_mut().deref() {
|
||||||
match storage {
|
match storage {
|
||||||
WlBufferStorage::Shm { mem, stride } => {
|
WlBufferStorage::Shm { mem, stride } => {
|
||||||
|
|
@ -284,10 +285,16 @@ impl OutputNode {
|
||||||
self.global.persistent.transform.get(),
|
self.global.persistent.transform.get(),
|
||||||
self.global.persistent.scale.get(),
|
self.global.persistent.scale.get(),
|
||||||
);
|
);
|
||||||
if let Err(e) = res {
|
match res {
|
||||||
log::warn!("Could not perform shm screencopy: {}", ErrorFmt(e));
|
Ok(p) => {
|
||||||
capture.send_failed();
|
ready = p.is_none();
|
||||||
continue;
|
capture.pending.set(p);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Could not perform shm screencopy: {}", ErrorFmt(e));
|
||||||
|
capture.send_failed();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WlBufferStorage::Dmabuf { fb, .. } => {
|
WlBufferStorage::Dmabuf { fb, .. } => {
|
||||||
|
|
@ -327,7 +334,9 @@ impl OutputNode {
|
||||||
if capture.with_damage.get() {
|
if capture.with_damage.get() {
|
||||||
capture.send_damage();
|
capture.send_damage();
|
||||||
}
|
}
|
||||||
capture.send_ready(now.0.tv_sec as _, now.0.tv_nsec as _);
|
if ready {
|
||||||
|
capture.send_ready(now.0.tv_sec as _, now.0.tv_nsec as _);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.screencast_changed();
|
self.screencast_changed();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue