From bc137cca3b1cb32d158ea1ef6561bac9d7c4f083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Fri, 6 Jun 2008 09:26:41 +0000 Subject: [PATCH] =?UTF-8?q?Implement=20missing=20shadows=20in=20XRender=20?= =?UTF-8?q?mode,=20patch=20from=20Thomas=20L=C3=BCbking.=20BUG:=20153144?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit svn path=/trunk/KDE/kdebase/workspace/; revision=817553 --- effects/shadow.cpp | 294 +++++++++++++++++++++++++++++++++++---------- effects/shadow.h | 13 +- 2 files changed, 241 insertions(+), 66 deletions(-) diff --git a/effects/shadow.cpp b/effects/shadow.cpp index a9eb5ee94c..7277df2f57 100644 --- a/effects/shadow.cpp +++ b/effects/shadow.cpp @@ -28,12 +28,51 @@ along with this program. If not, see . #include #include #include +#ifdef KWIN_HAVE_XRENDER_COMPOSITING +#include +#endif + +#include namespace KWin { KWIN_EFFECT( shadow, ShadowEffect ) +ShadowTiles::ShadowTiles(const QPixmap& shadow) + { + int w = shadow.width() / 2, h = shadow.height() / 2; + cornerSize = QSize(w, h); +#define DUMP_CNR(_TILE_, _W_, _H_, _XOFF_, _YOFF_)\ + dump = QPixmap(_W_, _H_);\ + dump.fill(Qt::transparent);\ + p.begin(&dump);\ + p.drawPixmap( 0, 0, shadow, _XOFF_, _YOFF_, _W_, _H_ );\ + p.end();\ + _TILE_ = dump + + QPixmap dump; QPainter p; + DUMP_CNR(topLeft, w, h, 0, 0); + DUMP_CNR(topRight, w, h, w, 0); + DUMP_CNR(btmLeft, w, h, 0, h); + DUMP_CNR(btmRight, w, h, w, h); + + XRenderPictureAttributes pa; pa.repeat = True; +#define DUMP_TILE(_TILE_, _W_, _H_, _XOFF_, _YOFF_)\ + DUMP_CNR(_TILE_, _W_, _H_, _XOFF_, _YOFF_);\ + XRenderChangePicture (display(), _TILE_, CPRepeat, &pa) + + DUMP_TILE(top, 1, h, w, 0); + DUMP_TILE(btm, 1, h, w, h); + DUMP_TILE(left, w, 1, 0, h); + DUMP_TILE(right, w, 1, w, h); + + DUMP_TILE(center, 1, 1, w, h); + } + +#undef DUMP_CNR +#undef DUMP_TILE + ShadowEffect::ShadowEffect() { KConfigGroup conf = effects->effectConfig("Shadow"); @@ -43,9 +82,40 @@ ShadowEffect::ShadowEffect() shadowFuzzyness = conf.readEntry( "Fuzzyness", 10 ); shadowSize = conf.readEntry( "Size", 5 ); intensifyActiveShadow = conf.readEntry( "IntensifyActiveShadow", true ); +#ifdef KWIN_HAVE_OPENGL_COMPOSITING + if ( effects->compositingType() == OpenGLCompositing) + { + QString shadowtexture = KGlobal::dirs()->findResource("data", "kwin/shadow-texture.png"); + mShadowTexture = new GLTexture(shadowtexture); + } + else + mShadowTexture = NULL; +#endif +#ifdef KWIN_HAVE_XRENDER_COMPOSITING + if ( effects->compositingType() == XRenderCompositing) + { + qreal size = 2*(shadowFuzzyness+shadowSize)+1; + QPixmap *shadow = new QPixmap(size, size); shadow->fill(Qt::transparent); + size /= 2.0; + QRadialGradient rg(size, size, size); + QColor c(0,0,0,255); + rg.setColorAt(0, c); + c.setAlpha(0.3*c.alpha()); + if (shadowSize > 0) + rg.setColorAt(((float)shadowSize)/(shadowFuzzyness+shadowSize), c); + c.setAlpha(0); rg.setColorAt(0.8, c); + QPainter p(shadow); + p.setRenderHint(QPainter::Antialiasing); + p.setPen(Qt::NoPen); p.setBrush(rg); + p.drawRect(shadow->rect()); + p.end(); - QString shadowtexture = KGlobal::dirs()->findResource("data", "kwin/shadow-texture.png"); - mShadowTexture = new GLTexture(shadowtexture); + mShadowPics = new ShadowTiles(*shadow); + delete shadow; + } + else + mShadowPics = NULL; +#endif updateShadowColor(); connect(KGlobalSettings::self(), SIGNAL(kdisplayPaletteChanged()), @@ -54,7 +124,12 @@ ShadowEffect::ShadowEffect() ShadowEffect::~ShadowEffect() { +#ifdef KWIN_HAVE_OPENGL_COMPOSITING delete mShadowTexture; +#endif +#ifdef KWIN_HAVE_XRENDER_COMPOSITING + delete mShadowPics; +#endif } void ShadowEffect::updateShadowColor() @@ -70,10 +145,23 @@ QRect ShadowEffect::shadowRectangle(const QRect& windowRectangle) const shadowXOffset + shadowGrow, shadowYOffset + shadowGrow); } +#ifdef KWIN_HAVE_XRENDER_COMPOSITING +static ScreenPaintData gScreenData; +#endif + void ShadowEffect::paintScreen( int mask, QRegion region, ScreenPaintData& data ) { shadowDatas.clear(); - +#ifdef KWIN_HAVE_XRENDER_COMPOSITING + if ((mask & PAINT_SCREEN_TRANSFORMED) && + (effects->compositingType() == XRenderCompositing)) // TODO: copy constructor? + { + gScreenData.xTranslate = data.xTranslate; + gScreenData.yTranslate = data.yTranslate; + gScreenData.xScale = data.xScale; + gScreenData.yScale = data.yScale; + } +#endif // Draw windows effects->paintScreen( mask, region, data ); @@ -177,73 +265,149 @@ void ShadowEffect::drawQueuedShadows( EffectWindow* behindWindow ) void ShadowEffect::drawShadow( EffectWindow* window, int mask, QRegion region, WindowPaintData& data ) { - glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT ); - glEnable( GL_BLEND ); - glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); +#ifdef KWIN_HAVE_OPENGL_COMPOSITING + if( effects->compositingType() == OpenGLCompositing) + { + glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT ); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); - int fuzzy = shadowFuzzyness; - // Shadow's size must be a least 2*fuzzy in both directions (or the corners will be broken) - int w = qMax(fuzzy*2, window->width() + 2*shadowSize); - int h = qMax(fuzzy*2, window->height() + 2*shadowSize); + int fuzzy = shadowFuzzyness; + // Shadow's size must be a least 2*fuzzy in both directions (or the corners will be broken) + int w = qMax(fuzzy*2, window->width() + 2*shadowSize); + int h = qMax(fuzzy*2, window->height() + 2*shadowSize); - glPushMatrix(); - if( mask & PAINT_WINDOW_TRANSFORMED ) - glTranslatef( data.xTranslate, data.yTranslate, 0 ); - glTranslatef( window->x() + shadowXOffset - qMax(0, w - window->width()) / 2.0, - window->y() + shadowYOffset - qMax(0, h - window->height()) / 2.0, 0 ); - if(( mask & PAINT_WINDOW_TRANSFORMED ) && ( data.xScale != 1 || data.yScale != 1 )) - glScalef( data.xScale, data.yScale, 1 ); + glPushMatrix(); + if( mask & PAINT_WINDOW_TRANSFORMED ) + glTranslatef( data.xTranslate, data.yTranslate, 0 ); + glTranslatef( window->x() + shadowXOffset - qMax(0, w - window->width()) / 2.0, + window->y() + shadowYOffset - qMax(0, h - window->height()) / 2.0, 0 ); + if(( mask & PAINT_WINDOW_TRANSFORMED ) && ( data.xScale != 1 || data.yScale != 1 )) + glScalef( data.xScale, data.yScale, 1 ); - QVector verts, texcoords; - verts.reserve(80); - texcoords.reserve(80); - // center - addQuadVertices(verts, 0 + fuzzy, 0 + fuzzy, w - fuzzy, h - fuzzy); - addQuadVertices(texcoords, 0.5, 0.5, 0.5, 0.5); - // sides - // left - addQuadVertices(verts, 0 - fuzzy, 0 + fuzzy, 0 + fuzzy, h - fuzzy); - addQuadVertices(texcoords, 0.0, 0.5, 0.5, 0.5); - // top - addQuadVertices(verts, 0 + fuzzy, 0 - fuzzy, w - fuzzy, 0 + fuzzy); - addQuadVertices(texcoords, 0.5, 0.0, 0.5, 0.5); - // right - addQuadVertices(verts, w - fuzzy, 0 + fuzzy, w + fuzzy, h - fuzzy); - addQuadVertices(texcoords, 0.5, 0.5, 1.0, 0.5); - // bottom - addQuadVertices(verts, 0 + fuzzy, h - fuzzy, w - fuzzy, h + fuzzy); - addQuadVertices(texcoords, 0.5, 0.5, 0.5, 1.0); - // corners - // top-left - addQuadVertices(verts, 0 - fuzzy, 0 - fuzzy, 0 + fuzzy, 0 + fuzzy); - addQuadVertices(texcoords, 0.0, 0.0, 0.5, 0.5); - // top-right - addQuadVertices(verts, w - fuzzy, 0 - fuzzy, w + fuzzy, 0 + fuzzy); - addQuadVertices(texcoords, 0.5, 0.0, 1.0, 0.5); - // bottom-left - addQuadVertices(verts, 0 - fuzzy, h - fuzzy, 0 + fuzzy, h + fuzzy); - addQuadVertices(texcoords, 0.0, 0.5, 0.5, 1.0); - // bottom-right - addQuadVertices(verts, w - fuzzy, h - fuzzy, w + fuzzy, h + fuzzy); - addQuadVertices(texcoords, 0.5, 0.5, 1.0, 1.0); + QVector verts, texcoords; + verts.reserve(80); + texcoords.reserve(80); + // center + addQuadVertices(verts, 0 + fuzzy, 0 + fuzzy, w - fuzzy, h - fuzzy); + addQuadVertices(texcoords, 0.5, 0.5, 0.5, 0.5); + // sides + // left + addQuadVertices(verts, 0 - fuzzy, 0 + fuzzy, 0 + fuzzy, h - fuzzy); + addQuadVertices(texcoords, 0.0, 0.5, 0.5, 0.5); + // top + addQuadVertices(verts, 0 + fuzzy, 0 - fuzzy, w - fuzzy, 0 + fuzzy); + addQuadVertices(texcoords, 0.5, 0.0, 0.5, 0.5); + // right + addQuadVertices(verts, w - fuzzy, 0 + fuzzy, w + fuzzy, h - fuzzy); + addQuadVertices(texcoords, 0.5, 0.5, 1.0, 0.5); + // bottom + addQuadVertices(verts, 0 + fuzzy, h - fuzzy, w - fuzzy, h + fuzzy); + addQuadVertices(texcoords, 0.5, 0.5, 0.5, 1.0); + // corners + // top-left + addQuadVertices(verts, 0 - fuzzy, 0 - fuzzy, 0 + fuzzy, 0 + fuzzy); + addQuadVertices(texcoords, 0.0, 0.0, 0.5, 0.5); + // top-right + addQuadVertices(verts, w - fuzzy, 0 - fuzzy, w + fuzzy, 0 + fuzzy); + addQuadVertices(texcoords, 0.5, 0.0, 1.0, 0.5); + // bottom-left + addQuadVertices(verts, 0 - fuzzy, h - fuzzy, 0 + fuzzy, h + fuzzy); + addQuadVertices(texcoords, 0.0, 0.5, 0.5, 1.0); + // bottom-right + addQuadVertices(verts, w - fuzzy, h - fuzzy, w + fuzzy, h + fuzzy); + addQuadVertices(texcoords, 0.5, 0.5, 1.0, 1.0); - mShadowTexture->bind(); - // Take the transparency settings and window's transparency into account. - // Also make the shadow more transparent if we've made it bigger - float opacity = shadowOpacity; - if( intensifyActiveShadow && window == effects->activeWindow() ) - { - opacity = 1 - (1 - shadowOpacity)*(1 - shadowOpacity); - } - glColor4f(shadowColor.redF(), shadowColor.greenF(), shadowColor.blueF(), opacity * data.opacity * (window->width() / (double)w) * (window->height() / (double)h)); - 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( region, verticesCount, verts.data(), texcoords.data() ); - mShadowTexture->unbind(); + mShadowTexture->bind(); + // Take the transparency settings and window's transparency into account. + // Also make the shadow more transparent if we've made it bigger + float opacity = shadowOpacity; + if( intensifyActiveShadow && window == effects->activeWindow() ) + { + opacity = 1 - (1 - shadowOpacity)*(1 - shadowOpacity); + } + glColor4f(shadowColor.redF(), shadowColor.greenF(), shadowColor.blueF(), opacity * data.opacity * (window->width() / (double)w) * (window->height() / (double)h)); + 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( region, verticesCount, verts.data(), texcoords.data() ); + mShadowTexture->unbind(); - glPopMatrix(); - glPopAttrib(); + glPopMatrix(); + glPopAttrib(); + } +#endif +#ifdef KWIN_HAVE_XRENDER_COMPOSITING + if( effects->compositingType() == XRenderCompositing) + { + // calculate opacity ================================================= + float opacity; + if( intensifyActiveShadow && window == effects->activeWindow() ) + { + opacity = (1 - (1 - shadowOpacity)*(1 - shadowOpacity)) * data.opacity; + } + else + { + opacity = data.opacity * shadowOpacity; + } + + // query rect and translate in case (may have impact on opacity)=========================== + QRect r = window->geometry(); + if ( mask & (PAINT_WINDOW_TRANSFORMED | PAINT_SCREEN_TRANSFORMED)) + { + float xScale = 1.0, yScale = 1.0, xTranslate = 0.0, yTranslate = 0.0; + if ( mask & PAINT_SCREEN_TRANSFORMED) + { + xScale = gScreenData.xScale; yScale = gScreenData.yScale; + xTranslate += (xScale-1.0)*r.x() + gScreenData.xTranslate; + yTranslate += (yScale-1.0)*r.y() + gScreenData.yTranslate; + } + + if ( mask & PAINT_WINDOW_TRANSFORMED) + { + xTranslate += xScale*data.xTranslate; + yTranslate += yScale*data.yTranslate; + xScale *= data.xScale; yScale *= data.yScale; + } + + r.translate(xTranslate, yTranslate); + + if (xScale != 1.0 || yScale != 1.0) + { + r.setWidth(xScale * r.width()); + r.setHeight(yScale * r.height()); +// opacity *= 2.0/(2 - (2 - (xScale + yScale))*(2 - (xScale + yScale))); + } + } + r = shadowRectangle(r); + + // create render mask ================================================================== + + XRenderColor xc = preMultiply(shadowColor, opacity); + XRenderPicture fill = xRenderFill(&xc); + + // clip, then paint shadow tiles ======================================================== + XRenderSetPictureClipRegion (display(), effects->xrenderBufferPicture(), region.handle()); +#define DRAW_CORNER(_CNR_, _X_, _Y_)\ +XRenderComposite( display(), PictOpOver, fill, mShadowPics->_CNR_, effects->xrenderBufferPicture(), 0, 0, 0, 0, _X_, _Y_, w, h ) +#define DRAW_TILE(_TILE_, _X_, _Y_, _W_, _H_)\ +XRenderComposite( display(), PictOpOver, fill, mShadowPics->_TILE_, effects->xrenderBufferPicture(), 0, 0, 0, 0, _X_, _Y_, _W_, _H_ ) + int w = qMin(mShadowPics->cornerSize.width(), r.width()/2); + int h = qMin(mShadowPics->cornerSize.height(), r.height()/2); + DRAW_CORNER(topLeft, r.x(), r.y()); + DRAW_CORNER(topRight, r.right()-w, r.y()); + DRAW_CORNER(btmLeft, r.x(), r.bottom()-h); + DRAW_CORNER(btmRight, r.right()-w, r.bottom()-h); + int w2 = r.width()-2*w-1, h2 = r.height()-2*h-1; + DRAW_TILE(top, r.x()+w, r.y(), w2, h); + DRAW_TILE(btm, r.x()+w, r.bottom()-h, w2, h); + DRAW_TILE(left, r.x(), r.y()+h, w, h2); + DRAW_TILE(right, r.right()-w, r.y()+h, w, h2); + DRAW_TILE(center, r.x()+w, r.y()+h, w2, h2); +#undef DRAW_CORNER +#undef DRAW_TILE + } +#endif } } // namespace diff --git a/effects/shadow.h b/effects/shadow.h index 32269a4b9d..4617a6b25f 100644 --- a/effects/shadow.h +++ b/effects/shadow.h @@ -22,13 +22,23 @@ along with this program. If not, see . #define KWIN_SHADOW_H #include - +#include namespace KWin { class GLTexture; +class ShadowTiles + { + public: + ShadowTiles(const QPixmap& shadow); + XRenderPicture topLeft, top, topRight, + left, center, right, + btmLeft, btm, btmRight; + QSize cornerSize; + }; + class ShadowEffect : public QObject, public Effect { @@ -60,6 +70,7 @@ class ShadowEffect bool intensifyActiveShadow; QColor shadowColor; GLTexture* mShadowTexture; + ShadowTiles *mShadowPics; struct ShadowData {