File indexing completed on 2024-11-10 04:56:57

0001 /*
0002     SPDX-FileCopyrightText: 2010 Fredrik Höglund <fredrik@kde.org>
0003     SPDX-FileCopyrightText: 2014 Marco Martin <mart@kde.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "contrastshader.h"
0009 
0010 #include "effect/effecthandler.h"
0011 #include "opengl/glplatform.h"
0012 
0013 #include <QByteArray>
0014 #include <QMatrix4x4>
0015 #include <QTextStream>
0016 #include <QVector2D>
0017 
0018 #include <cmath>
0019 
0020 namespace KWin
0021 {
0022 
0023 ContrastShader::ContrastShader()
0024     : m_valid(false)
0025     , m_shader(nullptr)
0026     , m_opacity(1)
0027 {
0028 }
0029 
0030 void ContrastShader::reset()
0031 {
0032     m_shader.reset();
0033 
0034     setIsValid(false);
0035 }
0036 
0037 void ContrastShader::setOpacity(float opacity)
0038 {
0039     m_opacity = opacity;
0040 
0041     ShaderManager::instance()->pushShader(m_shader.get());
0042     m_shader->setUniform(m_opacityLocation, opacity);
0043     ShaderManager::instance()->popShader();
0044 }
0045 
0046 float ContrastShader::opacity() const
0047 {
0048     return m_opacity;
0049 }
0050 
0051 void ContrastShader::setColorMatrix(const QMatrix4x4 &matrix)
0052 {
0053     if (!isValid()) {
0054         return;
0055     }
0056 
0057     ShaderManager::instance()->pushShader(m_shader.get());
0058     m_shader->setUniform(m_colorMatrixLocation, matrix);
0059     ShaderManager::instance()->popShader();
0060 }
0061 
0062 void ContrastShader::setTextureMatrix(const QMatrix4x4 &matrix)
0063 {
0064     if (!isValid()) {
0065         return;
0066     }
0067 
0068     m_shader->setUniform(m_textureMatrixLocation, matrix);
0069 }
0070 
0071 void ContrastShader::setModelViewProjectionMatrix(const QMatrix4x4 &matrix)
0072 {
0073     if (!isValid()) {
0074         return;
0075     }
0076 
0077     m_shader->setUniform(m_mvpMatrixLocation, matrix);
0078 }
0079 
0080 void ContrastShader::bind()
0081 {
0082     if (!isValid()) {
0083         return;
0084     }
0085 
0086     ShaderManager::instance()->pushShader(m_shader.get());
0087 }
0088 
0089 void ContrastShader::unbind()
0090 {
0091     ShaderManager::instance()->popShader();
0092 }
0093 
0094 void ContrastShader::init()
0095 {
0096     reset();
0097 
0098     const bool gles = GLPlatform::instance()->isGLES();
0099     const bool glsl_140 = !gles && GLPlatform::instance()->glslVersion() >= Version(1, 40);
0100     const bool core = glsl_140 || (gles && GLPlatform::instance()->glslVersion() >= Version(3, 0));
0101 
0102     QByteArray vertexSource;
0103     QByteArray fragmentSource;
0104 
0105     const QByteArray attribute = core ? "in" : "attribute";
0106     const QByteArray varying_in = core ? (gles ? "in" : "noperspective in") : "varying";
0107     const QByteArray varying_out = core ? (gles ? "out" : "noperspective out") : "varying";
0108     const QByteArray texture2D = core ? "texture" : "texture2D";
0109     const QByteArray fragColor = core ? "fragColor" : "gl_FragColor";
0110 
0111     // Vertex shader
0112     // ===================================================================
0113     QTextStream stream(&vertexSource);
0114 
0115     if (gles) {
0116         if (core) {
0117             stream << "#version 300 es\n\n";
0118         }
0119         stream << "precision highp float;\n";
0120     } else if (glsl_140) {
0121         stream << "#version 140\n\n";
0122     }
0123 
0124     stream << "uniform mat4 modelViewProjectionMatrix;\n";
0125     stream << "uniform mat4 textureMatrix;\n";
0126     stream << attribute << " vec4 vertex;\n\n";
0127     stream << varying_out << " vec4 varyingTexCoords;\n";
0128     stream << "\n";
0129     stream << "void main(void)\n";
0130     stream << "{\n";
0131     stream << "    varyingTexCoords = vec4(textureMatrix * vertex).stst;\n";
0132     stream << "    gl_Position = modelViewProjectionMatrix * vertex;\n";
0133     stream << "}\n";
0134     stream.flush();
0135 
0136     // Fragment shader
0137     // ===================================================================
0138     QTextStream stream2(&fragmentSource);
0139 
0140     if (gles) {
0141         if (core) {
0142             stream2 << "#version 300 es\n\n";
0143         }
0144         stream2 << "precision highp float;\n";
0145     } else if (glsl_140) {
0146         stream2 << "#version 140\n\n";
0147     }
0148 
0149     stream2 << "uniform mat4 colorMatrix;\n";
0150     stream2 << "uniform sampler2D sampler;\n";
0151     stream2 << "uniform float opacity;\n";
0152     stream2 << varying_in << " vec4 varyingTexCoords;\n";
0153 
0154     if (core) {
0155         stream2 << "out vec4 fragColor;\n\n";
0156     }
0157 
0158     stream2 << "void main(void)\n";
0159     stream2 << "{\n";
0160     stream2 << "    vec4 tex = " << texture2D << "(sampler, varyingTexCoords.st);\n";
0161 
0162     stream2 << "    if (opacity >= 1.0) {\n";
0163     stream2 << "        " << fragColor << " = tex * colorMatrix;\n";
0164     stream2 << "    } else {\n";
0165     stream2 << "        " << fragColor << " = tex * (opacity * colorMatrix + (1.0 - opacity) * mat4(1.0));\n";
0166     stream2 << "    }\n";
0167 
0168     stream2 << "}\n";
0169     stream2.flush();
0170 
0171     m_shader = ShaderManager::instance()->loadShaderFromCode(vertexSource, fragmentSource);
0172 
0173     if (m_shader->isValid()) {
0174         m_colorMatrixLocation = m_shader->uniformLocation("colorMatrix");
0175         m_textureMatrixLocation = m_shader->uniformLocation("textureMatrix");
0176         m_mvpMatrixLocation = m_shader->uniformLocation("modelViewProjectionMatrix");
0177         m_opacityLocation = m_shader->uniformLocation("opacity");
0178 
0179         QMatrix4x4 modelViewProjection;
0180         const QSize screenSize = effects->virtualScreenSize();
0181         modelViewProjection.ortho(0, screenSize.width(), screenSize.height(), 0, 0, 65535);
0182         ShaderManager::instance()->pushShader(m_shader.get());
0183         m_shader->setUniform(m_colorMatrixLocation, QMatrix4x4());
0184         m_shader->setUniform(m_textureMatrixLocation, QMatrix4x4());
0185         m_shader->setUniform(m_mvpMatrixLocation, modelViewProjection);
0186         m_shader->setUniform(m_opacityLocation, (float)1.0);
0187         ShaderManager::instance()->popShader();
0188     }
0189 
0190     setIsValid(m_shader->isValid());
0191 }
0192 
0193 void ContrastShader::setIsValid(bool value)
0194 {
0195     m_valid = value;
0196 }
0197 
0198 bool ContrastShader::isValid() const
0199 {
0200     return m_valid;
0201 }
0202 
0203 } // namespace KWin