From ceb5ac6f167e410cf724cbce8d98406a65178aba Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Mon, 20 Jul 2026 00:26:37 +1000 Subject: [PATCH] [client] wayland: use the locally configured white level for SDR --- client/displayservers/Wayland/gl.c | 39 +++++++++++++++---------- client/displayservers/Wayland/output.c | 6 ---- client/displayservers/Wayland/wayland.c | 8 ++--- client/displayservers/Wayland/wayland.h | 13 ++++----- 4 files changed, 31 insertions(+), 35 deletions(-) diff --git a/client/displayservers/Wayland/gl.c b/client/displayservers/Wayland/gl.c index 228a2b9d..8a69237b 100644 --- a/client/displayservers/Wayland/gl.c +++ b/client/displayservers/Wayland/gl.c @@ -89,6 +89,7 @@ static void applyHDRPending(void) params.minDisplayLuminance, params.maxCLL, params.maxFALL, + params.referenceWhiteLevel, params.pq, params.metadata); } @@ -162,9 +163,6 @@ 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); @@ -368,7 +366,7 @@ static bool hdrTargetLuminanceContained(uint32_t minLuminance, void waylandSetHDRImageDescription(const uint16_t displayPrimary[3][2], const uint16_t whitePoint[2], uint32_t maxDisplayLuminance, uint32_t minDisplayLuminance, uint32_t maxCLL, uint32_t maxFALL, - bool hdrPQ, bool hdrMetadata) + uint32_t referenceWhiteLevel, bool hdrPQ, bool hdrMetadata) { if (!wlWm.colorManager) return; @@ -484,17 +482,22 @@ void waylandSetHDRImageDescription(const uint16_t displayPrimary[3][2], wlWm.hdrImageCreator, WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ); - wlWm.hdrImageDescWhiteLevel = wlWm.cmHasLuminances ? - atomic_load(&wlWm.hdrPQWhiteLevel) : HDR_PQ_DEFAULT_WHITE_LEVEL; + const uint32_t sourceWhiteLevel = referenceWhiteLevel ? + referenceWhiteLevel : HDR_PQ_DEFAULT_WHITE_LEVEL; // The primary colour volume describes the PQ encoding itself. Mastering // display luminances are target-volume metadata and are set separately. + // Reference white describes the guest image content; the Wayland output + // reference white is used independently when composing local overlays. if (wlWm.cmHasLuminances) wp_image_description_creator_params_v1_set_luminances( wlWm.hdrImageCreator, HDR_PQ_MIN_LUMINANCE, HDR_PQ_MAX_LUMINANCE, - wlWm.hdrImageDescWhiteLevel); + sourceWhiteLevel); + else if (sourceWhiteLevel != HDR_PQ_DEFAULT_WHITE_LEVEL) + DEBUG_WARN("Compositor cannot accept the guest reference white level; " + "using the PQ default"); // KVMFR uses the ST 2086/DXGI scale of 50,000 units per coordinate while // color-management-v1 uses 1,000,000 units per coordinate. @@ -576,15 +579,17 @@ void waylandSetHDRImageDescription(const uint16_t displayPrimary[3][2], LG_UNLOCK(wlWm.hdrLock); DEBUG_INFO("HDR image description requested (%s, %s, " - "maxLum:%u cd/m² minLum:%u (0.0001 cd/m²) maxCLL:%u maxFALL:%u)", + "referenceWhite:%u cd/m² maxLum:%u cd/m² " + "minLum:%u (0.0001 cd/m²) maxCLL:%u maxFALL:%u)", hdrPQ ? "PQ" : "scRGB", hdrPQ ? "BT.2020" : "sRGB", - maxDisplayLuminance, minDisplayLuminance, maxCLL, maxFALL); + sourceWhiteLevel, maxDisplayLuminance, minDisplayLuminance, + maxCLL, maxFALL); } bool waylandRequestHDR(const uint16_t displayPrimary[3][2], const uint16_t whitePoint[2], uint32_t maxDisplayLuminance, uint32_t minDisplayLuminance, uint32_t maxCLL, uint32_t maxFALL, - bool hdrPQ, bool hdrMetadata) + uint32_t referenceWhiteLevel, bool hdrPQ, bool hdrMetadata) { if (!atomic_load_explicit(&wlWm.cmFeaturesDone, memory_order_acquire)) return false; @@ -600,16 +605,18 @@ bool waylandRequestHDR(const uint16_t displayPrimary[3][2], atomic_store(&wlWm.hdrRequested, true); LG_LOCK(wlWm.pendingHDRLock); - wlWm.pendingHDR.pq = hdrPQ; - wlWm.pendingHDR.metadata = hdrMetadata; + wlWm.pendingHDR.pq = hdrPQ; + wlWm.pendingHDR.metadata = hdrMetadata; + wlWm.pendingHDR.maxDisplayLuminance = maxDisplayLuminance; + wlWm.pendingHDR.minDisplayLuminance = minDisplayLuminance; + wlWm.pendingHDR.maxCLL = maxCLL; + wlWm.pendingHDR.maxFALL = maxFALL; + wlWm.pendingHDR.referenceWhiteLevel = referenceWhiteLevel; memcpy(wlWm.pendingHDR.displayPrimary, displayPrimary, sizeof(wlWm.pendingHDR.displayPrimary)); memcpy(wlWm.pendingHDR.whitePoint, whitePoint, sizeof(wlWm.pendingHDR.whitePoint)); - wlWm.pendingHDR.maxDisplayLuminance = maxDisplayLuminance; - wlWm.pendingHDR.minDisplayLuminance = minDisplayLuminance; - wlWm.pendingHDR.maxCLL = maxCLL; - wlWm.pendingHDR.maxFALL = maxFALL; + wlWm.pendingHDRAction = WAYLAND_HDR_PENDING_APPLY; LG_UNLOCK(wlWm.pendingHDRLock); return true; diff --git a/client/displayservers/Wayland/output.c b/client/displayservers/Wayland/output.c index 8e994649..7c9d32c0 100644 --- a/client/displayservers/Wayland/output.c +++ b/client/displayservers/Wayland/output.c @@ -82,12 +82,6 @@ void waylandOutputUpdateHDRWhiteLevel(void) if ((oldPQ != pqWhite || oldScRGB != scRGBWhite) && wlWm.frameEvent) { DEBUG_INFO("Wayland output reference white: %u cd/m²", pqWhite); - if (atomic_load(&wlWm.hdrRequested)) - { - LG_LOCK(wlWm.pendingHDRLock); - wlWm.pendingHDRAction = WAYLAND_HDR_PENDING_APPLY; - LG_UNLOCK(wlWm.pendingHDRLock); - } app_invalidateWindow(true); waylandStopWaitFrame(); } diff --git a/client/displayservers/Wayland/wayland.c b/client/displayservers/Wayland/wayland.c index 63760efb..712c6967 100644 --- a/client/displayservers/Wayland/wayland.c +++ b/client/displayservers/Wayland/wayland.c @@ -115,7 +115,6 @@ 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) @@ -236,12 +235,9 @@ 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 = activePQ ? atomic_load(&wlWm.hdrActivePQWhiteLevel) : - atomic_load(&wlWm.hdrPQWhiteLevel), + .pq = atomic_load(&wlWm.hdrPQWhiteLevel), .scRGB = atomic_load(&wlWm.hdrScRGBWhiteLevel), }; return true; @@ -282,7 +278,7 @@ static bool waylandHDRCallback(const void * rendererFormat) return waylandRequestHDR(format->hdrDisplayPrimary, format->hdrWhitePoint, format->hdrMaxDisplayLuminance, format->hdrMinDisplayLuminance, format->hdrMaxContentLightLevel, format->hdrMaxFrameAverageLightLevel, - format->hdrPQ, format->hdrMetadata); + format->sdrWhiteLevel, format->hdrPQ, format->hdrMetadata); else waylandRequestClearHDR(); return true; diff --git a/client/displayservers/Wayland/wayland.h b/client/displayservers/Wayland/wayland.h index 97258527..2892758b 100644 --- a/client/displayservers/Wayland/wayland.h +++ b/client/displayservers/Wayland/wayland.h @@ -116,6 +116,7 @@ struct WaylandHDRParameters uint32_t minDisplayLuminance; uint32_t maxCLL; uint32_t maxFALL; + uint32_t referenceWhiteLevel; }; struct WaylandDSState @@ -222,11 +223,9 @@ struct WaylandDSState _Atomic(bool) hdrActivePQ; _Atomic(bool) hdrRequested; _Atomic(bool) hdrRequestedPQ; - bool hdrImageDescPQ; - bool hdrImageDescReady; - uint32_t hdrImageDescWhiteLevel; - _Atomic(uint32_t) hdrActivePQWhiteLevel; - LG_Lock hdrLock; + bool hdrImageDescPQ; + bool hdrImageDescReady; + LG_Lock hdrLock; // wp_color_manager_v1 feature advertisement tracking. // Set to true after the done event for the color-manager has been received @@ -349,7 +348,7 @@ void waylandColorMgmtFree(void); void waylandSetHDRImageDescription(const uint16_t displayPrimary[3][2], const uint16_t whitePoint[2], uint32_t maxDisplayLuminance, uint32_t minDisplayLuminance, uint32_t maxCLL, uint32_t maxFALL, - bool hdrPQ, bool hdrMetadata); + uint32_t referenceWhiteLevel, bool hdrPQ, bool hdrMetadata); void waylandClearHDRImageDescription(void); // Queue HDR change from any thread (applied in waylandEGLSwapBuffers). @@ -358,7 +357,7 @@ void waylandClearHDRImageDescription(void); bool waylandRequestHDR(const uint16_t displayPrimary[3][2], const uint16_t whitePoint[2], uint32_t maxDisplayLuminance, uint32_t minDisplayLuminance, uint32_t maxCLL, uint32_t maxFALL, - bool hdrPQ, bool hdrMetadata); + uint32_t referenceWhiteLevel, bool hdrPQ, bool hdrMetadata); void waylandRequestClearHDR(void); // idle module