[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    KDE/kdebase/workspace/kwin
From:       Thomas Lübking <thomas.luebking () gmail ! com>
Date:       2010-12-18 16:51:44
Message-ID: 20101218165144.500C4AC8A8 () svn ! kde ! org
[Download RAW message or body]

SVN commit 1207577 by luebking:

commiting http://svn.reviewboard.kde.org/r/6120/#review9304
this should improve v'syncing, maybe v'synced "smoothness"
remaining and exposed issue are "dirty textures" w/o damage events (see the requst \
description) can be diminished by increasing MaxFPS above the fastest update (or \
                shadowed below the slowest one)
CCBUG: 258971


 M  +32 -37    composite.cpp  
 M  +4 -1      options.cpp  
 M  +1 -0      options.h  
 M  +23 -2     scene_opengl.cpp  
 M  +2 -0      scene_opengl.h  
 M  +2 -2      workspace.cpp  
 M  +4 -4      workspace.h  


--- trunk/KDE/kdebase/workspace/kwin/composite.cpp #1207576:1207577
@@ -57,6 +57,7 @@
 #include <stdio.h>
 
 #include <QMenu>
+#include <QTimerEvent>
 #include <kaction.h>
 #include <kactioncollection.h>
 #include <klocale.h>
@@ -197,12 +198,9 @@
         delete cm_selection;
         return;
         }
-    int rate = xrrRefreshRate = KWin::currentRefreshRate();
-    compositeRate = 1000 / rate;
-    lastCompositePaint.start();
-    // fake a previous paint, so that the next starts right now
-    nextPaintReference = QTime::currentTime().addMSecs( -compositeRate );
-    compositeTimer.setSingleShot( true );
+    xrrRefreshRate = KWin::currentRefreshRate();
+    // invalidate timer -> bounds delay to 0 and the update happens instantly
+    nextPaintReference = QTime::currentTime().addMSecs( -1000 );
     checkCompositeTimer();
     composite_paint_times.clear();
     XCompositeRedirectSubwindows( display(), rootWindow(), CompositeRedirectManual \
); @@ -253,7 +251,9 @@
     effects = NULL;
     delete scene;
     scene = NULL;
-    compositeTimer.stop();
+    if (compositeTimer)
+        killTimer(compositeTimer);
+    compositeTimer = 0;
     mousePollingTimer.stop();
     repaints_region = QRegion();
     for( ClientList::ConstIterator it = clients.constBegin();
@@ -370,24 +370,27 @@
     checkCompositeTimer();
     }
 
-void Workspace::performCompositing()
+void Workspace::timerEvent( QTimerEvent *te )
     {
-#ifdef KWIN_HAVE_COMPOSITING
-    // The event loop apparently tries to fire a QTimer as often as possible, even
-    // at the expense of not processing many X events. This means that the composite
-    // repaints can seriously impact performance of everything else, therefore \
                throttle
-    // them - leave at least 1msec time after one repaint is finished and next one
-    // is started.
-    if( lastCompositePaint.elapsed() < 1 )
+    if ( te->timerId() == compositeTimer )
         {
-        compositeTimer.start( 1 );
-        return;
+        killTimer( compositeTimer );
+        compositeTimer = 0;
+        performCompositing();
         }
-    if( !scene->waitSyncAvailable())
-        nextPaintReference = QTime::currentTime();
+    else
+        QObject::timerEvent( te );
+}
+
+void Workspace::performCompositing()
+    {
+#ifdef KWIN_HAVE_COMPOSITING
     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 );
         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 @@ -395,6 +398,8 @@
         // 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()) @@ -403,19 +408,16 @@
         windows.removeAll( t );
         windows.append( t );
         }
+#if 0
     // skip windows that are not yet ready for being painted
     ToplevelList tmp = windows;
     windows.clear();
-#if 0
     // There is a bug somewhere that prevents this from working properly (#160393), \
                but additionally
     // this cannot be used so carelessly - needs protections against broken clients, \
                the window
     // should not get focus before it's displayed, handle unredirected windows \
properly and so on.  foreach( Toplevel* c, tmp )
         if( c->readyForPainting())
             windows.append( c );
-#else
-    foreach( Toplevel* c, tmp )
-        windows.append( c );
 #endif
     foreach( Toplevel* c, windows )
         { // This could be possibly optimized WRT obscuring, but that'd need being \
already @@ -431,23 +433,12 @@
     repaints_region = QRegion();
     QTime t = QTime::currentTime();
     scene->paint( repaints, windows );
-    if( scene->waitSyncAvailable())
-        {
-        // 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. We have just \
                synced, and
-        // nextPaintReference is time from which multiples of compositeRate should \
                be added,
-        // 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();
     checkCompositePaintTime( t.elapsed());
-    lastCompositePaint.start();
 #endif
     }
 
@@ -477,9 +468,11 @@
     {
     if( !compositing()) // should not really happen, but there may be e.g. some \
damage events still pending  return;
-    // The last paint set nextPaintReference as a reference time to which multiples \
                of compositeRate
     // should be added for the next paint. qBound() for protection; system time can \
                change without notice.
-    compositeTimer.start( qBound( 0, nextPaintReference.msecsTo( \
QTime::currentTime() ), 250 ) % compositeRate ); +    if ( compositeTimer )
+        killTimer( compositeTimer );
+    int delay = options->maxFpsInterval - (qBound( 0, nextPaintReference.msecsTo( \
QTime::currentTime() ), 250 ) % options->maxFpsInterval); +    compositeTimer = \
startTimer( delay );  }
 
 void Workspace::startMousePolling()
@@ -567,7 +560,9 @@
                 "If this was only a temporary problem, you can resume using the '%1' \
                shortcut.\n"
                 "You can disable functionality checks in System Settings (on the \
Advanced tab in Desktop Effects).", shortcut );  Notify::raise( \
                Notify::CompositingSlow, message );
-        compositeTimer.start( 1000 ); // so that it doesn't trigger sooner than \
suspendCompositing() +        if ( compositeTimer )
+            killTimer( compositeTimer );
+        compositeTimer = startTimer( 1000 ); // so that it doesn't trigger sooner \
than suspendCompositing()  }
     }
 
--- trunk/KDE/kdebase/workspace/kwin/options.cpp #1207576:1207577
@@ -66,9 +66,11 @@
             {
             QString reply = QString::fromLocal8Bit( \
nvidia_settings.readAllStandardOutput() );  bool ok;
-            rate = reply.split(' \
').first().split(KGlobal::locale()->decimalSymbol()).first().toUInt( &ok ); +         \
const float frate = reply.split(' ').first().toFloat( &ok );  if ( !ok )
                 rate = -1;
+            else
+                rate = qRound(frate);
             }
         }
 #ifdef HAVE_XRANDR
@@ -247,6 +249,7 @@
     CmdAllWheel = mouseWheelCommand(config.readEntry("CommandAllWheel","Nothing"));
 
     config=KConfigGroup(_config,"Compositing");
+    maxFpsInterval = qRound(1000.0/config.readEntry( "MaxFPS", 35 ));
     refreshRate = config.readEntry( "RefreshRate", 0 );
 
     // Read button tooltip animation effect from kdeglobals
--- trunk/KDE/kdebase/workspace/kwin/options.h #1207576:1207577
@@ -365,6 +365,7 @@
         // XRender
         bool xrenderSmoothScale;
 
+        uint maxFpsInterval;
         // Settings that should be auto-detected
         uint refreshRate;
         bool glDirect;
--- trunk/KDE/kdebase/workspace/kwin/scene_opengl.cpp #1207576:1207577
@@ -91,6 +91,8 @@
 namespace KWin
 {
 
+extern int currentRefreshRate();
+
 //****************************************
 // SceneOpenGL
 //****************************************
@@ -109,6 +111,9 @@
 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
@@ -124,6 +129,8 @@
         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 || @@ -796,22 +803,30 @@
     { // NOTE that vsync has no effect with indirect rendering
     if( waitSyncAvailable())
         {
-        unsigned int sync;
-
+        // 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();
         }
     }
+    }
 
 // 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())
@@ -849,22 +864,28 @@
         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();
         }
     }
 
--- trunk/KDE/kdebase/workspace/kwin/scene_opengl.h #1207576:1207577
@@ -90,6 +90,8 @@
         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;
--- trunk/KDE/kdebase/workspace/kwin/workspace.cpp #1207576:1207577
@@ -151,7 +151,8 @@
     , forced_global_mouse_grab( false )
     , cm_selection( NULL )
     , compositingSuspended( false )
-    , compositeRate( 0 )
+    , compositeTimer( 0 )
+    , vBlankInterval( 0 )
     , xrrRefreshRate( 0 )
     , overlay( None )
     , overlay_visible( true )
@@ -384,7 +385,6 @@
 
     connect( &reconfigureTimer, SIGNAL( timeout() ), this, SLOT( slotReconfigure() \
                ));
     connect( &updateToolWindowsTimer, SIGNAL( timeout() ), this, SLOT( \
                slotUpdateToolWindows() ));
-    connect( &compositeTimer, SIGNAL( timeout() ), SLOT( performCompositing() ));
     connect( &mousePollingTimer, SIGNAL( timeout() ), SLOT( performMousePoll() ));
 
     connect( KGlobalSettings::self(), SIGNAL( appearanceChanged() ), this, SLOT( \
                reconfigure() ));
--- trunk/KDE/kdebase/workspace/kwin/workspace.h #1207576:1207577
@@ -774,6 +774,7 @@
 
     protected:
         bool keyPressMouseEmulation( XKeyEvent& ev );
+        void timerEvent( QTimerEvent *te );
 
     Q_SIGNALS:
         Q_SCRIPTABLE void compositingToggled( bool active );
@@ -1058,11 +1059,10 @@
 
         KSelectionOwner* cm_selection;
         bool compositingSuspended;
-        QTimer compositeTimer;
-        QTime lastCompositePaint;
+        int compositeTimer;
         QTime nextPaintReference;
         QTimer mousePollingTimer;
-        int compositeRate;
+        uint vBlankInterval;
         int xrrRefreshRate; // used only for compositing
         QRegion repaints_region;
         Window overlay; // XComposite overlay window
@@ -1348,7 +1348,7 @@
 
 inline void Workspace::checkCompositeTimer()
     {
-    if( !compositeTimer.isActive() )
+    if( !compositeTimer )
         setCompositeTimer();
     }
 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic