From 07ccc6e0b357dd3c7be0939957657d0a03738b9d Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 14 Dec 2021 18:35:44 +0100 Subject: [PATCH] scene: add wlr_scene_set_presentation() This helper automates sending presentation feedback to clients based on the primary output of scene surfaces. --- include/wlr/types/wlr_scene.h | 14 ++++++++++++ types/scene/wlr_scene.c | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index d2af9c5a..e0b370ad 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -62,6 +62,12 @@ struct wlr_scene { struct wlr_scene_node node; struct wl_list outputs; // wlr_scene_output.link + + // private state + + // May be NULL + struct wlr_presentation *presentation; + struct wl_listener presentation_destroy; }; /** A sub-tree in the scene-graph. */ @@ -201,6 +207,14 @@ struct wlr_scene *wlr_scene_create(void); */ void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, int lx, int ly, pixman_region32_t *damage); +/** + * Handle presentation feedback for all surfaces in the scene, assuming that + * scene outputs and the scene rendering functions are used. + * + * Asserts that a wlr_presentation hasn't already been set for the scene. + */ +void wlr_scene_set_presentation(struct wlr_scene *scene, + struct wlr_presentation *presentation); /** * Add a node displaying nothing but its children. diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 3d19acef..7b550963 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -101,6 +102,8 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wlr_scene_output_destroy(scene_output); } + wl_list_remove(&scene->presentation_destroy.link); + free(scene); break; case WLR_SCENE_NODE_TREE:; @@ -141,6 +144,7 @@ struct wlr_scene *wlr_scene_create(void) { } scene_node_init(&scene->node, WLR_SCENE_NODE_ROOT, NULL); wl_list_init(&scene->outputs); + wl_list_init(&scene->presentation_destroy.link); return scene; } @@ -767,6 +771,9 @@ static void render_texture(struct wlr_output *output, struct render_data { struct wlr_output *output; pixman_region32_t *damage; + + // May be NULL + struct wlr_presentation *presentation; }; static void render_node_iterator(struct wlr_scene_node *node, @@ -808,6 +815,11 @@ static void render_node_iterator(struct wlr_scene_node *node, render_texture(output, output_damage, texture, &src_box, &dst_box, matrix); + + if (data->presentation != NULL && scene_surface->primary_output == output) { + wlr_presentation_surface_sampled_on_output(data->presentation, + surface, output); + } break; case WLR_SCENE_NODE_RECT:; struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); @@ -867,6 +879,7 @@ void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, struct render_data data = { .output = output, .damage = damage, + .presentation = scene->presentation, }; scene_node_for_each_node(&scene->node, -lx, -ly, render_node_iterator, &data); @@ -876,6 +889,23 @@ void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, pixman_region32_fini(&full_region); } +static void scene_handle_presentation_destroy(struct wl_listener *listener, + void *data) { + struct wlr_scene *scene = + wl_container_of(listener, scene, presentation_destroy); + wl_list_remove(&scene->presentation_destroy.link); + wl_list_init(&scene->presentation_destroy.link); + scene->presentation = NULL; +} + +void wlr_scene_set_presentation(struct wlr_scene *scene, + struct wlr_presentation *presentation) { + assert(scene->presentation == NULL); + scene->presentation = presentation; + scene->presentation_destroy.notify = scene_handle_presentation_destroy; + wl_signal_add(&presentation->events.destroy, &scene->presentation_destroy); +} + static void scene_output_handle_destroy(struct wlr_addon *addon) { struct wlr_scene_output *scene_output = wl_container_of(addon, scene_output, addon); @@ -1028,6 +1058,18 @@ static bool scene_output_scanout(struct wlr_scene_output *scene_output) { return false; } + struct wlr_presentation *presentation = scene_output->scene->presentation; + if (presentation != NULL && node->type == WLR_SCENE_NODE_SURFACE) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_node(node); + // Since outputs may overlap, we still need to check this even though + // we know that the surface size matches the size of this output. + if (scene_surface->primary_output == output) { + wlr_presentation_surface_sampled_on_output(presentation, + scene_surface->surface, output); + } + } + return wlr_output_commit(output); }