lib/client/channel.cpp

00001 
00002 /* Copyright (c) 2005-2009, Stefan Eilemann <eile@equalizergraphics.com> 
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 #include "channel.h"
00019 
00020 #include "channelStatistics.h"
00021 #include "channelVisitor.h"
00022 #include "client.h"
00023 #include "compositor.h"
00024 #include "commands.h"
00025 #include "config.h"
00026 #include "configEvent.h"
00027 #include "frame.h"
00028 #include "global.h"
00029 #include "log.h"
00030 #include "node.h"
00031 #include "nodeFactory.h"
00032 #include "packets.h"
00033 #include "pipe.h"
00034 #include "range.h"
00035 #include "renderContext.h"
00036 #include "server.h"
00037 #include "task.h"
00038 #include "view.h"
00039 #include "frameBufferObject.h"
00040 
00041 #include <eq/net/command.h>
00042 
00043 using namespace eq::base;
00044 using namespace std;
00045 
00046 namespace eq
00047 {
00049 typedef net::CommandFunc<Channel> ChannelFunc;
00052 #define MAKE_ATTR_STRING( attr ) ( string("EQ_CHANNEL_") + #attr )
00053 std::string Channel::_iAttributeStrings[IATTR_ALL] = {
00054     MAKE_ATTR_STRING( IATTR_HINT_STATISTICS ),
00055     MAKE_ATTR_STRING( IATTR_HINT_SENDTOKEN ),
00056     MAKE_ATTR_STRING( IATTR_FILL1 ),
00057     MAKE_ATTR_STRING( IATTR_FILL2 )
00058 };
00059 
00060 Channel::Channel( Window* parent )
00061         : _window( parent )
00062         , _context( &_nativeContext )
00063         , _tasks( TASK_NONE )
00064         , _state( STATE_STOPPED )
00065         , _fixedPVP( false )
00066         , _fbo(0)
00067         , _drawable( 0 )
00068         , _initialSize( Vector2i::ZERO )
00069         , _maxSize( Vector2i::ZERO )
00070 {
00071     parent->_addChannel( this );
00072     EQINFO << " New eq::Channel @" << (void*)this << endl;
00073 }
00074 
00075 Channel::~Channel()
00076 {  
00077     EQINFO << " Delete eq::Channel @" << (void*)this << endl;
00078     _window->_removeChannel( this );
00079 }
00080 
00081 void Channel::attachToSession( const uint32_t id, 
00082                               const uint32_t instanceID, 
00083                               net::Session* session )
00084 {
00085     net::Object::attachToSession( id, instanceID, session );
00086 
00087     net::CommandQueue* queue = _window->getPipeThreadQueue();
00088 
00089     registerCommand( CMD_CHANNEL_CONFIG_INIT, 
00090                      ChannelFunc( this, &Channel::_cmdConfigInit ), queue );
00091     registerCommand( CMD_CHANNEL_CONFIG_EXIT, 
00092                      ChannelFunc( this, &Channel::_cmdConfigExit ), queue );
00093     registerCommand( CMD_CHANNEL_FRAME_START,
00094                      ChannelFunc( this, &Channel::_cmdFrameStart ), queue );
00095     registerCommand( CMD_CHANNEL_FRAME_FINISH,
00096                      ChannelFunc( this, &Channel::_cmdFrameFinish ), queue );
00097     registerCommand( CMD_CHANNEL_FRAME_CLEAR, 
00098                      ChannelFunc( this, &Channel::_cmdFrameClear ), queue );
00099     registerCommand( CMD_CHANNEL_FRAME_DRAW, 
00100                      ChannelFunc( this, &Channel::_cmdFrameDraw ), queue );
00101     registerCommand( CMD_CHANNEL_FRAME_DRAW_FINISH, 
00102                     ChannelFunc( this, &Channel::_cmdFrameDrawFinish ), queue );
00103     registerCommand( CMD_CHANNEL_FRAME_ASSEMBLE, 
00104                      ChannelFunc( this, &Channel::_cmdFrameAssemble ), queue );
00105     registerCommand( CMD_CHANNEL_FRAME_READBACK, 
00106                      ChannelFunc( this, &Channel::_cmdFrameReadback ), queue );
00107     registerCommand( CMD_CHANNEL_FRAME_TRANSMIT, 
00108                      ChannelFunc( this, &Channel::_cmdFrameTransmit ), queue );
00109     registerCommand( CMD_CHANNEL_FRAME_VIEW_START, 
00110                      ChannelFunc( this, &Channel::_cmdFrameViewStart ), queue );
00111     registerCommand( CMD_CHANNEL_FRAME_VIEW_FINISH, 
00112                      ChannelFunc( this, &Channel::_cmdFrameViewFinish ), queue);
00113 }
00114 
00115 Pipe* Channel::getPipe()
00116 {
00117     EQASSERT( _window );
00118     return ( _window ? _window->getPipe() : 0 );
00119 }
00120 const Pipe* Channel::getPipe() const
00121 {
00122     EQASSERT( _window );
00123     return ( _window ? _window->getPipe() : 0 );
00124 }
00125 
00126 Node* Channel::getNode()
00127 {
00128     EQASSERT( _window );
00129     return ( _window ? _window->getNode() : 0 );
00130 }
00131 const Node* Channel::getNode() const
00132 {
00133     EQASSERT( _window );
00134     return ( _window ? _window->getNode() : 0 );
00135 }
00136 
00137 Config* Channel::getConfig()
00138 {
00139     EQASSERT( _window );
00140     return ( _window ? _window->getConfig() : 0 );
00141 }
00142 const Config* Channel::getConfig() const
00143 {
00144     EQASSERT( _window );
00145     return ( _window ? _window->getConfig() : 0 );
00146 }
00147 
00148 ServerPtr Channel::getServer()
00149 {
00150     EQASSERT( _window );
00151     return ( _window ? _window->getServer() : 0 );
00152 }
00153 
00154 Window::ObjectManager* Channel::getObjectManager()
00155 {
00156     EQASSERT( _window );
00157     return _window->getObjectManager();
00158 }
00159 
00160 
00161 GLEWContext* Channel::glewGetContext()
00162 {
00163     EQASSERT( _window );
00164     return _window->glewGetContext();
00165 }
00166 const GLEWContext* Channel::glewGetContext() const
00167 {
00168     EQASSERT( _window );
00169     return _window->glewGetContext();
00170 }
00171 
00172 VisitorResult Channel::accept( ChannelVisitor& visitor )
00173 {
00174     return visitor.visit( this );
00175 }
00176 
00177 bool Channel::configExit()
00178 {
00179     delete _fbo;
00180     _fbo = 0;
00181     return true;
00182 }
00183 bool Channel::configInit( const uint32_t initID )
00184 { 
00185     return _configInitFBO(); 
00186 }
00187 
00188 bool Channel::_configInitFBO()
00189 {   
00190     if ( _drawable == FBO_NONE )
00191         return true;
00192     
00193     if  (  !_window->getOSWindow()  ||
00194           !GLEW_ARB_texture_non_power_of_two ||
00195           !GLEW_EXT_framebuffer_object )
00196     {
00197         setErrorMessage( "Can't use FBO due to missing GL extensions" );
00198         return false;
00199     }
00200         
00201     // needs glew initialized (see above)
00202     _fbo = new FrameBufferObject( glewGetContext( ));
00203     _fbo->setColorFormat( _window->getColorType( ));
00204         
00205     if( _fbo->init( _nativeContext.pvp.w, _nativeContext.pvp.h, 
00206                     _drawable & FBO_DEPTH, _drawable & FBO_STENCIL ) ) 
00207     {
00208          return true;
00209     }
00210 
00211     setErrorMessage( "FBO initialization failed" );
00212     delete _fbo;
00213     _fbo = 0;
00214     return false;
00215 }
00216 
00217 //----------------------------------------------------------------------
00218 // viewport
00219 //----------------------------------------------------------------------
00220 void Channel::_setPixelViewport( const PixelViewport& pvp )
00221 {
00222     EQASSERT( pvp.hasArea( ));
00223     if( !pvp.hasArea( ))
00224         return;
00225 
00226     _fixedPVP = true;
00227 
00228     if( _nativeContext.pvp == pvp && _nativeContext.vp.hasArea( ))
00229         return;
00230 
00231     _nativeContext.pvp = pvp;
00232     _nativeContext.vp.invalidate();
00233 
00234     if( !_window )
00235         return;
00236     
00237     const PixelViewport& windowPVP = _window->getPixelViewport();
00238     if( windowPVP.isValid( ))
00239         _nativeContext.vp = pvp.getSubVP( windowPVP );
00240 
00241     EQVERB << "Channel pvp set: " << _nativeContext.pvp << ":" 
00242            << _nativeContext.vp << std::endl;
00243 }
00244 
00245 void Channel::_setViewport( const Viewport& vp )
00246 {
00247     if( !vp.hasArea( ))
00248         return;
00249     
00250     _fixedPVP = false;
00251 
00252     if( _nativeContext.vp == vp && _nativeContext.pvp.hasArea( ))
00253         return;
00254 
00255     _nativeContext.vp = vp;
00256     _nativeContext.pvp.invalidate();
00257 
00258     if( !_window )
00259         return;
00260 
00261     PixelViewport windowPVP = _window->getPixelViewport();
00262     if( windowPVP.isValid( ))
00263     {
00264         windowPVP.x = 0;
00265         windowPVP.y = 0;
00266         _nativeContext.pvp = windowPVP.getSubPVP( vp );
00267 
00268         // send event
00269         Event event;
00270         event.type       = Event::CHANNEL_RESIZE;
00271         event.originator = getID();
00272         event.resize.x   = _nativeContext.pvp.x;
00273         event.resize.y   = _nativeContext.pvp.y;
00274         event.resize.w   = _nativeContext.pvp.w;
00275         event.resize.h   = _nativeContext.pvp.h;
00276 
00277         processEvent( event );
00278     }
00279 
00280     EQVERB << "Channel vp set: " << _nativeContext.pvp << ":" 
00281            << _nativeContext.vp << std::endl;
00282 }
00283 
00284 void Channel::_notifyViewportChanged()
00285 {
00286     if( !_window )
00287         return;
00288 
00289     eq::PixelViewport windowPVP = _window->getPixelViewport();
00290     if( !windowPVP.isValid( ))
00291         return;
00292 
00293     windowPVP.x = 0;
00294     windowPVP.y = 0;
00295 
00296     if( _fixedPVP ) // update viewport
00297         _nativeContext.vp = _nativeContext.pvp.getSubVP( windowPVP );
00298     else            // update pixel viewport
00299     {
00300         const eq::PixelViewport pvp = windowPVP.getSubPVP( _nativeContext.vp );
00301         if( _nativeContext.pvp == pvp )
00302             return;
00303 
00304         _nativeContext.pvp = pvp;
00305 
00306         // send event
00307         Event event;
00308         event.type       = Event::CHANNEL_RESIZE;
00309         event.originator = getID();
00310         event.resize.x   = _nativeContext.pvp.x;
00311         event.resize.y   = _nativeContext.pvp.y;
00312         event.resize.w   = _nativeContext.pvp.w;
00313         event.resize.h   = _nativeContext.pvp.h;
00314 
00315         processEvent( event );
00316     }
00317 
00318     EQINFO << "Channel viewport update: " << _nativeContext.pvp << ":" 
00319            << _nativeContext.vp << std::endl;
00320 }
00321 
00322 void Channel::setNearFar( const float nearPlane, const float farPlane )
00323 {
00324     if( _context->frustum.near_plane() == nearPlane && 
00325         _context->frustum.far_plane() == farPlane )
00326     {
00327         return;
00328     }
00329 
00330     _nativeContext.frustum.adjust_near( nearPlane );
00331     _nativeContext.frustum.far_plane() = farPlane;
00332     _nativeContext.ortho.near_plane()  = nearPlane;
00333     _nativeContext.ortho.far_plane()   = farPlane;
00334 
00335     if( _context != &_nativeContext )
00336     {
00337         _context->frustum.adjust_near( nearPlane );
00338         _context->frustum.far_plane() = farPlane;
00339         _context->ortho.near_plane() = nearPlane;
00340         _context->ortho.far_plane()  = farPlane;
00341     }
00342 
00343     ChannelSetNearFarPacket packet;
00344     packet.nearPlane = nearPlane;
00345     packet.farPlane  = farPlane;
00346     
00347     ServerPtr server = getServer();
00348     net::NodePtr node = server.get();
00349     send( node, packet );
00350 }
00351 
00352 void Channel::addStatistic( Event& event )
00353 {
00354     _statistics.push_back( event.statistic );
00355     processEvent( event );
00356 }
00357 
00358 //---------------------------------------------------------------------------
00359 // operations
00360 //---------------------------------------------------------------------------
00361 
00362 void Channel::frameClear( const uint32_t frameID )
00363 {
00364     EQ_GL_CALL( applyBuffer( ));
00365     EQ_GL_CALL( applyViewport( ));
00366 
00367 #ifndef NDEBUG
00368     if( getenv( "EQ_TAINT_CHANNELS" ))
00369     {
00370         const Vector3ub color = getUniqueColor();
00371         glClearColor( color.r()/255.0f, color.g()/255.0f, color.b()/255.0f, 1.0f );
00372     }
00373 #endif // NDEBUG
00374 
00375     EQ_GL_CALL( glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ));
00376 }
00377 
00378 void Channel::frameDraw( const uint32_t frameID )
00379 {
00380     EQ_GL_CALL( applyBuffer( ));
00381     EQ_GL_CALL( applyViewport( ));
00382     
00383     EQ_GL_CALL( glMatrixMode( GL_PROJECTION ));
00384     EQ_GL_CALL( glLoadIdentity( ));
00385     EQ_GL_CALL( applyFrustum( ));
00386 
00387     EQ_GL_CALL( glMatrixMode( GL_MODELVIEW ));
00388     EQ_GL_CALL( glLoadIdentity( ));
00389     EQ_GL_CALL( applyHeadTransform( ));
00390 }
00391 
00392 void Channel::frameAssemble( const uint32_t frameID )
00393 {
00394     EQ_GL_CALL( applyBuffer( ));
00395     EQ_GL_CALL( applyViewport( ));
00396     EQ_GL_CALL( setupAssemblyState( ));
00397 
00398     Compositor::assembleFrames( getInputFrames(), this );
00399 
00400     EQ_GL_CALL( resetAssemblyState( ));
00401 }
00402 
00403 void Channel::frameReadback( const uint32_t frameID )
00404 {
00405     EQ_GL_CALL( applyBuffer( ));
00406     EQ_GL_CALL( applyViewport( ));
00407     EQ_GL_CALL( setupAssemblyState( ));
00408 
00409     Window::ObjectManager* glObjects = getObjectManager();
00410 
00411     const FrameVector& frames = getOutputFrames();
00412     for( FrameVector::const_iterator i = frames.begin(); i != frames.end(); ++i)
00413     {
00414         Frame* frame = *i;
00415         frame->setColorType( _window->getColorType( ));
00416         frame->startReadback( glObjects );
00417     }
00418     for( FrameVector::const_iterator i = frames.begin(); i != frames.end(); ++i)
00419     {
00420         Frame* frame = *i;
00421         frame->syncReadback();
00422     }
00423 
00424     EQ_GL_CALL( resetAssemblyState( ));
00425 }
00426 
00427 void Channel::setupAssemblyState()
00428 {
00429     EQ_GL_ERROR( "before setupAssemblyState" );
00430     glPushAttrib( GL_ENABLE_BIT | GL_STENCIL_BUFFER_BIT | GL_VIEWPORT_BIT | 
00431                   GL_SCISSOR_BIT | GL_LINE_BIT | GL_PIXEL_MODE_BIT | 
00432                   GL_POLYGON_BIT );
00433 
00434     glDisable( GL_DEPTH_TEST );
00435     glDisable( GL_BLEND );
00436     glDisable( GL_ALPHA_TEST );
00437     glDisable( GL_STENCIL_TEST );
00438     glDisable( GL_TEXTURE_1D );
00439     glDisable( GL_TEXTURE_2D );
00440     glDisable( GL_TEXTURE_3D );
00441     glDisable( GL_FOG );
00442     glDisable( GL_CLIP_PLANE0 );
00443     glDisable( GL_CLIP_PLANE1 );
00444     glDisable( GL_CLIP_PLANE2 );
00445     glDisable( GL_CLIP_PLANE3 );
00446     glDisable( GL_CLIP_PLANE4 );
00447     glDisable( GL_CLIP_PLANE5 );
00448     
00449     glPolygonMode( GL_FRONT, GL_FILL );
00450 
00451     EQASSERT( _window );    
00452     // copy to be thread-safe when pvp changes
00453     const PixelViewport pvp(
00454         _fbo ? _fbo->getPixelViewport() : _window->getPixelViewport( ));
00455 
00456     if( pvp.hasArea( ))
00457     {
00458         glViewport( 0, 0, pvp.w, pvp.h );
00459         glScissor( 0, 0, pvp.w, pvp.h );
00460     }
00461     else
00462         EQERROR << "Can't apply viewport " << pvp << endl;
00463 
00464     glMatrixMode( GL_PROJECTION );
00465     glPushMatrix();
00466     glLoadIdentity();
00467     if( pvp.hasArea( ))
00468         glOrtho( 0.0f, pvp.w, 0.0f, pvp.h, -1.0f, 1.0f );
00469 
00470     glMatrixMode( GL_MODELVIEW );
00471     glPushMatrix();
00472     glLoadIdentity();
00473     EQ_GL_ERROR( "after  setupAssemblyState" );
00474 }
00475 
00476 void Channel::resetAssemblyState()
00477 {
00478     EQ_GL_ERROR( "before resetAssemblyState" );
00479     glMatrixMode( GL_PROJECTION );
00480     glPopMatrix();
00481 
00482     glMatrixMode( GL_MODELVIEW );
00483     glPopMatrix();
00484 
00485     glPopAttrib();
00486     EQ_GL_ERROR( "after  resetAssemblyState" );
00487 }
00488 
00489 void Channel::setErrorMessage( const std::string& message )
00490 {
00491     _error = message;
00492 }
00493 
00494 void Channel::_setRenderContext( RenderContext& context )
00495 {
00496     _context = &context;
00497     _window->addRenderContext( context );
00498 }
00499 
00500 const Viewport& Channel::getViewport() const
00501 {
00502     return _context->vp;
00503 }
00504 
00505 const PixelViewport& Channel::getPixelViewport() const
00506 {
00507     return _context->pvp;
00508 }
00509 
00510 const Vector2i& Channel::getPixelOffset() const
00511 {
00512     return _context->offset;
00513 }
00514 
00515 uint32_t Channel::getDrawBuffer() const
00516 {
00517     return _context->buffer;
00518 }
00519 
00520 uint32_t Channel::getReadBuffer() const
00521 {
00522     return _context->buffer;
00523 }
00524 
00525 const ColorMask& Channel::getDrawBufferMask() const
00526 {
00527     return _context->bufferMask;
00528 }
00529 
00530 const Frustumf& Channel::getFrustum() const
00531 {
00532     return _context->frustum;
00533 }
00534 
00535 const Frustumf& Channel::getOrtho() const
00536 {
00537     return _context->ortho;
00538 }
00539 
00540 const Range& Channel::getRange() const
00541 {
00542     return _context->range;
00543 }
00544 
00545 const Pixel& Channel::getPixel() const
00546 {
00547     return _context->pixel;
00548 }
00549 
00550 const Zoom& Channel::getZoom() const
00551 {
00552     return _context->zoom;
00553 }
00554 
00555 Eye Channel::getEye() const
00556 {
00557     return _context->eye;
00558 }
00559 
00560 const Matrix4f& Channel::getHeadTransform() const
00561 {
00562     return _context->headTransform;
00563 }
00564 
00565 Frustumf Channel::getScreenFrustum() const
00566 {
00567     const Pixel& pixel = getPixel();
00568     PixelViewport pvp( getPixelViewport( ));
00569     const Viewport& vp( getViewport( ));
00570 
00571     pvp.x = static_cast<int32_t>( pvp.w / vp.w * vp.x );
00572     pvp.y = static_cast<int32_t>( pvp.h / vp.h * vp.y );
00573     pvp *= pixel;
00574 
00575     return eq::Frustumf( static_cast< float >( pvp.x ),
00576                          static_cast< float >( pvp.getXEnd( )),
00577                          static_cast< float >( pvp.y ),
00578                          static_cast< float >( pvp.getYEnd( )),
00579                          -1.f, 1.f );
00580 }
00581 
00582 const Vector4i& Channel::getOverdraw() const
00583 {
00584     return _context->overdraw;
00585 }
00586 
00587 void Channel::setMaxSize( const Vector2i& size )
00588 {
00589     _maxSize = size;
00590 }
00591 
00592 
00593 uint32_t Channel::getTaskID() const
00594 {
00595     return _context->taskID;
00596 }
00597 
00598 FrameBufferObject* Channel::getFrameBufferObject()
00599 {
00600     return _fbo;
00601 }
00602 
00603 const View* Channel::getView()
00604 {
00605     Pipe* pipe = getPipe();
00606     return pipe->getView( _context->view );
00607 }
00608 
00609 const View* Channel::getNativeView()
00610 {
00611     Pipe* pipe = getPipe();
00612     return pipe->getView( _nativeContext.view );
00613 }
00614 
00615 //---------------------------------------------------------------------------
00616 // apply convenience methods
00617 //---------------------------------------------------------------------------
00618 
00619 void Channel::applyFrameBufferObject()
00620 {
00621     if( _fbo )
00622     {
00623         _fbo->resize( _nativeContext.pvp.w, _nativeContext.pvp.h );
00624         _fbo->bind(); 
00625     }
00626     else if( GLEW_EXT_framebuffer_object )
00627         glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
00628 }
00629 
00630 void Channel::applyBuffer()
00631 {
00632     if (( !_fbo )&&( !_window->isFBOWindow() ))
00633     {
00634         EQ_GL_CALL( glReadBuffer( getReadBuffer( )));
00635         EQ_GL_CALL( glDrawBuffer( getDrawBuffer( )));
00636     }
00637     
00638     applyColorMask();
00639 }
00640 
00641 void Channel::bindFrameBuffer()
00642 {
00643    if( !_window->getOSWindow() )
00644        return;
00645         
00646    if( _fbo )
00647        applyFrameBufferObject();
00648    else
00649        _window->bindFrameBuffer();
00650 }
00651 
00652 void Channel::applyColorMask() const
00653 {
00654     const ColorMask& colorMask = getDrawBufferMask();
00655     glColorMask( colorMask.red, colorMask.green, colorMask.blue, true );
00656 }
00657 
00658 void Channel::applyViewport() const
00659 {
00660     const PixelViewport& pvp = getPixelViewport();
00661     // TODO: OPT return if vp unchanged
00662 
00663     if( !pvp.hasArea( ))
00664     { 
00665         EQERROR << "Can't apply viewport " << pvp << endl;
00666         return;
00667     }
00668 
00669     EQ_GL_CALL( glViewport( pvp.x, pvp.y, pvp.w, pvp.h ));
00670     EQ_GL_CALL( glScissor( pvp.x, pvp.y, pvp.w, pvp.h ));
00671 }
00672 
00673 void Channel::applyFrustum() const
00674 {
00675     const Frustumf& frustum = getFrustum();
00676     EQ_GL_CALL( glFrustum( frustum.left(), frustum.right(),             \
00677                            frustum.bottom(), frustum.top(),             \
00678                            frustum.near_plane(), frustum.far_plane() )); 
00679     EQVERB << "Perspective " << frustum << endl;
00680 }
00681 
00682 void Channel::applyOrtho() const
00683 {
00684     const Frustumf& ortho = getOrtho();
00685     EQ_GL_CALL( glOrtho( ortho.left(), ortho.right(),               \
00686                          ortho.bottom(), ortho.top(),               \
00687                          ortho.near_plane(), ortho.far_plane() )); 
00688     EQVERB << "Orthographic " << ortho << endl;
00689 }
00690 
00691 void Channel::applyScreenFrustum() const
00692 {
00693     const Frustumf frustum = getScreenFrustum();
00694     EQ_GL_CALL( glOrtho( frustum.left(), frustum.right(),               \
00695                          frustum.bottom(), frustum.top(),               \
00696                          frustum.near_plane(), frustum.far_plane() ));
00697     EQVERB << "Apply " << frustum << endl;
00698 }
00699 
00700 void Channel::applyHeadTransform() const
00701 {
00702     const Matrix4f& xfm = getHeadTransform();
00703     EQ_GL_CALL( glMultMatrixf( xfm.array ));
00704     EQVERB << "Apply head transform: " << xfm << endl;
00705 }
00706 
00707 bool Channel::processEvent( const Event& event )
00708 {
00709     ConfigEvent configEvent;
00710     configEvent.data = event;
00711 
00712     switch( event.type )
00713     {
00714         case Event::STATISTIC:
00715             break;
00716 
00717         case Event::CHANNEL_RESIZE:
00718         {
00719             const uint32_t viewID = _nativeContext.view.id;
00720             if( viewID == EQ_ID_INVALID )
00721                 return true;
00722 
00723             // transform to view event, which is meaningful for the config 
00724             configEvent.data.type       = Event::VIEW_RESIZE;
00725             configEvent.data.originator = viewID;
00726 
00727             ResizeEvent& resize = configEvent.data.resize;
00728             resize.dw = resize.w / static_cast< float >( _initialSize.x() );
00729             resize.dh = resize.h / static_cast< float >( _initialSize.y() );
00730             break;
00731         }
00732 
00733         default:
00734             EQWARN << "Unhandled channel event of type " << event.type
00735                    << endl;
00736             EQUNIMPLEMENTED;
00737     }
00738 
00739     Config* config = getConfig();
00740     config->sendEvent( configEvent );
00741     return true;
00742 }
00743 
00744 namespace
00745 {
00746 #define HEIGHT 12
00747 #define SPACE  2
00748 
00749 struct EntityData
00750 {
00751     EntityData() : yPos( 0 ) {}
00752     uint32_t yPos;
00753     std::string name;
00754 };
00755 
00756 struct IdleData
00757 {
00758     IdleData() : idle( 0 ), nIdle( 0 ) {}
00759     uint32_t idle;
00760     uint32_t nIdle;
00761     std::string name;
00762 };
00763 
00764 }
00765 
00766 void Channel::drawStatistics()
00767 {
00768     Config* config = getConfig();
00769     EQASSERT( config );
00770 
00771     vector< FrameStatistics > statistics;
00772     config->getStatistics( statistics );
00773 
00774     if( statistics.empty( )) 
00775         return;
00776 
00777     EQ_GL_CALL( applyBuffer( ));
00778     EQ_GL_CALL( applyViewport( ));
00779     EQ_GL_CALL( setupAssemblyState( ));
00780 
00781     glClear( GL_DEPTH_BUFFER_BIT );
00782 
00783     glDisable( GL_LIGHTING );
00784     glEnable( GL_DEPTH_TEST );
00785 
00786     const util::BitmapFont& font = getObjectManager()->getDefaultFont();
00787 
00788     int64_t       xStart = 0;
00789     PixelViewport pvp    = _window->getPixelViewport();
00790     pvp.x = 0;
00791     pvp.y = 0;
00792 
00793     // find min/max time
00794     int64_t                 xMax      = 0;
00795     int64_t                 xMin      = std::numeric_limits< int64_t >::max();
00796 
00797     for( vector< FrameStatistics >::const_iterator i = statistics.begin();
00798          i != statistics.end(); ++i )
00799     {
00800         const FrameStatistics&  frameStats  = *i;
00801         const SortedStatistics& configStats = frameStats.second;
00802 
00803         for( SortedStatistics::const_iterator j = configStats.begin();
00804              j != configStats.end(); ++j )
00805         {
00806             const Statistics& stats = j->second;
00807 
00808             for( Statistics::const_iterator k = stats.begin(); 
00809                  k != stats.end(); ++k )
00810             {
00811                 const Statistic& stat = *k;
00812                 if( stat.type == Statistic::PIPE_IDLE )
00813                     continue;
00814 
00815                 xMax = EQ_MAX( xMax, stat.endTime );
00816                 xMin = EQ_MIN( xMin, stat.endTime );
00817             }
00818         }
00819     }
00820     uint32_t scale = 1;
00821     while( (xMax - xMin) / scale > pvp.w )
00822         scale *= 10;
00823 
00824     xMax  /= scale;
00825     xStart = xMax - pvp.getXEnd() + SPACE;
00826     uint32_t nextY = pvp.getYEnd() - SPACE;
00827 
00828     std::map< uint32_t, EntityData > entities;
00829     std::map< uint32_t, IdleData >   idles;
00830 
00831     float dim = 0.0f;
00832     for( vector< FrameStatistics >::reverse_iterator i = statistics.rbegin();
00833          i != statistics.rend(); ++i )
00834     {
00835         const FrameStatistics&  frameStats  = *i;
00836         const SortedStatistics& configStats = frameStats.second;
00837 
00838         int64_t     frameMin = xMax;
00839         int64_t     frameMax = 0;
00840 
00841         // draw stats
00842         for( SortedStatistics::const_iterator j = configStats.begin();
00843              j != configStats.end(); ++j )
00844         {
00845             const uint32_t    id    = j->first;
00846             const Statistics& stats = j->second;
00847 
00848             if( stats.empty( ))
00849                 continue;
00850 
00851             if( entities.find( id ) == entities.end( ))
00852             {
00853                 EntityData& data = entities[ id ];
00854                 data.yPos = nextY;
00855                 data.name = stats.front().resourceName;
00856 
00857                 nextY -= (HEIGHT + SPACE);
00858             }
00859 
00860             const uint32_t y = entities[ id ].yPos;
00861 
00862             for( Statistics::const_iterator k = stats.begin(); 
00863                  k != stats.end(); ++k )
00864             {
00865                 const Statistic& stat = *k;
00866 
00867                 if( stat.type == Statistic::PIPE_IDLE )
00868                 {
00869                     IdleData& data = idles[ id ];
00870                     std::map< uint32_t, EntityData >::iterator l = 
00871                         entities.find( id );
00872 
00873                     if( l != entities.end( ))
00874                     {
00875                         entities.erase( l );
00876                         nextY += (HEIGHT + SPACE);
00877                         data.name = stat.resourceName;
00878                     }
00879                     
00880                     data.idle += (stat.idleTime * 100ll / stat.totalTime);
00881                     ++data.nIdle;
00882                     continue;
00883                 }
00884 
00885                 const int64_t startTime = stat.startTime / scale;
00886                 const int64_t endTime   = stat.endTime   / scale;
00887 
00888                 frameMin = EQ_MIN( frameMin, startTime );
00889                 frameMax = EQ_MAX( frameMax, endTime   );
00890 
00891                 if( endTime < xStart || endTime == startTime )
00892                     continue;
00893 
00894                 float y1 = static_cast< float >( y );
00895                 float y2 = static_cast< float >( y - HEIGHT );
00896                 float z  = 0.0f;
00897                 const float x1 = static_cast< float >( startTime - xStart );
00898                 const float x2 = static_cast< float >( endTime   - xStart );
00899                 
00900                 switch( stat.type )
00901                 {
00902                     case Statistic::FRAME_COMPRESS:
00903                     {
00904                         z = 0.7f; 
00905                         
00906                         glColor3f( 0.f, 0.f, 0.f );
00907                         stringstream text;
00908                         text << static_cast< unsigned >( 100.f * stat.ratio ) 
00909                              << '%';
00910                         glRasterPos3f( x1+1, y2, 0.99f );
00911 
00912                         font.draw( text.str( ));
00913                         break;
00914                     }
00915 
00916                     case Statistic::FRAME_TRANSMIT:
00917                     case Statistic::FRAME_RECEIVE:
00918                         z = 0.5f; 
00919                         break;
00920 
00921                     case Statistic::CHANNEL_WAIT_FRAME:
00922                     case Statistic::CONFIG_WAIT_FINISH_FRAME:
00923                         y1 -= SPACE;
00924                         y2 += SPACE;
00925                         // no break;
00926                     case Statistic::CONFIG_START_FRAME:
00927                         z = 0.1f; 
00928                         break;
00929 
00930                     default:
00931                         z = 0.0f; 
00932                         break;
00933                 }
00934                 
00935                 const Vector3f color( Statistic::getColor( stat.type ) - dim );
00936                 glColor3fv( color.array );
00937 
00938                 glBegin( GL_QUADS );
00939                 glVertex3f( x2, y1, z );
00940                 glVertex3f( x1, y1, z );
00941                 glVertex3f( x1, y2, z );
00942                 glVertex3f( x2, y2, z );
00943                 glEnd();
00944             }
00945         }
00946 
00947         frameMin -= xStart;
00948         frameMax -= xStart;
00949 
00950         float x = static_cast< float >( frameMin );
00951         const float y1 = static_cast< float >( nextY );
00952         const float y2 = static_cast< float >( pvp.getYEnd( ));
00953 
00954         glBegin( GL_QUADS );
00955         glColor3f( .5f-dim, 1.0f-dim, .5f-dim );
00956         glVertex3f( x+1.0f, y2, 0.3f );
00957         glVertex3f( x,      y2, 0.3f );
00958         glVertex3f( x,      y1, 0.3f );
00959         glVertex3f( x+1.0f, y1, 0.3f );
00960 
00961         x = static_cast< float >( frameMax );
00962         glColor3f( .5f-dim, .5f-dim, .5f-dim );
00963         glVertex3f( x+1.0f, y2, 0.3f );
00964         glVertex3f( x,      y2, 0.3f );
00965         glVertex3f( x,      y1, 0.3f );
00966         glVertex3f( x+1.0f, y1, 0.3f );
00967         glEnd();
00968 
00969         dim += .1f;
00970     }
00971 
00972     // Entitity names
00973     for( std::map< uint32_t, EntityData >::const_iterator i = entities.begin();
00974          i != entities.end(); ++i )
00975     {
00976         const EntityData& data = i->second;
00977 
00978         glColor3f( 1.f, 1.f, 1.f );
00979         glRasterPos3f( 60.f, data.yPos-SPACE-12.0f, 0.99f );
00980         font.draw( data.name );
00981     }
00982 
00983     // Global stats (scale, GPU idle)
00984     glColor3f( 1.f, 1.f, 1.f );
00985     nextY -= (HEIGHT + SPACE);
00986     glRasterPos3f( 60.f, static_cast< float >( nextY ), 0.99f );
00987     ostringstream text;
00988     text << scale << "ms/pixel";
00989 
00990     if( !idles.empty( ))
00991         text << ", Idle:";
00992 
00993     for( std::map< uint32_t, IdleData >::const_iterator i = idles.begin();
00994          i != idles.end(); ++i )
00995     {
00996         const IdleData& data = i->second;
00997         EQASSERT( data.nIdle > 0 );
00998 
00999         text << " " << data.name << ":" << data.idle / data.nIdle << "%";
01000     }
01001 
01002     font.draw( text.str( ));
01003     
01004     // Legend
01005     nextY -= SPACE;
01006     float x = 0.f;
01007     float z = 0.f;
01008 
01009     glRasterPos3f( x+1.f, nextY-12.f, z );
01010     glColor3f( 1.f, 1.f, 1.f );
01011     font.draw( "channel" );
01012 
01013     for( size_t i = 1; i < Statistic::CONFIG_START_FRAME; ++i )
01014     {
01015         const Statistic::Type type = static_cast< Statistic::Type >( i );
01016         if( type == Statistic::CHANNEL_DRAW_FINISH ||
01017             type == Statistic::PIPE_IDLE )
01018         {
01019             continue;
01020         }
01021 
01022         if( type == Statistic::WINDOW_FINISH )
01023         {
01024             x = 0.f;
01025             nextY -= (HEIGHT + SPACE);
01026             z = 0.f;
01027 
01028             glColor3f( 1.f, 1.f, 1.f );
01029             glRasterPos3f( x+1.f, nextY-12.f, z );
01030             font.draw( "window" );
01031         }
01032         else if( type == Statistic::FRAME_TRANSMIT )
01033         {
01034             x = 0.f;
01035             nextY -= (HEIGHT + SPACE);
01036             z = 0.f;
01037 
01038             glColor3f( 1.f, 1.f, 1.f );
01039             glRasterPos3f( x+1.f, nextY-12.f, z );
01040             font.draw( "frame" );
01041         }
01042 
01043         x += 60.f;
01044         const float x2 = x + 60.f - SPACE; 
01045         const float y1 = static_cast< float >( nextY );
01046         const float y2 = static_cast< float >( nextY - HEIGHT );
01047 
01048         z += 0.01f;
01049         glColor3fv( Statistic::getColor( type ).array );
01050         glBegin( GL_QUADS );
01051         glVertex3f( x2, y1, z );
01052         glVertex3f( x,  y1, z );
01053         glVertex3f( x,  y2, z );
01054         glVertex3f( x2, y2, z );
01055         glEnd();
01056 
01057         z += 0.01f;
01058         glColor3f( 0.f, 0.f, 0.f );
01059         glRasterPos3f( x+1.f, nextY-12.f, z );
01060         font.draw( Statistic::getName( type ));
01061     }
01062     // nextY -= (HEIGHT + SPACE);
01063     
01064     glColor3f( 1.f, 1.f, 1.f );
01065     _window->drawFPS();
01066     EQ_GL_CALL( resetAssemblyState( ));
01067 }
01068 
01069 void Channel::outlineViewport()
01070 {
01071     setupAssemblyState();
01072 
01073     const PixelViewport& pvp = getPixelViewport();
01074     glDisable( GL_LIGHTING );
01075     glColor3f( 1.0f, 1.0f, 1.0f );
01076     glBegin( GL_LINE_LOOP );
01077     {
01078         glVertex3f( pvp.x + .5f,         pvp.y + .5f,         0.f );
01079         glVertex3f( pvp.getXEnd() - .5f, pvp.y + .5f,         0.f );
01080         glVertex3f( pvp.getXEnd() - .5f, pvp.getYEnd() - .5f, 0.f );
01081         glVertex3f( pvp.x + .5f,         pvp.getYEnd() - .5f, 0.f );
01082     } 
01083     glEnd();
01084 
01085     resetAssemblyState();
01086 }
01087 
01088 int32_t Channel::getIAttribute( const IAttribute attr ) const
01089 {
01090     return _iAttributes[attr];
01091 }
01092 
01093 const std::string& Channel::getIAttributeString( const IAttribute attr )
01094 {
01095     return _iAttributeStrings[attr];
01096 }
01097 
01098 //---------------------------------------------------------------------------
01099 // command handlers
01100 //---------------------------------------------------------------------------
01101 net::CommandResult Channel::_cmdConfigInit( net::Command& command )
01102 {
01103     const ChannelConfigInitPacket* packet = 
01104         command.getPacket<ChannelConfigInitPacket>();
01105     EQLOG( LOG_INIT ) << "TASK channel config init " << packet << endl;
01106 
01107     ChannelConfigInitReplyPacket reply;
01108     _error.clear();
01109 
01110     if( _window->isRunning( ))
01111     {
01112         _state = STATE_INITIALIZING;
01113         if( packet->pvp.isValid( ))
01114             _setPixelViewport( packet->pvp );
01115         else
01116             _setViewport( packet->vp );
01117         
01118         _name     = packet->name;
01119         _tasks    = packet->tasks;
01120         _color    = packet->color;
01121         _drawable = packet->drawable;
01122         _nativeContext.view = packet->view;
01123         _initialSize.x() = _nativeContext.pvp.w;
01124         _initialSize.y() = _nativeContext.pvp.h;
01125 
01126         memcpy( _iAttributes, packet->iAttributes, IATTR_ALL * sizeof(int32_t));
01127 
01128         reply.result = configInit( packet->initID );
01129 
01130         reply.nearPlane   = _nativeContext.frustum.near_plane();
01131         reply.farPlane    = _nativeContext.frustum.far_plane();
01132         reply.maxSize     = _maxSize;
01133 
01134         if( reply.result )
01135             _state = STATE_RUNNING;
01136     }
01137     else
01138         reply.result = false;
01139 
01140     EQLOG( LOG_INIT ) << "TASK channel config init reply " << &reply << endl;
01141     send( command.getNode(), reply, _error );
01142     return net::COMMAND_HANDLED;
01143 }
01144 
01145 net::CommandResult Channel::_cmdConfigExit( net::Command& command )
01146 {
01147     const ChannelConfigExitPacket* packet =
01148         command.getPacket<ChannelConfigExitPacket>();
01149     EQLOG( LOG_INIT ) << "Exit channel " << packet << endl;
01150 
01151     ChannelConfigExitReplyPacket reply;
01152     if( _state == STATE_STOPPED )
01153         reply.result = true;
01154     else
01155         reply.result = configExit();
01156 
01157     send( command.getNode(), reply );
01158     _state = STATE_STOPPED;
01159     return net::COMMAND_HANDLED;
01160 }
01161 
01162 net::CommandResult Channel::_cmdFrameStart( net::Command& command )
01163 {
01164     ChannelFrameStartPacket* packet = 
01165         command.getPacket<ChannelFrameStartPacket>();
01166     EQVERB << "handle channel frame start " << packet << endl;
01167 
01168     //_grabFrame( packet->frameNumber ); single-threaded
01169     _nativeContext.view     = packet->context.view;
01170     _nativeContext.overdraw = packet->context.overdraw;
01171 
01172     _context = &packet->context;
01173     bindFrameBuffer();
01174     frameStart( packet->context.frameID, packet->frameNumber );
01175     _context = &_nativeContext;
01176 
01177     return net::COMMAND_HANDLED;
01178 }
01179 
01180 net::CommandResult Channel::_cmdFrameFinish( net::Command& command )
01181 {
01182     ChannelFrameFinishPacket* packet =
01183         command.getPacket<ChannelFrameFinishPacket>();
01184     EQLOG( LOG_TASKS ) << "TASK frame finish " << getName() <<  " " << packet
01185                        << endl;
01186 
01187     _context = &packet->context;
01188     frameFinish( packet->context.frameID, packet->frameNumber );
01189     _context = &_nativeContext;
01190 
01191     ChannelFrameFinishReplyPacket reply( packet );
01192     reply.nStatistics = _statistics.size();
01193 
01194     command.getNode()->send( reply, _statistics );
01195 
01196     _statistics.clear();
01197     return net::COMMAND_HANDLED;
01198 }
01199 
01200 net::CommandResult Channel::_cmdFrameClear( net::Command& command )
01201 {
01202     ChannelFrameClearPacket* packet = 
01203         command.getPacket<ChannelFrameClearPacket>();
01204     EQLOG( LOG_TASKS ) << "TASK clear " << getName() <<  " " << packet << endl;
01205 
01206     _setRenderContext( packet->context );
01207     ChannelStatistics event( Statistic::CHANNEL_CLEAR, this );
01208     frameClear( packet->context.frameID );
01209     _context = &_nativeContext;
01210 
01211     return net::COMMAND_HANDLED;
01212 }
01213 
01214 net::CommandResult Channel::_cmdFrameDraw( net::Command& command )
01215 {
01216     ChannelFrameDrawPacket* packet = 
01217         command.getPacket<ChannelFrameDrawPacket>();
01218     EQLOG( LOG_TASKS ) << "TASK draw " << getName() <<  " " << packet << endl;
01219 
01220     _setRenderContext( packet->context );
01221     ChannelStatistics event( Statistic::CHANNEL_DRAW, this );
01222     frameDraw( packet->context.frameID );
01223     _context = &_nativeContext;
01224 
01225     return net::COMMAND_HANDLED;
01226 }
01227 
01228 net::CommandResult Channel::_cmdFrameDrawFinish( net::Command& command )
01229 {
01230     ChannelFrameDrawFinishPacket* packet = 
01231         command.getPacket< ChannelFrameDrawFinishPacket >();
01232     EQLOG( LOG_TASKS ) << "TASK draw finish " << getName() <<  " " << packet
01233                        << endl;
01234 
01235     ChannelStatistics event( Statistic::CHANNEL_DRAW_FINISH, this );
01236     frameDrawFinish( packet->frameID, packet->frameNumber );
01237 
01238     return net::COMMAND_HANDLED;
01239 }
01240 
01241 net::CommandResult Channel::_cmdFrameAssemble( net::Command& command )
01242 {
01243     ChannelFrameAssemblePacket* packet = 
01244         command.getPacket<ChannelFrameAssemblePacket>();
01245     EQLOG( LOG_TASKS | LOG_ASSEMBLY ) << "TASK assemble " << getName() <<  " " 
01246                                        << packet << endl;
01247 
01248     _setRenderContext( packet->context );
01249     ChannelStatistics event( Statistic::CHANNEL_ASSEMBLE, this );
01250 
01251     for( uint32_t i=0; i<packet->nFrames; ++i )
01252     {
01253         Pipe*  pipe  = getPipe();
01254         Frame* frame = pipe->getFrame( packet->frames[i], getEye( ));
01255         _inputFrames.push_back( frame );
01256     }
01257 
01258     frameAssemble( packet->context.frameID );
01259 
01260     for( FrameVector::const_iterator i = _inputFrames.begin();
01261          i != _inputFrames.end(); ++i )
01262     {
01263         // Unset the frame data on input frames, so that they only get flushed
01264         // once by the output frames during exit.
01265         (*i)->setData( 0 );
01266     }
01267     _inputFrames.clear();
01268     _context = &_nativeContext;
01269 
01270     return net::COMMAND_HANDLED;
01271 }
01272 
01273 net::CommandResult Channel::_cmdFrameReadback( net::Command& command )
01274 {
01275     ChannelFrameReadbackPacket* packet = 
01276         command.getPacket<ChannelFrameReadbackPacket>();
01277     EQLOG( LOG_TASKS | LOG_ASSEMBLY ) << "TASK readback " << getName() <<  " " 
01278                                        << packet << endl;
01279 
01280     _setRenderContext( packet->context );
01281     ChannelStatistics event( Statistic::CHANNEL_READBACK, this );
01282 
01283     for( uint32_t i=0; i<packet->nFrames; ++i )
01284     {
01285         Pipe*  pipe  = getPipe();
01286         Frame* frame = pipe->getFrame( packet->frames[i], getEye( ));
01287         _outputFrames.push_back( frame );
01288     }
01289 
01290     frameReadback( packet->context.frameID );
01291 
01292     for( FrameVector::const_iterator i = _outputFrames.begin(); 
01293          i != _outputFrames.end(); ++i)
01294     {
01295         Frame* frame = *i;
01296         frame->setReady();
01297     }
01298 
01299     _outputFrames.clear();
01300     _context = &_nativeContext;
01301     return net::COMMAND_HANDLED;
01302 }
01303 
01304 net::CommandResult Channel::_cmdFrameTransmit( net::Command& command )
01305 {
01306     const ChannelFrameTransmitPacket* packet = 
01307         command.getPacket<ChannelFrameTransmitPacket>();
01308     EQLOG( LOG_TASKS | LOG_ASSEMBLY ) << "TASK transmit " << getName() <<  " " 
01309                                       << packet << endl;
01310 
01311     net::Session* session   = getSession();
01312     net::NodePtr  localNode = session->getLocalNode();
01313     net::NodePtr  server    = session->getServer();
01314     Pipe*         pipe      = getPipe();
01315     Frame*        frame     = pipe->getFrame( packet->frame,
01316                                               packet->context.eye );
01317 
01318     for( uint32_t i=0; i<packet->nNodes; ++i )
01319     {
01320         net::NodeID nodeID = packet->nodes[i];
01321         nodeID.convertToHost();
01322 
01323         net::NodePtr toNode = localNode->connect( nodeID );
01324         EQASSERT( toNode->isConnected( ));
01325         EQLOG( LOG_ASSEMBLY ) << "channel \"" << getName() << "\" transmit " 
01326                               << frame << " to " << nodeID << endl;
01327 
01328         frame->useSendToken( getIAttribute( IATTR_HINT_SENDTOKEN ) == ON );
01329         getNode()->transmitter.send( frame->getData(), toNode, 
01330                                      getPipe()->getCurrentFrame( ));
01331     }
01332 
01333     return net::COMMAND_HANDLED;
01334 }
01335 
01336 net::CommandResult Channel::_cmdFrameViewStart( net::Command& command )
01337 {
01338     ChannelFrameViewStartPacket* packet = 
01339         command.getPacket<ChannelFrameViewStartPacket>();
01340     EQLOG( LOG_TASKS | LOG_ASSEMBLY ) << "TASK view start " << getName() <<  " "
01341                                        << packet << endl;
01342 
01343     _setRenderContext( packet->context );
01344     // TBD ChannelStatistics event( Statistic::CHANNEL_READBACK, this );
01345     frameViewStart( packet->context.frameID );
01346     _context = &_nativeContext;
01347 
01348     return net::COMMAND_HANDLED;
01349 }
01350 
01351 net::CommandResult Channel::_cmdFrameViewFinish( net::Command& command )
01352 {
01353     ChannelFrameViewFinishPacket* packet = 
01354         command.getPacket<ChannelFrameViewFinishPacket>();
01355     EQLOG( LOG_TASKS | LOG_ASSEMBLY ) << "TASK view finish " << getName()
01356                                       <<  " " << packet << endl;
01357 
01358     _setRenderContext( packet->context );
01359     // TBD ChannelStatistics event( Statistic::CHANNEL_READBACK, this );
01360     frameViewFinish( packet->context.frameID );
01361     _context = &_nativeContext;
01362 
01363     return net::COMMAND_HANDLED;
01364 }
01365 
01366 }
Generated on Mon Aug 10 18:58:31 2009 for Equalizer 0.9 by  doxygen 1.5.8