colors/colordevice: make channel factors linear
The redshift table is in gamma 2.2 encoding and not linear, which means that it only yields correct results with 1.0 pixel values. It also means that when it's being applied in linear space in the color management shaders, the result is quite wrong. To fix that, this commit makes the channel factors linear and the backend calculates the nonlinear factors where needed.
This commit is contained in:
parent
788c186701
commit
36bec2d941
5 changed files with 39 additions and 28 deletions
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue