diff --git a/COMPOSITE_TODO b/COMPOSITE_TODO index b73307fd2e..3f66defef2 100644 --- a/COMPOSITE_TODO +++ b/COMPOSITE_TODO @@ -152,6 +152,8 @@ XRender TODO in window's pre-paint - see the transformedShape() comment - and currently seems to be generally broken ++ implement self-check (SceneOpenGL::selfCheckSetup() etc.) also for XRender, possibly share some code + Effects framework TODO ============================== diff --git a/scene_opengl.cpp b/scene_opengl.cpp index 2220bb7203..48f459a8b7 100644 --- a/scene_opengl.cpp +++ b/scene_opengl.cpp @@ -84,6 +84,10 @@ Sources and other compositing managers: #ifdef KWIN_HAVE_OPENGL_COMPOSITING +#include + +#include + namespace KWin { @@ -113,6 +117,7 @@ XShmSegmentInfo SceneOpenGL::shm; SceneOpenGL::SceneOpenGL( Workspace* ws ) : Scene( ws ) , init_ok( false ) + , selfCheckDone( false ) { if( !Extensions::glxAvailable()) { @@ -615,6 +620,61 @@ bool SceneOpenGL::initDrawableConfigs() return true; } +// 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. +void SceneOpenGL::selfCheckSetup( QRegion& damage ) + { + QImage img( 5, 1, 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()); + img.setPixel( 3, 0, QColor( Qt::white ).rgb()); + img.setPixel( 4, 0, QColor( Qt::black ).rgb()); + XSetWindowAttributes wa; + wa.override_redirect = True; + ::Window window = XCreateWindow( display(), rootWindow(), 0, 0, 5, 1, 0, QX11Info::appDepth(), + CopyFromParent, CopyFromParent, CWOverrideRedirect, &wa ); + QPixmap pix = QPixmap::fromImage( img ); + XSetWindowBackgroundPixmap( display(), window, pix.handle()); + XClearWindow( display(), window ); + XMapWindow( display(), window ); + XSync( display(), False ); + Pixmap wpix = XCompositeNameWindowPixmap( display(), window ); + XDestroyWindow( display(), window ); + glXWaitX(); + Texture texture; + texture.load( wpix, QSize( 5, 1 ), QX11Info::appDepth()); + texture.bind(); + QRect rect( 0, 0, 5, 1 ); + texture.render( rect, rect ); + Workspace::self()->addRepaint( rect ); + texture.unbind(); + texture.discard(); + XFreePixmap( display(), wpix ); + damage |= rect; + } + +void SceneOpenGL::selfCheckFinish() + { + glXWaitGL(); + selfCheckDone = true; + QPixmap pix = QPixmap::grabWindow( rootWindow(), 0, 0, 5, 1 ); + QImage img = pix.toImage(); + if( img.pixel( 0, 0 ) != QColor( Qt::red ).rgb() + || img.pixel( 1, 0 ) != QColor( Qt::green ).rgb() + || img.pixel( 2, 0 ) != QColor( Qt::blue ).rgb() + || img.pixel( 3, 0 ) != QColor( Qt::white ).rgb() + || img.pixel( 4, 0 ) != QColor( Qt::black ).rgb()) + { + kError( 1212 ) << "Compositing self-check failed, disabling compositing."; + QTimer::singleShot( 0, Workspace::self(), SLOT( finishCompositing())); + } + else + kDebug( 1212 ) << "Compositing self-check passed."; + } + // the entry function for painting void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels ) { @@ -636,7 +696,13 @@ void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels ) #endif glPopMatrix(); 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 ); flushBuffer( mask, damage ); + if( !selfCheckDone ) + selfCheckFinish(); // do cleanup stacking_order.clear(); checkGLError( "PostPaint" ); @@ -658,8 +724,6 @@ void SceneOpenGL::waitSync() // actually paint to the screen (double-buffer swap or copy from pixmap buffer) void SceneOpenGL::flushBuffer( int mask, QRegion damage ) { - if( wspace->overlayWindow()) // show the window only after the first pass, since - wspace->showOverlay(); // that pass may take long if( db ) { if( mask & PAINT_SCREEN_REGION ) diff --git a/scene_opengl.h b/scene_opengl.h index 401ff4aca5..d84b88f4f8 100644 --- a/scene_opengl.h +++ b/scene_opengl.h @@ -64,6 +64,8 @@ class SceneOpenGL bool initDrawableConfigs(); void waitSync(); void flushBuffer( int mask, QRegion damage ); + void selfCheckSetup( QRegion& damage ); + void selfCheckFinish(); GC gcroot; class FBConfigInfo { @@ -90,6 +92,7 @@ class SceneOpenGL static XShmSegmentInfo shm; #endif bool init_ok; + bool selfCheckDone; }; class SceneOpenGL::Texture diff --git a/workspace.h b/workspace.h index 9b5f20be0c..3f8a2c39e5 100644 --- a/workspace.h +++ b/workspace.h @@ -488,6 +488,7 @@ class Workspace : public QObject, public KDecorationDefines void slotReloadConfig(); void setPopupClientOpacity( QAction* action ); void setupCompositing(); + void finishCompositing(); void performCompositing(); void lostCMSelection(); void updateElectricBorders(); @@ -571,7 +572,6 @@ class Workspace : public QObject, public KDecorationDefines void updateClientArea( bool force ); - void finishCompositing(); bool windowRepaintsPending() const; int current_desktop;