core/colorspace: move Colorimetry::toOther to ColorDescription

With some rendering intents we need to apply behavior based on brightness levels
or the SDR colorimetry
This commit is contained in:
Xaver Hugl 2024-08-12 01:43:56 +02:00
parent 833476a111
commit 418143a45b
6 changed files with 27 additions and 24 deletions

View file

@ -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);

View file

@ -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) {

View file

@ -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;

View file

@ -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<double> 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);
}

View file

@ -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
*/

View file

@ -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())