00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "glXWindow.h"
00020
00021 #include "global.h"
00022 #include "glXPipe.h"
00023 #include "pipe.h"
00024
00025 namespace eq
00026 {
00027
00028
00029 GLXWindow::GLXWindow( Window* parent )
00030 : GLXWindowIF( parent )
00031 , _xDrawable ( 0 )
00032 , _glXContext( 0 )
00033 , _glXNVSwapGroup( 0 )
00034 {
00035
00036 }
00037
00038 GLXWindow::~GLXWindow( )
00039 {
00040
00041 }
00042
00043
00044
00045
00046 namespace
00047 {
00048 static Bool WaitForNotify( Display*, XEvent *e, char *arg )
00049 { return (e->type == MapNotify) && (e->xmap.window == (::Window)arg); }
00050 }
00051
00052 bool GLXWindow::configInit( )
00053 {
00054 XVisualInfo* visualInfo = chooseXVisualInfo();
00055 if( !visualInfo )
00056 return false;
00057
00058 GLXContext context = createGLXContext( visualInfo );
00059 setGLXContext( context );
00060
00061 if( !context )
00062 return false;
00063
00064 const bool success = configInitGLXDrawable( visualInfo );
00065 XFree( visualInfo );
00066
00067 if( !success || !_xDrawable )
00068 {
00069 _window->setErrorMessage(
00070 "configInitGLXDrawable did not set a X11 drawable");
00071 return false;
00072 }
00073
00074 makeCurrent();
00075 initGLEW();
00076
00077 if( getIAttribute( Window::IATTR_HINT_DRAWABLE ) == FBO )
00078 configInitFBO();
00079
00080 return success;
00081 }
00082
00083
00084 Display* GLXWindow::getXDisplay()
00085 {
00086 Pipe* pipe = getPipe();
00087
00088 EQASSERT( pipe );
00089 EQASSERT( pipe->getOSPipe( ));
00090 EQASSERT( dynamic_cast< GLXPipe* >( pipe->getOSPipe( )));
00091
00092 GLXPipe* osPipe = static_cast< GLXPipe* >( pipe->getOSPipe( ));
00093
00094 return osPipe->getXDisplay();
00095 }
00096
00097 Display* GLXWindow::getXDisplay() const
00098 {
00099 const Pipe* pipe = getPipe();
00100
00101 EQASSERT( pipe );
00102 EQASSERT( pipe->getOSPipe( ));
00103 EQASSERT( dynamic_cast< const GLXPipe* >( pipe->getOSPipe( )));
00104
00105 const GLXPipe* osPipe = static_cast< const GLXPipe* >( pipe->getOSPipe( ));
00106
00107 return osPipe->getXDisplay();
00108 }
00109
00110
00111 XVisualInfo* GLXWindow::chooseXVisualInfo()
00112 {
00113 Display* display = getXDisplay();
00114 if( !display )
00115 {
00116 _window->setErrorMessage( "Pipe has no X11 display connection" );
00117 return 0;
00118 }
00119
00120
00121 std::vector<int> attributes;
00122 attributes.push_back( GLX_RGBA );
00123
00124 const int colorSize = getIAttribute( Window::IATTR_PLANES_COLOR );
00125 if( colorSize > 0 || colorSize == eq::AUTO )
00126 {
00127 attributes.push_back( GLX_RED_SIZE );
00128 attributes.push_back( colorSize>0 ? colorSize : 1 );
00129 attributes.push_back( GLX_GREEN_SIZE );
00130 attributes.push_back( colorSize>0 ? colorSize : 1 );
00131 attributes.push_back( GLX_BLUE_SIZE );
00132 attributes.push_back( colorSize>0 ? colorSize : 1 );
00133 }
00134 const int alphaSize = getIAttribute( Window::IATTR_PLANES_ALPHA );
00135 if( alphaSize > 0 || alphaSize == AUTO )
00136 {
00137 attributes.push_back( GLX_ALPHA_SIZE );
00138 attributes.push_back( alphaSize>0 ? alphaSize : 1 );
00139 }
00140 const int depthSize = getIAttribute( Window::IATTR_PLANES_DEPTH );
00141 if( depthSize > 0 || depthSize == AUTO )
00142 {
00143 attributes.push_back( GLX_DEPTH_SIZE );
00144 attributes.push_back( depthSize>0 ? depthSize : 1 );
00145 }
00146 const int stencilSize = getIAttribute( Window::IATTR_PLANES_STENCIL );
00147 if( stencilSize > 0 || stencilSize == AUTO )
00148 {
00149 attributes.push_back( GLX_STENCIL_SIZE );
00150 attributes.push_back( stencilSize>0 ? stencilSize : 1 );
00151 }
00152 const int accumSize = getIAttribute( Window::IATTR_PLANES_ACCUM );
00153 const int accumAlpha = getIAttribute( Window::IATTR_PLANES_ACCUM_ALPHA );
00154 if( accumSize >= 0 )
00155 {
00156 attributes.push_back( GLX_ACCUM_RED_SIZE );
00157 attributes.push_back( accumSize );
00158 attributes.push_back( GLX_ACCUM_GREEN_SIZE );
00159 attributes.push_back( accumSize );
00160 attributes.push_back( GLX_ACCUM_BLUE_SIZE );
00161 attributes.push_back( accumSize );
00162 attributes.push_back( GLX_ACCUM_ALPHA_SIZE );
00163 attributes.push_back( accumAlpha >= 0 ? accumAlpha : accumSize );
00164 }
00165 else if( accumAlpha >= 0 )
00166 {
00167 attributes.push_back( GLX_ACCUM_ALPHA_SIZE );
00168 attributes.push_back( accumAlpha );
00169 }
00170
00171 const int samplesSize = getIAttribute( Window::IATTR_PLANES_SAMPLES );
00172 if( samplesSize >= 0 )
00173 {
00174 attributes.push_back( GLX_SAMPLE_BUFFERS );
00175 attributes.push_back( 1 );
00176 attributes.push_back( GLX_SAMPLES );
00177 attributes.push_back( samplesSize );
00178 }
00179
00180 #ifdef DARWIN
00181
00182
00183 if( getIAttribute( Window::IATTR_HINT_STEREO ) == ON )
00184 attributes.push_back( GLX_STEREO );
00185 #else
00186 if( getIAttribute( Window::IATTR_HINT_STEREO ) == ON ||
00187 ( getIAttribute( Window::IATTR_HINT_STEREO ) == AUTO &&
00188 getIAttribute( Window::IATTR_HINT_DRAWABLE ) == WINDOW ))
00189
00190 attributes.push_back( GLX_STEREO );
00191 #endif
00192 if( getIAttribute( Window::IATTR_HINT_DOUBLEBUFFER ) == ON ||
00193 ( getIAttribute( Window::IATTR_HINT_DOUBLEBUFFER ) == AUTO &&
00194 getIAttribute( Window::IATTR_HINT_DRAWABLE ) == WINDOW ))
00195
00196 attributes.push_back( GLX_DOUBLEBUFFER );
00197
00198 attributes.push_back( None );
00199
00200
00201 std::vector<int> backoffAttributes;
00202 if( getIAttribute( Window::IATTR_HINT_DRAWABLE ) == WINDOW )
00203 {
00204 if( getIAttribute( Window::IATTR_HINT_DOUBLEBUFFER ) == AUTO )
00205 backoffAttributes.push_back( GLX_DOUBLEBUFFER );
00206
00207 #ifndef DARWIN
00208 if( getIAttribute( Window::IATTR_HINT_STEREO ) == AUTO )
00209 backoffAttributes.push_back( GLX_STEREO );
00210 #endif
00211 }
00212
00213 if( stencilSize == AUTO )
00214 backoffAttributes.push_back( GLX_STENCIL_SIZE );
00215
00216
00217
00218 const int screen = DefaultScreen( display );
00219 XVisualInfo *visInfo = glXChooseVisual( display, screen,
00220 &attributes.front( ));
00221
00222 while( !visInfo && !backoffAttributes.empty( ))
00223 {
00224 const int attribute = backoffAttributes.back();
00225 backoffAttributes.pop_back();
00226
00227 std::vector<int>::iterator iter = find( attributes.begin(), attributes.end(),
00228 attribute );
00229 EQASSERT( iter != attributes.end( ));
00230 if( *iter == GLX_STENCIL_SIZE )
00231 attributes.erase( iter, iter+2 );
00232 else
00233 attributes.erase( iter );
00234
00235 visInfo = glXChooseVisual( display, screen, &attributes.front( ));
00236 }
00237
00238 if ( !visInfo )
00239 _window->setErrorMessage( "Could not find a matching visual" );
00240 else
00241 EQINFO << "Using visual 0x" << std::hex << visInfo->visualid
00242 << std::dec << std::endl;
00243
00244 return visInfo;
00245 }
00246
00247
00248 GLXContext GLXWindow::createGLXContext( XVisualInfo* visualInfo )
00249 {
00250 if( !visualInfo )
00251 {
00252 _window->setErrorMessage( "No visual info given" );
00253 return 0;
00254 }
00255
00256 Display* display = getXDisplay();
00257
00258 if( !display )
00259 {
00260 _window->setErrorMessage( "Pipe has no X11 display connection" );
00261 return 0;
00262 }
00263
00264 GLXContext shareCtx = 0;
00265 const Window* shareWindow = _window->getSharedContextWindow();
00266 if( shareWindow )
00267 {
00268 const OSWindow* shareOSWindow = shareWindow->getOSWindow();
00269
00270 EQASSERT( dynamic_cast< const GLXWindow* >( shareOSWindow ));
00271 const GLXWindow* shareGLXWindow = static_cast< const GLXWindow* >(
00272 shareOSWindow );
00273 shareCtx = shareGLXWindow->getGLXContext();
00274 }
00275
00276 GLXContext context = glXCreateContext(display, visualInfo, shareCtx, True);
00277
00278 if ( !context )
00279 {
00280 _window->setErrorMessage( "Could not create OpenGL context" );
00281 return 0;
00282 }
00283
00284 return context;
00285 }
00286
00287 bool GLXWindow::configInitGLXDrawable( XVisualInfo* visualInfo )
00288 {
00289 switch( getIAttribute( Window::IATTR_HINT_DRAWABLE ))
00290 {
00291 case PBUFFER:
00292 return configInitGLXPBuffer( visualInfo );
00293
00294 case FBO:
00295 {
00296 const PixelViewport pvp( 0, 0, 1, 1 );
00297 _xDrawable = _createGLXWindow( visualInfo, pvp );
00298 return (_xDrawable != 0 );
00299 }
00300
00301 default:
00302 EQWARN << "Unknown drawable type "
00303 << getIAttribute( Window::IATTR_HINT_DRAWABLE )
00304 << ", using window" << std::endl;
00305
00306 case UNDEFINED:
00307 case WINDOW:
00308 return configInitGLXWindow( visualInfo );
00309 }
00310 }
00311
00312 bool GLXWindow::configInitGLXWindow( XVisualInfo* visualInfo )
00313 {
00314 Display* display = getXDisplay();
00315
00316 if( !display )
00317 {
00318 _window->setErrorMessage( "Pipe has no X11 display connection" );
00319 return false;
00320 }
00321
00322 PixelViewport pvp = _window->getPixelViewport();
00323 if( getIAttribute( Window::IATTR_HINT_FULLSCREEN ) == ON )
00324 {
00325 const int screen = DefaultScreen( display );
00326
00327 pvp.h = DisplayHeight( display, screen );
00328 pvp.w = DisplayWidth( display, screen );
00329 pvp.x = 0;
00330 pvp.y = 0;
00331
00332 _window->setPixelViewport( pvp );
00333 }
00334
00335 XID drawable = _createGLXWindow( visualInfo, pvp );
00336 if( !drawable )
00337 return false;
00338
00339
00340 XMapWindow( display, drawable );
00341
00342 XEvent event;
00343 XIfEvent( display, &event, WaitForNotify, (XPointer)(drawable) );
00344
00345 XMoveResizeWindow( display, drawable, pvp.x, pvp.y, pvp.w, pvp.h );
00346 XFlush( display );
00347
00348
00349 if( getIAttribute( Window::IATTR_HINT_FULLSCREEN ) == ON )
00350 XGrabKeyboard( display, drawable, True, GrabModeAsync, GrabModeAsync,
00351 CurrentTime );
00352
00353 setXDrawable( drawable );
00354
00355 EQINFO << "Created X11 drawable " << drawable << std::endl;
00356 return true;
00357 }
00358
00359 XID GLXWindow::_createGLXWindow( XVisualInfo* visualInfo ,
00360 const PixelViewport& pvp )
00361 {
00362 EQASSERT( getIAttribute( Window::IATTR_HINT_DRAWABLE ) != PBUFFER );
00363
00364 if( !visualInfo )
00365 {
00366 _window->setErrorMessage( "No visual info given" );
00367 return 0;
00368 }
00369
00370 Display* display = getXDisplay();
00371 if( !display )
00372 {
00373 _window->setErrorMessage( "Pipe has no X11 display connection" );
00374 return 0;
00375 }
00376
00377 const int screen = DefaultScreen( display );
00378 XID parent = RootWindow( display, screen );
00379 XSetWindowAttributes wa;
00380 wa.colormap = XCreateColormap( display, parent, visualInfo->visual,
00381 AllocNone );
00382 wa.background_pixmap = None;
00383 wa.border_pixel = 0;
00384 wa.event_mask = StructureNotifyMask | VisibilityChangeMask |
00385 ExposureMask | KeyPressMask | KeyReleaseMask |
00386 PointerMotionMask | ButtonPressMask |
00387 ButtonReleaseMask;
00388
00389 if( getIAttribute( Window::IATTR_HINT_DECORATION ) != OFF )
00390 wa.override_redirect = False;
00391 else
00392 wa.override_redirect = True;
00393
00394 XID drawable = XCreateWindow( display, parent,
00395 pvp.x, pvp.y, pvp.w, pvp.h,
00396 0, visualInfo->depth, InputOutput,
00397 visualInfo->visual,
00398 CWBackPixmap | CWBorderPixel |
00399 CWEventMask | CWColormap | CWOverrideRedirect,
00400 &wa );
00401
00402 if ( !drawable )
00403 {
00404 _window->setErrorMessage( "Could not create window" );
00405 return 0;
00406 }
00407
00408 std::stringstream windowTitle;
00409 const std::string& name = _window->getName();
00410
00411 if( name.empty( ))
00412 {
00413 windowTitle << "Equalizer";
00414 #ifndef NDEBUG
00415 windowTitle << " (" << getpid() << ")";
00416 #endif
00417 }
00418 else
00419 windowTitle << name;
00420
00421 XStoreName( display, drawable, windowTitle.str().c_str( ));
00422
00423
00424 Atom deleteAtom = XInternAtom( display, "WM_DELETE_WINDOW", False );
00425 XSetWMProtocols( display, drawable, &deleteAtom, 1 );
00426
00427 return drawable;
00428 }
00429
00430
00431 bool GLXWindow::configInitGLXPBuffer( XVisualInfo* visualInfo )
00432 {
00433 EQASSERT( getIAttribute( Window::IATTR_HINT_DRAWABLE ) == PBUFFER )
00434
00435 if( !visualInfo )
00436 {
00437 _window->setErrorMessage( "No visual info given" );
00438 return false;
00439 }
00440
00441 Display* display = getXDisplay();
00442 if( !display )
00443 {
00444 _window->setErrorMessage( "Pipe has no X11 display connection" );
00445 return false;
00446 }
00447
00448
00449 int major = 0;
00450 int minor = 0;
00451 if( !glXQueryVersion( display, &major, &minor ))
00452 {
00453 _window->setErrorMessage( "Can't get GLX version" );
00454 return false;
00455 }
00456
00457 if( major < 1 || (major == 1 && minor < 3 ))
00458 {
00459 _window->setErrorMessage( "Need at least GLX 1.3" );
00460 return false;
00461 }
00462
00463
00464 const int screen = DefaultScreen( display );
00465 int nConfigs = 0;
00466 GLXFBConfig* configs = glXGetFBConfigs( display, screen, &nConfigs );
00467 GLXFBConfig config = 0;
00468
00469 for( int i = 0; i < nConfigs; ++i )
00470 {
00471 int visualID;
00472 if( glXGetFBConfigAttrib( display, configs[i], GLX_VISUAL_ID,
00473 &visualID ) == 0 )
00474 {
00475 if( visualID == static_cast< int >( visualInfo->visualid ))
00476 {
00477 config = configs[i];
00478 break;
00479 }
00480 }
00481 }
00482
00483 if( !config )
00484 {
00485 _window->setErrorMessage( "Can't find FBConfig for visual" );
00486 return false;
00487 }
00488
00489
00490 const PixelViewport& pvp = _window->getPixelViewport();
00491 const int attributes[] = { GLX_PBUFFER_WIDTH, pvp.w,
00492 GLX_PBUFFER_HEIGHT, pvp.h,
00493 GLX_LARGEST_PBUFFER, True,
00494 GLX_PRESERVED_CONTENTS, True,
00495 0 };
00496
00497 XID pbuffer = glXCreatePbuffer( display, config, attributes );
00498 if ( !pbuffer )
00499 {
00500 _window->setErrorMessage( "Could not create PBuffer" );
00501 return false;
00502 }
00503
00504 XFlush( display );
00505 setXDrawable( pbuffer );
00506
00507 EQINFO << "Created X11 PBuffer " << pbuffer << std::endl;
00508 return true;
00509 }
00510
00511
00512 void GLXWindow::setXDrawable( XID drawable )
00513 {
00514 if( _xDrawable == drawable )
00515 return;
00516
00517 _xDrawable = drawable;
00518
00519 if( !drawable )
00520 return;
00521
00522
00523 Display* display = getXDisplay();
00524 EQASSERT( display );
00525
00526 PixelViewport pvp;
00527 if( getIAttribute( Window::IATTR_HINT_DRAWABLE ) == PBUFFER )
00528 {
00529 pvp.x = 0;
00530 pvp.y = 0;
00531
00532 unsigned value = 0;
00533 glXQueryDrawable( display, drawable, GLX_WIDTH, &value );
00534 pvp.w = static_cast< int32_t >( value );
00535
00536 value = 0;
00537 glXQueryDrawable( display, drawable, GLX_HEIGHT, &value );
00538 pvp.h = static_cast< int32_t >( value );
00539 }
00540 else
00541 {
00542 XWindowAttributes wa;
00543 XGetWindowAttributes( display, drawable, &wa );
00544
00545
00546 ::Window root, parent, *children;
00547 unsigned nChildren;
00548
00549 XQueryTree( display, drawable, &root, &parent, &children, &nChildren );
00550 if( children != 0 ) XFree( children );
00551
00552 int x,y;
00553 ::Window childReturn;
00554 XTranslateCoordinates( display, parent, root, wa.x, wa.y, &x, &y,
00555 &childReturn );
00556
00557 pvp.x = x;
00558 pvp.y = y;
00559 pvp.w = wa.width;
00560 pvp.h = wa.height;
00561 }
00562
00563 _window->setPixelViewport( pvp );
00564 }
00565
00566
00567 void GLXWindow::setGLXContext( GLXContext context )
00568 {
00569 _glXContext = context;
00570 }
00571
00572 void GLXWindow::configExit( )
00573 {
00574 Display* display = getXDisplay();
00575 if( !display )
00576 return;
00577
00578 leaveNVSwapBarrier();
00579 configExitFBO();
00580 exitGLEW();
00581
00582 glXMakeCurrent( display, None, 0 );
00583
00584 GLXContext context = getGLXContext();
00585 XID drawable = getXDrawable();
00586
00587 setGLXContext( 0 );
00588 setXDrawable( 0 );
00589
00590 if( context )
00591 glXDestroyContext( display, context );
00592
00593 if( drawable )
00594 {
00595 if( getIAttribute( Window::IATTR_HINT_DRAWABLE ) == PBUFFER )
00596 glXDestroyPbuffer( display, drawable );
00597 else
00598 XDestroyWindow( display, drawable );
00599 }
00600
00601 EQINFO << "Destroyed GLX context and X drawable " << std::endl;
00602 }
00603
00604 void GLXWindow::makeCurrent() const
00605 {
00606 Display* display = getXDisplay();
00607 EQASSERT( display );
00608
00609 glXMakeCurrent( display, _xDrawable, _glXContext );
00610 GLXWindowIF::makeCurrent();
00611 }
00612
00613 void GLXWindow::swapBuffers()
00614 {
00615 Display* display = getXDisplay();
00616 EQASSERT( display );
00617
00618 glXSwapBuffers( display, _xDrawable );
00619 }
00620
00621 void GLXWindow::joinNVSwapBarrier( const uint32_t group, const uint32_t barrier)
00622 {
00623 if( group == 0 && barrier == 0 )
00624 return;
00625
00626 #if 0
00627 EQWARN << "Entering untested function GLXWindow::joinNVSwapBarrier"
00628 << std::endl;
00629
00630 if ( !GLXEW_NV_swap_group )
00631 {
00632 EQWARN << "NV Swap group extension not supported" << std::endl;
00633 return;
00634 }
00635
00636 const Display* display = getXDisplay();
00637 const int screen = DefaultScreen( display );
00638 uint32_t maxBarrier = 0;
00639 uint32_t maxGroup = 0;
00640
00641 glxQueryMaxSwapGroupsNV( display, screen, &maxGroup, &maxBarrier )
00642
00643 if( group > maxGroup )
00644 {
00645 EQWARN << "Failed to initialize GLX_NV_swap_group: requested group "
00646 << group << " greater than maxGroups (" << maxGroups << ")"
00647 << std::endl;
00648 return;
00649 }
00650
00651 if( barrier > maxBarrier )
00652 {
00653 EQWARN << "Failed to initialize GLX_NV_swap_group: requested barrier "
00654 << barrier << "greater than maxBarriers (" << maxBarriers << ")"
00655 << std::endl;
00656 return;
00657 }
00658
00659 if( !glxJoinSwapGroupNV( display, _xDrawable, group ))
00660 {
00661 EQWARN << "Failed to join swap group " << group << std::endl;
00662 return;
00663 }
00664
00665 _glXNVSwapGroup = group;
00666
00667 if( !glxBindSwapBarrierNV( group, barrier ))
00668 {
00669 EQWARN << "Failed to bind swap barrier " << barrier << std::endl;
00670 return;
00671 }
00672
00673 return true;
00674 #else
00675 EQUNIMPLEMENTED;
00676 return;
00677 #endif
00678 }
00679
00680 void GLXWindow::leaveNVSwapBarrier()
00681 {
00682 if( _glXNVSwapGroup == 0)
00683 return;
00684
00685 #if 0
00686 const Display* display = getXDisplay();
00687 const int screen = DefaultScreen( display );
00688
00689 glxBindSwapBarrierNV( _glXNVSwapGroup, 0 );
00690 glxJoinSwapGroupNV( display, _xDrawable, 0 );
00691
00692 _glXNVSwapGroup = 0;
00693 #else
00694 EQUNIMPLEMENTED;
00695 #endif
00696 }
00697
00698 }