From 535fd939d5327b924d9f74c5d0b7a289e4d54a5e Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Mon, 15 Jul 2024 11:02:11 +0200 Subject: [PATCH 1/3] surface: damage whole surface if scale, transform, alpha, viewport, or size changes --- src/ifs/wl_surface.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index dcea1930..39af7408 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -1059,6 +1059,10 @@ impl WlSurface { alpha_changed = true; self.alpha.set(alpha); } + let buffer_abs_pos = self.buffer_abs_pos.get(); + let mut max_surface_size = buffer_abs_pos.size(); + let mut damage_full = + scale_changed || buffer_transform_changed || viewport_changed || alpha_changed; let mut buffer_changed = false; let mut old_raw_size = None; let (dx, dy) = mem::take(&mut pending.offset); @@ -1194,11 +1198,14 @@ impl WlSurface { } } let (width, height) = new_size.unwrap_or_default(); - if (width, height) != self.buffer_abs_pos.get().size() { + let (old_width, old_height) = buffer_abs_pos.size(); + if (width, height) != (old_width, old_height) { self.need_extents_update.set(true); + self.buffer_abs_pos + .set(buffer_abs_pos.with_size(width, height).unwrap()); + max_surface_size = (width.max(old_width), height.max(old_height)); + damage_full = true; } - self.buffer_abs_pos - .set(self.buffer_abs_pos.get().with_size(width, height).unwrap()); } self.frame_requests .borrow_mut() @@ -1248,7 +1255,15 @@ impl WlSurface { } self.ext.get().after_apply_commit(); if self.visible.get() { - if self.buffer_presented.get() { + if damage_full { + let mut damage = buffer_abs_pos + .with_size(max_surface_size.0, max_surface_size.1) + .unwrap(); + if let Some(tl) = self.toplevel.get() { + damage = damage.intersect(tl.node_absolute_position()); + } + self.client.state.damage(damage); + } else if self.buffer_presented.get() { let now = self.client.state.now_msec() as _; for fr in self.frame_requests.borrow_mut().drain(..) { fr.send_done(now); From d1893a68eb97a35eb1761171d0b609d55dae3894 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sun, 14 Jul 2024 14:03:10 +0200 Subject: [PATCH 2/3] surface: throttle frame requests at the refresh rate --- src/ifs/wl_surface.rs | 43 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 39af7408..59b12a74 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -267,6 +267,7 @@ pub struct WlSurface { pub need_extents_update: Cell, pub buffer: CloneCell>>, buffer_presented: Cell, + buffer_had_frame_request: Cell, pub shm_texture: CloneCell>>, pub buf_x: NumCell, pub buf_y: NumCell, @@ -579,6 +580,7 @@ impl WlSurface { need_extents_update: Default::default(), buffer: Default::default(), buffer_presented: Default::default(), + buffer_had_frame_request: Default::default(), shm_texture: Default::default(), buf_x: Default::default(), buf_y: Default::default(), @@ -1095,6 +1097,7 @@ impl WlSurface { self.buffer.set(Some(Rc::new(surface_buffer))); if pending.has_damage() { self.buffer_presented.set(false); + self.buffer_had_frame_request.set(false); } } else { self.shm_texture.take(); @@ -1207,9 +1210,14 @@ impl WlSurface { damage_full = true; } } - self.frame_requests - .borrow_mut() - .extend(pending.frame_request.drain(..)); + let had_frame_requests = self.buffer_had_frame_request.get(); + let has_frame_requests = { + let frs = &mut *self.frame_requests.borrow_mut(); + frs.extend(pending.frame_request.drain(..)); + frs.is_not_empty() + }; + self.buffer_had_frame_request + .set(had_frame_requests || has_frame_requests); { let mut fbs = self.presentation_feedback.borrow_mut(); for fb in fbs.drain(..) { @@ -1264,10 +1272,31 @@ impl WlSurface { } self.client.state.damage(damage); } else if self.buffer_presented.get() { - let now = self.client.state.now_msec() as _; - for fr in self.frame_requests.borrow_mut().drain(..) { - fr.send_done(now); - let _ = fr.client.remove_obj(&*fr); + // If the currently attached buffer has already been fully presented ... + if has_frame_requests { + // ... and there are new frame requests ... + if had_frame_requests { + // ... and we've already dispatched frame requests for that buffer, + // then schedule new presentation of the primary output and + // unset the buffer_presented flag. This is for clients that + // send frame requests at an uncapped rate and expect the + // compositor to dispatch frame requests at the monitor + // refresh rate (e.g. firefox). This is very inefficient and + // disables VRR from working correctly. But since only firefox + // is affected, I'm ok with this. + let rect = self.output.get().global.pos.get(); + self.client.state.damage(rect); + self.buffer_presented.set(false); + } else { + // ... and this is the first commit that attaches a frame request + // for that buffer, then dispatch the frame requests + // immediately. + let now = self.client.state.now_msec() as _; + for fr in self.frame_requests.borrow_mut().drain(..) { + fr.send_done(now); + let _ = fr.client.remove_obj(&*fr); + } + } } } else { self.apply_damage(pending); From fcaed80b8491d890e28a3804394182c8f7c08386 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Mon, 15 Jul 2024 13:44:33 +0200 Subject: [PATCH 3/3] tree: damage stacked nodes when visibility changes --- src/ifs/wl_surface/x_surface/xwindow.rs | 3 +++ src/ifs/wl_surface/xdg_surface/xdg_popup.rs | 5 +++++ src/tree/float.rs | 4 +++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ifs/wl_surface/x_surface/xwindow.rs b/src/ifs/wl_surface/x_surface/xwindow.rs index 49110421..43755334 100644 --- a/src/ifs/wl_surface/x_surface/xwindow.rs +++ b/src/ifs/wl_surface/x_surface/xwindow.rs @@ -470,6 +470,9 @@ impl StackedNode for Xwindow { stacked_node_impl!(); fn stacked_set_visible(&self, visible: bool) { + let extents = self.x.surface.extents.get(); + let (x, y) = self.x.surface.buffer_abs_pos.get().position(); + self.data.state.damage(extents.move_(x, y)); self.tl_set_visible(visible); } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs index 05d58c8a..cf25578a 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup.rs @@ -241,6 +241,11 @@ impl XdgPopupRequestHandler for XdgPopup { impl XdgPopup { pub fn set_visible(&self, visible: bool) { + let surface = &self.xdg.surface; + let extents = surface.extents.get(); + let (x, y) = surface.buffer_abs_pos.get().position(); + surface.client.state.damage(extents.move_(x, y)); + // log::info!("set visible = {}", visible); self.set_visible_prepared.set(false); self.xdg.set_visible(visible); diff --git a/src/tree/float.rs b/src/tree/float.rs index 1fc4350f..11929502 100644 --- a/src/tree/float.rs +++ b/src/tree/float.rs @@ -785,7 +785,9 @@ impl StackedNode for FloatNode { stacked_node_impl!(); fn stacked_set_visible(&self, visible: bool) { - self.visible.set(visible); + if self.visible.replace(visible) != visible { + self.state.damage(self.position.get()); + } if let Some(child) = self.child.get() { child.tl_set_visible(visible); }