From 7800488555c8c0f5cb0d88ed41f3a85600afe490 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Wed, 11 Sep 2024 21:19:30 +0200 Subject: [PATCH] wl_surface: dispatch presentation feedback via presented events --- src/backends/metal/present.rs | 3 -- src/backends/metal/video.rs | 27 +++------- src/compositor.rs | 1 + src/ifs/wl_compositor.rs | 2 +- src/ifs/wl_surface.rs | 93 +++++++++++++++++++++++++++++++---- src/ifs/wl_surface/cursor.rs | 4 ++ src/renderer.rs | 14 ------ src/tasks/connector.rs | 1 + src/tree/output.rs | 19 +++++++ 9 files changed, 117 insertions(+), 47 deletions(-) diff --git a/src/backends/metal/present.rs b/src/backends/metal/present.rs index 6d556858..e65aaa94 100644 --- a/src/backends/metal/present.rs +++ b/src/backends/metal/present.rs @@ -237,9 +237,6 @@ impl MetalConnector { } } if let Err(e) = res { - self.render_result - .borrow_mut() - .discard_presentation_feedback(); if let MetalError::Commit(DrmError::Atomic(OsError(c::EACCES))) = e { log::debug!("Could not perform atomic commit, likely because we're no longer the DRM master"); return Ok(()); diff --git a/src/backends/metal/video.rs b/src/backends/metal/video.rs index 3c80bf87..661c444f 100644 --- a/src/backends/metal/video.rs +++ b/src/backends/metal/video.rs @@ -1978,27 +1978,14 @@ impl MetalBackend { .set(tv_sec as u64 * 1_000_000_000 + tv_usec as u64 * 1000 + dd.refresh as u64); { let global = self.state.root.outputs.get(&connector.connector_id); - let mut rr = connector.render_result.borrow_mut(); if let Some(g) = &global { - let refresh = dd.refresh; - let bindings = g.global.bindings.borrow_mut(); - for fb in rr.presentation_feedbacks.drain(..) { - if let Some(bindings) = bindings.get(&fb.client.id) { - for binding in bindings.values() { - fb.send_sync_output(binding); - } - } - fb.send_presented( - tv_sec as _, - tv_usec * 1000, - refresh, - connector.sequence.get(), - KIND_VSYNC | KIND_HW_COMPLETION, - ); - let _ = fb.client.remove_obj(&*fb); - } - } else { - rr.discard_presentation_feedback(); + g.presented( + tv_sec as _, + tv_usec * 1000, + dd.refresh, + connector.sequence.get(), + KIND_VSYNC | KIND_HW_COMPLETION, + ); } } } diff --git a/src/compositor.rs b/src/compositor.rs index fc6e7f9d..01961e25 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -505,6 +505,7 @@ fn create_dummy_output(state: &Rc) { title_visible: Cell::new(false), schedule, latch_event: Default::default(), + presentation_event: Default::default(), }); let dummy_workspace = Rc::new(WorkspaceNode { id: state.node_ids.next(), diff --git a/src/ifs/wl_compositor.rs b/src/ifs/wl_compositor.rs index c7575663..4d0a1ebc 100644 --- a/src/ifs/wl_compositor.rs +++ b/src/ifs/wl_compositor.rs @@ -50,7 +50,7 @@ impl WlCompositorRequestHandler for WlCompositor { type Error = WlCompositorError; fn create_surface(&self, req: CreateSurface, _slf: &Rc) -> Result<(), Self::Error> { - let surface = Rc::new(WlSurface::new(req.id, &self.client, self.version)); + let surface = Rc::new_cyclic(|slf| WlSurface::new(req.id, &self.client, self.version, slf)); track!(self.client, surface); self.client.add_client_obj(&surface)?; if self.client.is_xwayland { diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 80c396d4..b70003d1 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -63,13 +63,15 @@ use { rect::{DamageQueue, Rect, Region}, renderer::Renderer, tree::{ - ContainerNode, FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, NodeVisitorBase, - OutputNode, OutputNodeId, PlaceholderNode, ToplevelNode, + ContainerNode, FindTreeResult, FoundNode, LatchListener, Node, NodeId, NodeVisitor, + NodeVisitorBase, OutputNode, OutputNodeId, PlaceholderNode, PresentationListener, + ToplevelNode, }, utils::{ cell_ext::CellExt, clonecell::CloneCell, copyhashmap::CopyHashMap, - double_buffered::DoubleBuffered, errorfmt::ErrorFmt, linkedlist::LinkedList, - numcell::NumCell, smallmap::SmallMap, transform_ext::TransformExt, + double_buffered::DoubleBuffered, errorfmt::ErrorFmt, event_listener::EventListener, + linkedlist::LinkedList, numcell::NumCell, smallmap::SmallMap, + transform_ext::TransformExt, }, video::{ dmabuf::DMA_BUF_SYNC_READ, @@ -91,7 +93,7 @@ use { fmt::{Debug, Formatter}, mem, ops::{Deref, DerefMut}, - rc::Rc, + rc::{Rc, Weak}, }, thiserror::Error, zwp_idle_inhibitor_v1::ZwpIdleInhibitorV1, @@ -282,7 +284,8 @@ pub struct WlSurface { pub children: RefCell>>, ext: CloneCell>, pub frame_requests: RefCell>>, - pub presentation_feedback: RefCell>>, + presentation_feedback: RefCell>>, + latched_presentation_feedback: RefCell>>, seat_state: NodeSeatState, toplevel: CloneCell>>, cursors: SmallMap, 1>, @@ -306,6 +309,10 @@ pub struct WlSurface { alpha_modifier: CloneCell>>, alpha: Cell>, pub text_input_connections: SmallMap, 1>, + latch_listener: EventListener, + presentation_listener: EventListener, + commit_version: NumCell, + latched_commit_version: Cell, } impl Debug for WlSurface { @@ -566,7 +573,7 @@ pub struct StackElement { } impl WlSurface { - pub fn new(id: WlSurfaceId, client: &Rc, version: Version) -> Self { + pub fn new(id: WlSurfaceId, client: &Rc, version: Version, slf: &Weak) -> Self { Self { id, node_id: client.state.node_ids.next(), @@ -599,6 +606,7 @@ impl WlSurface { ext: CloneCell::new(client.state.none_surface_ext.clone()), frame_requests: Default::default(), presentation_feedback: Default::default(), + latched_presentation_feedback: Default::default(), seat_state: Default::default(), toplevel: Default::default(), cursors: Default::default(), @@ -622,6 +630,10 @@ impl WlSurface { alpha_modifier: Default::default(), alpha: Default::default(), text_input_connections: Default::default(), + latch_listener: EventListener::new(slf.clone()), + presentation_listener: EventListener::new(slf.clone()), + commit_version: Default::default(), + latched_commit_version: Default::default(), } } @@ -652,6 +664,9 @@ impl WlSurface { if old.id == output.id { return; } + if self.visible.get() { + self.attach_events_to_output(output); + } output.global.send_enter(self); old.global.send_leave(self); if old.global.persistent.scale.get() != output.global.persistent.scale.get() { @@ -1230,14 +1245,15 @@ impl WlSurface { }; self.buffer_had_frame_request .set(had_frame_requests || has_frame_requests); - { + 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); } mem::swap(fbs.deref_mut(), &mut pending.presentation_feedback); - } + fbs.is_not_empty() + }; { if let Some(region) = pending.input_region.take() { self.input_region.set(region); @@ -1278,6 +1294,10 @@ impl WlSurface { } self.ext.get().after_apply_commit(); if self.visible.get() { + let output = self.output.get(); + if has_presentation_feedback { + self.latch_listener.attach(&output.latch_event); + } if damage_full { let mut damage = buffer_abs_pos .with_size(max_surface_size.0, max_surface_size.1) @@ -1327,6 +1347,7 @@ impl WlSurface { } } } + self.commit_version.fetch_add(1); Ok(()) } @@ -1469,10 +1490,17 @@ impl WlSurface { } } + fn attach_events_to_output(&self, output: &OutputNode) { + self.latch_listener.attach(&output.latch_event); + } + pub fn set_visible(&self, visible: bool) { if self.visible.replace(visible) == visible { return; } + if visible { + self.attach_events_to_output(&self.output.get()); + } for (_, inhibitor) in &self.idle_inhibitors { if visible { inhibitor.activate(); @@ -1586,6 +1614,7 @@ impl Object for WlSurface { self.idle_inhibitors.clear(); mem::take(self.pending.borrow_mut().deref_mut()); self.presentation_feedback.borrow_mut().clear(); + self.latched_presentation_feedback.borrow_mut().clear(); self.viewporter.take(); self.fractional_scale.take(); self.tearing_control.take(); @@ -2053,3 +2082,49 @@ impl DamageMatrix { } } } + +impl LatchListener for WlSurface { + fn after_latch(self: Rc) { + 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.append(&mut self.presentation_feedback.borrow_mut()); + if latched.is_not_empty() { + self.presentation_listener + .attach(&self.output.get().presentation_event); + } + self.latched_commit_version.set(self.commit_version.get()); + } + } + self.latch_listener.detach(); + } +} + +impl PresentationListener for WlSurface { + fn presented( + self: Rc, + output: &OutputNode, + tv_sec: u64, + tv_nsec: u32, + refresh: u32, + seq: u64, + flags: u32, + ) { + 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); + } + } + pf.send_presented(tv_sec, tv_nsec, refresh, seq, flags); + let _ = pf.client.remove_obj(&*pf); + } + self.presentation_listener.detach(); + } +} diff --git a/src/ifs/wl_surface/cursor.rs b/src/ifs/wl_surface/cursor.rs index 00163a0b..d9007dd1 100644 --- a/src/ifs/wl_surface/cursor.rs +++ b/src/ifs/wl_surface/cursor.rs @@ -107,6 +107,10 @@ impl Cursor for CursorSurface { 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.node_visit_children(self); } } diff --git a/src/renderer.rs b/src/renderer.rs index 03c2b87b..36327c33 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -9,7 +9,6 @@ use { zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, SurfaceBuffer, WlSurface, }, - wp_presentation_feedback::WpPresentationFeedback, }, rect::Rect, renderer::renderer_base::RendererBase, @@ -33,7 +32,6 @@ pub mod renderer_base; pub struct RenderResult { pub frame_requests: Vec>, - pub presentation_feedbacks: Vec>, pub output_id: OutputNodeId, } @@ -41,7 +39,6 @@ impl Default for RenderResult { fn default() -> Self { Self { frame_requests: Default::default(), - presentation_feedbacks: Default::default(), output_id: OutputNodeId::none(), } } @@ -54,13 +51,6 @@ impl RenderResult { let _ = fr.client.remove_obj(&*fr); } } - - pub fn discard_presentation_feedback(&mut self) { - for fb in self.presentation_feedbacks.drain(..) { - fb.send_discarded(); - let _ = fb.client.remove_obj(&*fb); - } - } } impl Debug for RenderResult { @@ -442,10 +432,6 @@ impl Renderer<'_> { let mut fr = surface.frame_requests.borrow_mut(); result.frame_requests.extend(fr.drain(..)); } - { - let mut fbs = surface.presentation_feedback.borrow_mut(); - result.presentation_feedbacks.extend(fbs.drain(..)); - } surface.presented(result.output_id); } } diff --git a/src/tasks/connector.rs b/src/tasks/connector.rs index 0a8d51ef..017cdd88 100644 --- a/src/tasks/connector.rs +++ b/src/tasks/connector.rs @@ -177,6 +177,7 @@ impl ConnectorHandler { title_visible: Default::default(), schedule, latch_event: Default::default(), + presentation_event: Default::default(), }); on.update_visible(); on.update_rects(); diff --git a/src/tree/output.rs b/src/tree/output.rs index 25f58c03..753fcc62 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -81,12 +81,25 @@ pub struct OutputNode { pub title_visible: Cell, pub schedule: Rc, pub latch_event: EventSource, + pub presentation_event: EventSource, } pub trait LatchListener { fn after_latch(self: Rc); } +pub trait PresentationListener { + fn presented( + self: Rc, + output: &OutputNode, + tv_sec: u64, + tv_nsec: u32, + refresh: u32, + seq: u64, + flags: u32, + ); +} + #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub enum PointerType { Seat(SeatId), @@ -113,6 +126,12 @@ impl OutputNode { } } + pub fn presented(&self, tv_sec: u64, tv_nsec: u32, refresh: u32, seq: u64, flags: u32) { + for listener in self.presentation_event.iter() { + listener.presented(self, tv_sec, tv_nsec, refresh, seq, flags); + } + } + pub fn update_exclusive_zones(self: &Rc) { let mut exclusive = ExclusiveSize::default(); for layer in &self.layers {