summaryrefslogtreecommitdiff
path: root/src/helpers/Monitor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/helpers/Monitor.cpp')
-rw-r--r--src/helpers/Monitor.cpp124
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) {
;
}