diff --git a/src/backends/drm/icc.frag b/src/backends/drm/icc.frag index be55244447..5f9963e6f0 100644 --- a/src/backends/drm/icc.frag +++ b/src/backends/drm/icc.frag @@ -9,7 +9,7 @@ in vec2 texcoord0; uniform sampler2D src; uniform float sdrBrightness; -uniform mat3 matrix1; +uniform mat4 toXYZD50; uniform int Bsize; uniform sampler2D Bsampler; @@ -39,7 +39,7 @@ void main() vec4 tex = texture2D(src, texcoord0); tex.rgb /= max(tex.a, 0.001); tex.rgb /= sdrBrightness; - tex.rgb = matrix1 * tex.rgb; + tex.rgb = (toXYZD50 * vec4(tex.rgb, 1.0)).rgb; if (Bsize > 0) { tex.rgb = sample1DLut(tex.rgb, Bsampler, Bsize); } diff --git a/src/backends/drm/icc_core.frag b/src/backends/drm/icc_core.frag index 872869bfe6..1f23127803 100644 --- a/src/backends/drm/icc_core.frag +++ b/src/backends/drm/icc_core.frag @@ -12,7 +12,7 @@ out vec4 fragColor; uniform sampler2D src; uniform float sdrBrightness; -uniform mat3 matrix1; +uniform mat4 toXYZD50; uniform int Bsize; uniform sampler2D Bsampler; @@ -42,7 +42,7 @@ void main() vec4 tex = texture(src, texcoord0); tex.rgb /= max(tex.a, 0.001); tex.rgb /= sdrBrightness; - tex.rgb = matrix1 * tex.rgb; + tex.rgb = (toXYZD50 * vec4(tex.rgb, 1.0)).rgb; if (Bsize > 0) { tex.rgb = sample1DLut(tex.rgb, Bsampler, Bsize); } diff --git a/src/backends/drm/icc_shader.cpp b/src/backends/drm/icc_shader.cpp index ea3e0a2a58..b36fc34d65 100644 --- a/src/backends/drm/icc_shader.cpp +++ b/src/backends/drm/icc_shader.cpp @@ -23,7 +23,7 @@ IccShader::IccShader() m_locations = { .src = m_shader->uniformLocation("src"), .sdrBrightness = m_shader->uniformLocation("sdrBrightness"), - .matrix1 = m_shader->uniformLocation("matrix1"), + .toXYZD50 = m_shader->uniformLocation("toXYZD50"), .bsize = m_shader->uniformLocation("Bsize"), .bsampler = m_shader->uniformLocation("Bsampler"), .matrix2 = m_shader->uniformLocation("matrix2"), @@ -45,7 +45,7 @@ static const QVector2D D50 = Colorimetry::xyzToXY(QVector3D(0.9642, 1.0, 0.8249) bool IccShader::setProfile(const std::shared_ptr &profile) { if (!profile) { - m_matrix1.setToIdentity(); + m_toXYZD50.setToIdentity(); m_B.reset(); m_matrix2.setToIdentity(); m_M.reset(); @@ -55,14 +55,14 @@ bool IccShader::setProfile(const std::shared_ptr &profile) } if (m_profile != profile) { const auto vcgt = profile->vcgt(); - QMatrix3x3 matrix1; + QMatrix4x4 toXYZD50; std::unique_ptr B; QMatrix4x4 matrix2; std::unique_ptr M; std::unique_ptr C; std::unique_ptr A; if (const IccProfile::BToATagData *tag = profile->BtToATag()) { - matrix1 = Colorimetry::chromaticAdaptationMatrix(profile->colorimetry().white(), D50) * profile->colorimetry().toXYZ(); + toXYZD50 = Colorimetry::chromaticAdaptationMatrix(profile->colorimetry().white(), D50) * profile->colorimetry().toXYZ(); if (tag->B) { const auto sample = [&tag](size_t x) { const float relativeX = x / double(lutSize - 1); @@ -129,7 +129,7 @@ bool IccShader::setProfile(const std::shared_ptr &profile) return false; } } - m_matrix1 = matrix1; + m_toXYZD50 = toXYZD50; m_B = std::move(B); m_matrix2 = matrix2; m_M = std::move(M); @@ -150,11 +150,11 @@ void IccShader::setUniforms(const std::shared_ptr &profile, float sd // this failing can be silently ignored, it should only happen with GPU resets and gets corrected later setProfile(profile); - QMatrix3x3 nightColor; + QMatrix4x4 nightColor; nightColor(0, 0) = channelFactors.x(); nightColor(1, 1) = channelFactors.y(); nightColor(2, 2) = channelFactors.z(); - m_shader->setUniform(m_locations.matrix1, m_matrix1 * nightColor); + m_shader->setUniform(m_locations.toXYZD50, m_toXYZD50 * nightColor); m_shader->setUniform(m_locations.sdrBrightness, sdrBrightness); glActiveTexture(GL_TEXTURE1); diff --git a/src/backends/drm/icc_shader.h b/src/backends/drm/icc_shader.h index 8159c2241e..faecfaca39 100644 --- a/src/backends/drm/icc_shader.h +++ b/src/backends/drm/icc_shader.h @@ -33,7 +33,7 @@ private: std::unique_ptr m_shader; std::shared_ptr m_profile; - QMatrix3x3 m_matrix1; + QMatrix4x4 m_toXYZD50; std::unique_ptr m_B; QMatrix4x4 m_matrix2; std::unique_ptr m_M; @@ -43,7 +43,7 @@ private: { int src; int sdrBrightness; - int matrix1; + int toXYZD50; int bsize; int bsampler; int matrix2; diff --git a/src/core/colorspace.cpp b/src/core/colorspace.cpp index 2905b892b7..1e50c8e604 100644 --- a/src/core/colorspace.cpp +++ b/src/core/colorspace.cpp @@ -10,25 +10,9 @@ namespace KWin { -static QMatrix3x3 inverse(const QMatrix3x3 &m) +static QMatrix4x4 matrixFromColumns(const QVector3D &first, const QVector3D &second, const QVector3D &third) { - const double determinant = m(0, 0) * (m(1, 1) * m(2, 2) - m(2, 1) * m(1, 2)) - m(0, 1) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) + m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0)); - QMatrix3x3 ret; - ret(0, 0) = (m(1, 1) * m(2, 2) - m(2, 1) * m(1, 2)) / determinant; - ret(0, 1) = (m(0, 2) * m(2, 1) - m(0, 1) * m(2, 2)) / determinant; - ret(0, 2) = (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)) / determinant; - ret(1, 0) = (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) / determinant; - ret(1, 1) = (m(0, 0) * m(2, 2) - m(0, 2) * m(2, 0)) / determinant; - ret(1, 2) = (m(1, 0) * m(0, 2) - m(0, 0) * m(1, 2)) / determinant; - ret(2, 0) = (m(1, 0) * m(2, 1) - m(2, 0) * m(1, 1)) / determinant; - ret(2, 1) = (m(2, 0) * m(0, 1) - m(0, 0) * m(2, 1)) / determinant; - ret(2, 2) = (m(0, 0) * m(1, 1) - m(1, 0) * m(0, 1)) / determinant; - return ret; -} - -static QMatrix3x3 matrixFromColumns(const QVector3D &first, const QVector3D &second, const QVector3D &third) -{ - QMatrix3x3 ret; + QMatrix4x4 ret; ret(0, 0) = first.x(); ret(1, 0) = first.y(); ret(2, 0) = first.z(); @@ -41,14 +25,6 @@ static QMatrix3x3 matrixFromColumns(const QVector3D &first, const QVector3D &sec return ret; } -static QVector3D operator*(const QMatrix3x3 &mat, const QVector3D &v) -{ - return QVector3D( - mat(0, 0) * v.x() + mat(0, 1) * v.y() + mat(0, 2) * v.z(), - mat(1, 0) * v.x() + mat(1, 1) * v.y() + mat(1, 2) * v.z(), - mat(2, 0) * v.x() + mat(2, 1) * v.y() + mat(2, 2) * v.z()); -} - QVector3D Colorimetry::xyToXYZ(QVector2D xy) { return QVector3D(xy.x() / xy.y(), 1, (1 - xy.x() - xy.y()) / xy.y()); @@ -60,10 +36,10 @@ QVector2D Colorimetry::xyzToXY(QVector3D xyz) return QVector2D(xyz.x() / (xyz.x() + xyz.y() + xyz.z()), xyz.y() / (xyz.x() + xyz.y() + xyz.z())); } -QMatrix3x3 Colorimetry::chromaticAdaptationMatrix(QVector2D sourceWhitepoint, QVector2D destinationWhitepoint) +QMatrix4x4 Colorimetry::chromaticAdaptationMatrix(QVector2D sourceWhitepoint, QVector2D destinationWhitepoint) { - static const QMatrix3x3 bradford = []() { - QMatrix3x3 ret; + static const QMatrix4x4 bradford = []() { + QMatrix4x4 ret; ret(0, 0) = 0.8951; ret(0, 1) = 0.2664; ret(0, 2) = -0.1614; @@ -75,8 +51,8 @@ QMatrix3x3 Colorimetry::chromaticAdaptationMatrix(QVector2D sourceWhitepoint, QV ret(2, 2) = 1.0296; return ret; }(); - static const QMatrix3x3 inverseBradford = []() { - QMatrix3x3 ret; + static const QMatrix4x4 inverseBradford = []() { + QMatrix4x4 ret; ret(0, 0) = 0.9869929; ret(0, 1) = -0.1470543; ret(0, 2) = 0.1599627; @@ -89,19 +65,19 @@ QMatrix3x3 Colorimetry::chromaticAdaptationMatrix(QVector2D sourceWhitepoint, QV return ret; }(); if (sourceWhitepoint == destinationWhitepoint) { - return QMatrix3x3{}; + return QMatrix4x4{}; } const QVector3D factors = (bradford * xyToXYZ(destinationWhitepoint)) / (bradford * xyToXYZ(sourceWhitepoint)); - QMatrix3x3 adaptation{}; + QMatrix4x4 adaptation{}; adaptation(0, 0) = factors.x(); adaptation(1, 1) = factors.y(); adaptation(2, 2) = factors.z(); return inverseBradford * adaptation * bradford; } -QMatrix3x3 Colorimetry::calculateToXYZMatrix(QVector3D red, QVector3D green, QVector3D blue, QVector3D white) +QMatrix4x4 Colorimetry::calculateToXYZMatrix(QVector3D red, QVector3D green, QVector3D blue, QVector3D white) { - const auto component_scale = inverse(matrixFromColumns(red, green, blue)) * white; + const auto component_scale = (matrixFromColumns(red, green, blue)).inverted() * white; return matrixFromColumns(red * component_scale.x(), green * component_scale.y(), blue * component_scale.z()); } @@ -111,7 +87,7 @@ Colorimetry::Colorimetry(QVector2D red, QVector2D green, QVector2D blue, QVector , m_blue(blue) , m_white(white) , m_toXYZ(calculateToXYZMatrix(xyToXYZ(red), xyToXYZ(green), xyToXYZ(blue), xyToXYZ(white))) - , m_fromXYZ(inverse(m_toXYZ)) + , m_fromXYZ(m_toXYZ.inverted()) { } @@ -121,21 +97,21 @@ Colorimetry::Colorimetry(QVector3D red, QVector3D green, QVector3D blue, QVector , m_blue(xyzToXY(blue)) , m_white(xyzToXY(white)) , m_toXYZ(calculateToXYZMatrix(red, green, blue, white)) - , m_fromXYZ(inverse(m_toXYZ)) + , m_fromXYZ(m_toXYZ.inverted()) { } -const QMatrix3x3 &Colorimetry::toXYZ() const +const QMatrix4x4 &Colorimetry::toXYZ() const { return m_toXYZ; } -const QMatrix3x3 &Colorimetry::fromXYZ() const +const QMatrix4x4 &Colorimetry::fromXYZ() const { return m_fromXYZ; } -QMatrix3x3 Colorimetry::toOther(const Colorimetry &other) const +QMatrix4x4 Colorimetry::toOther(const Colorimetry &other) const { // rendering intent is relative colorimetric, so adapt to the different whitepoint return other.fromXYZ() * chromaticAdaptationMatrix(this->white(), other.white()) * toXYZ(); diff --git a/src/core/colorspace.h b/src/core/colorspace.h index 48ab6ad20d..70a8e2f1d1 100644 --- a/src/core/colorspace.h +++ b/src/core/colorspace.h @@ -6,7 +6,7 @@ #pragma once #include -#include +#include #include #include "kwin_export.h" @@ -39,9 +39,9 @@ public: /** * @returns a matrix adapting XYZ values from the source whitepoint to the destination whitepoint with the Bradford transform */ - static QMatrix3x3 chromaticAdaptationMatrix(QVector2D sourceWhitepoint, QVector2D destinationWhitepoint); + static QMatrix4x4 chromaticAdaptationMatrix(QVector2D sourceWhitepoint, QVector2D destinationWhitepoint); - static QMatrix3x3 calculateToXYZMatrix(QVector3D red, QVector3D green, QVector3D blue, QVector3D white); + static QMatrix4x4 calculateToXYZMatrix(QVector3D red, QVector3D green, QVector3D blue, QVector3D white); explicit Colorimetry(QVector2D red, QVector2D green, QVector2D blue, QVector2D white); explicit Colorimetry(QVector3D red, QVector3D green, QVector3D blue, QVector3D white); @@ -49,16 +49,16 @@ public: /** * @returns a matrix that transforms from the linear RGB representation of colors in this colorimetry to the XYZ representation */ - const QMatrix3x3 &toXYZ() const; + const QMatrix4x4 &toXYZ() const; /** * @returns a matrix that transforms from the XYZ representation to the linear RGB representation of colors in this colorimetry */ - const QMatrix3x3 &fromXYZ() const; + const QMatrix4x4 &fromXYZ() const; /** * @returns a matrix that transforms from linear RGB in this colorimetry to linear RGB in the other colorimetry * the rendering intent is relative colorimetric */ - QMatrix3x3 toOther(const Colorimetry &colorimetry) const; + QMatrix4x4 toOther(const Colorimetry &colorimetry) const; bool operator==(const Colorimetry &other) const; bool operator==(NamedColorimetry name) const; /** @@ -76,8 +76,8 @@ private: QVector2D m_green; QVector2D m_blue; QVector2D m_white; - QMatrix3x3 m_toXYZ; - QMatrix3x3 m_fromXYZ; + QMatrix4x4 m_toXYZ; + QMatrix4x4 m_fromXYZ; }; /** diff --git a/src/opengl/colormanagement.glsl b/src/opengl/colormanagement.glsl index 27fe6c23ad..2645f5f034 100644 --- a/src/opengl/colormanagement.glsl +++ b/src/opengl/colormanagement.glsl @@ -4,7 +4,7 @@ const int PQ_EOTF = 2; const int scRGB_EOTF = 3; const int gamma22_EOTF = 4; -uniform mat3 colorimetryTransform; +uniform mat4 colorimetryTransform; uniform int sourceNamedTransferFunction; uniform int destinationNamedTransferFunction; uniform float sdrBrightness;// in nits @@ -57,7 +57,7 @@ vec3 linearToSrgb(vec3 color) { vec3 doTonemapping(vec3 color, float maxBrightness) { // TODO do something better here - return clamp(color, vec3(0.0), vec3(maxBrightness)); + return clamp(color.rgb, vec3(0.0), vec3(maxBrightness)); } vec4 encodingToNits(vec4 color, int sourceTransferFunction) { @@ -81,7 +81,8 @@ vec4 encodingToNits(vec4 color, int sourceTransferFunction) { vec4 sourceEncodingToNitsInDestinationColorspace(vec4 color) { color = encodingToNits(color, sourceNamedTransferFunction); - return vec4(doTonemapping(colorimetryTransform * color.rgb, maxHdrBrightness), color.a); + color.rgb = (colorimetryTransform * vec4(color.rgb, 1.0)).rgb; + return vec4(doTonemapping(color.rgb, maxHdrBrightness), color.a); } vec4 nitsToEncoding(vec4 color, int destinationTransferFunction) {