steamcompmgr, color_helpers: Added atoms for color gains

GAMESCOPE_HDR_INPUT_GAIN
GAMESCOPE_SDR_INPUT_GAIN
This commit is contained in:
Jeremy Selan 2023-04-19 15:25:38 -07:00 committed by Joshie
parent 378cfa5b7b
commit cfcea1433e
5 changed files with 72 additions and 34 deletions

View file

@ -210,7 +210,7 @@ glm::vec3 calcEOTFToLinear( const glm::vec3 & input, EOTF eotf, const tonemappin
{
if ( eotf == EOTF_Gamma22 )
{
return glm::pow( input, glm::vec3( 2.2f ) ) * tonemapping.g22_luminance_tolinear;
return glm::pow( input, glm::vec3( 2.2f ) ) * tonemapping.g22_luminance;
}
else if ( eotf == EOTF_PQ )
{
@ -225,9 +225,9 @@ glm::vec3 calcLinearToEOTF( const glm::vec3 & input, EOTF eotf, const tonemappin
if ( eotf == EOTF_Gamma22 )
{
glm::vec3 val = input;
if ( tonemapping.g22_luminance_fromlinear > 0.f )
if ( tonemapping.g22_luminance > 0.f )
{
val = glm::clamp( input / tonemapping.g22_luminance_fromlinear, glm::vec3( 0.f ), glm::vec3( 1.f ) );
val = glm::clamp( input / tonemapping.g22_luminance, glm::vec3( 0.f ), glm::vec3( 1.f ) );
}
return glm::pow( val, glm::vec3( 1.f/2.2f ) );
}
@ -241,7 +241,7 @@ glm::vec3 calcLinearToEOTF( const glm::vec3 & input, EOTF eotf, const tonemappin
// input is from 0->1
// TODO: use tone-mapping for white, black, contrast ratio
glm::vec3 applyShaper( const glm::vec3 & input, EOTF source, EOTF dest, const tonemapping_t & tonemapping, bool bInvert )
glm::vec3 applyShaper( const glm::vec3 & input, EOTF source, EOTF dest, const tonemapping_t & tonemapping, float flGain, bool bInvert )
{
if ( source == dest || !tonemapping.bUseShaper )
{
@ -252,16 +252,17 @@ glm::vec3 applyShaper( const glm::vec3 & input, EOTF source, EOTF dest, const to
{
// (once we do tone mapping this gets more complicated
std::swap( source, dest );
flGain = 1.f / flGain;
}
return calcLinearToEOTF( calcEOTFToLinear( input, source, tonemapping ), dest, tonemapping );
return calcLinearToEOTF( flGain * calcEOTFToLinear( input, source, tonemapping ), dest, tonemapping );
}
void calcColorTransform( uint16_t * pRgbxData1d, int nLutSize1d,
uint16_t * pRgbxData3d, int nLutEdgeSize3d,
const displaycolorimetry_t & source, EOTF sourceEOTF,
const displaycolorimetry_t & dest, EOTF destEOTF,
const colormapping_t & mapping, const nightmode_t & nightmode, const tonemapping_t & tonemapping )
const colormapping_t & mapping, const nightmode_t & nightmode, const tonemapping_t & tonemapping, float flGain )
{
glm::mat3 xyz_from_dest = normalised_primary_matrix( dest.primaries, dest.white, 1.f );
glm::mat3 dest_from_xyz = glm::inverse( xyz_from_dest );
@ -281,7 +282,7 @@ void calcColorTransform( uint16_t * pRgbxData1d, int nLutSize1d,
for ( int nVal=0; nVal<nLutSize1d; ++nVal )
{
glm::vec3 sourceColorEOTFEncoded = { nVal * flScale, nVal * flScale, nVal * flScale };
glm::vec3 shapedSourceColor = applyShaper( sourceColorEOTFEncoded, sourceEOTF, destEOTF, tonemapping, false );
glm::vec3 shapedSourceColor = applyShaper( sourceColorEOTFEncoded, sourceEOTF, destEOTF, tonemapping, flGain, false );
pRgbxData1d[nVal * 4 + 0] = drm_quantize_lut_value( shapedSourceColor.x );
pRgbxData1d[nVal * 4 + 1] = drm_quantize_lut_value( shapedSourceColor.y );
pRgbxData1d[nVal * 4 + 2] = drm_quantize_lut_value( shapedSourceColor.z );
@ -306,7 +307,7 @@ void calcColorTransform( uint16_t * pRgbxData1d, int nLutSize1d,
for ( int nRed=0; nRed<nLutEdgeSize3d; ++nRed )
{
glm::vec3 shapedSourceColor = { nRed * flScale, nGreen * flScale, nBlue * flScale };
glm::vec3 sourceColorEOTFEncoded = applyShaper( shapedSourceColor, sourceEOTF, destEOTF, tonemapping, true );
glm::vec3 sourceColorEOTFEncoded = applyShaper( shapedSourceColor, sourceEOTF, destEOTF, tonemapping, flGain, true );
// Convert to linearized display referred for source colorimetry
glm::vec3 sourceColorLinear = calcEOTFToLinear( sourceColorEOTFEncoded, sourceEOTF, tonemapping );
@ -322,7 +323,7 @@ void calcColorTransform( uint16_t * pRgbxData1d, int nLutSize1d,
destColorLinear = glm::mix( destColorLinear, sourceColorLinear, amount );
// Apply night mode
destColorLinear = vNightModeMultLinear * destColorLinear;
destColorLinear = vNightModeMultLinear * destColorLinear * glm::vec3( flGain );
// Apply dest EOTF
glm::vec3 destColorEOTFEncoded = calcLinearToEOTF( destColorLinear, destEOTF, tonemapping );

View file

@ -151,8 +151,7 @@ colormapping_t lerp( const colormapping_t & a, const colormapping_t & b, float t
struct tonemapping_t
{
bool bUseShaper = true;
float g22_luminance_tolinear = 1.f; // what luminance should be applied for g22 EOTF conversions?
float g22_luminance_fromlinear = 1.f; // what luminance should be applied for g22 EOTF conversions?
float g22_luminance = 1.f; // what luminance should be applied for g22 EOTF conversions?
};
// Generate a color transform from the source colorspace, to the dest colorspace,
@ -167,7 +166,8 @@ void calcColorTransform( uint16_t * pRgbxData1d, int nLutSize1d,
uint16_t * pRgbxData3d, int nLutEdgeSize3d,
const displaycolorimetry_t & source, EOTF sourceEOTF,
const displaycolorimetry_t & dest, EOTF destEOTF,
const colormapping_t & mapping, const nightmode_t & nightmode, const tonemapping_t & tonemapping );
const colormapping_t & mapping, const nightmode_t & nightmode, const tonemapping_t & tonemapping,
float flGain );
int writeRawLut( const char * outputFilename, uint16_t * pData, size_t nSize );

View file

@ -360,6 +360,8 @@ struct gamescope_color_mgmt_t
float sdrGamutWideness; // user property to widen gamut
float flInternalDisplayBrightness = 500.f;
float flSDROnHDRBrightness = 203.f;
float flHDRInputGain = 1.f;
float flSDRInputGain = 1.f;
// the native colorimetry capabilities of the display
displaycolorimetry_t displayColorimetry;

View file

@ -165,30 +165,21 @@ update_color_mgmt()
tonemapping.bUseShaper = true;
EOTF inputEOTF = static_cast<EOTF>( nInputEOTF );
float flGain = 1.f;
if ( inputEOTF == EOTF_Gamma22 )
{
flGain = g_ColorMgmt.pending.flSDRInputGain;
if ( g_ColorMgmt.pending.outputEncodingEOTF == EOTF_Gamma22 )
{
if ( g_bForceHDRSupportDebug )
{
tonemapping.g22_luminance_tolinear = g_ColorMgmt.pending.flSDROnHDRBrightness;
tonemapping.g22_luminance_fromlinear = g_ColorMgmt.pending.flInternalDisplayBrightness;
// xwm_log.infof("G22 -> G22 (force HDR) %f %f", tonemapping.g22_luminance_tolinear, tonemapping.g22_luminance_fromlinear );
}
else
{
// G22 -> G22. Does not matter what the g22 mult is
tonemapping.g22_luminance_tolinear = 1.f;
tonemapping.g22_luminance_fromlinear = 1.f;
// xwm_log.infof("G22 -> G22");
}
// G22 -> G22. Does not matter what the g22 mult is
tonemapping.g22_luminance = 1.f;
// xwm_log.infof("G22 -> G22");
}
else if ( g_ColorMgmt.pending.outputEncodingEOTF == EOTF_PQ )
{
// G22 -> PQ. SDR content going on an HDR output
tonemapping.g22_luminance_tolinear = g_ColorMgmt.pending.flSDROnHDRBrightness;
tonemapping.g22_luminance_fromlinear = g_ColorMgmt.pending.flSDROnHDRBrightness;
tonemapping.g22_luminance = g_ColorMgmt.pending.flSDROnHDRBrightness;
// xwm_log.infof("G22 -> PQ");
}
@ -199,18 +190,17 @@ update_color_mgmt()
}
else if ( inputEOTF == EOTF_PQ )
{
flGain = g_ColorMgmt.pending.flHDRInputGain;
if ( g_ColorMgmt.pending.outputEncodingEOTF == EOTF_Gamma22 )
{
// PQ -> G22 Leverage the display's native brightness
tonemapping.g22_luminance_tolinear = g_ColorMgmt.pending.flInternalDisplayBrightness;
tonemapping.g22_luminance_fromlinear = g_ColorMgmt.pending.flInternalDisplayBrightness;
// xwm_log.infof("PQ -> 2.2 - tonemapping.g22_luminance %f", tonemapping.g22_luminance_tolinear );
tonemapping.g22_luminance = g_ColorMgmt.pending.flInternalDisplayBrightness;
// xwm_log.infof("PQ -> 2.2 - tonemapping.g22_luminance %f", tonemapping.g22_luminance );
}
else if ( g_ColorMgmt.pending.outputEncodingEOTF == EOTF_PQ )
{
// PQ -> PQ. Better not matter what the g22 mult is
tonemapping.g22_luminance_tolinear = 1.f;
tonemapping.g22_luminance_fromlinear = 1.f;
tonemapping.g22_luminance = 1.f;
// xwm_log.infof("PQ -> PQ");
}
@ -219,7 +209,7 @@ update_color_mgmt()
calcColorTransform( &lut1d[0], nLutSize1d, &lut3d[0], nLutEdgeSize3d, inputColorimetry, inputEOTF,
outputEncodingColorimetry, g_ColorMgmt.pending.outputEncodingEOTF,
colorMapping, g_ColorMgmt.pending.nightmode, tonemapping );
colorMapping, g_ColorMgmt.pending.nightmode, tonemapping, flGain );
if ( !g_ColorMgmtLutsOverride[nInputEOTF].lut3d.empty() && !g_ColorMgmtLutsOverride[nInputEOTF].lut1d.empty() )
{
@ -293,6 +283,35 @@ bool set_sdr_on_hdr_brightness( float flVal )
return g_ColorMgmt.pending.enabled;
}
bool set_hdr_input_gain( float flVal )
{
if ( flVal < 0.f )
{
flVal = 1.f;
}
if ( g_ColorMgmt.pending.flHDRInputGain == flVal )
return false;
g_ColorMgmt.pending.flHDRInputGain = flVal;
return g_ColorMgmt.pending.enabled;
}
bool set_sdr_input_gain( float flVal )
{
if ( flVal < 0.f )
{
flVal = 1.f;
}
if ( g_ColorMgmt.pending.flSDRInputGain == flVal )
return false;
g_ColorMgmt.pending.flSDRInputGain = flVal;
return g_ColorMgmt.pending.enabled;
}
bool set_color_nightmode( const nightmode_t &nightmode )
{
if ( g_ColorMgmt.pending.nightmode == nightmode )
@ -4953,6 +4972,18 @@ handle_property_notify(xwayland_ctx_t *ctx, XPropertyEvent *ev)
if ( set_internal_display_brightness( bit_cast<float>(val) ) )
hasRepaint = true;
}
if ( ev->atom == ctx->atoms.gamescopeHDRInputGain )
{
uint32_t val = get_prop( ctx, ctx->root, ctx->atoms.gamescopeHDRInputGain, 0 );
if ( set_hdr_input_gain( bit_cast<float>(val) ) )
hasRepaint = true;
}
if ( ev->atom == ctx->atoms.gamescopeSDRInputGain )
{
uint32_t val = get_prop( ctx, ctx->root, ctx->atoms.gamescopeSDRInputGain, 0 );
if ( set_sdr_input_gain( bit_cast<float>(val) ) )
hasRepaint = true;
}
if ( ev->atom == ctx->atoms.gamescopeForceWindowsFullscreen )
{
ctx->force_windows_fullscreen = !!get_prop( ctx, ctx->root, ctx->atoms.gamescopeForceWindowsFullscreen, 0 );
@ -6149,6 +6180,8 @@ void init_xwayland_ctx(uint32_t serverId, gamescope_xwayland_server_t *xwayland_
ctx->atoms.gamescopeHDROutputFeedback = XInternAtom( ctx->dpy, "GAMESCOPE_HDR_OUTPUT_FEEDBACK", false );
ctx->atoms.gamescopeSDROnHDRContentBrightness = XInternAtom( ctx->dpy, "GAMESCOPE_SDR_ON_HDR_CONTENT_BRIGHTNESS", false );
ctx->atoms.gamescopeInternalDisplayBrightness = XInternAtom( ctx->dpy, "GAMESCOPE_INTERNAL_DISPLAY_BRIGHTNESS", false );
ctx->atoms.gamescopeHDRInputGain = XInternAtom( ctx->dpy, "GAMESCOPE_HDR_INPUT_GAIN", false );
ctx->atoms.gamescopeSDRInputGain = XInternAtom( ctx->dpy, "GAMESCOPE_SDR_INPUT_GAIN", false );
ctx->atoms.gamescopeHDRItmEnable = XInternAtom( ctx->dpy, "GAMESCOPE_HDR_ITM_ENABLE", false );
ctx->atoms.gamescopeHDRItmSDRNits = XInternAtom( ctx->dpy, "GAMESCOPE_HDR_ITM_SDR_NITS", false );
ctx->atoms.gamescopeHDRItmTargetNits = XInternAtom( ctx->dpy, "GAMESCOPE_HDR_ITM_TARGET_NITS", false );

View file

@ -179,6 +179,8 @@ struct xwayland_ctx_t
Atom gamescopeHDROutputFeedback;
Atom gamescopeSDROnHDRContentBrightness;
Atom gamescopeInternalDisplayBrightness;
Atom gamescopeHDRInputGain;
Atom gamescopeSDRInputGain;
Atom gamescopeHDRItmEnable;
Atom gamescopeHDRItmSDRNits;
Atom gamescopeHDRItmTargetNits;