git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commit275ceaf2cd94969783e89ad78387777c70352e35
parentfcc51dabb8
authorLucas Galante <[email protected]>
date2026-06-16 10:01
fix: resolve flickering by only updating scene node geometry if it changed

 src/server/window.rs             | 32 ++++++++++++++++----------------
 src/server/wlroots_log_wrapper.c | 18 ++++++++++++++++++
 wrapper.h                        |  6 ++++++
 3 files changed, 40 insertions(+), 16 deletions(-)

diff --git a/src/server/window.rs b/src/server/window.rs
index 6d48849..691e82f 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -1334,8 +1334,8 @@ impl Window {
                 let node = buffer as *mut ffi::wlr_scene_node;
 
                 if data.scale == 1.0 {
-                    ffi::wlr_scene_buffer_set_dest_size(buffer, 0, 0);
-                    ffi::wlr_scene_node_set_position(node, sx, sy);
+                    ffi::river_scene_buffer_set_dest_size_if_changed(buffer, 0, 0);
+                    ffi::river_scene_node_set_position_if_changed(node, sx, sy);
                 } else {
                     let surface = ffi::river_scene_node_get_surface(node);
                     if !surface.is_null() {
@@ -1343,11 +1343,11 @@ impl Window {
                         let h = ffi::river_wlr_surface_get_height(surface);
                         let dest_w = (w as f64 * data.scale) as i32;
                         let dest_h = (h as f64 * data.scale) as i32;
-                        ffi::wlr_scene_buffer_set_dest_size(buffer, dest_w, dest_h);
+                        ffi::river_scene_buffer_set_dest_size_if_changed(buffer, dest_w, dest_h);
 
                         let dest_x = (sx as f64 * data.scale) as i32;
                         let dest_y = (sy as f64 * data.scale) as i32;
-                        ffi::wlr_scene_node_set_position(node, dest_x, dest_y);
+                        ffi::river_scene_node_set_position_if_changed(node, dest_x, dest_y);
                     }
                 }
             }
@@ -1402,8 +1402,8 @@ impl Window {
             self.draw_borders();
         }
 
-        ffi::wlr_scene_node_set_position(self.tree as *mut ffi::wlr_scene_node, self.box_geom.x, self.box_geom.y);
-        ffi::wlr_scene_node_set_position(self.popup_tree as *mut ffi::wlr_scene_node, self.box_geom.x, self.box_geom.y);
+        ffi::river_scene_node_set_position_if_changed(self.tree as *mut ffi::wlr_scene_node, self.box_geom.x, self.box_geom.y);
+        ffi::river_scene_node_set_position_if_changed(self.popup_tree as *mut ffi::wlr_scene_node, self.box_geom.x, self.box_geom.y);
 
         let (geom_x, geom_y) = match self.impl_type {
             WindowImpl::Toplevel(toplevel) => {
@@ -1421,7 +1421,7 @@ impl Window {
             }
             _ => (0, 0),
         };
-        ffi::wlr_scene_node_set_position(self.surfaces.tree as *mut ffi::wlr_scene_node, -geom_x, -geom_y);
+        ffi::river_scene_node_set_position_if_changed(self.surfaces.tree as *mut ffi::wlr_scene_node, -geom_x, -geom_y);
 
         self.apply_surface_clip(&clip, &content_clip);
 
@@ -1469,10 +1469,10 @@ impl Window {
             (border.b as f64 / u32::MAX as f64) as f32,
             (border.a as f64 / u32::MAX as f64) as f32,
         ];
-        ffi::wlr_scene_node_set_position(self.window_background as *mut ffi::wlr_scene_node, 0, 0);
+        ffi::river_scene_node_set_position_if_changed(self.window_background as *mut ffi::wlr_scene_node, 0, 0);
         let bg_width = (self.box_geom.width as f64 * self.scale) as i32;
         let bg_height = (self.box_geom.height as f64 * self.scale) as i32;
-        ffi::wlr_scene_rect_set_size(self.window_background, bg_width, bg_height);
+        ffi::river_scene_rect_set_size_if_changed(self.window_background, bg_width, bg_height);
         ffi::wlr_scene_rect_set_color(self.window_background, bg_color.as_ptr());
         ffi::wlr_scene_node_set_enabled(self.window_background as *mut ffi::wlr_scene_node, !requested.hidden);
 
@@ -1555,8 +1555,8 @@ impl Window {
                 let scaled_y = ((*edge_box).y as f64 * self.scale) as i32;
                 let scaled_w = ((*edge_box).width as f64 * self.scale) as i32;
                 let scaled_h = ((*edge_box).height as f64 * self.scale) as i32;
-                ffi::wlr_scene_node_set_position(*rect as *mut ffi::wlr_scene_node, scaled_x, scaled_y);
-                ffi::wlr_scene_rect_set_size(*rect, scaled_w, scaled_h);
+                ffi::river_scene_node_set_position_if_changed(*rect as *mut ffi::wlr_scene_node, scaled_x, scaled_y);
+                ffi::river_scene_rect_set_size_if_changed(*rect, scaled_w, scaled_h);
                 ffi::wlr_scene_rect_set_color(*rect, color.as_ptr());
             }
         }
@@ -2373,7 +2373,7 @@ impl Decoration {
         let scale = (*self.window).scale;
         let scaled_x = (self.rendering_requested.offset_x as f64 * scale) as i32;
         let scaled_y = (self.rendering_requested.offset_y as f64 * scale) as i32;
-        ffi::wlr_scene_node_set_position(self.tree as *mut ffi::wlr_scene_node, scaled_x, scaled_y);
+        ffi::river_scene_node_set_position_if_changed(self.tree as *mut ffi::wlr_scene_node, scaled_x, scaled_y);
 
         struct ScaleData {
             scale: f64,
@@ -2389,8 +2389,8 @@ impl Decoration {
             let node = buffer as *mut ffi::wlr_scene_node;
 
             if data.scale == 1.0 {
-                ffi::wlr_scene_buffer_set_dest_size(buffer, 0, 0);
-                ffi::wlr_scene_node_set_position(node, sx, sy);
+                ffi::river_scene_buffer_set_dest_size_if_changed(buffer, 0, 0);
+                ffi::river_scene_node_set_position_if_changed(node, sx, sy);
             } else {
                 let surface = ffi::river_scene_node_get_surface(node);
                 if !surface.is_null() {
@@ -2398,11 +2398,11 @@ impl Decoration {
                     let h = ffi::river_wlr_surface_get_height(surface);
                     let dest_w = (w as f64 * data.scale) as i32;
                     let dest_h = (h as f64 * data.scale) as i32;
-                    ffi::wlr_scene_buffer_set_dest_size(buffer, dest_w, dest_h);
+                    ffi::river_scene_buffer_set_dest_size_if_changed(buffer, dest_w, dest_h);
 
                     let dest_x = (sx as f64 * data.scale) as i32;
                     let dest_y = (sy as f64 * data.scale) as i32;
-                    ffi::wlr_scene_node_set_position(node, dest_x, dest_y);
+                    ffi::river_scene_node_set_position_if_changed(node, dest_x, dest_y);
                 }
             }
         }
diff --git a/src/server/wlroots_log_wrapper.c b/src/server/wlroots_log_wrapper.c
index b23f0c9..4933120 100644
--- a/src/server/wlroots_log_wrapper.c
+++ b/src/server/wlroots_log_wrapper.c
@@ -670,6 +670,24 @@ void river_scene_node_set_opacity(struct wlr_scene_node *node, float opacity) {
 	wlr_scene_node_for_each_buffer(node, set_opacity_iterator, &opacity);
 }
 
+void river_scene_buffer_set_dest_size_if_changed(struct wlr_scene_buffer *scene_buffer, int width, int height) {
+	if (scene_buffer->dst_width != width || scene_buffer->dst_height != height) {
+		wlr_scene_buffer_set_dest_size(scene_buffer, width, height);
+	}
+}
+
+void river_scene_node_set_position_if_changed(struct wlr_scene_node *node, int x, int y) {
+	if (node->x != x || node->y != y) {
+		wlr_scene_node_set_position(node, x, y);
+	}
+}
+
+void river_scene_rect_set_size_if_changed(struct wlr_scene_rect *rect, int width, int height) {
+	if (rect->width != width || rect->height != height) {
+		wlr_scene_rect_set_size(rect, width, height);
+	}
+}
+
 
 
 
diff --git a/wrapper.h b/wrapper.h
index 756a637..0275a08 100644
--- a/wrapper.h
+++ b/wrapper.h
@@ -261,4 +261,10 @@ void river_scene_node_enable_blur(struct wlr_scene_node *node, bool enabled);
 
 void river_scene_node_set_opacity(struct wlr_scene_node *node, float opacity);
 
+void river_scene_buffer_set_dest_size_if_changed(struct wlr_scene_buffer *scene_buffer, int width, int height);
+
+void river_scene_node_set_position_if_changed(struct wlr_scene_node *node, int x, int y);
+
+void river_scene_rect_set_size_if_changed(struct wlr_scene_rect *rect, int width, int height);
+
 #endif // WRAPPER_H