KWin
Loading...
Searching...
No Matches
icc_shader.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2023 Xaver Hugl <xaver.hugl@gmail.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6#include "icc_shader.h"
7#include "core/colorlut3d.h"
9#include "core/iccprofile.h"
10#include "opengl/gllut.h"
11#include "opengl/gllut3D.h"
12#include "opengl/glshader.h"
14
15namespace KWin
16{
17
18static constexpr size_t lutSize = 1 << 12;
19
21 : m_shader(ShaderManager::instance()->generateShaderFromFile(ShaderTrait::MapTexture, QString(), QStringLiteral(":/backends/drm/icc.frag")))
22{
23 m_locations = {
24 .src = m_shader->uniformLocation("src"),
25 .sdrBrightness = m_shader->uniformLocation("sdrBrightness"),
26 .toXYZD50 = m_shader->uniformLocation("toXYZD50"),
27 .bsize = m_shader->uniformLocation("Bsize"),
28 .bsampler = m_shader->uniformLocation("Bsampler"),
29 .matrix2 = m_shader->uniformLocation("matrix2"),
30 .msize = m_shader->uniformLocation("Msize"),
31 .msampler = m_shader->uniformLocation("Msampler"),
32 .csize = m_shader->uniformLocation("Csize"),
33 .csampler = m_shader->uniformLocation("Csampler"),
34 .asize = m_shader->uniformLocation("Asize"),
35 .asampler = m_shader->uniformLocation("Asampler"),
36 };
37}
38
42
43static const QVector2D D50 = Colorimetry::xyzToXY(QVector3D(0.9642, 1.0, 0.8249));
44
45bool IccShader::setProfile(const std::shared_ptr<IccProfile> &profile)
46{
47 if (!profile) {
48 m_toXYZD50.setToIdentity();
49 m_B.reset();
50 m_matrix2.setToIdentity();
51 m_M.reset();
52 m_C.reset();
53 m_A.reset();
54 return false;
55 }
56 if (m_profile != profile) {
57 const auto vcgt = profile->vcgt();
58 QMatrix4x4 toXYZD50;
59 std::unique_ptr<GlLookUpTable> B;
60 QMatrix4x4 matrix2;
61 std::unique_ptr<GlLookUpTable> M;
62 std::unique_ptr<GlLookUpTable3D> C;
63 std::unique_ptr<GlLookUpTable> A;
64 if (const IccProfile::BToATagData *tag = profile->BtToATag()) {
65 toXYZD50 = Colorimetry::chromaticAdaptationMatrix(profile->colorimetry().white(), D50) * profile->colorimetry().toXYZ();
66 if (tag->B) {
67 const auto sample = [&tag](size_t x) {
68 const float relativeX = x / double(lutSize - 1);
69 return tag->B->transform(QVector3D(relativeX, relativeX, relativeX));
70 };
71 B = GlLookUpTable::create(sample, lutSize);
72 if (!B) {
73 return false;
74 }
75 }
76 matrix2 = tag->matrix.value_or(QMatrix4x4());
77 if (tag->M) {
78 const auto sample = [&tag](size_t x) {
79 const float relativeX = x / double(lutSize - 1);
80 return tag->M->transform(QVector3D(relativeX, relativeX, relativeX));
81 };
82 M = GlLookUpTable::create(sample, lutSize);
83 if (!M) {
84 return false;
85 }
86 }
87 if (tag->CLut) {
88 const auto sample = [&tag](size_t x, size_t y, size_t z) {
89 return tag->CLut->sample(x, y, z);
90 };
91 C = GlLookUpTable3D::create(sample, tag->CLut->xSize(), tag->CLut->ySize(), tag->CLut->zSize());
92 if (!C) {
93 return false;
94 }
95 }
96 if (tag->A) {
97 const auto sample = [&tag, vcgt](size_t x) {
98 const float relativeX = x / double(lutSize - 1);
99 QVector3D ret = tag->A->transform(QVector3D(relativeX, relativeX, relativeX));
100 if (vcgt) {
101 ret = vcgt->transform(ret);
102 }
103 return ret;
104 };
105 A = GlLookUpTable::create(sample, lutSize);
106 if (!A) {
107 return false;
108 }
109 } else if (vcgt) {
110 const auto sample = [&vcgt](size_t x) {
111 const float relativeX = x / double(lutSize - 1);
112 return vcgt->transform(QVector3D(relativeX, relativeX, relativeX));
113 };
114 A = GlLookUpTable::create(sample, lutSize);
115 }
116 } else {
117 const auto inverseEOTF = profile->inverseEOTF();
118 const auto sample = [inverseEOTF, vcgt](size_t x) {
119 const float relativeX = x / double(lutSize - 1);
120 QVector3D ret(relativeX, relativeX, relativeX);
121 ret = inverseEOTF->transform(ret);
122 if (vcgt) {
123 ret = vcgt->transform(ret);
124 }
125 return ret;
126 };
127 A = GlLookUpTable::create(sample, lutSize);
128 if (!A) {
129 return false;
130 }
131 }
132 m_toXYZD50 = toXYZD50;
133 m_B = std::move(B);
134 m_matrix2 = matrix2;
135 m_M = std::move(M);
136 m_C = std::move(C);
137 m_A = std::move(A);
138 m_profile = profile;
139 }
140 return true;
141}
142
144{
145 return m_shader.get();
146}
147
148void IccShader::setUniforms(const std::shared_ptr<IccProfile> &profile, float sdrBrightness, const QVector3D &channelFactors)
149{
150 // this failing can be silently ignored, it should only happen with GPU resets and gets corrected later
151 setProfile(profile);
152
153 QMatrix4x4 nightColor;
154 nightColor(0, 0) = channelFactors.x();
155 nightColor(1, 1) = channelFactors.y();
156 nightColor(2, 2) = channelFactors.z();
157 m_shader->setUniform(m_locations.toXYZD50, m_toXYZD50 * nightColor);
158 m_shader->setUniform(m_locations.sdrBrightness, sdrBrightness);
159
160 glActiveTexture(GL_TEXTURE1);
161 if (m_B) {
162 m_shader->setUniform(m_locations.bsize, int(m_B->size()));
163 m_shader->setUniform(m_locations.bsampler, 1);
164 m_B->bind();
165 } else {
166 m_shader->setUniform(m_locations.bsize, 0);
167 m_shader->setUniform(m_locations.bsampler, 1);
168 glBindTexture(GL_TEXTURE_1D, 0);
169 }
170
171 m_shader->setUniform(m_locations.matrix2, m_matrix2);
172
173 glActiveTexture(GL_TEXTURE2);
174 if (m_M) {
175 m_shader->setUniform(m_locations.msize, int(m_M->size()));
176 m_shader->setUniform(m_locations.msampler, 2);
177 m_M->bind();
178 } else {
179 m_shader->setUniform(m_locations.msize, 0);
180 m_shader->setUniform(m_locations.msampler, 1);
181 glBindTexture(GL_TEXTURE_1D, 0);
182 }
183
184 glActiveTexture(GL_TEXTURE3);
185 if (m_C) {
186 m_shader->setUniform(m_locations.csize, m_C->xSize(), m_C->ySize(), m_C->zSize());
187 m_shader->setUniform(m_locations.csampler, 3);
188 m_C->bind();
189 } else {
190 m_shader->setUniform(m_locations.csize, 0, 0, 0);
191 m_shader->setUniform(m_locations.csampler, 3);
192 glBindTexture(GL_TEXTURE_3D, 0);
193 }
194
195 glActiveTexture(GL_TEXTURE4);
196 if (m_A) {
197 m_shader->setUniform(m_locations.asize, int(m_A->size()));
198 m_shader->setUniform(m_locations.asampler, 4);
199 m_A->bind();
200 } else {
201 m_shader->setUniform(m_locations.asize, 0);
202 m_shader->setUniform(m_locations.asampler, 4);
203 glBindTexture(GL_TEXTURE_1D, 0);
204 }
205
206 glActiveTexture(GL_TEXTURE0);
207 m_shader->setUniform(m_locations.src, 0);
208}
209
210}
static QMatrix4x4 chromaticAdaptationMatrix(QVector2D sourceWhitepoint, QVector2D destinationWhitepoint)
static QVector2D xyzToXY(QVector3D xyz)
static std::unique_ptr< GlLookUpTable3D > create(const std::function< QVector3D(size_t x, size_t y, size_t z)> &mapping, size_t xSize, size_t ySize, size_t zSize)
Definition gllut3D.cpp:54
static std::unique_ptr< GlLookUpTable > create(const std::function< QVector3D(size_t value)> &func, size_t size)
Definition gllut.cpp:42
void setUniforms(const std::shared_ptr< IccProfile > &profile, float sdrBrightness, const QVector3D &channelFactors)
GLShader * shader() const
Manager for Shaders.