LCOV - code coverage report
Current view: top level - eq/client - channel.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 610 1060 57.5 %
Date: 2014-06-18 Functions: 88 113 77.9 %

          Line data    Source code
       1             : /* Copyright (c) 2005-2014, Stefan Eilemann <eile@equalizergraphics.com>
       2             :  *                    2011, Cedric Stalder <cedric.stalder@gmail.com>
       3             :  *               2011-2014, Daniel Nachbaur <danielnachbaur@gmail.com>
       4             :  *                                    2013, Julio Delgado Mangas <julio.delgadomangas@epfl.ch>
       5             :  *
       6             :  * This library is free software; you can redistribute it and/or modify it under
       7             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       8             :  * by the Free Software Foundation.
       9             :  *
      10             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      11             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      12             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      13             :  * details.
      14             :  *
      15             :  * You should have received a copy of the GNU Lesser General Public License
      16             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      17             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             :  */
      19             : 
      20             : #include "channel.h"
      21             : 
      22             : #include "channelStatistics.h"
      23             : #include "client.h"
      24             : #include "compositor.h"
      25             : #include "config.h"
      26             : #ifndef EQ_2_0_API
      27             : #  include "configEvent.h"
      28             : #endif
      29             : #include "detail/fileFrameWriter.h"
      30             : #include "error.h"
      31             : #include "frame.h"
      32             : #include "frameData.h"
      33             : #include "gl.h"
      34             : #include "global.h"
      35             : #include "image.h"
      36             : #include "jitter.h"
      37             : #include "log.h"
      38             : #include "node.h"
      39             : #include "nodeFactory.h"
      40             : #include "pipe.h"
      41             : #include "pixelData.h"
      42             : #include "server.h"
      43             : #include "systemWindow.h"
      44             : #include "view.h"
      45             : #include "window.h"
      46             : 
      47             : #include <eq/util/accum.h>
      48             : #include <eq/util/frameBufferObject.h>
      49             : #include <eq/util/objectManager.h>
      50             : #include <eq/fabric/commands.h>
      51             : #include <eq/fabric/task.h>
      52             : #include <eq/fabric/tile.h>
      53             : 
      54             : #include <co/connectionDescription.h>
      55             : #include <co/exception.h>
      56             : #include <co/objectICommand.h>
      57             : #include <co/queueSlave.h>
      58             : #include <co/sendToken.h>
      59             : #include <lunchbox/rng.h>
      60             : #include <lunchbox/scopedMutex.h>
      61             : #include <lunchbox/plugins/compressor.h>
      62             : 
      63             : #ifdef EQUALIZER_USE_GLSTATS
      64             : #  include "detail/statsRenderer.h"
      65             : #  include <GLStats/GLStats.h>
      66             : #endif
      67             : 
      68             : #include <bitset>
      69             : #include <set>
      70             : 
      71             : #include "detail/channel.ipp"
      72             : 
      73             : #ifdef EQUALIZER_USE_DISPLAYCLUSTER
      74             : #  include "dc/proxy.h"
      75             : #endif
      76             : 
      77             : namespace eq
      78             : {
      79             : /** @cond IGNORE */
      80             : typedef fabric::Channel< Window, Channel > Super;
      81             : typedef co::CommandFunc<Channel> CmdFunc;
      82             : using detail::STATE_STOPPED;
      83             : using detail::STATE_INITIALIZING;
      84             : using detail::STATE_RUNNING;
      85             : using detail::STATE_FAILED;
      86             : /** @endcond */
      87             : 
      88         825 : Channel::Channel( Window* parent )
      89             :         : Super( parent )
      90         825 :         , _impl( new detail::Channel )
      91         825 : {}
      92             : 
      93          42 : Channel::~Channel()
      94             : {
      95          15 :     delete _impl;
      96          27 : }
      97             : 
      98          15 : void Channel::attach( const uint128_t& id, const uint32_t instanceID )
      99             : {
     100          15 :     Super::attach( id, instanceID );
     101          15 :     co::CommandQueue* queue = getPipeThreadQueue();
     102          15 :     co::CommandQueue* commandQ = getCommandThreadQueue();
     103          15 :     co::CommandQueue* tmitQ = getNode()->getTransmitterQueue();
     104          15 :     co::CommandQueue* transferQ = getPipe()->getTransferThreadQueue();
     105             : 
     106             :     registerCommand( fabric::CMD_CHANNEL_CONFIG_INIT,
     107          15 :                      CmdFunc( this, &Channel::_cmdConfigInit ), queue );
     108             :     registerCommand( fabric::CMD_CHANNEL_CONFIG_EXIT,
     109          15 :                      CmdFunc( this, &Channel::_cmdConfigExit ), queue );
     110             :     registerCommand( fabric::CMD_CHANNEL_FRAME_START,
     111          15 :                      CmdFunc( this, &Channel::_cmdFrameStart ), queue );
     112             :     registerCommand( fabric::CMD_CHANNEL_FRAME_FINISH,
     113          15 :                      CmdFunc( this, &Channel::_cmdFrameFinish ), queue );
     114             :     registerCommand( fabric::CMD_CHANNEL_FRAME_CLEAR,
     115          15 :                      CmdFunc( this, &Channel::_cmdFrameClear ), queue );
     116             :     registerCommand( fabric::CMD_CHANNEL_FRAME_DRAW,
     117          15 :                      CmdFunc( this, &Channel::_cmdFrameDraw ), queue );
     118             :     registerCommand( fabric::CMD_CHANNEL_FRAME_DRAW_FINISH,
     119          15 :                      CmdFunc( this, &Channel::_cmdFrameDrawFinish ), queue );
     120             :     registerCommand( fabric::CMD_CHANNEL_FRAME_ASSEMBLE,
     121          15 :                      CmdFunc( this, &Channel::_cmdFrameAssemble ), queue );
     122             :     registerCommand( fabric::CMD_CHANNEL_FRAME_READBACK,
     123          15 :                      CmdFunc( this, &Channel::_cmdFrameReadback ), queue );
     124             :     registerCommand( fabric::CMD_CHANNEL_FRAME_TRANSMIT_IMAGE,
     125          15 :                      CmdFunc( this, &Channel::_cmdFrameTransmitImage ), tmitQ );
     126             :     registerCommand( fabric::CMD_CHANNEL_FRAME_SET_READY,
     127          15 :                      CmdFunc( this, &Channel::_cmdFrameSetReady ), transferQ );
     128             :     registerCommand( fabric::CMD_CHANNEL_FRAME_SET_READY_NODE,
     129          15 :                      CmdFunc( this, &Channel::_cmdFrameSetReadyNode ), tmitQ );
     130             :     registerCommand( fabric::CMD_CHANNEL_FRAME_VIEW_START,
     131          15 :                      CmdFunc( this, &Channel::_cmdFrameViewStart ), queue );
     132             :     registerCommand( fabric::CMD_CHANNEL_FRAME_VIEW_FINISH,
     133          15 :                      CmdFunc( this, &Channel::_cmdFrameViewFinish ), queue );
     134             :     registerCommand( fabric::CMD_CHANNEL_STOP_FRAME,
     135          15 :                      CmdFunc( this, &Channel::_cmdStopFrame ), commandQ );
     136             :     registerCommand( fabric::CMD_CHANNEL_FRAME_TILES,
     137          15 :                      CmdFunc( this, &Channel::_cmdFrameTiles ), queue );
     138             :     registerCommand( fabric::CMD_CHANNEL_FINISH_READBACK,
     139          15 :                      CmdFunc( this, &Channel::_cmdFinishReadback ), transferQ );
     140             :     registerCommand( fabric::CMD_CHANNEL_DELETE_TRANSFER_CONTEXT,
     141             :                      CmdFunc( this,&Channel::_cmdDeleteTransferContext ),
     142          15 :                      transferQ );
     143          15 : }
     144             : 
     145          15 : co::CommandQueue* Channel::getPipeThreadQueue()
     146             : {
     147          15 :     return getWindow()->getPipeThreadQueue();
     148             : }
     149             : 
     150          15 : co::CommandQueue* Channel::getCommandThreadQueue()
     151             : {
     152          15 :     return getWindow()->getCommandThreadQueue();
     153             : }
     154             : 
     155          34 : uint32_t Channel::getCurrentFrame() const
     156             : {
     157          34 :     return getPipe()->getCurrentFrame();
     158             : }
     159             : 
     160          44 : Pipe* Channel::getPipe()
     161             : {
     162          44 :     Window* window = getWindow();
     163          44 :     LBASSERT( window );
     164          44 :     return ( window ? window->getPipe() : 0 );
     165             : }
     166             : 
     167          36 : const Pipe* Channel::getPipe() const
     168             : {
     169          36 :     const Window* window = getWindow();
     170          36 :     LBASSERT( window );
     171          36 :     return ( window ? window->getPipe() : 0 );
     172             : }
     173             : 
     174          21 : Node* Channel::getNode()
     175             : {
     176          21 :     Window* window = getWindow();
     177          21 :     LBASSERT( window );
     178          21 :     return ( window ? window->getNode() : 0 );
     179             : }
     180           0 : const Node* Channel::getNode() const
     181             : {
     182           0 :     const Window* window = getWindow();
     183           0 :     LBASSERT( window );
     184           0 :     return ( window ? window->getNode() : 0 );
     185             : }
     186             : 
     187         113 : Config* Channel::getConfig()
     188             : {
     189         113 :     Window* window = getWindow();
     190         113 :     LBASSERT( window );
     191         113 :     return ( window ? window->getConfig() : 0 );
     192             : }
     193           0 : const Config* Channel::getConfig() const
     194             : {
     195           0 :     const Window* window = getWindow();
     196           0 :     LBASSERT( window );
     197           0 :     return ( window ? window->getConfig() : 0 );
     198             : }
     199             : 
     200           7 : ServerPtr Channel::getServer()
     201             : {
     202           7 :     Window* window = getWindow();
     203           7 :     LBASSERT( window );
     204           7 :     return ( window ? window->getServer() : 0 );
     205             : }
     206             : 
     207           5 : util::ObjectManager& Channel::getObjectManager()
     208             : {
     209           5 :     Window* window = getWindow();
     210           5 :     LBASSERT( window );
     211           5 :     return window->getObjectManager();
     212             : }
     213             : 
     214           4 : const DrawableConfig& Channel::getDrawableConfig() const
     215             : {
     216           4 :     const Window* window = getWindow();
     217           4 :     LBASSERT( window );
     218           4 :     if( _impl->fbo )
     219           0 :         return _impl->drawableConfig;
     220             : 
     221           4 :     return window->getDrawableConfig();
     222             : }
     223             : 
     224           7 : const GLEWContext* Channel::glewGetContext() const
     225             : {
     226           7 :     const Window* window = getWindow();
     227           7 :     LBASSERT( window );
     228           7 :     return window->glewGetContext();
     229             : }
     230             : 
     231          15 : bool Channel::configExit()
     232             : {
     233             : #ifdef EQUALIZER_USE_DISPLAYCLUSTER
     234             :     delete _impl->_dcProxy;
     235             :     _impl->_dcProxy = 0;
     236             : #endif
     237             : 
     238          15 :     delete _impl->fbo;
     239          15 :     _impl->fbo = 0;
     240          15 :     return true;
     241             : }
     242             : 
     243          15 : bool Channel::configInit( const uint128_t& )
     244             : {
     245             : #ifdef EQUALIZER_USE_DISPLAYCLUSTER
     246             :     if( getView() && !getView()->getDisplayCluster().empty( ))
     247             :     {
     248             :         LBASSERT( !_impl->_dcProxy );
     249             :         _impl->_dcProxy = new dc::Proxy( this );
     250             :     }
     251             : #endif
     252          15 :     return _configInitFBO();
     253             : }
     254             : 
     255          15 : bool Channel::_configInitFBO()
     256             : {
     257          15 :     const uint32_t drawable = getDrawable();
     258          15 :     if( drawable == FB_WINDOW )
     259          15 :         return true;
     260             : 
     261           0 :     const Window* window = getWindow();
     262           0 :     if( !window->getSystemWindow()  ||
     263           0 :         !GLEW_ARB_texture_non_power_of_two || !GLEW_EXT_framebuffer_object )
     264             :     {
     265           0 :         sendError( ERROR_FBO_UNSUPPORTED );
     266           0 :         return false;
     267             :     }
     268             : 
     269             :     // needs glew initialized (see above)
     270           0 :     _impl->fbo = new util::FrameBufferObject( glewGetContext( ));
     271             : 
     272           0 :     int depthSize = 0;
     273           0 :     if( drawable & FBO_DEPTH )
     274             :     {
     275           0 :         depthSize = window->getIAttribute( WindowSettings::IATTR_PLANES_DEPTH );
     276           0 :         if( depthSize < 1 )
     277           0 :             depthSize = 24;
     278             :     }
     279             : 
     280           0 :     int stencilSize = 0;
     281           0 :     if( drawable & FBO_STENCIL )
     282             :     {
     283             :         stencilSize =
     284           0 :                 window->getIAttribute( WindowSettings::IATTR_PLANES_STENCIL );
     285           0 :         if( stencilSize < 1 )
     286           0 :             stencilSize = 1;
     287             :     }
     288             : 
     289           0 :     const PixelViewport& pvp = getNativePixelViewport();
     290             :     const Error error = _impl->fbo->init( pvp.w, pvp.h,
     291             :                                           window->getColorFormat(), depthSize,
     292           0 :                                           stencilSize );
     293           0 :     if( !error )
     294           0 :         return true;
     295             : 
     296           0 :     sendError( error );
     297           0 :     delete _impl->fbo;
     298           0 :     _impl->fbo = 0;
     299           0 :     return false;
     300             : }
     301             : 
     302          15 : void Channel::_initDrawableConfig()
     303             : {
     304          15 :     const Window* window = getWindow();
     305          15 :     _impl->drawableConfig = window->getDrawableConfig();
     306          15 :     if( !_impl->fbo )
     307          30 :         return;
     308             : 
     309           0 :     const util::Textures& colors = _impl->fbo->getColorTextures();
     310           0 :     if( !colors.empty( ))
     311             :     {
     312           0 :         switch( colors.front()->getType( ))
     313             :         {
     314             :             case GL_FLOAT:
     315           0 :                 _impl->drawableConfig.colorBits = 32;
     316           0 :                 break;
     317             :             case GL_HALF_FLOAT:
     318           0 :                 _impl->drawableConfig.colorBits = 16;
     319           0 :                 break;
     320             :             case GL_UNSIGNED_INT_10_10_10_2:
     321           0 :                 _impl->drawableConfig.colorBits = 10;
     322           0 :                 break;
     323             : 
     324             :             default:
     325           0 :                 LBUNIMPLEMENTED;
     326             :             case GL_UNSIGNED_BYTE:
     327           0 :                 _impl->drawableConfig.colorBits = 8;
     328           0 :                 break;
     329             :         }
     330             :     }
     331             : }
     332             : 
     333             : 
     334          39 : void Channel::notifyViewportChanged()
     335             : {
     336          39 :     const PixelViewport oldPVP = getPixelViewport();
     337          39 :     Super::notifyViewportChanged();
     338          39 :     const PixelViewport& newPVP = getPixelViewport();
     339             : 
     340          39 :     if( newPVP == oldPVP )
     341          55 :         return;
     342             : 
     343          23 :     Event event;
     344          23 :     event.type       = Event::CHANNEL_RESIZE;
     345          23 :     event.originator = getID();
     346          23 :     event.serial     = getSerial();
     347          23 :     LBASSERT( event.originator != 0 );
     348          23 :     event.resize.x   = newPVP.x;
     349          23 :     event.resize.y   = newPVP.y;
     350          23 :     event.resize.w   = newPVP.w;
     351          23 :     event.resize.h   = newPVP.h;
     352             : 
     353          23 :     processEvent( event );
     354             : }
     355             : 
     356           0 : void Channel::notifyStopFrame( const uint32_t )
     357           0 : {}
     358             : 
     359          32 : void Channel::addStatistic( Event& event )
     360             : {
     361             :     {
     362          32 :         const uint32_t frameNumber = event.statistic.frameNumber;
     363          32 :         const size_t index = frameNumber % _impl->statistics->size();
     364          32 :         LBASSERT( index < _impl->statistics->size( ));
     365          32 :         LBASSERTINFO( _impl->statistics.data[ index ].used > 0, frameNumber );
     366             : 
     367          32 :         lunchbox::ScopedFastWrite mutex( _impl->statistics );
     368          32 :         Statistics& statistics = _impl->statistics.data[ index ].data;
     369          32 :         statistics.push_back( event.statistic );
     370             :     }
     371          32 :     processEvent( event );
     372          32 : }
     373             : 
     374             : //---------------------------------------------------------------------------
     375             : // operations
     376             : //---------------------------------------------------------------------------
     377           7 : void Channel::waitFrameFinished( const uint32_t frame ) const
     378             : {
     379           7 :     _impl->finishedFrame.waitGE( frame );
     380           7 : }
     381             : 
     382           9 : void Channel::frameClear( const uint128_t& )
     383             : {
     384           9 :     resetRegions();
     385           9 :     EQ_GL_CALL( applyBuffer( ));
     386           9 :     EQ_GL_CALL( applyViewport( ));
     387             : 
     388             : #ifndef NDEBUG
     389           9 :     if( getenv( "EQ_TAINT_CHANNELS" ))
     390             :     {
     391           0 :         const Vector3ub color = getUniqueColor();
     392           0 :         glClearColor( color.r()/255.f, color.g()/255.f, color.b()/255.f, 0.f );
     393             :     }
     394             : #endif // NDEBUG
     395             : 
     396           9 :     EQ_GL_CALL( glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ));
     397           9 : }
     398             : 
     399           4 : void Channel::frameDraw( const uint128_t& )
     400             : {
     401           4 :     EQ_GL_CALL( applyBuffer( ));
     402           4 :     EQ_GL_CALL( applyViewport( ));
     403             : 
     404           4 :     EQ_GL_CALL( glMatrixMode( GL_PROJECTION ));
     405           4 :     EQ_GL_CALL( glLoadIdentity( ));
     406           4 :     EQ_GL_CALL( applyFrustum( ));
     407             : 
     408           4 :     EQ_GL_CALL( glMatrixMode( GL_MODELVIEW ));
     409           4 :     EQ_GL_CALL( glLoadIdentity( ));
     410           4 :     EQ_GL_CALL( applyHeadTransform( ));
     411           4 : }
     412             : 
     413           2 : void Channel::frameAssemble( const uint128_t&, const Frames& frames )
     414             : {
     415           2 :     EQ_GL_CALL( applyBuffer( ));
     416           2 :     EQ_GL_CALL( applyViewport( ));
     417           2 :     EQ_GL_CALL( setupAssemblyState( ));
     418             :     try
     419             :     {
     420           2 :         Compositor::assembleFrames( frames, this, 0 );
     421             :     }
     422             :     catch( const co::Exception& e )
     423             :     {
     424             :         LBWARN << e.what() << std::endl;
     425             :     }
     426           2 :     EQ_GL_CALL( resetAssemblyState( ));
     427           2 : }
     428             : 
     429           2 : void Channel::frameReadback( const uint128_t&, const Frames& frames )
     430             : {
     431           2 :     const PixelViewport& region = getRegion();
     432           2 :     if( !region.hasArea( ))
     433           2 :         return;
     434             : 
     435           2 :     EQ_GL_CALL( applyBuffer( ));
     436           2 :     EQ_GL_CALL( applyViewport( ));
     437           2 :     EQ_GL_CALL( setupAssemblyState( ));
     438             : 
     439           2 :     util::ObjectManager&  glObjects   = getObjectManager();
     440           2 :     const DrawableConfig& drawable    = getDrawableConfig();
     441           2 :     const PixelViewports& regions     = getRegions();
     442             : 
     443           4 :     for( FramesCIter i = frames.begin(); i != frames.end(); ++i )
     444             :     {
     445           2 :         Frame* frame = *i;
     446           2 :         frame->startReadback( glObjects, drawable, regions );
     447             :     }
     448             : 
     449           2 :     EQ_GL_CALL( resetAssemblyState( ));
     450             : }
     451             : 
     452           7 : void Channel::startFrame( const uint32_t ) { /* nop */ }
     453           7 : void Channel::releaseFrame( const uint32_t ) { /* nop */ }
     454           7 : void Channel::releaseFrameLocal( const uint32_t ) { /* nop */ }
     455             : 
     456           7 : void Channel::frameStart( const uint128_t&, const uint32_t frameNumber )
     457             : {
     458           7 :     resetRegions();
     459           7 :     startFrame( frameNumber );
     460           7 : }
     461             : 
     462           7 : void Channel::frameFinish( const uint128_t&, const uint32_t frameNumber )
     463             : {
     464           7 :     releaseFrame( frameNumber );
     465           7 : }
     466             : 
     467           7 : void Channel::frameDrawFinish( const uint128_t&, const uint32_t frameNumber )
     468             : {
     469           7 :     releaseFrameLocal( frameNumber );
     470           7 : }
     471             : 
     472           5 : void Channel::frameViewStart( const uint128_t& ) { /* nop */ }
     473             : 
     474           5 : void Channel::frameViewFinish( const uint128_t& )
     475             : {
     476           5 :     _impl->frameViewFinish( this );
     477           5 : }
     478             : 
     479           4 : void Channel::setupAssemblyState()
     480             : {
     481           4 :     EQ_GL_CALL( bindFrameBuffer( ));
     482           4 :     const PixelViewport& pvp = getPixelViewport();
     483           4 :     Compositor::setupAssemblyState( pvp, glewGetContext( ));
     484           4 : }
     485             : 
     486           4 : void Channel::resetAssemblyState()
     487             : {
     488           4 :     EQ_GL_CALL( bindFrameBuffer( ));
     489           4 :     Compositor::resetAssemblyState();
     490           4 : }
     491             : 
     492          28 : void Channel::_overrideContext( RenderContext& context )
     493             : {
     494          28 :     overrideContext( context );
     495          28 :     Window* window = getWindow();
     496          28 :     window->_addRenderContext( context );
     497          28 : }
     498             : 
     499           0 : Frustumf Channel::getScreenFrustum() const
     500             : {
     501           0 :     const Pixel& pixel = getPixel();
     502           0 :     PixelViewport pvp( getPixelViewport( ));
     503           0 :     const Viewport& vp( getViewport( ));
     504             : 
     505           0 :     pvp.x = static_cast<int32_t>( pvp.w / vp.w * vp.x );
     506           0 :     pvp.y = static_cast<int32_t>( pvp.h / vp.h * vp.y );
     507           0 :     pvp.unapply( pixel );
     508             : 
     509             :     return eq::Frustumf( static_cast< float >( pvp.x ),
     510           0 :                          static_cast< float >( pvp.getXEnd( )),
     511             :                          static_cast< float >( pvp.y ),
     512           0 :                          static_cast< float >( pvp.getYEnd( )),
     513           0 :                          -1.f, 1.f );
     514             : }
     515             : 
     516           0 : util::FrameBufferObject* Channel::getFrameBufferObject()
     517             : {
     518           0 :     return _impl->fbo;
     519             : }
     520             : 
     521           0 : View* Channel::getView()
     522             : {
     523           0 :     LB_TS_THREAD( _pipeThread );
     524           0 :     Pipe* pipe = getPipe();
     525           0 :     return pipe->getView( getContext().view );
     526             : }
     527             : 
     528           1 : const View* Channel::getView() const
     529             : {
     530           1 :     LB_TS_THREAD( _pipeThread );
     531           1 :     const Pipe* pipe = getPipe();
     532           1 :     return pipe->getView( getContext().view );
     533             : }
     534             : 
     535           0 : co::QueueSlave* Channel::_getQueue( const uint128_t& queueID )
     536             : {
     537           0 :     LB_TS_THREAD( _pipeThread );
     538           0 :     Pipe* pipe = getPipe();
     539           0 :     return pipe->getQueue( queueID );
     540             : }
     541             : 
     542           0 : View* Channel::getNativeView()
     543             : {
     544           0 :     LB_TS_THREAD( _pipeThread );
     545           0 :     Pipe* pipe = getPipe();
     546           0 :     return pipe->getView( getNativeContext().view );
     547             : }
     548             : 
     549           0 : const View* Channel::getNativeView() const
     550             : {
     551           0 :     LB_TS_THREAD( _pipeThread );
     552           0 :     const Pipe* pipe = getPipe();
     553           0 :     return pipe->getView( getNativeContext().view );
     554             : }
     555             : 
     556          15 : void Channel::changeLatency( const uint32_t latency )
     557             : {
     558             : #ifndef NDEBUG
     559          45 :     for( detail::Channel::StatisticsRBCIter i = _impl->statistics->begin();
     560          30 :          i != _impl->statistics->end(); ++i )
     561             :     {
     562           0 :         LBASSERT( (*i).used == 0 );
     563             :     }
     564             : #endif //NDEBUG
     565          15 :     _impl->statistics->resize( latency + 1 );
     566          15 : }
     567             : 
     568             : //---------------------------------------------------------------------------
     569             : // apply convenience methods
     570             : //---------------------------------------------------------------------------
     571           0 : void Channel::applyFrameBufferObject()
     572             : {
     573           0 :     LB_TS_THREAD( _pipeThread );
     574           0 :     if( _impl->fbo )
     575             :     {
     576           0 :         const PixelViewport& pvp = getNativePixelViewport();
     577           0 :         const Error error = _impl->fbo->resize( pvp.w, pvp.h );
     578           0 :         if( error )
     579           0 :             sendError( error );
     580           0 :         _impl->fbo->bind();
     581             :     }
     582           0 :     else if( GLEW_EXT_framebuffer_object )
     583           0 :         glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
     584           0 : }
     585             : 
     586          17 : void Channel::applyBuffer()
     587             : {
     588          17 :     LB_TS_THREAD( _pipeThread );
     589          17 :     const Window* window = getWindow();
     590          17 :     if( !_impl->fbo && window->getSystemWindow()->getFrameBufferObject() == 0 )
     591             :     {
     592          12 :         EQ_GL_CALL( glReadBuffer( getReadBuffer( )));
     593          12 :         EQ_GL_CALL( glDrawBuffer( getDrawBuffer( )));
     594             :     }
     595             : 
     596          17 :     applyColorMask();
     597          17 : }
     598             : 
     599          15 : void Channel::bindFrameBuffer()
     600             : {
     601          15 :     LB_TS_THREAD( _pipeThread );
     602          15 :     const Window* window = getWindow();
     603          15 :     if( !window->getSystemWindow( ))
     604          15 :        return;
     605             : 
     606          15 :    if( _impl->fbo )
     607           0 :        applyFrameBufferObject();
     608             :    else
     609          15 :        window->bindFrameBuffer();
     610             : }
     611             : 
     612          17 : void Channel::applyColorMask() const
     613             : {
     614          17 :     LB_TS_THREAD( _pipeThread );
     615          17 :     const ColorMask& colorMask = getDrawBufferMask();
     616          17 :     glColorMask( colorMask.red, colorMask.green, colorMask.blue, true );
     617          17 : }
     618             : 
     619          17 : void Channel::applyViewport() const
     620             : {
     621          17 :     LB_TS_THREAD( _pipeThread );
     622          17 :     const PixelViewport& pvp = getPixelViewport();
     623             : 
     624          17 :     if( !pvp.hasArea( ))
     625             :     {
     626           0 :         LBERROR << "Can't apply viewport " << pvp << std::endl;
     627          17 :         return;
     628             :     }
     629             : 
     630          17 :     EQ_GL_CALL( glViewport( pvp.x, pvp.y, pvp.w, pvp.h ));
     631          17 :     EQ_GL_CALL( glScissor( pvp.x, pvp.y, pvp.w, pvp.h ));
     632             : }
     633             : 
     634           4 : void Channel::applyFrustum() const
     635             : {
     636           4 :     LB_TS_THREAD( _pipeThread );
     637           4 :     if( useOrtho( ))
     638           0 :         applyOrtho();
     639             :     else
     640           4 :         applyPerspective();
     641           4 : }
     642             : 
     643           4 : void Channel::applyPerspective() const
     644             : {
     645           4 :     LB_TS_THREAD( _pipeThread );
     646           4 :     Frustumf frustum = getPerspective();
     647           4 :     const Vector2f jitter = getJitter();
     648             : 
     649           4 :     frustum.apply_jitter( jitter );
     650           4 :     EQ_GL_CALL( glFrustum( frustum.left(), frustum.right(),
     651             :                            frustum.bottom(), frustum.top(),
     652           4 :                            frustum.near_plane(), frustum.far_plane() ));
     653           4 : }
     654             : 
     655           0 : void Channel::applyOrtho() const
     656             : {
     657           0 :     LB_TS_THREAD( _pipeThread );
     658           0 :     Frustumf ortho = getOrtho();
     659           0 :     const Vector2f jitter = getJitter();
     660             : 
     661           0 :     ortho.apply_jitter( jitter );
     662           0 :     EQ_GL_CALL( glOrtho( ortho.left(), ortho.right(),
     663             :                          ortho.bottom(), ortho.top(),
     664           0 :                          ortho.near_plane(), ortho.far_plane() ));
     665           0 : }
     666             : 
     667           0 : void Channel::applyScreenFrustum() const
     668             : {
     669           0 :     LB_TS_THREAD( _pipeThread );
     670           0 :     const Frustumf frustum = getScreenFrustum();
     671           0 :     EQ_GL_CALL( glOrtho( frustum.left(), frustum.right(),
     672             :                          frustum.bottom(), frustum.top(),
     673           0 :                          frustum.near_plane(), frustum.far_plane() ));
     674           0 : }
     675             : 
     676           4 : void Channel::applyHeadTransform() const
     677             : {
     678           4 :     LB_TS_THREAD( _pipeThread );
     679           4 :     if( useOrtho( ))
     680           0 :         applyOrthoTransform();
     681             :     else
     682           4 :         applyPerspectiveTransform();
     683           4 : }
     684             : 
     685           4 : void Channel::applyPerspectiveTransform() const
     686             : {
     687           4 :     LB_TS_THREAD( _pipeThread );
     688           4 :     const Matrix4f& xfm = getPerspectiveTransform();
     689           4 :     EQ_GL_CALL( glMultMatrixf( xfm.array ));
     690           4 : }
     691             : 
     692           0 : void Channel::applyOrthoTransform() const
     693             : {
     694           0 :     LB_TS_THREAD( _pipeThread );
     695           0 :     const Matrix4f& xfm = getOrthoTransform();
     696           0 :     EQ_GL_CALL( glMultMatrixf( xfm.array ));
     697           0 : }
     698             : 
     699             : namespace
     700             : {
     701           0 : static Vector2f* _lookupJitterTable( const uint32_t size )
     702             : {
     703           0 :     switch( size )
     704             :     {
     705             :         case 2:
     706           0 :             return Jitter::j2;
     707             :         case 3:
     708           0 :             return Jitter::j3;
     709             :         case 4:
     710           0 :             return Jitter::j4;
     711             :         case 8:
     712           0 :             return Jitter::j8;
     713             :         case 15:
     714           0 :             return Jitter::j15;
     715             :         case 24:
     716           0 :             return Jitter::j24;
     717             :         case 66:
     718           0 :             return Jitter::j66;
     719             :         default:
     720           0 :             break;
     721             :     }
     722           0 :     return 0;
     723             : }
     724             : }
     725             : 
     726           4 : Vector2f Channel::getJitter() const
     727             : {
     728           4 :     const SubPixel& subpixel = getSubPixel();
     729           4 :     if( subpixel == SubPixel::ALL )
     730           4 :         return Vector2f::ZERO;
     731             : 
     732             :     // Compute a pixel size
     733           0 :     const PixelViewport& pvp = getPixelViewport();
     734           0 :     const float pvp_w = static_cast<float>( pvp.w );
     735           0 :     const float pvp_h = static_cast<float>( pvp.h );
     736             : 
     737           0 :     const Frustumf& frustum = getFrustum();
     738           0 :     const float frustum_w = frustum.get_width();
     739           0 :     const float frustum_h = frustum.get_height();
     740             : 
     741           0 :     const float pixel_w = frustum_w / pvp_w;
     742           0 :     const float pixel_h = frustum_h / pvp_h;
     743             : 
     744           0 :     const Vector2f pixelSize( pixel_w, pixel_h );
     745             : 
     746           0 :     Vector2f* table = _lookupJitterTable( subpixel.size );
     747           0 :     Vector2f jitter;
     748           0 :     if( !table )
     749             :     {
     750           0 :         static lunchbox::RNG rng;
     751           0 :         jitter.x() = rng.get< float >();
     752           0 :         jitter.y() = rng.get< float >();
     753             :     }
     754             :     else
     755           0 :         jitter = table[ subpixel.index ];
     756             : 
     757           0 :     const Pixel& pixel = getPixel();
     758           0 :     jitter.x() /= static_cast<float>( pixel.w );
     759           0 :     jitter.y() /= static_cast<float>( pixel.h );
     760             : 
     761           0 :     return jitter * pixelSize;
     762             : }
     763             : 
     764          15 : bool Channel::isStopped() const { return _impl->state == STATE_STOPPED; }
     765             : 
     766           0 : const Vector3ub& Channel::getUniqueColor() const { return _impl->color; }
     767             : 
     768          16 : void Channel::resetRegions()
     769             : {
     770          16 :     _impl->regions.clear();
     771          16 : }
     772             : 
     773           0 : void Channel::declareRegion( const eq::Viewport& vp )
     774             : {
     775           0 :     eq::PixelViewport region = getPixelViewport();
     776           0 :     region.x = 0;
     777           0 :     region.y = 0;
     778             : 
     779           0 :     region.apply( vp );
     780           0 :     declareRegion( region );
     781           0 : }
     782             : 
     783             : namespace
     784             : {
     785             : 
     786             : #ifndef NDEBUG
     787           7 : bool _hasOverlap( PixelViewports& regions )
     788             : {
     789           7 :     if( regions.size() < 2 )
     790           7 :         return false;
     791             : 
     792           0 :     for( size_t i = 0; i < regions.size()-1; ++i )
     793           0 :         for( size_t j = i+1; j < regions.size(); ++j )
     794             :         {
     795           0 :             PixelViewport pv = regions[j];
     796           0 :             pv.intersect( regions[i] );
     797           0 :             if( pv.hasArea( ))
     798           0 :                 return true;
     799             :         }
     800           0 :     return false;
     801             : }
     802             : #endif
     803             : 
     804             : /** Remove overlapping regions by merging them */
     805           7 : bool _removeOverlap( PixelViewports& regions )
     806             : {
     807           7 :     if( regions.size() < 2 )
     808           7 :         return false;
     809             : 
     810           0 :     for( size_t i = 0; i < regions.size()-1; ++i )
     811           0 :         for( size_t j = i+1; j < regions.size(); ++j )
     812             :         {
     813           0 :             PixelViewport pvp = regions[i];
     814           0 :             if( !pvp.hasArea( ))
     815             :             {
     816           0 :                 std::swap( regions[i], regions.back() );
     817           0 :                 regions.pop_back();
     818           0 :                 return true;
     819             :             }
     820             : 
     821           0 :             pvp.intersect( regions[j] );
     822           0 :             if( pvp.hasArea( ))
     823             :             {
     824           0 :                 regions[i].merge( regions[j] );
     825           0 :                 std::swap( regions[j], regions.back() );
     826           0 :                 regions.pop_back();
     827           0 :                 return true;
     828             :             }
     829             :         }
     830           0 :     return false;
     831             : }
     832             : }
     833             : 
     834           7 : void Channel::declareRegion( const PixelViewport& region )
     835             : {
     836           7 :     PixelViewports& regions = _impl->regions;
     837             : 
     838           7 :     PixelViewport clippedRegion = region;
     839           7 :     PixelViewport pvp = getPixelViewport();
     840           7 :     pvp.x = 0;
     841           7 :     pvp.y = 0;
     842             : 
     843           7 :     clippedRegion.intersect( pvp );
     844             : 
     845           7 :     if( clippedRegion.hasArea( ))
     846             :     {
     847           7 :         regions.push_back( clippedRegion );
     848             : #ifndef NDEBUG
     849           7 :         const PixelViewport pvpBefore = getRegion();
     850             : #endif
     851           7 :         while( _removeOverlap( regions )) { /* nop */ }
     852             : 
     853             : #ifndef NDEBUG
     854           7 :         LBASSERT( !_hasOverlap( regions ));
     855           7 :         LBASSERT( pvpBefore == getRegion( ));
     856             : #endif
     857          14 :         return;
     858             :     }
     859             : 
     860           0 :     if( regions.empty( )) // set on first declaration of empty ROI
     861           0 :         regions.push_back( PixelViewport( 0, 0, 0, 0 ));
     862             : }
     863             : 
     864             : 
     865          26 : PixelViewport Channel::getRegion() const
     866             : {
     867          26 :     PixelViewport region;
     868          47 :     for( size_t i = 0; i < _impl->regions.size(); ++i )
     869          21 :         region.merge( _impl->regions[i] );
     870             : 
     871          26 :     return region;
     872             : }
     873             : 
     874           2 : const PixelViewports& Channel::getRegions() const
     875             : {
     876           2 :     return _impl->regions;
     877             : }
     878             : 
     879           0 : EventOCommand Channel::sendError( const uint32_t error )
     880             : {
     881           0 :     return getConfig()->sendError( Event::CHANNEL_ERROR, getID(), error );
     882             : }
     883             : 
     884          55 : bool Channel::processEvent( const Event& event )
     885             : {
     886          55 :     ConfigEvent configEvent;
     887          55 :     configEvent.data = event;
     888             : 
     889          55 :     switch( event.type )
     890             :     {
     891             :         case Event::CHANNEL_POINTER_MOTION:
     892             :         case Event::CHANNEL_POINTER_BUTTON_PRESS:
     893             :         case Event::CHANNEL_POINTER_BUTTON_RELEASE:
     894             :         case Event::CHANNEL_POINTER_WHEEL:
     895             :         case Event::STATISTIC:
     896             :         case Event::KEY_PRESS:
     897             :         case Event::KEY_RELEASE:
     898          32 :             break;
     899             : 
     900             :         case Event::CHANNEL_RESIZE:
     901             :         {
     902          23 :             const uint128_t& viewID = getNativeContext().view.identifier;
     903          23 :             if( viewID == 0 )
     904          23 :                 return true;
     905             : 
     906             :             // transform to view event, which is meaningful for the config
     907           0 :             configEvent.data.type       = Event::VIEW_RESIZE;
     908           0 :             configEvent.data.originator = viewID;
     909             : 
     910           0 :             ResizeEvent& resize = configEvent.data.resize;
     911           0 :             resize.dw = resize.w / float( _impl->initialSize.x( ));
     912           0 :             resize.dh = resize.h / float( _impl->initialSize.y( ));
     913           0 :             break;
     914             :         }
     915             : 
     916             :         default:
     917           0 :             LBWARN << "Unhandled channel event of type " << event.type
     918           0 :                    << std::endl;
     919           0 :             LBUNIMPLEMENTED;
     920             :     }
     921             : 
     922          32 :     Config* config = getConfig();
     923          32 :     config->sendEvent( configEvent );
     924          32 :     return true;
     925             : }
     926             : 
     927           0 : void Channel::drawStatistics()
     928             : {
     929           0 :     const PixelViewport& pvp = getPixelViewport();
     930           0 :     LBASSERT( pvp.hasArea( ));
     931           0 :     if( !pvp.hasArea( ))
     932           0 :         return;
     933             : 
     934             :     //----- setup
     935           0 :     EQ_GL_CALL( applyBuffer( ));
     936           0 :     EQ_GL_CALL( applyViewport( ));
     937           0 :     EQ_GL_CALL( setupAssemblyState( ));
     938             : 
     939           0 :     glMatrixMode( GL_PROJECTION );
     940           0 :     glLoadIdentity();
     941           0 :     applyScreenFrustum();
     942             : 
     943           0 :     glMatrixMode( GL_MODELVIEW );
     944           0 :     glDisable( GL_LIGHTING );
     945             : 
     946           0 :     glEnable( GL_BLEND );
     947           0 :     glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
     948           0 :     glDisable( GL_COLOR_LOGIC_OP );
     949             : 
     950           0 :     Window* window = getWindow();
     951             : 
     952             : #ifdef EQUALIZER_USE_GLSTATS
     953           0 :     const util::BitmapFont* font = window->getSmallFont();
     954           0 :     const Config* config = getConfig();
     955           0 :     const GLStats::Data& data = config->getStatistics();
     956           0 :     detail::StatsRenderer renderer( font );
     957           0 :     const Viewport& vp = getViewport();
     958           0 :     const uint32_t width = uint32_t( pvp.w / vp.w );
     959           0 :     const uint32_t height = uint32_t( pvp.h / vp.h);
     960             : 
     961           0 :     renderer.setViewport( width, height );
     962           0 :     renderer.draw( data );
     963             : #endif
     964             : 
     965           0 :     glColor3f( 1.f, 1.f, 1.f );
     966           0 :     window->drawFPS();
     967           0 :     EQ_GL_CALL( resetAssemblyState( ));
     968             : }
     969             : 
     970           0 : void Channel::outlineViewport()
     971             : {
     972           0 :     setupAssemblyState();
     973           0 :     glDisable( GL_LIGHTING );
     974             : 
     975           0 :     const eq::PixelViewport& region = getRegion();
     976           0 :     glColor3f( .5f, .5f, .5f );
     977           0 :     glBegin( GL_LINE_LOOP ); {
     978           0 :         glVertex3f( region.x + .5f,         region.y + .5f,         0.f );
     979           0 :         glVertex3f( region.getXEnd() - .5f, region.y + .5f,         0.f );
     980           0 :         glVertex3f( region.getXEnd() - .5f, region.getYEnd() - .5f, 0.f );
     981           0 :         glVertex3f( region.x + .5f,         region.getYEnd() - .5f, 0.f );
     982           0 :     } glEnd();
     983             : 
     984           0 :     const PixelViewport& pvp = getPixelViewport();
     985           0 :     glColor3f( 1.0f, 1.0f, 1.0f );
     986           0 :     glBegin( GL_LINE_LOOP ); {
     987           0 :         glVertex3f( pvp.x + .5f,         pvp.y + .5f,         0.f );
     988           0 :         glVertex3f( pvp.getXEnd() - .5f, pvp.y + .5f,         0.f );
     989           0 :         glVertex3f( pvp.getXEnd() - .5f, pvp.getYEnd() - .5f, 0.f );
     990           0 :         glVertex3f( pvp.x + .5f,         pvp.getYEnd() - .5f, 0.f );
     991           0 :     } glEnd();
     992             : 
     993           0 :     resetAssemblyState();
     994           0 : }
     995             : 
     996             : namespace detail
     997             : {
     998           2 : struct RBStat
     999             : {
    1000           2 :     RBStat( eq::Channel* channel )
    1001             :             : event( Statistic::CHANNEL_READBACK, channel )
    1002             :             , uncompressed( 0 )
    1003           2 :             , compressed( 0 )
    1004             :         {
    1005           2 :             event.event.data.statistic.plugins[0] = EQ_COMPRESSOR_NONE;
    1006           2 :             event.event.data.statistic.plugins[1] = EQ_COMPRESSOR_NONE;
    1007           2 :             LBASSERT( event.event.data.statistic.frameNumber > 0 );
    1008           2 :         }
    1009             : 
    1010             :     lunchbox::SpinLock lock;
    1011             :     ChannelStatistics event;
    1012             :     size_t uncompressed;
    1013             :     size_t compressed;
    1014             : 
    1015           4 :     void ref( void* ) { ++_refCount; }
    1016           4 :     bool unref( void* )
    1017             :         {
    1018           4 :             if( --_refCount > 0 )
    1019           2 :                 return false;
    1020             : 
    1021           2 :             if( uncompressed > 0 && compressed > 0 )
    1022           2 :                 event.event.data.statistic.ratio = float( compressed ) /
    1023           2 :                                                    float( uncompressed );
    1024             :             else
    1025           0 :                 event.event.data.statistic.ratio = 1.0f;
    1026           2 :             delete this;
    1027           2 :             return true;
    1028             :         }
    1029             : 
    1030             :     int32_t getRefCount() const { return _refCount; }
    1031             : 
    1032             : private:
    1033             :     a_int32_t _refCount;
    1034             : };
    1035             : }
    1036             : 
    1037             : typedef lunchbox::RefPtr< detail::RBStat > RBStatPtr;
    1038             : 
    1039           0 : void Channel::_frameTiles( RenderContext& context, const bool isLocal,
    1040             :                            const uint128_t& queueID, const uint32_t tasks,
    1041             :                            const co::ObjectVersions& frameIDs )
    1042             : {
    1043           0 :     _overrideContext( context );
    1044             : 
    1045           0 :     frameTilesStart( context.frameID );
    1046             : 
    1047           0 :     RBStatPtr stat;
    1048           0 :     Frames frames;
    1049           0 :     if( tasks & fabric::TASK_READBACK )
    1050             :     {
    1051           0 :         frames = _getFrames( frameIDs, true );
    1052           0 :         stat = new detail::RBStat( this );
    1053             :     }
    1054             : 
    1055           0 :     int64_t startTime = getConfig()->getTime();
    1056           0 :     int64_t clearTime = 0;
    1057           0 :     int64_t drawTime = 0;
    1058           0 :     int64_t readbackTime = 0;
    1059           0 :     bool hasAsyncReadback = false;
    1060           0 :     const uint32_t timeout = getConfig()->getTimeout();
    1061             : 
    1062           0 :     co::QueueSlave* queue = _getQueue( queueID );
    1063           0 :     LBASSERT( queue );
    1064             :     for( ;; )
    1065             :     {
    1066           0 :         co::ObjectICommand tileCmd = queue->pop( timeout );
    1067           0 :         if( !tileCmd.isValid( ))
    1068           0 :             break;
    1069             : 
    1070           0 :         const Tile& tile = tileCmd.read< Tile >();
    1071           0 :         context.apply( tile );
    1072             : 
    1073           0 :         const PixelViewport tilePVP = context.pvp;
    1074             : 
    1075           0 :         if ( !isLocal )
    1076             :         {
    1077           0 :             context.pvp.x = 0;
    1078           0 :             context.pvp.y = 0;
    1079             :         }
    1080             : 
    1081           0 :         if( tasks & fabric::TASK_CLEAR )
    1082             :         {
    1083           0 :             const int64_t time = getConfig()->getTime();
    1084           0 :             frameClear( context.frameID );
    1085           0 :             clearTime += getConfig()->getTime() - time;
    1086             :         }
    1087             : 
    1088           0 :         if( tasks & fabric::TASK_DRAW )
    1089             :         {
    1090           0 :             const int64_t time = getConfig()->getTime();
    1091           0 :             frameDraw( context.frameID );
    1092           0 :             drawTime += getConfig()->getTime() - time;
    1093             :         }
    1094             : 
    1095           0 :         if( tasks & fabric::TASK_READBACK )
    1096             :         {
    1097           0 :             const int64_t time = getConfig()->getTime();
    1098           0 :             const size_t nFrames = frames.size();
    1099             : 
    1100           0 :             std::vector< size_t > nImages( nFrames, 0 );
    1101           0 :             for( size_t i = 0; i < nFrames; ++i )
    1102             :             {
    1103           0 :                 nImages[i] = frames[i]->getImages().size();
    1104           0 :                 frames[i]->getFrameData()->setPixelViewport(
    1105           0 :                     getPixelViewport( ));
    1106             :             }
    1107             : 
    1108           0 :             frameReadback( context.frameID, frames );
    1109           0 :             readbackTime += getConfig()->getTime() - time;
    1110             : 
    1111           0 :             for( size_t i = 0; i < nFrames; ++i )
    1112             :             {
    1113           0 :                 const Frame* frame = frames[i];
    1114           0 :                 const Images& images = frame->getImages();
    1115           0 :                 for( size_t j = nImages[i]; j < images.size(); ++j )
    1116             :                 {
    1117           0 :                     Image* image = images[j];
    1118           0 :                     const PixelViewport& pvp = image->getPixelViewport();
    1119             :                     image->setOffset( pvp.x + tilePVP.x,
    1120           0 :                                       pvp.y + tilePVP.y );
    1121             :                 }
    1122             :             }
    1123             : 
    1124           0 :             if( _asyncFinishReadback( nImages, frames ))
    1125           0 :                 hasAsyncReadback = true;
    1126             :         }
    1127           0 :     }
    1128             : 
    1129           0 :     if( tasks & fabric::TASK_CLEAR )
    1130             :     {
    1131           0 :         ChannelStatistics event( Statistic::CHANNEL_CLEAR, this );
    1132           0 :         event.event.data.statistic.startTime = startTime;
    1133           0 :         startTime += clearTime;
    1134           0 :         event.event.data.statistic.endTime = startTime;
    1135             :     }
    1136             : 
    1137           0 :     if( tasks & fabric::TASK_DRAW )
    1138             :     {
    1139           0 :         ChannelStatistics event( Statistic::CHANNEL_DRAW, this );
    1140           0 :         event.event.data.statistic.startTime = startTime;
    1141           0 :         startTime += drawTime;
    1142           0 :         event.event.data.statistic.endTime = startTime;
    1143             :     }
    1144             : 
    1145           0 :     if( tasks & fabric::TASK_READBACK )
    1146             :     {
    1147           0 :         stat->event.event.data.statistic.startTime = startTime;
    1148           0 :         startTime += readbackTime;
    1149           0 :         stat->event.event.data.statistic.endTime = startTime;
    1150             : 
    1151           0 :         _setReady( hasAsyncReadback, stat.get(), frames );
    1152             :     }
    1153             : 
    1154           0 :     frameTilesFinish( context.frameID );
    1155           0 :     resetContext();
    1156           0 : }
    1157             : 
    1158           6 : void Channel::_refFrame( const uint32_t frameNumber )
    1159             : {
    1160           6 :     const size_t index = frameNumber % _impl->statistics->size();
    1161           6 :     detail::Channel::FrameStatistics& stats = _impl->statistics.data[ index ];
    1162           6 :     LBASSERTINFO( stats.used > 0, frameNumber );
    1163           6 :     ++stats.used;
    1164           6 : }
    1165             : 
    1166          13 : void Channel::_unrefFrame( const uint32_t frameNumber )
    1167             : {
    1168          13 :     const size_t index = frameNumber % _impl->statistics->size();
    1169          13 :     detail::Channel::FrameStatistics& stats = _impl->statistics.data[ index ];
    1170          13 :     if( --stats.used != 0 ) // Frame still in use
    1171          19 :         return;
    1172             : 
    1173             :     send( getServer(), fabric::CMD_CHANNEL_FRAME_FINISH_REPLY )
    1174           7 :             << stats.region << frameNumber << stats.data;
    1175             : 
    1176           7 :     stats.data.clear();
    1177           7 :     stats.region = Viewport::FULL;
    1178             : 
    1179           7 :     _impl->finishedFrame = frameNumber;
    1180             : }
    1181             : 
    1182           4 : Frames Channel::_getFrames( const co::ObjectVersions& frameIDs,
    1183             :                             const bool isOutput )
    1184             : {
    1185           4 :     LB_TS_THREAD( _pipeThread );
    1186             : 
    1187           4 :     Frames frames;
    1188           8 :     for( size_t i = 0; i < frameIDs.size(); ++i )
    1189             :     {
    1190           4 :         Pipe*  pipe  = getPipe();
    1191           4 :         Frame* frame = pipe->getFrame( frameIDs[i], getEye(), isOutput );
    1192           4 :         LBASSERTINFO( lunchbox::find( frames, frame ) == frames.end(),
    1193             :                       "frame " << i << " " << frameIDs[i] );
    1194             : 
    1195           4 :         frames.push_back( frame );
    1196             :     }
    1197             : 
    1198           4 :     return frames;
    1199             : }
    1200             : 
    1201             : //---------------------------------------------------------------------------
    1202             : // Asynchronous image readback, compression and transmission
    1203             : //---------------------------------------------------------------------------
    1204           2 : void Channel::_frameReadback( const uint128_t& frameID,
    1205             :                               const co::ObjectVersions& frameIDs )
    1206             : {
    1207           2 :     LB_TS_THREAD( _pipeThread );
    1208             : 
    1209           2 :     RBStatPtr stat = new detail::RBStat( this );
    1210           4 :     const Frames& frames = _getFrames( frameIDs, true );
    1211             : 
    1212           4 :     std::vector< size_t > nImages( frames.size(), 0 );
    1213           4 :     for( size_t i = 0; i < frames.size(); ++i )
    1214           2 :         nImages[i] = frames[i]->getImages().size();
    1215             : 
    1216           2 :     frameReadback( frameID, frames );
    1217           2 :     LBASSERT( stat->event.event.data.statistic.frameNumber > 0 );
    1218           2 :     const bool async = _asyncFinishReadback( nImages, frames );
    1219           4 :     _setReady( async, stat.get(), frames );
    1220           2 : }
    1221             : 
    1222           2 : bool Channel::_asyncFinishReadback( const std::vector< size_t >& imagePos,
    1223             :                                     const Frames& frames )
    1224             : {
    1225           2 :     LB_TS_THREAD( _pipeThread );
    1226             : 
    1227           2 :     bool hasAsyncReadback = false;
    1228           2 :     LBASSERT( frames.size() == imagePos.size( ));
    1229             : 
    1230           4 :     for( size_t i = 0; i < frames.size(); ++i )
    1231             :     {
    1232           2 :         Frame* frame = frames[i];
    1233           2 :         FrameDataPtr frameData = frame->getFrameData();
    1234           2 :         const uint32_t frameNumber = getCurrentFrame();
    1235             : 
    1236           2 :         if( frameData->getBuffers() == 0 )
    1237           0 :             continue;
    1238             : 
    1239           2 :         const Images& images = frameData->getImages();
    1240           2 :         const size_t nImages = images.size();
    1241           2 :         const Eye eye = getEye();
    1242           2 :         const std::vector< uint128_t >& nodes = frame->getInputNodes( eye );
    1243           2 :         const co::NodeIDs& netNodes = frame->getInputNetNodes(eye);
    1244             : 
    1245           4 :         for( uint64_t j = imagePos[i]; j < nImages; ++j )
    1246             :         {
    1247           2 :             if( images[j]->hasAsyncReadback( )) // finish async readback
    1248             :             {
    1249           2 :                 LBCHECK( getPipe()->startTransferThread( ));
    1250           2 :                 LBCHECK( getWindow()->createTransferWindow( ));
    1251             : 
    1252           2 :                 hasAsyncReadback = true;
    1253           2 :                 _refFrame( frameNumber );
    1254             : 
    1255             :                 send( getLocalNode(), fabric::CMD_CHANNEL_FINISH_READBACK )
    1256           4 :                         << co::ObjectVersion( frameData ) << j << frameNumber
    1257           6 :                         << getTaskID() << nodes << netNodes;
    1258             :             }
    1259             :             else // transmit images asynchronously
    1260             :                 _asyncTransmit( frameData, frameNumber, j, nodes, netNodes,
    1261           0 :                                 getTaskID( ));
    1262             :         }
    1263           2 :     }
    1264           2 :     return hasAsyncReadback;
    1265             : }
    1266             : 
    1267           2 : void Channel::_finishReadback( const co::ObjectVersion& frameDataVersion,
    1268             :                                const uint64_t imageIndex,
    1269             :                                const uint32_t frameNumber,
    1270             :                                const uint32_t taskID,
    1271             :                                const std::vector< uint128_t >& nodes,
    1272             :                                const co::NodeIDs& netNodes )
    1273             : {
    1274           2 :     LBLOG( LOG_TASKS|LOG_ASSEMBLY ) << "Finish readback" << std::endl;
    1275           2 :     FrameDataPtr frameData = getNode()->getFrameData( frameDataVersion );
    1276           2 :     const Images& images = frameData->getImages();
    1277           2 :     Image* image = images[ imageIndex ];
    1278           2 :     const GLEWContext* glewContext = getWindow()->getTransferGlewContext();
    1279             : 
    1280           2 :     LBASSERT( frameData );
    1281           2 :     LBASSERT( images.size() > imageIndex );
    1282           2 :     LBASSERT( image->hasAsyncReadback( ));
    1283             : 
    1284           2 :     image->finishReadback( glewContext );
    1285           2 :     LBASSERT( !image->hasAsyncReadback( ));
    1286             : 
    1287             :     // schedule async image tranmission
    1288             :     _asyncTransmit( frameData, frameNumber, imageIndex, nodes, netNodes,
    1289           2 :                     taskID );
    1290           2 : }
    1291             : 
    1292           2 : void Channel::_asyncTransmit( FrameDataPtr frame, const uint32_t frameNumber,
    1293             :                               const uint64_t image,
    1294             :                               const std::vector< uint128_t >& nodes,
    1295             :                               const co::NodeIDs& netNodes,
    1296             :                               const uint32_t taskID )
    1297             : {
    1298           2 :     LBASSERT( nodes.size() == netNodes.size( ));
    1299           2 :     co::NodeIDs::const_iterator j = netNodes.begin();
    1300           6 :     for( std::vector< uint128_t >::const_iterator i = nodes.begin();
    1301           4 :          i != nodes.end(); ++i, ++j )
    1302             :     {
    1303           0 :         _refFrame( frameNumber );
    1304             : 
    1305           0 :         LBLOG( LOG_TASKS|LOG_ASSEMBLY ) << "Start transmit frame data " << frame
    1306           0 :                                         << " receiver " << *i << " on " << *j
    1307           0 :                                         << std::endl;
    1308             :         send( getLocalNode(), fabric::CMD_CHANNEL_FRAME_TRANSMIT_IMAGE )
    1309           0 :                 << co::ObjectVersion( frame ) << *i << *j << image
    1310           0 :                 << frameNumber << taskID;
    1311             :     }
    1312           2 : }
    1313             : 
    1314           0 : void Channel::_transmitImage( const co::ObjectVersion& frameDataVersion,
    1315             :                               const uint128_t& nodeID,
    1316             :                               const co::NodeID& netNodeID,
    1317             :                               const uint64_t imageIndex,
    1318             :                               const uint32_t frameNumber,
    1319             :                               const uint32_t taskID )
    1320             : {
    1321           0 :     LBLOG( LOG_TASKS|LOG_ASSEMBLY ) << "Transmit" << std::endl;
    1322           0 :     FrameDataPtr frameData = getNode()->getFrameData( frameDataVersion );
    1323           0 :     LBASSERT( frameData );
    1324             : 
    1325           0 :     if( frameData->getBuffers() == 0 )
    1326             :     {
    1327           0 :         LBWARN << "No buffers for frame data" << std::endl;
    1328           0 :         return;
    1329             :     }
    1330             : 
    1331             :     ChannelStatistics transmitEvent( Statistic::CHANNEL_FRAME_TRANSMIT, this,
    1332           0 :                                      frameNumber );
    1333           0 :     transmitEvent.event.data.statistic.task = taskID;
    1334             : 
    1335           0 :     const Images& images = frameData->getImages();
    1336           0 :     Image* image = images[ imageIndex ];
    1337           0 :     LBASSERT( images.size() > imageIndex );
    1338             : 
    1339           0 :     if( image->getStorageType() == Frame::TYPE_TEXTURE )
    1340             :     {
    1341           0 :         LBWARN << "Can't transmit image of type TEXTURE" << std::endl;
    1342           0 :         LBUNIMPLEMENTED;
    1343           0 :         return;
    1344             :     }
    1345             : 
    1346           0 :     co::LocalNodePtr localNode = getLocalNode();
    1347           0 :     co::NodePtr toNode = localNode->connect( netNodeID );
    1348           0 :     if( !toNode || !toNode->isReachable( ))
    1349             :     {
    1350           0 :         LBWARN << "Can't connect node " << netNodeID << " to send output frame"
    1351           0 :                << std::endl;
    1352           0 :         return;
    1353             :     }
    1354             : 
    1355           0 :     co::ConnectionPtr connection = toNode->getConnection();
    1356           0 :     co::ConstConnectionDescriptionPtr description =connection->getDescription();
    1357             : 
    1358             :     // use compression on links up to 2 GBit/s
    1359           0 :     const bool useCompression = ( description->bandwidth <= 262144 );
    1360             : 
    1361           0 :     std::vector< const PixelData* > pixelDatas;
    1362           0 :     std::vector< float > qualities;
    1363             : 
    1364           0 :     uint32_t commandBuffers = Frame::BUFFER_NONE;
    1365           0 :     uint64_t imageDataSize = 0;
    1366             : 
    1367             :     {
    1368           0 :         uint64_t rawSize( 0 );
    1369             :         ChannelStatistics compressEvent( Statistic::CHANNEL_FRAME_COMPRESS,
    1370             :                                          this, frameNumber,
    1371           0 :                                          useCompression ? AUTO : OFF );
    1372           0 :         compressEvent.event.data.statistic.task = taskID;
    1373           0 :         compressEvent.event.data.statistic.ratio = 1.0f;
    1374           0 :         compressEvent.event.data.statistic.plugins[0] = EQ_COMPRESSOR_NONE;
    1375           0 :         compressEvent.event.data.statistic.plugins[1] = EQ_COMPRESSOR_NONE;
    1376             : 
    1377             :         // Prepare image pixel data
    1378           0 :         Frame::Buffer buffers[] = {Frame::BUFFER_COLOR,Frame::BUFFER_DEPTH};
    1379             : 
    1380             :         // for each image attachment
    1381           0 :         for( unsigned j = 0; j < 2; ++j )
    1382             :         {
    1383           0 :             Frame::Buffer buffer = buffers[j];
    1384           0 :             if( image->hasPixelData( buffer ))
    1385             :             {
    1386             :                 // format, type, nChunks, compressor name
    1387           0 :                 imageDataSize += sizeof( FrameData::ImageHeader );
    1388             : 
    1389             :                 const PixelData& data = useCompression ?
    1390             :                     image->compressPixelData( buffer ) :
    1391           0 :                     image->getPixelData( buffer );
    1392           0 :                 pixelDatas.push_back( &data );
    1393           0 :                 qualities.push_back( image->getQuality( buffer ));
    1394             : 
    1395           0 :                 if( data.compressedData.isCompressed( ))
    1396             :                 {
    1397           0 :                     imageDataSize += data.compressedData.getSize() +
    1398           0 :                         data.compressedData.chunks.size() * sizeof( uint64_t );
    1399             :                     compressEvent.event.data.statistic.plugins[j] =
    1400           0 :                         data.compressedData.compressor;
    1401             :                 }
    1402             :                 else
    1403           0 :                     imageDataSize += sizeof( uint64_t ) +
    1404           0 :                                      image->getPixelDataSize( buffer );
    1405             : 
    1406           0 :                 commandBuffers |= buffer;
    1407           0 :                 rawSize += image->getPixelDataSize( buffer );
    1408             :             }
    1409             :         }
    1410             : 
    1411           0 :         if( rawSize > 0 )
    1412             :             compressEvent.event.data.statistic.ratio =
    1413           0 :             static_cast< float >( imageDataSize ) /
    1414           0 :             static_cast< float >( rawSize );
    1415             :     }
    1416             : 
    1417           0 :     if( pixelDatas.empty( ))
    1418           0 :         return;
    1419             : 
    1420             :     // send image pixel data command
    1421           0 :     co::LocalNode::SendToken token;
    1422           0 :     if( getIAttribute( IATTR_HINT_SENDTOKEN ) == ON )
    1423             :     {
    1424             :         ChannelStatistics waitEvent( Statistic::CHANNEL_FRAME_WAIT_SENDTOKEN,
    1425           0 :                                      this, frameNumber );
    1426           0 :         waitEvent.event.data.statistic.task = taskID;
    1427           0 :         token = getLocalNode()->acquireSendToken( toNode );
    1428             :     }
    1429           0 :     LBASSERT( image->getPixelViewport().isValid( ));
    1430             : 
    1431             :     co::ObjectOCommand command( co::Connections( 1, connection ),
    1432             :                                 fabric::CMD_NODE_FRAMEDATA_TRANSMIT,
    1433             :                                 co::COMMANDTYPE_OBJECT, nodeID,
    1434           0 :                                 CO_INSTANCE_ALL );
    1435           0 :     command << frameDataVersion << image->getPixelViewport() << image->getZoom()
    1436           0 :             << commandBuffers << frameNumber << image->getAlphaUsage();
    1437           0 :     command.sendHeader( imageDataSize );
    1438             : 
    1439             : #ifndef NDEBUG
    1440           0 :     size_t sentBytes = 0;
    1441             : #endif
    1442             : 
    1443           0 :     for( uint32_t j=0; j < pixelDatas.size(); ++j )
    1444             :     {
    1445             : #ifndef NDEBUG
    1446           0 :         sentBytes += sizeof( FrameData::ImageHeader );
    1447             : #endif
    1448           0 :         const PixelData* data = pixelDatas[j];
    1449           0 :         const bool isCompressed = data->compressedData.isCompressed();
    1450             :         const uint32_t nChunks = isCompressed ?
    1451           0 :             uint32_t( data->compressedData.chunks.size( )) : 1;
    1452             : 
    1453             :         const FrameData::ImageHeader header =
    1454             :               { data->internalFormat, data->externalFormat,
    1455             :                 data->pixelSize, data->pvp,
    1456             :                 isCompressed ? data->compressedData.compressor :
    1457             :                                EQ_COMPRESSOR_NONE,
    1458           0 :                 data->compressorFlags, nChunks, qualities[ j ] };
    1459             : 
    1460           0 :         connection->send( &header, sizeof( header ), true );
    1461             : 
    1462           0 :         if( isCompressed )
    1463             :         {
    1464           0 :             BOOST_FOREACH( const lunchbox::CompressorChunk& chunk,
    1465             :                            data->compressedData.chunks )
    1466             :             {
    1467           0 :                 const uint64_t dataSize = chunk.getNumBytes();
    1468             : 
    1469           0 :                 connection->send( &dataSize, sizeof( dataSize ), true );
    1470           0 :                 if( dataSize > 0 )
    1471           0 :                     connection->send( chunk.data, dataSize, true );
    1472             : #ifndef NDEBUG
    1473           0 :                 sentBytes += sizeof( dataSize ) + dataSize;
    1474             : #endif
    1475             :             }
    1476             :         }
    1477             :         else
    1478             :         {
    1479           0 :             const uint64_t dataSize = data->pvp.getArea() * data->pixelSize;
    1480           0 :             connection->send( &dataSize, sizeof( dataSize ), true );
    1481           0 :             connection->send( data->pixels, dataSize, true );
    1482             : #ifndef NDEBUG
    1483           0 :             sentBytes += sizeof( dataSize ) + dataSize;
    1484             : #endif
    1485             :         }
    1486             :     }
    1487             : #ifndef NDEBUG
    1488           0 :     LBASSERTINFO( sentBytes == imageDataSize,
    1489           0 :         sentBytes << " != " << imageDataSize );
    1490             : #endif
    1491             : }
    1492             : 
    1493           2 : void Channel::_setReady( const bool async, detail::RBStat* stat,
    1494             :                          const Frames& frames )
    1495             : {
    1496           4 :     for( FramesCIter i = frames.begin(); i != frames.end(); ++i )
    1497             :     {
    1498           2 :         Frame* frame = *i;
    1499           2 :         const Eye eye = getEye();
    1500           2 :         const std::vector< uint128_t >& nodes = frame->getInputNodes( eye );
    1501           2 :         const co::NodeIDs& netNodes = frame->getInputNetNodes(eye);
    1502             : 
    1503           2 :         if( async )
    1504           2 :             _asyncSetReady( frame->getFrameData(), stat, nodes, netNodes );
    1505             :         else
    1506           0 :             _setReady( frame->getFrameData(), stat, nodes, netNodes );
    1507             :     }
    1508           2 : }
    1509             : 
    1510           2 : void Channel::_asyncSetReady( const FrameDataPtr frame, detail::RBStat* stat,
    1511             :                               const std::vector< uint128_t >& nodes,
    1512             :                               const co::NodeIDs& netNodes )
    1513             : {
    1514           2 :     LBASSERT( stat->event.event.data.statistic.frameNumber > 0 );
    1515             : 
    1516           2 :     stat->event.event.data.statistic.type = Statistic::CHANNEL_ASYNC_READBACK;
    1517             : 
    1518           2 :     _refFrame( stat->event.event.data.statistic.frameNumber );
    1519           2 :     stat->ref( 0 );
    1520             : 
    1521             :     send( getLocalNode(), fabric::CMD_CHANNEL_FRAME_SET_READY )
    1522           2 :             << co::ObjectVersion( frame ) << stat << nodes << netNodes;
    1523           2 : }
    1524             : 
    1525           2 : void Channel::_setReady( FrameDataPtr frame, detail::RBStat* stat,
    1526             :                          const std::vector< uint128_t >& nodes,
    1527             :                          const co::NodeIDs& netNodes )
    1528             : {
    1529           4 :     LBLOG( LOG_TASKS|LOG_ASSEMBLY ) << "Set ready " << co::ObjectVersion(frame)
    1530           6 :                                     << std::endl;
    1531           2 :     frame->setReady();
    1532             : 
    1533           2 :     const uint32_t frameNumber = stat->event.event.data.statistic.frameNumber;
    1534           2 :     _refFrame( frameNumber );
    1535             : 
    1536             :     send( getLocalNode(), fabric::CMD_CHANNEL_FRAME_SET_READY_NODE )
    1537           2 :             << co::ObjectVersion( frame ) << nodes << netNodes << frameNumber;
    1538             : 
    1539           2 :     const DrawableConfig& dc = getDrawableConfig();
    1540           2 :     const size_t colorBytes = ( 3 * dc.colorBits + dc.alphaBits ) / 8;
    1541             : 
    1542             :     {
    1543           2 :         lunchbox::ScopedFastWrite mutex( stat->lock );
    1544           2 :         const Images& images = frame->getImages();
    1545           4 :         for( ImagesCIter i = images.begin(); i != images.end(); ++i )
    1546             :         {
    1547           2 :             const Image* image = *i;
    1548           2 :             if( image->hasPixelData( Frame::BUFFER_COLOR ))
    1549             :             {
    1550             :                 stat->uncompressed +=
    1551           2 :                     colorBytes * image->getPixelViewport().getArea();
    1552             :                 stat->compressed +=
    1553           2 :                     image->getPixelDataSize( Frame::BUFFER_COLOR );
    1554             :                 stat->event.event.data.statistic.plugins[0] =
    1555           2 :                                 image->getDownloaderName( Frame::BUFFER_COLOR );
    1556             :             }
    1557           2 :             if( image->hasPixelData( Frame::BUFFER_DEPTH ))
    1558             :             {
    1559           0 :                 stat->uncompressed += 4 * image->getPixelViewport().getArea();
    1560           0 :                 stat->compressed +=image->getPixelDataSize(Frame::BUFFER_DEPTH);
    1561             :                 stat->event.event.data.statistic.plugins[1] =
    1562           0 :                                 image->getDownloaderName( Frame::BUFFER_DEPTH );
    1563             :             }
    1564           2 :         }
    1565             :     }
    1566           2 : }
    1567             : 
    1568          15 : void Channel::_deleteTransferContext()
    1569             : {
    1570          15 :     if( !getPipe()->hasTransferThread( ))
    1571          28 :         return;
    1572             : 
    1573           2 :     co::LocalNodePtr localNode = getLocalNode();
    1574             :     const lunchbox::Request< void >& request =
    1575           4 :         localNode->registerRequest< void >();
    1576           4 :     send( localNode, fabric::CMD_CHANNEL_DELETE_TRANSFER_CONTEXT ) << request;
    1577             : }
    1578             : 
    1579             : //---------------------------------------------------------------------------
    1580             : // command handlers
    1581             : //---------------------------------------------------------------------------
    1582          15 : bool Channel::_cmdConfigInit( co::ICommand& cmd )
    1583             : {
    1584          15 :     co::ObjectICommand command( cmd );
    1585             : 
    1586          15 :     LBLOG( LOG_INIT ) << "TASK channel config init " << command << std::endl;
    1587             : 
    1588          15 :     const Config* config = getConfig();
    1589          15 :     changeLatency( config->getLatency( ));
    1590             : 
    1591          15 :     bool result = false;
    1592          15 :     const Window* window = getWindow();
    1593          15 :     if( window->isRunning( ))
    1594             :     {
    1595          15 :         _impl->state = STATE_INITIALIZING;
    1596             : 
    1597          15 :         const PixelViewport& pvp = getPixelViewport();
    1598          15 :         LBASSERT( pvp.hasArea( ));
    1599          15 :         _impl->initialSize.x() = pvp.w;
    1600          15 :         _impl->initialSize.y() = pvp.h;
    1601          15 :         _impl->finishedFrame = window->getCurrentFrame();
    1602             : 
    1603          15 :         result = configInit( command.read< uint128_t >( ));
    1604             : 
    1605          15 :         if( result )
    1606             :         {
    1607          15 :             _initDrawableConfig();
    1608          15 :             _impl->state = STATE_RUNNING;
    1609             :         }
    1610             :     }
    1611             :     else
    1612           0 :         sendError( ERROR_CHANNEL_WINDOW_NOTRUNNING );
    1613             : 
    1614          15 :     LBLOG( LOG_INIT ) << "TASK channel config init reply " << result
    1615          15 :                       << std::endl;
    1616          15 :     commit();
    1617             :     send( command.getRemoteNode(), fabric::CMD_CHANNEL_CONFIG_INIT_REPLY )
    1618          15 :             << result;
    1619          15 :     return true;
    1620             : }
    1621             : 
    1622          15 : bool Channel::_cmdConfigExit( co::ICommand& cmd )
    1623             : {
    1624          30 :     LBLOG( LOG_INIT ) << "Exit channel " << co::ObjectICommand( cmd )
    1625          45 :                       << std::endl;
    1626             : 
    1627          15 :     _deleteTransferContext();
    1628             : 
    1629          15 :     if( _impl->state != STATE_STOPPED )
    1630          15 :         _impl->state = configExit() ? STATE_STOPPED : STATE_FAILED;
    1631             : 
    1632          15 :     getWindow()->send( getLocalNode(),
    1633          30 :                        fabric::CMD_WINDOW_DESTROY_CHANNEL ) << getID();
    1634          15 :     return true;
    1635             : }
    1636             : 
    1637           7 : bool Channel::_cmdFrameStart( co::ICommand& cmd )
    1638             : {
    1639           7 :     co::ObjectICommand command( cmd );
    1640             : 
    1641          14 :     RenderContext context = command.read< RenderContext >();
    1642           7 :     const uint128_t& version = command.read< uint128_t >();
    1643           7 :     const uint32_t frameNumber = command.read< uint32_t >();
    1644             : 
    1645           7 :     LBVERB << "handle channel frame start " << command << " " << context
    1646           7 :            << " frame " << frameNumber << std::endl;
    1647             : 
    1648             :     //_grabFrame( frameNumber ); single-threaded
    1649           7 :     sync( version );
    1650             : 
    1651           7 :     overrideContext( context );
    1652           7 :     bindFrameBuffer();
    1653           7 :     frameStart( context.frameID, frameNumber );
    1654             : 
    1655           7 :     const size_t index = frameNumber % _impl->statistics->size();
    1656           7 :     detail::Channel::FrameStatistics& statistic = _impl->statistics.data[index];
    1657           7 :     LBASSERTINFO( statistic.used == 0,
    1658             :                   "Frame " << frameNumber << " used " <<statistic.used);
    1659           7 :     LBASSERT( statistic.data.empty( ));
    1660           7 :     statistic.used = 1;
    1661             : 
    1662           7 :     resetContext();
    1663          14 :     return true;
    1664             : }
    1665             : 
    1666           7 : bool Channel::_cmdFrameFinish( co::ICommand& cmd )
    1667             : {
    1668           7 :     co::ObjectICommand command( cmd );
    1669             : 
    1670          14 :     RenderContext context = command.read< RenderContext >();
    1671           7 :     const uint32_t frameNumber = command.read< uint32_t >();
    1672             : 
    1673           7 :     LBLOG( LOG_TASKS ) << "TASK frame finish " << getName() <<  " " << command
    1674           7 :                        << " " << context << std::endl;
    1675             : 
    1676           7 :     overrideContext( context );
    1677           7 :     frameFinish( context.frameID, frameNumber );
    1678           7 :     resetContext();
    1679             : 
    1680           7 :     _unrefFrame( frameNumber );
    1681          14 :     return true;
    1682             : }
    1683             : 
    1684           9 : bool Channel::_cmdFrameClear( co::ICommand& cmd )
    1685             : {
    1686           9 :     LBASSERT( _impl->state == STATE_RUNNING );
    1687             : 
    1688           9 :     co::ObjectICommand command( cmd );
    1689          18 :     RenderContext context  = command.read< RenderContext >();
    1690             : 
    1691           9 :     LBLOG( LOG_TASKS ) << "TASK clear " << getName() <<  " " << command
    1692           9 :                        << " " << context << std::endl;
    1693             : 
    1694           9 :     _overrideContext( context );
    1695          18 :     ChannelStatistics event( Statistic::CHANNEL_CLEAR, this );
    1696           9 :     frameClear( context.frameID );
    1697           9 :     resetContext();
    1698             : 
    1699          18 :     return true;
    1700             : }
    1701             : 
    1702           5 : bool Channel::_cmdFrameDraw( co::ICommand& cmd )
    1703             : {
    1704           5 :     co::ObjectICommand command( cmd );
    1705          10 :     RenderContext context  = command.read< RenderContext >();
    1706           5 :     const bool finish = command.read< bool >();
    1707             : 
    1708           5 :     LBLOG( LOG_TASKS ) << "TASK draw " << getName() <<  " " << command
    1709           5 :                        << " " << context << std::endl;
    1710             : 
    1711           5 :     _overrideContext( context );
    1712           5 :     const uint32_t frameNumber = getCurrentFrame();
    1713             :     ChannelStatistics event( Statistic::CHANNEL_DRAW, this, frameNumber,
    1714          10 :                              finish ? NICEST : AUTO );
    1715             : 
    1716           5 :     frameDraw( context.frameID );
    1717             :     // Update ROI for server equalizers
    1718           5 :     if( !getRegion().isValid( ))
    1719           5 :         declareRegion( getPixelViewport( ));
    1720           5 :     const size_t index = frameNumber % _impl->statistics->size();
    1721           5 :     _impl->statistics.data[ index ].region = getRegion() / getPixelViewport();
    1722             : 
    1723           5 :     resetContext();
    1724             : 
    1725          10 :     return true;
    1726             : }
    1727             : 
    1728           7 : bool Channel::_cmdFrameDrawFinish( co::ICommand& cmd )
    1729             : {
    1730           7 :     co::ObjectICommand command( cmd );
    1731           7 :     const uint128_t& frameID = command.read< uint128_t >();
    1732           7 :     const uint32_t frameNumber = command.read< uint32_t >();
    1733             : 
    1734           7 :     LBLOG( LOG_TASKS ) << "TASK draw finish " << getName() <<  " " << command
    1735           0 :                        << " frame " << frameNumber << " id " << frameID
    1736           7 :                        << std::endl;
    1737             : 
    1738          14 :     ChannelStatistics event( Statistic::CHANNEL_DRAW_FINISH, this );
    1739           7 :     frameDrawFinish( frameID, frameNumber );
    1740             : 
    1741          14 :     return true;
    1742             : }
    1743             : 
    1744           2 : bool Channel::_cmdFrameAssemble( co::ICommand& cmd )
    1745             : {
    1746           2 :     co::ObjectICommand command( cmd );
    1747           4 :     RenderContext context = command.read< RenderContext >();
    1748           4 :     const co::ObjectVersions& frameIDs = command.read< co::ObjectVersions >();
    1749             : 
    1750           2 :     LBLOG( LOG_TASKS | LOG_ASSEMBLY )
    1751           0 :         << "TASK assemble " << getName() <<  " " << command << " " << context
    1752           2 :         << " nFrames " << frameIDs.size() << std::endl;
    1753             : 
    1754           2 :     _overrideContext( context );
    1755             : 
    1756           4 :     ChannelStatistics event( Statistic::CHANNEL_ASSEMBLE, this );
    1757           4 :     const Frames& frames = _getFrames( frameIDs, false );
    1758           2 :     frameAssemble( context.frameID, frames );
    1759             : 
    1760           2 :     resetContext();
    1761           4 :     return true;
    1762             : }
    1763             : 
    1764           2 : bool Channel::_cmdFrameReadback( co::ICommand& cmd )
    1765             : {
    1766           2 :     co::ObjectICommand command( cmd );
    1767           4 :     RenderContext context = command.read< RenderContext >();
    1768           4 :     const co::ObjectVersions& frames = command.read< co::ObjectVersions >();
    1769           2 :     LBLOG( LOG_TASKS | LOG_ASSEMBLY ) << "TASK readback " << getName() <<  " "
    1770           0 :                                       << command << " " << context<< " nFrames "
    1771           2 :                                       << frames.size() << std::endl;
    1772             : 
    1773           2 :     _overrideContext( context );
    1774           2 :     _frameReadback( context.frameID, frames );
    1775           2 :     resetContext();
    1776           4 :     return true;
    1777             : }
    1778             : 
    1779           2 : bool Channel::_cmdFinishReadback( co::ICommand& cmd )
    1780             : {
    1781           2 :     co::ObjectICommand command( cmd );
    1782             : 
    1783           2 :     LBLOG( LOG_TASKS|LOG_ASSEMBLY ) << "Finish readback " << command
    1784           2 :                                     << std::endl;
    1785             : 
    1786           2 :     const co::ObjectVersion& frameData = command.read< co::ObjectVersion >();
    1787           2 :     const uint64_t imageIndex = command.read< uint64_t >();
    1788           2 :     const uint32_t frameNumber = command.read< uint32_t >();
    1789           2 :     const uint32_t taskID = command.read< uint32_t >();
    1790             :     const std::vector< uint128_t >& nodes =
    1791           4 :             command.read< std::vector< uint128_t > >();
    1792           4 :     const co::NodeIDs& netNodes = command.read< co::NodeIDs >();
    1793             : 
    1794           2 :     getWindow()->makeCurrentTransfer();
    1795             :     _finishReadback( frameData, imageIndex, frameNumber, taskID, nodes,
    1796           2 :                      netNodes );
    1797           2 :     _unrefFrame( frameNumber );
    1798           4 :     return true;
    1799             : }
    1800             : 
    1801           2 : bool Channel::_cmdFrameSetReady( co::ICommand& cmd )
    1802             : {
    1803           2 :     co::ObjectICommand command( cmd );
    1804             : 
    1805             :     const co::ObjectVersion frameDataVersion =
    1806           2 :             command.read< co::ObjectVersion >();
    1807           2 :     detail::RBStat* stat = command.read< detail::RBStat* >();
    1808             :     const std::vector< uint128_t >& nodes =
    1809           4 :             command.read< std::vector< uint128_t > >();
    1810           4 :     const co::NodeIDs& netNodes = command.read< co::NodeIDs >();
    1811             : 
    1812           2 :     LBASSERT( stat->event.event.data.statistic.frameNumber > 0 );
    1813             : 
    1814           4 :     FrameDataPtr frameData = getNode()->getFrameData( frameDataVersion );
    1815           2 :     _setReady( frameData, stat, nodes, netNodes );
    1816             : 
    1817           2 :     const uint32_t frame = stat->event.event.data.statistic.frameNumber;
    1818           2 :     stat->unref( 0 );
    1819           2 :     _unrefFrame( frame );
    1820           4 :     return true;
    1821             : }
    1822             : 
    1823           0 : bool Channel::_cmdFrameTransmitImage( co::ICommand& cmd )
    1824             : {
    1825           0 :     co::ObjectICommand command( cmd );
    1826           0 :     const co::ObjectVersion& frameData = command.read< co::ObjectVersion >();
    1827           0 :     const uint128_t& nodeID = command.read< uint128_t >();
    1828           0 :     const co::NodeID& netNodeID = command.read< co::NodeID >();
    1829           0 :     const uint64_t imageIndex = command.read< uint64_t >();
    1830           0 :     const uint32_t frameNumber = command.read< uint32_t >();
    1831           0 :     const uint32_t taskID = command.read< uint32_t >();
    1832             : 
    1833           0 :     LBLOG( LOG_TASKS|LOG_ASSEMBLY ) << "Transmit " << command << " frame data "
    1834           0 :                                     << frameData << " receiver " << nodeID
    1835           0 :                                     << " on " << netNodeID << std::endl;
    1836             : 
    1837             :     _transmitImage( frameData, nodeID, netNodeID, imageIndex, frameNumber,
    1838           0 :                     taskID );
    1839           0 :     _unrefFrame( frameNumber );
    1840           0 :     return true;
    1841             : }
    1842             : 
    1843           2 : bool Channel::_cmdFrameSetReadyNode( co::ICommand& cmd )
    1844             : {
    1845           2 :     co::ObjectICommand command( cmd );
    1846             : 
    1847             :     const co::ObjectVersion& frameDataVersion =
    1848           2 :             command.read< co::ObjectVersion >();
    1849             :     const std::vector< uint128_t >& nodes =
    1850           4 :             command.read< std::vector< uint128_t > >();
    1851           4 :     const co::NodeIDs& netNodes = command.read< co::NodeIDs >();
    1852           2 :     const uint32_t frameNumber = command.read< uint32_t >();
    1853             : 
    1854           4 :     co::LocalNodePtr localNode = getLocalNode();
    1855           4 :     const FrameDataPtr frameData = getNode()->getFrameData( frameDataVersion );
    1856             : 
    1857           2 :     co::NodeIDs::const_iterator j = netNodes.begin();
    1858           6 :     for( std::vector< uint128_t >::const_iterator i = nodes.begin();
    1859           4 :          i != nodes.end(); ++i, ++j )
    1860             :     {
    1861           0 :         co::NodePtr toNode = localNode->connect( *j );
    1862           0 :         if( !toNode )
    1863             :         {
    1864           0 :             LBERROR << "Can't connect to " << *j << " to signal ready of frame "
    1865           0 :                     << frameNumber << std::endl;
    1866           0 :             continue;
    1867             :         }
    1868             :         co::ObjectOCommand( co::Connections( 1, toNode->getConnection( )),
    1869             :                             fabric::CMD_NODE_FRAMEDATA_READY,
    1870           0 :                             co::COMMANDTYPE_OBJECT, *i, CO_INSTANCE_ALL )
    1871           0 :             << frameDataVersion << frameData->getData();
    1872           0 :     }
    1873             : 
    1874           2 :     _unrefFrame( frameNumber );
    1875           4 :     return true;
    1876             : }
    1877             : 
    1878           5 : bool Channel::_cmdFrameViewStart( co::ICommand& cmd )
    1879             : {
    1880           5 :     co::ObjectICommand command( cmd );
    1881          10 :     RenderContext context = command.read< RenderContext >();
    1882             : 
    1883           5 :     LBLOG( LOG_TASKS ) << "TASK view start " << getName() <<  " " << command
    1884           5 :                        << " " << context << std::endl;
    1885             : 
    1886           5 :     _overrideContext( context );
    1887           5 :     frameViewStart( context.frameID );
    1888           5 :     resetContext();
    1889             : 
    1890          10 :     return true;
    1891             : }
    1892             : 
    1893           5 : bool Channel::_cmdFrameViewFinish( co::ICommand& cmd )
    1894             : {
    1895           5 :     co::ObjectICommand command( cmd );
    1896          10 :     RenderContext context = command.read< RenderContext >();
    1897             : 
    1898           5 :     LBLOG( LOG_TASKS ) << "TASK view finish " << getName() <<  " " << command
    1899           5 :                        << " " << context << std::endl;
    1900             : 
    1901           5 :     _overrideContext( context );
    1902             :     {
    1903           5 :         ChannelStatistics event( Statistic::CHANNEL_VIEW_FINISH, this );
    1904           5 :         frameViewFinish( context.frameID );
    1905             :     }
    1906           5 :     resetContext();
    1907             : 
    1908          10 :     return true;
    1909             : }
    1910             : 
    1911           0 : bool Channel::_cmdStopFrame( co::ICommand& cmd )
    1912             : {
    1913           0 :     co::ObjectICommand command( cmd );
    1914             : 
    1915           0 :     LBLOG( LOG_TASKS ) << "TASK channel stop frame " << getName() <<  " "
    1916           0 :                        << command << std::endl;
    1917             : 
    1918           0 :     notifyStopFrame( command.read< uint32_t >( ));
    1919           0 :     return true;
    1920             : }
    1921             : 
    1922           0 : bool Channel::_cmdFrameTiles( co::ICommand& cmd )
    1923             : {
    1924           0 :     co::ObjectICommand command( cmd );
    1925           0 :     RenderContext context = command.read< RenderContext >();
    1926           0 :     const bool isLocal = command.read< bool >();
    1927           0 :     const uint128_t& queueID = command.read< uint128_t >();
    1928           0 :     const uint32_t tasks = command.read< uint32_t >();
    1929           0 :     const co::ObjectVersions& frames = command.read< co::ObjectVersions >();
    1930             : 
    1931           0 :     LBLOG( LOG_TASKS ) << "TASK channel frame tiles " << getName() <<  " "
    1932           0 :                        << command << " " << context << std::endl;
    1933             : 
    1934           0 :     _frameTiles( context, isLocal, queueID, tasks, frames );
    1935           0 :     return true;
    1936             : }
    1937             : 
    1938           2 : bool Channel::_cmdDeleteTransferContext( co::ICommand& cmd )
    1939             : {
    1940           2 :     co::ObjectICommand command( cmd );
    1941             : 
    1942           2 :     LBLOG( LOG_INIT ) << "Delete transfer context " << command << std::endl;
    1943             : 
    1944           2 :     getWindow()->deleteTransferSystemWindow();
    1945           2 :     getLocalNode()->serveRequest( command.read< uint32_t >( ));
    1946           2 :     return true;
    1947             : }
    1948             : 
    1949             : }
    1950             : 
    1951             : namespace lunchbox
    1952             : {
    1953           0 : template<> inline void byteswap( eq::detail::RBStat*& ) { /*NOP*/ }
    1954             : }
    1955             : 
    1956             : #include "../fabric/channel.ipp"
    1957             : template class eq::fabric::Channel< eq::Window, eq::Channel >;
    1958             : 
    1959             : /** @cond IGNORE */
    1960             : template EQFABRIC_API std::ostream& eq::fabric::operator << ( std::ostream&,
    1961          36 :                                                  const eq::Super& );
    1962             : /** @endcond */

Generated by: LCOV version 1.10