From e9695f508413ab057e0714e80efcdc43aa9aa087 Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Sun, 19 Jul 2026 18:38:02 +1000 Subject: [PATCH] [client] wayland: retain coherent HDR state on failure Keep the reference white associated with the active PQ description until a replacement is ready. If asynchronous description creation fails, the renderer now retains the complete previous HDR state instead of combining new white-level values with stale compositor metadata. --- client/displayservers/Wayland/gl.c | 9 ++++++++- client/displayservers/Wayland/wayland.c | 6 +++++- client/displayservers/Wayland/wayland.h | 8 +++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/client/displayservers/Wayland/gl.c b/client/displayservers/Wayland/gl.c index e8bc7ef9..a96c70ca 100644 --- a/client/displayservers/Wayland/gl.c +++ b/client/displayservers/Wayland/gl.c @@ -162,6 +162,9 @@ static void activateReadyHDRImageDescription(void) wp_color_management_surface_v1_set_image_description( wlWm.colorSurface, desc, WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL); + if (wlWm.hdrImageDescPQ) + atomic_store(&wlWm.hdrActivePQWhiteLevel, + wlWm.hdrImageDescWhiteLevel); atomic_store(&wlWm.hdrActivePQ, wlWm.hdrImageDescPQ); atomic_store(&wlWm.hdrActive, true); @@ -192,6 +195,8 @@ static void hdrImageDescriptionFailed(void * data, DEBUG_WARN("Failed to create HDR image description (cause:%u): %s", cause, message); + if (atomic_load(&wlWm.hdrActive)) + DEBUG_WARN("Retaining the previous active HDR image description"); wlWm.hdrImageDesc = NULL; wlWm.hdrImageDescReady = false; wp_image_description_v1_destroy(desc); @@ -426,6 +431,8 @@ void waylandSetHDRImageDescription(const uint16_t displayPrimary[3][2], wlWm.hdrImageCreator, WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ); + wlWm.hdrImageDescWhiteLevel = atomic_load(&wlWm.hdrPQWhiteLevel); + // Set the primary colour volume luminances. // min_lum : 0.0001 cd/m² (source already scaled) -> pass through // max_lum : cd/m² (used only for scRGB; ignored for PQ, where the @@ -436,7 +443,7 @@ void waylandSetHDRImageDescription(const uint16_t displayPrimary[3][2], wlWm.hdrImageCreator, minDisplayLuminance > 0 ? minDisplayLuminance : 50, maxDisplayLuminance > 0 ? maxDisplayLuminance : 1000, - atomic_load(&wlWm.hdrPQWhiteLevel)); + wlWm.hdrImageDescWhiteLevel); // KVMFR uses the ST 2086/DXGI scale of 50,000 units per coordinate while // color-management-v1 uses 1,000,000 units per coordinate. diff --git a/client/displayservers/Wayland/wayland.c b/client/displayservers/Wayland/wayland.c index c205d10a..63760efb 100644 --- a/client/displayservers/Wayland/wayland.c +++ b/client/displayservers/Wayland/wayland.c @@ -115,6 +115,7 @@ static bool waylandInit(const LG_DSInitParams params) atomic_init(&wlWm.cmCanDoHDR, false); atomic_init(&wlWm.hdrPQWhiteLevel, 203); atomic_init(&wlWm.hdrScRGBWhiteLevel, 80); + atomic_init(&wlWm.hdrActivePQWhiteLevel, 203); wlWm.display = wl_display_connect(NULL); if (!wlWm.display) @@ -235,9 +236,12 @@ static bool waylandGetProp(LG_DSProperty prop, void * ret) if (prop == LG_DS_HDR_WHITE_LEVELS) { + const bool activePQ = atomic_load(&wlWm.hdrActive) && + atomic_load(&wlWm.hdrActivePQ); *(LG_DSHDRWhiteLevels *)ret = (LG_DSHDRWhiteLevels) { - .pq = atomic_load(&wlWm.hdrPQWhiteLevel), + .pq = activePQ ? atomic_load(&wlWm.hdrActivePQWhiteLevel) : + atomic_load(&wlWm.hdrPQWhiteLevel), .scRGB = atomic_load(&wlWm.hdrScRGBWhiteLevel), }; return true; diff --git a/client/displayservers/Wayland/wayland.h b/client/displayservers/Wayland/wayland.h index 5d40a48b..fa1aea56 100644 --- a/client/displayservers/Wayland/wayland.h +++ b/client/displayservers/Wayland/wayland.h @@ -222,9 +222,11 @@ struct WaylandDSState _Atomic(bool) hdrActivePQ; _Atomic(bool) hdrRequested; _Atomic(bool) hdrRequestedPQ; - bool hdrImageDescPQ; - bool hdrImageDescReady; - LG_Lock hdrLock; + bool hdrImageDescPQ; + bool hdrImageDescReady; + uint32_t hdrImageDescWhiteLevel; + _Atomic(uint32_t) hdrActivePQWhiteLevel; + LG_Lock hdrLock; // wp_color_manager_v1 feature advertisement tracking. // Set to true after the done event for the color-manager has been received