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:
parent
14a5fb8026
commit
7249ca2cfb
9 changed files with 144 additions and 51 deletions
4
main.cpp
4
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 )
|
||||
{
|
||||
|
|
13
scene.cpp
13
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
|
||||
//****************************************
|
||||
|
|
17
scene.h
17
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
|
||||
{
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
1
utils.h
1
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
|
||||
{
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in a new issue