From 1b78384da3d6c164d0c70582a20b3c1bda568a7e Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Thu, 6 Aug 2026 17:11:03 +1000 Subject: [PATCH] [client] wayland: publish stable presentation cadence --- client/displayservers/Wayland/output.c | 14 +++++++++++++- client/displayservers/Wayland/presentation.c | 11 ++++++++--- client/displayservers/Wayland/wayland.h | 4 +++- client/displayservers/Wayland/window.c | 2 ++ 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/client/displayservers/Wayland/output.c b/client/displayservers/Wayland/output.c index 43e4eb71..499ba017 100644 --- a/client/displayservers/Wayland/output.c +++ b/client/displayservers/Wayland/output.c @@ -325,6 +325,7 @@ static void outputDoneHandler(void * opaque, struct wl_output * output) { struct WaylandOutput * node = opaque; outputUpdateScale(node); + waylandOutputUpdateFramePeriod(); } static void outputScaleHandler(void * opaque, struct wl_output * output, int32_t scale) @@ -401,6 +402,7 @@ void waylandOutputFree(void) wl_list_remove(&node->link); free(node); } + atomic_store_explicit(&wlWm.nominalPeriod, 0, memory_order_release); } void waylandOutputBind(uint32_t name, uint32_t version) @@ -470,6 +472,7 @@ void waylandOutputTryUnbind(uint32_t name) free(node); waylandWindowUpdateScale(); waylandOutputUpdateHDRWhiteLevel(); + waylandOutputUpdateFramePeriod(); break; } } @@ -485,7 +488,7 @@ struct WaylandScale waylandOutputGetScale(struct wl_output * output) return waylandScaleFromInt(0); } -bool waylandOutputGetFramePeriod(uint64_t * period) +void waylandOutputUpdateFramePeriod(void) { uint64_t fastest = 0; struct SurfaceOutput * surfaceOutput; @@ -502,6 +505,15 @@ bool waylandOutputGetFramePeriod(uint64_t * period) fastest = candidate; } + atomic_store_explicit( + &wlWm.nominalPeriod, fastest, memory_order_release); +} + +bool waylandOutputGetFramePeriod(uint64_t * period) +{ + const uint64_t fastest = atomic_load_explicit( + &wlWm.nominalPeriod, memory_order_acquire); + if (!fastest) return false; diff --git a/client/displayservers/Wayland/presentation.c b/client/displayservers/Wayland/presentation.c index be5fa98d..c850c875 100644 --- a/client/displayservers/Wayland/presentation.c +++ b/client/displayservers/Wayland/presentation.c @@ -39,6 +39,8 @@ static void presentationClockId(void * data, struct wp_presentation * presentation, uint32_t clkId) { wlWm.clkId = clkId; + atomic_store_explicit( + &wlWm.presentationClockValid, true, memory_order_release); } static const struct wp_presentation_listener presentationListener = { @@ -56,8 +58,6 @@ static void presentationFeedbackPresented(void * opaque, uint32_t tvNsec, uint32_t refresh, uint32_t seqHi, uint32_t seqLo, uint32_t flags) { struct FrameData * data = opaque; - if (refresh) - atomic_store(&wlWm.presentationPeriod, refresh); struct timespec present = { .tv_sec = (uint64_t) tvSecHi << 32 | tvSecLo, .tv_nsec = tvNsec, @@ -96,6 +96,8 @@ bool waylandPresentationInit(void) { if (wlWm.presentation) { + atomic_store_explicit( + &wlWm.presentationClockValid, false, memory_order_release); wlWm.photonTimings = ringbuffer_new(256, sizeof(float)); wlWm.photonGraph = app_registerGraph("PHOTON", wlWm.photonTimings, 0.0f, 30.0f, NULL); @@ -110,6 +112,8 @@ void waylandPresentationFree(void) if (!wlWm.presentation) return; + atomic_store_explicit( + &wlWm.presentationClockValid, false, memory_order_release); wp_presentation_destroy(wlWm.presentation); app_unregisterGraph(wlWm.photonGraph); ringbuffer_free(&wlWm.photonTimings); @@ -117,7 +121,8 @@ void waylandPresentationFree(void) void waylandPresentationFrame(void) { - if (!wlWm.presentation) + if (!wlWm.presentation || !atomic_load_explicit( + &wlWm.presentationClockValid, memory_order_acquire)) return; struct FrameData * data = malloc(sizeof(*data)); diff --git a/client/displayservers/Wayland/wayland.h b/client/displayservers/Wayland/wayland.h index 44fd8bb2..fb64ca02 100644 --- a/client/displayservers/Wayland/wayland.h +++ b/client/displayservers/Wayland/wayland.h @@ -161,7 +161,8 @@ struct WaylandDSState struct wp_presentation * presentation; clockid_t clkId; - _Atomic(uint64_t) presentationPeriod; + _Atomic(bool) presentationClockValid; + _Atomic(uint64_t) nominalPeriod; RingBuffer photonTimings; GraphHandle photonGraph; @@ -397,6 +398,7 @@ void waylandOutputBind(uint32_t name, uint32_t version); void waylandOutputTryUnbind(uint32_t name); struct WaylandScale waylandOutputGetScale(struct wl_output * output); bool waylandOutputGetFramePeriod(uint64_t * period); +void waylandOutputUpdateFramePeriod(void); void waylandOutputColorMgmtInit(struct WaylandOutput * output); void waylandOutputColorMgmtInitAll(void); void waylandOutputUpdateHDRWhiteLevel(void); diff --git a/client/displayservers/Wayland/window.c b/client/displayservers/Wayland/window.c index 2bd367c2..d5c80cb9 100644 --- a/client/displayservers/Wayland/window.c +++ b/client/displayservers/Wayland/window.c @@ -92,6 +92,7 @@ static void wlSurfaceEnterHandler(void * data, struct wl_surface * surface, stru wl_list_insert(&wlWm.surfaceOutputs, &node->link); waylandWindowUpdateScale(); waylandOutputUpdateHDRWhiteLevel(); + waylandOutputUpdateFramePeriod(); } static void wlSurfaceLeaveHandler(void * data, struct wl_surface * surface, struct wl_output * output) @@ -106,6 +107,7 @@ static void wlSurfaceLeaveHandler(void * data, struct wl_surface * surface, stru } waylandWindowUpdateScale(); waylandOutputUpdateHDRWhiteLevel(); + waylandOutputUpdateFramePeriod(); } static const struct wl_surface_listener wlSurfaceListener = {