color_helpers, steamcompmgr: Avoid allocation of LUTs every time we re-setup color mgmt

This commit is contained in:
Joshua Ashton 2023-05-09 15:08:27 +00:00 committed by Joshie
parent 36c120901a
commit f9e47a612f
4 changed files with 89 additions and 96 deletions

View file

@ -611,7 +611,7 @@ void calcColorTransform( uint16_t * pRgbxData1d, int nLutSize1d,
destColorLinear = glm::mix( destColorLinear, sourceColorLinear, amount ); destColorLinear = glm::mix( destColorLinear, sourceColorLinear, amount );
// Apply night mode // Apply night mode
destColorLinear = vNightModeMultLinear * destColorLinear * glm::vec3( flGain ); destColorLinear = vNightModeMultLinear * destColorLinear * flGain;
// Apply dest EOTF // Apply dest EOTF
glm::vec3 destColorEOTFEncoded = calcLinearToEOTF( destColorLinear, destEOTF, tonemapping ); glm::vec3 destColorEOTFEncoded = calcLinearToEOTF( destColorLinear, destEOTF, tonemapping );

View file

@ -2590,18 +2590,18 @@ bool drm_update_color_mgmt(struct drm_t *drm)
for ( uint32_t i = 0; i < EOTF_Count; i++ ) for ( uint32_t i = 0; i < EOTF_Count; i++ )
{ {
if ( g_ColorMgmtLuts[i].lut1d.empty() || g_ColorMgmtLuts[i].lut3d.empty() ) if ( !g_ColorMgmtLuts[i].HasLuts() )
continue; continue;
uint32_t shaper_blob_id = 0; uint32_t shaper_blob_id = 0;
if (drmModeCreatePropertyBlob(drm->fd, g_ColorMgmtLuts[i].lut1d.data(), sizeof(uint16_t) * g_ColorMgmtLuts[i].lut1d.size(), &shaper_blob_id) != 0) { if (drmModeCreatePropertyBlob(drm->fd, g_ColorMgmtLuts[i].lut1d, sizeof(g_ColorMgmtLuts[i].lut1d), &shaper_blob_id) != 0) {
drm_log.errorf_errno("Unable to create SHAPERLUT property blob"); drm_log.errorf_errno("Unable to create SHAPERLUT property blob");
return false; return false;
} }
drm->pending.shaperlut_id[ i ] = shaper_blob_id; drm->pending.shaperlut_id[ i ] = shaper_blob_id;
uint32_t lut3d_blob_id = 0; uint32_t lut3d_blob_id = 0;
if (drmModeCreatePropertyBlob(drm->fd, g_ColorMgmtLuts[i].lut3d.data(), sizeof(uint16_t) * g_ColorMgmtLuts[i].lut3d.size(), &lut3d_blob_id) != 0) { if (drmModeCreatePropertyBlob(drm->fd, g_ColorMgmtLuts[i].lut3d, sizeof(g_ColorMgmtLuts[i].lut3d), &lut3d_blob_id) != 0) {
drm_log.errorf_errno("Unable to create LUT3D property blob"); drm_log.errorf_errno("Unable to create LUT3D property blob");
return false; return false;
} }

View file

@ -379,18 +379,28 @@ struct gamescope_color_mgmt_t
bool operator != (const gamescope_color_mgmt_t&) const = default; bool operator != (const gamescope_color_mgmt_t&) const = default;
}; };
static constexpr uint32_t nLutEdgeSize3d = 17;
static constexpr uint32_t nLutSize1d = 4096;
struct gamescope_color_mgmt_luts struct gamescope_color_mgmt_luts
{ {
std::vector<uint16_t> lut3d; bool bHasLut3D = false;
std::vector<uint16_t> lut1d; bool bHasLut1D = false;
uint16_t lut3d[nLutEdgeSize3d*nLutEdgeSize3d*nLutEdgeSize3d*4];
uint16_t lut1d[nLutSize1d*4];
std::shared_ptr<CVulkanTexture> vk_lut3d; std::shared_ptr<CVulkanTexture> vk_lut3d;
std::shared_ptr<CVulkanTexture> vk_lut1d; std::shared_ptr<CVulkanTexture> vk_lut1d;
bool HasLuts() const
{
return bHasLut3D && bHasLut1D;
}
void reset() void reset()
{ {
lut3d.clear(); bHasLut1D = false;
lut1d.clear(); bHasLut3D = false;
} }
}; };

View file

@ -164,92 +164,78 @@ update_color_mgmt()
for ( uint32_t nInputEOTF = 0; nInputEOTF < EOTF_Count; nInputEOTF++ ) for ( uint32_t nInputEOTF = 0; nInputEOTF < EOTF_Count; nInputEOTF++ )
{ {
std::vector<uint16_t> lut3d;
uint32_t nLutEdgeSize3d = 17;
lut3d.resize( nLutEdgeSize3d*nLutEdgeSize3d*nLutEdgeSize3d*4 );
std::vector<uint16_t> lut1d;
uint32_t nLutSize1d = 4096;
lut1d.resize( nLutSize1d*4 );
if (!g_ColorMgmtLuts[nInputEOTF].vk_lut1d) if (!g_ColorMgmtLuts[nInputEOTF].vk_lut1d)
g_ColorMgmtLuts[nInputEOTF].vk_lut1d = vulkan_create_1d_lut(4096); g_ColorMgmtLuts[nInputEOTF].vk_lut1d = vulkan_create_1d_lut(nLutSize1d);
if (!g_ColorMgmtLuts[nInputEOTF].vk_lut3d) if (!g_ColorMgmtLuts[nInputEOTF].vk_lut3d)
g_ColorMgmtLuts[nInputEOTF].vk_lut3d = vulkan_create_3d_lut(17, 17, 17); g_ColorMgmtLuts[nInputEOTF].vk_lut3d = vulkan_create_3d_lut(nLutEdgeSize3d, nLutEdgeSize3d, nLutEdgeSize3d);
displaycolorimetry_t inputColorimetry{}; if ( g_ColorMgmtLutsOverride[nInputEOTF].HasLuts() )
colormapping_t colorMapping{};
tonemapping_t tonemapping{};
tonemapping.bUseShaper = true;
EOTF inputEOTF = static_cast<EOTF>( nInputEOTF );
float flGain = 1.f;
lut3d_t * pLook = g_ColorMgmtLooks[nInputEOTF].lutEdgeSize > 0 ? &g_ColorMgmtLooks[nInputEOTF] : nullptr;
if ( inputEOTF == EOTF_Gamma22 )
{ {
flGain = g_ColorMgmt.pending.flSDRInputGain; memcpy(g_ColorMgmtLuts[nInputEOTF].lut1d, g_ColorMgmtLutsOverride[nInputEOTF].lut1d, sizeof(g_ColorMgmtLutsOverride[nInputEOTF].lut1d));
if ( g_ColorMgmt.pending.outputEncodingEOTF == EOTF_Gamma22 ) memcpy(g_ColorMgmtLuts[nInputEOTF].lut3d, g_ColorMgmtLutsOverride[nInputEOTF].lut3d, sizeof(g_ColorMgmtLutsOverride[nInputEOTF].lut3d));
{
// 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 = g_ColorMgmt.pending.flSDROnHDRBrightness;
// xwm_log.infof("G22 -> PQ");
}
// The final display colorimetry is used to build the output mapping, as we want a gamut-aware handling
// for sdrGamutWideness indepdendent of the output encoding (for SDR data), and when mapping SDR -> PQ output
// we only want to utilize a portion of the gamut the actual display can reproduce
buildSDRColorimetry( &inputColorimetry, &colorMapping, g_ColorMgmt.pending.sdrGamutWideness, displayColorimetry );
}
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 = 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 = 1.f;
// xwm_log.infof("PQ -> PQ");
}
buildPQColorimetry( &inputColorimetry, &colorMapping, displayColorimetry );
}
calcColorTransform( &lut1d[0], nLutSize1d, &lut3d[0], nLutEdgeSize3d, inputColorimetry, inputEOTF,
outputEncodingColorimetry, g_ColorMgmt.pending.outputEncodingEOTF,
colorMapping, g_ColorMgmt.pending.nightmode, tonemapping, pLook, flGain );
if ( !g_ColorMgmtLutsOverride[nInputEOTF].lut3d.empty() && !g_ColorMgmtLutsOverride[nInputEOTF].lut1d.empty() )
{
g_ColorMgmtLuts[nInputEOTF].lut1d = g_ColorMgmtLutsOverride[nInputEOTF].lut1d;
g_ColorMgmtLuts[nInputEOTF].lut3d = g_ColorMgmtLutsOverride[nInputEOTF].lut3d;
}
else if ( !lut3d.empty() && !lut1d.empty() )
{
g_ColorMgmtLuts[nInputEOTF].lut3d = std::move(lut3d);
g_ColorMgmtLuts[nInputEOTF].lut1d = std::move(lut1d);
} }
else else
{ {
g_ColorMgmtLuts[nInputEOTF].reset(); displaycolorimetry_t inputColorimetry{};
colormapping_t colorMapping{};
tonemapping_t tonemapping{};
tonemapping.bUseShaper = true;
EOTF inputEOTF = static_cast<EOTF>( nInputEOTF );
float flGain = 1.f;
lut3d_t * pLook = g_ColorMgmtLooks[nInputEOTF].lutEdgeSize > 0 ? &g_ColorMgmtLooks[nInputEOTF] : nullptr;
if ( inputEOTF == EOTF_Gamma22 )
{
flGain = g_ColorMgmt.pending.flSDRInputGain;
if ( g_ColorMgmt.pending.outputEncodingEOTF == EOTF_Gamma22 )
{
// 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 = g_ColorMgmt.pending.flSDROnHDRBrightness;
// xwm_log.infof("G22 -> PQ");
}
// The final display colorimetry is used to build the output mapping, as we want a gamut-aware handling
// for sdrGamutWideness indepdendent of the output encoding (for SDR data), and when mapping SDR -> PQ output
// we only want to utilize a portion of the gamut the actual display can reproduce
buildSDRColorimetry( &inputColorimetry, &colorMapping, g_ColorMgmt.pending.sdrGamutWideness, displayColorimetry );
}
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 = 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 = 1.f;
// xwm_log.infof("PQ -> PQ");
}
buildPQColorimetry( &inputColorimetry, &colorMapping, displayColorimetry );
}
calcColorTransform( g_ColorMgmtLuts[nInputEOTF].lut1d, nLutSize1d, g_ColorMgmtLuts[nInputEOTF].lut3d, nLutEdgeSize3d, inputColorimetry, inputEOTF,
outputEncodingColorimetry, g_ColorMgmt.pending.outputEncodingEOTF,
colorMapping, g_ColorMgmt.pending.nightmode, tonemapping, pLook, flGain );
} }
if (!g_ColorMgmtLuts[nInputEOTF].lut3d.empty() && !g_ColorMgmtLuts[nInputEOTF].lut1d.empty()) g_ColorMgmtLuts[nInputEOTF].bHasLut1D = true;
vulkan_update_luts(g_ColorMgmtLuts[nInputEOTF].vk_lut1d, g_ColorMgmtLuts[nInputEOTF].vk_lut3d, g_ColorMgmtLuts[nInputEOTF].lut1d.data(), g_ColorMgmtLuts[nInputEOTF].lut3d.data()); g_ColorMgmtLuts[nInputEOTF].bHasLut3D = true;
vulkan_update_luts(g_ColorMgmtLuts[nInputEOTF].vk_lut1d, g_ColorMgmtLuts[nInputEOTF].vk_lut3d, g_ColorMgmtLuts[nInputEOTF].lut1d, g_ColorMgmtLuts[nInputEOTF].lut3d);
} }
} }
else else
@ -378,8 +364,8 @@ bool set_color_mgmt_enabled( bool bEnabled )
bool set_color_3dlut_override(const char *path) bool set_color_3dlut_override(const char *path)
{ {
int nLutIndex = EOTF_Gamma22; int nLutIndex = EOTF_Gamma22;
g_ColorMgmtLutsOverride[nLutIndex].lut3d.clear();
g_ColorMgmt.pending.externalDirtyCtr++; g_ColorMgmt.pending.externalDirtyCtr++;
g_ColorMgmtLutsOverride[nLutIndex].bHasLut3D = false;
FILE *f = fopen(path, "rb"); FILE *f = fopen(path, "rb");
if (!f) { if (!f) {
@ -396,10 +382,8 @@ bool set_color_3dlut_override(const char *path)
return true; return true;
} }
auto data = std::vector<uint16_t>(elems); fread(g_ColorMgmtLutsOverride[nLutIndex].lut3d, elems, sizeof(uint16_t), f);
fread(data.data(), elems, sizeof(uint16_t), f); g_ColorMgmtLutsOverride[nLutIndex].bHasLut3D = true;
g_ColorMgmtLutsOverride[nLutIndex].lut3d = std::move(data);
return true; return true;
} }
@ -407,8 +391,8 @@ bool set_color_3dlut_override(const char *path)
bool set_color_shaperlut_override(const char *path) bool set_color_shaperlut_override(const char *path)
{ {
int nLutIndex = EOTF_Gamma22; int nLutIndex = EOTF_Gamma22;
g_ColorMgmtLutsOverride[nLutIndex].lut1d.clear();
g_ColorMgmt.pending.externalDirtyCtr++; g_ColorMgmt.pending.externalDirtyCtr++;
g_ColorMgmtLutsOverride[nLutIndex].bHasLut1D = false;
FILE *f = fopen(path, "rb"); FILE *f = fopen(path, "rb");
if (!f) { if (!f) {
@ -425,10 +409,8 @@ bool set_color_shaperlut_override(const char *path)
return true; return true;
} }
auto data = std::vector<uint16_t>(elems); fread(g_ColorMgmtLutsOverride[nLutIndex].lut1d, elems, sizeof(uint16_t), f);
fread(data.data(), elems, sizeof(uint16_t), f); g_ColorMgmtLutsOverride[nLutIndex].bHasLut1D = true;
g_ColorMgmtLutsOverride[nLutIndex].lut1d = std::move(data);
return true; return true;
} }
@ -2360,10 +2342,11 @@ paint_all(bool async)
for (uint32_t i = 0; i < EOTF_Count; i++) for (uint32_t i = 0; i < EOTF_Count; i++)
{ {
if (!g_ColorMgmtLuts[i].lut1d.empty()) if (g_ColorMgmtLuts[i].HasLuts())
{
frameInfo.shaperLut[i] = g_ColorMgmtLuts[i].vk_lut1d; frameInfo.shaperLut[i] = g_ColorMgmtLuts[i].vk_lut1d;
if (!g_ColorMgmtLuts[i].lut3d.empty())
frameInfo.lut3D[i] = g_ColorMgmtLuts[i].vk_lut3d; frameInfo.lut3D[i] = g_ColorMgmtLuts[i].vk_lut3d;
}
} }
if ( !BIsNested() && g_bOutputHDREnabled ) if ( !BIsNested() && g_bOutputHDREnabled )