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:
Rivo Laks 2007-12-08 16:24:48 +00:00
parent 881fd48854
commit 864dea425e
2 changed files with 86 additions and 28 deletions

View file

@ -52,36 +52,61 @@ QRect ShadowEffect::shadowRectangle(const QRect& windowRectangle) const
shadowXOffset + shadowGrow, shadowYOffset + shadowGrow); 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 ) void ShadowEffect::prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time )
{ {
if( useShadow( w )) if( useShadow( w ))
{ {
data.mask |= PAINT_WINDOW_TRANSLUCENT; data.paint |= shadowRectangle( data.paint.boundingRect() );
QRect r = ( QRegion( w->geometry()) & data.paint ).boundingRect();
if( !r.isEmpty())
data.paint |= shadowRectangle( r );
} }
effects->prePaintWindow( w, data, time ); 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 )) 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);
}
} }
void ShadowEffect::postPaintWindow( EffectWindow* w ) effects->drawWindow( w, mask, region, data );
{
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 ) void ShadowEffect::windowClosed( EffectWindow* c )
@ -102,10 +127,28 @@ void ShadowEffect::addQuadVertices(QVector<float>& verts, float x1, float y1, fl
verts << x2 << y1; 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 ); glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT );
glEnable( GL_BLEND ); glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
@ -168,6 +211,9 @@ void ShadowEffect::drawShadow( EffectWindow* window, int mask, QRegion region, W
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
// We have two elements per vertex in the verts array // We have two elements per vertex in the verts array
int verticesCount = verts.count() / 2; int verticesCount = verts.count() / 2;
if( clip )
renderGLGeometry( true, region, verticesCount, verts.data(), texcoords.data() );
else
renderGLGeometry( mask, region, verticesCount, verts.data(), texcoords.data() ); renderGLGeometry( mask, region, verticesCount, verts.data(), texcoords.data() );
mShadowTexture->unbind(); mShadowTexture->unbind();

View file

@ -35,16 +35,16 @@ class ShadowEffect
public: public:
ShadowEffect(); ShadowEffect();
virtual void prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time ); virtual void prePaintWindow( EffectWindow* w, WindowPrePaintData& data, int time );
virtual void paintWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); virtual void drawWindow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data );
virtual void postPaintWindow( EffectWindow* w ); virtual void paintScreen( int mask, QRegion region, ScreenPaintData& data );
virtual QRect transformWindowDamage( EffectWindow* w, const QRect& r );
virtual void windowClosed( EffectWindow* c ); virtual void windowClosed( EffectWindow* c );
private: 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; void addQuadVertices(QVector<float>& verts, float x1, float y1, float x2, float y2) const;
// transforms window rect -> shadow rect // transforms window rect -> shadow rect
QRect shadowRectangle(const QRect& windowRectangle) const; QRect shadowRectangle(const QRect& windowRectangle) const;
bool useShadow( EffectWindow* w ) const; bool useShadow( EffectWindow* w ) const;
void drawQueuedShadows( EffectWindow* behindWindow );
int shadowXOffset, shadowYOffset; int shadowXOffset, shadowYOffset;
double shadowOpacity; double shadowOpacity;
@ -52,6 +52,18 @@ class ShadowEffect
int shadowSize; int shadowSize;
bool intensifyActiveShadow; bool intensifyActiveShadow;
GLTexture* mShadowTexture; 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 } // namespace