From b13fe9b3a1e8832fbfd821db71f4fbe5484f96f7 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Fri, 24 Jan 2025 19:36:47 +0300 Subject: [PATCH] backend/wayland: use a separate event queue for busy loops This avoids processing events which we're not interested in. Specifically, this fixes a case where output_commit() could be indirectly called from itself either from import_dmabuf() or while waiting for a configure event when enabling the output. --- backend/wayland/backend.c | 11 ++++++++++- backend/wayland/output.c | 33 +++++++++++++++++++++++++++------ include/backend/wayland.h | 1 + 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 978209995..ff95a7b4b 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -555,6 +555,7 @@ static void backend_destroy(struct wlr_backend *backend) { wl_compositor_destroy(wl->compositor); wl_registry_destroy(wl->registry); wl_display_flush(wl->remote_display); + wl_event_queue_destroy(wl->busy_loop_queue); if (wl->own_remote_display) { wl_display_disconnect(wl->remote_display); } @@ -610,10 +611,16 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_event_loop *loop, wl->own_remote_display = true; } + wl->busy_loop_queue = wl_display_create_queue(wl->remote_display); + if (wl->busy_loop_queue == NULL) { + wlr_log_errno(WLR_ERROR, "Could not create a Wayland event queue"); + goto error_display; + } + wl->registry = wl_display_get_registry(wl->remote_display); if (!wl->registry) { wlr_log_errno(WLR_ERROR, "Could not obtain reference to remote registry"); - goto error_display; + goto error_queue; } wl_registry_add_listener(wl->registry, ®istry_listener, wl); @@ -715,6 +722,8 @@ error_registry: xdg_wm_base_destroy(wl->xdg_wm_base); } wl_registry_destroy(wl->registry); +error_queue: + wl_event_queue_destroy(wl->busy_loop_queue); error_display: if (wl->own_remote_display) { wl_display_disconnect(wl->remote_display); diff --git a/backend/wayland/output.c b/backend/wayland/output.c index e14b66a4c..fb4d1f914 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -243,15 +243,24 @@ static struct wl_buffer *import_dmabuf(struct wlr_wl_backend *wl, zwp_linux_buffer_params_v1_add_listener(params, &dmabuf_listener, &data); zwp_linux_buffer_params_v1_create(params, dmabuf->width, dmabuf->height, dmabuf->format, 0); + struct wl_event_queue *display_queue = + wl_proxy_get_queue((struct wl_proxy *)wl->remote_display); + wl_proxy_set_queue((struct wl_proxy *)params, wl->busy_loop_queue); + while (!data.done) { - if (wl_display_dispatch(wl->remote_display) < 0) { - wlr_log(WLR_ERROR, "wl_display_dispatch() failed"); + if (wl_display_dispatch_queue(wl->remote_display, wl->busy_loop_queue) < 0) { + wlr_log(WLR_ERROR, "wl_display_dispatch_queue() failed"); break; } } + struct wl_buffer *buffer = data.wl_buffer; + if (buffer != NULL) { + wl_proxy_set_queue((struct wl_proxy *)buffer, display_queue); + } + zwp_linux_buffer_params_v1_destroy(params); - return data.wl_buffer; + return buffer; } static struct wl_buffer *import_shm(struct wlr_wl_backend *wl, @@ -747,13 +756,25 @@ static bool output_commit(struct wlr_output *wlr_output, const struct wlr_output wl_surface_commit(output->surface); output->initialized = true; + struct wl_event_queue *display_queue = + wl_proxy_get_queue((struct wl_proxy *)wl->remote_display); + wl_proxy_set_queue((struct wl_proxy *)output->xdg_surface, wl->busy_loop_queue); + wl_proxy_set_queue((struct wl_proxy *)output->xdg_toplevel, wl->busy_loop_queue); + wl_display_flush(wl->remote_display); while (!output->configured) { - if (wl_display_dispatch(wl->remote_display) == -1) { - wlr_log(WLR_ERROR, "wl_display_dispatch() failed"); - return false; + if (wl_display_dispatch_queue(wl->remote_display, wl->busy_loop_queue) == -1) { + wlr_log(WLR_ERROR, "wl_display_dispatch_queue() failed"); + break; } } + + wl_proxy_set_queue((struct wl_proxy *)output->xdg_surface, display_queue); + wl_proxy_set_queue((struct wl_proxy *)output->xdg_toplevel, display_queue); + + if (!output->configured) { + return false; + } } struct wlr_wl_buffer *buffer = NULL; diff --git a/include/backend/wayland.h b/include/backend/wayland.h index daa98ef5e..e24eb9fdf 100644 --- a/include/backend/wayland.h +++ b/include/backend/wayland.h @@ -22,6 +22,7 @@ struct wlr_wl_backend { /* local state */ bool started; struct wl_event_loop *event_loop; + struct wl_event_queue *busy_loop_queue; struct wl_list outputs; int drm_fd; struct wl_list buffers; // wlr_wl_buffer.link