LCOV - code coverage report
Current view: top level - eq - channel.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 87 1067 8.2 %
Date: 2016-09-29 05:02:09 Functions: 18 117 15.4 %

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

Generated by: LCOV version 1.11