Use QRegion as much as possible to get even closer to the opengl code.

svn path=/branches/work/kwin_composite/; revision=595627
icc-effect-5.14.5
Luboš Luňák 2006-10-15 07:41:19 +00:00
parent c7584b3bf8
commit a3538cd80a
2 changed files with 110 additions and 56 deletions

View File

@ -16,6 +16,8 @@ License. See the file "COPYING" for the exact licensing terms.
#include "client.h"
#include "effects.h"
#include <X11/extensions/shape.h>
namespace KWinInternal
{
@ -50,7 +52,6 @@ kdbgstream& operator<<( kdbgstream& stream, RegionDebug r )
#endif
Picture SceneXrender::buffer;
XserverRegion SceneXrender::infiniteRegion;
SceneXrender::SceneXrender( Workspace* ws )
: Scene( ws )
@ -64,7 +65,6 @@ SceneXrender::SceneXrender( Workspace* ws )
xr.y = SHRT_MIN / 2;
xr.width = SHRT_MAX;
xr.height = SHRT_MAX;
infiniteRegion = XFixesCreateRegion( display(), &xr, 1 );
createBuffer();
}
@ -76,7 +76,6 @@ SceneXrender::~SceneXrender()
it != windows.end();
++it )
(*it).free();
XFixesDestroyRegion( display(), infiniteRegion );
}
void SceneXrender::paint( QRegion damage, ToplevelList windows )
@ -89,14 +88,14 @@ void SceneXrender::paint( QRegion damage, ToplevelList windows )
void SceneXrender::paintGenericScreen( ToplevelList windows )
{
paintBackground( infiniteRegion );
paintBackground( infiniteRegion());
foreach( Toplevel* c, windows ) // bottom to top
{
assert( this->windows.contains( c ));
Window& w = this->windows[ c ];
if( !w.isVisible())
continue;
w.paint( infiniteRegion, PAINT_OPAQUE | PAINT_TRANSLUCENT );
w.paint( infiniteRegion(), PAINT_OPAQUE | PAINT_TRANSLUCENT );
}
// copy composed buffer to the root window
XRenderComposite( display(), PictOpSrc, buffer, None, front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight());
@ -105,22 +104,8 @@ void SceneXrender::paintGenericScreen( ToplevelList windows )
void SceneXrender::paintSimpleScreen( QRegion damage, ToplevelList windows )
{
QVector< QRect > rects = damage.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 region = XFixesCreateRegion( display(), xr, rects.count());
delete[] xr;
// Use the damage region as the clip region for the root window
XFixesSetPictureClipRegion( display(), front, 0, 0, region );
QList< Phase2Data > phase2;
QRegion region = damage;
// Draw each opaque window top to bottom, subtracting the bounding rect of
// each window from the clip region after it's been drawn.
for( int i = windows.count() - 1;
@ -134,16 +119,12 @@ void SceneXrender::paintSimpleScreen( QRegion damage, ToplevelList windows )
continue;
if( !w.isOpaque())
{
XserverRegion saved_clip_region = XFixesCreateRegion( display(), NULL, 0 );
XFixesCopyRegion( display(), saved_clip_region, region );
phase2.prepend( Phase2Data( &w, saved_clip_region ));
phase2.prepend( Phase2Data( &w, region ));
continue;
}
w.paint( region, PAINT_OPAQUE );
// Subtract the clients shape from the damage region
XserverRegion shape = w.shape();
assert( shape != None );
XFixesSubtractRegion( display(), region, region, shape );
// window is opaque, clip windows below
region -= w.shape().translated( w.x(), w.y());
}
// Fill any areas of the root window not covered by windows
paintBackground( region );
@ -154,18 +135,22 @@ void SceneXrender::paintSimpleScreen( QRegion damage, ToplevelList windows )
{
Window& w = *d.window;
w.paint( d.region, PAINT_TRANSLUCENT );
XFixesDestroyRegion( display(), d.region );
}
// copy composed buffer to the root window (clipped by original damage area)
// Use the damage region as the clip region for the root window
XserverRegion front_region = toXserverRegion( damage );
XFixesSetPictureClipRegion( display(), front, 0, 0, front_region );
XFixesDestroyRegion( display(), front_region );
// copy composed buffer to the root window
XFixesSetPictureClipRegion( display(), buffer, 0, 0, None );
XRenderComposite( display(), PictOpSrc, buffer, None, front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight());
XFlush( display());
XFixesDestroyRegion( display(), region );
}
void SceneXrender::paintBackground( XserverRegion region )
void SceneXrender::paintBackground( QRegion region )
{
XFixesSetPictureClipRegion( display(), buffer, 0, 0, region );
XserverRegion background_region = toXserverRegion( region );
XFixesSetPictureClipRegion( display(), buffer, 0, 0, background_region );
XFixesDestroyRegion( display(), background_region );
XRenderColor col = { 0xffff, 0xffff, 0xffff, 0xffff };
XRenderFillRectangle( display(), PictOpSrc, buffer, &col, 0, 0, displayWidth(), displayHeight());
}
@ -212,12 +197,30 @@ void SceneXrender::createBuffer()
XFreePixmap( display(), pixmap ); // The picture owns the pixmap now
}
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::Window( Toplevel* c )
: toplevel( c )
, _picture( None )
, format( XRenderFindVisualFormat( display(), c->visual()))
, alpha( None )
, _shape( None )
, shape_valid( false )
{
}
@ -294,9 +297,7 @@ void SceneXrender::Window::discardAlpha()
void SceneXrender::Window::discardShape()
{
if( _shape != None )
XRenderFreePicture( display(), _shape );
_shape = None;
shape_valid = false;
}
Picture SceneXrender::Window::alphaMask()
@ -329,23 +330,37 @@ Picture SceneXrender::Window::alphaMask()
return alpha;
}
XserverRegion SceneXrender::Window::shape()
QRegion SceneXrender::Window::shape() const
{
#if 0 // it probably doesn't make sense to cache this, and perhaps some others - they aren't roundtrips
if( shape == None )
if( !shape_valid )
{
shape = XFixesCreateRegionFromWindow( display(), toplevel->handle(), WindowRegionBounding );
XFixesTranslateRegion( display(), shape, toplevel->x(), toplevel->y());
Client* c = dynamic_cast< Client* >( toplevel );
if( toplevel->shape() || ( c != NULL && !c->mask().isEmpty()))
{
int count, order;
XRectangle* rects = XShapeGetRectangles( display(), toplevel->handle(),
ShapeBounding, &count, &order );
if(rects)
{
shape_region = QRegion();
for( int i = 0;
i < count;
++i )
shape_region += QRegion( rects[ i ].x, rects[ i ].y,
rects[ i ].width, rects[ i ].height );
XFree(rects);
}
else
shape_region = QRegion( 0, 0, width(), height());
}
else
shape_region = QRegion( 0, 0, width(), height());
shape_valid = true;
}
return shape;
#else
XserverRegion shape = XFixesCreateRegionFromWindow( display(), toplevel->handle(), WindowRegionBounding );
XFixesTranslateRegion( display(), shape, toplevel->x(), toplevel->y());
return shape;
#endif
return shape_region;
}
void SceneXrender::Window::paint( XserverRegion region, int mask )
void SceneXrender::Window::paint( QRegion region, int mask )
{
if( mask & ( PAINT_OPAQUE | PAINT_TRANSLUCENT ))
{}
@ -359,7 +374,9 @@ void SceneXrender::Window::paint( XserverRegion region, int mask )
if( isOpaque())
return;
}
XFixesSetPictureClipRegion( display(), buffer, 0, 0, region );
XserverRegion clip_region = toXserverRegion( region );
XFixesSetPictureClipRegion( display(), buffer, 0, 0, clip_region );
XFixesDestroyRegion( display(), clip_region );
Picture pic = picture();
if( pic == None ) // The render format can be null for GL and/or Xv visuals
return;

View File

@ -18,6 +18,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "scene.h"
#include "effects.h"
#include "toplevel.h"
namespace KWinInternal
{
@ -39,7 +40,9 @@ class SceneXrender
void createBuffer();
void paintGenericScreen( ToplevelList windows );
void paintSimpleScreen( QRegion damage, ToplevelList windows );
void paintBackground( XserverRegion region );
void paintBackground( QRegion region );
static QRegion infiniteRegion();
static XserverRegion toXserverRegion( QRegion region );
enum
{
PAINT_OPAQUE = 1 << 0,
@ -49,13 +52,12 @@ class SceneXrender
Picture front;
static Picture buffer;
class Window;
static XserverRegion infiniteRegion;
QMap< Toplevel*, Window > windows;
struct Phase2Data
{
Phase2Data( Window* w, XserverRegion r ) : window( w ), region( r ) {}
Phase2Data( Window* w, QRegion r ) : window( w ), region( r ) {}
Window* window;
XserverRegion region;
QRegion region;
};
};
@ -64,12 +66,16 @@ class SceneXrender::Window
public:
Window( Toplevel* c );
void free(); // is often copied by value, use manually instead of dtor
void paint( XserverRegion region, int mask );
int x() const;
int y() const;
int width() const;
int height() const;
void paint( QRegion region, int mask );
bool isOpaque() const;
void geometryShapeChanged();
void opacityChanged();
bool isVisible() const;
XserverRegion shape();
QRegion shape() const;
void discardPicture();
void discardShape();
void discardAlpha();
@ -82,9 +88,40 @@ class SceneXrender::Window
XRenderPictFormat* format;
Picture alpha;
double alpha_cached_opacity;
XserverRegion _shape;
mutable QRegion shape_region;
mutable bool shape_valid;
};
inline
QRegion SceneXrender::infiniteRegion()
{ // INT_MIN / 2 because it's width/height (INT_MIN+INT_MAX==-1)
return QRegion( INT_MIN / 2, INT_MIN / 2, INT_MAX, INT_MAX );
}
inline
int SceneXrender::Window::x() const
{
return toplevel->x();
}
inline
int SceneXrender::Window::y() const
{
return toplevel->y();
}
inline
int SceneXrender::Window::width() const
{
return toplevel->width();
}
inline
int SceneXrender::Window::height() const
{
return toplevel->height();
}
} // namespace
#endif