compositor: don't get buffer from pending buffer resource too early

Fixes: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3795
This commit is contained in:
Kirill Primak 2024-01-19 12:10:39 +03:00
parent 00b869c1a9
commit 4688a371e0
2 changed files with 39 additions and 12 deletions

View file

@ -240,6 +240,9 @@ struct wlr_surface {
struct wl_list synced; // wlr_surface_synced.link struct wl_list synced; // wlr_surface_synced.link
size_t synced_len; size_t synced_len;
struct wl_resource *pending_buffer_resource;
struct wl_listener pending_buffer_resource_destroy;
}; };
struct wlr_renderer; struct wlr_renderer;

View file

@ -35,6 +35,24 @@ static int max(int fst, int snd) {
} }
} }
static void set_pending_buffer_resource(struct wlr_surface *surface,
struct wl_resource *resource) {
wl_list_remove(&surface->pending_buffer_resource_destroy.link);
surface->pending_buffer_resource = resource;
if (resource != NULL) {
wl_resource_add_destroy_listener(resource, &surface->pending_buffer_resource_destroy);
} else {
wl_list_init(&surface->pending_buffer_resource_destroy.link);
}
}
static void pending_buffer_resource_handle_destroy(struct wl_listener *listener, void *data) {
struct wlr_surface *surface =
wl_container_of(listener, surface, pending_buffer_resource_destroy);
set_pending_buffer_resource(surface, NULL);
}
static void surface_handle_destroy(struct wl_client *client, static void surface_handle_destroy(struct wl_client *client,
struct wl_resource *resource) { struct wl_resource *resource) {
struct wlr_surface *surface = wlr_surface_from_resource(resource); struct wlr_surface *surface = wlr_surface_from_resource(resource);
@ -60,19 +78,8 @@ static void surface_handle_attach(struct wl_client *client,
return; return;
} }
struct wlr_buffer *buffer = NULL;
if (buffer_resource != NULL) {
buffer = wlr_buffer_try_from_resource(buffer_resource);
if (buffer == NULL) {
wl_resource_post_error(buffer_resource, 0, "unknown buffer type");
return;
}
}
surface->pending.committed |= WLR_SURFACE_STATE_BUFFER; surface->pending.committed |= WLR_SURFACE_STATE_BUFFER;
set_pending_buffer_resource(surface, buffer_resource);
wlr_buffer_unlock(surface->pending.buffer);
surface->pending.buffer = buffer;
if (wl_resource_get_version(resource) < WL_SURFACE_OFFSET_SINCE_VERSION) { if (wl_resource_get_version(resource) < WL_SURFACE_OFFSET_SINCE_VERSION) {
surface->pending.committed |= WLR_SURFACE_STATE_OFFSET; surface->pending.committed |= WLR_SURFACE_STATE_OFFSET;
@ -180,6 +187,17 @@ static void surface_finalize_pending(struct wlr_surface *surface) {
struct wlr_surface_state *pending = &surface->pending; struct wlr_surface_state *pending = &surface->pending;
if ((pending->committed & WLR_SURFACE_STATE_BUFFER)) { if ((pending->committed & WLR_SURFACE_STATE_BUFFER)) {
struct wl_resource *buffer_resource = surface->pending_buffer_resource;
if (buffer_resource != NULL) {
set_pending_buffer_resource(surface, NULL);
pending->buffer = wlr_buffer_try_from_resource(buffer_resource);
if (pending->buffer == NULL) {
wlr_surface_reject_pending(surface,
buffer_resource, -1, "unknown buffer type");
}
}
if (pending->buffer != NULL) { if (pending->buffer != NULL) {
pending->buffer_width = pending->buffer->width; pending->buffer_width = pending->buffer->width;
pending->buffer_height = pending->buffer->height; pending->buffer_height = pending->buffer->height;
@ -737,6 +755,9 @@ static void surface_handle_resource_destroy(struct wl_resource *resource) {
wl_list_remove(&surface->renderer_destroy.link); wl_list_remove(&surface->renderer_destroy.link);
wl_list_remove(&surface->role_resource_destroy.link); wl_list_remove(&surface->role_resource_destroy.link);
wl_list_remove(&surface->pending_buffer_resource_destroy.link);
surface_state_finish(&surface->pending); surface_state_finish(&surface->pending);
surface_state_finish(&surface->current); surface_state_finish(&surface->current);
pixman_region32_fini(&surface->buffer_damage); pixman_region32_fini(&surface->buffer_damage);
@ -805,6 +826,9 @@ static struct wlr_surface *surface_create(struct wl_client *client,
wl_list_init(&surface->role_resource_destroy.link); wl_list_init(&surface->role_resource_destroy.link);
surface->pending_buffer_resource_destroy.notify = pending_buffer_resource_handle_destroy;
wl_list_init(&surface->pending_buffer_resource_destroy.link);
return surface; return surface;
} }