diff --git a/autotests/test_colorspaces.cpp b/autotests/test_colorspaces.cpp index 899ffb9958..f9e6714134 100644 --- a/autotests/test_colorspaces.cpp +++ b/autotests/test_colorspaces.cpp @@ -85,8 +85,8 @@ void TestColorspaces::roundtripConversion() void TestColorspaces::nonNormalizedPrimaries() { // this test ensures that non-normalized primaries don't mess up the transformations between color spaces - const auto from = Colorimetry::fromName(NamedColorimetry::BT709); - const auto to = Colorimetry(Colorimetry::xyToXYZ(from.red()) * 2, Colorimetry::xyToXYZ(from.green()) * 2, Colorimetry::xyToXYZ(from.blue()) * 2, Colorimetry::xyToXYZ(from.white()) * 2); + const auto &from = ColorDescription::sRGB; + const ColorDescription to(Colorimetry(Colorimetry::xyToXYZ(from.containerColorimetry().red()) * 2, Colorimetry::xyToXYZ(from.containerColorimetry().green()) * 2, Colorimetry::xyToXYZ(from.containerColorimetry().blue()) * 2, Colorimetry::xyToXYZ(from.containerColorimetry().white()) * 2), from.transferFunction(), from.referenceLuminance(), from.minLuminance(), from.maxAverageLuminance(), from.maxHdrLuminance()); const auto convertedWhite = from.toOther(to, RenderingIntent::RelativeColorimetric) * QVector3D(1, 1, 1); QCOMPARE_LE(std::abs(1 - convertedWhite.x()), s_resolution10bit); diff --git a/src/backends/drm/drm_output.cpp b/src/backends/drm/drm_output.cpp index d3ec260e5f..2a06bdbb12 100644 --- a/src/backends/drm/drm_output.cpp +++ b/src/backends/drm/drm_output.cpp @@ -517,7 +517,7 @@ bool DrmOutput::needsChannelFactorFallback() const QVector3D DrmOutput::effectiveChannelFactors() const { - QVector3D adaptedChannelFactors = Colorimetry::fromName(NamedColorimetry::BT709).toOther(m_state.colorDescription.containerColorimetry(), RenderingIntent::RelativeColorimetric) * m_channelFactors; + QVector3D adaptedChannelFactors = ColorDescription::sRGB.toOther(colorDescription(), RenderingIntent::RelativeColorimetric) * m_channelFactors; // normalize red to be the original brightness value again adaptedChannelFactors *= m_channelFactors.x() / adaptedChannelFactors.x(); if (m_state.highDynamicRange || !m_brightnessDevice) { diff --git a/src/core/colorpipeline.cpp b/src/core/colorpipeline.cpp index 337d7aba09..442b086021 100644 --- a/src/core/colorpipeline.cpp +++ b/src/core/colorpipeline.cpp @@ -23,7 +23,7 @@ ColorPipeline ColorPipeline::create(const ColorDescription &from, const ColorDes // FIXME this assumes that the range stays the same with matrix multiplication // that's not necessarily true, and figuring out the actual range could be complicated.. - ret.addMatrix(from.containerColorimetry().toOther(to.containerColorimetry(), intent), ret.currentOutputRange()); + ret.addMatrix(from.toOther(to, intent), ret.currentOutputRange()); ret.addInverseTransferFunction(to.transferFunction()); return ret; diff --git a/src/core/colorspace.cpp b/src/core/colorspace.cpp index 56ab7c8b9c..7bd7e4333e 100644 --- a/src/core/colorspace.cpp +++ b/src/core/colorspace.cpp @@ -126,18 +126,6 @@ const QMatrix4x4 &Colorimetry::fromXYZ() const return m_fromXYZ; } -QMatrix4x4 Colorimetry::toOther(const Colorimetry &other, RenderingIntent intent) const -{ - switch (intent) { - case RenderingIntent::Perceptual: - case RenderingIntent::RelativeColorimetric: - return other.fromXYZ() * chromaticAdaptationMatrix(this->white(), other.white()) * toXYZ(); - case RenderingIntent::AbsoluteColorimetric: - return other.fromXYZ() * toXYZ(); - } - Q_UNREACHABLE(); -} - Colorimetry Colorimetry::adaptedTo(QVector2D newWhitepoint) const { const auto mat = chromaticAdaptationMatrix(this->white(), newWhitepoint); @@ -273,11 +261,26 @@ std::optional ColorDescription::maxHdrLuminance() const return m_maxHdrLuminance; } +QMatrix4x4 ColorDescription::toOther(const ColorDescription &other, RenderingIntent intent) const +{ + switch (intent) { + case RenderingIntent::Perceptual: { + const Colorimetry &srcContainer = containerColorimetry() == NamedColorimetry::BT709 ? other.sdrColorimetry() : containerColorimetry(); + return other.containerColorimetry().fromXYZ() * Colorimetry::chromaticAdaptationMatrix(srcContainer.white(), other.containerColorimetry().white()) * srcContainer.toXYZ(); + } + case RenderingIntent::RelativeColorimetric: + return other.containerColorimetry().fromXYZ() * Colorimetry::chromaticAdaptationMatrix(containerColorimetry().white(), other.containerColorimetry().white()) * containerColorimetry().toXYZ(); + case RenderingIntent::AbsoluteColorimetric: + return other.containerColorimetry().fromXYZ() * containerColorimetry().toXYZ(); + } + Q_UNREACHABLE(); +} + QVector3D ColorDescription::mapTo(QVector3D rgb, const ColorDescription &dst, RenderingIntent intent) const { rgb = m_transferFunction.encodedToNits(rgb); rgb *= dst.referenceLuminance() / m_referenceLuminance; - rgb = m_containerColorimetry.toOther(dst.containerColorimetry(), intent) * rgb; + rgb = toOther(dst, intent) * rgb; return dst.transferFunction().nitsToEncoded(rgb); } diff --git a/src/core/colorspace.h b/src/core/colorspace.h index 8639f48da8..fcf92cb2a2 100644 --- a/src/core/colorspace.h +++ b/src/core/colorspace.h @@ -70,10 +70,6 @@ public: * @returns a matrix that transforms from the XYZ representation to the linear RGB representation of colors in this colorimetry */ const QMatrix4x4 &fromXYZ() const; - /** - * @returns a matrix that transforms from linear RGB in this colorimetry to linear RGB in the other colorimetry - */ - QMatrix4x4 toOther(const Colorimetry &colorimetry, RenderingIntent intent) const; bool operator==(const Colorimetry &other) const; bool operator==(NamedColorimetry name) const; /** @@ -179,9 +175,14 @@ public: bool operator==(const ColorDescription &other) const = default; - QVector3D mapTo(QVector3D rgb, const ColorDescription &other, RenderingIntent intent) const; ColorDescription withTransferFunction(const TransferFunction &func) const; + /** + * @returns a matrix that transforms from linear RGB in this color description to linear RGB in the other one + */ + QMatrix4x4 toOther(const ColorDescription &other, RenderingIntent intent) const; + QVector3D mapTo(QVector3D rgb, const ColorDescription &other, RenderingIntent intent) const; + /** * This color description describes display-referred sRGB, with a gamma22 transfer function */ diff --git a/src/opengl/glshader.cpp b/src/opengl/glshader.cpp index a63f2ec1c9..f1c3572aef 100644 --- a/src/opengl/glshader.cpp +++ b/src/opengl/glshader.cpp @@ -471,8 +471,7 @@ QMatrix4x4 GLShader::getUniformMatrix4x4(const char *name) bool GLShader::setColorspaceUniforms(const ColorDescription &src, const ColorDescription &dst, RenderingIntent intent) { - const auto &srcColorimetry = intent == RenderingIntent::Perceptual && src.containerColorimetry() == NamedColorimetry::BT709 ? dst.sdrColorimetry() : src.containerColorimetry(); - return setUniform(Mat4Uniform::ColorimetryTransformation, srcColorimetry.toOther(dst.containerColorimetry(), intent)) + return setUniform(Mat4Uniform::ColorimetryTransformation, src.toOther(dst, intent)) && setUniform(IntUniform::SourceNamedTransferFunction, src.transferFunction().type) && setUniform(Vec2Uniform::SourceTransferFunctionParams, QVector2D(src.transferFunction().minLuminance, src.transferFunction().maxLuminance - src.transferFunction().minLuminance)) && setUniform(FloatUniform::SourceReferenceLuminance, src.referenceLuminance())