Skip to content

Commit 51eb53b

Browse files
committed
Independently specify EOTF for SDR content and monitors
1 parent 6f406f2 commit 51eb53b

File tree

6 files changed

+41
-20
lines changed

6 files changed

+41
-20
lines changed

src/config/ConfigDescriptions.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,10 +1543,11 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
15431543
.data = SConfigOptionDescription::SChoiceData{0, "disable,always,ondemand,ignore"},
15441544
},
15451545
SConfigOptionDescription{
1546-
.value = "render:cm_itm_tf",
1547-
.description = "Default transfer function for displaying untagged SDR surfaces in HDR mode. 0 - sRGB, 1 - Gamma 2.2",
1546+
.value = "render:cm_srgb_eotf",
1547+
.description = "Default transfer function for displaying sRGB apps in HDR apps. 0 - Treat unspecified as sRGB, 1 - Treat unspecified as Gamma 2.2, 2 - Treat "
1548+
"unspecified and sRGB as Gamma 2.2",
15481549
.type = CONFIG_OPTION_CHOICE,
1549-
.data = SConfigOptionDescription::SChoiceData{0, "srgb,gamma22"},
1550+
.data = SConfigOptionDescription::SChoiceData{0, "srgb,gamma22,gamma22force"},
15501551
},
15511552

15521553
/*

src/config/ConfigManager.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,7 @@ CConfigManager::CConfigManager() {
781781
registerConfigVar("render:cm_auto_hdr", Hyprlang::INT{1});
782782
registerConfigVar("render:new_render_scheduling", Hyprlang::INT{0});
783783
registerConfigVar("render:non_shader_cm", Hyprlang::INT{2});
784-
registerConfigVar("render:cm_itm_tf", Hyprlang::INT{0});
784+
registerConfigVar("render:cm_srgb_eotf", Hyprlang::INT{0});
785785

786786
registerConfigVar("ecosystem:no_update_news", Hyprlang::INT{0});
787787
registerConfigVar("ecosystem:no_donation_nag", Hyprlang::INT{0});
@@ -843,6 +843,7 @@ CConfigManager::CConfigManager() {
843843
m_config->addSpecialConfigValue("monitorv2", "mirror", {STRVAL_EMPTY});
844844
m_config->addSpecialConfigValue("monitorv2", "bitdepth", {STRVAL_EMPTY}); // TODO use correct type
845845
m_config->addSpecialConfigValue("monitorv2", "cm", {"auto"});
846+
m_config->addSpecialConfigValue("monitorv2", "cm_srgb_eotf", Hyprlang::INT{0});
846847
m_config->addSpecialConfigValue("monitorv2", "sdrbrightness", Hyprlang::FLOAT{1.0});
847848
m_config->addSpecialConfigValue("monitorv2", "sdrsaturation", Hyprlang::FLOAT{1.0});
848849
m_config->addSpecialConfigValue("monitorv2", "vrr", Hyprlang::INT{0});
@@ -1116,6 +1117,9 @@ std::optional<std::string> CConfigManager::handleMonitorv2(const std::string& ou
11161117
VAL = m_config->getSpecialConfigValuePtr("monitorv2", "cm", output.c_str());
11171118
if (VAL && VAL->m_bSetByUser)
11181119
parser.parseCM(std::any_cast<Hyprlang::STRING>(VAL->getValue()));
1120+
VAL = m_config->getSpecialConfigValuePtr("monitorv2", "cm_srgb_eotf", output.c_str());
1121+
if (VAL && VAL->m_bSetByUser)
1122+
parser.rule().cmSrgbEotf = std::any_cast<Hyprlang::INT>(VAL->getValue());
11191123
VAL = m_config->getSpecialConfigValuePtr("monitorv2", "sdrbrightness", output.c_str());
11201124
if (VAL && VAL->m_bSetByUser)
11211125
parser.rule().sdrBrightness = std::any_cast<Hyprlang::FLOAT>(VAL->getValue());

src/helpers/Monitor.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -465,32 +465,39 @@ void CMonitor::onDisconnect(bool destroy) {
465465
std::erase_if(g_pCompositor->m_monitors, [&](PHLMONITOR& el) { return el.get() == this; });
466466
}
467467

468-
void CMonitor::applyCMType(eCMType cmType) {
468+
void CMonitor::applyCMType(eCMType cmType, int cmSrgbEotf) {
469469
auto oldImageDescription = m_imageDescription;
470470
switch (cmType) {
471-
case CM_SRGB: m_imageDescription = {}; break; // assumes SImageDescirption defaults to sRGB
471+
case CM_SRGB:
472+
m_imageDescription = {.transferFunction = cmSrgbEotf == 0 ? NColorManagement::CM_TRANSFER_FUNCTION_SRGB : NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22};
473+
break; // assumes SImageDescription defaults to sRGB
472474
case CM_WIDE:
473-
m_imageDescription = {.primariesNameSet = true,
475+
m_imageDescription = {.transferFunction = cmSrgbEotf == 0 ? NColorManagement::CM_TRANSFER_FUNCTION_SRGB : NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22,
476+
.primariesNameSet = true,
474477
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
475478
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020)};
476479
break;
477480
case CM_DCIP3:
478-
m_imageDescription = {.primariesNameSet = true,
481+
m_imageDescription = {.transferFunction = cmSrgbEotf == 0 ? NColorManagement::CM_TRANSFER_FUNCTION_SRGB : NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22,
482+
.primariesNameSet = true,
479483
.primariesNamed = NColorManagement::CM_PRIMARIES_DCI_P3,
480484
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_DCI_P3)};
481485
break;
482486
case CM_DP3:
483-
m_imageDescription = {.primariesNameSet = true,
487+
m_imageDescription = {.transferFunction = cmSrgbEotf == 0 ? NColorManagement::CM_TRANSFER_FUNCTION_SRGB : NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22,
488+
.primariesNameSet = true,
484489
.primariesNamed = NColorManagement::CM_PRIMARIES_DISPLAY_P3,
485490
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_DISPLAY_P3)};
486491
break;
487492
case CM_ADOBE:
488-
m_imageDescription = {.primariesNameSet = true,
493+
m_imageDescription = {.transferFunction = cmSrgbEotf == 0 ? NColorManagement::CM_TRANSFER_FUNCTION_SRGB : NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22,
494+
.primariesNameSet = true,
489495
.primariesNamed = NColorManagement::CM_PRIMARIES_ADOBE_RGB,
490496
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_ADOBE_RGB)};
491497
break;
492498
case CM_EDID:
493-
m_imageDescription = {.primariesNameSet = false,
499+
m_imageDescription = {.transferFunction = cmSrgbEotf == 0 ? NColorManagement::CM_TRANSFER_FUNCTION_SRGB : NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22,
500+
.primariesNameSet = true,
494501
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
495502
.primaries = {
496503
.red = {.x = m_output->parsedEDID.chromaticityCoords->red.x, .y = m_output->parsedEDID.chromaticityCoords->red.y},
@@ -868,14 +875,16 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) {
868875
default: break;
869876
}
870877

878+
m_cmSrgbEotf = RULE->cmSrgbEotf;
879+
871880
m_sdrMinLuminance = RULE->sdrMinLuminance;
872881
m_sdrMaxLuminance = RULE->sdrMaxLuminance;
873882

874883
m_minLuminance = RULE->minLuminance;
875884
m_maxLuminance = RULE->maxLuminance;
876885
m_maxAvgLuminance = RULE->maxAvgLuminance;
877886

878-
applyCMType(m_cmType);
887+
applyCMType(m_cmType, m_cmSrgbEotf);
879888

880889
m_sdrSaturation = RULE->sdrSaturation;
881890
m_sdrBrightness = RULE->sdrBrightness;

src/helpers/Monitor.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ struct SMonitorRule {
5959
std::string mirrorOf = "";
6060
bool enable10bit = false;
6161
eCMType cmType = CM_SRGB;
62+
int cmSrgbEotf = 0;
6263
float sdrSaturation = 1.0f; // SDR -> HDR
6364
float sdrBrightness = 1.0f; // SDR -> HDR
6465

@@ -142,6 +143,7 @@ class CMonitor {
142143
bool m_vrrActive = false; // this can be TRUE even if VRR is not active in the case that this display does not support it.
143144
bool m_enabled10bit = false; // as above, this can be TRUE even if 10 bit failed.
144145
eCMType m_cmType = CM_SRGB;
146+
int m_cmSrgbEotf = 0;
145147
float m_sdrSaturation = 1.0f;
146148
float m_sdrBrightness = 1.0f;
147149
float m_sdrMinLuminance = 0.2f;
@@ -283,7 +285,7 @@ class CMonitor {
283285
// methods
284286
void onConnect(bool noRule);
285287
void onDisconnect(bool destroy = false);
286-
void applyCMType(eCMType cmType);
288+
void applyCMType(eCMType cmType, int cmSrgbEotf);
287289
bool applyMonitorRule(SMonitorRule* pMonitorRule, bool force = false);
288290
void addDamage(const pixman_region32_t* rg);
289291
void addDamage(const CRegion& rg);

src/render/OpenGL.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,18 +1551,20 @@ void CHyprOpenGLImpl::renderTexture(SP<CTexture> tex, const CBox& box, STextureR
15511551
static std::map<std::pair<uint32_t, uint32_t>, std::array<GLfloat, 9>> primariesConversionCache;
15521552

15531553
static bool isSDR2HDR(const NColorManagement::SImageDescription& imageDescription, const NColorManagement::SImageDescription& targetImageDescription) {
1554-
// might be too strict
1555-
return imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_SRGB &&
1554+
return (imageDescription.transferFunction != NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ &&
1555+
imageDescription.transferFunction != NColorManagement::CM_TRANSFER_FUNCTION_HLG) &&
15561556
(targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ||
15571557
targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_HLG);
15581558
}
15591559

15601560
void CHyprOpenGLImpl::passCMUniforms(SShader& shader, const NColorManagement::SImageDescription& imageDescription,
15611561
const NColorManagement::SImageDescription& targetImageDescription, bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance) {
1562-
const bool needsSDRmod = modifySDR && isSDR2HDR(imageDescription, targetImageDescription);
1563-
static auto PITMTF = CConfigValue<Hyprlang::INT>("render:cm_itm_tf");
1562+
static auto PSRGBEOTF = CConfigValue<Hyprlang::INT>("render:cm_srgb_eotf");
15641563

1565-
if (needsSDRmod && m_renderData.surface.valid() && !m_renderData.surface->m_colorManagement.valid() && *PITMTF == 1) {
1564+
if (m_renderData.surface.valid() &&
1565+
((!m_renderData.surface->m_colorManagement.valid() && *PSRGBEOTF >= 1) ||
1566+
(*PSRGBEOTF == 2 && m_renderData.surface->m_colorManagement.valid() &&
1567+
imageDescription.transferFunction == NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_SRGB))) {
15661568
shader.setUniformInt(SHADER_SOURCE_TF, NColorManagement::eTransferFunction::CM_TRANSFER_FUNCTION_GAMMA22);
15671569
} else {
15681570
shader.setUniformInt(SHADER_SOURCE_TF, imageDescription.transferFunction);
@@ -1580,6 +1582,8 @@ void CHyprOpenGLImpl::passCMUniforms(SShader& shader, const NColorManagement::SI
15801582
};
15811583
shader.setUniformMatrix4x2fv(SHADER_TARGET_PRIMARIES, 1, false, glTargetPrimaries);
15821584

1585+
const bool needsSDRmod = modifySDR && isSDR2HDR(imageDescription, targetImageDescription);
1586+
15831587
shader.setUniformFloat2(SHADER_SRC_TF_RANGE, imageDescription.getTFMinLuminance(needsSDRmod ? sdrMinLuminance : -1),
15841588
imageDescription.getTFMaxLuminance(needsSDRmod ? sdrMaxLuminance : -1));
15851589
shader.setUniformFloat2(SHADER_DST_TF_RANGE, targetImageDescription.getTFMinLuminance(needsSDRmod ? sdrMinLuminance : -1),

src/render/Renderer.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1555,9 +1555,10 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
15551555
if (*PAUTOHDR && !(pMonitor->inHDR() && configuredHDR)) {
15561556
// modify or restore monitor image description for auto-hdr
15571557
// FIXME ok for now, will need some other logic if monitor image description can be modified some other way
1558-
const auto targetCM = wantHDR ? (*PAUTOHDR == 2 ? CM_HDR_EDID : CM_HDR) : pMonitor->m_cmType;
1558+
const auto targetCM = wantHDR ? (*PAUTOHDR == 2 ? CM_HDR_EDID : CM_HDR) : pMonitor->m_cmType;
1559+
const auto targetSRGBEOTF = pMonitor->m_cmSrgbEotf;
15591560
Debug::log(INFO, "[CM] Auto HDR: changing monitor cm to {}", sc<uint8_t>(targetCM));
1560-
pMonitor->applyCMType(targetCM);
1561+
pMonitor->applyCMType(targetCM, targetSRGBEOTF);
15611562
pMonitor->m_previousFSWindow.reset(); // trigger CTM update
15621563
}
15631564
Debug::log(INFO, wantHDR ? "[CM] Updating HDR metadata from monitor" : "[CM] Restoring SDR mode");

0 commit comments

Comments
 (0)