[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kwin
Subject:    RFC: Multiple clipping
From:       Lubos Lunak <l.lunak () suse ! cz>
Date:       2008-01-26 20:47:41
Message-ID: 200801262147.41388.l.lunak () suse ! cz
[Download RAW message or body]

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

["kwin.patch" (text/x-diff)]

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; i<flakes->count(); 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<float>& 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 <QtCore/QVector>
 #include <QtCore/QList>
 #include <QtCore/QHash>
+#include <QtCore/QStack>
 
 #include <KDE/KPluginFactory>
 #include <KDE/KShortcutsEditor>
 
 #include <assert.h>
+#include <limits.h>
 
+#ifdef KWIN_HAVE_XRENDER_COMPOSITING
+#include <X11/extensions/Xfixes.h>
+#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;



_______________________________________________
Kwin mailing list
Kwin@kde.org
https://mail.kde.org/mailman/listinfo/kwin


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic