1
0
Fork 0
forked from wry/wry

wl_surface: handle presentation feedback cleanup automatically

This commit is contained in:
Julian Orth 2026-02-28 02:06:48 +01:00
parent 7b0dc8879a
commit 6bdd1ff6e7
4 changed files with 62 additions and 46 deletions

View file

@ -67,7 +67,7 @@ use {
zwlr_layer_surface_v1::{PendingLayerSurfaceData, ZwlrLayerSurfaceV1Error}, zwlr_layer_surface_v1::{PendingLayerSurfaceData, ZwlrLayerSurfaceV1Error},
}, },
wp_content_type_v1::ContentType, wp_content_type_v1::ContentType,
wp_presentation_feedback::{VRR_REFRESH_SINCE, WpPresentationFeedback}, wp_presentation_feedback::PresentationFeedback,
zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1, zwp_linux_dmabuf_feedback_v1::ZwpLinuxDmabufFeedbackV1,
}, },
io_uring::IoUringError, io_uring::IoUringError,
@ -311,8 +311,8 @@ pub struct WlSurface {
pub children: RefCell<Option<Box<ParentData>>>, pub children: RefCell<Option<Box<ParentData>>>,
ext: CloneCell<Rc<dyn SurfaceExt>>, ext: CloneCell<Rc<dyn SurfaceExt>>,
frame_requests: RefCell<Vec<FrameRequest>>, frame_requests: RefCell<Vec<FrameRequest>>,
presentation_feedback: RefCell<Vec<Rc<WpPresentationFeedback>>>, presentation_feedback: RefCell<Vec<PresentationFeedback>>,
latched_presentation_feedback: RefCell<Vec<Rc<WpPresentationFeedback>>>, latched_presentation_feedback: RefCell<Vec<PresentationFeedback>>,
seat_state: NodeSeatState, seat_state: NodeSeatState,
toplevel: CloneCell<Option<Rc<dyn ToplevelNode>>>, toplevel: CloneCell<Option<Rc<dyn ToplevelNode>>>,
cursors: SmallMap<CursorUserId, Rc<CursorSurface>, 1>, cursors: SmallMap<CursorUserId, Rc<CursorSurface>, 1>,
@ -469,7 +469,7 @@ struct PendingState {
damage_full: bool, damage_full: bool,
buffer_damage: Vec<Rect>, buffer_damage: Vec<Rect>,
surface_damage: Vec<Rect>, surface_damage: Vec<Rect>,
presentation_feedback: Vec<Rc<WpPresentationFeedback>>, presentation_feedback: Vec<PresentationFeedback>,
src_rect: Option<Option<[Fixed; 4]>>, src_rect: Option<Option<[Fixed; 4]>>,
dst_size: Option<Option<(i32, i32)>>, dst_size: Option<Option<(i32, i32)>>,
scale: Option<i32>, scale: Option<i32>,
@ -511,10 +511,7 @@ impl PendingState {
} }
} }
} }
for fb in self.presentation_feedback.drain(..) { self.presentation_feedback.clear();
fb.send_discarded();
let _ = client.remove_obj(&*fb);
}
// overwrite state // overwrite state
@ -799,11 +796,8 @@ impl WlSurface {
} }
} }
pub fn add_presentation_feedback(&self, fb: &Rc<WpPresentationFeedback>) { pub fn add_presentation_feedback(&self, fb: PresentationFeedback) {
self.pending self.pending.borrow_mut().presentation_feedback.push(fb);
.borrow_mut()
.presentation_feedback
.push(fb.clone());
} }
pub fn is_cursor(&self) -> bool { pub fn is_cursor(&self) -> bool {
@ -1382,10 +1376,7 @@ impl WlSurface {
} }
let has_presentation_feedback = { let has_presentation_feedback = {
let mut fbs = self.presentation_feedback.borrow_mut(); let mut fbs = self.presentation_feedback.borrow_mut();
for fb in fbs.drain(..) { fbs.clear();
fb.send_discarded();
let _ = self.client.remove_obj(&*fb);
}
mem::swap(fbs.deref_mut(), &mut pending.presentation_feedback); mem::swap(fbs.deref_mut(), &mut pending.presentation_feedback);
fbs.is_not_empty() fbs.is_not_empty()
}; };
@ -2224,10 +2215,7 @@ impl LatchListener for WlSurface {
if self.visible.get() { if self.visible.get() {
if self.latched_commit_version.get() < self.commit_version.get() { if self.latched_commit_version.get() < self.commit_version.get() {
let latched = &mut *self.latched_presentation_feedback.borrow_mut(); let latched = &mut *self.latched_presentation_feedback.borrow_mut();
for pf in latched.drain(..) { latched.clear();
pf.send_discarded();
let _ = pf.client.remove_obj(&*pf);
}
latched.append(&mut self.presentation_feedback.borrow_mut()); latched.append(&mut self.presentation_feedback.borrow_mut());
if latched.is_not_empty() { if latched.is_not_empty() {
self.presentation_listener self.presentation_listener
@ -2262,17 +2250,7 @@ impl PresentationListener for WlSurface {
let bindings = output.global.bindings.borrow(); let bindings = output.global.bindings.borrow();
let bindings = bindings.get(&self.client.id); let bindings = bindings.get(&self.client.id);
for pf in self.latched_presentation_feedback.borrow_mut().drain(..) { for pf in self.latched_presentation_feedback.borrow_mut().drain(..) {
if let Some(bindings) = bindings { pf.presented(bindings, tv_sec, tv_nsec, refresh, seq, flags, vrr);
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);
} }
self.presentation_listener.detach(); self.presentation_listener.detach();
} }

View file

@ -10,7 +10,7 @@ use {
scale::Scale, scale::Scale,
tree::{Node, NodeLocation, NodeVisitorBase, OutputNode}, tree::{Node, NodeLocation, NodeVisitorBase, OutputNode},
}, },
std::{cell::Cell, ops::Deref, rc::Rc}, std::{cell::Cell, rc::Rc},
}; };
pub struct CursorSurface { pub struct CursorSurface {
@ -103,14 +103,8 @@ impl Cursor for CursorSurface {
fr.now = self.0; fr.now = self.0;
drop(fr); drop(fr);
} }
for fr in node.presentation_feedback.borrow_mut().drain(..) { node.presentation_feedback.borrow_mut().clear();
fr.send_discarded(); node.latched_presentation_feedback.borrow_mut().clear();
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); node.node_visit_children(self);
} }
} }

View file

@ -3,7 +3,7 @@ use {
crate::{ crate::{
client::{Client, ClientError}, client::{Client, ClientError},
globals::{Global, GlobalName}, globals::{Global, GlobalName},
ifs::wp_presentation_feedback::WpPresentationFeedback, ifs::wp_presentation_feedback::{PresentationFeedback, WpPresentationFeedback},
leaks::Tracker, leaks::Tracker,
object::{Object, Version}, object::{Object, Version},
state::State, state::State,
@ -94,7 +94,7 @@ impl WpPresentationRequestHandler for WpPresentation {
}); });
track!(self.client, fb); track!(self.client, fb);
self.client.add_client_obj(&fb)?; self.client.add_client_obj(&fb)?;
surface.add_presentation_feedback(&fb); surface.add_presentation_feedback(PresentationFeedback::new(fb));
Ok(()) Ok(())
} }
} }

View file

@ -4,11 +4,55 @@ use {
ifs::{wl_output::WlOutput, wl_surface::WlSurface}, ifs::{wl_output::WlOutput, wl_surface::WlSurface},
leaks::Tracker, leaks::Tracker,
object::{Object, Version}, object::{Object, Version},
wire::{WpPresentationFeedbackId, wp_presentation_feedback::*}, wire::{WlOutputId, WpPresentationFeedbackId, wp_presentation_feedback::*},
}, },
ahash::AHashMap,
std::{convert::Infallible, rc::Rc}, std::{convert::Infallible, rc::Rc},
}; };
pub struct PresentationFeedback {
fb: Option<Rc<WpPresentationFeedback>>,
}
impl PresentationFeedback {
pub fn new(fb: Rc<WpPresentationFeedback>) -> Self {
Self { fb: Some(fb) }
}
pub fn presented(
mut self,
outputs: Option<&AHashMap<WlOutputId, Rc<WlOutput>>>,
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 struct WpPresentationFeedback {
pub id: WpPresentationFeedbackId, pub id: WpPresentationFeedbackId,
pub client: Rc<Client>, pub client: Rc<Client>,
@ -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.client.event(Presented {
self_id: self.id, self_id: self.id,
tv_sec, 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 }); self.client.event(Discarded { self_id: self.id });
} }
} }