From 0a8e8aec581c2ef6e2ee948d5212352264f3fc6c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 11 Apr 2023 21:51:14 +0200 Subject: [PATCH 1/3] scene: make wlr_scene_buffer release buffers Make wlr_scene_buffer release buffers as soon as it doesn't need them anymore. This allows the caller to re-use the buffer. --- include/wlr/types/wlr_scene.h | 2 + types/scene/wlr_scene.c | 76 +++++++++++++++++++++++++---------- 2 files changed, 56 insertions(+), 22 deletions(-) diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index b6f0d2175..aca8a2b8b 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -173,6 +173,8 @@ struct wlr_scene_buffer { enum wl_output_transform transform; pixman_region32_t opaque_region; struct wlr_linux_dmabuf_feedback_v1_init_options prev_feedback_options; + bool buffer_locked; + struct wl_listener buffer_release; }; /** A viewport for an output in the scene-graph */ diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index c33461f17..1e319276a 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -108,7 +108,10 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { } wlr_texture_destroy(scene_buffer->texture); - wlr_buffer_unlock(scene_buffer->buffer); + if (scene_buffer->buffer_locked) { + wlr_buffer_unlock(scene_buffer->buffer); + } + wl_list_remove(&scene_buffer->buffer_release.link); 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); @@ -237,11 +240,11 @@ static void scene_node_opaque_region(struct wlr_scene_node *node, int x, int y, } else if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node); - if (!scene_buffer->buffer) { + if (!scene_buffer->buffer && !scene_buffer->texture) { return; } - if (!buffer_is_opaque(scene_buffer->buffer)) { + if (!scene_buffer->buffer || !buffer_is_opaque(scene_buffer->buffer)) { pixman_region32_copy(opaque, &scene_buffer->opaque_region); pixman_region32_translate(opaque, x, y); return; @@ -578,9 +581,7 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, assert(parent); scene_node_init(&scene_buffer->node, WLR_SCENE_NODE_BUFFER, parent); - if (buffer) { - scene_buffer->buffer = wlr_buffer_lock(buffer); - } + wl_list_init(&scene_buffer->buffer_release.link); wl_signal_init(&scene_buffer->events.outputs_update); wl_signal_init(&scene_buffer->events.output_enter); @@ -589,11 +590,20 @@ struct wlr_scene_buffer *wlr_scene_buffer_create(struct wlr_scene_tree *parent, wl_signal_init(&scene_buffer->events.frame_done); pixman_region32_init(&scene_buffer->opaque_region); + wlr_scene_buffer_set_buffer(scene_buffer, buffer); scene_node_update(&scene_buffer->node, NULL); return scene_buffer; } +static void scene_buffer_handle_release(struct wl_listener *listener, void *data) { + struct wlr_scene_buffer *scene_buffer = + wl_container_of(listener, scene_buffer, buffer_release); + wl_list_remove(&scene_buffer->buffer_release.link); + wl_list_init(&scene_buffer->buffer_release.link); + scene_buffer->buffer = NULL; +} + void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buffer, struct wlr_buffer *buffer, const pixman_region32_t *damage) { // specifying a region for a NULL buffer doesn't make sense. We need to know @@ -601,12 +611,18 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff // coordinates. assert(buffer || !damage); - bool update = false; - wlr_buffer_unlock(scene_buffer->buffer); + wl_list_remove(&scene_buffer->buffer_release.link); + wl_list_init(&scene_buffer->buffer_release.link); + if (scene_buffer->buffer_locked) { + wlr_buffer_unlock(scene_buffer->buffer); + } + scene_buffer->buffer = NULL; + scene_buffer->buffer_locked = false; wlr_texture_destroy(scene_buffer->texture); scene_buffer->texture = NULL; + bool update = false; 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 @@ -617,9 +633,11 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff scene_buffer->buffer->height != buffer->height)); scene_buffer->buffer = wlr_buffer_lock(buffer); + scene_buffer->buffer_locked = true; + scene_buffer->buffer_release.notify = scene_buffer_handle_release; + wl_signal_add(&buffer->events.release, &scene_buffer->buffer_release); } else { update = true; - scene_buffer->buffer = NULL; } if (update) { @@ -781,18 +799,24 @@ void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer, static struct wlr_texture *scene_buffer_get_texture( struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) { + if (scene_buffer->texture != NULL) { + return scene_buffer->texture; + } + + if (!scene_buffer->buffer_locked) { + return NULL; + } + 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); + wlr_buffer_unlock(scene_buffer->buffer); + scene_buffer->buffer_locked = false; return scene_buffer->texture; } @@ -814,13 +838,22 @@ 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 if (scene_buffer->buffer) { - if (scene_buffer->transform & WL_OUTPUT_TRANSFORM_90) { - *height = scene_buffer->buffer->width; - *width = scene_buffer->buffer->height; + } else if (scene_buffer->buffer || scene_buffer->texture) { + int w, h; + if (scene_buffer->buffer) { + w = scene_buffer->buffer->width; + h = scene_buffer->buffer->height; } else { - *width = scene_buffer->buffer->width; - *height = scene_buffer->buffer->height; + w = scene_buffer->texture->width; + h = scene_buffer->texture->height; + } + + if (scene_buffer->transform & WL_OUTPUT_TRANSFORM_90) { + *height = w; + *width = h; + } else { + *width = w; + *height = h; } } break; @@ -1141,7 +1174,6 @@ 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); - assert(scene_buffer->buffer); struct wlr_renderer *renderer = output->renderer; texture = scene_buffer_get_texture(scene_buffer, renderer); @@ -1373,7 +1405,7 @@ static bool scene_node_invisible(struct wlr_scene_node *node) { } else if (node->type == WLR_SCENE_NODE_BUFFER) { struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node); - return buffer->buffer == NULL; + return buffer->buffer == NULL && buffer->texture == NULL; } return false; @@ -1486,7 +1518,7 @@ static bool scene_buffer_can_consider_direct_scanout(struct wlr_scene_buffer *bu return false; } - if (node->type != WLR_SCENE_NODE_BUFFER) { + if (node->type != WLR_SCENE_NODE_BUFFER || buffer->buffer == NULL) { return false; } From dd0e70af5dcb91586327fea31684cb3a73087544 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 11 Apr 2023 22:07:39 +0200 Subject: [PATCH 2/3] scene: update textures with damage --- include/wlr/types/wlr_scene.h | 2 +- types/scene/wlr_scene.c | 31 +++++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index aca8a2b8b..efbbfcc1c 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -171,7 +171,7 @@ struct wlr_scene_buffer { struct wlr_fbox src_box; int dst_width, dst_height; enum wl_output_transform transform; - pixman_region32_t opaque_region; + pixman_region32_t damage, opaque_region; struct wlr_linux_dmabuf_feedback_v1_init_options prev_feedback_options; bool buffer_locked; struct wl_listener buffer_release; diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 1e319276a..5ffd59ca1 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -112,6 +112,7 @@ void wlr_scene_node_destroy(struct wlr_scene_node *node) { wlr_buffer_unlock(scene_buffer->buffer); } wl_list_remove(&scene_buffer->buffer_release.link); + pixman_region32_fini(&scene_buffer->damage); 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); @@ -588,6 +589,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->damage); pixman_region32_init(&scene_buffer->opaque_region); wlr_scene_buffer_set_buffer(scene_buffer, buffer); @@ -619,9 +621,6 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff scene_buffer->buffer = NULL; scene_buffer->buffer_locked = false; - wlr_texture_destroy(scene_buffer->texture); - scene_buffer->texture = NULL; - bool update = false; if (buffer) { // if this node used to not be mapped or its previous displayed @@ -640,6 +639,14 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff update = true; } + if (damage != NULL) { + pixman_region32_union(&scene_buffer->damage, &scene_buffer->damage, + damage); + } else if (buffer != NULL) { + pixman_region32_union_rect(&scene_buffer->damage, &scene_buffer->damage, + 0, 0, buffer->width, buffer->height); + } + if (update) { scene_node_update(&scene_buffer->node, NULL); // updating the node will already damage the whole node for us. Return @@ -799,7 +806,8 @@ void wlr_scene_buffer_send_frame_done(struct wlr_scene_buffer *scene_buffer, static struct wlr_texture *scene_buffer_get_texture( struct wlr_scene_buffer *scene_buffer, struct wlr_renderer *renderer) { - if (scene_buffer->texture != NULL) { + if (scene_buffer->texture != NULL && + !pixman_region32_not_empty(&scene_buffer->damage)) { return scene_buffer->texture; } @@ -813,10 +821,21 @@ static struct wlr_texture *scene_buffer_get_texture( return client_buffer->texture; } - scene_buffer->texture = - wlr_texture_from_buffer(renderer, scene_buffer->buffer); + if (scene_buffer->texture == NULL || + !wlr_texture_update_from_buffer(scene_buffer->texture, scene_buffer->buffer, &scene_buffer->damage)) { + struct wlr_texture *texture = wlr_texture_from_buffer(renderer, scene_buffer->buffer); + if (texture == NULL) { + return NULL; + } + wlr_texture_destroy(scene_buffer->texture); + scene_buffer->texture = texture; + } + wlr_buffer_unlock(scene_buffer->buffer); scene_buffer->buffer_locked = false; + + pixman_region32_clear(&scene_buffer->damage); + return scene_buffer->texture; } From cf63375f5371895c1e36046646df7f05ca0cf0ca Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 11 Apr 2023 22:34:47 +0200 Subject: [PATCH 3/3] scene: drop wlr_client_buffer support --- tinywl/tinywl.c | 2 +- types/scene/surface.c | 32 ++------------------------------ types/scene/wlr_scene.c | 8 +------- 3 files changed, 4 insertions(+), 38 deletions(-) diff --git a/tinywl/tinywl.c b/tinywl/tinywl.c index d490167dd..aaf10c378 100644 --- a/tinywl/tinywl.c +++ b/tinywl/tinywl.c @@ -879,7 +879,7 @@ int main(int argc, char *argv[]) { * to dig your fingers in and play with their behavior if you want. Note that * the clients cannot set the selection directly without compositor approval, * see the handling of the request_set_selection event below.*/ - wlr_compositor_create(server.wl_display, server.renderer); + wlr_compositor_create(server.wl_display, NULL); wlr_subcompositor_create(server.wl_display); wlr_data_device_manager_create(server.wl_display); diff --git a/types/scene/surface.c b/types/scene/surface.c index c58bcd940..20097a423 100644 --- a/types/scene/surface.c +++ b/types/scene/surface.c @@ -70,28 +70,6 @@ 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; @@ -105,13 +83,9 @@ 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); - + if (surface->current.buffer) { wlr_scene_buffer_set_buffer_with_damage(scene_buffer, - &surface->buffer->base, &surface->buffer_damage); + surface->current.buffer, &surface->buffer_damage); } else { wlr_scene_buffer_set_buffer(scene_buffer, NULL); } @@ -150,8 +124,6 @@ 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->outputs_update.link); diff --git a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c index 5ffd59ca1..90b68ba43 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -626,7 +626,7 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff // 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 || + update = (!scene_buffer->buffer && !scene_buffer->texture) || (scene_buffer->dst_width == 0 && scene_buffer->dst_height == 0 && (scene_buffer->buffer->width != buffer->width || scene_buffer->buffer->height != buffer->height)); @@ -815,12 +815,6 @@ static struct wlr_texture *scene_buffer_get_texture( return NULL; } - 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 || !wlr_texture_update_from_buffer(scene_buffer->texture, scene_buffer->buffer, &scene_buffer->damage)) { struct wlr_texture *texture = wlr_texture_from_buffer(renderer, scene_buffer->buffer);