File indexing completed on 2024-05-19 05:31:55
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 #pragma once 0012 #include "kwin_export.h" 0013 0014 #include <QByteArray> 0015 #include <QFlags> 0016 #include <QStack> 0017 #include <map> 0018 #include <memory> 0019 0020 namespace KWin 0021 { 0022 0023 class GLShader; 0024 0025 enum class ShaderTrait { 0026 MapTexture = (1 << 0), 0027 UniformColor = (1 << 1), 0028 Modulate = (1 << 2), 0029 AdjustSaturation = (1 << 3), 0030 TransformColorspace = (1 << 4), 0031 MapExternalTexture = (1 << 5), 0032 }; 0033 0034 Q_DECLARE_FLAGS(ShaderTraits, ShaderTrait) 0035 0036 /** 0037 * @short Manager for Shaders. 0038 * 0039 * This class provides some built-in shaders to be used by both compositing scene and effects. 0040 * The ShaderManager provides methods to bind a built-in or a custom shader and keeps track of 0041 * the shaders which have been bound. When a shader is unbound the previously bound shader 0042 * will be rebound. 0043 * 0044 * @author Martin Gräßlin <mgraesslin@kde.org> 0045 * @since 4.7 0046 */ 0047 class KWIN_EXPORT ShaderManager 0048 { 0049 public: 0050 explicit ShaderManager(); 0051 ~ShaderManager(); 0052 0053 /** 0054 * Returns a shader with the given traits, creating it if necessary. 0055 */ 0056 GLShader *shader(ShaderTraits traits); 0057 0058 /** 0059 * @return The currently bound shader or @c null if no shader is bound. 0060 */ 0061 GLShader *getBoundShader() const; 0062 0063 /** 0064 * @return @c true if a shader is bound, @c false otherwise 0065 */ 0066 bool isShaderBound() const; 0067 0068 /** 0069 * Pushes the current shader onto the stack and binds a shader 0070 * with the given traits. 0071 */ 0072 GLShader *pushShader(ShaderTraits traits); 0073 0074 /** 0075 * Binds the @p shader. 0076 * To unbind the shader use popShader. A previous bound shader will be rebound. 0077 * To bind a built-in shader use the more specific method. 0078 * @param shader The shader to be bound 0079 * @see popShader 0080 */ 0081 void pushShader(GLShader *shader); 0082 0083 /** 0084 * Unbinds the currently bound shader and rebinds a previous stored shader. 0085 * If there is no previous shader, no shader will be rebound. 0086 * It is not safe to call this method if there is no bound shader. 0087 * @see pushShader 0088 * @see getBoundShader 0089 */ 0090 void popShader(); 0091 0092 /** 0093 * Creates a GLShader with the specified sources. 0094 * The difference to GLShader is that it does not need to be loaded from files. 0095 * @param vertexSource The source code of the vertex shader 0096 * @param fragmentSource The source code of the fragment shader. 0097 * @return The created shader 0098 */ 0099 std::unique_ptr<GLShader> loadShaderFromCode(const QByteArray &vertexSource, const QByteArray &fragmentSource); 0100 0101 /** 0102 * Creates a custom shader with the given @p traits and custom @p vertexSource and or @p fragmentSource. 0103 * If the @p vertexSource is empty a vertex shader with the given @p traits is generated. 0104 * If it is not empty the @p vertexSource is used as the source for the vertex shader. 0105 * 0106 * The same applies for argument @p fragmentSource just for the fragment shader. 0107 * 0108 * So if both @p vertesSource and @p fragmentSource are provided the @p traits are ignored. 0109 * If neither are provided a new shader following the @p traits is generated. 0110 * 0111 * @param traits The shader traits for generating the shader 0112 * @param vertexSource optional vertex shader source code to be used instead of shader traits 0113 * @param fragmentSource optional fragment shader source code to be used instead of shader traits 0114 * @return new generated shader 0115 * @since 5.6 0116 */ 0117 std::unique_ptr<GLShader> generateCustomShader(ShaderTraits traits, const QByteArray &vertexSource = QByteArray(), const QByteArray &fragmentSource = QByteArray()); 0118 0119 /** 0120 * Creates a custom shader with the given @p traits and custom @p vertexFile and or @p fragmentFile. 0121 * 0122 * If the @p vertexFile is empty a vertex shader with the given @p traits is generated. 0123 * If it is not empty the @p vertexFile is used as the source for the vertex shader. 0124 * 0125 * The same applies for argument @p fragmentFile just for the fragment shader. 0126 * 0127 * So if both @p vertexFile and @p fragmentFile are provided the @p traits are ignored. 0128 * If neither are provided a new shader following the @p traits is generated. 0129 * 0130 * If a custom shader stage is provided and core profile is used, the final file path will 0131 * be resolved by appending "_core" to the basename. 0132 * 0133 * @param traits The shader traits for generating the shader 0134 * @param vertexFile optional vertex shader source code to be used instead of shader traits 0135 * @param fragmentFile optional fragment shader source code to be used instead of shader traits 0136 * @return new generated shader 0137 * @see generateCustomShader 0138 */ 0139 std::unique_ptr<GLShader> generateShaderFromFile(ShaderTraits traits, const QString &vertexFile = QString(), const QString &fragmentFile = QString()); 0140 0141 /** 0142 * @return a pointer to the ShaderManager instance 0143 */ 0144 static ShaderManager *instance(); 0145 0146 /** 0147 * @internal 0148 */ 0149 static void cleanup(); 0150 0151 private: 0152 void bindFragDataLocations(GLShader *shader); 0153 void bindAttributeLocations(GLShader *shader) const; 0154 0155 std::optional<QByteArray> preprocess(const QByteArray &src, int recursionDepth = 0) const; 0156 QByteArray generateVertexSource(ShaderTraits traits) const; 0157 QByteArray generateFragmentSource(ShaderTraits traits) const; 0158 std::unique_ptr<GLShader> generateShader(ShaderTraits traits); 0159 0160 QStack<GLShader *> m_boundShaders; 0161 std::map<ShaderTraits, std::unique_ptr<GLShader>> m_shaderHash; 0162 static std::unique_ptr<ShaderManager> s_shaderManager; 0163 }; 0164 0165 /** 0166 * An helper class to push a Shader on to ShaderManager's stack and ensuring that the Shader 0167 * gets popped again from the stack automatically once the object goes out of life. 0168 * 0169 * How to use: 0170 * @code 0171 * { 0172 * GLShader *myCustomShaderIWantToPush; 0173 * ShaderBinder binder(myCustomShaderIWantToPush); 0174 * // do stuff with the shader being pushed on the stack 0175 * } 0176 * // here the Shader is automatically popped as helper does no longer exist. 0177 * @endcode 0178 * 0179 * @since 4.10 0180 */ 0181 class KWIN_EXPORT ShaderBinder 0182 { 0183 public: 0184 /** 0185 * @brief Pushes the given @p shader to the ShaderManager's stack. 0186 * 0187 * @param shader The Shader to push on the stack 0188 * @see ShaderManager::pushShader 0189 */ 0190 explicit ShaderBinder(GLShader *shader); 0191 /** 0192 * @brief Pushes the Shader with the given @p traits to the ShaderManager's stack. 0193 * 0194 * @param traits The traits describing the shader 0195 * @see ShaderManager::pushShader 0196 * @since 5.6 0197 */ 0198 explicit ShaderBinder(ShaderTraits traits); 0199 ~ShaderBinder(); 0200 0201 /** 0202 * @return The Shader pushed to the Stack. 0203 */ 0204 GLShader *shader(); 0205 0206 private: 0207 GLShader *m_shader; 0208 }; 0209 0210 inline ShaderBinder::ShaderBinder(GLShader *shader) 0211 : m_shader(shader) 0212 { 0213 ShaderManager::instance()->pushShader(shader); 0214 } 0215 0216 inline ShaderBinder::ShaderBinder(ShaderTraits traits) 0217 : m_shader(nullptr) 0218 { 0219 m_shader = ShaderManager::instance()->pushShader(traits); 0220 } 0221 0222 inline ShaderBinder::~ShaderBinder() 0223 { 0224 ShaderManager::instance()->popShader(); 0225 } 0226 0227 inline GLShader *ShaderBinder::shader() 0228 { 0229 return m_shader; 0230 } 0231 0232 } 0233 0234 Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::ShaderTraits)