From 8c4fc28e1ab81c3d9b9ca8919b8cdd1ea7d8a945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Sat, 8 Jan 2011 19:56:22 +0100 Subject: [PATCH] Blur ported to GLES. It now uses a GLShader for GLSL shaders and pushes it using the ShaderManager. It does not work with the nouveau driver plus GLES, but it works with fglrx + desktop GL 2.x, so I assume it is a driver problem here. --- effects/CMakeLists.txt | 2 +- effects/blur/blur.cpp | 66 ++++++++-------- effects/blur/blurshader.cpp | 148 ++++++++++++++++------------------- effects/blur/blurshader.h | 12 +-- effects/configs_builtins.cpp | 4 +- 5 files changed, 110 insertions(+), 122 deletions(-) diff --git a/effects/CMakeLists.txt b/effects/CMakeLists.txt index 7985c4adae..4e27facdca 100644 --- a/effects/CMakeLists.txt +++ b/effects/CMakeLists.txt @@ -89,6 +89,7 @@ endif( NOT KWIN_HAVE_OPENGLES_COMPOSITING ) # OpenGL-specific effects if( KWIN_HAVE_OPENGL_COMPOSITING ) + include( blur/CMakeLists.txt ) include( coverswitch/CMakeLists.txt ) include( cube/CMakeLists.txt ) include( explosion/CMakeLists.txt ) @@ -106,7 +107,6 @@ if( KWIN_HAVE_OPENGL_COMPOSITING ) include( wobblywindows/CMakeLists.txt ) endif( KWIN_HAVE_OPENGL_COMPOSITING ) if( KWIN_HAVE_OPENGL_COMPOSITING AND NOT KWIN_HAVE_OPENGLES_COMPOSITING ) - include( blur/CMakeLists.txt ) include( sharpen/CMakeLists.txt ) include( snow/CMakeLists.txt ) endif( KWIN_HAVE_OPENGL_COMPOSITING AND NOT KWIN_HAVE_OPENGLES_COMPOSITING ) diff --git a/effects/blur/blur.cpp b/effects/blur/blur.cpp index 7420b89787..9dcecc267a 100644 --- a/effects/blur/blur.cpp +++ b/effects/blur/blur.cpp @@ -22,6 +22,7 @@ #include +#include #include namespace KWin @@ -191,34 +192,23 @@ QRegion BlurEffect::blurRegion(const EffectWindow *w) const void BlurEffect::drawRegion(const QRegion ®ion) { - const int vertexCount = region.rectCount() * 4; + const int vertexCount = region.rectCount() * 6; if (vertices.size() < vertexCount) vertices.resize(vertexCount); int i = 0; foreach (const QRect &r, region.rects()) { - vertices[i++] = QVector2D(r.x(), r.y()); - vertices[i++] = QVector2D(r.x() + r.width(), r.y()); - vertices[i++] = QVector2D(r.x() + r.width(), r.y() + r.height()); - vertices[i++] = QVector2D(r.x(), r.y() + r.height()); - } - - if (vertexCount > 1000) { - glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, 0, (float*)vertices.constData()); - glVertexPointer(2, GL_FLOAT, 0, (float*)vertices.constData()); - glDrawArrays(GL_QUADS, 0, vertexCount); - glPopClientAttrib(); - } else { - glBegin(GL_QUADS); - for (int i = 0; i < vertexCount; i++) { - glTexCoord2fv((const float*)&vertices[i]); - glVertex2fv((const float*)&vertices[i]); - } - glEnd(); + vertices[i++] = QVector2D(r.x() + r.width(), r.y()); + vertices[i++] = QVector2D(r.x(), r.y()); + vertices[i++] = QVector2D(r.x(), r.y() + r.height()); + vertices[i++] = QVector2D(r.x(), r.y() + r.height()); + vertices[i++] = QVector2D(r.x() + r.width(), r.y() + r.height()); + vertices[i++] = QVector2D(r.x() + r.width(), r.y()); } + GLVertexBuffer *vbo = GLVertexBuffer::streamingBuffer(); + vbo->reset(); + vbo->setData(vertexCount, 2, (float*)vertices.constData(), (float*)vertices.constData()); + vbo->render(GL_TRIANGLES); } void BlurEffect::paintScreen(int mask, QRegion region, ScreenPaintData &data) @@ -293,11 +283,15 @@ void BlurEffect::doBlur(const QRegion& shape, const QRect& screen, const float o // Set up the texture matrix to transform from screen coordinates // to texture coordinates. +#ifndef KWIN_HAVE_OPENGLES glMatrixMode(GL_TEXTURE); - glPushMatrix(); - glLoadIdentity(); - glScalef(1.0 / scratch.width(), -1.0 / scratch.height(), 1); - glTranslatef(-r.x(), -scratch.height() - r.y(), 0); +#endif + pushMatrix(); + QMatrix4x4 textureMatrix; + textureMatrix.scale(1.0 / scratch.width(), -1.0 / scratch.height(), 1); + textureMatrix.translate(-r.x(), -scratch.height() - r.y(), 0); + loadMatrix(textureMatrix); + shader->setTextureMatrix(textureMatrix); drawRegion(expanded); @@ -314,7 +308,9 @@ void BlurEffect::doBlur(const QRegion& shape, const QRect& screen, const float o // Modulate the blurred texture with the window opacity if the window isn't opaque if (opacity < 1.0) { +#ifndef KWIN_HAVE_OPENGLES glPushAttrib(GL_COLOR_BUFFER_BIT); +#endif glEnable(GL_BLEND); glBlendColor(0, 0, 0, opacity); glBlendFunc(GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA); @@ -322,17 +318,25 @@ void BlurEffect::doBlur(const QRegion& shape, const QRect& screen, const float o // Set the up the texture matrix to transform from screen coordinates // to texture coordinates. - glLoadIdentity(); - glScalef(1.0 / tex->width(), -1.0 / tex->height(), 1); - glTranslatef(0, -tex->height(), 0); + textureMatrix.setToIdentity(); + textureMatrix.scale(1.0 / tex->width(), -1.0 / tex->height(), 1); + textureMatrix.translate(0, -tex->height(), 0); + loadMatrix(textureMatrix); + shader->setTextureMatrix(textureMatrix); drawRegion(shape); - glPopMatrix(); + popMatrix(); +#ifndef KWIN_HAVE_OPENGLES glMatrixMode(GL_MODELVIEW); +#endif - if (opacity < 1.0) + if (opacity < 1.0) { + glDisable(GL_BLEND); +#ifndef KWIN_HAVE_OPENGLES glPopAttrib(); +#endif + } tex->unbind(); shader->unbind(); diff --git a/effects/blur/blurshader.cpp b/effects/blur/blurshader.cpp index 7890f722d7..35d30ff280 100644 --- a/effects/blur/blurshader.cpp +++ b/effects/blur/blurshader.cpp @@ -19,8 +19,12 @@ #include "blurshader.h" +#include + #include +#include #include +#include #include #include @@ -103,7 +107,7 @@ QVector BlurShader::gaussianKernel() const GLSLBlurShader::GLSLBlurShader() - : BlurShader(), program(0) + : BlurShader(), shader(NULL) { } @@ -114,10 +118,8 @@ GLSLBlurShader::~GLSLBlurShader() void GLSLBlurShader::reset() { - if (program) { - glDeleteProgram(program); - program = 0; - } + delete shader; + shader = NULL; setIsValid(false); } @@ -129,6 +131,7 @@ bool GLSLBlurShader::supported() (void) glGetError(); // Clear the error state +#ifndef KWIN_HAVE_OPENGLES // These are the minimum values the implementation is required to support int value = 0; @@ -143,6 +146,7 @@ bool GLSLBlurShader::supported() glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &value); if (value < 512) return false; +#endif if (glGetError() != GL_NO_ERROR) return false; @@ -155,14 +159,20 @@ void GLSLBlurShader::setPixelDistance(float val) if (!isValid()) return; - float pixelSize[2] = { 0.0, 0.0 }; - + QVector2D pixelSize(0.0, 0.0); if (direction() == Qt::Horizontal) - pixelSize[0] = val; + pixelSize.setX(val); else - pixelSize[1] = val; + pixelSize.setY(val); + shader->setUniform("pixelSize", pixelSize); +} - glUniform2fv(uPixelSize, 1, pixelSize); +void GLSLBlurShader::setTextureMatrix(const QMatrix4x4 &matrix) +{ + if (!isValid()) { + return; + } + shader->setUniform("u_textureMatrix", matrix); } void GLSLBlurShader::bind() @@ -170,74 +180,30 @@ void GLSLBlurShader::bind() if (!isValid()) return; - glUseProgram(program); - glUniform1i(uTexUnit, 0); + ShaderManager::instance()->pushShader(shader); } void GLSLBlurShader::unbind() { - glUseProgram(0); + ShaderManager::instance()->popShader(); } int GLSLBlurShader::maxKernelSize() const { int value; +#ifdef KWIN_HAVE_OPENGLES + // GL_MAX_VARYING_FLOATS not available in GLES + // querying for GL_MAX_VARYING_VECTORS crashes on nouveau + // using the minimum value of 8 + return 8; +#else glGetIntegerv(GL_MAX_VARYING_FLOATS, &value); // Note: In theory the driver could pack two vec2's in one vec4, // but we'll assume it doesn't do that return value / 4; // Max number of vec4 varyings +#endif } -GLuint GLSLBlurShader::compile(GLenum type, const QByteArray &source) -{ - const char *sourceData = source.constData(); - - GLuint shader = glCreateShader(type); - glShaderSource(shader, 1, &sourceData, 0); - glCompileShader(shader); - - int status; - glGetShaderiv(shader, GL_COMPILE_STATUS, &status); - - if (status == GL_FALSE) { - GLsizei size, length; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &size); - - QByteArray log(size, 0); - glGetShaderInfoLog(shader, size, &length, log.data()); - - kError() << "Failed to compile shader: " << log; - glDeleteShader(shader); - shader = 0; - } - - return shader; -} - -GLuint GLSLBlurShader::link(GLuint vertexShader, GLuint fragmentShader) -{ - GLuint program = glCreateProgram(); - glAttachShader(program, vertexShader); - glAttachShader(program, fragmentShader); - glLinkProgram(program); - - int status; - glGetProgramiv(program, GL_LINK_STATUS, &status); - - if (status == GL_FALSE) { - GLsizei size, length; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &size); - - QByteArray log(size, 0); - glGetProgramInfoLog(program, size, &length, log.data()); - - kError() << "Failed to link shader: " << log; - glDeleteProgram(program); - program = 0; - } - - return program; -} void GLSLBlurShader::init() { @@ -252,13 +218,17 @@ void GLSLBlurShader::init() // =================================================================== QTextStream stream(&vertexSource); + stream << "uniform mat4 u_modelViewProjectionMatrix;\n"; + stream << "uniform mat4 u_textureMatrix;\n"; stream << "uniform vec2 pixelSize;\n\n"; + stream << "attribute vec4 vertex;\n"; + stream << "attribute vec4 texCoord;\n\n"; for (int i = 0; i < size; i++) stream << "varying vec2 samplePos" << i << ";\n"; stream << "\n"; stream << "void main(void)\n"; stream << "{\n"; - stream << " vec2 center = vec4(gl_TextureMatrix[0] * gl_MultiTexCoord0).st;\n\n"; + stream << " vec2 center = vec4(texCoord * u_textureMatrix).st;\n\n"; for (int i = 0; i < center; i++) stream << " samplePos" << i << " = center + pixelSize * vec2(" @@ -268,7 +238,7 @@ void GLSLBlurShader::init() stream << " samplePos" << i << " = center + pixelSize * vec2(" << 1.5 + (i - center - 1) * 2.0 << ");\n"; stream << "\n"; - stream << " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"; + stream << " gl_Position = vertex * u_modelViewProjectionMatrix;\n"; stream << "}\n"; stream.flush(); @@ -294,24 +264,18 @@ void GLSLBlurShader::init() stream2 << "}\n"; stream2.flush(); - GLuint vertexShader = compile(GL_VERTEX_SHADER, vertexSource); - GLuint fragmentShader = compile(GL_FRAGMENT_SHADER, fragmentSource); - - if (vertexShader && fragmentShader) - program = link(vertexShader, fragmentShader); - - if (vertexShader) - glDeleteShader(vertexShader); - - if (fragmentShader) - glDeleteShader(fragmentShader); - - if (program) { - uTexUnit = glGetUniformLocation(program, "texUnit"); - uPixelSize = glGetUniformLocation(program, "pixelSize"); + shader = ShaderManager::instance()->loadShaderFromCode(vertexSource, fragmentSource); + if (shader->isValid()) { + QMatrix4x4 modelViewProjection; + modelViewProjection.ortho(0, displayWidth(), displayHeight(), 0, 0, 65535); + ShaderManager::instance()->pushShader(shader); + shader->setUniform("texUnit", 0); + shader->setUniform("u_textureMatrix", QMatrix4x4()); + shader->setUniform("u_modelViewProjectionMatrix", modelViewProjection); + ShaderManager::instance()->popShader(); } - setIsValid(program != 0); + setIsValid(shader->isValid()); } @@ -332,16 +296,21 @@ ARBBlurShader::~ARBBlurShader() void ARBBlurShader::reset() { +#ifndef KWIN_HAVE_OPENGLES if (program) { glDeleteProgramsARB(1, &program); program = 0; } setIsValid(false); +#endif } bool ARBBlurShader::supported() { +#ifdef KWIN_HAVE_OPENGLES + return false; +#else if (!hasGLExtension("GL_ARB_fragment_program")) return false; @@ -374,10 +343,14 @@ bool ARBBlurShader::supported() return false; return true; +#endif } void ARBBlurShader::setPixelDistance(float val) { +#ifdef KWIN_HAVE_OPENGLES + Q_UNUSED(val) +#else float firstStep = val * 1.5; float nextStep = val * 2.0; @@ -388,19 +361,23 @@ void ARBBlurShader::setPixelDistance(float val) glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 0, 0, firstStep, 0, 0); glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, 0, nextStep, 0, 0); } +#endif } void ARBBlurShader::bind() { +#ifndef KWIN_HAVE_OPENGLES if (!isValid()) return; glEnable(GL_FRAGMENT_PROGRAM_ARB); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, program); +#endif } void ARBBlurShader::unbind() { +#ifndef KWIN_HAVE_OPENGLES int boundObject; glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &boundObject); if( boundObject == program ) @@ -408,10 +385,14 @@ void ARBBlurShader::unbind() glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); glDisable(GL_FRAGMENT_PROGRAM_ARB); } +#endif } int ARBBlurShader::maxKernelSize() const { +#ifdef KWIN_HAVE_OPENGLES + return 0; +#else int value; int result; @@ -422,10 +403,12 @@ int ARBBlurShader::maxKernelSize() const result = qMin(result, value / 3); // We need 3 instructions / sample return result; +#endif } void ARBBlurShader::init() { +#ifndef KWIN_HAVE_OPENGLES QVector kernel = gaussianKernel(); const int size = kernel.size(); const int center = size / 2; @@ -481,6 +464,7 @@ void ARBBlurShader::init() } else setIsValid(true); - glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); +#endif } diff --git a/effects/blur/blurshader.h b/effects/blur/blurshader.h index 75b32eface..fe7360999a 100644 --- a/effects/blur/blurshader.h +++ b/effects/blur/blurshader.h @@ -22,6 +22,8 @@ #include +class QMatrix4x4; + namespace KWin { @@ -45,6 +47,7 @@ public: // Sets the distance between two pixels virtual void setPixelDistance(float val) = 0; + virtual void setTextureMatrix(const QMatrix4x4 &matrix) = 0; virtual void bind() = 0; virtual void unbind() = 0; @@ -77,6 +80,7 @@ public: void setPixelDistance(float val); void bind(); void unbind(); + void setTextureMatrix(const QMatrix4x4 &matrix); static bool supported(); @@ -85,13 +89,8 @@ protected: void reset(); int maxKernelSize() const; - GLuint compile(GLenum type, const QByteArray &source); - GLuint link(GLuint vertexShader, GLuint fragmentShader); - private: - GLuint program; - int uTexUnit; - int uPixelSize; + GLShader *shader; }; @@ -109,6 +108,7 @@ public: void setPixelDistance(float val); void bind(); void unbind(); + void setTextureMatrix(const QMatrix4x4 &) {}; static bool supported(); diff --git a/effects/configs_builtins.cpp b/effects/configs_builtins.cpp index 384513c6cf..07ddc90cda 100644 --- a/effects/configs_builtins.cpp +++ b/effects/configs_builtins.cpp @@ -39,6 +39,7 @@ along with this program. If not, see . #endif #ifdef KWIN_HAVE_OPENGL_COMPOSITING +#include "blur/blur_config.h" #include "coverswitch/coverswitch_config.h" #include "cube/cube_config.h" #include "cube/cubeslide_config.h" @@ -51,7 +52,6 @@ along with this program. If not, see . #include "trackmouse/trackmouse_config.h" #include "wobblywindows/wobblywindows_config.h" #ifndef KWIN_HAVE_OPENGLES -#include "blur/blur_config.h" #include "sharpen/sharpen_config.h" #include "snow/snow_config.h" #endif @@ -81,6 +81,7 @@ KWIN_EFFECT_CONFIG_MULTIPLE( builtins, #endif #ifdef KWIN_HAVE_OPENGL_COMPOSITING + KWIN_EFFECT_CONFIG_SINGLE( blur, BlurEffectConfig ) KWIN_EFFECT_CONFIG_SINGLE( coverswitch, CoverSwitchEffectConfig ) KWIN_EFFECT_CONFIG_SINGLE( cube, CubeEffectConfig ) KWIN_EFFECT_CONFIG_SINGLE( cubeslide, CubeSlideEffectConfig ) @@ -93,7 +94,6 @@ KWIN_EFFECT_CONFIG_MULTIPLE( builtins, KWIN_EFFECT_CONFIG_SINGLE( trackmouse, TrackMouseEffectConfig ) KWIN_EFFECT_CONFIG_SINGLE( wobblywindows, WobblyWindowsEffectConfig ) #ifndef KWIN_HAVE_OPENGLES - KWIN_EFFECT_CONFIG_SINGLE( blur, BlurEffectConfig ) KWIN_EFFECT_CONFIG_SINGLE( sharpen, SharpenEffectConfig ) KWIN_EFFECT_CONFIG_SINGLE( snow, SnowEffectConfig ) #endif