Move Lanczos filter from taskbarthumbnail effect into the scene and use it also in boxswitch, presentwindows and thumbnailaside effects.
svn path=/trunk/KDE/kdebase/workspace/; revision=1133901
This commit is contained in:
parent
171dfbd894
commit
191435d425
16 changed files with 385 additions and 244 deletions
|
@ -101,6 +101,7 @@ set(kwin_KDEINIT_SRCS
|
|||
scene_basic.cpp
|
||||
scene_xrender.cpp
|
||||
scene_opengl.cpp
|
||||
lanczosfilter.cpp
|
||||
deleted.cpp
|
||||
effects.cpp
|
||||
compositingprefs.cpp
|
||||
|
@ -126,7 +127,7 @@ set(kwin_KDEINIT_SRCS
|
|||
|
||||
qt4_add_dbus_adaptor( kwin_KDEINIT_SRCS org.kde.KWin.xml workspace.h KWin::Workspace )
|
||||
|
||||
|
||||
qt4_add_resources( kwin_KDEINIT_SRCS resources.qrc )
|
||||
|
||||
kde4_add_kdeinit_executable( kwin ${kwin_KDEINIT_SRCS})
|
||||
|
||||
|
|
|
@ -967,9 +967,12 @@ void BoxSwitchEffect::paintWindowThumbnail( EffectWindow* w )
|
|||
}
|
||||
else
|
||||
{
|
||||
int mask = PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED;
|
||||
if (!mAnimateSwitch)
|
||||
mask |= PAINT_WINDOW_LANCZOS;
|
||||
effects->drawWindow( w,
|
||||
PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSFORMED,
|
||||
windows[ w ]->thumbnail, data );
|
||||
mask,
|
||||
windows[ w ]->thumbnail, data );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -318,7 +318,7 @@ void PresentWindowsEffect::paintWindow( EffectWindow *w, int mask, QRegion regio
|
|||
{
|
||||
m_motionManager.apply( w, data );
|
||||
|
||||
effects->paintWindow( w, mask, region, data );
|
||||
effects->paintWindow( w, mask | PAINT_WINDOW_LANCZOS, region, data );
|
||||
|
||||
QRect rect = m_motionManager.transformedGeometry( w ).toRect();
|
||||
if( m_showIcons )
|
||||
|
|
|
@ -5,9 +5,6 @@
|
|||
set( kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources}
|
||||
taskbarthumbnail/taskbarthumbnail.cpp
|
||||
)
|
||||
qt4_add_resources( kwin4_effect_builtins_sources
|
||||
taskbarthumbnail/taskbarthumbnail.qrc
|
||||
)
|
||||
|
||||
# .desktop files
|
||||
install( FILES
|
||||
|
|
|
@ -27,9 +27,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <kwinglutils.h>
|
||||
#endif
|
||||
|
||||
#include <qmath.h>
|
||||
#include <cmath>
|
||||
|
||||
// This effect shows a preview inside a window that has a special property set
|
||||
// on it that says which window and where to render. It is used by the taskbar
|
||||
// to show window previews in tooltips.
|
||||
|
@ -46,34 +43,12 @@ TaskbarThumbnailEffect::TaskbarThumbnailEffect()
|
|||
// TODO hackish way to announce support, make better after 4.0
|
||||
unsigned char dummy = 0;
|
||||
XChangeProperty( display(), rootWindow(), atom, atom, 8, PropModeReplace, &dummy, 1 );
|
||||
|
||||
if ( GLShader::fragmentShaderSupported() &&
|
||||
GLShader::vertexShaderSupported() &&
|
||||
GLRenderTarget::supported() )
|
||||
{
|
||||
shader = new GLShader(":/taskbarthumbnail/vertex.glsl", ":/taskbarthumbnail/fragment.glsl");
|
||||
shader->bind();
|
||||
uTexUnit = shader->uniformLocation("texUnit");
|
||||
uKernelSize = shader->uniformLocation("kernelSize");
|
||||
uKernel = shader->uniformLocation("kernel");
|
||||
uOffsets = shader->uniformLocation("offsets");
|
||||
shader->unbind();
|
||||
}
|
||||
else
|
||||
{
|
||||
shader = 0;
|
||||
}
|
||||
offscreenTex = 0;
|
||||
offscreenTarget = 0;
|
||||
}
|
||||
|
||||
TaskbarThumbnailEffect::~TaskbarThumbnailEffect()
|
||||
{
|
||||
XDeleteProperty( display(), rootWindow(), atom );
|
||||
effects->registerPropertyType( atom, false );
|
||||
delete offscreenTarget;
|
||||
delete offscreenTex;
|
||||
delete shader;
|
||||
}
|
||||
|
||||
void TaskbarThumbnailEffect::prePaintScreen( ScreenPrePaintData& data, int time )
|
||||
|
@ -90,85 +65,6 @@ void TaskbarThumbnailEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData
|
|||
effects->prePaintWindow( w, data, time );
|
||||
}
|
||||
|
||||
void TaskbarThumbnailEffect::updateOffscreenSurfaces()
|
||||
{
|
||||
int w = displayWidth();
|
||||
int h = displayHeight();
|
||||
if ( !GLTexture::NPOTTextureSupported() )
|
||||
{
|
||||
w = nearestPowerOfTwo( w );
|
||||
h = nearestPowerOfTwo( h );
|
||||
}
|
||||
if ( !offscreenTex || offscreenTex->width() != w || offscreenTex->height() != h )
|
||||
{
|
||||
if ( offscreenTex )
|
||||
{
|
||||
delete offscreenTex;
|
||||
delete offscreenTarget;
|
||||
}
|
||||
offscreenTex = new GLTexture( w, h );
|
||||
offscreenTex->setFilter( GL_LINEAR );
|
||||
offscreenTex->setWrapMode( GL_CLAMP_TO_EDGE );
|
||||
offscreenTarget = new GLRenderTarget( offscreenTex );
|
||||
}
|
||||
}
|
||||
|
||||
static float sinc( float x )
|
||||
{
|
||||
return std::sin( x * M_PI ) / ( x * M_PI );
|
||||
}
|
||||
|
||||
static float lanczos( float x, float a )
|
||||
{
|
||||
if ( qFuzzyCompare( x + 1.0, 1.0 ) )
|
||||
return 1.0;
|
||||
|
||||
if ( qAbs( x ) >= a )
|
||||
return 0.0;
|
||||
|
||||
return sinc( x ) * sinc( x / a );
|
||||
}
|
||||
|
||||
QVector<QVector4D> TaskbarThumbnailEffect::createKernel( float delta )
|
||||
{
|
||||
const float a = 2.0;
|
||||
|
||||
// The two outermost samples always fall at points where the lanczos
|
||||
// function returns 0, so we'll skip them.
|
||||
const int sampleCount = qBound( 3, qCeil(delta * a) * 2 + 1 - 2, 49 );
|
||||
const int center = sampleCount / 2;
|
||||
const int kernelSize = center + 1;
|
||||
const float factor = 1.0 / delta;
|
||||
|
||||
QVector<float> values( kernelSize );
|
||||
QVector<QVector4D> kernel( kernelSize );
|
||||
float sum = 0;
|
||||
|
||||
for ( int i = 0; i < kernelSize; i++ ) {
|
||||
const float val = lanczos( i * factor, a );
|
||||
sum += i > 0 ? val * 2 : val;
|
||||
values[i] = val;
|
||||
}
|
||||
|
||||
// Normalize the kernel
|
||||
for ( int i = 0; i < kernelSize; i++ ) {
|
||||
const float val = values[i] / sum;
|
||||
kernel[i] = QVector4D( val, val, val, val );
|
||||
}
|
||||
|
||||
return kernel;
|
||||
}
|
||||
|
||||
QVector<QVector2D> TaskbarThumbnailEffect::createOffsets( int count, float width, Qt::Orientation direction )
|
||||
{
|
||||
QVector<QVector2D> offsets( count );
|
||||
for ( int i = 0; i < count; i++ ) {
|
||||
offsets[i] = ( direction == Qt::Horizontal ) ?
|
||||
QVector2D( i / width, 0 ) : QVector2D( 0, i / width );
|
||||
}
|
||||
return offsets;
|
||||
}
|
||||
|
||||
void TaskbarThumbnailEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
|
||||
{
|
||||
effects->paintWindow( w, mask, region, data ); // paint window first
|
||||
|
@ -179,6 +75,7 @@ void TaskbarThumbnailEffect::paintWindow( EffectWindow* w, int mask, QRegion reg
|
|||
mask |= PAINT_WINDOW_OPAQUE;
|
||||
else
|
||||
mask |= PAINT_WINDOW_TRANSLUCENT;
|
||||
mask |= PAINT_WINDOW_LANCZOS;
|
||||
foreach( const Data &thumb, thumbnails.values( w ))
|
||||
{
|
||||
EffectWindow* thumbw = effects->findWindow( thumb.window );
|
||||
|
@ -191,97 +88,6 @@ void TaskbarThumbnailEffect::paintWindow( EffectWindow* w, int mask, QRegion reg
|
|||
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
|
||||
if( effects->compositingType() == KWin::OpenGLCompositing )
|
||||
{
|
||||
if ( shader )
|
||||
{
|
||||
int tx = thumb.rect.x() + w->x();
|
||||
int ty = thumb.rect.y() + w->y();
|
||||
int tw = thumb.rect.width();
|
||||
int th = thumb.rect.height();
|
||||
|
||||
int sw = thumbw->width();
|
||||
int sh = thumbw->height();
|
||||
|
||||
setPositionTransformations( thumbData, r,
|
||||
thumbw, QRect(0, 0, sw, sh), Qt::KeepAspectRatio );
|
||||
|
||||
// Bind the offscreen FBO and draw the window on it unscaled
|
||||
updateOffscreenSurfaces();
|
||||
effects->pushRenderTarget( offscreenTarget );
|
||||
|
||||
glClear( GL_COLOR_BUFFER_BIT );
|
||||
effects->drawWindow( thumbw, mask, r, thumbData );
|
||||
|
||||
// Create a scratch texture and copy the rendered window into it
|
||||
GLTexture tex( sw, sh );
|
||||
tex.setFilter( GL_LINEAR );
|
||||
tex.setWrapMode( GL_CLAMP_TO_EDGE );
|
||||
tex.bind();
|
||||
|
||||
glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, offscreenTex->height() - sh, sw, sh );
|
||||
|
||||
// Set up the shader for horizontal scaling
|
||||
float dx = sw / float(tw);
|
||||
QVector<QVector4D> kernel = createKernel( dx );
|
||||
QVector<QVector2D> offsets = createOffsets( kernel.size(), sw, Qt::Horizontal );
|
||||
|
||||
shader->bind();
|
||||
glUniform1i( uTexUnit, 0 );
|
||||
glUniform1i( uKernelSize, kernel.size() );
|
||||
glUniform2fv( uOffsets, offsets.size(), (const GLfloat*)offsets.constData() );
|
||||
glUniform4fv( uKernel, kernel.size(), (const GLfloat*)kernel.constData() );
|
||||
|
||||
// Draw the window back into the FBO, this time scaled horizontally
|
||||
glClear( GL_COLOR_BUFFER_BIT );
|
||||
|
||||
glBegin( GL_QUADS );
|
||||
glTexCoord2f( 0, 0 ); glVertex2i( 0, 0 ); // Top left
|
||||
glTexCoord2f( 1, 0 ); glVertex2i( tw, 0 ); // Top right
|
||||
glTexCoord2f( 1, 1 ); glVertex2i( tw, sh ); // Bottom right
|
||||
glTexCoord2f( 0, 1 ); glVertex2i( 0, sh ); // Bottom left
|
||||
glEnd();
|
||||
|
||||
// At this point we don't need the scratch texture anymore
|
||||
tex.unbind();
|
||||
tex.discard();
|
||||
|
||||
// Unbind the FBO
|
||||
effects->popRenderTarget();
|
||||
|
||||
// Set up the shader for vertical scaling
|
||||
float dy = sh / float(th);
|
||||
kernel = createKernel( dy );
|
||||
offsets = createOffsets( kernel.size(), offscreenTex->height(), Qt::Vertical );
|
||||
|
||||
glUniform1i( uKernelSize, kernel.size() );
|
||||
glUniform2fv( uOffsets, offsets.size(), (const GLfloat*)offsets.constData() );
|
||||
glUniform4fv( uKernel, kernel.size(), (const GLfloat*)kernel.constData() );
|
||||
|
||||
float sx2 = tw / float(offscreenTex->width());
|
||||
float sy2 = 1 - (sh / float(offscreenTex->height()));
|
||||
|
||||
// Now draw the horizontally scaled window in the FBO at the right
|
||||
// coordinates on the screen, while scaling it vertically and blending it.
|
||||
offscreenTex->bind();
|
||||
|
||||
glPushAttrib( GL_COLOR_BUFFER_BIT );
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
glBegin( GL_QUADS );
|
||||
glTexCoord2f( 0, sy2 ); glVertex2i( tx, ty ); // Top left
|
||||
glTexCoord2f( sx2, sy2 ); glVertex2i( tx + tw, ty ); // Top right
|
||||
glTexCoord2f( sx2, 1 ); glVertex2i( tx + tw, ty + th ); // Bottom right
|
||||
glTexCoord2f( 0, 1 ); glVertex2i( tx, ty + th ); // Bottom left
|
||||
glEnd();
|
||||
|
||||
glPopAttrib();
|
||||
offscreenTex->unbind();
|
||||
shader->unbind();
|
||||
|
||||
// Delete the offscreen surface after 5 seconds
|
||||
timer.start( 5000, this );
|
||||
continue;
|
||||
}
|
||||
if ( data.shader )
|
||||
{
|
||||
// there is a shader - update texture width and height
|
||||
|
@ -355,18 +161,4 @@ void TaskbarThumbnailEffect::propertyNotify( EffectWindow* w, long a )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void TaskbarThumbnailEffect::timerEvent( QTimerEvent *event )
|
||||
{
|
||||
if (event->timerId() == timer.timerId())
|
||||
{
|
||||
timer.stop();
|
||||
|
||||
delete offscreenTarget;
|
||||
delete offscreenTex;
|
||||
offscreenTarget = 0;
|
||||
offscreenTex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -24,10 +24,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#include <kwineffects.h>
|
||||
#include <QObject>
|
||||
#include <QBasicTimer>
|
||||
#include <QVector>
|
||||
#include <QVector2D>
|
||||
#include <QVector4D>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
@ -45,28 +41,15 @@ class TaskbarThumbnailEffect
|
|||
virtual void windowAdded( EffectWindow* w );
|
||||
virtual void windowDeleted( EffectWindow* w );
|
||||
virtual void propertyNotify( EffectWindow* w, long atom );
|
||||
protected:
|
||||
virtual void timerEvent(QTimerEvent*);
|
||||
private:
|
||||
void updateOffscreenSurfaces();
|
||||
QVector<QVector4D> createKernel(float delta);
|
||||
QVector<QVector2D> createOffsets(int count, float width, Qt::Orientation direction);
|
||||
struct Data
|
||||
{
|
||||
Window window; // thumbnail of this window
|
||||
QRect rect;
|
||||
};
|
||||
long atom;
|
||||
GLTexture *offscreenTex;
|
||||
GLRenderTarget *offscreenTarget;
|
||||
GLShader *shader;
|
||||
QMultiHash< EffectWindow*, Data > thumbnails;
|
||||
EffectWindowList damagedWindows;
|
||||
QBasicTimer timer;
|
||||
int uTexUnit;
|
||||
int uOffsets;
|
||||
int uKernel;
|
||||
int uKernelSize;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/taskbarthumbnail">
|
||||
<file>vertex.glsl</file>
|
||||
<file>fragment.glsl</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -62,7 +62,7 @@ void ThumbnailAsideEffect::paintScreen( int mask, QRegion region, ScreenPaintDat
|
|||
data.opacity = opacity;
|
||||
QRect region;
|
||||
setPositionTransformations( data, region, d.window, d.rect, Qt::KeepAspectRatio );
|
||||
effects->drawWindow( d.window, PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_TRANSFORMED,
|
||||
effects->drawWindow( d.window, PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_TRANSFORMED | PAINT_WINDOW_LANCZOS,
|
||||
region, data );
|
||||
}
|
||||
}
|
||||
|
|
283
lanczosfilter.cpp
Normal file
283
lanczosfilter.cpp
Normal file
|
@ -0,0 +1,283 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2010 by Fredrik Höglund <fredrik@kde.org>
|
||||
|
||||
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/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include "lanczosfilter.h"
|
||||
#include "effects.h"
|
||||
|
||||
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
|
||||
#include <kwinglutils.h>
|
||||
#endif
|
||||
|
||||
#include <kwineffects.h>
|
||||
#include <KDE/KGlobalSettings>
|
||||
|
||||
#include <qmath.h>
|
||||
#include <cmath>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
LanczosFilter::LanczosFilter( QObject* parent )
|
||||
: QObject( parent )
|
||||
, m_offscreenTex( 0 )
|
||||
, m_offscreenTarget( 0 )
|
||||
, m_shader( 0 )
|
||||
, m_inited( false)
|
||||
{
|
||||
}
|
||||
|
||||
LanczosFilter::~LanczosFilter()
|
||||
{
|
||||
delete m_offscreenTarget;
|
||||
delete m_offscreenTex;
|
||||
delete m_shader;
|
||||
}
|
||||
|
||||
void LanczosFilter::init()
|
||||
{
|
||||
if (m_inited)
|
||||
return;
|
||||
m_inited = true;
|
||||
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
|
||||
if ( GLShader::fragmentShaderSupported() &&
|
||||
GLShader::vertexShaderSupported() &&
|
||||
GLRenderTarget::supported() )
|
||||
{
|
||||
m_shader = new GLShader(":/resources/lanczos-vertex.glsl", ":/resources/lanczos-fragment.glsl");
|
||||
if (m_shader->isValid())
|
||||
{
|
||||
m_shader->bind();
|
||||
m_uTexUnit = m_shader->uniformLocation("texUnit");
|
||||
m_uKernelSize = m_shader->uniformLocation("kernelSize");
|
||||
m_uKernel = m_shader->uniformLocation("kernel");
|
||||
m_uOffsets = m_shader->uniformLocation("offsets");
|
||||
m_shader->unbind();
|
||||
}
|
||||
else
|
||||
{
|
||||
kDebug(1212) << "Shader is not valid";
|
||||
m_shader = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void LanczosFilter::updateOffscreenSurfaces()
|
||||
{
|
||||
int w = displayWidth();
|
||||
int h = displayHeight();
|
||||
if ( !GLTexture::NPOTTextureSupported() )
|
||||
{
|
||||
w = nearestPowerOfTwo( w );
|
||||
h = nearestPowerOfTwo( h );
|
||||
}
|
||||
if ( !m_offscreenTex || m_offscreenTex->width() != w || m_offscreenTex->height() != h )
|
||||
{
|
||||
if ( m_offscreenTex )
|
||||
{
|
||||
delete m_offscreenTex;
|
||||
delete m_offscreenTarget;
|
||||
}
|
||||
m_offscreenTex = new GLTexture( w, h );
|
||||
m_offscreenTex->setFilter( GL_LINEAR );
|
||||
m_offscreenTex->setWrapMode( GL_CLAMP_TO_EDGE );
|
||||
m_offscreenTarget = new GLRenderTarget( m_offscreenTex );
|
||||
}
|
||||
}
|
||||
|
||||
static float sinc( float x )
|
||||
{
|
||||
return std::sin( x * M_PI ) / ( x * M_PI );
|
||||
}
|
||||
|
||||
static float lanczos( float x, float a )
|
||||
{
|
||||
if ( qFuzzyCompare( x + 1.0, 1.0 ) )
|
||||
return 1.0;
|
||||
|
||||
if ( qAbs( x ) >= a )
|
||||
return 0.0;
|
||||
|
||||
return sinc( x ) * sinc( x / a );
|
||||
}
|
||||
|
||||
QVector<QVector4D> LanczosFilter::createKernel( float delta )
|
||||
{
|
||||
const float a = 2.0;
|
||||
|
||||
// The two outermost samples always fall at points where the lanczos
|
||||
// function returns 0, so we'll skip them.
|
||||
const int sampleCount = qBound( 3, qCeil(delta * a) * 2 + 1 - 2, 49 );
|
||||
const int center = sampleCount / 2;
|
||||
const int kernelSize = center + 1;
|
||||
const float factor = 1.0 / delta;
|
||||
|
||||
QVector<float> values( kernelSize );
|
||||
QVector<QVector4D> kernel( kernelSize );
|
||||
float sum = 0;
|
||||
|
||||
for ( int i = 0; i < kernelSize; i++ ) {
|
||||
const float val = lanczos( i * factor, a );
|
||||
sum += i > 0 ? val * 2 : val;
|
||||
values[i] = val;
|
||||
}
|
||||
|
||||
// Normalize the kernel
|
||||
for ( int i = 0; i < kernelSize; i++ ) {
|
||||
const float val = values[i] / sum;
|
||||
kernel[i] = QVector4D( val, val, val, val );
|
||||
}
|
||||
|
||||
return kernel;
|
||||
}
|
||||
|
||||
QVector<QVector2D> LanczosFilter::createOffsets( int count, float width, Qt::Orientation direction )
|
||||
{
|
||||
QVector<QVector2D> offsets( count );
|
||||
for ( int i = 0; i < count; i++ ) {
|
||||
offsets[i] = ( direction == Qt::Horizontal ) ?
|
||||
QVector2D( i / width, 0 ) : QVector2D( 0, i / width );
|
||||
}
|
||||
return offsets;
|
||||
}
|
||||
|
||||
void LanczosFilter::performPaint( EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data )
|
||||
{
|
||||
#ifdef KWIN_HAVE_OPENGL_COMPOSITING
|
||||
if( effects->compositingType() == KWin::OpenGLCompositing &&
|
||||
KGlobalSettings::graphicEffectsLevel() & KGlobalSettings::SimpleAnimationEffects )
|
||||
{
|
||||
if (!m_inited)
|
||||
init();
|
||||
if ( m_shader )
|
||||
{
|
||||
int tx = data.xTranslate + w->x();
|
||||
int ty = data.yTranslate + w->y();
|
||||
int tw = w->width()*data.xScale;
|
||||
int th = w->height()*data.yScale;
|
||||
|
||||
int sw = w->width();
|
||||
int sh = w->height();
|
||||
|
||||
WindowPaintData thumbData = data;
|
||||
thumbData.xScale = 1.0;
|
||||
thumbData.yScale = 1.0;
|
||||
thumbData.xTranslate = -w->x();
|
||||
thumbData.yTranslate = -w->y();
|
||||
|
||||
// Bind the offscreen FBO and draw the window on it unscaled
|
||||
updateOffscreenSurfaces();
|
||||
effects->pushRenderTarget( m_offscreenTarget );
|
||||
|
||||
glClear( GL_COLOR_BUFFER_BIT );
|
||||
w->sceneWindow()->performPaint( mask, QRegion(0, 0, sw, sh), thumbData );
|
||||
|
||||
// Create a scratch texture and copy the rendered window into it
|
||||
GLTexture tex( sw, sh );
|
||||
tex.setFilter( GL_LINEAR );
|
||||
tex.setWrapMode( GL_CLAMP_TO_EDGE );
|
||||
tex.bind();
|
||||
|
||||
glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, m_offscreenTex->height() - sh, sw, sh );
|
||||
|
||||
// Set up the shader for horizontal scaling
|
||||
float dx = sw / float(tw);
|
||||
QVector<QVector4D> kernel = createKernel( dx );
|
||||
QVector<QVector2D> offsets = createOffsets( kernel.size(), sw, Qt::Horizontal );
|
||||
|
||||
m_shader->bind();
|
||||
glUniform1i( m_uTexUnit, 0 );
|
||||
glUniform1i( m_uKernelSize, kernel.size() );
|
||||
glUniform2fv( m_uOffsets, offsets.size(), (const GLfloat*)offsets.constData() );
|
||||
glUniform4fv( m_uKernel, kernel.size(), (const GLfloat*)kernel.constData() );
|
||||
|
||||
// Draw the window back into the FBO, this time scaled horizontally
|
||||
glClear( GL_COLOR_BUFFER_BIT );
|
||||
|
||||
glBegin( GL_QUADS );
|
||||
glTexCoord2f( 0, 0 ); glVertex2i( 0, 0 ); // Top left
|
||||
glTexCoord2f( 1, 0 ); glVertex2i( tw, 0 ); // Top right
|
||||
glTexCoord2f( 1, 1 ); glVertex2i( tw, sh ); // Bottom right
|
||||
glTexCoord2f( 0, 1 ); glVertex2i( 0, sh ); // Bottom left
|
||||
glEnd();
|
||||
|
||||
// At this point we don't need the scratch texture anymore
|
||||
tex.unbind();
|
||||
tex.discard();
|
||||
|
||||
// Unbind the FBO
|
||||
effects->popRenderTarget();
|
||||
|
||||
// Set up the shader for vertical scaling
|
||||
float dy = sh / float(th);
|
||||
kernel = createKernel( dy );
|
||||
offsets = createOffsets( kernel.size(), m_offscreenTex->height(), Qt::Vertical );
|
||||
|
||||
glUniform1i( m_uKernelSize, kernel.size() );
|
||||
glUniform2fv( m_uOffsets, offsets.size(), (const GLfloat*)offsets.constData() );
|
||||
glUniform4fv( m_uKernel, kernel.size(), (const GLfloat*)kernel.constData() );
|
||||
|
||||
float sx2 = tw / float(m_offscreenTex->width());
|
||||
float sy2 = 1 - (sh / float(m_offscreenTex->height()));
|
||||
|
||||
// Now draw the horizontally scaled window in the FBO at the right
|
||||
// coordinates on the screen, while scaling it vertically and blending it.
|
||||
m_offscreenTex->bind();
|
||||
|
||||
glPushAttrib( GL_COLOR_BUFFER_BIT );
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
||||
glBegin( GL_QUADS );
|
||||
glTexCoord2f( 0, sy2 ); glVertex2i( tx, ty ); // Top left
|
||||
glTexCoord2f( sx2, sy2 ); glVertex2i( tx + tw, ty ); // Top right
|
||||
glTexCoord2f( sx2, 1 ); glVertex2i( tx + tw, ty + th ); // Bottom right
|
||||
glTexCoord2f( 0, 1 ); glVertex2i( tx, ty + th ); // Bottom left
|
||||
glEnd();
|
||||
|
||||
glPopAttrib();
|
||||
m_offscreenTex->unbind();
|
||||
m_shader->unbind();
|
||||
|
||||
// Delete the offscreen surface after 5 seconds
|
||||
m_timer.start( 5000, this );
|
||||
return;
|
||||
}
|
||||
} // if ( effects->compositingType() == KWin::OpenGLCompositing )
|
||||
#endif
|
||||
w->sceneWindow()->performPaint( mask, region, data );
|
||||
} // End of function
|
||||
|
||||
void LanczosFilter::timerEvent( QTimerEvent *event )
|
||||
{
|
||||
if (event->timerId() == m_timer.timerId())
|
||||
{
|
||||
m_timer.stop();
|
||||
|
||||
delete m_offscreenTarget;
|
||||
delete m_offscreenTex;
|
||||
m_offscreenTarget = 0;
|
||||
m_offscreenTex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
69
lanczosfilter.h
Normal file
69
lanczosfilter.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2010 by Fredrik Höglund <fredrik@kde.org>
|
||||
|
||||
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/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef KWIN_LANCZOSFILTER_P_H
|
||||
#define KWIN_LANCZOSFILTER_P_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QBasicTimer>
|
||||
#include <QVector>
|
||||
#include <QVector2D>
|
||||
#include <QVector4D>
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
|
||||
class EffectWindowImpl;
|
||||
class WindowPaintData;
|
||||
class GLTexture;
|
||||
class GLRenderTarget;
|
||||
class GLShader;
|
||||
|
||||
class LanczosFilter
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LanczosFilter(QObject* parent = 0);
|
||||
~LanczosFilter();
|
||||
void performPaint( EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data );
|
||||
|
||||
protected:
|
||||
virtual void timerEvent(QTimerEvent*);
|
||||
private:
|
||||
void init();
|
||||
void updateOffscreenSurfaces();
|
||||
QVector<QVector4D> createKernel(float delta);
|
||||
QVector<QVector2D> createOffsets(int count, float width, Qt::Orientation direction);
|
||||
GLTexture *m_offscreenTex;
|
||||
GLRenderTarget *m_offscreenTarget;
|
||||
GLShader *m_shader;
|
||||
QBasicTimer m_timer;
|
||||
bool m_inited;
|
||||
int m_uTexUnit;
|
||||
int m_uOffsets;
|
||||
int m_uKernel;
|
||||
int m_uKernelSize;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // KWIN_LANCZOSFILTER_P_H
|
|
@ -54,7 +54,6 @@ class QKeyEvent;
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
|
||||
class EffectWindow;
|
||||
class EffectWindowGroup;
|
||||
class Effect;
|
||||
|
@ -294,7 +293,11 @@ class KWIN_EXPORT Effect
|
|||
/**
|
||||
* Temporary solution since (_OPAQUE | _TRANSLUCENT) is not working currently.
|
||||
**/
|
||||
PAINT_DECORATION_ONLY = 1 << 7
|
||||
PAINT_DECORATION_ONLY = 1 << 7,
|
||||
/**
|
||||
* Window will be painted with a lanczos filter.
|
||||
**/
|
||||
PAINT_WINDOW_LANCZOS = 1 << 8
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
6
resources.qrc
Normal file
6
resources.qrc
Normal file
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/resources">
|
||||
<file>lanczos-vertex.glsl</file>
|
||||
<file>lanczos-fragment.glsl</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -76,6 +76,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "client.h"
|
||||
#include "deleted.h"
|
||||
#include "effects.h"
|
||||
#include "lanczosfilter.h"
|
||||
|
||||
#include <kephal/screens.h>
|
||||
|
||||
|
@ -92,11 +93,13 @@ Scene::Scene( Workspace* ws )
|
|||
: wspace( ws )
|
||||
, has_waitSync( false )
|
||||
, selfCheckDone( false )
|
||||
, lanczos_filter( new LanczosFilter() )
|
||||
{
|
||||
}
|
||||
|
||||
Scene::~Scene()
|
||||
{
|
||||
delete lanczos_filter;
|
||||
}
|
||||
|
||||
// returns mask and possibly modified region
|
||||
|
@ -321,7 +324,10 @@ void Scene::finalPaintWindow( EffectWindowImpl* w, int mask, QRegion region, Win
|
|||
// will be eventually called from drawWindow()
|
||||
void Scene::finalDrawWindow( EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data )
|
||||
{
|
||||
w->sceneWindow()->performPaint( mask, region, data );
|
||||
if (mask & PAINT_WINDOW_LANCZOS )
|
||||
lanczos_filter->performPaint( w, mask, region, data );
|
||||
else
|
||||
w->sceneWindow()->performPaint( mask, region, data );
|
||||
}
|
||||
|
||||
QList< QPoint > Scene::selfCheckPoints() const
|
||||
|
|
6
scene.h
6
scene.h
|
@ -33,6 +33,7 @@ namespace KWin
|
|||
class Workspace;
|
||||
class Deleted;
|
||||
class EffectWindowImpl;
|
||||
class LanczosFilter;
|
||||
|
||||
// The base class for compositing backends.
|
||||
class Scene
|
||||
|
@ -81,7 +82,9 @@ class Scene
|
|||
// Clear whole background as the very first step, without optimizing it
|
||||
PAINT_SCREEN_BACKGROUND_FIRST = 1 << 6,
|
||||
// Temporary solution since (_OPAQUE | _TRANSLUCENT) is not working currently.
|
||||
PAINT_DECORATION_ONLY = 1 << 7
|
||||
PAINT_DECORATION_ONLY = 1 << 7,
|
||||
// Window will be painted with a lanczos filter.
|
||||
PAINT_WINDOW_LANCZOS = 1 << 8
|
||||
};
|
||||
// types of filtering available
|
||||
enum ImageFilterType { ImageFilterFast, ImageFilterGood };
|
||||
|
@ -140,6 +143,7 @@ class Scene
|
|||
Workspace* wspace;
|
||||
bool has_waitSync;
|
||||
bool selfCheckDone;
|
||||
LanczosFilter* lanczos_filter;
|
||||
};
|
||||
|
||||
// The base class for windows representations in composite backends
|
||||
|
|
Loading…
Reference in a new issue