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

Generated by: LCOV version 1.11