wlr_linux_drm_syncobj_v1: Lock surface state until acquire signal

For surfaces utilizing linux-drm-syncobj-v1, we currently wait for the
acquire point to have materialized before applying surface state.

If a client provides a buffer that will take considerable time to
render, using this buffer for composition or direct scanout will cause
the compositor to miss frames, making the entire user experience
stutter.

By waiting for the acquire point to be signaled before allowing the
surface state to take effect and thereby allow usage of the buffer, the
user experience remains smooth even under such high-load scenarios. For
very low-load scenarios where the client only submitted materialized
fences, this comes at a slight scheduling overhead.
This commit is contained in:
Kenny Levinsen 2026-03-08 17:33:19 +01:00
parent e22084f639
commit 0fd093d8a8

View file

@ -232,15 +232,14 @@ static void surface_commit_handle_surface_destroy(struct wl_listener *listener,
surface_commit_destroy(commit); surface_commit_destroy(commit);
} }
// Block the surface commit until the fence materializes // Block the surface commit until the fence signals
static bool lock_surface_commit(struct wlr_linux_drm_syncobj_surface_v1 *surface, static bool lock_surface_commit(struct wlr_linux_drm_syncobj_surface_v1 *surface,
struct wlr_drm_syncobj_timeline *timeline, uint64_t point) { struct wlr_drm_syncobj_timeline *timeline, uint64_t point) {
uint32_t flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE; bool already_signaled = false;
if (!wlr_drm_syncobj_timeline_check(timeline, point,
bool already_materialized = false; DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, &already_signaled)) {
if (!wlr_drm_syncobj_timeline_check(timeline, point, flags, &already_materialized)) {
return false; return false;
} else if (already_materialized) { } else if (already_signaled) {
return true; return true;
} }
@ -253,7 +252,7 @@ static bool lock_surface_commit(struct wlr_linux_drm_syncobj_surface_v1 *surface
struct wl_display *display = wl_client_get_display(client); struct wl_display *display = wl_client_get_display(client);
struct wl_event_loop *loop = wl_display_get_event_loop(display); struct wl_event_loop *loop = wl_display_get_event_loop(display);
if (!wlr_drm_syncobj_timeline_waiter_init(&commit->waiter, timeline, point, if (!wlr_drm_syncobj_timeline_waiter_init(&commit->waiter, timeline, point,
flags, loop, surface_commit_handle_waiter_ready)) { 0, loop, surface_commit_handle_waiter_ready)) {
free(commit); free(commit);
return false; return false;
} }