Reworked shadow effect which should bring nice speedup (especially on cards where fill
rate is expensive). It optimizes shadow rendering a lot by eliminating tons of overdraw: - Windows are not forced to be drawn bottom-to-top anymore. - For opaque windows, shadows are drawn only to where they will actually be visible, not under the whole window. svn path=/trunk/KDE/kdebase/workspace/; revision=746296
This commit is contained in:
parent
881fd48854
commit
864dea425e
2 changed files with 86 additions and 28 deletions
|
@ -52,38 +52,63 @@ QRect ShadowEffect::shadowRectangle(const QRect& windowRectangle) const
|
|||
shadowXOffset + shadowGrow, shadowYOffset + shadowGrow);
|
||||
}
|
||||
|
||||
void ShadowEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data )
|
||||
{
|
||||
shadowDatas.clear();
|
||||
|
||||
// Draw windows
|
||||
effects->paintScreen( mask, region, data );
|
||||
|
||||
// Draw shadows
|
||||
drawQueuedShadows( 0 );
|
||||
}
|
||||
|
||||
void ShadowEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
|
||||
{
|
||||
if( useShadow( w ))
|
||||
{
|
||||
data.mask |= PAINT_WINDOW_TRANSLUCENT;
|
||||
QRect r = ( QRegion( w->geometry()) & data.paint ).boundingRect();
|
||||
if( !r.isEmpty())
|
||||
data.paint |= shadowRectangle( r );
|
||||
data.paint |= shadowRectangle( data.paint.boundingRect() );
|
||||
}
|
||||
effects->prePaintWindow( w, data, time );
|
||||
}
|
||||
|
||||
void ShadowEffect::paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
|
||||
void ShadowEffect::drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data )
|
||||
{
|
||||
// Whether the shadow drawing can be delayed or not.
|
||||
bool optimize = !( mask & ( PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED |
|
||||
PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS | PAINT_WINDOW_TRANSLUCENT ));
|
||||
if( !optimize )
|
||||
{
|
||||
// Transformed or translucent windows are drawn bottom-to-top, so
|
||||
// first we need to draw all queued shadows.
|
||||
drawQueuedShadows( w );
|
||||
}
|
||||
if( useShadow( w ))
|
||||
drawShadow( w, mask, region, data );
|
||||
effects->paintWindow( w, mask, region, data );
|
||||
{
|
||||
if( !optimize )
|
||||
{
|
||||
// For translucent windows, shadow needs to be drawn before the
|
||||
// window itself.
|
||||
drawShadow( w, mask, region, data, false );
|
||||
}
|
||||
else
|
||||
{
|
||||
// For opaque windows, just schedule the shadow to be drawn later
|
||||
ShadowData d(w, data);
|
||||
d.clip = w->shape().translated( w->x(), w->y());
|
||||
if( !shadowDatas.isEmpty())
|
||||
d.clip |= shadowDatas.last().clip;
|
||||
d.mask = mask;
|
||||
foreach(QRect r, region.rects())
|
||||
d.region |= shadowRectangle(r);
|
||||
d.region &= region;
|
||||
shadowDatas.append(d);
|
||||
}
|
||||
}
|
||||
|
||||
effects->drawWindow( w, mask, region, data );
|
||||
}
|
||||
|
||||
void ShadowEffect::postPaintWindow( EffectWindow* w )
|
||||
{
|
||||
effects->postPaintWindow( w );
|
||||
}
|
||||
|
||||
QRect ShadowEffect::transformWindowDamage( EffectWindow* w, const QRect& r )
|
||||
{
|
||||
if( !useShadow( w ))
|
||||
return effects->transformWindowDamage( w, r );
|
||||
QRect r2 = r | shadowRectangle( r );
|
||||
return effects->transformWindowDamage( w, r2 );
|
||||
}
|
||||
|
||||
void ShadowEffect::windowClosed( EffectWindow* c )
|
||||
{
|
||||
effects->addRepaint( shadowRectangle( c->geometry() ));
|
||||
|
@ -102,10 +127,28 @@ void ShadowEffect::addQuadVertices(QVector<float>& verts, float x1, float y1, fl
|
|||
verts << x2 << y1;
|
||||
}
|
||||
|
||||
void ShadowEffect::drawShadow( EffectWindow* window, int mask, QRegion region, WindowPaintData& data )
|
||||
void ShadowEffect::drawQueuedShadows( EffectWindow* behindWindow )
|
||||
{
|
||||
QList<ShadowData> newShadowDatas;
|
||||
EffectWindowList stack = effects->stackingOrder();
|
||||
foreach( ShadowData d, shadowDatas )
|
||||
{
|
||||
// If behindWindow is given then only render shadows of the windows
|
||||
// that are behind that window.
|
||||
if( !behindWindow || stack.indexOf(d.w) < stack.indexOf(behindWindow))
|
||||
{
|
||||
drawShadow( d.w, d.mask, d.region.subtracted( d.clip ), d.data, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
newShadowDatas.append(d);
|
||||
}
|
||||
}
|
||||
shadowDatas = newShadowDatas;
|
||||
}
|
||||
|
||||
void ShadowEffect::drawShadow( EffectWindow* window, int mask, QRegion region, WindowPaintData& data, bool clip )
|
||||
{
|
||||
if(( mask & PAINT_WINDOW_TRANSLUCENT ) == 0 )
|
||||
return;
|
||||
glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT );
|
||||
glEnable( GL_BLEND );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
|
@ -168,7 +211,10 @@ void ShadowEffect::drawShadow( EffectWindow* window, int mask, QRegion region, W
|
|||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
// We have two elements per vertex in the verts array
|
||||
int verticesCount = verts.count() / 2;
|
||||
renderGLGeometry( mask, region, verticesCount, verts.data(), texcoords.data() );
|
||||
if( clip )
|
||||
renderGLGeometry( true, region, verticesCount, verts.data(), texcoords.data() );
|
||||
else
|
||||
renderGLGeometry( mask, region, verticesCount, verts.data(), texcoords.data() );
|
||||
mShadowTexture->unbind();
|
||||
|
||||
glPopMatrix();
|
||||
|
|
|
@ -35,16 +35,16 @@ class ShadowEffect
|
|||
public:
|
||||
ShadowEffect();
|
||||
virtual void prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time );
|
||||
virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
|
||||
virtual void postPaintWindow( EffectWindow* w );
|
||||
virtual QRect transformWindowDamage( EffectWindow* w, const QRect& r );
|
||||
virtual void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
|
||||
virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data );
|
||||
virtual void windowClosed( EffectWindow* c );
|
||||
private:
|
||||
void drawShadow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
|
||||
void drawShadow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data, bool clip );
|
||||
void addQuadVertices(QVector<float>& verts, float x1, float y1, float x2, float y2) const;
|
||||
// transforms window rect -> shadow rect
|
||||
QRect shadowRectangle(const QRect& windowRectangle) const;
|
||||
bool useShadow( EffectWindow* w ) const;
|
||||
void drawQueuedShadows( EffectWindow* behindWindow );
|
||||
|
||||
int shadowXOffset, shadowYOffset;
|
||||
double shadowOpacity;
|
||||
|
@ -52,6 +52,18 @@ class ShadowEffect
|
|||
int shadowSize;
|
||||
bool intensifyActiveShadow;
|
||||
GLTexture* mShadowTexture;
|
||||
|
||||
struct ShadowData
|
||||
{
|
||||
ShadowData(EffectWindow* _w, WindowPaintData& _data) : w(_w), data(_data) {}
|
||||
EffectWindow* w;
|
||||
QRegion clip;
|
||||
int mask;
|
||||
QRegion region;
|
||||
WindowPaintData data;
|
||||
};
|
||||
|
||||
QList<ShadowData> shadowDatas;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
Loading…
Reference in a new issue