KWin
Loading...
Searching...
No Matches
glshader.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2006-2007 Rivo Laks <rivolaks@hot.ee>
6 SPDX-FileCopyrightText: 2010, 2011 Martin Gräßlin <mgraesslin@kde.org>
7 SPDX-FileCopyrightText: 2023 Xaver Hugl <xaver.hugl@kde.org>
8
9 SPDX-License-Identifier: GPL-2.0-or-later
10*/
11#include "glshader.h"
12#include "glplatform.h"
13#include "glutils.h"
14#include "utils/common.h"
15
16#include <QFile>
17
18namespace KWin
19{
20
21GLShader::GLShader(unsigned int flags)
22 : m_valid(false)
23 , m_locationsResolved(false)
24 , m_explicitLinking(flags & ExplicitLinking)
25{
26 m_program = glCreateProgram();
27}
28
29GLShader::GLShader(const QString &vertexfile, const QString &fragmentfile, unsigned int flags)
30 : m_valid(false)
31 , m_locationsResolved(false)
32 , m_explicitLinking(flags & ExplicitLinking)
33{
34 m_program = glCreateProgram();
35 loadFromFiles(vertexfile, fragmentfile);
36}
37
39{
40 if (m_program) {
41 glDeleteProgram(m_program);
42 }
43}
44
45bool GLShader::loadFromFiles(const QString &vertexFile, const QString &fragmentFile)
46{
47 QFile vf(vertexFile);
48 if (!vf.open(QIODevice::ReadOnly)) {
49 qCCritical(KWIN_OPENGL) << "Couldn't open" << vertexFile << "for reading!";
50 return false;
51 }
52 const QByteArray vertexSource = vf.readAll();
53
54 QFile ff(fragmentFile);
55 if (!ff.open(QIODevice::ReadOnly)) {
56 qCCritical(KWIN_OPENGL) << "Couldn't open" << fragmentFile << "for reading!";
57 return false;
58 }
59 const QByteArray fragmentSource = ff.readAll();
60
61 return load(vertexSource, fragmentSource);
62}
63
65{
66 // Be optimistic
67 m_valid = true;
68
69 glLinkProgram(m_program);
70
71 // Get the program info log
72 int maxLength, length;
73 glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &maxLength);
74
75 QByteArray log(maxLength, 0);
76 glGetProgramInfoLog(m_program, maxLength, &length, log.data());
77
78 // Make sure the program linked successfully
79 int status;
80 glGetProgramiv(m_program, GL_LINK_STATUS, &status);
81
82 if (status == 0) {
83 qCCritical(KWIN_OPENGL) << "Failed to link shader:"
84 << "\n"
85 << log;
86 m_valid = false;
87 } else if (length > 0) {
88 qCDebug(KWIN_OPENGL) << "Shader link log:" << log;
89 }
90
91 return m_valid;
92}
93
94const QByteArray GLShader::prepareSource(GLenum shaderType, const QByteArray &source) const
95{
96 // Prepare the source code
97 QByteArray ba;
98 if (GLPlatform::instance()->isGLES() && GLPlatform::instance()->glslVersion() < Version(3, 0)) {
99 ba.append("precision highp float;\n");
100 }
101 ba.append(source);
102 if (GLPlatform::instance()->isGLES() && GLPlatform::instance()->glslVersion() >= Version(3, 0)) {
103 ba.replace("#version 140", "#version 300 es\n\nprecision highp float;\n");
104 }
105
106 return ba;
107}
108
109bool GLShader::compile(GLuint program, GLenum shaderType, const QByteArray &source) const
110{
111 GLuint shader = glCreateShader(shaderType);
112
113 QByteArray preparedSource = prepareSource(shaderType, source);
114 const char *src = preparedSource.constData();
115 glShaderSource(shader, 1, &src, nullptr);
116
117 // Compile the shader
118 glCompileShader(shader);
119
120 // Get the shader info log
121 int maxLength, length;
122 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
123
124 QByteArray log(maxLength, 0);
125 glGetShaderInfoLog(shader, maxLength, &length, log.data());
126
127 // Check the status
128 int status;
129 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
130
131 if (status == 0) {
132 const char *typeName = (shaderType == GL_VERTEX_SHADER ? "vertex" : "fragment");
133 qCCritical(KWIN_OPENGL) << "Failed to compile" << typeName << "shader:"
134 << "\n"
135 << log;
136 size_t line = 0;
137 const auto split = source.split('\n');
138 for (const auto &l : split) {
139 qCCritical(KWIN_OPENGL).nospace() << "line " << line++ << ":" << l;
140 }
141 } else if (length > 0) {
142 qCDebug(KWIN_OPENGL) << "Shader compile log:" << log;
143 }
144
145 if (status != 0) {
146 glAttachShader(program, shader);
147 }
148
149 glDeleteShader(shader);
150 return status != 0;
151}
152
153bool GLShader::load(const QByteArray &vertexSource, const QByteArray &fragmentSource)
154{
155 m_valid = false;
156
157 // Compile the vertex shader
158 if (!vertexSource.isEmpty()) {
159 bool success = compile(m_program, GL_VERTEX_SHADER, vertexSource);
160
161 if (!success) {
162 return false;
163 }
164 }
165
166 // Compile the fragment shader
167 if (!fragmentSource.isEmpty()) {
168 bool success = compile(m_program, GL_FRAGMENT_SHADER, fragmentSource);
169
170 if (!success) {
171 return false;
172 }
173 }
174
175 if (m_explicitLinking) {
176 return true;
177 }
178
179 // link() sets mValid
180 return link();
181}
182
183void GLShader::bindAttributeLocation(const char *name, int index)
184{
185 glBindAttribLocation(m_program, index, name);
186}
187
188void GLShader::bindFragDataLocation(const char *name, int index)
189{
190 if (!GLPlatform::instance()->isGLES() && (hasGLVersion(3, 0) || hasGLExtension(QByteArrayLiteral("GL_EXT_gpu_shader4")))) {
191 glBindFragDataLocation(m_program, index, name);
192 }
193}
194
196{
197 glUseProgram(m_program);
198}
199
201{
202 glUseProgram(0);
203}
204
206{
207 if (m_locationsResolved) {
208 return;
209 }
210
211 m_matrix4Locations[Mat4Uniform::TextureMatrix] = uniformLocation("textureMatrix");
212 m_matrix4Locations[Mat4Uniform::ProjectionMatrix] = uniformLocation("projection");
213 m_matrix4Locations[Mat4Uniform::ModelViewMatrix] = uniformLocation("modelview");
214 m_matrix4Locations[Mat4Uniform::ModelViewProjectionMatrix] = uniformLocation("modelViewProjectionMatrix");
215 m_matrix4Locations[Mat4Uniform::WindowTransformation] = uniformLocation("windowTransformation");
216 m_matrix4Locations[Mat4Uniform::ScreenTransformation] = uniformLocation("screenTransformation");
217 m_matrix4Locations[Mat4Uniform::ColorimetryTransformation] = uniformLocation("colorimetryTransform");
218
219 m_vec2Locations[Vec2Uniform::Offset] = uniformLocation("offset");
220
221 m_vec3Locations[Vec3Uniform::PrimaryBrightness] = uniformLocation("primaryBrightness");
222
223 m_vec4Locations[Vec4Uniform::ModulationConstant] = uniformLocation("modulation");
224
225 m_floatLocations[FloatUniform::Saturation] = uniformLocation("saturation");
226 m_floatLocations[FloatUniform::MaxHdrBrightness] = uniformLocation("maxHdrBrightness");
227 m_floatLocations[FloatUniform::SdrBrightness] = uniformLocation("sdrBrightness");
228
229 m_colorLocations[ColorUniform::Color] = uniformLocation("geometryColor");
230
231 m_intLocations[IntUniform::TextureWidth] = uniformLocation("textureWidth");
232 m_intLocations[IntUniform::TextureHeight] = uniformLocation("textureHeight");
233 m_intLocations[IntUniform::Sampler] = uniformLocation("sampler");
234 m_intLocations[IntUniform::Sampler1] = uniformLocation("sampler1");
235 m_intLocations[IntUniform::SourceNamedTransferFunction] = uniformLocation("sourceNamedTransferFunction");
236 m_intLocations[IntUniform::DestinationNamedTransferFunction] = uniformLocation("destinationNamedTransferFunction");
237
238 m_locationsResolved = true;
239}
240
241int GLShader::uniformLocation(const char *name)
242{
243 const int location = glGetUniformLocation(m_program, name);
244 return location;
245}
246
247bool GLShader::setUniform(Mat3Uniform uniform, const QMatrix3x3 &value)
248{
250 return setUniform(m_matrix3Locations[uniform], value);
251}
252
253bool GLShader::setUniform(Mat4Uniform uniform, const QMatrix4x4 &matrix)
254{
256 return setUniform(m_matrix4Locations[uniform], matrix);
257}
258
259bool GLShader::setUniform(Vec2Uniform uniform, const QVector2D &value)
260{
262 return setUniform(m_vec2Locations[uniform], value);
263}
264
265bool GLShader::setUniform(Vec3Uniform uniform, const QVector3D &value)
266{
268 return setUniform(m_vec3Locations[uniform], value);
269}
270
271bool GLShader::setUniform(Vec4Uniform uniform, const QVector4D &value)
272{
274 return setUniform(m_vec4Locations[uniform], value);
275}
276
277bool GLShader::setUniform(FloatUniform uniform, float value)
278{
280 return setUniform(m_floatLocations[uniform], value);
281}
282
283bool GLShader::setUniform(IntUniform uniform, int value)
284{
286 return setUniform(m_intLocations[uniform], value);
287}
288
289bool GLShader::setUniform(ColorUniform uniform, const QVector4D &value)
290{
292 return setUniform(m_colorLocations[uniform], value);
293}
294
295bool GLShader::setUniform(ColorUniform uniform, const QColor &value)
296{
298 return setUniform(m_colorLocations[uniform], value);
299}
300
301bool GLShader::setUniform(const char *name, float value)
302{
303 const int location = uniformLocation(name);
304 return setUniform(location, value);
305}
306
307bool GLShader::setUniform(const char *name, int value)
308{
309 const int location = uniformLocation(name);
310 return setUniform(location, value);
311}
312
313bool GLShader::setUniform(const char *name, const QVector2D &value)
314{
315 const int location = uniformLocation(name);
316 return setUniform(location, value);
317}
318
319bool GLShader::setUniform(const char *name, const QVector3D &value)
320{
321 const int location = uniformLocation(name);
322 return setUniform(location, value);
323}
324
325bool GLShader::setUniform(const char *name, const QVector4D &value)
326{
327 const int location = uniformLocation(name);
328 return setUniform(location, value);
329}
330
331bool GLShader::setUniform(const char *name, const QMatrix4x4 &value)
332{
333 const int location = uniformLocation(name);
334 return setUniform(location, value);
335}
336
337bool GLShader::setUniform(const char *name, const QColor &color)
338{
339 const int location = uniformLocation(name);
340 return setUniform(location, color);
341}
342
343bool GLShader::setUniform(int location, float value)
344{
345 if (location >= 0) {
346 glUniform1f(location, value);
347 }
348 return (location >= 0);
349}
350
351bool GLShader::setUniform(int location, int value)
352{
353 if (location >= 0) {
354 glUniform1i(location, value);
355 }
356 return (location >= 0);
357}
358
359bool GLShader::setUniform(int location, int xValue, int yValue, int zValue)
360{
361 if (location >= 0) {
362 glUniform3i(location, xValue, yValue, zValue);
363 }
364 return location >= 0;
365}
366
367bool GLShader::setUniform(int location, const QVector2D &value)
368{
369 if (location >= 0) {
370 glUniform2fv(location, 1, (const GLfloat *)&value);
371 }
372 return (location >= 0);
373}
374
375bool GLShader::setUniform(int location, const QVector3D &value)
376{
377 if (location >= 0) {
378 glUniform3fv(location, 1, (const GLfloat *)&value);
379 }
380 return (location >= 0);
381}
382
383bool GLShader::setUniform(int location, const QVector4D &value)
384{
385 if (location >= 0) {
386 glUniform4fv(location, 1, (const GLfloat *)&value);
387 }
388 return (location >= 0);
389}
390
391bool GLShader::setUniform(int location, const QMatrix3x3 &value)
392{
393 if (location >= 0) {
394 glUniformMatrix3fv(location, 1, GL_FALSE, value.constData());
395 }
396 return location >= 0;
397}
398
399bool GLShader::setUniform(int location, const QMatrix4x4 &value)
400{
401 if (location >= 0) {
402 glUniformMatrix4fv(location, 1, GL_FALSE, value.constData());
403 }
404 return (location >= 0);
405}
406
407bool GLShader::setUniform(int location, const QColor &color)
408{
409 if (location >= 0) {
410 glUniform4f(location, color.redF(), color.greenF(), color.blueF(), color.alphaF());
411 }
412 return (location >= 0);
413}
414
415int GLShader::attributeLocation(const char *name)
416{
417 int location = glGetAttribLocation(m_program, name);
418 return location;
419}
420
421bool GLShader::setAttribute(const char *name, float value)
422{
423 int location = attributeLocation(name);
424 if (location >= 0) {
425 glVertexAttrib1f(location, value);
426 }
427 return (location >= 0);
428}
429
430QMatrix4x4 GLShader::getUniformMatrix4x4(const char *name)
431{
432 int location = uniformLocation(name);
433 if (location >= 0) {
434 GLfloat m[16];
435 glGetnUniformfv(m_program, location, sizeof(m), m);
436 QMatrix4x4 matrix(m[0], m[4], m[8], m[12],
437 m[1], m[5], m[9], m[13],
438 m[2], m[6], m[10], m[14],
439 m[3], m[7], m[11], m[15]);
440 matrix.optimize();
441 return matrix;
442 } else {
443 return QMatrix4x4();
444 }
445}
446
456
461
470}
NamedTransferFunction transferFunction() const
static const ColorDescription sRGB
Definition colorspace.h:132
double maxHdrHighlightBrightness() const
const Colorimetry & colorimetry() const
const Colorimetry & sdrColorimetry() const
double sdrBrightness() const
QMatrix4x4 toOther(const Colorimetry &colorimetry) const
static GLPlatform * instance()
Definition glplatform.h:394
bool load(const QByteArray &vertexSource, const QByteArray &fragmentSource)
Definition glshader.cpp:153
bool setColorspaceUniformsFromSRGB(const ColorDescription &dst)
Definition glshader.cpp:457
bool setColorspaceUniformsToSRGB(const ColorDescription &src)
Definition glshader.cpp:462
bool loadFromFiles(const QString &vertexfile, const QString &fragmentfile)
Definition glshader.cpp:45
const QByteArray prepareSource(GLenum shaderType, const QByteArray &sourceCode) const
Definition glshader.cpp:94
QMatrix4x4 getUniformMatrix4x4(const char *name)
Definition glshader.cpp:430
int uniformLocation(const char *name)
Definition glshader.cpp:241
bool setAttribute(const char *name, float value)
Definition glshader.cpp:421
void resolveLocations()
Definition glshader.cpp:205
void bindAttributeLocation(const char *name, int index)
Definition glshader.cpp:183
void bindFragDataLocation(const char *name, int index)
Definition glshader.cpp:188
bool compile(GLuint program, GLenum shaderType, const QByteArray &sourceCode) const
Definition glshader.cpp:109
GLShader(const QString &vertexfile, const QString &fragmentfile, unsigned int flags=NoFlags)
Definition glshader.cpp:29
int attributeLocation(const char *name)
Definition glshader.cpp:415
bool setUniform(const char *name, float value)
Definition glshader.cpp:301
bool setColorspaceUniforms(const ColorDescription &src, const ColorDescription &dst)
Definition glshader.cpp:447
glGetnUniformfv_func glGetnUniformfv
bool hasGLVersion(int major, int minor, int release)
Definition glutils.cpp:133
bool hasGLExtension(const QByteArray &extension)
Definition glutils.cpp:138