From 0e98ddc9c313d6653610dc8d0856382af97cb5ec Mon Sep 17 00:00:00 2001 From: Will Temple <666532+willmtemple@users.noreply.github.com> Date: Sat, 8 Aug 2026 18:21:00 -0400 Subject: [PATCH] render/cm: re-send HDR metadata when its content changes (#15761) Compare the metadata we would send against what is already committed and send if there is any difference. Found this testing whether MaxCLL influences in-panel tonemapping. setHDRMetadata was only called when the monitor entered or left HDR or in some cases surrounding direct scanout. Changes to the metadata itself while the monitor stayed in HDR was computed and stored in the image description, but never sent. This particularly effects mastering data and min/max/max_avg luminance changes. Signed-off-by: Will Temple --- src/render/Renderer.cpp | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 76a05cec8..4c3274b1a 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include "../config/ConfigValue.hpp" #include "../config/ConfigManager.hpp" @@ -2297,6 +2299,14 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, P }; } +static bool hdrMetadataEqual(const hdr_output_metadata& a, const hdr_output_metadata& b) { + if (a.metadata_type != b.metadata_type) + return false; + + static_assert(std::has_unique_object_representations_v); + return std::memcmp(&a.hdmi_metadata_type1, &b.hdmi_metadata_type1, sizeof(a.hdmi_metadata_type1)); +} + void IHyprRenderer::handleFullscreenSettings(PHLMONITOR pMonitor) { static auto PCT = CConfigValue("render:send_content_type"); static auto PAUTOHDR = CConfigValue("render:cm_auto_hdr"); @@ -2350,18 +2360,20 @@ void IHyprRenderer::handleFullscreenSettings(PHLMONITOR pMonitor) { if (!hdrIsHandled) { const bool HDR_CHANGED = pMonitor->inHDR() != wantHDR; - if (HDR_CHANGED || pMonitor->m_hdrMetadataFromSurface) { - if (HDR_CHANGED && *PAUTOHDR && !(pMonitor->inHDR() && configuredHDR)) { - // modify or restore monitor image description for auto-hdr - // FIXME ok for now, will need some other logic if monitor image description can be modified some other way - const auto targetCM = wantHDR ? (*PAUTOHDR == 2 ? NCMType::CM_HDR_EDID : NCMType::CM_HDR) : pMonitor->m_cmType; - const auto targetSDREOTF = pMonitor->m_sdrEotf; - Log::logger->log(Log::INFO, "[CM] Auto HDR: changing monitor cm to {}", sc(targetCM)); - pMonitor->applyCMType(targetCM, targetSDREOTF); - pMonitor->m_previousFSWindow.reset(); // trigger CTM update - } + if (HDR_CHANGED && *PAUTOHDR && !(pMonitor->inHDR() && configuredHDR)) { + const auto targetCM = wantHDR ? (*PAUTOHDR == 2 ? NCMType::CM_HDR_EDID : NCMType::CM_HDR) : pMonitor->m_cmType; + const auto targetSDREOTF = pMonitor->m_sdrEotf; + Log::logger->log(Log::INFO, "[CM] Auto HDR: changing monitor cm to {}", sc(targetCM)); + pMonitor->applyCMType(targetCM, targetSDREOTF); + pMonitor->m_previousFSWindow.reset(); // trigger CTM update + } + + const auto WANTED = wantHDR ? createHDRMetadata(pMonitor->m_imageDescription->value(), pMonitor) : NO_HDR_METADATA; + const auto CURRENT = pMonitor->m_output->state->state().hdrMetadata; + + if (HDR_CHANGED || pMonitor->m_hdrMetadataFromSurface || (wantHDR && !hdrMetadataEqual(WANTED, CURRENT))) { Log::logger->log(Log::INFO, wantHDR ? "[CM] Updating HDR metadata from monitor" : "[CM] Restoring SDR mode"); - pMonitor->m_output->state->setHDRMetadata(wantHDR ? createHDRMetadata(pMonitor->m_imageDescription->value(), pMonitor) : NO_HDR_METADATA); + pMonitor->m_output->state->setHDRMetadata(WANTED); pMonitor->m_hdrMetadataFromSurface = false; } pMonitor->m_needsHDRupdate = true;