[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.
This commit is contained in:
Geoffrey McRae
2026-07-19 18:38:02 +10:00
parent c190aaf579
commit e9695f5084
3 changed files with 18 additions and 5 deletions

View File

@@ -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.

View File

@@ -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;

View File

@@ -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