From fd870f6d27601063bad2219308a80775a9b9a12b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Poisot?= Date: Fri, 20 Mar 2026 12:35:21 +0000 Subject: [PATCH] linux_drm_syncobj_v1: fix handling of empty first commit As reported in https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4979#note_3385626, bfd6e619fc8642fb3f2cca6f9cb94d257def8780 did not correctly handle clients that don't immediately follow their call to `wp_linux_drm_syncobj_manager_v1.get_surface` with a commit attaching a buffer Fixes: bfd6e619fc8642fb3f2cca6f9cb94d257def8780 --- include/wlr/types/wlr_linux_drm_syncobj_v1.h | 1 + types/wlr_linux_drm_syncobj_v1.c | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/wlr/types/wlr_linux_drm_syncobj_v1.h b/include/wlr/types/wlr_linux_drm_syncobj_v1.h index 70a3f547f..7fd55ec2e 100644 --- a/include/wlr/types/wlr_linux_drm_syncobj_v1.h +++ b/include/wlr/types/wlr_linux_drm_syncobj_v1.h @@ -20,6 +20,7 @@ struct wlr_linux_drm_syncobj_surface_v1_state { uint64_t acquire_point; struct { + bool committed; struct wlr_drm_syncobj_timeline *release_timeline; uint64_t release_point; struct wlr_drm_syncobj_merger *release_merger; diff --git a/types/wlr_linux_drm_syncobj_v1.c b/types/wlr_linux_drm_syncobj_v1.c index 200f4c9e6..53fc2fd43 100644 --- a/types/wlr_linux_drm_syncobj_v1.c +++ b/types/wlr_linux_drm_syncobj_v1.c @@ -171,19 +171,20 @@ static void surface_synced_move_state(void *_dst, void *_src) { } surface_synced_finish_state(dst); *dst = *src; + dst->committed = true; *src = (struct wlr_linux_drm_syncobj_surface_v1_state){0}; } static void surface_synced_commit(struct wlr_surface_synced *synced) { struct wlr_linux_drm_syncobj_surface_v1 *surface = wl_container_of(synced, surface, synced); - if (surface->current.release_merger != NULL) { - // ignore commits that did not attach a buffer + if (!surface->current.committed) { return; } surface->current.release_merger = wlr_drm_syncobj_merger_create( surface->current.release_timeline, surface->current.release_point); + surface->current.committed = false; } @@ -507,7 +508,7 @@ static void release_signaller_handle_buffer_release(struct wl_listener *listener bool wlr_linux_drm_syncobj_v1_state_signal_release_with_buffer( struct wlr_linux_drm_syncobj_surface_v1_state *state, struct wlr_buffer *buffer) { assert(buffer->n_locks > 0); - if (state->release_timeline == NULL) { + if (state->release_merger == NULL) { // This can happen if an existing surface with a buffer has a // syncobj_surface_v1_state created but no new buffer with release // timeline committed. @@ -530,6 +531,12 @@ bool wlr_linux_drm_syncobj_v1_state_add_release_point( struct wlr_linux_drm_syncobj_surface_v1_state *state, struct wlr_drm_syncobj_timeline *release_timeline, uint64_t release_point, struct wl_event_loop *event_loop) { + if (state->release_merger == NULL) { + // This can happen if an existing surface with a buffer has a + // syncobj_surface_v1_state created but no new buffer with release + // timeline committed. + return true; + } return wlr_drm_syncobj_merger_add(state->release_merger, release_timeline, release_point, event_loop); }