revert vsync strategy, fix timeouts
differecens to patch atteched to 258971: - removed debug statements - fixed indention... - NON vsync strategy does not rely on the estimation, but on the time passed since the last repaint trigger, allowing a precise framerate CCBUG: 258971 svn path=/trunk/KDE/kdebase/workspace/; revision=1210445
This commit is contained in:
parent
c81051a46f
commit
337e1eac18
9 changed files with 59 additions and 40 deletions
|
@ -199,8 +199,17 @@ void Workspace::setupCompositing()
|
|||
return;
|
||||
}
|
||||
xrrRefreshRate = KWin::currentRefreshRate();
|
||||
// invalidate timer -> bounds delay to 0 and the update happens instantly
|
||||
nextPaintReference = QTime::currentTime().addMSecs( -1000 );
|
||||
fpsInterval = (options->maxFpsInterval<<10);
|
||||
if ( scene->waitSyncAvailable() ) // if we do vsync, set the fps to the next multiple of the vblank rate
|
||||
{
|
||||
vBlankInterval = (1000<<10)/xrrRefreshRate;
|
||||
fpsInterval -= (fpsInterval % vBlankInterval);
|
||||
fpsInterval = qMax(fpsInterval, vBlankInterval);
|
||||
}
|
||||
else
|
||||
vBlankInterval = 1<<10; // no sync - DO NOT set "0", would cause div-by-zero segfaults.
|
||||
vBlankPadding = 3; // vblank rounding errors... :-(
|
||||
nextPaintReference = QTime::currentTime();
|
||||
checkCompositeTimer();
|
||||
composite_paint_times.clear();
|
||||
XCompositeRedirectSubwindows( display(), rootWindow(), CompositeRedirectManual );
|
||||
|
@ -388,9 +397,7 @@ void Workspace::performCompositing()
|
|||
if((( repaints_region.isEmpty() && !windowRepaintsPending()) // no damage
|
||||
|| !overlay_visible )) // nothing is visible anyway
|
||||
{
|
||||
// invalidate timer, we're idle, thus have already waited maxFps don't want to
|
||||
// wait more when we woke up
|
||||
nextPaintReference = QTime::currentTime().addMSecs( -1000 );
|
||||
vBlankPadding += 3;
|
||||
scene->idle();
|
||||
// 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
|
||||
|
@ -398,8 +405,6 @@ void Workspace::performCompositing()
|
|||
// Otherwise the window would not be painted normally anyway.
|
||||
return;
|
||||
}
|
||||
// we paint now, how much time ever it takes, we wanna show up in maxfps from now
|
||||
nextPaintReference = QTime::currentTime();
|
||||
// create a list of all windows in the stacking order
|
||||
ToplevelList windows = xStackingOrder();
|
||||
foreach( EffectWindow* c, static_cast< EffectsHandlerImpl* >( effects )->elevatedWindows())
|
||||
|
@ -432,7 +437,18 @@ void Workspace::performCompositing()
|
|||
// clear all repaints, so that post-pass can add repaints for the next repaint
|
||||
repaints_region = QRegion();
|
||||
QTime t = QTime::currentTime();
|
||||
scene->paint( repaints, windows );
|
||||
if ( scene->waitSyncAvailable() )
|
||||
{ // vsync: paint the scene, than rebase the timer and use the duration for next timeout estimation
|
||||
scene->paint( repaints, windows );
|
||||
nextPaintReference = QTime::currentTime();
|
||||
}
|
||||
else
|
||||
{ // no vsyc -> inversion: reset the timer, then paint the scene, this way we can provide a constant framerate
|
||||
nextPaintReference = QTime::currentTime();
|
||||
scene->paint( repaints, windows );
|
||||
}
|
||||
// reset the roundin error corrective... :-(
|
||||
vBlankPadding = 3;
|
||||
// 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
|
||||
|
@ -468,11 +484,25 @@ void Workspace::setCompositeTimer()
|
|||
{
|
||||
if( !compositing()) // should not really happen, but there may be e.g. some damage events still pending
|
||||
return;
|
||||
// should be added for the next paint. qBound() for protection; system time can change without notice.
|
||||
|
||||
if ( compositeTimer )
|
||||
killTimer( compositeTimer );
|
||||
int delay = options->maxFpsInterval - (qBound( 0, nextPaintReference.msecsTo( QTime::currentTime() ), 250 ) % options->maxFpsInterval);
|
||||
compositeTimer = startTimer( delay );
|
||||
|
||||
// interval - "time since last paint completion" - "time we need to paint"
|
||||
uint passed = nextPaintReference.msecsTo( QTime::currentTime() ) << 10;
|
||||
uint delay = fpsInterval;
|
||||
if ( scene->waitSyncAvailable() )
|
||||
{
|
||||
if ( passed > fpsInterval )
|
||||
{
|
||||
delay = vBlankInterval;
|
||||
passed %= vBlankInterval;
|
||||
}
|
||||
delay -= ( (passed + ((scene->estimatedRenderTime() + vBlankPadding)<<10) ) % vBlankInterval );
|
||||
}
|
||||
else
|
||||
delay = qBound( 0, int(delay - passed), 250<<10 );
|
||||
compositeTimer = startTimer( delay>>10 );
|
||||
}
|
||||
|
||||
void Workspace::startMousePolling()
|
||||
|
|
|
@ -251,7 +251,7 @@ unsigned long Options::updateSettings()
|
|||
CmdAllWheel = mouseWheelCommand(config.readEntry("CommandAllWheel","Nothing"));
|
||||
|
||||
config=KConfigGroup(_config,"Compositing");
|
||||
maxFpsInterval = qRound(1000.0/config.readEntry( "MaxFPS", 35 ));
|
||||
maxFpsInterval = qRound(1000.0/config.readEntry( "MaxFPS", 60 ));
|
||||
refreshRate = config.readEntry( "RefreshRate", 0 );
|
||||
|
||||
// Read button tooltip animation effect from kdeglobals
|
||||
|
|
2
scene.h
2
scene.h
|
@ -92,6 +92,7 @@ class Scene
|
|||
};
|
||||
// types of filtering available
|
||||
enum ImageFilterType { ImageFilterFast, ImageFilterGood };
|
||||
inline uint estimatedRenderTime() { return lastRenderTime; }
|
||||
// there's nothing to paint (adjust time_diff later)
|
||||
void idle();
|
||||
bool waitSyncAvailable() { return has_waitSync; }
|
||||
|
@ -143,6 +144,7 @@ class Scene
|
|||
QRegion painted_region;
|
||||
// time since last repaint
|
||||
int time_diff;
|
||||
uint lastRenderTime;
|
||||
QTime last_time;
|
||||
Workspace* wspace;
|
||||
bool has_waitSync;
|
||||
|
|
|
@ -44,6 +44,7 @@ SceneBasic::~SceneBasic()
|
|||
|
||||
void SceneBasic::paint( QRegion, ToplevelList windows )
|
||||
{
|
||||
QTime t = QTime::currentTime();
|
||||
Pixmap composite_pixmap = XCreatePixmap( display(), rootWindow(), displayWidth(), displayHeight(), DefaultDepth( display(), DefaultScreen( display())));
|
||||
XGCValues val;
|
||||
val.foreground = WhitePixel( display(), DefaultScreen( display()));
|
||||
|
@ -64,6 +65,7 @@ void SceneBasic::paint( QRegion, ToplevelList windows )
|
|||
qMax( 0, -(*it)->x()), qMax( 0, -(*it)->y()), r.width(), r.height(), r.x(), r.y());
|
||||
}
|
||||
}
|
||||
lastRenderTime = t.elapsed();
|
||||
XCopyArea( display(), composite_pixmap, rootWindow(), gc, 0, 0, displayWidth(), displayHeight(), 0, 0 );
|
||||
XFreeGC( display(), gc );
|
||||
XFreePixmap( display(), composite_pixmap );
|
||||
|
|
|
@ -111,9 +111,6 @@ GLXDrawable SceneOpenGL::last_pixmap = None;
|
|||
bool SceneOpenGL::tfp_mode; // using glXBindTexImageEXT (texture_from_pixmap)
|
||||
bool SceneOpenGL::db; // destination drawable is double-buffered
|
||||
bool SceneOpenGL::shm_mode;
|
||||
uint SceneOpenGL::vBlankInterval;
|
||||
uint SceneOpenGL::estimatedRenderTime = 0xfffffff; // Looooong - to ensure we wait on the first frame
|
||||
QTime SceneOpenGL::lastVBlank;
|
||||
#ifdef HAVE_XSHM
|
||||
XShmSegmentInfo SceneOpenGL::shm;
|
||||
#endif
|
||||
|
@ -129,8 +126,6 @@ SceneOpenGL::SceneOpenGL( Workspace* ws )
|
|||
kDebug( 1212 ) << "No glx extensions available";
|
||||
return; // error
|
||||
}
|
||||
vBlankInterval = (1000<<10) / KWin::currentRefreshRate();
|
||||
lastVBlank = QTime::currentTime();
|
||||
initGLX();
|
||||
// check for FBConfig support
|
||||
if( !hasGLExtension( "GLX_SGIX_fbconfig" ) || !glXGetFBConfigAttrib || !glXGetFBConfigs ||
|
||||
|
@ -171,7 +166,11 @@ SceneOpenGL::SceneOpenGL( Workspace* ws )
|
|||
{
|
||||
if( glXWaitVideoSync( 1, 0, &sync ) == 0 )
|
||||
has_waitSync = true;
|
||||
else
|
||||
qWarning() << "NO VSYNC! glXWaitVideoSync(1,0,&uint) isn't 0 but" << glXWaitVideoSync( 1, 0, &sync );
|
||||
}
|
||||
else
|
||||
qWarning() << "NO VSYNC! glXGetVideoSync(&uint) isn't 0 but" << glXGetVideoSync( &sync );
|
||||
}
|
||||
|
||||
// OpenGL scene setup
|
||||
|
@ -756,6 +755,7 @@ bool SceneOpenGL::selfCheckFinish()
|
|||
// the entry function for painting
|
||||
void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels )
|
||||
{
|
||||
QTime t = QTime::currentTime();
|
||||
foreach( Toplevel* c, toplevels )
|
||||
{
|
||||
assert( windows.contains( c ));
|
||||
|
@ -784,6 +784,7 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels )
|
|||
damage |= selfCheckRegion();
|
||||
}
|
||||
#endif
|
||||
lastRenderTime = t.elapsed();
|
||||
flushBuffer( mask, damage );
|
||||
#if 0
|
||||
if( !selfCheckDone )
|
||||
|
@ -803,30 +804,21 @@ void SceneOpenGL::waitSync()
|
|||
{ // NOTE that vsync has no effect with indirect rendering
|
||||
if( waitSyncAvailable())
|
||||
{
|
||||
// hackalert - we abuse "sync" as "remaining time before next estimated vblank"
|
||||
// reason: we do not "just wait" for the next vsync if we estimate that we can paint the
|
||||
// entire frame before this event, what could effectively mean "usleep(10000)", as it used to
|
||||
uint sync = ((lastVBlank.msecsTo( QTime::currentTime() )<<10) % vBlankInterval);
|
||||
if ( sync < (estimatedRenderTime+1)<<10 )
|
||||
{
|
||||
glFlush();
|
||||
glXGetVideoSync( &sync );
|
||||
glXWaitVideoSync( 2, ( sync + 1 ) % 2, &sync );
|
||||
lastVBlank = QTime::currentTime();
|
||||
}
|
||||
uint sync;
|
||||
glFlush();
|
||||
glXGetVideoSync( &sync );
|
||||
glXWaitVideoSync( 2, ( sync + 1 ) % 2, &sync );
|
||||
}
|
||||
}
|
||||
|
||||
// actually paint to the screen (double-buffer swap or copy from pixmap buffer)
|
||||
void SceneOpenGL::flushBuffer( int mask, QRegion damage )
|
||||
{
|
||||
QTime t;
|
||||
if( db )
|
||||
{
|
||||
if( mask & PAINT_SCREEN_REGION )
|
||||
{
|
||||
waitSync();
|
||||
t = QTime::currentTime();
|
||||
if( glXCopySubBuffer )
|
||||
{
|
||||
foreach( const QRect &r, damage.rects())
|
||||
|
@ -864,28 +856,22 @@ void SceneOpenGL::flushBuffer( int mask, QRegion damage )
|
|||
else
|
||||
{
|
||||
waitSync();
|
||||
t = QTime::currentTime();
|
||||
glXSwapBuffers( display(), glxbuffer );
|
||||
}
|
||||
glXWaitGL();
|
||||
XFlush( display());
|
||||
estimatedRenderTime = t.elapsed();
|
||||
}
|
||||
else
|
||||
{
|
||||
t = QTime::currentTime();
|
||||
glFlush();
|
||||
glXWaitGL();
|
||||
estimatedRenderTime = t.elapsed();
|
||||
waitSync();
|
||||
t = QTime::currentTime();
|
||||
if( mask & PAINT_SCREEN_REGION )
|
||||
foreach( const QRect &r, damage.rects())
|
||||
XCopyArea( display(), buffer, rootWindow(), gcroot, r.x(), r.y(), r.width(), r.height(), r.x(), r.y());
|
||||
else
|
||||
XCopyArea( display(), buffer, rootWindow(), gcroot, 0, 0, displayWidth(), displayHeight(), 0, 0 );
|
||||
XFlush( display());
|
||||
estimatedRenderTime += t.elapsed();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -90,8 +90,6 @@ class SceneOpenGL
|
|||
static GLXDrawable last_pixmap; // for a workaround in bindTexture()
|
||||
static bool tfp_mode;
|
||||
static bool shm_mode;
|
||||
static uint vBlankInterval, estimatedRenderTime;
|
||||
static QTime lastVBlank;
|
||||
QHash< Toplevel*, Window* > windows;
|
||||
#ifdef HAVE_XSHM
|
||||
static XShmSegmentInfo shm;
|
||||
|
|
|
@ -271,6 +271,7 @@ bool SceneXrender::selfCheckFinish()
|
|||
// the entry point for painting
|
||||
void SceneXrender::paint( QRegion damage, ToplevelList toplevels )
|
||||
{
|
||||
QTime t = QTime::currentTime();
|
||||
foreach( Toplevel* c, toplevels )
|
||||
{
|
||||
assert( windows.contains( c ));
|
||||
|
@ -285,6 +286,7 @@ void SceneXrender::paint( QRegion damage, ToplevelList toplevels )
|
|||
selfCheckSetup();
|
||||
damage |= selfCheckRegion();
|
||||
}
|
||||
lastRenderTime = t.elapsed();
|
||||
flushBuffer( mask, damage );
|
||||
if( !selfCheckDone )
|
||||
{
|
||||
|
|
|
@ -152,7 +152,6 @@ Workspace::Workspace( bool restore )
|
|||
, cm_selection( NULL )
|
||||
, compositingSuspended( false )
|
||||
, compositeTimer( 0 )
|
||||
, vBlankInterval( 0 )
|
||||
, xrrRefreshRate( 0 )
|
||||
, overlay( None )
|
||||
, overlay_visible( true )
|
||||
|
|
|
@ -1062,7 +1062,7 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
int compositeTimer;
|
||||
QTime nextPaintReference;
|
||||
QTimer mousePollingTimer;
|
||||
uint vBlankInterval;
|
||||
uint vBlankInterval, vBlankPadding, fpsInterval, estimatedRenderTime;
|
||||
int xrrRefreshRate; // used only for compositing
|
||||
QRegion repaints_region;
|
||||
Window overlay; // XComposite overlay window
|
||||
|
|
Loading…
Reference in a new issue