From a3bfdcd5e171bdd14f68e0afc20f995a120e5784 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Fri, 4 Feb 2022 14:14:06 +0300 Subject: [PATCH] compositor: introduce surface-synced objects --- include/wlr/types/wlr_compositor.h | 45 +++++++ types/wlr_compositor.c | 192 +++++++++++++++++++++++------ 2 files changed, 198 insertions(+), 39 deletions(-) diff --git a/include/wlr/types/wlr_compositor.h b/include/wlr/types/wlr_compositor.h index 0bbf257c0..7d2b33795 100644 --- a/include/wlr/types/wlr_compositor.h +++ b/include/wlr/types/wlr_compositor.h @@ -18,6 +18,13 @@ #include #include +struct wlr_surface_synced_state { + struct wlr_surface_synced *synced; + + struct wl_list synced_link; // wlr_surface_state.synced + struct wl_list state_link; // wlr_surface_synced.states +}; + enum wlr_surface_state_field { WLR_SURFACE_STATE_BUFFER = 1 << 0, WLR_SURFACE_STATE_SURFACE_DAMAGE = 1 << 1, @@ -65,11 +72,39 @@ struct wlr_surface_state { int dst_width, dst_height; // in surface-local coordinates } viewport; + struct wl_list synced; // wlr_surface_synced_state.synced_link + // Number of locks that prevent this surface state from being committed. size_t n_locks; struct wl_list link; // wlr_surface.states }; +struct wlr_surface_synced; + +struct wlr_surface_synced_interface { + const char *name; + void (*destroy)(struct wlr_surface_synced *synced); + void (*squash_state)(struct wlr_surface_synced_state *dst, + struct wlr_surface_synced_state *src); + struct wlr_surface_synced_state *(*create_state)(void); + void (*destroy_state)(struct wlr_surface_synced_state *state); + void (*precommit)(struct wlr_surface_synced *synced, + struct wlr_surface_synced_state *state); +}; + +/** + * A surface-synced object is an object which has its double-buffered state flow + * synchronized with the surface state flow. + */ +struct wlr_surface_synced { + const struct wlr_surface_synced_interface *impl; + struct wl_list link; // wlr_surface.synced + + // See wlr_surface + struct wlr_surface_synced_state *current, *pending; + struct wl_list states; // wlr_surface_synced_state.state_link +}; + struct wlr_surface_role { const char *name; void (*commit)(struct wlr_surface *surface); @@ -152,6 +187,8 @@ struct wlr_surface { // private state + struct wl_list synced; // wlr_surface_synced.link + /** * The queue of all states the surface has. The current state is always * the first and the pending state is always the last. @@ -186,6 +223,14 @@ struct wlr_compositor { typedef void (*wlr_surface_iterator_func_t)(struct wlr_surface *surface, int sx, int sy, void *data); +bool wlr_surface_synced_init(struct wlr_surface_synced *synced, + const struct wlr_surface_synced_interface *impl, + struct wlr_surface *surface, + struct wlr_surface_synced_state *current, + struct wlr_surface_synced_state *pending); + +void wlr_surface_synced_finish(struct wlr_surface_synced *synced); + /** * Set the lifetime role for this surface. Returns 0 on success or -1 if the * role cannot be set. diff --git a/types/wlr_compositor.c b/types/wlr_compositor.c index dc5bb74f4..2ee5eacb8 100644 --- a/types/wlr_compositor.c +++ b/types/wlr_compositor.c @@ -33,6 +33,117 @@ static int max(int fst, int snd) { } } +static void surface_synced_state_init( + struct wlr_surface_synced_state *synced_state, + struct wlr_surface_state *state, + struct wlr_surface_synced *synced) { + synced_state->synced = synced; + wl_list_insert(&state->synced, &synced_state->synced_link); +} + +bool wlr_surface_synced_init(struct wlr_surface_synced *synced, + const struct wlr_surface_synced_interface *impl, + struct wlr_surface *surface, + struct wlr_surface_synced_state *current, + struct wlr_surface_synced_state *pending) { + wl_list_init(&synced->states); + wl_list_insert(&surface->synced, &synced->link); + synced->impl = impl; + + synced->current = current; + surface_synced_state_init(current, &surface->current, synced); + synced->pending = pending; + surface_synced_state_init(pending, &surface->pending, synced); + + wl_list_insert(&synced->states, ¤t->state_link); + wl_list_insert(synced->states.prev, &pending->state_link); + + struct wlr_surface_state *cached; + wl_list_for_each(cached, &surface->states, link) { + if (cached == &surface->current || cached == &surface->pending) { + continue; + } + struct wlr_surface_synced_state *synced_cached = + synced->impl->create_state(); + if (synced_cached == NULL) { + wlr_surface_synced_finish(synced); + return false; + } + surface_synced_state_init(synced_cached, cached, synced); + wl_list_insert(pending->state_link.prev, + &synced_cached->state_link); + } + + return true; +} + +void wlr_surface_synced_finish(struct wlr_surface_synced *synced) { + if (wl_list_empty(&synced->states)) { + // Already finished + return; + } + + wl_list_remove(&synced->link); + + wl_list_remove(&synced->current->synced_link); + wl_list_remove(&synced->current->state_link); + wl_list_remove(&synced->pending->synced_link); + wl_list_remove(&synced->pending->state_link); + + struct wlr_surface_synced_state *synced_cached, *tmp; + wl_list_for_each_safe(synced_cached, tmp, &synced->states, state_link) { + wl_list_remove(&synced_cached->synced_link); + wl_list_remove(&synced_cached->state_link); + synced->impl->destroy_state(synced_cached); + } +} + +static void surface_state_init(struct wlr_surface_state *state) { + state->scale = 1; + state->transform = WL_OUTPUT_TRANSFORM_NORMAL; + + wl_list_init(&state->subsurfaces_above); + wl_list_init(&state->subsurfaces_below); + + wl_list_init(&state->frame_callback_list); + + pixman_region32_init(&state->surface_damage); + pixman_region32_init(&state->buffer_damage); + pixman_region32_init(&state->opaque); + pixman_region32_init_rect(&state->input, + INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX); + + wl_list_init(&state->synced); +} + +static void surface_state_finish(struct wlr_surface_state *state) { + wlr_buffer_unlock(state->buffer); + + struct wl_resource *resource, *tmp; + wl_resource_for_each_safe(resource, tmp, &state->frame_callback_list) { + wl_resource_destroy(resource); + } + + pixman_region32_fini(&state->surface_damage); + pixman_region32_fini(&state->buffer_damage); + pixman_region32_fini(&state->opaque); + pixman_region32_fini(&state->input); +} + +static void surface_state_destroy_cached(struct wlr_surface_state *state) { + surface_state_finish(state); + + struct wlr_surface_synced_state *synced_state, *tmp; + wl_list_for_each_safe(synced_state, tmp, &state->synced, synced_link) { + wl_list_remove(&synced_state->synced_link); + wl_list_remove(&synced_state->state_link); + synced_state->synced->impl->destroy_state(synced_state); + } + + wl_list_remove(&state->link); + free(state); +} + static void surface_state_transformed_buffer_size(struct wlr_surface_state *state, int *out_width, int *out_height) { int width = state->buffer_width; @@ -224,8 +335,6 @@ static void surface_update_input_region(struct wlr_surface *surface) { 0, 0, surface->current.width, surface->current.height); } -static void surface_state_init(struct wlr_surface_state *state); - static void subsurface_parent_commit(struct wlr_subsurface *subsurface); static void surface_precommit(struct wlr_surface *surface, @@ -247,6 +356,17 @@ static void surface_precommit(struct wlr_surface *surface, if (surface->role && surface->role->precommit) { surface->role->precommit(surface, next); } + + struct wlr_surface_synced *synced; + wl_list_for_each(synced, &surface->synced, link) { + if (synced->impl->precommit == NULL) { + continue; + } + struct wlr_surface_synced_state *synced_state = + wl_container_of(synced->current->state_link.next, + synced_state, state_link); + synced->impl->precommit(synced, synced_state); + } } static void surface_commit(struct wlr_surface *surface) { @@ -408,6 +528,13 @@ static void surface_squash_state(struct wlr_surface *surface, dst->committed |= src->committed; src->committed = 0; + struct wlr_surface_synced_state *synced_dst, *synced_src; + wl_list_for_each(synced_src, &src->synced, synced_link) { + synced_dst = wl_container_of( + synced_src->state_link.prev, synced_dst, state_link); + synced_dst->synced->impl->squash_state(synced_dst, synced_src); + } + if (dst == &surface->current) { surface_commit(surface); } @@ -513,12 +640,27 @@ static void surface_handle_commit(struct wl_client *client, if (surface->pending.n_locks > 0) { struct wlr_surface_state *cached = calloc(1, sizeof(*cached)); - if (!cached) { + if (cached == NULL) { wl_resource_post_no_memory(surface->resource); return; } surface_state_init(cached); wl_list_insert(surface->pending.link.prev, &cached->link); + + struct wlr_surface_synced *synced; + wl_list_for_each(synced, &surface->synced, link) { + struct wlr_surface_synced_state *synced_cached = + synced->impl->create_state(); + if (synced_cached == NULL) { + surface_state_destroy_cached(cached); + wl_resource_post_no_memory(surface->resource); + return; + } + surface_synced_state_init(synced_cached, cached, synced); + wl_list_insert(synced->pending->state_link.prev, + &synced_cached->state_link); + } + cached->seq = surface->pending.seq; cached->n_locks = surface->pending.n_locks; surface->pending.n_locks = 0; @@ -586,42 +728,6 @@ struct wlr_surface *wlr_surface_from_resource(struct wl_resource *resource) { return wl_resource_get_user_data(resource); } -static void surface_state_init(struct wlr_surface_state *state) { - state->scale = 1; - state->transform = WL_OUTPUT_TRANSFORM_NORMAL; - - wl_list_init(&state->subsurfaces_above); - wl_list_init(&state->subsurfaces_below); - - wl_list_init(&state->frame_callback_list); - - pixman_region32_init(&state->surface_damage); - pixman_region32_init(&state->buffer_damage); - pixman_region32_init(&state->opaque); - pixman_region32_init_rect(&state->input, - INT32_MIN, INT32_MIN, UINT32_MAX, UINT32_MAX); -} - -static void surface_state_finish(struct wlr_surface_state *state) { - wlr_buffer_unlock(state->buffer); - - struct wl_resource *resource, *tmp; - wl_resource_for_each_safe(resource, tmp, &state->frame_callback_list) { - wl_resource_destroy(resource); - } - - pixman_region32_fini(&state->surface_damage); - pixman_region32_fini(&state->buffer_damage); - pixman_region32_fini(&state->opaque); - pixman_region32_fini(&state->input); -} - -static void surface_state_destroy_cached(struct wlr_surface_state *state) { - surface_state_finish(state); - wl_list_remove(&state->link); - free(state); -} - static void surface_output_destroy(struct wlr_surface_output *surface_output); static void surface_handle_resource_destroy(struct wl_resource *resource) { @@ -637,6 +743,12 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) { wlr_addon_set_finish(&surface->addons); + struct wlr_surface_synced *synced, *synced_tmp; + wl_list_for_each_safe(synced, synced_tmp, &surface->synced, link) { + wlr_surface_synced_finish(synced); + synced->impl->destroy(synced); + } + wl_list_remove(&surface->current.link); wl_list_remove(&surface->pending.link); @@ -694,6 +806,8 @@ static struct wlr_surface *surface_create(struct wl_client *client, wl_list_insert(&surface->states, &surface->current.link); wl_list_insert(surface->states.prev, &surface->pending.link); + wl_list_init(&surface->synced); + wl_signal_init(&surface->events.client_commit); wl_signal_init(&surface->events.commit); wl_signal_init(&surface->events.destroy);