Skip to content

Commit

Permalink
surface: use async uploads for shm buffers
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed Sep 8, 2024
1 parent 80310f4 commit c87bc69
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 73 deletions.
4 changes: 0 additions & 4 deletions src/gfx_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,6 @@ pub struct PendingShmUpload {
}

pub trait AsyncShmGfxTexture: GfxTexture {
#[expect(dead_code)]
fn async_upload(
self: Rc<Self>,
callback: Rc<dyn AsyncShmGfxTextureCallback>,
Expand All @@ -561,7 +560,6 @@ pub trait AsyncShmGfxTexture: GfxTexture {

fn sync_upload(self: Rc<Self>, shm: &[Cell<u8>], damage: Region) -> Result<(), GfxError>;

#[expect(dead_code)]
fn compatible_with(
&self,
format: &'static Format,
Expand All @@ -570,7 +568,6 @@ pub trait AsyncShmGfxTexture: GfxTexture {
stride: i32,
) -> bool;

#[expect(dead_code)]
fn into_texture(self: Rc<Self>) -> Rc<dyn GfxTexture>;
}

Expand Down Expand Up @@ -598,7 +595,6 @@ pub trait GfxContext: Debug {
damage: Option<&[Rect]>,
) -> Result<Rc<dyn ShmGfxTexture>, GfxError>;

#[expect(dead_code)]
fn async_shmem_texture(
self: Rc<Self>,
format: &'static Format,
Expand Down
57 changes: 34 additions & 23 deletions src/ifs/wl_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use {
ifs::wl_surface::WlSurface,
leaks::Tracker,
object::{Object, Version},
rect::Rect,
rect::{Rect, Region},
theme::Color,
utils::errorfmt::ErrorFmt,
video::dmabuf::DmaBuf,
Expand All @@ -22,7 +22,7 @@ use {

pub enum WlBufferStorage {
Shm {
mem: ClientMemOffset,
mem: Rc<ClientMemOffset>,
stride: i32,
},
Dmabuf {
Expand All @@ -41,6 +41,7 @@ pub struct WlBuffer {
pub dmabuf: Option<DmaBuf>,
render_ctx_version: Cell<u32>,
pub storage: RefCell<Option<WlBufferStorage>>,
shm: bool,
pub color: Option<Color>,
width: i32,
height: i32,
Expand All @@ -52,6 +53,10 @@ impl WlBuffer {
self.destroyed.get()
}

pub fn is_shm(&self) -> bool {
self.shm
}

pub fn new_dmabuf(
id: WlBufferId,
client: &Rc<Client>,
Expand All @@ -76,6 +81,7 @@ impl WlBuffer {
tex: None,
fb: None,
})),
shm: false,
tracker: Default::default(),
color: None,
}
Expand All @@ -100,7 +106,7 @@ impl WlBuffer {
if required > mem.len() as u64 {
return Err(WlBufferError::OutOfBounds);
}
let mem = mem.offset(offset);
let mem = Rc::new(mem.offset(offset));
let min_row_size = width as u64 * shm_info.bpp as u64;
if (stride as u64) < min_row_size {
return Err(WlBufferError::StrideTooSmall);
Expand All @@ -114,6 +120,7 @@ impl WlBuffer {
dmabuf: None,
render_ctx_version: Cell::new(client.state.render_ctx_version.get()),
storage: RefCell::new(Some(WlBufferStorage::Shm { mem, stride })),
shm: true,
width,
height,
tracker: Default::default(),
Expand All @@ -138,6 +145,7 @@ impl WlBuffer {
dmabuf: None,
render_ctx_version: Cell::new(client.state.render_ctx_version.get()),
storage: RefCell::new(None),
shm: false,
width: 1,
height: 1,
tracker: Default::default(),
Expand All @@ -153,7 +161,7 @@ impl WlBuffer {
let had_texture = self.reset_gfx_objects(surface);
if had_texture {
if let Some(surface) = surface {
self.update_texture_or_log(surface, None);
self.update_texture_or_log(surface, true);
}
}
}
Expand All @@ -166,7 +174,10 @@ impl WlBuffer {
let had_texture = match s {
WlBufferStorage::Shm { .. } => {
return match surface {
Some(s) => s.shm_texture.take().is_some(),
Some(s) => {
s.shm_textures.back().tex.take();
s.shm_textures.front().tex.take().is_some()
}
None => false,
};
}
Expand Down Expand Up @@ -201,44 +212,44 @@ impl WlBuffer {
match &*self.storage.borrow() {
None => None,
Some(s) => match s {
WlBufferStorage::Shm { .. } => surface.shm_texture.get().map(|t| t.into_texture()),
WlBufferStorage::Shm { .. } => surface
.shm_textures
.front()
.tex
.get()
.map(|t| t.into_texture()),
WlBufferStorage::Dmabuf { tex, .. } => tex.clone(),
},
}
}

pub fn update_texture_or_log(&self, surface: &WlSurface, damage: Option<&[Rect]>) {
if let Err(e) = self.update_texture(surface, damage) {
pub fn update_texture_or_log(&self, surface: &WlSurface, sync_shm: bool) {
if let Err(e) = self.update_texture(surface, sync_shm) {
log::warn!("Could not update texture: {}", ErrorFmt(e));
}
}

fn update_texture(
&self,
surface: &WlSurface,
damage: Option<&[Rect]>,
) -> Result<(), WlBufferError> {
let old_shm_texture = surface.shm_texture.take();
fn update_texture(&self, surface: &WlSurface, sync_shm: bool) -> Result<(), WlBufferError> {
let storage = &mut *self.storage.borrow_mut();
let storage = match storage {
Some(s) => s,
_ => return Ok(()),
};
match storage {
WlBufferStorage::Shm { mem, stride } => {
if let Some(ctx) = self.client.state.render_ctx.get() {
let tex = mem.access(|mem| {
ctx.shmem_texture(
old_shm_texture,
mem,
if sync_shm {
if let Some(ctx) = self.client.state.render_ctx.get() {
let tex = ctx.async_shmem_texture(
self.format,
self.width,
self.height,
*stride,
damage,
)
})??;
surface.shm_texture.set(Some(tex));
&self.client.state.cpu_worker,
)?;
mem.access(|mem| tex.clone().sync_upload(mem, Region::new2(self.rect)))??;
surface.shm_textures.front().tex.set(Some(tex));
surface.shm_textures.front().damage.clear();
}
}
}
WlBufferStorage::Dmabuf { img, tex, .. } => {
Expand Down
53 changes: 38 additions & 15 deletions src/ifs/wl_surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ use {
drm_feedback::DrmFeedback,
fixed::Fixed,
gfx_api::{
AcquireSync, BufferResv, BufferResvUser, ReleaseSync, SampleRect, ShmGfxTexture,
SyncFile,
AcquireSync, AsyncShmGfxTexture, BufferResv, BufferResvUser, GfxError, ReleaseSync,
SampleRect, SyncFile,
},
ifs::{
wl_buffer::WlBuffer,
Expand Down Expand Up @@ -60,16 +60,16 @@ use {
},
leaks::Tracker,
object::{Object, Version},
rect::{Rect, Region},
rect::{DamageQueue, Rect, Region},
renderer::Renderer,
tree::{
ContainerNode, FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, NodeVisitorBase,
OutputNode, OutputNodeId, PlaceholderNode, ToplevelNode,
},
utils::{
cell_ext::CellExt, clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt,
linkedlist::LinkedList, numcell::NumCell, smallmap::SmallMap,
transform_ext::TransformExt,
cell_ext::CellExt, clonecell::CloneCell, copyhashmap::CopyHashMap,
double_buffered::DoubleBuffered, errorfmt::ErrorFmt, linkedlist::LinkedList,
numcell::NumCell, smallmap::SmallMap, transform_ext::TransformExt,
},
video::{
dmabuf::DMA_BUF_SYNC_READ,
Expand Down Expand Up @@ -250,6 +250,11 @@ impl BufferResv for SurfaceBuffer {
}
}

pub struct SurfaceShmTexture {
pub tex: CloneCell<Option<Rc<dyn AsyncShmGfxTexture>>>,
pub damage: DamageQueue,
}

pub struct WlSurface {
pub id: WlSurfaceId,
pub node_id: SurfaceNodeId,
Expand All @@ -272,7 +277,7 @@ pub struct WlSurface {
pub buffer: CloneCell<Option<Rc<SurfaceBuffer>>>,
buffer_presented: Cell<bool>,
buffer_had_frame_request: Cell<bool>,
pub shm_texture: CloneCell<Option<Rc<dyn ShmGfxTexture>>>,
pub shm_textures: DoubleBuffered<SurfaceShmTexture>,
pub buf_x: NumCell<i32>,
pub buf_y: NumCell<i32>,
pub children: RefCell<Option<Box<ParentData>>>,
Expand Down Expand Up @@ -585,7 +590,10 @@ impl WlSurface {
buffer: Default::default(),
buffer_presented: Default::default(),
buffer_had_frame_request: Default::default(),
shm_texture: Default::default(),
shm_textures: DoubleBuffered::new(DamageQueue::new().map(|damage| SurfaceShmTexture {
tex: Default::default(),
damage,
})),
buf_x: Default::default(),
buf_y: Default::default(),
children: Default::default(),
Expand Down Expand Up @@ -910,7 +918,7 @@ impl WlSurfaceRequestHandler for WlSurface {
*children = None;
}
self.buffer.set(None);
self.shm_texture.take();
self.reset_shm_textures();
if let Some(xwayland_serial) = self.xwayland_serial.get() {
self.client
.surfaces_by_xwayland_serial
Expand Down Expand Up @@ -1078,11 +1086,13 @@ impl WlSurface {
old_raw_size = Some(buffer.buffer.rect);
}
if let Some(buffer) = buffer_change {
let damage = match pending.damage_full || pending.surface_damage.is_not_empty() {
true => None,
false => Some(&pending.buffer_damage[..]),
};
buffer.update_texture_or_log(self, damage);
if buffer.is_shm() {
self.shm_textures.flip();
self.shm_textures.front().damage.clear();
} else {
self.reset_shm_textures();
}
buffer.update_texture_or_log(self, false);
let (sync, release_sync) = match pending.explicit_sync {
false => (AcquireSync::Implicit, ReleaseSync::Implicit),
true => (AcquireSync::Unnecessary, ReleaseSync::Explicit),
Expand All @@ -1104,7 +1114,7 @@ impl WlSurface {
self.buffer_had_frame_request.set(false);
}
} else {
self.shm_texture.take();
self.reset_shm_textures();
self.buf_x.set(0);
self.buf_y.set(0);
for (_, cursor) in &self.cursors {
Expand Down Expand Up @@ -1322,6 +1332,13 @@ impl WlSurface {
Ok(())
}

pub fn reset_shm_textures(&self) {
for tex in &*self.shm_textures {
tex.tex.take();
tex.damage.clear();
}
}

fn apply_damage(&self, pending: &PendingState) {
let bounds = self.toplevel.get().map(|tl| tl.node_absolute_position());
let pos = self.buffer_abs_pos.get();
Expand Down Expand Up @@ -1916,6 +1933,12 @@ pub enum WlSurfaceError {
UnexpectedSyncPoints,
#[error("The supplied region is invalid")]
InvalidRect,
#[error("There is no render context")]
NoRenderContext,
#[error("Could not create a shm texture")]
CreateAsyncShmTexture(#[source] GfxError),
#[error("Could not prepare upload to a shm texture")]
PrepareAsyncUpload(#[source] GfxError),
}
efrom!(WlSurfaceError, ClientError);
efrom!(WlSurfaceError, XdgSurfaceError);
Expand Down
Loading

0 comments on commit c87bc69

Please sign in to comment.