[client] wayland: use the locally configured white level for SDR

This commit is contained in:
Geoffrey McRae
2026-07-20 00:26:37 +10:00
parent 23e394fd57
commit ceb5ac6f16
4 changed files with 31 additions and 35 deletions

View File

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

View File

@@ -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();
}

View File

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

View File

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