1
0
Fork 0
forked from wry/wry

render: add abstraction for async-upload storage

This commit is contained in:
Julian Orth 2024-09-28 16:02:20 +02:00
parent d99444bd3c
commit ca134e683b
8 changed files with 149 additions and 93 deletions

View file

@ -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<OwnedFd> {
&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<u8>] {
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<u8>])) -> Result<(), Box<dyn Error + Sync + Send>> {
self.access(f).map_err(|e| e.into())
}
}

View file

@ -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<u8>])) -> Result<(), Box<dyn Error + Sync + Send>>;
}
pub enum ShmMemoryBacking {
Ptr(*const [Cell<u8>]),
Fd(Rc<OwnedFd>, usize),
}
impl ShmMemory for Vec<Cell<u8>> {
fn len(&self) -> usize {
self.len()
}
fn safe_access(&self) -> ShmMemoryBacking {
ShmMemoryBacking::Ptr(&**self)
}
fn access(&self, f: &mut dyn FnMut(&[Cell<u8>])) -> Result<(), Box<dyn Error + Sync + Send>> {
f(self);
Ok(())
}
}
pub trait AsyncShmGfxTexture: GfxTexture {
fn async_upload(
self: Rc<Self>,
callback: Rc<dyn AsyncShmGfxTextureCallback>,
mem: &Rc<ClientMemOffset>,
mem: Rc<dyn ShmMemory>,
damage: Region,
) -> Result<Option<PendingShmUpload>, GfxError>;

View file

@ -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<dyn Error + Sync + Send>),
}
#[derive(Default)]

View file

@ -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<Self>,
_callback: Rc<dyn AsyncShmGfxTextureCallback>,
mem: &Rc<ClientMemOffset>,
damage: Region,
mem: Rc<dyn ShmMemory>,
_damage: Region,
) -> Result<Option<PendingShmUpload>, 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<Self>, data: &[Cell<u8>], _damage: Region) -> Result<(), GfxError> {

View file

@ -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<Self>,
callback: Rc<dyn AsyncShmGfxTextureCallback>,
mem: &Rc<ClientMemOffset>,
mem: Rc<dyn ShmMemory>,
damage: Region,
) -> Result<Option<PendingShmUpload>, 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)
}

View file

@ -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<VulkanImage>,
client_mem: &Rc<ClientMemOffset>,
client_mem: &Rc<dyn ShmMemory>,
damage: Region,
callback: Rc<dyn AsyncShmGfxTextureCallback>,
) -> Result<Option<PendingShmUpload>, VulkanError> {
@ -350,13 +351,13 @@ impl VulkanShmImage {
&self,
img: &Rc<VulkanImage>,
data: &VulkanShmImageAsyncData,
client_mem: &Rc<ClientMemOffset>,
client_mem: &Rc<dyn ShmMemory>,
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<VulkanImage>,
client_mem: &Rc<ClientMemOffset>,
client_mem: &Rc<dyn ShmMemory>,
res: Result<VulkanStagingBuffer, VulkanError>,
) -> Result<(), VulkanError> {
let staging = Rc::new(res?);
@ -546,73 +547,76 @@ impl VulkanShmImage {
data: &VulkanShmImageAsyncData,
staging: &VulkanStagingBuffer,
copies: &[BufferImageCopy2],
client_mem: &Rc<ClientMemOffset>,
client_mem: &Rc<dyn ShmMemory>,
) -> 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<Rc<VulkanImage>>,
id: u64,
_mem: Option<Rc<ClientMemOffset>>,
_mem: Option<Rc<dyn ShmMemory>>,
fd: Option<Rc<OwnedFd>>,
work: ReadWriteWork,
}
@ -661,7 +665,7 @@ pub(super) struct IoUploadJob {
pub(super) struct CopyUploadJob {
img: Option<Rc<VulkanImage>>,
id: u64,
_mem: Option<Rc<ClientMemOffset>>,
_mem: Option<Rc<dyn ShmMemory>>,
work: ImgCopyWork,
}

View file

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

View file

@ -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<dyn Error + Sync + Send>),
}
impl From<TestGfxError> for GfxError {
@ -336,12 +336,15 @@ impl AsyncShmGfxTexture for TestGfxImage {
fn async_upload(
self: Rc<Self>,
_callback: Rc<dyn AsyncShmGfxTextureCallback>,
mem: &Rc<ClientMemOffset>,
damage: Region,
mem: Rc<dyn ShmMemory>,
_damage: Region,
) -> Result<Option<PendingShmUpload>, 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<Self>, mem: &[Cell<u8>], _damage: Region) -> Result<(), GfxError> {