From 7249ca2cfb8d86d6b4c8781f740fcb69d9e18812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Mon, 9 Feb 2009 14:51:11 +0000 Subject: [PATCH] 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. With this patch, KDE startup is without any flicker. svn path=/trunk/KDE/kdebase/workspace/; revision=923842 --- main.cpp | 4 +-- scene.cpp | 13 ++++++-- scene.h | 17 ++++++++++ scene_opengl.cpp | 81 +++++++++++++++++++++++++++++++++-------------- scene_opengl.h | 3 ++ scene_xrender.cpp | 72 ++++++++++++++++++++++++++++------------- scene_xrender.h | 2 ++ utils.h | 1 + workspace.h | 2 +- 9 files changed, 144 insertions(+), 51 deletions(-) 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 );