aglWindow.cpp

00001 
00002 /* Copyright (c) 2005-2009, Stefan Eilemann <eile@equalizergraphics.com>
00003                           , Makhinya Maxim
00004  *
00005  * This library is free software; you can redistribute it and/or modify it under
00006  * the terms of the GNU Lesser General Public License version 2.1 as published
00007  * by the Free Software Foundation.
00008  *  
00009  * This library is distributed in the hope that it will be useful, but WITHOUT
00010  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00012  * details.
00013  * 
00014  * You should have received a copy of the GNU Lesser General Public License
00015  * along with this library; if not, write to the Free Software Foundation, Inc.,
00016  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
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 // AGL init
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     // build attribute list
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     // build backoff list, least important attribute last
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     // choose pixel format
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 ||              // found one or
00289             backoffAttributes.empty( )) // nothing else to try
00290 
00291             break;
00292 
00293         // Gradually remove backoff attributes
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 ); // remove two item (attr, value)
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     // set vsync on/off
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             // no break;
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     // PBuffer
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     // attach to context
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     // window
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     // top, left, bottom, right
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     // window title
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     // show
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 }
Generated on Mon Aug 10 18:58:31 2009 for Equalizer 0.9 by  doxygen 1.5.8