Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
fix(scenefx): stop blur-node reorder churn in river_scene_node_enable_blur
The trailing lower_to_bottom pair is not idempotent: on an already-ordered
tree ([opt_blur, std_blur, content]) each call swaps the two blur nodes
twice, and every swap fires scene_node_update over the node's whole
window-sized region. Since enable_blur runs on every surface commit and
every render_finish, every blurred window's full area was damaged and
recomposited on every wm tick — the background flicker visible through
semi-opaque unfocused (dimmed) windows. Reorder only when the desired
bottom order doesn't already hold.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/server/wlroots_log_wrapper.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/src/server/wlroots_log_wrapper.c b/src/server/wlroots_log_wrapper.c
index ef47fd7..65b36e9 100644
--- a/src/server/wlroots_log_wrapper.c
+++ b/src/server/wlroots_log_wrapper.c
@@ -770,12 +770,23 @@ void river_scene_node_enable_blur(struct wlr_scene_node *node, bool enabled, boo
wlr_scene_blur_set_transparency_mask_source((struct wlr_scene_blur *)std_blur_node, source_buffer);
}
- // Ensure correct stack order (from back to front): opt_blur_node -> std_blur_node -> window content
- if (std_blur_node) {
- wlr_scene_node_lower_to_bottom(std_blur_node);
- }
- if (opt_blur_node) {
- wlr_scene_node_lower_to_bottom(opt_blur_node);
+ // Ensure correct stack order (from back to front): opt_blur_node -> std_blur_node -> window content.
+ // Only reorder when out of order: the lower_to_bottom pair is not idempotent
+ // (on an already-ordered tree each call swaps the two nodes, and every swap
+ // damages the node's whole window-sized region — this runs per commit and
+ // per render_finish, so the no-op path must not touch the scene graph).
+ struct wlr_scene_node *want_bottom = opt_blur_node ? opt_blur_node : std_blur_node;
+ struct wlr_scene_node *want_second = opt_blur_node ? std_blur_node : NULL;
+ bool ordered = want_bottom != NULL
+ && tree->children.next == &want_bottom->link
+ && (want_second == NULL || want_bottom->link.next == &want_second->link);
+ if (!ordered) {
+ if (std_blur_node) {
+ wlr_scene_node_lower_to_bottom(std_blur_node);
+ }
+ if (opt_blur_node) {
+ wlr_scene_node_lower_to_bottom(opt_blur_node);
+ }
}
}