diff --git a/src/config/ConfigDescriptions.hpp b/src/config/ConfigDescriptions.hpp index 9081fd34e..207aa6f1d 100644 --- a/src/config/ConfigDescriptions.hpp +++ b/src/config/ConfigDescriptions.hpp @@ -1524,6 +1524,12 @@ inline static const std::vector CONFIG_OPTIONS = { .type = CONFIG_OPTION_BOOL, .data = SConfigOptionDescription::SBoolData{false}, }, + SConfigOptionDescription{ + .value = "render:non_shader_cm", + .description = "Enable CM without shader. 0 - disable, 1 - whenever possible, 2 - DS and passthrough only, 3 - don't block DS when non-shader CM isn't available", + .type = CONFIG_OPTION_CHOICE, + .data = SConfigOptionDescription::SChoiceData{0, "disable,always,ondemand,ignore"}, + }, /* * cursor: diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index d6dcba7e0..94db0c471 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -777,6 +777,7 @@ CConfigManager::CConfigManager() { registerConfigVar("render:send_content_type", Hyprlang::INT{1}); registerConfigVar("render:cm_auto_hdr", Hyprlang::INT{1}); registerConfigVar("render:new_render_scheduling", Hyprlang::INT{0}); + registerConfigVar("render:non_shader_cm", Hyprlang::INT{2}); registerConfigVar("ecosystem:no_update_news", Hyprlang::INT{0}); registerConfigVar("ecosystem:no_donation_nag", Hyprlang::INT{0}); diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index f38f009ff..273bc1c77 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -534,7 +534,8 @@ void CMonitor::applyCMType(eCMType cmType) { if (oldImageDescription != m_imageDescription) { m_imageDescription.updateId(); - PROTO::colorManagement->onMonitorImageDescriptionChanged(m_self); + if (PROTO::colorManagement) + PROTO::colorManagement->onMonitorImageDescriptionChanged(m_self); } } @@ -1701,6 +1702,7 @@ uint16_t CMonitor::isDSBlocked(bool full) { uint16_t reasons = 0; static auto PDIRECTSCANOUT = CConfigValue("render:direct_scanout"); static auto PPASS = CConfigValue("render:cm_fs_passthrough"); + static auto PNONSHADER = CConfigValue("render:non_shader_cm"); if (*PDIRECTSCANOUT == 0) { reasons |= DS_BLOCK_USER; @@ -1770,7 +1772,8 @@ uint16_t CMonitor::isDSBlocked(bool full) { return reasons; } - if (!canNoShaderCM() && (!inHDR() || (PSURFACE->m_colorManagement.valid() && PSURFACE->m_colorManagement->isWindowsScRGB())) && *PPASS != 1) + if (needsCM() && *PNONSHADER != CM_NS_IGNORE && !canNoShaderCM() && (!inHDR() || (PSURFACE->m_colorManagement.valid() && PSURFACE->m_colorManagement->isWindowsScRGB())) && + *PPASS != 1) reasons |= DS_BLOCK_CM; return reasons; @@ -1989,11 +1992,16 @@ std::optional CMonitor::getFSImageDescripti } bool CMonitor::needsCM() { - return getFSImageDescription() != m_imageDescription; + const auto SRC_DESC = getFSImageDescription(); + return SRC_DESC.has_value() && SRC_DESC.value() != m_imageDescription; } // TODO support more drm properties bool CMonitor::canNoShaderCM() { + static auto PNONSHADER = CConfigValue("render:non_shader_cm"); + if (*PNONSHADER == CM_NS_DISABLE) + return false; + const auto SRC_DESC = getFSImageDescription(); if (!SRC_DESC.has_value()) return false; @@ -2006,7 +2014,7 @@ bool CMonitor::canNoShaderCM() { // only primaries differ if (SRC_DESC->transferFunction == m_imageDescription.transferFunction && SRC_DESC->transferFunctionPower == m_imageDescription.transferFunctionPower && - SRC_DESC->luminances == m_imageDescription.luminances && SRC_DESC->masteringLuminances == m_imageDescription.masteringLuminances && + (!inHDR() || SRC_DESC->luminances == m_imageDescription.luminances) && SRC_DESC->masteringLuminances == m_imageDescription.masteringLuminances && SRC_DESC->maxCLL == m_imageDescription.maxCLL && SRC_DESC->maxFALL == m_imageDescription.maxFALL) return true; diff --git a/src/protocols/types/ColorManagement.hpp b/src/protocols/types/ColorManagement.hpp index b7cfd37a9..80cea49f3 100644 --- a/src/protocols/types/ColorManagement.hpp +++ b/src/protocols/types/ColorManagement.hpp @@ -11,6 +11,13 @@ #define HLG_MAX_LUMINANCE 1000.0 namespace NColorManagement { + enum eNoShader : uint8_t { + CM_NS_DISABLE = 0, + CM_NS_ALWAYS = 1, + CM_NS_ONDEMAND = 2, + CM_NS_IGNORE = 3, + }; + enum ePrimaries : uint8_t { CM_PRIMARIES_SRGB = 1, CM_PRIMARIES_PAL_M = 2, diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 0626271e8..f8f4cec53 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1483,9 +1483,10 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, S } bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { - static auto PCT = CConfigValue("render:send_content_type"); - static auto PPASS = CConfigValue("render:cm_fs_passthrough"); - static auto PAUTOHDR = CConfigValue("render:cm_auto_hdr"); + static auto PCT = CConfigValue("render:send_content_type"); + static auto PPASS = CConfigValue("render:cm_fs_passthrough"); + static auto PAUTOHDR = CConfigValue("render:cm_auto_hdr"); + static auto PNONSHADER = CConfigValue("render:non_shader_cm"); static bool needsHDRupdate = false; @@ -1570,7 +1571,7 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) { pMonitor->m_output->state->setContentType(NContentType::toDRM(FS_WINDOW ? FS_WINDOW->getContentType() : CONTENT_TYPE_NONE)); if (FS_WINDOW != pMonitor->m_previousFSWindow) { - if (!FS_WINDOW || !pMonitor->needsCM() || !pMonitor->canNoShaderCM()) { + if (!FS_WINDOW || !pMonitor->needsCM() || !pMonitor->canNoShaderCM() || (*PNONSHADER == CM_NS_ONDEMAND && pMonitor->m_lastScanout.expired() && *PPASS != 1)) { if (pMonitor->m_noShaderCTM) { Debug::log(INFO, "[CM] No fullscreen CTM, restoring previous one"); pMonitor->m_noShaderCTM = false;