Stop the compositing timer when idle.

FEATURE: 155694


svn path=/trunk/KDE/kdebase/workspace/; revision=854913
This commit is contained in:
Luboš Luňák 2008-08-30 15:28:47 +00:00
parent 28e08082d2
commit c6230db535
3 changed files with 50 additions and 11 deletions

View file

@ -188,8 +188,11 @@ void Workspace::setupCompositing()
rate = 1000; rate = 1000;
kDebug( 1212 ) << "Refresh rate " << rate << "Hz"; kDebug( 1212 ) << "Refresh rate " << rate << "Hz";
compositeRate = 1000 / rate; compositeRate = 1000 / rate;
compositeTimer.start( compositeRate );
lastCompositePaint.start(); lastCompositePaint.start();
// fake a previous paint, so that the next starts right now
nextPaintReference = QTime::currentTime().addMSecs( -compositeRate );
compositeTimer.setSingleShot( true );
checkCompositeTimer();
XCompositeRedirectSubwindows( display(), rootWindow(), CompositeRedirectManual ); XCompositeRedirectSubwindows( display(), rootWindow(), CompositeRedirectManual );
new EffectsHandlerImpl( scene->compositingType() ); // sets also the 'effects' pointer new EffectsHandlerImpl( scene->compositingType() ); // sets also the 'effects' pointer
addRepaintFull(); addRepaintFull();
@ -234,11 +237,11 @@ void Workspace::finishCompositing()
foreach( Deleted* c, deleted ) foreach( Deleted* c, deleted )
c->finishCompositing(); c->finishCompositing();
XCompositeUnredirectSubwindows( display(), rootWindow(), CompositeRedirectManual ); XCompositeUnredirectSubwindows( display(), rootWindow(), CompositeRedirectManual );
compositeTimer.stop();
delete effects; delete effects;
effects = NULL; effects = NULL;
delete scene; delete scene;
scene = NULL; scene = NULL;
compositeTimer.stop();
repaints_region = QRegion(); repaints_region = QRegion();
for( ClientList::ConstIterator it = clients.begin(); for( ClientList::ConstIterator it = clients.begin();
it != clients.end(); it != clients.end();
@ -276,6 +279,7 @@ void Workspace::addRepaint( int x, int y, int w, int h )
if( !compositing()) if( !compositing())
return; return;
repaints_region += QRegion( x, y, w, h ); repaints_region += QRegion( x, y, w, h );
checkCompositeTimer();
} }
void Workspace::addRepaint( const QRect& r ) void Workspace::addRepaint( const QRect& r )
@ -283,6 +287,7 @@ void Workspace::addRepaint( const QRect& r )
if( !compositing()) if( !compositing())
return; return;
repaints_region += r; repaints_region += r;
checkCompositeTimer();
} }
void Workspace::addRepaint( const QRegion& r ) void Workspace::addRepaint( const QRegion& r )
@ -290,6 +295,7 @@ void Workspace::addRepaint( const QRegion& r )
if( !compositing()) if( !compositing())
return; return;
repaints_region += r; repaints_region += r;
checkCompositeTimer();
} }
void Workspace::addRepaintFull() void Workspace::addRepaintFull()
@ -297,6 +303,7 @@ void Workspace::addRepaintFull()
if( !compositing()) if( !compositing())
return; return;
repaints_region = QRegion( 0, 0, displayWidth(), displayHeight()); repaints_region = QRegion( 0, 0, displayWidth(), displayHeight());
checkCompositeTimer();
} }
void Workspace::performCompositing() void Workspace::performCompositing()
@ -308,17 +315,17 @@ void Workspace::performCompositing()
// them - leave at least 1msec time after one repaint is finished and next one // them - leave at least 1msec time after one repaint is finished and next one
// is started. // is started.
if( lastCompositePaint.elapsed() < 1 ) if( lastCompositePaint.elapsed() < 1 )
{
compositeTimer.start( 1 );
return; return;
}
if( !scene->waitSyncAvailable())
nextPaintReference = QTime::currentTime();
checkCursorPos(); checkCursorPos();
if(( repaints_region.isEmpty() && !windowRepaintsPending()) // no damage if(( repaints_region.isEmpty() && !windowRepaintsPending()) // no damage
|| !overlay_visible ) // nothing is visible anyway || !overlay_visible ) // nothing is visible anyway
{ {
scene->idle(); scene->idle();
// With vsync, next repaint is scheduled dynamically at the end of this function,
// and it can have a very short timeout. If we now idle here, make sure the idling
// does not actually caused heavy load by firing the timer often too quickly.
if( compositeTimer.interval() != compositeRate )
compositeTimer.start( compositeRate );
// Note: It would seem here we should undo suspended unredirect, but when scenes need // Note: It would seem here we should undo suspended unredirect, but when scenes need
// it for some reason, e.g. transformations or translucency, the next pass that does not // it for some reason, e.g. transformations or translucency, the next pass that does not
// need this anymore and paints normally will also reset the suspended unredirect. // need this anymore and paints normally will also reset the suspended unredirect.
@ -361,11 +368,19 @@ void Workspace::performCompositing()
scene->paint( repaints, windows ); scene->paint( repaints, windows );
if( scene->waitSyncAvailable()) if( scene->waitSyncAvailable())
{ {
// if vsync is used, schedule the next repaint slightly in advance of the next sync, // If vsync is used, schedule the next repaint slightly in advance of the next sync,
// so that there is still time for the drawing to take place // so that there is still time for the drawing to take place. We have just synced, and
int untilNextSync = compositeRate - ( lastCompositePaint.elapsed() % compositeRate ); // nextPaintReference is time from which multiples of compositeRate should be added,
compositeTimer.start( qMax( 1, untilNextSync - 10 )); // 10 ms in advance - TODO maybe less? // so set it 10ms back (meaning next paint will be in 'compositeRate - 10').
// However, make sure the reserve is smaller than the composite rate.
int reserve = compositeRate <= 10 ? compositeRate - 1 : 10;
nextPaintReference = QTime::currentTime().addMSecs( -reserve );
} }
// Trigger at least one more pass even if there would be nothing to paint, so that scene->idle()
// is called the next time. If there would be nothing pending, it will not restart the timer and
// checkCompositeTime() would restart it again somewhen later, called from functions that
// would again add something pending.
checkCompositeTimer();
lastCompositePaint.start(); lastCompositePaint.start();
#endif #endif
} }
@ -387,6 +402,15 @@ bool Workspace::windowRepaintsPending() const
return false; return false;
} }
void Workspace::setCompositeTimer()
{
if( !compositing()) // should not really happen, but there may be e.g. some damage events still pending
return;
// Last paint set nextPaintReference as a reference time from which multiples of compositeRate
// should be added for the next paint.
compositeTimer.start( nextPaintReference.msecsTo( QTime::currentTime()) % compositeRate );
}
bool Workspace::createOverlay() bool Workspace::createOverlay()
{ {
assert( overlay == None ); assert( overlay == None );
@ -661,6 +685,7 @@ void Toplevel::addDamage( int x, int y, int w, int h )
damage_region += r; damage_region += r;
repaints_region += r; repaints_region += r;
static_cast<EffectsHandlerImpl*>(effects)->windowDamaged( effectWindow(), r ); static_cast<EffectsHandlerImpl*>(effects)->windowDamaged( effectWindow(), r );
workspace()->checkCompositeTimer();
} }
void Toplevel::addDamageFull() void Toplevel::addDamageFull()
@ -670,6 +695,7 @@ void Toplevel::addDamageFull()
damage_region = rect(); damage_region = rect();
repaints_region = rect(); repaints_region = rect();
static_cast<EffectsHandlerImpl*>(effects)->windowDamaged( effectWindow(), rect()); static_cast<EffectsHandlerImpl*>(effects)->windowDamaged( effectWindow(), rect());
workspace()->checkCompositeTimer();
} }
void Toplevel::resetDamage( const QRect& r ) void Toplevel::resetDamage( const QRect& r )
@ -689,11 +715,13 @@ void Toplevel::addRepaint( int x, int y, int w, int h )
QRect r( x, y, w, h ); QRect r( x, y, w, h );
r &= rect(); r &= rect();
repaints_region += r; repaints_region += r;
workspace()->checkCompositeTimer();
} }
void Toplevel::addRepaintFull() void Toplevel::addRepaintFull()
{ {
repaints_region = rect(); repaints_region = rect();
workspace()->checkCompositeTimer();
} }
void Toplevel::resetRepaints( const QRect& r ) void Toplevel::resetRepaints( const QRect& r )

View file

@ -488,6 +488,7 @@ bool Workspace::workspaceEvent( XEvent * e )
addRepaintFull(); addRepaintFull();
QTimer::singleShot( 2000, this, SLOT( addRepaintFull())); QTimer::singleShot( 2000, this, SLOT( addRepaintFull()));
} }
checkCompositeTimer();
} }
break; break;
default: default:

View file

@ -331,6 +331,7 @@ class Workspace : public QObject, public KDecorationDefines
void destroyOverlay(); void destroyOverlay();
Window overlayWindow(); Window overlayWindow();
void checkUnredirect( bool force = false ); void checkUnredirect( bool force = false );
void checkCompositeTimer();
public slots: public slots:
void addRepaintFull(); void addRepaintFull();
@ -573,6 +574,7 @@ class Workspace : public QObject, public KDecorationDefines
void updateClientArea( bool force ); void updateClientArea( bool force );
bool windowRepaintsPending() const; bool windowRepaintsPending() const;
void setCompositeTimer();
int current_desktop; int current_desktop;
int number_of_desktops; int number_of_desktops;
@ -734,6 +736,7 @@ class Workspace : public QObject, public KDecorationDefines
bool compositingSuspended; bool compositingSuspended;
QTimer compositeTimer; QTimer compositeTimer;
QTime lastCompositePaint; QTime lastCompositePaint;
QTime nextPaintReference;
int compositeRate; int compositeRate;
QRegion repaints_region; QRegion repaints_region;
Window overlay; // XComposite overlay window Window overlay; // XComposite overlay window
@ -966,6 +969,13 @@ inline bool Workspace::hasClient( const Client* c )
return findClient( ClientMatchPredicate( c )); return findClient( ClientMatchPredicate( c ));
} }
inline
void Workspace::checkCompositeTimer()
{
if( !compositeTimer.isActive())
setCompositeTimer();
}
} // namespace } // namespace
#endif #endif