From 7b0dc8879a1bdf2181da7c4554ea34450d6d5549 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 28 Feb 2026 01:44:19 +0100 Subject: [PATCH 1/4] wl_surface: handle frame callback cleanup automatically --- src/ifs/wl_surface.rs | 29 ++++++++++++++++++++++------- src/ifs/wl_surface/cursor.rs | 10 +++++----- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 9cc4bb3d..fbc67207 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -310,7 +310,7 @@ pub struct WlSurface { pub buf_y: NumCell, pub children: RefCell>>, ext: CloneCell>, - frame_requests: RefCell>>, + frame_requests: RefCell>, presentation_feedback: RefCell>>, latched_presentation_feedback: RefCell>>, seat_state: NodeSeatState, @@ -465,7 +465,7 @@ struct PendingState { offset: (i32, i32), opaque_region: Option>>, input_region: Option>>, - frame_request: Vec>, + frame_request: Vec, damage_full: bool, buffer_damage: Vec, surface_damage: Vec, @@ -1094,7 +1094,10 @@ impl WlSurfaceRequestHandler for WlSurface { let cb = Rc::new(WlCallback::new(req.callback, &self.client)); track!(self.client, cb); self.client.add_client_obj(&cb)?; - self.pending.borrow_mut().frame_request.push(cb); + self.pending + .borrow_mut() + .frame_request + .push(FrameRequest { now: 0, cb }); Ok(()) } @@ -2197,10 +2200,10 @@ efrom!(WlSurfaceError, CommitTimelineError); impl VblankListener for WlSurface { fn after_vblank(self: Rc) { if self.visible.get() { - let now = self.client.state.now_msec(); - for fr in self.frame_requests.borrow_mut().drain(..) { - fr.send_done(now as _); - let _ = fr.client.remove_obj(&*fr); + let now = self.client.state.now_msec() as u32; + for mut fr in self.frame_requests.borrow_mut().drain(..) { + fr.now = now; + drop(fr); } } if self.clear_fifo_on_vblank.take() { @@ -2274,3 +2277,15 @@ impl PresentationListener for WlSurface { self.presentation_listener.detach(); } } + +pub struct FrameRequest { + now: u32, + cb: Rc, +} + +impl Drop for FrameRequest { + fn drop(&mut self) { + self.cb.send_done(self.now); + let _ = self.cb.client.remove_obj(&*self.cb); + } +} diff --git a/src/ifs/wl_surface/cursor.rs b/src/ifs/wl_surface/cursor.rs index 54f9aa51..68f41796 100644 --- a/src/ifs/wl_surface/cursor.rs +++ b/src/ifs/wl_surface/cursor.rs @@ -96,12 +96,12 @@ impl Cursor for CursorSurface { let extents = self.surface.extents.get(); renderer.render_surface(&self.surface, -extents.x1(), -extents.y1(), None); - struct FrameRequests(u64); + struct FrameRequests(u32); impl NodeVisitorBase for FrameRequests { fn visit_surface(&mut self, node: &Rc) { - for fr in node.frame_requests.borrow_mut().drain(..) { - fr.send_done(self.0 as _); - let _ = fr.client.remove_obj(fr.deref()); + for mut fr in node.frame_requests.borrow_mut().drain(..) { + fr.now = self.0; + drop(fr); } for fr in node.presentation_feedback.borrow_mut().drain(..) { fr.send_discarded(); @@ -114,7 +114,7 @@ impl Cursor for CursorSurface { node.node_visit_children(self); } } - FrameRequests(self.surface.client.state.now_msec()).visit_surface(&self.surface); + FrameRequests(self.surface.client.state.now_msec() as u32).visit_surface(&self.surface); } fn extents_at_scale(&self, scale: Scale) -> Rect { From 6bdd1ff6e7060bc3c236fd3c1ace37470b20c38c Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 28 Feb 2026 02:06:48 +0100 Subject: [PATCH 2/4] wl_surface: handle presentation feedback cleanup automatically --- src/ifs/wl_surface.rs | 42 ++++++------------------ src/ifs/wl_surface/cursor.rs | 12 ++----- src/ifs/wp_presentation.rs | 4 +-- src/ifs/wp_presentation_feedback.rs | 50 +++++++++++++++++++++++++++-- 4 files changed, 62 insertions(+), 46 deletions(-) diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index fbc67207..e7c8a08c 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -67,7 +67,7 @@ use { zwlr_layer_surface_v1::{PendingLayerSurfaceData, ZwlrLayerSurfaceV1Error}, }, wp_content_type_v1::ContentType, - wp_presentation_feedback::{VRR_REFRESH_SINCE, WpPresentationFeedback}, + wp_presentation_feedback::PresentationFeedback, zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1, }, io_uring::IoUringError, @@ -311,8 +311,8 @@ pub struct WlSurface { pub children: RefCell>>, ext: CloneCell>, frame_requests: RefCell>, - presentation_feedback: RefCell>>, - latched_presentation_feedback: RefCell>>, + presentation_feedback: RefCell>, + latched_presentation_feedback: RefCell>, seat_state: NodeSeatState, toplevel: CloneCell>>, cursors: SmallMap, 1>, @@ -469,7 +469,7 @@ struct PendingState { damage_full: bool, buffer_damage: Vec, surface_damage: Vec, - presentation_feedback: Vec>, + presentation_feedback: Vec, src_rect: Option>, dst_size: Option>, scale: Option, @@ -511,10 +511,7 @@ impl PendingState { } } } - for fb in self.presentation_feedback.drain(..) { - fb.send_discarded(); - let _ = client.remove_obj(&*fb); - } + self.presentation_feedback.clear(); // overwrite state @@ -799,11 +796,8 @@ impl WlSurface { } } - pub fn add_presentation_feedback(&self, fb: &Rc) { - self.pending - .borrow_mut() - .presentation_feedback - .push(fb.clone()); + pub fn add_presentation_feedback(&self, fb: PresentationFeedback) { + self.pending.borrow_mut().presentation_feedback.push(fb); } pub fn is_cursor(&self) -> bool { @@ -1382,10 +1376,7 @@ impl WlSurface { } let has_presentation_feedback = { let mut fbs = self.presentation_feedback.borrow_mut(); - for fb in fbs.drain(..) { - fb.send_discarded(); - let _ = self.client.remove_obj(&*fb); - } + fbs.clear(); mem::swap(fbs.deref_mut(), &mut pending.presentation_feedback); fbs.is_not_empty() }; @@ -2224,10 +2215,7 @@ impl LatchListener for WlSurface { if self.visible.get() { if self.latched_commit_version.get() < self.commit_version.get() { let latched = &mut *self.latched_presentation_feedback.borrow_mut(); - for pf in latched.drain(..) { - pf.send_discarded(); - let _ = pf.client.remove_obj(&*pf); - } + latched.clear(); latched.append(&mut self.presentation_feedback.borrow_mut()); if latched.is_not_empty() { self.presentation_listener @@ -2262,17 +2250,7 @@ impl PresentationListener for WlSurface { let bindings = output.global.bindings.borrow(); let bindings = bindings.get(&self.client.id); for pf in self.latched_presentation_feedback.borrow_mut().drain(..) { - if let Some(bindings) = bindings { - for binding in bindings.values() { - pf.send_sync_output(binding); - } - } - let mut refresh = refresh; - if vrr && pf.version < VRR_REFRESH_SINCE { - refresh = 0; - } - pf.send_presented(tv_sec, tv_nsec, refresh, seq, flags); - let _ = pf.client.remove_obj(&*pf); + pf.presented(bindings, tv_sec, tv_nsec, refresh, seq, flags, vrr); } self.presentation_listener.detach(); } diff --git a/src/ifs/wl_surface/cursor.rs b/src/ifs/wl_surface/cursor.rs index 68f41796..fabcea95 100644 --- a/src/ifs/wl_surface/cursor.rs +++ b/src/ifs/wl_surface/cursor.rs @@ -10,7 +10,7 @@ use { scale::Scale, tree::{Node, NodeLocation, NodeVisitorBase, OutputNode}, }, - std::{cell::Cell, ops::Deref, rc::Rc}, + std::{cell::Cell, rc::Rc}, }; pub struct CursorSurface { @@ -103,14 +103,8 @@ impl Cursor for CursorSurface { fr.now = self.0; drop(fr); } - for fr in node.presentation_feedback.borrow_mut().drain(..) { - fr.send_discarded(); - let _ = fr.client.remove_obj(fr.deref()); - } - for fr in node.latched_presentation_feedback.borrow_mut().drain(..) { - fr.send_discarded(); - let _ = fr.client.remove_obj(fr.deref()); - } + node.presentation_feedback.borrow_mut().clear(); + node.latched_presentation_feedback.borrow_mut().clear(); node.node_visit_children(self); } } diff --git a/src/ifs/wp_presentation.rs b/src/ifs/wp_presentation.rs index 347cf39b..1314d0d4 100644 --- a/src/ifs/wp_presentation.rs +++ b/src/ifs/wp_presentation.rs @@ -3,7 +3,7 @@ use { crate::{ client::{Client, ClientError}, globals::{Global, GlobalName}, - ifs::wp_presentation_feedback::WpPresentationFeedback, + ifs::wp_presentation_feedback::{PresentationFeedback, WpPresentationFeedback}, leaks::Tracker, object::{Object, Version}, state::State, @@ -94,7 +94,7 @@ impl WpPresentationRequestHandler for WpPresentation { }); track!(self.client, fb); self.client.add_client_obj(&fb)?; - surface.add_presentation_feedback(&fb); + surface.add_presentation_feedback(PresentationFeedback::new(fb)); Ok(()) } } diff --git a/src/ifs/wp_presentation_feedback.rs b/src/ifs/wp_presentation_feedback.rs index 57cdbd15..5a481120 100644 --- a/src/ifs/wp_presentation_feedback.rs +++ b/src/ifs/wp_presentation_feedback.rs @@ -4,11 +4,55 @@ use { ifs::{wl_output::WlOutput, wl_surface::WlSurface}, leaks::Tracker, object::{Object, Version}, - wire::{WpPresentationFeedbackId, wp_presentation_feedback::*}, + wire::{WlOutputId, WpPresentationFeedbackId, wp_presentation_feedback::*}, }, + ahash::AHashMap, std::{convert::Infallible, rc::Rc}, }; +pub struct PresentationFeedback { + fb: Option>, +} + +impl PresentationFeedback { + pub fn new(fb: Rc) -> Self { + Self { fb: Some(fb) } + } + + pub fn presented( + mut self, + outputs: Option<&AHashMap>>, + tv_sec: u64, + tv_nsec: u32, + mut refresh: u32, + seq: u64, + flags: u32, + vrr: bool, + ) { + if let Some(fb) = self.fb.take() { + if let Some(outputs) = outputs { + for output in outputs.values() { + fb.send_sync_output(output); + } + } + if vrr && fb.version < VRR_REFRESH_SINCE { + refresh = 0; + } + fb.send_presented(tv_sec, tv_nsec, refresh, seq, flags); + let _ = fb.client.remove_obj(&*fb); + } + } +} + +impl Drop for PresentationFeedback { + fn drop(&mut self) { + if let Some(fb) = self.fb.take() { + fb.send_discarded(); + let _ = fb.client.remove_obj(&*fb); + } + } +} + pub struct WpPresentationFeedback { pub id: WpPresentationFeedbackId, pub client: Rc, @@ -33,7 +77,7 @@ impl WpPresentationFeedback { }); } - pub fn send_presented(&self, tv_sec: u64, tv_nsec: u32, refresh: u32, seq: u64, flags: u32) { + fn send_presented(&self, tv_sec: u64, tv_nsec: u32, refresh: u32, seq: u64, flags: u32) { self.client.event(Presented { self_id: self.id, tv_sec, @@ -44,7 +88,7 @@ impl WpPresentationFeedback { }); } - pub fn send_discarded(&self) { + fn send_discarded(&self) { self.client.event(Discarded { self_id: self.id }); } } From 8f576f498ef8ffd8848fe3d2a5a3aff8dab00279 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 28 Feb 2026 02:19:45 +0100 Subject: [PATCH 3/4] wl_surface: handle buffer release automatically --- src/ifs/wl_buffer.rs | 15 ++++++- src/ifs/wl_surface.rs | 57 ++++++++++++++------------- src/ifs/wl_surface/commit_timeline.rs | 2 + src/renderer.rs | 5 ++- src/state.rs | 6 +-- 5 files changed, 51 insertions(+), 34 deletions(-) diff --git a/src/ifs/wl_buffer.rs b/src/ifs/wl_buffer.rs index 331dc9f2..1fff5db3 100644 --- a/src/ifs/wl_buffer.rs +++ b/src/ifs/wl_buffer.rs @@ -48,6 +48,19 @@ pub struct DmabufBufferParams { tex_impossible: bool, } +pub struct AttachedBuffer { + pub send_release: bool, + pub buf: Rc, +} + +impl Drop for AttachedBuffer { + fn drop(&mut self) { + if self.send_release && !self.buf.destroyed() { + self.buf.send_release(); + } + } +} + pub struct WlBuffer { pub id: WlBufferId, destroyed: Cell, @@ -507,7 +520,7 @@ impl WlBuffer { Ok(()) } - pub fn send_release(&self) { + fn send_release(&self) { self.client.event(Release { self_id: self.id }) } } diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index e7c8a08c..b243ee37 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -35,7 +35,7 @@ use { }, ifs::{ color_management::wp_color_management_surface_feedback_v1::WpColorManagementSurfaceFeedbackV1, - wl_buffer::WlBuffer, + wl_buffer::AttachedBuffer, wl_callback::WlCallback, wl_seat::{ Dnd, NodeSeatState, SeatId, WlSeatGlobal, @@ -217,7 +217,7 @@ struct SurfaceBufferExplicitRelease { } pub struct SurfaceBuffer { - pub buffer: Rc, + pub buffer: AttachedBuffer, sync_files: SmallMap, pub release_sync: ReleaseSync, release: Option, @@ -227,7 +227,7 @@ 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.client.state.render_ctx.get() else { + 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; }; @@ -253,16 +253,13 @@ impl Drop for SurfaceBuffer { } return; } - if let Some(dmabuf) = &self.buffer.client_dmabuf { + if let Some(dmabuf) = &self.buffer.buf.client_dmabuf { for (_, sync_file) in &sync_files { if let Err(e) = dmabuf.import_sync_file(DMA_BUF_SYNC_READ, sync_file) { log::error!("Could not import sync file: {}", ErrorFmt(e)); } } } - if !self.buffer.destroyed() { - self.buffer.send_release(); - } } } @@ -461,7 +458,7 @@ impl SurfaceExt for NoneSurfaceExt { #[derive(Default)] struct PendingState { - buffer: Option>>, + buffer: Option>, offset: (i32, i32), opaque_region: Option>>, input_region: Option>>, @@ -505,10 +502,6 @@ impl PendingState { if next.buffer.is_some() { if let Some((sync_obj, point)) = self.release_point.take() { client.state.signal_point(&sync_obj, point); - } else if let Some(Some(prev)) = self.buffer.take() { - if !prev.destroyed() { - prev.send_release(); - } } } self.presentation_feedback.clear(); @@ -1074,7 +1067,10 @@ impl WlSurfaceRequestHandler for WlSurface { } else { None }; - pending.buffer = Some(buf); + pending.buffer = Some(buf.map(|buf| AttachedBuffer { + send_release: false, + buf, + })); Ok(()) } @@ -1122,6 +1118,11 @@ impl WlSurfaceRequestHandler for WlSurface { fn commit(&self, _req: Commit, slf: &Rc) -> Result<(), Self::Error> { let ext = self.ext.get(); let pending = &mut *self.pending.borrow_mut(); + if let Some(Some(buffer)) = &mut pending.buffer + && pending.release_point.is_none() + { + buffer.send_release = true; + } self.verify_explicit_sync(pending)?; if ext.commit_requested(pending) == CommitAction::ContinueCommit { self.commit_timeline.commit(slf, pending)?; @@ -1227,16 +1228,16 @@ impl WlSurface { if let Some(buffer_change) = pending.buffer.take() { buffer_changed = true; if let Some(buffer) = self.buffer.take() { - old_raw_size = Some(buffer.buffer.rect); + old_raw_size = Some(buffer.buffer.buf.rect); } if let Some(buffer) = buffer_change { - if buffer.is_shm() { + if buffer.buf.is_shm() { self.shm_textures.flip(); self.shm_textures.front().damage.clear(); } else { self.reset_shm_textures(); } - buffer.update_texture_or_log(self, false); + buffer.buf.update_texture_or_log(self, false); let release_sync = match pending.explicit_sync { false => ReleaseSync::Implicit, true => ReleaseSync::Explicit, @@ -1304,11 +1305,10 @@ impl WlSurface { new_size = Some(size); } if let Some(buffer) = self.buffer.get() { + let buf = &buffer.buffer.buf; if new_size.is_none() { - let (mut width, mut height) = self - .buffer_transform - .get() - .maybe_swap(buffer.buffer.rect.size()); + let (mut width, mut height) = + self.buffer_transform.get().maybe_swap(buf.rect.size()); let scale = self.buffer_scale.get(); if scale != 1 { width = (width + scale - 1) / scale; @@ -1316,14 +1316,12 @@ impl WlSurface { } new_size = Some((width, height)); } - if transform_changed || Some(buffer.buffer.rect) != old_raw_size { + if transform_changed || Some(buf.rect) != old_raw_size { let (x1, y1, x2, y2) = if self.src_rect.is_none() { (0.0, 0.0, 1.0, 1.0) } else { - let (width, height) = self - .buffer_transform - .get() - .maybe_swap(buffer.buffer.rect.size()); + let (width, height) = + self.buffer_transform.get().maybe_swap(buf.rect.size()); let width = width as f32; let height = height as f32; let x1 = buffer_points.x1 / width; @@ -1342,7 +1340,7 @@ impl WlSurface { y2, buffer_transform: self.buffer_transform.get(), }; - let (buffer_width, buffer_height) = buffer.buffer.rect.size(); + let (buffer_width, buffer_height) = buf.rect.size(); let (mut dst_width, mut dst_height) = new_size.unwrap_or_default(); client_wire_scale_to_logical!(self.client, dst_width, dst_height); let damage_matrix = DamageMatrix::new( @@ -1513,8 +1511,11 @@ impl WlSurface { let matrix = self.damage_matrix.get(); if let Some(buffer) = self.buffer.get() { for damage in &pending.buffer_damage { - let mut damage = - matrix.apply(pos.x1(), pos.y1(), damage.intersect(buffer.buffer.rect)); + let mut damage = matrix.apply( + pos.x1(), + pos.y1(), + damage.intersect(buffer.buffer.buf.rect), + ); if let Some(bounds) = bounds { damage = damage.intersect(bounds); } diff --git a/src/ifs/wl_surface/commit_timeline.rs b/src/ifs/wl_surface/commit_timeline.rs index b790436b..6f352551 100644 --- a/src/ifs/wl_surface/commit_timeline.rs +++ b/src/ifs/wl_surface/commit_timeline.rs @@ -598,6 +598,7 @@ fn schedule_async_upload( let Some(Some(buf)) = &pending.buffer else { return Ok(None); }; + let buf = &buf.buf; let Some(WlBufferStorage::Shm { mem, stride, @@ -698,6 +699,7 @@ struct CommitDataCollector { impl CommitDataCollector { fn collect(&mut self, pending: &mut PendingState) { if let Some(Some(buffer)) = &pending.buffer { + let buffer = &buffer.buf; if buffer.is_shm() { self.shm_uploads += 1; } diff --git a/src/renderer.rs b/src/renderer.rs index 74d56b2e..6acd59e5 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -468,10 +468,11 @@ impl Renderer<'_> { tsize: (i32, i32), bounds: Option<&Rect>, ) { + let buf = &buffer.buffer.buf; let alpha = surface.alpha(); let cd = surface.color_description(); let alpha_mode = surface.alpha_mode(); - if let Some(tex) = buffer.buffer.get_texture(surface) { + if let Some(tex) = buf.get_texture(surface) { let mut opaque = surface.opaque(); if !opaque && tex.format().has_alpha { opaque = self.bounds_are_opaque(x, y, bounds, surface); @@ -492,7 +493,7 @@ impl Renderer<'_> { &cd, alpha_mode, ); - } else if let Some(color) = &buffer.buffer.color { + } else if let Some(color) = &buf.color { if let Some(rect) = Rect::new_sized(x, y, tsize.0, tsize.1) { let rect = match bounds { None => rect, diff --git a/src/state.rs b/src/state.rs index ee07b0f7..d0b55399 100644 --- a/src/state.rs +++ b/src/state.rs @@ -689,10 +689,10 @@ impl State { for surface in client.data.objects.surfaces.lock().values() { let had_shm_texture = surface.reset_shm_textures(); if let Some(buffer) = surface.buffer.get() { - let had_buffer_texture = - *updated_buffers.get(&Rc::as_ptr(&buffer.buffer)).unwrap(); + let buf = &buffer.buffer.buf; + let had_buffer_texture = *updated_buffers.get(&Rc::as_ptr(buf)).unwrap(); if had_shm_texture || had_buffer_texture { - buffer.buffer.update_texture_or_log(surface, true); + buf.update_texture_or_log(surface, true); } } } From 382c0b6c716cbc66cd42559cf4cfabc2e5e0883f Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 28 Feb 2026 02:47:22 +0100 Subject: [PATCH 4/4] 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);