From f400646a6dc6a144eccba3b8a7b2adeec1f2e30b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Wed, 5 Jul 2006 16:04:11 +0000 Subject: [PATCH] xrender compositing work - now it uses damage areas to reduce amount of painting svn path=/branches/work/kwin_composite/; revision=558580 --- CMakeLists.txt | 3 ++ client.cpp | 3 +- client.h | 2 - composite.cpp | 104 ++++++++++++++++++++++++++++++---------------- events.cpp | 10 +++-- geometry.cpp | 9 ++-- manage.cpp | 3 ++ scene.h | 2 +- scene_basic.cpp | 2 +- scene_basic.h | 2 +- scene_xrender.cpp | 47 +++++++++++++-------- scene_xrender.h | 2 +- toplevel.cpp | 2 +- toplevel.h | 4 +- unmanaged.cpp | 1 + unmanaged.h | 1 - utils.cpp | 6 +++ utils.h | 10 +++++ workspace.cpp | 6 ++- workspace.h | 6 ++- 20 files changed, 151 insertions(+), 74 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bb075ece8..4c54e45875 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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} ) diff --git a/client.cpp b/client.cpp index 41b99d8726..6885d8970b 100644 --- a/client.cpp +++ b/client.cpp @@ -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; diff --git a/client.h b/client.h index 086a5ea718..2509dbf4a9 100644 --- a/client.h +++ b/client.h @@ -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) diff --git a/composite.cpp b/composite.cpp index c21914b4ad..7d7a97fa16 100644 --- a/composite.cpp +++ b/composite.cpp @@ -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 diff --git a/events.cpp b/events.cpp index 3481f6c1fe..5bf9b6e7dd 100644 --- a/events.cpp +++ b/events.cpp @@ -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()); } // **************************************** diff --git a/geometry.cpp b/geometry.cpp index 5a64c6f336..6506ad2dc9 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -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 ) diff --git a/manage.cpp b/manage.cpp index fcc52877f5..4f96dc780c 100644 --- a/manage.cpp +++ b/manage.cpp @@ -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(); diff --git a/scene.h b/scene.h index b9b3d954ba..df70978836 100644 --- a/scene.h +++ b/scene.h @@ -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; diff --git a/scene_basic.cpp b/scene_basic.cpp index 38dff23f9c..a6ff7ee3a9 100644 --- a/scene_basic.cpp +++ b/scene_basic.cpp @@ -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; diff --git a/scene_basic.h b/scene_basic.h index 0210da92c5..eb39b943b3 100644 --- a/scene_basic.h +++ b/scene_basic.h @@ -22,7 +22,7 @@ class SceneBasic public: SceneBasic( Workspace* ws ); virtual ~SceneBasic(); - virtual void paint(); + virtual void paint( XserverRegion damage ); }; } // namespace diff --git a/scene_xrender.cpp b/scene_xrender.cpp index 6918ec668a..395150b21b 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -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()); } diff --git a/scene_xrender.h b/scene_xrender.h index 220799279a..1865572342 100644 --- a/scene_xrender.h +++ b/scene_xrender.h @@ -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; diff --git a/toplevel.cpp b/toplevel.cpp index 819b1ec554..766e977863 100644 --- a/toplevel.cpp +++ b/toplevel.cpp @@ -16,7 +16,7 @@ namespace KWinInternal Toplevel::Toplevel( Workspace* ws ) : id( None ) , wspace( ws ) - , damage( None ) + , damage_handle( None ) , window_pixmap( None ) { } diff --git a/toplevel.h b/toplevel.h index 9a8ffa51f2..7e6e5fd448 100644 --- a/toplevel.h +++ b/toplevel.h @@ -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; }; diff --git a/unmanaged.cpp b/unmanaged.cpp index c1b8b66e88..5aa448e5d9 100644 --- a/unmanaged.cpp +++ b/unmanaged.cpp @@ -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; } diff --git a/unmanaged.h b/unmanaged.h index 9e1f803067..e8e0843638 100644 --- a/unmanaged.h +++ b/unmanaged.h @@ -34,7 +34,6 @@ class Unmanaged void mapNotifyEvent( XMapEvent* e ); void unmapNotifyEvent( XUnmapEvent*e ); void configureNotifyEvent( XConfigureEvent* e ); - void damageNotifyEvent( XDamageNotifyEvent* e ); }; } // namespace diff --git a/utils.cpp b/utils.cpp index 275afd6e4c..b096a0d259 100644 --- a/utils.cpp +++ b/utils.cpp @@ -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 } diff --git a/utils.h b/utils.h index cf16175228..251d720a1c 100644 --- a/utils.h +++ b/utils.h @@ -21,6 +21,9 @@ License. See the file "COPYING" for the exact licensing terms. #ifdef HAVE_XDAMAGE #include #endif +#ifdef HAVE_XFIXES +#include +#endif #include @@ -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 diff --git a/workspace.cpp b/workspace.cpp index 08b001f188..3bb8adbc7d 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -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; } diff --git a/workspace.h b/workspace.h index f0331b3625..8fe701041b 100644 --- a/workspace.h +++ b/workspace.h @@ -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;