diff options
Diffstat (limited to 'src/helpers/Monitor.cpp')
| -rw-r--r-- | src/helpers/Monitor.cpp | 124 |
1 files changed, 104 insertions, 20 deletions
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index 3be5be40..626c3bce 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -30,7 +30,7 @@ #include "../hyprerror/HyprError.hpp" #include "../layout/LayoutManager.hpp" #include "../i18n/Engine.hpp" -#include "../protocols/types/ColorManagement.hpp" +#include "../helpers/cm/ColorManagement.hpp" #include "sync/SyncTimeline.hpp" #include "time/Time.hpp" #include "../desktop/view/LayerSurface.hpp" @@ -933,28 +933,45 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { m_supportsWideColor = RULE->supportsHDR; m_supportsHDR = RULE->supportsHDR; - m_cmType = RULE->cmType; - switch (m_cmType) { - case NCMType::CM_AUTO: m_cmType = m_enabled10bit && supportsWideColor() ? NCMType::CM_WIDE : NCMType::CM_SRGB; break; - case NCMType::CM_EDID: m_cmType = m_output->parsedEDID.chromaticityCoords.has_value() ? NCMType::CM_EDID : NCMType::CM_SRGB; break; - case NCMType::CM_HDR: - case NCMType::CM_HDR_EDID: m_cmType = supportsHDR() ? m_cmType : NCMType::CM_SRGB; break; - default: break; - } + if (RULE->iccFile.empty()) { + // only apply explicit cm settings if we have no icc file + + m_cmType = RULE->cmType; + switch (m_cmType) { + case NCMType::CM_AUTO: m_cmType = m_enabled10bit && supportsWideColor() ? NCMType::CM_WIDE : NCMType::CM_SRGB; break; + case NCMType::CM_EDID: m_cmType = m_output->parsedEDID.chromaticityCoords.has_value() ? NCMType::CM_EDID : NCMType::CM_SRGB; break; + case NCMType::CM_HDR: + case NCMType::CM_HDR_EDID: m_cmType = supportsHDR() ? m_cmType : NCMType::CM_SRGB; break; + default: break; + } - m_sdrEotf = RULE->sdrEotf; + m_sdrEotf = RULE->sdrEotf; - m_sdrMinLuminance = RULE->sdrMinLuminance; - m_sdrMaxLuminance = RULE->sdrMaxLuminance; + m_sdrMinLuminance = RULE->sdrMinLuminance; + m_sdrMaxLuminance = RULE->sdrMaxLuminance; - m_minLuminance = RULE->minLuminance; - m_maxLuminance = RULE->maxLuminance; - m_maxAvgLuminance = RULE->maxAvgLuminance; + m_minLuminance = RULE->minLuminance; + m_maxLuminance = RULE->maxLuminance; + m_maxAvgLuminance = RULE->maxAvgLuminance; - applyCMType(m_cmType, m_sdrEotf); + applyCMType(m_cmType, m_sdrEotf); - m_sdrSaturation = RULE->sdrSaturation; - m_sdrBrightness = RULE->sdrBrightness; + m_sdrSaturation = RULE->sdrSaturation; + m_sdrBrightness = RULE->sdrBrightness; + } else { + auto image = NColorManagement::SImageDescription::fromICC(RULE->iccFile); + if (!image) { + Log::logger->log(Log::ERR, "icc for {} ({}) failed: {}", m_name, RULE->iccFile, image.error()); + g_pConfigManager->addParseError(std::format("failed to apply icc {} to {}: {}", RULE->iccFile, m_name, image.error())); + } else { + m_imageDescription = CImageDescription::from(*image); + if (!m_imageDescription) { + Log::logger->log(Log::ERR, "icc for {} ({}) failed 2: {}", m_name, RULE->iccFile, image.error()); + g_pConfigManager->addParseError(std::format("failed to apply icc {} to {}: {}", RULE->iccFile, m_name, image.error())); + m_imageDescription = CImageDescription::from(SImageDescription{}); + } + } + } Vector2D logicalSize = m_pixelSize / m_scale; if (!*PDISABLESCALECHECKS && (logicalSize.x != std::round(logicalSize.x) || logicalSize.y != std::round(logicalSize.y))) { @@ -1037,6 +1054,8 @@ bool CMonitor::applyMonitorRule(SMonitorRule* pMonitorRule, bool force) { m_damage.setSize(m_transformedSize); + updateVCGTRamps(); + // Set scale for all surfaces on this monitor, needed for some clients // but not on unsafe state to avoid crashes if (!g_pCompositor->m_unsafeState) { @@ -2187,8 +2206,8 @@ bool CMonitor::canNoShaderCM() { const auto SRC_DESC_VALUE = SRC_DESC.value()->value(); - if (SRC_DESC_VALUE.icc.fd >= 0 || m_imageDescription->value().icc.fd >= 0) - return false; // no ICC support + if (m_imageDescription->value().icc.present) + return false; const auto sdrEOTF = NTransferFunction::fromConfig(); // only primaries differ @@ -2207,6 +2226,71 @@ bool CMonitor::doesNoShaderCM() { return m_noShaderCTM; } +static std::vector<uint16_t> resampleInterleavedToKms(const SVCGTTable16& t, size_t gammaSize) { + std::vector<uint16_t> out; + out.resize(gammaSize * 3); + + // + auto sample = [&](int c, float x) -> uint16_t { + const float maxX = t.entries - 1; + x = std::clamp(x, 0.F, maxX); + + const size_t i0 = (size_t)std::floor(x); + const size_t i1 = std::min(i0 + 1, (size_t)t.entries - 1); + const float f = x - sc<float>(i0); + + const float v0 = sc<float>(t.ch[c][i0]); + const float v1 = sc<float>(t.ch[c][i1]); + const float v = v0 + ((v1 - v0) * f); + + int64_t vi = std::round(v); + vi = std::clamp(vi, sc<int64_t>(0), sc<int64_t>(65535)); + return sc<uint16_t>(vi); + }; + + for (size_t i = 0; i < gammaSize; ++i) { + float x = sc<float>(i) * sc<float>(t.entries - 1) / sc<float>(gammaSize - 1); + + const uint16_t r = sample(0, x); + const uint16_t g = sample(1, x); + const uint16_t b = sample(2, x); + + out[i * 3 + 0] = r; + out[i * 3 + 1] = g; + out[i * 3 + 2] = b; + } + + return out; +} + +void CMonitor::updateVCGTRamps() { + auto gammaSize = m_output->getGammaSize(); + + if (gammaSize <= 10) { + Log::logger->log(Log::DEBUG, "CMonitor::updateVCGTRamps: skipping, no gamma ramp for output"); + return; + } + + if (!m_imageDescription->value().icc.vcgt) { + if (m_vcgtRampsSet) + m_output->state->setGammaLut({}); + + m_vcgtRampsSet = false; + return; + } + + // build table + auto table = resampleInterleavedToKms(*m_imageDescription->value().icc.vcgt, gammaSize); + + m_output->state->setGammaLut(table); + + m_vcgtRampsSet = true; +} + +bool CMonitor::gammaRampsInUse() { + return m_vcgtRampsSet; +} + CMonitorState::CMonitorState(CMonitor* owner) : m_owner(owner) { ; } |
