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