Add wlr_compositor_dmabuf_waiter

This helper monitors buffers for implicit and explicit work
synchronization, delaying the surface commit until the fences are ready
to be consumed for synchronization (i.e., fences have materialized), or
for the work to be complete, depending on the specified waiter mode.

Through this, the compositor can avoid stalling on incomplete work,
staying fully interactive until the buffer is ready to be sampled.

This is a generalization of Simon's patch that added a waiter for
traditional implicit sync.

Based-on-patch-by: Simon Ser <contact@emersion.fr>
This commit is contained in:
Kenny Levinsen 2026-04-01 14:32:08 +00:00
parent c66a910753
commit b84aadb5c1
4 changed files with 427 additions and 22 deletions

View file

@ -97,11 +97,7 @@ bool wlr_drm_syncobj_timeline_signal(struct wlr_drm_syncobj_timeline *timeline,
/**
* Asynchronously wait for a timeline point.
*
* Flags can be:
*
* - 0 to wait for the point to be signalled
* - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE to only wait for a fence to
* materialize
* See wlr_drm_syncobj_timeline_eventfd for available flags.
*
* A callback must be provided that will be invoked when the waiter has finished.
*/
@ -112,6 +108,20 @@ bool wlr_drm_syncobj_timeline_waiter_init(struct wlr_drm_syncobj_timeline_waiter
* Cancel a timeline waiter.
*/
void wlr_drm_syncobj_timeline_waiter_finish(struct wlr_drm_syncobj_timeline_waiter *waiter);
/**
* Create an eventfd that becomes readable when a timeline point is ready.
*
* Flags can be:
*
* - 0 to wait for the point to be signaled
* - DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE to only wait for a fence to
* materialize
*
* The returned FD is owned by the caller and must be closed when no longer
* needed.
*/
int wlr_drm_syncobj_timeline_eventfd(struct wlr_drm_syncobj_timeline *timeline,
uint64_t point, uint32_t flags);
/**
* Export a timeline point as a sync_file FD.
*

View file

@ -16,6 +16,7 @@
#include <wlr/render/dmabuf.h>
#include <wlr/render/drm_format_set.h>
struct wlr_compositor;
struct wlr_surface;
struct wlr_dmabuf_v1_buffer {
@ -134,4 +135,51 @@ struct wlr_linux_dmabuf_feedback_v1_init_options {
bool wlr_linux_dmabuf_feedback_v1_init_with_options(struct wlr_linux_dmabuf_feedback_v1 *feedback,
const struct wlr_linux_dmabuf_feedback_v1_init_options *options);
enum wlr_surface_dmabuf_waiter_mode {
WLR_SURFACE_DMABUF_WAITER_MODE_AVAILABLE,
WLR_SURFACE_DMABUF_WAITER_MODE_COMPLETE,
};
/**
* A helper to wait for client buffers to be ready.
*
* When attached to a surface, this helper will delay commits until the
* relevant GPU fences are materialized or work has completed, depending on
* mode. When set to WLR_SURFACE_DMABUF_WAITER_MODE_COMPLETE, this means that
* wlr_surface.events.commit will only fire when the GPU buffers attached to
* that commit are ready to be read.
*/
struct wlr_surface_dmabuf_waiter {
struct wlr_surface *surface;
enum wlr_surface_dmabuf_waiter_mode mode;
struct {
struct wl_list commits; // wlr_surface_dmabuf_waiter_commit.link
struct wl_listener client_commit;
} WLR_PRIVATE;
};
/**
* Initialize a buffer waiter for a surface.
*
* Callers must call wlr_surface_dmabuf_waiter_finish() to unregister the waiter.
*/
void wlr_surface_dmabuf_waiter_init(struct wlr_surface_dmabuf_waiter *waiter,
struct wlr_surface *surface, enum wlr_surface_dmabuf_waiter_mode mode);
/**
* Clean up a buffer waiter.
*
* Any pending commit waiting on GPU work to complete will be applied
* immediately.
*/
void wlr_surface_dmabuf_waiter_finish(struct wlr_surface_dmabuf_waiter *waiter);
/**
* Initialize a compositor-wide buffer waiter, which will listen for new
* surfaces and attach buffer waiters to them.
*/
void wlr_compositor_dmabuf_waiter_create(struct wlr_compositor *compositor,
enum wlr_surface_dmabuf_waiter_mode mode);
#endif