Skip to content

Commit cf7e3aa

Browse files
authored
renderer/cm: Add automatic hdr (#9785)
1 parent c7c8ca4 commit cf7e3aa

File tree

5 files changed

+94
-68
lines changed

5 files changed

+94
-68
lines changed

src/config/ConfigDescriptions.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,6 +1482,12 @@ inline static const std::vector<SConfigOptionDescription> CONFIG_OPTIONS = {
14821482
.type = CONFIG_OPTION_BOOL,
14831483
.data = SConfigOptionDescription::SBoolData{true},
14841484
},
1485+
SConfigOptionDescription{
1486+
.value = "render:cm_auto_hdr",
1487+
.description = "Auto-switch to hdr mode when fullscreen app is in hdr, 0 - off, 1 - hdr, 2 - hdredid (cm_fs_passthrough can switch to hdr even when this setting is off)",
1488+
.type = CONFIG_OPTION_INT,
1489+
.data = SConfigOptionDescription::SRangeData{.value = 1, .min = 0, .max = 2},
1490+
},
14851491

14861492
/*
14871493
* cursor:

src/config/ConfigManager.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,7 @@ CConfigManager::CConfigManager() {
748748
registerConfigVar("render:cm_fs_passthrough", Hyprlang::INT{2});
749749
registerConfigVar("render:cm_enabled", Hyprlang::INT{1});
750750
registerConfigVar("render:send_content_type", Hyprlang::INT{1});
751+
registerConfigVar("render:cm_auto_hdr", Hyprlang::INT{1});
751752

752753
registerConfigVar("ecosystem:no_update_news", Hyprlang::INT{0});
753754
registerConfigVar("ecosystem:no_donation_nag", Hyprlang::INT{0});

src/helpers/Monitor.cpp

Lines changed: 56 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,58 @@ void CMonitor::onDisconnect(bool destroy) {
419419
std::erase_if(g_pCompositor->m_monitors, [&](PHLMONITOR& el) { return el.get() == this; });
420420
}
421421

422+
void CMonitor::applyCMType(eCMType cmType) {
423+
switch (cmType) {
424+
case CM_SRGB: m_imageDescription = {}; break; // assumes SImageDescirption defaults to sRGB
425+
case CM_WIDE:
426+
m_imageDescription = {.primariesNameSet = true,
427+
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
428+
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020)};
429+
break;
430+
case CM_EDID:
431+
m_imageDescription = {.primariesNameSet = false,
432+
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
433+
.primaries = {
434+
.red = {.x = m_output->parsedEDID.chromaticityCoords->red.x, .y = m_output->parsedEDID.chromaticityCoords->red.y},
435+
.green = {.x = m_output->parsedEDID.chromaticityCoords->green.x, .y = m_output->parsedEDID.chromaticityCoords->green.y},
436+
.blue = {.x = m_output->parsedEDID.chromaticityCoords->blue.x, .y = m_output->parsedEDID.chromaticityCoords->blue.y},
437+
.white = {.x = m_output->parsedEDID.chromaticityCoords->white.x, .y = m_output->parsedEDID.chromaticityCoords->white.y},
438+
}};
439+
break;
440+
case CM_HDR:
441+
m_imageDescription = {.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
442+
.primariesNameSet = true,
443+
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
444+
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
445+
.luminances = {.min = 0, .max = 10000, .reference = 203}};
446+
break;
447+
case CM_HDR_EDID:
448+
m_imageDescription = {.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
449+
.primariesNameSet = false,
450+
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
451+
.primaries = m_output->parsedEDID.chromaticityCoords.has_value() ?
452+
NColorManagement::SPCPRimaries{
453+
.red = {.x = m_output->parsedEDID.chromaticityCoords->red.x, .y = m_output->parsedEDID.chromaticityCoords->red.y},
454+
.green = {.x = m_output->parsedEDID.chromaticityCoords->green.x, .y = m_output->parsedEDID.chromaticityCoords->green.y},
455+
.blue = {.x = m_output->parsedEDID.chromaticityCoords->blue.x, .y = m_output->parsedEDID.chromaticityCoords->blue.y},
456+
.white = {.x = m_output->parsedEDID.chromaticityCoords->white.x, .y = m_output->parsedEDID.chromaticityCoords->white.y},
457+
} :
458+
NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
459+
.luminances = {.min = m_output->parsedEDID.hdrMetadata->desiredContentMinLuminance,
460+
.max = m_output->parsedEDID.hdrMetadata->desiredContentMaxLuminance,
461+
.reference = m_output->parsedEDID.hdrMetadata->desiredMaxFrameAverageLuminance}};
462+
463+
break;
464+
default: UNREACHABLE();
465+
}
466+
if (m_minLuminance >= 0)
467+
m_imageDescription.luminances.min = m_minLuminance;
468+
if (m_maxLuminance >= 0)
469+
m_imageDescription.luminances.max = m_maxLuminance;
470+
if (m_maxAvgLuminance >= 0)
471+
m_imageDescription.luminances.reference = m_maxAvgLuminance;
472+
}
473+
422474
bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) {
423475

424476
static auto PDISABLESCALECHECKS = CConfigValue<Hyprlang::INT>("debug:disable_scale_checks");
@@ -748,62 +800,15 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) {
748800
case CM_HDR_EDID: m_cmType = supportsHDR() ? m_cmType : CM_SRGB; break;
749801
default: break;
750802
}
751-
switch (m_cmType) {
752-
case CM_SRGB: m_imageDescription = {}; break; // assumes SImageDescirption defaults to sRGB
753-
case CM_WIDE:
754-
m_imageDescription = {.primariesNameSet = true,
755-
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
756-
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020)};
757-
break;
758-
case CM_EDID:
759-
m_imageDescription = {.primariesNameSet = false,
760-
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
761-
.primaries = {
762-
.red = {.x = m_output->parsedEDID.chromaticityCoords->red.x, .y = m_output->parsedEDID.chromaticityCoords->red.y},
763-
.green = {.x = m_output->parsedEDID.chromaticityCoords->green.x, .y = m_output->parsedEDID.chromaticityCoords->green.y},
764-
.blue = {.x = m_output->parsedEDID.chromaticityCoords->blue.x, .y = m_output->parsedEDID.chromaticityCoords->blue.y},
765-
.white = {.x = m_output->parsedEDID.chromaticityCoords->white.x, .y = m_output->parsedEDID.chromaticityCoords->white.y},
766-
}};
767-
break;
768-
case CM_HDR:
769-
m_imageDescription = {.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
770-
.primariesNameSet = true,
771-
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
772-
.primaries = NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
773-
.luminances = {.min = 0, .max = 10000, .reference = 203}};
774-
break;
775-
case CM_HDR_EDID:
776-
m_imageDescription = {.transferFunction = NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ,
777-
.primariesNameSet = false,
778-
.primariesNamed = NColorManagement::CM_PRIMARIES_BT2020,
779-
.primaries = m_output->parsedEDID.chromaticityCoords.has_value() ?
780-
NColorManagement::SPCPRimaries{
781-
.red = {.x = m_output->parsedEDID.chromaticityCoords->red.x, .y = m_output->parsedEDID.chromaticityCoords->red.y},
782-
.green = {.x = m_output->parsedEDID.chromaticityCoords->green.x, .y = m_output->parsedEDID.chromaticityCoords->green.y},
783-
.blue = {.x = m_output->parsedEDID.chromaticityCoords->blue.x, .y = m_output->parsedEDID.chromaticityCoords->blue.y},
784-
.white = {.x = m_output->parsedEDID.chromaticityCoords->white.x, .y = m_output->parsedEDID.chromaticityCoords->white.y},
785-
} :
786-
NColorManagement::getPrimaries(NColorManagement::CM_PRIMARIES_BT2020),
787-
.luminances = {.min = m_output->parsedEDID.hdrMetadata->desiredContentMinLuminance,
788-
.max = m_output->parsedEDID.hdrMetadata->desiredContentMaxLuminance,
789-
.reference = m_output->parsedEDID.hdrMetadata->desiredMaxFrameAverageLuminance}};
790-
791-
break;
792-
default: UNREACHABLE();
793-
}
794803

795804
m_sdrMinLuminance = RULE->sdrMinLuminance;
796805
m_sdrMaxLuminance = RULE->sdrMaxLuminance;
797806

798-
m_minLuminance = RULE->minLuminance;
799-
if (m_minLuminance >= 0)
800-
m_imageDescription.luminances.min = m_minLuminance;
801-
m_maxLuminance = RULE->maxLuminance;
802-
if (m_maxLuminance >= 0)
803-
m_imageDescription.luminances.max = m_maxLuminance;
807+
m_minLuminance = RULE->minLuminance;
808+
m_maxLuminance = RULE->maxLuminance;
804809
m_maxAvgLuminance = RULE->maxAvgLuminance;
805-
if (m_maxAvgLuminance >= 0)
806-
m_imageDescription.luminances.reference = m_maxAvgLuminance;
810+
811+
applyCMType(m_cmType);
807812
if (oldImageDescription != m_imageDescription)
808813
PROTO::colorManagement->onMonitorImageDescriptionChanged(m_self);
809814

src/helpers/Monitor.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ class CMonitor {
200200
// methods
201201
void onConnect(bool noRule);
202202
void onDisconnect(bool destroy = false);
203+
void applyCMType(eCMType cmType);
203204
bool applyMonitorRule(SMonitorRule* pMonitorRule, bool force = false);
204205
void addDamage(const pixman_region32_t* rg);
205206
void addDamage(const CRegion& rg);

src/render/Renderer.cpp

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "../hyprerror/HyprError.hpp"
2727
#include "../debug/HyprDebugOverlay.hpp"
2828
#include "../debug/HyprNotificationOverlay.hpp"
29+
#include "helpers/Monitor.hpp"
2930
#include "pass/TexPassElement.hpp"
3031
#include "pass/ClearPassElement.hpp"
3132
#include "pass/RectPassElement.hpp"
@@ -1489,9 +1490,13 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, A
14891490
}
14901491

14911492
bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
1492-
static auto PCT = CConfigValue<Hyprlang::INT>("render:send_content_type");
1493-
static auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
1494-
const bool PHDR = pMonitor->m_imageDescription.transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ;
1493+
static auto PCT = CConfigValue<Hyprlang::INT>("render:send_content_type");
1494+
static auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
1495+
static auto PAUTOHDR = CConfigValue<Hyprlang::INT>("render:cm_auto_hdr");
1496+
1497+
const bool configuredHDR = (pMonitor->m_cmType == CM_HDR_EDID || pMonitor->m_cmType == CM_HDR);
1498+
const bool hdsIsActive = pMonitor->m_output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2;
1499+
bool wantHDR = configuredHDR;
14951500

14961501
if (pMonitor->supportsHDR()) {
14971502
// HDR metadata determined by
@@ -1504,32 +1509,40 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
15041509
// fullscreen SDR surface: monitor settings
15051510
// fullscreen HDR surface: surface settings
15061511

1507-
bool wantHDR = PHDR;
15081512
bool hdrIsHandled = false;
1509-
if (*PPASS && pMonitor->m_activeWorkspace && pMonitor->m_activeWorkspace->m_hasFullscreenWindow && pMonitor->m_activeWorkspace->m_fullscreenMode == FSMODE_FULLSCREEN) {
1513+
if (pMonitor->m_activeWorkspace && pMonitor->m_activeWorkspace->m_hasFullscreenWindow && pMonitor->m_activeWorkspace->m_fullscreenMode == FSMODE_FULLSCREEN) {
15101514
const auto WINDOW = pMonitor->m_activeWorkspace->getFullscreenWindow();
15111515
const auto ROOT_SURF = WINDOW->m_wlSurface->resource();
15121516
const auto SURF =
15131517
ROOT_SURF->findFirstPreorder([ROOT_SURF](SP<CWLSurfaceResource> surf) { return surf->m_colorManagement.valid() && surf->extends() == ROOT_SURF->extends(); });
15141518

1515-
wantHDR = PHDR && *PPASS == 2;
1516-
1517-
// we have a surface with image description and it's allowed by wantHDR
1518-
if (SURF && SURF->m_colorManagement.valid() && SURF->m_colorManagement->hasImageDescription() &&
1519-
(!wantHDR || SURF->m_colorManagement->imageDescription().transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ)) {
1520-
bool needsHdrMetadataUpdate = SURF->m_colorManagement->needsHdrMetadataUpdate() || pMonitor->m_previousFSWindow != WINDOW;
1521-
if (SURF->m_colorManagement->needsHdrMetadataUpdate())
1522-
SURF->m_colorManagement->setHDRMetadata(createHDRMetadata(SURF->m_colorManagement->imageDescription(), pMonitor->m_output->parsedEDID));
1523-
if (needsHdrMetadataUpdate)
1524-
pMonitor->m_output->state->setHDRMetadata(SURF->m_colorManagement->hdrMetadata());
1525-
hdrIsHandled = true;
1519+
// we have a surface with image description
1520+
if (SURF && SURF->m_colorManagement.valid() && SURF->m_colorManagement->hasImageDescription()) {
1521+
const bool surfaceIsHDR = SURF->m_colorManagement->imageDescription().transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ;
1522+
if (*PPASS == 1 || (*PPASS == 2 && surfaceIsHDR)) {
1523+
// passthrough
1524+
bool needsHdrMetadataUpdate = SURF->m_colorManagement->needsHdrMetadataUpdate() || pMonitor->m_previousFSWindow != WINDOW;
1525+
if (SURF->m_colorManagement->needsHdrMetadataUpdate())
1526+
SURF->m_colorManagement->setHDRMetadata(createHDRMetadata(SURF->m_colorManagement->imageDescription(), pMonitor->m_output->parsedEDID));
1527+
if (needsHdrMetadataUpdate)
1528+
pMonitor->m_output->state->setHDRMetadata(SURF->m_colorManagement->hdrMetadata());
1529+
hdrIsHandled = true;
1530+
} else if (*PAUTOHDR && surfaceIsHDR)
1531+
wantHDR = true; // auto-hdr: hdr on
15261532
}
15271533

15281534
pMonitor->m_previousFSWindow = WINDOW;
15291535
}
1536+
15301537
if (!hdrIsHandled) {
1531-
if ((pMonitor->m_output->state->state().hdrMetadata.hdmi_metadata_type1.eotf == 2) != wantHDR)
1538+
if (hdsIsActive != wantHDR) {
1539+
if (*PAUTOHDR && !(hdsIsActive && configuredHDR)) {
1540+
// modify or restore monitor image description for auto-hdr
1541+
// FIXME ok for now, will need some other logic if monitor image description can be modified some other way
1542+
pMonitor->applyCMType(wantHDR ? (*PAUTOHDR == 2 ? CM_HDR_EDID : CM_HDR) : pMonitor->m_cmType);
1543+
}
15321544
pMonitor->m_output->state->setHDRMetadata(wantHDR ? createHDRMetadata(pMonitor->m_imageDescription, pMonitor->m_output->parsedEDID) : NO_HDR_METADATA);
1545+
}
15331546
pMonitor->m_previousFSWindow.reset();
15341547
}
15351548
}

0 commit comments

Comments
 (0)