libkwineffects/kwinglutils: fix saturation calculation with wide color gamut and document it

This commit is contained in:
Xaver Hugl 2023-05-25 15:04:01 +02:00
parent 84ce4751d9
commit 6272d1d9f3
4 changed files with 29 additions and 5 deletions

View file

@ -430,6 +430,8 @@ void GLShader::resolveLocations()
mVec2Location[Offset] = uniformLocation("offset");
m_vec3Locations[Vec3Uniform::PrimaryBrightness] = uniformLocation("primaryBrightness");
mVec4Location[ModulationConstant] = uniformLocation("modulation");
mFloatLocation[Saturation] = uniformLocation("saturation");
@ -470,6 +472,12 @@ bool GLShader::setUniform(GLShader::Vec2Uniform uniform, const QVector2D &value)
return setUniform(mVec2Location[uniform], value);
}
bool GLShader::setUniform(Vec3Uniform uniform, const QVector3D &value)
{
resolveLocations();
return setUniform(m_vec3Locations[uniform], value);
}
bool GLShader::setUniform(GLShader::Vec4Uniform uniform, const QVector4D &value)
{
resolveLocations();
@ -783,6 +791,7 @@ QByteArray ShaderManager::generateFragmentSource(ShaderTraits traits) const
}
if (traits & ShaderTrait::AdjustSaturation) {
stream << "uniform float saturation;\n";
stream << "uniform vec3 primaryBrightness;\n";
}
stream << "\n"
@ -841,9 +850,6 @@ QByteArray ShaderManager::generateFragmentSource(ShaderTraits traits) const
} else if (traits & ShaderTrait::UniformColor) {
stream << " result = geometryColor;\n";
}
if (traits & ShaderTrait::AdjustSaturation) {
stream << " result.rgb = mix(vec3(dot(result.rgb, vec3(0.2126, 0.7152, 0.0722))), result.rgb, saturation);\n";
}
if (traits & ShaderTrait::TransformColorspace) {
// sRGB -> output colorspace & linear
stream << " if (sourceNamedTransferFunction == 0) {\n";
@ -851,6 +857,12 @@ QByteArray ShaderManager::generateFragmentSource(ShaderTraits traits) const
stream << " }\n";
stream << " result.rgb = doTonemapping(colorimetryTransform * result.rgb, maxHdrBrightness);\n";
}
if (traits & ShaderTrait::AdjustSaturation) {
// this calculates the Y component of the XYZ color representation for the color,
// which roughly corresponds to the brightness of the RGB tuple
stream << " float Y = dot(result.rgb, primaryBrightness);\n";
stream << " result.rgb = mix(vec3(Y), result.rgb, saturation);\n";
}
if (traits & ShaderTrait::Modulate) {
stream << " result *= modulation;\n";
}

View file

@ -121,6 +121,10 @@ public:
Vec2UniformCount
};
enum class Vec3Uniform {
PrimaryBrightness = 0
};
enum Vec4Uniform {
ModulationConstant,
Vec4UniformCount
@ -150,6 +154,7 @@ public:
bool setUniform(MatrixUniform uniform, const QMatrix3x3 &value);
bool setUniform(MatrixUniform uniform, const QMatrix4x4 &matrix);
bool setUniform(Vec2Uniform uniform, const QVector2D &value);
bool setUniform(Vec3Uniform uniform, const QVector3D &value);
bool setUniform(Vec4Uniform uniform, const QVector4D &value);
bool setUniform(FloatUniform uniform, float value);
bool setUniform(IntUniform uniform, int value);
@ -177,6 +182,7 @@ private:
bool mExplicitLinking : 1;
int mMatrixLocation[MatrixCount];
int mVec2Location[Vec2UniformCount];
QHash<Vec3Uniform, int> m_vec3Locations;
int mVec4Location[Vec4UniformCount];
int mFloatLocation[FloatUniformCount];
int mIntLocation[IntUniformCount];

View file

@ -155,7 +155,6 @@ void OffscreenData::paint(const RenderTarget &renderTarget, const RenderViewport
{
GLShader *shader = m_shader ? m_shader : ShaderManager::instance()->shader(ShaderTrait::MapTexture | ShaderTrait::Modulate | ShaderTrait::AdjustSaturation | ShaderTrait::TransformColorspace);
ShaderBinder binder(shader);
shader->setColorspaceUniformsFromSRGB(renderTarget.colorDescription());
const double scale = viewport.scale();
@ -185,11 +184,14 @@ void OffscreenData::paint(const RenderTarget &renderTarget, const RenderViewport
QMatrix4x4 mvp = data.projectionMatrix();
mvp.translate(window->x() * scale, window->y() * scale);
const auto toXYZ = renderTarget.colorDescription().colorimetry().toXYZ();
shader->setUniform(GLShader::ModelViewProjectionMatrix, mvp * data.toMatrix(scale));
shader->setUniform(GLShader::ModulationConstant, QVector4D(rgb, rgb, rgb, a));
shader->setUniform(GLShader::Saturation, data.saturation());
shader->setUniform(GLShader::Vec3Uniform::PrimaryBrightness, QVector3D(toXYZ(1, 0), toXYZ(1, 1), toXYZ(1, 2)));
shader->setUniform(GLShader::TextureWidth, m_texture->width());
shader->setUniform(GLShader::TextureHeight, m_texture->height());
shader->setColorspaceUniformsFromSRGB(renderTarget.colorDescription());
const bool clipping = region != infiniteRegion();
const QRegion clipRegion = clipping ? viewport.mapToRenderTarget(region) : infiniteRegion();

View file

@ -322,7 +322,11 @@ void ItemRendererOpenGL::renderItem(const RenderTarget &renderTarget, const Rend
vbo->bindArrays();
GLShader *shader = ShaderManager::instance()->pushShader(shaderTraits);
shader->setUniform(GLShader::Saturation, data.saturation());
if (shaderTraits & ShaderTrait::AdjustSaturation) {
const auto toXYZ = renderTarget.colorDescription().colorimetry().toXYZ();
shader->setUniform(GLShader::Saturation, data.saturation());
shader->setUniform(GLShader::Vec3Uniform::PrimaryBrightness, QVector3D(toXYZ(1, 0), toXYZ(1, 1), toXYZ(1, 2)));
}
shader->setColorspaceUniformsFromSRGB(renderTarget.colorDescription());
if (renderContext.hardwareClipping) {