From 0272bcb3139dd52b86bfc427b01055d2131a458f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 9 Sep 2021 10:20:06 +0200 Subject: scene: move source to subdir This will allow more scene-graph extensions to be added without cluttering wlr_scene.c, for instance for sub-surface handling and wlr_output_layout integration. --- wlr_scene.c | 721 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 721 insertions(+) create mode 100644 wlr_scene.c diff --git a/wlr_scene.c b/wlr_scene.c new file mode 100644 index 0000000..6a988e5 --- /dev/null +++ b/wlr_scene.c @@ -0,0 +1,721 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "util/signal.h" + +static struct wlr_scene *scene_root_from_node(struct wlr_scene_node *node) { + assert(node->type == WLR_SCENE_NODE_ROOT); + return (struct wlr_scene *)node; +} + +struct wlr_scene_surface *wlr_scene_surface_from_node( + struct wlr_scene_node *node) { + assert(node->type == WLR_SCENE_NODE_SURFACE); + return (struct wlr_scene_surface *)node; +} + +static struct wlr_scene_rect *scene_rect_from_node( + struct wlr_scene_node *node) { + assert(node->type == WLR_SCENE_NODE_RECT); + return (struct wlr_scene_rect *)node; +} + +static void scene_node_state_init(struct wlr_scene_node_state *state) { + wl_list_init(&state->children); + wl_list_init(&state->link); + state->enabled = true; +} + +static void scene_node_state_finish(struct wlr_scene_node_state *state) { + wl_list_remove(&state->link); +} + +static void scene_node_init(struct wlr_scene_node *node, + enum wlr_scene_node_type type, struct wlr_scene_node *parent) { + assert(type == WLR_SCENE_NODE_ROOT || parent != NULL); + + node->type = type; + node->parent = parent; + scene_node_state_init(&node->state); + wl_signal_init(&node->events.destroy); + + if (parent != NULL) { + wl_list_insert(parent->state.children.prev, &node->state.link); + } +} + +static void scene_node_finish(struct wlr_scene_node *node) { + wlr_signal_emit_safe(&node->events.destroy, NULL); + + struct wlr_scene_node *child, *child_tmp; + wl_list_for_each_safe(child, child_tmp, + &node->state.children, state.link) { + wlr_scene_node_destroy(child); + } + + scene_node_state_finish(&node->state); +} + +static void scene_node_damage_whole(struct wlr_scene_node *node); + +void wlr_scene_node_destroy(struct wlr_scene_node *node) { + if (node == NULL) { + return; + } + + scene_node_damage_whole(node); + scene_node_finish(node); + + switch (node->type) { + case WLR_SCENE_NODE_ROOT:; + struct wlr_scene *scene = scene_root_from_node(node); + + struct wlr_scene_output *scene_output, *scene_output_tmp; + wl_list_for_each_safe(scene_output, scene_output_tmp, &scene->outputs, link) { + wlr_scene_output_destroy(scene_output); + } + + free(scene); + break; + case WLR_SCENE_NODE_SURFACE:; + struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); + wl_list_remove(&scene_surface->surface_destroy.link); + free(scene_surface); + break; + case WLR_SCENE_NODE_RECT:; + struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); + free(scene_rect); + break; + } +} + +struct wlr_scene *wlr_scene_create(void) { + struct wlr_scene *scene = calloc(1, sizeof(struct wlr_scene)); + if (scene == NULL) { + return NULL; + } + scene_node_init(&scene->node, WLR_SCENE_NODE_ROOT, NULL); + wl_list_init(&scene->outputs); + return scene; +} + +static void scene_surface_handle_surface_destroy(struct wl_listener *listener, + void *data) { + struct wlr_scene_surface *scene_surface = + wl_container_of(listener, scene_surface, surface_destroy); + wlr_scene_node_destroy(&scene_surface->node); +} + +static struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { + while (node->parent != NULL) { + node = node->parent; + } + return scene_root_from_node(node); +} + +static void scene_surface_handle_surface_commit(struct wl_listener *listener, + void *data) { + struct wlr_scene_surface *scene_surface = + wl_container_of(listener, scene_surface, surface_commit); + struct wlr_surface *surface = scene_surface->surface; + + if (!pixman_region32_not_empty(&surface->buffer_damage)) { + return; + } + + int lx, ly; + if (!wlr_scene_node_coords(&scene_surface->node, &lx, &ly)) { + return; + } + + struct wlr_scene *scene = scene_node_get_root(&scene_surface->node); + + struct wlr_scene_output *scene_output; + wl_list_for_each(scene_output, &scene->outputs, link) { + struct wlr_output *output = scene_output->output; + + pixman_region32_t damage; + pixman_region32_init(&damage); + wlr_surface_get_effective_damage(surface, &damage); + + pixman_region32_translate(&damage, + lx - scene_output->x, ly - scene_output->y); + + wlr_region_scale(&damage, &damage, output->scale); + if (ceil(output->scale) > surface->current.scale) { + // When scaling up a surface it'll become blurry, so we need to + // expand the damage region. + wlr_region_expand(&damage, &damage, + ceil(output->scale) - surface->current.scale); + } + wlr_output_damage_add(scene_output->damage, &damage); + pixman_region32_fini(&damage); + } +} + +struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_node *parent, + struct wlr_surface *surface) { + struct wlr_scene_surface *scene_surface = + calloc(1, sizeof(struct wlr_scene_surface)); + if (scene_surface == NULL) { + return NULL; + } + scene_node_init(&scene_surface->node, WLR_SCENE_NODE_SURFACE, parent); + + scene_surface->surface = surface; + + scene_surface->surface_destroy.notify = scene_surface_handle_surface_destroy; + wl_signal_add(&surface->events.destroy, &scene_surface->surface_destroy); + + scene_surface->surface_commit.notify = scene_surface_handle_surface_commit; + wl_signal_add(&surface->events.commit, &scene_surface->surface_commit); + + scene_node_damage_whole(&scene_surface->node); + + return scene_surface; +} + +struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_node *parent, + int width, int height, const float color[static 4]) { + struct wlr_scene_rect *scene_rect = + calloc(1, sizeof(struct wlr_scene_rect)); + if (scene_rect == NULL) { + return NULL; + } + scene_node_init(&scene_rect->node, WLR_SCENE_NODE_RECT, parent); + + scene_rect->width = width; + scene_rect->height = height; + memcpy(scene_rect->color, color, sizeof(scene_rect->color)); + + scene_node_damage_whole(&scene_rect->node); + + return scene_rect; +} + +void wlr_scene_rect_set_size(struct wlr_scene_rect *rect, int width, int height) { + if (rect->width == width && rect->height == height) { + return; + } + + scene_node_damage_whole(&rect->node); + rect->width = width; + rect->height = height; + scene_node_damage_whole(&rect->node); +} + +void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[static 4]) { + if (memcmp(rect->color, color, sizeof(rect->color)) == 0) { + return; + } + + memcpy(rect->color, color, sizeof(rect->color)); + scene_node_damage_whole(&rect->node); +} + +static int scale_length(int length, int offset, float scale) { + return round((offset + length) * scale) - round(offset * scale); +} + +static void scale_box(struct wlr_box *box, float scale) { + box->width = scale_length(box->width, box->x, scale); + box->height = scale_length(box->height, box->y, scale); + box->x = round(box->x * scale); + box->y = round(box->y * scale); +} + +static void _scene_node_damage_whole(struct wlr_scene_node *node, + struct wlr_scene *scene, int lx, int ly) { + if (!node->state.enabled) { + return; + } + + struct wlr_scene_node *child; + wl_list_for_each(child, &node->state.children, state.link) { + _scene_node_damage_whole(child, scene, + lx + child->state.x, ly + child->state.y); + } + + int width = 0, height = 0; + switch (node->type) { + case WLR_SCENE_NODE_ROOT: + return; + case WLR_SCENE_NODE_SURFACE:; + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_node(node); + width = scene_surface->surface->current.width; + height = scene_surface->surface->current.height; + break; + case WLR_SCENE_NODE_RECT:; + struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); + width = scene_rect->width; + height = scene_rect->height; + break; + } + + struct wlr_scene_output *scene_output; + wl_list_for_each(scene_output, &scene->outputs, link) { + struct wlr_box box = { + .x = lx - scene_output->x, + .y = ly - scene_output->y, + .width = width, + .height = height, + }; + + scale_box(&box, scene_output->output->scale); + + wlr_output_damage_add_box(scene_output->damage, &box); + } +} + +static void scene_node_damage_whole(struct wlr_scene_node *node) { + struct wlr_scene *scene = scene_node_get_root(node); + if (wl_list_empty(&scene->outputs)) { + return; + } + + int lx, ly; + if (!wlr_scene_node_coords(node, &lx, &ly)) { + return; + } + + _scene_node_damage_whole(node, scene, lx, ly); +} + +void wlr_scene_node_set_enabled(struct wlr_scene_node *node, bool enabled) { + if (node->state.enabled == enabled) { + return; + } + + // One of these damage_whole() calls will short-circuit and be a no-op + scene_node_damage_whole(node); + node->state.enabled = enabled; + scene_node_damage_whole(node); +} + +void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y) { + if (node->state.x == x && node->state.y == y) { + return; + } + + scene_node_damage_whole(node); + node->state.x = x; + node->state.y = y; + scene_node_damage_whole(node); +} + +void wlr_scene_node_place_above(struct wlr_scene_node *node, + struct wlr_scene_node *sibling) { + assert(node->parent == sibling->parent); + + if (node->state.link.prev == &sibling->state.link) { + return; + } + + wl_list_remove(&node->state.link); + wl_list_insert(&sibling->state.link, &node->state.link); + + scene_node_damage_whole(node); + scene_node_damage_whole(sibling); +} + +void wlr_scene_node_place_below(struct wlr_scene_node *node, + struct wlr_scene_node *sibling) { + assert(node->parent == sibling->parent); + + if (node->state.link.next == &sibling->state.link) { + return; + } + + wl_list_remove(&node->state.link); + wl_list_insert(sibling->state.link.prev, &node->state.link); + + scene_node_damage_whole(node); + scene_node_damage_whole(sibling); +} + +void wlr_scene_node_reparent(struct wlr_scene_node *node, + struct wlr_scene_node *new_parent) { + assert(node->type != WLR_SCENE_NODE_ROOT && new_parent != NULL); + + if (node->parent == new_parent) { + return; + } + + /* Ensure that a node cannot become its own ancestor */ + for (struct wlr_scene_node *ancestor = new_parent; ancestor != NULL; + ancestor = ancestor->parent) { + assert(ancestor != node); + } + + scene_node_damage_whole(node); + + wl_list_remove(&node->state.link); + node->parent = new_parent; + wl_list_insert(new_parent->state.children.prev, &node->state.link); + + scene_node_damage_whole(node); +} + +bool wlr_scene_node_coords(struct wlr_scene_node *node, + int *lx_ptr, int *ly_ptr) { + int lx = 0, ly = 0; + bool enabled = true; + while (node != NULL) { + lx += node->state.x; + ly += node->state.y; + enabled = enabled && node->state.enabled; + node = node->parent; + } + + *lx_ptr = lx; + *ly_ptr = ly; + return enabled; +} + +static void scene_node_for_each_surface(struct wlr_scene_node *node, + int lx, int ly, wlr_surface_iterator_func_t user_iterator, + void *user_data) { + if (!node->state.enabled) { + return; + } + + lx += node->state.x; + ly += node->state.y; + + if (node->type == WLR_SCENE_NODE_SURFACE) { + struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); + user_iterator(scene_surface->surface, lx, ly, user_data); + } + + struct wlr_scene_node *child; + wl_list_for_each(child, &node->state.children, state.link) { + scene_node_for_each_surface(child, lx, ly, user_iterator, user_data); + } +} + +void wlr_scene_node_for_each_surface(struct wlr_scene_node *node, + wlr_surface_iterator_func_t user_iterator, void *user_data) { + scene_node_for_each_surface(node, 0, 0, user_iterator, user_data); +} + +struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, + double lx, double ly, double *nx, double *ny) { + if (!node->state.enabled) { + return NULL; + } + + // TODO: optimize by storing a bounding box in each node? + lx -= node->state.x; + ly -= node->state.y; + + struct wlr_scene_node *child; + wl_list_for_each_reverse(child, &node->state.children, state.link) { + struct wlr_scene_node *node = + wlr_scene_node_at(child, lx, ly, nx, ny); + if (node != NULL) { + return node; + } + } + + switch (node->type) { + case WLR_SCENE_NODE_SURFACE:; + struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); + if (wlr_surface_point_accepts_input(scene_surface->surface, lx, ly)) { + if (nx != NULL) { + *nx = lx; + } + if (ny != NULL) { + *ny = ly; + } + return &scene_surface->node; + } + break; + case WLR_SCENE_NODE_RECT:; + struct wlr_scene_rect *rect = scene_rect_from_node(node); + if (lx >= 0 && lx < rect->width && ly >= 0 && ly < rect->height) { + if (nx != NULL) { + *nx = lx; + } + if (ny != NULL) { + *ny = ly; + } + return &rect->node; + } + break; + default: + break; + } + + return NULL; +} + +static void scissor_output(struct wlr_output *output, pixman_box32_t *rect) { + struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + assert(renderer); + + struct wlr_box box = { + .x = rect->x1, + .y = rect->y1, + .width = rect->x2 - rect->x1, + .height = rect->y2 - rect->y1, + }; + + int ow, oh; + wlr_output_transformed_resolution(output, &ow, &oh); + + enum wl_output_transform transform = + wlr_output_transform_invert(output->transform); + wlr_box_transform(&box, &box, transform, ow, oh); + + wlr_renderer_scissor(renderer, &box); +} + +static void render_rect(struct wlr_output *output, + pixman_region32_t *output_damage, const float color[static 4], + const struct wlr_box *box, const float matrix[static 9]) { + struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + assert(renderer); + + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_init_rect(&damage, box->x, box->y, box->width, box->height); + pixman_region32_intersect(&damage, &damage, output_damage); + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(output, &rects[i]); + wlr_render_rect(renderer, box, color, matrix); + } + + pixman_region32_fini(&damage); +} + +static void render_texture(struct wlr_output *output, + pixman_region32_t *output_damage, struct wlr_texture *texture, + const struct wlr_box *box, const float matrix[static 9]) { + struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + assert(renderer); + + pixman_region32_t damage; + pixman_region32_init(&damage); + pixman_region32_init_rect(&damage, box->x, box->y, box->width, box->height); + pixman_region32_intersect(&damage, &damage, output_damage); + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(output, &rects[i]); + wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0); + } + + pixman_region32_fini(&damage); +} + +struct render_data { + struct wlr_output *output; + pixman_region32_t *damage; +}; + +static void render_node_iterator(struct wlr_scene_node *node, + int x, int y, void *_data) { + struct render_data *data = _data; + struct wlr_output *output = data->output; + pixman_region32_t *output_damage = data->damage; + struct wlr_box box = { + .x = x, + .y = y, + }; + + switch (node->type) { + case WLR_SCENE_NODE_ROOT:; + /* Root node has nothing to render itself */ + break; + case WLR_SCENE_NODE_SURFACE:; + struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); + struct wlr_surface *surface = scene_surface->surface; + + struct wlr_texture *texture = wlr_surface_get_texture(surface); + if (texture == NULL) { + return; + } + + box.width = surface->current.width; + box.height = surface->current.height; + scale_box(&box, output->scale); + + float matrix[9]; + enum wl_output_transform transform = + wlr_output_transform_invert(surface->current.transform); + wlr_matrix_project_box(matrix, &box, transform, 0.0, + output->transform_matrix); + + render_texture(output, output_damage, texture, &box, matrix); + break; + case WLR_SCENE_NODE_RECT:; + struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); + + box.width = scene_rect->width; + box.height = scene_rect->height; + scale_box(&box, data->output->scale); + + render_rect(output, output_damage, scene_rect->color, &box, + output->transform_matrix); + break; + } +} + +static void scene_node_for_each_node(struct wlr_scene_node *node, + int lx, int ly, wlr_scene_node_iterator_func_t user_iterator, + void *user_data) { + if (!node->state.enabled) { + return; + } + + lx += node->state.x; + ly += node->state.y; + + user_iterator(node, lx, ly, user_data); + + struct wlr_scene_node *child; + wl_list_for_each(child, &node->state.children, state.link) { + scene_node_for_each_node(child, lx, ly, user_iterator, user_data); + } +} + +void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, + int lx, int ly, pixman_region32_t *damage) { + pixman_region32_t full_region; + pixman_region32_init_rect(&full_region, 0, 0, output->width, output->height); + if (damage == NULL) { + damage = &full_region; + } + + struct wlr_renderer *renderer = + wlr_backend_get_renderer(output->backend); + assert(renderer); + + if (output->enabled && pixman_region32_not_empty(damage)) { + struct render_data data = { + .output = output, + .damage = damage, + }; + scene_node_for_each_node(&scene->node, -lx, -ly, + render_node_iterator, &data); + wlr_renderer_scissor(renderer, NULL); + } + + pixman_region32_fini(&full_region); +} + +static void scene_output_handle_destroy(struct wlr_addon *addon) { + struct wlr_scene_output *scene_output = + wl_container_of(addon, scene_output, addon); + wlr_scene_output_destroy(scene_output); +} + +static const struct wlr_addon_interface output_addon_impl = { + .name = "wlr_scene_output", + .destroy = scene_output_handle_destroy, +}; + +struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, + struct wlr_output *output) { + struct wlr_scene_output *scene_output = calloc(1, sizeof(*output)); + if (scene_output == NULL) { + return NULL; + } + + scene_output->damage = wlr_output_damage_create(output); + if (scene_output->damage == NULL) { + free(scene_output); + return NULL; + } + + scene_output->output = output; + scene_output->scene = scene; + wlr_addon_init(&scene_output->addon, &output->addons, scene, &output_addon_impl); + wl_list_insert(&scene->outputs, &scene_output->link); + + wlr_output_damage_add_whole(scene_output->damage); + + return scene_output; +} + +void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { + wlr_addon_finish(&scene_output->addon); + wl_list_remove(&scene_output->link); + free(scene_output); +} + +void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, + int lx, int ly) { + if (scene_output->x == lx && scene_output->y == ly) { + return; + } + + scene_output->x = lx; + scene_output->y = ly; + wlr_output_damage_add_whole(scene_output->damage); +} + +bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { + struct wlr_output *output = scene_output->output; + + struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + assert(renderer != NULL); + + bool needs_frame; + pixman_region32_t damage; + pixman_region32_init(&damage); + if (!wlr_output_damage_attach_render(scene_output->damage, + &needs_frame, &damage)) { + pixman_region32_fini(&damage); + return false; + } + + if (!needs_frame) { + pixman_region32_fini(&damage); + wlr_output_rollback(output); + return true; + } + + wlr_renderer_begin(renderer, output->width, output->height); + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(output, &rects[i]); + wlr_renderer_clear(renderer, (float[4]){ 0.0, 0.0, 0.0, 1.0 }); + } + + wlr_scene_render_output(scene_output->scene, output, + scene_output->x, scene_output->y, &damage); + wlr_output_render_software_cursors(output, &damage); + + wlr_renderer_end(renderer); + pixman_region32_fini(&damage); + + int tr_width, tr_height; + wlr_output_transformed_resolution(output, &tr_width, &tr_height); + + enum wl_output_transform transform = + wlr_output_transform_invert(output->transform); + + pixman_region32_t frame_damage; + pixman_region32_init(&frame_damage); + wlr_region_transform(&frame_damage, &scene_output->damage->current, + transform, tr_width, tr_height); + wlr_output_set_damage(output, &frame_damage); + pixman_region32_fini(&frame_damage); + + return wlr_output_commit(output); +} -- cgit v1.2.3 From f5b359f5b68b92be2cac3d396fef6feab6078700 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 2 Sep 2021 12:47:28 +0200 Subject: scene: add wlr_scene_attach_output_layout This is a helper to integrate wlr_scene with wlr_output_layout. --- output_layout.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 output_layout.c diff --git a/output_layout.c b/output_layout.c new file mode 100644 index 0000000..33dac13 --- /dev/null +++ b/output_layout.c @@ -0,0 +1,105 @@ +#include +#include +#include + +struct wlr_scene_output_layout { + struct wlr_output_layout *layout; + struct wlr_scene *scene; + + struct wl_listener layout_add; + struct wl_listener layout_change; + struct wl_listener layout_destroy; + struct wl_listener scene_destroy; +}; + +static void scene_output_layout_destroy(struct wlr_scene_output_layout *sol) { + wl_list_remove(&sol->layout_destroy.link); + wl_list_remove(&sol->layout_add.link); + wl_list_remove(&sol->layout_change.link); + wl_list_remove(&sol->scene_destroy.link); + free(sol); +} + +static void scene_output_layout_handle_layout_destroy( + struct wl_listener *listener, void *data) { + struct wlr_scene_output_layout *sol = + wl_container_of(listener, sol, layout_destroy); + + // Remove all outputs managed by the output layout + struct wlr_scene_output *scene_output, *tmp; + wl_list_for_each_safe(scene_output, tmp, &sol->scene->outputs, link) { + struct wlr_output_layout_output *lo = + wlr_output_layout_get(sol->layout, scene_output->output); + if (lo != NULL) { + wlr_scene_output_destroy(scene_output); + } + } + + scene_output_layout_destroy(sol); +} + +static void scene_output_layout_handle_layout_change( + struct wl_listener *listener, void *data) { + struct wlr_scene_output_layout *sol = + wl_container_of(listener, sol, layout_change); + + struct wlr_scene_output *scene_output, *tmp; + wl_list_for_each_safe(scene_output, tmp, &sol->scene->outputs, link) { + struct wlr_output_layout_output *lo = + wlr_output_layout_get(sol->layout, scene_output->output); + if (lo == NULL) { + // Output has been removed from the layout + wlr_scene_output_destroy(scene_output); + continue; + } + + wlr_scene_output_set_position(scene_output, lo->x, lo->y); + } +} + +static void scene_output_layout_handle_layout_add( + struct wl_listener *listener, void *data) { + struct wlr_scene_output_layout *sol = + wl_container_of(listener, sol, layout_add); + struct wlr_output_layout_output *lo = data; + + struct wlr_scene_output *scene_output = + wlr_scene_output_create(sol->scene, lo->output); + if (scene_output == NULL) { + return; + } + + wlr_scene_output_set_position(scene_output, lo->x, lo->y); +} + +static void scene_output_layout_handle_scene_destroy( + struct wl_listener *listener, void *data) { + struct wlr_scene_output_layout *sol = + wl_container_of(listener, sol, scene_destroy); + scene_output_layout_destroy(sol); +} + +bool wlr_scene_attach_output_layout(struct wlr_scene *scene, + struct wlr_output_layout *output_layout) { + struct wlr_scene_output_layout *sol = calloc(1, sizeof(*sol)); + if (sol == NULL) { + return false; + } + + sol->scene = scene; + sol->layout = output_layout; + + sol->layout_destroy.notify = scene_output_layout_handle_layout_destroy; + wl_signal_add(&output_layout->events.destroy, &sol->layout_destroy); + + sol->layout_change.notify = scene_output_layout_handle_layout_change; + wl_signal_add(&output_layout->events.change, &sol->layout_change); + + sol->layout_add.notify = scene_output_layout_handle_layout_add; + wl_signal_add(&output_layout->events.add, &sol->layout_add); + + sol->scene_destroy.notify = scene_output_layout_handle_scene_destroy; + wl_signal_add(&output_layout->events.destroy, &sol->scene_destroy); + + return true; +} -- cgit v1.2.3 From c171032baa8574b3629772a82ec5ea2ac98d6f11 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 20 Aug 2021 11:25:02 +0200 Subject: scene: add wlr_scene_tree --- wlr_scene.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 6a988e5..5d57504 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -15,6 +15,11 @@ static struct wlr_scene *scene_root_from_node(struct wlr_scene_node *node) { return (struct wlr_scene *)node; } +static struct wlr_scene_tree *scene_tree_from_node(struct wlr_scene_node *node) { + assert(node->type == WLR_SCENE_NODE_TREE); + return (struct wlr_scene_tree *)node; +} + struct wlr_scene_surface *wlr_scene_surface_from_node( struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_SURFACE); @@ -84,6 +89,10 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { free(scene); break; + case WLR_SCENE_NODE_TREE:; + struct wlr_scene_tree *tree = scene_tree_from_node(node); + free(tree); + break; case WLR_SCENE_NODE_SURFACE:; struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); wl_list_remove(&scene_surface->surface_destroy.link); @@ -106,6 +115,16 @@ struct wlr_scene *wlr_scene_create(void) { return scene; } +struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_node *parent) { + struct wlr_scene_tree *tree = calloc(1, sizeof(struct wlr_scene_tree)); + if (tree == NULL) { + return NULL; + } + scene_node_init(&tree->node, WLR_SCENE_NODE_TREE, parent); + + return tree; +} + static void scene_surface_handle_surface_destroy(struct wl_listener *listener, void *data) { struct wlr_scene_surface *scene_surface = @@ -246,6 +265,7 @@ static void _scene_node_damage_whole(struct wlr_scene_node *node, int width = 0, height = 0; switch (node->type) { case WLR_SCENE_NODE_ROOT: + case WLR_SCENE_NODE_TREE: return; case WLR_SCENE_NODE_SURFACE:; struct wlr_scene_surface *scene_surface = @@ -536,8 +556,9 @@ static void render_node_iterator(struct wlr_scene_node *node, }; switch (node->type) { - case WLR_SCENE_NODE_ROOT:; - /* Root node has nothing to render itself */ + case WLR_SCENE_NODE_ROOT: + case WLR_SCENE_NODE_TREE: + /* Root or tree node has nothing to render itself */ break; case WLR_SCENE_NODE_SURFACE:; struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); -- cgit v1.2.3 From da2fd7b1ab124c36e9caca17218d33f6e9df852e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 20 Aug 2021 12:41:23 +0200 Subject: scene: add wlr_scene_subsurface_tree_create --- subsurface_tree.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) create mode 100644 subsurface_tree.c diff --git a/subsurface_tree.c b/subsurface_tree.c new file mode 100644 index 0000000..7cfa882 --- /dev/null +++ b/subsurface_tree.c @@ -0,0 +1,218 @@ +#include +#include +#include +#include + +/** + * A tree for a surface and all of its child sub-surfaces. + * + * `tree` contains `scene_surface` and one node per sub-surface. + */ +struct wlr_scene_subsurface_tree { + struct wlr_scene_tree *tree; + struct wlr_surface *surface; + struct wlr_scene_surface *scene_surface; + + struct wlr_scene_subsurface_tree *parent; // NULL for the top-level surface + struct wlr_addon surface_addon; // only set if there's a parent + + struct wl_listener tree_destroy; + struct wl_listener surface_destroy; + struct wl_listener surface_commit; + struct wl_listener surface_new_subsurface; +}; + +static void subsurface_tree_destroy(struct wlr_scene_subsurface_tree *subsurface_tree) { + // tree and scene_surface will be cleaned up by scene_node_finish + if (subsurface_tree->parent) { + wlr_addon_finish(&subsurface_tree->surface_addon); + } + wl_list_remove(&subsurface_tree->tree_destroy.link); + wl_list_remove(&subsurface_tree->surface_destroy.link); + wl_list_remove(&subsurface_tree->surface_commit.link); + wl_list_remove(&subsurface_tree->surface_new_subsurface.link); + free(subsurface_tree); +} + +static void subsurface_tree_handle_tree_destroy(struct wl_listener *listener, + void *data) { + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(listener, subsurface_tree, tree_destroy); + subsurface_tree_destroy(subsurface_tree); +} + +static void subsurface_tree_handle_surface_destroy(struct wl_listener *listener, + void *data) { + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(listener, subsurface_tree, surface_destroy); + wlr_scene_node_destroy(&subsurface_tree->tree->node); +} + +static const struct wlr_addon_interface subsurface_tree_addon_impl; + +static struct wlr_scene_subsurface_tree *subsurface_tree_from_subsurface( + struct wlr_scene_subsurface_tree *parent, + struct wlr_subsurface *subsurface) { + struct wlr_addon *addon = wlr_addon_find(&subsurface->surface->addons, + parent, &subsurface_tree_addon_impl); + assert(addon != NULL); + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(addon, subsurface_tree, surface_addon); + return subsurface_tree; +} + +static void subsurface_tree_reconfigure( + struct wlr_scene_subsurface_tree *subsurface_tree) { + struct wlr_surface *surface = subsurface_tree->surface; + + struct wlr_scene_node *prev = NULL; + struct wlr_subsurface *subsurface; + wl_list_for_each(subsurface, &surface->current.subsurfaces_below, + current.link) { + struct wlr_scene_subsurface_tree *child = + subsurface_tree_from_subsurface(subsurface_tree, subsurface); + if (prev != NULL) { + wlr_scene_node_place_above(&child->tree->node, prev); + } + prev = &child->tree->node; + + wlr_scene_node_set_position(&child->tree->node, + subsurface->current.x, subsurface->current.y); + } + + if (prev != NULL) { + wlr_scene_node_place_above(&subsurface_tree->scene_surface->node, prev); + } + prev = &subsurface_tree->scene_surface->node; + + wl_list_for_each(subsurface, &surface->current.subsurfaces_above, + current.link) { + struct wlr_scene_subsurface_tree *child = + subsurface_tree_from_subsurface(subsurface_tree, subsurface); + wlr_scene_node_place_above(&child->tree->node, prev); + prev = &child->tree->node; + + wlr_scene_node_set_position(&child->tree->node, + subsurface->current.x, subsurface->current.y); + } +} + +static void subsurface_tree_handle_surface_commit(struct wl_listener *listener, + void *data) { + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(listener, subsurface_tree, surface_commit); + + // TODO: only do this on subsurface order or position change + subsurface_tree_reconfigure(subsurface_tree); +} + +static void subsurface_tree_addon_destroy(struct wlr_addon *addon) { + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(addon, subsurface_tree, surface_addon); + wlr_scene_node_destroy(&subsurface_tree->tree->node); +} + +static const struct wlr_addon_interface subsurface_tree_addon_impl = { + .name = "wlr_scene_subsurface_tree", + .destroy = subsurface_tree_addon_destroy, +}; + +static struct wlr_scene_subsurface_tree *scene_surface_tree_create( + struct wlr_scene_node *parent, struct wlr_surface *surface); + +static bool subsurface_tree_create_subsurface( + struct wlr_scene_subsurface_tree *parent, + struct wlr_subsurface *subsurface) { + struct wlr_scene_subsurface_tree *child = scene_surface_tree_create( + &parent->tree->node, subsurface->surface); + if (child == NULL) { + return false; + } + + child->parent = parent; + wlr_addon_init(&child->surface_addon, &subsurface->surface->addons, + parent, &subsurface_tree_addon_impl); + + return true; +} + +static void subsurface_tree_handle_surface_new_subsurface( + struct wl_listener *listener, void *data) { + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(listener, subsurface_tree, surface_new_subsurface); + struct wlr_subsurface *subsurface = data; + if (!subsurface_tree_create_subsurface(subsurface_tree, subsurface)) { + wl_resource_post_no_memory(subsurface->resource); + } +} + +static struct wlr_scene_subsurface_tree *scene_surface_tree_create( + struct wlr_scene_node *parent, struct wlr_surface *surface) { + struct wlr_scene_subsurface_tree *subsurface_tree = + calloc(1, sizeof(*subsurface_tree)); + if (subsurface_tree == NULL) { + return NULL; + } + + subsurface_tree->tree = wlr_scene_tree_create(parent); + if (subsurface_tree->tree == NULL) { + goto error_surface_tree; + } + + subsurface_tree->scene_surface = + wlr_scene_surface_create(&subsurface_tree->tree->node, surface); + if (subsurface_tree->scene_surface == NULL) { + goto error_scene_surface; + } + + subsurface_tree->surface = surface; + + struct wlr_subsurface *subsurface; + wl_list_for_each(subsurface, &surface->current.subsurfaces_below, + current.link) { + if (!subsurface_tree_create_subsurface(subsurface_tree, subsurface)) { + goto error_scene_surface; + } + } + wl_list_for_each(subsurface, &surface->current.subsurfaces_above, + current.link) { + if (!subsurface_tree_create_subsurface(subsurface_tree, subsurface)) { + goto error_scene_surface; + } + } + + subsurface_tree_reconfigure(subsurface_tree); + + subsurface_tree->tree_destroy.notify = subsurface_tree_handle_tree_destroy; + wl_signal_add(&subsurface_tree->tree->node.events.destroy, + &subsurface_tree->tree_destroy); + + subsurface_tree->surface_destroy.notify = subsurface_tree_handle_surface_destroy; + wl_signal_add(&surface->events.destroy, &subsurface_tree->surface_destroy); + + subsurface_tree->surface_commit.notify = subsurface_tree_handle_surface_commit; + wl_signal_add(&surface->events.commit, &subsurface_tree->surface_commit); + + subsurface_tree->surface_new_subsurface.notify = + subsurface_tree_handle_surface_new_subsurface; + wl_signal_add(&surface->events.new_subsurface, + &subsurface_tree->surface_new_subsurface); + + return subsurface_tree; + +error_scene_surface: + wlr_scene_node_destroy(&subsurface_tree->tree->node); +error_surface_tree: + free(subsurface_tree); + return NULL; +} + +struct wlr_scene_node *wlr_scene_subsurface_tree_create( + struct wlr_scene_node *parent, struct wlr_surface *surface) { + struct wlr_scene_subsurface_tree *subsurface_tree = + scene_surface_tree_create(parent, surface); + if (subsurface_tree == NULL) { + return NULL; + } + return &subsurface_tree->tree->node; +} -- cgit v1.2.3 From 6c1a00b6d73e4374d1ec354366cade34d0f66e4d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 20 Sep 2021 18:20:12 +0200 Subject: scene: drop default case in wlr_scene_node_at This allows the compiler to error out if we haven't enumerated all of the cases. This is useful to avoid a missing implementation when adding a new node type. --- wlr_scene.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 5d57504..31e0fd9 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -446,6 +446,9 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, } switch (node->type) { + case WLR_SCENE_NODE_ROOT: + case WLR_SCENE_NODE_TREE: + break; case WLR_SCENE_NODE_SURFACE:; struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); if (wlr_surface_point_accepts_input(scene_surface->surface, lx, ly)) { @@ -470,8 +473,6 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, return &rect->node; } break; - default: - break; } return NULL; -- cgit v1.2.3 From 7a4056aaa24353165ea2d6f082c541a2b370333a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 20 Sep 2021 18:32:44 +0200 Subject: scene: unify intersection logic in wlr_scene_node_at Let's extract the common bits. --- wlr_scene.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 31e0fd9..7f8f8e7 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -445,36 +445,31 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, } } + bool intersects = false; switch (node->type) { case WLR_SCENE_NODE_ROOT: case WLR_SCENE_NODE_TREE: break; case WLR_SCENE_NODE_SURFACE:; struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); - if (wlr_surface_point_accepts_input(scene_surface->surface, lx, ly)) { - if (nx != NULL) { - *nx = lx; - } - if (ny != NULL) { - *ny = ly; - } - return &scene_surface->node; - } + intersects = wlr_surface_point_accepts_input(scene_surface->surface, lx, ly); break; case WLR_SCENE_NODE_RECT:; struct wlr_scene_rect *rect = scene_rect_from_node(node); - if (lx >= 0 && lx < rect->width && ly >= 0 && ly < rect->height) { - if (nx != NULL) { - *nx = lx; - } - if (ny != NULL) { - *ny = ly; - } - return &rect->node; - } + intersects = lx >= 0 && lx < rect->width && ly >= 0 && ly < rect->height; break; } + if (intersects) { + if (nx != NULL) { + *nx = lx; + } + if (ny != NULL) { + *ny = ly; + } + return node; + } + return NULL; } -- cgit v1.2.3 From 2e9bcd0a57884aefed9fbabb0ff9474121fa7b5a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 20 Sep 2021 16:05:19 +0200 Subject: scene: add wlr_scene_buffer This new scene-graph node displays a wlr_buffer. Closes: https://github.com/swaywm/wlroots/issues/3161 --- wlr_scene.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 7f8f8e7..aa126f8 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -32,6 +32,12 @@ static struct wlr_scene_rect *scene_rect_from_node( return (struct wlr_scene_rect *)node; } +static struct wlr_scene_buffer *scene_buffer_from_node( + struct wlr_scene_node *node) { + assert(node->type == WLR_SCENE_NODE_BUFFER); + return (struct wlr_scene_buffer *)node; +} + static void scene_node_state_init(struct wlr_scene_node_state *state) { wl_list_init(&state->children); wl_list_init(&state->link); @@ -102,6 +108,12 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); free(scene_rect); break; + case WLR_SCENE_NODE_BUFFER:; + struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + wlr_texture_destroy(scene_buffer->texture); + wlr_buffer_unlock(scene_buffer->buffer); + free(scene_buffer); + break; } } @@ -239,6 +251,38 @@ void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[sta scene_node_damage_whole(&rect->node); } +struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, + struct wlr_buffer *buffer) { + struct wlr_scene_buffer *scene_buffer = calloc(1, sizeof(*scene_buffer)); + if (scene_buffer == NULL) { + return NULL; + } + scene_node_init(&scene_buffer->node, WLR_SCENE_NODE_BUFFER, parent); + + scene_buffer->buffer = wlr_buffer_lock(buffer); + + scene_node_damage_whole(&scene_buffer->node); + + return scene_buffer; +} + +static struct wlr_texture *scene_buffer_get_texture( + struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) { + struct wlr_client_buffer *client_buffer = + wlr_client_buffer_get(scene_buffer->buffer); + if (client_buffer != NULL) { + return client_buffer->texture; + } + + if (scene_buffer->texture != NULL) { + return scene_buffer->texture; + } + + scene_buffer->texture = + wlr_texture_from_buffer(renderer, scene_buffer->buffer); + return scene_buffer->texture; +} + static int scale_length(int length, int offset, float scale) { return round((offset + length) * scale) - round(offset * scale); } @@ -278,6 +322,11 @@ static void _scene_node_damage_whole(struct wlr_scene_node *node, width = scene_rect->width; height = scene_rect->height; break; + case WLR_SCENE_NODE_BUFFER:; + struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + width = scene_buffer->buffer->width; + height = scene_buffer->buffer->height; + break; } struct wlr_scene_output *scene_output; @@ -458,6 +507,11 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, struct wlr_scene_rect *rect = scene_rect_from_node(node); intersects = lx >= 0 && lx < rect->width && ly >= 0 && ly < rect->height; break; + case WLR_SCENE_NODE_BUFFER:; + struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + intersects = lx >= 0 && lx < scene_buffer->buffer->width && + ly >= 0 && ly < scene_buffer->buffer->height; + break; } if (intersects) { @@ -551,6 +605,8 @@ static void render_node_iterator(struct wlr_scene_node *node, .y = y, }; + struct wlr_texture *texture; + float matrix[9]; switch (node->type) { case WLR_SCENE_NODE_ROOT: case WLR_SCENE_NODE_TREE: @@ -560,7 +616,7 @@ static void render_node_iterator(struct wlr_scene_node *node, struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); struct wlr_surface *surface = scene_surface->surface; - struct wlr_texture *texture = wlr_surface_get_texture(surface); + texture = wlr_surface_get_texture(surface); if (texture == NULL) { return; } @@ -569,7 +625,6 @@ static void render_node_iterator(struct wlr_scene_node *node, box.height = surface->current.height; scale_box(&box, output->scale); - float matrix[9]; enum wl_output_transform transform = wlr_output_transform_invert(surface->current.transform); wlr_matrix_project_box(matrix, &box, transform, 0.0, @@ -587,6 +642,24 @@ static void render_node_iterator(struct wlr_scene_node *node, render_rect(output, output_damage, scene_rect->color, &box, output->transform_matrix); break; + case WLR_SCENE_NODE_BUFFER:; + struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + + struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + texture = scene_buffer_get_texture(scene_buffer, renderer); + if (texture == NULL) { + return; + } + + box.width = scene_buffer->buffer->width; + box.height = scene_buffer->buffer->height; + scale_box(&box, data->output->scale); + + wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0.0, + output->transform_matrix); + + render_texture(output, output_damage, texture, &box, matrix); + break; } } -- cgit v1.2.3 From 9a1123b2e15ceb870fb4d351eba49ca439b3877b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 20 Sep 2021 17:41:52 +0200 Subject: scene: add wlr_scene_buffer_set_source_box --- wlr_scene.c | 65 +++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index aa126f8..108f18f 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -266,6 +266,23 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, return scene_buffer; } +void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer, + const struct wlr_fbox *box) { + struct wlr_fbox *cur = &scene_buffer->src_box; + if ((wlr_fbox_empty(box) && wlr_fbox_empty(cur)) || + (box != NULL && memcmp(cur, box, sizeof(*box)) == 0)) { + return; + } + + if (box != NULL) { + memcpy(cur, box, sizeof(*box)); + } else { + memset(cur, 0, sizeof(*cur)); + } + + scene_node_damage_whole(&scene_buffer->node); +} + static struct wlr_texture *scene_buffer_get_texture( struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) { struct wlr_client_buffer *client_buffer = @@ -571,20 +588,29 @@ static void render_rect(struct wlr_output *output, static void render_texture(struct wlr_output *output, pixman_region32_t *output_damage, struct wlr_texture *texture, - const struct wlr_box *box, const float matrix[static 9]) { + const struct wlr_fbox *src_box, const struct wlr_box *dst_box, + const float matrix[static 9]) { struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); assert(renderer); + struct wlr_fbox default_src_box = {0}; + if (wlr_fbox_empty(src_box)) { + default_src_box.width = dst_box->width; + default_src_box.height = dst_box->height; + src_box = &default_src_box; + } + pixman_region32_t damage; pixman_region32_init(&damage); - pixman_region32_init_rect(&damage, box->x, box->y, box->width, box->height); + pixman_region32_init_rect(&damage, dst_box->x, dst_box->y, + dst_box->width, dst_box->height); pixman_region32_intersect(&damage, &damage, output_damage); int nrects; pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); - wlr_render_texture_with_matrix(renderer, texture, matrix, 1.0); + wlr_render_subtexture_with_matrix(renderer, texture, src_box, matrix, 1.0); } pixman_region32_fini(&damage); @@ -600,7 +626,7 @@ static void render_node_iterator(struct wlr_scene_node *node, struct render_data *data = _data; struct wlr_output *output = data->output; pixman_region32_t *output_damage = data->damage; - struct wlr_box box = { + struct wlr_box dst_box = { .x = x, .y = y, }; @@ -621,26 +647,26 @@ static void render_node_iterator(struct wlr_scene_node *node, return; } - box.width = surface->current.width; - box.height = surface->current.height; - scale_box(&box, output->scale); + dst_box.width = surface->current.width; + dst_box.height = surface->current.height; + scale_box(&dst_box, output->scale); enum wl_output_transform transform = wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box(matrix, &box, transform, 0.0, + wlr_matrix_project_box(matrix, &dst_box, transform, 0.0, output->transform_matrix); - render_texture(output, output_damage, texture, &box, matrix); + render_texture(output, output_damage, texture, NULL, &dst_box, matrix); break; case WLR_SCENE_NODE_RECT:; struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); - box.width = scene_rect->width; - box.height = scene_rect->height; - scale_box(&box, data->output->scale); + dst_box.width = scene_rect->width; + dst_box.height = scene_rect->height; + scale_box(&dst_box, data->output->scale); - render_rect(output, output_damage, scene_rect->color, &box, - output->transform_matrix); + render_rect(output, output_damage, scene_rect->color, &dst_box, + output->transform_matrix); break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); @@ -651,14 +677,15 @@ static void render_node_iterator(struct wlr_scene_node *node, return; } - box.width = scene_buffer->buffer->width; - box.height = scene_buffer->buffer->height; - scale_box(&box, data->output->scale); + dst_box.width = scene_buffer->buffer->width; + dst_box.height = scene_buffer->buffer->height; + scale_box(&dst_box, data->output->scale); - wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, 0.0, + wlr_matrix_project_box(matrix, &dst_box, WL_OUTPUT_TRANSFORM_NORMAL, 0.0, output->transform_matrix); - render_texture(output, output_damage, texture, &box, matrix); + render_texture(output, output_damage, texture, &scene_buffer->src_box, + &dst_box, matrix); break; } } -- cgit v1.2.3 From fe764946fa7c995adccf30ca40f294c8f1151d44 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 20 Sep 2021 18:14:50 +0200 Subject: scene: add scene_node_get_size helper --- wlr_scene.c | 67 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 108f18f..4004b50 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -300,6 +300,34 @@ static struct wlr_texture *scene_buffer_get_texture( return scene_buffer->texture; } +static void scene_node_get_size(struct wlr_scene_node *node, + int *width, int *height) { + *width = 0; + *height = 0; + + switch (node->type) { + case WLR_SCENE_NODE_ROOT: + case WLR_SCENE_NODE_TREE: + return; + case WLR_SCENE_NODE_SURFACE:; + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_node(node); + *width = scene_surface->surface->current.width; + *height = scene_surface->surface->current.height; + break; + case WLR_SCENE_NODE_RECT:; + struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); + *width = scene_rect->width; + *height = scene_rect->height; + break; + case WLR_SCENE_NODE_BUFFER:; + struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + *width = scene_buffer->buffer->width; + *height = scene_buffer->buffer->height; + break; + } +} + static int scale_length(int length, int offset, float scale) { return round((offset + length) * scale) - round(offset * scale); } @@ -323,28 +351,8 @@ static void _scene_node_damage_whole(struct wlr_scene_node *node, lx + child->state.x, ly + child->state.y); } - int width = 0, height = 0; - switch (node->type) { - case WLR_SCENE_NODE_ROOT: - case WLR_SCENE_NODE_TREE: - return; - case WLR_SCENE_NODE_SURFACE:; - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_from_node(node); - width = scene_surface->surface->current.width; - height = scene_surface->surface->current.height; - break; - case WLR_SCENE_NODE_RECT:; - struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); - width = scene_rect->width; - height = scene_rect->height; - break; - case WLR_SCENE_NODE_BUFFER:; - struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); - width = scene_buffer->buffer->width; - height = scene_buffer->buffer->height; - break; - } + int width, height; + scene_node_get_size(node, &width, &height); struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { @@ -626,10 +634,13 @@ static void render_node_iterator(struct wlr_scene_node *node, struct render_data *data = _data; struct wlr_output *output = data->output; pixman_region32_t *output_damage = data->damage; + struct wlr_box dst_box = { .x = x, .y = y, }; + scene_node_get_size(node, &dst_box.width, &dst_box.height); + scale_box(&dst_box, output->scale); struct wlr_texture *texture; float matrix[9]; @@ -647,10 +658,6 @@ static void render_node_iterator(struct wlr_scene_node *node, return; } - dst_box.width = surface->current.width; - dst_box.height = surface->current.height; - scale_box(&dst_box, output->scale); - enum wl_output_transform transform = wlr_output_transform_invert(surface->current.transform); wlr_matrix_project_box(matrix, &dst_box, transform, 0.0, @@ -661,10 +668,6 @@ static void render_node_iterator(struct wlr_scene_node *node, case WLR_SCENE_NODE_RECT:; struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); - dst_box.width = scene_rect->width; - dst_box.height = scene_rect->height; - scale_box(&dst_box, data->output->scale); - render_rect(output, output_damage, scene_rect->color, &dst_box, output->transform_matrix); break; @@ -677,10 +680,6 @@ static void render_node_iterator(struct wlr_scene_node *node, return; } - dst_box.width = scene_buffer->buffer->width; - dst_box.height = scene_buffer->buffer->height; - scale_box(&dst_box, data->output->scale); - wlr_matrix_project_box(matrix, &dst_box, WL_OUTPUT_TRANSFORM_NORMAL, 0.0, output->transform_matrix); -- cgit v1.2.3 From 8bffb941c9a4791558e66bf0ce35af268c208203 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 20 Sep 2021 18:46:55 +0200 Subject: scene: use scene_node_get_size in wlr_scene_node_at This allows to unify the RECT and BUFFER code-paths. The BUFFER one will become more complicated with destination size and transforms. --- wlr_scene.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 4004b50..2d3dccd 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -528,14 +528,11 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); intersects = wlr_surface_point_accepts_input(scene_surface->surface, lx, ly); break; - case WLR_SCENE_NODE_RECT:; - struct wlr_scene_rect *rect = scene_rect_from_node(node); - intersects = lx >= 0 && lx < rect->width && ly >= 0 && ly < rect->height; - break; + case WLR_SCENE_NODE_RECT: case WLR_SCENE_NODE_BUFFER:; - struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); - intersects = lx >= 0 && lx < scene_buffer->buffer->width && - ly >= 0 && ly < scene_buffer->buffer->height; + int width, height; + scene_node_get_size(node, &width, &height); + intersects = lx >= 0 && lx < width && ly >= 0 && ly < height; break; } -- cgit v1.2.3 From 8b2b38375343f890da8666dd2077cf8c6fe1aeb5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 20 Sep 2021 18:05:11 +0200 Subject: scene: add wlr_scene_buffer_set_dest_size --- wlr_scene.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 2d3dccd..f4aec1d 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -283,6 +283,18 @@ void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer, scene_node_damage_whole(&scene_buffer->node); } +void wlr_scene_buffer_set_dest_size(struct wlr_scene_buffer *scene_buffer, + int width, int height) { + if (scene_buffer->dst_width == width && scene_buffer->dst_height == height) { + return; + } + + scene_node_damage_whole(&scene_buffer->node); + scene_buffer->dst_width = width; + scene_buffer->dst_height = height; + scene_node_damage_whole(&scene_buffer->node); +} + static struct wlr_texture *scene_buffer_get_texture( struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) { struct wlr_client_buffer *client_buffer = @@ -322,8 +334,13 @@ static void scene_node_get_size(struct wlr_scene_node *node, break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); - *width = scene_buffer->buffer->width; - *height = scene_buffer->buffer->height; + if (scene_buffer->dst_width > 0 && scene_buffer->dst_height > 0) { + *width = scene_buffer->dst_width; + *height = scene_buffer->dst_height; + } else { + *width = scene_buffer->buffer->width; + *height = scene_buffer->buffer->height; + } break; } } -- cgit v1.2.3 From 226c87b894a41fcee38e61257bc97e4c021c9a5b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 20 Sep 2021 18:19:05 +0200 Subject: scene: add wlr_scene_buffer_set_transform --- wlr_scene.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index f4aec1d..9ba283e 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -295,6 +295,17 @@ void wlr_scene_buffer_set_dest_size(struct wlr_scene_buffer *scene_buffer, scene_node_damage_whole(&scene_buffer->node); } +void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer, + enum wl_output_transform transform) { + if (scene_buffer->transform == transform) { + return; + } + + scene_node_damage_whole(&scene_buffer->node); + scene_buffer->transform = transform; + scene_node_damage_whole(&scene_buffer->node); +} + static struct wlr_texture *scene_buffer_get_texture( struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) { struct wlr_client_buffer *client_buffer = @@ -338,8 +349,13 @@ static void scene_node_get_size(struct wlr_scene_node *node, *width = scene_buffer->dst_width; *height = scene_buffer->dst_height; } else { - *width = scene_buffer->buffer->width; - *height = scene_buffer->buffer->height; + if (scene_buffer->transform & WL_OUTPUT_TRANSFORM_90) { + *height = scene_buffer->buffer->width; + *width = scene_buffer->buffer->height; + } else { + *width = scene_buffer->buffer->width; + *height = scene_buffer->buffer->height; + } } break; } @@ -658,6 +674,7 @@ static void render_node_iterator(struct wlr_scene_node *node, struct wlr_texture *texture; float matrix[9]; + enum wl_output_transform transform; switch (node->type) { case WLR_SCENE_NODE_ROOT: case WLR_SCENE_NODE_TREE: @@ -672,8 +689,7 @@ static void render_node_iterator(struct wlr_scene_node *node, return; } - enum wl_output_transform transform = - wlr_output_transform_invert(surface->current.transform); + transform = wlr_output_transform_invert(surface->current.transform); wlr_matrix_project_box(matrix, &dst_box, transform, 0.0, output->transform_matrix); @@ -694,7 +710,8 @@ static void render_node_iterator(struct wlr_scene_node *node, return; } - wlr_matrix_project_box(matrix, &dst_box, WL_OUTPUT_TRANSFORM_NORMAL, 0.0, + transform = wlr_output_transform_invert(scene_buffer->transform); + wlr_matrix_project_box(matrix, &dst_box, transform, 0.0, output->transform_matrix); render_texture(output, output_damage, texture, &scene_buffer->src_box, -- cgit v1.2.3 From a4ea63f084e292e7bca884605fb0607ffd9b454f Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Wed, 13 Oct 2021 16:00:53 +0200 Subject: scene: assert that node != sibling in place above/below Currently these functions remove the node from the scene if the sibling argument is the same node as the node. To prevent confusion when misusing this API, assert that the nodes are distinct and document this. --- wlr_scene.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 9ba283e..2dc2924 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -440,6 +440,7 @@ void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y) { void wlr_scene_node_place_above(struct wlr_scene_node *node, struct wlr_scene_node *sibling) { + assert(node != sibling); assert(node->parent == sibling->parent); if (node->state.link.prev == &sibling->state.link) { @@ -455,6 +456,7 @@ void wlr_scene_node_place_above(struct wlr_scene_node *node, void wlr_scene_node_place_below(struct wlr_scene_node *node, struct wlr_scene_node *sibling) { + assert(node != sibling); assert(node->parent == sibling->parent); if (node->state.link.next == &sibling->state.link) { -- cgit v1.2.3 From aa739b6a833370263d721ec89a7fa203e19f690d Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Wed, 13 Oct 2021 16:11:54 +0200 Subject: scene: add functions to place node on top/bottom These are very common operations for compositors (including tinywl) to perform. --- wlr_scene.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 2dc2924..be44bcc 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -470,6 +470,24 @@ void wlr_scene_node_place_below(struct wlr_scene_node *node, scene_node_damage_whole(sibling); } +void wlr_scene_node_raise_to_top(struct wlr_scene_node *node) { + struct wlr_scene_node *current_top = wl_container_of( + node->parent->state.children.prev, current_top, state.link); + if (node == current_top) { + return; + } + wlr_scene_node_place_above(node, current_top); +} + +void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node) { + struct wlr_scene_node *current_bottom = wl_container_of( + node->parent->state.children.prev, current_bottom, state.link); + if (node == current_bottom) { + return; + } + wlr_scene_node_place_below(node, current_bottom); +} + void wlr_scene_node_reparent(struct wlr_scene_node *node, struct wlr_scene_node *new_parent) { assert(node->type != WLR_SCENE_NODE_ROOT && new_parent != NULL); -- cgit v1.2.3 From d0da010a72e4d5eced4ea18fff280bb28ddd9d40 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 18 Oct 2021 14:33:59 +0200 Subject: scene: remove surface commit listener when node is destroyed --- wlr_scene.c | 1 + 1 file changed, 1 insertion(+) diff --git a/wlr_scene.c b/wlr_scene.c index be44bcc..30d5deb 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -101,6 +101,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { break; case WLR_SCENE_NODE_SURFACE:; struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); + wl_list_remove(&scene_surface->surface_commit.link); wl_list_remove(&scene_surface->surface_destroy.link); free(scene_surface); break; -- cgit v1.2.3 From ad910d4a900f6f61affddc298d135324e4e09c62 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 20 Oct 2021 18:16:27 +0200 Subject: scene: add wlr_scene_output_for_each_surface This allows compositors to more easily implement sending wl_surface.frame callback done events. --- wlr_scene.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 30d5deb..ddb6f21 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -887,3 +887,41 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { return wlr_output_commit(output); } + +static void scene_output_for_each_surface(const struct wlr_box *output_box, + struct wlr_scene_node *node, int lx, int ly, + wlr_surface_iterator_func_t user_iterator, void *user_data) { + if (!node->state.enabled) { + return; + } + + lx += node->state.x; + ly += node->state.y; + + if (node->type == WLR_SCENE_NODE_SURFACE) { + struct wlr_box node_box = { .x = lx, .y = ly }; + scene_node_get_size(node, &node_box.width, &node_box.height); + + struct wlr_box intersection; + if (wlr_box_intersection(&intersection, output_box, &node_box)) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_node(node); + user_iterator(scene_surface->surface, lx, ly, user_data); + } + } + + struct wlr_scene_node *child; + wl_list_for_each(child, &node->state.children, state.link) { + scene_output_for_each_surface(output_box, child, lx, ly, + user_iterator, user_data); + } +} + +void wlr_scene_output_for_each_surface(struct wlr_scene_output *scene_output, + wlr_surface_iterator_func_t iterator, void *user_data) { + struct wlr_box box = { .x = scene_output->x, .y = scene_output->y }; + wlr_output_effective_resolution(scene_output->output, + &box.width, &box.height); + scene_output_for_each_surface(&box, &scene_output->scene->node, 0, 0, + iterator, user_data); +} -- cgit v1.2.3 From 45f5723ecb93fad6705bddc01e899af0bea5072d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 20 Oct 2021 16:08:47 +0200 Subject: scene: add support for direct scan-out Check if only a single node intersects with the output viewport and all of its properties match. In this case, attempt direct scan-out. --- wlr_scene.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index ddb6f21..940886a 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "util/signal.h" @@ -835,12 +836,104 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, wlr_output_damage_add_whole(scene_output->damage); } +struct check_scanout_data { + // in + struct wlr_box viewport_box; + // out + struct wlr_scene_node *node; + size_t n; +}; + +static void check_scanout_iterator(struct wlr_scene_node *node, + int x, int y, void *_data) { + struct check_scanout_data *data = _data; + + struct wlr_box node_box = { .x = x, .y = y }; + scene_node_get_size(node, &node_box.width, &node_box.height); + + struct wlr_box intersection; + if (!wlr_box_intersection(&intersection, &data->viewport_box, &node_box)) { + return; + } + + data->n++; + + if (data->viewport_box.x == node_box.x && + data->viewport_box.y == node_box.y && + data->viewport_box.width == node_box.width && + data->viewport_box.height == node_box.height) { + data->node = node; + } +} + +static bool scene_output_scanout(struct wlr_scene_output *scene_output) { + struct wlr_output *output = scene_output->output; + + struct wlr_box viewport_box = { .x = scene_output->x, .y = scene_output->y }; + wlr_output_effective_resolution(output, + &viewport_box.width, &viewport_box.height); + + struct check_scanout_data check_scanout_data = { + .viewport_box = viewport_box, + }; + scene_node_for_each_node(&scene_output->scene->node, 0, 0, + check_scanout_iterator, &check_scanout_data); + if (check_scanout_data.n != 1 || check_scanout_data.node == NULL) { + return false; + } + + struct wlr_scene_node *node = check_scanout_data.node; + struct wlr_buffer *buffer; + switch (node->type) { + case WLR_SCENE_NODE_SURFACE:; + struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); + if (scene_surface->surface->buffer == NULL || + scene_surface->surface->current.viewport.has_src || + scene_surface->surface->current.transform != output->transform) { + return false; + } + buffer = &scene_surface->surface->buffer->base; + break; + case WLR_SCENE_NODE_BUFFER:; + struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + if (scene_buffer->buffer == NULL || + !wlr_fbox_empty(&scene_buffer->src_box) || + scene_buffer->transform != output->transform) { + return false; + } + buffer = scene_buffer->buffer; + break; + default: + return false; + } + + wlr_output_attach_buffer(output, buffer); + if (!wlr_output_test(output)) { + wlr_output_rollback(output); + return false; + } + + return wlr_output_commit(output); +} + bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { struct wlr_output *output = scene_output->output; struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); assert(renderer != NULL); + bool scanout = scene_output_scanout(scene_output); + if (scanout != scene_output->prev_scanout) { + wlr_log(WLR_DEBUG, "Direct scan-out %s", + scanout ? "enabled" : "disabled"); + // When exiting direct scan-out, damage everything + wlr_output_damage_add_whole(scene_output->damage); + } + scene_output->prev_scanout = scanout; + if (scanout) { + return true; + } + bool needs_frame; pixman_region32_t damage; pixman_region32_init(&damage); -- cgit v1.2.3 From e17a0b7eae81901f55fce785eb090543288d5d2d Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 27 Oct 2021 15:42:08 +0200 Subject: scene: inline subsurface_tree_destroy This is only called from one function. To destroy the wlr_scene_subsurface_tree from elsewhere, callers can destroy the scene-graph node returned by wlr_scene_subsurface_tree_create instead (just like a compositor would do). subsurface_tree_handle_surface_destroy does exactly this. Inlining avoids calling subsurface_tree_destroy by mistake. --- subsurface_tree.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/subsurface_tree.c b/subsurface_tree.c index 7cfa882..cd8d23d 100644 --- a/subsurface_tree.c +++ b/subsurface_tree.c @@ -22,7 +22,10 @@ struct wlr_scene_subsurface_tree { struct wl_listener surface_new_subsurface; }; -static void subsurface_tree_destroy(struct wlr_scene_subsurface_tree *subsurface_tree) { +static void subsurface_tree_handle_tree_destroy(struct wl_listener *listener, + void *data) { + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(listener, subsurface_tree, tree_destroy); // tree and scene_surface will be cleaned up by scene_node_finish if (subsurface_tree->parent) { wlr_addon_finish(&subsurface_tree->surface_addon); @@ -34,13 +37,6 @@ static void subsurface_tree_destroy(struct wlr_scene_subsurface_tree *subsurface free(subsurface_tree); } -static void subsurface_tree_handle_tree_destroy(struct wl_listener *listener, - void *data) { - struct wlr_scene_subsurface_tree *subsurface_tree = - wl_container_of(listener, subsurface_tree, tree_destroy); - subsurface_tree_destroy(subsurface_tree); -} - static void subsurface_tree_handle_surface_destroy(struct wl_listener *listener, void *data) { struct wlr_scene_subsurface_tree *subsurface_tree = -- cgit v1.2.3 From 07deb675c09eac2f8ea08302b035a629ea6f2edd Mon Sep 17 00:00:00 2001 From: tiosgz Date: Sun, 31 Oct 2021 14:34:09 +0000 Subject: scene/subsurface_tree: hide unmapped subsurfaces --- subsurface_tree.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/subsurface_tree.c b/subsurface_tree.c index cd8d23d..3f22ee3 100644 --- a/subsurface_tree.c +++ b/subsurface_tree.c @@ -19,6 +19,8 @@ struct wlr_scene_subsurface_tree { struct wl_listener tree_destroy; struct wl_listener surface_destroy; struct wl_listener surface_commit; + struct wl_listener surface_map; + struct wl_listener surface_unmap; struct wl_listener surface_new_subsurface; }; @@ -33,6 +35,8 @@ static void subsurface_tree_handle_tree_destroy(struct wl_listener *listener, wl_list_remove(&subsurface_tree->tree_destroy.link); wl_list_remove(&subsurface_tree->surface_destroy.link); wl_list_remove(&subsurface_tree->surface_commit.link); + wl_list_remove(&subsurface_tree->surface_map.link); + wl_list_remove(&subsurface_tree->surface_unmap.link); wl_list_remove(&subsurface_tree->surface_new_subsurface.link); free(subsurface_tree); } @@ -102,6 +106,22 @@ static void subsurface_tree_handle_surface_commit(struct wl_listener *listener, subsurface_tree_reconfigure(subsurface_tree); } +static void subsurface_tree_handle_surface_map(struct wl_listener *listener, + void *data) { + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(listener, subsurface_tree, surface_map); + + wlr_scene_node_set_enabled(&subsurface_tree->tree->node, true); +} + +static void subsurface_tree_handle_surface_unmap(struct wl_listener *listener, + void *data) { + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(listener, subsurface_tree, surface_unmap); + + wlr_scene_node_set_enabled(&subsurface_tree->tree->node, false); +} + static void subsurface_tree_addon_destroy(struct wlr_addon *addon) { struct wlr_scene_subsurface_tree *subsurface_tree = wl_container_of(addon, subsurface_tree, surface_addon); @@ -126,9 +146,14 @@ static bool subsurface_tree_create_subsurface( } child->parent = parent; + wlr_scene_node_set_enabled(&child->tree->node, subsurface->mapped); + wlr_addon_init(&child->surface_addon, &subsurface->surface->addons, parent, &subsurface_tree_addon_impl); + wl_signal_add(&subsurface->events.map, &child->surface_map); + wl_signal_add(&subsurface->events.unmap, &child->surface_unmap); + return true; } @@ -189,6 +214,12 @@ static struct wlr_scene_subsurface_tree *scene_surface_tree_create( subsurface_tree->surface_commit.notify = subsurface_tree_handle_surface_commit; wl_signal_add(&surface->events.commit, &subsurface_tree->surface_commit); + subsurface_tree->surface_map.notify = subsurface_tree_handle_surface_map; + wl_list_init(&subsurface_tree->surface_map.link); + + subsurface_tree->surface_unmap.notify = subsurface_tree_handle_surface_unmap; + wl_list_init(&subsurface_tree->surface_unmap.link); + subsurface_tree->surface_new_subsurface.notify = subsurface_tree_handle_surface_new_subsurface; wl_signal_add(&surface->events.new_subsurface, -- cgit v1.2.3 From 6fb028b2e0538de6ef1b2c420eb476e1f9a37d25 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 7 Nov 2021 13:28:23 +0100 Subject: scene: fix calloc size mismatch --- wlr_scene.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wlr_scene.c b/wlr_scene.c index 940886a..5a2528d 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -798,7 +798,7 @@ static const struct wlr_addon_interface output_addon_impl = { struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, struct wlr_output *output) { - struct wlr_scene_output *scene_output = calloc(1, sizeof(*output)); + struct wlr_scene_output *scene_output = calloc(1, sizeof(*scene_output)); if (scene_output == NULL) { return NULL; } -- cgit v1.2.3 From 8b556a4864fac7a7d4326e895206f279032f6c0a Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Mon, 15 Nov 2021 12:50:37 -0500 Subject: types/wlr_scene: use renderer from wlr_output --- wlr_scene.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 5a2528d..b6eed41 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -605,7 +605,7 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, } static void scissor_output(struct wlr_output *output, pixman_box32_t *rect) { - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer); struct wlr_box box = { @@ -628,7 +628,7 @@ static void scissor_output(struct wlr_output *output, pixman_box32_t *rect) { static void render_rect(struct wlr_output *output, pixman_region32_t *output_damage, const float color[static 4], const struct wlr_box *box, const float matrix[static 9]) { - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer); pixman_region32_t damage; @@ -650,7 +650,7 @@ static void render_texture(struct wlr_output *output, pixman_region32_t *output_damage, struct wlr_texture *texture, const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9]) { - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer); struct wlr_fbox default_src_box = {0}; @@ -726,7 +726,7 @@ static void render_node_iterator(struct wlr_scene_node *node, case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; texture = scene_buffer_get_texture(scene_buffer, renderer); if (texture == NULL) { return; @@ -768,8 +768,7 @@ void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, damage = &full_region; } - struct wlr_renderer *renderer = - wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer); if (output->enabled && pixman_region32_not_empty(damage)) { @@ -919,7 +918,7 @@ static bool scene_output_scanout(struct wlr_scene_output *scene_output) { bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { struct wlr_output *output = scene_output->output; - struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend); + struct wlr_renderer *renderer = output->renderer; assert(renderer != NULL); bool scanout = scene_output_scanout(scene_output); -- cgit v1.2.3 From f03e1ec21368105ebc0c5bce3a7464b3a7aa8bdc Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 25 Oct 2021 18:29:24 +0200 Subject: scene: add wlr_scene_xdg_surface_create This allows compositors to easily add an xdg_surface to the scene-graph while retaining the ability to unconstraint popups and decide their final position. Compositors can handle new popups with the wlr_xdg_shell.new_surface event, get the parent scene-graph node via wlr_xdg_popup.parent.data, create a new scene-graph node via wlr_scene_xdg_surface_tree_create, and unconstraint the popup if they want to. --- xdg_shell.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 xdg_shell.c diff --git a/xdg_shell.c b/xdg_shell.c new file mode 100644 index 0000000..9b3ad71 --- /dev/null +++ b/xdg_shell.c @@ -0,0 +1,124 @@ +#include +#include +#include + +struct wlr_scene_xdg_surface { + struct wlr_scene_tree *tree; + struct wlr_xdg_surface *xdg_surface; + struct wlr_scene_node *surface_node; + + struct wl_listener tree_destroy; + struct wl_listener xdg_surface_destroy; + struct wl_listener xdg_surface_map; + struct wl_listener xdg_surface_unmap; + struct wl_listener xdg_surface_commit; +}; + +static void scene_xdg_surface_handle_tree_destroy(struct wl_listener *listener, + void *data) { + struct wlr_scene_xdg_surface *scene_xdg_surface = + wl_container_of(listener, scene_xdg_surface, tree_destroy); + // tree and surface_node will be cleaned up by scene_node_finish + wl_list_remove(&scene_xdg_surface->tree_destroy.link); + wl_list_remove(&scene_xdg_surface->xdg_surface_destroy.link); + wl_list_remove(&scene_xdg_surface->xdg_surface_map.link); + wl_list_remove(&scene_xdg_surface->xdg_surface_unmap.link); + wl_list_remove(&scene_xdg_surface->xdg_surface_commit.link); + free(scene_xdg_surface); +} + +static void scene_xdg_surface_handle_xdg_surface_destroy(struct wl_listener *listener, + void *data) { + struct wlr_scene_xdg_surface *scene_xdg_surface = + wl_container_of(listener, scene_xdg_surface, xdg_surface_destroy); + wlr_scene_node_destroy(&scene_xdg_surface->tree->node); +} + +static void scene_xdg_surface_handle_xdg_surface_map(struct wl_listener *listener, + void *data) { + struct wlr_scene_xdg_surface *scene_xdg_surface = + wl_container_of(listener, scene_xdg_surface, xdg_surface_map); + wlr_scene_node_set_enabled(&scene_xdg_surface->tree->node, true); +} + +static void scene_xdg_surface_handle_xdg_surface_unmap(struct wl_listener *listener, + void *data) { + struct wlr_scene_xdg_surface *scene_xdg_surface = + wl_container_of(listener, scene_xdg_surface, xdg_surface_unmap); + wlr_scene_node_set_enabled(&scene_xdg_surface->tree->node, false); +} + +static void scene_xdg_surface_update_position( + struct wlr_scene_xdg_surface *scene_xdg_surface) { + struct wlr_xdg_surface *xdg_surface = scene_xdg_surface->xdg_surface; + + struct wlr_box geo = {0}; + wlr_xdg_surface_get_geometry(xdg_surface, &geo); + wlr_scene_node_set_position(scene_xdg_surface->surface_node, + -geo.x, -geo.y); + + if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { + struct wlr_xdg_popup *popup = xdg_surface->popup; + wlr_scene_node_set_position(&scene_xdg_surface->tree->node, + popup->geometry.x, popup->geometry.y); + } +} + +static void scene_xdg_surface_handle_xdg_surface_commit(struct wl_listener *listener, + void *data) { + struct wlr_scene_xdg_surface *scene_xdg_surface = + wl_container_of(listener, scene_xdg_surface, xdg_surface_commit); + scene_xdg_surface_update_position(scene_xdg_surface); +} + +struct wlr_scene_node *wlr_scene_xdg_surface_create( + struct wlr_scene_node *parent, struct wlr_xdg_surface *xdg_surface) { + struct wlr_scene_xdg_surface *scene_xdg_surface = + calloc(1, sizeof(*scene_xdg_surface)); + if (scene_xdg_surface == NULL) { + return NULL; + } + + scene_xdg_surface->xdg_surface = xdg_surface; + + scene_xdg_surface->tree = wlr_scene_tree_create(parent); + if (scene_xdg_surface->tree == NULL) { + free(scene_xdg_surface); + return NULL; + } + + scene_xdg_surface->surface_node = wlr_scene_subsurface_tree_create( + &scene_xdg_surface->tree->node, xdg_surface->surface); + if (scene_xdg_surface->surface_node == NULL) { + wlr_scene_node_destroy(&scene_xdg_surface->tree->node); + free(scene_xdg_surface); + return NULL; + } + + scene_xdg_surface->tree_destroy.notify = + scene_xdg_surface_handle_tree_destroy; + wl_signal_add(&scene_xdg_surface->tree->node.events.destroy, + &scene_xdg_surface->tree_destroy); + + scene_xdg_surface->xdg_surface_destroy.notify = + scene_xdg_surface_handle_xdg_surface_destroy; + wl_signal_add(&xdg_surface->events.destroy, &scene_xdg_surface->xdg_surface_destroy); + + scene_xdg_surface->xdg_surface_map.notify = + scene_xdg_surface_handle_xdg_surface_map; + wl_signal_add(&xdg_surface->events.map, &scene_xdg_surface->xdg_surface_map); + + scene_xdg_surface->xdg_surface_unmap.notify = + scene_xdg_surface_handle_xdg_surface_unmap; + wl_signal_add(&xdg_surface->events.unmap, &scene_xdg_surface->xdg_surface_unmap); + + scene_xdg_surface->xdg_surface_commit.notify = + scene_xdg_surface_handle_xdg_surface_commit; + wl_signal_add(&xdg_surface->surface->events.commit, + &scene_xdg_surface->xdg_surface_commit); + + wlr_scene_node_set_enabled(&scene_xdg_surface->tree->node, xdg_surface->mapped); + scene_xdg_surface_update_position(scene_xdg_surface); + + return &scene_xdg_surface->tree->node; +} -- cgit v1.2.3 From d320c2acc3a5733e87a883f8c8f615799f019de7 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 26 Nov 2021 10:26:01 +0100 Subject: scene: add support for viewporter If the surface has a source box set, use that. Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3172 --- wlr_scene.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/wlr_scene.c b/wlr_scene.c index b6eed41..0343922 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -715,7 +715,11 @@ static void render_node_iterator(struct wlr_scene_node *node, wlr_matrix_project_box(matrix, &dst_box, transform, 0.0, output->transform_matrix); - render_texture(output, output_damage, texture, NULL, &dst_box, matrix); + struct wlr_fbox src_box = {0}; + wlr_surface_get_buffer_source_box(surface, &src_box); + + render_texture(output, output_damage, texture, + &src_box, &dst_box, matrix); break; case WLR_SCENE_NODE_RECT:; struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); -- cgit v1.2.3 From 7970772290d21575fa00dbe50556914d0723bd4e Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 30 Nov 2021 20:55:04 +0100 Subject: scene: add wlr_scene_get_scene_output This allows getting a wlr_scene_output from a wlr_output. Since an output can only be added once to a scene-graph there's no ambiguity. This is useful for compositors using wlr_scene_attach_output_layout: the output layout integration automatically creates a scene-graph output for each wlr_output added to the layout. --- wlr_scene.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 0343922..d1236fe 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -828,6 +828,18 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { free(scene_output); } +struct wlr_scene_output *wlr_scene_get_scene_output(struct wlr_scene *scene, + struct wlr_output *output) { + struct wlr_addon *addon = + wlr_addon_find(&output->addons, scene, &output_addon_impl); + if (addon == NULL) { + return NULL; + } + struct wlr_scene_output *scene_output = + wl_container_of(addon, scene_output, addon); + return scene_output; +} + void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, int lx, int ly) { if (scene_output->x == lx && scene_output->y == ly) { -- cgit v1.2.3 From cd711ff930198c88598876e39fe07f33b8675837 Mon Sep 17 00:00:00 2001 From: tiosgz Date: Sat, 4 Dec 2021 22:12:58 +0000 Subject: Fix wlr_scene_node_lower_to_bottom Before this commit, it would keep the node at the top or make it second- topmost. --- wlr_scene.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wlr_scene.c b/wlr_scene.c index d1236fe..b1db7b8 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -483,7 +483,7 @@ void wlr_scene_node_raise_to_top(struct wlr_scene_node *node) { void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node) { struct wlr_scene_node *current_bottom = wl_container_of( - node->parent->state.children.prev, current_bottom, state.link); + node->parent->state.children.next, current_bottom, state.link); if (node == current_bottom) { return; } -- cgit v1.2.3 From 3e48d0979e6de643f560f766b15ed3934d79d7e0 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Thu, 9 Dec 2021 23:17:16 +0100 Subject: scene: send surface enter/leave output events Co-authored-by: Simon Ser --- wlr_scene.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 101 insertions(+), 10 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index b1db7b8..d2f3f4a 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -39,6 +39,13 @@ static struct wlr_scene_buffer *scene_buffer_from_node( return (struct wlr_scene_buffer *)node; } +static struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { + while (node->parent != NULL) { + node = node->parent; + } + return scene_root_from_node(node); +} + static void scene_node_state_init(struct wlr_scene_node_state *state) { wl_list_init(&state->children); wl_list_init(&state->link); @@ -85,11 +92,11 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { scene_node_damage_whole(node); scene_node_finish(node); + struct wlr_scene *scene = scene_node_get_root(node); + struct wlr_scene_output *scene_output; switch (node->type) { case WLR_SCENE_NODE_ROOT:; - struct wlr_scene *scene = scene_root_from_node(node); - - struct wlr_scene_output *scene_output, *scene_output_tmp; + struct wlr_scene_output *scene_output_tmp; wl_list_for_each_safe(scene_output, scene_output_tmp, &scene->outputs, link) { wlr_scene_output_destroy(scene_output); } @@ -102,8 +109,16 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { break; case WLR_SCENE_NODE_SURFACE:; struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); + + wl_list_for_each(scene_output, &scene->outputs, link) { + // This is a noop if wlr_surface_send_enter() wasn't previously called for + // the given output. + wlr_surface_send_leave(scene_surface->surface, scene_output->output); + } + wl_list_remove(&scene_surface->surface_commit.link); wl_list_remove(&scene_surface->surface_destroy.link); + free(scene_surface); break; case WLR_SCENE_NODE_RECT:; @@ -146,11 +161,60 @@ static void scene_surface_handle_surface_destroy(struct wl_listener *listener, wlr_scene_node_destroy(&scene_surface->node); } -static struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { - while (node->parent != NULL) { - node = node->parent; +// This function must be called whenever the coordinates/dimensions of a scene +// surface or scene output change. It is not necessary to call when a scene +// surface's node is enabled/disabled or obscured by other nodes. To quote the +// protocol: "The surface might be hidden even if no leave event has been sent." +static void scene_surface_update_outputs( + struct wlr_scene_surface *scene_surface, + int lx, int ly, struct wlr_scene *scene) { + struct wlr_box surface_box = { + .x = lx, + .y = ly, + .width = scene_surface->surface->current.width, + .height = scene_surface->surface->current.height, + }; + + struct wlr_scene_output *scene_output; + wl_list_for_each(scene_output, &scene->outputs, link) { + struct wlr_box output_box = { + .x = scene_output->x, + .y = scene_output->y, + }; + wlr_output_effective_resolution(scene_output->output, + &output_box.width, &output_box.height); + + // These enter/leave functions are a noop if the event has already been + // sent for the given output. + struct wlr_box intersection; + if (wlr_box_intersection(&intersection, &surface_box, &output_box)) { + wlr_surface_send_enter(scene_surface->surface, scene_output->output); + } else { + wlr_surface_send_leave(scene_surface->surface, scene_output->output); + } + } +} + +static void scene_node_update_surface_outputs_iterator( + struct wlr_scene_node *node, int lx, int ly, struct wlr_scene *scene) { + if (node->type == WLR_SCENE_NODE_SURFACE) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_node(node); + scene_surface_update_outputs(scene_surface, lx, ly, scene); + } + + struct wlr_scene_node *child; + wl_list_for_each(child, &node->state.children, state.link) { + scene_node_update_surface_outputs_iterator(child, lx + child->state.x, + ly + child->state.y, scene); } - return scene_root_from_node(node); +} + +static void scene_node_update_surface_outputs(struct wlr_scene_node *node) { + struct wlr_scene *scene = scene_node_get_root(node); + int lx, ly; + wlr_scene_node_coords(node, &lx, &ly); + scene_node_update_surface_outputs_iterator(node, lx, ly, scene); } static void scene_surface_handle_surface_commit(struct wl_listener *listener, @@ -163,12 +227,21 @@ static void scene_surface_handle_surface_commit(struct wl_listener *listener, return; } + struct wlr_scene *scene = scene_node_get_root(&scene_surface->node); + int lx, ly; - if (!wlr_scene_node_coords(&scene_surface->node, &lx, &ly)) { - return; + bool enabled = wlr_scene_node_coords(&scene_surface->node, &lx, &ly); + + if (surface->current.width != scene_surface->prev_width || + surface->current.height != scene_surface->prev_height) { + scene_surface_update_outputs(scene_surface, lx, ly, scene); + scene_surface->prev_width = surface->current.width; + scene_surface->prev_height = surface->current.height; } - struct wlr_scene *scene = scene_node_get_root(&scene_surface->node); + if (!enabled) { + return; + } struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { @@ -212,6 +285,8 @@ struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_node *parent scene_node_damage_whole(&scene_surface->node); + scene_node_update_surface_outputs(&scene_surface->node); + return scene_surface; } @@ -438,6 +513,8 @@ void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y) { node->state.x = x; node->state.y = y; scene_node_damage_whole(node); + + scene_node_update_surface_outputs(node); } void wlr_scene_node_place_above(struct wlr_scene_node *node, @@ -511,6 +588,8 @@ void wlr_scene_node_reparent(struct wlr_scene_node *node, wl_list_insert(new_parent->state.children.prev, &node->state.link); scene_node_damage_whole(node); + + scene_node_update_surface_outputs(node); } bool wlr_scene_node_coords(struct wlr_scene_node *node, @@ -822,9 +901,19 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, return scene_output; } +static void scene_output_send_leave_iterator(struct wlr_surface *surface, + int sx, int sy, void *data) { + struct wlr_output *output = data; + wlr_surface_send_leave(surface, output); +} + void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { wlr_addon_finish(&scene_output->addon); wl_list_remove(&scene_output->link); + + wlr_scene_output_for_each_surface(scene_output, + scene_output_send_leave_iterator, scene_output->output); + free(scene_output); } @@ -849,6 +938,8 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, scene_output->x = lx; scene_output->y = ly; wlr_output_damage_add_whole(scene_output->damage); + + scene_node_update_surface_outputs(&scene_output->scene->node); } struct check_scanout_data { -- cgit v1.2.3 From d164e76c0b89b6cff614ae82525812494f3db54c Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sat, 11 Dec 2021 12:25:53 +0100 Subject: scene: add primary output to wlr_scene_surface This allows compositors to avoid sending multiple frame done events to a surface that is rendered on multiple outputs at once. This may also be used in the same way for presentation feedback. --- wlr_scene.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index d2f3f4a..4269707 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -175,6 +175,9 @@ static void scene_surface_update_outputs( .height = scene_surface->surface->current.height, }; + int largest_overlap = 0; + scene_surface->primary_output = NULL; + struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { struct wlr_box output_box = { @@ -184,10 +187,16 @@ static void scene_surface_update_outputs( wlr_output_effective_resolution(scene_output->output, &output_box.width, &output_box.height); - // These enter/leave functions are a noop if the event has already been - // sent for the given output. struct wlr_box intersection; if (wlr_box_intersection(&intersection, &surface_box, &output_box)) { + int overlap = intersection.width * intersection.height; + if (overlap > largest_overlap) { + largest_overlap = overlap; + scene_surface->primary_output = scene_output->output; + } + + // These enter/leave functions are a noop if the event has already been + // sent for the given output. wlr_surface_send_enter(scene_surface->surface, scene_output->output); } else { wlr_surface_send_leave(scene_surface->surface, scene_output->output); -- cgit v1.2.3 From 9111ef3e3758fbf2d148946dc5544c908d18a044 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 13 Dec 2021 16:11:19 +0100 Subject: scene: add wlr_scene_send_frame_done() --- wlr_scene.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 4269707..daaf8d9 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -876,6 +876,31 @@ void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, pixman_region32_fini(&full_region); } +static void scene_send_frame_done_iterator(struct wlr_scene_node *node, + struct wlr_output *output, struct timespec *now) { + if (!node->state.enabled) { + return; + } + + if (node->type == WLR_SCENE_NODE_SURFACE) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_node(node); + if (scene_surface->primary_output == output) { + wlr_surface_send_frame_done(scene_surface->surface, now); + } + } + + struct wlr_scene_node *child; + wl_list_for_each(child, &node->state.children, state.link) { + scene_send_frame_done_iterator(child, output, now); + } +} + +void wlr_scene_send_frame_done(struct wlr_scene *scene, + struct wlr_output *output, struct timespec *now) { + scene_send_frame_done_iterator(&scene->node, output, now); +} + static void scene_output_handle_destroy(struct wlr_addon *addon) { struct wlr_scene_output *scene_output = wl_container_of(addon, scene_output, addon); -- cgit v1.2.3 From 9b5dfe3dba3330a8dc160900a55cd1b987ee6a86 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Mon, 13 Dec 2021 17:23:47 +0100 Subject: scene: fix wlr_scene_send_frame_done() API This doesn't work if scene outputs are not used as the primary output of scene surfaces will always be NULL. Therefore, take a wlr_scene_output instead of separate wlr_scene and wlr_output arguments and rename the function to wlr_scene_output_send_frame_done(). The actual behavior of the function is unchanged. --- wlr_scene.c | 51 ++++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index daaf8d9..3d19ace 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -876,31 +876,6 @@ void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, pixman_region32_fini(&full_region); } -static void scene_send_frame_done_iterator(struct wlr_scene_node *node, - struct wlr_output *output, struct timespec *now) { - if (!node->state.enabled) { - return; - } - - if (node->type == WLR_SCENE_NODE_SURFACE) { - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_from_node(node); - if (scene_surface->primary_output == output) { - wlr_surface_send_frame_done(scene_surface->surface, now); - } - } - - struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { - scene_send_frame_done_iterator(child, output, now); - } -} - -void wlr_scene_send_frame_done(struct wlr_scene *scene, - struct wlr_output *output, struct timespec *now) { - scene_send_frame_done_iterator(&scene->node, output, now); -} - static void scene_output_handle_destroy(struct wlr_addon *addon) { struct wlr_scene_output *scene_output = wl_container_of(addon, scene_output, addon); @@ -1121,6 +1096,32 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { return wlr_output_commit(output); } +static void scene_output_send_frame_done_iterator(struct wlr_scene_node *node, + struct wlr_output *output, struct timespec *now) { + if (!node->state.enabled) { + return; + } + + if (node->type == WLR_SCENE_NODE_SURFACE) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_node(node); + if (scene_surface->primary_output == output) { + wlr_surface_send_frame_done(scene_surface->surface, now); + } + } + + struct wlr_scene_node *child; + wl_list_for_each(child, &node->state.children, state.link) { + scene_output_send_frame_done_iterator(child, output, now); + } +} + +void wlr_scene_output_send_frame_done(struct wlr_scene_output *scene_output, + struct timespec *now) { + scene_output_send_frame_done_iterator(&scene_output->scene->node, + scene_output->output, now); +} + static void scene_output_for_each_surface(const struct wlr_box *output_box, struct wlr_scene_node *node, int lx, int ly, wlr_surface_iterator_func_t user_iterator, void *user_data) { -- cgit v1.2.3 From 7b6187beca0f700e774b4eef02170cc35a9b6a10 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Tue, 14 Dec 2021 18:35:44 +0100 Subject: scene: add wlr_scene_set_presentation() This helper automates sending presentation feedback to clients based on the primary output of scene surfaces. --- wlr_scene.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 3d19ace..7b55096 100644 --- a/wlr_scene.c +++ b/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); } -- cgit v1.2.3 From b769fcae11ac5af6695b23236bad7324767b5ec1 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 23 Dec 2021 16:30:24 +0100 Subject: scene: schedule an output frame on wl_surface.frame Some clients (e.g. mpv, Firefox) request a new wl_surface.frame callback without damaging their surface. When this happens, schedule a new output frame. Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3350 --- wlr_scene.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 7b55096..a0c06b6 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -236,10 +236,6 @@ static void scene_surface_handle_surface_commit(struct wl_listener *listener, wl_container_of(listener, scene_surface, surface_commit); struct wlr_surface *surface = scene_surface->surface; - if (!pixman_region32_not_empty(&surface->buffer_damage)) { - return; - } - struct wlr_scene *scene = scene_node_get_root(&scene_surface->node); int lx, ly; @@ -256,6 +252,17 @@ static void scene_surface_handle_surface_commit(struct wl_listener *listener, return; } + // Even if the surface hasn't submitted damage, schedule a new frame if + // the client has requested a wl_surface.frame callback. + if (!wl_list_empty(&surface->current.frame_callback_list) && + scene_surface->primary_output != NULL) { + wlr_output_schedule_frame(scene_surface->primary_output); + } + + if (!pixman_region32_not_empty(&surface->buffer_damage)) { + return; + } + struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { struct wlr_output *output = scene_output->output; -- cgit v1.2.3 From ddd0f15a1f2452eacd4d7c489aea2280416ccbfc Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 1 Jan 2022 14:04:53 +0300 Subject: scene/subsurface_tree: fix handling subsurface destruction This commit renames map/unmap listeners to clarify that they handle subsurface events, and ensures the node is always destroyed before the subsurface. Without this patch, wl_list_remove() would operate on listener links in already freed memory. glibc is usually lenient to bugs like this, but musl isn't. --- subsurface_tree.c | 65 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/subsurface_tree.c b/subsurface_tree.c index 3f22ee3..bb3c7ff 100644 --- a/subsurface_tree.c +++ b/subsurface_tree.c @@ -13,15 +13,20 @@ struct wlr_scene_subsurface_tree { struct wlr_surface *surface; struct wlr_scene_surface *scene_surface; - struct wlr_scene_subsurface_tree *parent; // NULL for the top-level surface - struct wlr_addon surface_addon; // only set if there's a parent - struct wl_listener tree_destroy; struct wl_listener surface_destroy; struct wl_listener surface_commit; - struct wl_listener surface_map; - struct wl_listener surface_unmap; struct wl_listener surface_new_subsurface; + + struct wlr_scene_subsurface_tree *parent; // NULL for the top-level surface + + // Only valid if the surface is a sub-surface + + struct wlr_addon surface_addon; + + struct wl_listener subsurface_destroy; + struct wl_listener subsurface_map; + struct wl_listener subsurface_unmap; }; static void subsurface_tree_handle_tree_destroy(struct wl_listener *listener, @@ -31,23 +36,17 @@ static void subsurface_tree_handle_tree_destroy(struct wl_listener *listener, // tree and scene_surface will be cleaned up by scene_node_finish if (subsurface_tree->parent) { wlr_addon_finish(&subsurface_tree->surface_addon); + wl_list_remove(&subsurface_tree->subsurface_destroy.link); + wl_list_remove(&subsurface_tree->subsurface_map.link); + wl_list_remove(&subsurface_tree->subsurface_unmap.link); } wl_list_remove(&subsurface_tree->tree_destroy.link); wl_list_remove(&subsurface_tree->surface_destroy.link); wl_list_remove(&subsurface_tree->surface_commit.link); - wl_list_remove(&subsurface_tree->surface_map.link); - wl_list_remove(&subsurface_tree->surface_unmap.link); wl_list_remove(&subsurface_tree->surface_new_subsurface.link); free(subsurface_tree); } -static void subsurface_tree_handle_surface_destroy(struct wl_listener *listener, - void *data) { - struct wlr_scene_subsurface_tree *subsurface_tree = - wl_container_of(listener, subsurface_tree, surface_destroy); - wlr_scene_node_destroy(&subsurface_tree->tree->node); -} - static const struct wlr_addon_interface subsurface_tree_addon_impl; static struct wlr_scene_subsurface_tree *subsurface_tree_from_subsurface( @@ -97,6 +96,13 @@ static void subsurface_tree_reconfigure( } } +static void subsurface_tree_handle_surface_destroy(struct wl_listener *listener, + void *data) { + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(listener, subsurface_tree, surface_destroy); + wlr_scene_node_destroy(&subsurface_tree->tree->node); +} + static void subsurface_tree_handle_surface_commit(struct wl_listener *listener, void *data) { struct wlr_scene_subsurface_tree *subsurface_tree = @@ -106,18 +112,25 @@ static void subsurface_tree_handle_surface_commit(struct wl_listener *listener, subsurface_tree_reconfigure(subsurface_tree); } -static void subsurface_tree_handle_surface_map(struct wl_listener *listener, +static void subsurface_tree_handle_subsurface_destroy(struct wl_listener *listener, void *data) { struct wlr_scene_subsurface_tree *subsurface_tree = - wl_container_of(listener, subsurface_tree, surface_map); + wl_container_of(listener, subsurface_tree, subsurface_destroy); + wlr_scene_node_destroy(&subsurface_tree->tree->node); +} + +static void subsurface_tree_handle_subsurface_map(struct wl_listener *listener, + void *data) { + struct wlr_scene_subsurface_tree *subsurface_tree = + wl_container_of(listener, subsurface_tree, subsurface_map); wlr_scene_node_set_enabled(&subsurface_tree->tree->node, true); } -static void subsurface_tree_handle_surface_unmap(struct wl_listener *listener, +static void subsurface_tree_handle_subsurface_unmap(struct wl_listener *listener, void *data) { struct wlr_scene_subsurface_tree *subsurface_tree = - wl_container_of(listener, subsurface_tree, surface_unmap); + wl_container_of(listener, subsurface_tree, subsurface_unmap); wlr_scene_node_set_enabled(&subsurface_tree->tree->node, false); } @@ -151,8 +164,14 @@ static bool subsurface_tree_create_subsurface( wlr_addon_init(&child->surface_addon, &subsurface->surface->addons, parent, &subsurface_tree_addon_impl); - wl_signal_add(&subsurface->events.map, &child->surface_map); - wl_signal_add(&subsurface->events.unmap, &child->surface_unmap); + child->subsurface_destroy.notify = subsurface_tree_handle_subsurface_destroy; + wl_signal_add(&subsurface->events.destroy, &child->subsurface_destroy); + + child->subsurface_map.notify = subsurface_tree_handle_subsurface_map; + wl_signal_add(&subsurface->events.map, &child->subsurface_map); + + child->subsurface_unmap.notify = subsurface_tree_handle_subsurface_unmap; + wl_signal_add(&subsurface->events.unmap, &child->subsurface_unmap); return true; } @@ -214,12 +233,6 @@ static struct wlr_scene_subsurface_tree *scene_surface_tree_create( subsurface_tree->surface_commit.notify = subsurface_tree_handle_surface_commit; wl_signal_add(&surface->events.commit, &subsurface_tree->surface_commit); - subsurface_tree->surface_map.notify = subsurface_tree_handle_surface_map; - wl_list_init(&subsurface_tree->surface_map.link); - - subsurface_tree->surface_unmap.notify = subsurface_tree_handle_surface_unmap; - wl_list_init(&subsurface_tree->surface_unmap.link); - subsurface_tree->surface_new_subsurface.notify = subsurface_tree_handle_surface_new_subsurface; wl_signal_add(&surface->events.new_subsurface, -- cgit v1.2.3 From e2045a155dc54c93fcdc38104b1ff1f84eac2788 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Thu, 13 Jan 2022 11:55:09 +0300 Subject: surface: deprecate wlr_surface.h --- subsurface_tree.c | 1 + wlr_scene.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/subsurface_tree.c b/subsurface_tree.c index bb3c7ff..8384db8 100644 --- a/subsurface_tree.c +++ b/subsurface_tree.c @@ -1,6 +1,7 @@ #include #include #include +#include #include /** diff --git a/wlr_scene.c b/wlr_scene.c index a0c06b6..9353fef 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -3,11 +3,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include "util/signal.h" -- cgit v1.2.3 From ba83a3197660df5340c303c02d55e3cd31a3f501 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 18 Jan 2022 14:27:37 +0100 Subject: scene: try to import buffers as textures before rendering The wlroots APIs currently don't allow importing/uploading a buffer during rendering operations. Scene-graph buffer nodes need to turn their wlr_buffer into a wlr_texture at some point. It's not always possible to do so at wlr_scene_buffer creation time because the scene-graph may have zero outputs at this point, thus no way to grab a wlr_renderer. Instead, add scene-graph buffers to a pending list and try to import them in wlr_scene_output_commit. References: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3354 --- wlr_scene.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 9353fef..5d5ff96 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -130,6 +130,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + wl_list_remove(&scene_buffer->pending_link); wlr_texture_destroy(scene_buffer->texture); wlr_buffer_unlock(scene_buffer->buffer); free(scene_buffer); @@ -145,6 +146,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); + wl_list_init(&scene->pending_buffers); return scene; } @@ -360,6 +362,9 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, scene_node_damage_whole(&scene_buffer->node); + struct wlr_scene *scene = scene_node_get_root(parent); + wl_list_insert(&scene->pending_buffers, &scene_buffer->pending_link); + return scene_buffer; } @@ -1113,6 +1118,15 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { return true; } + // Try to import new buffers as textures + struct wlr_scene_buffer *scene_buffer, *scene_buffer_tmp; + wl_list_for_each_safe(scene_buffer, scene_buffer_tmp, + &scene_output->scene->pending_buffers, pending_link) { + scene_buffer_get_texture(scene_buffer, renderer); + wl_list_remove(&scene_buffer->pending_link); + wl_list_init(&scene_buffer->pending_link); + } + wlr_renderer_begin(renderer, output->width, output->height); int nrects; -- cgit v1.2.3 From 35b3b273b93de057c4976527547dbfab46e64fee Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Sun, 9 Jan 2022 23:48:24 +0100 Subject: scene: Add layer_shell_v1 helper This helper behaves similar to the xdg_shell helper, and additionally provides a little assistance for positioning and exclusive_zone management. --- layer_shell_v1.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 layer_shell_v1.c diff --git a/layer_shell_v1.c b/layer_shell_v1.c new file mode 100644 index 0000000..1c2b6e4 --- /dev/null +++ b/layer_shell_v1.c @@ -0,0 +1,183 @@ +#include +#include +#include + +static void scene_layer_surface_handle_tree_destroy( + struct wl_listener *listener, void *data) { + struct wlr_scene_layer_surface_v1 *scene_layer_surface = + wl_container_of(listener, scene_layer_surface, tree_destroy); + // tree and surface_node will be cleaned up by scene_node_finish + wl_list_remove(&scene_layer_surface->tree_destroy.link); + wl_list_remove(&scene_layer_surface->layer_surface_destroy.link); + wl_list_remove(&scene_layer_surface->layer_surface_map.link); + wl_list_remove(&scene_layer_surface->layer_surface_unmap.link); + free(scene_layer_surface); +} + +static void scene_layer_surface_handle_layer_surface_destroy( + struct wl_listener *listener, void *data) { + struct wlr_scene_layer_surface_v1 *scene_layer_surface = + wl_container_of(listener, scene_layer_surface, layer_surface_destroy); + wlr_scene_node_destroy(scene_layer_surface->node); +} + +static void scene_layer_surface_handle_layer_surface_map( + struct wl_listener *listener, void *data) { + struct wlr_scene_layer_surface_v1 *scene_layer_surface = + wl_container_of(listener, scene_layer_surface, layer_surface_map); + wlr_scene_node_set_enabled(scene_layer_surface->node, true); +} + +static void scene_layer_surface_handle_layer_surface_unmap( + struct wl_listener *listener, void *data) { + struct wlr_scene_layer_surface_v1 *scene_layer_surface = + wl_container_of(listener, scene_layer_surface, layer_surface_unmap); + wlr_scene_node_set_enabled(scene_layer_surface->node, false); +} + +static void layer_surface_exclusive_zone( + struct wlr_layer_surface_v1_state *state, + struct wlr_box *usable_area) { + switch (state->anchor) { + case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT): + // Anchor top + usable_area->y += state->exclusive_zone + state->margin.top; + usable_area->height -= state->exclusive_zone + state->margin.top; + break; + case (ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT): + // Anchor bottom + usable_area->height -= state->exclusive_zone + state->margin.bottom; + break; + case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | + ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT): + // Anchor left + usable_area->x += state->exclusive_zone + state->margin.left; + usable_area->width -= state->exclusive_zone + state->margin.left; + break; + case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | + ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT): // Anchor right + // Anchor right + usable_area->width -= state->exclusive_zone + state->margin.right; + break; + } +} + +void wlr_scene_layer_surface_v1_configure( + struct wlr_scene_layer_surface_v1 *scene_layer_surface, + const struct wlr_box *full_area, struct wlr_box *usable_area) { + struct wlr_layer_surface_v1 *layer_surface = + scene_layer_surface->layer_surface; + struct wlr_layer_surface_v1_state *state = &layer_surface->current; + + // If the exclusive zone is set to -1, the layer surface will use the + // full area of the output, otherwise it is constrained to the + // remaining usable area. + struct wlr_box bounds; + if (state->exclusive_zone == -1) { + bounds = *full_area; + } else { + bounds = *usable_area; + } + + struct wlr_box box = { + .width = state->desired_width, + .height = state->desired_height, + }; + + // Horizontal positioning + if (box.width == 0) { + box.x = bounds.x + state->margin.left; + box.width = bounds.width - + state->margin.left + state->margin.right; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT && + state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) { + box.x = bounds.x + bounds.width/2 -box.width/2; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) { + box.x = bounds.x + state->margin.left; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) { + box.x = bounds.x + bounds.width - box.width - state->margin.right; + } else { + box.x = bounds.x + bounds.width/2 - box.width/2; + } + + // Vertical positioning + if (box.height == 0) { + box.y = bounds.y + state->margin.top; + box.height = bounds.height - + state->margin.top + state->margin.bottom; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP && + state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) { + box.y = bounds.y + bounds.height/2 - box.height/2; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) { + box.y = bounds.y + state->margin.top; + } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) { + box.y = bounds.y + bounds.height - box.height - state->margin.bottom; + } else { + box.y = bounds.y + bounds.height/2 - box.height/2; + } + + wlr_scene_node_set_position(scene_layer_surface->node, box.x, box.y); + wlr_layer_surface_v1_configure(layer_surface, box.width, box.height); + + if (state->exclusive_zone > 0) { + layer_surface_exclusive_zone(state, usable_area); + } +} + +struct wlr_scene_layer_surface_v1 *wlr_scene_layer_surface_v1_create( + struct wlr_scene_node *parent, + struct wlr_layer_surface_v1 *layer_surface) { + struct wlr_scene_layer_surface_v1 *scene_layer_surface = + calloc(1, sizeof(*scene_layer_surface)); + if (scene_layer_surface == NULL) { + return NULL; + } + + scene_layer_surface->layer_surface = layer_surface; + + struct wlr_scene_tree *tree = wlr_scene_tree_create(parent); + if (tree == NULL) { + free(scene_layer_surface); + return NULL; + } + scene_layer_surface->node = &tree->node; + + struct wlr_scene_node *surface_node = wlr_scene_subsurface_tree_create( + scene_layer_surface->node, layer_surface->surface); + if (surface_node == NULL) { + wlr_scene_node_destroy(scene_layer_surface->node); + free(scene_layer_surface); + return NULL; + } + + scene_layer_surface->tree_destroy.notify = + scene_layer_surface_handle_tree_destroy; + wl_signal_add(&scene_layer_surface->node->events.destroy, + &scene_layer_surface->tree_destroy); + + scene_layer_surface->layer_surface_destroy.notify = + scene_layer_surface_handle_layer_surface_destroy; + wl_signal_add(&layer_surface->events.destroy, + &scene_layer_surface->layer_surface_destroy); + + scene_layer_surface->layer_surface_map.notify = + scene_layer_surface_handle_layer_surface_map; + wl_signal_add(&layer_surface->events.map, + &scene_layer_surface->layer_surface_map); + + scene_layer_surface->layer_surface_unmap.notify = + scene_layer_surface_handle_layer_surface_unmap; + wl_signal_add(&layer_surface->events.unmap, + &scene_layer_surface->layer_surface_unmap); + + wlr_scene_node_set_enabled(scene_layer_surface->node, + layer_surface->mapped); + + return scene_layer_surface; +} -- cgit v1.2.3 From 339ef8dbd92c21c8d807024b875fc0887666430f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 13 Mar 2022 11:21:56 +0100 Subject: Revert "scene: try to import buffers as textures before rendering" This reverts commit 3db1bcbe641b407b9f5c9e5d0a012b45aa2c6cb7. Since [1], importing buffers as textures before wlr_renderer_begin isn't necessary anymore. [1]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3464 --- wlr_scene.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 5d5ff96..9353fef 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -130,7 +130,6 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); - wl_list_remove(&scene_buffer->pending_link); wlr_texture_destroy(scene_buffer->texture); wlr_buffer_unlock(scene_buffer->buffer); free(scene_buffer); @@ -146,7 +145,6 @@ 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); - wl_list_init(&scene->pending_buffers); return scene; } @@ -362,9 +360,6 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, scene_node_damage_whole(&scene_buffer->node); - struct wlr_scene *scene = scene_node_get_root(parent); - wl_list_insert(&scene->pending_buffers, &scene_buffer->pending_link); - return scene_buffer; } @@ -1118,15 +1113,6 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { return true; } - // Try to import new buffers as textures - struct wlr_scene_buffer *scene_buffer, *scene_buffer_tmp; - wl_list_for_each_safe(scene_buffer, scene_buffer_tmp, - &scene_output->scene->pending_buffers, pending_link) { - scene_buffer_get_texture(scene_buffer, renderer); - wl_list_remove(&scene_buffer->pending_link); - wl_list_init(&scene_buffer->pending_link); - } - wlr_renderer_begin(renderer, output->width, output->height); int nrects; -- cgit v1.2.3 From fcbdeee3bf0e78fd538a27654edaf5497c8892f7 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Thu, 14 Apr 2022 09:26:54 +0300 Subject: scene/output-layout: fix scene destroy handler --- output_layout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/output_layout.c b/output_layout.c index 33dac13..b80759f 100644 --- a/output_layout.c +++ b/output_layout.c @@ -99,7 +99,7 @@ bool wlr_scene_attach_output_layout(struct wlr_scene *scene, wl_signal_add(&output_layout->events.add, &sol->layout_add); sol->scene_destroy.notify = scene_output_layout_handle_scene_destroy; - wl_signal_add(&output_layout->events.destroy, &sol->scene_destroy); + wl_signal_add(&scene->node.events.destroy, &sol->scene_destroy); return true; } -- cgit v1.2.3 From fc43a84af93cbf3a76207a1e43bda40993f689f0 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 26 Apr 2022 09:43:54 +0200 Subject: Zero-initialize structs in init functions Ensures there is no field left to its previous undefined value after calling an init function. --- wlr_scene.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 9353fef..d88dd55 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -48,6 +48,7 @@ static struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { } static void scene_node_state_init(struct wlr_scene_node_state *state) { + memset(state, 0, sizeof(*state)); wl_list_init(&state->children); wl_list_init(&state->link); state->enabled = true; @@ -61,6 +62,7 @@ static void scene_node_init(struct wlr_scene_node *node, enum wlr_scene_node_type type, struct wlr_scene_node *parent) { assert(type == WLR_SCENE_NODE_ROOT || parent != NULL); + memset(node, 0, sizeof(*node)); node->type = type; node->parent = parent; scene_node_state_init(&node->state); -- cgit v1.2.3 From f6e31284060e036898877ed4e13d07af6397cf4b Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 19 May 2022 14:16:52 -0400 Subject: wlr_scene: Allow buffer in wlr_scene_buffer to be NULL This is useful to emulate an unmapped surface. --- wlr_scene.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index d88dd55..777f8cb 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -358,7 +358,9 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, } scene_node_init(&scene_buffer->node, WLR_SCENE_NODE_BUFFER, parent); - scene_buffer->buffer = wlr_buffer_lock(buffer); + if (buffer) { + scene_buffer->buffer = wlr_buffer_lock(buffer); + } scene_node_damage_whole(&scene_buffer->node); @@ -447,7 +449,7 @@ static void scene_node_get_size(struct wlr_scene_node *node, if (scene_buffer->dst_width > 0 && scene_buffer->dst_height > 0) { *width = scene_buffer->dst_width; *height = scene_buffer->dst_height; - } else { + } else if (scene_buffer->buffer) { if (scene_buffer->transform & WL_OUTPUT_TRANSFORM_90) { *height = scene_buffer->buffer->width; *width = scene_buffer->buffer->height; @@ -838,6 +840,9 @@ static void render_node_iterator(struct wlr_scene_node *node, break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + if (!scene_buffer->buffer) { + return; + } struct wlr_renderer *renderer = output->renderer; texture = scene_buffer_get_texture(scene_buffer, renderer); -- cgit v1.2.3 From 74ada54cccbcbdd19aafc3b102d49e84f45c1f4e Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 19 May 2022 14:17:51 -0400 Subject: wlr_scene: Add setter for buffer of a wlr_scene_buffer --- wlr_scene.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 777f8cb..e1e381d 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -367,6 +367,27 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, return scene_buffer; } +void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer, + struct wlr_buffer *buffer) { + if (buffer == scene_buffer->buffer) { + return; + } + + scene_node_damage_whole(&scene_buffer->node); + + wlr_texture_destroy(scene_buffer->texture); + scene_buffer->texture = NULL; + wlr_buffer_unlock(scene_buffer->buffer); + + if (buffer) { + scene_buffer->buffer = wlr_buffer_lock(buffer); + } else { + scene_buffer->buffer = NULL; + } + + scene_node_damage_whole(&scene_buffer->node); +} + void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer, const struct wlr_fbox *box) { struct wlr_fbox *cur = &scene_buffer->src_box; -- cgit v1.2.3 From 5b7bd5b931a37b8d74efa1c061348659e3ddf433 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 16 Apr 2022 05:39:22 -0400 Subject: wlr_scene_output: Send output leave events before destroying the output --- wlr_scene.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index e1e381d..656f662 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -982,12 +982,12 @@ static void scene_output_send_leave_iterator(struct wlr_surface *surface, } void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { - wlr_addon_finish(&scene_output->addon); - wl_list_remove(&scene_output->link); - wlr_scene_output_for_each_surface(scene_output, scene_output_send_leave_iterator, scene_output->output); + wlr_addon_finish(&scene_output->addon); + wl_list_remove(&scene_output->link); + free(scene_output); } -- cgit v1.2.3 From d5159260a1bca923c54bea66d2a49ae925143d33 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 18 May 2022 18:08:35 -0400 Subject: wlr_scene: Add output_enter/output_leave signals When we destroy a scene buffer, let's make sure that we call output_leave signals before we finish the node which will call destroy listeners. --- wlr_scene.c | 167 +++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 121 insertions(+), 46 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 656f662..5eb8165 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -17,11 +17,6 @@ static struct wlr_scene *scene_root_from_node(struct wlr_scene_node *node) { return (struct wlr_scene *)node; } -static struct wlr_scene_tree *scene_tree_from_node(struct wlr_scene_node *node) { - assert(node->type == WLR_SCENE_NODE_TREE); - return (struct wlr_scene_tree *)node; -} - struct wlr_scene_surface *wlr_scene_surface_from_node( struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_SURFACE); @@ -73,18 +68,6 @@ static void scene_node_init(struct wlr_scene_node *node, } } -static void scene_node_finish(struct wlr_scene_node *node) { - wlr_signal_emit_safe(&node->events.destroy, NULL); - - struct wlr_scene_node *child, *child_tmp; - wl_list_for_each_safe(child, child_tmp, - &node->state.children, state.link) { - wlr_scene_node_destroy(child); - } - - scene_node_state_finish(&node->state); -} - static void scene_node_damage_whole(struct wlr_scene_node *node); void wlr_scene_node_destroy(struct wlr_scene_node *node) { @@ -93,7 +76,11 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { } scene_node_damage_whole(node); - scene_node_finish(node); + + // We want to call the destroy listeners before we do anything else + // in case the destroy signal would like to remove children before they + // are recursively destroyed. + wlr_signal_emit_safe(&node->events.destroy, NULL); struct wlr_scene *scene = scene_node_get_root(node); struct wlr_scene_output *scene_output; @@ -105,12 +92,6 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { } wl_list_remove(&scene->presentation_destroy.link); - - free(scene); - break; - case WLR_SCENE_NODE_TREE:; - struct wlr_scene_tree *tree = scene_tree_from_node(node); - free(tree); break; case WLR_SCENE_NODE_SURFACE:; struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); @@ -123,20 +104,36 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wl_list_remove(&scene_surface->surface_commit.link); wl_list_remove(&scene_surface->surface_destroy.link); - - free(scene_surface); - break; - case WLR_SCENE_NODE_RECT:; - struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); - free(scene_rect); break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + + uint64_t active = scene_buffer->active_outputs; + if (active) { + wl_list_for_each(scene_output, &scene->outputs, link) { + if (active & (1ull << scene_output->index)) { + wlr_signal_emit_safe(&scene_buffer->events.output_leave, + scene_output); + } + } + } + wlr_texture_destroy(scene_buffer->texture); wlr_buffer_unlock(scene_buffer->buffer); - free(scene_buffer); + break; + case WLR_SCENE_NODE_TREE: + case WLR_SCENE_NODE_RECT: break; } + + struct wlr_scene_node *child, *child_tmp; + wl_list_for_each_safe(child, child_tmp, + &node->state.children, state.link) { + wlr_scene_node_destroy(child); + } + + scene_node_state_finish(&node->state); + free(node); } struct wlr_scene *wlr_scene_create(void) { @@ -167,6 +164,8 @@ static void scene_surface_handle_surface_destroy(struct wl_listener *listener, wlr_scene_node_destroy(&scene_surface->node); } +static void scene_node_get_size(struct wlr_scene_node *node, int *lx, int *ly); + // This function must be called whenever the coordinates/dimensions of a scene // surface or scene output change. It is not necessary to call when a scene // surface's node is enabled/disabled or obscured by other nodes. To quote the @@ -210,26 +209,62 @@ static void scene_surface_update_outputs( } } -static void scene_node_update_surface_outputs_iterator( +// This function must be called whenever the coordinates/dimensions of a scene +// buffer or scene output change. It is not necessary to call when a scene +// buffer's node is enabled/disabled or obscured by other nodes. +static void scene_buffer_update_outputs( + struct wlr_scene_buffer *scene_buffer, + int lx, int ly, struct wlr_scene *scene) { + struct wlr_box buffer_box = { .x = lx, .y = ly }; + scene_node_get_size(&scene_buffer->node, &buffer_box.width, &buffer_box.height); + + struct wlr_scene_output *scene_output; + wl_list_for_each(scene_output, &scene->outputs, link) { + struct wlr_box output_box = { + .x = scene_output->x, + .y = scene_output->y, + }; + wlr_output_effective_resolution(scene_output->output, + &output_box.width, &output_box.height); + + struct wlr_box intersection; + bool intersects = wlr_box_intersection(&intersection, &buffer_box, &output_box); + bool intersects_before = scene_buffer->active_outputs & (1ull << scene_output->index); + + if (intersects && !intersects_before) { + scene_buffer->active_outputs |= 1ull << scene_output->index; + wlr_signal_emit_safe(&scene_buffer->events.output_enter, scene_output); + } else if (!intersects && intersects_before) { + scene_buffer->active_outputs &= ~(1ull << scene_output->index); + wlr_signal_emit_safe(&scene_buffer->events.output_leave, scene_output); + } + } +} + +static void _scene_node_update_outputs( struct wlr_scene_node *node, int lx, int ly, struct wlr_scene *scene) { if (node->type == WLR_SCENE_NODE_SURFACE) { struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); scene_surface_update_outputs(scene_surface, lx, ly, scene); + } else if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *scene_buffer = + scene_buffer_from_node(node); + scene_buffer_update_outputs(scene_buffer, lx, ly, scene); } struct wlr_scene_node *child; wl_list_for_each(child, &node->state.children, state.link) { - scene_node_update_surface_outputs_iterator(child, lx + child->state.x, + _scene_node_update_outputs(child, lx + child->state.x, ly + child->state.y, scene); } } -static void scene_node_update_surface_outputs(struct wlr_scene_node *node) { +static void scene_node_update_outputs(struct wlr_scene_node *node) { struct wlr_scene *scene = scene_node_get_root(node); int lx, ly; wlr_scene_node_coords(node, &lx, &ly); - scene_node_update_surface_outputs_iterator(node, lx, ly, scene); + _scene_node_update_outputs(node, lx, ly, scene); } static void scene_surface_handle_surface_commit(struct wl_listener *listener, @@ -307,7 +342,7 @@ struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_node *parent scene_node_damage_whole(&scene_surface->node); - scene_node_update_surface_outputs(&scene_surface->node); + scene_node_update_outputs(&scene_surface->node); return scene_surface; } @@ -362,8 +397,13 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, scene_buffer->buffer = wlr_buffer_lock(buffer); } + wl_signal_init(&scene_buffer->events.output_enter); + wl_signal_init(&scene_buffer->events.output_leave); + scene_node_damage_whole(&scene_buffer->node); + scene_node_update_outputs(&scene_buffer->node); + return scene_buffer; } @@ -386,6 +426,8 @@ void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer, } scene_node_damage_whole(&scene_buffer->node); + + scene_node_update_outputs(&scene_buffer->node); } void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer, @@ -415,6 +457,8 @@ void wlr_scene_buffer_set_dest_size(struct wlr_scene_buffer *scene_buffer, scene_buffer->dst_width = width; scene_buffer->dst_height = height; scene_node_damage_whole(&scene_buffer->node); + + scene_node_update_outputs(&scene_buffer->node); } void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer, @@ -559,7 +603,7 @@ void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y) { node->state.y = y; scene_node_damage_whole(node); - scene_node_update_surface_outputs(node); + scene_node_update_outputs(node); } void wlr_scene_node_place_above(struct wlr_scene_node *node, @@ -634,7 +678,7 @@ void wlr_scene_node_reparent(struct wlr_scene_node *node, scene_node_damage_whole(node); - scene_node_update_surface_outputs(node); + scene_node_update_outputs(node); } bool wlr_scene_node_coords(struct wlr_scene_node *node, @@ -968,22 +1012,53 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, scene_output->output = output; scene_output->scene = scene; wlr_addon_init(&scene_output->addon, &output->addons, scene, &output_addon_impl); - wl_list_insert(&scene->outputs, &scene_output->link); + + int prev_output_index = -1; + struct wl_list *prev_output_link = &scene->outputs; + + struct wlr_scene_output *current_output; + wl_list_for_each(current_output, &scene->outputs, link) { + if (prev_output_index + 1 != current_output->index) { + break; + } + + prev_output_index = current_output->index; + prev_output_link = ¤t_output->link; + } + + scene_output->index = prev_output_index + 1; + assert(scene_output->index < 64); + wl_list_insert(prev_output_link, &scene_output->link); wlr_output_damage_add_whole(scene_output->damage); return scene_output; } -static void scene_output_send_leave_iterator(struct wlr_surface *surface, - int sx, int sy, void *data) { - struct wlr_output *output = data; - wlr_surface_send_leave(surface, output); +static void scene_node_remove_output(struct wlr_scene_node *node, + struct wlr_scene_output *output) { + if (node->type == WLR_SCENE_NODE_SURFACE) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_node(node); + wlr_surface_send_leave(scene_surface->surface, output->output); + } else if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *scene_buffer = + scene_buffer_from_node(node); + uint64_t mask = 1ull << output->index; + if (scene_buffer->active_outputs & mask) { + scene_buffer->active_outputs &= ~mask; + wlr_signal_emit_safe(&scene_buffer->events.output_leave, output); + } + } + + struct wlr_scene_node *child; + wl_list_for_each(child, &node->state.children, state.link) { + scene_node_remove_output(child, output); + } } void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { - wlr_scene_output_for_each_surface(scene_output, - scene_output_send_leave_iterator, scene_output->output); + scene_node_remove_output(&scene_output->scene->node, scene_output); wlr_addon_finish(&scene_output->addon); wl_list_remove(&scene_output->link); @@ -1013,7 +1088,7 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, scene_output->y = ly; wlr_output_damage_add_whole(scene_output->damage); - scene_node_update_surface_outputs(&scene_output->scene->node); + scene_node_update_outputs(&scene_output->scene->node); } struct check_scanout_data { -- cgit v1.2.3 From 51f0d56f41a7e2da2d17a545475450eddc6e227f Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 19 May 2022 14:01:03 -0400 Subject: wlr_scene: Fix missing calls to scene_node_update_outputs There were a couple places this was missing - on mode change of an output. If the resolution changes for example nodes may fall out of the view. - on commits on an output for scale or transform changes - when the transform of a buffer is changed. If the dest size is not set, the buffer may have been rotated potentially changing its size if the buffer width != height --- wlr_scene.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 5eb8165..52d8d00 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -470,6 +470,8 @@ void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer, scene_node_damage_whole(&scene_buffer->node); scene_buffer->transform = transform; scene_node_damage_whole(&scene_buffer->node); + + scene_node_update_outputs(&scene_buffer->node); } static struct wlr_texture *scene_buffer_get_texture( @@ -996,6 +998,24 @@ static const struct wlr_addon_interface output_addon_impl = { .destroy = scene_output_handle_destroy, }; +static void scene_output_handle_commit(struct wl_listener *listener, void *data) { + struct wlr_scene_output *scene_output = wl_container_of(listener, + scene_output, output_commit); + struct wlr_output_event_commit *event = data; + + if (event->committed & (WLR_OUTPUT_STATE_MODE | + WLR_OUTPUT_STATE_TRANSFORM | + WLR_OUTPUT_STATE_SCALE)) { + scene_node_update_outputs(&scene_output->scene->node); + } +} + +static void scene_output_handle_mode(struct wl_listener *listener, void *data) { + struct wlr_scene_output *scene_output = wl_container_of(listener, + scene_output, output_mode); + scene_node_update_outputs(&scene_output->scene->node); +} + struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, struct wlr_output *output) { struct wlr_scene_output *scene_output = calloc(1, sizeof(*scene_output)); @@ -1030,7 +1050,14 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, assert(scene_output->index < 64); wl_list_insert(prev_output_link, &scene_output->link); + scene_output->output_commit.notify = scene_output_handle_commit; + wl_signal_add(&output->events.commit, &scene_output->output_commit); + + scene_output->output_mode.notify = scene_output_handle_mode; + wl_signal_add(&output->events.mode, &scene_output->output_mode); + wlr_output_damage_add_whole(scene_output->damage); + scene_node_update_outputs(&scene->node); return scene_output; } @@ -1062,6 +1089,8 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { wlr_addon_finish(&scene_output->addon); wl_list_remove(&scene_output->link); + wl_list_remove(&scene_output->output_commit.link); + wl_list_remove(&scene_output->output_mode.link); free(scene_output); } -- cgit v1.2.3 From eaf951ce47014da8bb98a094e52d72fbad09707b Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 6 Apr 2022 07:59:54 -0400 Subject: wlr_scene: Make wlr_scene_render_output private This function sidesteps damage tracking and output awareness on buffers/surfaces. This function isn't a great fit for the API. Let's also inline the function and simplify it. --- wlr_scene.c | 36 +++++++++--------------------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 52d8d00..3de721f 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -945,31 +945,6 @@ static void scene_node_for_each_node(struct wlr_scene_node *node, } } -void wlr_scene_render_output(struct wlr_scene *scene, struct wlr_output *output, - int lx, int ly, pixman_region32_t *damage) { - pixman_region32_t full_region; - pixman_region32_init_rect(&full_region, 0, 0, output->width, output->height); - if (damage == NULL) { - damage = &full_region; - } - - struct wlr_renderer *renderer = output->renderer; - assert(renderer); - - if (output->enabled && pixman_region32_not_empty(damage)) { - struct render_data data = { - .output = output, - .damage = damage, - .presentation = scene->presentation, - }; - scene_node_for_each_node(&scene->node, -lx, -ly, - render_node_iterator, &data); - wlr_renderer_scissor(renderer, NULL); - } - - pixman_region32_fini(&full_region); -} - static void scene_handle_presentation_destroy(struct wl_listener *listener, void *data) { struct wlr_scene *scene = @@ -1254,8 +1229,15 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { wlr_renderer_clear(renderer, (float[4]){ 0.0, 0.0, 0.0, 1.0 }); } - wlr_scene_render_output(scene_output->scene, output, - scene_output->x, scene_output->y, &damage); + struct render_data data = { + .output = output, + .damage = &damage, + .presentation = scene_output->scene->presentation, + }; + scene_node_for_each_node(&scene_output->scene->node, + -scene_output->x, -scene_output->y, + render_node_iterator, &data); + wlr_renderer_scissor(renderer, NULL); wlr_output_render_software_cursors(output, &damage); wlr_renderer_end(renderer); -- cgit v1.2.3 From b390fce88442550a54ad5dfd78ae97047902b2e0 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 19 May 2022 14:21:21 -0400 Subject: wlr_scene: Add presentation signal for wlr_scene_buffer --- wlr_scene.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 3de721f..86d75ab 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -399,6 +399,7 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, wl_signal_init(&scene_buffer->events.output_enter); wl_signal_init(&scene_buffer->events.output_leave); + wl_signal_init(&scene_buffer->events.output_present); scene_node_damage_whole(&scene_buffer->node); @@ -847,7 +848,7 @@ static void render_texture(struct wlr_output *output, } struct render_data { - struct wlr_output *output; + struct wlr_scene_output *scene_output; pixman_region32_t *damage; // May be NULL @@ -857,7 +858,8 @@ struct render_data { static void render_node_iterator(struct wlr_scene_node *node, int x, int y, void *_data) { struct render_data *data = _data; - struct wlr_output *output = data->output; + struct wlr_scene_output *scene_output = data->scene_output; + struct wlr_output *output = scene_output->output; pixman_region32_t *output_damage = data->damage; struct wlr_box dst_box = { @@ -923,6 +925,8 @@ static void render_node_iterator(struct wlr_scene_node *node, render_texture(output, output_damage, texture, &scene_buffer->src_box, &dst_box, matrix); + + wlr_signal_emit_safe(&scene_buffer->events.output_present, scene_output); break; } } @@ -1184,6 +1188,12 @@ static bool scene_output_scanout(struct wlr_scene_output *scene_output) { } } + if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *scene_buffer = + scene_buffer_from_node(node); + wlr_signal_emit_safe(&scene_buffer->events.output_present, scene_output); + } + return wlr_output_commit(output); } @@ -1230,7 +1240,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { } struct render_data data = { - .output = output, + .scene_output = scene_output, .damage = &damage, .presentation = scene_output->scene->presentation, }; -- cgit v1.2.3 From 832b0ea4034290c6af2a1c2025d90e50f9740b26 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sun, 24 Apr 2022 22:32:58 -0400 Subject: wlr_scene: Add primary_output property to wlr_scene_buffer --- wlr_scene.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 86d75ab..cdb04c9 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -218,6 +218,9 @@ static void scene_buffer_update_outputs( struct wlr_box buffer_box = { .x = lx, .y = ly }; scene_node_get_size(&scene_buffer->node, &buffer_box.width, &buffer_box.height); + int largest_overlap = 0; + scene_buffer->primary_output = NULL; + struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { struct wlr_box output_box = { @@ -231,6 +234,14 @@ static void scene_buffer_update_outputs( bool intersects = wlr_box_intersection(&intersection, &buffer_box, &output_box); bool intersects_before = scene_buffer->active_outputs & (1ull << scene_output->index); + if (intersects) { + int overlap = intersection.width * intersection.height; + if (overlap > largest_overlap) { + largest_overlap = overlap; + scene_buffer->primary_output = scene_output; + } + } + if (intersects && !intersects_before) { scene_buffer->active_outputs |= 1ull << scene_output->index; wlr_signal_emit_safe(&scene_buffer->events.output_enter, scene_output); -- cgit v1.2.3 From 6fe1bda02bf6525e9ee4d5ca828fb68fbd39c32c Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 19 May 2022 14:23:10 -0400 Subject: wlr_scene: Add frame_done signal for wlr_scene_buffer Let's also change the name of the function. Motivation [1]. [1] https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3496#note_1357824 --- wlr_scene.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index cdb04c9..87f571d 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -411,6 +411,7 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, wl_signal_init(&scene_buffer->events.output_enter); wl_signal_init(&scene_buffer->events.output_leave); wl_signal_init(&scene_buffer->events.output_present); + wl_signal_init(&scene_buffer->events.frame_done); scene_node_damage_whole(&scene_buffer->node); @@ -486,6 +487,11 @@ void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer, scene_node_update_outputs(&scene_buffer->node); } +void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer, + struct timespec *now) { + wlr_signal_emit_safe(&scene_buffer->events.frame_done, now); +} + static struct wlr_texture *scene_buffer_get_texture( struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) { struct wlr_client_buffer *client_buffer = @@ -1280,8 +1286,8 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { return wlr_output_commit(output); } -static void scene_output_send_frame_done_iterator(struct wlr_scene_node *node, - struct wlr_output *output, struct timespec *now) { +static void scene_node_send_frame_done(struct wlr_scene_node *node, + struct wlr_scene_output *scene_output, struct timespec *now) { if (!node->state.enabled) { return; } @@ -1289,21 +1295,30 @@ static void scene_output_send_frame_done_iterator(struct wlr_scene_node *node, if (node->type == WLR_SCENE_NODE_SURFACE) { struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); - if (scene_surface->primary_output == output) { + if (scene_surface->primary_output == scene_output->output) { wlr_surface_send_frame_done(scene_surface->surface, now); } } + if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *scene_buffer = + scene_buffer_from_node(node); + + if (scene_buffer->primary_output == scene_output) { + wlr_scene_buffer_send_frame_done(scene_buffer, now); + } + } + struct wlr_scene_node *child; wl_list_for_each(child, &node->state.children, state.link) { - scene_output_send_frame_done_iterator(child, output, now); + scene_node_send_frame_done(child, scene_output, now); } } void wlr_scene_output_send_frame_done(struct wlr_scene_output *scene_output, struct timespec *now) { - scene_output_send_frame_done_iterator(&scene_output->scene->node, - scene_output->output, now); + scene_node_send_frame_done(&scene_output->scene->node, + scene_output, now); } static void scene_output_for_each_surface(const struct wlr_box *output_box, -- cgit v1.2.3 From d713e72338101cd36cdddb94b685771a24fcdde5 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 19 May 2022 14:24:05 -0400 Subject: wlr_scene: Add a way to choose when input interactions happen on a buffer --- wlr_scene.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 87f571d..5c110c3 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -771,12 +771,22 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); intersects = wlr_surface_point_accepts_input(scene_surface->surface, lx, ly); break; - case WLR_SCENE_NODE_RECT: - case WLR_SCENE_NODE_BUFFER:; + case WLR_SCENE_NODE_RECT:; int width, height; scene_node_get_size(node, &width, &height); intersects = lx >= 0 && lx < width && ly >= 0 && ly < height; break; + case WLR_SCENE_NODE_BUFFER:; + struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + + if (scene_buffer->point_accepts_input) { + intersects = scene_buffer->point_accepts_input(scene_buffer, lx, ly); + } else { + int width, height; + scene_node_get_size(node, &width, &height); + intersects = lx >= 0 && lx < width && ly >= 0 && ly < height; + } + break; } if (intersects) { -- cgit v1.2.3 From 9c8b661ea81206ceac665155444f0b32d55f6446 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 18 May 2022 22:37:05 -0400 Subject: wlr_scene: Add a function to also specify damage when applying a buffer to wlr_scene_buffer --- wlr_scene.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 79 insertions(+), 12 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 5c110c3..96b70df 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -420,27 +420,94 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, return scene_buffer; } -void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer, - struct wlr_buffer *buffer) { - if (buffer == scene_buffer->buffer) { +void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buffer, + struct wlr_buffer *buffer, pixman_region32_t *damage) { + // specifying a region for a NULL buffer doesn't make sense. We need to know + // about the buffer to scale the buffer local coordinates down to scene + // coordinates. + assert(buffer || !damage); + + if (buffer != scene_buffer->buffer) { + if (!damage) { + scene_node_damage_whole(&scene_buffer->node); + } + + wlr_texture_destroy(scene_buffer->texture); + scene_buffer->texture = NULL; + wlr_buffer_unlock(scene_buffer->buffer); + + if (buffer) { + scene_buffer->buffer = wlr_buffer_lock(buffer); + } else { + scene_buffer->buffer = NULL; + } + + scene_node_update_outputs(&scene_buffer->node); + + if (!damage) { + scene_node_damage_whole(&scene_buffer->node); + } + } + + if (!damage) { return; } - scene_node_damage_whole(&scene_buffer->node); + int lx, ly; + if (!wlr_scene_node_coords(&scene_buffer->node, &lx, &ly)) { + return; + } - wlr_texture_destroy(scene_buffer->texture); - scene_buffer->texture = NULL; - wlr_buffer_unlock(scene_buffer->buffer); + struct wlr_fbox box = scene_buffer->src_box; + if (wlr_fbox_empty(&box)) { + box.x = 0; + box.y = 0; - if (buffer) { - scene_buffer->buffer = wlr_buffer_lock(buffer); + if (scene_buffer->transform & WL_OUTPUT_TRANSFORM_90) { + box.width = buffer->height; + box.height = buffer->width; + } else { + box.width = buffer->width; + box.height = buffer->height; + } + } + + double scale_x, scale_y; + if (scene_buffer->dst_width || scene_buffer->dst_height) { + scale_x = scene_buffer->dst_width / box.width; + scale_y = scene_buffer->dst_height / box.height; } else { - scene_buffer->buffer = NULL; + scale_x = buffer->width / box.width; + scale_y = buffer->height / box.height; } - scene_node_damage_whole(&scene_buffer->node); + pixman_region32_t trans_damage; + pixman_region32_init(&trans_damage); + wlr_region_transform(&trans_damage, damage, + scene_buffer->transform, buffer->width, buffer->height); + pixman_region32_intersect_rect(&trans_damage, &trans_damage, + box.x, box.y, box.width, box.height); - scene_node_update_outputs(&scene_buffer->node); + struct wlr_scene *scene = scene_node_get_root(&scene_buffer->node); + struct wlr_scene_output *scene_output; + wl_list_for_each(scene_output, &scene->outputs, link) { + float output_scale = scene_output->output->scale; + pixman_region32_t output_damage; + pixman_region32_init(&output_damage); + wlr_region_scale_xy(&output_damage, &trans_damage, + output_scale * scale_x, output_scale * scale_y); + pixman_region32_translate(&output_damage, + (lx - scene_output->x) * output_scale, (ly - scene_output->y) * output_scale); + wlr_output_damage_add(scene_output->damage, &output_damage); + pixman_region32_fini(&output_damage); + } + + pixman_region32_fini(&trans_damage); +} + +void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer, + struct wlr_buffer *buffer) { + wlr_scene_buffer_set_buffer_with_damage(scene_buffer, buffer, NULL); } void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer, -- cgit v1.2.3 From 29e68cc8c9c9543b6fcc407e83c47a87a59fe38e Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Mon, 28 Mar 2022 06:19:45 -0400 Subject: wlr_scene: Make scene_buffer_from_node public --- wlr_scene.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 96b70df..6e940cb 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -29,7 +29,7 @@ static struct wlr_scene_rect *scene_rect_from_node( return (struct wlr_scene_rect *)node; } -static struct wlr_scene_buffer *scene_buffer_from_node( +struct wlr_scene_buffer *wlr_scene_buffer_from_node( struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_BUFFER); return (struct wlr_scene_buffer *)node; @@ -106,7 +106,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wl_list_remove(&scene_surface->surface_destroy.link); break; case WLR_SCENE_NODE_BUFFER:; - struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); uint64_t active = scene_buffer->active_outputs; if (active) { @@ -260,7 +260,7 @@ static void _scene_node_update_outputs( scene_surface_update_outputs(scene_surface, lx, ly, scene); } else if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = - scene_buffer_from_node(node); + wlr_scene_buffer_from_node(node); scene_buffer_update_outputs(scene_buffer, lx, ly, scene); } @@ -597,7 +597,7 @@ static void scene_node_get_size(struct wlr_scene_node *node, *height = scene_rect->height; break; case WLR_SCENE_NODE_BUFFER:; - struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); if (scene_buffer->dst_width > 0 && scene_buffer->dst_height > 0) { *width = scene_buffer->dst_width; *height = scene_buffer->dst_height; @@ -844,7 +844,7 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, intersects = lx >= 0 && lx < width && ly >= 0 && ly < height; break; case WLR_SCENE_NODE_BUFFER:; - struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); if (scene_buffer->point_accepts_input) { intersects = scene_buffer->point_accepts_input(scene_buffer, lx, ly); @@ -1002,7 +1002,7 @@ static void render_node_iterator(struct wlr_scene_node *node, output->transform_matrix); break; case WLR_SCENE_NODE_BUFFER:; - struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); if (!scene_buffer->buffer) { return; } @@ -1143,7 +1143,7 @@ static void scene_node_remove_output(struct wlr_scene_node *node, wlr_surface_send_leave(scene_surface->surface, output->output); } else if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = - scene_buffer_from_node(node); + wlr_scene_buffer_from_node(node); uint64_t mask = 1ull << output->index; if (scene_buffer->active_outputs & mask) { scene_buffer->active_outputs &= ~mask; @@ -1252,7 +1252,7 @@ static bool scene_output_scanout(struct wlr_scene_output *scene_output) { buffer = &scene_surface->surface->buffer->base; break; case WLR_SCENE_NODE_BUFFER:; - struct wlr_scene_buffer *scene_buffer = scene_buffer_from_node(node); + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); if (scene_buffer->buffer == NULL || !wlr_fbox_empty(&scene_buffer->src_box) || scene_buffer->transform != output->transform) { @@ -1284,7 +1284,7 @@ static bool scene_output_scanout(struct wlr_scene_output *scene_output) { if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = - scene_buffer_from_node(node); + wlr_scene_buffer_from_node(node); wlr_signal_emit_safe(&scene_buffer->events.output_present, scene_output); } @@ -1379,7 +1379,7 @@ static void scene_node_send_frame_done(struct wlr_scene_node *node, if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = - scene_buffer_from_node(node); + wlr_scene_buffer_from_node(node); if (scene_buffer->primary_output == scene_output) { wlr_scene_buffer_send_frame_done(scene_buffer, now); -- cgit v1.2.3 From ae39acc1c14d3c2267eebce4e0e7427865fb5003 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 19 May 2022 14:01:44 -0400 Subject: wlr_scene: Pull scene_node_get_root into a private header We will need this for surface emulation on buffers. --- wlr_scene.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wlr_scene.c b/wlr_scene.c index 6e940cb..823ddcf 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -10,6 +10,7 @@ #include #include #include +#include "types/wlr_scene.h" #include "util/signal.h" static struct wlr_scene *scene_root_from_node(struct wlr_scene_node *node) { @@ -35,7 +36,7 @@ struct wlr_scene_buffer *wlr_scene_buffer_from_node( return (struct wlr_scene_buffer *)node; } -static struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { +struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { while (node->parent != NULL) { node = node->parent; } -- cgit v1.2.3 From e163399606b2890c007d8d5d2a4a6c5710252027 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Tue, 12 Apr 2022 11:47:59 -0400 Subject: wlr_scene: Change out surface specific iterator functions Instead iterate over wlr_scene_buffer --- wlr_scene.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 823ddcf..89d48c1 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -785,8 +785,8 @@ bool wlr_scene_node_coords(struct wlr_scene_node *node, return enabled; } -static void scene_node_for_each_surface(struct wlr_scene_node *node, - int lx, int ly, wlr_surface_iterator_func_t user_iterator, +static void scene_node_for_each_scene_buffer(struct wlr_scene_node *node, + int lx, int ly, wlr_scene_buffer_iterator_func_t user_iterator, void *user_data) { if (!node->state.enabled) { return; @@ -795,20 +795,20 @@ static void scene_node_for_each_surface(struct wlr_scene_node *node, lx += node->state.x; ly += node->state.y; - if (node->type == WLR_SCENE_NODE_SURFACE) { - struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); - user_iterator(scene_surface->surface, lx, ly, user_data); + if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); + user_iterator(scene_buffer, lx, ly, user_data); } struct wlr_scene_node *child; wl_list_for_each(child, &node->state.children, state.link) { - scene_node_for_each_surface(child, lx, ly, user_iterator, user_data); + scene_node_for_each_scene_buffer(child, lx, ly, user_iterator, user_data); } } -void wlr_scene_node_for_each_surface(struct wlr_scene_node *node, - wlr_surface_iterator_func_t user_iterator, void *user_data) { - scene_node_for_each_surface(node, 0, 0, user_iterator, user_data); +void wlr_scene_node_for_each_buffer(struct wlr_scene_node *node, + wlr_scene_buffer_iterator_func_t user_iterator, void *user_data) { + scene_node_for_each_scene_buffer(node, 0, 0, user_iterator, user_data); } struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, @@ -1399,9 +1399,9 @@ void wlr_scene_output_send_frame_done(struct wlr_scene_output *scene_output, scene_output, now); } -static void scene_output_for_each_surface(const struct wlr_box *output_box, +static void scene_output_for_each_scene_buffer(const struct wlr_box *output_box, struct wlr_scene_node *node, int lx, int ly, - wlr_surface_iterator_func_t user_iterator, void *user_data) { + wlr_scene_buffer_iterator_func_t user_iterator, void *user_data) { if (!node->state.enabled) { return; } @@ -1409,30 +1409,30 @@ static void scene_output_for_each_surface(const struct wlr_box *output_box, lx += node->state.x; ly += node->state.y; - if (node->type == WLR_SCENE_NODE_SURFACE) { + if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_box node_box = { .x = lx, .y = ly }; scene_node_get_size(node, &node_box.width, &node_box.height); struct wlr_box intersection; if (wlr_box_intersection(&intersection, output_box, &node_box)) { - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_from_node(node); - user_iterator(scene_surface->surface, lx, ly, user_data); + struct wlr_scene_buffer *scene_buffer = + wlr_scene_buffer_from_node(node); + user_iterator(scene_buffer, lx, ly, user_data); } } struct wlr_scene_node *child; wl_list_for_each(child, &node->state.children, state.link) { - scene_output_for_each_surface(output_box, child, lx, ly, + scene_output_for_each_scene_buffer(output_box, child, lx, ly, user_iterator, user_data); } } -void wlr_scene_output_for_each_surface(struct wlr_scene_output *scene_output, - wlr_surface_iterator_func_t iterator, void *user_data) { +void wlr_scene_output_for_each_buffer(struct wlr_scene_output *scene_output, + wlr_scene_buffer_iterator_func_t iterator, void *user_data) { struct wlr_box box = { .x = scene_output->x, .y = scene_output->y }; wlr_output_effective_resolution(scene_output->output, &box.width, &box.height); - scene_output_for_each_surface(&box, &scene_output->scene->node, 0, 0, + scene_output_for_each_scene_buffer(&box, &scene_output->scene->node, 0, 0, iterator, user_data); } -- cgit v1.2.3 From d9ccd5585ce61ea040e3b6c757eb4cf21aeebb5b Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 19 May 2022 14:25:34 -0400 Subject: wlr_scene: Introduce addons to scene nodes --- wlr_scene.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 89d48c1..f4fab20 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -67,6 +67,8 @@ static void scene_node_init(struct wlr_scene_node *node, if (parent != NULL) { wl_list_insert(parent->state.children.prev, &node->state.link); } + + wlr_addon_set_init(&node->addons); } static void scene_node_damage_whole(struct wlr_scene_node *node); @@ -133,6 +135,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wlr_scene_node_destroy(child); } + wlr_addon_set_finish(&node->addons); scene_node_state_finish(&node->state); free(node); } -- cgit v1.2.3 From 14965ffedf841c6fb1c94a116be6bd7f1c729c9c Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 19 May 2022 14:26:50 -0400 Subject: wlr_scene: Refactor wlr_scene_surface to be a helper on top of wlr_scene_buffer --- subsurface_tree.c | 4 +- surface.c | 179 ++++++++++++++++++++++++++++++++++++++++++ wlr_scene.c | 227 +----------------------------------------------------- 3 files changed, 183 insertions(+), 227 deletions(-) create mode 100644 surface.c diff --git a/subsurface_tree.c b/subsurface_tree.c index 8384db8..1cb2977 100644 --- a/subsurface_tree.c +++ b/subsurface_tree.c @@ -81,9 +81,9 @@ static void subsurface_tree_reconfigure( } if (prev != NULL) { - wlr_scene_node_place_above(&subsurface_tree->scene_surface->node, prev); + wlr_scene_node_place_above(&subsurface_tree->scene_surface->buffer->node, prev); } - prev = &subsurface_tree->scene_surface->node; + prev = &subsurface_tree->scene_surface->buffer->node; wl_list_for_each(subsurface, &surface->current.subsurfaces_above, current.link) { diff --git a/surface.c b/surface.c new file mode 100644 index 0000000..e6a8b6b --- /dev/null +++ b/surface.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include "types/wlr_scene.h" + +static void handle_scene_buffer_output_enter( + struct wl_listener *listener, void *data) { + struct wlr_scene_surface *surface = + wl_container_of(listener, surface, output_enter); + struct wlr_scene_output *output = data; + + wlr_surface_send_enter(surface->surface, output->output); +} + +static void handle_scene_buffer_output_leave( + struct wl_listener *listener, void *data) { + struct wlr_scene_surface *surface = + wl_container_of(listener, surface, output_leave); + struct wlr_scene_output *output = data; + + wlr_surface_send_leave(surface->surface, output->output); +} + +static void handle_scene_buffer_output_present( + struct wl_listener *listener, void *data) { + struct wlr_scene_surface *surface = + wl_container_of(listener, surface, output_present); + struct wlr_scene_output *scene_output = data; + + if (surface->buffer->primary_output == scene_output) { + struct wlr_scene *root = scene_node_get_root(&surface->buffer->node); + struct wlr_presentation *presentation = root->presentation; + + if (presentation) { + wlr_presentation_surface_sampled_on_output( + presentation, surface->surface, scene_output->output); + } + } +} + +static void handle_scene_buffer_frame_done( + struct wl_listener *listener, void *data) { + struct wlr_scene_surface *surface = + wl_container_of(listener, surface, frame_done); + struct timespec *now = data; + + wlr_surface_send_frame_done(surface->surface, now); +} + +static void scene_surface_handle_surface_destroy( + struct wl_listener *listener, void *data) { + struct wlr_scene_surface *surface = + wl_container_of(listener, surface, surface_destroy); + + wlr_scene_node_destroy(&surface->buffer->node); +} + +static void set_buffer_with_surface_state(struct wlr_scene_buffer *scene_buffer, + struct wlr_surface *surface) { + struct wlr_surface_state *state = &surface->current; + + struct wlr_fbox src_box; + wlr_surface_get_buffer_source_box(surface, &src_box); + wlr_scene_buffer_set_source_box(scene_buffer, &src_box); + + wlr_scene_buffer_set_dest_size(scene_buffer, state->width, state->height); + wlr_scene_buffer_set_transform(scene_buffer, state->transform); + + if (surface->buffer) { + wlr_scene_buffer_set_buffer_with_damage(scene_buffer, + &surface->buffer->base, &surface->buffer_damage); + } else { + wlr_scene_buffer_set_buffer(scene_buffer, NULL); + } +} + +static void handle_scene_surface_surface_commit( + struct wl_listener *listener, void *data) { + struct wlr_scene_surface *surface = + wl_container_of(listener, surface, surface_commit); + struct wlr_scene_buffer *scene_buffer = surface->buffer; + + set_buffer_with_surface_state(scene_buffer, surface->surface); + + // Even if the surface hasn't submitted damage, schedule a new frame if + // the client has requested a wl_surface.frame callback. Check if the node + // is visible. If not, the client will never receive a frame_done event + // anyway so it doesn't make sense to schedule here. + int lx, ly; + bool enabled = wlr_scene_node_coords(&scene_buffer->node, &lx, &ly); + + if (!wl_list_empty(&surface->surface->current.frame_callback_list) && + surface->buffer->primary_output != NULL && enabled) { + wlr_output_schedule_frame(surface->buffer->primary_output->output); + } +} + +static bool scene_buffer_point_accepts_input(struct wlr_scene_buffer *scene_buffer, + int sx, int sy) { + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_from_buffer(scene_buffer); + + return wlr_surface_point_accepts_input(scene_surface->surface, sx, sy); +} + +static void surface_addon_destroy(struct wlr_addon *addon) { + struct wlr_scene_surface *surface = wl_container_of(addon, surface, addon); + + wlr_addon_finish(&surface->addon); + + wl_list_remove(&surface->output_enter.link); + wl_list_remove(&surface->output_leave.link); + wl_list_remove(&surface->output_present.link); + wl_list_remove(&surface->frame_done.link); + wl_list_remove(&surface->surface_destroy.link); + wl_list_remove(&surface->surface_commit.link); + + free(surface); +} + +static const struct wlr_addon_interface surface_addon_impl = { + .name = "wlr_scene_surface", + .destroy = surface_addon_destroy, +}; + +struct wlr_scene_surface *wlr_scene_surface_from_buffer( + struct wlr_scene_buffer *scene_buffer) { + struct wlr_addon *addon = wlr_addon_find(&scene_buffer->node.addons, + scene_buffer, &surface_addon_impl); + if (!addon) { + return NULL; + } + + struct wlr_scene_surface *surface = wl_container_of(addon, surface, addon); + return surface; +} + +struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_node *parent, + struct wlr_surface *wlr_surface) { + struct wlr_scene_surface *surface = calloc(1, sizeof(*surface)); + if (surface == NULL) { + return NULL; + } + + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_create(parent, NULL); + if (!scene_buffer) { + free(surface); + return NULL; + } + + surface->buffer = scene_buffer; + surface->surface = wlr_surface; + scene_buffer->point_accepts_input = scene_buffer_point_accepts_input; + + surface->output_enter.notify = handle_scene_buffer_output_enter; + wl_signal_add(&scene_buffer->events.output_enter, &surface->output_enter); + + surface->output_leave.notify = handle_scene_buffer_output_leave; + wl_signal_add(&scene_buffer->events.output_leave, &surface->output_leave); + + surface->output_present.notify = handle_scene_buffer_output_present; + wl_signal_add(&scene_buffer->events.output_present, &surface->output_present); + + surface->frame_done.notify = handle_scene_buffer_frame_done; + wl_signal_add(&scene_buffer->events.frame_done, &surface->frame_done); + + surface->surface_destroy.notify = scene_surface_handle_surface_destroy; + wl_signal_add(&wlr_surface->events.destroy, &surface->surface_destroy); + + surface->surface_commit.notify = handle_scene_surface_surface_commit; + wl_signal_add(&wlr_surface->events.commit, &surface->surface_commit); + + wlr_addon_init(&surface->addon, &scene_buffer->node.addons, + scene_buffer, &surface_addon_impl); + + set_buffer_with_surface_state(scene_buffer, wlr_surface); + + return surface; +} diff --git a/wlr_scene.c b/wlr_scene.c index f4fab20..2435ede 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -18,12 +18,6 @@ static struct wlr_scene *scene_root_from_node(struct wlr_scene_node *node) { return (struct wlr_scene *)node; } -struct wlr_scene_surface *wlr_scene_surface_from_node( - struct wlr_scene_node *node) { - assert(node->type == WLR_SCENE_NODE_SURFACE); - return (struct wlr_scene_surface *)node; -} - static struct wlr_scene_rect *scene_rect_from_node( struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_RECT); @@ -96,18 +90,6 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wl_list_remove(&scene->presentation_destroy.link); break; - case WLR_SCENE_NODE_SURFACE:; - struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); - - wl_list_for_each(scene_output, &scene->outputs, link) { - // This is a noop if wlr_surface_send_enter() wasn't previously called for - // the given output. - wlr_surface_send_leave(scene_surface->surface, scene_output->output); - } - - wl_list_remove(&scene_surface->surface_commit.link); - wl_list_remove(&scene_surface->surface_destroy.link); - break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); @@ -161,58 +143,8 @@ struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_node *parent) { return tree; } -static void scene_surface_handle_surface_destroy(struct wl_listener *listener, - void *data) { - struct wlr_scene_surface *scene_surface = - wl_container_of(listener, scene_surface, surface_destroy); - wlr_scene_node_destroy(&scene_surface->node); -} - static void scene_node_get_size(struct wlr_scene_node *node, int *lx, int *ly); -// This function must be called whenever the coordinates/dimensions of a scene -// surface or scene output change. It is not necessary to call when a scene -// surface's node is enabled/disabled or obscured by other nodes. To quote the -// protocol: "The surface might be hidden even if no leave event has been sent." -static void scene_surface_update_outputs( - struct wlr_scene_surface *scene_surface, - int lx, int ly, struct wlr_scene *scene) { - struct wlr_box surface_box = { - .x = lx, - .y = ly, - .width = scene_surface->surface->current.width, - .height = scene_surface->surface->current.height, - }; - - int largest_overlap = 0; - scene_surface->primary_output = NULL; - - struct wlr_scene_output *scene_output; - wl_list_for_each(scene_output, &scene->outputs, link) { - struct wlr_box output_box = { - .x = scene_output->x, - .y = scene_output->y, - }; - wlr_output_effective_resolution(scene_output->output, - &output_box.width, &output_box.height); - - struct wlr_box intersection; - if (wlr_box_intersection(&intersection, &surface_box, &output_box)) { - int overlap = intersection.width * intersection.height; - if (overlap > largest_overlap) { - largest_overlap = overlap; - scene_surface->primary_output = scene_output->output; - } - - // These enter/leave functions are a noop if the event has already been - // sent for the given output. - wlr_surface_send_enter(scene_surface->surface, scene_output->output); - } else { - wlr_surface_send_leave(scene_surface->surface, scene_output->output); - } - } -} - // This function must be called whenever the coordinates/dimensions of a scene // buffer or scene output change. It is not necessary to call when a scene // buffer's node is enabled/disabled or obscured by other nodes. @@ -258,11 +190,7 @@ static void scene_buffer_update_outputs( static void _scene_node_update_outputs( struct wlr_scene_node *node, int lx, int ly, struct wlr_scene *scene) { - if (node->type == WLR_SCENE_NODE_SURFACE) { - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_from_node(node); - scene_surface_update_outputs(scene_surface, lx, ly, scene); - } else if (node->type == WLR_SCENE_NODE_BUFFER) { + if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); scene_buffer_update_outputs(scene_buffer, lx, ly, scene); @@ -282,86 +210,6 @@ static void scene_node_update_outputs(struct wlr_scene_node *node) { _scene_node_update_outputs(node, lx, ly, scene); } -static void scene_surface_handle_surface_commit(struct wl_listener *listener, - void *data) { - struct wlr_scene_surface *scene_surface = - wl_container_of(listener, scene_surface, surface_commit); - struct wlr_surface *surface = scene_surface->surface; - - struct wlr_scene *scene = scene_node_get_root(&scene_surface->node); - - int lx, ly; - bool enabled = wlr_scene_node_coords(&scene_surface->node, &lx, &ly); - - if (surface->current.width != scene_surface->prev_width || - surface->current.height != scene_surface->prev_height) { - scene_surface_update_outputs(scene_surface, lx, ly, scene); - scene_surface->prev_width = surface->current.width; - scene_surface->prev_height = surface->current.height; - } - - if (!enabled) { - return; - } - - // Even if the surface hasn't submitted damage, schedule a new frame if - // the client has requested a wl_surface.frame callback. - if (!wl_list_empty(&surface->current.frame_callback_list) && - scene_surface->primary_output != NULL) { - wlr_output_schedule_frame(scene_surface->primary_output); - } - - if (!pixman_region32_not_empty(&surface->buffer_damage)) { - return; - } - - struct wlr_scene_output *scene_output; - wl_list_for_each(scene_output, &scene->outputs, link) { - struct wlr_output *output = scene_output->output; - - pixman_region32_t damage; - pixman_region32_init(&damage); - wlr_surface_get_effective_damage(surface, &damage); - - pixman_region32_translate(&damage, - lx - scene_output->x, ly - scene_output->y); - - wlr_region_scale(&damage, &damage, output->scale); - if (ceil(output->scale) > surface->current.scale) { - // When scaling up a surface it'll become blurry, so we need to - // expand the damage region. - wlr_region_expand(&damage, &damage, - ceil(output->scale) - surface->current.scale); - } - wlr_output_damage_add(scene_output->damage, &damage); - pixman_region32_fini(&damage); - } -} - -struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_node *parent, - struct wlr_surface *surface) { - struct wlr_scene_surface *scene_surface = - calloc(1, sizeof(struct wlr_scene_surface)); - if (scene_surface == NULL) { - return NULL; - } - scene_node_init(&scene_surface->node, WLR_SCENE_NODE_SURFACE, parent); - - scene_surface->surface = surface; - - scene_surface->surface_destroy.notify = scene_surface_handle_surface_destroy; - wl_signal_add(&surface->events.destroy, &scene_surface->surface_destroy); - - scene_surface->surface_commit.notify = scene_surface_handle_surface_commit; - wl_signal_add(&surface->events.commit, &scene_surface->surface_commit); - - scene_node_damage_whole(&scene_surface->node); - - scene_node_update_outputs(&scene_surface->node); - - return scene_surface; -} - struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_node *parent, int width, int height, const float color[static 4]) { struct wlr_scene_rect *scene_rect = @@ -589,12 +437,6 @@ static void scene_node_get_size(struct wlr_scene_node *node, case WLR_SCENE_NODE_ROOT: case WLR_SCENE_NODE_TREE: return; - case WLR_SCENE_NODE_SURFACE:; - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_from_node(node); - *width = scene_surface->surface->current.width; - *height = scene_surface->surface->current.height; - break; case WLR_SCENE_NODE_RECT:; struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); *width = scene_rect->width; @@ -838,10 +680,6 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, case WLR_SCENE_NODE_ROOT: case WLR_SCENE_NODE_TREE: break; - case WLR_SCENE_NODE_SURFACE:; - struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); - intersects = wlr_surface_point_accepts_input(scene_surface->surface, lx, ly); - break; case WLR_SCENE_NODE_RECT:; int width, height; scene_node_get_size(node, &width, &height); @@ -948,9 +786,6 @@ static void render_texture(struct wlr_output *output, struct render_data { struct wlr_scene_output *scene_output; pixman_region32_t *damage; - - // May be NULL - struct wlr_presentation *presentation; }; static void render_node_iterator(struct wlr_scene_node *node, @@ -975,30 +810,6 @@ static void render_node_iterator(struct wlr_scene_node *node, case WLR_SCENE_NODE_TREE: /* Root or tree node has nothing to render itself */ break; - case WLR_SCENE_NODE_SURFACE:; - struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); - struct wlr_surface *surface = scene_surface->surface; - - texture = wlr_surface_get_texture(surface); - if (texture == NULL) { - return; - } - - transform = wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box(matrix, &dst_box, transform, 0.0, - output->transform_matrix); - - struct wlr_fbox src_box = {0}; - wlr_surface_get_buffer_source_box(surface, &src_box); - - 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); @@ -1141,11 +952,7 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, static void scene_node_remove_output(struct wlr_scene_node *node, struct wlr_scene_output *output) { - if (node->type == WLR_SCENE_NODE_SURFACE) { - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_from_node(node); - wlr_surface_send_leave(scene_surface->surface, output->output); - } else if (node->type == WLR_SCENE_NODE_BUFFER) { + if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); uint64_t mask = 1ull << output->index; @@ -1246,15 +1053,6 @@ static bool scene_output_scanout(struct wlr_scene_output *scene_output) { struct wlr_scene_node *node = check_scanout_data.node; struct wlr_buffer *buffer; switch (node->type) { - case WLR_SCENE_NODE_SURFACE:; - struct wlr_scene_surface *scene_surface = wlr_scene_surface_from_node(node); - if (scene_surface->surface->buffer == NULL || - scene_surface->surface->current.viewport.has_src || - scene_surface->surface->current.transform != output->transform) { - return false; - } - buffer = &scene_surface->surface->buffer->base; - break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); if (scene_buffer->buffer == NULL || @@ -1274,18 +1072,6 @@ 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); - } - } - if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); @@ -1340,7 +1126,6 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { struct render_data data = { .scene_output = scene_output, .damage = &damage, - .presentation = scene_output->scene->presentation, }; scene_node_for_each_node(&scene_output->scene->node, -scene_output->x, -scene_output->y, @@ -1373,14 +1158,6 @@ static void scene_node_send_frame_done(struct wlr_scene_node *node, return; } - if (node->type == WLR_SCENE_NODE_SURFACE) { - struct wlr_scene_surface *scene_surface = - wlr_scene_surface_from_node(node); - if (scene_surface->primary_output == scene_output->output) { - wlr_surface_send_frame_done(scene_surface->surface, now); - } - } - if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); -- cgit v1.2.3 From aea018c787a3cca4310cadd16372865bfeaf23a7 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sun, 22 May 2022 10:36:25 +0300 Subject: scene/output: check for NULL in destructor --- wlr_scene.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 2435ede..303325f 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -969,6 +969,10 @@ static void scene_node_remove_output(struct wlr_scene_node *node, } void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { + if (scene_output == NULL) { + return; + } + scene_node_remove_output(&scene_output->scene->node, scene_output); wlr_addon_finish(&scene_output->addon); -- cgit v1.2.3 From 4eb610b627cb3063785883f89b432b8d95be4be9 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Fri, 20 May 2022 18:28:08 -0400 Subject: wlr_scene: Parse out WLR_SCENE_DEBUG_DAMAGE --- wlr_scene.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 303325f..4241a57 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -130,6 +130,23 @@ 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); + + char *debug_damage = getenv("WLR_SCENE_DEBUG_DAMAGE"); + if (debug_damage) { + wlr_log(WLR_INFO, "Loading WLR_SCENE_DEBUG_DAMAGE option: %s", debug_damage); + } + + if (!debug_damage || strcmp(debug_damage, "none") == 0) { + scene->debug_damage_option = WLR_SCENE_DEBUG_DAMAGE_NONE; + } else if (strcmp(debug_damage, "rerender") == 0) { + scene->debug_damage_option = WLR_SCENE_DEBUG_DAMAGE_RERENDER; + } else if (strcmp(debug_damage, "highlight") == 0) { + scene->debug_damage_option = WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT; + } else { + wlr_log(WLR_ERROR, "Unknown WLR_SCENE_DEBUG_DAMAGE option: %s", debug_damage); + scene->debug_damage_option = WLR_SCENE_DEBUG_DAMAGE_NONE; + } + return scene; } -- cgit v1.2.3 From ea5413394d981ad3cc3e46e26784d2a36f94daa4 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Fri, 20 May 2022 18:31:41 -0400 Subject: wlr_scene: Hook up RERENDER logic --- wlr_scene.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 4241a57..6f0591b 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -1104,6 +1104,8 @@ static bool scene_output_scanout(struct wlr_scene_output *scene_output) { bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { struct wlr_output *output = scene_output->output; + enum wlr_scene_debug_damage_option debug_damage = + scene_output->scene->debug_damage_option; struct wlr_renderer *renderer = output->renderer; assert(renderer != NULL); @@ -1120,6 +1122,10 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { return true; } + if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_RERENDER) { + wlr_output_damage_add_whole(scene_output->damage); + } + bool needs_frame; pixman_region32_t damage; pixman_region32_init(&damage); -- cgit v1.2.3 From 99828d96d67e90e04faf595915aece664fc08c4e Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Mon, 23 May 2022 15:58:49 -0400 Subject: wlr_scene: Hook up HIGHLIGHT logic This will display red translucent rectangles on the screen regions that have been damaged. These rectangles will fade out over the span of 250 msecs. If the area is damaged again while the region is fading out, the timer is reset. Let's also disable direct scan out when this option is enabled, or else we won't be able to render the highlight damage regions. --- wlr_scene.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/wlr_scene.c b/wlr_scene.c index 6f0591b..676fe12 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -1,3 +1,4 @@ +#define _POSIX_C_SOURCE 200809L #include #include #include @@ -12,6 +13,9 @@ #include #include "types/wlr_scene.h" #include "util/signal.h" +#include "util/time.h" + +#define HIGHLIGHT_DAMAGE_FADEOUT_TIME 250 static struct wlr_scene *scene_root_from_node(struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_ROOT); @@ -67,6 +71,18 @@ static void scene_node_init(struct wlr_scene_node *node, static void scene_node_damage_whole(struct wlr_scene_node *node); +struct highlight_region { + pixman_region32_t region; + struct timespec when; + struct wl_list link; +}; + +static void highlight_region_destroy(struct highlight_region *damage) { + wl_list_remove(&damage->link); + pixman_region32_fini(&damage->region); + free(damage); +} + void wlr_scene_node_destroy(struct wlr_scene_node *node) { if (node == NULL) { return; @@ -88,6 +104,11 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wlr_scene_output_destroy(scene_output); } + struct highlight_region *damage, *tmp_damage; + wl_list_for_each_safe(damage, tmp_damage, &scene->damage_highlight_regions, link) { + highlight_region_destroy(damage); + } + wl_list_remove(&scene->presentation_destroy.link); break; case WLR_SCENE_NODE_BUFFER:; @@ -130,6 +151,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); + wl_list_init(&scene->damage_highlight_regions); char *debug_damage = getenv("WLR_SCENE_DEBUG_DAMAGE"); if (debug_damage) { @@ -1056,6 +1078,13 @@ static void check_scanout_iterator(struct wlr_scene_node *node, } static bool scene_output_scanout(struct wlr_scene_output *scene_output) { + if (scene_output->scene->debug_damage_option == + WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { + // We don't want to enter direct scan out if we have highlight regions + // enabled. Otherwise, we won't be able to render the damage regions. + return false; + } + struct wlr_output *output = scene_output->output; struct wlr_box viewport_box = { .x = scene_output->x, .y = scene_output->y }; @@ -1126,6 +1155,45 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { wlr_output_damage_add_whole(scene_output->damage); } + struct timespec now; + if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { + struct wl_list *regions = &scene_output->scene->damage_highlight_regions; + clock_gettime(CLOCK_MONOTONIC, &now); + + // add the current frame's damage if there is damage + if (pixman_region32_not_empty(&scene_output->damage->current)) { + struct highlight_region *current_damage = + calloc(1, sizeof(*current_damage)); + if (current_damage) { + pixman_region32_init(¤t_damage->region); + pixman_region32_copy(¤t_damage->region, + &scene_output->damage->current); + memcpy(¤t_damage->when, &now, sizeof(now)); + wl_list_insert(regions, ¤t_damage->link); + } + } + + pixman_region32_t acc_damage; + pixman_region32_init(&acc_damage); + struct highlight_region *damage, *tmp_damage; + wl_list_for_each_safe(damage, tmp_damage, regions, link) { + // remove overlaping damage regions + pixman_region32_subtract(&damage->region, &damage->region, &acc_damage); + pixman_region32_union(&acc_damage, &acc_damage, &damage->region); + + // if this damage is too old or has nothing in it, get rid of it + struct timespec time_diff; + timespec_sub(&time_diff, &now, &damage->when); + if (timespec_to_msec(&time_diff) >= HIGHLIGHT_DAMAGE_FADEOUT_TIME || + !pixman_region32_not_empty(&damage->region)) { + highlight_region_destroy(damage); + } + } + + wlr_output_damage_add(scene_output->damage, &acc_damage); + pixman_region32_fini(&acc_damage); + } + bool needs_frame; pixman_region32_t damage; pixman_region32_init(&damage); @@ -1158,6 +1226,31 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { -scene_output->x, -scene_output->y, render_node_iterator, &data); wlr_renderer_scissor(renderer, NULL); + + if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { + struct highlight_region *damage; + wl_list_for_each(damage, &scene_output->scene->damage_highlight_regions, link) { + struct timespec time_diff; + timespec_sub(&time_diff, &now, &damage->when); + int64_t time_diff_ms = timespec_to_msec(&time_diff); + float alpha = 1.0 - (double)time_diff_ms / HIGHLIGHT_DAMAGE_FADEOUT_TIME; + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(&damage->region, &nrects); + for (int i = 0; i < nrects; ++i) { + struct wlr_box box = { + .x = rects[i].x1, + .y = rects[i].y1, + .width = rects[i].x2 - rects[i].x1, + .height = rects[i].y2 - rects[i].y1, + }; + + float color[4] = { alpha * .5, 0.0, 0.0, alpha * .5 }; + wlr_render_rect(renderer, &box, color, output->transform_matrix); + } + } + } + wlr_output_render_software_cursors(output, &damage); wlr_renderer_end(renderer); @@ -1176,7 +1269,14 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { wlr_output_set_damage(output, &frame_damage); pixman_region32_fini(&frame_damage); - return wlr_output_commit(output); + bool success = wlr_output_commit(output); + + if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT && + !wl_list_empty(&scene_output->scene->damage_highlight_regions)) { + wlr_output_schedule_frame(scene_output->output); + } + + return success; } static void scene_node_send_frame_done(struct wlr_scene_node *node, -- cgit v1.2.3 From 3ca1c8543b25f92d0bff843468c5c4812b474d8a Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Wed, 13 Apr 2022 20:22:14 +0300 Subject: xdg-popup: use current/pending state pattern --- xdg_shell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xdg_shell.c b/xdg_shell.c index 9b3ad71..909719d 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -60,7 +60,7 @@ static void scene_xdg_surface_update_position( if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { struct wlr_xdg_popup *popup = xdg_surface->popup; wlr_scene_node_set_position(&scene_xdg_surface->tree->node, - popup->geometry.x, popup->geometry.y); + popup->current.geometry.x, popup->current.geometry.y); } } -- cgit v1.2.3 From c7cc2125a642a21cea6a8098208dd147473f321a Mon Sep 17 00:00:00 2001 From: Consolatis <40171-Consolatis@users.noreply.gitlab.freedesktop.org> Date: Mon, 30 May 2022 17:31:47 +0200 Subject: wlr_scene: Fix scaling with default source_box Default to texture instead of destination_box geometry. --- wlr_scene.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 676fe12..86eb2bf 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -801,8 +801,8 @@ static void render_texture(struct wlr_output *output, struct wlr_fbox default_src_box = {0}; if (wlr_fbox_empty(src_box)) { - default_src_box.width = dst_box->width; - default_src_box.height = dst_box->height; + default_src_box.width = texture->width; + default_src_box.height = texture->height; src_box = &default_src_box; } -- cgit v1.2.3 From 6975c82d95080589882b71083f67dc905e5a7f80 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Mon, 30 May 2022 19:26:08 -0400 Subject: wlr_scene: Refactor wlr_scene (the root element) to encase a wlr_scene_tree Co-authored-by: Isaac Freund --- output_layout.c | 2 +- wlr_scene.c | 87 +++++++++++++++++++++++++++++---------------------------- 2 files changed, 45 insertions(+), 44 deletions(-) diff --git a/output_layout.c b/output_layout.c index b80759f..e2327eb 100644 --- a/output_layout.c +++ b/output_layout.c @@ -99,7 +99,7 @@ bool wlr_scene_attach_output_layout(struct wlr_scene *scene, wl_signal_add(&output_layout->events.add, &sol->layout_add); sol->scene_destroy.notify = scene_output_layout_handle_scene_destroy; - wl_signal_add(&scene->node.events.destroy, &sol->scene_destroy); + wl_signal_add(&scene->tree.node.events.destroy, &sol->scene_destroy); return true; } diff --git a/wlr_scene.c b/wlr_scene.c index 86eb2bf..410fbe3 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -17,11 +17,6 @@ #define HIGHLIGHT_DAMAGE_FADEOUT_TIME 250 -static struct wlr_scene *scene_root_from_node(struct wlr_scene_node *node) { - assert(node->type == WLR_SCENE_NODE_ROOT); - return (struct wlr_scene *)node; -} - static struct wlr_scene_rect *scene_rect_from_node( struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_RECT); @@ -38,7 +33,7 @@ struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { while (node->parent != NULL) { node = node->parent; } - return scene_root_from_node(node); + return (struct wlr_scene *)node; } static void scene_node_state_init(struct wlr_scene_node_state *state) { @@ -54,8 +49,6 @@ static void scene_node_state_finish(struct wlr_scene_node_state *state) { static void scene_node_init(struct wlr_scene_node *node, enum wlr_scene_node_type type, struct wlr_scene_node *parent) { - assert(type == WLR_SCENE_NODE_ROOT || parent != NULL); - memset(node, 0, sizeof(*node)); node->type = type; node->parent = parent; @@ -96,26 +89,12 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wlr_signal_emit_safe(&node->events.destroy, NULL); struct wlr_scene *scene = scene_node_get_root(node); - struct wlr_scene_output *scene_output; - switch (node->type) { - case WLR_SCENE_NODE_ROOT:; - struct wlr_scene_output *scene_output_tmp; - wl_list_for_each_safe(scene_output, scene_output_tmp, &scene->outputs, link) { - wlr_scene_output_destroy(scene_output); - } - - struct highlight_region *damage, *tmp_damage; - wl_list_for_each_safe(damage, tmp_damage, &scene->damage_highlight_regions, link) { - highlight_region_destroy(damage); - } - - wl_list_remove(&scene->presentation_destroy.link); - break; - case WLR_SCENE_NODE_BUFFER:; + if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); uint64_t active = scene_buffer->active_outputs; if (active) { + struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { if (active & (1ull << scene_output->index)) { wlr_signal_emit_safe(&scene_buffer->events.output_leave, @@ -126,10 +105,23 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wlr_texture_destroy(scene_buffer->texture); wlr_buffer_unlock(scene_buffer->buffer); - break; - case WLR_SCENE_NODE_TREE: - case WLR_SCENE_NODE_RECT: - break; + } else if (node->type == WLR_SCENE_NODE_TREE) { + if (node == &scene->tree.node) { + assert(!node->parent); + struct wlr_scene_output *scene_output, *scene_output_tmp; + wl_list_for_each_safe(scene_output, scene_output_tmp, &scene->outputs, link) { + wlr_scene_output_destroy(scene_output); + } + + struct highlight_region *damage, *tmp_damage; + wl_list_for_each_safe(damage, tmp_damage, &scene->damage_highlight_regions, link) { + highlight_region_destroy(damage); + } + + wl_list_remove(&scene->presentation_destroy.link); + } else { + assert(node->parent); + } } struct wlr_scene_node *child, *child_tmp; @@ -143,12 +135,20 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { free(node); } +static void scene_tree_init(struct wlr_scene_tree *tree, + struct wlr_scene_node *parent) { + memset(tree, 0, sizeof(*tree)); + scene_node_init(&tree->node, WLR_SCENE_NODE_TREE, parent); +} + struct wlr_scene *wlr_scene_create(void) { struct wlr_scene *scene = calloc(1, sizeof(struct wlr_scene)); if (scene == NULL) { return NULL; } - scene_node_init(&scene->node, WLR_SCENE_NODE_ROOT, NULL); + + scene_tree_init(&scene->tree, NULL); + wl_list_init(&scene->outputs); wl_list_init(&scene->presentation_destroy.link); wl_list_init(&scene->damage_highlight_regions); @@ -173,12 +173,14 @@ struct wlr_scene *wlr_scene_create(void) { } struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_node *parent) { + assert(parent); + struct wlr_scene_tree *tree = calloc(1, sizeof(struct wlr_scene_tree)); if (tree == NULL) { return NULL; } - scene_node_init(&tree->node, WLR_SCENE_NODE_TREE, parent); + scene_tree_init(tree, parent); return tree; } @@ -256,6 +258,7 @@ struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_node *parent, if (scene_rect == NULL) { return NULL; } + assert(parent); scene_node_init(&scene_rect->node, WLR_SCENE_NODE_RECT, parent); scene_rect->width = width; @@ -293,6 +296,7 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, if (scene_buffer == NULL) { return NULL; } + assert(parent); scene_node_init(&scene_buffer->node, WLR_SCENE_NODE_BUFFER, parent); if (buffer) { @@ -473,7 +477,6 @@ static void scene_node_get_size(struct wlr_scene_node *node, *height = 0; switch (node->type) { - case WLR_SCENE_NODE_ROOT: case WLR_SCENE_NODE_TREE: return; case WLR_SCENE_NODE_RECT:; @@ -630,7 +633,7 @@ void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node) { void wlr_scene_node_reparent(struct wlr_scene_node *node, struct wlr_scene_node *new_parent) { - assert(node->type != WLR_SCENE_NODE_ROOT && new_parent != NULL); + assert(new_parent != NULL); if (node->parent == new_parent) { return; @@ -716,7 +719,6 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, bool intersects = false; switch (node->type) { - case WLR_SCENE_NODE_ROOT: case WLR_SCENE_NODE_TREE: break; case WLR_SCENE_NODE_RECT:; @@ -845,7 +847,6 @@ static void render_node_iterator(struct wlr_scene_node *node, float matrix[9]; enum wl_output_transform transform; switch (node->type) { - case WLR_SCENE_NODE_ROOT: case WLR_SCENE_NODE_TREE: /* Root or tree node has nothing to render itself */ break; @@ -933,14 +934,14 @@ static void scene_output_handle_commit(struct wl_listener *listener, void *data) if (event->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM | WLR_OUTPUT_STATE_SCALE)) { - scene_node_update_outputs(&scene_output->scene->node); + scene_node_update_outputs(&scene_output->scene->tree.node); } } static void scene_output_handle_mode(struct wl_listener *listener, void *data) { struct wlr_scene_output *scene_output = wl_container_of(listener, scene_output, output_mode); - scene_node_update_outputs(&scene_output->scene->node); + scene_node_update_outputs(&scene_output->scene->tree.node); } struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, @@ -984,7 +985,7 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, wl_signal_add(&output->events.mode, &scene_output->output_mode); wlr_output_damage_add_whole(scene_output->damage); - scene_node_update_outputs(&scene->node); + scene_node_update_outputs(&scene->tree.node); return scene_output; } @@ -1012,7 +1013,7 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { return; } - scene_node_remove_output(&scene_output->scene->node, scene_output); + scene_node_remove_output(&scene_output->scene->tree.node, scene_output); wlr_addon_finish(&scene_output->addon); wl_list_remove(&scene_output->link); @@ -1044,7 +1045,7 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, scene_output->y = ly; wlr_output_damage_add_whole(scene_output->damage); - scene_node_update_outputs(&scene_output->scene->node); + scene_node_update_outputs(&scene_output->scene->tree.node); } struct check_scanout_data { @@ -1094,7 +1095,7 @@ static bool scene_output_scanout(struct wlr_scene_output *scene_output) { struct check_scanout_data check_scanout_data = { .viewport_box = viewport_box, }; - scene_node_for_each_node(&scene_output->scene->node, 0, 0, + scene_node_for_each_node(&scene_output->scene->tree.node, 0, 0, check_scanout_iterator, &check_scanout_data); if (check_scanout_data.n != 1 || check_scanout_data.node == NULL) { return false; @@ -1222,7 +1223,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { .scene_output = scene_output, .damage = &damage, }; - scene_node_for_each_node(&scene_output->scene->node, + scene_node_for_each_node(&scene_output->scene->tree.node, -scene_output->x, -scene_output->y, render_node_iterator, &data); wlr_renderer_scissor(renderer, NULL); @@ -1302,7 +1303,7 @@ static void scene_node_send_frame_done(struct wlr_scene_node *node, void wlr_scene_output_send_frame_done(struct wlr_scene_output *scene_output, struct timespec *now) { - scene_node_send_frame_done(&scene_output->scene->node, + scene_node_send_frame_done(&scene_output->scene->tree.node, scene_output, now); } @@ -1340,6 +1341,6 @@ void wlr_scene_output_for_each_buffer(struct wlr_scene_output *scene_output, struct wlr_box box = { .x = scene_output->x, .y = scene_output->y }; wlr_output_effective_resolution(scene_output->output, &box.width, &box.height); - scene_output_for_each_scene_buffer(&box, &scene_output->scene->node, 0, 0, + scene_output_for_each_scene_buffer(&box, &scene_output->scene->tree.node, 0, 0, iterator, user_data); } -- cgit v1.2.3 From 3a68007693f9d91c3b6dc12a204455df36ae65a1 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Mon, 30 May 2022 19:23:27 -0400 Subject: wlr_scene: Only allow parenting on a wlr_scene_tree --- layer_shell_v1.c | 27 +++++++++++++-------------- subsurface_tree.c | 14 +++++++------- surface.c | 2 +- wlr_scene.c | 54 ++++++++++++++++++++++++++++++++++++------------------ xdg_shell.c | 16 ++++++++-------- 5 files changed, 65 insertions(+), 48 deletions(-) diff --git a/layer_shell_v1.c b/layer_shell_v1.c index 1c2b6e4..eb0bc76 100644 --- a/layer_shell_v1.c +++ b/layer_shell_v1.c @@ -18,21 +18,21 @@ static void scene_layer_surface_handle_layer_surface_destroy( struct wl_listener *listener, void *data) { struct wlr_scene_layer_surface_v1 *scene_layer_surface = wl_container_of(listener, scene_layer_surface, layer_surface_destroy); - wlr_scene_node_destroy(scene_layer_surface->node); + wlr_scene_node_destroy(&scene_layer_surface->tree->node); } static void scene_layer_surface_handle_layer_surface_map( struct wl_listener *listener, void *data) { struct wlr_scene_layer_surface_v1 *scene_layer_surface = wl_container_of(listener, scene_layer_surface, layer_surface_map); - wlr_scene_node_set_enabled(scene_layer_surface->node, true); + wlr_scene_node_set_enabled(&scene_layer_surface->tree->node, true); } static void scene_layer_surface_handle_layer_surface_unmap( struct wl_listener *listener, void *data) { struct wlr_scene_layer_surface_v1 *scene_layer_surface = wl_container_of(listener, scene_layer_surface, layer_surface_unmap); - wlr_scene_node_set_enabled(scene_layer_surface->node, false); + wlr_scene_node_set_enabled(&scene_layer_surface->tree->node, false); } static void layer_surface_exclusive_zone( @@ -122,7 +122,7 @@ void wlr_scene_layer_surface_v1_configure( box.y = bounds.y + bounds.height/2 - box.height/2; } - wlr_scene_node_set_position(scene_layer_surface->node, box.x, box.y); + wlr_scene_node_set_position(&scene_layer_surface->tree->node, box.x, box.y); wlr_layer_surface_v1_configure(layer_surface, box.width, box.height); if (state->exclusive_zone > 0) { @@ -131,7 +131,7 @@ void wlr_scene_layer_surface_v1_configure( } struct wlr_scene_layer_surface_v1 *wlr_scene_layer_surface_v1_create( - struct wlr_scene_node *parent, + struct wlr_scene_tree *parent, struct wlr_layer_surface_v1 *layer_surface) { struct wlr_scene_layer_surface_v1 *scene_layer_surface = calloc(1, sizeof(*scene_layer_surface)); @@ -141,24 +141,23 @@ struct wlr_scene_layer_surface_v1 *wlr_scene_layer_surface_v1_create( scene_layer_surface->layer_surface = layer_surface; - struct wlr_scene_tree *tree = wlr_scene_tree_create(parent); - if (tree == NULL) { + scene_layer_surface->tree = wlr_scene_tree_create(parent); + if (scene_layer_surface->tree == NULL) { free(scene_layer_surface); return NULL; } - scene_layer_surface->node = &tree->node; - struct wlr_scene_node *surface_node = wlr_scene_subsurface_tree_create( - scene_layer_surface->node, layer_surface->surface); - if (surface_node == NULL) { - wlr_scene_node_destroy(scene_layer_surface->node); + struct wlr_scene_tree *surface_tree = wlr_scene_subsurface_tree_create( + scene_layer_surface->tree, layer_surface->surface); + if (surface_tree == NULL) { + wlr_scene_node_destroy(&scene_layer_surface->tree->node); free(scene_layer_surface); return NULL; } scene_layer_surface->tree_destroy.notify = scene_layer_surface_handle_tree_destroy; - wl_signal_add(&scene_layer_surface->node->events.destroy, + wl_signal_add(&scene_layer_surface->tree->node.events.destroy, &scene_layer_surface->tree_destroy); scene_layer_surface->layer_surface_destroy.notify = @@ -176,7 +175,7 @@ struct wlr_scene_layer_surface_v1 *wlr_scene_layer_surface_v1_create( wl_signal_add(&layer_surface->events.unmap, &scene_layer_surface->layer_surface_unmap); - wlr_scene_node_set_enabled(scene_layer_surface->node, + wlr_scene_node_set_enabled(&scene_layer_surface->tree->node, layer_surface->mapped); return scene_layer_surface; diff --git a/subsurface_tree.c b/subsurface_tree.c index 1cb2977..35420ab 100644 --- a/subsurface_tree.c +++ b/subsurface_tree.c @@ -148,13 +148,13 @@ static const struct wlr_addon_interface subsurface_tree_addon_impl = { }; static struct wlr_scene_subsurface_tree *scene_surface_tree_create( - struct wlr_scene_node *parent, struct wlr_surface *surface); + struct wlr_scene_tree *parent, struct wlr_surface *surface); static bool subsurface_tree_create_subsurface( struct wlr_scene_subsurface_tree *parent, struct wlr_subsurface *subsurface) { struct wlr_scene_subsurface_tree *child = scene_surface_tree_create( - &parent->tree->node, subsurface->surface); + parent->tree, subsurface->surface); if (child == NULL) { return false; } @@ -188,7 +188,7 @@ static void subsurface_tree_handle_surface_new_subsurface( } static struct wlr_scene_subsurface_tree *scene_surface_tree_create( - struct wlr_scene_node *parent, struct wlr_surface *surface) { + struct wlr_scene_tree *parent, struct wlr_surface *surface) { struct wlr_scene_subsurface_tree *subsurface_tree = calloc(1, sizeof(*subsurface_tree)); if (subsurface_tree == NULL) { @@ -201,7 +201,7 @@ static struct wlr_scene_subsurface_tree *scene_surface_tree_create( } subsurface_tree->scene_surface = - wlr_scene_surface_create(&subsurface_tree->tree->node, surface); + wlr_scene_surface_create(subsurface_tree->tree, surface); if (subsurface_tree->scene_surface == NULL) { goto error_scene_surface; } @@ -248,12 +248,12 @@ error_surface_tree: return NULL; } -struct wlr_scene_node *wlr_scene_subsurface_tree_create( - struct wlr_scene_node *parent, struct wlr_surface *surface) { +struct wlr_scene_tree *wlr_scene_subsurface_tree_create( + struct wlr_scene_tree *parent, struct wlr_surface *surface) { struct wlr_scene_subsurface_tree *subsurface_tree = scene_surface_tree_create(parent, surface); if (subsurface_tree == NULL) { return NULL; } - return &subsurface_tree->tree->node; + return subsurface_tree->tree; } diff --git a/surface.c b/surface.c index e6a8b6b..d3a0b03 100644 --- a/surface.c +++ b/surface.c @@ -135,7 +135,7 @@ struct wlr_scene_surface *wlr_scene_surface_from_buffer( return surface; } -struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_node *parent, +struct wlr_scene_surface *wlr_scene_surface_create(struct wlr_scene_tree *parent, struct wlr_surface *wlr_surface) { struct wlr_scene_surface *surface = calloc(1, sizeof(*surface)); if (surface == NULL) { diff --git a/wlr_scene.c b/wlr_scene.c index 410fbe3..e60ff5d 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -17,6 +17,11 @@ #define HIGHLIGHT_DAMAGE_FADEOUT_TIME 250 +static struct wlr_scene_tree *scene_tree_from_node(struct wlr_scene_node *node) { + assert(node->type == WLR_SCENE_NODE_TREE); + return (struct wlr_scene_tree *)node; +} + static struct wlr_scene_rect *scene_rect_from_node( struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_RECT); @@ -30,10 +35,17 @@ struct wlr_scene_buffer *wlr_scene_buffer_from_node( } struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { - while (node->parent != NULL) { - node = node->parent; + struct wlr_scene_tree *tree; + if (node->type == WLR_SCENE_NODE_TREE) { + tree = scene_tree_from_node(node); + } else { + tree = node->parent; + } + + while (tree->node.parent != NULL) { + tree = tree->node.parent; } - return (struct wlr_scene *)node; + return (struct wlr_scene *)tree; } static void scene_node_state_init(struct wlr_scene_node_state *state) { @@ -48,7 +60,7 @@ static void scene_node_state_finish(struct wlr_scene_node_state *state) { } static void scene_node_init(struct wlr_scene_node *node, - enum wlr_scene_node_type type, struct wlr_scene_node *parent) { + enum wlr_scene_node_type type, struct wlr_scene_tree *parent) { memset(node, 0, sizeof(*node)); node->type = type; node->parent = parent; @@ -56,7 +68,7 @@ static void scene_node_init(struct wlr_scene_node *node, wl_signal_init(&node->events.destroy); if (parent != NULL) { - wl_list_insert(parent->state.children.prev, &node->state.link); + wl_list_insert(parent->node.state.children.prev, &node->state.link); } wlr_addon_set_init(&node->addons); @@ -136,7 +148,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { } static void scene_tree_init(struct wlr_scene_tree *tree, - struct wlr_scene_node *parent) { + struct wlr_scene_tree *parent) { memset(tree, 0, sizeof(*tree)); scene_node_init(&tree->node, WLR_SCENE_NODE_TREE, parent); } @@ -172,7 +184,7 @@ struct wlr_scene *wlr_scene_create(void) { return scene; } -struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_node *parent) { +struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent) { assert(parent); struct wlr_scene_tree *tree = calloc(1, sizeof(struct wlr_scene_tree)); @@ -251,7 +263,7 @@ static void scene_node_update_outputs(struct wlr_scene_node *node) { _scene_node_update_outputs(node, lx, ly, scene); } -struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_node *parent, +struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent, int width, int height, const float color[static 4]) { struct wlr_scene_rect *scene_rect = calloc(1, sizeof(struct wlr_scene_rect)); @@ -290,7 +302,7 @@ void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[sta scene_node_damage_whole(&rect->node); } -struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_node *parent, +struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, struct wlr_buffer *buffer) { struct wlr_scene_buffer *scene_buffer = calloc(1, sizeof(*scene_buffer)); if (scene_buffer == NULL) { @@ -615,7 +627,7 @@ void wlr_scene_node_place_below(struct wlr_scene_node *node, void wlr_scene_node_raise_to_top(struct wlr_scene_node *node) { struct wlr_scene_node *current_top = wl_container_of( - node->parent->state.children.prev, current_top, state.link); + node->parent->node.state.children.prev, current_top, state.link); if (node == current_top) { return; } @@ -624,7 +636,7 @@ void wlr_scene_node_raise_to_top(struct wlr_scene_node *node) { void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node) { struct wlr_scene_node *current_bottom = wl_container_of( - node->parent->state.children.next, current_bottom, state.link); + node->parent->node.state.children.next, current_bottom, state.link); if (node == current_bottom) { return; } @@ -632,7 +644,7 @@ void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node) { } void wlr_scene_node_reparent(struct wlr_scene_node *node, - struct wlr_scene_node *new_parent) { + struct wlr_scene_tree *new_parent) { assert(new_parent != NULL); if (node->parent == new_parent) { @@ -640,16 +652,16 @@ void wlr_scene_node_reparent(struct wlr_scene_node *node, } /* Ensure that a node cannot become its own ancestor */ - for (struct wlr_scene_node *ancestor = new_parent; ancestor != NULL; - ancestor = ancestor->parent) { - assert(ancestor != node); + for (struct wlr_scene_tree *ancestor = new_parent; ancestor != NULL; + ancestor = ancestor->node.parent) { + assert(&ancestor->node != node); } scene_node_damage_whole(node); wl_list_remove(&node->state.link); node->parent = new_parent; - wl_list_insert(new_parent->state.children.prev, &node->state.link); + wl_list_insert(new_parent->node.state.children.prev, &node->state.link); scene_node_damage_whole(node); @@ -658,13 +670,19 @@ void wlr_scene_node_reparent(struct wlr_scene_node *node, bool wlr_scene_node_coords(struct wlr_scene_node *node, int *lx_ptr, int *ly_ptr) { + assert(node); + int lx = 0, ly = 0; bool enabled = true; - while (node != NULL) { + while (true) { lx += node->state.x; ly += node->state.y; enabled = enabled && node->state.enabled; - node = node->parent; + if (node->parent == NULL) { + break; + } + + node = &node->parent->node; } *lx_ptr = lx; diff --git a/xdg_shell.c b/xdg_shell.c index 909719d..1688348 100644 --- a/xdg_shell.c +++ b/xdg_shell.c @@ -5,7 +5,7 @@ struct wlr_scene_xdg_surface { struct wlr_scene_tree *tree; struct wlr_xdg_surface *xdg_surface; - struct wlr_scene_node *surface_node; + struct wlr_scene_tree *surface_tree; struct wl_listener tree_destroy; struct wl_listener xdg_surface_destroy; @@ -54,7 +54,7 @@ static void scene_xdg_surface_update_position( struct wlr_box geo = {0}; wlr_xdg_surface_get_geometry(xdg_surface, &geo); - wlr_scene_node_set_position(scene_xdg_surface->surface_node, + wlr_scene_node_set_position(&scene_xdg_surface->surface_tree->node, -geo.x, -geo.y); if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { @@ -71,8 +71,8 @@ static void scene_xdg_surface_handle_xdg_surface_commit(struct wl_listener *list scene_xdg_surface_update_position(scene_xdg_surface); } -struct wlr_scene_node *wlr_scene_xdg_surface_create( - struct wlr_scene_node *parent, struct wlr_xdg_surface *xdg_surface) { +struct wlr_scene_tree *wlr_scene_xdg_surface_create( + struct wlr_scene_tree *parent, struct wlr_xdg_surface *xdg_surface) { struct wlr_scene_xdg_surface *scene_xdg_surface = calloc(1, sizeof(*scene_xdg_surface)); if (scene_xdg_surface == NULL) { @@ -87,9 +87,9 @@ struct wlr_scene_node *wlr_scene_xdg_surface_create( return NULL; } - scene_xdg_surface->surface_node = wlr_scene_subsurface_tree_create( - &scene_xdg_surface->tree->node, xdg_surface->surface); - if (scene_xdg_surface->surface_node == NULL) { + scene_xdg_surface->surface_tree = wlr_scene_subsurface_tree_create( + scene_xdg_surface->tree, xdg_surface->surface); + if (scene_xdg_surface->surface_tree == NULL) { wlr_scene_node_destroy(&scene_xdg_surface->tree->node); free(scene_xdg_surface); return NULL; @@ -120,5 +120,5 @@ struct wlr_scene_node *wlr_scene_xdg_surface_create( wlr_scene_node_set_enabled(&scene_xdg_surface->tree->node, xdg_surface->mapped); scene_xdg_surface_update_position(scene_xdg_surface); - return &scene_xdg_surface->tree->node; + return scene_xdg_surface->tree; } -- cgit v1.2.3 From 4ef1ce94b42a54f5f734a26b91fe13ab761e00a0 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 6 Apr 2022 08:17:21 -0400 Subject: wlr_scene: Inline wlr_scene_node_state This seems like nothing interesting was done with this. Let's simplify and allow us some flexibility in the future. --- wlr_scene.c | 110 ++++++++++++++++++++++++++++-------------------------------- 1 file changed, 51 insertions(+), 59 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index e60ff5d..8d05d0f 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -48,27 +48,20 @@ struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { return (struct wlr_scene *)tree; } -static void scene_node_state_init(struct wlr_scene_node_state *state) { - memset(state, 0, sizeof(*state)); - wl_list_init(&state->children); - wl_list_init(&state->link); - state->enabled = true; -} - -static void scene_node_state_finish(struct wlr_scene_node_state *state) { - wl_list_remove(&state->link); -} - static void scene_node_init(struct wlr_scene_node *node, enum wlr_scene_node_type type, struct wlr_scene_tree *parent) { memset(node, 0, sizeof(*node)); node->type = type; node->parent = parent; - scene_node_state_init(&node->state); + node->enabled = true; + + wl_list_init(&node->children); + wl_list_init(&node->link); + wl_signal_init(&node->events.destroy); if (parent != NULL) { - wl_list_insert(parent->node.state.children.prev, &node->state.link); + wl_list_insert(parent->node.children.prev, &node->link); } wlr_addon_set_init(&node->addons); @@ -137,13 +130,12 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { } struct wlr_scene_node *child, *child_tmp; - wl_list_for_each_safe(child, child_tmp, - &node->state.children, state.link) { + wl_list_for_each_safe(child, child_tmp, &node->children, link) { wlr_scene_node_destroy(child); } wlr_addon_set_finish(&node->addons); - scene_node_state_finish(&node->state); + wl_list_remove(&node->link); free(node); } @@ -250,9 +242,9 @@ static void _scene_node_update_outputs( } struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { - _scene_node_update_outputs(child, lx + child->state.x, - ly + child->state.y, scene); + wl_list_for_each(child, &node->children, link) { + _scene_node_update_outputs(child, lx + child->x, + ly + child->y, scene); } } @@ -527,14 +519,14 @@ static void scale_box(struct wlr_box *box, float scale) { static void _scene_node_damage_whole(struct wlr_scene_node *node, struct wlr_scene *scene, int lx, int ly) { - if (!node->state.enabled) { + if (!node->enabled) { return; } struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { + wl_list_for_each(child, &node->children, link) { _scene_node_damage_whole(child, scene, - lx + child->state.x, ly + child->state.y); + lx + child->x, ly + child->y); } int width, height; @@ -570,24 +562,24 @@ static void scene_node_damage_whole(struct wlr_scene_node *node) { } void wlr_scene_node_set_enabled(struct wlr_scene_node *node, bool enabled) { - if (node->state.enabled == enabled) { + if (node->enabled == enabled) { return; } // One of these damage_whole() calls will short-circuit and be a no-op scene_node_damage_whole(node); - node->state.enabled = enabled; + node->enabled = enabled; scene_node_damage_whole(node); } void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y) { - if (node->state.x == x && node->state.y == y) { + if (node->x == x && node->y == y) { return; } scene_node_damage_whole(node); - node->state.x = x; - node->state.y = y; + node->x = x; + node->y = y; scene_node_damage_whole(node); scene_node_update_outputs(node); @@ -598,12 +590,12 @@ void wlr_scene_node_place_above(struct wlr_scene_node *node, assert(node != sibling); assert(node->parent == sibling->parent); - if (node->state.link.prev == &sibling->state.link) { + if (node->link.prev == &sibling->link) { return; } - wl_list_remove(&node->state.link); - wl_list_insert(&sibling->state.link, &node->state.link); + wl_list_remove(&node->link); + wl_list_insert(&sibling->link, &node->link); scene_node_damage_whole(node); scene_node_damage_whole(sibling); @@ -614,12 +606,12 @@ void wlr_scene_node_place_below(struct wlr_scene_node *node, assert(node != sibling); assert(node->parent == sibling->parent); - if (node->state.link.next == &sibling->state.link) { + if (node->link.next == &sibling->link) { return; } - wl_list_remove(&node->state.link); - wl_list_insert(sibling->state.link.prev, &node->state.link); + wl_list_remove(&node->link); + wl_list_insert(sibling->link.prev, &node->link); scene_node_damage_whole(node); scene_node_damage_whole(sibling); @@ -627,7 +619,7 @@ void wlr_scene_node_place_below(struct wlr_scene_node *node, void wlr_scene_node_raise_to_top(struct wlr_scene_node *node) { struct wlr_scene_node *current_top = wl_container_of( - node->parent->node.state.children.prev, current_top, state.link); + node->parent->node.children.prev, current_top, link); if (node == current_top) { return; } @@ -636,7 +628,7 @@ void wlr_scene_node_raise_to_top(struct wlr_scene_node *node) { void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node) { struct wlr_scene_node *current_bottom = wl_container_of( - node->parent->node.state.children.next, current_bottom, state.link); + node->parent->node.children.next, current_bottom, link); if (node == current_bottom) { return; } @@ -659,9 +651,9 @@ void wlr_scene_node_reparent(struct wlr_scene_node *node, scene_node_damage_whole(node); - wl_list_remove(&node->state.link); + wl_list_remove(&node->link); node->parent = new_parent; - wl_list_insert(new_parent->node.state.children.prev, &node->state.link); + wl_list_insert(new_parent->node.children.prev, &node->link); scene_node_damage_whole(node); @@ -675,9 +667,9 @@ bool wlr_scene_node_coords(struct wlr_scene_node *node, int lx = 0, ly = 0; bool enabled = true; while (true) { - lx += node->state.x; - ly += node->state.y; - enabled = enabled && node->state.enabled; + lx += node->x; + ly += node->y; + enabled = enabled && node->enabled; if (node->parent == NULL) { break; } @@ -693,12 +685,12 @@ bool wlr_scene_node_coords(struct wlr_scene_node *node, static void scene_node_for_each_scene_buffer(struct wlr_scene_node *node, int lx, int ly, wlr_scene_buffer_iterator_func_t user_iterator, void *user_data) { - if (!node->state.enabled) { + if (!node->enabled) { return; } - lx += node->state.x; - ly += node->state.y; + lx += node->x; + ly += node->y; if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); @@ -706,7 +698,7 @@ static void scene_node_for_each_scene_buffer(struct wlr_scene_node *node, } struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { + wl_list_for_each(child, &node->children, link) { scene_node_for_each_scene_buffer(child, lx, ly, user_iterator, user_data); } } @@ -718,16 +710,16 @@ 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) { - if (!node->state.enabled) { + if (!node->enabled) { return NULL; } // TODO: optimize by storing a bounding box in each node? - lx -= node->state.x; - ly -= node->state.y; + lx -= node->x; + ly -= node->y; struct wlr_scene_node *child; - wl_list_for_each_reverse(child, &node->state.children, state.link) { + wl_list_for_each_reverse(child, &node->children, link) { struct wlr_scene_node *node = wlr_scene_node_at(child, lx, ly, nx, ny); if (node != NULL) { @@ -901,17 +893,17 @@ static void render_node_iterator(struct wlr_scene_node *node, static void scene_node_for_each_node(struct wlr_scene_node *node, int lx, int ly, wlr_scene_node_iterator_func_t user_iterator, void *user_data) { - if (!node->state.enabled) { + if (!node->enabled) { return; } - lx += node->state.x; - ly += node->state.y; + lx += node->x; + ly += node->y; user_iterator(node, lx, ly, user_data); struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { + wl_list_for_each(child, &node->children, link) { scene_node_for_each_node(child, lx, ly, user_iterator, user_data); } } @@ -1021,7 +1013,7 @@ static void scene_node_remove_output(struct wlr_scene_node *node, } struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { + wl_list_for_each(child, &node->children, link) { scene_node_remove_output(child, output); } } @@ -1300,7 +1292,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { static void scene_node_send_frame_done(struct wlr_scene_node *node, struct wlr_scene_output *scene_output, struct timespec *now) { - if (!node->state.enabled) { + if (!node->enabled) { return; } @@ -1314,7 +1306,7 @@ static void scene_node_send_frame_done(struct wlr_scene_node *node, } struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { + wl_list_for_each(child, &node->children, link) { scene_node_send_frame_done(child, scene_output, now); } } @@ -1328,12 +1320,12 @@ void wlr_scene_output_send_frame_done(struct wlr_scene_output *scene_output, static void scene_output_for_each_scene_buffer(const struct wlr_box *output_box, struct wlr_scene_node *node, int lx, int ly, wlr_scene_buffer_iterator_func_t user_iterator, void *user_data) { - if (!node->state.enabled) { + if (!node->enabled) { return; } - lx += node->state.x; - ly += node->state.y; + lx += node->x; + ly += node->y; if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_box node_box = { .x = lx, .y = ly }; @@ -1348,7 +1340,7 @@ static void scene_output_for_each_scene_buffer(const struct wlr_box *output_box, } struct wlr_scene_node *child; - wl_list_for_each(child, &node->state.children, state.link) { + wl_list_for_each(child, &node->children, link) { scene_output_for_each_scene_buffer(output_box, child, lx, ly, user_iterator, user_data); } -- cgit v1.2.3 From 06e3a70f2cc02de55dab29e4d72790e7cb8c5497 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Wed, 18 May 2022 18:16:44 -0400 Subject: wlr_scene: Move children list from wlr_scene_node to wlr_scene_tree --- wlr_scene.c | 122 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 68 insertions(+), 54 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 8d05d0f..6789413 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -55,13 +55,12 @@ static void scene_node_init(struct wlr_scene_node *node, node->parent = parent; node->enabled = true; - wl_list_init(&node->children); wl_list_init(&node->link); wl_signal_init(&node->events.destroy); if (parent != NULL) { - wl_list_insert(parent->node.children.prev, &node->link); + wl_list_insert(parent->children.prev, &node->link); } wlr_addon_set_init(&node->addons); @@ -111,7 +110,9 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wlr_texture_destroy(scene_buffer->texture); wlr_buffer_unlock(scene_buffer->buffer); } else if (node->type == WLR_SCENE_NODE_TREE) { - if (node == &scene->tree.node) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + + if (scene_tree == &scene->tree) { assert(!node->parent); struct wlr_scene_output *scene_output, *scene_output_tmp; wl_list_for_each_safe(scene_output, scene_output_tmp, &scene->outputs, link) { @@ -127,11 +128,12 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { } else { assert(node->parent); } - } - struct wlr_scene_node *child, *child_tmp; - wl_list_for_each_safe(child, child_tmp, &node->children, link) { - wlr_scene_node_destroy(child); + struct wlr_scene_node *child, *child_tmp; + wl_list_for_each_safe(child, child_tmp, + &scene_tree->children, link) { + wlr_scene_node_destroy(child); + } } wlr_addon_set_finish(&node->addons); @@ -143,6 +145,7 @@ static void scene_tree_init(struct wlr_scene_tree *tree, struct wlr_scene_tree *parent) { memset(tree, 0, sizeof(*tree)); scene_node_init(&tree->node, WLR_SCENE_NODE_TREE, parent); + wl_list_init(&tree->children); } struct wlr_scene *wlr_scene_create(void) { @@ -239,12 +242,13 @@ static void _scene_node_update_outputs( struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); scene_buffer_update_outputs(scene_buffer, lx, ly, scene); - } - - struct wlr_scene_node *child; - wl_list_for_each(child, &node->children, link) { - _scene_node_update_outputs(child, lx + child->x, - ly + child->y, scene); + } else if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + _scene_node_update_outputs(child, lx + child->x, + ly + child->y, scene); + } } } @@ -523,10 +527,13 @@ static void _scene_node_damage_whole(struct wlr_scene_node *node, return; } - struct wlr_scene_node *child; - wl_list_for_each(child, &node->children, link) { - _scene_node_damage_whole(child, scene, - lx + child->x, ly + child->y); + if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + _scene_node_damage_whole(child, scene, + lx + child->x, ly + child->y); + } } int width, height; @@ -619,7 +626,7 @@ void wlr_scene_node_place_below(struct wlr_scene_node *node, void wlr_scene_node_raise_to_top(struct wlr_scene_node *node) { struct wlr_scene_node *current_top = wl_container_of( - node->parent->node.children.prev, current_top, link); + node->parent->children.prev, current_top, link); if (node == current_top) { return; } @@ -628,7 +635,7 @@ void wlr_scene_node_raise_to_top(struct wlr_scene_node *node) { void wlr_scene_node_lower_to_bottom(struct wlr_scene_node *node) { struct wlr_scene_node *current_bottom = wl_container_of( - node->parent->node.children.next, current_bottom, link); + node->parent->children.next, current_bottom, link); if (node == current_bottom) { return; } @@ -653,7 +660,7 @@ void wlr_scene_node_reparent(struct wlr_scene_node *node, wl_list_remove(&node->link); node->parent = new_parent; - wl_list_insert(new_parent->node.children.prev, &node->link); + wl_list_insert(new_parent->children.prev, &node->link); scene_node_damage_whole(node); @@ -695,11 +702,12 @@ static void scene_node_for_each_scene_buffer(struct wlr_scene_node *node, if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); user_iterator(scene_buffer, lx, ly, user_data); - } - - struct wlr_scene_node *child; - wl_list_for_each(child, &node->children, link) { - scene_node_for_each_scene_buffer(child, lx, ly, user_iterator, user_data); + } else if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + scene_node_for_each_scene_buffer(child, lx, ly, user_iterator, user_data); + } } } @@ -718,18 +726,18 @@ struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, lx -= node->x; ly -= node->y; - struct wlr_scene_node *child; - wl_list_for_each_reverse(child, &node->children, link) { - struct wlr_scene_node *node = - wlr_scene_node_at(child, lx, ly, nx, ny); - if (node != NULL) { - return node; - } - } - bool intersects = false; switch (node->type) { - case WLR_SCENE_NODE_TREE: + case WLR_SCENE_NODE_TREE:; + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each_reverse(child, &scene_tree->children, link) { + struct wlr_scene_node *node = + wlr_scene_node_at(child, lx, ly, nx, ny); + if (node != NULL) { + return node; + } + } break; case WLR_SCENE_NODE_RECT:; int width, height; @@ -902,9 +910,12 @@ static void scene_node_for_each_node(struct wlr_scene_node *node, user_iterator(node, lx, ly, user_data); - struct wlr_scene_node *child; - wl_list_for_each(child, &node->children, link) { - scene_node_for_each_node(child, lx, ly, user_iterator, user_data); + if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + scene_node_for_each_node(child, lx, ly, user_iterator, user_data); + } } } @@ -1010,11 +1021,12 @@ static void scene_node_remove_output(struct wlr_scene_node *node, scene_buffer->active_outputs &= ~mask; wlr_signal_emit_safe(&scene_buffer->events.output_leave, output); } - } - - struct wlr_scene_node *child; - wl_list_for_each(child, &node->children, link) { - scene_node_remove_output(child, output); + } else if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + scene_node_remove_output(child, output); + } } } @@ -1303,11 +1315,12 @@ static void scene_node_send_frame_done(struct wlr_scene_node *node, if (scene_buffer->primary_output == scene_output) { wlr_scene_buffer_send_frame_done(scene_buffer, now); } - } - - struct wlr_scene_node *child; - wl_list_for_each(child, &node->children, link) { - scene_node_send_frame_done(child, scene_output, now); + } else if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + scene_node_send_frame_done(child, scene_output, now); + } } } @@ -1337,12 +1350,13 @@ static void scene_output_for_each_scene_buffer(const struct wlr_box *output_box, wlr_scene_buffer_from_node(node); user_iterator(scene_buffer, lx, ly, user_data); } - } - - struct wlr_scene_node *child; - wl_list_for_each(child, &node->children, link) { - scene_output_for_each_scene_buffer(output_box, child, lx, ly, - user_iterator, user_data); + } else if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + scene_output_for_each_scene_buffer(output_box, child, lx, ly, + user_iterator, user_data); + } } } -- cgit v1.2.3 From 76e40fe163b5fbdfd920cd95c1a103b69bbbd8a9 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Tue, 31 May 2022 21:39:53 +0300 Subject: scene: add wlr_scene_output.events.destroy --- wlr_scene.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 6789413..8f9d036 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -999,6 +999,8 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, assert(scene_output->index < 64); wl_list_insert(prev_output_link, &scene_output->link); + wl_signal_init(&scene_output->events.destroy); + scene_output->output_commit.notify = scene_output_handle_commit; wl_signal_add(&output->events.commit, &scene_output->output_commit); @@ -1035,6 +1037,8 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { return; } + wlr_signal_emit_safe(&scene_output->events.destroy, NULL); + scene_node_remove_output(&scene_output->scene->tree.node, scene_output); wlr_addon_finish(&scene_output->addon); -- cgit v1.2.3 From 60eff6dd7f02dbfceff444bb8921a3b29ff71c3f Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Tue, 31 May 2022 21:40:03 +0300 Subject: scene/output-layout: improve ownership logic This commit ensures that outputs that weren't created by the output layout helper aren't destroyed on the output layout change. Consider the following piece of logic: // struct wlr_output *o1, *o2; // struct wlr_scene *scene; // struct wlr_output_layout *layout; wlr_scene_attach_output_layout(scene, layout); wlr_output_layout_add_auto(layout, o1); struct wlr_scene_output *so2 = wlr_scene_output_create(scene, o2); wlr_output_layout_move(layout, o1, 100, 200); // so2 is invalid now --- output_layout.c | 110 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 76 insertions(+), 34 deletions(-) diff --git a/output_layout.c b/output_layout.c index e2327eb..2122311 100644 --- a/output_layout.c +++ b/output_layout.c @@ -6,36 +6,58 @@ struct wlr_scene_output_layout { struct wlr_output_layout *layout; struct wlr_scene *scene; + struct wl_list outputs; // wlr_scene_output_layout_output.link + struct wl_listener layout_add; struct wl_listener layout_change; struct wl_listener layout_destroy; struct wl_listener scene_destroy; }; -static void scene_output_layout_destroy(struct wlr_scene_output_layout *sol) { - wl_list_remove(&sol->layout_destroy.link); - wl_list_remove(&sol->layout_add.link); - wl_list_remove(&sol->layout_change.link); - wl_list_remove(&sol->scene_destroy.link); - free(sol); +struct wlr_scene_output_layout_output { + struct wlr_output_layout_output *layout_output; + struct wlr_scene_output *scene_output; + + struct wl_list link; // wlr_scene_output_layout.outputs + + struct wl_listener layout_output_destroy; + struct wl_listener scene_output_destroy; +}; + +static void scene_output_layout_output_destroy( + struct wlr_scene_output_layout_output *solo) { + wlr_scene_output_destroy(solo->scene_output); + wl_list_remove(&solo->layout_output_destroy.link); + wl_list_remove(&solo->scene_output_destroy.link); + wl_list_remove(&solo->link); + free(solo); } -static void scene_output_layout_handle_layout_destroy( +static void scene_output_layout_output_handle_layout_output_destroy( struct wl_listener *listener, void *data) { - struct wlr_scene_output_layout *sol = - wl_container_of(listener, sol, layout_destroy); + struct wlr_scene_output_layout_output *solo = + wl_container_of(listener, solo, layout_output_destroy); + scene_output_layout_output_destroy(solo); +} - // Remove all outputs managed by the output layout - struct wlr_scene_output *scene_output, *tmp; - wl_list_for_each_safe(scene_output, tmp, &sol->scene->outputs, link) { - struct wlr_output_layout_output *lo = - wlr_output_layout_get(sol->layout, scene_output->output); - if (lo != NULL) { - wlr_scene_output_destroy(scene_output); - } - } +static void scene_output_layout_output_handle_scene_output_destroy( + struct wl_listener *listener, void *data) { + struct wlr_scene_output_layout_output *solo = + wl_container_of(listener, solo, scene_output_destroy); + solo->scene_output = NULL; + scene_output_layout_output_destroy(solo); +} - scene_output_layout_destroy(sol); +static void scene_output_layout_destroy(struct wlr_scene_output_layout *sol) { + struct wlr_scene_output_layout_output *solo, *tmp; + wl_list_for_each_safe(solo, tmp, &sol->outputs, link) { + scene_output_layout_output_destroy(solo); + } + wl_list_remove(&sol->layout_add.link); + wl_list_remove(&sol->layout_change.link); + wl_list_remove(&sol->layout_destroy.link); + wl_list_remove(&sol->scene_destroy.link); + free(sol); } static void scene_output_layout_handle_layout_change( @@ -43,17 +65,10 @@ static void scene_output_layout_handle_layout_change( struct wlr_scene_output_layout *sol = wl_container_of(listener, sol, layout_change); - struct wlr_scene_output *scene_output, *tmp; - wl_list_for_each_safe(scene_output, tmp, &sol->scene->outputs, link) { - struct wlr_output_layout_output *lo = - wlr_output_layout_get(sol->layout, scene_output->output); - if (lo == NULL) { - // Output has been removed from the layout - wlr_scene_output_destroy(scene_output); - continue; - } - - wlr_scene_output_set_position(scene_output, lo->x, lo->y); + struct wlr_scene_output_layout_output *solo; + wl_list_for_each(solo, &sol->outputs, link) { + wlr_scene_output_set_position(solo->scene_output, + solo->layout_output->x, solo->layout_output->y); } } @@ -63,13 +78,38 @@ static void scene_output_layout_handle_layout_add( wl_container_of(listener, sol, layout_add); struct wlr_output_layout_output *lo = data; - struct wlr_scene_output *scene_output = - wlr_scene_output_create(sol->scene, lo->output); - if (scene_output == NULL) { + struct wlr_scene_output_layout_output *solo = calloc(1, sizeof(*solo)); + if (solo == NULL) { return; } - wlr_scene_output_set_position(scene_output, lo->x, lo->y); + solo->scene_output = wlr_scene_output_create(sol->scene, lo->output); + if (solo->scene_output == NULL) { + free(solo); + return; + } + + solo->layout_output = lo; + + solo->layout_output_destroy.notify = + scene_output_layout_output_handle_layout_output_destroy; + wl_signal_add(&lo->events.destroy, &solo->layout_output_destroy); + + solo->scene_output_destroy.notify = + scene_output_layout_output_handle_scene_output_destroy; + wl_signal_add(&solo->scene_output->events.destroy, + &solo->scene_output_destroy); + + wl_list_insert(&sol->outputs, &solo->link); + + wlr_scene_output_set_position(solo->scene_output, lo->x, lo->y); +} + +static void scene_output_layout_handle_layout_destroy( + struct wl_listener *listener, void *data) { + struct wlr_scene_output_layout *sol = + wl_container_of(listener, sol, layout_destroy); + scene_output_layout_destroy(sol); } static void scene_output_layout_handle_scene_destroy( @@ -89,6 +129,8 @@ bool wlr_scene_attach_output_layout(struct wlr_scene *scene, sol->scene = scene; sol->layout = output_layout; + wl_list_init(&sol->outputs); + sol->layout_destroy.notify = scene_output_layout_handle_layout_destroy; wl_signal_add(&output_layout->events.destroy, &sol->layout_destroy); -- cgit v1.2.3 From 69393d13db99e8c24e820d5e696bb6b19fd5557d Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Tue, 31 May 2022 21:44:10 +0300 Subject: scene/output-layout: add initial outputs --- output_layout.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/output_layout.c b/output_layout.c index 2122311..900cabc 100644 --- a/output_layout.c +++ b/output_layout.c @@ -72,12 +72,8 @@ static void scene_output_layout_handle_layout_change( } } -static void scene_output_layout_handle_layout_add( - struct wl_listener *listener, void *data) { - struct wlr_scene_output_layout *sol = - wl_container_of(listener, sol, layout_add); - struct wlr_output_layout_output *lo = data; - +static void scene_output_layout_add(struct wlr_scene_output_layout *sol, + struct wlr_output_layout_output *lo) { struct wlr_scene_output_layout_output *solo = calloc(1, sizeof(*solo)); if (solo == NULL) { return; @@ -105,6 +101,15 @@ static void scene_output_layout_handle_layout_add( wlr_scene_output_set_position(solo->scene_output, lo->x, lo->y); } +static void scene_output_layout_handle_layout_add( + struct wl_listener *listener, void *data) { + struct wlr_scene_output_layout *sol = + wl_container_of(listener, sol, layout_add); + struct wlr_output_layout_output *lo = data; + + scene_output_layout_add(sol, lo); +} + static void scene_output_layout_handle_layout_destroy( struct wl_listener *listener, void *data) { struct wlr_scene_output_layout *sol = @@ -143,5 +148,10 @@ bool wlr_scene_attach_output_layout(struct wlr_scene *scene, sol->scene_destroy.notify = scene_output_layout_handle_scene_destroy; wl_signal_add(&scene->tree.node.events.destroy, &sol->scene_destroy); + struct wlr_output_layout_output *lo; + wl_list_for_each(lo, &output_layout->outputs, link) { + scene_output_layout_add(sol, lo); + } + return true; } -- cgit v1.2.3 From cf6724c5565ddc95a586e7461f27bf47713b2802 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 2 Jun 2022 10:33:04 -0400 Subject: wlr_scene_buffer: Call output enter/leave after primary_output calculation --- wlr_scene.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 8f9d036..791462d 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -205,6 +205,14 @@ static void scene_buffer_update_outputs( int largest_overlap = 0; scene_buffer->primary_output = NULL; + uint64_t active_outputs = 0; + + // let's update the outputs in two steps: + // - the primary outputs + // - the enter/leave signals + // This ensures that the enter/leave signals can rely on the primary output + // to have a reasonable value. Otherwise, they may get a value that's in + // the middle of a calculation. struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { struct wlr_box output_box = { @@ -216,7 +224,6 @@ static void scene_buffer_update_outputs( struct wlr_box intersection; bool intersects = wlr_box_intersection(&intersection, &buffer_box, &output_box); - bool intersects_before = scene_buffer->active_outputs & (1ull << scene_output->index); if (intersects) { int overlap = intersection.width * intersection.height; @@ -224,13 +231,22 @@ static void scene_buffer_update_outputs( largest_overlap = overlap; scene_buffer->primary_output = scene_output; } + + active_outputs |= 1ull << scene_output->index; } + } + + uint64_t old_active = scene_buffer->active_outputs; + scene_buffer->active_outputs = active_outputs; + + wl_list_for_each(scene_output, &scene->outputs, link) { + uint64_t mask = 1ull << scene_output->index; + bool intersects = active_outputs & mask; + bool intersects_before = old_active & mask; if (intersects && !intersects_before) { - scene_buffer->active_outputs |= 1ull << scene_output->index; wlr_signal_emit_safe(&scene_buffer->events.output_enter, scene_output); } else if (!intersects && intersects_before) { - scene_buffer->active_outputs &= ~(1ull << scene_output->index); wlr_signal_emit_safe(&scene_buffer->events.output_leave, scene_output); } } -- cgit v1.2.3 From 32face7d34dc66efa4607cc45378e2a31f3b3339 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Tue, 31 May 2022 15:22:45 -0400 Subject: wlr_scene_buffer: Update primary_output on output destroy --- wlr_scene.c | 65 +++++++++++++++++++++++++------------------------------------ 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 791462d..4cdf4be 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -196,9 +196,9 @@ static void scene_node_get_size(struct wlr_scene_node *node, int *lx, int *ly); // This function must be called whenever the coordinates/dimensions of a scene // buffer or scene output change. It is not necessary to call when a scene // buffer's node is enabled/disabled or obscured by other nodes. -static void scene_buffer_update_outputs( - struct wlr_scene_buffer *scene_buffer, - int lx, int ly, struct wlr_scene *scene) { +static void scene_buffer_update_outputs(struct wlr_scene_buffer *scene_buffer, + int lx, int ly, struct wlr_scene *scene, + struct wlr_scene_output *ignore) { struct wlr_box buffer_box = { .x = lx, .y = ly }; scene_node_get_size(&scene_buffer->node, &buffer_box.width, &buffer_box.height); @@ -215,6 +215,10 @@ static void scene_buffer_update_outputs( // the middle of a calculation. struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { + if (scene_output == ignore) { + continue; + } + struct wlr_box output_box = { .x = scene_output->x, .y = scene_output->y, @@ -252,27 +256,29 @@ static void scene_buffer_update_outputs( } } -static void _scene_node_update_outputs( - struct wlr_scene_node *node, int lx, int ly, struct wlr_scene *scene) { +static void _scene_node_update_outputs(struct wlr_scene_node *node, + int lx, int ly, struct wlr_scene *scene, + struct wlr_scene_output *ignore) { if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); - scene_buffer_update_outputs(scene_buffer, lx, ly, scene); + scene_buffer_update_outputs(scene_buffer, lx, ly, scene, ignore); } else if (node->type == WLR_SCENE_NODE_TREE) { struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); struct wlr_scene_node *child; wl_list_for_each(child, &scene_tree->children, link) { _scene_node_update_outputs(child, lx + child->x, - ly + child->y, scene); + ly + child->y, scene, ignore); } } } -static void scene_node_update_outputs(struct wlr_scene_node *node) { +static void scene_node_update_outputs(struct wlr_scene_node *node, + struct wlr_scene_output *ignore) { struct wlr_scene *scene = scene_node_get_root(node); int lx, ly; wlr_scene_node_coords(node, &lx, &ly); - _scene_node_update_outputs(node, lx, ly, scene); + _scene_node_update_outputs(node, lx, ly, scene, ignore); } struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent, @@ -334,7 +340,7 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, scene_node_damage_whole(&scene_buffer->node); - scene_node_update_outputs(&scene_buffer->node); + scene_node_update_outputs(&scene_buffer->node, NULL); return scene_buffer; } @@ -361,7 +367,7 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff scene_buffer->buffer = NULL; } - scene_node_update_outputs(&scene_buffer->node); + scene_node_update_outputs(&scene_buffer->node, NULL); if (!damage) { scene_node_damage_whole(&scene_buffer->node); @@ -457,7 +463,7 @@ void wlr_scene_buffer_set_dest_size(struct wlr_scene_buffer *scene_buffer, scene_buffer->dst_height = height; scene_node_damage_whole(&scene_buffer->node); - scene_node_update_outputs(&scene_buffer->node); + scene_node_update_outputs(&scene_buffer->node, NULL); } void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer, @@ -470,7 +476,7 @@ void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer, scene_buffer->transform = transform; scene_node_damage_whole(&scene_buffer->node); - scene_node_update_outputs(&scene_buffer->node); + scene_node_update_outputs(&scene_buffer->node, NULL); } void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer, @@ -605,7 +611,7 @@ void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y) { node->y = y; scene_node_damage_whole(node); - scene_node_update_outputs(node); + scene_node_update_outputs(node, NULL); } void wlr_scene_node_place_above(struct wlr_scene_node *node, @@ -680,7 +686,7 @@ void wlr_scene_node_reparent(struct wlr_scene_node *node, scene_node_damage_whole(node); - scene_node_update_outputs(node); + scene_node_update_outputs(node, NULL); } bool wlr_scene_node_coords(struct wlr_scene_node *node, @@ -971,14 +977,14 @@ static void scene_output_handle_commit(struct wl_listener *listener, void *data) if (event->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM | WLR_OUTPUT_STATE_SCALE)) { - scene_node_update_outputs(&scene_output->scene->tree.node); + scene_node_update_outputs(&scene_output->scene->tree.node, NULL); } } static void scene_output_handle_mode(struct wl_listener *listener, void *data) { struct wlr_scene_output *scene_output = wl_container_of(listener, scene_output, output_mode); - scene_node_update_outputs(&scene_output->scene->tree.node); + scene_node_update_outputs(&scene_output->scene->tree.node, NULL); } struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, @@ -1024,30 +1030,11 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, wl_signal_add(&output->events.mode, &scene_output->output_mode); wlr_output_damage_add_whole(scene_output->damage); - scene_node_update_outputs(&scene->tree.node); + scene_node_update_outputs(&scene->tree.node, NULL); return scene_output; } -static void scene_node_remove_output(struct wlr_scene_node *node, - struct wlr_scene_output *output) { - if (node->type == WLR_SCENE_NODE_BUFFER) { - struct wlr_scene_buffer *scene_buffer = - wlr_scene_buffer_from_node(node); - uint64_t mask = 1ull << output->index; - if (scene_buffer->active_outputs & mask) { - scene_buffer->active_outputs &= ~mask; - wlr_signal_emit_safe(&scene_buffer->events.output_leave, output); - } - } else if (node->type == WLR_SCENE_NODE_TREE) { - struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); - struct wlr_scene_node *child; - wl_list_for_each(child, &scene_tree->children, link) { - scene_node_remove_output(child, output); - } - } -} - void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { if (scene_output == NULL) { return; @@ -1055,7 +1042,7 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { wlr_signal_emit_safe(&scene_output->events.destroy, NULL); - scene_node_remove_output(&scene_output->scene->tree.node, scene_output); + scene_node_update_outputs(&scene_output->scene->tree.node, scene_output); wlr_addon_finish(&scene_output->addon); wl_list_remove(&scene_output->link); @@ -1087,7 +1074,7 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, scene_output->y = ly; wlr_output_damage_add_whole(scene_output->damage); - scene_node_update_outputs(&scene_output->scene->tree.node); + scene_node_update_outputs(&scene_output->scene->tree.node, NULL); } struct check_scanout_data { -- cgit v1.2.3 From b7e78a469aec2478a1c7ad00162b7b3745631682 Mon Sep 17 00:00:00 2001 From: Consolatis <40171-Consolatis@users.noreply.gitlab.freedesktop.org> Date: Tue, 7 Jun 2022 20:52:26 +0200 Subject: scene/output_layout: Fix crash in scene_output_layout_output_destroy Closes: #3448 --- output_layout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/output_layout.c b/output_layout.c index 900cabc..1d1484a 100644 --- a/output_layout.c +++ b/output_layout.c @@ -26,10 +26,10 @@ struct wlr_scene_output_layout_output { static void scene_output_layout_output_destroy( struct wlr_scene_output_layout_output *solo) { - wlr_scene_output_destroy(solo->scene_output); wl_list_remove(&solo->layout_output_destroy.link); wl_list_remove(&solo->scene_output_destroy.link); wl_list_remove(&solo->link); + wlr_scene_output_destroy(solo->scene_output); free(solo); } -- cgit v1.2.3 From 3e35ece7cf3ddf846d7fca8f3b063e31fe7dcb38 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Wed, 8 Jun 2022 20:27:50 +0100 Subject: scene/layer_shell_v1.c: fix bug in width/height calculations ...in wlr_scene_layer_surface_v1_configure() Reproduce bug with waybar by setting `"margin": 5,` in ~/.config/waybar/config. It will result in the right edge of the panel extending outside the edge of the output. The bug can also be reproduced with gtk-layer-demo by anchoring left/right/top/bottom and setting respective margins Relates-to: https://github.com/labwc/labwc/issues/382 --- layer_shell_v1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/layer_shell_v1.c b/layer_shell_v1.c index eb0bc76..b674cd3 100644 --- a/layer_shell_v1.c +++ b/layer_shell_v1.c @@ -94,7 +94,7 @@ void wlr_scene_layer_surface_v1_configure( if (box.width == 0) { box.x = bounds.x + state->margin.left; box.width = bounds.width - - state->margin.left + state->margin.right; + (state->margin.left + state->margin.right); } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT && state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) { box.x = bounds.x + bounds.width/2 -box.width/2; @@ -110,7 +110,7 @@ void wlr_scene_layer_surface_v1_configure( if (box.height == 0) { box.y = bounds.y + state->margin.top; box.height = bounds.height - - state->margin.top + state->margin.bottom; + (state->margin.top + state->margin.bottom); } else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP && state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) { box.y = bounds.y + bounds.height/2 - box.height/2; -- cgit v1.2.3 From dfc28c46d99cdd49ca24f49744ce53e711ce2e3f Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sun, 22 May 2022 10:18:43 +0300 Subject: scene: switch to wlr_damage_ring --- wlr_scene.c | 83 ++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 29 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 4cdf4be..0b127e6 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -5,8 +5,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -422,8 +422,11 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff wlr_region_scale_xy(&output_damage, &trans_damage, output_scale * scale_x, output_scale * scale_y); pixman_region32_translate(&output_damage, - (lx - scene_output->x) * output_scale, (ly - scene_output->y) * output_scale); - wlr_output_damage_add(scene_output->damage, &output_damage); + (lx - scene_output->x) * output_scale, + (ly - scene_output->y) * output_scale); + if (wlr_damage_ring_add(&scene_output->damage_ring, &output_damage)) { + wlr_output_schedule_frame(scene_output->output); + } pixman_region32_fini(&output_damage); } @@ -572,7 +575,9 @@ static void _scene_node_damage_whole(struct wlr_scene_node *node, scale_box(&box, scene_output->output->scale); - wlr_output_damage_add_box(scene_output->damage, &box); + if (wlr_damage_ring_add_box(&scene_output->damage_ring, &box)) { + wlr_output_schedule_frame(scene_output->output); + } } } @@ -969,6 +974,15 @@ static const struct wlr_addon_interface output_addon_impl = { .destroy = scene_output_handle_destroy, }; +static void scene_output_update_geometry(struct wlr_scene_output *scene_output) { + int width, height; + wlr_output_transformed_resolution(scene_output->output, &width, &height); + wlr_damage_ring_set_bounds(&scene_output->damage_ring, width, height); + wlr_output_schedule_frame(scene_output->output); + + scene_node_update_outputs(&scene_output->scene->tree.node, NULL); +} + static void scene_output_handle_commit(struct wl_listener *listener, void *data) { struct wlr_scene_output *scene_output = wl_container_of(listener, scene_output, output_commit); @@ -977,14 +991,20 @@ static void scene_output_handle_commit(struct wl_listener *listener, void *data) if (event->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM | WLR_OUTPUT_STATE_SCALE)) { - scene_node_update_outputs(&scene_output->scene->tree.node, NULL); + scene_output_update_geometry(scene_output); } } static void scene_output_handle_mode(struct wl_listener *listener, void *data) { struct wlr_scene_output *scene_output = wl_container_of(listener, scene_output, output_mode); - scene_node_update_outputs(&scene_output->scene->tree.node, NULL); + scene_output_update_geometry(scene_output); +} + +static void scene_output_handle_needs_frame(struct wl_listener *listener, void *data) { + struct wlr_scene_output *scene_output = wl_container_of(listener, + scene_output, output_needs_frame); + wlr_output_schedule_frame(scene_output->output); } struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, @@ -994,16 +1014,12 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, return NULL; } - scene_output->damage = wlr_output_damage_create(output); - if (scene_output->damage == NULL) { - free(scene_output); - return NULL; - } - scene_output->output = output; scene_output->scene = scene; wlr_addon_init(&scene_output->addon, &output->addons, scene, &output_addon_impl); + wlr_damage_ring_init(&scene_output->damage_ring); + int prev_output_index = -1; struct wl_list *prev_output_link = &scene->outputs; @@ -1029,8 +1045,10 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, scene_output->output_mode.notify = scene_output_handle_mode; wl_signal_add(&output->events.mode, &scene_output->output_mode); - wlr_output_damage_add_whole(scene_output->damage); - scene_node_update_outputs(&scene->tree.node, NULL); + scene_output->output_needs_frame.notify = scene_output_handle_needs_frame; + wl_signal_add(&output->events.needs_frame, &scene_output->output_needs_frame); + + scene_output_update_geometry(scene_output); return scene_output; } @@ -1045,9 +1063,11 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { scene_node_update_outputs(&scene_output->scene->tree.node, scene_output); wlr_addon_finish(&scene_output->addon); + wlr_damage_ring_finish(&scene_output->damage_ring); wl_list_remove(&scene_output->link); wl_list_remove(&scene_output->output_commit.link); wl_list_remove(&scene_output->output_mode.link); + wl_list_remove(&scene_output->output_needs_frame.link); free(scene_output); } @@ -1072,9 +1092,8 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, scene_output->x = lx; scene_output->y = ly; - wlr_output_damage_add_whole(scene_output->damage); - scene_node_update_outputs(&scene_output->scene->tree.node, NULL); + scene_output_update_geometry(scene_output); } struct check_scanout_data { @@ -1174,7 +1193,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { wlr_log(WLR_DEBUG, "Direct scan-out %s", scanout ? "enabled" : "disabled"); // When exiting direct scan-out, damage everything - wlr_output_damage_add_whole(scene_output->damage); + wlr_damage_ring_add_whole(&scene_output->damage_ring); } scene_output->prev_scanout = scanout; if (scanout) { @@ -1182,7 +1201,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { } if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_RERENDER) { - wlr_output_damage_add_whole(scene_output->damage); + wlr_damage_ring_add_whole(&scene_output->damage_ring); } struct timespec now; @@ -1191,13 +1210,13 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { clock_gettime(CLOCK_MONOTONIC, &now); // add the current frame's damage if there is damage - if (pixman_region32_not_empty(&scene_output->damage->current)) { + if (pixman_region32_not_empty(&scene_output->damage_ring.current)) { struct highlight_region *current_damage = calloc(1, sizeof(*current_damage)); if (current_damage) { pixman_region32_init(¤t_damage->region); pixman_region32_copy(¤t_damage->region, - &scene_output->damage->current); + &scene_output->damage_ring.current); memcpy(¤t_damage->when, &now, sizeof(now)); wl_list_insert(regions, ¤t_damage->link); } @@ -1220,20 +1239,21 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { } } - wlr_output_damage_add(scene_output->damage, &acc_damage); + wlr_damage_ring_add(&scene_output->damage_ring, &acc_damage); pixman_region32_fini(&acc_damage); } - bool needs_frame; - pixman_region32_t damage; - pixman_region32_init(&damage); - if (!wlr_output_damage_attach_render(scene_output->damage, - &needs_frame, &damage)) { - pixman_region32_fini(&damage); + int buffer_age; + if (!wlr_output_attach_render(output, &buffer_age)) { return false; } - if (!needs_frame) { + pixman_region32_t damage; + pixman_region32_init(&damage); + wlr_damage_ring_get_buffer_damage(&scene_output->damage_ring, + buffer_age, &damage); + if (!output->needs_frame && !pixman_region32_not_empty( + &scene_output->damage_ring.current)) { pixman_region32_fini(&damage); wlr_output_rollback(output); return true; @@ -1294,13 +1314,18 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { pixman_region32_t frame_damage; pixman_region32_init(&frame_damage); - wlr_region_transform(&frame_damage, &scene_output->damage->current, + wlr_region_transform(&frame_damage, + &scene_output->damage_ring.current, transform, tr_width, tr_height); wlr_output_set_damage(output, &frame_damage); pixman_region32_fini(&frame_damage); bool success = wlr_output_commit(output); + if (success) { + wlr_damage_ring_rotate(&scene_output->damage_ring); + } + if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT && !wl_list_empty(&scene_output->scene->damage_highlight_regions)) { wlr_output_schedule_frame(scene_output->output); -- cgit v1.2.3 From 9e9d0420728b21de04faacf799af0179397eb8f3 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Wed, 29 Jun 2022 21:10:08 +0300 Subject: scene: add missing output damage listener This is necessary to handle damage coming from the backend and software cursors. --- wlr_scene.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 0b127e6..a6328a3 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -1001,6 +1001,15 @@ static void scene_output_handle_mode(struct wl_listener *listener, void *data) { scene_output_update_geometry(scene_output); } +static void scene_output_handle_damage(struct wl_listener *listener, void *data) { + struct wlr_scene_output *scene_output = wl_container_of(listener, + scene_output, output_damage); + struct wlr_output_event_damage *event = data; + if (wlr_damage_ring_add(&scene_output->damage_ring, event->damage)) { + wlr_output_schedule_frame(scene_output->output); + } +} + static void scene_output_handle_needs_frame(struct wl_listener *listener, void *data) { struct wlr_scene_output *scene_output = wl_container_of(listener, scene_output, output_needs_frame); @@ -1045,6 +1054,9 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, scene_output->output_mode.notify = scene_output_handle_mode; wl_signal_add(&output->events.mode, &scene_output->output_mode); + scene_output->output_damage.notify = scene_output_handle_damage; + wl_signal_add(&output->events.damage, &scene_output->output_damage); + scene_output->output_needs_frame.notify = scene_output_handle_needs_frame; wl_signal_add(&output->events.needs_frame, &scene_output->output_needs_frame); @@ -1067,6 +1079,7 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { wl_list_remove(&scene_output->link); wl_list_remove(&scene_output->output_commit.link); wl_list_remove(&scene_output->output_mode.link); + wl_list_remove(&scene_output->output_damage.link); wl_list_remove(&scene_output->output_needs_frame.link); free(scene_output); -- cgit v1.2.3 From d80108745c74e757a3aec0bcaa33559a0fc862df Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sun, 3 Jul 2022 12:15:08 -0400 Subject: wlr_scene: Use direct assignment for damage indicator timestamps --- wlr_scene.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wlr_scene.c b/wlr_scene.c index a6328a3..828d06e 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -1230,7 +1230,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { pixman_region32_init(¤t_damage->region); pixman_region32_copy(¤t_damage->region, &scene_output->damage_ring.current); - memcpy(¤t_damage->when, &now, sizeof(now)); + current_damage->when = now; wl_list_insert(regions, ¤t_damage->link); } } -- cgit v1.2.3 From 684fd113d5d56cb31a46f1ae08909bba15e0934a Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sun, 3 Jul 2022 12:20:41 -0400 Subject: wlr_scene: Maintain damage highlight regions per output The logic doesn't support handling multiple outputs so let's not break the assumption and handle damages per output much like how damage_ring is done. --- wlr_scene.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 828d06e..68b05b7 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -74,12 +74,6 @@ struct highlight_region { struct wl_list link; }; -static void highlight_region_destroy(struct highlight_region *damage) { - wl_list_remove(&damage->link); - pixman_region32_fini(&damage->region); - free(damage); -} - void wlr_scene_node_destroy(struct wlr_scene_node *node) { if (node == NULL) { return; @@ -119,11 +113,6 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wlr_scene_output_destroy(scene_output); } - struct highlight_region *damage, *tmp_damage; - wl_list_for_each_safe(damage, tmp_damage, &scene->damage_highlight_regions, link) { - highlight_region_destroy(damage); - } - wl_list_remove(&scene->presentation_destroy.link); } else { assert(node->parent); @@ -158,7 +147,6 @@ struct wlr_scene *wlr_scene_create(void) { wl_list_init(&scene->outputs); wl_list_init(&scene->presentation_destroy.link); - wl_list_init(&scene->damage_highlight_regions); char *debug_damage = getenv("WLR_SCENE_DEBUG_DAMAGE"); if (debug_damage) { @@ -1028,6 +1016,7 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, wlr_addon_init(&scene_output->addon, &output->addons, scene, &output_addon_impl); wlr_damage_ring_init(&scene_output->damage_ring); + wl_list_init(&scene_output->damage_highlight_regions); int prev_output_index = -1; struct wl_list *prev_output_link = &scene->outputs; @@ -1065,6 +1054,12 @@ struct wlr_scene_output *wlr_scene_output_create(struct wlr_scene *scene, return scene_output; } +static void highlight_region_destroy(struct highlight_region *damage) { + wl_list_remove(&damage->link); + pixman_region32_fini(&damage->region); + free(damage); +} + void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { if (scene_output == NULL) { return; @@ -1074,6 +1069,11 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { scene_node_update_outputs(&scene_output->scene->tree.node, scene_output); + struct highlight_region *damage, *tmp_damage; + wl_list_for_each_safe(damage, tmp_damage, &scene_output->damage_highlight_regions, link) { + highlight_region_destroy(damage); + } + wlr_addon_finish(&scene_output->addon); wlr_damage_ring_finish(&scene_output->damage_ring); wl_list_remove(&scene_output->link); @@ -1219,7 +1219,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { struct timespec now; if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { - struct wl_list *regions = &scene_output->scene->damage_highlight_regions; + struct wl_list *regions = &scene_output->damage_highlight_regions; clock_gettime(CLOCK_MONOTONIC, &now); // add the current frame's damage if there is damage @@ -1292,7 +1292,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { struct highlight_region *damage; - wl_list_for_each(damage, &scene_output->scene->damage_highlight_regions, link) { + wl_list_for_each(damage, &scene_output->damage_highlight_regions, link) { struct timespec time_diff; timespec_sub(&time_diff, &now, &damage->when); int64_t time_diff_ms = timespec_to_msec(&time_diff); @@ -1340,7 +1340,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { } if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT && - !wl_list_empty(&scene_output->scene->damage_highlight_regions)) { + !wl_list_empty(&scene_output->damage_highlight_regions)) { wlr_output_schedule_frame(scene_output->output); } -- cgit v1.2.3 From b36818c39a6e2d4312888694d34e75eddb42fa56 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 2 Aug 2022 18:28:06 +0200 Subject: scene/layer_shell: Ignore unmapped exclusion zone Only the exclusion zone for mapped layer shell surfaces should be respected. In particular, a layer shell surface that was mapped with an exclusion zone but is now unmapped should not adjust the usable area. Closes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3471 --- layer_shell_v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layer_shell_v1.c b/layer_shell_v1.c index b674cd3..2298698 100644 --- a/layer_shell_v1.c +++ b/layer_shell_v1.c @@ -125,7 +125,7 @@ void wlr_scene_layer_surface_v1_configure( wlr_scene_node_set_position(&scene_layer_surface->tree->node, box.x, box.y); wlr_layer_surface_v1_configure(layer_surface, box.width, box.height); - if (state->exclusive_zone > 0) { + if (layer_surface->mapped && state->exclusive_zone > 0) { layer_surface_exclusive_zone(state, usable_area); } } -- cgit v1.2.3 From d165c3d5454d47ea25fa81d07f68e3a963d80310 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Mon, 8 Aug 2022 00:40:21 -0400 Subject: wlr_scene: Add option to disable direct scanout Closes: #3405 Supersedes: !3562 Co-authored-by: Xiao YaoBing --- wlr_scene.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 68b05b7..3c45811 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -164,6 +164,20 @@ struct wlr_scene *wlr_scene_create(void) { scene->debug_damage_option = WLR_SCENE_DEBUG_DAMAGE_NONE; } + char *disable_direct_scanout = getenv("WLR_SCENE_DISABLE_DIRECT_SCANOUT"); + if (disable_direct_scanout) { + wlr_log(WLR_INFO, "Loading WLR_SCENE_DISABLE_DIRECT_SCANOUT option: %s", disable_direct_scanout); + } + + if (!disable_direct_scanout || strcmp(disable_direct_scanout, "0") == 0) { + scene->direct_scanout = true; + } else if (strcmp(disable_direct_scanout, "1") == 0) { + scene->direct_scanout = false; + } else { + wlr_log(WLR_ERROR, "Unknown WLR_SCENE_DISABLE_DIRECT_SCANOUT option: %s", disable_direct_scanout); + scene->direct_scanout = true; + } + return scene; } @@ -1140,6 +1154,10 @@ static void check_scanout_iterator(struct wlr_scene_node *node, } static bool scene_output_scanout(struct wlr_scene_output *scene_output) { + if (!scene_output->scene->direct_scanout) { + return false; + } + if (scene_output->scene->debug_damage_option == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { // We don't want to enter direct scan out if we have highlight regions -- cgit v1.2.3 From 26c910a62daf3463541fd1619ded32029602381f Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 11 Aug 2022 03:14:14 -0400 Subject: wlr_scene: Introduce scene_nodes_in_box Will query the scene for all nodes that appear in the given wlr_box. The nodes will be sent to the iterator from closest to farthest from the eye. Refactor wlr_scene_node_at to use this new function. --- wlr_scene.c | 125 +++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 85 insertions(+), 40 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 3c45811..64b898d 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -195,6 +195,50 @@ struct wlr_scene_tree *wlr_scene_tree_create(struct wlr_scene_tree *parent) { static void scene_node_get_size(struct wlr_scene_node *node, int *lx, int *ly); +typedef bool (*scene_node_box_iterator_func_t)(struct wlr_scene_node *node, + int sx, int sy, void *data); + +static bool _scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box, + scene_node_box_iterator_func_t iterator, void *user_data, int lx, int ly) { + if (!node->enabled) { + return false; + } + + switch (node->type) { + case WLR_SCENE_NODE_TREE:; + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each_reverse(child, &scene_tree->children, link) { + if (_scene_nodes_in_box(child, box, iterator, user_data, lx + child->x, ly + child->y)) { + return true; + } + } + break; + case WLR_SCENE_NODE_RECT: + case WLR_SCENE_NODE_BUFFER:; + struct wlr_box node_box = { .x = lx, .y = ly }; + scene_node_get_size(node, &node_box.width, &node_box.height); + bool intersects; + + intersects = wlr_box_intersection(&node_box, &node_box, box); + + if (intersects && iterator(node, lx, ly, user_data)) { + return true; + } + break; + } + + return false; +} + +static bool scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box, + scene_node_box_iterator_func_t iterator, void *user_data) { + int x, y; + wlr_scene_node_coords(node, &x, &y); + + return _scene_nodes_in_box(node, box, iterator, user_data, x, y); +} + // This function must be called whenever the coordinates/dimensions of a scene // buffer or scene output change. It is not necessary to call when a scene // buffer's node is enabled/disabled or obscured by other nodes. @@ -745,55 +789,56 @@ void wlr_scene_node_for_each_buffer(struct wlr_scene_node *node, scene_node_for_each_scene_buffer(node, 0, 0, user_iterator, user_data); } -struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, - double lx, double ly, double *nx, double *ny) { - if (!node->enabled) { - return NULL; - } +struct node_at_data { + double lx, ly; + double rx, ry; + struct wlr_scene_node *node; +}; - // TODO: optimize by storing a bounding box in each node? - lx -= node->x; - ly -= node->y; +static bool scene_node_at_iterator(struct wlr_scene_node *node, + int lx, int ly, void *data) { + struct node_at_data *at_data = data; - bool intersects = false; - switch (node->type) { - case WLR_SCENE_NODE_TREE:; - struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); - struct wlr_scene_node *child; - wl_list_for_each_reverse(child, &scene_tree->children, link) { - struct wlr_scene_node *node = - wlr_scene_node_at(child, lx, ly, nx, ny); - if (node != NULL) { - return node; - } - } - break; - case WLR_SCENE_NODE_RECT:; - int width, height; - scene_node_get_size(node, &width, &height); - intersects = lx >= 0 && lx < width && ly >= 0 && ly < height; - break; - case WLR_SCENE_NODE_BUFFER:; + double rx = at_data->lx - lx; + double ry = at_data->ly - ly; + + if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); - if (scene_buffer->point_accepts_input) { - intersects = scene_buffer->point_accepts_input(scene_buffer, lx, ly); - } else { - int width, height; - scene_node_get_size(node, &width, &height); - intersects = lx >= 0 && lx < width && ly >= 0 && ly < height; + if (scene_buffer->point_accepts_input && + !scene_buffer->point_accepts_input(scene_buffer, rx, ry)) { + return false; } - break; } - if (intersects) { - if (nx != NULL) { - *nx = lx; + at_data->rx = rx; + at_data->ry = ry; + at_data->node = node; + return true; +} + +struct wlr_scene_node *wlr_scene_node_at(struct wlr_scene_node *node, + double lx, double ly, double *nx, double *ny) { + struct wlr_box box = { + .x = floor(lx), + .y = floor(ly), + .width = 1, + .height = 1 + }; + + struct node_at_data data = { + .lx = lx, + .ly = ly + }; + + if (scene_nodes_in_box(node, &box, scene_node_at_iterator, &data)) { + if (nx) { + *nx = data.rx; } - if (ny != NULL) { - *ny = ly; + if (ny) { + *ny = data.ry; } - return node; + return data.node; } return NULL; -- cgit v1.2.3 From 347401dcfcf27a957420f304a2693de1e8d7fb1d Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 25 Jun 2022 17:53:45 -0400 Subject: wlr_scene: Damage scene on node destroy by disabling node This removes one trivial call of scene_node_damage_whole. It's easier to disable the node later than it is to do the damage dance later. --- wlr_scene.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 64b898d..4f62a88 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -79,13 +79,13 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { return; } - scene_node_damage_whole(node); - // We want to call the destroy listeners before we do anything else // in case the destroy signal would like to remove children before they // are recursively destroyed. wlr_signal_emit_safe(&node->events.destroy, NULL); + wlr_scene_node_set_enabled(node, false); + struct wlr_scene *scene = scene_node_get_root(node); if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); -- cgit v1.2.3 From 670e92397494f6ff8d4b5266c7615909dd127329 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 25 Jun 2022 17:58:13 -0400 Subject: wlr_scene: Add per scene node visibility --- wlr_scene.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 4f62a88..f4815ec 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -58,6 +58,7 @@ static void scene_node_init(struct wlr_scene_node *node, wl_list_init(&node->link); wl_signal_init(&node->events.destroy); + pixman_region32_init(&node->visible); if (parent != NULL) { wl_list_insert(parent->children.prev, &node->link); @@ -127,6 +128,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wlr_addon_set_finish(&node->addons); wl_list_remove(&node->link); + pixman_region32_fini(&node->visible); free(node); } @@ -610,6 +612,9 @@ static void _scene_node_damage_whole(struct wlr_scene_node *node, int width, height; scene_node_get_size(node, &width, &height); + pixman_region32_fini(&node->visible); + pixman_region32_init_rect(&node->visible, lx, ly, width, height); + struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { struct wlr_box box = { -- cgit v1.2.3 From 4539c226cb796cb337023097c5aed6de3c06cdc2 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 25 Jun 2022 23:25:05 -0400 Subject: wlr_scene: Rework damage handling Simplify damage handling by using our cached visibility state. Damaging can happen in one step because since we can use the old visibility state which represent what portions of the screen the scene node was. This way we can damage everything in one step after the fact. --- wlr_scene.c | 311 ++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 189 insertions(+), 122 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index f4815ec..498fa87 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -67,8 +67,6 @@ static void scene_node_init(struct wlr_scene_node *node, wlr_addon_set_init(&node->addons); } -static void scene_node_damage_whole(struct wlr_scene_node *node); - struct highlight_region { pixman_region32_t region; struct timespec when; @@ -241,14 +239,44 @@ static bool scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box, return _scene_nodes_in_box(node, box, iterator, user_data, x, y); } -// This function must be called whenever the coordinates/dimensions of a scene -// buffer or scene output change. It is not necessary to call when a scene -// buffer's node is enabled/disabled or obscured by other nodes. -static void scene_buffer_update_outputs(struct wlr_scene_buffer *scene_buffer, - int lx, int ly, struct wlr_scene *scene, - struct wlr_scene_output *ignore) { - struct wlr_box buffer_box = { .x = lx, .y = ly }; - scene_node_get_size(&scene_buffer->node, &buffer_box.width, &buffer_box.height); +struct scene_update_data { + pixman_region32_t *visible; + pixman_region32_t *update_region; + struct wl_list *outputs; +}; + +static void scene_damage_outputs(struct wlr_scene *scene, pixman_region32_t *damage) { + if (!pixman_region32_not_empty(damage)) { + return; + } + + struct wlr_scene_output *scene_output; + wl_list_for_each(scene_output, &scene->outputs, link) { + pixman_region32_t output_damage; + pixman_region32_init(&output_damage); + pixman_region32_copy(&output_damage, damage); + pixman_region32_translate(&output_damage, + -scene_output->x, -scene_output->y); + wlr_region_scale(&output_damage, &output_damage, + scene_output->output->scale); + if (wlr_damage_ring_add(&scene_output->damage_ring, &output_damage)) { + wlr_output_schedule_frame(scene_output->output); + } + pixman_region32_fini(&output_damage); + } +} + +static void update_node_update_outputs(struct wlr_scene_node *node, + struct wl_list *outputs, struct wlr_scene_output *ignore) { + if (node->type != WLR_SCENE_NODE_BUFFER) { + return; + } + + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); + + struct wlr_box buffer_box; + wlr_scene_node_coords(node, &buffer_box.x, &buffer_box.y); + scene_node_get_size(node, &buffer_box.width, &buffer_box.height); int largest_overlap = 0; scene_buffer->primary_output = NULL; @@ -262,7 +290,7 @@ static void scene_buffer_update_outputs(struct wlr_scene_buffer *scene_buffer, // to have a reasonable value. Otherwise, they may get a value that's in // the middle of a calculation. struct wlr_scene_output *scene_output; - wl_list_for_each(scene_output, &scene->outputs, link) { + wl_list_for_each(scene_output, outputs, link) { if (scene_output == ignore) { continue; } @@ -291,7 +319,7 @@ static void scene_buffer_update_outputs(struct wlr_scene_buffer *scene_buffer, uint64_t old_active = scene_buffer->active_outputs; scene_buffer->active_outputs = active_outputs; - wl_list_for_each(scene_output, &scene->outputs, link) { + wl_list_for_each(scene_output, outputs, link) { uint64_t mask = 1ull << scene_output->index; bool intersects = active_outputs & mask; bool intersects_before = old_active & mask; @@ -304,29 +332,118 @@ static void scene_buffer_update_outputs(struct wlr_scene_buffer *scene_buffer, } } -static void _scene_node_update_outputs(struct wlr_scene_node *node, - int lx, int ly, struct wlr_scene *scene, - struct wlr_scene_output *ignore) { - if (node->type == WLR_SCENE_NODE_BUFFER) { - struct wlr_scene_buffer *scene_buffer = - wlr_scene_buffer_from_node(node); - scene_buffer_update_outputs(scene_buffer, lx, ly, scene, ignore); - } else if (node->type == WLR_SCENE_NODE_TREE) { +static bool scene_node_update_iterator(struct wlr_scene_node *node, + int lx, int ly, void *_data) { + struct scene_update_data *data = _data; + + struct wlr_box box = { .x = lx, .y = ly }; + scene_node_get_size(node, &box.width, &box.height); + + pixman_region32_fini(&node->visible); + pixman_region32_init_rect(&node->visible, lx, ly, box.width, box.height); + + update_node_update_outputs(node, data->outputs, NULL); + + return false; +} + +static void scene_node_visibility(struct wlr_scene_node *node, + pixman_region32_t *visible) { + if (!node->enabled) { + return; + } + + if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + scene_node_visibility(child, visible); + } + return; + } + + pixman_region32_union(visible, visible, &node->visible); +} + +static void scene_node_bounds(struct wlr_scene_node *node, + int x, int y, pixman_region32_t *visible) { + if (!node->enabled) { + return; + } + + if (node->type == WLR_SCENE_NODE_TREE) { struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); struct wlr_scene_node *child; wl_list_for_each(child, &scene_tree->children, link) { - _scene_node_update_outputs(child, lx + child->x, - ly + child->y, scene, ignore); + scene_node_bounds(child, x + child->x, y + child->y, visible); } + return; } + + int width, height; + scene_node_get_size(node, &width, &height); + pixman_region32_union_rect(visible, visible, x, y, width, height); +} + +static void scene_update_region(struct wlr_scene *scene, + pixman_region32_t *update_region) { + pixman_region32_t visible; + pixman_region32_init(&visible); + pixman_region32_copy(&visible, update_region); + + struct scene_update_data data = { + .visible = &visible, + .update_region = update_region, + .outputs = &scene->outputs, + }; + + struct pixman_box32 *region_box = pixman_region32_extents(update_region); + struct wlr_box box = { + .x = region_box->x1, + .y = region_box->y1, + .width = region_box->x2 - region_box->x1, + .height = region_box->y2 - region_box->y1, + }; + + // update node visibility and output enter/leave events + scene_nodes_in_box(&scene->tree.node, &box, scene_node_update_iterator, &data); + + pixman_region32_fini(&visible); } -static void scene_node_update_outputs(struct wlr_scene_node *node, - struct wlr_scene_output *ignore) { +static void scene_node_update(struct wlr_scene_node *node, + pixman_region32_t *damage) { struct wlr_scene *scene = scene_node_get_root(node); - int lx, ly; - wlr_scene_node_coords(node, &lx, &ly); - _scene_node_update_outputs(node, lx, ly, scene, ignore); + + int x, y; + if (!wlr_scene_node_coords(node, &x, &y)) { + if (damage) { + scene_update_region(scene, damage); + scene_damage_outputs(scene, damage); + pixman_region32_fini(damage); + } + + return; + } + + pixman_region32_t visible; + if (!damage) { + pixman_region32_init(&visible); + scene_node_visibility(node, &visible); + damage = &visible; + } + + pixman_region32_t update_region; + pixman_region32_init(&update_region); + pixman_region32_copy(&update_region, damage); + scene_node_bounds(node, x, y, &update_region); + + scene_update_region(scene, &update_region); + pixman_region32_fini(&update_region); + + scene_node_visibility(node, damage); + scene_damage_outputs(scene, damage); + pixman_region32_fini(damage); } struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent, @@ -343,7 +460,7 @@ struct wlr_scene_rect *wlr_scene_rect_create(struct wlr_scene_tree *parent, scene_rect->height = height; memcpy(scene_rect->color, color, sizeof(scene_rect->color)); - scene_node_damage_whole(&scene_rect->node); + scene_node_update(&scene_rect->node, NULL); return scene_rect; } @@ -353,10 +470,9 @@ void wlr_scene_rect_set_size(struct wlr_scene_rect *rect, int width, int height) return; } - scene_node_damage_whole(&rect->node); rect->width = width; rect->height = height; - scene_node_damage_whole(&rect->node); + scene_node_update(&rect->node, NULL); } void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[static 4]) { @@ -365,7 +481,7 @@ void wlr_scene_rect_set_color(struct wlr_scene_rect *rect, const float color[sta } memcpy(rect->color, color, sizeof(rect->color)); - scene_node_damage_whole(&rect->node); + scene_node_update(&rect->node, NULL); } struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, @@ -386,9 +502,7 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, wl_signal_init(&scene_buffer->events.output_present); wl_signal_init(&scene_buffer->events.frame_done); - scene_node_damage_whole(&scene_buffer->node); - - scene_node_update_outputs(&scene_buffer->node, NULL); + scene_node_update(&scene_buffer->node, NULL); return scene_buffer; } @@ -401,10 +515,6 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff assert(buffer || !damage); if (buffer != scene_buffer->buffer) { - if (!damage) { - scene_node_damage_whole(&scene_buffer->node); - } - wlr_texture_destroy(scene_buffer->texture); scene_buffer->texture = NULL; wlr_buffer_unlock(scene_buffer->buffer); @@ -415,10 +525,8 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff scene_buffer->buffer = NULL; } - scene_node_update_outputs(&scene_buffer->node, NULL); - if (!damage) { - scene_node_damage_whole(&scene_buffer->node); + scene_node_update(&scene_buffer->node, NULL); } } @@ -500,7 +608,7 @@ void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer, memset(cur, 0, sizeof(*cur)); } - scene_node_damage_whole(&scene_buffer->node); + scene_node_update(&scene_buffer->node, NULL); } void wlr_scene_buffer_set_dest_size(struct wlr_scene_buffer *scene_buffer, @@ -509,12 +617,9 @@ void wlr_scene_buffer_set_dest_size(struct wlr_scene_buffer *scene_buffer, return; } - scene_node_damage_whole(&scene_buffer->node); scene_buffer->dst_width = width; scene_buffer->dst_height = height; - scene_node_damage_whole(&scene_buffer->node); - - scene_node_update_outputs(&scene_buffer->node, NULL); + scene_node_update(&scene_buffer->node, NULL); } void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer, @@ -523,11 +628,8 @@ void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer, return; } - scene_node_damage_whole(&scene_buffer->node); scene_buffer->transform = transform; - scene_node_damage_whole(&scene_buffer->node); - - scene_node_update_outputs(&scene_buffer->node, NULL); + scene_node_update(&scene_buffer->node, NULL); } void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer, @@ -594,67 +696,21 @@ static void scale_box(struct wlr_box *box, float scale) { box->y = round(box->y * scale); } -static void _scene_node_damage_whole(struct wlr_scene_node *node, - struct wlr_scene *scene, int lx, int ly) { - if (!node->enabled) { - return; - } - - if (node->type == WLR_SCENE_NODE_TREE) { - struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); - struct wlr_scene_node *child; - wl_list_for_each(child, &scene_tree->children, link) { - _scene_node_damage_whole(child, scene, - lx + child->x, ly + child->y); - } - } - - int width, height; - scene_node_get_size(node, &width, &height); - - pixman_region32_fini(&node->visible); - pixman_region32_init_rect(&node->visible, lx, ly, width, height); - - struct wlr_scene_output *scene_output; - wl_list_for_each(scene_output, &scene->outputs, link) { - struct wlr_box box = { - .x = lx - scene_output->x, - .y = ly - scene_output->y, - .width = width, - .height = height, - }; - - scale_box(&box, scene_output->output->scale); - - if (wlr_damage_ring_add_box(&scene_output->damage_ring, &box)) { - wlr_output_schedule_frame(scene_output->output); - } - } -} - -static void scene_node_damage_whole(struct wlr_scene_node *node) { - struct wlr_scene *scene = scene_node_get_root(node); - if (wl_list_empty(&scene->outputs)) { - return; - } - - int lx, ly; - if (!wlr_scene_node_coords(node, &lx, &ly)) { - return; - } - - _scene_node_damage_whole(node, scene, lx, ly); -} - void wlr_scene_node_set_enabled(struct wlr_scene_node *node, bool enabled) { if (node->enabled == enabled) { return; } - // One of these damage_whole() calls will short-circuit and be a no-op - scene_node_damage_whole(node); + int x, y; + pixman_region32_t visible; + pixman_region32_init(&visible); + if (wlr_scene_node_coords(node, &x, &y)) { + scene_node_visibility(node, &visible); + } + node->enabled = enabled; - scene_node_damage_whole(node); + + scene_node_update(node, &visible); } void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y) { @@ -662,12 +718,9 @@ void wlr_scene_node_set_position(struct wlr_scene_node *node, int x, int y) { return; } - scene_node_damage_whole(node); node->x = x; node->y = y; - scene_node_damage_whole(node); - - scene_node_update_outputs(node, NULL); + scene_node_update(node, NULL); } void wlr_scene_node_place_above(struct wlr_scene_node *node, @@ -681,9 +734,7 @@ void wlr_scene_node_place_above(struct wlr_scene_node *node, wl_list_remove(&node->link); wl_list_insert(&sibling->link, &node->link); - - scene_node_damage_whole(node); - scene_node_damage_whole(sibling); + scene_node_update(node, NULL); } void wlr_scene_node_place_below(struct wlr_scene_node *node, @@ -697,9 +748,7 @@ void wlr_scene_node_place_below(struct wlr_scene_node *node, wl_list_remove(&node->link); wl_list_insert(sibling->link.prev, &node->link); - - scene_node_damage_whole(node); - scene_node_damage_whole(sibling); + scene_node_update(node, NULL); } void wlr_scene_node_raise_to_top(struct wlr_scene_node *node) { @@ -734,15 +783,17 @@ void wlr_scene_node_reparent(struct wlr_scene_node *node, assert(&ancestor->node != node); } - scene_node_damage_whole(node); + int x, y; + pixman_region32_t visible; + pixman_region32_init(&visible); + if (wlr_scene_node_coords(node, &x, &y)) { + scene_node_visibility(node, &visible); + } wl_list_remove(&node->link); node->parent = new_parent; wl_list_insert(new_parent->children.prev, &node->link); - - scene_node_damage_whole(node); - - scene_node_update_outputs(node, NULL); + scene_node_update(node, &visible); } bool wlr_scene_node_coords(struct wlr_scene_node *node, @@ -1026,13 +1077,28 @@ static const struct wlr_addon_interface output_addon_impl = { .destroy = scene_output_handle_destroy, }; +static void scene_node_output_update(struct wlr_scene_node *node, + struct wl_list *outputs, struct wlr_scene_output *ignore) { + if (node->type == WLR_SCENE_NODE_TREE) { + struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); + struct wlr_scene_node *child; + wl_list_for_each(child, &scene_tree->children, link) { + scene_node_output_update(child, outputs, ignore); + } + return; + } + + update_node_update_outputs(node, outputs, ignore); +} + static void scene_output_update_geometry(struct wlr_scene_output *scene_output) { int width, height; wlr_output_transformed_resolution(scene_output->output, &width, &height); wlr_damage_ring_set_bounds(&scene_output->damage_ring, width, height); wlr_output_schedule_frame(scene_output->output); - scene_node_update_outputs(&scene_output->scene->tree.node, NULL); + scene_node_output_update(&scene_output->scene->tree.node, + &scene_output->scene->outputs, NULL); } static void scene_output_handle_commit(struct wl_listener *listener, void *data) { @@ -1131,7 +1197,8 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { wlr_signal_emit_safe(&scene_output->events.destroy, NULL); - scene_node_update_outputs(&scene_output->scene->tree.node, scene_output); + scene_node_output_update(&scene_output->scene->tree.node, + &scene_output->scene->outputs, scene_output); struct highlight_region *damage, *tmp_damage; wl_list_for_each_safe(damage, tmp_damage, &scene_output->damage_highlight_regions, link) { -- cgit v1.2.3 From ab1ebc20123b11e8f09e347dd74e9ae63c8a4443 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 25 Jun 2022 18:22:00 -0400 Subject: wlr_scene_set_buffer_with_damage: Only damage the visible parts of the node --- wlr_scene.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 498fa87..94d0c02 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -577,6 +577,14 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff pixman_region32_init(&output_damage); wlr_region_scale_xy(&output_damage, &trans_damage, output_scale * scale_x, output_scale * scale_y); + + pixman_region32_t cull_region; + pixman_region32_init(&cull_region); + wlr_region_scale(&cull_region, &scene_buffer->node.visible, output_scale); + pixman_region32_translate(&cull_region, -lx * output_scale, -ly * output_scale); + pixman_region32_intersect(&output_damage, &output_damage, &cull_region); + pixman_region32_fini(&cull_region); + pixman_region32_translate(&output_damage, (lx - scene_output->x) * output_scale, (ly - scene_output->y) * output_scale); -- cgit v1.2.3 From 323c3a2732397a7b3962bb5c71a212d60cb022d0 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 19 May 2022 00:58:04 -0400 Subject: wlr_scene: Only send frame done events for visible buffers --- wlr_scene.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wlr_scene.c b/wlr_scene.c index 94d0c02..f5af07e 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -642,7 +642,9 @@ void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer, void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer, struct timespec *now) { - wlr_signal_emit_safe(&scene_buffer->events.frame_done, now); + if (pixman_region32_not_empty(&scene_buffer->node.visible)) { + wlr_signal_emit_safe(&scene_buffer->events.frame_done, now); + } } static struct wlr_texture *scene_buffer_get_texture( -- cgit v1.2.3 From 0dcf410f380a7f1c503c9292ab7d35dd51fb390c Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 25 Jun 2022 19:53:17 -0400 Subject: wlr_scene: Don't render non visible parts of textures/rects We can also get rid of the intersection checks in the rendering functions because we are guaranteed to already be in the node do to the prior intersection checking of the node visibility. --- wlr_scene.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index f5af07e..ec71491 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -932,28 +932,21 @@ static void scissor_output(struct wlr_output *output, pixman_box32_t *rect) { } static void render_rect(struct wlr_output *output, - pixman_region32_t *output_damage, const float color[static 4], + pixman_region32_t *damage, const float color[static 4], const struct wlr_box *box, const float matrix[static 9]) { struct wlr_renderer *renderer = output->renderer; assert(renderer); - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_init_rect(&damage, box->x, box->y, box->width, box->height); - pixman_region32_intersect(&damage, &damage, output_damage); - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); wlr_render_rect(renderer, box, color, matrix); } - - pixman_region32_fini(&damage); } static void render_texture(struct wlr_output *output, - pixman_region32_t *output_damage, struct wlr_texture *texture, + pixman_region32_t *damage, struct wlr_texture *texture, const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9]) { struct wlr_renderer *renderer = output->renderer; @@ -966,20 +959,12 @@ static void render_texture(struct wlr_output *output, src_box = &default_src_box; } - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_init_rect(&damage, dst_box->x, dst_box->y, - dst_box->width, dst_box->height); - pixman_region32_intersect(&damage, &damage, output_damage); - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); wlr_render_subtexture_with_matrix(renderer, texture, src_box, matrix, 1.0); } - - pixman_region32_fini(&damage); } struct render_data { @@ -992,7 +977,17 @@ static void render_node_iterator(struct wlr_scene_node *node, struct render_data *data = _data; struct wlr_scene_output *scene_output = data->scene_output; struct wlr_output *output = scene_output->output; - pixman_region32_t *output_damage = data->damage; + + pixman_region32_t render_region; + pixman_region32_init(&render_region); + pixman_region32_copy(&render_region, &node->visible); + pixman_region32_translate(&render_region, -scene_output->x, -scene_output->y); + wlr_region_scale(&render_region, &render_region, output->scale); + pixman_region32_intersect(&render_region, &render_region, data->damage); + if (!pixman_region32_not_empty(&render_region)) { + pixman_region32_fini(&render_region); + return; + } struct wlr_box dst_box = { .x = x, @@ -1011,7 +1006,7 @@ static void render_node_iterator(struct wlr_scene_node *node, case WLR_SCENE_NODE_RECT:; struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); - render_rect(output, output_damage, scene_rect->color, &dst_box, + render_rect(output, &render_region, scene_rect->color, &dst_box, output->transform_matrix); break; case WLR_SCENE_NODE_BUFFER:; @@ -1030,12 +1025,14 @@ static void render_node_iterator(struct wlr_scene_node *node, wlr_matrix_project_box(matrix, &dst_box, transform, 0.0, output->transform_matrix); - render_texture(output, output_damage, texture, &scene_buffer->src_box, + render_texture(output, &render_region, texture, &scene_buffer->src_box, &dst_box, matrix); wlr_signal_emit_safe(&scene_buffer->events.output_present, scene_output); break; } + + pixman_region32_fini(&render_region); } static void scene_node_for_each_node(struct wlr_scene_node *node, -- cgit v1.2.3 From 1a7af5e0bfb06ac9626dd5f2ff0341a110c8ddf6 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sun, 14 Aug 2022 02:17:09 -0400 Subject: wlr_scene: Rewrite direct scan out logic to rely on visibility Also make the regular rendering logic use the introduced render list. --- wlr_scene.c | 247 ++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 158 insertions(+), 89 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index ec71491..e560547 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -16,6 +16,7 @@ #include "util/time.h" #define HIGHLIGHT_DAMAGE_FADEOUT_TIME 250 +#define RENDER_LIST_MIN_ALLOCATION 8 static struct wlr_scene_tree *scene_tree_from_node(struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_TREE); @@ -967,15 +968,13 @@ static void render_texture(struct wlr_output *output, } } -struct render_data { - struct wlr_scene_output *scene_output; - pixman_region32_t *damage; -}; +static void scene_node_render(struct wlr_scene_node *node, + struct wlr_scene_output *scene_output, pixman_region32_t *damage) { + int x, y; + wlr_scene_node_coords(node, &x, &y); + x -= scene_output->x; + y -= scene_output->y; -static void render_node_iterator(struct wlr_scene_node *node, - int x, int y, void *_data) { - struct render_data *data = _data; - struct wlr_scene_output *scene_output = data->scene_output; struct wlr_output *output = scene_output->output; pixman_region32_t render_region; @@ -983,7 +982,7 @@ static void render_node_iterator(struct wlr_scene_node *node, pixman_region32_copy(&render_region, &node->visible); pixman_region32_translate(&render_region, -scene_output->x, -scene_output->y); wlr_region_scale(&render_region, &render_region, output->scale); - pixman_region32_intersect(&render_region, &render_region, data->damage); + pixman_region32_intersect(&render_region, &render_region, damage); if (!pixman_region32_not_empty(&render_region)) { pixman_region32_fini(&render_region); return; @@ -1035,27 +1034,6 @@ static void render_node_iterator(struct wlr_scene_node *node, pixman_region32_fini(&render_region); } -static void scene_node_for_each_node(struct wlr_scene_node *node, - int lx, int ly, wlr_scene_node_iterator_func_t user_iterator, - void *user_data) { - if (!node->enabled) { - return; - } - - lx += node->x; - ly += node->y; - - user_iterator(node, lx, ly, user_data); - - if (node->type == WLR_SCENE_NODE_TREE) { - struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); - struct wlr_scene_node *child; - wl_list_for_each(child, &scene_tree->children, link) { - scene_node_for_each_node(child, lx, ly, user_iterator, user_data); - } - } -} - static void scene_handle_presentation_destroy(struct wl_listener *listener, void *data) { struct wlr_scene *scene = @@ -1220,6 +1198,7 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { wl_list_remove(&scene_output->output_damage.link); wl_list_remove(&scene_output->output_needs_frame.link); + free(scene_output->render_list.data); free(scene_output); } @@ -1247,37 +1226,90 @@ void wlr_scene_output_set_position(struct wlr_scene_output *scene_output, scene_output_update_geometry(scene_output); } -struct check_scanout_data { - // in - struct wlr_box viewport_box; - // out - struct wlr_scene_node *node; - size_t n; +static bool scene_node_invisible(struct wlr_scene_node *node) { + if (node->type == WLR_SCENE_NODE_TREE) { + return true; + } else if (node->type == WLR_SCENE_NODE_RECT) { + float *clear = (float[4]){ 0.f, 0.f, 0.f, 0.f }; + struct wlr_scene_rect *rect = scene_rect_from_node(node); + + return memcmp(rect->color, clear, sizeof(float) * 4) == 0; + } else if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); + + return buffer->buffer == NULL; + } + + return false; +} + +static size_t max(size_t fst, size_t snd) { + if (fst > snd) { + return fst; + } else { + return snd; + } +} + +struct render_list_constructor_data { + struct wlr_box box; + struct wlr_scene_output_render_list *render_list; + size_t size; }; -static void check_scanout_iterator(struct wlr_scene_node *node, - int x, int y, void *_data) { - struct check_scanout_data *data = _data; +static bool construct_render_list_iterator(struct wlr_scene_node *node, + int lx, int ly, void *_data) { + struct render_list_constructor_data *data = _data; - struct wlr_box node_box = { .x = x, .y = y }; - scene_node_get_size(node, &node_box.width, &node_box.height); + if (scene_node_invisible(node)) { + return false; + } - struct wlr_box intersection; - if (!wlr_box_intersection(&intersection, &data->viewport_box, &node_box)) { - return; + // while rendering, the background should always be black. + // If we see a black rect, we can ignore rendering everything under the rect + // and even the rect itself. + if (node->type == WLR_SCENE_NODE_RECT) { + struct wlr_scene_rect *rect = scene_rect_from_node(node); + float *black = (float[4]){ 1.f, 1.f, 1.f, 1.f }; + + if (memcmp(rect->color, black, sizeof(float) * 4) == 0) { + return false; + } + } + + pixman_region32_t intersection; + pixman_region32_init(&intersection); + pixman_region32_intersect_rect(&intersection, &node->visible, + data->box.x, data->box.y, + data->box.width, data->box.height); + if (!pixman_region32_not_empty(&intersection)) { + pixman_region32_fini(&intersection); + return false; } - data->n++; + pixman_region32_fini(&intersection); - if (data->viewport_box.x == node_box.x && - data->viewport_box.y == node_box.y && - data->viewport_box.width == node_box.width && - data->viewport_box.height == node_box.height) { - data->node = node; + if (data->size == data->render_list->capacity) { + size_t alloc_size = + max(data->render_list->capacity * 2, RENDER_LIST_MIN_ALLOCATION); + void *alloc = realloc(data->render_list->data, alloc_size + * sizeof(struct wlr_scene_node *)); + + if (alloc) { + data->render_list->data = alloc; + data->render_list->capacity = alloc_size; + } + } + + if (data->size < data->render_list->capacity) { + data->render_list->data[data->size++] = node; } + + return false; } -static bool scene_output_scanout(struct wlr_scene_output *scene_output) { +static bool scene_node_try_direct_scanout(struct wlr_scene_node *node, + struct wlr_scene_output *scene_output, struct wlr_box *box) { if (!scene_output->scene->direct_scanout) { return false; } @@ -1289,50 +1321,64 @@ static bool scene_output_scanout(struct wlr_scene_output *scene_output) { return false; } + if (node->type != WLR_SCENE_NODE_BUFFER) { + return false; + } + + struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); struct wlr_output *output = scene_output->output; - struct wlr_box viewport_box = { .x = scene_output->x, .y = scene_output->y }; - wlr_output_effective_resolution(output, - &viewport_box.width, &viewport_box.height); + struct wlr_fbox default_box = {0}; + if (buffer->transform & WL_OUTPUT_TRANSFORM_90) { + default_box.width = buffer->buffer->height; + default_box.height = buffer->buffer->width; + } else { + default_box.width = buffer->buffer->width; + default_box.height = buffer->buffer->height; + } - struct check_scanout_data check_scanout_data = { - .viewport_box = viewport_box, - }; - scene_node_for_each_node(&scene_output->scene->tree.node, 0, 0, - check_scanout_iterator, &check_scanout_data); - if (check_scanout_data.n != 1 || check_scanout_data.node == NULL) { + if (!wlr_fbox_empty(&buffer->src_box) && + memcmp(&buffer->src_box, &default_box, sizeof(default_box)) != 0) { return false; } - struct wlr_scene_node *node = check_scanout_data.node; - struct wlr_buffer *buffer; - switch (node->type) { - case WLR_SCENE_NODE_BUFFER:; - struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); - if (scene_buffer->buffer == NULL || - !wlr_fbox_empty(&scene_buffer->src_box) || - scene_buffer->transform != output->transform) { - return false; - } - buffer = scene_buffer->buffer; - break; - default: + if (buffer->transform != output->transform) { + return false; + } + + struct wlr_box node_box; + wlr_scene_node_coords(node, &node_box.x, &node_box.y); + scene_node_get_size(node, &node_box.width, &node_box.height); + + if (node_box.x != box->x || + node_box.y != box->y || + node_box.width != box->width || + node_box.height != box->height) { return false; } - wlr_output_attach_buffer(output, buffer); + wlr_output_attach_buffer(output, buffer->buffer); if (!wlr_output_test(output)) { wlr_output_rollback(output); return false; } - if (node->type == WLR_SCENE_NODE_BUFFER) { - struct wlr_scene_buffer *scene_buffer = - wlr_scene_buffer_from_node(node); - wlr_signal_emit_safe(&scene_buffer->events.output_present, scene_output); + return wlr_output_commit(output); +} + +static void compact_render_list(struct wlr_scene_output_render_list *list, size_t size) { + assert(size <= list->capacity); + + size_t alloc_size = max(RENDER_LIST_MIN_ALLOCATION, size); + if (alloc_size == list->capacity) { + return; } - return wlr_output_commit(output); + void *alloc = realloc(list->data, alloc_size * sizeof(struct wlr_scene_node *)); + if (alloc) { + list->data = alloc; + list->capacity = alloc_size; + } } bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { @@ -1343,15 +1389,40 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { struct wlr_renderer *renderer = output->renderer; assert(renderer != NULL); - bool scanout = scene_output_scanout(scene_output); - if (scanout != scene_output->prev_scanout) { + struct render_list_constructor_data list_con = { + .box = { .x = scene_output->x, .y = scene_output->y }, + .render_list = &scene_output->render_list, + .size = 0, + }; + wlr_output_effective_resolution(output, + &list_con.box.width, &list_con.box.height); + + scene_nodes_in_box(&scene_output->scene->tree.node, &list_con.box, + construct_render_list_iterator, &list_con); + compact_render_list(list_con.render_list, list_con.size); + + // if there is only one thing to render let's see if that thing can be + // directly scanned out + bool scanout = false; + if (list_con.size == 1) { + struct wlr_scene_node *node = list_con.render_list->data[0]; + scanout = scene_node_try_direct_scanout(node, scene_output, &list_con.box); + } + + if (scene_output->prev_scanout != scanout) { + scene_output->prev_scanout = scanout; wlr_log(WLR_DEBUG, "Direct scan-out %s", scanout ? "enabled" : "disabled"); // When exiting direct scan-out, damage everything wlr_damage_ring_add_whole(&scene_output->damage_ring); } - scene_output->prev_scanout = scanout; + if (scanout) { + struct wlr_scene_node *node = list_con.render_list->data[0]; + + assert(node->type == WLR_SCENE_NODE_BUFFER); + struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); + wlr_signal_emit_safe(&buffer->events.output_present, scene_output); return true; } @@ -1423,13 +1494,11 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { wlr_renderer_clear(renderer, (float[4]){ 0.0, 0.0, 0.0, 1.0 }); } - struct render_data data = { - .scene_output = scene_output, - .damage = &damage, - }; - scene_node_for_each_node(&scene_output->scene->tree.node, - -scene_output->x, -scene_output->y, - render_node_iterator, &data); + for (int i = list_con.size - 1; i >= 0; i--) { + struct wlr_scene_node *node = list_con.render_list->data[i]; + scene_node_render(node, scene_output, &damage); + } + wlr_renderer_scissor(renderer, NULL); if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { -- cgit v1.2.3 From 191147a68031a271c6e86492036e98b25f374508 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 25 Jun 2022 23:26:12 -0400 Subject: wlr_scene: Introduce buffer opaque region metadata --- wlr_scene.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index e560547..36a12a0 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -103,6 +103,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wlr_texture_destroy(scene_buffer->texture); wlr_buffer_unlock(scene_buffer->buffer); + pixman_region32_fini(&scene_buffer->opaque_region); } else if (node->type == WLR_SCENE_NODE_TREE) { struct wlr_scene_tree *scene_tree = scene_tree_from_node(node); @@ -502,6 +503,7 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, wl_signal_init(&scene_buffer->events.output_leave); wl_signal_init(&scene_buffer->events.output_present); wl_signal_init(&scene_buffer->events.frame_done); + pixman_region32_init(&scene_buffer->opaque_region); scene_node_update(&scene_buffer->node, NULL); @@ -603,6 +605,16 @@ void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer, wlr_scene_buffer_set_buffer_with_damage(scene_buffer, buffer, NULL); } +void wlr_scene_buffer_set_opaque_region(struct wlr_scene_buffer *scene_buffer, + pixman_region32_t *region) { + if (pixman_region32_equal(&scene_buffer->opaque_region, region)) { + return; + } + + pixman_region32_copy(&scene_buffer->opaque_region, region); + scene_node_update(&scene_buffer->node, NULL); +} + void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer, const struct wlr_fbox *box) { struct wlr_fbox *cur = &scene_buffer->src_box; -- cgit v1.2.3 From ab247322029d0d0642944282edc3fa2bcb19b635 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 19 May 2022 22:32:41 -0400 Subject: wlr_scene/surface: Hook through opaque metadata --- surface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/surface.c b/surface.c index d3a0b03..b122d21 100644 --- a/surface.c +++ b/surface.c @@ -59,6 +59,8 @@ static void set_buffer_with_surface_state(struct wlr_scene_buffer *scene_buffer, struct wlr_surface *surface) { struct wlr_surface_state *state = &surface->current; + wlr_scene_buffer_set_opaque_region(scene_buffer, &surface->opaque_region); + struct wlr_fbox src_box; wlr_surface_get_buffer_source_box(surface, &src_box); wlr_scene_buffer_set_source_box(scene_buffer, &src_box); -- cgit v1.2.3 From c00e090e3c8536da51bc7330f76df1f3db445dd0 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 25 Jun 2022 18:33:40 -0400 Subject: wlr_scene: Calculate output intersections based on node visibility This has a few benefits one of them crucial for proper operation: - The primary output will be based on the largest area that is actually visible to the user. Presentation and frame done events are based on this state. This is important to do since we cull frame done events. If we happen to be in a situation where a surface sits mostly on output A and some on output B but is completely obstructed by for instance a fullscreen surface on output A we will erroneously send frame_done events based on output A. If we base things as they are in reality (visibility) the primary output will instead be output B and things will work properly. - The primary output will be NULL if the surface is completely hidden. Due to quirks with wayland, on a surface commit, frame done events are required to be sent. Therefore, a new frame will be submitted for rendering on the primary output. We can improve adaptive sync on completely hidden but enabled surfaces if we null out the primary output in this state. - The client will be more likely to choose better metadata to use for rendering to an output's optimal rendering characteristics. --- wlr_scene.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 36a12a0..627d7e7 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -247,6 +247,18 @@ struct scene_update_data { struct wl_list *outputs; }; +static uint32_t region_area(pixman_region32_t *region) { + uint32_t area = 0; + + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(region, &nrects); + for (int i = 0; i < nrects; ++i) { + area += (rects[i].x2 - rects[i].x1) * (rects[i].y2 - rects[i].y1); + } + + return area; +} + static void scene_damage_outputs(struct wlr_scene *scene, pixman_region32_t *damage) { if (!pixman_region32_not_empty(damage)) { return; @@ -276,10 +288,6 @@ static void update_node_update_outputs(struct wlr_scene_node *node, struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); - struct wlr_box buffer_box; - wlr_scene_node_coords(node, &buffer_box.x, &buffer_box.y); - scene_node_get_size(node, &buffer_box.width, &buffer_box.height); - int largest_overlap = 0; scene_buffer->primary_output = NULL; @@ -304,11 +312,13 @@ static void update_node_update_outputs(struct wlr_scene_node *node, wlr_output_effective_resolution(scene_output->output, &output_box.width, &output_box.height); - struct wlr_box intersection; - bool intersects = wlr_box_intersection(&intersection, &buffer_box, &output_box); + pixman_region32_t intersection; + pixman_region32_init(&intersection); + pixman_region32_intersect_rect(&intersection, &node->visible, + output_box.x, output_box.y, output_box.width, output_box.height); - if (intersects) { - int overlap = intersection.width * intersection.height; + if (pixman_region32_not_empty(&intersection)) { + int overlap = region_area(&intersection); if (overlap > largest_overlap) { largest_overlap = overlap; scene_buffer->primary_output = scene_output; @@ -316,6 +326,8 @@ static void update_node_update_outputs(struct wlr_scene_node *node, active_outputs |= 1ull << scene_output->index; } + + pixman_region32_fini(&intersection); } uint64_t old_active = scene_buffer->active_outputs; -- cgit v1.2.3 From 0b0f3bdf9075228535c310f0c7e2ec35ab3ff92d Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 25 Jun 2022 18:34:26 -0400 Subject: wlr_scene: Account for occlusion by other scene nodes when calculating visibility --- wlr_scene.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 627d7e7..9e68e6c 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -11,6 +11,7 @@ #include #include #include +#include "types/wlr_buffer.h" #include "types/wlr_scene.h" #include "util/signal.h" #include "util/time.h" @@ -180,6 +181,20 @@ struct wlr_scene *wlr_scene_create(void) { scene->direct_scanout = true; } + char *visibility_disabled = getenv("WLR_SCENE_DISABLE_VISIBILITY"); + if (visibility_disabled) { + wlr_log(WLR_INFO, "Loading WLR_SCENE_DISABLE_VISIBILITY option: %s", visibility_disabled); + } + + if (!visibility_disabled || strcmp(visibility_disabled, "0") == 0) { + scene->calculate_visibility = true; + } else if (strcmp(visibility_disabled, "1") == 0) { + scene->calculate_visibility = false; + } else { + wlr_log(WLR_ERROR, "Unknown WLR_SCENE_DISABLE_VISIBILITY option: %s", visibility_disabled); + scene->calculate_visibility = true; + } + return scene; } @@ -241,10 +256,41 @@ static bool scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box, return _scene_nodes_in_box(node, box, iterator, user_data, x, y); } +static void scene_node_cull_hidden(struct wlr_scene_node *node, int x, int y, + pixman_region32_t *visible) { + if (node->type == WLR_SCENE_NODE_RECT) { + struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); + if (scene_rect->color[3] != 1) { + return; + } + } else if (node->type == WLR_SCENE_NODE_BUFFER) { + struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); + + if (!scene_buffer->buffer) { + return; + } + + if (!buffer_is_opaque(scene_buffer->buffer)) { + pixman_region32_translate(visible, -x, -y); + pixman_region32_subtract(visible, visible, &scene_buffer->opaque_region); + pixman_region32_translate(visible, x, y); + return; + } + } + + int width, height; + scene_node_get_size(node, &width, &height); + pixman_region32_t opaque; + pixman_region32_init_rect(&opaque, x, y, width, height); + pixman_region32_subtract(visible, visible, &opaque); + pixman_region32_fini(&opaque); +} + struct scene_update_data { pixman_region32_t *visible; pixman_region32_t *update_region; struct wl_list *outputs; + bool calculate_visibility; }; static uint32_t region_area(pixman_region32_t *region) { @@ -353,8 +399,16 @@ static bool scene_node_update_iterator(struct wlr_scene_node *node, struct wlr_box box = { .x = lx, .y = ly }; scene_node_get_size(node, &box.width, &box.height); - pixman_region32_fini(&node->visible); - pixman_region32_init_rect(&node->visible, lx, ly, box.width, box.height); + if (data->calculate_visibility) { + pixman_region32_subtract(&node->visible, &node->visible, data->update_region); + pixman_region32_union(&node->visible, &node->visible, data->visible); + pixman_region32_intersect_rect(&node->visible, &node->visible, + lx, ly, box.width, box.height); + scene_node_cull_hidden(node, lx, ly, data->visible); + } else { + pixman_region32_fini(&node->visible); + pixman_region32_init_rect(&node->visible, lx, ly, box.width, box.height); + } update_node_update_outputs(node, data->outputs, NULL); @@ -409,6 +463,7 @@ static void scene_update_region(struct wlr_scene *scene, .visible = &visible, .update_region = update_region, .outputs = &scene->outputs, + .calculate_visibility = scene->calculate_visibility, }; struct pixman_box32 *region_box = pixman_region32_extents(update_region); -- cgit v1.2.3 From 8409df1445186a043c4c188eb4bc4a08fb5f69ac Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Mon, 15 Aug 2022 06:03:54 -0400 Subject: wlr_scene: Use wlr_fbox_equals --- wlr_scene.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 9e68e6c..b2e7d71 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -686,7 +686,7 @@ void wlr_scene_buffer_set_source_box(struct wlr_scene_buffer *scene_buffer, const struct wlr_fbox *box) { struct wlr_fbox *cur = &scene_buffer->src_box; if ((wlr_fbox_empty(box) && wlr_fbox_empty(cur)) || - (box != NULL && memcmp(cur, box, sizeof(*box)) == 0)) { + (box != NULL && wlr_fbox_equal(cur, box))) { return; } @@ -1417,7 +1417,7 @@ static bool scene_node_try_direct_scanout(struct wlr_scene_node *node, } if (!wlr_fbox_empty(&buffer->src_box) && - memcmp(&buffer->src_box, &default_box, sizeof(default_box)) != 0) { + !wlr_fbox_equal(&buffer->src_box, &default_box)) { return false; } -- cgit v1.2.3 From 894e7917f0842c2d9115f352bfc141cf02879bae Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Mon, 15 Aug 2022 07:37:09 -0400 Subject: wlr_scene: Use wlr_box_equal --- wlr_scene.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index b2e7d71..b522f37 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -1429,10 +1429,7 @@ static bool scene_node_try_direct_scanout(struct wlr_scene_node *node, wlr_scene_node_coords(node, &node_box.x, &node_box.y); scene_node_get_size(node, &node_box.width, &node_box.height); - if (node_box.x != box->x || - node_box.y != box->y || - node_box.width != box->width || - node_box.height != box->height) { + if (!wlr_box_equal(box, &node_box)) { return false; } -- cgit v1.2.3 From b0a7bb8d51a176dd2c7837a7047e1ab23915b56a Mon Sep 17 00:00:00 2001 From: yiqiang Date: Tue, 16 Aug 2022 10:46:21 +0800 Subject: wlr_scene: fix color value when filtering black boxes Signed-off-by: yiqiang --- wlr_scene.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wlr_scene.c b/wlr_scene.c index b522f37..d2da8bd 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -1349,7 +1349,7 @@ static bool construct_render_list_iterator(struct wlr_scene_node *node, // and even the rect itself. if (node->type == WLR_SCENE_NODE_RECT) { struct wlr_scene_rect *rect = scene_rect_from_node(node); - float *black = (float[4]){ 1.f, 1.f, 1.f, 1.f }; + float *black = (float[4]){ 0.f, 0.f, 0.f, 1.f }; if (memcmp(rect->color, black, sizeof(float) * 4) == 0) { return false; -- cgit v1.2.3 From 4066cdc7cc6e1cc95306046d89305a76c7a35fbd Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 18 Aug 2022 07:16:16 -0400 Subject: Use wl_signal_emit_mutable --- wlr_scene.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index d2da8bd..2749424 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -13,7 +13,6 @@ #include #include "types/wlr_buffer.h" #include "types/wlr_scene.h" -#include "util/signal.h" #include "util/time.h" #define HIGHLIGHT_DAMAGE_FADEOUT_TIME 250 @@ -83,7 +82,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { // We want to call the destroy listeners before we do anything else // in case the destroy signal would like to remove children before they // are recursively destroyed. - wlr_signal_emit_safe(&node->events.destroy, NULL); + wl_signal_emit_mutable(&node->events.destroy, NULL); wlr_scene_node_set_enabled(node, false); @@ -96,7 +95,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { if (active & (1ull << scene_output->index)) { - wlr_signal_emit_safe(&scene_buffer->events.output_leave, + wl_signal_emit_mutable(&scene_buffer->events.output_leave, scene_output); } } @@ -385,9 +384,9 @@ static void update_node_update_outputs(struct wlr_scene_node *node, bool intersects_before = old_active & mask; if (intersects && !intersects_before) { - wlr_signal_emit_safe(&scene_buffer->events.output_enter, scene_output); + wl_signal_emit_mutable(&scene_buffer->events.output_enter, scene_output); } else if (!intersects && intersects_before) { - wlr_signal_emit_safe(&scene_buffer->events.output_leave, scene_output); + wl_signal_emit_mutable(&scene_buffer->events.output_leave, scene_output); } } } @@ -723,7 +722,7 @@ void wlr_scene_buffer_set_transform(struct wlr_scene_buffer *scene_buffer, void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer, struct timespec *now) { if (pixman_region32_not_empty(&scene_buffer->node.visible)) { - wlr_signal_emit_safe(&scene_buffer->events.frame_done, now); + wl_signal_emit_mutable(&scene_buffer->events.frame_done, now); } } @@ -1106,7 +1105,7 @@ static void scene_node_render(struct wlr_scene_node *node, render_texture(output, &render_region, texture, &scene_buffer->src_box, &dst_box, matrix); - wlr_signal_emit_safe(&scene_buffer->events.output_present, scene_output); + wl_signal_emit_mutable(&scene_buffer->events.output_present, scene_output); break; } @@ -1259,7 +1258,7 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { return; } - wlr_signal_emit_safe(&scene_output->events.destroy, NULL); + wl_signal_emit_mutable(&scene_output->events.destroy, NULL); scene_node_output_update(&scene_output->scene->tree.node, &scene_output->scene->outputs, scene_output); @@ -1498,7 +1497,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { assert(node->type == WLR_SCENE_NODE_BUFFER); struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); - wlr_signal_emit_safe(&buffer->events.output_present, scene_output); + wl_signal_emit_mutable(&buffer->events.output_present, scene_output); return true; } -- cgit v1.2.3 From d15c279302d5093c4841bfecfa7aabfa7da665d8 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 18 Aug 2022 11:54:03 +0200 Subject: wlr_scene: Convert render_list to wl_array This simplifies some of the growth logic, but uses array_realloc to shrink the array if needed. --- wlr_scene.c | 68 ++++++++++++++++--------------------------------------------- 1 file changed, 18 insertions(+), 50 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 2749424..79701ab 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -13,10 +13,10 @@ #include #include "types/wlr_buffer.h" #include "types/wlr_scene.h" +#include "util/array.h" #include "util/time.h" #define HIGHLIGHT_DAMAGE_FADEOUT_TIME 250 -#define RENDER_LIST_MIN_ALLOCATION 8 static struct wlr_scene_tree *scene_tree_from_node(struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_TREE); @@ -1276,7 +1276,7 @@ void wlr_scene_output_destroy(struct wlr_scene_output *scene_output) { wl_list_remove(&scene_output->output_damage.link); wl_list_remove(&scene_output->output_needs_frame.link); - free(scene_output->render_list.data); + wl_array_release(&scene_output->render_list); free(scene_output); } @@ -1321,18 +1321,9 @@ static bool scene_node_invisible(struct wlr_scene_node *node) { return false; } -static size_t max(size_t fst, size_t snd) { - if (fst > snd) { - return fst; - } else { - return snd; - } -} - struct render_list_constructor_data { struct wlr_box box; - struct wlr_scene_output_render_list *render_list; - size_t size; + struct wl_array *render_list; }; static bool construct_render_list_iterator(struct wlr_scene_node *node, @@ -1367,22 +1358,11 @@ static bool construct_render_list_iterator(struct wlr_scene_node *node, pixman_region32_fini(&intersection); - if (data->size == data->render_list->capacity) { - size_t alloc_size = - max(data->render_list->capacity * 2, RENDER_LIST_MIN_ALLOCATION); - void *alloc = realloc(data->render_list->data, alloc_size - * sizeof(struct wlr_scene_node *)); - - if (alloc) { - data->render_list->data = alloc; - data->render_list->capacity = alloc_size; - } - } - - if (data->size < data->render_list->capacity) { - data->render_list->data[data->size++] = node; + struct wlr_scene_node **entry = wl_array_add(data->render_list, + sizeof(struct wlr_scene_node *)); + if (entry) { + *entry = node; } - return false; } @@ -1441,21 +1421,6 @@ static bool scene_node_try_direct_scanout(struct wlr_scene_node *node, return wlr_output_commit(output); } -static void compact_render_list(struct wlr_scene_output_render_list *list, size_t size) { - assert(size <= list->capacity); - - size_t alloc_size = max(RENDER_LIST_MIN_ALLOCATION, size); - if (alloc_size == list->capacity) { - return; - } - - void *alloc = realloc(list->data, alloc_size * sizeof(struct wlr_scene_node *)); - if (alloc) { - list->data = alloc; - list->capacity = alloc_size; - } -} - bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { struct wlr_output *output = scene_output->output; enum wlr_scene_debug_damage_option debug_damage = @@ -1467,20 +1432,23 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { struct render_list_constructor_data list_con = { .box = { .x = scene_output->x, .y = scene_output->y }, .render_list = &scene_output->render_list, - .size = 0, }; wlr_output_effective_resolution(output, &list_con.box.width, &list_con.box.height); + list_con.render_list->size = 0; scene_nodes_in_box(&scene_output->scene->tree.node, &list_con.box, construct_render_list_iterator, &list_con); - compact_render_list(list_con.render_list, list_con.size); + array_realloc(list_con.render_list, list_con.render_list->size); + + int list_len = list_con.render_list->size / sizeof(struct wlr_scene_node *); + struct wlr_scene_node **list_data = list_con.render_list->data; // if there is only one thing to render let's see if that thing can be // directly scanned out bool scanout = false; - if (list_con.size == 1) { - struct wlr_scene_node *node = list_con.render_list->data[0]; + if (list_len == 1) { + struct wlr_scene_node *node = list_data[0]; scanout = scene_node_try_direct_scanout(node, scene_output, &list_con.box); } @@ -1493,7 +1461,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { } if (scanout) { - struct wlr_scene_node *node = list_con.render_list->data[0]; + struct wlr_scene_node *node = list_data[0]; assert(node->type == WLR_SCENE_NODE_BUFFER); struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); @@ -1569,11 +1537,11 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { wlr_renderer_clear(renderer, (float[4]){ 0.0, 0.0, 0.0, 1.0 }); } - for (int i = list_con.size - 1; i >= 0; i--) { - struct wlr_scene_node *node = list_con.render_list->data[i]; + for (int i = list_len - 1; i >= 0; i--) { + struct wlr_scene_node *node = list_data[i]; scene_node_render(node, scene_output, &damage); } - + wlr_renderer_scissor(renderer, NULL); if (debug_damage == WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT) { -- cgit v1.2.3 From 4fd0b08bf3c3f2da2a1c89dd54f25553a43ea3a6 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Tue, 16 Aug 2022 07:03:22 -0400 Subject: wlr_scene: Simplify calculate_visibilty option --- wlr_scene.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 79701ab..ddd09a3 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -398,15 +398,13 @@ static bool scene_node_update_iterator(struct wlr_scene_node *node, struct wlr_box box = { .x = lx, .y = ly }; scene_node_get_size(node, &box.width, &box.height); + pixman_region32_subtract(&node->visible, &node->visible, data->update_region); + pixman_region32_union(&node->visible, &node->visible, data->visible); + pixman_region32_intersect_rect(&node->visible, &node->visible, + lx, ly, box.width, box.height); + if (data->calculate_visibility) { - pixman_region32_subtract(&node->visible, &node->visible, data->update_region); - pixman_region32_union(&node->visible, &node->visible, data->visible); - pixman_region32_intersect_rect(&node->visible, &node->visible, - lx, ly, box.width, box.height); scene_node_cull_hidden(node, lx, ly, data->visible); - } else { - pixman_region32_fini(&node->visible); - pixman_region32_init_rect(&node->visible, lx, ly, box.width, box.height); } update_node_update_outputs(node, data->outputs, NULL); -- cgit v1.2.3 From 59db20b014320e86bc047c81c8eae6511a10d09a Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Tue, 16 Aug 2022 07:06:17 -0400 Subject: wlr_scene: Only enable black rect optimization if culling is enabled If culling is not enabled, there is no longer any guarantee that the elements behind the rect won't be rendered. We must render the black rect in all circumstances to cover up anything rendered. This fixes the WLR_SCENE_DISABLE_VISIBILTY option. --- wlr_scene.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/wlr_scene.c b/wlr_scene.c index ddd09a3..5c14aa6 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -1322,6 +1322,7 @@ static bool scene_node_invisible(struct wlr_scene_node *node) { struct render_list_constructor_data { struct wlr_box box; struct wl_array *render_list; + bool calculate_visibility; }; static bool construct_render_list_iterator(struct wlr_scene_node *node, @@ -1335,7 +1336,7 @@ static bool construct_render_list_iterator(struct wlr_scene_node *node, // while rendering, the background should always be black. // If we see a black rect, we can ignore rendering everything under the rect // and even the rect itself. - if (node->type == WLR_SCENE_NODE_RECT) { + if (node->type == WLR_SCENE_NODE_RECT && data->calculate_visibility) { struct wlr_scene_rect *rect = scene_rect_from_node(node); float *black = (float[4]){ 0.f, 0.f, 0.f, 1.f }; @@ -1430,6 +1431,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { struct render_list_constructor_data list_con = { .box = { .x = scene_output->x, .y = scene_output->y }, .render_list = &scene_output->render_list, + .calculate_visibility = scene_output->scene->calculate_visibility, }; wlr_output_effective_resolution(output, &list_con.box.width, &list_con.box.height); -- cgit v1.2.3 From 7c4c11b222af34c7a571329d1a4f2895a54982e9 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Mon, 22 Aug 2022 10:17:59 -0400 Subject: wlr_scene: Cull background We don't need to worry about the black rect optimization here (that always assumes that there will be a black background) because the background is culled based on the render list. That means if a black rect is removed, the visibility will reach all the way to the bottom forcing the renderer to clear the area not breaking the assumption. --- wlr_scene.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/wlr_scene.c b/wlr_scene.c index 5c14aa6..c1d7569 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -1530,12 +1530,28 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { wlr_renderer_begin(renderer, output->width, output->height); + pixman_region32_t background; + pixman_region32_copy(&background, &damage); + + // Cull areas of the background that are occluded by opaque regions of + // scene nodes above. Those scene nodes will just render atop having us + // never see the background. + if (scene_output->scene->calculate_visibility) { + for (int i = list_len - 1; i >= 0; i--) { + struct wlr_scene_node *node = list_data[i]; + int x, y; + wlr_scene_node_coords(node, &x, &y); + scene_node_cull_hidden(node, x, y, &background); + } + } + int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); + pixman_box32_t *rects = pixman_region32_rectangles(&background, &nrects); for (int i = 0; i < nrects; ++i) { scissor_output(output, &rects[i]); wlr_renderer_clear(renderer, (float[4]){ 0.0, 0.0, 0.0, 1.0 }); } + pixman_region32_fini(&background); for (int i = list_len - 1; i >= 0; i--) { struct wlr_scene_node *node = list_data[i]; -- cgit v1.2.3 From 562a27cf62aee55b112d8b92436194d3df41102e Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Tue, 16 Aug 2022 08:17:13 -0400 Subject: wlr_scene: Improve awkward code style --- wlr_scene.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index c1d7569..a33ea1b 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -234,11 +234,9 @@ static bool _scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box case WLR_SCENE_NODE_BUFFER:; struct wlr_box node_box = { .x = lx, .y = ly }; scene_node_get_size(node, &node_box.width, &node_box.height); - bool intersects; - intersects = wlr_box_intersection(&node_box, &node_box, box); - - if (intersects && iterator(node, lx, ly, user_data)) { + if (wlr_box_intersection(&node_box, &node_box, box) && + iterator(node, lx, ly, user_data)) { return true; } break; -- cgit v1.2.3 From 682649f37b492a7f016890adaa41e5bf7682748a Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Fri, 19 Aug 2022 10:10:52 -0400 Subject: Use env helpers --- wlr_scene.c | 52 ++++++++++------------------------------------------ 1 file changed, 10 insertions(+), 42 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index a33ea1b..7541aff 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -14,6 +14,7 @@ #include "types/wlr_buffer.h" #include "types/wlr_scene.h" #include "util/array.h" +#include "util/env.h" #include "util/time.h" #define HIGHLIGHT_DAMAGE_FADEOUT_TIME 250 @@ -150,49 +151,16 @@ struct wlr_scene *wlr_scene_create(void) { wl_list_init(&scene->outputs); wl_list_init(&scene->presentation_destroy.link); - char *debug_damage = getenv("WLR_SCENE_DEBUG_DAMAGE"); - if (debug_damage) { - wlr_log(WLR_INFO, "Loading WLR_SCENE_DEBUG_DAMAGE option: %s", debug_damage); - } - - if (!debug_damage || strcmp(debug_damage, "none") == 0) { - scene->debug_damage_option = WLR_SCENE_DEBUG_DAMAGE_NONE; - } else if (strcmp(debug_damage, "rerender") == 0) { - scene->debug_damage_option = WLR_SCENE_DEBUG_DAMAGE_RERENDER; - } else if (strcmp(debug_damage, "highlight") == 0) { - scene->debug_damage_option = WLR_SCENE_DEBUG_DAMAGE_HIGHLIGHT; - } else { - wlr_log(WLR_ERROR, "Unknown WLR_SCENE_DEBUG_DAMAGE option: %s", debug_damage); - scene->debug_damage_option = WLR_SCENE_DEBUG_DAMAGE_NONE; - } - - char *disable_direct_scanout = getenv("WLR_SCENE_DISABLE_DIRECT_SCANOUT"); - if (disable_direct_scanout) { - wlr_log(WLR_INFO, "Loading WLR_SCENE_DISABLE_DIRECT_SCANOUT option: %s", disable_direct_scanout); - } - - if (!disable_direct_scanout || strcmp(disable_direct_scanout, "0") == 0) { - scene->direct_scanout = true; - } else if (strcmp(disable_direct_scanout, "1") == 0) { - scene->direct_scanout = false; - } else { - wlr_log(WLR_ERROR, "Unknown WLR_SCENE_DISABLE_DIRECT_SCANOUT option: %s", disable_direct_scanout); - scene->direct_scanout = true; - } - - char *visibility_disabled = getenv("WLR_SCENE_DISABLE_VISIBILITY"); - if (visibility_disabled) { - wlr_log(WLR_INFO, "Loading WLR_SCENE_DISABLE_VISIBILITY option: %s", visibility_disabled); - } + const char *debug_damage_options[] = { + "none", + "rerender", + "highlight", + NULL + }; - if (!visibility_disabled || strcmp(visibility_disabled, "0") == 0) { - scene->calculate_visibility = true; - } else if (strcmp(visibility_disabled, "1") == 0) { - scene->calculate_visibility = false; - } else { - wlr_log(WLR_ERROR, "Unknown WLR_SCENE_DISABLE_VISIBILITY option: %s", visibility_disabled); - scene->calculate_visibility = true; - } + scene->debug_damage_option = env_parse_switch("WLR_SCENE_DEBUG_DAMAGE", debug_damage_options); + scene->direct_scanout = !env_parse_bool("WLR_SCENE_DISABLE_DIRECT_SCANOUT"); + scene->calculate_visibility = !env_parse_bool("WLR_SCENE_DISABLE_VISIBILITY"); return scene; } -- cgit v1.2.3 From 304e0524e9cb2298acad1673656dd5c266c13817 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Mon, 22 Aug 2022 14:45:30 -0400 Subject: wlr_scene: Initialize region32 before trying to use it --- wlr_scene.c | 1 + 1 file changed, 1 insertion(+) diff --git a/wlr_scene.c b/wlr_scene.c index 7541aff..102e9e3 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -1497,6 +1497,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { wlr_renderer_begin(renderer, output->width, output->height); pixman_region32_t background; + pixman_region32_init(&background); pixman_region32_copy(&background, &damage); // Cull areas of the background that are occluded by opaque regions of -- cgit v1.2.3 From 50cec289e83c36924ecc1f3b10f5af68a5613405 Mon Sep 17 00:00:00 2001 From: yiqiang Date: Tue, 23 Aug 2022 15:44:26 +0800 Subject: scene/wlr_scene:fix judgment of invisible node --- wlr_scene.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 102e9e3..9516971 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -1272,10 +1272,9 @@ static bool scene_node_invisible(struct wlr_scene_node *node) { if (node->type == WLR_SCENE_NODE_TREE) { return true; } else if (node->type == WLR_SCENE_NODE_RECT) { - float *clear = (float[4]){ 0.f, 0.f, 0.f, 0.f }; struct wlr_scene_rect *rect = scene_rect_from_node(node); - return memcmp(rect->color, clear, sizeof(float) * 4) == 0; + return rect->color[3] == 0.f; } else if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); -- cgit v1.2.3 From d34a07994fac07c6c98c6c6c351743ab2655a90e Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Fri, 26 Aug 2022 19:07:52 -0400 Subject: wlr_scene: Only consider visible parts of the node when culling background Originally, I thought that we could safely subtract opaque regions from the background even if the black rect optimization was kicking in. This is wrong because a scene node that isn't fully occluded will still appear in the render list even if its partially under a black rect. We need to make sure that while culling the background, we only consider opaque regions that are also visible. This will fix the black rect optimization with the background. --- wlr_scene.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 9516971..5e5f800 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -221,8 +221,8 @@ static bool scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box, return _scene_nodes_in_box(node, box, iterator, user_data, x, y); } -static void scene_node_cull_hidden(struct wlr_scene_node *node, int x, int y, - pixman_region32_t *visible) { +static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y, + pixman_region32_t *opaque) { if (node->type == WLR_SCENE_NODE_RECT) { struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); if (scene_rect->color[3] != 1) { @@ -236,19 +236,16 @@ static void scene_node_cull_hidden(struct wlr_scene_node *node, int x, int y, } if (!buffer_is_opaque(scene_buffer->buffer)) { - pixman_region32_translate(visible, -x, -y); - pixman_region32_subtract(visible, visible, &scene_buffer->opaque_region); - pixman_region32_translate(visible, x, y); + pixman_region32_copy(opaque, &scene_buffer->opaque_region); + pixman_region32_translate(opaque, x, y); return; } } int width, height; scene_node_get_size(node, &width, &height); - pixman_region32_t opaque; - pixman_region32_init_rect(&opaque, x, y, width, height); - pixman_region32_subtract(visible, visible, &opaque); - pixman_region32_fini(&opaque); + pixman_region32_fini(opaque); + pixman_region32_init_rect(opaque, x, y, width, height); } struct scene_update_data { @@ -370,7 +367,11 @@ static bool scene_node_update_iterator(struct wlr_scene_node *node, lx, ly, box.width, box.height); if (data->calculate_visibility) { - scene_node_cull_hidden(node, lx, ly, data->visible); + pixman_region32_t opaque; + pixman_region32_init(&opaque); + scene_node_opaque_region(node, lx, ly, &opaque); + pixman_region32_subtract(data->visible, data->visible, &opaque); + pixman_region32_fini(&opaque); } update_node_update_outputs(node, data->outputs, NULL); @@ -1507,7 +1508,20 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { struct wlr_scene_node *node = list_data[i]; int x, y; wlr_scene_node_coords(node, &x, &y); - scene_node_cull_hidden(node, x, y, &background); + + // We must only cull opaque regions that are visible by the node. + // The node's visibility will have the knowledge of a black rect + // that may have been omitted from the render list via the black + // rect optimization. In order to ensure we don't cull background + // rendering in that black rect region, consider the node's visibility. + pixman_region32_t opaque; + pixman_region32_init(&opaque); + scene_node_opaque_region(node, x, y, &opaque); + pixman_region32_intersect(&opaque, &opaque, &node->visible); + + wlr_region_scale(&opaque, &opaque, scene_output->output->scale); + pixman_region32_subtract(&background, &background, &opaque); + pixman_region32_fini(&opaque); } } -- cgit v1.2.3 From fdd43fdd8eb777d6140e235db228713fca17fff7 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sun, 28 Aug 2022 11:01:19 -0400 Subject: wlr_scene: More sanity checking The render list should neither contain scene trees or null buffers. --- wlr_scene.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 5e5f800..3088db7 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -1043,7 +1043,7 @@ static void scene_node_render(struct wlr_scene_node *node, enum wl_output_transform transform; switch (node->type) { case WLR_SCENE_NODE_TREE: - /* Root or tree node has nothing to render itself */ + assert(false); break; case WLR_SCENE_NODE_RECT:; struct wlr_scene_rect *scene_rect = scene_rect_from_node(node); @@ -1053,9 +1053,7 @@ static void scene_node_render(struct wlr_scene_node *node, break; case WLR_SCENE_NODE_BUFFER:; struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); - if (!scene_buffer->buffer) { - return; - } + assert(scene_buffer->buffer); struct wlr_renderer *renderer = output->renderer; texture = scene_buffer_get_texture(scene_buffer, renderer); -- cgit v1.2.3 From 0af47bbd8801e193199a023b6c7daef9a5d4b6de Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 27 Aug 2022 20:35:18 -0400 Subject: wlr_scene: Don't leak a region32 when texture failed to upload --- wlr_scene.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wlr_scene.c b/wlr_scene.c index 3088db7..d963e70 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -1058,7 +1058,7 @@ static void scene_node_render(struct wlr_scene_node *node, struct wlr_renderer *renderer = output->renderer; texture = scene_buffer_get_texture(scene_buffer, renderer); if (texture == NULL) { - return; + break; } transform = wlr_output_transform_invert(scene_buffer->transform); -- cgit v1.2.3 From 2bb4dfef5a9baeef5fc2e9fd4e2046cf514c9ab3 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 3 Sep 2022 18:39:16 -0400 Subject: wlr_scene: Consider screen position when culling background --- wlr_scene.c | 1 + 1 file changed, 1 insertion(+) diff --git a/wlr_scene.c b/wlr_scene.c index d963e70..dff664d 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -1517,6 +1517,7 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { scene_node_opaque_region(node, x, y, &opaque); pixman_region32_intersect(&opaque, &opaque, &node->visible); + pixman_region32_translate(&opaque, -scene_output->x, -scene_output->y); wlr_region_scale(&opaque, &opaque, scene_output->output->scale); pixman_region32_subtract(&background, &background, &opaque); pixman_region32_fini(&opaque); -- cgit v1.2.3 From 096de5d937149d86d1fc1e724b82c49a18215a15 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 3 Sep 2022 16:20:39 -0400 Subject: wlr_scene: Clarify surface commit frame events --- surface.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/surface.c b/surface.c index b122d21..f8bb553 100644 --- a/surface.c +++ b/surface.c @@ -84,10 +84,11 @@ static void handle_scene_surface_surface_commit( set_buffer_with_surface_state(scene_buffer, surface->surface); - // Even if the surface hasn't submitted damage, schedule a new frame if - // the client has requested a wl_surface.frame callback. Check if the node - // is visible. If not, the client will never receive a frame_done event - // anyway so it doesn't make sense to schedule here. + // If the surface has requested a frame done event, honour that. The + // frame_callback_list will be populated in this case. We should only + // schedule the frame however if the node is enabled and there is an + // output intersecting, otherwise the frame done events would never reach + // the surface anyway. int lx, ly; bool enabled = wlr_scene_node_coords(&scene_buffer->node, &lx, &ly); -- cgit v1.2.3 From 8e19a9e3e4e2c7340706c89071d0c8dfb57717d1 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Tue, 27 Sep 2022 20:07:08 -0400 Subject: wlr_scene: Be resilient against overflow conditions If the area calculations for output overlap overflow a signed int, we may not consider it to be a primary output. Turn this into an unsigned type so this happens less frequently. Additionally, it is possible the overflow would produce 0, we can handle this by simply changing the comparison to more than or equal. While we're here, let's assert that we always assign a primary output if there are any intersecting outputs. --- wlr_scene.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index dff664d..89aae84 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -296,7 +296,7 @@ static void update_node_update_outputs(struct wlr_scene_node *node, struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); - int largest_overlap = 0; + uint32_t largest_overlap = 0; scene_buffer->primary_output = NULL; uint64_t active_outputs = 0; @@ -326,8 +326,8 @@ static void update_node_update_outputs(struct wlr_scene_node *node, output_box.x, output_box.y, output_box.width, output_box.height); if (pixman_region32_not_empty(&intersection)) { - int overlap = region_area(&intersection); - if (overlap > largest_overlap) { + uint32_t overlap = region_area(&intersection); + if (overlap >= largest_overlap) { largest_overlap = overlap; scene_buffer->primary_output = scene_output; } @@ -352,6 +352,10 @@ static void update_node_update_outputs(struct wlr_scene_node *node, wl_signal_emit_mutable(&scene_buffer->events.output_leave, scene_output); } } + + // if there are active outputs on this node, we should always have a primary + // output + assert(!scene_buffer->active_outputs || scene_buffer->primary_output); } static bool scene_node_update_iterator(struct wlr_scene_node *node, -- cgit v1.2.3 From b16a406077498a832d39e0d0df052f9eebf12624 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Fri, 7 Oct 2022 11:31:07 -0400 Subject: wlr_scene: Fix not updating the scene node when setting a new buffer If a new buffer is set for a buffer node, we must update the entire node unconditionally if the buffer size changes, or the buffer is given a buffer where it was previously NULL. While we're here, let's avoid calling scene_node_update on just damage updates. If the caller hasn't given us a damage region we just assume the whole buffer. --- wlr_scene.c | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 89aae84..3f662ce 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -552,23 +552,32 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff // coordinates. assert(buffer || !damage); - if (buffer != scene_buffer->buffer) { - wlr_texture_destroy(scene_buffer->texture); - scene_buffer->texture = NULL; - wlr_buffer_unlock(scene_buffer->buffer); + if (buffer == scene_buffer->buffer) { + return; + } - if (buffer) { - scene_buffer->buffer = wlr_buffer_lock(buffer); - } else { - scene_buffer->buffer = NULL; - } + bool update = false; + wlr_buffer_unlock(scene_buffer->buffer); - if (!damage) { - scene_node_update(&scene_buffer->node, NULL); - } + if (buffer) { + // if this node used to not be mapped or its previous displayed + // buffer region will be different from what the new buffer would + // produce we need to update the node. + update = !scene_buffer->buffer || + (scene_buffer->dst_width == 0 && scene_buffer->dst_height == 0 && + (scene_buffer->buffer->width != buffer->width || + scene_buffer->buffer->height != buffer->height)); + + scene_buffer->buffer = wlr_buffer_lock(buffer); + } else { + update = true; + scene_buffer->buffer = NULL; } - if (!damage) { + if (update) { + scene_node_update(&scene_buffer->node, NULL); + // updating the node will already damage the whole node for us. Return + // early to not damage again return; } @@ -577,6 +586,12 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff return; } + pixman_region32_t fallback_damage; + pixman_region32_init_rect(&fallback_damage, 0, 0, buffer->width, buffer->height); + if (!damage) { + damage = &fallback_damage; + } + struct wlr_fbox box = scene_buffer->src_box; if (wlr_fbox_empty(&box)) { box.x = 0; @@ -633,6 +648,7 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff } pixman_region32_fini(&trans_damage); + pixman_region32_fini(&fallback_damage); } void wlr_scene_buffer_set_buffer(struct wlr_scene_buffer *scene_buffer, -- cgit v1.2.3 From d1d9c3f3d1393265337fbd87d5b6b44e839def37 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 1 Oct 2022 20:38:06 -0400 Subject: wlr_scene: Ignore disabled outputs --- wlr_scene.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/wlr_scene.c b/wlr_scene.c index 3f662ce..872e0ed 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -313,6 +313,10 @@ static void update_node_update_outputs(struct wlr_scene_node *node, continue; } + if (!scene_output->output->enabled) { + continue; + } + struct wlr_box output_box = { .x = scene_output->x, .y = scene_output->y, @@ -1154,7 +1158,8 @@ static void scene_output_handle_commit(struct wl_listener *listener, void *data) if (event->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM | - WLR_OUTPUT_STATE_SCALE)) { + WLR_OUTPUT_STATE_SCALE | + WLR_OUTPUT_STATE_ENABLED)) { scene_output_update_geometry(scene_output); } } -- cgit v1.2.3 From bd311bdd570f705019035d2f666c0e4b8a7d0329 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 6 Oct 2022 15:40:50 -0400 Subject: wlr_scene: Apply source box translation --- wlr_scene.c | 1 + 1 file changed, 1 insertion(+) diff --git a/wlr_scene.c b/wlr_scene.c index 872e0ed..f786ca9 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -625,6 +625,7 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff scene_buffer->transform, buffer->width, buffer->height); pixman_region32_intersect_rect(&trans_damage, &trans_damage, box.x, box.y, box.width, box.height); + pixman_region32_translate(&trans_damage, -box.x, -box.y); struct wlr_scene *scene = scene_node_get_root(&scene_buffer->node); struct wlr_scene_output *scene_output; -- cgit v1.2.3 From f5f83652b274683ecc8fd84f87fb768236d2733e Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Thu, 13 Oct 2022 12:10:23 -0400 Subject: wlr_scene: use wl_container_of() instead of casts --- wlr_scene.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index f786ca9..9c274f3 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -21,19 +21,22 @@ static struct wlr_scene_tree *scene_tree_from_node(struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_TREE); - return (struct wlr_scene_tree *)node; + struct wlr_scene_tree *tree = wl_container_of(node, tree, node); + return tree; } static struct wlr_scene_rect *scene_rect_from_node( struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_RECT); - return (struct wlr_scene_rect *)node; + struct wlr_scene_rect *rect = wl_container_of(node, rect, node); + return rect; } struct wlr_scene_buffer *wlr_scene_buffer_from_node( struct wlr_scene_node *node) { assert(node->type == WLR_SCENE_NODE_BUFFER); - return (struct wlr_scene_buffer *)node; + struct wlr_scene_buffer *buffer = wl_container_of(node, buffer, node); + return buffer; } struct wlr_scene *scene_node_get_root(struct wlr_scene_node *node) { -- cgit v1.2.3 From 5d41344ec0f3369732fd4e5d75d8ac8d2d867fe6 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Fri, 14 Oct 2022 14:30:44 -0400 Subject: wlr_scene: Destroy the texture when setting a new buffer. Fixes: https://github.com/labwc/labwc/issues/587 Fixes: f0e31e806f7cb88c9d55dc0eb1876c86600d28df (wlr_scene: Fix not updating the scene node when setting a new buffer) --- wlr_scene.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wlr_scene.c b/wlr_scene.c index 9c274f3..c5c301a 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -566,6 +566,9 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff bool update = false; wlr_buffer_unlock(scene_buffer->buffer); + wlr_texture_destroy(scene_buffer->texture); + scene_buffer->texture = NULL; + if (buffer) { // if this node used to not be mapped or its previous displayed // buffer region will be different from what the new buffer would -- cgit v1.2.3 From 06aea43a1d277263438057132998896785163f90 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sun, 16 Oct 2022 20:14:01 -0400 Subject: wlr_scene: Handle fractional scaling better Try to alleviate scaling inaccuracies by implementing a fudge factor. --- wlr_scene.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index c5c301a..69d6f4a 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -270,6 +270,14 @@ static uint32_t region_area(pixman_region32_t *region) { return area; } +static void scale_output_damage(pixman_region32_t *damage, float scale) { + wlr_region_scale(damage, damage, scale); + + if (floor(scale) != scale) { + wlr_region_expand(damage, damage, 1); + } +} + static void scene_damage_outputs(struct wlr_scene *scene, pixman_region32_t *damage) { if (!pixman_region32_not_empty(damage)) { return; @@ -282,8 +290,7 @@ static void scene_damage_outputs(struct wlr_scene *scene, pixman_region32_t *dam pixman_region32_copy(&output_damage, damage); pixman_region32_translate(&output_damage, -scene_output->x, -scene_output->y); - wlr_region_scale(&output_damage, &output_damage, - scene_output->output->scale); + scale_output_damage(&output_damage, scene_output->output->scale); if (wlr_damage_ring_add(&scene_output->damage_ring, &output_damage)) { wlr_output_schedule_frame(scene_output->output); } @@ -649,6 +656,11 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff pixman_region32_intersect(&output_damage, &output_damage, &cull_region); pixman_region32_fini(&cull_region); + // if we are using fractional scaling add a 1px margin. + if (floor(output_scale) != output_scale) { + wlr_region_expand(&output_damage, &output_damage, 1); + } + pixman_region32_translate(&output_damage, (lx - scene_output->x) * output_scale, (ly - scene_output->y) * output_scale); @@ -1055,7 +1067,7 @@ static void scene_node_render(struct wlr_scene_node *node, pixman_region32_init(&render_region); pixman_region32_copy(&render_region, &node->visible); pixman_region32_translate(&render_region, -scene_output->x, -scene_output->y); - wlr_region_scale(&render_region, &render_region, output->scale); + scale_output_damage(&render_region, output->scale); pixman_region32_intersect(&render_region, &render_region, damage); if (!pixman_region32_not_empty(&render_region)) { pixman_region32_fini(&render_region); @@ -1534,6 +1546,8 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { // scene nodes above. Those scene nodes will just render atop having us // never see the background. if (scene_output->scene->calculate_visibility) { + float output_scale = scene_output->output->scale; + for (int i = list_len - 1; i >= 0; i--) { struct wlr_scene_node *node = list_data[i]; int x, y; @@ -1550,10 +1564,18 @@ bool wlr_scene_output_commit(struct wlr_scene_output *scene_output) { pixman_region32_intersect(&opaque, &opaque, &node->visible); pixman_region32_translate(&opaque, -scene_output->x, -scene_output->y); - wlr_region_scale(&opaque, &opaque, scene_output->output->scale); + wlr_region_scale(&opaque, &opaque, output_scale); pixman_region32_subtract(&background, &background, &opaque); pixman_region32_fini(&opaque); } + + if (floor(output_scale) != output_scale) { + wlr_region_expand(&background, &background, 1); + + // reintersect with the damage because we never want to render + // outside of the damage region + pixman_region32_intersect(&background, &background, &damage); + } } int nrects; -- cgit v1.2.3 From 0500183cfa49ff289487a81a511a847ab25f407a Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 5 Nov 2022 13:34:29 +0300 Subject: scene: fix buffer source box transforming --- wlr_scene.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 69d6f4a..c0be855 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -613,16 +613,13 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff if (wlr_fbox_empty(&box)) { box.x = 0; box.y = 0; - - if (scene_buffer->transform & WL_OUTPUT_TRANSFORM_90) { - box.width = buffer->height; - box.height = buffer->width; - } else { - box.width = buffer->width; - box.height = buffer->height; - } + box.width = buffer->width; + box.height = buffer->height; } + wlr_fbox_transform(&box, &box, scene_buffer->transform, + buffer->width, buffer->height); + double scale_x, scale_y; if (scene_buffer->dst_width || scene_buffer->dst_height) { scale_x = scene_buffer->dst_width / box.width; -- cgit v1.2.3 From 6b14907312f96eae3b84fe5b2039c94b6d226973 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sun, 6 Nov 2022 20:53:42 +0300 Subject: scene: fix output damage expansion This fixes e.g. `weston-simple-damage --use-viewport` which technically renders at the buffer scale of 0.5. --- wlr_scene.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index c0be855..4754b0e 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -620,7 +620,7 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff wlr_fbox_transform(&box, &box, scene_buffer->transform, buffer->width, buffer->height); - double scale_x, scale_y; + float scale_x, scale_y; if (scene_buffer->dst_width || scene_buffer->dst_height) { scale_x = scene_buffer->dst_width / box.width; scale_y = scene_buffer->dst_height / box.height; @@ -641,10 +641,24 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff struct wlr_scene_output *scene_output; wl_list_for_each(scene_output, &scene->outputs, link) { float output_scale = scene_output->output->scale; + float output_scale_x = output_scale * scale_x; + float output_scale_y = output_scale * scale_y; pixman_region32_t output_damage; pixman_region32_init(&output_damage); wlr_region_scale_xy(&output_damage, &trans_damage, - output_scale * scale_x, output_scale * scale_y); + output_scale_x, output_scale_y); + + // One buffer pixel will match (output_scale_x)x(output_scale_y) output + // pixels. If max(output_scale_x, output_scale_y) is bigger than 1, + // the result will be blurry, and with linear filtering, will bleed into + // adjacent (output_scale_x / 2) pixels on X axis and (output_scale_y / 2) + // pixels on Y axis. To fix this, the damage region is expanded by largest + // distance of the two. + float bigger_scale = fmaxf(output_scale_x, output_scale_y); + if (bigger_scale > 1.0f) { + wlr_region_expand(&output_damage, &output_damage, + ceilf(bigger_scale / 2.0f)); + } pixman_region32_t cull_region; pixman_region32_init(&cull_region); @@ -653,11 +667,6 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff pixman_region32_intersect(&output_damage, &output_damage, &cull_region); pixman_region32_fini(&cull_region); - // if we are using fractional scaling add a 1px margin. - if (floor(output_scale) != output_scale) { - wlr_region_expand(&output_damage, &output_damage, 1); - } - pixman_region32_translate(&output_damage, (lx - scene_output->x) * output_scale, (ly - scene_output->y) * output_scale); -- cgit v1.2.3 From 13330063c46f6f3261b72d5b268a1cb5f503a90c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 8 Nov 2022 17:43:41 +0100 Subject: scene: fix whitespace --- wlr_scene.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 4754b0e..1be2d13 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -185,7 +185,7 @@ static void scene_node_get_size(struct wlr_scene_node *node, int *lx, int *ly); typedef bool (*scene_node_box_iterator_func_t)(struct wlr_scene_node *node, int sx, int sy, void *data); -static bool _scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box, +static bool _scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box, scene_node_box_iterator_func_t iterator, void *user_data, int lx, int ly) { if (!node->enabled) { return false; @@ -216,7 +216,7 @@ static bool _scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box return false; } -static bool scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box, +static bool scene_nodes_in_box(struct wlr_scene_node *node, struct wlr_box *box, scene_node_box_iterator_func_t iterator, void *user_data) { int x, y; wlr_scene_node_coords(node, &x, &y); @@ -348,7 +348,7 @@ static void update_node_update_outputs(struct wlr_scene_node *node, active_outputs |= 1ull << scene_output->index; } - + pixman_region32_fini(&intersection); } @@ -563,7 +563,7 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff struct wlr_buffer *buffer, pixman_region32_t *damage) { // specifying a region for a NULL buffer doesn't make sense. We need to know // about the buffer to scale the buffer local coordinates down to scene - // coordinates. + // coordinates. assert(buffer || !damage); if (buffer == scene_buffer->buffer) { -- cgit v1.2.3 From a71111fdea69b3134b33fce899149ade274a8232 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 8 Nov 2022 17:43:49 +0100 Subject: scene: destroy addons before cleaning up internal state This allows addons to access wlr_scene_node/wlr_scene_surface fields to clean up themselves. --- wlr_scene.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wlr_scene.c b/wlr_scene.c index 1be2d13..0eed588 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -87,6 +87,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { // in case the destroy signal would like to remove children before they // are recursively destroyed. wl_signal_emit_mutable(&node->events.destroy, NULL); + wlr_addon_set_finish(&node->addons); wlr_scene_node_set_enabled(node, false); @@ -130,7 +131,6 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { } } - wlr_addon_set_finish(&node->addons); wl_list_remove(&node->link); pixman_region32_fini(&node->visible); free(node); -- cgit v1.2.3 From 30b8729a52b0af02fa079f2e98f8ebb3ec10ddf5 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Tue, 8 Nov 2022 11:55:05 -0500 Subject: wlr_scene: Fix texture reuse Add private interface to ignore a buffer that's locking a client_buffer for damage tracking. This should eventually be replaced by wlr_raster. --- surface.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/surface.c b/surface.c index f8bb553..553cc42 100644 --- a/surface.c +++ b/surface.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -55,6 +56,28 @@ static void scene_surface_handle_surface_destroy( wlr_scene_node_destroy(&surface->buffer->node); } +// This is used for wlr_scene where it unconditionally locks buffers preventing +// reuse of the existing texture for shm clients. With the usage pattern of +// wlr_scene surface handling, we can mark its locked buffer as safe +// for mutation. +static void client_buffer_mark_next_can_damage(struct wlr_client_buffer *buffer) { + buffer->n_ignore_locks++; +} + +static void scene_buffer_unmark_client_buffer(struct wlr_scene_buffer *scene_buffer) { + if (!scene_buffer->buffer) { + return; + } + + struct wlr_client_buffer *buffer = wlr_client_buffer_get(scene_buffer->buffer); + if (!buffer) { + return; + } + + assert(buffer->n_ignore_locks > 0); + buffer->n_ignore_locks--; +} + static void set_buffer_with_surface_state(struct wlr_scene_buffer *scene_buffer, struct wlr_surface *surface) { struct wlr_surface_state *state = &surface->current; @@ -68,7 +91,11 @@ static void set_buffer_with_surface_state(struct wlr_scene_buffer *scene_buffer, wlr_scene_buffer_set_dest_size(scene_buffer, state->width, state->height); wlr_scene_buffer_set_transform(scene_buffer, state->transform); + scene_buffer_unmark_client_buffer(scene_buffer); + if (surface->buffer) { + client_buffer_mark_next_can_damage(surface->buffer); + wlr_scene_buffer_set_buffer_with_damage(scene_buffer, &surface->buffer->base, &surface->buffer_damage); } else { @@ -109,6 +136,8 @@ static bool scene_buffer_point_accepts_input(struct wlr_scene_buffer *scene_buff static void surface_addon_destroy(struct wlr_addon *addon) { struct wlr_scene_surface *surface = wl_container_of(addon, surface, addon); + scene_buffer_unmark_client_buffer(surface->buffer); + wlr_addon_finish(&surface->addon); wl_list_remove(&surface->output_enter.link); -- cgit v1.2.3 From bc4f884e01c957022991eff299e07972ea3f56d5 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Fri, 11 Nov 2022 10:22:26 -0500 Subject: wlr_scene: Remove duplicate buffer check when submitting a new buffer wlr_buffer allows mutation during its lifetime. This happens for wlr_client_buffer which fixes damage tracking issues. --- wlr_scene.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 0eed588..79855f0 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -566,10 +566,6 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff // coordinates. assert(buffer || !damage); - if (buffer == scene_buffer->buffer) { - return; - } - bool update = false; wlr_buffer_unlock(scene_buffer->buffer); -- cgit v1.2.3 From 946cc0d426f21d13313076ef02b258bce10c032d Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Sat, 26 Nov 2022 17:18:33 +0000 Subject: scene/layer_shell_v1.c: set exclusive zone correctly ...when only one edge is anchored. The layer-shell protocol specifies that a positive exclusive-zone value is 'meaningful' if the surface is anchored to either: 1. one edge 2. one edge and both perpendicular edges. For example, if you wish to position a layer-shell client along the top edge and make it exclusive, you should be able to either set anchor=TOP or anchor=TOP|LEFT|RIGHT. It appears that many panels/bars use the latter approach (anchor to an edge and also both perpendicular edges) which is probably why this has not been reported previously. This patch adds support for the first case and thereby makes exclusive zone behaviour consistent with the protocol and also with sway's extant layer-shell implementation. (cherry picked from commit 8e80432a72b18a1ddbacdb08ff0c41645578f1ee) --- layer_shell_v1.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/layer_shell_v1.c b/layer_shell_v1.c index 2298698..e523d31 100644 --- a/layer_shell_v1.c +++ b/layer_shell_v1.c @@ -39,6 +39,7 @@ static void layer_surface_exclusive_zone( struct wlr_layer_surface_v1_state *state, struct wlr_box *usable_area) { switch (state->anchor) { + case ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP: case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT): @@ -46,12 +47,14 @@ static void layer_surface_exclusive_zone( usable_area->y += state->exclusive_zone + state->margin.top; usable_area->height -= state->exclusive_zone + state->margin.top; break; + case ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM: case (ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT): // Anchor bottom usable_area->height -= state->exclusive_zone + state->margin.bottom; break; + case ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT: case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT): @@ -59,6 +62,7 @@ static void layer_surface_exclusive_zone( usable_area->x += state->exclusive_zone + state->margin.left; usable_area->width -= state->exclusive_zone + state->margin.left; break; + case ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT: case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT): // Anchor right -- cgit v1.2.3 From 7ad3682d1d3701dab66f16e26a6e6cc7b14cac7d Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Sat, 26 Nov 2022 17:23:51 +0000 Subject: scene/layer_shell_v1.c: remove redundant comment (cherry picked from commit 338e0a3976f2bad5ec048b022648a671ed443b4f) --- layer_shell_v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layer_shell_v1.c b/layer_shell_v1.c index e523d31..3ed616a 100644 --- a/layer_shell_v1.c +++ b/layer_shell_v1.c @@ -65,7 +65,7 @@ static void layer_surface_exclusive_zone( case ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT: case (ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT): // Anchor right + ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT): // Anchor right usable_area->width -= state->exclusive_zone + state->margin.right; break; -- cgit v1.2.3 From 4e434ad5fccef7b6c4fff86661b22db196cc99a4 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sun, 27 Nov 2022 12:41:22 +0300 Subject: scene: fix output damage expansion condition Now, it is checked whether an output pixel corresponds to an integer number of buffer pixels; if it doesn't, the region is altered to take this into account. (cherry picked from commit 5477ad7d9079c59d64fed9acb98ccccebc24af93) --- wlr_scene.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/wlr_scene.c b/wlr_scene.c index 79855f0..08f269d 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -644,17 +644,24 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff wlr_region_scale_xy(&output_damage, &trans_damage, output_scale_x, output_scale_y); - // One buffer pixel will match (output_scale_x)x(output_scale_y) output - // pixels. If max(output_scale_x, output_scale_y) is bigger than 1, - // the result will be blurry, and with linear filtering, will bleed into - // adjacent (output_scale_x / 2) pixels on X axis and (output_scale_y / 2) - // pixels on Y axis. To fix this, the damage region is expanded by largest - // distance of the two. - float bigger_scale = fmaxf(output_scale_x, output_scale_y); - if (bigger_scale > 1.0f) { - wlr_region_expand(&output_damage, &output_damage, - ceilf(bigger_scale / 2.0f)); - } + // One output pixel will match (buffer_scale_x)x(buffer_scale_y) buffer pixels. + // If the buffer is upscaled on the given axis (output_scale_* > 1.0, + // buffer_scale_* < 1.0), its contents will bleed into adjacent + // (ceil(output_scale_* / 2)) output pixels because of linear filtering. + // Additionally, if the buffer is downscaled (output_scale_* < 1.0, + // buffer_scale_* > 1.0), and one output pixel matches a non-integer number of + // buffer pixels, its contents will bleed into neighboring output pixels. + // Handle both cases by computing buffer_scale_{x,y} and checking if they are + // integer numbers; ceilf() is used to ensure that the distance is at least 1. + float buffer_scale_x = 1.0f / output_scale_x; + float buffer_scale_y = 1.0f / output_scale_y; + int dist_x = floor(buffer_scale_x) != buffer_scale_x ? + (int)ceilf(output_scale_x / 2.0f) : 0; + int dist_y = floor(buffer_scale_y) != buffer_scale_y ? + (int)ceilf(output_scale_y / 2.0f) : 0; + // TODO: expand with per-axis distances + wlr_region_expand(&output_damage, &output_damage, + dist_x >= dist_y ? dist_x : dist_y); pixman_region32_t cull_region; pixman_region32_init(&cull_region); -- cgit v1.2.3 From 43b5ef7c24123234d2102d11d0344caff4da5dec Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Sat, 26 Nov 2022 21:01:24 -0500 Subject: wlr_scene: Expand damage cull region with fractional scales (cherry picked from commit 32d00984e19b494c1f9fb04d6064777bc42ed943) --- wlr_scene.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wlr_scene.c b/wlr_scene.c index 08f269d..eb1ce3e 100644 --- a/wlr_scene.c +++ b/wlr_scene.c @@ -665,7 +665,8 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff pixman_region32_t cull_region; pixman_region32_init(&cull_region); - wlr_region_scale(&cull_region, &scene_buffer->node.visible, output_scale); + pixman_region32_copy(&cull_region, &scene_buffer->node.visible); + scale_output_damage(&cull_region, output_scale); pixman_region32_translate(&cull_region, -lx * output_scale, -ly * output_scale); pixman_region32_intersect(&output_damage, &output_damage, &cull_region); pixman_region32_fini(&cull_region); -- cgit v1.2.3