--Boundary-00=_tx5mHAPsQKX0r4n Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Hello, I'd like to commit the attached patch, but I'd like to get comments on it first. The patch basically adds class PaintClipper that can be used to specify the area where it's allowed to paint, and these add up (or, rather, intersect). It fixes the bug with DesktopGrid where an overlapped window can be sometimes seen even on desktops where it's not (a desktop with smaller number). Since neither glScissor nor XFixesSetPictureClipRegion() can be stacked, there could be a problem with possible multiple clipping. Actually, I could simply use it here, because the rest is painted transformed and as such not clipped, but maybe there can be such cases. The patch is a bit bigger because I had to move few things around, but the important parts are the PaintClipper class, the parts in magnifier.cpp/desktopgrid.cpp and in renderGLGeometry(), those should be enough to get the idea. Shortly, every clipping is specified using PaintClipper, it's used when painting anything and there no longer is a flag for 'clip', as there's always clipping, with e.g. transformed screen the clipping is done by infiniteRegion(). The thing I'm wondering is whether it's worth it. I have no idea how big performance impact has the increased use of glScissor(). I'm also not sure there actually realistically can happen cases where multiple clipping would be needed - basically, currently we can't do very complicated stacked transformations, because they'd probably break something (including PaintClipper presumably). Opinions, comments? -- Lubos Lunak KDE developer -------------------------------------------------------------- SUSE LINUX, s.r.o. e-mail: l.lunak@suse.cz , l.lunak@kde.org Lihovarska 1060/12 tel: +420 284 028 972 190 00 Prague 9 fax: +420 284 028 951 Czech Republic http//www.suse.cz --Boundary-00=_tx5mHAPsQKX0r4n Content-Type: text/x-diff; charset="us-ascii"; name="kwin.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="kwin.patch" Index: kwin/effects/shadow.cpp =================================================================== --- kwin/effects/shadow.cpp (revision 766576) +++ kwin/effects/shadow.cpp (working copy) @@ -89,7 +89,7 @@ { // For translucent windows, shadow needs to be drawn before the // window itself. - drawShadow( w, mask, region, data, false ); + drawShadow( w, mask, region, data ); } else { @@ -145,7 +145,7 @@ // 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 ); + drawShadow( d.w, d.mask, d.region.subtracted( d.clip ), d.data ); } else { @@ -155,7 +155,7 @@ shadowDatas = newShadowDatas; } -void ShadowEffect::drawShadow( EffectWindow* window, int mask, QRegion region, WindowPaintData& data, bool clip ) +void ShadowEffect::drawShadow( EffectWindow* window, int mask, QRegion region, WindowPaintData& data ) { glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT ); glEnable( GL_BLEND ); @@ -219,10 +219,7 @@ 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; - if( clip ) - renderGLGeometry( true, region, verticesCount, verts.data(), texcoords.data() ); - else - renderGLGeometry( mask, region, verticesCount, verts.data(), texcoords.data() ); + renderGLGeometry( region, verticesCount, verts.data(), texcoords.data() ); mShadowTexture->unbind(); glPopMatrix(); Index: kwin/effects/snow.cpp =================================================================== --- kwin/effects/snow.cpp (revision 766576) +++ kwin/effects/snow.cpp (working copy) @@ -142,7 +142,7 @@ glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); for (int i=0; icount(); i++) { - texture->render( false, region, flakes->at(i)); + texture->render( region, flakes->at(i)); } texture->unbind(); glPopAttrib(); Index: kwin/effects/presentwindows.cpp =================================================================== --- kwin/effects/presentwindows.cpp (revision 766576) +++ kwin/effects/presentwindows.cpp (working copy) @@ -149,7 +149,7 @@ renderRoundBoxWithEdge( filterFrameRect ); // And then the text on top of it filterTexture->bind(); - filterTexture->render( mask, region, filterTextureRect ); + filterTexture->render( region, filterTextureRect ); filterTexture->unbind(); glPopAttrib(); } Index: kwin/effects/shadow.h =================================================================== --- kwin/effects/shadow.h (revision 766576) +++ kwin/effects/shadow.h (working copy) @@ -40,7 +40,7 @@ virtual void windowClosed( EffectWindow* c ); virtual QRect transformWindowDamage( EffectWindow* w, const QRect& r ); private: - void drawShadow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data, bool clip ); + void drawShadow( EffectWindow* w, int mask, QRegion region, WindowPaintData& data ); void addQuadVertices(QVector& verts, float x1, float y1, float x2, float y2) const; // transforms window rect -> shadow rect QRect shadowRectangle(const QRect& windowRectangle) const; Index: kwin/effects/magnifier.cpp =================================================================== --- kwin/effects/magnifier.cpp (revision 766576) +++ kwin/effects/magnifier.cpp (working copy) @@ -81,13 +81,8 @@ effects->paintScreen( mask, region, data ); // paint normal screen if( zoom != 1.0 ) { // paint magnifier -// ## TODO this should be inside KWIN_HAVE_OPENGL_COMPOSITING - glPushAttrib( GL_ENABLE_BIT ); QRect area = magnifierArea(); - glEnable( GL_SCISSOR_TEST ); - int dh = displayHeight(); - // Scissor rect has to be given in OpenGL coords - glScissor( area.x(), dh - area.y() - area.height(), area.width(), area.height()); + PaintClipper::push( area ); // don't allow any painting outside of the area mask |= PAINT_SCREEN_TRANSFORMED; data2.xScale *= zoom; data2.yScale *= zoom; @@ -96,27 +91,33 @@ data2.xTranslate = - int( cursor.x() * ( zoom - 1 )); data2.yTranslate = - int( cursor.y() * ( zoom - 1 )); effects->paintScreen( mask, region, data2 ); - glPopAttrib(); + PaintClipper::pop( area ); +// ## TODO this should be inside KWIN_HAVE_OPENGL_COMPOSITING glPushAttrib( GL_CURRENT_BIT ); glColor4f( 0, 0, 0, 1 ); // black - glBegin( GL_QUADS ); - glVertex2i( area.left() - FRAME_WIDTH, area.top() - FRAME_WIDTH ); // top frame - glVertex2i( area.right() + FRAME_WIDTH, area.top() - FRAME_WIDTH ); - glVertex2i( area.right() + FRAME_WIDTH, area.top() - 1 ); - glVertex2i( area.left() - FRAME_WIDTH, area.top() - 1 ); - glVertex2i( area.left() - FRAME_WIDTH, area.top() - FRAME_WIDTH ); // left frame - glVertex2i( area.left() - 1, area.top() - FRAME_WIDTH ); - glVertex2i( area.left() - 1, area.bottom() + FRAME_WIDTH ); - glVertex2i( area.left() - FRAME_WIDTH, area.bottom() + FRAME_WIDTH ); - glVertex2i( area.right() + 1, area.top() - FRAME_WIDTH ); // right frame - glVertex2i( area.right() + FRAME_WIDTH, area.top() - FRAME_WIDTH ); - glVertex2i( area.right() + FRAME_WIDTH, area.bottom() + FRAME_WIDTH ); - glVertex2i( area.right() + 1, area.bottom() + FRAME_WIDTH ); - glVertex2i( area.left() - FRAME_WIDTH, area.bottom() + 1 ); // bottom frame - glVertex2i( area.right() + FRAME_WIDTH, area.bottom() + 1 ); - glVertex2i( area.right() + FRAME_WIDTH, area.bottom() + FRAME_WIDTH ); - glVertex2i( area.left() - FRAME_WIDTH, area.bottom() + FRAME_WIDTH ); - glEnd(); + for( PaintClipper::Iterator iterator; + !iterator.isDone(); + iterator.next()) + { + glBegin( GL_QUADS ); + glVertex2i( area.left() - FRAME_WIDTH, area.top() - FRAME_WIDTH ); // top frame + glVertex2i( area.right() + FRAME_WIDTH, area.top() - FRAME_WIDTH ); + glVertex2i( area.right() + FRAME_WIDTH, area.top() - 1 ); + glVertex2i( area.left() - FRAME_WIDTH, area.top() - 1 ); + glVertex2i( area.left() - FRAME_WIDTH, area.top() - FRAME_WIDTH ); // left frame + glVertex2i( area.left() - 1, area.top() - FRAME_WIDTH ); + glVertex2i( area.left() - 1, area.bottom() + FRAME_WIDTH ); + glVertex2i( area.left() - FRAME_WIDTH, area.bottom() + FRAME_WIDTH ); + glVertex2i( area.right() + 1, area.top() - FRAME_WIDTH ); // right frame + glVertex2i( area.right() + FRAME_WIDTH, area.top() - FRAME_WIDTH ); + glVertex2i( area.right() + FRAME_WIDTH, area.bottom() + FRAME_WIDTH ); + glVertex2i( area.right() + 1, area.bottom() + FRAME_WIDTH ); + glVertex2i( area.left() - FRAME_WIDTH, area.bottom() + 1 ); // bottom frame + glVertex2i( area.right() + FRAME_WIDTH, area.bottom() + 1 ); + glVertex2i( area.right() + FRAME_WIDTH, area.bottom() + FRAME_WIDTH ); + glVertex2i( area.left() - FRAME_WIDTH, area.bottom() + FRAME_WIDTH ); + glEnd(); + } glPopAttrib(); } } Index: kwin/effects/flipswitch.cpp =================================================================== --- kwin/effects/flipswitch.cpp (revision 766576) +++ kwin/effects/flipswitch.cpp (working copy) @@ -363,7 +363,7 @@ frameRect.y() + frameRect.height()*0.1f, frameRect.height()*0.8f, frameRect.height()*0.8f ); - icon->render( false, region, iconRect); + icon->render( region, iconRect); icon->unbind(); glPopAttrib(); #endif Index: kwin/effects/trackmouse.cpp =================================================================== --- kwin/effects/trackmouse.cpp (revision 766576) +++ kwin/effects/trackmouse.cpp (working copy) @@ -77,7 +77,7 @@ ++i ) { QRect r = starRect( i ); - texture->render( mask, region, r ); + texture->render( region, r ); } texture->unbind(); glPopAttrib(); Index: kwin/effects/desktopgrid.cpp =================================================================== --- kwin/effects/desktopgrid.cpp (revision 766576) +++ kwin/effects/desktopgrid.cpp (working copy) @@ -137,11 +137,19 @@ ++desktop ) { if( desktop != desktop_with_move ) + { + PaintClipper pc( desktopRect( desktop, true )); paintScreenDesktop( desktop, mask, region, data ); + } } // paint the desktop with the window being moved as the last one, i.e. on top of others if( desktop_with_move != -1 ) + { + QRegion paintreg = desktopRect( desktop_with_move, true ); // paint only the desktop + paintreg |= windowRect( window_move ); // and wherever the moved window is + PaintClipper pc( paintreg ); paintScreenDesktop( desktop_with_move, mask, region, data ); + } } void DesktopGridEffect::paintScreenDesktop( int desktop, int mask, QRegion region, ScreenPaintData data ) Index: kwin/scene.h =================================================================== --- kwin/scene.h (revision 766576) +++ kwin/scene.h (working copy) @@ -105,8 +105,6 @@ virtual void paintWindow( Window* w, int mask, QRegion region, WindowQuadList quads ); // called after all effects had their drawWindow() called void finalDrawWindow( EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data ); - // infinite region, i.e. everything - static QRegion infiniteRegion(); // compute time since the last repaint void updateTimeDiff(); // saved data for 2nd pass of optimized screen painting @@ -198,12 +196,6 @@ extern Scene* scene; inline -QRegion Scene::infiniteRegion() - { // INT_MIN / 2 because width/height is used (INT_MIN+INT_MAX==-1) - return QRegion( INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX ); - } - -inline int Scene::Window::x() const { return toplevel->x(); Index: kwin/scene.cpp =================================================================== --- kwin/scene.cpp (revision 766576) +++ kwin/scene.cpp (working copy) @@ -135,6 +135,8 @@ *region |= painted_region; // make sure not to go outside of the screen area *region &= QRegion( 0, 0, displayWidth(), displayHeight()); + // make sure all clipping is restored + Q_ASSERT( !PaintClipper::clip()); } // Compute time since the last painting pass. Index: kwin/scene_opengl.cpp =================================================================== --- kwin/scene_opengl.cpp (revision 766576) +++ kwin/scene_opengl.cpp (working copy) @@ -723,22 +723,24 @@ void SceneOpenGL::paintBackground( QRegion region ) { - if( region == infiniteRegion()) + PaintClipper pc( region ); + if( !PaintClipper::clip()) { glClearColor( 0, 0, 0, 1 ); // black glClear( GL_COLOR_BUFFER_BIT ); + return; } - else + glColor4f( 0, 0, 0, 1 ); // black + for( PaintClipper::Iterator iterator; + !iterator.isDone(); + iterator.next()) { - glColor4f( 0, 0, 0, 1 ); // black glBegin( GL_QUADS ); - foreach( QRect r, region.rects()) - { - glVertex2i( r.x(), r.y()); - glVertex2i( r.x() + r.width(), r.y()); - glVertex2i( r.x() + r.width(), r.y() + r.height()); - glVertex2i( r.x(), r.y() + r.height()); - } + QRect r = iterator.boundingRect(); + glVertex2i( r.x(), r.y()); + glVertex2i( r.x() + r.width(), r.y()); + glVertex2i( r.x() + r.width(), r.y() + r.height()); + glVertex2i( r.x(), r.y() + r.height()); glEnd(); } } @@ -1257,7 +1259,7 @@ glPopMatrix(); } -void SceneOpenGL::Window::renderQuads( int mask, const QRegion& region, const WindowQuadList& quads ) +void SceneOpenGL::Window::renderQuads( int, const QRegion& region, const WindowQuadList& quads ) { if( quads.isEmpty()) return; @@ -1265,7 +1267,7 @@ float* vertices; float* texcoords; quads.makeArrays( &vertices, &texcoords ); - renderGLGeometry( mask, region, quads.count() * 4, + renderGLGeometry( region, quads.count() * 4, vertices, texcoords, NULL, 2, 0 ); delete[] vertices; delete[] texcoords; Index: kwin/scene_xrender.cpp =================================================================== --- kwin/scene_xrender.cpp (revision 766576) +++ kwin/scene_xrender.cpp (working copy) @@ -267,15 +267,14 @@ // fill the screen background void SceneXrender::paintBackground( QRegion region ) { - if( region != infiniteRegion()) + PaintClipper pc( region ); + for( PaintClipper::Iterator iterator; + !iterator.isDone(); + iterator.next()) { - XserverRegion background_region = toXserverRegion( region ); - XFixesSetPictureClipRegion( display(), buffer, 0, 0, background_region ); - XFixesDestroyRegion( display(), background_region ); + XRenderColor col = { 0, 0, 0, 0xffff }; // black + XRenderFillRectangle( display(), PictOpSrc, buffer, &col, 0, 0, displayWidth(), displayHeight()); } - XRenderColor col = { 0, 0, 0, 0xffff }; // black - XRenderFillRectangle( display(), PictOpSrc, buffer, &col, 0, 0, displayWidth(), displayHeight()); - XFixesSetPictureClipRegion( display(), buffer, 0, 0, None ); } void SceneXrender::windowGeometryShapeChanged( Toplevel* c ) @@ -326,27 +325,6 @@ c->effectWindow()->setSceneWindow( windows[ c ]); } -// Convert QRegion to XserverRegion. This code uses XserverRegion -// only when really necessary as the shared implementation uses -// QRegion. -XserverRegion SceneXrender::toXserverRegion( QRegion region ) - { - QVector< QRect > rects = region.rects(); - XRectangle* xr = new XRectangle[ rects.count() ]; - for( int i = 0; - i < rects.count(); - ++i ) - { - xr[ i ].x = rects[ i ].x(); - xr[ i ].y = rects[ i ].y(); - xr[ i ].width = rects[ i ].width(); - xr[ i ].height = rects[ i ].height(); - } - XserverRegion ret = XFixesCreateRegion( display(), xr, rects.count()); - delete[] xr; - return ret; - } - //**************************************** // SceneXrender::Window //**************************************** @@ -451,12 +429,6 @@ if( opaque ) return; } - if( region != infiniteRegion()) - { - XserverRegion clip_region = toXserverRegion( region ); - XFixesSetPictureClipRegion( display(), buffer, 0, 0, clip_region ); - XFixesDestroyRegion( display(), clip_region ); - } Picture pic = picture(); // get XRender picture if( pic == None ) // The render format can be null for GL and/or Xv visuals return; @@ -522,18 +494,24 @@ } if( x != toplevel->x() || y != toplevel->y()) transformed_shape.translate( x, y ); - if( opaque ) + PaintClipper pc( region ); + for( PaintClipper::Iterator iterator; + !iterator.isDone(); + iterator.next()) { - XRenderComposite( display(), PictOpSrc, pic, None, buffer, 0, 0, 0, 0, - x, y, width, height); + if( opaque ) + { + XRenderComposite( display(), PictOpSrc, pic, None, buffer, 0, 0, 0, 0, + x, y, width, height); + } + else + { + Picture alpha = alphaMask( data.opacity ); + XRenderComposite( display(), PictOpOver, pic, alpha, buffer, 0, 0, 0, 0, + x, y, width, height); + transformed_shape = QRegion(); + } } - else - { - Picture alpha = alphaMask( data.opacity ); - XRenderComposite( display(), PictOpOver, pic, alpha, buffer, 0, 0, 0, 0, - x, y, width, height); - transformed_shape = QRegion(); - } if( xscale != 1 || yscale != 1 ) { XTransform xform = {{ @@ -545,7 +523,6 @@ if( filter == ImageFilterGood ) XRenderSetPictureFilter( display(), pic, const_cast< char* >( "fast" ), NULL, 0 ); } - XFixesSetPictureClipRegion( display(), buffer, 0, 0, None ); } } // namespace Index: kwin/lib/kwineffects.cpp =================================================================== --- kwin/lib/kwineffects.cpp (revision 766576) +++ kwin/lib/kwineffects.cpp (working copy) @@ -677,4 +677,168 @@ return false; } +/*************************************************************** + PaintClipper +***************************************************************/ + +QStack< QRegion >* PaintClipper::areas = NULL; + +PaintClipper::PaintClipper( const QRegion& allowed_area ) + : area( allowed_area ) + { + push( area ); + } + +PaintClipper::~PaintClipper() + { + pop( area ); + } + +void PaintClipper::push( const QRegion& allowed_area ) + { + if( allowed_area == infiniteRegion()) // don't push these + return; + if( areas == NULL ) + areas = new QStack< QRegion >; + areas->push( allowed_area ); + } + +void PaintClipper::pop( const QRegion& allowed_area ) + { + if( allowed_area == infiniteRegion()) + return; + Q_ASSERT( areas != NULL ); + Q_ASSERT( areas->top() == allowed_area ); + areas->pop(); + if( areas->isEmpty()) + { + delete areas; + areas = NULL; + } + } + +bool PaintClipper::clip() + { + return areas != NULL; + } + +QRegion PaintClipper::paintArea() + { + QRegion ret = QRegion( 0, 0, displayWidth(), displayHeight()); + foreach( QRegion r, *areas ) + ret &= r; + return ret; + } + +struct PaintClipper::Iterator::Data + { + Data() : index( 0 ) {} + int index; +#ifdef KWIN_HAVE_OPENGL_COMPOSITING + QVector< QRect > rects; +#endif + }; + +PaintClipper::Iterator::Iterator() + : data( new Data ) + { +#ifdef KWIN_HAVE_OPENGL_COMPOSITING + if( clip() && effects->compositingType() == OpenGLCompositing ) + { + glPushAttrib( GL_SCISSOR_BIT ); + glEnable( GL_SCISSOR_TEST ); + data->rects = paintArea().rects(); + data->index = -1; + next(); // move to the first one + } +#endif +#ifdef KWIN_HAVE_XRENDER_COMPOSITING + if( clip() && effects->compositingType() == XRenderCompositing ) + { + XserverRegion region = toXserverRegion( paintArea()); + XFixesSetPictureClipRegion( display(), effects->xrenderBufferPicture(), 0, 0, region ); + XFixesDestroyRegion( display(), region ); // it's ref-counted + } +#endif + } + +PaintClipper::Iterator::~Iterator() + { +#ifdef KWIN_HAVE_OPENGL_COMPOSITING + if( clip() && effects->compositingType() == OpenGLCompositing ) + glPopAttrib(); +#endif +#ifdef KWIN_HAVE_XRENDER_COMPOSITING + if( clip() && effects->compositingType() == XRenderCompositing ) + XFixesSetPictureClipRegion( display(), effects->xrenderBufferPicture(), 0, 0, None ); +#endif + delete data; + } + +bool PaintClipper::Iterator::isDone() + { + if( !clip()) + return data->index == 1; // run once +#ifdef KWIN_HAVE_OPENGL_COMPOSITING + if( effects->compositingType() == OpenGLCompositing ) + return data->index >= data->rects.count(); // run once per each area +#endif +#ifdef KWIN_HAVE_XRENDER_COMPOSITING + if( effects->compositingType() == XRenderCompositing ) + return data->index == 1; // run once +#endif + assert( false ); + } + +void PaintClipper::Iterator::next() + { + data->index++; +#ifdef KWIN_HAVE_OPENGL_COMPOSITING + if( clip() && effects->compositingType() == OpenGLCompositing && data->index < data->rects.count()) + { + const QRect& r = data->rects[ data->index ]; + // Scissor rect has to be given in OpenGL coords + glScissor( r.x(), displayHeight() - r.y() - r.height(), r.width(), r.height()); + } +#endif + } + +QRect PaintClipper::Iterator::boundingRect() const + { + if( !clip()) + return infiniteRegion(); +#ifdef KWIN_HAVE_OPENGL_COMPOSITING + if( effects->compositingType() == OpenGLCompositing ) + return data->rects[ data->index ]; +#endif +#ifdef KWIN_HAVE_XRENDER_COMPOSITING + if( effects->compositingType() == XRenderCompositing ) + return paintArea().boundingRect(); +#endif + assert( false ); + } + + +// Convert QRegion to XserverRegion. All code uses XserverRegion +// only when really necessary as the shared implementation uses +// QRegion. +XserverRegion toXserverRegion( QRegion region ) + { + QVector< QRect > rects = region.rects(); + XRectangle* xr = new XRectangle[ rects.count() ]; + for( int i = 0; + i < rects.count(); + ++i ) + { + xr[ i ].x = rects[ i ].x(); + xr[ i ].y = rects[ i ].y(); + xr[ i ].width = rects[ i ].width(); + xr[ i ].height = rects[ i ].height(); + } + XserverRegion ret = XFixesCreateRegion( display(), xr, rects.count()); + delete[] xr; + return ret; + } + + } // namespace Index: kwin/lib/kwinglutils.cpp =================================================================== --- kwin/lib/kwinglutils.cpp (revision 766576) +++ kwin/lib/kwinglutils.cpp (working copy) @@ -128,21 +128,13 @@ void renderGLGeometry( int count, const float* vertices, const float* texture, const float* color, int dim, int stride ) { - return renderGLGeometry( false, QRegion(), count, vertices, texture, color, dim, stride ); + return renderGLGeometry( infiniteRegion(), count, vertices, texture, color, dim, stride ); } -void renderGLGeometry( int mask, const QRegion& region, int count, +void renderGLGeometry( const QRegion& region, int count, const float* vertices, const float* texture, const float* color, int dim, int stride ) { - return renderGLGeometry( !( mask & ( Effect::PAINT_WINDOW_TRANSFORMED | Effect::PAINT_SCREEN_TRANSFORMED )), - region, count, vertices, texture, color, dim, stride ); - } - -void renderGLGeometry( bool clip, const QRegion& region, int count, - const float* vertices, const float* texture, const float* color, - int dim, int stride ) - { // Using arrays only makes sense if we have larger number of vertices. // Otherwise overhead of enabling/disabling them is too big. bool use_arrays = (count > 5); @@ -166,40 +158,17 @@ } } - // Render - if( !clip ) + // Clip using scissoring + PaintClipper pc( region ); + for( PaintClipper::Iterator iterator; + !iterator.isDone(); + iterator.next()) { - // Just draw the entire window, no clipping if( use_arrays ) glDrawArrays( GL_QUADS, 0, count ); else renderGLGeometryImmediate( count, vertices, texture, color, dim, stride ); } - else - { - // Make sure there's only a single quad (no transformed vertices) - // Clip using scissoring - glEnable( GL_SCISSOR_TEST ); - int dh = displayHeight(); - if( use_arrays ) - { - foreach( QRect r, region.rects()) - { - // Scissor rect has to be given in OpenGL coords - glScissor(r.x(), dh - r.y() - r.height(), r.width(), r.height()); - glDrawArrays( GL_QUADS, 0, count ); - } - } - else - { - foreach( QRect r, region.rects()) - { - // Scissor rect has to be given in OpenGL coords - glScissor(r.x(), dh - r.y() - r.height(), r.width(), r.height()); - renderGLGeometryImmediate( count, vertices, texture, color, dim, stride ); - } - } - } if( use_arrays ) { @@ -500,14 +469,8 @@ glDisable( mTarget ); } -void GLTexture::render( int mask, QRegion region, const QRect& rect ) +void GLTexture::render( QRegion region, const QRect& rect ) { - return render( !( mask & ( Effect::PAINT_WINDOW_TRANSFORMED | Effect::PAINT_SCREEN_TRANSFORMED )), - region, rect ); - } - -void GLTexture::render( bool clip, QRegion region, const QRect& rect ) - { const float verts[ 4 * 2 ] = { rect.x(), rect.y(), @@ -522,7 +485,7 @@ 1, 0, 1, 1 }; - renderGLGeometry( clip, region, 4, verts, texcoords ); + renderGLGeometry( region, 4, verts, texcoords ); } void GLTexture::enableUnnormalizedTexCoords() Index: kwin/lib/kwineffects.h =================================================================== --- kwin/lib/kwineffects.h (revision 766576) +++ kwin/lib/kwineffects.h (working copy) @@ -32,12 +32,19 @@ #include #include #include +#include #include #include #include +#include +#ifdef KWIN_HAVE_XRENDER_COMPOSITING +#include +#endif + + /** @addtogroup kwineffects */ /** @{ */ @@ -76,6 +83,22 @@ /** + * Infinite region (i.e. a special region type saying that everything needs to be painted). + */ +KWIN_EXPORT inline +QRect infiniteRegion() + { // INT_MIN / 2 because width/height is used (INT_MIN+INT_MAX==-1) + return QRect( INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX ); + } + +#ifdef KWIN_HAVE_XRENDER_COMPOSITING +/** + * Convert QRegion to XserverRegion. + */ +KWIN_EXPORT XserverRegion toXserverRegion( QRegion region ); +#endif + +/** * @short Base class for all KWin effects * * This is the base class for all effects. By reimplementing virtual methods @@ -734,6 +757,71 @@ }; /** + * @short Helper class for restricting painting area only to allowed area. + * + * This helper class helps specifying areas that should be painted, clipping + * out the rest. The simplest usage is creating an object on the stack + * and giving it the area that is allowed to be painted to. When the object + * is destroyed, the restriction will be removed. + * Note that all painting code must use paintArea() to actually perform the clipping. + */ +class KWIN_EXPORT PaintClipper + { + public: + /** + * Calls push(). + */ + PaintClipper( const QRegion& allowed_area ); + /** + * Calls pop(). + */ + ~PaintClipper(); + /** + * Allows painting only in the given area. When areas have been already + * specified, painting is allowed only in the intersection of all areas. + */ + static void push( const QRegion& allowed_area ); + /** + * Removes the given area. It must match the top item in the stack. + */ + static void pop( const QRegion& allowed_area ); + /** + * Returns true if any clipping should be performed. + */ + static bool clip(); + /** + * If clip() returns true, this function gives the resulting area in which + * painting is allowed. It is usually simpler to use the helper Iterator class. + */ + static QRegion paintArea(); + /** + * Helper class to perform the clipped painting. The usage is: + * @code + * for( PaintClipper::Iterator iterator; + * !iterator.isDone(); + * iterator.next()) + * { // do the painting, possibly use iterator.boundingRect() + * } + * @endcode + */ + class Iterator + { + public: + Iterator(); + ~Iterator(); + bool isDone(); + void next(); + QRect boundingRect() const; + private: + struct Data; + Data* data; + }; + private: + QRegion area; + static QStack< QRegion >* areas; + }; + +/** * Pointer to the global EffectsHandler object. **/ extern KWIN_EXPORT EffectsHandler* effects; Index: kwin/lib/kwinglutils.h =================================================================== --- kwin/lib/kwinglutils.h (revision 766576) +++ kwin/lib/kwinglutils.h (working copy) @@ -82,22 +82,17 @@ * @param stride byte offset of consecutive elements in arrays. If 0, then * arrays must be tighly packed. Stride must be a multiple of sizeof(float)! **/ -KWIN_EXPORT void renderGLGeometry( bool clip, const QRegion& region, int count, +KWIN_EXPORT void renderGLGeometry( const QRegion& region, int count, const float* vertices, const float* texture = 0, const float* color = 0, int dim = 2, int stride = 0 ); /** - * Same as above, sets clip parameter according to mask. + * Same as above, renders without specified region **/ -KWIN_EXPORT void renderGLGeometry( int mask, const QRegion& region, int count, - const float* vertices, const float* texture = 0, const float* color = 0, - int dim = 2, int stride = 0 ); -/** - * Same as above, renders without clipping - **/ KWIN_EXPORT void renderGLGeometry( int count, const float* vertices, const float* texture = 0, const float* color = 0, int dim = 2, int stride = 0 ); + KWIN_EXPORT void renderGLGeometryImmediate( int count, const float* vertices, const float* texture = 0, const float* color = 0, int dim = 2, int stride = 0 ); @@ -125,8 +120,7 @@ virtual void discard(); virtual void bind(); virtual void unbind(); - void render( bool clip, QRegion region, const QRect& rect ); - void render( int mask, QRegion region, const QRect& rect ); + void render( QRegion region, const QRect& rect ); void enableUnnormalizedTexCoords(); void disableUnnormalizedTexCoords(); Index: kwin/scene_xrender.h =================================================================== --- kwin/scene_xrender.h (revision 766576) +++ kwin/scene_xrender.h (working copy) @@ -54,7 +54,6 @@ private: void paintTransformedScreen( int mask ); void createBuffer(); - static XserverRegion toXserverRegion( QRegion region ); XRenderPictFormat* format; Picture front; static Picture buffer; --Boundary-00=_tx5mHAPsQKX0r4n Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Kwin mailing list Kwin@kde.org https://mail.kde.org/mailman/listinfo/kwin --Boundary-00=_tx5mHAPsQKX0r4n--