Adding optional shader to snow effect. Shader is used when hardware support is available.

Using shader reduces CPU load from approximately 50 % to less than 20 % on my system.

svn path=/trunk/KDE/kdebase/workspace/; revision=883348
This commit is contained in:
Martin Gräßlin 2008-11-12 18:38:36 +00:00
parent 5535a9de5e
commit 8ecaefebcc
5 changed files with 158 additions and 21 deletions

View file

@ -166,6 +166,8 @@ if(KWIN_HAVE_OPENGL_COMPOSITING)
data/lookingglass.frag
data/lookingglass.vert
data/shadow-texture.png
data/snow.frag
data/snow.vert
data/snowflake.png
data/circle.png
data/circle-edgy.png

25
effects/data/snow.frag Normal file
View file

@ -0,0 +1,25 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2008 Martin Gräßlin <ubuntu@martin-graesslin.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
uniform sampler2D snowTexture;
void main()
{
gl_FragColor = texture2D( snowTexture, gl_TexCoord[0].st );
}

31
effects/data/snow.vert Normal file
View file

@ -0,0 +1,31 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2008 Martin Gräßlin <ubuntu@martin-graesslin.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
attribute float angle;
attribute float x;
attribute float y;
void main()
{
float radian = radians(angle);
mat2 rotation = mat2( cos(radian), sin(radian), -sin(radian), cos(radian) );
vec2 vertex = (gl_Vertex.xy-vec2(x, y))*rotation+vec2(x, y);
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * vec4(vertex, gl_Vertex.zw);
}

View file

@ -50,6 +50,9 @@ SnowEffect::SnowEffect()
, flakes( NULL )
, active( false)
, snowBehindWindows( false )
, mShader( 0 )
, mInited( false )
, mUseShader( true )
{
srandom( std::time( NULL ) );
lastFlakeTime = QTime::currentTime();
@ -66,6 +69,7 @@ SnowEffect::~SnowEffect()
{
delete texture;
delete flakes;
delete mShader;
}
void SnowEffect::reconfigure( ReconfigureFlags )
@ -145,35 +149,73 @@ void SnowEffect::snowing( QRegion& region )
if(! texture ) loadTexture();
if( texture )
{
glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT );
glActiveTexture(GL_TEXTURE0);
texture->bind();
if( mUseShader && !mInited )
mUseShader = loadShader();
glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glNewList( list, GL_COMPILE_AND_EXECUTE );
if( mUseShader )
{
mShader->bind();
glNewList( list, GL_COMPILE_AND_EXECUTE );
glBegin( GL_QUADS );
}
else
glNewList( list, GL_COMPILE_AND_EXECUTE );
for (int i=0; i<flakes->count(); i++)
{
SnowFlake flake = flakes->at(i);
// save the matrix
glPushMatrix();
// translate to the center of the flake
glTranslatef(flake.getWidth()/2 + flake.getX(), flake.getHeight()/2 + flake.getY(), 0);
// rotate around the Z-axis
glRotatef(flake.getRotationAngle(), 0.0, 0.0, 1.0);
// translate back to the starting point
glTranslatef(-flake.getWidth()/2 - flake.getX(), -flake.getHeight()/2 - flake.getY(), 0);
// paint the snowflake
texture->render( region, flake.getRect());
// restore the matrix
glPopMatrix();
if( snowBehindWindows && !region.contains( flake.getRect() ) )
continue;
if( mUseShader )
{
// use shader
mShader->setAttribute( "angle", flake.getRotationAngle() );
mShader->setAttribute( "x", flake.getWidth()/2 + flake.getX() );
mShader->setAttribute( "y", flake.getHeight()/2 + flake.getY() );
glTexCoord2f( 0.0f, 0.0f );
glVertex2i( flake.getRect().x(), flake.getRect().y() );
glTexCoord2f( 1.0f, 0.0f );
glVertex2i( flake.getRect().x()+flake.getRect().width(), flake.getRect().y() );
glTexCoord2f( 1.0f, 1.0f );
glVertex2i( flake.getRect().x()+flake.getRect().width(), flake.getRect().y()+flake.getRect().height() );
glTexCoord2f( 0.0f, 1.0f );
glVertex2i( flake.getRect().x(), flake.getRect().y()+flake.getRect().height() );
}
else
{
// no shader
// save the matrix
glPushMatrix();
// translate to the center of the flake
glTranslatef(flake.getWidth()/2 + flake.getX(), flake.getHeight()/2 + flake.getY(), 0);
// rotate around the Z-axis
glRotatef(flake.getRotationAngle(), 0.0, 0.0, 1.0);
// translate back to the starting point
glTranslatef(-flake.getWidth()/2 - flake.getX(), -flake.getHeight()/2 - flake.getY(), 0);
// paint the snowflake
texture->render( region, flake.getRect());
// restore the matrix
glPopMatrix();
}
}
glEndList();
if( mUseShader )
{
glEnd();
glEndList();
mShader->unbind();
}
else
glEndList();
glDisable( GL_BLEND );
texture->unbind();
glPopAttrib();
@ -212,6 +254,39 @@ void SnowEffect::toggle()
effects->addRepaintFull();
}
bool SnowEffect::loadShader()
{
mInited = true;
if( !(GLShader::fragmentShaderSupported() &&
(effects->compositingType() == OpenGLCompositing)) )
{
kDebug() << "Shaders not supported - waisting CPU cycles" << endl;
return false;
}
QString fragmentshader = KGlobal::dirs()->findResource("data", "kwin/snow.frag");
QString vertexshader = KGlobal::dirs()->findResource("data", "kwin/snow.vert");
if(fragmentshader.isEmpty() || vertexshader.isEmpty())
{
kDebug() << "Couldn't locate shader files" << endl;
return false;
}
mShader = new GLShader(vertexshader, fragmentshader);
if(!mShader->isValid())
{
kDebug() << "The shader failed to load!" << endl;
return false;
}
else
{
mShader->bind();
mShader->setUniform( "snowTexture", 0 );
mShader->unbind();
}
kDebug() << "using shader";
return true;
}
void SnowEffect::loadTexture()
{
#ifdef KWIN_HAVE_OPENGL_COMPOSITING

View file

@ -78,6 +78,7 @@ class SnowEffect
private:
void loadTexture();
void snowing( QRegion& region );
bool loadShader();
GLTexture* texture;
QList<SnowFlake>* flakes;
QTime lastFlakeTime;
@ -90,6 +91,9 @@ class SnowEffect
bool active;
GLuint list;
bool snowBehindWindows;
GLShader* mShader;
bool mInited;
bool mUseShader;
};
} // namespace