diff --git a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h index b6f0d2175..efbbfcc1c 100644 --- a/include/wlr/types/wlr_scene.h +++ b/include/wlr/types/wlr_scene.h @@ -171,8 +171,10 @@ 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; }; /** A viewport for an output in the scene-graph */ 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 c33461f17..90b68ba43 100644 --- a/types/scene/wlr_scene.c +++ b/types/scene/wlr_scene.c @@ -108,7 +108,11 @@ 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->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); @@ -237,11 +241,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,22 +582,30 @@ 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); 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); 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,25 +613,38 @@ void wlr_scene_buffer_set_buffer_with_damage(struct wlr_scene_buffer *scene_buff // coordinates. assert(buffer || !damage); + 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; + 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 // 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)); 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 (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) { @@ -781,18 +806,30 @@ 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) { - 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) { + if (scene_buffer->texture != NULL && + !pixman_region32_not_empty(&scene_buffer->damage)) { return scene_buffer->texture; } - scene_buffer->texture = - wlr_texture_from_buffer(renderer, scene_buffer->buffer); + if (!scene_buffer->buffer_locked) { + return NULL; + } + + 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; } @@ -814,13 +851,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 +1187,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 +1418,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 +1531,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; }