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