core/colorspace: implement black point compensation
This commit is contained in:
parent
cd371d8618
commit
0d0135e237
6 changed files with 39 additions and 11 deletions
|
@ -11,6 +11,14 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
ValueRange ValueRange::operator*(double mult) const
|
||||
{
|
||||
return ValueRange{
|
||||
.min = min * mult,
|
||||
.max = max * mult,
|
||||
};
|
||||
}
|
||||
|
||||
ColorPipeline ColorPipeline::create(const ColorDescription &from, const ColorDescription &to, RenderingIntent intent)
|
||||
{
|
||||
const auto range1 = ValueRange(from.minLuminance(), from.maxHdrLuminance().value_or(from.referenceLuminance()));
|
||||
|
@ -19,11 +27,10 @@ ColorPipeline ColorPipeline::create(const ColorDescription &from, const ColorDes
|
|||
.max = from.transferFunction().nitsToEncoded(range1.max),
|
||||
});
|
||||
ret.addTransferFunction(from.transferFunction());
|
||||
ret.addMultiplier(to.referenceLuminance() / from.referenceLuminance());
|
||||
|
||||
// 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.toOther(to, intent), ret.currentOutputRange());
|
||||
ret.addMatrix(from.toOther(to, intent), ret.currentOutputRange() * (to.referenceLuminance() / from.referenceLuminance()));
|
||||
|
||||
ret.addInverseTransferFunction(to.transferFunction());
|
||||
return ret;
|
||||
|
|
|
@ -20,6 +20,7 @@ public:
|
|||
double max = 1;
|
||||
|
||||
bool operator==(const ValueRange &) const = default;
|
||||
ValueRange operator*(double mult) const;
|
||||
};
|
||||
|
||||
class KWIN_EXPORT ColorTransferFunction
|
||||
|
|
|
@ -326,15 +326,36 @@ std::optional<double> ColorDescription::maxHdrLuminance() const
|
|||
|
||||
QMatrix4x4 ColorDescription::toOther(const ColorDescription &other, RenderingIntent intent) const
|
||||
{
|
||||
QMatrix4x4 luminanceBefore;
|
||||
QMatrix4x4 luminanceAfter;
|
||||
if (intent == RenderingIntent::Perceptual || intent == RenderingIntent::RelativeColorimetricWithBPC) {
|
||||
// add black point compensation: black and reference white from the source color space
|
||||
// should both be mapped to black and reference white in the destination color space
|
||||
|
||||
// before color conversions, map [src min, src ref] to [0, 1]
|
||||
luminanceBefore.scale(1.0 / (referenceLuminance() - minLuminance()));
|
||||
luminanceBefore.translate(-minLuminance(), -minLuminance(), -minLuminance());
|
||||
// afterwards, map [0, 1] again to [dst min, dst ref]
|
||||
luminanceAfter.translate(other.minLuminance(), other.minLuminance(), other.minLuminance());
|
||||
luminanceAfter.scale(other.referenceLuminance() - other.minLuminance());
|
||||
} else {
|
||||
// map only the reference luminance
|
||||
luminanceBefore.scale(other.referenceLuminance() / referenceLuminance());
|
||||
}
|
||||
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();
|
||||
return luminanceAfter * other.containerColorimetry().fromXYZ() * Colorimetry::chromaticAdaptationMatrix(srcContainer.white(), other.containerColorimetry().white()) * srcContainer.toXYZ() * luminanceBefore;
|
||||
}
|
||||
case RenderingIntent::RelativeColorimetric: {
|
||||
return luminanceAfter * other.containerColorimetry().fromXYZ() * Colorimetry::chromaticAdaptationMatrix(containerColorimetry().white(), other.containerColorimetry().white()) * containerColorimetry().toXYZ() * luminanceBefore;
|
||||
}
|
||||
case RenderingIntent::RelativeColorimetricWithBPC: {
|
||||
return luminanceAfter * other.containerColorimetry().fromXYZ() * Colorimetry::chromaticAdaptationMatrix(containerColorimetry().white(), other.containerColorimetry().white()) * containerColorimetry().toXYZ() * luminanceBefore;
|
||||
}
|
||||
case RenderingIntent::AbsoluteColorimetric: {
|
||||
return luminanceAfter * other.containerColorimetry().fromXYZ() * containerColorimetry().toXYZ() * luminanceBefore;
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
@ -342,7 +363,6 @@ QMatrix4x4 ColorDescription::toOther(const ColorDescription &other, RenderingInt
|
|||
QVector3D ColorDescription::mapTo(QVector3D rgb, const ColorDescription &dst, RenderingIntent intent) const
|
||||
{
|
||||
rgb = m_transferFunction.encodedToNits(rgb);
|
||||
rgb *= dst.referenceLuminance() / m_referenceLuminance;
|
||||
rgb = toOther(dst, intent) * rgb;
|
||||
return dst.transferFunction().nitsToEncoded(rgb);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ enum class RenderingIntent {
|
|||
/* colorimetric mapping between color spaces, without whitepoint adaptation */
|
||||
AbsoluteColorimetric,
|
||||
/* colorimetric mapping between color spaces, with whitepoint adaptation and black point compensation */
|
||||
// TODO RelativeColorimetricWithBPC,
|
||||
RelativeColorimetricWithBPC,
|
||||
};
|
||||
|
||||
enum class NamedColorimetry {
|
||||
|
|
|
@ -94,7 +94,6 @@ vec4 encodingToNits(vec4 color, int sourceTransferFunction, float luminanceOffse
|
|||
|
||||
vec4 sourceEncodingToNitsInDestinationColorspace(vec4 color) {
|
||||
color = encodingToNits(color, sourceNamedTransferFunction, sourceTransferFunctionParams.x, sourceTransferFunctionParams.y);
|
||||
color.rgb = color.rgb * (destinationReferenceLuminance / sourceReferenceLuminance);
|
||||
color.rgb = (colorimetryTransform * vec4(color.rgb, 1.0)).rgb;
|
||||
return vec4(doTonemapping(color.rgb, maxDestinationLuminance), color.a);
|
||||
}
|
||||
|
|
|
@ -46,7 +46,8 @@ void XXColorManagerV4::xx_color_manager_v4_bind_resource(Resource *resource)
|
|||
send_supported_intent(resource->handle, render_intent::render_intent_perceptual);
|
||||
send_supported_intent(resource->handle, render_intent::render_intent_relative);
|
||||
send_supported_intent(resource->handle, render_intent::render_intent_absolute);
|
||||
// TODO implement saturation and relative bpc intents
|
||||
send_supported_intent(resource->handle, render_intent::render_intent_relative_bpc);
|
||||
// TODO implement saturation intent
|
||||
}
|
||||
|
||||
void XXColorManagerV4::xx_color_manager_v4_destroy(Resource *resource)
|
||||
|
|
Loading…
Reference in a new issue