diff --git a/src/clientmem.rs b/src/clientmem.rs index 1255ee22..1f763a8d 100644 --- a/src/clientmem.rs +++ b/src/clientmem.rs @@ -2,11 +2,14 @@ use { crate::{ client::Client, cpu_worker::{AsyncCpuWork, CpuJob, CpuWork, CpuWorker}, + gfx_api::{ShmMemory, ShmMemoryBacking}, utils::vec_ext::VecExt, }, std::{ cell::Cell, + error::Error, mem::{ManuallyDrop, MaybeUninit}, + ops::Deref, ptr, rc::Rc, sync::atomic::{compiler_fence, Ordering}, @@ -105,6 +108,7 @@ impl ClientMem { } } + #[expect(dead_code)] pub fn fd(&self) -> &Rc { &self.fd } @@ -115,14 +119,17 @@ impl ClientMem { } impl ClientMemOffset { + #[expect(dead_code)] pub fn pool(&self) -> &ClientMem { &self.mem } + #[expect(dead_code)] pub fn offset(&self) -> usize { self.offset } + #[expect(dead_code)] pub fn ptr(&self) -> *const [Cell] { self.data } @@ -263,3 +270,20 @@ impl CpuWork for CloseMemWork { None } } + +impl ShmMemory for ClientMemOffset { + fn len(&self) -> usize { + self.data.len() + } + + fn safe_access(&self) -> ShmMemoryBacking { + match self.mem.sigbus_impossible() { + true => ShmMemoryBacking::Ptr(self.data), + false => ShmMemoryBacking::Fd(self.mem.fd.deref().clone(), self.offset), + } + } + + fn access(&self, f: &mut dyn FnMut(&[Cell])) -> Result<(), Box> { + self.access(f).map_err(|e| e.into()) + } +} diff --git a/src/gfx_api.rs b/src/gfx_api.rs index 9fe14ef3..825a4a42 100644 --- a/src/gfx_api.rs +++ b/src/gfx_api.rs @@ -1,7 +1,6 @@ use { crate::{ allocator::Allocator, - clientmem::ClientMemOffset, cpu_worker::CpuWorker, cursor::Cursor, damage::DamageVisualizer, @@ -513,11 +512,37 @@ pub struct PendingShmUpload { id: u64, } +pub trait ShmMemory { + fn len(&self) -> usize; + fn safe_access(&self) -> ShmMemoryBacking; + fn access(&self, f: &mut dyn FnMut(&[Cell])) -> Result<(), Box>; +} + +pub enum ShmMemoryBacking { + Ptr(*const [Cell]), + Fd(Rc, usize), +} + +impl ShmMemory for Vec> { + fn len(&self) -> usize { + self.len() + } + + fn safe_access(&self) -> ShmMemoryBacking { + ShmMemoryBacking::Ptr(&**self) + } + + fn access(&self, f: &mut dyn FnMut(&[Cell])) -> Result<(), Box> { + f(self); + Ok(()) + } +} + pub trait AsyncShmGfxTexture: GfxTexture { fn async_upload( self: Rc, callback: Rc, - mem: &Rc, + mem: Rc, damage: Region, ) -> Result, GfxError>; diff --git a/src/gfx_apis/gl.rs b/src/gfx_apis/gl.rs index 3ef1e19f..dd45501a 100644 --- a/src/gfx_apis/gl.rs +++ b/src/gfx_apis/gl.rs @@ -67,7 +67,6 @@ macro_rules! dynload { use { crate::{ - clientmem::ClientMemError, gfx_api::{ AcquireSync, CopyTexture, FillRect, GfxApiOpt, GfxContext, GfxError, GfxTexture, ReleaseSync, SyncFile, @@ -95,7 +94,7 @@ use { }, isnt::std_1::vec::IsntVecExt, once_cell::sync::Lazy, - std::{cell::RefCell, rc::Rc, sync::Arc}, + std::{cell::RefCell, error::Error, rc::Rc, sync::Arc}, thiserror::Error, }; @@ -199,7 +198,7 @@ enum RenderError { #[error("Buffer format {0} is not supported for shm buffers in OpenGL context")] UnsupportedShmFormat(&'static str), #[error("Could not access the client memory")] - AccessFailed(#[source] ClientMemError), + AccessFailed(#[source] Box), } #[derive(Default)] diff --git a/src/gfx_apis/gl/renderer/texture.rs b/src/gfx_apis/gl/renderer/texture.rs index efa45b84..7add2b78 100644 --- a/src/gfx_apis/gl/renderer/texture.rs +++ b/src/gfx_apis/gl/renderer/texture.rs @@ -1,10 +1,9 @@ use { crate::{ - clientmem::ClientMemOffset, format::Format, gfx_api::{ AsyncShmGfxTexture, AsyncShmGfxTextureCallback, GfxError, GfxTexture, PendingShmUpload, - ShmGfxTexture, + ShmGfxTexture, ShmMemory, }, gfx_apis::gl::{ gl::texture::GlTexture, @@ -102,12 +101,15 @@ impl AsyncShmGfxTexture for Texture { fn async_upload( self: Rc, _callback: Rc, - mem: &Rc, - damage: Region, + mem: Rc, + _damage: Region, ) -> Result, GfxError> { - mem.access(|data| self.clone().sync_upload(data, damage)) - .map_err(RenderError::AccessFailed)??; - Ok(None) + let mut res = Ok(()); + mem.access(&mut |data| { + res = self.clone().sync_upload(data, Region::default()); + }) + .map_err(RenderError::AccessFailed)?; + res.map(|_| None) } fn sync_upload(self: Rc, data: &[Cell], _damage: Region) -> Result<(), GfxError> { diff --git a/src/gfx_apis/vulkan/image.rs b/src/gfx_apis/vulkan/image.rs index aa02a734..6826c2f6 100644 --- a/src/gfx_apis/vulkan/image.rs +++ b/src/gfx_apis/vulkan/image.rs @@ -1,11 +1,10 @@ use { crate::{ - clientmem::ClientMemOffset, format::Format, gfx_api::{ AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback, AsyncShmGfxTextureUploadCancellable, GfxApiOpt, GfxError, GfxFramebuffer, GfxImage, - GfxTexture, PendingShmUpload, ReleaseSync, ShmGfxTexture, SyncFile, + GfxTexture, PendingShmUpload, ReleaseSync, ShmGfxTexture, ShmMemory, SyncFile, }, gfx_apis::vulkan::{ allocator::VulkanAllocation, device::VulkanDevice, format::VulkanModifierLimits, @@ -579,13 +578,13 @@ impl AsyncShmGfxTexture for VulkanImage { fn async_upload( self: Rc, callback: Rc, - mem: &Rc, + mem: Rc, damage: Region, ) -> Result, GfxError> { let VulkanImageMemory::Internal(shm) = &self.ty else { unreachable!(); }; - let pending = shm.async_upload(&self, mem, damage, callback)?; + let pending = shm.async_upload(&self, &mem, damage, callback)?; Ok(pending) } diff --git a/src/gfx_apis/vulkan/shm_image.rs b/src/gfx_apis/vulkan/shm_image.rs index 7dcbb199..ced7ea0a 100644 --- a/src/gfx_apis/vulkan/shm_image.rs +++ b/src/gfx_apis/vulkan/shm_image.rs @@ -1,6 +1,5 @@ use { crate::{ - clientmem::ClientMemOffset, cpu_worker::{ jobs::{ img_copy::ImgCopyWork, @@ -9,7 +8,9 @@ use { CpuJob, CpuWork, CpuWorker, }, format::{Format, FormatShmInfo}, - gfx_api::{AsyncShmGfxTextureCallback, PendingShmUpload, SyncFile}, + gfx_api::{ + AsyncShmGfxTextureCallback, PendingShmUpload, ShmMemory, ShmMemoryBacking, SyncFile, + }, gfx_apis::vulkan::{ allocator::VulkanAllocation, command::VulkanCommandBuffer, @@ -329,7 +330,7 @@ impl VulkanShmImage { pub fn async_upload( &self, img: &Rc, - client_mem: &Rc, + client_mem: &Rc, damage: Region, callback: Rc, ) -> Result, VulkanError> { @@ -350,13 +351,13 @@ impl VulkanShmImage { &self, img: &Rc, data: &VulkanShmImageAsyncData, - client_mem: &Rc, + client_mem: &Rc, mut damage: Region, ) -> Result<(), VulkanError> { if data.busy.get() { return Err(VulkanError::AsyncCopyBusy); } - if self.size > client_mem.ptr().len() as u64 { + if self.size > client_mem.len() as u64 { return Err(VulkanError::InvalidBufferSize); } data.busy.set(true); @@ -530,7 +531,7 @@ impl VulkanShmImage { fn async_upload_after_allocation( &self, img: &Rc, - client_mem: &Rc, + client_mem: &Rc, res: Result, ) -> Result<(), VulkanError> { let staging = Rc::new(res?); @@ -546,73 +547,76 @@ impl VulkanShmImage { data: &VulkanShmImageAsyncData, staging: &VulkanStagingBuffer, copies: &[BufferImageCopy2], - client_mem: &Rc, + client_mem: &Rc, ) -> Result<(), VulkanError> { img.renderer.check_defunct()?; let id = img.renderer.allocate_point(); let pending; - if client_mem.pool().sigbus_impossible() { - let mut job = data.copy_job.take().unwrap_or_else(|| { - Box::new(CopyUploadJob { - img: None, - id, - _mem: None, - work: unsafe { ImgCopyWork::new() }, - }) - }); - job.id = id; - job.img = Some(img.clone()); - job._mem = Some(client_mem.clone()); - job.work.src = client_mem.ptr() as _; - job.work.dst = staging.allocation.mem.unwrap(); - job.work.width = img.width as _; - job.work.stride = img.stride as _; - job.work.bpp = self.shm_info.bpp as _; - job.work.rects.clear(); - for copy in copies { - job.work.rects.push( - Rect::new_sized( - copy.image_offset.x as _, - copy.image_offset.y as _, - copy.image_extent.width as _, - copy.image_extent.height as _, - ) - .unwrap(), - ); + match client_mem.safe_access() { + ShmMemoryBacking::Ptr(ptr) => { + let mut job = data.copy_job.take().unwrap_or_else(|| { + Box::new(CopyUploadJob { + img: None, + id, + _mem: None, + work: unsafe { ImgCopyWork::new() }, + }) + }); + job.id = id; + job.img = Some(img.clone()); + job._mem = Some(client_mem.clone()); + job.work.src = ptr as _; + job.work.dst = staging.allocation.mem.unwrap(); + job.work.width = img.width as _; + job.work.stride = img.stride as _; + job.work.bpp = self.shm_info.bpp as _; + job.work.rects.clear(); + for copy in copies { + job.work.rects.push( + Rect::new_sized( + copy.image_offset.x as _, + copy.image_offset.y as _, + copy.image_extent.width as _, + copy.image_extent.height as _, + ) + .unwrap(), + ); + } + pending = data.cpu.submit(job); } - pending = data.cpu.submit(job); - } else { - let mut min_offset = client_mem.ptr().len() as u64; - let mut max_offset = 0; - for copy in copies { - min_offset = min_offset.min(copy.buffer_offset); - let len = img.stride * (copy.image_extent.height - 1) - + copy.image_extent.width * self.shm_info.bpp; - max_offset = max_offset.max(copy.buffer_offset + len as u64); + ShmMemoryBacking::Fd(fd, offset) => { + let mut min_offset = client_mem.len() as u64; + let mut max_offset = 0; + for copy in copies { + min_offset = min_offset.min(copy.buffer_offset); + let len = img.stride * (copy.image_extent.height - 1) + + copy.image_extent.width * self.shm_info.bpp; + max_offset = max_offset.max(copy.buffer_offset + len as u64); + } + let mut job = data.io_job.take().unwrap_or_else(|| { + Box::new(IoUploadJob { + img: None, + id, + _mem: None, + work: unsafe { ReadWriteWork::new() }, + fd: None, + }) + }); + job.id = id; + job.img = Some(img.clone()); + job._mem = Some(client_mem.clone()); + job.fd = Some(fd.clone()); + unsafe { + let config = job.work.config(); + config.fd = fd.raw(); + config.offset = offset + min_offset as usize; + config.ptr = staging.allocation.mem.unwrap().add(min_offset as _); + config.len = max_offset.saturating_sub(min_offset) as usize; + config.write = false; + } + pending = data.cpu.submit(job); } - let mut job = data.io_job.take().unwrap_or_else(|| { - Box::new(IoUploadJob { - img: None, - id, - _mem: None, - work: unsafe { ReadWriteWork::new() }, - fd: None, - }) - }); - job.id = id; - job.img = Some(img.clone()); - job._mem = Some(client_mem.clone()); - job.fd = Some(client_mem.pool().fd().clone()); - unsafe { - let config = job.work.config(); - config.fd = client_mem.pool().fd().raw(); - config.offset = client_mem.offset() + min_offset as usize; - config.ptr = staging.allocation.mem.unwrap().add(min_offset as _); - config.len = max_offset.saturating_sub(min_offset) as usize; - config.write = false; - } - pending = data.cpu.submit(job); } img.renderer.pending_cpu_jobs.set(id, pending); @@ -653,7 +657,7 @@ impl VulkanShmImage { pub(super) struct IoUploadJob { img: Option>, id: u64, - _mem: Option>, + _mem: Option>, fd: Option>, work: ReadWriteWork, } @@ -661,7 +665,7 @@ pub(super) struct IoUploadJob { pub(super) struct CopyUploadJob { img: Option>, id: u64, - _mem: Option>, + _mem: Option>, work: ImgCopyWork, } diff --git a/src/ifs/wl_surface/commit_timeline.rs b/src/ifs/wl_surface/commit_timeline.rs index da4a2c46..544d98a6 100644 --- a/src/ifs/wl_surface/commit_timeline.rs +++ b/src/ifs/wl_surface/commit_timeline.rs @@ -460,7 +460,7 @@ fn schedule_async_upload( } }; back_tex - .async_upload(node_ref.clone(), mem, back.damage.get()) + .async_upload(node_ref.clone(), mem.clone(), back.damage.get()) .map_err(WlSurfaceError::PrepareAsyncUpload) } diff --git a/src/it/test_gfx_api.rs b/src/it/test_gfx_api.rs index 90157cfa..95c52864 100644 --- a/src/it/test_gfx_api.rs +++ b/src/it/test_gfx_api.rs @@ -1,14 +1,13 @@ use { crate::{ allocator::{Allocator, AllocatorError, BufferObject, BufferUsage}, - clientmem::{ClientMemError, ClientMemOffset}, cpu_worker::CpuWorker, format::{Format, ARGB8888, XRGB8888}, gfx_api::{ AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback, CopyTexture, FillRect, FramebufferRect, GfxApiOpt, GfxContext, GfxError, GfxFormat, GfxFramebuffer, GfxImage, GfxTexture, GfxWriteModifier, PendingShmUpload, ReleaseSync, ResetStatus, - ShmGfxTexture, SyncFile, + ShmGfxTexture, ShmMemory, SyncFile, }, rect::{Rect, Region}, theme::Color, @@ -20,6 +19,7 @@ use { std::{ any::Any, cell::{Cell, RefCell}, + error::Error, ffi::CString, fmt::{Debug, Formatter}, ops::Deref, @@ -36,7 +36,7 @@ enum TestGfxError { #[error("Could not import dmabuf")] ImportDmaBuf(#[source] AllocatorError), #[error("Could not access the client memory")] - AccessFailed(#[source] ClientMemError), + AccessFailed(#[source] Box), } impl From for GfxError { @@ -336,12 +336,15 @@ impl AsyncShmGfxTexture for TestGfxImage { fn async_upload( self: Rc, _callback: Rc, - mem: &Rc, - damage: Region, + mem: Rc, + _damage: Region, ) -> Result, GfxError> { - mem.access(|d| self.clone().sync_upload(d, damage)) - .map_err(TestGfxError::AccessFailed)??; - Ok(None) + let mut res = Ok(()); + mem.access(&mut |d| { + res = self.clone().sync_upload(d, Region::default()); + }) + .map_err(TestGfxError::AccessFailed)?; + res.map(|_| None) } fn sync_upload(self: Rc, mem: &[Cell], _damage: Region) -> Result<(), GfxError> {