00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #include "scene_xrender.h"
00041
00042 #ifdef KWIN_HAVE_XRENDER_COMPOSITING
00043
00044 #include "toplevel.h"
00045 #include "client.h"
00046 #include "deleted.h"
00047 #include "effects.h"
00048 #include "kwinxrenderutils.h"
00049
00050 #include <X11/extensions/Xcomposite.h>
00051
00052 #include <kxerrorhandler.h>
00053
00054 namespace KWin
00055 {
00056
00057
00058
00059
00060
00061
00062 struct RegionDebug
00063 {
00064 RegionDebug( XserverRegion r ) : rr( r ) {}
00065 XserverRegion rr;
00066 };
00067
00068 kdbgstream& operator<<( kdbgstream& stream, RegionDebug r )
00069 {
00070 if( r.rr == None )
00071 return stream << "EMPTY";
00072 int num;
00073 XRectangle* rects = XFixesFetchRegion( display(), r.rr, &num );
00074 if( rects == NULL || num == 0 )
00075 return stream << "EMPTY";
00076 for( int i = 0;
00077 i < num;
00078 ++i )
00079 stream << "[" << rects[ i ].x << "+" << rects[ i ].y << " " << rects[ i ].width << "x" << rects[ i ].height << "]";
00080 return stream;
00081 }
00082
00083 Picture SceneXrender::buffer = None;
00084 ScreenPaintData SceneXrender::screen_paint;
00085
00086 SceneXrender::SceneXrender( Workspace* ws )
00087 : Scene( ws )
00088 , front( None )
00089 , init_ok( false )
00090 {
00091 if( !Extensions::renderAvailable())
00092 {
00093 kError( 1212 ) << "No XRender extension available";
00094 return;
00095 }
00096 if( !Extensions::fixesRegionAvailable())
00097 {
00098 kError( 1212 ) << "No XFixes v3+ extension available";
00099 return;
00100 }
00101 KXErrorHandler xerr;
00102 if( wspace->createOverlay())
00103 {
00104 wspace->setupOverlay( None );
00105 XWindowAttributes attrs;
00106 XGetWindowAttributes( display(), wspace->overlayWindow(), &attrs );
00107 format = XRenderFindVisualFormat( display(), attrs.visual );
00108 if( format == NULL )
00109 {
00110 kError( 1212 ) << "Failed to find XRender format for overlay window";
00111 return;
00112 }
00113 front = XRenderCreatePicture( display(), wspace->overlayWindow(), format, 0, NULL );
00114 }
00115 else
00116 {
00117
00118 format = XRenderFindVisualFormat( display(), DefaultVisual( display(), DefaultScreen( display())));
00119 if( format == NULL )
00120 {
00121 kError( 1212 ) << "Failed to find XRender format for root window";
00122 return;
00123 }
00124 XRenderPictureAttributes pa;
00125 pa.subwindow_mode = IncludeInferiors;
00126 front = XRenderCreatePicture( display(), rootWindow(), format, CPSubwindowMode, &pa );
00127 }
00128 createBuffer();
00129 if( xerr.error( true ))
00130 {
00131 kError( 1212 ) << "XRender compositing setup failed";
00132 return;
00133 }
00134 if( !selfCheck())
00135 return;
00136 init_ok = true;
00137 }
00138
00139 SceneXrender::~SceneXrender()
00140 {
00141 if( !init_ok )
00142 {
00143
00144 wspace->destroyOverlay();
00145 return;
00146 }
00147 XRenderFreePicture( display(), front );
00148 XRenderFreePicture( display(), buffer );
00149 buffer = None;
00150 wspace->destroyOverlay();
00151 foreach( Window* w, windows )
00152 delete w;
00153 }
00154
00155 bool SceneXrender::initFailed() const
00156 {
00157 return !init_ok;
00158 }
00159
00160
00161
00162 void SceneXrender::createBuffer()
00163 {
00164 Pixmap pixmap = XCreatePixmap( display(), rootWindow(), displayWidth(), displayHeight(), DefaultDepth( display(), DefaultScreen( display())));
00165 buffer = XRenderCreatePicture( display(), pixmap, format, 0, 0 );
00166 XFreePixmap( display(), pixmap );
00167 }
00168
00169
00170 bool SceneXrender::selfCheck()
00171 {
00172 QImage img( 3, 2, QImage::Format_RGB32 );
00173 img.setPixel( 0, 0, QColor( Qt::red ).rgb());
00174 img.setPixel( 1, 0, QColor( Qt::green ).rgb());
00175 img.setPixel( 2, 0, QColor( Qt::blue ).rgb());
00176 img.setPixel( 0, 1, QColor( Qt::white ).rgb());
00177 img.setPixel( 1, 1, QColor( Qt::black ).rgb());
00178 img.setPixel( 2, 1, QColor( Qt::white ).rgb());
00179 QPixmap pix = QPixmap::fromImage( img );
00180 QList< QPoint > points = selfCheckPoints();
00181 QRegion reg;
00182 foreach( const QPoint& p, points )
00183 reg |= QRect( p, pix.size());
00184 if( wspace->overlayWindow())
00185 {
00186 wspace->setOverlayShape( reg );
00187 wspace->showOverlay();
00188 }
00189 foreach( const QPoint& p, points )
00190 {
00191 XSetWindowAttributes wa;
00192 wa.override_redirect = True;
00193 ::Window window = XCreateWindow( display(), rootWindow(), 0, 0, 3, 2, 0, QX11Info::appDepth(),
00194 CopyFromParent, CopyFromParent, CWOverrideRedirect, &wa );
00195 XSetWindowBackgroundPixmap( display(), window, pix.handle());
00196 XClearWindow( display(), window );
00197 XMapWindow( display(), window );
00198
00199
00200 XMoveWindow( display(), window, p.x() + 1, p.y());
00201 XCompositeRedirectWindow( display(), window, CompositeRedirectManual );
00202 Pixmap wpix = XCompositeNameWindowPixmap( display(), window );
00203 XWindowAttributes attrs;
00204 XGetWindowAttributes( display(), window, &attrs );
00205 XRenderPictFormat* format = XRenderFindVisualFormat( display(), attrs.visual );
00206 Picture pic = XRenderCreatePicture( display(), wpix, format, 0, 0 );
00207 QRect rect( p.x(), p.y(), 3, 2 );
00208 XRenderComposite( display(), PictOpSrc, pic, None, buffer, 0, 0, 0, 0,
00209 rect.x(), rect.y(), rect.width(), rect.height());
00210 XFreePixmap( display(), wpix );
00211 XDestroyWindow( display(), window );
00212 }
00213 flushBuffer( PAINT_SCREEN_REGION, reg );
00214 bool ok = true;
00215 foreach( const QPoint& p, points )
00216 {
00217 QPixmap pix = QPixmap::grabWindow( rootWindow(), p.x(), p.y(), 3, 2 );
00218 QImage img = pix.toImage();
00219
00220
00221
00222
00223
00224
00225 if( img.pixel( 0, 0 ) != QColor( Qt::red ).rgb()
00226 || img.pixel( 1, 0 ) != QColor( Qt::green ).rgb()
00227 || img.pixel( 2, 0 ) != QColor( Qt::blue ).rgb()
00228 || img.pixel( 0, 1 ) != QColor( Qt::white ).rgb()
00229 || img.pixel( 1, 1 ) != QColor( Qt::black ).rgb()
00230 || img.pixel( 2, 1 ) != QColor( Qt::white ).rgb())
00231 {
00232 kError( 1212 ) << "Compositing self-check failed, disabling compositing.";
00233 ok = false;
00234 break;
00235 }
00236 }
00237 if( wspace->overlayWindow())
00238 wspace->hideOverlay();
00239 if( ok )
00240 kDebug( 1212 ) << "Compositing self-check passed.";
00241 if( !ok && options->disableCompositingChecks )
00242 {
00243 kWarning( 1212 ) << "Compositing checks disabled, proceeding regardless of self-check failure.";
00244 return true;
00245 }
00246 return ok;
00247 }
00248
00249
00250
00251 void SceneXrender::paint( QRegion damage, ToplevelList toplevels )
00252 {
00253 foreach( Toplevel* c, toplevels )
00254 {
00255 assert( windows.contains( c ));
00256 stacking_order.append( windows[ c ] );
00257 }
00258 int mask = 0;
00259 paintScreen( &mask, &damage );
00260 if( wspace->overlayWindow())
00261 wspace->showOverlay();
00262 flushBuffer( mask, damage );
00263
00264 stacking_order.clear();
00265 }
00266
00267 void SceneXrender::flushBuffer( int mask, QRegion damage )
00268 {
00269 if( mask & PAINT_SCREEN_REGION )
00270 {
00271
00272 XserverRegion front_region = toXserverRegion( damage );
00273 XFixesSetPictureClipRegion( display(), front, 0, 0, front_region );
00274 XFixesDestroyRegion( display(), front_region );
00275
00276 XFixesSetPictureClipRegion( display(), buffer, 0, 0, None );
00277 XRenderComposite( display(), PictOpSrc, buffer, None, front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight());
00278 XFixesSetPictureClipRegion( display(), front, 0, 0, None );
00279 XFlush( display());
00280 }
00281 else
00282 {
00283
00284 XRenderComposite( display(), PictOpSrc, buffer, None, front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight());
00285 XFlush( display());
00286 }
00287 }
00288
00289 void SceneXrender::paintGenericScreen( int mask, ScreenPaintData data )
00290 {
00291 screen_paint = data;
00292 if( true )
00293 Scene::paintGenericScreen( mask, data );
00294 else
00295 paintTransformedScreen( mask );
00296 }
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 void SceneXrender::paintTransformedScreen( int orig_mask )
00311 {
00312 QRegion region( 0, 0, displayWidth(), displayHeight());
00313 QList< Phase2Data > phase2;
00314 QRegion allclips;
00315
00316
00317 for( int i = stacking_order.count() - 1;
00318 i >= 0;
00319 --i )
00320 {
00321 Window* w = static_cast< Window* >( stacking_order[ i ] );
00322 WindowPrePaintData data;
00323 data.mask = orig_mask | ( w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT );
00324 w->resetPaintingEnabled();
00325 data.paint = region;
00326
00327 data.clip = w->isOpaque() ? region : QRegion();
00328 data.quads = w->buildQuads();
00329
00330 effects->prePaintWindow( effectWindow( w ), data, time_diff );
00331 #ifndef NDEBUG
00332 foreach( const WindowQuad &q, data.quads )
00333 if( q.isTransformed())
00334 kFatal( 1212 ) << "Pre-paint calls are not allowed to transform quads!" ;
00335 #endif
00336 if( !w->isPaintingEnabled())
00337 continue;
00338 data.paint -= allclips;
00339 if( data.paint.isEmpty())
00340 continue;
00341 if( data.paint != region )
00342 {
00343 region |= data.paint;
00344 painted_region |= data.paint;
00345 }
00346
00347
00348 if( data.mask & PAINT_WINDOW_TRANSLUCENT )
00349 phase2.prepend( Phase2Data( w, data.paint, data.clip, data.mask, data.quads ));
00350 if( data.mask & PAINT_WINDOW_OPAQUE )
00351 {
00352 w->setTransformedShape( QRegion());
00353 paintWindow( w, data.mask, data.paint, data.quads );
00354
00355 region -= w->transformedShape();
00356 }
00357
00358 w->suspendUnredirect( data.mask & ( PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_TRANSFORMED ));
00359 }
00360 if( !( orig_mask & PAINT_SCREEN_BACKGROUND_FIRST ))
00361 paintBackground( region );
00362
00363
00364
00365 QRegion add_paint;
00366 foreach( const Phase2Data &d, phase2 )
00367 {
00368 Scene::Window* w = d.window;
00369 paintWindow( w, d.mask, d.region | add_paint, d.quads );
00370
00371
00372 add_paint |= d.region;
00373 }
00374 }
00375
00376
00377 void SceneXrender::paintBackground( QRegion region )
00378 {
00379 PaintClipper pc( region );
00380 for( PaintClipper::Iterator iterator;
00381 !iterator.isDone();
00382 iterator.next())
00383 {
00384 XRenderColor col = { 0, 0, 0, 0xffff };
00385 XRenderFillRectangle( display(), PictOpSrc, buffer, &col, 0, 0, displayWidth(), displayHeight());
00386 }
00387 }
00388
00389 void SceneXrender::windowGeometryShapeChanged( Toplevel* c )
00390 {
00391 if( !windows.contains( c ))
00392 return;
00393 Window* w = windows[ c ];
00394 w->discardPicture();
00395 w->discardShape();
00396 w->discardAlpha();
00397 }
00398
00399 void SceneXrender::windowOpacityChanged( Toplevel* c )
00400 {
00401 if( !windows.contains( c ))
00402 return;
00403 Window* w = windows[ c ];
00404 w->discardAlpha();
00405 }
00406
00407 void SceneXrender::windowClosed( Toplevel* c, Deleted* deleted )
00408 {
00409 assert( windows.contains( c ));
00410 if( deleted != NULL )
00411 {
00412 Window* w = windows.take( c );
00413 w->updateToplevel( deleted );
00414 windows[ deleted ] = w;
00415 }
00416 else
00417 {
00418 delete windows.take( c );
00419 c->effectWindow()->setSceneWindow( NULL );
00420 }
00421 }
00422
00423 void SceneXrender::windowDeleted( Deleted* c )
00424 {
00425 assert( windows.contains( c ));
00426 delete windows.take( c );
00427 c->effectWindow()->setSceneWindow( NULL );
00428 }
00429
00430 void SceneXrender::windowAdded( Toplevel* c )
00431 {
00432 assert( !windows.contains( c ));
00433 windows[ c ] = new Window( c );
00434 c->effectWindow()->setSceneWindow( windows[ c ]);
00435 }
00436
00437
00438
00439
00440
00441 SceneXrender::Window::Window( Toplevel* c )
00442 : Scene::Window( c )
00443 , _picture( None )
00444 , format( XRenderFindVisualFormat( display(), c->visual()))
00445 , alpha( None )
00446 {
00447 }
00448
00449 SceneXrender::Window::~Window()
00450 {
00451 discardPicture();
00452 discardAlpha();
00453 discardShape();
00454 }
00455
00456
00457 Picture SceneXrender::Window::picture()
00458 {
00459 if( !toplevel->damage().isEmpty() && _picture != None )
00460 {
00461 XRenderFreePicture( display(), _picture );
00462 _picture = None;
00463 }
00464 if( _picture == None && format != NULL )
00465 {
00466
00467 Pixmap pix = toplevel->windowPixmap();
00468 if( pix == None )
00469 return None;
00470 _picture = XRenderCreatePicture( display(), pix, format, 0, 0 );
00471 toplevel->resetDamage( toplevel->rect());
00472 }
00473 return _picture;
00474 }
00475
00476
00477 void SceneXrender::Window::discardPicture()
00478 {
00479 if( _picture != None )
00480 XRenderFreePicture( display(), _picture );
00481 _picture = None;
00482 }
00483
00484 void SceneXrender::Window::discardAlpha()
00485 {
00486 if( alpha != None )
00487 XRenderFreePicture( display(), alpha );
00488 alpha = None;
00489 }
00490
00491
00492 Picture SceneXrender::Window::alphaMask( double opacity )
00493 {
00494 if( isOpaque() && opacity == 1.0 )
00495 return None;
00496 if( alpha != None && alpha_cached_opacity != opacity )
00497 {
00498 if( alpha != None )
00499 XRenderFreePicture( display(), alpha );
00500 alpha = None;
00501 }
00502 if( alpha != None )
00503 return alpha;
00504 if( opacity == 1.0 )
00505 {
00506 alpha_cached_opacity = 1.0;
00507 return None;
00508 }
00509
00510 Pixmap pixmap = XCreatePixmap( display(), rootWindow(), 1, 1, 8 );
00511 XRenderPictFormat* format = XRenderFindStandardFormat( display(), PictStandardA8 );
00512 XRenderPictureAttributes pa;
00513 pa.repeat = True;
00514 alpha = XRenderCreatePicture( display(), pixmap, format, CPRepeat, &pa );
00515 XFreePixmap( display(), pixmap );
00516 XRenderColor col;
00517 col.alpha = int( opacity * 0xffff );
00518 alpha_cached_opacity = opacity;
00519 XRenderFillRectangle( display(), PictOpSrc, alpha, &col, 0, 0, 1, 1 );
00520 return alpha;
00521 }
00522
00523
00524 void SceneXrender::Window::performPaint( int mask, QRegion region, WindowPaintData data )
00525 {
00526 setTransformedShape( QRegion());
00527
00528 bool opaque = isOpaque() && data.opacity == 1.0;
00529
00530
00531
00532
00533
00534
00535
00536
00537 Picture pic = picture();
00538 if( pic == None )
00539 return;
00540
00541 if( options->xrenderSmoothScale )
00542 {
00543 if( mask & PAINT_WINDOW_TRANSFORMED )
00544 filter = ImageFilterGood;
00545 else if( mask & PAINT_SCREEN_TRANSFORMED )
00546 filter = ImageFilterGood;
00547 else
00548 filter = ImageFilterFast;
00549 }
00550 else
00551 filter = ImageFilterFast;
00552
00553 int x = toplevel->x();
00554 int y = toplevel->y();
00555 int width = toplevel->width();
00556 int height = toplevel->height();
00557 double xscale = 1;
00558 double yscale = 1;
00559 transformed_shape = shape();
00560 if( mask & PAINT_WINDOW_TRANSFORMED )
00561 {
00562 xscale *= data.xScale;
00563 yscale *= data.yScale;
00564 x += data.xTranslate;
00565 y += data.yTranslate;
00566 }
00567 if( mask & PAINT_SCREEN_TRANSFORMED )
00568 {
00569 xscale *= screen_paint.xScale;
00570 yscale *= screen_paint.yScale;
00571 x = int( x * screen_paint.xScale );
00572 y = int( y * screen_paint.yScale );
00573 x += screen_paint.xTranslate;
00574 y += screen_paint.yTranslate;
00575 }
00576 if( yscale != 1 || xscale != 1 )
00577 {
00578 XTransform xform = {{
00579 { XDoubleToFixed( 1 / xscale ), XDoubleToFixed( 0 ), XDoubleToFixed( 0 ) },
00580 { XDoubleToFixed( 0 ), XDoubleToFixed( 1 / yscale ), XDoubleToFixed( 0 ) },
00581 { XDoubleToFixed( 0 ), XDoubleToFixed( 0 ), XDoubleToFixed( 1 ) }
00582 }};
00583 XRenderSetPictureTransform( display(), pic, &xform );
00584 width = (int)(width * xscale);
00585 height = (int)(height * yscale);
00586 if( filter == ImageFilterGood )
00587 XRenderSetPictureFilter( display(), pic, const_cast< char* >( "good" ), NULL, 0 );
00588
00589 QVector< QRect > rects = transformed_shape.rects();
00590 for( int i = 0;
00591 i < rects.count();
00592 ++i )
00593 {
00594 QRect& r = rects[ i ];
00595 r = QRect( int( r.x() * xscale ), int( r.y() * yscale ),
00596 int( r.width() * xscale ), int( r.height() * xscale ));
00597 }
00598 transformed_shape.setRects( rects.constData(), rects.count());
00599 }
00600 transformed_shape.translate( x, y );
00601 PaintClipper pcreg( region );
00602 PaintClipper pc( transformed_shape );
00603 for( PaintClipper::Iterator iterator;
00604 !iterator.isDone();
00605 iterator.next())
00606 {
00607 if( opaque )
00608 {
00609 XRenderComposite( display(), PictOpSrc, pic, None, buffer, 0, 0, 0, 0,
00610 x, y, width, height);
00611
00612 XRenderColor col = { 0, 0, 0, 0xffff * ( 1 - data.brightness ) };
00613 XRenderFillRectangle( display(), PictOpOver, buffer, &col, x, y, width, height );
00614 }
00615 else
00616 {
00617 Picture alpha = alphaMask( data.opacity );
00618 XRenderComposite( display(), PictOpOver, pic, alpha, buffer, 0, 0, 0, 0,
00619 x, y, width, height);
00620
00621 XRenderColor col = { 0, 0, 0, 0xffff * ( 1 - data.brightness ) * data.opacity };
00622 XRenderFillRectangle( display(), PictOpOver, buffer, &col, x, y, width, height );
00623 transformed_shape = QRegion();
00624 }
00625 }
00626 if( xscale != 1 || yscale != 1 )
00627 {
00628 XTransform xform = {{
00629 { XDoubleToFixed( 1 ), XDoubleToFixed( 0 ), XDoubleToFixed( 0 ) },
00630 { XDoubleToFixed( 0 ), XDoubleToFixed( 1 ), XDoubleToFixed( 0 ) },
00631 { XDoubleToFixed( 0 ), XDoubleToFixed( 0 ), XDoubleToFixed( 1 ) }
00632 }};
00633 XRenderSetPictureTransform( display(), pic, &xform );
00634 if( filter == ImageFilterGood )
00635 XRenderSetPictureFilter( display(), pic, const_cast< char* >( "fast" ), NULL, 0 );
00636 }
00637 }
00638
00639 }
00640 #endif