File indexing completed on 2024-11-10 04:56:54
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2006-2007 Rivo Laks <rivolaks@hot.ee> 0006 SPDX-FileCopyrightText: 2010, 2011 Martin Gräßlin <mgraesslin@kde.org> 0007 SPDX-FileCopyrightText: 2023 Xaver Hugl <xaver.hugl@kde.org> 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later 0010 */ 0011 #include "glshader.h" 0012 #include "glplatform.h" 0013 #include "glutils.h" 0014 #include "utils/common.h" 0015 0016 #include <QFile> 0017 0018 namespace KWin 0019 { 0020 0021 GLShader::GLShader(unsigned int flags) 0022 : m_valid(false) 0023 , m_locationsResolved(false) 0024 , m_explicitLinking(flags & ExplicitLinking) 0025 { 0026 m_program = glCreateProgram(); 0027 } 0028 0029 GLShader::GLShader(const QString &vertexfile, const QString &fragmentfile, unsigned int flags) 0030 : m_valid(false) 0031 , m_locationsResolved(false) 0032 , m_explicitLinking(flags & ExplicitLinking) 0033 { 0034 m_program = glCreateProgram(); 0035 loadFromFiles(vertexfile, fragmentfile); 0036 } 0037 0038 GLShader::~GLShader() 0039 { 0040 if (m_program) { 0041 glDeleteProgram(m_program); 0042 } 0043 } 0044 0045 bool GLShader::loadFromFiles(const QString &vertexFile, const QString &fragmentFile) 0046 { 0047 QFile vf(vertexFile); 0048 if (!vf.open(QIODevice::ReadOnly)) { 0049 qCCritical(KWIN_OPENGL) << "Couldn't open" << vertexFile << "for reading!"; 0050 return false; 0051 } 0052 const QByteArray vertexSource = vf.readAll(); 0053 0054 QFile ff(fragmentFile); 0055 if (!ff.open(QIODevice::ReadOnly)) { 0056 qCCritical(KWIN_OPENGL) << "Couldn't open" << fragmentFile << "for reading!"; 0057 return false; 0058 } 0059 const QByteArray fragmentSource = ff.readAll(); 0060 0061 return load(vertexSource, fragmentSource); 0062 } 0063 0064 bool GLShader::link() 0065 { 0066 // Be optimistic 0067 m_valid = true; 0068 0069 glLinkProgram(m_program); 0070 0071 // Get the program info log 0072 int maxLength, length; 0073 glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &maxLength); 0074 0075 QByteArray log(maxLength, 0); 0076 glGetProgramInfoLog(m_program, maxLength, &length, log.data()); 0077 0078 // Make sure the program linked successfully 0079 int status; 0080 glGetProgramiv(m_program, GL_LINK_STATUS, &status); 0081 0082 if (status == 0) { 0083 qCCritical(KWIN_OPENGL) << "Failed to link shader:" 0084 << "\n" 0085 << log; 0086 m_valid = false; 0087 } else if (length > 0) { 0088 qCDebug(KWIN_OPENGL) << "Shader link log:" << log; 0089 } 0090 0091 return m_valid; 0092 } 0093 0094 const QByteArray GLShader::prepareSource(GLenum shaderType, const QByteArray &source) const 0095 { 0096 // Prepare the source code 0097 QByteArray ba; 0098 if (GLPlatform::instance()->isGLES() && GLPlatform::instance()->glslVersion() < Version(3, 0)) { 0099 ba.append("precision highp float;\n"); 0100 } 0101 ba.append(source); 0102 if (GLPlatform::instance()->isGLES() && GLPlatform::instance()->glslVersion() >= Version(3, 0)) { 0103 ba.replace("#version 140", "#version 300 es\n\nprecision highp float;\n"); 0104 } 0105 0106 return ba; 0107 } 0108 0109 bool GLShader::compile(GLuint program, GLenum shaderType, const QByteArray &source) const 0110 { 0111 GLuint shader = glCreateShader(shaderType); 0112 0113 QByteArray preparedSource = prepareSource(shaderType, source); 0114 const char *src = preparedSource.constData(); 0115 glShaderSource(shader, 1, &src, nullptr); 0116 0117 // Compile the shader 0118 glCompileShader(shader); 0119 0120 // Get the shader info log 0121 int maxLength, length; 0122 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); 0123 0124 QByteArray log(maxLength, 0); 0125 glGetShaderInfoLog(shader, maxLength, &length, log.data()); 0126 0127 // Check the status 0128 int status; 0129 glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 0130 0131 if (status == 0) { 0132 const char *typeName = (shaderType == GL_VERTEX_SHADER ? "vertex" : "fragment"); 0133 qCCritical(KWIN_OPENGL) << "Failed to compile" << typeName << "shader:" 0134 << "\n" 0135 << log; 0136 size_t line = 0; 0137 const auto split = source.split('\n'); 0138 for (const auto &l : split) { 0139 qCCritical(KWIN_OPENGL).nospace() << "line " << line++ << ":" << l; 0140 } 0141 } else if (length > 0) { 0142 qCDebug(KWIN_OPENGL) << "Shader compile log:" << log; 0143 } 0144 0145 if (status != 0) { 0146 glAttachShader(program, shader); 0147 } 0148 0149 glDeleteShader(shader); 0150 return status != 0; 0151 } 0152 0153 bool GLShader::load(const QByteArray &vertexSource, const QByteArray &fragmentSource) 0154 { 0155 m_valid = false; 0156 0157 // Compile the vertex shader 0158 if (!vertexSource.isEmpty()) { 0159 bool success = compile(m_program, GL_VERTEX_SHADER, vertexSource); 0160 0161 if (!success) { 0162 return false; 0163 } 0164 } 0165 0166 // Compile the fragment shader 0167 if (!fragmentSource.isEmpty()) { 0168 bool success = compile(m_program, GL_FRAGMENT_SHADER, fragmentSource); 0169 0170 if (!success) { 0171 return false; 0172 } 0173 } 0174 0175 if (m_explicitLinking) { 0176 return true; 0177 } 0178 0179 // link() sets mValid 0180 return link(); 0181 } 0182 0183 void GLShader::bindAttributeLocation(const char *name, int index) 0184 { 0185 glBindAttribLocation(m_program, index, name); 0186 } 0187 0188 void GLShader::bindFragDataLocation(const char *name, int index) 0189 { 0190 if (!GLPlatform::instance()->isGLES() && (hasGLVersion(3, 0) || hasGLExtension(QByteArrayLiteral("GL_EXT_gpu_shader4")))) { 0191 glBindFragDataLocation(m_program, index, name); 0192 } 0193 } 0194 0195 void GLShader::bind() 0196 { 0197 glUseProgram(m_program); 0198 } 0199 0200 void GLShader::unbind() 0201 { 0202 glUseProgram(0); 0203 } 0204 0205 void GLShader::resolveLocations() 0206 { 0207 if (m_locationsResolved) { 0208 return; 0209 } 0210 0211 m_matrix4Locations[Mat4Uniform::TextureMatrix] = uniformLocation("textureMatrix"); 0212 m_matrix4Locations[Mat4Uniform::ProjectionMatrix] = uniformLocation("projection"); 0213 m_matrix4Locations[Mat4Uniform::ModelViewMatrix] = uniformLocation("modelview"); 0214 m_matrix4Locations[Mat4Uniform::ModelViewProjectionMatrix] = uniformLocation("modelViewProjectionMatrix"); 0215 m_matrix4Locations[Mat4Uniform::WindowTransformation] = uniformLocation("windowTransformation"); 0216 m_matrix4Locations[Mat4Uniform::ScreenTransformation] = uniformLocation("screenTransformation"); 0217 m_matrix4Locations[Mat4Uniform::ColorimetryTransformation] = uniformLocation("colorimetryTransform"); 0218 0219 m_vec2Locations[Vec2Uniform::Offset] = uniformLocation("offset"); 0220 0221 m_vec3Locations[Vec3Uniform::PrimaryBrightness] = uniformLocation("primaryBrightness"); 0222 0223 m_vec4Locations[Vec4Uniform::ModulationConstant] = uniformLocation("modulation"); 0224 0225 m_floatLocations[FloatUniform::Saturation] = uniformLocation("saturation"); 0226 m_floatLocations[FloatUniform::MaxHdrBrightness] = uniformLocation("maxHdrBrightness"); 0227 m_floatLocations[FloatUniform::SdrBrightness] = uniformLocation("sdrBrightness"); 0228 0229 m_colorLocations[ColorUniform::Color] = uniformLocation("geometryColor"); 0230 0231 m_intLocations[IntUniform::TextureWidth] = uniformLocation("textureWidth"); 0232 m_intLocations[IntUniform::TextureHeight] = uniformLocation("textureHeight"); 0233 m_intLocations[IntUniform::Sampler] = uniformLocation("sampler"); 0234 m_intLocations[IntUniform::Sampler1] = uniformLocation("sampler1"); 0235 m_intLocations[IntUniform::SourceNamedTransferFunction] = uniformLocation("sourceNamedTransferFunction"); 0236 m_intLocations[IntUniform::DestinationNamedTransferFunction] = uniformLocation("destinationNamedTransferFunction"); 0237 0238 m_locationsResolved = true; 0239 } 0240 0241 int GLShader::uniformLocation(const char *name) 0242 { 0243 const int location = glGetUniformLocation(m_program, name); 0244 return location; 0245 } 0246 0247 bool GLShader::setUniform(Mat3Uniform uniform, const QMatrix3x3 &value) 0248 { 0249 resolveLocations(); 0250 return setUniform(m_matrix3Locations[uniform], value); 0251 } 0252 0253 bool GLShader::setUniform(Mat4Uniform uniform, const QMatrix4x4 &matrix) 0254 { 0255 resolveLocations(); 0256 return setUniform(m_matrix4Locations[uniform], matrix); 0257 } 0258 0259 bool GLShader::setUniform(Vec2Uniform uniform, const QVector2D &value) 0260 { 0261 resolveLocations(); 0262 return setUniform(m_vec2Locations[uniform], value); 0263 } 0264 0265 bool GLShader::setUniform(Vec3Uniform uniform, const QVector3D &value) 0266 { 0267 resolveLocations(); 0268 return setUniform(m_vec3Locations[uniform], value); 0269 } 0270 0271 bool GLShader::setUniform(Vec4Uniform uniform, const QVector4D &value) 0272 { 0273 resolveLocations(); 0274 return setUniform(m_vec4Locations[uniform], value); 0275 } 0276 0277 bool GLShader::setUniform(FloatUniform uniform, float value) 0278 { 0279 resolveLocations(); 0280 return setUniform(m_floatLocations[uniform], value); 0281 } 0282 0283 bool GLShader::setUniform(IntUniform uniform, int value) 0284 { 0285 resolveLocations(); 0286 return setUniform(m_intLocations[uniform], value); 0287 } 0288 0289 bool GLShader::setUniform(ColorUniform uniform, const QVector4D &value) 0290 { 0291 resolveLocations(); 0292 return setUniform(m_colorLocations[uniform], value); 0293 } 0294 0295 bool GLShader::setUniform(ColorUniform uniform, const QColor &value) 0296 { 0297 resolveLocations(); 0298 return setUniform(m_colorLocations[uniform], value); 0299 } 0300 0301 bool GLShader::setUniform(const char *name, float value) 0302 { 0303 const int location = uniformLocation(name); 0304 return setUniform(location, value); 0305 } 0306 0307 bool GLShader::setUniform(const char *name, int value) 0308 { 0309 const int location = uniformLocation(name); 0310 return setUniform(location, value); 0311 } 0312 0313 bool GLShader::setUniform(const char *name, const QVector2D &value) 0314 { 0315 const int location = uniformLocation(name); 0316 return setUniform(location, value); 0317 } 0318 0319 bool GLShader::setUniform(const char *name, const QVector3D &value) 0320 { 0321 const int location = uniformLocation(name); 0322 return setUniform(location, value); 0323 } 0324 0325 bool GLShader::setUniform(const char *name, const QVector4D &value) 0326 { 0327 const int location = uniformLocation(name); 0328 return setUniform(location, value); 0329 } 0330 0331 bool GLShader::setUniform(const char *name, const QMatrix4x4 &value) 0332 { 0333 const int location = uniformLocation(name); 0334 return setUniform(location, value); 0335 } 0336 0337 bool GLShader::setUniform(const char *name, const QColor &color) 0338 { 0339 const int location = uniformLocation(name); 0340 return setUniform(location, color); 0341 } 0342 0343 bool GLShader::setUniform(int location, float value) 0344 { 0345 if (location >= 0) { 0346 glUniform1f(location, value); 0347 } 0348 return (location >= 0); 0349 } 0350 0351 bool GLShader::setUniform(int location, int value) 0352 { 0353 if (location >= 0) { 0354 glUniform1i(location, value); 0355 } 0356 return (location >= 0); 0357 } 0358 0359 bool GLShader::setUniform(int location, int xValue, int yValue, int zValue) 0360 { 0361 if (location >= 0) { 0362 glUniform3i(location, xValue, yValue, zValue); 0363 } 0364 return location >= 0; 0365 } 0366 0367 bool GLShader::setUniform(int location, const QVector2D &value) 0368 { 0369 if (location >= 0) { 0370 glUniform2fv(location, 1, (const GLfloat *)&value); 0371 } 0372 return (location >= 0); 0373 } 0374 0375 bool GLShader::setUniform(int location, const QVector3D &value) 0376 { 0377 if (location >= 0) { 0378 glUniform3fv(location, 1, (const GLfloat *)&value); 0379 } 0380 return (location >= 0); 0381 } 0382 0383 bool GLShader::setUniform(int location, const QVector4D &value) 0384 { 0385 if (location >= 0) { 0386 glUniform4fv(location, 1, (const GLfloat *)&value); 0387 } 0388 return (location >= 0); 0389 } 0390 0391 bool GLShader::setUniform(int location, const QMatrix3x3 &value) 0392 { 0393 if (location >= 0) { 0394 glUniformMatrix3fv(location, 1, GL_FALSE, value.constData()); 0395 } 0396 return location >= 0; 0397 } 0398 0399 bool GLShader::setUniform(int location, const QMatrix4x4 &value) 0400 { 0401 if (location >= 0) { 0402 glUniformMatrix4fv(location, 1, GL_FALSE, value.constData()); 0403 } 0404 return (location >= 0); 0405 } 0406 0407 bool GLShader::setUniform(int location, const QColor &color) 0408 { 0409 if (location >= 0) { 0410 glUniform4f(location, color.redF(), color.greenF(), color.blueF(), color.alphaF()); 0411 } 0412 return (location >= 0); 0413 } 0414 0415 int GLShader::attributeLocation(const char *name) 0416 { 0417 int location = glGetAttribLocation(m_program, name); 0418 return location; 0419 } 0420 0421 bool GLShader::setAttribute(const char *name, float value) 0422 { 0423 int location = attributeLocation(name); 0424 if (location >= 0) { 0425 glVertexAttrib1f(location, value); 0426 } 0427 return (location >= 0); 0428 } 0429 0430 QMatrix4x4 GLShader::getUniformMatrix4x4(const char *name) 0431 { 0432 int location = uniformLocation(name); 0433 if (location >= 0) { 0434 GLfloat m[16]; 0435 glGetnUniformfv(m_program, location, sizeof(m), m); 0436 QMatrix4x4 matrix(m[0], m[4], m[8], m[12], 0437 m[1], m[5], m[9], m[13], 0438 m[2], m[6], m[10], m[14], 0439 m[3], m[7], m[11], m[15]); 0440 matrix.optimize(); 0441 return matrix; 0442 } else { 0443 return QMatrix4x4(); 0444 } 0445 } 0446 0447 bool GLShader::setColorspaceUniforms(const ColorDescription &src, const ColorDescription &dst) 0448 { 0449 const auto &srcColorimetry = src.colorimetry() == NamedColorimetry::BT709 ? dst.sdrColorimetry() : src.colorimetry(); 0450 return setUniform(GLShader::Mat4Uniform::ColorimetryTransformation, srcColorimetry.toOther(dst.colorimetry())) 0451 && setUniform(GLShader::IntUniform::SourceNamedTransferFunction, int(src.transferFunction())) 0452 && setUniform(GLShader::IntUniform::DestinationNamedTransferFunction, int(dst.transferFunction())) 0453 && setUniform(FloatUniform::SdrBrightness, dst.sdrBrightness()) 0454 && setUniform(FloatUniform::MaxHdrBrightness, dst.maxHdrHighlightBrightness()); 0455 } 0456 0457 bool GLShader::setColorspaceUniformsFromSRGB(const ColorDescription &dst) 0458 { 0459 return setColorspaceUniforms(ColorDescription::sRGB, dst); 0460 } 0461 0462 bool GLShader::setColorspaceUniformsToSRGB(const ColorDescription &src) 0463 { 0464 return setUniform(GLShader::Mat4Uniform::ColorimetryTransformation, src.colorimetry().toOther(src.sdrColorimetry())) 0465 && setUniform(GLShader::IntUniform::SourceNamedTransferFunction, int(src.transferFunction())) 0466 && setUniform(GLShader::IntUniform::DestinationNamedTransferFunction, int(NamedTransferFunction::gamma22)) 0467 && setUniform(FloatUniform::SdrBrightness, src.sdrBrightness()) 0468 && setUniform(FloatUniform::MaxHdrBrightness, src.sdrBrightness()); 0469 } 0470 }