diff --git a/src/backends/drm/drm_output.cpp b/src/backends/drm/drm_output.cpp index 99f8941de2..b54c2b07df 100644 --- a/src/backends/drm/drm_output.cpp +++ b/src/backends/drm/drm_output.cpp @@ -437,11 +437,12 @@ bool DrmOutput::doSetChannelFactors(const QVector3D &rgb) if (!m_pipeline->activePending()) { return false; } + const auto inGamma22 = ColorDescription::nitsToEncoded(rgb, NamedTransferFunction::gamma22, 1); if (m_pipeline->hasCTM()) { QMatrix3x3 ctm; - ctm(0, 0) = rgb.x(); - ctm(1, 1) = rgb.y(); - ctm(2, 2) = rgb.z(); + ctm(0, 0) = inGamma22.x(); + ctm(1, 1) = inGamma22.y(); + ctm(2, 2) = inGamma22.z(); m_pipeline->setCTM(ctm); m_pipeline->setGammaRamp(nullptr); if (DrmPipeline::commitPipelines({m_pipeline}, DrmPipeline::CommitMode::Test) == DrmPipeline::Error::None) { @@ -454,7 +455,7 @@ bool DrmOutput::doSetChannelFactors(const QVector3D &rgb) } } if (m_pipeline->hasGammaRamp()) { - auto lut = ColorTransformation::createScalingTransform(rgb); + auto lut = ColorTransformation::createScalingTransform(inGamma22); if (lut) { m_pipeline->setGammaRamp(std::move(lut)); if (DrmPipeline::commitPipelines({m_pipeline}, DrmPipeline::CommitMode::Test) == DrmPipeline::Error::None) { diff --git a/src/backends/x11/standalone/x11_standalone_output.cpp b/src/backends/x11/standalone/x11_standalone_output.cpp index 862a257711..2987f85b8c 100644 --- a/src/backends/x11/standalone/x11_standalone_output.cpp +++ b/src/backends/x11/standalone/x11_standalone_output.cpp @@ -46,7 +46,7 @@ bool X11Output::setChannelFactors(const QVector3D &rgb) if (m_crtc == XCB_NONE) { return true; } - auto transformation = ColorTransformation::createScalingTransform(rgb); + auto transformation = ColorTransformation::createScalingTransform(ColorDescription::nitsToEncoded(rgb, NamedTransferFunction::gamma22, 1)); if (!transformation) { return false; } diff --git a/src/colors/colordevice.cpp b/src/colors/colordevice.cpp index a5c9835729..b73e9c9660 100644 --- a/src/colors/colordevice.cpp +++ b/src/colors/colordevice.cpp @@ -62,7 +62,8 @@ void ColorDevicePrivate::recalculateFactors() const qreal zWhitePoint = interpolate(blackbodyColor[blackBodyColorIndex + 2], blackbodyColor[blackBodyColorIndex + 5], blendFactor); - temperatureFactors = QVector3D(xWhitePoint, yWhitePoint, zWhitePoint); + // the values in the blackbodyColor array are "gamma corrected", but we need a linear value + temperatureFactors = ColorDescription::encodedToNits(QVector3D(xWhitePoint, yWhitePoint, zWhitePoint), NamedTransferFunction::gamma22, 1); } simpleTransformation = brightnessFactors * temperatureFactors; } diff --git a/src/core/colorspace.cpp b/src/core/colorspace.cpp index f913771ca7..2905b892b7 100644 --- a/src/core/colorspace.cpp +++ b/src/core/colorspace.cpp @@ -344,34 +344,34 @@ static QVector3D clamp(const QVector3D &vect, float min = 0, float max = 1) return QVector3D(std::clamp(vect.x(), min, max), std::clamp(vect.y(), min, max), std::clamp(vect.z(), min, max)); } -QVector3D ColorDescription::mapTo(QVector3D rgb, const ColorDescription &dst) const +QVector3D ColorDescription::encodedToNits(const QVector3D &nits, NamedTransferFunction tf, double sdrBrightness) { - // transfer function -> nits - switch (m_transferFunction) { + switch (tf) { case NamedTransferFunction::sRGB: - rgb = m_sdrBrightness * QVector3D(srgbToLinear(rgb.x()), srgbToLinear(rgb.y()), srgbToLinear(rgb.z())); - break; + return sdrBrightness * QVector3D(srgbToLinear(nits.x()), srgbToLinear(nits.y()), srgbToLinear(nits.z())); case NamedTransferFunction::gamma22: - rgb = m_sdrBrightness * QVector3D(std::pow(rgb.x(), 2.2), std::pow(rgb.y(), 2.2), std::pow(rgb.z(), 2.2)); - break; + return sdrBrightness * QVector3D(std::pow(nits.x(), 2.2), std::pow(nits.y(), 2.2), std::pow(nits.z(), 2.2)); case NamedTransferFunction::linear: - break; + return nits; case NamedTransferFunction::scRGB: - rgb *= 80.0f; - break; + return nits * 80.0f; case NamedTransferFunction::PerceptualQuantizer: - rgb = QVector3D(pqToNits(rgb.x()), pqToNits(rgb.y()), pqToNits(rgb.z())); - break; + return QVector3D(pqToNits(nits.x()), pqToNits(nits.y()), pqToNits(nits.z())); + } + Q_UNREACHABLE(); +} + +QVector3D ColorDescription::nitsToEncoded(const QVector3D &rgb, NamedTransferFunction tf, double sdrBrightness) +{ + switch (tf) { + case NamedTransferFunction::sRGB: { + const auto clamped = clamp(rgb / sdrBrightness); + return QVector3D(linearToSRGB(clamped.x()), linearToSRGB(clamped.y()), linearToSRGB(clamped.z())); + } + case NamedTransferFunction::gamma22: { + const auto clamped = clamp(rgb / sdrBrightness); + return QVector3D(std::pow(clamped.x(), 1 / 2.2), std::pow(clamped.y(), 1 / 2.2), std::pow(clamped.z(), 1 / 2.2)); } - rgb = m_colorimetry.toOther(dst.colorimetry()) * rgb; - // nits -> transfer function - switch (dst.transferFunction()) { - case NamedTransferFunction::sRGB: - rgb = clamp(rgb / dst.sdrBrightness()); - return QVector3D(linearToSRGB(rgb.x()), linearToSRGB(rgb.y()), linearToSRGB(rgb.z())); - case NamedTransferFunction::gamma22: - rgb = clamp(rgb / dst.sdrBrightness()); - return QVector3D(std::pow(rgb.x(), 1 / 2.2), std::pow(rgb.y(), 1 / 2.2), std::pow(rgb.z(), 1 / 2.2)); case NamedTransferFunction::linear: return rgb; case NamedTransferFunction::scRGB: @@ -379,6 +379,13 @@ QVector3D ColorDescription::mapTo(QVector3D rgb, const ColorDescription &dst) co case NamedTransferFunction::PerceptualQuantizer: return QVector3D(nitsToPQ(rgb.x()), nitsToPQ(rgb.y()), nitsToPQ(rgb.z())); } - return QVector3D(); + Q_UNREACHABLE(); +} + +QVector3D ColorDescription::mapTo(QVector3D rgb, const ColorDescription &dst) const +{ + rgb = encodedToNits(rgb, m_transferFunction, m_sdrBrightness); + rgb = m_colorimetry.toOther(dst.colorimetry()) * rgb; + return nitsToEncoded(rgb, dst.transferFunction(), dst.sdrBrightness()); } } diff --git a/src/core/colorspace.h b/src/core/colorspace.h index e39affd0d2..48ab6ad20d 100644 --- a/src/core/colorspace.h +++ b/src/core/colorspace.h @@ -127,6 +127,8 @@ public: * This color description describes display-referred sRGB, with a gamma22 transfer function */ static const ColorDescription sRGB; + static QVector3D encodedToNits(const QVector3D &nits, NamedTransferFunction tf, double sdrBrightness); + static QVector3D nitsToEncoded(const QVector3D &rgb, NamedTransferFunction tf, double sdrBrightness); private: Colorimetry m_colorimetry;