mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-07-20 14:22:00 +00:00
[client] wayland: forward HDR mastering metadata
Propagate valid ST 2086 mastering primaries and luminance data, MaxCLL, and MaxFALL to the Wayland compositor using the protocol's expected units.
This commit is contained in:
@@ -82,7 +82,8 @@ static void applyHDRPending(void)
|
||||
wlWm.pendingHDRMinDisplayLuminance,
|
||||
wlWm.pendingHDRMaxCLL,
|
||||
wlWm.pendingHDRMaxFALL,
|
||||
wlWm.pendingHDRPQ);
|
||||
wlWm.pendingHDRPQ,
|
||||
wlWm.pendingHDRMetadata);
|
||||
}
|
||||
else if (wlWm.pendingHDRClear)
|
||||
{
|
||||
@@ -200,7 +201,7 @@ EGLNativeWindowType waylandGetEGLNativeWindow(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 hdrPQ, bool hdrMetadata)
|
||||
{
|
||||
if (!wlWm.colorManager)
|
||||
return;
|
||||
@@ -294,26 +295,32 @@ void waylandSetHDRImageDescription(const uint16_t displayPrimary[3][2],
|
||||
wlWm.hdrWhiteLevels.pq :
|
||||
wlWm.hdrWhiteLevels.scRGB);
|
||||
|
||||
// Advertise the content primaries (BT.2020 for PQ). These describe the real
|
||||
// colour gamut of the signal and are safe to forward.
|
||||
if (wlWm.cmHasMasteringPrimaries)
|
||||
// KVMFR uses the ST 2086/DXGI scale of 50,000 units per coordinate while
|
||||
// color-management-v1 uses 1,000,000 units per coordinate.
|
||||
if (hdrPQ && hdrMetadata && wlWm.cmHasMasteringPrimaries)
|
||||
{
|
||||
wp_image_description_creator_params_v1_set_mastering_display_primaries(
|
||||
wlWm.hdrImageCreator,
|
||||
displayPrimary[0][0], displayPrimary[0][1],
|
||||
displayPrimary[1][0], displayPrimary[1][1],
|
||||
displayPrimary[2][0], displayPrimary[2][1],
|
||||
whitePoint[0], whitePoint[1]);
|
||||
displayPrimary[0][0] * 20, displayPrimary[0][1] * 20,
|
||||
displayPrimary[1][0] * 20, displayPrimary[1][1] * 20,
|
||||
displayPrimary[2][0] * 20, displayPrimary[2][1] * 20,
|
||||
whitePoint[0] * 20, whitePoint[1] * 20);
|
||||
|
||||
// NOTE: we deliberately do NOT forward the host's mastering luminance range,
|
||||
// MaxCLL or MaxFALL. Those values describe the *virtual display* the IDD
|
||||
// advertises to Windows (~1000 cd/m² from our EDID), not the content. LG
|
||||
// captures the full-range scRGB desktop composition and passes it through to
|
||||
// PQ without tone mapping, so the signal spans the entire PQ range (scRGB
|
||||
// 125.0 == 10000 cd/m²). Advertising the virtual display's peak as the
|
||||
// content peak makes the compositor place its tone-mapping knee there and
|
||||
// hard-clip everything brighter, crushing highlights. Leaving these unset
|
||||
// lets the content be treated as standard full-range PQ so the compositor
|
||||
// tone-maps it to the actual physical display.
|
||||
if ((uint64_t)maxDisplayLuminance * 10000 > minDisplayLuminance)
|
||||
wp_image_description_creator_params_v1_set_mastering_luminance(
|
||||
wlWm.hdrImageCreator,
|
||||
minDisplayLuminance, maxDisplayLuminance);
|
||||
}
|
||||
|
||||
if (hdrPQ && hdrMetadata)
|
||||
{
|
||||
if (maxCLL > 0)
|
||||
wp_image_description_creator_params_v1_set_max_cll(
|
||||
wlWm.hdrImageCreator, maxCLL);
|
||||
if (maxFALL > 0 && (maxCLL == 0 || maxFALL <= maxCLL))
|
||||
wp_image_description_creator_params_v1_set_max_fall(
|
||||
wlWm.hdrImageCreator, maxFALL);
|
||||
}
|
||||
|
||||
wlWm.hdrImageDesc =
|
||||
wp_image_description_creator_params_v1_create(wlWm.hdrImageCreator);
|
||||
@@ -349,7 +356,7 @@ void waylandSetHDRImageDescription(const uint16_t displayPrimary[3][2],
|
||||
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 hdrPQ, bool hdrMetadata)
|
||||
{
|
||||
if (!wlWm.cmFeaturesDone || !wlWm.cmHasParametric)
|
||||
return false;
|
||||
@@ -363,6 +370,7 @@ bool waylandRequestHDR(const uint16_t displayPrimary[3][2],
|
||||
return false;
|
||||
|
||||
wlWm.pendingHDRPQ = hdrPQ;
|
||||
wlWm.pendingHDRMetadata = hdrMetadata;
|
||||
|
||||
// Write all metadata before setting the apply flag to ensure the
|
||||
// render thread sees the complete HDR metadata when it observes
|
||||
|
||||
@@ -268,7 +268,7 @@ static bool waylandHDRCallback(const void * rendererFormat)
|
||||
return waylandRequestHDR(format->hdrDisplayPrimary, format->hdrWhitePoint,
|
||||
format->hdrMaxDisplayLuminance, format->hdrMinDisplayLuminance,
|
||||
format->hdrMaxContentLightLevel, format->hdrMaxFrameAverageLightLevel,
|
||||
format->hdrPQ);
|
||||
format->hdrPQ, format->hdrMetadata);
|
||||
else
|
||||
waylandRequestClearHDR();
|
||||
return true;
|
||||
|
||||
@@ -221,6 +221,7 @@ struct WaylandDSState
|
||||
_Atomic(bool) pendingHDRApply;
|
||||
_Atomic(bool) pendingHDRClear;
|
||||
bool pendingHDRPQ;
|
||||
bool pendingHDRMetadata;
|
||||
uint16_t pendingHDRDisplayPrimary[3][2];
|
||||
uint16_t pendingHDRWhitePoint[2];
|
||||
uint32_t pendingHDRMaxDisplayLuminance;
|
||||
@@ -316,7 +317,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 hdrPQ, bool hdrMetadata);
|
||||
void waylandClearHDRImageDescription(void);
|
||||
|
||||
// Queue HDR change from any thread (applied in waylandEGLSwapBuffers).
|
||||
@@ -325,7 +326,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 hdrPQ, bool hdrMetadata);
|
||||
void waylandRequestClearHDR(void);
|
||||
|
||||
// idle module
|
||||
|
||||
@@ -74,6 +74,7 @@ typedef struct LG_RendererFormat
|
||||
FrameType type; // frame type
|
||||
bool hdr; // if the frame is HDR or not
|
||||
bool hdrPQ; // if the HDR content is PQ mapped
|
||||
bool hdrMetadata; // if the HDR static metadata is valid
|
||||
unsigned int screenWidth; // actual width of the host
|
||||
unsigned int screenHeight; // actual height of the host
|
||||
unsigned int dataWidth; // the width of the packed data
|
||||
@@ -85,7 +86,7 @@ typedef struct LG_RendererFormat
|
||||
unsigned int bpp; // bits per pixel (zero if compressed)
|
||||
LG_RendererRotate rotate; // guest rotation
|
||||
|
||||
// HDR static metadata (from KVMFRFrame, valid when hdr is true)
|
||||
// HDR static metadata (from KVMFRFrame, valid when hdrMetadata is true)
|
||||
uint16_t hdrDisplayPrimary[3][2];
|
||||
uint16_t hdrWhitePoint[2];
|
||||
uint32_t hdrMaxDisplayLuminance;
|
||||
|
||||
@@ -641,10 +641,11 @@ int main_frameThread(void * unused)
|
||||
lgrFormat.pitch = frame->pitch;
|
||||
lgrFormat.hdr = frame->flags & FRAME_FLAG_HDR;
|
||||
lgrFormat.hdrPQ = frame->flags & FRAME_FLAG_HDR_PQ;
|
||||
lgrFormat.hdrMetadata = frame->flags & FRAME_FLAG_HDR_METADATA;
|
||||
lgrFormat.sdrWhiteLevel = frame->sdrWhiteLevel ?
|
||||
frame->sdrWhiteLevel : KVMFR_SDR_WHITE_LEVEL_DEFAULT;
|
||||
|
||||
if (lgrFormat.hdr)
|
||||
if (lgrFormat.hdrMetadata)
|
||||
{
|
||||
memcpy(lgrFormat.hdrDisplayPrimary, frame->hdrDisplayPrimary, sizeof(lgrFormat.hdrDisplayPrimary));
|
||||
memcpy(lgrFormat.hdrWhitePoint , frame->hdrWhitePoint , sizeof(lgrFormat.hdrWhitePoint ));
|
||||
|
||||
Reference in New Issue
Block a user