xrender compositing work - now it uses damage areas

to reduce amount of painting


svn path=/branches/work/kwin_composite/; revision=558580
This commit is contained in:
Luboš Luňák 2006-07-05 16:04:11 +00:00
parent 29111875e1
commit f400646a6d
20 changed files with 151 additions and 74 deletions

View file

@ -63,6 +63,9 @@ endif (X11_Xdamage_FOUND)
if (X11_Xrender_FOUND)
target_link_libraries(kdeinit_kwin ${X11_Xrender_LIB})
endif (X11_Xrender_FOUND)
if (X11_Xfixes_FOUND)
target_link_libraries(kdeinit_kwin ${X11_Xfixes_LIB})
endif (X11_Xfixes_FOUND)
install(TARGETS kdeinit_kwin DESTINATION ${LIB_INSTALL_DIR} )

View file

@ -88,8 +88,7 @@ Client::Client( Workspace *ws )
border_top( 0 ),
border_bottom( 0 ),
sm_stacking_order( -1 ),
demandAttentionKNotifyTimer( NULL ),
damage( None )
demandAttentionKNotifyTimer( NULL )
// SELI do all as initialization
{
autoRaiseTimer = 0;

View file

@ -316,7 +316,6 @@ class Client
void visibilityNotifyEvent( XVisibilityEvent* e );
void focusInEvent( XFocusInEvent* e );
void focusOutEvent( XFocusOutEvent* e );
void damageNotifyEvent( XDamageNotifyEvent* e );
bool buttonPressEvent( Window w, int button, int state, int x, int y, int x_root, int y_root );
bool buttonReleaseEvent( Window w, int button, int state, int x, int y, int x_root, int y_root );
@ -516,7 +515,6 @@ class Client
void show() { assert( false ); } // SELI remove after Client is no longer QWidget
void hide() { assert( false ); }
QTimer* demandAttentionKNotifyTimer;
Damage damage;
};
// helper for Client::postponeGeometryUpdates() being called in pairs (true/false)

View file

@ -23,7 +23,7 @@ namespace KWinInternal
// Workspace
//****************************************
#if defined( HAVE_XCOMPOSITE ) && defined( HAVE_XDAMAGE )
#if defined( HAVE_XCOMPOSITE ) && defined( HAVE_XDAMAGE ) && defined( HAVE_XFIXES )
void Workspace::setupCompositing()
{
if( !Extensions::compositeAvailable() || !Extensions::damageAvailable())
@ -33,9 +33,9 @@ void Workspace::setupCompositing()
// TODO start tracking unmanaged windows
compositeTimer.start( 20 );
XCompositeRedirectSubwindows( display(), rootWindow(), CompositeRedirectManual );
setDamaged();
// scene = new SceneBasic( this );
scene = new SceneXrender( this );
addDamage( 0, 0, displayWidth(), displayHeight());
}
void Workspace::finishCompositing()
@ -49,18 +49,69 @@ void Workspace::finishCompositing()
scene = NULL;
}
void Workspace::setDamaged()
void Workspace::addDamage( const QRect& r )
{
addDamage( r.x(), r.y(), r.height(), r.width());
}
void Workspace::addDamage( int x, int y, int w, int h )
{
XRectangle r;
r.x = x;
r.y = y;
r.width = w;
r.height = h;
addDamage( XFixesCreateRegion( display(), &r, 1 ), true );
}
struct XXX
{
XXX( XserverRegion r ) : rr( r ) {}
XserverRegion rr;
};
kdbgstream& operator<<( kdbgstream& stream, XXX r )
{
if( r.rr == None )
return stream << "NONE";
int num;
XRectangle* rects = XFixesFetchRegion( display(), r.rr, &num );
if( rects == NULL || num == 0 )
return stream << "NONE";
for( int i = 0;
i < num;
++i )
stream << "[" << rects[ i ].x << "+" << rects[ i ].y << " " << rects[ i ].width << "x" << rects[ i ].height << "]";
return stream;
}
void Workspace::addDamage( XserverRegion r, bool destroy )
{
if( !compositing())
return;
damaged = true;
if( damage != None )
{
XFixesUnionRegion( display(), damage, damage, r );
if( destroy )
XFixesDestroyRegion( display(), r );
}
else
{
if( destroy )
damage = r;
else
{
damage = XFixesCreateRegion( display(), NULL, 0 );
XFixesCopyRegion( display(), damage, r );
}
}
}
void Workspace::compositeTimeout()
{
if( !damaged )
if( damage == None )
return;
damaged = false;
ToplevelList windows;
Window* children;
unsigned int children_count;
@ -79,7 +130,9 @@ void Workspace::compositeTimeout()
windows.append( c );
}
scene->setWindows( windows );
scene->paint();
scene->paint( damage );
XFixesDestroyRegion( display(), damage );
damage = None;
}
//****************************************
@ -90,18 +143,17 @@ void Toplevel::setupCompositing()
{
if( !compositing())
return;
if( damage != None )
if( damage_handle != None )
return;
damage = XDamageCreate( display(), handle(), XDamageReportRawRectangles );
setDamaged();
damage_handle = XDamageCreate( display(), handle(), XDamageReportRawRectangles );
}
void Toplevel::finishCompositing()
{
if( damage == None )
if( damage_handle == None )
return;
XDamageDestroy( display(), damage );
damage = None;
XDamageDestroy( display(), damage_handle );
damage_handle = None;
if( window_pixmap != None )
{
XFreePixmap( display(), window_pixmap );
@ -109,13 +161,6 @@ void Toplevel::finishCompositing()
}
}
void Toplevel::setDamaged()
{
if( !compositing())
return;
workspace()->setDamaged();
}
void Toplevel::resetWindowPixmap()
{
if( !compositing())
@ -132,22 +177,11 @@ Pixmap Toplevel::windowPixmap() const
return window_pixmap;
}
//****************************************
// Client
//****************************************
void Client::damageNotifyEvent( XDamageNotifyEvent* )
void Toplevel::damageNotifyEvent( XDamageNotifyEvent* e )
{
setDamaged();
}
//****************************************
// Unmanaged
//****************************************
void Unmanaged::damageNotifyEvent( XDamageNotifyEvent* )
{
setDamaged();
XserverRegion r = XFixesCreateRegion( display(), &e->area, 1 );
XFixesTranslateRegion( display(), r, x(), y());
workspace()->addDamage( r, true );
}
#endif

View file

@ -473,8 +473,8 @@ bool Workspace::workspaceEvent( XEvent * e )
tab_box->updateKeyMapping();
break;
case Expose:
if( e->xexpose.window == rootWindow() && compositing())
setDamaged(); // root window needs repainting
if( e->xexpose.window == rootWindow() && compositing()) // root window needs repainting
addDamage( e->xexpose.x, e->xexpose.y, e->xexpose.width, e->xexpose.height );
break;
default:
break;
@ -1624,9 +1624,11 @@ void Unmanaged::unmapNotifyEvent( XUnmapEvent* )
void Unmanaged::configureNotifyEvent( XConfigureEvent* e )
{
geom = QRect( e->x, e->y, e->width, e->height );
resetWindowPixmap();
setDamaged();
// add old and new geometry to damage
workspace()->addDamage( geometry());
geom = QRect( e->x, e->y, e->width, e->height );
workspace()->addDamage( geometry());
}
// ****************************************

View file

@ -1660,6 +1660,7 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
}
if( force == NormalGeometrySet && geom == QRect( x, y, w, h ))
return;
workspace()->addDamage( geometry()); // TODO cache the previous real geometry
geom = QRect( x, y, w, h );
updateWorkareaDiffs();
if( postpone_geometry_updates != 0 )
@ -1684,8 +1685,8 @@ void Client::setGeometry( int x, int y, int w, int h, ForceGeometry_t force )
sendSyntheticConfigureNotify();
updateWindowRules();
checkMaximizeGeometry();
setDamaged();
resetWindowPixmap();
workspace()->addDamage( geometry());
}
void Client::plainResize( int w, int h, ForceGeometry_t force )
@ -1717,6 +1718,7 @@ void Client::plainResize( int w, int h, ForceGeometry_t force )
}
if( force == NormalGeometrySet && geom.size() == QSize( w, h ))
return;
workspace()->addDamage( geometry()); // TODO cache the previous real geometry
geom.setSize( QSize( w, h ));
updateWorkareaDiffs();
if( postpone_geometry_updates != 0 )
@ -1740,8 +1742,8 @@ void Client::plainResize( int w, int h, ForceGeometry_t force )
sendSyntheticConfigureNotify();
updateWindowRules();
checkMaximizeGeometry();
setDamaged();
resetWindowPixmap();
workspace()->addDamage( geometry());
}
/*!
@ -1751,6 +1753,7 @@ void Client::move( int x, int y, ForceGeometry_t force )
{
if( force == NormalGeometrySet && geom.topLeft() == QPoint( x, y ))
return;
workspace()->addDamage( geometry()); // TODO cache the previous real geometry
geom.moveTopLeft( QPoint( x, y ));
updateWorkareaDiffs();
if( postpone_geometry_updates != 0 )
@ -1762,7 +1765,7 @@ void Client::move( int x, int y, ForceGeometry_t force )
sendSyntheticConfigureNotify();
updateWindowRules();
checkMaximizeGeometry();
setDamaged();
workspace()->addDamage( geometry());
}
void Client::postponeGeometryUpdates( bool postpone )

View file

@ -518,6 +518,9 @@ bool Client::manage( Window w, bool isMapped )
// sendSyntheticConfigureNotify(); done when setting mapping state
delete session;
if( isMapped ) // otherwise damage will come when the client paints it
workspace()->addDamage( geometry());
ungrabXServer();

View file

@ -24,7 +24,7 @@ class Scene
Scene( Workspace* ws );
virtual ~Scene();
void setWindows( const ToplevelList& list );
virtual void paint() = 0;
virtual void paint( XserverRegion damage ) = 0;
protected:
Workspace* wspace;
ToplevelList windows;

View file

@ -29,7 +29,7 @@ SceneBasic::~SceneBasic()
{
}
void SceneBasic::paint()
void SceneBasic::paint( XserverRegion )
{
Pixmap composite_pixmap = XCreatePixmap( display(), rootWindow(), displayWidth(), displayHeight(), QX11Info::appDepth());
XGCValues val;

View file

@ -22,7 +22,7 @@ class SceneBasic
public:
SceneBasic( Workspace* ws );
virtual ~SceneBasic();
virtual void paint();
virtual void paint( XserverRegion damage );
};
} // namespace

View file

@ -48,28 +48,41 @@ void SceneXrender::createBuffer()
XFreePixmap( display(), pixmap ); // The picture owns the pixmap now
}
void SceneXrender::paint()
void SceneXrender::paint( XserverRegion damage )
{
XRenderColor col = { 0xffff, 0xffff, 0xffff, 0xffff };
XRenderFillRectangle( display(), PictOpSrc, buffer, &col, 0, 0, displayWidth(), displayHeight());
for( ToplevelList::ConstIterator it = windows.begin();
it != windows.end();
++it )
// Use the damage region as the clip region for the root window
XFixesSetPictureClipRegion( display(), front, 0, 0, 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;
i >= 0;
--i )
{
QRect r = (*it)->geometry().intersect( QRect( 0, 0, displayWidth(), displayHeight()));
if( !r.isEmpty())
Toplevel* c = windows[ i ];
XWindowAttributes attrs;
if( !XGetWindowAttributes( display(), c->handle(), &attrs ))
continue;
if( XRenderPictFormat* clientFormat = XRenderFindVisualFormat( display(), attrs.visual ))
{
XWindowAttributes attrs;
if( !XGetWindowAttributes( display(), (*it)->handle(), &attrs ))
continue;
if( XRenderPictFormat* clientFormat = XRenderFindVisualFormat( display(), attrs.visual ))
{
Picture picture = XRenderCreatePicture( display(), (*it)->windowPixmap(), clientFormat, 0, 0 );
XRenderComposite( display(), PictOpSrc, picture, None, buffer, 0, 0, 0, 0,
(*it)->x(), (*it)->y(), (*it)->width(), (*it)->height());
}
Picture picture = XRenderCreatePicture( display(), c->windowPixmap(), clientFormat, 0, 0 );
// Set the clip region for the buffer to the damage region, and
// subtract the clients shape from the damage region
XFixesSetPictureClipRegion( display(), buffer, 0, 0, damage );
XserverRegion cr = XFixesCreateRegionFromWindow( display(), c->handle(), WindowRegionBounding );
XFixesTranslateRegion( display(), cr, c->x(), c->y());
XFixesSubtractRegion( display(), damage, damage, cr );
XFixesDestroyRegion( display(), cr );
XRenderComposite( display(), PictOpSrc, picture, None, buffer, 0, 0, 0, 0,
c->x(), c->y(), c->width(), c->height());
XRenderFreePicture( display(), picture );
}
}
// fill background
XFixesSetPictureClipRegion( display(), buffer, 0, 0, damage );
XRenderColor col = { 0xffff, 0xffff, 0xffff, 0xffff };
XRenderFillRectangle( display(), PictOpSrc, buffer, &col, 0, 0, displayWidth(), displayHeight());
// 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());
}

View file

@ -27,7 +27,7 @@ class SceneXrender
public:
SceneXrender( Workspace* ws );
virtual ~SceneXrender();
virtual void paint();
virtual void paint( XserverRegion damage );
private:
void createBuffer();
XRenderPictFormat* format;

View file

@ -16,7 +16,7 @@ namespace KWinInternal
Toplevel::Toplevel( Workspace* ws )
: id( None )
, wspace( ws )
, damage( None )
, damage_handle( None )
, window_pixmap( None )
{
}

View file

@ -43,16 +43,16 @@ class Toplevel
protected:
void setupCompositing();
void finishCompositing();
void setDamaged();
void setHandle( Window id );
void resetWindowPixmap();
void damageNotifyEvent( XDamageNotifyEvent* e );
QRect geom;
virtual void debug( kdbgstream& stream ) const = 0;
friend kdbgstream& operator<<( kdbgstream& stream, const Toplevel* );
private:
Window id;
Workspace* wspace;
Damage damage;
Damage damage_handle;
mutable Pixmap window_pixmap;
};

View file

@ -34,6 +34,7 @@ bool Unmanaged::track( Window w )
geom = QRect( attr.x, attr.y, attr.width, attr.height );
setupCompositing();
resetWindowPixmap();
workspace()->addDamage( geometry());
return true;
}

View file

@ -34,7 +34,6 @@ class Unmanaged
void mapNotifyEvent( XMapEvent* e );
void unmapNotifyEvent( XUnmapEvent*e );
void configureNotifyEvent( XConfigureEvent* e );
void damageNotifyEvent( XDamageNotifyEvent* e );
};
} // namespace

View file

@ -48,6 +48,7 @@ int Extensions::shape_event_base = 0;
bool Extensions::has_damage = 0;
int Extensions::damage_event_base = 0;
bool Extensions::has_composite = 0;
bool Extensions::has_fixes = 0;
void Extensions::init()
{
@ -70,6 +71,11 @@ void Extensions::init()
}
#else
has_composite = false;
#endif
#ifdef HAVE_XFIXES
has_fixes = XFixesQueryExtension( display(), &dummy, &dummy );
#else
has_fixes = false;
#endif
}

10
utils.h
View file

@ -21,6 +21,9 @@ License. See the file "COPYING" for the exact licensing terms.
#ifdef HAVE_XDAMAGE
#include <X11/extensions/Xdamage.h>
#endif
#ifdef HAVE_XFIXES
#include <X11/extensions/Xfixes.h>
#endif
#include <fixx11h.h>
@ -40,6 +43,11 @@ struct XDamageNotifyEvent
{
};
#endif
#ifndef HAVE_XFIXES
struct XserverRegion
{
};
#endif
const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
| NET::ToolbarMask | NET::MenuMask | NET::DialogMask /*| NET::OverrideMask*/ | NET::TopMenuMask
@ -143,12 +151,14 @@ class Extensions
static bool damageAvailable() { return has_damage; }
static int damageNotifyEvent();
static bool compositeAvailable() { return has_composite; }
static bool fixesAvailable() { return has_fixes; }
private:
static bool has_shape;
static int shape_event_base;
static bool has_damage;
static int damage_event_base;
static bool has_composite;
static bool has_fixes;
};
class Motif

View file

@ -124,7 +124,7 @@ Workspace::Workspace( bool restore )
set_active_client_recursion( 0 ),
block_stacking_updates( 0 ),
forced_global_mouse_grab( false ),
damaged( false )
damage( None )
{
new KWinAdaptor( "org.kde.kwin", "/KWin", QDBus::sessionBus(), this );
@ -471,6 +471,10 @@ Workspace::~Workspace()
foreach ( SessionInfo* s, session )
delete s;
XDestroyWindow( display(), null_focus_window );
#ifdef HAVE_XFIXES
if( damage != None )
XFixesDestroyRegion( display(), damage );
#endif
// TODO ungrabXServer();
_self = 0;
}

View file

@ -283,7 +283,9 @@ class Workspace : public QObject, public KDecorationDefines
void toggleTopDockShadows(bool on);
void setDamaged();
void addDamage( const QRect& r );
void addDamage( int x, int y, int w, int h );
void addDamage( XserverRegion r, bool destroy );
public slots:
void refresh();
@ -630,8 +632,8 @@ class Workspace : public QObject, public KDecorationDefines
bool forced_global_mouse_grab;
friend class StackingUpdatesBlocker;
bool damaged;
QTimer compositeTimer;
XserverRegion damage;
//kompmgr
QSlider *transSlider;