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
This commit is contained in:
Luboš Luňák 2009-02-09 14:51:11 +00:00
parent 14a5fb8026
commit 7249ca2cfb
9 changed files with 144 additions and 51 deletions

View file

@ -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 )
{

View file

@ -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
//****************************************

17
scene.h
View file

@ -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
{

View file

@ -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" );

View file

@ -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

View file

@ -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();
}

View file

@ -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;

View file

@ -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
{

View file

@ -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 );