From f9becb31e14e9ede8dc4c077d2ee76d450680357 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 16 Feb 2024 13:40:39 +0100 Subject: [PATCH] scene: add wlr_scene_node_snapshot() --- include/wlr/types/wlr_scene.h | 9 ++++ types/scene/wlr_scene.c | 80 +++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index 253de1695..c742b2096 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -301,6 +301,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. diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 7e5b31363..aa993fd29 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -2008,3 +2008,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; +}