Better synchronization of refresh rate and vsyncing,

patch by Philip Falkner.


svn path=/branches/work/kwin_composite/; revision=610110
This commit is contained in:
Luboš Luňák 2006-12-03 13:29:14 +00:00
parent 50b7fc5409
commit 6a66250620
6 changed files with 102 additions and 38 deletions

View file

@ -107,7 +107,8 @@ void Workspace::setupCompositing()
else if( rate > 1000 )
rate = 1000;
kDebug( 1212 ) << "Refresh rate " << rate << "Hz" << endl;
compositeTimer.start( 1000 / rate );
compositeRate = 1000 / rate;
compositeTimer.start( compositeRate );
lastCompositePaint.start();
XCompositeRedirectSubwindows( display(), rootWindow(), CompositeRedirectManual );
if( dynamic_cast< SceneOpenGL* >( scene ))
@ -228,6 +229,16 @@ void Workspace::performCompositing()
// clear all damage, so that post-pass can add damage for the next repaint
damage_region = QRegion();
scene->paint( damage, windows );
if( scene->waitSyncAvailable() && options->glVSync )
{ // if we're using vsync, then time the next paint pass to
// before the next available sync
int paintTime = ( lastCompositePaint.elapsed() % compositeRate ) +
( compositeRate / 2 );
if( paintTime >= compositeRate )
compositeTimer.start( paintTime );
else if( paintTime < compositeRate )
compositeTimer.start( compositeRate - paintTime );
}
lastCompositePaint.start();
}

View file

@ -84,7 +84,8 @@ namespace KWinInternal
Scene* scene;
Scene::Scene( Workspace* ws )
: wspace( ws )
: wspace( ws ),
has_waitSync( false )
{
}

View file

@ -62,6 +62,7 @@ class Scene
};
// there's nothing to paint (adjust time_diff later)
void idle();
bool waitSyncAvailable() { return has_waitSync; }
protected:
// shared implementation, starts painting the screen
void paintScreen( int* mask, QRegion* region );
@ -97,6 +98,7 @@ class Scene
int time_diff;
QTime last_time;
Workspace* wspace;
bool has_waitSync;
};
// The base class for windows representations in composite backends

View file

@ -175,6 +175,7 @@ SceneOpenGL::SceneOpenGL( Workspace* ws )
initGL();
if( db )
glDrawBuffer( GL_BACK );
has_waitSync = glXGetVideoSync ? true : false;
// Check whether certain features are supported
supports_saturation = ((hasGLExtension("GL_ARB_texture_env_crossbar")
@ -456,13 +457,10 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels )
// wait for vblank signal before painting
void SceneOpenGL::waitSync()
{ // NOTE that vsync has no effect with indirect rendering
bool vsync = options->glVSync;
unsigned int sync;
if( !vsync )
return;
if( glXGetVideoSync )
if( waitSyncAvailable() && options->glVSync )
{
unsigned int sync;
glFlush();
glXGetVideoSync( &sync );
glXWaitVideoSync( 2, ( sync + 1 ) % 2, &sync );

View file

@ -42,6 +42,9 @@ License. See the file "COPYING" for the exact licensing terms.
#include "group.h"
#include "rules.h"
#include "kwinadaptor.h"
#include "unmanaged.h"
#include "scene.h"
#include "effects.h"
#include <X11/extensions/shape.h>
#include <X11/keysym.h>
@ -93,6 +96,7 @@ Workspace::Workspace( bool restore )
popupinfo (0),
popup (0),
advanced_popup (0),
trans_popup (0),
desk_popup (0),
desk_popup_index (0),
keys (0),
@ -122,7 +126,13 @@ Workspace::Workspace( bool restore )
topmenu_space( NULL ),
set_active_client_recursion( 0 ),
block_stacking_updates( 0 ),
forced_global_mouse_grab( false )
forced_global_mouse_grab( false ),
cm_selection( NULL ),
compositeRate( 0 ),
damage_region( None ),
overlay( None ),
transSlider( NULL ),
transButton( NULL )
{
new KWinAdaptor( "org.kde.kwin", "/KWin", QDBusConnection::sessionBus(), this );
@ -166,10 +176,12 @@ Workspace::Workspace( bool restore )
ColormapChangeMask |
SubstructureRedirectMask |
SubstructureNotifyMask |
FocusChangeMask // for NotifyDetailNone
FocusChangeMask | // for NotifyDetailNone
ExposureMask
);
Shape::init();
Extensions::init();
setupCompositing();
// compatibility
long data = 1;
@ -318,6 +330,7 @@ void Workspace::init()
connect(&reconfigureTimer, SIGNAL(timeout()), this,
SLOT(slotReconfigure()));
connect( &updateToolWindowsTimer, SIGNAL( timeout()), this, SLOT( slotUpdateToolWindows()));
connect( &compositeTimer, SIGNAL( timeout()), SLOT( performCompositing()));
connect(KGlobalSettings::self(), SIGNAL(appearanceChanged()), this,
SLOT(slotReconfigure()));
@ -355,7 +368,11 @@ void Workspace::init()
XWindowAttributes attr;
XGetWindowAttributes(display(), wins[i], &attr);
if (attr.override_redirect )
{
if( attr.map_state != IsUnmapped && attr.c_class != InputOnly && compositing())
createUnmanaged( wins[ i ] );
continue;
}
if( topmenu_space && topmenu_space->winId() == wins[ i ] )
continue;
if (attr.map_state != IsUnmapped)
@ -418,6 +435,7 @@ void Workspace::init()
Workspace::~Workspace()
{
finishCompositing();
blockStackingUpdates( true );
// TODO grabXServer();
// use stacking_order, so that kwin --replace keeps stacking order
@ -429,6 +447,10 @@ Workspace::~Workspace()
(*it)->releaseWindow( true );
// no removeClient() is called !
}
for( UnmanagedList::ConstIterator it = unmanaged.begin();
it != unmanaged.end();
++it )
(*it)->release();
delete desktop_widget;
delete tab_box;
delete popupinfo;
@ -472,6 +494,28 @@ Client* Workspace::createClient( Window w, bool is_mapped )
return NULL;
}
addClient( c, Allowed );
if( scene )
scene->windowAdded( c );
if( effects )
effects->windowAdded( c );
return c;
}
Unmanaged* Workspace::createUnmanaged( Window w )
{
if( w == overlay )
return NULL;
Unmanaged* c = new Unmanaged( this );
if( !c->track( w ))
{
Unmanaged::deleteUnmanaged( c, Allowed );
return NULL;
}
addUnmanaged( c, Allowed );
if( scene )
scene->windowAdded( c );
if( effects )
effects->windowAdded( c );
return c;
}
@ -514,6 +558,11 @@ void Workspace::addClient( Client* c, allowed_t )
updateToolWindows( true );
}
void Workspace::addUnmanaged( Unmanaged* c, allowed_t )
{
unmanaged.append( c );
}
/*
Destroys the client \a c
*/
@ -524,7 +573,7 @@ void Workspace::removeClient( Client* c, allowed_t )
if( client_keys_client == c )
setupWindowShortcutDone( false );
if( !c->shortcut().isEmpty())
if( !c->shortcut().isNull())
c->setShortcut( QString() ); // remove from client_keys
if( c->isDialog())
@ -533,6 +582,10 @@ void Workspace::removeClient( Client* c, allowed_t )
Notify::raise( Notify::Delete );
Q_ASSERT( clients.contains( c ) || desktops.contains( c ));
if( scene )
scene->windowDeleted( c );
if( effects )
effects->windowDeleted( c );
clients.removeAll( c );
desktops.removeAll( c );
unconstrained_stacking_order.removeAll( c );
@ -568,6 +621,16 @@ void Workspace::removeClient( Client* c, allowed_t )
updateClientArea();
}
void Workspace::removeUnmanaged( Unmanaged* c, allowed_t )
{
assert( unmanaged.contains( c ));
if( scene )
scene->windowDeleted( c );
if( effects )
effects->windowDeleted( c );
unmanaged.removeAll( c );
}
void Workspace::updateFocusChains( Client* c, FocusChainChange change )
{
if( !c->wantsTabFocus()) // doesn't want tab focus, remove
@ -593,13 +656,7 @@ void Workspace::updateFocusChains( Client* c, FocusChainChange change )
focus_chain[ i ].prepend( c );
}
else if( !focus_chain[ i ].contains( c ))
{ // add it after the active one
if( active_client != NULL && active_client != c
&& !focus_chain[ i ].isEmpty() && focus_chain[ i ].last() == active_client )
focus_chain[ i ].insert( focus_chain[ i ].size() - 1, c );
else
focus_chain[ i ].append( c ); // otherwise add as the first one
}
focus_chain[ i ].prepend( c ); // otherwise add as the last one
}
}
else //now only on desktop, remove it anywhere else
@ -619,13 +676,7 @@ void Workspace::updateFocusChains( Client* c, FocusChainChange change )
focus_chain[ i ].prepend( c );
}
else if( !focus_chain[ i ].contains( c ))
{ // add it after the active one
if( active_client != NULL && active_client != c
&& !focus_chain[ i ].isEmpty() && focus_chain[ i ].last() == active_client )
focus_chain[ i ].insert( focus_chain[ i ].size() - 1, c );
else
focus_chain[ i ].append( c ); // otherwise add as the first one
}
focus_chain[ i ].prepend( c );
}
else
focus_chain[ i ].removeAll( c );
@ -642,13 +693,7 @@ void Workspace::updateFocusChains( Client* c, FocusChainChange change )
global_focus_chain.prepend( c );
}
else if( !global_focus_chain.contains( c ))
{ // add it after the active one
if( active_client != NULL && active_client != c
&& !global_focus_chain.isEmpty() && global_focus_chain.last() == active_client )
global_focus_chain.insert( global_focus_chain.size() - 1, c );
else
global_focus_chain.append( c ); // otherwise add as the first one
}
global_focus_chain.prepend( c );
}
void Workspace::updateCurrentTopMenu()
@ -882,7 +927,7 @@ void Workspace::slotSettingsChanged(int category)
/*!
Reread settings
*/
KWIN_PROCEDURE( CheckBorderSizesProcedure, cl->checkBorderSizes() );
KWIN_PROCEDURE( CheckBorderSizesProcedure, Client, cl->checkBorderSizes() );
void Workspace::slotReconfigure()
{
@ -939,6 +984,11 @@ void Workspace::slotReconfigure()
updateTopMenuGeometry();
updateCurrentTopMenu();
}
if( options->useTranslucency )
setupCompositing();
else
finishCompositing();
loadWindowRules();
for( ClientList::Iterator it = clients.begin();
@ -1640,7 +1690,7 @@ void Workspace::slotGrabWindow()
QPixmap snapshot = QPixmap::grabWindow( active_client->frameId() );
//No XShape - no work.
if( Shape::available())
if( Extensions::shapeAvailable())
{
//As the first step, get the mask from XShape.
int count, order;
@ -1993,7 +2043,8 @@ void Workspace::createBorderWindows()
XSetWindowAttributes attributes;
unsigned long valuemask;
attributes.override_redirect = True;
attributes.event_mask = ( EnterWindowMask | LeaveWindowMask );
attributes.event_mask = (EnterWindowMask | LeaveWindowMask |
VisibilityChangeMask);
valuemask= (CWOverrideRedirect | CWEventMask | CWCursor );
attributes.cursor = XCreateFontCursor(display(),
XC_sb_up_arrow);
@ -2352,7 +2403,7 @@ void Workspace::helperDialog( const QString& message, const Client* c )
{
KAction* action = keys->action( "Window Operations Menu" );
QString shortcut = QString( "%1 (%2)" ).arg( action->text() )
.arg( action->globalShortcut().primary().toString());
.arg( action->globalShortcut().seq( 0 ).toString());
args << "--msgbox" <<
i18n( "You have selected to show a window without its border.\n"
"Without the border, you will not be able to enable the border "
@ -2365,7 +2416,7 @@ void Workspace::helperDialog( const QString& message, const Client* c )
{
KAction* action = keys->action( "Window Operations Menu" );
QString shortcut = QString( "%1 (%2)" ).arg( action->text() )
.arg( action->globalShortcut().primary().toString());
.arg( action->globalShortcut().seq( 0 ).toString());
args << "--msgbox" <<
i18n( "You have selected to show a window in fullscreen mode.\n"
"If the application itself does not have an option to turn the fullscreen "

View file

@ -682,6 +682,7 @@ class Workspace : public QObject, public KDecorationDefines
KSelectionOwner* cm_selection;
QTimer compositeTimer;
QTime lastCompositePaint;
int compositeRate;
QRegion damage_region;
Window overlay; // XComposite overlay window
QSlider *transSlider;