diff --git a/lib/kwinglutils.cpp b/lib/kwinglutils.cpp
index 8db291397d..50593af815 100644
--- a/lib/kwinglutils.cpp
+++ b/lib/kwinglutils.cpp
@@ -36,6 +36,7 @@ along with this program. If not, see .
#include
#include
+#include
#define DEBUG_GLRENDERTARGET 0
@@ -1081,6 +1082,221 @@ void GLShader::bindAttributeLocation(int index, const char* name)
// TODO: relink the shader
}
+//****************************************
+// ShaderManager
+//****************************************
+ShaderManager *ShaderManager::s_shaderManager = NULL;
+
+ShaderManager *ShaderManager::instance()
+{
+ if (!s_shaderManager) {
+ s_shaderManager = new ShaderManager();
+ }
+ return s_shaderManager;
+}
+
+void ShaderManager::cleanup()
+{
+ delete s_shaderManager;
+}
+
+ShaderManager::ShaderManager()
+ : m_orthoShader(NULL)
+ , m_genericShader(NULL)
+ , m_colorShader(NULL)
+ , m_inited(false)
+ , m_valid(false)
+{
+ initShaders();
+ m_inited = true;
+}
+
+ShaderManager::~ShaderManager()
+{
+ while (!m_boundShaders.isEmpty()) {
+ popShader();
+ }
+ delete m_orthoShader;
+ delete m_genericShader;
+ delete m_colorShader;
+}
+
+GLShader *ShaderManager::getBoundShader() const
+{
+ if (m_boundShaders.isEmpty()) {
+ return NULL;
+ } else {
+ return m_boundShaders.top();
+ }
+}
+
+bool ShaderManager::isShaderBound() const
+{
+ return !m_boundShaders.isEmpty();
+}
+
+bool ShaderManager::isValid() const
+{
+ return m_valid;
+}
+
+GLShader *ShaderManager::pushShader(ShaderType type, bool reset)
+{
+ if (m_inited && !m_valid) {
+ return NULL;
+ }
+ GLShader *shader;
+ switch (type) {
+ case SimpleShader:
+ shader = m_orthoShader;
+ break;
+ case GenericShader:
+ shader = m_genericShader;
+ break;
+ case ColorShader:
+ shader = m_colorShader;
+ break;
+ default:
+ return NULL;
+ }
+
+ pushShader(shader);
+ if (reset) {
+ resetShader(type);
+ }
+
+ return shader;
+}
+
+void ShaderManager::pushShader(GLShader *shader)
+{
+ // only bind shader if it is not already bound
+ if (shader != getBoundShader()) {
+ shader->bind();
+ }
+ m_boundShaders.push(shader);
+}
+
+void ShaderManager::popShader()
+{
+ if (m_boundShaders.isEmpty()) {
+ return;
+ }
+ GLShader *shader = m_boundShaders.pop();
+ if (m_boundShaders.isEmpty()) {
+ // no more shader bound - unbind
+ shader->unbind();
+ } else if (shader != m_boundShaders.top()) {
+ // only rebind if a different shader is on top of stack
+ m_boundShaders.top()->bind();
+ }
+}
+
+void ShaderManager::initShaders()
+{
+ m_orthoShader = new GLShader(":/resources/scene-vertex.glsl", ":/resources/scene-fragment.glsl");
+ if (m_orthoShader->isValid()) {
+ pushShader(SimpleShader, true);
+ popShader();
+ kDebug(1212) << "Ortho Shader is valid";
+ }
+ else {
+ delete m_orthoShader;
+ m_orthoShader = NULL;
+ kDebug(1212) << "Orho Shader is not valid";
+ return;
+ }
+ m_genericShader = new GLShader( ":/resources/scene-generic-vertex.glsl", ":/resources/scene-fragment.glsl" );
+ if (m_genericShader->isValid()) {
+ pushShader(GenericShader, true);
+ popShader();
+ kDebug(1212) << "Generic Shader is valid";
+ }
+ else {
+ delete m_genericShader;
+ m_genericShader = NULL;
+ delete m_orthoShader;
+ m_orthoShader = NULL;
+ kDebug(1212) << "Generic Shader is not valid";
+ return;
+ }
+ m_colorShader = new GLShader(":/resources/scene-color-vertex.glsl", ":/resources/scene-color-fragment.glsl");
+ if (m_colorShader->isValid()) {
+ pushShader(ColorShader, true);
+ popShader();
+ kDebug(1212) << "Color Shader is valid";
+ } else {
+ delete m_genericShader;
+ m_genericShader = NULL;
+ delete m_orthoShader;
+ m_orthoShader = NULL;
+ delete m_colorShader;
+ m_colorShader = NULL;
+ kDebug(1212) << "Color Scene Shader is not valid";
+ return;
+ }
+ m_valid = true;
+}
+
+void ShaderManager::resetShader(ShaderType type)
+{
+ // resetShader is either called from init or from push, we know that a built-in shader is bound
+ GLShader *shader = getBoundShader();
+ switch (type) {
+ case SimpleShader:
+ shader->setUniform("displaySize", QVector2D(displayWidth(), displayHeight()));
+ // TODO: has to become offset
+ shader->setUniform("geometry", QVector4D(0, 0, 0, 0));
+ shader->setUniform("debug", 0);
+ shader->setUniform("sample", 0);
+ // TODO: has to become textureSize
+ shader->setUniform("textureWidth", 1.0f);
+ shader->setUniform("textureHeight", 1.0f);
+ // TODO: has to become colorManiuplation
+ shader->setUniform("opacity", 1.0f);
+ shader->setUniform("brightness", 1.0f);
+ shader->setUniform("saturation", 1.0f);
+ break;
+ case GenericShader: {
+ shader->setUniform("debug", 0);
+ shader->setUniform("sample", 0);
+ QMatrix4x4 projection;
+ float fovy = 60.0f;
+ float aspect = 1.0f;
+ float zNear = 0.1f;
+ float zFar = 100.0f;
+ float ymax = zNear * tan(fovy * M_PI / 360.0f);
+ float ymin = -ymax;
+ float xmin = ymin * aspect;
+ float xmax = ymax * aspect;
+ projection.frustum(xmin, xmax, ymin, ymax, zNear, zFar);
+ shader->setUniform("projection", projection);
+ QMatrix4x4 modelview;
+ float scaleFactor = 1.1 * tan( fovy * M_PI / 360.0f )/ymax;
+ modelview.translate(xmin*scaleFactor, ymax*scaleFactor, -1.1);
+ modelview.scale((xmax-xmin)*scaleFactor/displayWidth(), -(ymax-ymin)*scaleFactor/displayHeight(), 0.001);
+ shader->setUniform("modelview", modelview);
+ const QMatrix4x4 identity;
+ shader->setUniform("screenTransformation", identity);
+ shader->setUniform("windowTransformation", identity);
+ // TODO: has to become textureSize
+ shader->setUniform("textureWidth", 1.0f);
+ shader->setUniform("textureHeight", 1.0f);
+ // TODO: has to become colorManiuplation
+ shader->setUniform("opacity", 1.0f);
+ shader->setUniform("brightness", 1.0f);
+ shader->setUniform("saturation", 1.0f);
+ break;
+ }
+ case ColorShader:
+ shader->setUniform("displaySize", QVector2D(displayWidth(), displayHeight()));
+ // TODO: has to become offset
+ shader->setUniform("geometry", QVector4D(0, 0, 0, 0));
+ shader->setUniform("geometryColor", QVector4D(0, 0, 0, 1));
+ break;
+ }
+}
+
/*** GLRenderTarget ***/
bool GLRenderTarget::mSupported = false;
diff --git a/lib/kwinglutils.h b/lib/kwinglutils.h
index 761a0cc5fb..cc928848d0 100644
--- a/lib/kwinglutils.h
+++ b/lib/kwinglutils.h
@@ -31,6 +31,7 @@ along with this program. If not, see .
#include
#include
#include
+#include
/** @addtogroup kwineffects */
/** @{ */
@@ -293,6 +294,121 @@ class KWIN_EXPORT GLShader
float mTextureHeight;
};
+/**
+ * @short Manager for Shaders.
+ *
+ * This class provides some built-in shaders to be used by both compositing scene and effects.
+ * The ShaderManager provides methods to bind a built-in or a custom shader and keeps track of
+ * the shaders which have been bound. When a shader is unbound the previously bound shader
+ * will be rebound.
+ *
+ * @author Martin Gräßlin
+ * @since 4.7
+ **/
+class KWIN_EXPORT ShaderManager
+{
+ public:
+ /**
+ * Identifiers for built-in shaders available for effects and scene
+ **/
+ enum ShaderType {
+ /**
+ * An orthographic projection shader able to render textured geometries.
+ * Expects a @c vec2 uniform @c offset describing the offset from top-left corner
+ * and defaults to @c (0/0). Expects a @c vec2 uniform @c textureSize to calculate
+ * normalized texture coordinates. Defaults to @c (1.0/1.0). And expects a @c vec3
+ * uniform @c colorManiuplation, with @c x being opacity, @c y being brightness and
+ * @c z being saturation. All three values default to @c 1.0.
+ * The sampler uniform is @c sample and defaults to @c 0.
+ * The shader uses two vertex attributes @c vertex and @c texCoord.
+ **/
+ SimpleShader,
+ /**
+ * A generic shader able to render transformed, textured geometries.
+ * This shader is mostly needed by the scene and not of much interest for effects.
+ * Effects can influence this shader through @link ScreenPaintData and @link WindowPaintData.
+ * The shader expects four @c mat4 uniforms @c projection, @c modelview,
+ * @c screenTransformation and @c windowTransformation. The fragment shader expect the
+ * same uniforms as the SimpleShader and the same vertex attributes are used.
+ **/
+ GenericShader,
+ /**
+ * An orthographic shader to render simple colored geometries without texturing.
+ * Expects a @c vec2 uniform @c offset describing the offset from top-left corner
+ * and defaults to @c (0/0). The fragment shader expects a single @c vec4 uniform
+ * @c geometryColor, which defaults to fully opaque black.
+ * The Shader uses one vertex attribute @c vertex.
+ **/
+ ColorShader
+ };
+
+ /**
+ * @return The currently bound shader or @c null if no shader is bound.
+ **/
+ GLShader *getBoundShader() const;
+
+ /**
+ * @return @c true if a shader is bound, @c false otherwise
+ **/
+ bool isShaderBound() const;
+ /**
+ * @return @c true if the built-in shaders are valid, @c false otherwise
+ **/
+ bool isValid() const;
+
+ /**
+ * Binds the shader of specified @p type.
+ * To unbind the shader use @link popShader. A previous bound shader will be rebound.
+ * @param type The built-in shader to bind
+ * @param reset Whether all uniforms should be reset to their default values
+ * @return The bound shader or @c NULL if shaders are not valid
+ * @see popShader
+ **/
+ GLShader *pushShader(ShaderType type, bool reset = false);
+ /**
+ * Binds the @p shader.
+ * To unbind the shader use @link popShader. A previous bound shader will be rebound.
+ * To bind a built-in shader use the more specific method.
+ * @param shader The shader to be bound
+ * @see popShader
+ **/
+ void pushShader(GLShader *shader);
+
+ /**
+ * Unbinds the currently bound shader and rebinds a previous stored shader.
+ * If there is no previous shader, no shader will be rebound.
+ * It is not safe to call this method if there is no bound shader.
+ * @see pushShader
+ * @see getBoundShader
+ **/
+ void popShader();
+
+ /**
+ * @return a pointer to the ShaderManager instance
+ **/
+ static ShaderManager *instance();
+
+ /**
+ * @internal
+ **/
+ static void cleanup();
+
+ private:
+ ShaderManager();
+ ~ShaderManager();
+
+ void initShaders();
+ void resetShader(ShaderType type);
+
+ QStack m_boundShaders;
+ GLShader *m_orthoShader;
+ GLShader *m_genericShader;
+ GLShader *m_colorShader;
+ bool m_inited;
+ bool m_valid;
+ static ShaderManager *s_shaderManager;
+};
+
/**
* @short Render target object
*