Equalizer  1.4.1
eqPixelBench/channel.cpp
00001 
00002 /* Copyright (c) 2007-2012, Stefan Eilemann <eile@equalizergraphics.com>
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions are met:
00006  *
00007  * - Redistributions of source code must retain the above copyright notice, this
00008  *   list of conditions and the following disclaimer.
00009  * - Redistributions in binary form must reproduce the above copyright notice,
00010  *   this list of conditions and the following disclaimer in the documentation
00011  *   and/or other materials provided with the distribution.
00012  * - Neither the name of Eyescale Software GmbH nor the names of its
00013  *   contributors may be used to endorse or promote products derived from this
00014  *   software without specific prior written permission.
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00017  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00019  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00020  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00021  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00022  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00023  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00024  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00025  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00026  * POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00029 #include "channel.h"
00030 
00031 #include "config.h"
00032 #include "configEvent.h"
00033 
00034 #include <co/plugins/compressor.h>
00035 
00036 #ifdef WIN32_API
00037 #  define snprintf _snprintf
00038 #endif
00039 
00040 namespace eqPixelBench
00041 {
00042 namespace
00043 {
00044 #pragma warning(disable: 411) // class defines no constructor to initialize ...
00045 struct EnumMap
00046 {
00047     const char*    internalFormatString;
00048     const uint32_t internalFormat;
00049     const size_t   pixelSize;
00050 };
00051 
00052 #pragma warning(default: 411)
00053 
00054 #define ENUM_MAP_ITEM( internalFormat, pixelSize )  \
00055     { #internalFormat, EQ_COMPRESSOR_DATATYPE_ ## internalFormat, pixelSize }
00056 
00057 static EnumMap _enums[] = {
00058     ENUM_MAP_ITEM( RGBA32F, 16 ), // initial buffer resize
00059     ENUM_MAP_ITEM( RGBA, 4 ),
00060     ENUM_MAP_ITEM( RGB10_A2, 4 ),
00061     ENUM_MAP_ITEM( RGBA16F, 8 ),
00062     ENUM_MAP_ITEM( RGBA32F, 16 ),
00063     ENUM_MAP_ITEM( DEPTH, 4 ),
00064     { 0, 0, 0 }};
00065 #define NUM_IMAGES 8
00066 }
00067 
00068 Channel::Channel( eq::Window* parent )
00069         : eq::Channel( parent )
00070 {
00071     eq::FrameDataPtr frameData = new eq::FrameData;
00072     _frame.setFrameData( frameData );
00073 
00074     for( unsigned i = 0; i < NUM_IMAGES; ++i )
00075         frameData->newImage( eq::Frame::TYPE_MEMORY, getDrawableConfig( ));
00076 }
00077 
00078 bool Channel::configExit()
00079 {
00080     _frame.getData()->resetPlugins();
00081     return eq::Channel::configExit();
00082 }
00083 
00084 void Channel::frameStart( const eq::uint128_t& frameID,
00085                           const uint32_t frameNumber )
00086 {
00087     Config* config = static_cast< Config* >( getConfig( ));
00088     const lunchbox::Clock* clock  = config->getClock();
00089 
00090     if( clock )
00091     {
00092         ConfigEvent   event;
00093         event.msec = clock->getTimef();
00094 
00095         const std::string& name  = getName();
00096         if( name.empty( ))
00097             snprintf( event.data.user.data, 32, "%p", this);
00098         else
00099             snprintf( event.data.user.data, 32, "%s", name.c_str( ));
00100 
00101         event.data.user.data[31] = 0;
00102         event.area.x() = 0;
00103         event.area.y() = 0;
00104 
00105         snprintf( event.formatType, 32, "app->pipe thread latency");
00106         event.data.type = ConfigEvent::START_LATENCY;
00107 
00108         config->sendEvent( event );
00109     }
00110 
00111     eq::Channel::frameStart( frameID, frameNumber );
00112 }
00113 
00114 void Channel::frameDraw( const eq::uint128_t& frameID )
00115 {
00116     //----- setup GL state
00117     applyBuffer();
00118     applyViewport();
00119 
00120     glMatrixMode( GL_PROJECTION );
00121     glLoadIdentity();
00122 
00123     applyFrustum();
00124 
00125     glMatrixMode( GL_MODELVIEW );
00126     glLoadIdentity();
00127     applyHeadTransform();
00128 
00129     setupAssemblyState();
00130 
00131     _testFormats( 1.0f );
00132     _testFormats( 0.5f );
00133     _testFormats( 2.0f );
00134     _testTiledOperations();
00135     _testDepthAssemble();
00136 
00137     resetAssemblyState();
00138 }
00139 
00140 ConfigEvent Channel::_createConfigEvent()
00141 {
00142     ConfigEvent   event;
00143     const std::string& name = getName();
00144 
00145     if( name.empty( ))
00146         snprintf( event.data.user.data, 32, "%p", this );
00147     else
00148         snprintf( event.data.user.data, 32, "%s", name.c_str( ));
00149 
00150     event.data.user.data[31] = 0;
00151     return event;
00152 }
00153 
00154 void Channel::_testFormats( float applyZoom )
00155 {
00156     glGetError(); // reset
00157 
00158     //----- setup constant data
00159     const eq::Images& images = _frame.getImages();
00160     eq::Image*        image  = images[ 0 ];
00161     LBASSERT( image );
00162 
00163     Config* config = static_cast< Config* >( getConfig( ));
00164     const eq::PixelViewport& pvp = getPixelViewport();
00165     const eq::Vector2i offset( pvp.x, pvp.y );
00166     const eq::Zoom zoom( applyZoom, applyZoom );
00167 
00168     lunchbox::Clock clock;
00169     eq::Window::ObjectManager* glObjects = getObjectManager();
00170 
00171     //----- test all default format/type combinations
00172     ConfigEvent event = _createConfigEvent();
00173     for( uint32_t i=0; _enums[i].internalFormatString; ++i )
00174     {
00175         const uint32_t internalFormat = _enums[i].internalFormat;
00176         image->flush();
00177         image->setInternalFormat( eq::Frame::BUFFER_COLOR, internalFormat );
00178         image->setQuality( eq::Frame::BUFFER_COLOR, 0.f );
00179         image->setAlphaUsage( false );
00180 
00181         const GLEWContext* glewContext = glewGetContext();
00182         const std::vector< uint32_t >& names =
00183             image->findTransferers( eq::Frame::BUFFER_COLOR, glewContext );
00184 
00185         for( std::vector< uint32_t >::const_iterator j = names.begin();
00186              j != names.end(); ++j )
00187         {
00188             _draw( 0 );
00189 
00190             // setup
00191             event.formatType[31] = '\0';
00192             event.data.type = ConfigEvent::READBACK;
00193 
00194             image->allocDownloader( eq::Frame::BUFFER_COLOR, *j, glewContext );
00195             image->setPixelViewport( pvp );
00196 
00197             const uint32_t outputToken =
00198                 image->getExternalFormat( eq::Frame::BUFFER_COLOR );
00199             snprintf( event.formatType, 32, "%s/%x/%x",
00200                 _enums[i].internalFormatString, outputToken, *j );
00201 
00202             // read
00203             glFinish();
00204             size_t nLoops = 0;
00205             try
00206             {
00207                 clock.reset();
00208                 while( clock.getTime64() < 100 /*ms*/ )
00209                 {
00210                     image->startReadback( eq::Frame::BUFFER_COLOR, pvp, zoom,
00211                                           glObjects );
00212                     image->finishReadback( zoom, glObjects->glewGetContext( ));
00213                     ++nLoops;
00214                 }
00215                 glFinish();
00216                 event.msec = clock.getTimef() / float( nLoops );
00217 
00218                 const eq::PixelData& pixels =
00219                     image->getPixelData( eq::Frame::BUFFER_COLOR );
00220                 event.area.x() = pixels.pvp.w;
00221                 event.area.y() = pixels.pvp.h;
00222                 event.dataSizeGPU = pixels.pvp.getArea() * _enums[i].pixelSize;
00223                 event.dataSizeCPU =
00224                     image->getPixelDataSize( eq::Frame::BUFFER_COLOR );
00225             }
00226             catch( const eq::GLException& e ) // debug mode
00227             {
00228                 event.msec = -static_cast<float>( e.glError );
00229             }
00230 
00231             GLenum error = glGetError(); // release mode
00232             if( error != GL_NO_ERROR )
00233                 event.msec = -static_cast<float>( error );
00234 
00235             config->sendEvent( event );
00236 
00237             if( event.msec < 0 )  // error, don't write back data
00238                 continue;
00239 
00240             // write
00241             eq::Compositor::ImageOp op;
00242             op.channel = this;
00243             op.buffers = eq::Frame::BUFFER_COLOR;
00244             op.offset = offset;
00245             op.zoom = zoom;
00246 
00247             event.data.type = ConfigEvent::ASSEMBLE;
00248             event.dataSizeCPU =
00249                 image->getPixelDataSize( eq::Frame::BUFFER_COLOR );
00250 
00251             try
00252             {
00253                 clock.reset();
00254                 eq::Compositor::assembleImage( image, op );
00255                 event.msec = clock.getTimef();
00256 
00257                 const eq::PixelData& pixels =
00258                     image->getPixelData( eq::Frame::BUFFER_COLOR );
00259                 event.area.x() = pixels.pvp.w;
00260                 event.area.y() = pixels.pvp.h;
00261                 event.dataSizeGPU =
00262                     image->getPixelDataSize( eq::Frame::BUFFER_COLOR );
00263             }
00264             catch( const eq::GLException& e ) // debug mode
00265             {
00266                 event.msec = -static_cast<float>( e.glError );
00267             }
00268 
00269             error = glGetError(); // release mode
00270             if( error != GL_NO_ERROR )
00271                 event.msec = -static_cast<float>( error );
00272 
00273             config->sendEvent( event );
00274         }
00275     }
00276 }
00277 
00278 void Channel::_testTiledOperations()
00279 {
00280     glGetError(); // reset
00281 
00282     //----- setup constant data
00283     const eq::Images& images = _frame.getImages();
00284     LBASSERT( images[0] );
00285 
00286     eq::Config* config = getConfig();
00287     const eq::PixelViewport& pvp    = getPixelViewport();
00288     const eq::Vector2i     offset( pvp.x, pvp.y );
00289 
00290     ConfigEvent event = _createConfigEvent();
00291     event.area.x() = pvp.w;
00292 
00293     lunchbox::Clock clock;
00294     eq::Window::ObjectManager* glObjects = getObjectManager();
00295     const GLEWContext* glewContext = glewGetContext();
00296 
00297     //----- test tiled assembly algorithms
00298     eq::PixelViewport subPVP = pvp;
00299     subPVP.h /= NUM_IMAGES;
00300 
00301     for( unsigned i = 0; i < NUM_IMAGES; ++i )
00302     {
00303         LBASSERT( images[ i ] );
00304         images[ i ]->setPixelViewport( subPVP );
00305     }
00306 
00307     for( unsigned tiles = 0; tiles < NUM_IMAGES; ++tiles )
00308     {
00309         EQ_GL_CALL( _draw( 0 ));
00310         event.area.y() = subPVP.h * (tiles+1);
00311 
00312         //---- readback of 'tiles' depth images
00313         event.data.type = ConfigEvent::READBACK;
00314         snprintf( event.formatType, 32, "%d depth tiles", tiles+1 );
00315 
00316         event.msec = 0;
00317         for( unsigned j = 0; j <= tiles; ++j )
00318         {
00319             subPVP.y = pvp.y + j * subPVP.h;
00320             eq::Image* image = images[ j ];
00321             LBCHECK( image->allocDownloader( eq::Frame::BUFFER_DEPTH,
00322                              EQ_COMPRESSOR_TRANSFER_DEPTH_TO_DEPTH_UNSIGNED_INT,
00323                                              glewContext ));
00324             image->clearPixelData( eq::Frame::BUFFER_DEPTH );
00325 
00326             clock.reset();
00327             image->startReadback( eq::Frame::BUFFER_DEPTH, subPVP,
00328                                   eq::Zoom::NONE, glObjects );
00329             image->finishReadback( eq::Zoom::NONE, glObjects->glewGetContext());
00330             event.msec += clock.getTimef();
00331         }
00332 
00333         config->sendEvent( event );
00334 
00335         if( tiles == NUM_IMAGES-1 )
00336             for( unsigned j = 0; j <= tiles; ++j )
00337                 _saveImage( images[j],
00338                             "EQ_COMPRESSOR_DATATYPE_DEPTH_UNSIGNED_INT",
00339                             "tiles" );
00340 
00341         //---- readback of 'tiles' color images
00342         event.data.type = ConfigEvent::READBACK;
00343         snprintf( event.formatType, 32, "%d color tiles", tiles+1 );
00344 
00345         event.msec = 0;
00346         for( unsigned j = 0; j <= tiles; ++j )
00347         {
00348             subPVP.y = pvp.y + j * subPVP.h;
00349             eq::Image* image = images[ j ];
00350 
00351             LBCHECK( image->allocDownloader( eq::Frame::BUFFER_COLOR,
00352                                             EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGRA,
00353                                               glewContext ));
00354             image->clearPixelData( eq::Frame::BUFFER_COLOR );
00355 
00356             clock.reset();
00357             image->startReadback( eq::Frame::BUFFER_COLOR, subPVP,
00358                                   eq::Zoom::NONE, glObjects );
00359             image->finishReadback( eq::Zoom::NONE, glObjects->glewGetContext());
00360             event.msec += clock.getTimef();
00361         }
00362         config->sendEvent( event );
00363 
00364         if( tiles == NUM_IMAGES-1 )
00365             for( unsigned j = 0; j <= tiles; ++j )
00366                 _saveImage( images[j],"EQ_COMPRESSOR_DATATYPE_BGRA","tiles" );
00367 
00368         //---- benchmark assembly operations
00369         subPVP.y = pvp.y + tiles * subPVP.h;
00370 
00371         eq::Compositor::ImageOp op;
00372         op.channel = this;
00373         op.buffers = eq::Frame::BUFFER_COLOR | eq::Frame::BUFFER_DEPTH;
00374         op.offset  = offset;
00375 
00376         // fixed-function
00377         event.data.type = ConfigEvent::ASSEMBLE;
00378         snprintf( event.formatType, 32, "tiles, GL1.1, %d images", tiles+1 );
00379 
00380         clock.reset();
00381         for( unsigned j = 0; j <= tiles; ++j )
00382             eq::Compositor::assembleImage( images[j], op );
00383 
00384         event.msec = clock.getTimef();
00385         config->sendEvent( event );
00386 
00387         // CPU
00388         snprintf( event.formatType, 32, "tiles, CPU,   %d images", tiles+1 );
00389 
00390         std::vector< eq::Frame* > frames;
00391         frames.push_back( &_frame );
00392 
00393         clock.reset();
00394         eq::Compositor::assembleFramesCPU( frames, this );
00395         event.msec = clock.getTimef();
00396         config->sendEvent( event );
00397     }
00398 }
00399 
00400 void Channel::_testDepthAssemble()
00401 {
00402     glGetError(); // reset
00403 
00404     //----- setup constant data
00405     const eq::Images& images = _frame.getImages();
00406     eq::Image* image  = images[ 0 ];
00407     LBASSERT( image );
00408 
00409     eq::Config* config = getConfig();
00410     const eq::PixelViewport& pvp    = getPixelViewport();
00411     const eq::Vector2i offset( pvp.x, pvp.y );
00412 
00413     ConfigEvent event = _createConfigEvent();
00414     event.area.x() = pvp.w;
00415 
00416     lunchbox::Clock clock;
00417     eq::Window::ObjectManager* glObjects = getObjectManager();
00418     const GLEWContext* glewContext = glewGetContext();
00419 
00420     //----- test depth-based assembly algorithms
00421     for( unsigned i = 0; i < NUM_IMAGES; ++i )
00422     {
00423         image = images[ i ];
00424         LBASSERT( image );
00425         image->setPixelViewport( pvp );
00426     }
00427 
00428     event.area.y() = pvp.h;
00429 
00430     for( unsigned i = 0; i < NUM_IMAGES; ++i )
00431     {
00432         _draw( i );
00433 
00434         // fill depth & color image
00435         image = images[ i ];
00436 
00437         LBCHECK( image->allocDownloader( eq::Frame::BUFFER_COLOR,
00438                                          EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGRA,
00439                                          glewContext ));
00440 
00441         LBCHECK( image->allocDownloader( eq::Frame::BUFFER_DEPTH,
00442                              EQ_COMPRESSOR_TRANSFER_DEPTH_TO_DEPTH_UNSIGNED_INT,
00443                                          glewContext ));
00444 
00445         image->clearPixelData( eq::Frame::BUFFER_COLOR );
00446         image->clearPixelData( eq::Frame::BUFFER_DEPTH );
00447 
00448         image->startReadback( eq::Frame::BUFFER_COLOR | eq::Frame::BUFFER_DEPTH,
00449                               pvp, eq::Zoom::NONE, glObjects );
00450         image->finishReadback( eq::Zoom::NONE, glObjects->glewGetContext( ));
00451 
00452         if( i == NUM_IMAGES-1 )
00453             _saveImage( image,"EQ_COMPRESSOR_DATATYPE_DEPTH_UNSIGNED_INT",
00454                               "depthAssemble" );
00455 
00456         // benchmark
00457         eq::Compositor::ImageOp op;
00458         op.channel = this;
00459         op.buffers = eq::Frame::BUFFER_COLOR | eq::Frame::BUFFER_DEPTH;
00460         op.offset  = offset;
00461 
00462         // fixed-function
00463         event.data.type = ConfigEvent::ASSEMBLE;
00464         snprintf( event.formatType, 32, "depth, GL1.1, %d images", i+1 );
00465 
00466         clock.reset();
00467         for( unsigned j = 0; j <= i; ++j )
00468             eq::Compositor::assembleImageDB_FF( images[j], op );
00469 
00470         event.msec = clock.getTimef();
00471         config->sendEvent( event );
00472 
00473         // GLSL
00474         if( GLEW_VERSION_2_0 )
00475         {
00476             snprintf( event.formatType, 32, "depth, GLSL,  %d images", i+1 );
00477 
00478             clock.reset();
00479             for( unsigned j = 0; j <= i; ++j )
00480                 eq::Compositor::assembleImageDB_GLSL( images[j], op );
00481             event.msec = clock.getTimef();
00482             config->sendEvent( event );
00483         }
00484 
00485         // CPU
00486         snprintf( event.formatType, 32, "depth, CPU,   %d images", i+1 );
00487 
00488         std::vector< eq::Frame* > frames;
00489         frames.push_back( &_frame );
00490 
00491         clock.reset();
00492         eq::Compositor::assembleFramesCPU( frames, this );
00493         event.msec = clock.getTimef();
00494         config->sendEvent( event );
00495     }
00496 }
00497 
00498 void Channel::_saveImage( const eq::Image* image,
00499                           const char*      externalformat,
00500                           const char*      info    )
00501 {
00502     return;
00503 
00504     static uint32_t counter = 0;
00505     std::ostringstream stringstream;
00506     stringstream << "Image_" << ++counter << "_" << externalformat << "_"
00507                  << info;
00508     image->writeImages( stringstream.str( ));
00509 }
00510 
00511 void Channel::_draw( const eq::uint128_t& spin )
00512 {
00513     EQ_GL_CALL( glPushAttrib( GL_ALL_ATTRIB_BITS ));
00514 
00515     bindFrameBuffer();
00516     eq::Channel::frameDraw( spin );
00517 
00518     EQ_GL_CALL( glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT ));
00519     EQ_GL_CALL( glEnable( GL_DEPTH_TEST ));
00520 
00521     const float lightPos[] = { 0.0f, 0.0f, 1.0f, 0.0f };
00522     glLightfv( GL_LIGHT0, GL_POSITION, lightPos );
00523 
00524     const float lightAmbient[] = { 0.2f, 0.2f, 0.2f, 1.0f };
00525     glLightfv( GL_LIGHT0, GL_AMBIENT, lightAmbient );
00526 
00527     // rotate scene around the origin
00528     glRotatef( static_cast< float >( spin.low() + 3 ) * 10, 1.0f, 0.5f, 0.25f );
00529 
00530     // render six axis-aligned colored quads around the origin
00531     //  front
00532     glColor3f( 1.0f, 0.5f, 0.5f );
00533     glNormal3f( 0.0f, 0.0f, 1.0f );
00534     glBegin( GL_TRIANGLE_STRIP );
00535     glVertex3f(  .7f,  .7f, -1.0f );
00536     glVertex3f( -.7f,  .7f, -1.0f );
00537     glVertex3f(  .7f, -.7f, -1.0f );
00538     glVertex3f( -.7f, -.7f, -1.0f );
00539     glEnd();
00540 
00541     //  bottom
00542     glColor3f( 0.5f, 1.0f, 0.5f );
00543     glNormal3f( 0.0f, 1.0f, 0.0f );
00544     glBegin( GL_TRIANGLE_STRIP );
00545     glVertex3f(  .7f, -1.0f,  .7f );
00546     glVertex3f( -.7f, -1.0f,  .7f );
00547     glVertex3f(  .7f, -1.0f, -.7f );
00548     glVertex3f( -.7f, -1.0f, -.7f );
00549     glEnd();
00550 
00551     //  back
00552     glColor3f( 0.5f, 0.5f, 1.0f );
00553     glNormal3f( 0.0f, 0.0f, -1.0f );
00554     glBegin( GL_TRIANGLE_STRIP );
00555     glVertex3f(  .7f,  .7f, 1.0f );
00556     glVertex3f( -.7f,  .7f, 1.0f );
00557     glVertex3f(  .7f, -.7f, 1.0f );
00558     glVertex3f( -.7f, -.7f, 1.0f );
00559     glEnd();
00560 
00561     //  top
00562     glColor3f( 1.0f, 1.0f, 0.5f );
00563     glNormal3f( 0.f, -1.f, 0.f );
00564     glBegin( GL_TRIANGLE_STRIP );
00565     glVertex3f(  .7f, 1.0f,  .7f );
00566     glVertex3f( -.7f, 1.0f,  .7f );
00567     glVertex3f(  .7f, 1.0f, -.7f );
00568     glVertex3f( -.7f, 1.0f, -.7f );
00569     glEnd();
00570 
00571     //  right
00572     glColor3f( 1.0f, 0.5f, 1.0f );
00573     glNormal3f( -1.f, 0.f, 0.f );
00574     glBegin( GL_TRIANGLE_STRIP );
00575     glVertex3f( 1.0f,  .7f,  .7f );
00576     glVertex3f( 1.0f, -.7f,  .7f );
00577     glVertex3f( 1.0f,  .7f, -.7f );
00578     glVertex3f( 1.0f, -.7f, -.7f );
00579     glEnd();
00580 
00581     //  left
00582     glColor3f( 0.5f, 1.0f, 1.0f );
00583     glNormal3f( 1.f, 0.f, 0.f );
00584     glBegin( GL_TRIANGLE_STRIP );
00585     glVertex3f( -1.0f,  .7f,  .7f );
00586     glVertex3f( -1.0f, -.7f,  .7f );
00587     glVertex3f( -1.0f,  .7f, -.7f );
00588     glVertex3f( -1.0f, -.7f, -.7f );
00589     glEnd();
00590 
00591     EQ_GL_CALL( glPopAttrib( ));
00592 }
00593 
00594 
00595 }
Generated on Mon Nov 26 2012 14:41:48 for Equalizer 1.4.1 by  doxygen 1.7.6.1