wlr_compositor: release state on buffer release

wlr_compositor will now wait for the current buffer to be released before
clearing relevant state. For now, this will always happen at the end of
the commit so there should be no functional change here.
This commit is contained in:
Alexander Orzechowski 2024-05-05 12:57:29 -04:00
parent 06cd96b832
commit 42c395f39c
2 changed files with 40 additions and 5 deletions

View file

@ -239,6 +239,7 @@ struct wlr_surface {
// private state
struct wl_listener role_resource_destroy;
struct wl_listener current_buffer_release;
struct {
int32_t scale;
@ -250,6 +251,7 @@ struct wlr_surface {
bool unmap_commit;
bool opaque;
bool consumed;
bool handling_commit;
bool pending_rejected;

View file

@ -405,8 +405,12 @@ static void surface_state_move(struct wlr_surface_state *state,
}
static void surface_apply_damage(struct wlr_surface *surface) {
wl_list_remove(&surface->current_buffer_release.link);
if (surface->current.buffer == NULL) {
// NULL commit
wl_list_init(&surface->current_buffer_release.link);
if (surface->buffer != NULL) {
wlr_buffer_unlock(&surface->buffer->base);
}
@ -415,13 +419,14 @@ static void surface_apply_damage(struct wlr_surface *surface) {
return;
}
wl_signal_add(&surface->current.buffer->events.release,
&surface->current_buffer_release);
surface->opaque = buffer_is_opaque(surface->current.buffer);
if (surface->buffer != NULL) {
if (wlr_client_buffer_apply_damage(surface->buffer,
surface->current.buffer, &surface->buffer_damage)) {
wlr_buffer_unlock(surface->current.buffer);
surface->current.buffer = NULL;
return;
}
}
@ -508,10 +513,26 @@ error:
wl_resource_post_no_memory(surface->resource);
}
static void surface_clean_state(struct wlr_surface *surface) {
assert(surface->consumed);
wl_list_remove(&surface->current_buffer_release.link);
wl_list_init(&surface->current_buffer_release.link);
pixman_region32_clear(&surface->buffer_damage);
surface->current.buffer = NULL;
surface->consumed = false;
}
static void surface_commit_state(struct wlr_surface *surface,
struct wlr_surface_state *next) {
assert(next->cached_state_locks == 0);
// if the surface was consumed that means we don't own the current buffer
// anymore.
if (surface->consumed) {
surface_clean_state(surface);
}
bool invalid_buffer = next->committed & WLR_SURFACE_STATE_BUFFER;
if (invalid_buffer && next->buffer == NULL) {
@ -562,10 +583,8 @@ static void surface_commit_state(struct wlr_surface *surface,
// Release the buffer after emitting the commit event, so that listeners can
// access it. Don't leave the buffer locked so that wl_shm buffers can be
// released immediately on commit when they are uploaded to the GPU.
surface->consumed = true;
wlr_buffer_unlock(surface->current.buffer);
surface->current.buffer = NULL;
pixman_region32_clear(&surface->buffer_damage);
}
static void surface_handle_commit(struct wl_client *client,
@ -720,6 +739,10 @@ static void surface_destroy_role_object(struct wlr_surface *surface);
static void surface_handle_resource_destroy(struct wl_resource *resource) {
struct wlr_surface *surface = wlr_surface_from_resource(resource);
if (surface->consumed) {
surface_clean_state(surface);
}
struct wlr_surface_output *surface_output, *surface_output_tmp;
wl_list_for_each_safe(surface_output, surface_output_tmp,
&surface->current_outputs, link) {
@ -738,6 +761,7 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) {
surface_state_destroy_cached(cached, surface);
}
wl_list_remove(&surface->current_buffer_release.link);
wl_list_remove(&surface->role_resource_destroy.link);
wl_list_remove(&surface->pending_buffer_resource_destroy.link);
@ -753,6 +777,12 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) {
free(surface);
}
static void surface_handle_current_buffer_release(struct wl_listener *listener,
void *data) {
struct wlr_surface *surface = wl_container_of(listener, surface, current_buffer_release);
surface_clean_state(surface);
}
static struct wlr_surface *surface_create(struct wl_client *client,
uint32_t version, uint32_t id, struct wlr_compositor *compositor) {
struct wlr_surface *surface = calloc(1, sizeof(*surface));
@ -797,6 +827,9 @@ static struct wlr_surface *surface_create(struct wl_client *client,
surface->pending_buffer_resource_destroy.notify = pending_buffer_resource_handle_destroy;
wl_list_init(&surface->pending_buffer_resource_destroy.link);
surface->current_buffer_release.notify = surface_handle_current_buffer_release;
wl_list_init(&surface->current_buffer_release.link);
return surface;
}