colorspace: make sdr colorimetry not be about rec.2020 anymore

This was just done because of the wrong assumption that displays needed that
to show the full native gamut. That turned out to be an amdgpu bug though; with
that fixed, most of the 0-100% range is wildly oversaturated.
To make the slider more intuitive, this changes the sdr gamut wideness to instead
interpolate to the native display primaries as indicated by the EDID.
This commit is contained in:
Xaver Hugl 2024-01-30 15:54:04 +01:00
parent 8d44ece874
commit 9c0085f5a9
7 changed files with 30 additions and 33 deletions

View file

@ -57,8 +57,8 @@ void TestColorspaces::roundtripConversion()
QFETCH(NamedTransferFunction, dstTransferFunction);
QFETCH(double, requiredAccuracy);
const auto src = ColorDescription(srcColorimetry, srcTransferFunction, 100, 0, 100, 100, 0);
const auto dst = ColorDescription(dstColorimetry, dstTransferFunction, 100, 0, 100, 100, 0);
const auto src = ColorDescription(srcColorimetry, srcTransferFunction, 100, 0, 100, 100);
const auto dst = ColorDescription(dstColorimetry, dstTransferFunction, 100, 0, 100, 100);
const QVector3D red(1, 0, 0);
const QVector3D green(0, 1, 0);

View file

@ -112,7 +112,7 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmLayerSurface::startRendering(cons
m_surface->intermediaryColorDescription = ColorDescription(colorDescription.colorimetry(), NamedTransferFunction::linear,
colorDescription.sdrBrightness(), colorDescription.minHdrBrightness(),
colorDescription.maxFrameAverageBrightness(), colorDescription.maxHdrHighlightBrightness(),
colorDescription.sdrGamutWideness());
colorDescription.sdrColorimetry());
} else {
m_surface->intermediaryColorDescription = colorDescription;
}

View file

@ -342,14 +342,15 @@ ColorDescription DrmOutput::createColorDescription(const std::shared_ptr<OutputC
{
if (props->highDynamicRange.value_or(m_state.highDynamicRange) && m_connector->edid()) {
const auto colorimetry = props->wideColorGamut.value_or(m_state.wideColorGamut) ? NamedColorimetry::BT2020 : NamedColorimetry::BT709;
const auto nativeColorimetry = m_information.edid.colorimetry().value_or(Colorimetry::fromName(NamedColorimetry::BT709));
const auto sdrBrightness = props->sdrBrightness.value_or(m_state.sdrBrightness);
return ColorDescription(colorimetry, NamedTransferFunction::PerceptualQuantizer, sdrBrightness,
props->minBrightnessOverride.value_or(m_state.minBrightnessOverride).value_or(m_connector->edid()->desiredMinLuminance()),
props->maxAverageBrightnessOverride.value_or(m_state.maxAverageBrightnessOverride).value_or(m_connector->edid()->desiredMaxFrameAverageLuminance().value_or(sdrBrightness)),
props->maxPeakBrightnessOverride.value_or(m_state.maxPeakBrightnessOverride).value_or(m_connector->edid()->desiredMaxLuminance().value_or(1000)),
props->sdrGamutWideness.value_or(m_state.sdrGamutWideness));
Colorimetry::fromName(NamedColorimetry::BT709).interpolateGamutTo(nativeColorimetry, props->sdrGamutWideness.value_or(m_state.sdrGamutWideness)));
} else if (const auto profile = props->iccProfile.value_or(m_state.iccProfile)) {
return ColorDescription(profile->colorimetry(), NamedTransferFunction::gamma22, 200, 0, 200, 200, 0);
return ColorDescription(profile->colorimetry(), NamedTransferFunction::gamma22, 200, 0, 200, 200);
} else {
return ColorDescription::sRGB;
}

View file

@ -81,6 +81,16 @@ QMatrix4x4 Colorimetry::calculateToXYZMatrix(QVector3D red, QVector3D green, QVe
return matrixFromColumns(red * component_scale.x(), green * component_scale.y(), blue * component_scale.z());
}
Colorimetry Colorimetry::interpolateGamutTo(const Colorimetry &one, double factor) const
{
return Colorimetry{
m_red * (1 - factor) + one.red() * factor,
m_green * (1 - factor) + one.green() * factor,
m_blue * (1 - factor) + one.blue() * factor,
m_white, // whitepoint should stay the same
};
}
Colorimetry::Colorimetry(QVector2D red, QVector2D green, QVector2D blue, QVector2D white)
: m_red(red)
, m_green(green)
@ -183,23 +193,12 @@ const Colorimetry &Colorimetry::fromName(NamedColorimetry name)
Q_UNREACHABLE();
}
const ColorDescription ColorDescription::sRGB = ColorDescription(NamedColorimetry::BT709, NamedTransferFunction::gamma22, 100, 0, 100, 100, 0);
const ColorDescription ColorDescription::sRGB = ColorDescription(NamedColorimetry::BT709, NamedTransferFunction::gamma22, 100, 0, 100, 100);
static Colorimetry sRGBColorimetry(double factor)
{
return Colorimetry{
BT709.red() * (1 - factor) + BT2020.red() * factor,
BT709.green() * (1 - factor) + BT2020.green() * factor,
BT709.blue() * (1 - factor) + BT2020.blue() * factor,
BT709.white(), // whitepoint is the same
};
}
ColorDescription::ColorDescription(const Colorimetry &colorimety, NamedTransferFunction tf, double sdrBrightness, double minHdrBrightness, double maxFrameAverageBrightness, double maxHdrHighlightBrightness, double sdrGamutWideness)
ColorDescription::ColorDescription(const Colorimetry &colorimety, NamedTransferFunction tf, double sdrBrightness, double minHdrBrightness, double maxFrameAverageBrightness, double maxHdrHighlightBrightness, const Colorimetry &sdrColorimetry)
: m_colorimetry(colorimety)
, m_transferFunction(tf)
, m_sdrColorimetry(sRGBColorimetry(sdrGamutWideness))
, m_sdrGamutWideness(sdrGamutWideness)
, m_sdrColorimetry(sdrColorimetry)
, m_sdrBrightness(sdrBrightness)
, m_minHdrBrightness(minHdrBrightness)
, m_maxFrameAverageBrightness(maxFrameAverageBrightness)
@ -207,11 +206,10 @@ ColorDescription::ColorDescription(const Colorimetry &colorimety, NamedTransferF
{
}
ColorDescription::ColorDescription(NamedColorimetry colorimetry, NamedTransferFunction tf, double sdrBrightness, double minHdrBrightness, double maxFrameAverageBrightness, double maxHdrHighlightBrightness, double sdrGamutWideness)
ColorDescription::ColorDescription(NamedColorimetry colorimetry, NamedTransferFunction tf, double sdrBrightness, double minHdrBrightness, double maxFrameAverageBrightness, double maxHdrHighlightBrightness, const Colorimetry &sdrColorimetry)
: m_colorimetry(Colorimetry::fromName(colorimetry))
, m_transferFunction(tf)
, m_sdrColorimetry(sRGBColorimetry(sdrGamutWideness))
, m_sdrGamutWideness(sdrGamutWideness)
, m_sdrColorimetry(sdrColorimetry)
, m_sdrBrightness(sdrBrightness)
, m_minHdrBrightness(minHdrBrightness)
, m_maxFrameAverageBrightness(maxFrameAverageBrightness)
@ -254,11 +252,6 @@ double ColorDescription::maxHdrHighlightBrightness() const
return m_maxHdrHighlightBrightness;
}
double ColorDescription::sdrGamutWideness() const
{
return m_sdrGamutWideness;
}
bool ColorDescription::operator==(const ColorDescription &other) const
{
return m_colorimetry == other.m_colorimetry

View file

@ -65,6 +65,10 @@ public:
* @returns this colorimetry, adapted to the new whitepoint using the Bradford transform
*/
Colorimetry adaptedTo(QVector2D newWhitepoint) const;
/**
* interpolates the primaries depending on the passed factor. The whitepoint stays unchanged
*/
Colorimetry interpolateGamutTo(const Colorimetry &one, double factor) const;
const QVector2D &red() const;
const QVector2D &green() const;
@ -105,10 +109,10 @@ public:
* @param minHdrBrightness the minimum brightness of HDR content
* @param maxFrameAverageBrightness the maximum brightness of HDR content, if the whole screen is white
* @param maxHdrHighlightBrightness the maximum brightness of HDR content, for a small part of the screen only
* @param sdrGamutWideness the gamut wideness of sRGB content; 0 is rec.709, 1 is rec.2020, everything in between is interpolated
* @param sdrColorimetry
*/
explicit ColorDescription(const Colorimetry &colorimety, NamedTransferFunction tf, double sdrBrightness, double minHdrBrightness, double maxFrameAverageBrightness, double maxHdrHighlightBrightness, double sdrGamutWideness);
explicit ColorDescription(NamedColorimetry colorimetry, NamedTransferFunction tf, double sdrBrightness, double minHdrBrightness, double maxFrameAverageBrightness, double maxHdrHighlightBrightness, double sdrGamutWideness);
explicit ColorDescription(const Colorimetry &colorimety, NamedTransferFunction tf, double sdrBrightness, double minHdrBrightness, double maxFrameAverageBrightness, double maxHdrHighlightBrightness, const Colorimetry &sdrColorimetry = Colorimetry::fromName(NamedColorimetry::BT709));
explicit ColorDescription(NamedColorimetry colorimetry, NamedTransferFunction tf, double sdrBrightness, double minHdrBrightness, double maxFrameAverageBrightness, double maxHdrHighlightBrightness, const Colorimetry &sdrColorimetry = Colorimetry::fromName(NamedColorimetry::BT709));
const Colorimetry &colorimetry() const;
const Colorimetry &sdrColorimetry() const;
@ -117,7 +121,6 @@ public:
double minHdrBrightness() const;
double maxFrameAverageBrightness() const;
double maxHdrHighlightBrightness() const;
double sdrGamutWideness() const;
bool operator==(const ColorDescription &other) const;

View file

@ -150,7 +150,7 @@ void FrogColorManagementSurfaceV1::updateColorDescription()
if (m_surface) {
// TODO make brightness values optional in ColorDescription
SurfaceInterfacePrivate *priv = SurfaceInterfacePrivate::get(m_surface);
priv->pending->colorDescription = ColorDescription(m_colorimetry, m_transferFunction, 0, 0, m_maxFrameAverageBrightness, m_maxPeakBrightness, 0);
priv->pending->colorDescription = ColorDescription(m_colorimetry, m_transferFunction, 0, 0, m_maxFrameAverageBrightness, m_maxPeakBrightness);
priv->pending->colorDescriptionIsSet = true;
}
}

View file

@ -157,7 +157,7 @@ void XXColorParametricCreatorV1::xx_image_description_creator_params_v1_create(R
wl_resource_post_error(resource->handle, error::error_inconsistent_set, "max_cll and max_fall must only be set with the PQ transfer function");
return;
}
new XXImageDescriptionV1(resource->client(), image_description, resource->version(), ColorDescription(*m_colorimetry, *m_transferFunction, 100, 0, m_maxFrameAverageBrightness.value_or(100), m_maxPeakBrightness.value_or(100), 0));
new XXImageDescriptionV1(resource->client(), image_description, resource->version(), ColorDescription(*m_colorimetry, *m_transferFunction, 100, 0, m_maxFrameAverageBrightness.value_or(100), m_maxPeakBrightness.value_or(100)));
}
void XXColorParametricCreatorV1::xx_image_description_creator_params_v1_set_tf_named(Resource *resource, uint32_t tf)