glXWindow.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 "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 // GLX init
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     // build attribute list
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     // WAR: glDrawBuffer( GL_BACK ) renders only to the left back buffer on a
00182     // stereo visual on Darwin which creates ugly flickering on mono configs
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     // build backoff list, least important attribute last
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     // Choose visual
00218     const int    screen  = DefaultScreen( display );
00219     XVisualInfo *visInfo = glXChooseVisual( display, screen, 
00220                                             &attributes.front( ));
00221 
00222     while( !visInfo && !backoffAttributes.empty( ))
00223     {   // Gradually remove backoff attributes
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 ) // two-elem attribute
00231             attributes.erase( iter, iter+2 );
00232         else                            // one-elem attribute
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             // no break;
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     // map and wait for MapNotify event
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     // Grab keyboard focus in fullscreen mode
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     // Register for close window request from the window manager
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     // Check for GLX >= 1.3
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     // Find FB config for X visual
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     // Create PBuffer
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     // query pixel viewport of window
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         // Window position is relative to parent: translate to absolute coords
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 }
Generated on Mon Aug 10 18:58:39 2009 for Equalizer 0.9 by  doxygen 1.5.8