From 382c0b6c716cbc66cd42559cf4cfabc2e5e0883f Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 28 Feb 2026 02:47:22 +0100 Subject: [PATCH] wl_surface: handle explicit sync release automatically --- src/ifs/wl_surface.rs | 98 +++++++++++-------- .../wp_linux_drm_syncobj_surface_v1.rs | 9 +- src/state.rs | 20 +--- 3 files changed, 64 insertions(+), 63 deletions(-) diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index b243ee37..82a472cd 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -76,6 +76,7 @@ use { object::{Object, Version}, rect::{DamageQueue, Rect, Region}, renderer::Renderer, + state::State, tree::{ BeforeLatchListener, BeforeLatchResult, ContainerNode, FindTreeResult, FoundNode, LatchListener, Node, NodeId, NodeLayerLink, NodeLocation, NodeVisitor, NodeVisitorBase, @@ -99,6 +100,7 @@ use { }, ahash::AHashMap, isnt::std_1::{primitive::IsntSliceExt, vec::IsntVecExt}, + smallvec::SmallVec, std::{ cell::{Cell, RefCell}, collections::hash_map::{Entry, OccupiedEntry}, @@ -211,46 +213,18 @@ impl NodeVisitorBase for SurfaceSendPreferredColorDescription { } } -struct SurfaceBufferExplicitRelease { - sync_obj: Rc, - point: SyncObjPoint, -} - pub struct SurfaceBuffer { pub buffer: AttachedBuffer, sync_files: SmallMap, pub release_sync: ReleaseSync, - release: Option, + release: Option, } impl Drop for SurfaceBuffer { fn drop(&mut self) { let sync_files = self.sync_files.take(); - if let Some(release) = &self.release { - let Some(ctx) = self.buffer.buf.client.state.render_ctx.get() else { - log::error!("Cannot signal release point because there is no render context"); - return; - }; - let Some(ctx) = ctx.sync_obj_ctx() else { - log::error!("Cannot signal release point because there is no syncobj context"); - return; - }; - if sync_files.is_not_empty() { - let res = ctx.import_sync_files( - &release.sync_obj, - release.point, - sync_files.iter().map(|f| &f.1), - ); - match res { - Ok(_) => return, - Err(e) => { - log::error!("Could not import sync files into sync obj: {}", ErrorFmt(e)); - } - } - } - if let Err(e) = ctx.signal(&release.sync_obj, release.point) { - log::error!("Could not signal release point: {}", ErrorFmt(e)); - } + if let Some(release) = &mut self.release { + release.signal(Some(&sync_files)); return; } if let Some(dmabuf) = &self.buffer.buf.client_dmabuf { @@ -478,7 +452,7 @@ struct PendingState { layer_surface: Option>, subsurfaces: AHashMap, acquire_point: Option<(Rc, SyncObjPoint)>, - release_point: Option<(Rc, SyncObjPoint)>, + release_point: Option, alpha_multiplier: Option>, explicit_sync: bool, fifo_barrier_set: bool, @@ -499,11 +473,6 @@ impl PendingState { fn merge(&mut self, next: &mut Self, client: &Rc) { // discard state - if next.buffer.is_some() { - if let Some((sync_obj, point)) = self.release_point.take() { - client.state.signal_point(&sync_obj, point); - } - } self.presentation_feedback.clear(); // overwrite state @@ -1123,6 +1092,9 @@ impl WlSurfaceRequestHandler for WlSurface { { buffer.send_release = true; } + if let Some(release) = &mut pending.release_point { + release.committed = true; + } self.verify_explicit_sync(pending)?; if ext.commit_requested(pending) == CommitAction::ContinueCommit { self.commit_timeline.commit(slf, pending)?; @@ -1242,15 +1214,11 @@ impl WlSurface { false => ReleaseSync::Implicit, true => ReleaseSync::Explicit, }; - let release = pending - .release_point - .take() - .map(|(sync_obj, point)| SurfaceBufferExplicitRelease { sync_obj, point }); let surface_buffer = SurfaceBuffer { buffer, sync_files: Default::default(), release_sync, - release, + release: pending.release_point.take(), }; self.buffer.set(Some(Rc::new(surface_buffer))); } else { @@ -2268,3 +2236,49 @@ impl Drop for FrameRequest { let _ = self.cb.client.remove_obj(&*self.cb); } } + +pub struct SyncObjRelease { + state: Rc, + committed: bool, + syncobj: Option>, + point: SyncObjPoint, +} + +impl SyncObjRelease { + fn signal(&mut self, sync_files: Option<&SmallVec<[(BufferResvUser, SyncFile); 1]>>) { + if !self.committed { + return; + } + let Some(sync_obj) = self.syncobj.take() else { + return; + }; + let Some(ctx) = self.state.render_ctx.get() else { + log::error!("Cannot signal release point because there is no render context"); + return; + }; + let Some(ctx) = ctx.sync_obj_ctx() else { + log::error!("Cannot signal release point because there is no syncobj context"); + return; + }; + if let Some(sync_files) = sync_files + && sync_files.is_not_empty() + { + let res = ctx.import_sync_files(&sync_obj, self.point, sync_files.iter().map(|f| &f.1)); + match res { + Ok(_) => return, + Err(e) => { + log::error!("Could not import sync files into sync obj: {}", ErrorFmt(e)); + } + } + } + if let Err(e) = ctx.signal(&sync_obj, self.point) { + log::error!("Could not signal release point: {}", ErrorFmt(e)); + } + } +} + +impl Drop for SyncObjRelease { + fn drop(&mut self) { + self.signal(None); + } +} diff --git a/src/ifs/wl_surface/wp_linux_drm_syncobj_surface_v1.rs b/src/ifs/wl_surface/wp_linux_drm_syncobj_surface_v1.rs index ffe9759b..799ae414 100644 --- a/src/ifs/wl_surface/wp_linux_drm_syncobj_surface_v1.rs +++ b/src/ifs/wl_surface/wp_linux_drm_syncobj_surface_v1.rs @@ -1,7 +1,7 @@ use { crate::{ client::{Client, ClientError}, - ifs::wl_surface::WlSurface, + ifs::wl_surface::{SyncObjRelease, WlSurface}, leaks::Tracker, object::{Object, Version}, video::drm::sync_obj::SyncObjPoint, @@ -66,7 +66,12 @@ impl WpLinuxDrmSyncobjSurfaceV1RequestHandler for WpLinuxDrmSyncobjSurfaceV1 { fn set_release_point(&self, req: SetReleasePoint, _slf: &Rc) -> Result<(), Self::Error> { let point = SyncObjPoint(req.point); let timeline = self.client.lookup(req.timeline)?; - self.surface.pending.borrow_mut().release_point = Some((timeline.sync_obj.clone(), point)); + self.surface.pending.borrow_mut().release_point = Some(SyncObjRelease { + state: self.client.state.clone(), + committed: false, + syncobj: Some(timeline.sync_obj.clone()), + point, + }); Ok(()) } } diff --git a/src/state.rs b/src/state.rs index d0b55399..eea19da1 100644 --- a/src/state.rs +++ b/src/state.rs @@ -121,11 +121,7 @@ use { }, video::{ dmabuf::DmaBufIds, - drm::{ - Drm, - sync_obj::{SyncObj, SyncObjPoint}, - wait_for_sync_obj::WaitForSyncObj, - }, + drm::{Drm, wait_for_sync_obj::WaitForSyncObj}, }, wheel::Wheel, wire::{ @@ -1360,20 +1356,6 @@ impl State { seat } - pub fn signal_point(&self, sync_obj: &SyncObj, point: SyncObjPoint) { - let Some(ctx) = self.render_ctx.get() else { - log::error!("Cannot signal sync obj point because there is no render context"); - return; - }; - let Some(ctx) = ctx.sync_obj_ctx() else { - log::error!("Cannot signal sync obj point because there is no syncobj context"); - return; - }; - if let Err(e) = ctx.signal(sync_obj, point) { - log::error!("Could not signal sync obj: {}", ErrorFmt(e)); - } - } - pub fn set_backend_idle(&self, idle: bool) { if self.idle.backend_idle.replace(idle) != idle { self.root.update_visible(self);