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 <kxerrorhandler.h>
00051
00052 namespace KWin
00053 {
00054
00055
00056
00057
00058
00059
00060 struct RegionDebug
00061 {
00062 RegionDebug( XserverRegion r ) : rr( r ) {}
00063 XserverRegion rr;
00064 };
00065
00066 kdbgstream& operator<<( kdbgstream& stream, RegionDebug r )
00067 {
00068 if( r.rr == None )
00069 return stream << "EMPTY";
00070 int num;
00071 XRectangle* rects = XFixesFetchRegion( display(), r.rr, &num );
00072 if( rects == NULL || num == 0 )
00073 return stream << "EMPTY";
00074 for( int i = 0;
00075 i < num;
00076 ++i )
00077 stream << "[" << rects[ i ].x << "+" << rects[ i ].y << " " << rects[ i ].width << "x" << rects[ i ].height << "]";
00078 return stream;
00079 }
00080
00081 Picture SceneXrender::buffer = None;
00082 ScreenPaintData SceneXrender::screen_paint;
00083
00084 SceneXrender::SceneXrender( Workspace* ws )
00085 : Scene( ws )
00086 , front( None )
00087 , init_ok( false )
00088 {
00089 if( !Extensions::renderAvailable())
00090 {
00091 kError( 1212 ) << "No XRender extension available";
00092 return;
00093 }
00094 if( !Extensions::fixesRegionAvailable())
00095 {
00096 kError( 1212 ) << "No XFixes v3+ extension available";
00097 return;
00098 }
00099 KXErrorHandler xerr;
00100 if( wspace->createOverlay())
00101 {
00102 wspace->setupOverlay( None );
00103 XWindowAttributes attrs;
00104 XGetWindowAttributes( display(), wspace->overlayWindow(), &attrs );
00105 format = XRenderFindVisualFormat( display(), attrs.visual );
00106 if( format == NULL )
00107 {
00108 kError( 1212 ) << "Failed to find XRender format for overlay window";
00109 return;
00110 }
00111 front = XRenderCreatePicture( display(), wspace->overlayWindow(), format, 0, NULL );
00112 }
00113 else
00114 {
00115
00116 format = XRenderFindVisualFormat( display(), DefaultVisual( display(), DefaultScreen( display())));
00117 if( format == NULL )
00118 {
00119 kError( 1212 ) << "Failed to find XRender format for root window";
00120 return;
00121 }
00122 XRenderPictureAttributes pa;
00123 pa.subwindow_mode = IncludeInferiors;
00124 front = XRenderCreatePicture( display(), rootWindow(), format, CPSubwindowMode, &pa );
00125 }
00126 createBuffer();
00127 init_ok = !xerr.error( true );
00128 if( !init_ok )
00129 kError( 1212 ) << "XRender compositing setup failed";
00130 }
00131
00132 SceneXrender::~SceneXrender()
00133 {
00134 if( !init_ok )
00135 {
00136
00137 wspace->destroyOverlay();
00138 return;
00139 }
00140 XRenderFreePicture( display(), front );
00141 XRenderFreePicture( display(), buffer );
00142 buffer = None;
00143 wspace->destroyOverlay();
00144 foreach( Window* w, windows )
00145 delete w;
00146 }
00147
00148 bool SceneXrender::initFailed() const
00149 {
00150 return !init_ok;
00151 }
00152
00153
00154
00155 void SceneXrender::createBuffer()
00156 {
00157 Pixmap pixmap = XCreatePixmap( display(), rootWindow(), displayWidth(), displayHeight(), DefaultDepth( display(), DefaultScreen( display())));
00158 buffer = XRenderCreatePicture( display(), pixmap, format, 0, 0 );
00159 XFreePixmap( display(), pixmap );
00160 }
00161
00162
00163 void SceneXrender::paint( QRegion damage, ToplevelList toplevels )
00164 {
00165 foreach( Toplevel* c, toplevels )
00166 {
00167 assert( windows.contains( c ));
00168 stacking_order.append( windows[ c ] );
00169 }
00170 int mask = 0;
00171 paintScreen( &mask, &damage );
00172 if( wspace->overlayWindow())
00173 wspace->showOverlay();
00174 if( mask & PAINT_SCREEN_REGION )
00175 {
00176
00177 XserverRegion front_region = toXserverRegion( damage );
00178 XFixesSetPictureClipRegion( display(), front, 0, 0, front_region );
00179 XFixesDestroyRegion( display(), front_region );
00180
00181 XFixesSetPictureClipRegion( display(), buffer, 0, 0, None );
00182 XRenderComposite( display(), PictOpSrc, buffer, None, front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight());
00183 XFixesSetPictureClipRegion( display(), front, 0, 0, None );
00184 XFlush( display());
00185 }
00186 else
00187 {
00188
00189 XRenderComposite( display(), PictOpSrc, buffer, None, front, 0, 0, 0, 0, 0, 0, displayWidth(), displayHeight());
00190 XFlush( display());
00191 }
00192
00193 stacking_order.clear();
00194 }
00195
00196 void SceneXrender::paintGenericScreen( int mask, ScreenPaintData data )
00197 {
00198 screen_paint = data;
00199 if( true )
00200 Scene::paintGenericScreen( mask, data );
00201 else
00202 paintTransformedScreen( mask );
00203 }
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 void SceneXrender::paintTransformedScreen( int orig_mask )
00218 {
00219 QRegion region( 0, 0, displayWidth(), displayHeight());
00220 QList< Phase2Data > phase2;
00221 QRegion allclips;
00222
00223
00224 for( int i = stacking_order.count() - 1;
00225 i >= 0;
00226 --i )
00227 {
00228 Window* w = static_cast< Window* >( stacking_order[ i ] );
00229 WindowPrePaintData data;
00230 data.mask = orig_mask | ( w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT );
00231 w->resetPaintingEnabled();
00232 data.paint = region;
00233
00234 data.clip = w->isOpaque() ? region : QRegion();
00235 data.quads = w->buildQuads();
00236
00237 effects->prePaintWindow( effectWindow( w ), data, time_diff );
00238 #ifndef NDEBUG
00239 foreach( const WindowQuad &q, data.quads )
00240 if( q.isTransformed())
00241 kFatal( 1212 ) << "Pre-paint calls are not allowed to transform quads!" ;
00242 #endif
00243 if( !w->isPaintingEnabled())
00244 continue;
00245 data.paint -= allclips;
00246 if( data.paint.isEmpty())
00247 continue;
00248 if( data.paint != region )
00249 {
00250 region |= data.paint;
00251 painted_region |= data.paint;
00252 }
00253
00254
00255 if( data.mask & PAINT_WINDOW_TRANSLUCENT )
00256 phase2.prepend( Phase2Data( w, data.paint, data.clip, data.mask, data.quads ));
00257 if( data.mask & PAINT_WINDOW_OPAQUE )
00258 {
00259 w->setTransformedShape( QRegion());
00260 paintWindow( w, data.mask, data.paint, data.quads );
00261
00262 region -= w->transformedShape();
00263 }
00264 }
00265 if( !( orig_mask & PAINT_SCREEN_BACKGROUND_FIRST ))
00266 paintBackground( region );
00267
00268
00269
00270 QRegion add_paint;
00271 foreach( const Phase2Data &d, phase2 )
00272 {
00273 Scene::Window* w = d.window;
00274 paintWindow( w, d.mask, d.region | add_paint, d.quads );
00275
00276
00277 add_paint |= d.region;
00278 }
00279 }
00280
00281
00282 void SceneXrender::paintBackground( QRegion region )
00283 {
00284 PaintClipper pc( region );
00285 for( PaintClipper::Iterator iterator;
00286 !iterator.isDone();
00287 iterator.next())
00288 {
00289 XRenderColor col = { 0, 0, 0, 0xffff };
00290 XRenderFillRectangle( display(), PictOpSrc, buffer, &col, 0, 0, displayWidth(), displayHeight());
00291 }
00292 }
00293
00294 void SceneXrender::windowGeometryShapeChanged( Toplevel* c )
00295 {
00296 if( !windows.contains( c ))
00297 return;
00298 Window* w = windows[ c ];
00299 w->discardPicture();
00300 w->discardShape();
00301 w->discardAlpha();
00302 }
00303
00304 void SceneXrender::windowOpacityChanged( Toplevel* c )
00305 {
00306 if( !windows.contains( c ))
00307 return;
00308 Window* w = windows[ c ];
00309 w->discardAlpha();
00310 }
00311
00312 void SceneXrender::windowClosed( Toplevel* c, Deleted* deleted )
00313 {
00314 assert( windows.contains( c ));
00315 if( deleted != NULL )
00316 {
00317 Window* w = windows.take( c );
00318 w->updateToplevel( deleted );
00319 windows[ deleted ] = w;
00320 }
00321 else
00322 {
00323 delete windows.take( c );
00324 c->effectWindow()->setSceneWindow( NULL );
00325 }
00326 }
00327
00328 void SceneXrender::windowDeleted( Deleted* c )
00329 {
00330 assert( windows.contains( c ));
00331 delete windows.take( c );
00332 c->effectWindow()->setSceneWindow( NULL );
00333 }
00334
00335 void SceneXrender::windowAdded( Toplevel* c )
00336 {
00337 assert( !windows.contains( c ));
00338 windows[ c ] = new Window( c );
00339 c->effectWindow()->setSceneWindow( windows[ c ]);
00340 }
00341
00342
00343
00344
00345
00346 SceneXrender::Window::Window( Toplevel* c )
00347 : Scene::Window( c )
00348 , _picture( None )
00349 , format( XRenderFindVisualFormat( display(), c->visual()))
00350 , alpha( None )
00351 {
00352 }
00353
00354 SceneXrender::Window::~Window()
00355 {
00356 discardPicture();
00357 discardAlpha();
00358 discardShape();
00359 }
00360
00361
00362 Picture SceneXrender::Window::picture()
00363 {
00364 if( !toplevel->damage().isEmpty() && _picture != None )
00365 {
00366 XRenderFreePicture( display(), _picture );
00367 _picture = None;
00368 }
00369 if( _picture == None && format != NULL )
00370 {
00371
00372 Pixmap pix = toplevel->windowPixmap();
00373 if( pix == None )
00374 return None;
00375 _picture = XRenderCreatePicture( display(), pix, format, 0, 0 );
00376 toplevel->resetDamage( toplevel->rect());
00377 }
00378 return _picture;
00379 }
00380
00381
00382 void SceneXrender::Window::discardPicture()
00383 {
00384 if( _picture != None )
00385 XRenderFreePicture( display(), _picture );
00386 _picture = None;
00387 }
00388
00389 void SceneXrender::Window::discardAlpha()
00390 {
00391 if( alpha != None )
00392 XRenderFreePicture( display(), alpha );
00393 alpha = None;
00394 }
00395
00396
00397 Picture SceneXrender::Window::alphaMask( double opacity )
00398 {
00399 if( isOpaque() && opacity == 1.0 )
00400 return None;
00401 if( alpha != None && alpha_cached_opacity != opacity )
00402 {
00403 if( alpha != None )
00404 XRenderFreePicture( display(), alpha );
00405 alpha = None;
00406 }
00407 if( alpha != None )
00408 return alpha;
00409 if( opacity == 1.0 )
00410 {
00411 alpha_cached_opacity = 1.0;
00412 return None;
00413 }
00414
00415 Pixmap pixmap = XCreatePixmap( display(), rootWindow(), 1, 1, 8 );
00416 XRenderPictFormat* format = XRenderFindStandardFormat( display(), PictStandardA8 );
00417 XRenderPictureAttributes pa;
00418 pa.repeat = True;
00419 alpha = XRenderCreatePicture( display(), pixmap, format, CPRepeat, &pa );
00420 XFreePixmap( display(), pixmap );
00421 XRenderColor col;
00422 col.alpha = int( opacity * 0xffff );
00423 alpha_cached_opacity = opacity;
00424 XRenderFillRectangle( display(), PictOpSrc, alpha, &col, 0, 0, 1, 1 );
00425 return alpha;
00426 }
00427
00428
00429 void SceneXrender::Window::performPaint( int mask, QRegion region, WindowPaintData data )
00430 {
00431 setTransformedShape( QRegion());
00432
00433 bool opaque = isOpaque() && data.opacity == 1.0;
00434 if( mask & ( PAINT_WINDOW_OPAQUE | PAINT_WINDOW_TRANSLUCENT ))
00435 {}
00436 else if( mask & PAINT_WINDOW_OPAQUE )
00437 {
00438 if( !opaque )
00439 return;
00440 }
00441 else if( mask & PAINT_WINDOW_TRANSLUCENT )
00442 {
00443 if( opaque )
00444 return;
00445 }
00446 Picture pic = picture();
00447 if( pic == None )
00448 return;
00449
00450 if( options->xrenderSmoothScale )
00451 {
00452 if( mask & PAINT_WINDOW_TRANSFORMED )
00453 filter = ImageFilterGood;
00454 else if( mask & PAINT_SCREEN_TRANSFORMED )
00455 filter = ImageFilterGood;
00456 else
00457 filter = ImageFilterFast;
00458 }
00459 else
00460 filter = ImageFilterFast;
00461
00462 int x = toplevel->x();
00463 int y = toplevel->y();
00464 int width = toplevel->width();
00465 int height = toplevel->height();
00466 double xscale = 1;
00467 double yscale = 1;
00468 transformed_shape = shape();
00469 if( mask & PAINT_WINDOW_TRANSFORMED )
00470 {
00471 xscale *= data.xScale;
00472 yscale *= data.yScale;
00473 x += data.xTranslate;
00474 y += data.yTranslate;
00475 }
00476 if( mask & PAINT_SCREEN_TRANSFORMED )
00477 {
00478 xscale *= screen_paint.xScale;
00479 yscale *= screen_paint.yScale;
00480 x = int( x * screen_paint.xScale );
00481 y = int( y * screen_paint.yScale );
00482 x += screen_paint.xTranslate;
00483 y += screen_paint.yTranslate;
00484 }
00485 if( yscale != 1 || xscale != 1 )
00486 {
00487 XTransform xform = {{
00488 { XDoubleToFixed( 1 / xscale ), XDoubleToFixed( 0 ), XDoubleToFixed( 0 ) },
00489 { XDoubleToFixed( 0 ), XDoubleToFixed( 1 / yscale ), XDoubleToFixed( 0 ) },
00490 { XDoubleToFixed( 0 ), XDoubleToFixed( 0 ), XDoubleToFixed( 1 ) }
00491 }};
00492 XRenderSetPictureTransform( display(), pic, &xform );
00493 width = (int)(width * xscale);
00494 height = (int)(height * yscale);
00495 if( filter == ImageFilterGood )
00496 XRenderSetPictureFilter( display(), pic, const_cast< char* >( "good" ), NULL, 0 );
00497
00498 QVector< QRect > rects = transformed_shape.rects();
00499 for( int i = 0;
00500 i < rects.count();
00501 ++i )
00502 {
00503 QRect& r = rects[ i ];
00504 r = QRect( int( r.x() * xscale ), int( r.y() * yscale ),
00505 int( r.width() * xscale ), int( r.height() * xscale ));
00506 }
00507 transformed_shape.setRects( rects.constData(), rects.count());
00508 }
00509 transformed_shape.translate( x, y );
00510 PaintClipper pcreg( region );
00511 PaintClipper pc( transformed_shape );
00512 for( PaintClipper::Iterator iterator;
00513 !iterator.isDone();
00514 iterator.next())
00515 {
00516 if( opaque )
00517 {
00518 XRenderComposite( display(), PictOpSrc, pic, None, buffer, 0, 0, 0, 0,
00519 x, y, width, height);
00520
00521 XRenderColor col = { 0, 0, 0, 0xffff * ( 1 - data.brightness ) };
00522 XRenderFillRectangle( display(), PictOpOver, buffer, &col, x, y, width, height );
00523 }
00524 else
00525 {
00526 Picture alpha = alphaMask( data.opacity );
00527 XRenderComposite( display(), PictOpOver, pic, alpha, buffer, 0, 0, 0, 0,
00528 x, y, width, height);
00529
00530 XRenderColor col = { 0, 0, 0, 0xffff * ( 1 - data.brightness ) * data.opacity };
00531 XRenderFillRectangle( display(), PictOpOver, buffer, &col, x, y, width, height );
00532 transformed_shape = QRegion();
00533 }
00534 }
00535 if( xscale != 1 || yscale != 1 )
00536 {
00537 XTransform xform = {{
00538 { XDoubleToFixed( 1 ), XDoubleToFixed( 0 ), XDoubleToFixed( 0 ) },
00539 { XDoubleToFixed( 0 ), XDoubleToFixed( 1 ), XDoubleToFixed( 0 ) },
00540 { XDoubleToFixed( 0 ), XDoubleToFixed( 0 ), XDoubleToFixed( 1 ) }
00541 }};
00542 XRenderSetPictureTransform( display(), pic, &xform );
00543 if( filter == ImageFilterGood )
00544 XRenderSetPictureFilter( display(), pic, const_cast< char* >( "fast" ), NULL, 0 );
00545 }
00546 }
00547
00548 }
00549 #endif