render: add abstraction for async-upload storage
This commit is contained in:
parent
d99444bd3c
commit
ca134e683b
8 changed files with 149 additions and 93 deletions
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue