diff --git a/main.cpp b/main.cpp index b9db78f700..7b70502a56 100644 --- a/main.cpp +++ b/main.cpp @@ -68,7 +68,7 @@ Atoms* atoms; int screen_number = -1; -static bool initting = false; +bool initting = false; /** * Whether to run Xlib in synchronous mode and print backtraces for X errors. @@ -180,7 +180,7 @@ static int x11ErrorHandler( Display* d, XErrorEvent* e ) fprintf( stderr, "kwin: X Error (%s)\n", errorMessage( *e, d ).data() ); if( kwin_sync ) - fprintf( stderr, "%s\n", kBacktrace().toLocal8Bit().data() ); + fprintf( stderr, "%s\n", kBacktrace().toLocal8Bit().data() ); if( initting ) { diff --git a/scene.cpp b/scene.cpp index 3acf357b99..6642ea7530 100644 --- a/scene.cpp +++ b/scene.cpp @@ -89,8 +89,9 @@ namespace KWin Scene* scene; Scene::Scene( Workspace* ws ) - : wspace( ws ), - has_waitSync( false ) + : wspace( ws ) + , has_waitSync( false ) + , selfCheckDone( false ) { } @@ -337,6 +338,14 @@ QList< QPoint > Scene::selfCheckPoints() const return ret; } +QRegion Scene::selfCheckRegion() const + { + QRegion reg; + foreach( const QPoint& p, selfCheckPoints()) + reg |= QRect( p, QSize( selfCheckWidth(), selfCheckHeight())); + return reg; + } + //**************************************** // Scene::Window //**************************************** diff --git a/scene.h b/scene.h index 680e3433a8..8c326f2ea7 100644 --- a/scene.h +++ b/scene.h @@ -108,6 +108,10 @@ class Scene // compute time since the last repaint void updateTimeDiff(); QList< QPoint > selfCheckPoints() const; + QRegion selfCheckRegion() const; + // dimensions of the test pixmap for selfcheck + int selfCheckWidth() const; + int selfCheckHeight() const; // saved data for 2nd pass of optimized screen painting struct Phase2Data { @@ -133,6 +137,7 @@ class Scene QTime last_time; Workspace* wspace; bool has_waitSync; + bool selfCheckDone; }; // The base class for windows representations in composite backends @@ -198,6 +203,18 @@ class Scene::Window extern Scene* scene; +inline +int Scene::selfCheckWidth() const + { + return 3; + } + +inline +int Scene::selfCheckHeight() const + { + return 2; + } + inline int Scene::Window::x() const { diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 6fb8f9cf65..4b34a1b69d 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -183,8 +183,16 @@ SceneOpenGL::SceneOpenGL( Workspace* ws ) kError( 1212 ) << "OpenGL compositing setup failed"; return; // error } - if( !selfCheck()) - return; + // Do self-check immediatelly during compositing setup only when it's not KWin startup + // at the same time (in other words, only when activating compositing using the kcm). + // Currently selfcheck causes bad flicker (due to X mapping the overlay window + // for too long?) which looks bad during KDE startup. + if( !initting ) + { + if( !selfCheck()) + return; + selfCheckDone = true; + } kDebug( 1212 ) << "DB:" << db << ", TFP:" << tfp_mode << ", SHM:" << shm_mode << ", Direct:" << bool( glXIsDirect( display(), ctxbuffer )) << endl; init_ok = true; @@ -624,10 +632,28 @@ bool SceneOpenGL::initDrawableConfigs() // Test if compositing actually _really_ works, by creating a texture from a testing // window, drawing it on the screen, reading the contents back and comparing. This // should test whether compositing really works. -// It would be still nice to check somehow if compositing is not awfully slow. +// This function does the whole selfcheck, it can be done also in two parts +// during actual drawing (to avoid flicker, see selfCheck() call from the ctor). bool SceneOpenGL::selfCheck() { - QImage img( 3, 2, QImage::Format_RGB32 ); + QRegion reg = selfCheckRegion(); + if( wspace->overlayWindow()) + { // avoid covering the whole screen too soon + wspace->setOverlayShape( reg ); + wspace->showOverlay(); + } + selfCheckSetup(); + flushBuffer( PAINT_SCREEN_REGION, reg ); + bool ok = selfCheckFinish(); + if( wspace->overlayWindow()) + wspace->hideOverlay(); + return ok; + } + +void SceneOpenGL::selfCheckSetup() + { + KXErrorHandler err; + QImage img( selfCheckWidth(), selfCheckHeight(), QImage::Format_RGB32 ); img.setPixel( 0, 0, QColor( Qt::red ).rgb()); img.setPixel( 1, 0, QColor( Qt::green ).rgb()); img.setPixel( 2, 0, QColor( Qt::blue ).rgb()); @@ -635,46 +661,42 @@ bool SceneOpenGL::selfCheck() img.setPixel( 1, 1, QColor( Qt::black ).rgb()); img.setPixel( 2, 1, QColor( Qt::white ).rgb()); QPixmap pix = QPixmap::fromImage( img ); - QList< QPoint > points = selfCheckPoints(); - QRegion reg; - foreach( const QPoint& p, points ) - reg |= QRect( p, pix.size()); - if( wspace->overlayWindow()) - { // avoid covering the whole screen too soon - wspace->setOverlayShape( reg ); - wspace->showOverlay(); - } - foreach( const QPoint& p, points ) + foreach( const QPoint& p, selfCheckPoints()) { XSetWindowAttributes wa; wa.override_redirect = True; - ::Window window = XCreateWindow( display(), rootWindow(), 0, 0, 3, 2, 0, QX11Info::appDepth(), - CopyFromParent, CopyFromParent, CWOverrideRedirect, &wa ); + ::Window window = XCreateWindow( display(), rootWindow(), 0, 0, selfCheckWidth(), selfCheckHeight(), + 0, QX11Info::appDepth(), CopyFromParent, CopyFromParent, CWOverrideRedirect, &wa ); XSetWindowBackgroundPixmap( display(), window, pix.handle()); XClearWindow( display(), window ); XMapWindow( display(), window ); // move the window one down to where the result will be rendered too, just in case // the render would fail completely and eventual check would try to read this window's contents XMoveWindow( display(), window, p.x() + 1, p.y()); - XCompositeRedirectWindow( display(), window, CompositeRedirectManual ); + XCompositeRedirectWindow( display(), window, CompositeRedirectAutomatic ); Pixmap wpix = XCompositeNameWindowPixmap( display(), window ); glXWaitX(); Texture texture; - texture.load( wpix, QSize( 3, 2 ), QX11Info::appDepth()); + texture.load( wpix, QSize( selfCheckWidth(), selfCheckHeight()), QX11Info::appDepth()); texture.bind(); - QRect rect( p.x(), p.y(), 3, 2 ); + QRect rect( p.x(), p.y(), selfCheckWidth(), selfCheckHeight()); texture.render( infiniteRegion(), rect ); texture.unbind(); glXWaitGL(); XFreePixmap( display(), wpix ); XDestroyWindow( display(), window ); } - flushBuffer( PAINT_SCREEN_REGION, reg ); + err.error( true ); // just sync and discard + } + +bool SceneOpenGL::selfCheckFinish() + { glXWaitGL(); + KXErrorHandler err; bool ok = true; - foreach( const QPoint& p, points ) + foreach( const QPoint& p, selfCheckPoints()) { - QPixmap pix = QPixmap::grabWindow( rootWindow(), p.x(), p.y(), 3, 2 ); + QPixmap pix = QPixmap::grabWindow( rootWindow(), p.x(), p.y(), selfCheckWidth(), selfCheckHeight()); QImage img = pix.toImage(); // kDebug(1212) << "P:" << QColor( img.pixel( 0, 0 )).name(); // kDebug(1212) << "P:" << QColor( img.pixel( 1, 0 )).name(); @@ -694,8 +716,8 @@ bool SceneOpenGL::selfCheck() break; } } - if( wspace->overlayWindow()) - wspace->hideOverlay(); + if( err.error( true )) + ok = false; if( ok ) kDebug( 1212 ) << "Compositing self-check passed."; if( !ok && options->disableCompositingChecks ) @@ -729,7 +751,18 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels ) ungrabXServer(); // ungrab before flushBuffer(), it may wait for vsync if( wspace->overlayWindow()) // show the window only after the first pass, since wspace->showOverlay(); // that pass may take long + if( !selfCheckDone ) + { + selfCheckSetup(); + damage |= selfCheckRegion(); + } flushBuffer( mask, damage ); + if( !selfCheckDone ) + { + if( !selfCheckFinish()) + QTimer::singleShot( 0, Workspace::self(), SLOT( finishCompositing())); + selfCheckDone = true; + } // do cleanup stacking_order.clear(); checkGLError( "PostPaint" ); diff --git a/scene_opengl.h b/scene_opengl.h index 6be75c6ea6..3e7c636b64 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -65,6 +65,8 @@ class SceneOpenGL void waitSync(); void flushBuffer( int mask, QRegion damage ); bool selfCheck(); + void selfCheckSetup(); + bool selfCheckFinish(); GC gcroot; class FBConfigInfo { @@ -91,6 +93,7 @@ class SceneOpenGL static XShmSegmentInfo shm; #endif bool init_ok; + bool selfCheckDone; }; class SceneOpenGL::Texture diff --git a/scene_xrender.cpp b/scene_xrender.cpp index 33b827de13..35a7e5ffc5 100644 --- a/scene_xrender.cpp +++ b/scene_xrender.cpp @@ -131,8 +131,12 @@ SceneXrender::SceneXrender( Workspace* ws ) kError( 1212 ) << "XRender compositing setup failed"; return; } - if( !selfCheck()) - return; + if( !initting ) // see comment for opengl version + { + if( !selfCheck()) + return; + selfCheckDone = true; + } init_ok = true; } @@ -169,7 +173,24 @@ void SceneXrender::createBuffer() // Just like SceneOpenGL::selfCheck() bool SceneXrender::selfCheck() { - QImage img( 3, 2, QImage::Format_RGB32 ); + QRegion reg = selfCheckRegion(); + if( wspace->overlayWindow()) + { // avoid covering the whole screen too soon + wspace->setOverlayShape( reg ); + wspace->showOverlay(); + } + selfCheckSetup(); + flushBuffer( PAINT_SCREEN_REGION, reg ); + bool ok = selfCheckFinish(); + if( wspace->overlayWindow()) + wspace->hideOverlay(); + return ok; + } + +void SceneXrender::selfCheckSetup() + { + KXErrorHandler err; + QImage img( selfCheckWidth(), selfCheckHeight(), QImage::Format_RGB32 ); img.setPixel( 0, 0, QColor( Qt::red ).rgb()); img.setPixel( 1, 0, QColor( Qt::green ).rgb()); img.setPixel( 2, 0, QColor( Qt::blue ).rgb()); @@ -177,44 +198,40 @@ bool SceneXrender::selfCheck() img.setPixel( 1, 1, QColor( Qt::black ).rgb()); img.setPixel( 2, 1, QColor( Qt::white ).rgb()); QPixmap pix = QPixmap::fromImage( img ); - QList< QPoint > points = selfCheckPoints(); - QRegion reg; - foreach( const QPoint& p, points ) - reg |= QRect( p, pix.size()); - if( wspace->overlayWindow()) - { // avoid covering the whole screen too soon - wspace->setOverlayShape( reg ); - wspace->showOverlay(); - } - foreach( const QPoint& p, points ) + foreach( const QPoint& p, selfCheckPoints()) { XSetWindowAttributes wa; wa.override_redirect = True; - ::Window window = XCreateWindow( display(), rootWindow(), 0, 0, 3, 2, 0, QX11Info::appDepth(), - CopyFromParent, CopyFromParent, CWOverrideRedirect, &wa ); + ::Window window = XCreateWindow( display(), rootWindow(), 0, 0, selfCheckWidth(), selfCheckHeight(), + 0, QX11Info::appDepth(), CopyFromParent, CopyFromParent, CWOverrideRedirect, &wa ); XSetWindowBackgroundPixmap( display(), window, pix.handle()); XClearWindow( display(), window ); XMapWindow( display(), window ); // move the window one down to where the result will be rendered too, just in case // the render would fail completely and eventual check would try to read this window's contents XMoveWindow( display(), window, p.x() + 1, p.y()); - XCompositeRedirectWindow( display(), window, CompositeRedirectManual ); + XCompositeRedirectWindow( display(), window, CompositeRedirectAutomatic ); Pixmap wpix = XCompositeNameWindowPixmap( display(), window ); XWindowAttributes attrs; XGetWindowAttributes( display(), window, &attrs ); XRenderPictFormat* format = XRenderFindVisualFormat( display(), attrs.visual ); Picture pic = XRenderCreatePicture( display(), wpix, format, 0, 0 ); - QRect rect( p.x(), p.y(), 3, 2 ); + QRect rect( p.x(), p.y(), selfCheckWidth(), selfCheckHeight()); XRenderComposite( display(), PictOpSrc, pic, None, buffer, 0, 0, 0, 0, rect.x(), rect.y(), rect.width(), rect.height()); XFreePixmap( display(), wpix ); XDestroyWindow( display(), window ); } - flushBuffer( PAINT_SCREEN_REGION, reg ); + err.error( true ); // just sync and discard + } + +bool SceneXrender::selfCheckFinish() + { + KXErrorHandler err; bool ok = true; - foreach( const QPoint& p, points ) + foreach( const QPoint& p, selfCheckPoints()) { - QPixmap pix = QPixmap::grabWindow( rootWindow(), p.x(), p.y(), 3, 2 ); + QPixmap pix = QPixmap::grabWindow( rootWindow(), p.x(), p.y(), selfCheckWidth(), selfCheckHeight()); QImage img = pix.toImage(); // kDebug(1212) << "P:" << QColor( img.pixel( 0, 0 )).name(); // kDebug(1212) << "P:" << QColor( img.pixel( 1, 0 )).name(); @@ -234,8 +251,8 @@ bool SceneXrender::selfCheck() break; } } - if( wspace->overlayWindow()) - wspace->hideOverlay(); + if( err.error( true )) + ok = false; if( ok ) kDebug( 1212 ) << "Compositing self-check passed."; if( !ok && options->disableCompositingChecks ) @@ -259,7 +276,18 @@ void SceneXrender::paint( QRegion damage, ToplevelList toplevels ) paintScreen( &mask, &damage ); if( wspace->overlayWindow()) // show the window only after the first pass, since wspace->showOverlay(); // that pass may take long + if( !selfCheckDone ) + { + selfCheckSetup(); + damage |= selfCheckRegion(); + } flushBuffer( mask, damage ); + if( !selfCheckDone ) + { + if( !selfCheckFinish()) + QTimer::singleShot( 0, Workspace::self(), SLOT( finishCompositing())); + selfCheckDone = true; + } // do cleanup stacking_order.clear(); } diff --git a/scene_xrender.h b/scene_xrender.h index 2b800de434..a4fa392660 100644 --- a/scene_xrender.h +++ b/scene_xrender.h @@ -56,6 +56,8 @@ class SceneXrender void createBuffer(); void flushBuffer( int mask, QRegion damage ); bool selfCheck(); + void selfCheckSetup(); + bool selfCheckFinish(); XRenderPictFormat* format; Picture front; static Picture buffer; diff --git a/utils.h b/utils.h index 8e0cdd9a8e..880af40093 100644 --- a/utils.h +++ b/utils.h @@ -98,6 +98,7 @@ typedef QList< Group* > GroupList; typedef QList< const Group* > ConstGroupList; extern Options* options; +extern bool initting; // whether kwin is starting up enum Layer { diff --git a/workspace.h b/workspace.h index d6c474eb30..79889c966a 100644 --- a/workspace.h +++ b/workspace.h @@ -522,6 +522,7 @@ class Workspace : public QObject, public KDecorationDefines void slotReloadConfig(); void setPopupClientOpacity( QAction* action ); void setupCompositing(); + void finishCompositing(); void performCompositing(); void performMousePoll(); void lostCMSelection(); @@ -606,7 +607,6 @@ class Workspace : public QObject, public KDecorationDefines void updateClientArea( bool force ); - void finishCompositing(); bool windowRepaintsPending() const; void setCompositeTimer(); void checkCompositePaintTime( int msec );