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.
This commit is contained in:
parent
a478fc7ff3
commit
8c4fc28e1a
5 changed files with 110 additions and 122 deletions
|
@ -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 )
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include <QMatrix4x4>
|
||||
#include <KDebug>
|
||||
|
||||
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();
|
||||
|
|
|
@ -19,8 +19,12 @@
|
|||
|
||||
#include "blurshader.h"
|
||||
|
||||
#include <kwineffects.h>
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QMatrix4x4>
|
||||
#include <QTextStream>
|
||||
#include <QVector2D>
|
||||
#include <KDebug>
|
||||
|
||||
#include <cmath>
|
||||
|
@ -103,7 +107,7 @@ QVector<float> 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<float> 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
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include <kwinglutils.h>
|
||||
|
||||
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();
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#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 <http://www.gnu.org/licenses/>.
|
|||
#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
|
||||
|
|
Loading…
Reference in a new issue