aglWindow.cpp

00001 
00002 /* Copyright (c) 2005-2009, Stefan Eilemann <eile@equalizergraphics.com>
00003                           , Maxim Makhinya
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     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 // AGL init
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     // build attribute list
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     // build backoff list, least important attribute last
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     // choose pixel format
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 ||              // found one or
00293             backoffAttributes.empty( )) // nothing else to try
00294 
00295             break;
00296 
00297         // Gradually remove backoff attributes
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 ); // remove two item (attr, value)
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     // set vsync on/off
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             // no break;
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     // PBuffer
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     // attach to context
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     // window
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     // top, left, bottom, right
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     // window title
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     // show
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 }
Generated on Sat Feb 6 12:59:40 2010 for Equalizer 0.9.1 by  doxygen 1.6.1