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

scenefx/types/scene/wlr_scene.c (160.8K)

   1 #include <assert.h>
   2 #include <math.h>
   3 #include <pixman.h>
   4 #include <stdint.h>
   5 #include <stdio.h>
   6 #include <stdlib.h>
   7 #include <string.h>
   8 #include <time.h>
   9 #include <wlr/backend.h>
  10 #include <wlr/render/swapchain.h>
  11 #include <wlr/render/drm_syncobj.h>
  12 #include <wlr/render/wlr_renderer.h>
  13 #include <wlr/types/wlr_color_management_v1.h>
  14 #include <wlr/types/wlr_compositor.h>
  15 #include <wlr/types/wlr_damage_ring.h>
  16 #include <wlr/types/wlr_gamma_control_v1.h>
  17 #include <wlr/types/wlr_linux_dmabuf_v1.h>
  18 #include <wlr/types/wlr_presentation_time.h>
  19 #include <wlr/util/log.h>
  20 #include <wlr/util/region.h>
  21 #include <wlr/util/transform.h>
  22 
  23 static bool cce_scene_blur_debug(void);
  24 
  25 #include "render/color.h"
  26 #include "render/tracy.h"
  27 #include "scenefx/render/fx_renderer/fx_offscreen_buffers.h"
  28 #include "scenefx/render/pass.h"
  29 #include "scenefx/types/fx/blur_data.h"
  30 #include "scenefx/types/fx/clipped_region.h"
  31 #include "scenefx/types/wlr_scene.h"
  32 #include "types/fx/clipped_region.h"
  33 #include "types/wlr_output.h"
  34 #include "types/wlr_scene.h"
  35 #include "util/array.h"
  36 #include "util/env.h"
  37 #include "util/time.h"
  38 
  39 #include <wlr/config.h>
  40 
  41 #if WLR_HAS_XWAYLAND
  42 #include <wlr/xwayland/xwayland.h>
  43 #endif
  44 
  45 #define DMABUF_FEEDBACK_DEBOUNCE_FRAMES  30
  46 #define HIGHLIGHT_DAMAGE_FADEOUT_TIME   250
  47 
  48 #define CURSOR_HISTORY_SIZE 16
  49 // Only this many of the most recent footprints are damage: a stale cursor
  50 // can only be baked into a buffer the swapchain still hands back, and a
  51 // wlroots swapchain holds at most WLR_SWAPCHAIN_CAP (4) — so twice that is
  52 // a margin, not a guess. Until 2026-10-06 all 16 counted, forever: the
  53 // trail of a moving cursor was re-rendered (and re-blurred) every frame, and
  54 // after it stopped, every unrelated frame still pulled in the old trail.
  55 #define CURSOR_HISTORY_DAMAGE 8
  56 static struct {
  57 	int x, y, w, h;
  58 	bool valid;
  59 	// The footprint is in this output's coordinates.
  60 	struct wlr_output *output;
  61 } g_cursor_history[CURSOR_HISTORY_SIZE];
  62 static int g_cursor_history_index = 0;
  63 
  64 struct wlr_scene_tree *wlr_scene_tree_from_node(struct wlr_scene_node *node) {
  65 	assert(node->type == WLR_SCENE_NODE_TREE);
  66 	struct wlr_scene_tree *tree = wl_container_of(node, tree, node);
  67 	return tree;
  68 }
  69 
  70 struct wlr_scene_rect *wlr_scene_rect_from_node(struct wlr_scene_node *node) {
  71 	assert(node->type == WLR_SCENE_NODE_RECT);
  72 	struct wlr_scene_rect *rect = wl_container_of(node, rect, node);
  73 	return rect;
  74 }
  75 
  76 struct wlr_scene_optimized_blur *wlr_scene_optimized_blur_from_node(
  77 		struct wlr_scene_node *node) {
  78 	assert(node->type == WLR_SCENE_NODE_OPTIMIZED_BLUR);
  79 	struct wlr_scene_optimized_blur *blur_node =
  80 		wl_container_of(node, blur_node, node);
  81 	return blur_node;
  82 }
  83 
  84 struct wlr_scene_buffer *wlr_scene_buffer_from_node(
  85 		struct wlr_scene_node *node) {
  86 	assert(node->type == WLR_SCENE_NODE_BUFFER);
  87 	struct wlr_scene_buffer *buffer = wl_container_of(node, buffer, node);
  88 	return buffer;
  89 }
  90 
  91 struct wlr_scene_shadow *wlr_scene_shadow_from_node(struct wlr_scene_node *node) {
  92 	assert(node->type == WLR_SCENE_NODE_SHADOW);
  93 	struct wlr_scene_shadow *shadow = wl_container_of(node, shadow, node);
  94 	return shadow;
  95 }
  96 
  97 struct wlr_scene_frame *wlr_scene_frame_from_node(struct wlr_scene_node *node) {
  98 	assert(node->type == WLR_SCENE_NODE_FRAME);
  99 	struct wlr_scene_frame *frame = wl_container_of(node, frame, node);
 100 	return frame;
 101 }
 102 
 103 struct wlr_scene_bevel *wlr_scene_bevel_from_node(struct wlr_scene_node *node) {
 104 	assert(node->type == WLR_SCENE_NODE_BEVEL);
 105 	struct wlr_scene_bevel *bevel = wl_container_of(node, bevel, node);
 106 	return bevel;
 107 }
 108 
 109 struct wlr_scene_droplet *wlr_scene_droplet_from_node(struct wlr_scene_node *node) {
 110 	assert(node->type == WLR_SCENE_NODE_DROPLET);
 111 	struct wlr_scene_droplet *droplet = wl_container_of(node, droplet, node);
 112 	return droplet;
 113 }
 114 
 115 struct wlr_scene_blur *wlr_scene_blur_from_node(struct wlr_scene_node *node) {
 116 	assert(node->type == WLR_SCENE_NODE_BLUR);
 117 	struct wlr_scene_blur *blur = wl_container_of(node, blur, node);
 118 	return blur;
 119 }
 120 
 121 struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) {
 122 	struct wlr_scene_tree *tree;
 123 	if (node->type == WLR_SCENE_NODE_TREE) {
 124 		tree = wlr_scene_tree_from_node(node);
 125 	} else {
 126 		tree = node->parent;
 127 	}
 128 
 129 	while (tree->node.parent != NULL) {
 130 		tree = tree->node.parent;
 131 	}
 132 	struct wlr_scene *scene = wl_container_of(tree, scene, tree);
 133 	return scene;
 134 }
 135 
 136 static void scene_node_init(struct wlr_scene_node *node,
 137 		enum wlr_scene_node_type type, struct wlr_scene_tree *parent) {
 138 	*node = (struct wlr_scene_node){
 139 		.type = type,
 140 		.parent = parent,
 141 		.enabled = true,
 142 	};
 143 
 144 	wl_list_init(&node->link);
 145 
 146 	wl_signal_init(&node->events.destroy);
 147 	pixman_region32_init(&node->visible);
 148 
 149 	if (parent != NULL) {
 150 		wl_list_insert(parent->children.prev, &node->link);
 151 	}
 152 
 153 	wlr_addon_set_init(&node->addons);
 154 }
 155 
 156 struct highlight_region {
 157 	pixman_region32_t region;
 158 	struct timespec when;
 159 	struct wl_list link;
 160 };
 161 
 162 static void scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer,
 163 	struct wlr_buffer *buffer);
 164 static void scene_buffer_set_texture(struct wlr_scene_buffer *scene_buffer,
 165 	struct wlr_texture *texture);
 166 
 167 void wlr_scene_node_destroy(struct wlr_scene_node *node) {
 168 	if (node == NULL) {
 169 		return;
 170 	}
 171 
 172 	// We want to call the destroy listeners before we do anything else
 173 	// in case the destroy signal would like to remove children before they
 174 	// are recursively destroyed.
 175 	wl_signal_emit_mutable(&node->events.destroy, NULL);
 176 	wlr_addon_set_finish(&node->addons);
 177 
 178 	wlr_scene_node_set_enabled(node, false);
 179 
 180 	struct wlr_scene *scene = scene_node_get_root(node);
 181 	if (node->type == WLR_SCENE_NODE_BUFFER) {
 182 		struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
 183 
 184 		uint64_t active = scene_buffer->active_outputs;
 185 		if (active) {
 186 			struct wlr_scene_output *scene_output;
 187 			wl_list_for_each(scene_output, &scene->outputs, link) {
 188 				if (active & (1ull << scene_output->index)) {
 189 					wl_signal_emit_mutable(&scene_buffer->events.output_leave,
 190 						scene_output);
 191 				}
 192 			}
 193 		}
 194 
 195 		scene_buffer_set_buffer(scene_buffer, NULL);
 196 		scene_buffer_set_texture(scene_buffer, NULL);
 197 		pixman_region32_fini(&scene_buffer->opaque_region);
 198 		wlr_drm_syncobj_timeline_unref(scene_buffer->wait_timeline);
 199 		linked_node_destroy(&scene_buffer->blur);
 200 
 201 		assert(wl_list_empty(&scene_buffer->events.output_leave.listener_list));
 202 		assert(wl_list_empty(&scene_buffer->events.output_enter.listener_list));
 203 		assert(wl_list_empty(&scene_buffer->events.outputs_update.listener_list));
 204 		assert(wl_list_empty(&scene_buffer->events.output_sample.listener_list));
 205 		assert(wl_list_empty(&scene_buffer->events.frame_done.listener_list));
 206 	} else if (node->type == WLR_SCENE_NODE_OPTIMIZED_BLUR) {
 207 		pixman_region32_fini(&wlr_scene_optimized_blur_from_node(node)->baked_region);
 208 		pixman_region32_fini(&wlr_scene_optimized_blur_from_node(node)->edge_region);
 209 	} else if (node->type == WLR_SCENE_NODE_TREE) {
 210 		struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
 211 
 212 		if (scene_tree == &scene->tree) {
 213 			assert(!node->parent);
 214 			struct wlr_scene_output *scene_output, *scene_output_tmp;
 215 			wl_list_for_each_safe(scene_output, scene_output_tmp, &scene->outputs, link) {
 216 				wlr_scene_output_destroy(scene_output);
 217 			}
 218 
 219 			wl_list_remove(&scene->linux_dmabuf_v1_destroy.link);
 220 			wl_list_remove(&scene->gamma_control_manager_v1_destroy.link);
 221 			wl_list_remove(&scene->gamma_control_manager_v1_set_gamma.link);
 222 		} else {
 223 			assert(node->parent);
 224 		}
 225 
 226 		struct wlr_scene_node *child, *child_tmp;
 227 		wl_list_for_each_safe(child, child_tmp,
 228 				&scene_tree->children, link) {
 229 			wlr_scene_node_destroy(child);
 230 		}
 231 	} else if (node->type == WLR_SCENE_NODE_BLUR) {
 232 		struct wlr_scene_blur *blur = wlr_scene_blur_from_node(node);
 233 		linked_node_destroy(&blur->transparency_mask_source);
 234 	}
 235 
 236 	assert(wl_list_empty(&node->events.destroy.listener_list));
 237 
 238 	wl_list_remove(&node->link);
 239 	pixman_region32_fini(&node->visible);
 240 	free(node);
 241 }
 242 
 243 static void scene_tree_init(struct wlr_scene_tree *tree,
 244 		struct wlr_scene_tree *parent) {
 245 	*tree = (struct wlr_scene_tree){0};
 246 	scene_node_init(&tree->node, WLR_SCENE_NODE_TREE, parent);
 247 	wl_list_init(&tree->children);
 248 }
 249 
 250 struct wlr_scene *wlr_scene_create(void) {
 251 	struct wlr_scene *scene = calloc(1, sizeof(*scene));
 252 	if (scene == NULL) {
 253 		return NULL;
 254 	}
 255 
 256 	scene_tree_init(&scene->tree, NULL);
 257 
 258 	wl_list_init(&scene->outputs);
 259 	wl_list_init(&scene->linux_dmabuf_v1_destroy.link);
 260 	wl_list_init(&scene->gamma_control_manager_v1_destroy.link);
 261 	wl_list_init(&scene->gamma_control_manager_v1_set_gamma.link);
 262 
 263 	scene->restack_xwayland_surfaces = true;
 264 
 265 	const char *debug_damage_options[] = {
 266 		"none",
 267 		"rerender",
 268 		"highlight",
 269 		NULL
 270 	};
 271 
 272 	scene->debug_damage_option = env_parse_switch("WLR_SCENE_DEBUG_DAMAGE", debug_damage_options);
 273 	scene->direct_scanout = !env_parse_bool("WLR_SCENE_DISABLE_DIRECT_SCANOUT");
 274 	scene->calculate_visibility = !env_parse_bool("WLR_SCENE_DISABLE_VISIBILITY");
 275 	scene->highlight_transparent_region = env_parse_bool("WLR_SCENE_HIGHLIGHT_TRANSPARENT_REGION");
 276 
 277 	scene->blur_data = blur_data_get_default();
 278 
 279 	return scene;
 280 }
 281 
 282 struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent) {
 283 	assert(parent);
 284 
 285 	struct wlr_scene_tree *tree = calloc(1, sizeof(*tree));
 286 	if (tree == NULL) {
 287 		return NULL;
 288 	}
 289 
 290 	scene_tree_init(tree, parent);
 291 	return tree;
 292 }
 293 
 294 typedef bool (*scene_node_box_iterator_func_t)(struct wlr_scene_node *node,
 295 	int sx, int sy, void *data);
 296 
 297 static bool _scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box,
 298 		scene_node_box_iterator_func_t iterator, void *user_data, int lx, int ly) {
 299 	if (!node->enabled) {
 300 		return false;
 301 	}
 302 
 303 	switch (node->type) {
 304 	case WLR_SCENE_NODE_TREE:;
 305 		struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
 306 		struct wlr_scene_node *child;
 307 		wl_list_for_each_reverse(child, &scene_tree->children, link) {
 308 			if (_scene_nodes_in_box(child, box, iterator, user_data, lx + child->x, ly + child->y)) {
 309 				return true;
 310 			}
 311 		}
 312 		break;
 313 	case WLR_SCENE_NODE_RECT:
 314 	case WLR_SCENE_NODE_BUFFER:
 315 	case WLR_SCENE_NODE_SHADOW:
 316 	case WLR_SCENE_NODE_BEVEL:
 317 	case WLR_SCENE_NODE_FRAME:
 318 	case WLR_SCENE_NODE_DROPLET:
 319 	case WLR_SCENE_NODE_OPTIMIZED_BLUR:
 320 	case WLR_SCENE_NODE_BLUR:;
 321 		struct wlr_box node_box = { .x = lx, .y = ly };
 322 		scene_node_get_size(node, &node_box.width, &node_box.height);
 323 
 324 		if (wlr_box_intersection(&node_box, &node_box, box) &&
 325 				iterator(node, lx, ly, user_data)) {
 326 			return true;
 327 		}
 328 		break;
 329 	}
 330 
 331 	return false;
 332 }
 333 
 334 static bool scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box,
 335 		scene_node_box_iterator_func_t iterator, void *user_data) {
 336 	int x, y;
 337 	wlr_scene_node_coords(node, &x, &y);
 338 
 339 	return _scene_nodes_in_box(node, box, iterator, user_data, x, y);
 340 }
 341 
 342 static pixman_region32_t create_corner_location_region(struct fx_corner_radii corners, int x, int y, int width, int height) {
 343 	pixman_region32_t corner_region;
 344 	pixman_region32_init(&corner_region);
 345 	if (corners.top_left) {
 346 		pixman_region32_union_rect(&corner_region, &corner_region, x, y, corners.top_left, corners.top_left);
 347 	}
 348 
 349 	if (corners.top_right) {
 350 		pixman_region32_union_rect(&corner_region, &corner_region, x + (width - corners.top_right), y,
 351 			corners.top_right, corners.top_right);
 352 	}
 353 
 354 	if (corners.bottom_left) {
 355 		pixman_region32_union_rect(&corner_region, &corner_region, x, y + (height - corners.bottom_left),
 356 			corners.bottom_left, corners.bottom_left);
 357 	}
 358 
 359 	if (corners.bottom_right) {
 360 		pixman_region32_union_rect(&corner_region, &corner_region,
 361 			x + (width - corners.bottom_right), y + (height - corners.bottom_right),
 362 			corners.bottom_right, corners.bottom_right);
 363 	}
 364 
 365 	return corner_region;
 366 }
 367 
 368 static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y,
 369 		pixman_region32_t *opaque) {
 370 	int width, height;
 371 	scene_node_get_size(node, &width, &height);
 372 
 373 	if (node->type == WLR_SCENE_NODE_RECT) {
 374 		struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node);
 375 		if (scene_rect->color[3] != 1 || scene_rect->fade_inset > 0) {
 376 			return;
 377 		}
 378 
 379 		pixman_region32_fini(opaque);
 380 		pixman_region32_init_rect(opaque, x, y, width, height);
 381 
 382 		// subtract corners from opaque region
 383 		if (!fx_corner_radii_is_empty(&scene_rect->corners)) {
 384 			pixman_region32_t corners = create_corner_location_region(scene_rect->corners, x, y, width, height);
 385 			pixman_region32_subtract(opaque, opaque, &corners);
 386 			pixman_region32_fini(&corners);
 387 		}
 388 
 389 		// subtract clipped area from opaque region
 390 		if (!wlr_box_empty(&scene_rect->clipped_region.area)) {
 391 			struct wlr_box *clipped = &scene_rect->clipped_region.area;
 392 			pixman_region32_t clipped_region;
 393 			pixman_region32_init_rect(&clipped_region, clipped->x + x, clipped->y + y,
 394 					clipped->width, clipped->height);
 395 			pixman_region32_subtract(opaque, opaque, &clipped_region);
 396 			pixman_region32_fini(&clipped_region);
 397 		}
 398 		return;
 399 	} else if (node->type == WLR_SCENE_NODE_BUFFER) {
 400 		struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
 401 
 402 		if (!scene_buffer->buffer) {
 403 			return;
 404 		}
 405 
 406 		if (scene_buffer->opacity != 1) {
 407 			return;
 408 		}
 409 
 410 		if (!scene_buffer->buffer_is_opaque) {
 411 			pixman_region32_copy(opaque, &scene_buffer->opaque_region);
 412 			pixman_region32_intersect_rect(opaque, opaque, 0, 0, width, height);
 413 			pixman_region32_translate(opaque, x, y);
 414 		} else {
 415 			pixman_region32_fini(opaque);
 416 			pixman_region32_init_rect(opaque, x, y, width, height);
 417 		}
 418 
 419 		// subtract the corners from the opaque region
 420 		if (!fx_corner_radii_is_empty(&scene_buffer->corners)) {
 421 			pixman_region32_t corners = create_corner_location_region(scene_buffer->corners, x, y, width, height);
 422 			pixman_region32_subtract(opaque, opaque, &corners);
 423 			pixman_region32_fini(&corners);
 424 		}
 425 
 426 		return;
 427 	} else if (node->type == WLR_SCENE_NODE_SHADOW) {
 428 		// TODO: test & handle case of blur sigma = 0 and color[3] = 1?
 429 		return;
 430 	} else if (node->type == WLR_SCENE_NODE_BEVEL
 431 			|| node->type == WLR_SCENE_NODE_FRAME
 432 			|| node->type == WLR_SCENE_NODE_DROPLET
 433 			|| node->type == WLR_SCENE_NODE_OPTIMIZED_BLUR
 434 			|| node->type == WLR_SCENE_NODE_BLUR) {
 435 		// Always transparent (the droplet is opaque inside its silhouette
 436 		// but never box-shaped, so it must not occlude as a box).
 437 		return;
 438 	}
 439 
 440 	pixman_region32_fini(opaque);
 441 	pixman_region32_init_rect(opaque, x, y, width, height);
 442 }
 443 
 444 struct scene_update_data {
 445 	struct wlr_scene_node *updated_node;
 446 	pixman_region32_t *visible;
 447 	const pixman_region32_t *update_region;
 448 	struct wlr_box update_box;
 449 	struct wl_list *outputs;
 450 	bool calculate_visibility;
 451 	bool restack_xwayland_surfaces;
 452 
 453 #if WLR_HAS_XWAYLAND
 454 	struct wlr_xwayland_surface *restack_above;
 455 #endif
 456 	bool blur_frozen;
 457 	bool content_update;
 458 };
 459 
 460 static uint32_t region_area(const pixman_region32_t *region) {
 461 	uint32_t area = 0;
 462 
 463 	int nrects;
 464 	pixman_box32_t *rects = pixman_region32_rectangles(region, &nrects);
 465 	for (int i = 0; i < nrects; ++i) {
 466 		area += (rects[i].x2 - rects[i].x1) * (rects[i].y2 - rects[i].y1);
 467 	}
 468 
 469 	return area;
 470 }
 471 
 472 static void scale_region(pixman_region32_t *region, float scale, bool round_up) {
 473 	wlr_region_scale(region, region, scale);
 474 
 475 	if (round_up && floor(scale) != scale) {
 476 		wlr_region_expand(region, region, 1);
 477 	}
 478 }
 479 
 480 struct render_data {
 481 	enum wl_output_transform transform;
 482 	float scale;
 483 	struct wlr_box logical;
 484 	int trans_width, trans_height;
 485 
 486 	struct wlr_scene_output *output;
 487 
 488 	struct wlr_render_pass *render_pass;
 489 	pixman_region32_t damage;
 490 };
 491 
 492 static void logical_to_buffer_coords(pixman_region32_t *region, const struct render_data *data,
 493 		bool round_up) {
 494 	enum wl_output_transform transform = wlr_output_transform_invert(data->transform);
 495 	scale_region(region, data->scale, round_up);
 496 	wlr_region_transform(region, region, transform, data->trans_width, data->trans_height);
 497 }
 498 
 499 static void output_to_buffer_coords(pixman_region32_t *damage, struct wlr_output *output) {
 500 	int width, height;
 501 	wlr_output_transformed_resolution(output, &width, &height);
 502 
 503 	wlr_region_transform(damage, damage,
 504 		wlr_output_transform_invert(output->transform), width, height);
 505 }
 506 
 507 static int scale_length(int length, int offset, float scale) {
 508 	return round((offset + length) * scale) - round(offset * scale);
 509 }
 510 
 511 static void scale_box(struct wlr_box *box, float scale) {
 512 	box->width = scale_length(box->width, box->x, scale);
 513 	box->height = scale_length(box->height, box->y, scale);
 514 	box->x = round(box->x * scale);
 515 	box->y = round(box->y * scale);
 516 }
 517 
 518 static void transform_output_box(struct wlr_box *box, const struct render_data *data) {
 519 	enum wl_output_transform transform = wlr_output_transform_invert(data->transform);
 520 	scale_box(box, data->scale);
 521 	wlr_box_transform(box, box, transform, data->trans_width, data->trans_height);
 522 }
 523 
 524 /* Whether a node renders with the scene's desk sub-pixel offset: any
 525  * ancestor is one of the scene's desk trees. */
 526 static bool scene_node_has_desk_offset(struct wlr_scene *scene, struct wlr_scene_node *node) {
 527 	for (struct wlr_scene_tree *t = node->parent; t != NULL; t = t->node.parent) {
 528 		for (int i = 0; i < WLR_SCENE_DESK_TREES; i++) {
 529 			if (scene->desk_trees[i] == t) {
 530 				return true;
 531 			}
 532 		}
 533 	}
 534 	return false;
 535 }
 536 
 537 /* The desk offset in an output's device px (each 0 or negative). Only a
 538  * NORMAL transform is shifted: on a rotated output the vector would need
 539  * rotating too, and no cce output is rotated. */
 540 static void scene_desk_offset_px(struct wlr_scene *scene, float scale,
 541 		enum wl_output_transform transform, int *dx, int *dy) {
 542 	*dx = 0;
 543 	*dy = 0;
 544 	if (transform != WL_OUTPUT_TRANSFORM_NORMAL) {
 545 		return;
 546 	}
 547 	*dx = (int)lround(scene->desk_sub_x * scale);
 548 	*dy = (int)lround(scene->desk_sub_y * scale);
 549 }
 550 
 551 static void scene_output_damage(struct wlr_scene_output *scene_output,
 552 		const pixman_region32_t *damage) {
 553 	struct wlr_output *output = scene_output->output;
 554 
 555 	pixman_region32_t clipped;
 556 	pixman_region32_init(&clipped);
 557 	pixman_region32_intersect_rect(&clipped, damage, 0, 0, output->width, output->height);
 558 
 559 	// A desk shifted by the sub-pixel offset draws its nodes up to one
 560 	// device px away from where their layout boxes say; widen the damage
 561 	// by that shift so the drawn pixels are always inside it.
 562 	{
 563 		int dx, dy;
 564 		scene_desk_offset_px(scene_output->scene, output->scale, output->transform, &dx, &dy);
 565 		if (dx != 0 || dy != 0) {
 566 			pixman_region32_t shifted;
 567 			pixman_region32_init(&shifted);
 568 			pixman_region32_copy(&shifted, &clipped);
 569 			pixman_region32_translate(&shifted, dx, dy);
 570 			pixman_region32_union(&clipped, &clipped, &shifted);
 571 			pixman_region32_intersect_rect(&clipped, &clipped, 0, 0, output->width, output->height);
 572 			pixman_region32_fini(&shifted);
 573 		}
 574 	}
 575 
 576 	if (!pixman_region32_empty(&clipped)) {
 577 		wlr_output_schedule_frame(scene_output->output);
 578 		wlr_damage_ring_add(&scene_output->damage_ring, &clipped);
 579 
 580 		pixman_region32_union(&scene_output->pending_commit_damage,
 581 			&scene_output->pending_commit_damage, &clipped);
 582 	}
 583 
 584 	pixman_region32_fini(&clipped);
 585 }
 586 
 587 static void scene_output_damage_whole(struct wlr_scene_output *scene_output) {
 588 	struct wlr_output *output = scene_output->output;
 589 
 590 	pixman_region32_t damage;
 591 	pixman_region32_init_rect(&damage, 0, 0, output->width, output->height);
 592 	scene_output_damage(scene_output, &damage);
 593 	pixman_region32_fini(&damage);
 594 }
 595 
 596 static void scene_damage_outputs(struct wlr_scene *scene, const pixman_region32_t *damage) {
 597 	if (pixman_region32_empty(damage)) {
 598 		return;
 599 	}
 600 
 601 	struct wlr_scene_output *scene_output;
 602 	wl_list_for_each(scene_output, &scene->outputs, link) {
 603 		pixman_region32_t output_damage;
 604 		pixman_region32_init(&output_damage);
 605 		pixman_region32_copy(&output_damage, damage);
 606 		pixman_region32_translate(&output_damage,
 607 			-scene_output->x, -scene_output->y);
 608 		scale_region(&output_damage, scene_output->output->scale, true);
 609 		output_to_buffer_coords(&output_damage, scene_output->output);
 610 		scene_output_damage(scene_output, &output_damage);
 611 		pixman_region32_fini(&output_damage);
 612 	}
 613 }
 614 
 615 static void update_node_update_outputs(struct wlr_scene_node *node,
 616 		struct wl_list *outputs, struct wlr_scene_output *ignore,
 617 		struct wlr_scene_output *force) {
 618 	if (node->type != WLR_SCENE_NODE_BUFFER) {
 619 		return;
 620 	}
 621 
 622 	struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
 623 
 624 	uint32_t largest_overlap = 0;
 625 	struct wlr_scene_output *old_primary_output = scene_buffer->primary_output;
 626 	scene_buffer->primary_output = NULL;
 627 
 628 	size_t count = 0;
 629 	uint64_t active_outputs = 0;
 630 
 631 	if (!pixman_region32_empty(&node->visible)) {
 632 		uint32_t visible_area = region_area(&node->visible);
 633 
 634 		// let's update the outputs in two steps:
 635 		//  - the primary outputs
 636 		//  - the enter/leave signals
 637 		// This ensures that the enter/leave signals can rely on the primary output
 638 		// to have a reasonable value. Otherwise, they may get a value that's in
 639 		// the middle of a calculation.
 640 		struct wlr_scene_output *scene_output;
 641 		wl_list_for_each(scene_output, outputs, link) {
 642 			if (scene_output == ignore) {
 643 				continue;
 644 			}
 645 
 646 			if (!scene_output->output->enabled) {
 647 				continue;
 648 			}
 649 
 650 			struct wlr_box output_box = {
 651 				.x = scene_output->x,
 652 				.y = scene_output->y,
 653 			};
 654 			wlr_output_effective_resolution(scene_output->output,
 655 				&output_box.width, &output_box.height);
 656 
 657 			pixman_region32_t intersection;
 658 			pixman_region32_init(&intersection);
 659 			pixman_region32_intersect_rect(&intersection, &node->visible,
 660 				output_box.x, output_box.y, output_box.width, output_box.height);
 661 			uint32_t overlap = region_area(&intersection);
 662 			pixman_region32_fini(&intersection);
 663 
 664 			// If the overlap accounts for less than 10% of the visible node area,
 665 			// ignore this output
 666 			if (overlap >= 0.1 * visible_area) {
 667 				if (overlap >= largest_overlap) {
 668 					largest_overlap = overlap;
 669 					scene_buffer->primary_output = scene_output;
 670 				}
 671 
 672 				active_outputs |= 1ull << scene_output->index;
 673 				count++;
 674 			}
 675 		}
 676 	}
 677 
 678 	// NOT cleared on a primary_output change (cce): clearing it defeats the
 679 	// duplicate-suppression memcmp in scene_buffer_send_dmabuf_feedback, and
 680 	// the options it compares already carry everything a change here could
 681 	// affect — main_renderer and scanout_primary_output. Composition feedback
 682 	// is {renderer, NULL} whichever output is primary, so clearing only ever
 683 	// forced a byte-identical resend.
 684 	//
 685 	// Each resend costs the client a format-table fd, and Mesa parks those on
 686 	// its private WSI queues until the next acquire/present — so an idle,
 687 	// damage-driven window banks one per resend and never drains. Measured on
 688 	// a live session before this change: one enter+exit of the overview added
 689 	// 67 fds to every long-lived client at once, against a 1024 soft limit.
 690 
 691 	uint64_t old_active = scene_buffer->active_outputs;
 692 	scene_buffer->active_outputs = active_outputs;
 693 
 694 	struct wlr_scene_output *scene_output;
 695 	wl_list_for_each(scene_output, outputs, link) {
 696 		uint64_t mask = 1ull << scene_output->index;
 697 		bool intersects = active_outputs & mask;
 698 		bool intersects_before = old_active & mask;
 699 
 700 		if (intersects && !intersects_before) {
 701 			wl_signal_emit_mutable(&scene_buffer->events.output_enter, scene_output);
 702 		} else if (!intersects && intersects_before) {
 703 			wl_signal_emit_mutable(&scene_buffer->events.output_leave, scene_output);
 704 		}
 705 	}
 706 
 707 	// if there are active outputs on this node, we should always have a primary
 708 	// output
 709 	assert(!scene_buffer->active_outputs || scene_buffer->primary_output);
 710 
 711 	// Skip output update event if nothing was updated
 712 	if (old_active == active_outputs &&
 713 			(!force || ((1ull << force->index) & ~active_outputs)) &&
 714 			old_primary_output == scene_buffer->primary_output) {
 715 		return;
 716 	}
 717 
 718 	struct wlr_scene_output *outputs_array[64];
 719 	struct wlr_scene_outputs_update_event event = {
 720 		.active = outputs_array,
 721 		.size = count,
 722 	};
 723 
 724 	size_t i = 0;
 725 	wl_list_for_each(scene_output, outputs, link) {
 726 		if (~active_outputs & (1ull << scene_output->index)) {
 727 			continue;
 728 		}
 729 
 730 		assert(i < count);
 731 		outputs_array[i++] = scene_output;
 732 	}
 733 
 734 	wl_signal_emit_mutable(&scene_buffer->events.outputs_update, &event);
 735 }
 736 
 737 #if WLR_HAS_XWAYLAND
 738 static struct wlr_xwayland_surface *scene_node_try_get_managed_xwayland_surface(
 739 		struct wlr_scene_node *node) {
 740 	if (node->type != WLR_SCENE_NODE_BUFFER) {
 741 		return NULL;
 742 	}
 743 
 744 	struct wlr_scene_buffer *buffer_node = wlr_scene_buffer_from_node(node);
 745 	struct wlr_scene_surface *surface_node = wlr_scene_surface_try_from_buffer(buffer_node);
 746 	if (!surface_node) {
 747 		return NULL;
 748 	}
 749 
 750 	struct wlr_xwayland_surface *xwayland_surface =
 751 		wlr_xwayland_surface_try_from_wlr_surface(surface_node->surface);
 752 	if (!xwayland_surface || xwayland_surface->override_redirect) {
 753 		return NULL;
 754 	}
 755 
 756 	return xwayland_surface;
 757 }
 758 
 759 static void restack_xwayland_surface(struct wlr_scene_node *node,
 760 		struct wlr_box *box, struct scene_update_data *data) {
 761 	struct wlr_xwayland_surface *xwayland_surface =
 762 		scene_node_try_get_managed_xwayland_surface(node);
 763 	if (!xwayland_surface) {
 764 		return;
 765 	}
 766 
 767 	// ensure this node is entirely inside the update region. If not, we can't
 768 	// restack this node since we're not considering the whole thing.
 769 	if (wlr_box_contains_box(&data->update_box, box)) {
 770 		if (data->restack_above) {
 771 			wlr_xwayland_surface_restack(xwayland_surface, data->restack_above, XCB_STACK_MODE_BELOW);
 772 		} else {
 773 			wlr_xwayland_surface_restack(xwayland_surface, NULL, XCB_STACK_MODE_ABOVE);
 774 		}
 775 	}
 776 
 777 	data->restack_above = xwayland_surface;
 778 }
 779 #endif
 780 
 781 static bool cce_scene_blur_debug(void) {
 782 	static int enabled = -1;
 783 	if (enabled < 0) {
 784 		const char *v = getenv("CCE_BLUR_DEBUG");
 785 		enabled = v && *v && strcmp(v, "0") != 0;
 786 	}
 787 	return enabled;
 788 }
 789 
 790 static bool scene_node_is_below(struct wlr_scene_node *a, struct wlr_scene_node *b) {
 791 	if (a == b) {
 792 		return false;
 793 	}
 794 
 795 	struct wlr_scene_node *chain_a[64];
 796 	struct wlr_scene_node *chain_b[64];
 797 	int len_a = 0;
 798 	int len_b = 0;
 799 
 800 	struct wlr_scene_node *curr = a;
 801 	while (curr && len_a < 64) {
 802 		chain_a[len_a++] = curr;
 803 		curr = curr->parent ? &curr->parent->node : NULL;
 804 	}
 805 
 806 	curr = b;
 807 	while (curr && len_b < 64) {
 808 		chain_b[len_b++] = curr;
 809 		curr = curr->parent ? &curr->parent->node : NULL;
 810 	}
 811 
 812 	int idx_a = len_a - 1;
 813 	int idx_b = len_b - 1;
 814 
 815 	if (chain_a[idx_a] != chain_b[idx_b]) {
 816 		return false;
 817 	}
 818 
 819 	while (idx_a >= 0 && idx_b >= 0 && chain_a[idx_a] == chain_b[idx_b]) {
 820 		idx_a--;
 821 		idx_b--;
 822 	}
 823 
 824 	if (idx_a < 0) {
 825 		return true;
 826 	}
 827 	if (idx_b < 0) {
 828 		return false;
 829 	}
 830 
 831 	struct wlr_scene_tree *lca = wlr_scene_tree_from_node(chain_a[idx_a + 1]);
 832 	struct wlr_scene_node *child;
 833 	wl_list_for_each(child, &lca->children, link) {
 834 		if (child == chain_a[idx_a]) {
 835 			return true;
 836 		}
 837 		if (child == chain_b[idx_b]) {
 838 			return false;
 839 		}
 840 	}
 841 
 842 	return false;
 843 }
 844 
 845 static bool scene_node_update_iterator(struct wlr_scene_node *node,
 846 		int lx, int ly, void *_data) {
 847 	struct scene_update_data *data = _data;
 848 
 849 	if (node->type == WLR_SCENE_NODE_OPTIMIZED_BLUR) {
 850 		struct wlr_scene_optimized_blur *scene_blur = wlr_scene_optimized_blur_from_node(node);
 851 		// A frozen scene ignores nodes MOVING below (the backdrop travelling
 852 		// with a pan); content changing below still re-bakes.
 853 		if (data->updated_node && (!data->blur_frozen || data->content_update) &&
 854 				scene_node_is_below(data->updated_node, node)) {
 855 			if (data->blur_frozen && cce_scene_blur_debug()) {
 856 				wlr_log(WLR_INFO, "[scenefx] frozen: content dirty from node type %d (%dx%d) below opt %dx%d",
 857 					data->updated_node->type, data->update_box.width, data->update_box.height,
 858 					scene_blur->width, scene_blur->height);
 859 			}
 860 			scene_blur->dirty = true;
 861 		}
 862 		if (scene_blur->dirty) {
 863 			// Restore the visible region back to default, without any opaque
 864 			// regions. This ensures that all nodes below are fully re-rendered
 865 			// and not culled by above nodes.
 866 			pixman_region32_clear(data->visible);
 867 			pixman_region32_copy(data->visible, data->update_region);
 868 		}
 869 	}
 870 
 871 	struct wlr_box box = { .x = lx, .y = ly };
 872 	scene_node_get_size(node, &box.width, &box.height);
 873 
 874 	pixman_region32_subtract(&node->visible, &node->visible, data->update_region);
 875 	pixman_region32_union(&node->visible, &node->visible, data->visible);
 876 	pixman_region32_intersect_rect(&node->visible, &node->visible,
 877 		lx, ly, box.width, box.height);
 878 
 879 	if (data->calculate_visibility) {
 880 		pixman_region32_t opaque;
 881 		pixman_region32_init(&opaque);
 882 		scene_node_opaque_region(node, lx, ly, &opaque);
 883 		pixman_region32_subtract(data->visible, data->visible, &opaque);
 884 		pixman_region32_fini(&opaque);
 885 	}
 886 
 887 	update_node_update_outputs(node, data->outputs, NULL, NULL);
 888 #if WLR_HAS_XWAYLAND
 889 	if (data->restack_xwayland_surfaces) {
 890 		restack_xwayland_surface(node, &box, data);
 891 	}
 892 #endif
 893 
 894 	return false;
 895 }
 896 
 897 static void scene_node_visibility(struct wlr_scene_node *node,
 898 		pixman_region32_t *visible) {
 899 	if (!node->enabled) {
 900 		return;
 901 	}
 902 
 903 	if (node->type == WLR_SCENE_NODE_TREE) {
 904 		struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
 905 		struct wlr_scene_node *child;
 906 		wl_list_for_each(child, &scene_tree->children, link) {
 907 			scene_node_visibility(child, visible);
 908 		}
 909 		return;
 910 	}
 911 
 912 	pixman_region32_union(visible, visible, &node->visible);
 913 }
 914 
 915 static void scene_node_bounds(struct wlr_scene_node *node,
 916 		int x, int y, pixman_region32_t *visible) {
 917 	if (!node->enabled) {
 918 		return;
 919 	}
 920 
 921 	if (node->type == WLR_SCENE_NODE_TREE) {
 922 		struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
 923 		struct wlr_scene_node *child;
 924 		wl_list_for_each(child, &scene_tree->children, link) {
 925 			scene_node_bounds(child, x + child->x, y + child->y, visible);
 926 		}
 927 		return;
 928 	}
 929 
 930 	int width, height;
 931 	scene_node_get_size(node, &width, &height);
 932 	pixman_region32_union_rect(visible, visible, x, y, width, height);
 933 }
 934 
 935 static void scene_update_region(struct wlr_scene *scene,
 936 		struct wlr_scene_node *updated_node,
 937 		const pixman_region32_t *update_region, bool content_update) {
 938 	pixman_region32_t visible;
 939 	pixman_region32_init(&visible);
 940 	pixman_region32_copy(&visible, update_region);
 941 
 942 	struct pixman_box32 *region_box = pixman_region32_extents(update_region);
 943 	struct scene_update_data data = {
 944 		.updated_node = updated_node,
 945 		.visible = &visible,
 946 		.update_region = update_region,
 947 		.update_box = {
 948 			.x = region_box->x1,
 949 			.y = region_box->y1,
 950 			.width = region_box->x2 - region_box->x1,
 951 			.height = region_box->y2 - region_box->y1,
 952 		},
 953 		.outputs = &scene->outputs,
 954 		.calculate_visibility = scene->calculate_visibility,
 955 		.restack_xwayland_surfaces = scene->restack_xwayland_surfaces,
 956 		.blur_frozen = scene->blur_frozen,
 957 		.content_update = content_update,
 958 	};
 959 
 960 	// update node visibility and output enter/leave events
 961 	scene_nodes_in_box(&scene->tree.node, &data.update_box, scene_node_update_iterator, &data);
 962 
 963 	pixman_region32_fini(&visible);
 964 }
 965 
 966 static void scene_node_cleanup_when_disabled(struct wlr_scene_node *node,
 967 		bool xwayland_restack, struct wl_list *outputs) {
 968 	if (node->type == WLR_SCENE_NODE_TREE) {
 969 		struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
 970 		struct wlr_scene_node *child;
 971 		wl_list_for_each(child, &scene_tree->children, link) {
 972 			if (!child->enabled) {
 973 				continue;
 974 			}
 975 
 976 			scene_node_cleanup_when_disabled(child, xwayland_restack, outputs);
 977 		}
 978 		return;
 979 	}
 980 
 981 	pixman_region32_clear(&node->visible);
 982 	update_node_update_outputs(node, outputs, NULL, NULL);
 983 
 984 #if WLR_HAS_XWAYLAND
 985 	if (xwayland_restack) {
 986 		struct wlr_xwayland_surface *xwayland_surface =
 987 			scene_node_try_get_managed_xwayland_surface(node);
 988 		if (!xwayland_surface) {
 989 			return;
 990 		}
 991 
 992 		wlr_xwayland_surface_restack(xwayland_surface, NULL, XCB_STACK_MODE_BELOW);
 993 	}
 994 #endif
 995 }
 996 
 997 /**
 998  * Updates the nodes visibility, xwayland restacking, send leave/enter events
 999  * and damages the screen. The damage region is used to not only damage the
1000  * screen, but to direct the update logic to only update certain parts of the
1001  * screen and not the whole thing. If a NULL damage is given, the damage is
1002  * assumed to be the previous nodes visibility.
1003  *
1004  * Currently, the only usage for an explicit damage is for update scenarios where
1005  * the scene node might be enabled/disabled. If the scene node is disabled, the
1006  * update logic will ignore the node. This is normally desirable as most update
1007  * scenarios like updating the color or whatever. However, it's not what we want
1008  * when disabling the node. Note that reparenting the node could lead to the node
1009  * being reparented to a disabled super tree.
1010  */
1011 static void scene_node_update(struct wlr_scene_node *node,
1012 		pixman_region32_t *damage) {
1013 	struct wlr_scene *scene = scene_node_get_root(node);
1014 	// Explicit damage means the node's CONTENT changed (a buffer commit, a
1015 	// disable); NULL means a property or position change.
1016 	bool content_update = damage != NULL;
1017 
1018 	int x, y;
1019 	if (!wlr_scene_node_coords(node, &x, &y)) {
1020 		// We assume explicit damage on a disabled tree means the node was just
1021 		// disabled.
1022 		if (damage) {
1023 			scene_node_cleanup_when_disabled(node, scene->restack_xwayland_surfaces, &scene->outputs);
1024 
1025 			scene_update_region(scene, node, damage, content_update);
1026 			scene_damage_outputs(scene, damage);
1027 			pixman_region32_fini(damage);
1028 		}
1029 
1030 		return;
1031 	}
1032 
1033 	pixman_region32_t visible;
1034 	if (!damage) {
1035 		pixman_region32_init(&visible);
1036 		scene_node_visibility(node, &visible);
1037 		damage = &visible;
1038 	}
1039 
1040 	pixman_region32_t update_region;
1041 	pixman_region32_init(&update_region);
1042 	pixman_region32_copy(&update_region, damage);
1043 	scene_node_bounds(node, x, y, &update_region);
1044 
1045 	scene_update_region(scene, node, &update_region, content_update);
1046 	pixman_region32_fini(&update_region);
1047 
1048 	scene_node_visibility(node, damage);
1049 	scene_damage_outputs(scene, damage);
1050 	pixman_region32_fini(damage);
1051 }
1052 
1053 struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent,
1054 		int width, int height, const float color[static 4]) {
1055 	assert(parent);
1056 	assert(width >= 0 && height >= 0);
1057 
1058 	struct wlr_scene_rect *scene_rect = calloc(1, sizeof(*scene_rect));
1059 	if (scene_rect == NULL) {
1060 		return NULL;
1061 	}
1062 	scene_node_init(&scene_rect->node, WLR_SCENE_NODE_RECT, parent);
1063 
1064 	scene_rect->width = width;
1065 	scene_rect->height = height;
1066 	memcpy(scene_rect->color, color, sizeof(scene_rect->color));
1067 	scene_rect->corners = (struct fx_corner_radii){0};
1068 	scene_rect->accepts_input = true;
1069 	scene_rect->clipped_region = clipped_region_get_default();
1070 
1071 	scene_node_update(&scene_rect->node, NULL);
1072 
1073 	return scene_rect;
1074 }
1075 
1076 void wlr_scene_rect_set_size(struct wlr_scene_rect *rect, int width, int height) {
1077 	if (rect->width == width && rect->height == height) {
1078 		return;
1079 	}
1080 
1081 	assert(width >= 0 && height >= 0);
1082 
1083 	scene_node_update(&rect->node, NULL);
1084 	rect->width = width;
1085 	rect->height = height;
1086 	scene_node_update(&rect->node, NULL);
1087 }
1088 
1089 void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[static 4]) {
1090 	if (memcmp(rect->color, color, sizeof(rect->color)) == 0) {
1091 		return;
1092 	}
1093 
1094 	memcpy(rect->color, color, sizeof(rect->color));
1095 	scene_node_update(&rect->node, NULL);
1096 }
1097 
1098 void wlr_scene_rect_set_fade_inset(struct wlr_scene_rect *rect, int fade_inset) {
1099 	if (rect->fade_inset == fade_inset) {
1100 		return;
1101 	}
1102 
1103 	rect->fade_inset = fade_inset;
1104 	scene_node_update(&rect->node, NULL);
1105 }
1106 
1107 static void scene_buffer_handle_buffer_release(struct wl_listener *listener,
1108 		void *data) {
1109 	struct wlr_scene_buffer *scene_buffer =
1110 		wl_container_of(listener, scene_buffer, buffer_release);
1111 
1112 	scene_buffer->buffer = NULL;
1113 	wl_list_remove(&scene_buffer->buffer_release.link);
1114 	wl_list_init(&scene_buffer->buffer_release.link);
1115 }
1116 
1117 static void scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer,
1118 		struct wlr_buffer *buffer) {
1119 	wl_list_remove(&scene_buffer->buffer_release.link);
1120 	wl_list_init(&scene_buffer->buffer_release.link);
1121 	if (scene_buffer->own_buffer) {
1122 		wlr_buffer_unlock(scene_buffer->buffer);
1123 	}
1124 	scene_buffer->buffer = NULL;
1125 	scene_buffer->own_buffer = false;
1126 	scene_buffer->buffer_width = scene_buffer->buffer_height = 0;
1127 	scene_buffer->buffer_is_opaque = false;
1128 
1129 	if (!buffer) {
1130 		return;
1131 	}
1132 
1133 	scene_buffer->own_buffer = true;
1134 	scene_buffer->buffer = wlr_buffer_lock(buffer);
1135 	scene_buffer->buffer_width = buffer->width;
1136 	scene_buffer->buffer_height = buffer->height;
1137 	scene_buffer->buffer_is_opaque = wlr_buffer_is_opaque(buffer);
1138 
1139 	scene_buffer->buffer_release.notify = scene_buffer_handle_buffer_release;
1140 	wl_signal_add(&buffer->events.release, &scene_buffer->buffer_release);
1141 }
1142 
1143 static void scene_buffer_handle_renderer_destroy(struct wl_listener *listener,
1144 		void *data) {
1145 	struct wlr_scene_buffer *scene_buffer = wl_container_of(listener, scene_buffer, renderer_destroy);
1146 	scene_buffer_set_texture(scene_buffer, NULL);
1147 }
1148 
1149 static void scene_buffer_set_texture(struct wlr_scene_buffer *scene_buffer,
1150 		struct wlr_texture *texture) {
1151 	wl_list_remove(&scene_buffer->renderer_destroy.link);
1152 	wlr_texture_destroy(scene_buffer->texture);
1153 	scene_buffer->texture = texture;
1154 
1155 	if (texture != NULL) {
1156 		scene_buffer->renderer_destroy.notify = scene_buffer_handle_renderer_destroy;
1157 		wl_signal_add(&texture->renderer->events.destroy, &scene_buffer->renderer_destroy);
1158 	} else {
1159 		wl_list_init(&scene_buffer->renderer_destroy.link);
1160 	}
1161 }
1162 
1163 static void scene_buffer_set_wait_timeline(struct wlr_scene_buffer *scene_buffer,
1164 		struct wlr_drm_syncobj_timeline *timeline, uint64_t point) {
1165 	wlr_drm_syncobj_timeline_unref(scene_buffer->wait_timeline);
1166 	if (timeline != NULL) {
1167 		scene_buffer->wait_timeline = wlr_drm_syncobj_timeline_ref(timeline);
1168 		scene_buffer->wait_point = point;
1169 	} else {
1170 		scene_buffer->wait_timeline = NULL;
1171 		scene_buffer->wait_point = 0;
1172 	}
1173 }
1174 
1175 inline void wlr_scene_rect_set_corner_radius(struct wlr_scene_rect *rect, int corner_radius) {
1176 	wlr_scene_rect_set_corner_radii(rect, corner_radii_all(corner_radius));
1177 }
1178 
1179 void wlr_scene_rect_set_corner_radii(struct wlr_scene_rect *rect, struct fx_corner_radii corners) {
1180 	if (fx_corner_radii_eq(rect->corners, corners)) {
1181 		return;
1182 	}
1183 
1184 	rect->corners = corners;
1185 	scene_node_update(&rect->node, NULL);
1186 }
1187 
1188 void wlr_scene_rect_set_clipped_region(struct wlr_scene_rect *rect,
1189 		struct clipped_region clipped_region) {
1190 	if (fx_corner_radii_eq(rect->clipped_region.corners, clipped_region.corners) &&
1191 			wlr_box_equal(&rect->clipped_region.area, &clipped_region.area)) {
1192 		return;
1193 	}
1194 
1195 	rect->clipped_region = clipped_region;
1196 	scene_node_update(&rect->node, NULL);
1197 }
1198 
1199 struct wlr_scene_shadow *wlr_scene_shadow_create(struct wlr_scene_tree *parent,
1200 		int width, int height, int corner_radius, float blur_sigma,
1201 		const float color [static 4]) {
1202 	struct wlr_scene_shadow *scene_shadow = calloc(1, sizeof(*scene_shadow));
1203 	if (scene_shadow == NULL) {
1204 		return NULL;
1205 	}
1206 	assert(parent);
1207 	scene_node_init(&scene_shadow->node, WLR_SCENE_NODE_SHADOW, parent);
1208 
1209 	scene_shadow->width = width;
1210 	scene_shadow->height = height;
1211 	scene_shadow->corner_radius = corner_radius;
1212 	scene_shadow->blur_sigma = blur_sigma;
1213 	memcpy(scene_shadow->color, color, sizeof(scene_shadow->color));
1214 	scene_shadow->clipped_region = clipped_region_get_default();
1215 
1216 	scene_node_update(&scene_shadow->node, NULL);
1217 
1218 	return scene_shadow;
1219 }
1220 
1221 struct wlr_scene_frame *wlr_scene_frame_create(struct wlr_scene_tree *parent,
1222 		int width, int height, int corner_radius, const float color[static 4]) {
1223 	struct wlr_scene_frame *scene_frame = calloc(1, sizeof(*scene_frame));
1224 	if (scene_frame == NULL) {
1225 		return NULL;
1226 	}
1227 	scene_node_init(&scene_frame->node, WLR_SCENE_NODE_FRAME, parent);
1228 
1229 	scene_frame->width = width;
1230 	scene_frame->height = height;
1231 	scene_frame->corner_radius = corner_radius;
1232 	// Shape defaults to a plain even ring; the compositor sets the real
1233 	// profile every frame through wlr_scene_frame_set_shape.
1234 	scene_frame->band = 0.0f;
1235 	scene_frame->band_min = 0.0f;
1236 	scene_frame->corner_len = 0.0f;
1237 	scene_frame->gap = 0.0f;
1238 	scene_frame->hovered = -1.0f;
1239 	scene_frame->swell_curve = 1.0f;
1240 	scene_frame->bulge = 0.0f;
1241 	scene_frame->buttons = 0.0f;
1242 	memcpy(scene_frame->color, color, sizeof(scene_frame->color));
1243 	memcpy(scene_frame->hover_color, color, sizeof(scene_frame->hover_color));
1244 
1245 	scene_node_update(&scene_frame->node, NULL);
1246 
1247 	return scene_frame;
1248 }
1249 
1250 void wlr_scene_frame_set_size(struct wlr_scene_frame *frame, int width, int height) {
1251 	if (frame->width == width && frame->height == height) {
1252 		return;
1253 	}
1254 	frame->width = width;
1255 	frame->height = height;
1256 	scene_node_update(&frame->node, NULL);
1257 }
1258 
1259 void wlr_scene_frame_set_corner_radius(struct wlr_scene_frame *frame, int radius) {
1260 	if (frame->corner_radius == radius) {
1261 		return;
1262 	}
1263 	frame->corner_radius = radius;
1264 	scene_node_update(&frame->node, NULL);
1265 }
1266 
1267 void wlr_scene_frame_set_shape(struct wlr_scene_frame *frame, float band,
1268 		float band_min, float corner_len, float gap, float swell_curve, float bulge) {
1269 	if (frame->band == band && frame->band_min == band_min
1270 			&& frame->corner_len == corner_len && frame->gap == gap
1271 			&& frame->swell_curve == swell_curve && frame->bulge == bulge) {
1272 		return;
1273 	}
1274 	frame->swell_curve = swell_curve;
1275 	frame->bulge = bulge;
1276 	frame->band = band;
1277 	frame->band_min = band_min;
1278 	frame->corner_len = corner_len;
1279 	frame->gap = gap;
1280 	scene_node_update(&frame->node, NULL);
1281 }
1282 
1283 void wlr_scene_frame_set_exclusion(struct wlr_scene_frame *frame,
1284 		const float rect[static 4]) {
1285 	if (memcmp(frame->exclusion, rect, sizeof(frame->exclusion)) == 0) {
1286 		return;
1287 	}
1288 	memcpy(frame->exclusion, rect, sizeof(frame->exclusion));
1289 	scene_node_update(&frame->node, NULL);
1290 }
1291 
1292 void wlr_scene_frame_set_buttons(struct wlr_scene_frame *frame, float buttons) {
1293 	if (frame->buttons == buttons) {
1294 		return;
1295 	}
1296 	frame->buttons = buttons;
1297 	scene_node_update(&frame->node, NULL);
1298 }
1299 
1300 void wlr_scene_frame_set_color(struct wlr_scene_frame *frame, const float color[static 4]) {
1301 	if (memcmp(frame->color, color, sizeof(frame->color)) == 0) {
1302 		return;
1303 	}
1304 	memcpy(frame->color, color, sizeof(frame->color));
1305 	scene_node_update(&frame->node, NULL);
1306 }
1307 
1308 void wlr_scene_frame_set_hover(struct wlr_scene_frame *frame, float hovered,
1309 		const float color[static 4]) {
1310 	if (frame->hovered == hovered
1311 			&& memcmp(frame->hover_color, color, sizeof(frame->hover_color)) == 0) {
1312 		return;
1313 	}
1314 	frame->hovered = hovered;
1315 	memcpy(frame->hover_color, color, sizeof(frame->hover_color));
1316 	scene_node_update(&frame->node, NULL);
1317 }
1318 
1319 struct wlr_scene_bevel *wlr_scene_bevel_create(struct wlr_scene_tree *parent,
1320 		int width, int height, int corner_radius, float thickness,
1321 		const float color[static 4]) {
1322 	struct wlr_scene_bevel *scene_bevel = calloc(1, sizeof(*scene_bevel));
1323 	if (scene_bevel == NULL) {
1324 		return NULL;
1325 	}
1326 	assert(parent);
1327 	scene_node_init(&scene_bevel->node, WLR_SCENE_NODE_BEVEL, parent);
1328 
1329 	scene_bevel->width = width;
1330 	scene_bevel->height = height;
1331 	scene_bevel->corner_radius = corner_radius;
1332 	scene_bevel->thickness = thickness;
1333 	// Default light: top-left, matching the DE's shadow convention.
1334 	scene_bevel->light_dir[0] = -0.7071f;
1335 	scene_bevel->light_dir[1] = -0.7071f;
1336 	scene_bevel->light_intensity = 1.0f;
1337 	scene_bevel->shade_intensity = 1.0f;
1338 	scene_bevel->shoulder = 0.5f;
1339 	memcpy(scene_bevel->color, color, sizeof(scene_bevel->color));
1340 
1341 	scene_node_update(&scene_bevel->node, NULL);
1342 
1343 	return scene_bevel;
1344 }
1345 
1346 void wlr_scene_bevel_set_size(struct wlr_scene_bevel *bevel, int width, int height) {
1347 	if (bevel->width == width && bevel->height == height) {
1348 		return;
1349 	}
1350 	bevel->width = width;
1351 	bevel->height = height;
1352 	scene_node_update(&bevel->node, NULL);
1353 }
1354 
1355 void wlr_scene_bevel_set_corner_radius(struct wlr_scene_bevel *bevel, int radius) {
1356 	if (bevel->corner_radius == radius) {
1357 		return;
1358 	}
1359 	bevel->corner_radius = radius;
1360 	scene_node_update(&bevel->node, NULL);
1361 }
1362 
1363 void wlr_scene_bevel_set_thickness(struct wlr_scene_bevel *bevel, float thickness) {
1364 	if (bevel->thickness == thickness) {
1365 		return;
1366 	}
1367 	bevel->thickness = thickness;
1368 	scene_node_update(&bevel->node, NULL);
1369 }
1370 
1371 void wlr_scene_bevel_set_light(struct wlr_scene_bevel *bevel, float dir_x, float dir_y,
1372 		float light_intensity, float shade_intensity) {
1373 	if (bevel->light_dir[0] == dir_x && bevel->light_dir[1] == dir_y
1374 			&& bevel->light_intensity == light_intensity
1375 			&& bevel->shade_intensity == shade_intensity) {
1376 		return;
1377 	}
1378 	bevel->light_dir[0] = dir_x;
1379 	bevel->light_dir[1] = dir_y;
1380 	bevel->light_intensity = light_intensity;
1381 	bevel->shade_intensity = shade_intensity;
1382 	scene_node_update(&bevel->node, NULL);
1383 }
1384 
1385 void wlr_scene_bevel_set_shoulder(struct wlr_scene_bevel *bevel, float shoulder) {
1386 	if (bevel->shoulder == shoulder) {
1387 		return;
1388 	}
1389 	bevel->shoulder = shoulder;
1390 	scene_node_update(&bevel->node, NULL);
1391 }
1392 
1393 struct wlr_scene_droplet *wlr_scene_droplet_create(struct wlr_scene_tree *parent,
1394 		int width, int height) {
1395 	struct wlr_scene_droplet *droplet = calloc(1, sizeof(*droplet));
1396 	if (droplet == NULL) {
1397 		return NULL;
1398 	}
1399 	assert(parent);
1400 	scene_node_init(&droplet->node, WLR_SCENE_NODE_DROPLET, parent);
1401 
1402 	droplet->width = width;
1403 	droplet->height = height;
1404 	droplet->curve = 2.0f;
1405 
1406 	scene_node_update(&droplet->node, NULL);
1407 
1408 	return droplet;
1409 }
1410 
1411 void wlr_scene_droplet_set_size(struct wlr_scene_droplet *droplet, int width, int height) {
1412 	if (droplet->width == width && droplet->height == height) {
1413 		return;
1414 	}
1415 	droplet->width = width;
1416 	droplet->height = height;
1417 	scene_node_update(&droplet->node, NULL);
1418 }
1419 
1420 void wlr_scene_droplet_set_silhouette(struct wlr_scene_droplet *droplet,
1421 		float attach_r, float sheet_r, float bow_rise, float blend_k, float curve) {
1422 	if (droplet->attach_r == attach_r && droplet->sheet_r == sheet_r
1423 			&& droplet->bow_rise == bow_rise && droplet->blend_k == blend_k
1424 			&& droplet->curve == curve) {
1425 		return;
1426 	}
1427 	droplet->attach_r = attach_r;
1428 	droplet->sheet_r = sheet_r;
1429 	droplet->bow_rise = bow_rise;
1430 	droplet->blend_k = blend_k;
1431 	droplet->curve = curve;
1432 	scene_node_update(&droplet->node, NULL);
1433 }
1434 
1435 void wlr_scene_droplet_set_lens(struct wlr_scene_droplet *droplet,
1436 		float band_px, float refr, float ghost) {
1437 	if (droplet->band_px == band_px && droplet->refr == refr
1438 			&& droplet->ghost == ghost) {
1439 		return;
1440 	}
1441 	droplet->band_px = band_px;
1442 	droplet->refr = refr;
1443 	droplet->ghost = ghost;
1444 	scene_node_update(&droplet->node, NULL);
1445 }
1446 
1447 void wlr_scene_droplet_set_compress(struct wlr_scene_droplet *droplet,
1448 		float ceil, float knee, bool invert) {
1449 	if (droplet->compress_ceil == ceil && droplet->compress_knee == knee
1450 			&& droplet->compress_invert == invert) {
1451 		return;
1452 	}
1453 	droplet->compress_ceil = ceil;
1454 	droplet->compress_knee = knee;
1455 	droplet->compress_invert = invert;
1456 	scene_node_update(&droplet->node, NULL);
1457 }
1458 
1459 void wlr_scene_bevel_set_color(struct wlr_scene_bevel *bevel, const float color[static 4]) {
1460 	if (memcmp(bevel->color, color, sizeof(bevel->color)) == 0) {
1461 		return;
1462 	}
1463 	memcpy(bevel->color, color, sizeof(bevel->color));
1464 	scene_node_update(&bevel->node, NULL);
1465 }
1466 
1467 void wlr_scene_bevel_set_focus(struct wlr_scene_bevel *bevel, float focus, float sharpness,
1468 		const float color[static 3]) {
1469 	if (bevel->focus == focus && bevel->focus_sharpness == sharpness &&
1470 			memcmp(bevel->focus_color, color, sizeof(bevel->focus_color)) == 0) {
1471 		return;
1472 	}
1473 	bevel->focus = focus;
1474 	bevel->focus_sharpness = sharpness;
1475 	memcpy(bevel->focus_color, color, sizeof(bevel->focus_color));
1476 	scene_node_update(&bevel->node, NULL);
1477 }
1478 
1479 void wlr_scene_shadow_set_size(struct wlr_scene_shadow *shadow, int width, int height) {
1480 	if (shadow->width == width && shadow->height == height) {
1481 		return;
1482 	}
1483 
1484 	shadow->width = width;
1485 	shadow->height = height;
1486 	scene_node_update(&shadow->node, NULL);
1487 }
1488 
1489 void wlr_scene_shadow_set_corner_radius(struct wlr_scene_shadow *shadow, int corner_radius) {
1490 	if (shadow->corner_radius == corner_radius) {
1491 		return;
1492 	}
1493 
1494 	shadow->corner_radius = corner_radius;
1495 	scene_node_update(&shadow->node, NULL);
1496 }
1497 
1498 void wlr_scene_shadow_set_blur_sigma(struct wlr_scene_shadow *shadow, float blur_sigma) {
1499 	if (shadow->blur_sigma == blur_sigma) {
1500 		return;
1501 	}
1502 
1503 	shadow->blur_sigma = blur_sigma;
1504 	scene_node_update(&shadow->node, NULL);
1505 }
1506 
1507 void wlr_scene_shadow_set_color(struct wlr_scene_shadow *shadow, const float color[static 4]) {
1508 	if (memcmp(shadow->color, color, sizeof(shadow->color)) == 0) {
1509 		return;
1510 	}
1511 
1512 	memcpy(shadow->color, color, sizeof(shadow->color));
1513 	scene_node_update(&shadow->node, NULL);
1514 }
1515 
1516 void wlr_scene_shadow_set_clipped_region(struct wlr_scene_shadow *shadow,
1517 		struct clipped_region clipped_region) {
1518 	if (fx_corner_radii_eq(shadow->clipped_region.corners, clipped_region.corners) &&
1519 			wlr_box_equal(&shadow->clipped_region.area, &clipped_region.area)) {
1520 		return;
1521 	}
1522 
1523 	shadow->clipped_region = clipped_region;
1524 	scene_node_update(&shadow->node, NULL);
1525 }
1526 
1527 static void mark_all_optimized_blur_nodes_dirty(struct wlr_scene_node *node) {
1528 	if (node->type == WLR_SCENE_NODE_OPTIMIZED_BLUR) {
1529 		struct wlr_scene_optimized_blur *scene_blur = wlr_scene_optimized_blur_from_node(node);
1530 		wlr_scene_optimized_blur_mark_dirty(scene_blur);
1531 	} else if (node->type == WLR_SCENE_NODE_TREE) {
1532 		struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
1533 		struct wlr_scene_node *child;
1534 		wl_list_for_each(child, &scene_tree->children, link) {
1535 			mark_all_optimized_blur_nodes_dirty(child);
1536 		}
1537 	}
1538 }
1539 
1540 struct wlr_scene_blur *wlr_scene_blur_create(struct wlr_scene_tree *parent,
1541 	   int width, int height) {
1542 	struct wlr_scene_blur *blur = calloc(1, sizeof(*blur));
1543 	if (blur == NULL) {
1544 		return NULL;
1545 	}
1546 	assert(parent);
1547 	scene_node_init(&blur->node, WLR_SCENE_NODE_BLUR, parent);
1548 
1549 	blur->alpha = 1.0f;
1550 	blur->strength = 1.0f;
1551 	blur->clipped_region = (struct clipped_region){0};
1552 	blur->corners = corner_radii_all(0);
1553 	blur->should_only_blur_bottom_layer = false;
1554 	blur->transparency_mask_source = linked_node_init();
1555 	blur->width = width;
1556 	blur->height = height;
1557 
1558 	scene_node_update(&blur->node, NULL);
1559 
1560 	return blur;
1561 }
1562 
1563 void wlr_scene_blur_set_size(struct wlr_scene_blur *blur, int width, int height) {
1564 	if (blur->width == width && blur->height == height) {
1565 		return;
1566 	}
1567 
1568 	blur->width = width;
1569 	blur->height = height;
1570 
1571 	scene_node_update(&blur->node, NULL);
1572 }
1573 
1574 inline void wlr_scene_blur_set_corner_radius(struct wlr_scene_blur *blur, int corner_radius) {
1575 	wlr_scene_blur_set_corner_radii(blur, corner_radii_all(corner_radius));
1576 }
1577 
1578 void wlr_scene_blur_set_corner_radii(struct wlr_scene_blur *blur, struct fx_corner_radii corners) {
1579 	if (fx_corner_radii_eq(blur->corners, corners)) {
1580 		return;
1581 	}
1582 
1583 	blur->corners = corners;
1584 	scene_node_update(&blur->node, NULL);
1585 }
1586 
1587 void wlr_scene_blur_set_should_only_blur_bottom_layer(struct wlr_scene_blur *blur,
1588 	bool should_only_blur_bottom_layer) {
1589 	if (blur->should_only_blur_bottom_layer == should_only_blur_bottom_layer) {
1590 		return;
1591 	}
1592 
1593 	blur->should_only_blur_bottom_layer = should_only_blur_bottom_layer;
1594 	scene_node_update(&blur->node, NULL);
1595 }
1596 
1597 void wlr_scene_blur_set_transparency_mask_source(struct wlr_scene_blur *blur,
1598        struct wlr_scene_buffer *source) {
1599 	if (source == NULL && blur->transparency_mask_source.link == NULL) {
1600 		return;
1601 	}
1602 
1603 	if (source != NULL && linked_nodes_are_linked(&blur->transparency_mask_source, &source->blur)) {
1604 		return;
1605 	}
1606 
1607 	linked_node_destroy(&blur->transparency_mask_source);
1608 
1609 	if (source != NULL) {
1610 		linked_node_destroy(&source->blur);
1611 		linked_node_init_link(&blur->transparency_mask_source, &source->blur);
1612 	}
1613 
1614 	scene_node_update(&blur->node, NULL);
1615 }
1616 
1617 struct wlr_scene_buffer *wlr_scene_blur_get_transparency_mask_source(
1618 	struct wlr_scene_blur *blur) {
1619 	struct linked_node *node = linked_nodes_get_sibling(&blur->transparency_mask_source);
1620 	if (node == NULL) {
1621 		return NULL;
1622 	}
1623 
1624 	struct wlr_scene_buffer *output = wl_container_of(node, output, blur);
1625 	return output;
1626 }
1627 
1628 void wlr_scene_blur_set_alpha(struct wlr_scene_blur *blur, float alpha) {
1629 	if (blur->alpha == alpha) {
1630 		return;
1631 	}
1632 
1633 	blur->alpha = alpha;
1634 	scene_node_update(&blur->node, NULL);
1635 }
1636 
1637 void wlr_scene_blur_set_strength(struct wlr_scene_blur *blur, float strength) {
1638 	if (blur->strength == strength) {
1639 		return;
1640 	}
1641 
1642 	blur->strength = strength;
1643 	scene_node_update(&blur->node, NULL);
1644 }
1645 
1646 void wlr_scene_blur_set_compress(struct wlr_scene_blur *blur,
1647 		float ceil, float knee, bool invert) {
1648 	if (blur->compress_ceil == ceil && blur->compress_knee == knee
1649 			&& blur->compress_invert == invert) {
1650 		return;
1651 	}
1652 	blur->compress_ceil = ceil;
1653 	blur->compress_knee = knee;
1654 	blur->compress_invert = invert;
1655 	scene_node_update(&blur->node, NULL);
1656 }
1657 
1658 void wlr_scene_blur_set_clipped_region(struct wlr_scene_blur *blur,
1659 		struct clipped_region clipped_region) {
1660 	if (fx_corner_radii_eq(blur->clipped_region.corners, clipped_region.corners) &&
1661 		wlr_box_equal(&blur->clipped_region.area, &clipped_region.area)) {
1662 		return;
1663 	}
1664 
1665 	blur->clipped_region = clipped_region;
1666 	scene_node_update(&blur->node, NULL);
1667 }
1668 
1669 void wlr_scene_set_blur_data(struct wlr_scene *scene, int num_passes,
1670 		int radius, float noise, float brightness, float contrast, float saturation) {
1671 	struct blur_data *buff_data = &scene->blur_data;
1672 	if (buff_data->num_passes == num_passes
1673 			&& buff_data->radius == radius
1674 			&& buff_data->noise == noise
1675 			&& buff_data->brightness == brightness
1676 			&& buff_data->contrast == contrast
1677 			&& buff_data->saturation == saturation) {
1678 		return;
1679 	}
1680 
1681 	buff_data->num_passes = num_passes;
1682 	buff_data->radius = radius;
1683 	buff_data->noise = noise;
1684 	buff_data->brightness = brightness;
1685 	buff_data->contrast = contrast;
1686 	buff_data->saturation = saturation;
1687 
1688 	mark_all_optimized_blur_nodes_dirty(&scene->tree.node);
1689 	scene_node_update(&scene->tree.node, NULL);
1690 }
1691 
1692 void wlr_scene_set_blur_num_passes(struct wlr_scene *scene, int num_passes) {
1693 	struct blur_data *buff_data = &scene->blur_data;
1694 	if (buff_data->num_passes == num_passes) {
1695 		return;
1696 	}
1697 	buff_data->num_passes = num_passes;
1698 	mark_all_optimized_blur_nodes_dirty(&scene->tree.node);
1699 	scene_node_update(&scene->tree.node, NULL);
1700 }
1701 
1702 void wlr_scene_set_blur_radius(struct wlr_scene *scene, int radius) {
1703 	struct blur_data *buff_data = &scene->blur_data;
1704 	if (buff_data->radius == radius) {
1705 		return;
1706 	}
1707 	buff_data->radius = radius;
1708 	mark_all_optimized_blur_nodes_dirty(&scene->tree.node);
1709 	scene_node_update(&scene->tree.node, NULL);
1710 }
1711 
1712 void wlr_scene_set_blur_noise(struct wlr_scene *scene, float noise) {
1713 	struct blur_data *buff_data = &scene->blur_data;
1714 	if (buff_data->noise == noise) {
1715 		return;
1716 	}
1717 	buff_data->noise = noise;
1718 	mark_all_optimized_blur_nodes_dirty(&scene->tree.node);
1719 	scene_node_update(&scene->tree.node, NULL);
1720 }
1721 
1722 void wlr_scene_set_blur_brightness(struct wlr_scene *scene, float brightness) {
1723 	struct blur_data *buff_data = &scene->blur_data;
1724 	if (buff_data->brightness == brightness) {
1725 		return;
1726 	}
1727 	buff_data->brightness = brightness;
1728 	mark_all_optimized_blur_nodes_dirty(&scene->tree.node);
1729 	scene_node_update(&scene->tree.node, NULL);
1730 }
1731 
1732 void wlr_scene_set_blur_contrast(struct wlr_scene *scene, float contrast) {
1733 	struct blur_data *buff_data = &scene->blur_data;
1734 	if (buff_data->contrast == contrast) {
1735 		return;
1736 	}
1737 	buff_data->contrast = contrast;
1738 	mark_all_optimized_blur_nodes_dirty(&scene->tree.node);
1739 	scene_node_update(&scene->tree.node, NULL);
1740 }
1741 
1742 void wlr_scene_set_blur_saturation(struct wlr_scene *scene, float saturation) {
1743 	struct blur_data *buff_data = &scene->blur_data;
1744 	if (buff_data->saturation == saturation) {
1745 		return;
1746 	}
1747 	buff_data->saturation = saturation;
1748 	mark_all_optimized_blur_nodes_dirty(&scene->tree.node);
1749 	scene_node_update(&scene->tree.node, NULL);
1750 }
1751 
1752 struct wlr_scene_optimized_blur *wlr_scene_optimized_blur_create(
1753 		struct wlr_scene_tree *parent, int width, int height) {
1754 	struct wlr_scene_optimized_blur *scene_blur = calloc(1, sizeof(*scene_blur));
1755 	if (scene_blur == NULL) {
1756 		return NULL;
1757 	}
1758 	assert(parent);
1759 	scene_node_init(&scene_blur->node, WLR_SCENE_NODE_OPTIMIZED_BLUR, parent);
1760 
1761 	scene_blur->width = width;
1762 	scene_blur->height = height;
1763 	pixman_region32_init(&scene_blur->baked_region);
1764 	pixman_region32_init(&scene_blur->edge_region);
1765 	// Start dirty so the first render pass bakes the cache; scene_entry_render
1766 	// only re-bakes when dirty (re-baking on undamaged frames samples stale
1767 	// pass->buffer content, ghosting whatever was composited above the node).
1768 	scene_blur->dirty = true;
1769 
1770 	scene_node_update(&scene_blur->node, NULL);
1771 
1772 	return scene_blur;
1773 }
1774 
1775 void wlr_scene_optimized_blur_set_size(struct wlr_scene_optimized_blur *blur_node,
1776 		int width, int height) {
1777 	assert(blur_node);
1778 	if (blur_node->width == width && blur_node->height == height) {
1779 		return;
1780 	}
1781 
1782 	blur_node->width = width;
1783 	blur_node->height = height;
1784 
1785 	// While the scene is frozen (a camera gesture in flight, see
1786 	// wlr_scene.blur_frozen) a resize keeps its bake: the anchored render
1787 	// path bakes only the strips a grown node newly exposes, and a shrunk
1788 	// one needs nothing. Re-baking here made every frame of a zoom re-bake
1789 	// every blur, which the freeze exists to avoid; the thaw re-bakes once.
1790 	struct wlr_scene *scene = scene_node_get_root(&blur_node->node);
1791 	if (scene != NULL && scene->blur_frozen && blur_node->baked) {
1792 		scene_node_update(&blur_node->node, NULL);
1793 		return;
1794 	}
1795 
1796 	wlr_scene_optimized_blur_mark_dirty(blur_node);
1797 }
1798 
1799 void wlr_scene_optimized_blur_mark_dirty(struct wlr_scene_optimized_blur *blur_node) {
1800 	// Skip re-rendering the optimized blur if the blur node is disabled
1801 	if (blur_node && !blur_node->node.enabled) {
1802 		return;
1803 	}
1804 
1805 	blur_node->dirty = true;
1806 
1807 	scene_node_update(&blur_node->node, NULL);
1808 }
1809 
1810 struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent,
1811 		struct wlr_buffer *buffer) {
1812 	struct wlr_scene_buffer *scene_buffer = calloc(1, sizeof(*scene_buffer));
1813 	if (scene_buffer == NULL) {
1814 		return NULL;
1815 	}
1816 	assert(parent);
1817 	scene_node_init(&scene_buffer->node, WLR_SCENE_NODE_BUFFER, parent);
1818 
1819 	wl_signal_init(&scene_buffer->events.outputs_update);
1820 	wl_signal_init(&scene_buffer->events.output_enter);
1821 	wl_signal_init(&scene_buffer->events.output_leave);
1822 	wl_signal_init(&scene_buffer->events.output_sample);
1823 	wl_signal_init(&scene_buffer->events.frame_done);
1824 
1825 	pixman_region32_init(&scene_buffer->opaque_region);
1826 	wl_list_init(&scene_buffer->buffer_release.link);
1827 	wl_list_init(&scene_buffer->renderer_destroy.link);
1828 	scene_buffer->opacity = 1;
1829 
1830 	scene_buffer->corners = corner_radii_none();
1831 
1832 	scene_buffer->blur = linked_node_init();
1833 
1834 	scene_buffer_set_buffer(scene_buffer, buffer);
1835 	scene_node_update(&scene_buffer->node, NULL);
1836 
1837 	return scene_buffer;
1838 }
1839 
1840 void wlr_scene_buffer_set_buffer_with_options(struct wlr_scene_buffer *scene_buffer,
1841 		struct wlr_buffer *buffer, const struct wlr_scene_buffer_set_buffer_options *options) {
1842 	const struct wlr_scene_buffer_set_buffer_options default_options = {0};
1843 	if (options == NULL) {
1844 		options = &default_options;
1845 	}
1846 
1847 	// specifying a region for a NULL buffer doesn't make sense. We need to know
1848 	// about the buffer to scale the buffer local coordinates down to scene
1849 	// coordinates.
1850 	assert(buffer || !options->damage);
1851 
1852 	bool mapped = buffer != NULL;
1853 	bool prev_mapped = scene_buffer->buffer != NULL || scene_buffer->texture != NULL;
1854 
1855 	if (!mapped && !prev_mapped) {
1856 		// unmapping already unmapped buffer - noop
1857 		return;
1858 	}
1859 
1860 	// if this node used to not be mapped or its previous displayed
1861 	// buffer region will be different from what the new buffer would
1862 	// produce we need to update the node.
1863 	bool update = mapped != prev_mapped;
1864 	if (buffer != NULL && scene_buffer->dst_width == 0 && scene_buffer->dst_height == 0) {
1865 		update = update || scene_buffer->buffer_width != buffer->width ||
1866 			scene_buffer->buffer_height != buffer->height;
1867 	}
1868 
1869 	// If this is a buffer change, check if it's a single pixel buffer.
1870 	// Cache that so we can still apply rendering optimisations even when
1871 	// the original buffer has been freed after texture upload.
1872 	if (buffer != scene_buffer->buffer) {
1873 		scene_buffer->is_single_pixel_buffer = false;
1874 		struct wlr_client_buffer *client_buffer = NULL;
1875 		if (buffer != NULL) {
1876 			client_buffer = wlr_client_buffer_get(buffer);
1877 		}
1878 		if (client_buffer != NULL && client_buffer->source != NULL) {
1879 			struct wlr_single_pixel_buffer_v1 *single_pixel_buffer =
1880 				wlr_single_pixel_buffer_v1_try_from_buffer(client_buffer->source);
1881 			if (single_pixel_buffer != NULL) {
1882 				scene_buffer->is_single_pixel_buffer = true;
1883 				scene_buffer->single_pixel_buffer_color[0] = single_pixel_buffer->r;
1884 				scene_buffer->single_pixel_buffer_color[1] = single_pixel_buffer->g;
1885 				scene_buffer->single_pixel_buffer_color[2] = single_pixel_buffer->b;
1886 				scene_buffer->single_pixel_buffer_color[3] = single_pixel_buffer->a;
1887 			}
1888 		}
1889 	}
1890 
1891 	scene_buffer_set_buffer(scene_buffer, buffer);
1892 	scene_buffer_set_texture(scene_buffer, NULL);
1893 	scene_buffer_set_wait_timeline(scene_buffer,
1894 		options->wait_timeline, options->wait_point);
1895 
1896 	if (update) {
1897 		scene_node_update(&scene_buffer->node, NULL);
1898 		// updating the node will already damage the whole node for us. Return
1899 		// early to not damage again
1900 		return;
1901 	}
1902 
1903 	int lx, ly;
1904 	if (!wlr_scene_node_coords(&scene_buffer->node, &lx, &ly)) {
1905 		return;
1906 	}
1907 
1908 	pixman_region32_t fallback_damage;
1909 	pixman_region32_init_rect(&fallback_damage, 0, 0, buffer->width, buffer->height);
1910 	const pixman_region32_t *damage = options->damage;
1911 	if (!damage) {
1912 		damage = &fallback_damage;
1913 	}
1914 
1915 	struct wlr_fbox box = scene_buffer->src_box;
1916 	if (wlr_fbox_empty(&box)) {
1917 		box.x = 0;
1918 		box.y = 0;
1919 		box.width = buffer->width;
1920 		box.height = buffer->height;
1921 	}
1922 
1923 	wlr_fbox_transform(&box, &box, scene_buffer->transform,
1924 		buffer->width, buffer->height);
1925 
1926 	float scale_x, scale_y;
1927 	if (scene_buffer->dst_width || scene_buffer->dst_height) {
1928 		scale_x = scene_buffer->dst_width / box.width;
1929 		scale_y = scene_buffer->dst_height / box.height;
1930 	} else {
1931 		scale_x = buffer->width / box.width;
1932 		scale_y = buffer->height / box.height;
1933 	}
1934 
1935 	pixman_region32_t trans_damage;
1936 	pixman_region32_init(&trans_damage);
1937 	wlr_region_transform(&trans_damage, damage,
1938 		scene_buffer->transform, buffer->width, buffer->height);
1939 	pixman_region32_intersect_rect(&trans_damage, &trans_damage,
1940 		box.x, box.y, box.width, box.height);
1941 	pixman_region32_translate(&trans_damage, -box.x, -box.y);
1942 
1943 	struct wlr_scene *scene = scene_node_get_root(&scene_buffer->node);
1944 	struct wlr_scene_output *scene_output;
1945 	wl_list_for_each(scene_output, &scene->outputs, link) {
1946 		float output_scale = scene_output->output->scale;
1947 		float output_scale_x = output_scale * scale_x;
1948 		float output_scale_y = output_scale * scale_y;
1949 		pixman_region32_t output_damage;
1950 		pixman_region32_init(&output_damage);
1951 		wlr_region_scale_xy(&output_damage, &trans_damage,
1952 			output_scale_x, output_scale_y);
1953 
1954 		// One output pixel will match (buffer_scale_x)x(buffer_scale_y) buffer pixels.
1955 		// If the buffer is upscaled on the given axis (output_scale_* > 1.0,
1956 		// buffer_scale_* < 1.0), its contents will bleed into adjacent
1957 		// (ceil(output_scale_* / 2)) output pixels because of linear filtering.
1958 		// Additionally, if the buffer is downscaled (output_scale_* < 1.0,
1959 		// buffer_scale_* > 1.0), and one output pixel matches a non-integer number of
1960 		// buffer pixels, its contents will bleed into neighboring output pixels.
1961 		// Handle both cases by computing buffer_scale_{x,y} and checking if they are
1962 		// integer numbers; ceilf() is used to ensure that the distance is at least 1.
1963 		float buffer_scale_x = 1.0f / output_scale_x;
1964 		float buffer_scale_y = 1.0f / output_scale_y;
1965 		int dist_x = floor(buffer_scale_x) != buffer_scale_x ?
1966 			(int)ceilf(output_scale_x / 2.0f) : 0;
1967 		int dist_y = floor(buffer_scale_y) != buffer_scale_y ?
1968 			(int)ceilf(output_scale_y / 2.0f) : 0;
1969 		// TODO: expand with per-axis distances
1970 		wlr_region_expand(&output_damage, &output_damage,
1971 			dist_x >= dist_y ? dist_x : dist_y);
1972 
1973 		pixman_region32_t cull_region;
1974 		pixman_region32_init(&cull_region);
1975 		pixman_region32_copy(&cull_region, &scene_buffer->node.visible);
1976 		scale_region(&cull_region, output_scale, true);
1977 		pixman_region32_translate(&cull_region, -lx * output_scale, -ly * output_scale);
1978 		pixman_region32_intersect(&output_damage, &output_damage, &cull_region);
1979 		pixman_region32_fini(&cull_region);
1980 
1981 		pixman_region32_translate(&output_damage,
1982 			(int)round((lx - scene_output->x) * output_scale),
1983 			(int)round((ly - scene_output->y) * output_scale));
1984 		output_to_buffer_coords(&output_damage, scene_output->output);
1985 		scene_output_damage(scene_output, &output_damage);
1986 		pixman_region32_fini(&output_damage);
1987 	}
1988 
1989 	pixman_region32_fini(&trans_damage);
1990 	pixman_region32_fini(&fallback_damage);
1991 }
1992 
1993 void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buffer,
1994 		struct wlr_buffer *buffer, const pixman_region32_t *damage) {
1995 	const struct wlr_scene_buffer_set_buffer_options options = {
1996 		.damage = damage,
1997 	};
1998 	wlr_scene_buffer_set_buffer_with_options(scene_buffer, buffer, &options);
1999 }
2000 
2001 void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer,
2002 		struct wlr_buffer *buffer)  {
2003 	wlr_scene_buffer_set_buffer_with_options(scene_buffer, buffer, NULL);
2004 }
2005 
2006 void wlr_scene_buffer_set_geometry_pinned(struct wlr_scene_buffer *scene_buffer,
2007 		bool pinned) {
2008 	scene_buffer->geometry_pinned = pinned;
2009 }
2010 
2011 void wlr_scene_buffer_set_opaque_region(struct wlr_scene_buffer *scene_buffer,
2012 		const pixman_region32_t *region) {
2013 	if (scene_buffer->geometry_pinned) {
2014 		return;
2015 	}
2016 	wlr_scene_buffer_set_opaque_region_pinned(scene_buffer, region);
2017 }
2018 
2019 void wlr_scene_buffer_set_opaque_region_pinned(struct wlr_scene_buffer *scene_buffer,
2020 		const pixman_region32_t *region) {
2021 	if (pixman_region32_equal(&scene_buffer->opaque_region, region)) {
2022 		return;
2023 	}
2024 
2025 	pixman_region32_copy(&scene_buffer->opaque_region, region);
2026 
2027 	int x, y;
2028 	if (!wlr_scene_node_coords(&scene_buffer->node, &x, &y)) {
2029 		return;
2030 	}
2031 
2032 	pixman_region32_t update_region;
2033 	pixman_region32_init(&update_region);
2034 	scene_node_bounds(&scene_buffer->node, x, y, &update_region);
2035 	scene_update_region(scene_node_get_root(&scene_buffer->node), &scene_buffer->node, &update_region, true);
2036 	pixman_region32_fini(&update_region);
2037 }
2038 
2039 void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer,
2040 		const struct wlr_fbox *box) {
2041 	if (wlr_fbox_equal(&scene_buffer->src_box, box)) {
2042 		return;
2043 	}
2044 
2045 	if (box != NULL) {
2046 		assert(box->x >= 0 && box->y >= 0 && box->width >= 0 && box->height >= 0);
2047 		scene_buffer->src_box = *box;
2048 	} else {
2049 		scene_buffer->src_box = (struct wlr_fbox){0};
2050 	}
2051 
2052 	scene_node_update(&scene_buffer->node, NULL);
2053 }
2054 
2055 void wlr_scene_buffer_set_dest_size(struct wlr_scene_buffer *scene_buffer,
2056 		int width, int height) {
2057 	if (scene_buffer->geometry_pinned) {
2058 		return;
2059 	}
2060 	wlr_scene_buffer_set_dest_size_pinned(scene_buffer, width, height);
2061 }
2062 
2063 void wlr_scene_buffer_set_dest_size_pinned(struct wlr_scene_buffer *scene_buffer,
2064 		int width, int height) {
2065 	if (scene_buffer->dst_width == width && scene_buffer->dst_height == height) {
2066 		return;
2067 	}
2068 
2069 	assert(width >= 0 && height >= 0);
2070 	scene_node_update(&scene_buffer->node, NULL);
2071 	scene_buffer->dst_width = width;
2072 	scene_buffer->dst_height = height;
2073 	scene_node_update(&scene_buffer->node, NULL);
2074 }
2075 
2076 void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer,
2077 		enum wl_output_transform transform) {
2078 	if (scene_buffer->transform == transform) {
2079 		return;
2080 	}
2081 
2082 	scene_node_update(&scene_buffer->node, NULL);
2083 	scene_buffer->transform = transform;
2084 	scene_node_update(&scene_buffer->node, NULL);
2085 }
2086 
2087 // Frame-callback delivery tracer. A demand-driven client cannot repaint while
2088 // it waits on a frame callback, so a surface silently skipped by the visible
2089 // gate below stalls until the next output frame that does reach it. Set
2090 // CCE_FRAME_DEBUG=1 to trace every buffer, or CCE_FRAME_DEBUG=WxH (the dst
2091 // size, e.g. 504x1032) to trace one window — the filtered form is what to use
2092 // while measuring, since tracing every buffer adds writes to the very thread
2093 // whose latency is under test.
2094 static bool cce_frame_debug_match(int dst_width, int dst_height) {
2095 	static bool initialized = false;
2096 	static bool enabled = false;
2097 	static int want_w = -1, want_h = -1;
2098 	if (!initialized) {
2099 		const char *value = getenv("CCE_FRAME_DEBUG");
2100 		if (value && *value) {
2101 			enabled = true;
2102 			// "WxH" matches one size exactly; a bare "W" matches on width only
2103 			// (a window's height can change under it); anything else traces all.
2104 			int parsed = sscanf(value, "%dx%d", &want_w, &want_h);
2105 			if (parsed == 1) {
2106 				want_h = -1;
2107 			} else if (parsed != 2) {
2108 				want_w = want_h = -1;
2109 			}
2110 		}
2111 		initialized = true;
2112 	}
2113 	if (!enabled) {
2114 		return false;
2115 	}
2116 	if (want_w < 0) {
2117 		return true;
2118 	}
2119 	return dst_width == want_w && (want_h < 0 || dst_height == want_h);
2120 }
2121 
2122 // Same time base as cce-ui's CCE_PRESENT_DEBUG and cce-system-interface's
2123 // CCE_HOVER_DEBUG (epoch ms mod 100000) so the three logs interleave directly.
2124 static int64_t cce_now_ms(void) {
2125 	struct timespec ts;
2126 	clock_gettime(CLOCK_REALTIME, &ts);
2127 	return ((int64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000) % 100000;
2128 }
2129 
2130 void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer,
2131 		struct wlr_scene_frame_done_event *event) {
2132 	bool visible = !pixman_region32_empty(&scene_buffer->node.visible);
2133 	if (cce_frame_debug_match(scene_buffer->dst_width, scene_buffer->dst_height)) {
2134 		pixman_box32_t *extents = pixman_region32_extents(&scene_buffer->node.visible);
2135 		// listeners: is anything wired to turn this signal into a client callback?
2136 		// (wlr_scene_surface registers one; zero means the emit goes nowhere.)
2137 		// committed_cb / pending_cb: does the surface actually hold a frame callback
2138 		// for wlr_surface_send_frame_done to fire? A request stuck in `pending` means
2139 		// the client asked but the compositor has not applied that commit yet — which
2140 		// separates "compositor drops it" from "client's request never landed".
2141 		int listeners = wl_list_length(&scene_buffer->events.frame_done.listener_list);
2142 		int committed_cb = -1, pending_cb = -1;
2143 		struct wlr_scene_surface *scene_surface =
2144 			wlr_scene_surface_try_from_buffer(scene_buffer);
2145 		if (scene_surface != NULL && scene_surface->surface != NULL) {
2146 			committed_cb = wl_list_length(&scene_surface->surface->current.frame_callback_list);
2147 			pending_cb = wl_list_length(&scene_surface->surface->pending.frame_callback_list);
2148 		}
2149 		wlr_log(WLR_INFO, "[cce-frame] t=%lld send_frame_done dst=%dx%d sent=%d listeners=%d committed_cb=%d pending_cb=%d visible_extents=(%d,%d %dx%d)",
2150 				(long long)cce_now_ms(), scene_buffer->dst_width, scene_buffer->dst_height,
2151 				visible, listeners, committed_cb, pending_cb,
2152 				extents->x1, extents->y1,
2153 				extents->x2 - extents->x1, extents->y2 - extents->y1);
2154 	}
2155 	if (visible) {
2156 		wl_signal_emit_mutable(&scene_buffer->events.frame_done, event);
2157 	}
2158 }
2159 
2160 void wlr_scene_buffer_set_opacity(struct wlr_scene_buffer *scene_buffer,
2161 		float opacity) {
2162 	if (scene_buffer->opacity == opacity) {
2163 		return;
2164 	}
2165 
2166 	assert(opacity >= 0 && opacity <= 1);
2167 	scene_buffer->opacity = opacity;
2168 	scene_node_update(&scene_buffer->node, NULL);
2169 }
2170 
2171 void wlr_scene_buffer_set_filter_mode(struct wlr_scene_buffer *scene_buffer,
2172 		enum wlr_scale_filter_mode filter_mode) {
2173 	if (scene_buffer->filter_mode == filter_mode) {
2174 		return;
2175 	}
2176 
2177 	scene_buffer->filter_mode = filter_mode;
2178 	scene_node_update(&scene_buffer->node, NULL);
2179 }
2180 
2181 void wlr_scene_buffer_set_transfer_function(struct wlr_scene_buffer *scene_buffer,
2182 		enum wlr_color_transfer_function transfer_function) {
2183 	if (scene_buffer->transfer_function == transfer_function) {
2184 		return;
2185 	}
2186 
2187 	scene_buffer->transfer_function = transfer_function;
2188 	scene_node_update(&scene_buffer->node, NULL);
2189 }
2190 
2191 void wlr_scene_buffer_set_primaries(struct wlr_scene_buffer *scene_buffer,
2192 		enum wlr_color_named_primaries primaries) {
2193 	if (scene_buffer->primaries == primaries) {
2194 		return;
2195 	}
2196 
2197 	scene_buffer->primaries = primaries;
2198 	scene_node_update(&scene_buffer->node, NULL);
2199 }
2200 
2201 void wlr_scene_buffer_set_color_encoding(struct wlr_scene_buffer *scene_buffer,
2202 		enum wlr_color_encoding color_encoding) {
2203 	if (scene_buffer->color_encoding == color_encoding) {
2204 		return;
2205 	}
2206 
2207 	scene_buffer->color_encoding = color_encoding;
2208 	scene_node_update(&scene_buffer->node, NULL);
2209 }
2210 
2211 void wlr_scene_buffer_set_color_range(struct wlr_scene_buffer *scene_buffer,
2212 		enum wlr_color_range color_range) {
2213 	if (scene_buffer->color_range == color_range) {
2214 		return;
2215 	}
2216 
2217 	scene_buffer->color_range = color_range;
2218 	scene_node_update(&scene_buffer->node, NULL);
2219 }
2220 
2221 inline void wlr_scene_buffer_set_corner_radius(struct wlr_scene_buffer *scene_buffer,
2222 		int radii) {
2223 	wlr_scene_buffer_set_corner_radii(scene_buffer, corner_radii_all(radii));
2224 }
2225 
2226 void wlr_scene_buffer_set_corner_radii(struct wlr_scene_buffer *scene_buffer,
2227 	struct fx_corner_radii corner_radii) {
2228 	if (fx_corner_radii_eq(scene_buffer->corners, corner_radii)) {
2229 		return;
2230 	}
2231 
2232 	scene_buffer->corners = corner_radii;
2233 	scene_node_update(&scene_buffer->node, NULL);
2234 }
2235 
2236 static struct wlr_texture *scene_buffer_get_texture(
2237 		struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) {
2238 	if (scene_buffer->buffer == NULL || scene_buffer->texture != NULL) {
2239 		return scene_buffer->texture;
2240 	}
2241 
2242 	struct wlr_client_buffer *client_buffer =
2243 		wlr_client_buffer_get(scene_buffer->buffer);
2244 	if (client_buffer != NULL) {
2245 		return client_buffer->texture;
2246 	}
2247 
2248 	struct wlr_texture *texture =
2249 		wlr_texture_from_buffer(renderer, scene_buffer->buffer);
2250 	if (texture != NULL && scene_buffer->own_buffer) {
2251 		scene_buffer->own_buffer = false;
2252 		wlr_buffer_unlock(scene_buffer->buffer);
2253 	}
2254 	scene_buffer_set_texture(scene_buffer, texture);
2255 	return texture;
2256 }
2257 
2258 void scene_node_get_size(struct wlr_scene_node *node, int *width, int *height) {
2259 	*width = 0;
2260 	*height = 0;
2261 
2262 	switch (node->type) {
2263 	case WLR_SCENE_NODE_TREE:
2264 		return;
2265 	case WLR_SCENE_NODE_RECT:;
2266 		struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node);
2267 		*width = scene_rect->width;
2268 		*height = scene_rect->height;
2269 		break;
2270 	case WLR_SCENE_NODE_BUFFER:;
2271 		struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
2272 		if (scene_buffer->dst_width > 0 && scene_buffer->dst_height > 0) {
2273 			*width = scene_buffer->dst_width;
2274 			*height = scene_buffer->dst_height;
2275 		} else {
2276 			*width = scene_buffer->buffer_width;
2277 			*height = scene_buffer->buffer_height;
2278 			wlr_output_transform_coords(scene_buffer->transform, width, height);
2279 		}
2280 		break;
2281 	case WLR_SCENE_NODE_SHADOW:;
2282 		struct wlr_scene_shadow *scene_shadow = wlr_scene_shadow_from_node(node);
2283 		*width = scene_shadow->width;
2284 		*height = scene_shadow->height;
2285 		break;
2286 	case WLR_SCENE_NODE_BEVEL:;
2287 		struct wlr_scene_bevel *scene_bevel = wlr_scene_bevel_from_node(node);
2288 		*width = scene_bevel->width;
2289 		*height = scene_bevel->height;
2290 		break;
2291 	case WLR_SCENE_NODE_FRAME:;
2292 		struct wlr_scene_frame *scene_frame_sz = wlr_scene_frame_from_node(node);
2293 		*width = scene_frame_sz->width;
2294 		*height = scene_frame_sz->height;
2295 		break;
2296 	case WLR_SCENE_NODE_DROPLET:;
2297 		struct wlr_scene_droplet *scene_droplet = wlr_scene_droplet_from_node(node);
2298 		*width = scene_droplet->width;
2299 		*height = scene_droplet->height;
2300 		break;
2301 	case WLR_SCENE_NODE_OPTIMIZED_BLUR:;
2302 		struct wlr_scene_optimized_blur *scene_blur =
2303 			wlr_scene_optimized_blur_from_node(node);
2304 		*width = scene_blur->width;
2305 		*height = scene_blur->height;
2306 		break;
2307 	case WLR_SCENE_NODE_BLUR:;
2308 		struct wlr_scene_blur *blur = wlr_scene_blur_from_node(node);
2309 		*width = blur->width;
2310 		*height = blur->height;
2311 		break;
2312 	}
2313 }
2314 
2315 void wlr_scene_node_set_enabled(struct wlr_scene_node *node, bool enabled) {
2316 	if (node->enabled == enabled) {
2317 		return;
2318 	}
2319 
2320 	int x, y;
2321 	pixman_region32_t visible;
2322 	pixman_region32_init(&visible);
2323 	if (wlr_scene_node_coords(node, &x, &y)) {
2324 		scene_node_visibility(node, &visible);
2325 	}
2326 
2327 	node->enabled = enabled;
2328 
2329 	scene_node_update(node, &visible);
2330 }
2331 
2332 void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y) {
2333 	if (node->x == x && node->y == y) {
2334 		return;
2335 	}
2336 
2337 	scene_node_update(node, NULL);
2338 	node->x = x;
2339 	node->y = y;
2340 	scene_node_update(node, NULL);
2341 }
2342 
2343 void wlr_scene_node_place_above(struct wlr_scene_node *node,
2344 		struct wlr_scene_node *sibling) {
2345 	assert(node != sibling);
2346 	assert(node->parent == sibling->parent);
2347 
2348 	if (node->link.prev == &sibling->link) {
2349 		return;
2350 	}
2351 
2352 	wl_list_remove(&node->link);
2353 	wl_list_insert(&sibling->link, &node->link);
2354 	scene_node_update(node, NULL);
2355 }
2356 
2357 void wlr_scene_node_place_below(struct wlr_scene_node *node,
2358 		struct wlr_scene_node *sibling) {
2359 	assert(node != sibling);
2360 	assert(node->parent == sibling->parent);
2361 
2362 	if (node->link.next == &sibling->link) {
2363 		return;
2364 	}
2365 
2366 	wl_list_remove(&node->link);
2367 	wl_list_insert(sibling->link.prev, &node->link);
2368 	scene_node_update(node, NULL);
2369 }
2370 
2371 void wlr_scene_node_raise_to_top(struct wlr_scene_node *node) {
2372 	struct wlr_scene_node *current_top = wl_container_of(
2373 		node->parent->children.prev, current_top, link);
2374 	if (node == current_top) {
2375 		return;
2376 	}
2377 	wlr_scene_node_place_above(node, current_top);
2378 }
2379 
2380 void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node) {
2381 	struct wlr_scene_node *current_bottom = wl_container_of(
2382 		node->parent->children.next, current_bottom, link);
2383 	if (node == current_bottom) {
2384 		return;
2385 	}
2386 	wlr_scene_node_place_below(node, current_bottom);
2387 }
2388 
2389 void wlr_scene_node_reparent(struct wlr_scene_node *node,
2390 		struct wlr_scene_tree *new_parent) {
2391 	assert(new_parent != NULL);
2392 
2393 	if (node->parent == new_parent) {
2394 		return;
2395 	}
2396 
2397 	/* Ensure that a node cannot become its own ancestor */
2398 	for (struct wlr_scene_tree *ancestor = new_parent; ancestor != NULL;
2399 			ancestor = ancestor->node.parent) {
2400 		assert(&ancestor->node != node);
2401 	}
2402 
2403 	int x, y;
2404 	pixman_region32_t visible;
2405 	pixman_region32_init(&visible);
2406 	if (wlr_scene_node_coords(node, &x, &y)) {
2407 		scene_node_visibility(node, &visible);
2408 	}
2409 
2410 	wl_list_remove(&node->link);
2411 	node->parent = new_parent;
2412 	wl_list_insert(new_parent->children.prev, &node->link);
2413 	scene_node_update(node, &visible);
2414 }
2415 
2416 bool wlr_scene_node_coords(struct wlr_scene_node *node,
2417 		int *lx_ptr, int *ly_ptr) {
2418 	assert(node);
2419 
2420 	int lx = 0, ly = 0;
2421 	bool enabled = true;
2422 	while (true) {
2423 		lx += node->x;
2424 		ly += node->y;
2425 		enabled = enabled && node->enabled;
2426 		if (node->parent == NULL) {
2427 			break;
2428 		}
2429 
2430 		node = &node->parent->node;
2431 	}
2432 
2433 	*lx_ptr = lx;
2434 	*ly_ptr = ly;
2435 	return enabled;
2436 }
2437 
2438 static void scene_node_for_each_scene_buffer(struct wlr_scene_node *node,
2439 		int lx, int ly, wlr_scene_buffer_iterator_func_t user_iterator,
2440 		void *user_data) {
2441 	if (!node->enabled) {
2442 		return;
2443 	}
2444 
2445 	lx += node->x;
2446 	ly += node->y;
2447 
2448 	if (node->type == WLR_SCENE_NODE_BUFFER) {
2449 		struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
2450 		user_iterator(scene_buffer, lx, ly, user_data);
2451 	} else if (node->type == WLR_SCENE_NODE_TREE) {
2452 		struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
2453 		struct wlr_scene_node *child;
2454 		wl_list_for_each(child, &scene_tree->children, link) {
2455 			scene_node_for_each_scene_buffer(child, lx, ly, user_iterator, user_data);
2456 		}
2457 	}
2458 }
2459 
2460 void wlr_scene_node_for_each_buffer(struct wlr_scene_node *node,
2461 		wlr_scene_buffer_iterator_func_t user_iterator, void *user_data) {
2462 	scene_node_for_each_scene_buffer(node, 0, 0, user_iterator, user_data);
2463 }
2464 
2465 struct node_at_data {
2466 	double lx, ly;
2467 	double rx, ry;
2468 	struct wlr_scene_node *node;
2469 };
2470 
2471 static bool scene_node_at_iterator(struct wlr_scene_node *node,
2472 		int lx, int ly, void *data) {
2473 	struct node_at_data *at_data = data;
2474 
2475 	double rx = at_data->lx - lx;
2476 	double ry = at_data->ly - ly;
2477 
2478 	if (node->type == WLR_SCENE_NODE_BUFFER) {
2479 		struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
2480 
2481 		// A dest-scaled surface buffer occupies dst_width x dst_height in
2482 		// layout space while its input region (and the coordinates its
2483 		// client expects) live in SURFACE-LOCAL logical space. Map the
2484 		// node-local point between the two before the region check, or a
2485 		// buffer resting at a display ratio != 1 (the desktop grid's
2486 		// patch, whenever the camera zoom sits off the pow2 quantization)
2487 		// hit-tests and reports coordinates displaced by exactly that
2488 		// ratio — which is how a click on a desktop item read as
2489 		// background, and how the press position disagreed with the drag
2490 		// deltas hard enough to fling the item across the canvas.
2491 		// Buffers displayed at their natural size (every window at rest)
2492 		// scale by exactly 1 here and are untouched.
2493 		//
2494 		// The ratio is between dst and the DISPLAYED region of the
2495 		// surface, which is the whole surface only while no clip is set.
2496 		// A clipped surface (wlr_scene_subsurface_tree_set_clip — how a
2497 		// CSD toplevel is cropped to its xdg geometry, shedding the
2498 		// client-side shadow margins) shows just the clip, at dst ==
2499 		// clip size, so it is a crop at ratio 1, not a scale — yet its
2500 		// surface size still differs from dst by the margins. Measuring
2501 		// against the whole surface inflated every pointer coordinate on
2502 		// such a window by (surface / geometry): a GTK3 dialog 718px
2503 		// tall cropped to 666 received clicks 8% below the cursor, more
2504 		// the further down, and the bottom band was dead because the
2505 		// inflated point fell outside the surface. The clip's origin is
2506 		// added by the surface callback below; only the extent matters
2507 		// here, clamped to the surface as the commit path clamps it.
2508 		if (scene_buffer->dst_width > 0 && scene_buffer->dst_height > 0) {
2509 			struct wlr_scene_surface *scene_surface =
2510 				wlr_scene_surface_try_from_buffer(scene_buffer);
2511 			if (scene_surface != NULL && scene_surface->surface != NULL) {
2512 				int sw = scene_surface->surface->current.width;
2513 				int sh = scene_surface->surface->current.height;
2514 				const struct wlr_box *clip = &scene_surface->clip;
2515 				if (!wlr_box_empty(clip)) {
2516 					if (clip->width < sw - clip->x) {
2517 						sw = clip->width;
2518 					} else {
2519 						sw -= clip->x;
2520 					}
2521 					if (clip->height < sh - clip->y) {
2522 						sh = clip->height;
2523 					} else {
2524 						sh -= clip->y;
2525 					}
2526 				}
2527 				if (sw > 0 && sh > 0 && (sw != scene_buffer->dst_width ||
2528 						sh != scene_buffer->dst_height)) {
2529 					rx = rx * sw / scene_buffer->dst_width;
2530 					ry = ry * sh / scene_buffer->dst_height;
2531 				}
2532 			}
2533 		}
2534 
2535 		if (scene_buffer->point_accepts_input &&
2536 				!scene_buffer->point_accepts_input(scene_buffer, &rx, &ry)) {
2537 			return false;
2538 		}
2539 	} else if (node->type == WLR_SCENE_NODE_RECT) {
2540 		struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
2541 		if (!rect->accepts_input) {
2542 			return false;
2543 		} else if (!wlr_box_empty(&rect->clipped_region.area)
2544 				&& wlr_box_contains_point(&rect->clipped_region.area, rx, ry)) {
2545 			// Inside clipped region
2546 			return false;
2547 		}
2548 	} else if (node->type == WLR_SCENE_NODE_SHADOW
2549 			|| node->type == WLR_SCENE_NODE_BEVEL
2550 			|| node->type == WLR_SCENE_NODE_FRAME
2551 			|| node->type == WLR_SCENE_NODE_DROPLET
2552 			|| node->type == WLR_SCENE_NODE_OPTIMIZED_BLUR
2553 			|| node->type == WLR_SCENE_NODE_BLUR) {
2554 		// Disable interaction
2555 		return false;
2556 	}
2557 
2558 	at_data->rx = rx;
2559 	at_data->ry = ry;
2560 	at_data->node = node;
2561 	return true;
2562 }
2563 
2564 struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node,
2565 		double lx, double ly, double *nx, double *ny) {
2566 	struct wlr_box box = {
2567 		.x = floor(lx),
2568 		.y = floor(ly),
2569 		.width = 1,
2570 		.height = 1
2571 	};
2572 
2573 	struct node_at_data data = {
2574 		.lx = lx,
2575 		.ly = ly
2576 	};
2577 
2578 	if (scene_nodes_in_box(node, &box, scene_node_at_iterator, &data)) {
2579 		if (nx) {
2580 			*nx = data.rx;
2581 		}
2582 		if (ny) {
2583 			*ny = data.ry;
2584 		}
2585 		return data.node;
2586 	}
2587 
2588 	return NULL;
2589 }
2590 
2591 struct render_list_entry {
2592 	struct wlr_scene_node *node;
2593 	bool highlight_transparent_region;
2594 	int x, y;
2595 };
2596 
2597 static float get_luminance_multiplier(const struct wlr_color_luminances *src_lum,
2598 		const struct wlr_color_luminances *dst_lum) {
2599 	return (dst_lum->reference / src_lum->reference) * (src_lum->max / dst_lum->max);
2600 }
2601 
2602 /* Bake the content below the node within one screen-space layout rect into
2603  * the cache, landing at `shift` (buffer px added to the screen buffer
2604  * coordinates: the node's anchor plus the cache margin). */
2605 static bool optimized_blur_bake_rect(struct fx_gles_render_pass *fx_pass,
2606 		struct wlr_scene *scene, const struct render_data *data,
2607 		const struct wlr_box *layout_rect, int shift_x, int shift_y) {
2608 	struct wlr_box buf = {
2609 		.x = (int)round((layout_rect->x - data->logical.x) * data->scale),
2610 		.y = (int)round((layout_rect->y - data->logical.y) * data->scale),
2611 		.width = (int)round(layout_rect->width * data->scale),
2612 		.height = (int)round(layout_rect->height * data->scale),
2613 	};
2614 	if (buf.width <= 0 || buf.height <= 0) {
2615 		return true;
2616 	}
2617 	const float opacity = 1.0f;
2618 	struct fx_render_blur_pass_options blur_options = {
2619 		.tex_options = {
2620 			.base = {
2621 				.transform = WL_OUTPUT_TRANSFORM_NORMAL,
2622 				.alpha = &opacity,
2623 				.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
2624 				.dst_box = buf,
2625 			},
2626 			.clip_box = &buf,
2627 			.discard_transparent = false,
2628 			.clipped_region = {0}
2629 		},
2630 		.blur_data = &scene->blur_data,
2631 		.blur_strength = 1.0f,
2632 		.cache_shift_x = shift_x,
2633 		.cache_shift_y = shift_y,
2634 	};
2635 	return fx_render_pass_add_optimized_blur(fx_pass, &blur_options);
2636 }
2637 
2638 /* Record a just-baked rect (anchor space) in the node's region. What lay
2639  * within the blur's reach of an output edge — anything outside `trusted`,
2640  * the output inset by that reach, in the same space — sampled clamped edge
2641  * pixels in place of the backdrop beyond, so it also goes into
2642  * `edge_region` to be re-baked once it is clear of the edge. */
2643 static void optimized_blur_note_baked(struct wlr_scene_optimized_blur *ob,
2644 		const pixman_box32_t *rect, const struct wlr_box *trusted) {
2645 	pixman_region32_t guessed;
2646 	pixman_region32_init_rect(&guessed, rect->x1, rect->y1,
2647 		rect->x2 - rect->x1, rect->y2 - rect->y1);
2648 	pixman_region32_union(&ob->baked_region, &ob->baked_region, &guessed);
2649 	pixman_region32_subtract(&ob->edge_region, &ob->edge_region, &guessed);
2650 	if (trusted->width > 0 && trusted->height > 0) {
2651 		pixman_region32_t keep;
2652 		pixman_region32_init_rect(&keep, trusted->x, trusted->y,
2653 			trusted->width, trusted->height);
2654 		pixman_region32_subtract(&guessed, &guessed, &keep);
2655 		pixman_region32_fini(&keep);
2656 	}
2657 	pixman_region32_union(&ob->edge_region, &ob->edge_region, &guessed);
2658 	pixman_region32_fini(&guessed);
2659 }
2660 
2661 /* The optimized node's per-frame work: a full bake (anchored where the node
2662  * is now) when dirty, never baked, baked elsewhere, or travelled past the
2663  * cache margin; otherwise only the strips the node now shows that its bake
2664  * does not cover, landed at its existing anchor. */
2665 static void optimized_blur_render(struct wlr_scene *scene,
2666 		struct wlr_scene_optimized_blur *ob, struct wlr_scene_node *node,
2667 		struct fx_gles_render_pass *fx_pass, const struct render_data *data,
2668 		struct wlr_box dst_box) {
2669 	struct fx_offscreen_buffers *fbos = fx_pass->fx_offscreen_buffers;
2670 	if (fbos == NULL) {
2671 		return;
2672 	}
2673 	const int mx = fbos->cache_margin_x, my = fbos->cache_margin_y;
2674 	const bool normal = data->transform == WL_OUTPUT_TRANSFORM_NORMAL;
2675 	int cx, cy;
2676 	if (!wlr_scene_node_coords(node, &cx, &cy)) {
2677 		return;
2678 	}
2679 	struct wlr_box cur = { .x = cx, .y = cy, .width = ob->width, .height = ob->height };
2680 	struct wlr_box vis;
2681 	if (!wlr_box_intersection(&vis, &cur, &data->logical)) {
2682 		return;
2683 	}
2684 
2685 	// The output inset by the blur's sampling reach (layout px): a pixel
2686 	// baked outside it sampled past the output's edge.
2687 	const int reach = (int)ceil(blur_data_calc_size(&scene->blur_data) / data->scale);
2688 	const struct wlr_box trusted = {
2689 		.x = data->logical.x + reach,
2690 		.y = data->logical.y + reach,
2691 		.width = data->logical.width - 2 * reach,
2692 		.height = data->logical.height - 2 * reach,
2693 	};
2694 
2695 	bool full = ob->dirty || !ob->baked || ob->baked_output != data->output || !normal;
2696 	int dx = 0, dy = 0; // anchor-space shift, layout px: anchor - current
2697 	if (!full) {
2698 		dx = ob->baked_x - cx;
2699 		dy = ob->baked_y - cy;
2700 		double mlx = mx / data->scale, mly = my / data->scale;
2701 		if (vis.x + dx < data->logical.x - mlx || vis.y + dy < data->logical.y - mly ||
2702 				vis.x + dx + vis.width > data->logical.x + data->logical.width + mlx ||
2703 				vis.y + dy + vis.height > data->logical.y + data->logical.height + mly) {
2704 			full = true;
2705 		}
2706 	}
2707 
2708 	if (full) {
2709 		if (cce_scene_blur_debug()) {
2710 			wlr_log(WLR_INFO, "[scenefx] optimized bake full %dx%d dirty=%d baked=%d",
2711 				vis.width, vis.height, ob->dirty, ob->baked);
2712 		}
2713 		bool ok;
2714 		if (normal) {
2715 			ok = optimized_blur_bake_rect(fx_pass, scene, data, &vis, mx, my);
2716 		} else {
2717 			// Transformed output: the whole node in its buffer-space box,
2718 			// in place (no anchoring on rotated outputs).
2719 			const float opacity = 1.0f;
2720 			enum wl_output_transform transform = wlr_output_transform_invert(data->transform);
2721 			transform = wlr_output_transform_compose(transform, data->transform);
2722 			struct fx_render_blur_pass_options blur_options = {
2723 				.tex_options = {
2724 					.base = {
2725 						.transform = transform,
2726 						.alpha = &opacity,
2727 						.blend_mode = WLR_RENDER_BLEND_MODE_NONE,
2728 						.dst_box = dst_box,
2729 					},
2730 					.clip_box = &dst_box,
2731 					.discard_transparent = false,
2732 					.clipped_region = {0}
2733 				},
2734 				.blur_data = &scene->blur_data,
2735 				.blur_strength = 1.0f,
2736 				.cache_shift_x = mx,
2737 				.cache_shift_y = my,
2738 			};
2739 			ok = fx_render_pass_add_optimized_blur(fx_pass, &blur_options);
2740 		}
2741 		if (!ok) {
2742 			return;
2743 		}
2744 		ob->dirty = false;
2745 		ob->baked = true;
2746 		ob->baked_x = cx;
2747 		ob->baked_y = cy;
2748 		ob->baked_output = data->output;
2749 		pixman_region32_clear(&ob->baked_region);
2750 		pixman_region32_clear(&ob->edge_region);
2751 		const pixman_box32_t all = { vis.x, vis.y, vis.x + vis.width, vis.y + vis.height };
2752 		optimized_blur_note_baked(ob, &all, &trusted);
2753 		return;
2754 	}
2755 
2756 	// Anchored: what the node shows now, in anchor space, minus what the
2757 	// cache already holds for it — plus what it holds only as an edge guess
2758 	// that has since moved clear of every edge (a pan carrying a window
2759 	// that hung off the output inward: without this, the band along the
2760 	// old edge kept its clamped blur, a seam of smeared backdrop).
2761 	const struct wlr_box trusted_a = {
2762 		.x = trusted.x + dx, .y = trusted.y + dy,
2763 		.width = trusted.width, .height = trusted.height,
2764 	};
2765 	pixman_region32_t need, uncovered, stale;
2766 	pixman_region32_init_rect(&need, vis.x + dx, vis.y + dy, vis.width, vis.height);
2767 	pixman_region32_init(&uncovered);
2768 	pixman_region32_subtract(&uncovered, &need, &ob->baked_region);
2769 	pixman_region32_init(&stale);
2770 	if (trusted.width > 0 && trusted.height > 0) {
2771 		pixman_region32_intersect_rect(&stale, &ob->edge_region,
2772 			trusted_a.x, trusted_a.y, trusted_a.width, trusted_a.height);
2773 		pixman_region32_intersect(&stale, &stale, &need);
2774 		if (cce_scene_blur_debug() && pixman_region32_not_empty(&stale)) {
2775 			const pixman_box32_t *e = pixman_region32_extents(&stale);
2776 			wlr_log(WLR_INFO, "[scenefx] optimized re-bake edge guess %dx%d at (%d, %d), node travel (%d, %d)",
2777 				e->x2 - e->x1, e->y2 - e->y1, e->x1, e->y1, -dx, -dy);
2778 		}
2779 		pixman_region32_union(&uncovered, &uncovered, &stale);
2780 	}
2781 	pixman_region32_fini(&stale);
2782 	int n = 0;
2783 	const pixman_box32_t *rects = pixman_region32_rectangles(&uncovered, &n);
2784 	const int shift_x = (int)round(dx * data->scale) + mx;
2785 	const int shift_y = (int)round(dy * data->scale) + my;
2786 	for (int i = 0; i < n; i++) {
2787 		// The strip in screen space (where its content is being composited
2788 		// this frame); it lands in the cache at the node's anchor.
2789 		struct wlr_box r = {
2790 			.x = rects[i].x1 - dx, .y = rects[i].y1 - dy,
2791 			.width = rects[i].x2 - rects[i].x1, .height = rects[i].y2 - rects[i].y1,
2792 		};
2793 		if (optimized_blur_bake_rect(fx_pass, scene, data, &r, shift_x, shift_y)) {
2794 			optimized_blur_note_baked(ob, &rects[i], &trusted_a);
2795 		}
2796 	}
2797 	pixman_region32_fini(&need);
2798 	pixman_region32_fini(&uncovered);
2799 }
2800 
2801 static void scene_entry_render(struct render_list_entry *entry, const struct render_data *data) {
2802 	struct wlr_scene_node *node = entry->node;
2803 	struct fx_gles_render_pass *fx_pass = fx_get_render_pass(data->render_pass);
2804 
2805 	// Desk nodes draw shifted by the sub-pixel offset (device px); every
2806 	// box and region derived from the node's layout position below gets
2807 	// the same shift, so the node stays self-consistent and only its
2808 	// placement against unshifted layers (bars, fullscreen) is off by it.
2809 	int desk_dx = 0, desk_dy = 0;
2810 	if (scene_node_has_desk_offset(data->output->scene, node)) {
2811 		scene_desk_offset_px(data->output->scene, data->scale, data->transform, &desk_dx, &desk_dy);
2812 	}
2813 
2814 	pixman_region32_t render_region;
2815 	pixman_region32_init(&render_region);
2816 	pixman_region32_copy(&render_region, &node->visible);
2817 	pixman_region32_translate(&render_region, -data->logical.x, -data->logical.y);
2818 	logical_to_buffer_coords(&render_region, data, true);
2819 	pixman_region32_translate(&render_region, desk_dx, desk_dy);
2820 	pixman_region32_intersect(&render_region, &render_region, &data->damage);
2821 	if (pixman_region32_empty(&render_region)) {
2822 		pixman_region32_fini(&render_region);
2823 		return;
2824 	}
2825 
2826 	// CCE_BLUR_DEBUG: why is this blur node rendering — its box, the slice
2827 	// inside this frame's damage, and the damage extents.
2828 	if (node->type == WLR_SCENE_NODE_BLUR && cce_scene_blur_debug()) {
2829 		const pixman_box32_t *v = pixman_region32_extents(&node->visible);
2830 		const pixman_box32_t *r = pixman_region32_extents(&render_region);
2831 		const pixman_box32_t *d = pixman_region32_extents(&data->damage);
2832 		wlr_log(WLR_INFO, "[scenefx] blur entry visible=(%d,%d)-(%d,%d) render=(%d,%d)-(%d,%d) damage=(%d,%d)-(%d,%d) rects=%d",
2833 			v->x1, v->y1, v->x2, v->y2, r->x1, r->y1, r->x2, r->y2,
2834 			d->x1, d->y1, d->x2, d->y2, pixman_region32_n_rects(&data->damage));
2835 	}
2836 
2837 	int x = entry->x - data->logical.x;
2838 	int y = entry->y - data->logical.y;
2839 
2840 	struct wlr_box dst_box = {
2841 		.x = x,
2842 		.y = y,
2843 	};
2844 	scene_node_get_size(node, &dst_box.width, &dst_box.height);
2845 	transform_output_box(&dst_box, data);
2846 	dst_box.x += desk_dx;
2847 	dst_box.y += desk_dy;
2848 
2849 	pixman_region32_t opaque;
2850 	pixman_region32_init(&opaque);
2851 	scene_node_opaque_region(node, x, y, &opaque);
2852 	logical_to_buffer_coords(&opaque, data, false);
2853 	pixman_region32_translate(&opaque, desk_dx, desk_dy);
2854 	pixman_region32_subtract(&opaque, &render_region, &opaque);
2855 
2856 	enum wl_output_transform node_transform =
2857 		wlr_output_transform_compose(WL_OUTPUT_TRANSFORM_NORMAL, data->transform);
2858 
2859 	struct wlr_scene *scene = data->output->scene;
2860 	switch (node->type) {
2861 	case WLR_SCENE_NODE_TREE:
2862 		assert(false);
2863 		break;
2864 	case WLR_SCENE_NODE_RECT:;
2865 		struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node);
2866 		struct fx_corner_radii rect_corners = scene_rect->corners;
2867 
2868 		fx_corner_radii_transform(node_transform, &rect_corners);
2869 
2870 		struct wlr_box rect_clipped_region_box = scene_rect->clipped_region.area;
2871 		struct fx_corner_radii rect_clipped_corners = scene_rect->clipped_region.corners;
2872 
2873 		// Node relative -> Root relative
2874 		rect_clipped_region_box.x += x;
2875 		rect_clipped_region_box.y += y;
2876 
2877 		transform_output_box(&rect_clipped_region_box, data);
2878 		rect_clipped_region_box.x += desk_dx;
2879 		rect_clipped_region_box.y += desk_dy;
2880 		fx_corner_radii_transform(node_transform, &rect_clipped_corners);
2881 
2882 		struct fx_render_rect_options rect_options = {
2883 			.base = {
2884 				.box = dst_box,
2885 				.color = {
2886 					.r = scene_rect->color[0],
2887 					.g = scene_rect->color[1],
2888 					.b = scene_rect->color[2],
2889 					.a = scene_rect->color[3],
2890 				},
2891 				.clip = &render_region,
2892 				.blend_mode = (scene_rect->color[3] == 1.0f && fx_corner_radii_is_empty(&rect_corners) && scene_rect->fade_inset == 0) ?
2893 					WLR_RENDER_BLEND_MODE_NONE : WLR_RENDER_BLEND_MODE_PREMULTIPLIED,
2894 			},
2895 			.clipped_region = {
2896 				.area = rect_clipped_region_box,
2897 				.corners = fx_corner_radii_scale(rect_clipped_corners, data->scale),
2898 			},
2899 		};
2900 
2901 		// TODO: Use the base wlr_render_pass_add_rect as a fast-path in the future
2902 		if (!fx_corner_radii_is_empty(&rect_corners) || scene_rect->fade_inset > 0) {
2903 			// fade_inset is wire-encoded as inset_px * 1000 + fade_mode:
2904 			// scale only the inset part — multiplying the whole encoding
2905 			// also multiplied the mode digit (quadratic became gaussian on
2906 			// a 2x output).
2907 			int fade_enc = scene_rect->fade_inset;
2908 			int fade_px = (int)((float)(fade_enc / 1000) * data->scale + 0.5f);
2909 			struct fx_render_rounded_rect_options rounded_rect_options = {
2910 				.base = rect_options.base,
2911 				.corners = fx_corner_radii_scale(rect_corners, data->scale),
2912 				.clipped_region = rect_options.clipped_region,
2913 				.fade_inset = fade_px * 1000 + fade_enc % 1000,
2914 			};
2915 			fx_render_pass_add_rounded_rect(fx_pass, &rounded_rect_options);
2916 		} else {
2917 			fx_render_pass_add_rect(fx_pass, &rect_options);
2918 		}
2919 		break;
2920 	case WLR_SCENE_NODE_BUFFER:;
2921 		struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
2922 		struct fx_corner_radii buffer_corners = scene_buffer->corners;
2923 
2924 		if (scene_buffer->is_single_pixel_buffer) {
2925 			// TODO: Render blur/rounded corners/etc here:
2926 
2927 			// Render the buffer as a rect, this is likely to be more efficient
2928 			wlr_render_pass_add_rect(data->render_pass, &(struct wlr_render_rect_options){
2929 				.box = dst_box,
2930 				.color = {
2931 					.r = (float)scene_buffer->single_pixel_buffer_color[0] / (float)UINT32_MAX,
2932 					.g = (float)scene_buffer->single_pixel_buffer_color[1] / (float)UINT32_MAX,
2933 					.b = (float)scene_buffer->single_pixel_buffer_color[2] / (float)UINT32_MAX,
2934 					.a = (float)scene_buffer->single_pixel_buffer_color[3] /
2935 						(float)UINT32_MAX * scene_buffer->opacity,
2936 				},
2937 				.clip = &render_region,
2938 			});
2939 			break;
2940 		}
2941 
2942 		struct wlr_texture *texture = scene_buffer_get_texture(scene_buffer,
2943 			data->output->output->renderer);
2944 		if (texture == NULL) {
2945 			scene_output_damage(data->output, &render_region);
2946 			break;
2947 		}
2948 
2949 		enum wl_output_transform transform =
2950 			wlr_output_transform_invert(scene_buffer->transform);
2951 		transform = wlr_output_transform_compose(transform, data->transform);
2952 		fx_corner_radii_transform(transform, &buffer_corners);
2953 
2954 		struct wlr_color_primaries primaries = {0};
2955 		if (scene_buffer->primaries != 0) {
2956 			wlr_color_primaries_from_named(&primaries, scene_buffer->primaries);
2957 		}
2958 
2959 		struct wlr_color_luminances src_lum, srgb_lum;
2960 		wlr_color_transfer_function_get_default_luminance(
2961 			scene_buffer->transfer_function, &src_lum);
2962 		wlr_color_transfer_function_get_default_luminance(
2963 			WLR_COLOR_TRANSFER_FUNCTION_SRGB, &srgb_lum);
2964 		float luminance_multiplier = get_luminance_multiplier(&src_lum, &srgb_lum);
2965 
2966 		struct fx_render_texture_options tex_options = {
2967 			.base = (struct wlr_render_texture_options){
2968 				.texture = texture,
2969 				.src_box = scene_buffer->src_box,
2970 				.dst_box = dst_box,
2971 				.transform = transform,
2972 				.clip = &render_region, // Render with the smaller region, clipping CSD
2973 				.alpha = &scene_buffer->opacity,
2974 				.filter_mode = scene_buffer->filter_mode,
2975 				.blend_mode = !data->output->scene->calculate_visibility ||
2976 					!pixman_region32_empty(&opaque) ?
2977 					WLR_RENDER_BLEND_MODE_PREMULTIPLIED : WLR_RENDER_BLEND_MODE_NONE,
2978 				.transfer_function = scene_buffer->transfer_function,
2979 				.primaries = scene_buffer->primaries != 0 ? &primaries : NULL,
2980 				.color_encoding = scene_buffer->color_encoding,
2981 				.color_range = scene_buffer->color_range,
2982 				.luminance_multiplier = &luminance_multiplier,
2983 				.wait_timeline = scene_buffer->wait_timeline,
2984 				.wait_point = scene_buffer->wait_point,
2985 			},
2986 			.clip_box = &dst_box,
2987 			.corners = fx_corner_radii_scale(buffer_corners, data->scale),
2988 			.clipped_region = {0},
2989 		};
2990 
2991 		// TODO: Use the base wlr_render_pass_add_texture as a fast-path in the future
2992 		fx_render_pass_add_texture(fx_pass, &tex_options);
2993 
2994 		struct wlr_scene_output_sample_event sample_event = {
2995 			.output = data->output,
2996 			.direct_scanout = false,
2997 			.release_timeline = data->output->in_timeline,
2998 			.release_point = data->output->in_point,
2999 		};
3000 		wl_signal_emit_mutable(&scene_buffer->events.output_sample, &sample_event);
3001 
3002 		if (entry->highlight_transparent_region) {
3003 			wlr_render_pass_add_rect(data->render_pass, &(struct wlr_render_rect_options){
3004 					.box = dst_box,
3005 					.color = { .r = 0, .g = 0.3, .b = 0, .a = 0.3 },
3006 					.clip = &opaque,
3007 			});
3008 		}
3009 		break;
3010 	case WLR_SCENE_NODE_SHADOW:;
3011 		struct wlr_scene_shadow *scene_shadow = wlr_scene_shadow_from_node(node);
3012 
3013 		struct wlr_box shadow_clipped_region_box = scene_shadow->clipped_region.area;
3014 		struct fx_corner_radii shadow_clipped_corners = scene_shadow->clipped_region.corners;
3015 
3016 		// Node relative -> Root relative
3017 		shadow_clipped_region_box.x += x;
3018 		shadow_clipped_region_box.y += y;
3019 
3020 		transform_output_box(&shadow_clipped_region_box, data);
3021 		shadow_clipped_region_box.x += desk_dx;
3022 		shadow_clipped_region_box.y += desk_dy;
3023 		fx_corner_radii_transform(node_transform, &shadow_clipped_corners);
3024 
3025 		struct fx_render_box_shadow_options shadow_options = {
3026 			.box = dst_box,
3027 			.clipped_region = {
3028 				.area = shadow_clipped_region_box,
3029 				.corners = fx_corner_radii_scale(shadow_clipped_corners, data->scale),
3030 			},
3031 			.blur_sigma = scene_shadow->blur_sigma,
3032 			.corner_radius = scene_shadow->corner_radius * data->scale,
3033 			.color = {
3034 				.r = scene_shadow->color[0],
3035 				.g = scene_shadow->color[1],
3036 				.b = scene_shadow->color[2],
3037 				.a = scene_shadow->color[3],
3038 			},
3039 			.clip = &render_region,
3040 		};
3041 		fx_render_pass_add_box_shadow(fx_pass, &shadow_options);
3042 		break;
3043 	case WLR_SCENE_NODE_FRAME:;
3044 		struct wlr_scene_frame *scene_frame = wlr_scene_frame_from_node(node);
3045 
3046 		struct fx_render_frame_options frame_options = {
3047 			.box = dst_box,
3048 			/* Lengths are node-local logical px, like the bevel's
3049 			 * thickness and the exclusion rect below; the shader works
3050 			 * in buffer px, so every one takes the output scale. Left
3051 			 * unscaled, the handles drew at half size on a scale-2
3052 			 * output — and smaller than the compositor's hit zone,
3053 			 * which is sized in logical px. */
3054 			.corner_radius = scene_frame->corner_radius * data->scale,
3055 			.band = scene_frame->band * data->scale,
3056 			.band_min = scene_frame->band_min * data->scale,
3057 			.corner_len = scene_frame->corner_len * data->scale,
3058 			.gap = scene_frame->gap * data->scale,
3059 			.hovered = scene_frame->hovered,
3060 			.swell_curve = scene_frame->swell_curve,
3061 			.bulge = scene_frame->bulge * data->scale,
3062 			.buttons = scene_frame->buttons,
3063 			.exclusion = {
3064 				scene_frame->exclusion[0] * data->scale,
3065 				scene_frame->exclusion[1] * data->scale,
3066 				scene_frame->exclusion[2] * data->scale,
3067 				scene_frame->exclusion[3] * data->scale,
3068 			},
3069 			.hover_color = {
3070 				scene_frame->hover_color[0],
3071 				scene_frame->hover_color[1],
3072 				scene_frame->hover_color[2],
3073 				scene_frame->hover_color[3],
3074 			},
3075 			.color = {
3076 				.r = scene_frame->color[0],
3077 				.g = scene_frame->color[1],
3078 				.b = scene_frame->color[2],
3079 				.a = scene_frame->color[3],
3080 			},
3081 			.clip = &render_region,
3082 		};
3083 		fx_render_pass_add_frame(fx_pass, &frame_options);
3084 		break;
3085 	case WLR_SCENE_NODE_BEVEL:;
3086 		struct wlr_scene_bevel *scene_bevel = wlr_scene_bevel_from_node(node);
3087 
3088 		// The light direction is authored in screen space, so it has to
3089 		// follow the output transform along with the box it lights.
3090 		float bevel_dir_x = scene_bevel->light_dir[0];
3091 		float bevel_dir_y = scene_bevel->light_dir[1];
3092 		switch (node_transform) {
3093 		case WL_OUTPUT_TRANSFORM_90:
3094 			bevel_dir_x = scene_bevel->light_dir[1];
3095 			bevel_dir_y = -scene_bevel->light_dir[0];
3096 			break;
3097 		case WL_OUTPUT_TRANSFORM_180:
3098 			bevel_dir_x = -scene_bevel->light_dir[0];
3099 			bevel_dir_y = -scene_bevel->light_dir[1];
3100 			break;
3101 		case WL_OUTPUT_TRANSFORM_270:
3102 			bevel_dir_x = -scene_bevel->light_dir[1];
3103 			bevel_dir_y = scene_bevel->light_dir[0];
3104 			break;
3105 		default:
3106 			break;
3107 		}
3108 
3109 		struct fx_render_bevel_options bevel_options = {
3110 			.box = dst_box,
3111 			.corner_radius = scene_bevel->corner_radius * data->scale,
3112 			.thickness = scene_bevel->thickness * data->scale,
3113 			.light_dir = { bevel_dir_x, bevel_dir_y },
3114 			.light_intensity = scene_bevel->light_intensity,
3115 			.shade_intensity = scene_bevel->shade_intensity,
3116 			.shoulder = scene_bevel->shoulder,
3117 			.focus = scene_bevel->focus,
3118 			.focus_color = {
3119 				scene_bevel->focus_color[0],
3120 				scene_bevel->focus_color[1],
3121 				scene_bevel->focus_color[2],
3122 			},
3123 			.focus_sharpness = scene_bevel->focus_sharpness,
3124 			.color = {
3125 				.r = scene_bevel->color[0],
3126 				.g = scene_bevel->color[1],
3127 				.b = scene_bevel->color[2],
3128 				.a = scene_bevel->color[3],
3129 			},
3130 			.clip = &render_region,
3131 		};
3132 		fx_render_pass_add_bevel(fx_pass, &bevel_options);
3133 		break;
3134 	case WLR_SCENE_NODE_DROPLET:;
3135 		struct wlr_scene_droplet *scene_droplet = wlr_scene_droplet_from_node(node);
3136 
3137 		struct fx_render_droplet_options droplet_options = {
3138 			.box = dst_box,
3139 			.attach_r = scene_droplet->attach_r * data->scale,
3140 			.sheet_r = scene_droplet->sheet_r * data->scale,
3141 			.bow_rise = scene_droplet->bow_rise * data->scale,
3142 			.blend_k = scene_droplet->blend_k * data->scale,
3143 			.curve = scene_droplet->curve,
3144 			.band_px = scene_droplet->band_px * data->scale,
3145 			.refr = scene_droplet->refr * data->scale,
3146 			.ghost = scene_droplet->ghost,
3147 			.compress = {
3148 				.ceil = scene_droplet->compress_ceil,
3149 				.knee = scene_droplet->compress_knee,
3150 				.invert = scene_droplet->compress_invert,
3151 			},
3152 			.clip = &render_region,
3153 		};
3154 		fx_render_pass_add_droplet(fx_pass, &droplet_options);
3155 		break;
3156 	case WLR_SCENE_NODE_OPTIMIZED_BLUR:;
3157 		struct wlr_scene_optimized_blur *scene_blur = wlr_scene_optimized_blur_from_node(node);
3158 		// Bake (or top up) this node's cache entry. The dirty gate on a full
3159 		// bake is load-bearing: mark_dirty damages the node's whole box, so
3160 		// pass->buffer holds fresh below-node content when the bake samples
3161 		// it; strips are baked only where the node newly shows content, in
3162 		// the frame that composites it.
3163 		if (fx_pass->has_blur && is_scene_blur_enabled(&scene->blur_data)) {
3164 			optimized_blur_render(scene, scene_blur, node, fx_pass, data, dst_box);
3165 		}
3166 		break;
3167 	case WLR_SCENE_NODE_BLUR:;
3168 		struct wlr_scene_blur *blur = wlr_scene_blur_from_node(node);
3169 
3170 		struct wlr_texture *tex = NULL;
3171 		struct wlr_scene_buffer *mask = wlr_scene_blur_get_transparency_mask_source(blur);
3172 
3173 		enum wl_output_transform mask_transform = WL_OUTPUT_TRANSFORM_NORMAL;
3174 
3175 		struct wlr_fbox mask_src_box = {0};
3176 		if (mask != NULL) {
3177 			tex = scene_buffer_get_texture(mask, data->output->output->renderer);
3178 			mask_transform = wlr_output_transform_invert(mask->transform);
3179 			mask_transform = wlr_output_transform_compose(mask_transform, data->transform);
3180 			mask_src_box = mask->src_box;
3181 
3182 			// Map the blur box through the mask buffer's own geometry instead
3183 			// of stretching the whole mask texture over the blur rect: a mask
3184 			// buffer LARGER than the blur box (a client overflow rim — the
3185 			// surface extends transparently past the xdg geometry the blur is
3186 			// sized to) would otherwise squeeze its transparent rim INTO the
3187 			// box, and ignore_transparent then kills the blur in a rim-scaled
3188 			// band at the window's right/bottom. Sample exactly the sub-rect
3189 			// of the mask that overlaps the blur box, 1:1 in layout space.
3190 			// Congruent boxes (the common case) skip this and keep the
3191 			// previous full-texture mapping byte-for-byte.
3192 			if (tex != NULL) {
3193 				int mask_x, mask_y, blur_x, blur_y;
3194 				if (wlr_scene_node_coords(&mask->node, &mask_x, &mask_y) &&
3195 						wlr_scene_node_coords(node, &blur_x, &blur_y)) {
3196 					int mask_w = 0, mask_h = 0;
3197 					scene_node_get_size(&mask->node, &mask_w, &mask_h);
3198 					if (mask_w > 0 && mask_h > 0 &&
3199 							(mask_w != blur->width || mask_h != blur->height ||
3200 								mask_x != blur_x || mask_y != blur_y)) {
3201 						struct wlr_fbox full = mask_src_box;
3202 						if (full.width <= 0 || full.height <= 0) {
3203 							full = (struct wlr_fbox){
3204 								.x = 0,
3205 								.y = 0,
3206 								.width = tex->width,
3207 								.height = tex->height,
3208 							};
3209 						}
3210 						double sx = full.width / mask_w;
3211 						double sy = full.height / mask_h;
3212 						mask_src_box = (struct wlr_fbox){
3213 							.x = full.x + (blur_x - mask_x) * sx,
3214 							.y = full.y + (blur_y - mask_y) * sy,
3215 							.width = blur->width * sx,
3216 							.height = blur->height * sy,
3217 						};
3218 					}
3219 				}
3220 			}
3221 		}
3222 
3223 		struct fx_corner_radii blur_corners = blur->corners;
3224 		fx_corner_radii_transform(node_transform, &blur_corners);
3225 
3226 		// Sample the shared cache at this node's own bake: the sibling
3227 		// optimized node's anchor (its coordinates at its last full bake)
3228 		// plus the cache margin. The optimized node, rendered just before
3229 		// this one, has already baked whatever the node newly shows.
3230 		int cache_mx = 0, cache_my = 0;
3231 		if (fx_pass->fx_offscreen_buffers) {
3232 			cache_mx = fx_pass->fx_offscreen_buffers->cache_margin_x;
3233 			cache_my = fx_pass->fx_offscreen_buffers->cache_margin_y;
3234 		}
3235 		int shift_x = cache_mx, shift_y = cache_my;
3236 		if (blur->should_only_blur_bottom_layer &&
3237 				data->transform == WL_OUTPUT_TRANSFORM_NORMAL && node->parent) {
3238 			struct wlr_scene_node *sib;
3239 			wl_list_for_each(sib, &node->parent->children, link) {
3240 				if (sib->type != WLR_SCENE_NODE_OPTIMIZED_BLUR) {
3241 					continue;
3242 				}
3243 				struct wlr_scene_optimized_blur *opt = wlr_scene_optimized_blur_from_node(sib);
3244 				int cur_x, cur_y;
3245 				if (opt->baked && opt->baked_output == data->output &&
3246 						wlr_scene_node_coords(sib, &cur_x, &cur_y)) {
3247 					shift_x += (int)round((opt->baked_x - cur_x) * data->scale);
3248 					shift_y += (int)round((opt->baked_y - cur_y) * data->scale);
3249 				}
3250 				break;
3251 			}
3252 		}
3253 
3254 		struct fx_render_blur_pass_options blur_options = {
3255 			.tex_options = {
3256 				.base = (struct wlr_render_texture_options) {
3257 					.texture = tex,
3258 					.src_box = mask_src_box,
3259 					.dst_box = dst_box,
3260 					.transform = mask_transform,
3261 					.clip = &render_region,
3262 					.alpha = &blur->alpha,
3263 					.filter_mode = WLR_SCALE_FILTER_BILINEAR,
3264 					.blend_mode = WLR_RENDER_BLEND_MODE_PREMULTIPLIED,
3265 				},
3266 				.clip_box = &dst_box,
3267 				.corners = fx_corner_radii_scale(blur_corners, data->scale),
3268 				.discard_transparent = false,
3269 				.compress = {
3270 					.ceil = blur->compress_ceil,
3271 					.knee = blur->compress_knee,
3272 					.invert = blur->compress_invert,
3273 				},
3274 			},
3275 			.use_optimized_blur = blur->should_only_blur_bottom_layer,
3276 			.blur_data = &scene->blur_data,
3277 			.ignore_transparent = mask != NULL,
3278 			.blur_strength = blur->strength,
3279 			// Frozen cache: sample at this node's own delta since the freeze
3280 			// (layout px -> buffer px), so it reads its own bake. Only
3281 			// meaningful for an untransformed output; a rotated one gets
3282 			// the unshifted cache.
3283 			.cache_shift_x = shift_x,
3284 			.cache_shift_y = shift_y,
3285 		};
3286 		fx_render_pass_add_blur(fx_pass, &blur_options);
3287 		break;
3288 	}
3289 
3290 	pixman_region32_fini(&opaque);
3291 	pixman_region32_fini(&render_region);
3292 }
3293 
3294 static void scene_handle_linux_dmabuf_v1_destroy(struct wl_listener *listener,
3295 		void *data) {
3296 	struct wlr_scene *scene =
3297 		wl_container_of(listener, scene, linux_dmabuf_v1_destroy);
3298 	wl_list_remove(&scene->linux_dmabuf_v1_destroy.link);
3299 	wl_list_init(&scene->linux_dmabuf_v1_destroy.link);
3300 	scene->linux_dmabuf_v1 = NULL;
3301 }
3302 
3303 void wlr_scene_set_linux_dmabuf_v1(struct wlr_scene *scene,
3304 		struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1) {
3305 	assert(scene->linux_dmabuf_v1 == NULL);
3306 	scene->linux_dmabuf_v1 = linux_dmabuf_v1;
3307 	scene->linux_dmabuf_v1_destroy.notify = scene_handle_linux_dmabuf_v1_destroy;
3308 	wl_signal_add(&linux_dmabuf_v1->events.destroy, &scene->linux_dmabuf_v1_destroy);
3309 }
3310 
3311 static void scene_handle_gamma_control_manager_v1_set_gamma(struct wl_listener *listener,
3312 		void *data) {
3313 	const struct wlr_gamma_control_manager_v1_set_gamma_event *event = data;
3314 	struct wlr_scene *scene =
3315 		wl_container_of(listener, scene, gamma_control_manager_v1_set_gamma);
3316 	struct wlr_scene_output *output = wlr_scene_get_scene_output(scene, event->output);
3317 	if (!output) {
3318 		// this scene might not own this output.
3319 		return;
3320 	}
3321 
3322 	output->gamma_lut_changed = true;
3323 	output->gamma_lut = event->control;
3324 	wlr_color_transform_unref(output->gamma_lut_color_transform);
3325 	output->gamma_lut_color_transform = wlr_gamma_control_v1_get_color_transform(event->control);
3326 	wlr_output_schedule_frame(output->output);
3327 }
3328 
3329 static void scene_handle_gamma_control_manager_v1_destroy(struct wl_listener *listener,
3330 		void *data) {
3331 	struct wlr_scene *scene =
3332 		wl_container_of(listener, scene, gamma_control_manager_v1_destroy);
3333 	wl_list_remove(&scene->gamma_control_manager_v1_destroy.link);
3334 	wl_list_init(&scene->gamma_control_manager_v1_destroy.link);
3335 	wl_list_remove(&scene->gamma_control_manager_v1_set_gamma.link);
3336 	wl_list_init(&scene->gamma_control_manager_v1_set_gamma.link);
3337 	scene->gamma_control_manager_v1 = NULL;
3338 
3339 	struct wlr_scene_output *output;
3340 	wl_list_for_each(output, &scene->outputs, link) {
3341 		output->gamma_lut_changed = false;
3342 		output->gamma_lut = NULL;
3343 		wlr_color_transform_unref(output->gamma_lut_color_transform);
3344 		output->gamma_lut_color_transform = NULL;
3345 	}
3346 }
3347 
3348 void wlr_scene_set_gamma_control_manager_v1(struct wlr_scene *scene,
3349 	    struct wlr_gamma_control_manager_v1 *gamma_control) {
3350 	assert(scene->gamma_control_manager_v1 == NULL);
3351 	scene->gamma_control_manager_v1 = gamma_control;
3352 
3353 	scene->gamma_control_manager_v1_destroy.notify =
3354 		scene_handle_gamma_control_manager_v1_destroy;
3355 	wl_signal_add(&gamma_control->events.destroy, &scene->gamma_control_manager_v1_destroy);
3356 	scene->gamma_control_manager_v1_set_gamma.notify =
3357 		scene_handle_gamma_control_manager_v1_set_gamma;
3358 	wl_signal_add(&gamma_control->events.set_gamma, &scene->gamma_control_manager_v1_set_gamma);
3359 }
3360 
3361 static void scene_handle_color_manager_v1_destroy(struct wl_listener *listener, void *data) {
3362 	struct wlr_scene *scene = wl_container_of(listener, scene, color_manager_v1_destroy);
3363 	wl_list_remove(&scene->color_manager_v1_destroy.link);
3364 	wl_list_init(&scene->color_manager_v1_destroy.link);
3365 	scene->color_manager_v1 = NULL;
3366 }
3367 
3368 void wlr_scene_set_color_manager_v1(struct wlr_scene *scene, struct wlr_color_manager_v1 *manager) {
3369 	assert(scene->color_manager_v1 == NULL);
3370 	scene->color_manager_v1 = manager;
3371 
3372 	scene->color_manager_v1_destroy.notify = scene_handle_color_manager_v1_destroy;
3373 	wl_signal_add(&manager->events.destroy, &scene->color_manager_v1_destroy);
3374 }
3375 
3376 static void scene_output_handle_destroy(struct wlr_addon *addon) {
3377 	struct wlr_scene_output *scene_output =
3378 		wl_container_of(addon, scene_output, addon);
3379 	wlr_scene_output_destroy(scene_output);
3380 }
3381 
3382 static const struct wlr_addon_interface output_addon_impl = {
3383 	.name = "wlr_scene_output",
3384 	.destroy = scene_output_handle_destroy,
3385 };
3386 
3387 static void scene_node_output_update(struct wlr_scene_node *node,
3388 		struct wl_list *outputs, struct wlr_scene_output *ignore,
3389 		struct wlr_scene_output *force) {
3390 	if (node->type == WLR_SCENE_NODE_TREE) {
3391 		struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
3392 		struct wlr_scene_node *child;
3393 		wl_list_for_each(child, &scene_tree->children, link) {
3394 			scene_node_output_update(child, outputs, ignore, force);
3395 		}
3396 		return;
3397 	}
3398 
3399 	update_node_update_outputs(node, outputs, ignore, force);
3400 }
3401 
3402 static void scene_output_update_geometry(struct wlr_scene_output *scene_output,
3403 		bool force_update) {
3404 	scene_output_damage_whole(scene_output);
3405 
3406 	scene_node_output_update(&scene_output->scene->tree.node,
3407 			&scene_output->scene->outputs, NULL, force_update ? scene_output : NULL);
3408 }
3409 
3410 static void scene_output_handle_commit(struct wl_listener *listener, void *data) {
3411 	struct wlr_scene_output *scene_output = wl_container_of(listener,
3412 		scene_output, output_commit);
3413 	struct wlr_output_event_commit *event = data;
3414 	const struct wlr_output_state *state = event->state;
3415 
3416 	// if the output has been committed with a certain damage, we know that region
3417 	// will be acknowledged by the backend so we don't need to keep track of it
3418 	// anymore
3419 	if (state->committed & WLR_OUTPUT_STATE_BUFFER) {
3420 		if (state->committed & WLR_OUTPUT_STATE_DAMAGE) {
3421 			pixman_region32_subtract(&scene_output->pending_commit_damage,
3422 				&scene_output->pending_commit_damage, &state->damage);
3423 		} else {
3424 			pixman_region32_fini(&scene_output->pending_commit_damage);
3425 			pixman_region32_init(&scene_output->pending_commit_damage);
3426 		}
3427 	}
3428 
3429 	bool force_update = state->committed & (
3430 		WLR_OUTPUT_STATE_TRANSFORM |
3431 		WLR_OUTPUT_STATE_SCALE |
3432 		WLR_OUTPUT_STATE_SUBPIXEL);
3433 
3434 	if (force_update || state->committed & (WLR_OUTPUT_STATE_MODE |
3435 			WLR_OUTPUT_STATE_ENABLED)) {
3436 		scene_output_update_geometry(scene_output, force_update);
3437 	}
3438 
3439 	if (scene_output->scene->debug_damage_option == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT &&
3440 			!wl_list_empty(&scene_output->damage_highlight_regions)) {
3441 		wlr_output_schedule_frame(scene_output->output);
3442 	}
3443 
3444 	TRACY_WHEN_CONNECTED({
3445 		// Queue a new frame as soon as possible when profiling
3446 		wlr_output_schedule_frame(scene_output->output);
3447 	})
3448 
3449 	// Next time the output is enabled, try to re-apply the gamma LUT
3450 	if (scene_output->scene->gamma_control_manager_v1 &&
3451 			(state->committed & WLR_OUTPUT_STATE_ENABLED) &&
3452 			!scene_output->output->enabled) {
3453 		scene_output->gamma_lut_changed = true;
3454 	}
3455 }
3456 
3457 static void scene_output_handle_damage(struct wl_listener *listener, void *data) {
3458 	struct wlr_scene_output *scene_output = wl_container_of(listener,
3459 		scene_output, output_damage);
3460 	struct wlr_output *output = scene_output->output;
3461 	struct wlr_output_event_damage *event = data;
3462 
3463 	int width, height;
3464 	wlr_output_transformed_resolution(output, &width, &height);
3465 
3466 	pixman_region32_t damage;
3467 	pixman_region32_init(&damage);
3468 	pixman_region32_copy(&damage, event->damage);
3469 	wlr_region_transform(&damage, &damage,
3470 		wlr_output_transform_invert(output->transform), width, height);
3471 	scene_output_damage(scene_output, &damage);
3472 	pixman_region32_fini(&damage);
3473 }
3474 
3475 static void scene_output_handle_needs_frame(struct wl_listener *listener, void *data) {
3476 	struct wlr_scene_output *scene_output = wl_container_of(listener,
3477 		scene_output, output_needs_frame);
3478 	wlr_output_schedule_frame(scene_output->output);
3479 }
3480 
3481 struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene,
3482 		struct wlr_output *output) {
3483 	struct wlr_scene_output *scene_output = calloc(1, sizeof(*scene_output));
3484 	if (scene_output == NULL) {
3485 		return NULL;
3486 	}
3487 
3488 	scene_output->output = output;
3489 	scene_output->scene = scene;
3490 	wlr_addon_init(&scene_output->addon, &output->addons, scene, &output_addon_impl);
3491 
3492 	wlr_damage_ring_init(&scene_output->damage_ring);
3493 	pixman_region32_init(&scene_output->pending_commit_damage);
3494 	wl_list_init(&scene_output->damage_highlight_regions);
3495 
3496 	int prev_output_index = -1;
3497 	struct wl_list *prev_output_link = &scene->outputs;
3498 
3499 	struct wlr_scene_output *current_output;
3500 	wl_list_for_each(current_output, &scene->outputs, link) {
3501 		if (prev_output_index + 1 != current_output->index) {
3502 			break;
3503 		}
3504 
3505 		prev_output_index = current_output->index;
3506 		prev_output_link = &current_output->link;
3507 	}
3508 
3509 	int drm_fd = wlr_backend_get_drm_fd(output->backend);
3510 	if (drm_fd >= 0 && output->backend->features.timeline &&
3511 			output->renderer != NULL && output->renderer->features.timeline) {
3512 		scene_output->in_timeline = wlr_drm_syncobj_timeline_create(drm_fd);
3513 		scene_output->out_timeline = wlr_drm_syncobj_timeline_create(drm_fd);
3514 		if (scene_output->in_timeline == NULL || scene_output->out_timeline == NULL) {
3515 			wlr_drm_syncobj_timeline_unref(scene_output->in_timeline);
3516 			wlr_drm_syncobj_timeline_unref(scene_output->out_timeline);
3517 			return NULL;
3518 		}
3519 	}
3520 
3521 	scene_output->index = prev_output_index + 1;
3522 	assert(scene_output->index < 64);
3523 	wl_list_insert(prev_output_link, &scene_output->link);
3524 
3525 	wl_signal_init(&scene_output->events.destroy);
3526 
3527 	scene_output->output_commit.notify = scene_output_handle_commit;
3528 	wl_signal_add(&output->events.commit, &scene_output->output_commit);
3529 
3530 	scene_output->output_damage.notify = scene_output_handle_damage;
3531 	wl_signal_add(&output->events.damage, &scene_output->output_damage);
3532 
3533 	scene_output->output_needs_frame.notify = scene_output_handle_needs_frame;
3534 	wl_signal_add(&output->events.needs_frame, &scene_output->output_needs_frame);
3535 
3536 	scene_output_update_geometry(scene_output, false);
3537 
3538 	return scene_output;
3539 }
3540 
3541 static void highlight_region_destroy(struct highlight_region *damage) {
3542 	wl_list_remove(&damage->link);
3543 	pixman_region32_fini(&damage->region);
3544 	free(damage);
3545 }
3546 
3547 void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) {
3548 	if (scene_output == NULL) {
3549 		return;
3550 	}
3551 
3552 	wl_signal_emit_mutable(&scene_output->events.destroy, NULL);
3553 
3554 	scene_node_output_update(&scene_output->scene->tree.node,
3555 		&scene_output->scene->outputs, scene_output, NULL);
3556 
3557 	assert(wl_list_empty(&scene_output->events.destroy.listener_list));
3558 
3559 	struct highlight_region *damage, *tmp_damage;
3560 	wl_list_for_each_safe(damage, tmp_damage, &scene_output->damage_highlight_regions, link) {
3561 		highlight_region_destroy(damage);
3562 	}
3563 
3564 	wlr_addon_finish(&scene_output->addon);
3565 	wlr_damage_ring_finish(&scene_output->damage_ring);
3566 	pixman_region32_fini(&scene_output->pending_commit_damage);
3567 	wl_list_remove(&scene_output->link);
3568 	wl_list_remove(&scene_output->output_commit.link);
3569 	wl_list_remove(&scene_output->output_damage.link);
3570 	wl_list_remove(&scene_output->output_needs_frame.link);
3571 	if (scene_output->in_timeline != NULL) {
3572 		wlr_drm_syncobj_timeline_signal(scene_output->in_timeline, UINT64_MAX);
3573 		wlr_drm_syncobj_timeline_unref(scene_output->in_timeline);
3574 	}
3575 	if (scene_output->out_timeline != NULL) {
3576 		wlr_drm_syncobj_timeline_signal(scene_output->out_timeline, UINT64_MAX);
3577 		wlr_drm_syncobj_timeline_unref(scene_output->out_timeline);
3578 	}
3579 	wlr_color_transform_unref(scene_output->gamma_lut_color_transform);
3580 	wlr_color_transform_unref(scene_output->prev_gamma_lut_color_transform);
3581 	wlr_color_transform_unref(scene_output->prev_supplied_color_transform);
3582 	wlr_color_transform_unref(scene_output->combined_color_transform);
3583 	wl_array_release(&scene_output->render_list);
3584 	free(scene_output);
3585 }
3586 
3587 struct wlr_scene_output *wlr_scene_get_scene_output(struct wlr_scene *scene,
3588 		struct wlr_output *output) {
3589 	struct wlr_addon *addon =
3590 		wlr_addon_find(&output->addons, scene, &output_addon_impl);
3591 	if (addon == NULL) {
3592 		return NULL;
3593 	}
3594 	struct wlr_scene_output *scene_output =
3595 		wl_container_of(addon, scene_output, addon);
3596 	return scene_output;
3597 }
3598 
3599 void wlr_scene_output_set_position(struct wlr_scene_output *scene_output,
3600 		int lx, int ly) {
3601 	if (scene_output->x == lx && scene_output->y == ly) {
3602 		return;
3603 	}
3604 
3605 	scene_output->x = lx;
3606 	scene_output->y = ly;
3607 
3608 	scene_output_update_geometry(scene_output, false);
3609 }
3610 
3611 static bool scene_node_invisible(struct wlr_scene_node *node) {
3612 	if (node->type == WLR_SCENE_NODE_TREE) {
3613 		return true;
3614 	} else if (node->type == WLR_SCENE_NODE_RECT) {
3615 		struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
3616 		// TODO: Check if clipped region covers whole rect?
3617 		return rect->color[3] == 0.f;
3618 	} else if (node->type == WLR_SCENE_NODE_BUFFER) {
3619 		struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
3620 
3621 		return buffer->buffer == NULL && buffer->texture == NULL;
3622 	} else if (node->type == WLR_SCENE_NODE_SHADOW) {
3623 		struct wlr_scene_shadow *shadow = wlr_scene_shadow_from_node(node);
3624 
3625 		return shadow->color[3] == 0.f;
3626 	} else if (node->type == WLR_SCENE_NODE_BEVEL) {
3627 		struct wlr_scene_bevel *bevel = wlr_scene_bevel_from_node(node);
3628 
3629 		return bevel->color[3] == 0.f || bevel->thickness <= 0.f;
3630 	} else if (node->type == WLR_SCENE_NODE_FRAME) {
3631 		struct wlr_scene_frame *frame = wlr_scene_frame_from_node(node);
3632 
3633 		return frame->color[3] == 0.f || frame->band <= 0.f;
3634 	}
3635 
3636 	return false;
3637 }
3638 
3639 struct render_list_constructor_data {
3640 	struct wlr_box box;
3641 	struct wl_array *render_list;
3642 	bool calculate_visibility;
3643 	bool highlight_transparent_region;
3644 	bool fractional_scale;
3645 };
3646 
3647 static bool scene_buffer_is_black_opaque(struct wlr_scene_buffer *scene_buffer) {
3648 	return scene_buffer->is_single_pixel_buffer &&
3649 		scene_buffer->single_pixel_buffer_color[0] == 0 &&
3650 		scene_buffer->single_pixel_buffer_color[1] == 0 &&
3651 		scene_buffer->single_pixel_buffer_color[2] == 0 &&
3652 		scene_buffer->single_pixel_buffer_color[3] == UINT32_MAX &&
3653 		scene_buffer->opacity == 1.0 &&
3654 		fx_corner_radii_is_empty(&scene_buffer->corners);
3655 }
3656 
3657 static bool scene_rect_is_black_opaque(struct wlr_scene_rect *scene_rect) {
3658 	return scene_rect->color[0] == 0.f &&
3659 		scene_rect->color[1] == 0.f &&
3660 		scene_rect->color[2] == 0.f &&
3661 		scene_rect->color[3] == 1.f &&
3662 		scene_rect->fade_inset == 0 &&
3663 		fx_corner_radii_is_empty(&scene_rect->corners) &&
3664 		fx_corner_radii_is_empty(&scene_rect->clipped_region.corners) &&
3665 		wlr_box_empty(&scene_rect->clipped_region.area);
3666 }
3667 
3668 static bool construct_render_list_iterator(struct wlr_scene_node *node,
3669 		int lx, int ly, void *_data) {
3670 	struct render_list_constructor_data *data = _data;
3671 
3672 	if (scene_node_invisible(node)) {
3673 		return false;
3674 	}
3675 
3676 	// While rendering, the background should always be black. If we see a
3677 	// black rect, we can ignore rendering everything under the rect, and
3678 	// unless fractional scale is used even the rect itself (to avoid running
3679 	// into issues regarding damage region expansion).
3680 	if (node->type == WLR_SCENE_NODE_RECT && data->calculate_visibility &&
3681 			(!data->fractional_scale || data->render_list->size == 0)) {
3682 		struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
3683 
3684 		if (scene_rect_is_black_opaque(rect)) {
3685 			return false;
3686 		}
3687 	}
3688 
3689 	// Apply the same special-case to black opaque single-pixel buffers
3690 	if (node->type == WLR_SCENE_NODE_BUFFER && data->calculate_visibility &&
3691 			(!data->fractional_scale || data->render_list->size == 0)) {
3692 		struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
3693 
3694 		if (scene_buffer_is_black_opaque(scene_buffer)) {
3695 			return false;
3696 		}
3697 	}
3698 
3699 	pixman_region32_t intersection;
3700 	pixman_region32_init(&intersection);
3701 	pixman_region32_intersect_rect(&intersection, &node->visible,
3702 			data->box.x, data->box.y,
3703 			data->box.width, data->box.height);
3704 	if (pixman_region32_empty(&intersection)) {
3705 		pixman_region32_fini(&intersection);
3706 		return false;
3707 	}
3708 
3709 	pixman_region32_fini(&intersection);
3710 
3711 	struct render_list_entry *entry = wl_array_add(data->render_list, sizeof(*entry));
3712 	if (!entry) {
3713 		return false;
3714 	}
3715 
3716 	*entry = (struct render_list_entry){
3717 		.node = node,
3718 		.x = lx,
3719 		.y = ly,
3720 		.highlight_transparent_region = data->highlight_transparent_region,
3721 	};
3722 
3723 	return false;
3724 }
3725 
3726 static void scene_buffer_send_dmabuf_feedback(const struct wlr_scene *scene,
3727 		struct wlr_scene_buffer *scene_buffer,
3728 		const struct wlr_linux_dmabuf_feedback_v1_init_options *options) {
3729 	if (!scene->linux_dmabuf_v1) {
3730 		return;
3731 	}
3732 
3733 	struct wlr_scene_surface *surface = wlr_scene_surface_try_from_buffer(scene_buffer);
3734 	if (!surface) {
3735 		return;
3736 	}
3737 
3738 	// compare to the previous options so that we don't send
3739 	// duplicate feedback events.
3740 	if (memcmp(options, &scene_buffer->prev_feedback_options, sizeof(*options)) == 0) {
3741 		return;
3742 	}
3743 
3744 	scene_buffer->prev_feedback_options = *options;
3745 
3746 	// One line per feedback that actually goes out (the memcmp above having
3747 	// found a real change). Each carries an fd to the client, so a burst here
3748 	// is the fd-exhaustion signature: `grep -c 'dmabuf feedback sent'`.
3749 	wlr_log(WLR_DEBUG, "dmabuf feedback sent (scanout_output=%p)",
3750 		(void *)options->scanout_primary_output);
3751 
3752 	struct wlr_linux_dmabuf_feedback_v1 feedback = {0};
3753 	if (!wlr_linux_dmabuf_feedback_v1_init_with_options(&feedback, options)) {
3754 		return;
3755 	}
3756 
3757 	enum wl_output_transform preferred_buffer_transform = WL_OUTPUT_TRANSFORM_NORMAL;
3758 	if (options->scanout_primary_output != NULL) {
3759 		preferred_buffer_transform = options->scanout_primary_output->transform;
3760 	}
3761 
3762 	// TODO: also send wl_surface.preferred_buffer_transform when running with
3763 	// pure software rendering
3764 	wlr_surface_set_preferred_buffer_transform(surface->surface, preferred_buffer_transform);
3765 	wlr_linux_dmabuf_v1_set_surface_feedback(scene->linux_dmabuf_v1,
3766 		surface->surface, &feedback);
3767 
3768 	wlr_linux_dmabuf_feedback_v1_finish(&feedback);
3769 }
3770 
3771 static bool color_management_is_scanout_allowed(const struct wlr_output_image_description *img_desc,
3772 		const struct wlr_scene_buffer *buffer) {
3773 	// Disallow scanout if the output has colorimetry information but buffer
3774 	// doesn't; allow it only if the output also lacks it.
3775 	if (buffer->transfer_function == 0 && buffer->primaries == 0) {
3776 		return img_desc == NULL;
3777 	}
3778 
3779 	// If the output has colorimetry information, the buffer must match it for
3780 	// direct scanout to be allowed.
3781 	if (img_desc != NULL) {
3782 		return img_desc->transfer_function == buffer->transfer_function &&
3783 				img_desc->primaries == buffer->primaries;
3784 	}
3785 	// If the output doesn't have colorimetry image description set, we can only
3786 	// scan out buffers with default colorimetry (gamma2.2 transfer and sRGB
3787 	// primaries) used in wlroots.
3788 	return buffer->transfer_function == WLR_COLOR_TRANSFER_FUNCTION_GAMMA22 &&
3789 			buffer->primaries == WLR_COLOR_NAMED_PRIMARIES_SRGB;
3790 }
3791 
3792 enum scene_direct_scanout_result {
3793 	// This scene node is not a candidate for scanout
3794 	SCANOUT_INELIGIBLE,
3795 
3796 	// This scene node is a candidate for scanout, but is currently
3797 	// incompatible due to e.g. buffer mismatch, and if possible we'd like to
3798 	// resolve this incompatibility.
3799 	SCANOUT_CANDIDATE,
3800 
3801 	// Scanout is successful.
3802 	SCANOUT_SUCCESS,
3803 };
3804 
3805 static enum scene_direct_scanout_result scene_entry_try_direct_scanout(
3806 		struct render_list_entry *entry, struct wlr_output_state *state,
3807 		const struct render_data *data) {
3808 	struct wlr_scene_output *scene_output = data->output;
3809 	struct wlr_scene_node *node = entry->node;
3810 
3811 	if (!scene_output->scene->direct_scanout) {
3812 		return SCANOUT_INELIGIBLE;
3813 	}
3814 
3815 	if (node->type != WLR_SCENE_NODE_BUFFER) {
3816 		return SCANOUT_INELIGIBLE;
3817 	}
3818 
3819 	// A desk node drawn with a sub-pixel shift is not where its buffer
3820 	// would be scanned out.
3821 	{
3822 		int dx, dy;
3823 		scene_desk_offset_px(scene_output->scene, data->scale, data->transform, &dx, &dy);
3824 		if ((dx != 0 || dy != 0) && scene_node_has_desk_offset(scene_output->scene, node)) {
3825 			return SCANOUT_INELIGIBLE;
3826 		}
3827 	}
3828 
3829 	if (state->committed & (WLR_OUTPUT_STATE_MODE |
3830 			WLR_OUTPUT_STATE_ENABLED |
3831 			WLR_OUTPUT_STATE_RENDER_FORMAT)) {
3832 		// Legacy DRM will explode if we try to modeset with a direct scanout buffer
3833 		return SCANOUT_INELIGIBLE;
3834 	}
3835 
3836 	if (!wlr_output_is_direct_scanout_allowed(scene_output->output)) {
3837 		return SCANOUT_INELIGIBLE;
3838 	}
3839 
3840 	struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
3841 	if (buffer->buffer == NULL) {
3842 		return SCANOUT_INELIGIBLE;
3843 	}
3844 
3845 	// The native size of the buffer after any transform is applied
3846 	int default_width = buffer->buffer->width;
3847 	int default_height = buffer->buffer->height;
3848 	wlr_output_transform_coords(buffer->transform, &default_width, &default_height);
3849 	struct wlr_fbox default_box = {
3850 		.width = default_width,
3851 		.height = default_height,
3852 	};
3853 
3854 	if (buffer->transform != data->transform) {
3855 		return SCANOUT_INELIGIBLE;
3856 	}
3857 
3858 	const struct wlr_output_image_description *img_desc = output_pending_image_description(scene_output->output, state);
3859 	if (!color_management_is_scanout_allowed(img_desc, buffer)) {
3860 		return SCANOUT_INELIGIBLE;
3861 	}
3862 
3863 	bool is_color_repr_none = buffer->color_encoding == WLR_COLOR_ENCODING_NONE &&
3864 			buffer->color_range == WLR_COLOR_RANGE_NONE;
3865 	bool is_color_repr_identity_full = buffer->color_encoding == WLR_COLOR_ENCODING_IDENTITY &&
3866 			buffer->color_range == WLR_COLOR_RANGE_FULL;
3867 
3868 	if (!(is_color_repr_none || is_color_repr_identity_full)) {
3869 		return SCANOUT_INELIGIBLE;
3870 	}
3871 
3872 	// We want to ensure optimal buffer selection, but as direct-scanout can be enabled and disabled
3873 	// on a frame-by-frame basis, we wait for a few frames to send the new format recommendations.
3874 	// Maybe we should only send feedback in this case if tests fail.
3875 	if (scene_output->dmabuf_feedback_debounce >= DMABUF_FEEDBACK_DEBOUNCE_FRAMES
3876 			&& buffer->primary_output == scene_output) {
3877 		struct wlr_linux_dmabuf_feedback_v1_init_options options = {
3878 			.main_renderer = scene_output->output->renderer,
3879 			.scanout_primary_output = scene_output->output,
3880 		};
3881 
3882 		scene_buffer_send_dmabuf_feedback(scene_output->scene, buffer, &options);
3883 	}
3884 
3885 	struct wlr_output_state pending;
3886 	wlr_output_state_init(&pending);
3887 	if (!wlr_output_state_copy(&pending, state)) {
3888 		return SCANOUT_CANDIDATE;
3889 	}
3890 
3891 	if (!wlr_fbox_empty(&buffer->src_box) &&
3892 			!wlr_fbox_equal(&buffer->src_box, &default_box)) {
3893 		pending.buffer_src_box = buffer->src_box;
3894 	}
3895 
3896 	// Translate the position from scene coordinates to output coordinates
3897 	pending.buffer_dst_box.x = entry->x - scene_output->x;
3898 	pending.buffer_dst_box.y = entry->y - scene_output->y;
3899 
3900 	scene_node_get_size(node, &pending.buffer_dst_box.width, &pending.buffer_dst_box.height);
3901 	transform_output_box(&pending.buffer_dst_box, data);
3902 
3903 	struct wlr_buffer *wlr_buffer = buffer->buffer;
3904 	struct wlr_client_buffer *client_buffer = wlr_client_buffer_get(wlr_buffer);
3905 	if (client_buffer != NULL && client_buffer->source != NULL && client_buffer->source->n_locks > 0) {
3906 		wlr_buffer = client_buffer->source;
3907 	}
3908 
3909 	wlr_output_state_set_buffer(&pending, wlr_buffer);
3910 	if (buffer->wait_timeline != NULL) {
3911 		wlr_output_state_set_wait_timeline(&pending, buffer->wait_timeline, buffer->wait_point);
3912 	}
3913 
3914 	if (scene_output->out_timeline) {
3915 		scene_output->out_point++;
3916 		wlr_output_state_set_signal_timeline(&pending, scene_output->out_timeline, scene_output->out_point);
3917 	}
3918 
3919 	if (!wlr_output_test_state(scene_output->output, &pending)) {
3920 		wlr_output_state_finish(&pending);
3921 		return SCANOUT_CANDIDATE;
3922 	}
3923 
3924 	wlr_output_state_copy(state, &pending);
3925 	wlr_output_state_finish(&pending);
3926 
3927 	struct wlr_scene_output_sample_event sample_event = {
3928 		.output = scene_output,
3929 		.direct_scanout = true,
3930 		.release_timeline = data->output->out_timeline,
3931 		.release_point = data->output->out_point,
3932 	};
3933 	wl_signal_emit_mutable(&buffer->events.output_sample, &sample_event);
3934 	return SCANOUT_SUCCESS;
3935 }
3936 
3937 bool wlr_scene_output_needs_frame(struct wlr_scene_output *scene_output) {
3938 	return scene_output->output->needs_frame ||
3939 		!pixman_region32_empty(&scene_output->pending_commit_damage) ||
3940 		scene_output->gamma_lut_changed;
3941 }
3942 
3943 static bool should_blur_node_extend_damage(struct wlr_scene_node *node,
3944 		struct fx_gles_render_pass *fx_pass, struct blur_data *blur_data) {
3945 	switch (node->type) {
3946 	case WLR_SCENE_NODE_BLUR:;
3947 		struct wlr_scene_blur *blur_node = wlr_scene_blur_from_node(node);
3948 		// No artifact prevention needed when the whole blur is already
3949 		// rendered
3950 		if (blur_node->should_only_blur_bottom_layer && blur_node->strength == 1.0) {
3951 			fx_pass->has_blur = true;
3952 			return false;
3953 		}
3954 		// Apply the blur strength to avoid rendering more blur than
3955 		// what's needed
3956 		if (blur_node->strength < 1.0f) {
3957 			*blur_data = blur_data_apply_strength(blur_data, blur_node->strength);
3958 		}
3959 		break;
3960 	case WLR_SCENE_NODE_OPTIMIZED_BLUR:;
3961 		struct wlr_scene_optimized_blur *optimized_node =
3962 			wlr_scene_optimized_blur_from_node(node);
3963 		if (!optimized_node->dirty) {
3964 			return false;
3965 		}
3966 		break;
3967 	case WLR_SCENE_NODE_DROPLET:;
3968 		// The droplet lens samples the frame-so-far around itself, so it has
3969 		// the same stale-sample problem the blur comment below describes:
3970 		// partial damage under or NEAR the drop leaves neighboring pixels
3971 		// holding last frame's final composite (including the drop's own
3972 		// output), and re-rendering only the damaged sliver bakes those into
3973 		// part of the lens while the rest keeps the old frame — which is
3974 		// exactly the visible/invisible flashing on segments whose text
3975 		// ticks (clock, battery). Whole-node re-render, independent of the
3976 		// scene blur config.
3977 		struct wlr_scene_droplet *droplet_node = wlr_scene_droplet_from_node(node);
3978 		if (droplet_node->refr <= 0.0f && droplet_node->ghost <= 0.0f) {
3979 			return false;
3980 		}
3981 		return true;
3982 	default:
3983 		return false;
3984 	}
3985 
3986 	return is_scene_blur_enabled(blur_data);
3987 }
3988 
3989 static bool apply_blur_region(struct wlr_scene_node *node, struct blur_data *blur_data,
3990 		struct render_data *render_data, struct wlr_output_state *output_state,
3991 		const pixman_region32_t *original_damage, pixman_region32_t *blur_padding_region) {
3992 	bool should_compensate_blur = false;
3993 	int sample_size = blur_data_calc_size(blur_data);
3994 	if (node->type == WLR_SCENE_NODE_DROPLET) {
3995 		// The droplet's sampling reach: rim refraction plus the inverted
3996 		// ghost's span (0.35 x the box about its center) — the same margin
3997 		// fx_render_pass_add_droplet copies. Node fields are logical px.
3998 		struct wlr_scene_droplet *droplet = wlr_scene_droplet_from_node(node);
3999 		int dim = droplet->width > droplet->height ? droplet->width : droplet->height;
4000 		sample_size = (int)((droplet->refr + 1.0f + 0.35f * (float)dim)
4001 				* render_data->scale) + 1;
4002 	}
4003 
4004 	pixman_region32_t node_visible_region;
4005 	pixman_region32_init(&node_visible_region);
4006 	pixman_region32_copy(&node_visible_region, &node->visible);
4007 	pixman_region32_translate(&node_visible_region, -render_data->output->x, -render_data->output->y);
4008 	logical_to_buffer_coords(&node_visible_region, render_data, false);
4009 
4010 	pixman_region32_t expanded_damage;
4011 	pixman_region32_init(&expanded_damage);
4012 	wlr_region_expand(&expanded_damage, original_damage, sample_size);
4013 
4014 	pixman_region32_t intersection;
4015 	pixman_region32_init(&intersection);
4016 	pixman_region32_intersect(&intersection, &expanded_damage, &node_visible_region);
4017 	// pixman_region32_intersect's return value reports allocation success,
4018 	// not a non-empty result — testing it here made EVERY blur node count as
4019 	// touched by EVERY frame's damage, so all of them re-blurred (and pulled
4020 	// their whole box into the damage) whenever anything on screen changed:
4021 	// one animating window cost a full re-blur of every status segment and
4022 	// translucent window each frame. Only a node the expanded damage
4023 	// actually reaches has stale samples to worry about.
4024 	if (pixman_region32_not_empty(&intersection)) {
4025 		should_compensate_blur = true;
4026 		if (cce_scene_blur_debug()) {
4027 			const pixman_box32_t *nv = pixman_region32_extents(&node_visible_region);
4028 			const pixman_box32_t *od = pixman_region32_extents(original_damage);
4029 			wlr_log(WLR_INFO, "[scenefx] blur_region: type=%d sample=%d node=(%d,%d)-(%d,%d) orig=(%d,%d)-(%d,%d)",
4030 				node->type, sample_size, nv->x1, nv->y1, nv->x2, nv->y2,
4031 				od->x1, od->y1, od->x2, od->y2);
4032 		}
4033 
4034 		// Re-render the node's entire blur region, not just the damaged
4035 		// sliver: the blur samples the framebuffer up to sample_size beyond
4036 		// the damage, where pixels still hold the previous frame's final
4037 		// composited content — including this node's own content drawn above
4038 		// the blur. Re-blurring only the sliver bakes those stale samples
4039 		// into part of the backdrop while neighboring pixels keep last
4040 		// frame's blur, which shimmers whenever damage sweeps underneath
4041 		// (e.g. grid lines during a desktop pan). Re-blurring the whole node
4042 		// computes every pixel from the same freshly rendered below-content.
4043 		pixman_region32_union(&render_data->damage, &render_data->damage, &node_visible_region);
4044 		// Also make sure that the backend also knows about the new
4045 		// damage. Very important
4046 		output_state->committed |= WLR_OUTPUT_STATE_DAMAGE;
4047 		pixman_region32_union(&output_state->damage, &output_state->damage, &node_visible_region);
4048 
4049 		// Expand it once more to get the blur padding region
4050 		// which is key for artifact removal :)
4051 		wlr_region_expand(&intersection, &node_visible_region, sample_size);
4052 		// Don't re-add already added rectangles
4053 		pixman_region32_subtract(&intersection, &intersection, blur_padding_region);
4054 		pixman_region32_union(blur_padding_region, blur_padding_region, &intersection);
4055 	}
4056 
4057 	pixman_region32_fini(&intersection);
4058 	pixman_region32_fini(&expanded_damage);
4059 	pixman_region32_fini(&node_visible_region);
4060 	return should_compensate_blur;
4061 }
4062 
4063 bool wlr_scene_output_commit(struct wlr_scene_output *scene_output,
4064 		const struct wlr_scene_output_state_options *options) {
4065 	if (!wlr_scene_output_needs_frame(scene_output)) {
4066 		return true;
4067 	}
4068 
4069 	bool ok = false;
4070 	struct wlr_output_state state;
4071 	wlr_output_state_init(&state);
4072 	if (!wlr_scene_output_build_state(scene_output, &state, options)) {
4073 		goto out;
4074 	}
4075 
4076 	ok = wlr_output_commit_state(scene_output->output, &state);
4077 	if (!ok) {
4078 		goto out;
4079 	}
4080 
4081 out:
4082 	wlr_output_state_finish(&state);
4083 	return ok;
4084 }
4085 
4086 static void scene_output_state_attempt_gamma(struct wlr_scene_output *scene_output,
4087 		struct wlr_output_state *state) {
4088 	if (!scene_output->gamma_lut_changed) {
4089 		return;
4090 	}
4091 
4092 	struct wlr_output_state gamma_pending = {0};
4093 	if (!wlr_output_state_copy(&gamma_pending, state)) {
4094 		return;
4095 	}
4096 
4097 	wlr_output_state_set_color_transform(&gamma_pending, scene_output->gamma_lut_color_transform);
4098 	scene_output->gamma_lut_changed = false;
4099 
4100 	if (!wlr_output_test_state(scene_output->output, &gamma_pending)) {
4101 		wlr_gamma_control_v1_send_failed_and_destroy(scene_output->gamma_lut);
4102 
4103 		scene_output->gamma_lut = NULL;
4104 		wlr_color_transform_unref(scene_output->gamma_lut_color_transform);
4105 		scene_output->gamma_lut_color_transform = NULL;
4106 		wlr_output_state_finish(&gamma_pending);
4107 		return;
4108 	}
4109 
4110 	wlr_output_state_copy(state, &gamma_pending);
4111 	wlr_output_state_finish(&gamma_pending);
4112 }
4113 
4114 static bool scene_output_combine_color_transforms(
4115 		struct wlr_scene_output *scene_output, struct wlr_color_transform *supplied,
4116 		const struct wlr_output_image_description *img_desc, bool render_gamma_lut) {
4117 	bool result = false;
4118 	struct wlr_color_transform *color_matrix = NULL;
4119 	struct wlr_color_transform *inv_eotf = NULL;
4120 	struct wlr_color_transform *user_gamma = NULL;
4121 
4122 	if (img_desc != NULL) {
4123 		assert(supplied == NULL);
4124 		struct wlr_color_primaries primaries_srgb;
4125 		wlr_color_primaries_from_named(&primaries_srgb, WLR_COLOR_NAMED_PRIMARIES_SRGB);
4126 		struct wlr_color_primaries primaries;
4127 		wlr_color_primaries_from_named(&primaries, img_desc->primaries);
4128 		float matrix[9];
4129 		wlr_color_primaries_transform_absolute_colorimetric(&primaries_srgb, &primaries, matrix);
4130 
4131 		struct wlr_color_luminances srgb_lum, dst_lum;
4132 		wlr_color_transfer_function_get_default_luminance(
4133 			WLR_COLOR_TRANSFER_FUNCTION_SRGB, &srgb_lum);
4134 		wlr_color_transfer_function_get_default_luminance(img_desc->transfer_function, &dst_lum);
4135 		float luminance_multiplier = get_luminance_multiplier(&srgb_lum, &dst_lum);
4136 		for (int i = 0; i < 9; ++i) {
4137 			matrix[i] *= luminance_multiplier;
4138 		}
4139 
4140 		color_matrix = wlr_color_transform_init_matrix(matrix);
4141 		inv_eotf = wlr_color_transform_init_linear_to_inverse_eotf(img_desc->transfer_function);
4142 		if (color_matrix == NULL || inv_eotf == NULL) {
4143 			goto cleanup_transforms;
4144 		}
4145 	} else if (supplied != NULL) {
4146 		inv_eotf = wlr_color_transform_ref(supplied);
4147 	} else {
4148 		inv_eotf = wlr_color_transform_init_linear_to_inverse_eotf(
4149 			WLR_COLOR_TRANSFER_FUNCTION_GAMMA22);
4150 		if (inv_eotf == NULL) {
4151 			goto cleanup_transforms;
4152 		}
4153 	}
4154 
4155 	struct wlr_color_transform *gamma_lut = scene_output->gamma_lut_color_transform;
4156 	if (gamma_lut != NULL && render_gamma_lut) {
4157 		user_gamma = wlr_color_transform_ref(gamma_lut);
4158 	}
4159 
4160 	struct wlr_color_transform *combined;
4161 	struct wlr_color_transform *transforms[] = {
4162 		color_matrix,
4163 		inv_eotf,
4164 		user_gamma,
4165 	};
4166 	const size_t transforms_len = sizeof(transforms) / sizeof(transforms[0]);
4167 	if (!color_transform_compose(&combined, transforms, transforms_len)) {
4168 		goto cleanup_transforms;
4169 	}
4170 
4171 	wlr_color_transform_unref(scene_output->prev_gamma_lut_color_transform);
4172 	scene_output->prev_gamma_lut_color_transform = gamma_lut ? wlr_color_transform_ref(gamma_lut) : NULL;
4173 	wlr_color_transform_unref(scene_output->prev_supplied_color_transform);
4174 	scene_output->prev_supplied_color_transform = supplied ? wlr_color_transform_ref(supplied) : NULL;
4175 	wlr_color_transform_unref(scene_output->combined_color_transform);
4176 	scene_output->combined_color_transform = combined;
4177 
4178 	result = true;
4179 
4180 cleanup_transforms:
4181 	wlr_color_transform_unref(color_matrix);
4182 	wlr_color_transform_unref(inv_eotf);
4183 	wlr_color_transform_unref(user_gamma);
4184 	return result;
4185 }
4186 
4187 bool wlr_scene_output_build_state(struct wlr_scene_output *scene_output,
4188 		struct wlr_output_state *state, const struct wlr_scene_output_state_options *options) {
4189 	struct wlr_scene_output_state_options default_options = {0};
4190 	if (!options) {
4191 		options = &default_options;
4192 	}
4193 	struct wlr_scene_timer *timer = options->timer;
4194 	struct timespec start_time;
4195 	if (timer) {
4196 		clock_gettime(CLOCK_MONOTONIC, &start_time);
4197 		wlr_scene_timer_finish(timer);
4198 		*timer = (struct wlr_scene_timer){0};
4199 	}
4200 
4201 	if ((state->committed & WLR_OUTPUT_STATE_ENABLED) && !state->enabled) {
4202 		// if the state is being disabled, do nothing.
4203 		return true;
4204 	}
4205 
4206 	struct wlr_output *output = scene_output->output;
4207 	enum wlr_scene_debug_damage_option debug_damage =
4208 		scene_output->scene->debug_damage_option;
4209 
4210 	bool render_gamma_lut = false;
4211 	if (wlr_output_get_gamma_size(output) == 0 && output->renderer->features.output_color_transform) {
4212 		if (scene_output->gamma_lut_color_transform != scene_output->prev_gamma_lut_color_transform) {
4213 			scene_output_damage_whole(scene_output);
4214 		}
4215 		if (scene_output->gamma_lut_color_transform != NULL) {
4216 			render_gamma_lut = true;
4217 		}
4218 	}
4219 
4220 	struct render_data render_data = {
4221 		.transform = output->transform,
4222 		.scale = output->scale,
4223 		.logical = { .x = scene_output->x, .y = scene_output->y },
4224 		.output = scene_output,
4225 	};
4226 
4227 	int resolution_width, resolution_height;
4228 	output_pending_resolution(output, state,
4229 		&resolution_width, &resolution_height);
4230 
4231 	if (state->committed & WLR_OUTPUT_STATE_TRANSFORM) {
4232 		if (render_data.transform != state->transform) {
4233 			scene_output_damage_whole(scene_output);
4234 		}
4235 
4236 		render_data.transform = state->transform;
4237 	}
4238 
4239 	if (state->committed & WLR_OUTPUT_STATE_SCALE) {
4240 		if (render_data.scale != state->scale) {
4241 			scene_output_damage_whole(scene_output);
4242 		}
4243 
4244 		render_data.scale = state->scale;
4245 	}
4246 
4247 	render_data.trans_width = resolution_width;
4248 	render_data.trans_height = resolution_height;
4249 	wlr_output_transform_coords(render_data.transform,
4250 		&render_data.trans_width, &render_data.trans_height);
4251 
4252 	render_data.logical.width = render_data.trans_width / render_data.scale;
4253 	render_data.logical.height = render_data.trans_height / render_data.scale;
4254 
4255 	struct render_list_constructor_data list_con = {
4256 		.box = render_data.logical,
4257 		.render_list = &scene_output->render_list,
4258 		.calculate_visibility = scene_output->scene->calculate_visibility,
4259 		.highlight_transparent_region = scene_output->scene->highlight_transparent_region,
4260 		.fractional_scale = floor(render_data.scale) != render_data.scale,
4261 	};
4262 
4263 	list_con.render_list->size = 0;
4264 	scene_nodes_in_box(&scene_output->scene->tree.node, &list_con.box,
4265 		construct_render_list_iterator, &list_con);
4266 	array_realloc(list_con.render_list, list_con.render_list->size);
4267 
4268 	struct render_list_entry *list_data = list_con.render_list->data;
4269 	int list_len = list_con.render_list->size / sizeof(*list_data);
4270 
4271 	if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_RERENDER) {
4272 		scene_output_damage_whole(scene_output);
4273 	}
4274 
4275 	struct timespec now;
4276 	if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
4277 		struct wl_list *regions = &scene_output->damage_highlight_regions;
4278 		clock_gettime(CLOCK_MONOTONIC, &now);
4279 
4280 		// add the current frame's damage if there is damage
4281 		if (!pixman_region32_empty(&scene_output->damage_ring.current)) {
4282 			struct highlight_region *current_damage = calloc(1, sizeof(*current_damage));
4283 			if (current_damage) {
4284 				pixman_region32_init(&current_damage->region);
4285 				pixman_region32_copy(&current_damage->region,
4286 					&scene_output->damage_ring.current);
4287 				current_damage->when = now;
4288 				wl_list_insert(regions, &current_damage->link);
4289 			}
4290 		}
4291 
4292 		pixman_region32_t acc_damage;
4293 		pixman_region32_init(&acc_damage);
4294 		struct highlight_region *damage, *tmp_damage;
4295 		wl_list_for_each_safe(damage, tmp_damage, regions, link) {
4296 			// remove overlapping damage regions
4297 			pixman_region32_subtract(&damage->region, &damage->region, &acc_damage);
4298 			pixman_region32_union(&acc_damage, &acc_damage, &damage->region);
4299 
4300 			// if this damage is too old or has nothing in it, get rid of it
4301 			struct timespec time_diff;
4302 			timespec_sub(&time_diff, &now, &damage->when);
4303 			if (timespec_to_msec(&time_diff) >= HIGHLIGHT_DAMAGE_FADEOUT_TIME ||
4304 					pixman_region32_empty(&damage->region)) {
4305 				highlight_region_destroy(damage);
4306 			}
4307 		}
4308 
4309 		scene_output_damage(scene_output, &acc_damage);
4310 		pixman_region32_fini(&acc_damage);
4311 	}
4312 
4313 	wlr_output_state_set_damage(state, &scene_output->pending_commit_damage);
4314 
4315 	// We only want to try direct scanout if:
4316 	// - There is only one entry in the render list
4317 	// - There are no color transforms that need to be applied
4318 	// - Damage highlight debugging is not enabled
4319 	enum scene_direct_scanout_result scanout_result = SCANOUT_INELIGIBLE;
4320 	if (options->color_transform == NULL && !render_gamma_lut && list_len == 1
4321 			&& debug_damage != WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
4322 		scanout_result = scene_entry_try_direct_scanout(&list_data[0], state, &render_data);
4323 	}
4324 
4325 	if (scanout_result == SCANOUT_INELIGIBLE) {
4326 		if (scene_output->dmabuf_feedback_debounce > 0) {
4327 			// We cannot scan out, so count down towards sending composition dmabuf feedback
4328 			scene_output->dmabuf_feedback_debounce--;
4329 		}
4330 	} else if (scene_output->dmabuf_feedback_debounce < DMABUF_FEEDBACK_DEBOUNCE_FRAMES) {
4331 		// We either want to scan out or successfully scanned out, so count up towards sending
4332 		// scanout dmabuf feedback
4333 		scene_output->dmabuf_feedback_debounce++;
4334 	}
4335 
4336 	bool scanout = scanout_result == SCANOUT_SUCCESS;
4337 	if (scene_output->prev_scanout != scanout) {
4338 		scene_output->prev_scanout = scanout;
4339 		wlr_log(WLR_DEBUG, "Direct scan-out %s",
4340 			scanout ? "enabled" : "disabled");
4341 	}
4342 
4343 	if (scanout) {
4344 		scene_output_state_attempt_gamma(scene_output, state);
4345 
4346 		if (timer) {
4347 			struct timespec end_time, duration;
4348 			clock_gettime(CLOCK_MONOTONIC, &end_time);
4349 			timespec_sub(&duration, &end_time, &start_time);
4350 			timer->pre_render_duration = timespec_to_nsec(&duration);
4351 		}
4352 
4353 		TRACY_MARK_FRAME;
4354 		return true;
4355 	}
4356 
4357 	struct wlr_swapchain *swapchain = options->swapchain;
4358 	if (!swapchain) {
4359 		if (!wlr_output_configure_primary_swapchain(output, state, &output->swapchain)) {
4360 			TRACY_MARK_FRAME;
4361 			return false;
4362 		}
4363 
4364 		swapchain = output->swapchain;
4365 	}
4366 
4367 	struct wlr_buffer *buffer = wlr_swapchain_acquire(swapchain);
4368 	if (buffer == NULL) {
4369 		TRACY_MARK_FRAME;
4370 		return false;
4371 	}
4372 
4373 	assert(buffer->width == resolution_width && buffer->height == resolution_height);
4374 
4375 	if (timer) {
4376 		timer->render_timer = wlr_render_timer_create(output->renderer);
4377 
4378 		struct timespec end_time, duration;
4379 		clock_gettime(CLOCK_MONOTONIC, &end_time);
4380 		timespec_sub(&duration, &end_time, &start_time);
4381 		timer->pre_render_duration = timespec_to_nsec(&duration);
4382 	}
4383 
4384 	if ((render_gamma_lut
4385 			&& scene_output->gamma_lut_color_transform != scene_output->prev_gamma_lut_color_transform)
4386 			|| scene_output->prev_supplied_color_transform != options->color_transform
4387 			|| (state->committed & WLR_OUTPUT_STATE_IMAGE_DESCRIPTION)) {
4388 		const struct wlr_output_image_description *output_description =
4389 			output_pending_image_description(output, state);
4390 		if (!scene_output_combine_color_transforms(scene_output, options->color_transform,
4391 				output_description, render_gamma_lut)) {
4392 			wlr_buffer_unlock(buffer);
4393 			return false;
4394 		}
4395 	}
4396 
4397 	scene_output->in_point++;
4398 	struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass(output->renderer, buffer,
4399 			&(struct wlr_buffer_pass_options){
4400 		.timer = timer ? timer->render_timer : NULL,
4401 		.color_transform = scene_output->combined_color_transform,
4402 		.signal_timeline = scene_output->in_timeline,
4403 		.signal_point = scene_output->in_point,
4404 	});
4405 	if (render_pass == NULL) {
4406 		wlr_buffer_unlock(buffer);
4407 
4408 		TRACY_MARK_FRAME;
4409 		return false;
4410 	}
4411 
4412 	render_data.render_pass = render_pass;
4413 
4414 	pixman_region32_init(&render_data.damage);
4415 	wlr_damage_ring_rotate_buffer(&scene_output->damage_ring, buffer,
4416 		&render_data.damage);
4417 
4418 	struct fx_gles_render_pass *fx_pass = fx_get_render_pass(render_pass);
4419 	bool should_compensate_blur = false;
4420 	if (fx_render_pass_init_offscreen_buffers(render_pass, output)
4421 			&& pixman_region32_not_empty(&render_data.damage)) {
4422 		// Software cursors are baked into the reused buffer, so their recent
4423 		// footprints must be treated as damage before the blur compensation
4424 		// geometry is computed: inside the damage they get re-blurred with
4425 		// full sampling context, and the padding restore (which excludes
4426 		// damage) can never paste a stale cursor back. The live cursor is
4427 		// redrawn on top afterwards since
4428 		// wlr_output_add_software_cursors_to_render_pass() clips to this
4429 		// damage.
4430 		if (is_scene_blur_enabled(&scene_output->scene->blur_data)) {
4431 			struct wlr_output_cursor *cursor;
4432 			wl_list_for_each(cursor, &output->cursors, link) {
4433 				if (!cursor->enabled || !cursor->visible) {
4434 					continue;
4435 				}
4436 				double scale = output->scale;
4437 				g_cursor_history[g_cursor_history_index].x =
4438 					(cursor->x - cursor->hotspot_x) * scale;
4439 				g_cursor_history[g_cursor_history_index].y =
4440 					(cursor->y - cursor->hotspot_y) * scale;
4441 				g_cursor_history[g_cursor_history_index].w = cursor->width;
4442 				g_cursor_history[g_cursor_history_index].h = cursor->height;
4443 				g_cursor_history[g_cursor_history_index].valid = true;
4444 				g_cursor_history[g_cursor_history_index].output = output;
4445 				g_cursor_history_index =
4446 					(g_cursor_history_index + 1) % CURSOR_HISTORY_SIZE;
4447 			}
4448 
4449 			// Newest first, this output's only, the most recent few.
4450 			for (int k = 1, taken = 0; k <= CURSOR_HISTORY_SIZE && taken < CURSOR_HISTORY_DAMAGE; k++) {
4451 				int i = (g_cursor_history_index - k + CURSOR_HISTORY_SIZE) % CURSOR_HISTORY_SIZE;
4452 				if (!g_cursor_history[i].valid || g_cursor_history[i].output != output) {
4453 					continue;
4454 				}
4455 				taken++;
4456 				pixman_region32_union_rect(&render_data.damage, &render_data.damage,
4457 						g_cursor_history[i].x - 16,
4458 						g_cursor_history[i].y - 16,
4459 						g_cursor_history[i].w + 32,
4460 						g_cursor_history[i].h + 32);
4461 				pixman_region32_union_rect(&state->damage, &state->damage,
4462 						g_cursor_history[i].x - 16,
4463 						g_cursor_history[i].y - 16,
4464 						g_cursor_history[i].w + 32,
4465 						g_cursor_history[i].h + 32);
4466 				state->committed |= WLR_OUTPUT_STATE_DAMAGE;
4467 			}
4468 			pixman_region32_intersect_rect(&render_data.damage, &render_data.damage,
4469 					0, 0, output->width, output->height);
4470 		}
4471 
4472 		// Blur artifact prevention
4473 		// Note: Supports individual blur node blur_data
4474 		pixman_region32_t original_damage;
4475 		pixman_region32_init(&original_damage);
4476 		pixman_region32_copy(&original_damage, &render_data.damage);
4477 
4478 		// Only compensate for blur artifacts when the damage doesn't cover
4479 		// the whole output. Test actual coverage, not extents: scattered
4480 		// damage (e.g. every grid cell rect moving during a desktop pan)
4481 		// has full-output extents while being mostly holes, and skipping
4482 		// compensation then leaves each blur node re-blurring only slivers
4483 		// against stale framebuffer content.
4484 		pixman_box32_t full_output_box = {
4485 			.x1 = 0, .y1 = 0,
4486 			.x2 = output->width, .y2 = output->height,
4487 		};
4488 		const bool full_damage = pixman_region32_contains_rectangle(
4489 			&original_damage, &full_output_box) == PIXMAN_REGION_IN;
4490 
4491 		// The extra region we copy and paste onto the framebuffer after render
4492 		// for artifact removal
4493 		pixman_region32_t blur_padding_region;
4494 		pixman_region32_init(&blur_padding_region);
4495 
4496 		// Check if the original damage expanded by the to-be-rendered blur
4497 		// nodes sampling size intersects with said nodes visible region. The
4498 		// intersection gets expanded once more which becomes the region to be
4499 		// copied before render and pasted onto the framebuffer after render
4500 		// (the region where artifacts will be visible). This method fixes blur
4501 		// nodes not updating properly when nearby, non-blurred nodes get
4502 		// damaged while avoiding to re-render the whole nodes blur region. It
4503 		// also allows for node-individual blur_data if needed in the future.
4504 		for (int i = list_len - 1; i >= 0; i--) {
4505 			struct render_list_entry *entry = &list_data[i];
4506 			struct wlr_scene_node *node = entry->node;
4507 			struct blur_data blur_data = scene_output->scene->blur_data;
4508 			if (!should_blur_node_extend_damage(node, fx_pass, &blur_data)) {
4509 				continue;
4510 			}
4511 
4512 			// End early. No need to compensate for blur if the whole output
4513 			// is damaged anyway, but still make sure to let the renderer know that
4514 			// there's blur nodes to render.
4515 			if (full_damage) {
4516 				should_compensate_blur = false;
4517 				fx_pass->has_blur = true;
4518 				break;
4519 			}
4520 
4521 			if (apply_blur_region(node, &blur_data, &render_data, state,
4522 						&original_damage, &blur_padding_region)) {
4523 				should_compensate_blur = true;
4524 				fx_pass->has_blur = true;
4525 			}
4526 		}
4527 
4528 		// Expand the damage to compensate for blur
4529 		if (should_compensate_blur) {
4530 			// Capture the padding pixels around the blur where artifacts will be drawn
4531 			pixman_region32_subtract(&fx_pass->blur_padding_region,
4532 					&blur_padding_region, &render_data.damage);
4533 			// Make sure that the padding and damage doesn't exceed the output bounds
4534 			pixman_region32_intersect_rect(&fx_pass->blur_padding_region, &fx_pass->blur_padding_region,
4535 					0, 0, output->width, output->height);
4536 
4537 			// Combine with the render damage (we need to redraw the padding area as well)
4538 			pixman_region32_union(&render_data.damage,
4539 					&render_data.damage, &fx_pass->blur_padding_region);
4540 			pixman_region32_intersect_rect(&render_data.damage, &render_data.damage,
4541 					0, 0, output->width, output->height);
4542 
4543 			// Copy the surrounding content where the blur would display artifacts
4544 			// and draw it above the artifacts. Otherwise The old rendered
4545 			// content would be included into the new blur. This means that
4546 			// content like a high z-index toplevel would be included into the
4547 			// blur of a toplevel with a low z-index.
4548 			fx_render_pass_read_to_buffer(fx_pass, &fx_pass->blur_padding_region,
4549 					fx_pass->fx_offscreen_buffers->blur_saved_pixels_buffer, fx_pass->buffer);
4550 		}
4551 
4552 		pixman_region32_fini(&blur_padding_region);
4553 		pixman_region32_fini(&original_damage);
4554 	}
4555 
4556 	pixman_region32_t background;
4557 	pixman_region32_init(&background);
4558 	pixman_region32_copy(&background, &render_data.damage);
4559 
4560 	// Cull areas of the background that are occluded by opaque regions of
4561 	// scene nodes above. Those scene nodes will just render atop having us
4562 	// never see the background.
4563 	if (scene_output->scene->calculate_visibility) {
4564 		for (int i = list_len - 1; i >= 0; i--) {
4565 			struct render_list_entry *entry = &list_data[i];
4566 
4567 			// We must only cull opaque regions that are visible by the node.
4568 			// The node's visibility will have the knowledge of a black rect
4569 			// that may have been omitted from the render list via the black
4570 			// rect optimization. In order to ensure we don't cull background
4571 			// rendering in that black rect region, consider the node's visibility.
4572 			pixman_region32_t opaque;
4573 			pixman_region32_init(&opaque);
4574 			scene_node_opaque_region(entry->node, entry->x, entry->y, &opaque);
4575 			pixman_region32_intersect(&opaque, &opaque, &entry->node->visible);
4576 
4577 			pixman_region32_translate(&opaque, -scene_output->x, -scene_output->y);
4578 			logical_to_buffer_coords(&opaque, &render_data, false);
4579 			pixman_region32_subtract(&background, &background, &opaque);
4580 			pixman_region32_fini(&opaque);
4581 		}
4582 
4583 		if (floor(render_data.scale) != render_data.scale) {
4584 			wlr_region_expand(&background, &background, 1);
4585 
4586 			// reintersect with the damage because we never want to render
4587 			// outside of the damage region
4588 			pixman_region32_intersect(&background, &background, &render_data.damage);
4589 		}
4590 	}
4591 
4592 	wlr_render_pass_add_rect(render_pass, &(struct wlr_render_rect_options){
4593 		.box = { .width = buffer->width, .height = buffer->height },
4594 		.color = { .r = 0, .g = 0, .b = 0, .a = 1 },
4595 		.clip = &background,
4596 	});
4597 	pixman_region32_fini(&background);
4598 
4599 	for (int i = list_len - 1; i >= 0; i--) {
4600 		struct render_list_entry *entry = &list_data[i];
4601 		scene_entry_render(entry, &render_data);
4602 
4603 		if (entry->node->type == WLR_SCENE_NODE_BUFFER) {
4604 			struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(entry->node);
4605 
4606 			// Direct scanout counts up to DMABUF_FEEDBACK_DEBOUNCE_FRAMES before sending new dmabuf
4607 			// feedback, and on composition we wait until it hits zero again. If we knew that an
4608 			// entry could never be a scanout candidate, we could send feedback to it
4609 			// unconditionally without debounce, but for now it is all or nothing
4610 			if (scene_output->dmabuf_feedback_debounce == 0 && buffer->primary_output == scene_output) {
4611 				struct wlr_linux_dmabuf_feedback_v1_init_options options = {
4612 					.main_renderer = output->renderer,
4613 					.scanout_primary_output = NULL,
4614 				};
4615 
4616 				scene_buffer_send_dmabuf_feedback(scene_output->scene, buffer, &options);
4617 			}
4618 		}
4619 	}
4620 
4621 	if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) {
4622 		struct highlight_region *damage;
4623 		wl_list_for_each(damage, &scene_output->damage_highlight_regions, link) {
4624 			struct timespec time_diff;
4625 			timespec_sub(&time_diff, &now, &damage->when);
4626 			int64_t time_diff_ms = timespec_to_msec(&time_diff);
4627 			float alpha = 1.0 - (double)time_diff_ms / HIGHLIGHT_DAMAGE_FADEOUT_TIME;
4628 
4629 			wlr_render_pass_add_rect(render_pass, &(struct wlr_render_rect_options){
4630 				.box = { .width = buffer->width, .height = buffer->height },
4631 				.color = { .r = alpha * 0.5, .g = 0, .b = 0, .a = alpha * 0.5 },
4632 				.clip = &damage->region,
4633 			});
4634 		}
4635 	}
4636 
4637 	if (should_compensate_blur) {
4638 		// Render the saved pixels over the blur artifacts
4639 		fx_render_pass_read_to_buffer(fx_pass, &fx_pass->blur_padding_region,
4640 				fx_pass->buffer, fx_pass->fx_offscreen_buffers->blur_saved_pixels_buffer);
4641 	}
4642 
4643 	wlr_output_add_software_cursors_to_render_pass(output, render_pass, &render_data.damage);
4644 
4645 	pixman_region32_fini(&render_data.damage);
4646 
4647 	if (!wlr_render_pass_submit(render_pass)) {
4648 		wlr_buffer_unlock(buffer);
4649 
4650 		// if we failed to render the buffer, it will have undefined contents
4651 		// Trash the damage ring
4652 		wlr_damage_ring_add_whole(&scene_output->damage_ring);
4653 
4654 		TRACY_MARK_FRAME;
4655 		return false;
4656 	}
4657 
4658 	wlr_output_state_set_buffer(state, buffer);
4659 	wlr_buffer_unlock(buffer);
4660 
4661 	if (scene_output->in_timeline != NULL) {
4662 		wlr_output_state_set_wait_timeline(state, scene_output->in_timeline,
4663 			scene_output->in_point);
4664 		scene_output->out_point++;
4665 		wlr_output_state_set_signal_timeline(state, scene_output->out_timeline,
4666 			scene_output->out_point);
4667 	}
4668 
4669 	if (!render_gamma_lut) {
4670 		scene_output_state_attempt_gamma(scene_output, state);
4671 	}
4672 
4673 	TRACY_MARK_FRAME;
4674 	return true;
4675 }
4676 
4677 int64_t wlr_scene_timer_get_duration_ns(struct wlr_scene_timer *timer) {
4678 	int64_t pre_render = timer->pre_render_duration;
4679 	if (!timer->render_timer) {
4680 		return pre_render;
4681 	}
4682 	int64_t render = wlr_render_timer_get_duration_ns(timer->render_timer);
4683 	return render != -1 ? pre_render + render : -1;
4684 }
4685 
4686 void wlr_scene_timer_finish(struct wlr_scene_timer *timer) {
4687 	if (timer->render_timer) {
4688 		wlr_render_timer_destroy(timer->render_timer);
4689 	}
4690 }
4691 
4692 static void scene_node_send_frame_done(struct wlr_scene_node *node,
4693 		struct wlr_scene_output *scene_output, struct timespec *now) {
4694 	if (!node->enabled) {
4695 		return;
4696 	}
4697 
4698 	if (node->type == WLR_SCENE_NODE_BUFFER) {
4699 		struct wlr_scene_buffer *scene_buffer =
4700 			wlr_scene_buffer_from_node(node);
4701 		struct wlr_scene_frame_done_event event = {
4702 			.output = scene_output,
4703 			.when = *now,
4704 		};
4705 		wlr_scene_buffer_send_frame_done(scene_buffer, &event);
4706 	} else if (node->type == WLR_SCENE_NODE_TREE) {
4707 		struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
4708 		struct wlr_scene_node *child;
4709 		wl_list_for_each(child, &scene_tree->children, link) {
4710 			scene_node_send_frame_done(child, scene_output, now);
4711 		}
4712 	}
4713 }
4714 
4715 void wlr_scene_output_send_frame_done(struct wlr_scene_output *scene_output,
4716 		struct timespec *now) {
4717 	scene_node_send_frame_done(&scene_output->scene->tree.node,
4718 		scene_output, now);
4719 }
4720 
4721 static void scene_output_for_each_scene_buffer(const struct wlr_box *output_box,
4722 		struct wlr_scene_node *node, int lx, int ly,
4723 		wlr_scene_buffer_iterator_func_t user_iterator, void *user_data) {
4724 	if (!node->enabled) {
4725 		return;
4726 	}
4727 
4728 	lx += node->x;
4729 	ly += node->y;
4730 
4731 	if (node->type == WLR_SCENE_NODE_BUFFER) {
4732 		struct wlr_box node_box = { .x = lx, .y = ly };
4733 		scene_node_get_size(node, &node_box.width, &node_box.height);
4734 
4735 		struct wlr_box intersection;
4736 		if (wlr_box_intersection(&intersection, output_box, &node_box)) {
4737 			struct wlr_scene_buffer *scene_buffer =
4738 				wlr_scene_buffer_from_node(node);
4739 			user_iterator(scene_buffer, lx, ly, user_data);
4740 		}
4741 	} else if (node->type == WLR_SCENE_NODE_TREE) {
4742 		struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
4743 		struct wlr_scene_node *child;
4744 		wl_list_for_each(child, &scene_tree->children, link) {
4745 			scene_output_for_each_scene_buffer(output_box, child, lx, ly,
4746 				user_iterator, user_data);
4747 		}
4748 	}
4749 }
4750 
4751 void wlr_scene_output_for_each_buffer(struct wlr_scene_output *scene_output,
4752 		wlr_scene_buffer_iterator_func_t iterator, void *user_data) {
4753 	struct wlr_box box = { .x = scene_output->x, .y = scene_output->y };
4754 	wlr_output_effective_resolution(scene_output->output,
4755 		&box.width, &box.height);
4756 	scene_output_for_each_scene_buffer(&box, &scene_output->scene->tree.node, 0, 0,
4757 		iterator, user_data);
4758 }