00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "aglWindow.h"
00020
00021 #include "aglEventHandler.h"
00022 #include "aglPipe.h"
00023 #include "aglWindowEvent.h"
00024 #include "global.h"
00025 #include "pipe.h"
00026 #include "window.h"
00027
00028 #define ERROR( code ) \
00029 std::string( reinterpret_cast< const char* >( aglErrorString( code )))
00030
00031 namespace eq
00032 {
00033
00034 bool AGLWindowIF::processEvent( const AGLWindowEvent& event )
00035 {
00036 EQASSERT( _window );
00037 return _window->processEvent( event );
00038 }
00039
00040 AGLWindow::AGLWindow( Window* parent )
00041 : AGLWindowIF( parent )
00042 , _aglContext( 0 )
00043 , _carbonWindow( 0 )
00044 , _aglPBuffer( 0 )
00045 , _eventHandler( 0 )
00046 {
00047 }
00048
00049 AGLWindow::~AGLWindow( )
00050 {
00051 }
00052
00053 void AGLWindow::configExit( )
00054 {
00055 WindowRef window = getCarbonWindow();
00056 setCarbonWindow( 0 );
00057
00058 AGLPbuffer pbuffer = getAGLPBuffer();
00059 setAGLPBuffer( 0 );
00060
00061 if( window )
00062 {
00063 Global::enterCarbon();
00064 DisposeWindow( window );
00065 Global::leaveCarbon();
00066 }
00067 if( pbuffer )
00068 aglDestroyPBuffer( pbuffer );
00069
00070 configExitFBO();
00071 exitGLEW();
00072
00073 AGLContext context = getAGLContext();
00074 if( context )
00075 {
00076 Global::enterCarbon();
00077 if( getIAttribute( Window::IATTR_HINT_FULLSCREEN ) != ON )
00078 {
00079 #ifdef LEOPARD
00080 aglSetWindowRef( context, 0 );
00081 #else
00082 aglSetDrawable( context, 0 );
00083 #endif
00084 }
00085
00086 aglSetCurrentContext( 0 );
00087 aglDestroyContext( context );
00088 Global::leaveCarbon();
00089 setAGLContext( 0 );
00090 }
00091
00092 EQINFO << "Destroyed AGL window and context" << std::endl;
00093 }
00094
00095 void AGLWindow::makeCurrent() const
00096 {
00097 aglSetCurrentContext( _aglContext );
00098
00099 AGLWindowIF::makeCurrent();
00100 }
00101
00102 void AGLWindow::swapBuffers()
00103 {
00104 aglSwapBuffers( _aglContext );
00105 }
00106
00107 void AGLWindow::joinNVSwapBarrier( const uint32_t group, const uint32_t barrier)
00108 {
00109 EQWARN << "NV_swap_group not supported on AGL" << std::endl;
00110 }
00111
00112 bool AGLWindow::processEvent( const AGLWindowEvent& event )
00113 {
00114 if( event.type == Event::WINDOW_RESIZE && _aglContext )
00115 aglUpdateContext( _aglContext );
00116
00117 return AGLWindowIF::processEvent( event );
00118 }
00119
00120 void AGLWindow::setAGLContext( AGLContext context )
00121 {
00122 _aglContext = context;
00123 }
00124
00125
00126
00127
00128
00129 bool AGLWindow::configInit( )
00130 {
00131 AGLPixelFormat pixelFormat = chooseAGLPixelFormat();
00132 if( !pixelFormat )
00133 return false;
00134
00135 AGLContext context = createAGLContext( pixelFormat );
00136 destroyAGLPixelFormat ( pixelFormat );
00137 setAGLContext( context );
00138
00139 if( !context )
00140 return false;
00141
00142 makeCurrent();
00143 initGLEW();
00144 return configInitAGLDrawable();
00145 }
00146
00147 AGLPixelFormat AGLWindow::chooseAGLPixelFormat()
00148 {
00149 Pipe* pipe = getPipe();
00150 EQASSERT( pipe );
00151 EQASSERT( pipe->getOSPipe( ));
00152 EQASSERT( dynamic_cast< const AGLPipe* >( pipe->getOSPipe( )));
00153
00154 const AGLPipe* osPipe = static_cast< const AGLPipe* >( pipe->getOSPipe( ));
00155
00156 CGDirectDisplayID displayID = osPipe->getCGDisplayID();
00157
00158 Global::enterCarbon();
00159
00160 #ifdef LEOPARD
00161 CGOpenGLDisplayMask glDisplayMask =
00162 CGDisplayIDToOpenGLDisplayMask( displayID );
00163 #else
00164 GDHandle displayHandle = 0;
00165
00166 DMGetGDeviceByDisplayID( (DisplayIDType)displayID, &displayHandle, false );
00167
00168 if( !displayHandle )
00169 {
00170 _window->setErrorMessage( "Can't get display handle" );
00171 Global::leaveCarbon();
00172 return 0;
00173 }
00174 #endif
00175
00176
00177 std::vector<GLint> attributes;
00178
00179 attributes.push_back( AGL_RGBA );
00180 attributes.push_back( GL_TRUE );
00181 attributes.push_back( AGL_ACCELERATED );
00182 attributes.push_back( GL_TRUE );
00183
00184 if( getIAttribute( Window::IATTR_HINT_FULLSCREEN ) == ON &&
00185 getIAttribute( Window::IATTR_HINT_DRAWABLE ) == WINDOW )
00186
00187 attributes.push_back( AGL_FULLSCREEN );
00188
00189 #ifdef LEOPARD
00190 attributes.push_back( AGL_DISPLAY_MASK );
00191 attributes.push_back( glDisplayMask );
00192 #endif
00193
00194 const int colorSize = getIAttribute( Window::IATTR_PLANES_COLOR );
00195 if( colorSize > 0 || colorSize == AUTO )
00196 {
00197 const GLint size = colorSize > 0 ? colorSize : 8;
00198
00199 attributes.push_back( AGL_RED_SIZE );
00200 attributes.push_back( size );
00201 attributes.push_back( AGL_GREEN_SIZE );
00202 attributes.push_back( size );
00203 attributes.push_back( AGL_BLUE_SIZE );
00204 attributes.push_back( size );
00205 }
00206 const int alphaSize = getIAttribute( Window::IATTR_PLANES_ALPHA );
00207 if( alphaSize > 0 || alphaSize == AUTO )
00208 {
00209 attributes.push_back( AGL_ALPHA_SIZE );
00210 attributes.push_back( alphaSize>0 ? alphaSize : 8 );
00211 }
00212 const int depthSize = getIAttribute( Window::IATTR_PLANES_DEPTH );
00213 if( depthSize > 0 || depthSize == AUTO )
00214 {
00215 attributes.push_back( AGL_DEPTH_SIZE );
00216 attributes.push_back( depthSize>0 ? depthSize : 24 );
00217 }
00218 const int stencilSize = getIAttribute( Window::IATTR_PLANES_STENCIL );
00219 if( stencilSize > 0 || stencilSize == AUTO )
00220 {
00221 attributes.push_back( AGL_STENCIL_SIZE );
00222 attributes.push_back( stencilSize>0 ? stencilSize : 1 );
00223 }
00224 const int accumSize = getIAttribute( Window::IATTR_PLANES_ACCUM );
00225 const int accumAlpha = getIAttribute( Window::IATTR_PLANES_ACCUM_ALPHA );
00226 if( accumSize >= 0 )
00227 {
00228 attributes.push_back( AGL_ACCUM_RED_SIZE );
00229 attributes.push_back( accumSize );
00230 attributes.push_back( AGL_ACCUM_GREEN_SIZE );
00231 attributes.push_back( accumSize );
00232 attributes.push_back( AGL_ACCUM_BLUE_SIZE );
00233 attributes.push_back( accumSize );
00234 attributes.push_back( AGL_ACCUM_ALPHA_SIZE );
00235 attributes.push_back( accumAlpha >= 0 ? accumAlpha : accumSize );
00236 }
00237 else if( accumAlpha >= 0 )
00238 {
00239 attributes.push_back( AGL_ACCUM_ALPHA_SIZE );
00240 attributes.push_back( accumAlpha );
00241 }
00242
00243 const int samplesSize = getIAttribute( Window::IATTR_PLANES_SAMPLES );
00244 if( samplesSize >= 0 )
00245 {
00246 attributes.push_back( AGL_SAMPLE_BUFFERS_ARB );
00247 attributes.push_back( 1 );
00248 attributes.push_back( AGL_SAMPLES_ARB );
00249 attributes.push_back( samplesSize );
00250 }
00251
00252 if( getIAttribute( Window::IATTR_HINT_DOUBLEBUFFER ) == ON ||
00253 ( getIAttribute( Window::IATTR_HINT_DOUBLEBUFFER ) == AUTO &&
00254 getIAttribute( Window::IATTR_HINT_DRAWABLE ) == WINDOW ))
00255 {
00256 attributes.push_back( AGL_DOUBLEBUFFER );
00257 attributes.push_back( GL_TRUE );
00258 }
00259 if( getIAttribute( Window::IATTR_HINT_STEREO ) == ON )
00260 {
00261 attributes.push_back( AGL_STEREO );
00262 attributes.push_back( GL_TRUE );
00263 }
00264
00265 attributes.push_back( AGL_NONE );
00266
00267
00268 std::vector<int> backoffAttributes;
00269 if( getIAttribute( Window::IATTR_HINT_DOUBLEBUFFER ) == AUTO &&
00270 getIAttribute( Window::IATTR_HINT_DRAWABLE ) == WINDOW )
00271
00272 backoffAttributes.push_back( AGL_DOUBLEBUFFER );
00273
00274 if( stencilSize == AUTO )
00275 backoffAttributes.push_back( AGL_STENCIL_SIZE );
00276
00277
00278 AGLPixelFormat pixelFormat = 0;
00279 while( true )
00280 {
00281 #ifdef LEOPARD
00282 pixelFormat = aglCreatePixelFormat( &attributes.front( ));
00283 #else
00284 pixelFormat = aglChoosePixelFormat( &displayHandle, 1,
00285 &attributes.front( ));
00286 #endif
00287
00288 if( pixelFormat ||
00289 backoffAttributes.empty( ))
00290
00291 break;
00292
00293
00294 const GLint attribute = backoffAttributes.back();
00295 backoffAttributes.pop_back();
00296
00297 std::vector<GLint>::iterator iter = find( attributes.begin(),
00298 attributes.end(), attribute );
00299 EQASSERT( iter != attributes.end( ));
00300
00301 attributes.erase( iter, iter+2 );
00302 }
00303
00304 if( !pixelFormat )
00305 _window->setErrorMessage( "Could not find a matching pixel format" );
00306
00307 Global::leaveCarbon();
00308 return pixelFormat;
00309 }
00310
00311 void AGLWindow::destroyAGLPixelFormat( AGLPixelFormat pixelFormat )
00312 {
00313 if( !pixelFormat )
00314 return;
00315
00316 Global::enterCarbon();
00317 aglDestroyPixelFormat( pixelFormat );
00318 Global::leaveCarbon();
00319 }
00320
00321 AGLContext AGLWindow::createAGLContext( AGLPixelFormat pixelFormat )
00322 {
00323 if( !pixelFormat )
00324 {
00325 _window->setErrorMessage( "No pixel format given" );
00326 return 0;
00327 }
00328
00329 AGLContext shareCtx = 0;
00330 const Window* shareWindow = _window->getSharedContextWindow();
00331 const OSWindow* shareOSWindow = shareWindow ? shareWindow->getOSWindow() : 0;
00332 if( shareOSWindow )
00333 {
00334
00335 EQASSERT( dynamic_cast< const AGLWindow* >( shareOSWindow ));
00336 const AGLWindow* shareAGLWindow = static_cast< const AGLWindow* >(
00337 shareOSWindow );
00338 shareCtx = shareAGLWindow->getAGLContext();
00339 }
00340
00341 Global::enterCarbon();
00342 AGLContext context = aglCreateContext( pixelFormat, shareCtx );
00343
00344 if( !context )
00345 {
00346 _window->setErrorMessage( "Could not create AGL context: " +
00347 ERROR( aglGetError( )));
00348 Global::leaveCarbon();
00349 return 0;
00350 }
00351
00352
00353 if( getIAttribute( Window::IATTR_HINT_SWAPSYNC ) != AUTO )
00354 {
00355 const GLint vsync =
00356 ( getIAttribute( Window::IATTR_HINT_SWAPSYNC )==OFF ? 0 : 1 );
00357 aglSetInteger( context, AGL_SWAP_INTERVAL, &vsync );
00358 }
00359
00360 aglSetCurrentContext( context );
00361
00362 Global::leaveCarbon();
00363
00364 EQINFO << "Created AGL context " << context << " shared with " << shareCtx
00365 << std::endl;
00366 return context;
00367 }
00368
00369
00370 bool AGLWindow::configInitAGLDrawable()
00371 {
00372 switch( getIAttribute( Window::IATTR_HINT_DRAWABLE ))
00373 {
00374 case PBUFFER:
00375 return configInitAGLPBuffer();
00376
00377 case FBO:
00378 return configInitFBO();
00379
00380 default:
00381 EQWARN << "Unknown drawable type "
00382 << getIAttribute( Window::IATTR_HINT_DRAWABLE )
00383 << ", using window" << std::endl;
00384
00385 case UNDEFINED:
00386 case WINDOW:
00387 if( getIAttribute( Window::IATTR_HINT_FULLSCREEN ) == ON )
00388 return configInitAGLFullscreen();
00389 else
00390 return configInitAGLWindow();
00391 }
00392 }
00393
00394 bool AGLWindow::configInitAGLPBuffer()
00395 {
00396 AGLContext context = getAGLContext();
00397 if( !context )
00398 {
00399 _window->setErrorMessage( "No AGLContext set" );
00400 return false;
00401 }
00402
00403
00404 const PixelViewport pvp = _window->getPixelViewport();
00405 AGLPbuffer pbuffer;
00406 if( !aglCreatePBuffer( pvp.w, pvp.h, GL_TEXTURE_RECTANGLE_EXT, GL_RGBA,
00407 0, &pbuffer ))
00408 {
00409 _window->setErrorMessage( "Could not create PBuffer: " +
00410 ERROR( aglGetError( )));
00411 return false;
00412 }
00413
00414
00415 if( !aglSetPBuffer( context, pbuffer, 0, 0, aglGetVirtualScreen( context )))
00416 {
00417 _window->setErrorMessage( "aglSetPBuffer failed: " +
00418 ERROR( aglGetError( )));
00419 return false;
00420 }
00421
00422 setAGLPBuffer( pbuffer );
00423 return true;
00424 }
00425
00426 bool AGLWindow::configInitAGLFullscreen()
00427 {
00428 AGLContext context = getAGLContext();
00429 if( !context )
00430 {
00431 _window->setErrorMessage( "No AGLContext set" );
00432 return false;
00433 }
00434
00435 Global::enterCarbon();
00436
00437 aglEnable( context, AGL_FS_CAPTURE_SINGLE );
00438
00439 const Pipe* pipe = getPipe();
00440 EQASSERT( pipe );
00441
00442 const PixelViewport& pipePVP = pipe->getPixelViewport();
00443 const PixelViewport& windowPVP = _window->getPixelViewport();
00444 const PixelViewport& pvp = pipePVP.isValid() ? pipePVP : windowPVP;
00445
00446 #if 1
00447 if( !aglSetFullScreen( context, pvp.w, pvp.h, 0, 0 ))
00448 EQWARN << "aglSetFullScreen to " << pvp << " failed: " << aglGetError()
00449 << std::endl;
00450 #else
00451 if( !aglSetFullScreen( context, 0, 0, 0, 0 ))
00452 EQWARN << "aglSetFullScreen failed: " << aglGetError() << std::endl;
00453 #endif
00454
00455 Global::leaveCarbon();
00456 _window->setPixelViewport( pvp );
00457 return true;
00458 }
00459
00460 bool AGLWindow::configInitAGLWindow()
00461 {
00462 AGLContext context = getAGLContext();
00463 if( !context )
00464 {
00465 _window->setErrorMessage( "No AGLContext set" );
00466 return false;
00467 }
00468
00469
00470 const bool decoration = getIAttribute(Window::IATTR_HINT_DECORATION) != OFF;
00471 WindowAttributes winAttributes = ( decoration ?
00472 kWindowStandardDocumentAttributes :
00473 kWindowNoTitleBarAttribute |
00474 kWindowNoShadowAttribute |
00475 kWindowResizableAttribute ) |
00476 kWindowStandardHandlerAttribute | kWindowInWindowMenuAttribute;
00477
00478
00479 const PixelViewport pvp = _window->getPixelViewport();
00480 const int32_t menuHeight = decoration ? EQ_AGL_MENUBARHEIGHT : 0 ;
00481 Rect windowRect = { pvp.y + menuHeight, pvp.x,
00482 pvp.y + pvp.h + menuHeight,
00483 pvp.x + pvp.w };
00484 WindowRef windowRef;
00485
00486 Global::enterCarbon();
00487 const OSStatus status = CreateNewWindow( kDocumentWindowClass,
00488 winAttributes,
00489 &windowRect, &windowRef );
00490 if( status != noErr )
00491 {
00492 std::stringstream error;
00493 error << "Could not create carbon window: " << status;
00494 _window->setErrorMessage( error.str( ));
00495 Global::leaveCarbon();
00496 return false;
00497 }
00498
00499
00500 const std::string& name = _window->getName();
00501 std::stringstream windowTitle;
00502
00503 if( name.empty( ))
00504 {
00505 windowTitle << "Equalizer";
00506 #ifndef NDEBUG
00507 windowTitle << " (" << getpid() << ")";
00508 #endif;
00509 }
00510 else
00511 windowTitle << name;
00512
00513 CFStringRef title = CFStringCreateWithCString( kCFAllocatorDefault,
00514 windowTitle.str().c_str(),
00515 kCFStringEncodingMacRoman );
00516 SetWindowTitleWithCFString( windowRef, title );
00517 CFRelease( title );
00518
00519 #ifdef LEOPARD
00520 if( !aglSetWindowRef( context, windowRef ))
00521 {
00522 _window->setErrorMessage( "aglSetWindowRef failed: " +
00523 ERROR( aglGetError( )));
00524 Global::leaveCarbon();
00525 return false;
00526 }
00527 #else
00528 if( !aglSetDrawable( context, GetWindowPort( windowRef )))
00529 {
00530 _window->setErrorMessage( "aglSetDrawable failed: " +
00531 ERROR( aglGetError( )));
00532 Global::leaveCarbon();
00533 return false;
00534 }
00535 #endif
00536
00537
00538 ShowWindow( windowRef );
00539 Global::leaveCarbon();
00540 setCarbonWindow( windowRef );
00541
00542 return true;
00543 }
00544
00545 void AGLWindow::setCarbonWindow( WindowRef window )
00546 {
00547 EQINFO << "set Carbon window " << window << std::endl;
00548
00549 if( _carbonWindow == window )
00550 return;
00551
00552 if( _carbonWindow )
00553 exitEventHandler();
00554 _carbonWindow = window;
00555
00556 if( !window )
00557 return;
00558
00559 initEventHandler();
00560
00561 Rect rect;
00562 Global::enterCarbon();
00563 if( GetWindowBounds( window, kWindowContentRgn, &rect ) == noErr )
00564 {
00565 PixelViewport pvp( rect.left, rect.top,
00566 rect.right - rect.left, rect.bottom - rect.top );
00567
00568 if( getIAttribute( Window::IATTR_HINT_DECORATION ) != OFF )
00569 pvp.y -= EQ_AGL_MENUBARHEIGHT;
00570
00571 _window->setPixelViewport( pvp );
00572 }
00573 Global::leaveCarbon();
00574 }
00575
00576 void AGLWindow::setAGLPBuffer( AGLPbuffer pbuffer )
00577 {
00578 EQINFO << "set AGL PBuffer " << pbuffer << std::endl;
00579
00580 if( _aglPBuffer == pbuffer )
00581 return;
00582
00583 _aglPBuffer = pbuffer;
00584
00585 if( !pbuffer )
00586 return;
00587
00588 GLint w;
00589 GLint h;
00590 GLenum target;
00591 GLenum format;
00592 GLint maxLevel;
00593
00594 if( aglDescribePBuffer( pbuffer, &w, &h, &target, &format, &maxLevel ))
00595 {
00596 EQASSERT( target == GL_TEXTURE_RECTANGLE_EXT );
00597
00598 const PixelViewport pvp( 0, 0, w, h );
00599 _window->setPixelViewport( pvp );
00600 }
00601 }
00602
00603 void AGLWindow::initEventHandler()
00604 {
00605 EQASSERT( !_eventHandler );
00606 _eventHandler = new AGLEventHandler( this );
00607 }
00608
00609 void AGLWindow::exitEventHandler()
00610 {
00611 delete _eventHandler;
00612 _eventHandler = 0;
00613 }
00614
00615 }