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

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

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