Merge branch 'scene-snapshot' into 'master'

scene: add wlr_scene_node_snapshot()

See merge request wlroots/wlroots!4558
This commit is contained in:
Simon Ser 2026-01-09 04:21:12 +00:00
commit 89ec249be1
2 changed files with 89 additions and 0 deletions

View file

@ -348,6 +348,15 @@ void wlr_scene_node_for_each_buffer(struct wlr_scene_node *node,
*/
struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node,
double lx, double ly, double *nx, double *ny);
/**
* Create a new scene node which represents a snapshot of another node.
*
* The snapshot displays the same contents as the source node at the time of
* its creation. The snapshot is completely independent from the source node:
* when the source node is updated, the snapshot will stay as-is.
*/
struct wlr_scene_node *wlr_scene_node_snapshot(struct wlr_scene_node *node,
struct wlr_scene_tree *parent);
/**
* Create a new scene-graph.

View file

@ -2670,3 +2670,83 @@ void wlr_scene_output_for_each_buffer(struct wlr_scene_output *scene_output,
scene_output_for_each_scene_buffer(&box, &scene_output->scene->tree.node, 0, 0,
iterator, user_data);
}
static bool scene_node_snapshot(struct wlr_scene_node *node, int lx, int ly,
struct wlr_scene_tree *snapshot_tree) {
if (!node->enabled) {
return true;
}
lx += node->x;
ly += node->y;
struct wlr_scene_node *snapshot_node = NULL;
switch (node->type) {
case WLR_SCENE_NODE_TREE:;
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
struct wlr_scene_node *child;
wl_list_for_each(child, &scene_tree->children, link) {
scene_node_snapshot(node, lx, ly, snapshot_tree);
}
break;
case WLR_SCENE_NODE_RECT:;
struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node);
struct wlr_scene_rect *snapshot_rect = wlr_scene_rect_create(snapshot_tree,
scene_rect->width, scene_rect->height, scene_rect->color);
if (snapshot_rect == NULL) {
return false;
}
snapshot_node = &snapshot_rect->node;
break;
case WLR_SCENE_NODE_BUFFER:;
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
struct wlr_scene_buffer *snapshot_buffer = wlr_scene_buffer_create(snapshot_tree, NULL);
if (snapshot_buffer == NULL) {
return false;
}
snapshot_node = &snapshot_buffer->node;
wlr_scene_buffer_set_dest_size(snapshot_buffer, scene_buffer->dst_width, scene_buffer->dst_height);
wlr_scene_buffer_set_opaque_region(snapshot_buffer, &scene_buffer->opaque_region);
wlr_scene_buffer_set_source_box(snapshot_buffer, &scene_buffer->src_box);
wlr_scene_buffer_set_transform(snapshot_buffer, scene_buffer->transform);
struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(scene_buffer);
if (scene_surface != NULL && scene_surface->surface->buffer != NULL) {
wlr_scene_buffer_set_buffer(snapshot_buffer, &scene_surface->surface->buffer->base);
} else {
wlr_scene_buffer_set_buffer(snapshot_buffer, scene_buffer->buffer);
}
break;
}
if (snapshot_node != NULL) {
wlr_scene_node_set_position(snapshot_node, lx, ly);
}
return true;
}
struct wlr_scene_node *wlr_scene_node_snapshot(struct wlr_scene_node *node,
struct wlr_scene_tree *parent) {
struct wlr_scene_tree *snapshot = wlr_scene_tree_create(parent);
if (snapshot == NULL) {
return NULL;
}
// Disable and enable the snapshot tree like so to atomically update
// the scene-graph. This will prevent over-damaging or other weirdness.
wlr_scene_node_set_enabled(&snapshot->node, false);
if (!scene_node_snapshot(node, 0, 0, snapshot)) {
wlr_scene_node_destroy(&snapshot->node);
return NULL;
}
wlr_scene_node_set_enabled(&snapshot->node, true);
return &snapshot->node;
}