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)