mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2025-10-29 05:40:12 -04:00
compositor: introduce surface-synced objects
This commit is contained in:
parent
c6b067779b
commit
a3bfdcd5e1
2 changed files with 198 additions and 39 deletions
|
|
@ -18,6 +18,13 @@
|
|||
#include <wlr/util/addon.h>
|
||||
#include <wlr/util/box.h>
|
||||
|
||||
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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue