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
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 #include "scene_opengl.h"
00069
00070 #include <kxerrorhandler.h>
00071
00072 #include "utils.h"
00073 #include "client.h"
00074 #include "deleted.h"
00075 #include "effects.h"
00076
00077 #include <sys/ipc.h>
00078 #include <sys/shm.h>
00079 #include <math.h>
00080
00081
00082
00083
00084
00085 #ifdef KWIN_HAVE_OPENGL_COMPOSITING
00086
00087 #include <X11/extensions/Xcomposite.h>
00088
00089 #include <qpainter.h>
00090
00091 namespace KWin
00092 {
00093
00094
00095
00096
00097
00098
00099 GLXFBConfig SceneOpenGL::fbcbuffer_db;
00100 GLXFBConfig SceneOpenGL::fbcbuffer_nondb;
00101
00102 SceneOpenGL::FBConfigInfo SceneOpenGL::fbcdrawableinfo[ 32 + 1 ];
00103
00104 GLXContext SceneOpenGL::ctxbuffer;
00105 GLXContext SceneOpenGL::ctxdrawable;
00106
00107 GLXDrawable SceneOpenGL::glxbuffer = None;
00108 GLXDrawable SceneOpenGL::last_pixmap = None;
00109 bool SceneOpenGL::tfp_mode;
00110 bool SceneOpenGL::db;
00111 bool SceneOpenGL::shm_mode;
00112 #ifdef HAVE_XSHM
00113 XShmSegmentInfo SceneOpenGL::shm;
00114 #endif
00115
00116
00117 SceneOpenGL::SceneOpenGL( Workspace* ws )
00118 : Scene( ws )
00119 , init_ok( false )
00120 {
00121 if( !Extensions::glxAvailable())
00122 {
00123 kDebug( 1212 ) << "No glx extensions available";
00124 return;
00125 }
00126 initGLX();
00127
00128 if( !hasGLExtension( "GLX_SGIX_fbconfig" ) || !glXGetFBConfigAttrib || !glXGetFBConfigs ||
00129 !glXGetVisualFromFBConfig || !glXCreatePixmap || !glXDestroyPixmap ||
00130 !glXCreateWindow || !glXDestroyWindow )
00131 {
00132 kError( 1212 ) << "GLX_SGIX_fbconfig or required GLX functions missing";
00133 return;
00134 }
00135 if( !selectMode())
00136 return;
00137 if( !initBuffer())
00138 return;
00139 if( !initRenderingContext())
00140 return;
00141
00142 initGL();
00143 if( !hasGLExtension( "GL_ARB_texture_non_power_of_two" )
00144 && !hasGLExtension( "GL_ARB_texture_rectangle" ))
00145 {
00146 kError( 1212 ) << "GL_ARB_texture_non_power_of_two and GL_ARB_texture_rectangle missing";
00147 return;
00148 }
00149 if( db )
00150 glDrawBuffer( GL_BACK );
00151
00152 has_waitSync = false;
00153 if( glXGetVideoSync && glXIsDirect( display(), ctxbuffer ) && options->glVSync )
00154 {
00155 unsigned int sync;
00156 if( glXGetVideoSync( &sync ) == 0 )
00157 {
00158 if( glXWaitVideoSync( 1, 0, &sync ) == 0 )
00159 has_waitSync = true;
00160 }
00161 }
00162
00163
00164 glMatrixMode( GL_PROJECTION );
00165 glLoadIdentity();
00166 float fovy = 60.0f;
00167 float aspect = 1.0f;
00168 float zNear = 0.1f;
00169 float zFar = 100.0f;
00170 float ymax = zNear * tan( fovy * M_PI / 360.0f );
00171 float ymin = -ymax;
00172 float xmin = ymin * aspect;
00173 float xmax = ymax * aspect;
00174
00175 glFrustum( xmin, xmax, ymin, ymax, zNear, zFar );
00176 glMatrixMode( GL_MODELVIEW );
00177 glLoadIdentity();
00178 float scaleFactor = 1.1 * tan( fovy * M_PI / 360.0f )/ymax;
00179 glTranslatef( xmin*scaleFactor, ymax*scaleFactor, -1.1 );
00180 glScalef( (xmax-xmin)*scaleFactor/displayWidth(), -(ymax-ymin)*scaleFactor/displayHeight(), 0.001 );
00181 if( checkGLError( "Init" ))
00182 {
00183 kError( 1212 ) << "OpenGL compositing setup failed";
00184 return;
00185 }
00186 if( !selfCheck())
00187 return;
00188 kDebug( 1212 ) << "DB:" << db << ", TFP:" << tfp_mode << ", SHM:" << shm_mode
00189 << ", Direct:" << bool( glXIsDirect( display(), ctxbuffer )) << endl;
00190 init_ok = true;
00191 }
00192
00193 SceneOpenGL::~SceneOpenGL()
00194 {
00195 if( !init_ok )
00196 {
00197
00198 wspace->destroyOverlay();
00199 return;
00200 }
00201 foreach( Window* w, windows )
00202 delete w;
00203
00204 glXMakeCurrent( display(), None, NULL );
00205 glXDestroyContext( display(), ctxbuffer );
00206 if( wspace->overlayWindow())
00207 {
00208 if( hasGLXVersion( 1, 3 ))
00209 glXDestroyWindow( display(), glxbuffer );
00210 XDestroyWindow( display(), buffer );
00211 wspace->destroyOverlay();
00212 }
00213 else
00214 {
00215 glXDestroyPixmap( display(), glxbuffer );
00216 XFreeGC( display(), gcroot );
00217 XFreePixmap( display(), buffer );
00218 }
00219 if( shm_mode )
00220 cleanupShm();
00221 if( !tfp_mode && !shm_mode )
00222 {
00223 if( last_pixmap != None )
00224 glXDestroyPixmap( display(), last_pixmap );
00225 glXDestroyContext( display(), ctxdrawable );
00226 }
00227 checkGLError( "Cleanup" );
00228 }
00229
00230 bool SceneOpenGL::initFailed() const
00231 {
00232 return !init_ok;
00233 }
00234
00235 bool SceneOpenGL::selectMode()
00236 {
00237
00238 shm_mode = false;
00239 tfp_mode = false;
00240 if( options->glMode == Options::GLTFP )
00241 {
00242 if( initTfp())
00243 tfp_mode = true;
00244 else if( initShm())
00245 shm_mode = true;
00246 }
00247 else if( options->glMode == Options::GLSHM )
00248 {
00249 if( initShm())
00250 shm_mode = true;
00251 else if( initTfp())
00252 tfp_mode = true;
00253 }
00254 if( !initDrawableConfigs())
00255 return false;
00256 return true;
00257 }
00258
00259 bool SceneOpenGL::initTfp()
00260 {
00261 if( glXBindTexImageEXT == NULL || glXReleaseTexImageEXT == NULL )
00262 return false;
00263 return true;
00264 }
00265
00266 bool SceneOpenGL::initShm()
00267 {
00268 #ifdef HAVE_XSHM
00269 int major, minor;
00270 Bool pixmaps;
00271 if( !XShmQueryVersion( display(), &major, &minor, &pixmaps ) || !pixmaps )
00272 return false;
00273 if( XShmPixmapFormat( display()) != ZPixmap )
00274 return false;
00275 const int MAXSIZE = 4096 * 2048 * 4;
00276
00277 shm.readOnly = False;
00278 shm.shmid = shmget( IPC_PRIVATE, MAXSIZE, IPC_CREAT | 0600 );
00279 if( shm.shmid < 0 )
00280 return false;
00281 shm.shmaddr = ( char* ) shmat( shm.shmid, NULL, 0 );
00282 if( shm.shmaddr == ( void * ) -1 )
00283 {
00284 shmctl( shm.shmid, IPC_RMID, 0 );
00285 return false;
00286 }
00287 #ifdef __linux__
00288
00289
00290 shmctl( shm.shmid, IPC_RMID, 0 );
00291 #endif
00292 KXErrorHandler errs;
00293 XShmAttach( display(), &shm );
00294 if( errs.error( true ))
00295 {
00296 #ifndef __linux__
00297 shmctl( shm.shmid, IPC_RMID, 0 );
00298 #endif
00299 shmdt( shm.shmaddr );
00300 return false;
00301 }
00302 return true;
00303 #else
00304 return false;
00305 #endif
00306 }
00307
00308 void SceneOpenGL::cleanupShm()
00309 {
00310 #ifdef HAVE_XSHM
00311 shmdt( shm.shmaddr );
00312 #ifndef __linux__
00313 shmctl( shm.shmid, IPC_RMID, 0 );
00314 #endif
00315 #endif
00316 }
00317
00318 bool SceneOpenGL::initRenderingContext()
00319 {
00320 bool direct_rendering = options->glDirect;
00321 if( !tfp_mode && !shm_mode )
00322 direct_rendering = false;
00323 KXErrorHandler errs1;
00324 ctxbuffer = glXCreateNewContext( display(), fbcbuffer, GLX_RGBA_TYPE, NULL,
00325 direct_rendering ? GL_TRUE : GL_FALSE );
00326 bool failed = ( ctxbuffer == NULL || !glXMakeCurrent( display(), glxbuffer, ctxbuffer ));
00327 if( errs1.error( true ))
00328 failed = true;
00329 if( failed )
00330 {
00331 if( !direct_rendering )
00332 {
00333 kDebug( 1212 ).nospace() << "Couldn't initialize rendering context ("
00334 << KXErrorHandler::errorMessage( errs1.errorEvent()) << ")";
00335 return false;
00336 }
00337 glXMakeCurrent( display(), None, NULL );
00338 if( ctxbuffer != NULL )
00339 glXDestroyContext( display(), ctxbuffer );
00340 direct_rendering = false;
00341 KXErrorHandler errs2;
00342 ctxbuffer = glXCreateNewContext( display(), fbcbuffer, GLX_RGBA_TYPE, NULL, GL_FALSE );
00343 bool failed = ( ctxbuffer == NULL || !glXMakeCurrent( display(), glxbuffer, ctxbuffer ));
00344 if( errs2.error( true ))
00345 failed = true;
00346 if( failed )
00347 {
00348 kDebug( 1212 ).nospace() << "Couldn't initialize rendering context ("
00349 << KXErrorHandler::errorMessage( errs2.errorEvent()) << ")";
00350 return false;
00351 }
00352 }
00353 if( !tfp_mode && !shm_mode )
00354 {
00355 ctxdrawable = glXCreateNewContext( display(), fbcdrawableinfo[ QX11Info::appDepth() ].fbconfig, GLX_RGBA_TYPE, ctxbuffer,
00356 direct_rendering ? GL_TRUE : GL_FALSE );
00357 }
00358 return true;
00359 }
00360
00361
00362 bool SceneOpenGL::initBuffer()
00363 {
00364 if( !initBufferConfigs())
00365 return false;
00366 if( fbcbuffer_db != NULL && wspace->createOverlay())
00367 {
00368 fbcbuffer = fbcbuffer_db;
00369 XVisualInfo* visual = glXGetVisualFromFBConfig( display(), fbcbuffer );
00370 XSetWindowAttributes attrs;
00371 attrs.colormap = XCreateColormap( display(), rootWindow(), visual->visual, AllocNone );
00372 buffer = XCreateWindow( display(), wspace->overlayWindow(), 0, 0, displayWidth(), displayHeight(),
00373 0, visual->depth, InputOutput, visual->visual, CWColormap, &attrs );
00374 if( hasGLXVersion( 1, 3 ))
00375 glxbuffer = glXCreateWindow( display(), fbcbuffer, buffer, NULL );
00376 else
00377 glxbuffer = buffer;
00378 wspace->setupOverlay( buffer );
00379 db = true;
00380 XFree( visual );
00381 }
00382 else if( fbcbuffer_nondb != NULL )
00383 {
00384 fbcbuffer = fbcbuffer_nondb;
00385 XVisualInfo* visual = glXGetVisualFromFBConfig( display(), fbcbuffer );
00386 XGCValues gcattr;
00387 gcattr.subwindow_mode = IncludeInferiors;
00388 gcroot = XCreateGC( display(), rootWindow(), GCSubwindowMode, &gcattr );
00389 buffer = XCreatePixmap( display(), rootWindow(), displayWidth(), displayHeight(),
00390 visual->depth );
00391 glxbuffer = glXCreatePixmap( display(), fbcbuffer, buffer, NULL );
00392 db = false;
00393 XFree( visual );
00394 }
00395 else
00396 {
00397 kError( 1212 ) << "Couldn't create output buffer (failed to create overlay window?) !";
00398 return false;
00399 }
00400 int vis_buffer;
00401 glXGetFBConfigAttrib( display(), fbcbuffer, GLX_VISUAL_ID, &vis_buffer );
00402 XVisualInfo* visinfo_buffer = glXGetVisualFromFBConfig( display(), fbcbuffer );
00403 kDebug( 1212 ) << "Buffer visual (depth " << visinfo_buffer->depth << "): 0x" << QString::number( vis_buffer, 16 );
00404 XFree( visinfo_buffer );
00405 return true;
00406 }
00407
00408
00409 bool SceneOpenGL::initBufferConfigs()
00410 {
00411 int cnt;
00412 GLXFBConfig *fbconfigs = glXGetFBConfigs( display(), DefaultScreen( display() ), &cnt );
00413 fbcbuffer_db = NULL;
00414 fbcbuffer_nondb = NULL;
00415
00416 for( int i = 0; i < 2; i++ )
00417 {
00418 int back, stencil, depth, caveat, alpha;
00419 back = i > 0 ? INT_MAX : 1;
00420 stencil = INT_MAX;
00421 depth = INT_MAX;
00422 caveat = INT_MAX;
00423 alpha = 0;
00424 for( int j = 0; j < cnt; j++ )
00425 {
00426 XVisualInfo *vi;
00427 int visual_depth;
00428 vi = glXGetVisualFromFBConfig( display(), fbconfigs[ j ] );
00429 if( vi == NULL )
00430 continue;
00431 visual_depth = vi->depth;
00432 XFree( vi );
00433 if( visual_depth != DefaultDepth( display(), DefaultScreen( display())))
00434 continue;
00435 int value;
00436 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00437 GLX_ALPHA_SIZE, &alpha );
00438 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00439 GLX_BUFFER_SIZE, &value );
00440 if( value != visual_depth && ( value - alpha ) != visual_depth )
00441 continue;
00442 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00443 GLX_RENDER_TYPE, &value );
00444 if( !( value & GLX_RGBA_BIT ))
00445 continue;
00446 int back_value;
00447 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00448 GLX_DOUBLEBUFFER, &back_value );
00449 if( i > 0 )
00450 {
00451 if( back_value > back )
00452 continue;
00453 }
00454 else
00455 {
00456 if( back_value < back )
00457 continue;
00458 }
00459 int stencil_value;
00460 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00461 GLX_STENCIL_SIZE, &stencil_value );
00462 if( stencil_value > stencil )
00463 continue;
00464 int depth_value;
00465 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00466 GLX_DEPTH_SIZE, &depth_value );
00467 if( depth_value > depth )
00468 continue;
00469 int caveat_value;
00470 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00471 GLX_CONFIG_CAVEAT, &caveat_value );
00472 if( caveat_value > caveat )
00473 continue;
00474 back = back_value;
00475 stencil = stencil_value;
00476 depth = depth_value;
00477 caveat = caveat_value;
00478 if( i > 0 )
00479 fbcbuffer_nondb = fbconfigs[ j ];
00480 else
00481 fbcbuffer_db = fbconfigs[ j ];
00482 }
00483 }
00484 if( cnt )
00485 XFree( fbconfigs );
00486 if( fbcbuffer_db == NULL && fbcbuffer_nondb == NULL )
00487 {
00488 kError( 1212 ) << "Couldn't find framebuffer configuration for buffer!";
00489 return false;
00490 }
00491 for( int i = 0; i <= 32; i++ )
00492 {
00493 if( fbcdrawableinfo[ i ].fbconfig == NULL )
00494 continue;
00495 int vis_drawable = 0;
00496 glXGetFBConfigAttrib( display(), fbcdrawableinfo[ i ].fbconfig, GLX_VISUAL_ID, &vis_drawable );
00497 kDebug( 1212 ) << "Drawable visual (depth " << i << "): 0x" << QString::number( vis_drawable, 16 );
00498 }
00499 return true;
00500 }
00501
00502
00503 bool SceneOpenGL::initDrawableConfigs()
00504 {
00505 int cnt;
00506 GLXFBConfig *fbconfigs = glXGetFBConfigs( display(), DefaultScreen( display() ), &cnt );
00507
00508 for( int i = 0; i <= 32; i++ )
00509 {
00510 int back, stencil, depth, caveat, alpha, mipmap, rgba;
00511 back = INT_MAX;
00512 stencil = INT_MAX;
00513 depth = INT_MAX;
00514 caveat = INT_MAX;
00515 mipmap = 0;
00516 rgba = 0;
00517 fbcdrawableinfo[ i ].fbconfig = NULL;
00518 fbcdrawableinfo[ i ].bind_texture_format = 0;
00519 fbcdrawableinfo[ i ].y_inverted = 0;
00520 fbcdrawableinfo[ i ].mipmap = 0;
00521 for( int j = 0; j < cnt; j++ )
00522 {
00523 XVisualInfo *vi;
00524 int visual_depth;
00525 vi = glXGetVisualFromFBConfig( display(), fbconfigs[ j ] );
00526 if( vi == NULL )
00527 continue;
00528 visual_depth = vi->depth;
00529 XFree( vi );
00530 if( visual_depth != i )
00531 continue;
00532 int value;
00533 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00534 GLX_ALPHA_SIZE, &alpha );
00535 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00536 GLX_BUFFER_SIZE, &value );
00537 if( value != i && ( value - alpha ) != i )
00538 continue;
00539 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00540 GLX_RENDER_TYPE, &value );
00541 if( !( value & GLX_RGBA_BIT ))
00542 continue;
00543 if( tfp_mode )
00544 {
00545 value = 0;
00546 if( i == 32 )
00547 {
00548 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00549 GLX_BIND_TO_TEXTURE_RGBA_EXT, &value );
00550 if( value )
00551 {
00552
00553 rgba = 1;
00554 fbcdrawableinfo[ i ].bind_texture_format = GLX_TEXTURE_FORMAT_RGBA_EXT;
00555 }
00556 }
00557 if( !value )
00558 {
00559 if( rgba )
00560 continue;
00561 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00562 GLX_BIND_TO_TEXTURE_RGB_EXT, &value );
00563 if( !value )
00564 continue;
00565 fbcdrawableinfo[ i ].bind_texture_format = GLX_TEXTURE_FORMAT_RGB_EXT;
00566 }
00567 }
00568 int back_value;
00569 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00570 GLX_DOUBLEBUFFER, &back_value );
00571 if( back_value > back )
00572 continue;
00573 int stencil_value;
00574 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00575 GLX_STENCIL_SIZE, &stencil_value );
00576 if( stencil_value > stencil )
00577 continue;
00578 int depth_value;
00579 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00580 GLX_DEPTH_SIZE, &depth_value );
00581 if( depth_value > depth )
00582 continue;
00583 int mipmap_value = -1;
00584 if( tfp_mode && GLTexture::framebufferObjectSupported())
00585 {
00586 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00587 GLX_BIND_TO_MIPMAP_TEXTURE_EXT, &mipmap_value );
00588 if( mipmap_value < mipmap )
00589 continue;
00590 }
00591 int caveat_value;
00592 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00593 GLX_CONFIG_CAVEAT, &caveat_value );
00594 if( caveat_value > caveat )
00595 continue;
00596
00597 fbcdrawableinfo[ i ].fbconfig = fbconfigs[ j ];
00598 caveat = caveat_value;
00599 back = back_value;
00600 stencil = stencil_value;
00601 depth = depth_value;
00602 mipmap = mipmap_value;
00603 glXGetFBConfigAttrib( display(), fbconfigs[ j ],
00604 GLX_Y_INVERTED_EXT, &value );
00605 fbcdrawableinfo[ i ].y_inverted = value;
00606 fbcdrawableinfo[ i ].mipmap = mipmap;
00607 }
00608 }
00609 if( cnt )
00610 XFree( fbconfigs );
00611 if( fbcdrawableinfo[ DefaultDepth( display(), DefaultScreen( display())) ].fbconfig == NULL )
00612 {
00613 kError( 1212 ) << "Couldn't find framebuffer configuration for default depth!";
00614 return false;
00615 }
00616 if( fbcdrawableinfo[ 32 ].fbconfig == NULL )
00617 {
00618 kError( 1212 ) << "Couldn't find framebuffer configuration for depth 32 (no ARGB GLX visual)!";
00619 return false;
00620 }
00621 return true;
00622 }
00623
00624
00625
00626
00627
00628 bool SceneOpenGL::selfCheck()
00629 {
00630 QImage img( 3, 2, QImage::Format_RGB32 );
00631 img.setPixel( 0, 0, QColor( Qt::red ).rgb());
00632 img.setPixel( 1, 0, QColor( Qt::green ).rgb());
00633 img.setPixel( 2, 0, QColor( Qt::blue ).rgb());
00634 img.setPixel( 0, 1, QColor( Qt::white ).rgb());
00635 img.setPixel( 1, 1, QColor( Qt::black ).rgb());
00636 img.setPixel( 2, 1, QColor( Qt::white ).rgb());
00637 QPixmap pix = QPixmap::fromImage( img );
00638 QList< QPoint > points = selfCheckPoints();
00639 QRegion reg;
00640 foreach( const QPoint& p, points )
00641 reg |= QRect( p, pix.size());
00642 if( wspace->overlayWindow())
00643 {
00644 wspace->setOverlayShape( reg );
00645 wspace->showOverlay();
00646 }
00647 foreach( const QPoint& p, points )
00648 {
00649 XSetWindowAttributes wa;
00650 wa.override_redirect = True;
00651 ::Window window = XCreateWindow( display(), rootWindow(), 0, 0, 3, 2, 0, QX11Info::appDepth(),
00652 CopyFromParent, CopyFromParent, CWOverrideRedirect, &wa );
00653 XSetWindowBackgroundPixmap( display(), window, pix.handle());
00654 XClearWindow( display(), window );
00655 XMapWindow( display(), window );
00656
00657
00658 XMoveWindow( display(), window, p.x() + 1, p.y());
00659 XCompositeRedirectWindow( display(), window, CompositeRedirectManual );
00660 Pixmap wpix = XCompositeNameWindowPixmap( display(), window );
00661 glXWaitX();
00662 Texture texture;
00663 texture.load( wpix, QSize( 3, 2 ), QX11Info::appDepth());
00664 texture.bind();
00665 QRect rect( p.x(), p.y(), 3, 2 );
00666 texture.render( infiniteRegion(), rect );
00667 texture.unbind();
00668 glXWaitGL();
00669 XFreePixmap( display(), wpix );
00670 XDestroyWindow( display(), window );
00671 }
00672 flushBuffer( PAINT_SCREEN_REGION, reg );
00673 glXWaitGL();
00674 bool ok = true;
00675 foreach( const QPoint& p, points )
00676 {
00677 QPixmap pix = QPixmap::grabWindow( rootWindow(), p.x(), p.y(), 3, 2 );
00678 QImage img = pix.toImage();
00679
00680
00681
00682
00683
00684
00685 if( img.pixel( 0, 0 ) != QColor( Qt::red ).rgb()
00686 || img.pixel( 1, 0 ) != QColor( Qt::green ).rgb()
00687 || img.pixel( 2, 0 ) != QColor( Qt::blue ).rgb()
00688 || img.pixel( 0, 1 ) != QColor( Qt::white ).rgb()
00689 || img.pixel( 1, 1 ) != QColor( Qt::black ).rgb()
00690 || img.pixel( 2, 1 ) != QColor( Qt::white ).rgb())
00691 {
00692 kError( 1212 ) << "Compositing self-check failed, disabling compositing.";
00693 ok = false;
00694 break;
00695 }
00696 }
00697 if( wspace->overlayWindow())
00698 wspace->hideOverlay();
00699 if( ok )
00700 kDebug( 1212 ) << "Compositing self-check passed.";
00701 if( !ok && options->disableCompositingChecks )
00702 {
00703 kWarning( 1212 ) << "Compositing checks disabled, proceeding regardless of self-check failure.";
00704 return true;
00705 }
00706 return ok;
00707 }
00708
00709
00710 void SceneOpenGL::paint( QRegion damage, ToplevelList toplevels )
00711 {
00712 foreach( Toplevel* c, toplevels )
00713 {
00714 assert( windows.contains( c ));
00715 stacking_order.append( windows[ c ] );
00716 }
00717 grabXServer();
00718 glXWaitX();
00719 glPushMatrix();
00720 int mask = 0;
00721 #ifdef CHECK_GL_ERROR
00722 checkGLError( "Paint1" );
00723 #endif
00724 paintScreen( &mask, &damage );
00725 #ifdef CHECK_GL_ERROR
00726 checkGLError( "Paint2" );
00727 #endif
00728 glPopMatrix();
00729 ungrabXServer();
00730 if( wspace->overlayWindow())
00731 wspace->showOverlay();
00732 flushBuffer( mask, damage );
00733
00734 stacking_order.clear();
00735 checkGLError( "PostPaint" );
00736 }
00737
00738
00739 void SceneOpenGL::waitSync()
00740 {
00741 if( waitSyncAvailable())
00742 {
00743 unsigned int sync;
00744
00745 glFlush();
00746 glXGetVideoSync( &sync );
00747 glXWaitVideoSync( 2, ( sync + 1 ) % 2, &sync );
00748 }
00749 }
00750
00751
00752 void SceneOpenGL::flushBuffer( int mask, QRegion damage )
00753 {
00754 if( db )
00755 {
00756 if( mask & PAINT_SCREEN_REGION )
00757 {
00758 waitSync();
00759 if( glXCopySubBuffer )
00760 {
00761 foreach( const QRect &r, damage.rects())
00762 {
00763
00764 int y = displayHeight() - r.y() - r.height();
00765 glXCopySubBuffer( display(), glxbuffer, r.x(), y, r.width(), r.height());
00766 }
00767 }
00768 else
00769 {
00770 glEnable( GL_SCISSOR_TEST );
00771 glDrawBuffer( GL_FRONT );
00772 int xpos = 0;
00773 int ypos = 0;
00774 foreach( const QRect &r, damage.rects())
00775 {
00776
00777 int y = displayHeight() - r.y() - r.height();
00778
00779
00780
00781
00782 glBitmap( 0, 0, 0, 0, r.x() - xpos, y - ypos, NULL );
00783 xpos = r.x();
00784 ypos = y;
00785 glScissor( r.x(), y, r.width(), r.height());
00786 glCopyPixels( r.x(), y, r.width(), r.height(), GL_COLOR );
00787 }
00788 glBitmap( 0, 0, 0, 0, -xpos, -ypos, NULL );
00789 glDrawBuffer( GL_BACK );
00790 glDisable( GL_SCISSOR_TEST );
00791 }
00792 }
00793 else
00794 {
00795 waitSync();
00796 glXSwapBuffers( display(), glxbuffer );
00797 }
00798 glXWaitGL();
00799 XFlush( display());
00800 }
00801 else
00802 {
00803 glFlush();
00804 glXWaitGL();
00805 waitSync();
00806 if( mask & PAINT_SCREEN_REGION )
00807 foreach( const QRect &r, damage.rects())
00808 XCopyArea( display(), buffer, rootWindow(), gcroot, r.x(), r.y(), r.width(), r.height(), r.x(), r.y());
00809 else
00810 XCopyArea( display(), buffer, rootWindow(), gcroot, 0, 0, displayWidth(), displayHeight(), 0, 0 );
00811 XFlush( display());
00812 }
00813 }
00814
00815 void SceneOpenGL::paintGenericScreen( int mask, ScreenPaintData data )
00816 {
00817 if( mask & PAINT_SCREEN_TRANSFORMED )
00818 {
00819 glPushMatrix();
00820 glTranslatef( data.xTranslate, data.yTranslate, data.zTranslate );
00821 if( data.rotation )
00822 {
00823
00824 glTranslatef( data.rotation->xRotationPoint, data.rotation->yRotationPoint, data.rotation->zRotationPoint );
00825 float xAxis = 0.0;
00826 float yAxis = 0.0;
00827 float zAxis = 0.0;
00828 switch( data.rotation->axis )
00829 {
00830 case RotationData::XAxis:
00831 xAxis = 1.0;
00832 break;
00833 case RotationData::YAxis:
00834 yAxis = 1.0;
00835 break;
00836 case RotationData::ZAxis:
00837 zAxis = 1.0;
00838 break;
00839 }
00840 glRotatef( data.rotation->angle, xAxis, yAxis, zAxis );
00841 glTranslatef( -data.rotation->xRotationPoint, -data.rotation->yRotationPoint, -data.rotation->zRotationPoint );
00842 }
00843 glScalef( data.xScale, data.yScale, data.zScale );
00844 }
00845 Scene::paintGenericScreen( mask, data );
00846 if( mask & PAINT_SCREEN_TRANSFORMED )
00847 glPopMatrix();
00848 }
00849
00850 void SceneOpenGL::paintBackground( QRegion region )
00851 {
00852 PaintClipper pc( region );
00853 if( !PaintClipper::clip())
00854 {
00855 glPushAttrib( GL_COLOR_BUFFER_BIT );
00856 glClearColor( 0, 0, 0, 1 );
00857 glClear( GL_COLOR_BUFFER_BIT );
00858 glPopAttrib();
00859 return;
00860 }
00861 if( pc.clip() && pc.paintArea().isEmpty())
00862 return;
00863 glPushAttrib( GL_CURRENT_BIT );
00864 glColor4f( 0, 0, 0, 1 );
00865 for( PaintClipper::Iterator iterator;
00866 !iterator.isDone();
00867 iterator.next())
00868 {
00869 glBegin( GL_QUADS );
00870 QRect r = iterator.boundingRect();
00871 glVertex2i( r.x(), r.y());
00872 glVertex2i( r.x() + r.width(), r.y());
00873 glVertex2i( r.x() + r.width(), r.y() + r.height());
00874 glVertex2i( r.x(), r.y() + r.height());
00875 glEnd();
00876 }
00877 glPopAttrib();
00878 }
00879
00880 void SceneOpenGL::windowAdded( Toplevel* c )
00881 {
00882 assert( !windows.contains( c ));
00883 windows[ c ] = new Window( c );
00884 c->effectWindow()->setSceneWindow( windows[ c ]);
00885 }
00886
00887 void SceneOpenGL::windowClosed( Toplevel* c, Deleted* deleted )
00888 {
00889 assert( windows.contains( c ));
00890 if( deleted != NULL )
00891 {
00892 Window* w = windows.take( c );
00893 w->updateToplevel( deleted );
00894 windows[ deleted ] = w;
00895 }
00896 else
00897 {
00898 delete windows.take( c );
00899 c->effectWindow()->setSceneWindow( NULL );
00900 }
00901 }
00902
00903 void SceneOpenGL::windowDeleted( Deleted* c )
00904 {
00905 assert( windows.contains( c ));
00906 delete windows.take( c );
00907 c->effectWindow()->setSceneWindow( NULL );
00908 }
00909
00910 void SceneOpenGL::windowGeometryShapeChanged( Toplevel* c )
00911 {
00912 if( !windows.contains( c ))
00913 return;
00914 Window* w = windows[ c ];
00915 w->discardShape();
00916 w->checkTextureSize();
00917 }
00918
00919 void SceneOpenGL::windowOpacityChanged( Toplevel* )
00920 {
00921 #if 0 // not really needed, windows are painted on every repaint
00922
00923
00924 if( !windows.contains( c ))
00925 return;
00926 Window* w = windows[ c ];
00927 w->discardTexture();
00928 #endif
00929 }
00930
00931
00932
00933
00934
00935 SceneOpenGL::Texture::Texture() : GLTexture()
00936 {
00937 init();
00938 }
00939
00940 SceneOpenGL::Texture::Texture( const Pixmap& pix, const QSize& size, int depth ) : GLTexture()
00941 {
00942 init();
00943 load( pix, size, depth );
00944 }
00945
00946 SceneOpenGL::Texture::~Texture()
00947 {
00948 discard();
00949 }
00950
00951 void SceneOpenGL::Texture::init()
00952 {
00953 bound_glxpixmap = None;
00954 }
00955
00956 void SceneOpenGL::Texture::createTexture()
00957 {
00958 glGenTextures( 1, &mTexture );
00959 }
00960
00961 void SceneOpenGL::Texture::discard()
00962 {
00963 if( mTexture != None )
00964 release();
00965 GLTexture::discard();
00966 }
00967
00968 void SceneOpenGL::Texture::release()
00969 {
00970 if( tfp_mode && bound_glxpixmap != None )
00971 {
00972 if( !options->glStrictBinding )
00973 glXReleaseTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT );
00974 glXDestroyGLXPixmap( display(), bound_glxpixmap );
00975 bound_glxpixmap = None;
00976 }
00977 }
00978
00979 void SceneOpenGL::Texture::findTarget()
00980 {
00981 unsigned int new_target = 0;
00982 if( tfp_mode && glXQueryDrawable && bound_glxpixmap != None )
00983 glXQueryDrawable( display(), bound_glxpixmap, GLX_TEXTURE_TARGET_EXT, &new_target );
00984
00985
00986
00987
00988 if( new_target == 0 )
00989 {
00990 if( NPOTTextureSupported() ||
00991 ( isPowerOfTwo( mSize.width()) && isPowerOfTwo( mSize.height())))
00992 new_target = GLX_TEXTURE_2D_EXT;
00993 else
00994 new_target = GLX_TEXTURE_RECTANGLE_EXT;
00995 }
00996 switch( new_target )
00997 {
00998 case GLX_TEXTURE_2D_EXT:
00999 mTarget = GL_TEXTURE_2D;
01000 mScale.setWidth( 1.0f / mSize.width());
01001 mScale.setHeight( 1.0f / mSize.height());
01002 break;
01003 case GLX_TEXTURE_RECTANGLE_EXT:
01004 mTarget = GL_TEXTURE_RECTANGLE_ARB;
01005 mScale.setWidth( 1.0f );
01006 mScale.setHeight( 1.0f );
01007 break;
01008 default:
01009 abort();
01010 }
01011 }
01012
01013 QRegion SceneOpenGL::Texture::optimizeBindDamage( const QRegion& reg, int limit )
01014 {
01015 if( reg.rects().count() <= 1 )
01016 return reg;
01017
01018
01019
01020
01021 int size = 0;
01022 foreach( const QRect &r, reg.rects())
01023 size += r.width() * r.height();
01024 if( reg.boundingRect().width() * reg.boundingRect().height() - size < limit )
01025 return reg.boundingRect();
01026 return reg;
01027 }
01028
01029 bool SceneOpenGL::Texture::load( const Pixmap& pix, const QSize& size,
01030 int depth, QRegion region )
01031 {
01032 #ifdef CHECK_GL_ERROR
01033 checkGLError( "TextureLoad1" );
01034 #endif
01035 if( pix == None || size.isEmpty() || depth < 1 )
01036 return false;
01037 if( tfp_mode )
01038 {
01039 if( fbcdrawableinfo[ depth ].fbconfig == NULL )
01040 {
01041 kDebug( 1212 ) << "No framebuffer configuration for depth " << depth
01042 << "; not binding pixmap" << endl;
01043 return false;
01044 }
01045 }
01046
01047 mSize = size;
01048 if( mTexture == None || !region.isEmpty())
01049 {
01050 setDirty();
01051 }
01052
01053 #ifdef CHECK_GL_ERROR
01054 checkGLError( "TextureLoad2" );
01055 #endif
01056 if( tfp_mode )
01057 {
01058 if( mTexture == None )
01059 createTexture();
01060
01061
01062 if( bound_glxpixmap != None )
01063 glBindTexture( mTarget, mTexture );
01064 else
01065 {
01066 int attrs[] =
01067 {
01068 GLX_TEXTURE_FORMAT_EXT, fbcdrawableinfo[ depth ].bind_texture_format,
01069 GLX_MIPMAP_TEXTURE_EXT, fbcdrawableinfo[ depth ].mipmap,
01070 None
01071 };
01072
01073
01074 bound_glxpixmap = glXCreatePixmap( display(), fbcdrawableinfo[ depth ].fbconfig, pix, attrs );
01075 #ifdef CHECK_GL_ERROR
01076 checkGLError( "TextureLoadTFP1" );
01077 #endif
01078 findTarget();
01079 y_inverted = fbcdrawableinfo[ depth ].y_inverted ? true : false;
01080 can_use_mipmaps = fbcdrawableinfo[ depth ].mipmap ? true : false;
01081 glBindTexture( mTarget, mTexture );
01082 #ifdef CHECK_GL_ERROR
01083 checkGLError( "TextureLoadTFP2" );
01084 #endif
01085 if( !options->glStrictBinding )
01086 glXBindTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT, NULL );
01087 }
01088 }
01089 else if( shm_mode )
01090 {
01091 #ifdef HAVE_XSHM
01092 GLenum pixfmt, type;
01093 if( depth >= 24 )
01094 {
01095 pixfmt = GL_BGRA;
01096 type = GL_UNSIGNED_BYTE;
01097 }
01098 else
01099 {
01100 pixfmt = GL_RGB;
01101 type = GL_UNSIGNED_SHORT_5_6_5;
01102 }
01103 findTarget();
01104 #ifdef CHECK_GL_ERROR
01105 checkGLError( "TextureLoadSHM1" );
01106 #endif
01107 if( mTexture == None )
01108 {
01109 createTexture();
01110 glBindTexture( mTarget, mTexture );
01111 y_inverted = false;
01112 glTexImage2D( mTarget, 0, depth == 32 ? GL_RGBA : GL_RGB,
01113 mSize.width(), mSize.height(), 0,
01114 pixfmt, type, NULL );
01115 }
01116 else
01117 glBindTexture( mTarget, mTexture );
01118 if( !region.isEmpty())
01119 {
01120 XGCValues xgcv;
01121 xgcv.graphics_exposures = False;
01122 xgcv.subwindow_mode = IncludeInferiors;
01123 GC gc = XCreateGC( display(), pix, GCGraphicsExposures | GCSubwindowMode, &xgcv );
01124 Pixmap p = XShmCreatePixmap( display(), rootWindow(), shm.shmaddr, &shm,
01125 mSize.width(), mSize.height(), depth );
01126 QRegion damage = optimizeBindDamage( region, 100 * 100 );
01127 glPixelStorei( GL_UNPACK_ROW_LENGTH, mSize.width());
01128 foreach( const QRect &r, damage.rects())
01129 {
01130 XCopyArea( display(), pix, p, gc, r.x(), r.y(), r.width(), r.height(), 0, 0 );
01131 glXWaitX();
01132 glTexSubImage2D( mTarget, 0,
01133 r.x(), r.y(), r.width(), r.height(),
01134 pixfmt, type, shm.shmaddr );
01135 glXWaitGL();
01136 }
01137 glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 );
01138 XFreePixmap( display(), p );
01139 XFreeGC( display(), gc );
01140 }
01141 #ifdef CHECK_GL_ERROR
01142 checkGLError( "TextureLoadSHM2" );
01143 #endif
01144 y_inverted = true;
01145 can_use_mipmaps = true;
01146 #endif
01147 }
01148 else
01149 {
01150
01151
01152 findTarget();
01153 GLXDrawable pixmap = glXCreatePixmap( display(), fbcdrawableinfo[ QX11Info::appDepth() ].fbconfig, pix, NULL );
01154 glXMakeCurrent( display(), pixmap, ctxdrawable );
01155 if( last_pixmap != None )
01156 glXDestroyPixmap( display(), last_pixmap );
01157
01158
01159 last_pixmap = pixmap;
01160 glReadBuffer( GL_FRONT );
01161 glDrawBuffer( GL_FRONT );
01162 if( mTexture == None )
01163 {
01164 createTexture();
01165 glBindTexture( mTarget, mTexture );
01166 y_inverted = false;
01167 glCopyTexImage2D( mTarget, 0,
01168 depth == 32 ? GL_RGBA : GL_RGB,
01169 0, 0, mSize.width(), mSize.height(), 0 );
01170 }
01171 else
01172 {
01173 glBindTexture( mTarget, mTexture );
01174 QRegion damage = optimizeBindDamage( region, 30 * 30 );
01175 foreach( const QRect &r, damage.rects())
01176 {
01177
01178
01179
01180 int gly = mSize.height() - r.y() - r.height();
01181 glCopyTexSubImage2D( mTarget, 0,
01182 r.x(), gly, r.x(), gly, r.width(), r.height());
01183 }
01184 }
01185 glXWaitGL();
01186 if( db )
01187 glDrawBuffer( GL_BACK );
01188 glXMakeCurrent( display(), glxbuffer, ctxbuffer );
01189 glBindTexture( mTarget, mTexture );
01190 y_inverted = false;
01191 can_use_mipmaps = true;
01192 }
01193 #ifdef CHECK_GL_ERROR
01194 checkGLError( "TextureLoad0" );
01195 #endif
01196 return true;
01197 }
01198
01199 bool SceneOpenGL::Texture::load( const Pixmap& pix, const QSize& size,
01200 int depth )
01201 {
01202 return load( pix, size, depth,
01203 QRegion( 0, 0, size.width(), size.height()));
01204 }
01205
01206 bool SceneOpenGL::Texture::load( const QImage& image, GLenum target )
01207 {
01208 if( image.isNull())
01209 return false;
01210 return load( QPixmap::fromImage( image ), target );
01211 }
01212
01213 bool SceneOpenGL::Texture::load( const QPixmap& pixmap, GLenum target )
01214 {
01215 Q_UNUSED( target );
01216 if( pixmap.isNull())
01217 return false;
01218 return load( pixmap.handle(), pixmap.size(), pixmap.depth());
01219 }
01220
01221 void SceneOpenGL::Texture::bind()
01222 {
01223 glEnable( mTarget );
01224 glBindTexture( mTarget, mTexture );
01225 if( tfp_mode && options->glStrictBinding )
01226 {
01227 assert( bound_glxpixmap != None );
01228 glXBindTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT, NULL );
01229 }
01230 enableFilter();
01231 if( hasGLVersion( 1, 4, 0 ))
01232 {
01233
01234 glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, -1.0f );
01235 }
01236 }
01237
01238 void SceneOpenGL::Texture::unbind()
01239 {
01240 if( hasGLVersion( 1, 4, 0 ))
01241 {
01242 glTexEnvf( GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, 0.0f );
01243 }
01244 if( tfp_mode && options->glStrictBinding )
01245 {
01246 assert( bound_glxpixmap != None );
01247 glBindTexture( mTarget, mTexture );
01248 glXReleaseTexImageEXT( display(), bound_glxpixmap, GLX_FRONT_LEFT_EXT );
01249 }
01250 GLTexture::unbind();
01251 }
01252
01253
01254
01255
01256
01257 SceneOpenGL::Window::Window( Toplevel* c )
01258 : Scene::Window( c )
01259 , texture()
01260 {
01261 }
01262
01263 SceneOpenGL::Window::~Window()
01264 {
01265 discardTexture();
01266 }
01267
01268
01269 bool SceneOpenGL::Window::bindTexture()
01270 {
01271 if( texture.texture() != None && toplevel->damage().isEmpty())
01272 {
01273
01274 glBindTexture( texture.target(), texture.texture());
01275 return true;
01276 }
01277
01278 Pixmap pix = toplevel->windowPixmap();
01279 if( pix == None )
01280 return false;
01281 bool success = texture.load( pix, toplevel->size(), toplevel->depth(),
01282 toplevel->damage());
01283 if( success )
01284 toplevel->resetDamage( toplevel->rect());
01285 else
01286 kDebug( 1212 ) << "Failed to bind window";
01287 return success;
01288 }
01289
01290 void SceneOpenGL::Window::discardTexture()
01291 {
01292 texture.discard();
01293 }
01294
01295
01296
01297
01298
01299
01300
01301 void SceneOpenGL::Window::checkTextureSize()
01302 {
01303 if( texture.size() != size())
01304 discardTexture();
01305 }
01306
01307
01308 void SceneOpenGL::Window::pixmapDiscarded()
01309 {
01310 texture.release();
01311 }
01312
01313
01314 void SceneOpenGL::Window::performPaint( int mask, QRegion region, WindowPaintData data )
01315 {
01316
01317
01318 bool opaque = isOpaque() && data.opacity == 1.0;
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328 if( region != infiniteRegion())
01329 region.translate( -x(), -y());
01330 if(( mask & ( PAINT_SCREEN_TRANSFORMED | PAINT_WINDOW_TRANSFORMED )) == 0 )
01331 region &= shape();
01332 if( region.isEmpty())
01333 return;
01334 if( !bindTexture())
01335 return;
01336 glPushMatrix();
01337
01338 if( options->smoothScale != 0 )
01339 {
01340 if( mask & PAINT_WINDOW_TRANSFORMED )
01341 filter = ImageFilterGood;
01342 else if( mask & PAINT_SCREEN_TRANSFORMED )
01343 filter = ImageFilterGood;
01344 else
01345 filter = ImageFilterFast;
01346 }
01347 else
01348 filter = ImageFilterFast;
01349 if( filter == ImageFilterGood )
01350 {
01351
01352
01353
01354 if( options->smoothScale == 2
01355 && ( data.quads.smoothNeeded() || data.xScale < 1 || data.yScale < 1 ))
01356 {
01357 texture.setFilter( GL_LINEAR_MIPMAP_LINEAR );
01358 }
01359 else
01360 texture.setFilter( GL_LINEAR );
01361 }
01362 else
01363 texture.setFilter( GL_NEAREST );
01364
01365 int x = toplevel->x();
01366 int y = toplevel->y();
01367 double z = 0.0;
01368 if( mask & PAINT_WINDOW_TRANSFORMED )
01369 {
01370 x += data.xTranslate;
01371 y += data.yTranslate;
01372 z += data.zTranslate;
01373 }
01374 glTranslatef( x, y, z );
01375 if(( mask & PAINT_WINDOW_TRANSFORMED ) && ( data.xScale != 1 || data.yScale != 1 || data.zScale != 1 ))
01376 glScalef( data.xScale, data.yScale, data.zScale );
01377 if(( mask & PAINT_WINDOW_TRANSFORMED ) && data.rotation )
01378 {
01379 glTranslatef( data.rotation->xRotationPoint, data.rotation->yRotationPoint, data.rotation->zRotationPoint );
01380 float xAxis = 0.0;
01381 float yAxis = 0.0;
01382 float zAxis = 0.0;
01383 switch( data.rotation->axis )
01384 {
01385 case RotationData::XAxis:
01386 xAxis = 1.0;
01387 break;
01388 case RotationData::YAxis:
01389 yAxis = 1.0;
01390 break;
01391 case RotationData::ZAxis:
01392 zAxis = 1.0;
01393 break;
01394 }
01395 glRotatef( data.rotation->angle, xAxis, yAxis, zAxis );
01396 glTranslatef( -data.rotation->xRotationPoint, -data.rotation->yRotationPoint, -data.rotation->zRotationPoint );
01397 }
01398 region.translate( toplevel->x(), toplevel->y() );
01399
01400 texture.bind();
01401 texture.enableUnnormalizedTexCoords();
01402
01403 WindowQuadList decoration = data.quads.select( WindowQuadDecoration );
01404 if( data.contents_opacity != data.decoration_opacity && !decoration.isEmpty())
01405 {
01406 prepareStates( data.opacity * data.contents_opacity, data.brightness, data.saturation, data.shader );
01407 renderQuads( mask, region, data.quads.select( WindowQuadContents ));
01408 restoreStates( data.opacity * data.contents_opacity, data.brightness, data.saturation, data.shader );
01409 prepareStates( data.opacity * data.decoration_opacity, data.brightness, data.saturation, data.shader );
01410 renderQuads( mask, region, decoration );
01411 restoreStates( data.opacity * data.decoration_opacity, data.brightness, data.saturation, data.shader );
01412 }
01413 else
01414 {
01415 prepareStates( data.opacity * data.contents_opacity, data.brightness, data.saturation, data.shader );
01416 renderQuads( mask, region, data.quads.select( WindowQuadContents ));
01417 renderQuads( mask, region, data.quads.select( WindowQuadDecoration ));
01418 restoreStates( data.opacity * data.contents_opacity, data.brightness, data.saturation, data.shader );
01419 }
01420
01421 texture.disableUnnormalizedTexCoords();
01422 texture.unbind();
01423 glPopMatrix();
01424 }
01425
01426 void SceneOpenGL::Window::renderQuads( int, const QRegion& region, const WindowQuadList& quads )
01427 {
01428 if( quads.isEmpty())
01429 return;
01430
01431 float* vertices;
01432 float* texcoords;
01433 quads.makeArrays( &vertices, &texcoords );
01434 renderGLGeometry( region, quads.count() * 4,
01435 vertices, texcoords, NULL, 2, 0 );
01436 delete[] vertices;
01437 delete[] texcoords;
01438 }
01439
01440 void SceneOpenGL::Window::prepareStates( double opacity, double brightness, double saturation, GLShader* shader )
01441 {
01442 if(shader)
01443 prepareShaderRenderStates( opacity, brightness, saturation, shader );
01444 else
01445 prepareRenderStates( opacity, brightness, saturation );
01446 }
01447
01448 void SceneOpenGL::Window::prepareShaderRenderStates( double opacity, double brightness, double saturation, GLShader* shader )
01449 {
01450
01451 glPushAttrib( GL_ENABLE_BIT );
01452 bool opaque = isOpaque() && opacity == 1.0;
01453 if( !opaque )
01454 {
01455 glEnable( GL_BLEND );
01456 glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
01457 }
01458 shader->setUniform("opacity", (float)opacity);
01459 shader->setUniform("saturation", (float)saturation);
01460 shader->setUniform("brightness", (float)brightness);
01461 }
01462
01463 void SceneOpenGL::Window::prepareRenderStates( double opacity, double brightness, double saturation )
01464 {
01465
01466 glPushAttrib( GL_ENABLE_BIT );
01467 bool opaque = isOpaque() && opacity == 1.0;
01468 if( !opaque )
01469 {
01470 glEnable( GL_BLEND );
01471 glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
01472 }
01473 if( saturation != 1.0 && texture.saturationSupported())
01474 {
01475
01476 glActiveTexture( GL_TEXTURE0 );
01477 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
01478 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
01479 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE );
01480 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
01481 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT );
01482 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
01483 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT );
01484 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA );
01485 const float scale_constant[] = { 1.0, 1.0, 1.0, 0.5};
01486 glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, scale_constant );
01487 texture.bind();
01488
01489
01490
01491
01492
01493
01494 glActiveTexture( GL_TEXTURE1 );
01495 float saturation_constant[] = { 0.5 + 0.5*0.30, 0.5 + 0.5*0.59, 0.5 + 0.5*0.11, saturation };
01496 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
01497 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB );
01498 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS );
01499 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
01500 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT );
01501 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
01502 glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, saturation_constant );
01503 texture.bind();
01504
01505
01506
01507 glActiveTexture( GL_TEXTURE2 );
01508 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
01509 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE );
01510 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0 );
01511 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
01512 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS );
01513 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
01514 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT );
01515 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA );
01516 glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, saturation_constant );
01517
01518 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE );
01519 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR );
01520 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
01521
01522 glColor4f( opacity, opacity, opacity, opacity );
01523 texture.bind();
01524
01525 if( toplevel->hasAlpha() || brightness != 1.0f )
01526 {
01527 glActiveTexture( GL_TEXTURE3 );
01528 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
01529 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE );
01530 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS );
01531 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
01532 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR );
01533 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
01534
01535 float opacityByBrightness = opacity * brightness;
01536 glColor4f( opacityByBrightness, opacityByBrightness, opacityByBrightness, opacity );
01537 if( toplevel->hasAlpha() )
01538 {
01539
01540 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE );
01541 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0 );
01542 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
01543 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR );
01544 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA );
01545 }
01546 else
01547 {
01548
01549 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE );
01550 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS );
01551 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA );
01552 }
01553 texture.bind();
01554 }
01555
01556 glActiveTexture(GL_TEXTURE0 );
01557 }
01558 else if( opacity != 1.0 || brightness != 1.0 )
01559 {
01560
01561
01562 float opacityByBrightness = opacity * brightness;
01563 if( toplevel->hasAlpha())
01564 {
01565 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
01566 glColor4f( opacityByBrightness, opacityByBrightness, opacityByBrightness,
01567 opacity);
01568 }
01569 else
01570 {
01571
01572 float constant[] = { opacityByBrightness, opacityByBrightness, opacityByBrightness, opacity };
01573 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
01574 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE );
01575 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE );
01576 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
01577 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT );
01578 glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );
01579 glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE );
01580 glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT );
01581 glTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, constant );
01582 }
01583 }
01584 }
01585
01586 void SceneOpenGL::Window::restoreStates( double opacity, double brightness, double saturation, GLShader* shader )
01587 {
01588 if(shader)
01589 restoreShaderRenderStates( opacity, brightness, saturation, shader );
01590 else
01591 restoreRenderStates( opacity, brightness, saturation );
01592 }
01593
01594 void SceneOpenGL::Window::restoreShaderRenderStates( double opacity, double brightness, double saturation, GLShader* shader )
01595 {
01596 Q_UNUSED( opacity );
01597 Q_UNUSED( brightness );
01598 Q_UNUSED( saturation );
01599 Q_UNUSED( shader );
01600 glPopAttrib();
01601 }
01602
01603 void SceneOpenGL::Window::restoreRenderStates( double opacity, double brightness, double saturation )
01604 {
01605 if( opacity != 1.0 || saturation != 1.0 || brightness != 1.0f )
01606 {
01607 if( saturation != 1.0 && texture.saturationSupported())
01608 {
01609 glActiveTexture(GL_TEXTURE3);
01610 glDisable( texture.target());
01611 glActiveTexture(GL_TEXTURE2);
01612 glDisable( texture.target());
01613 glActiveTexture(GL_TEXTURE1);
01614 glDisable( texture.target());
01615 glActiveTexture(GL_TEXTURE0);
01616 }
01617 glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
01618 glColor4f( 0, 0, 0, 0 );
01619 }
01620
01621 glPopAttrib();
01622 }
01623
01624 }
01625
01626 #endif