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