LCOV - code coverage report
Current view: top level - eq/client - config.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 439 627 70.0 %
Date: 2014-06-18 Functions: 58 84 69.0 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2005-2014, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *               2010-2012, Daniel Nachbaur <danielnachbaur@gmail.com>
       4             :  *                    2011, Cedric Stalder <cedric Stalder@gmail.com>
       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 "config.h"
      21             : 
      22             : #include "canvas.h"
      23             : #include "channel.h"
      24             : #include "client.h"
      25             : #include "configEvent.h"
      26             : #include "configStatistics.h"
      27             : #include "eventICommand.h"
      28             : #include "global.h"
      29             : #include "layout.h"
      30             : #include "log.h"
      31             : #include "messagePump.h"
      32             : #include "node.h"
      33             : #include "nodeFactory.h"
      34             : #include "observer.h"
      35             : #include "pipe.h"
      36             : #include "server.h"
      37             : #include "view.h"
      38             : #include "window.h"
      39             : 
      40             : #include <eq/fabric/commands.h>
      41             : #include <eq/fabric/task.h>
      42             : 
      43             : #include <co/exception.h>
      44             : #include <co/object.h>
      45             : #include <co/connectionDescription.h>
      46             : #include <co/global.h>
      47             : 
      48             : #include <lunchbox/clock.h>
      49             : #include <lunchbox/monitor.h>
      50             : #include <lunchbox/plugins/compressor.h>
      51             : #include <lunchbox/scopedMutex.h>
      52             : #include <lunchbox/spinLock.h>
      53             : 
      54             : #ifdef EQUALIZER_USE_GLSTATS
      55             : #  include <GLStats/GLStats.h>
      56             : #else
      57             :     namespace GLStats { class Data {} _fakeStats; }
      58             : #endif
      59             : 
      60             : #include "exitVisitor.h"
      61             : #include "frameVisitor.h"
      62             : #include "initVisitor.h"
      63             : 
      64             : namespace eq
      65             : {
      66             : namespace
      67             : {
      68             : /** A proxy object to keep master data within latency. */
      69           0 : class LatencyObject : public co::Object
      70             : {
      71             : public:
      72           0 :     LatencyObject( const ChangeType type, const uint32_t compressor,
      73             :                    const uint32_t frame )
      74             :             : frameNumber( frame ), _changeType( type )
      75           0 :             , _compressor( compressor ) {}
      76             : 
      77             :     const uint32_t frameNumber;
      78             : 
      79             : protected:
      80           0 :     virtual ChangeType getChangeType() const { return _changeType; }
      81           0 :     virtual void getInstanceData( co::DataOStream& ){ LBDONTCALL }
      82           0 :     virtual void applyInstanceData( co::DataIStream& ){ LBDONTCALL }
      83           0 :     virtual uint32_t chooseCompressor() const { return _compressor; }
      84             : 
      85             : private:
      86             :     const ChangeType _changeType;
      87             :     const uint32_t _compressor;
      88             : };
      89             : #ifdef EQUALIZER_USE_GLSTATS
      90             : namespace
      91             : {
      92             : enum
      93             : {
      94             :     THREAD_MAIN,
      95             :     THREAD_ASYNC1,
      96             :     THREAD_ASYNC2,
      97             : };
      98             : }
      99             : #endif
     100             : }
     101             : 
     102             : namespace detail
     103             : {
     104             : class Config
     105             : {
     106             : public:
     107          20 :     Config()
     108             :         : eventQueue( co::Global::getCommandQueueLimit( ))
     109             :         , currentFrame( 0 )
     110             :         , unlockedFrame( 0 )
     111             :         , finishedFrame( 0 )
     112          20 :         , running( false )
     113             :     {
     114          20 :         lunchbox::Log::setClock( &clock );
     115          20 :     }
     116             : 
     117          10 :     ~Config()
     118          10 :     {
     119          10 :         appNode = 0;
     120          10 :         lunchbox::Log::setClock( 0 );
     121          10 :     }
     122             : 
     123             :     /** The node running the application thread. */
     124             :     co::NodePtr appNode;
     125             : 
     126             :     /** The receiver->app thread event queue. */
     127             :     CommandQueue eventQueue;
     128             : 
     129             :     /** The last received event to be released. */
     130             :     co::ICommand lastEvent;
     131             : 
     132             :     /** The connections configured by the server for this config. */
     133             :     co::Connections connections;
     134             : 
     135             : #ifdef EQUALIZER_USE_GLSTATS
     136             :     /** Global statistics data. */
     137             :     lunchbox::Lockable< GLStats::Data, lunchbox::SpinLock > statistics;
     138             : #endif
     139             : 
     140             :     /** The last started frame. */
     141             :     uint32_t currentFrame;
     142             :     /** The last locally released frame. */
     143             :     uint32_t unlockedFrame;
     144             :     /** The last completed frame. */
     145             :     lunchbox::Monitor< uint32_t > finishedFrame;
     146             : 
     147             :     /** The global clock. */
     148             :     lunchbox::Clock clock;
     149             : 
     150             :     std::deque< int64_t > frameTimes; //!< Start time of last frames
     151             : 
     152             :     /** list of the current latency object */
     153             :     typedef std::vector< LatencyObject* > LatencyObjects;
     154             : 
     155             :     /** protected list of the current latency object */
     156             :     lunchbox::Lockable< LatencyObjects, lunchbox::SpinLock > latencyObjects;
     157             : 
     158             :     /** true while the config is initialized and no window has exited. */
     159             :     bool running;
     160             : };
     161             : }
     162             : 
     163             : /** @cond IGNORE */
     164             : typedef co::CommandFunc<Config> ConfigFunc;
     165             : /** @endcond */
     166             : 
     167          20 : Config::Config( ServerPtr server )
     168             :         : Super( server )
     169          20 :         , _impl( new detail::Config )
     170          20 : {}
     171             : 
     172          29 : Config::~Config()
     173             : {
     174          10 :     LBASSERT( getObservers().empty( ));
     175          10 :     LBASSERT( getLayouts().empty( ));
     176          10 :     LBASSERT( getCanvases().empty( ));
     177          10 :     LBASSERT( getNodes().empty( ));
     178          10 :     LBASSERT( _impl->latencyObjects->empty() );
     179             : 
     180          10 :     _impl->eventQueue.flush();
     181          10 :     delete _impl;
     182          19 : }
     183             : 
     184          10 : void Config::attach( const uint128_t& id, const uint32_t instanceID )
     185             : {
     186          10 :     Super::attach( id, instanceID );
     187             : 
     188          10 :     co::CommandQueue* queue = getMainThreadQueue();
     189             : 
     190             :     registerCommand( fabric::CMD_CONFIG_CREATE_NODE,
     191          10 :                      ConfigFunc( this, &Config::_cmdCreateNode ), queue );
     192             :     registerCommand( fabric::CMD_CONFIG_DESTROY_NODE,
     193          10 :                      ConfigFunc( this, &Config::_cmdDestroyNode ), queue );
     194             :     registerCommand( fabric::CMD_CONFIG_INIT_REPLY,
     195          10 :                      ConfigFunc( this, &Config::_cmdInitReply ), queue );
     196             :     registerCommand( fabric::CMD_CONFIG_EXIT_REPLY,
     197          10 :                      ConfigFunc( this, &Config::_cmdExitReply ), queue );
     198             :     registerCommand( fabric::CMD_CONFIG_UPDATE_VERSION,
     199          10 :                      ConfigFunc( this, &Config::_cmdUpdateVersion ), 0 );
     200             :     registerCommand( fabric::CMD_CONFIG_UPDATE_REPLY,
     201          10 :                      ConfigFunc( this, &Config::_cmdUpdateReply ), queue );
     202             :     registerCommand( fabric::CMD_CONFIG_RELEASE_FRAME_LOCAL,
     203          10 :                      ConfigFunc( this, &Config::_cmdReleaseFrameLocal ), queue);
     204             :     registerCommand( fabric::CMD_CONFIG_FRAME_FINISH,
     205          10 :                      ConfigFunc( this, &Config::_cmdFrameFinish ), 0 );
     206             :     registerCommand( fabric::CMD_CONFIG_EVENT_OLD, ConfigFunc( 0, 0 ),
     207          10 :                      &_impl->eventQueue );
     208             :     registerCommand( fabric::CMD_CONFIG_EVENT, ConfigFunc( 0, 0 ),
     209          10 :                      &_impl->eventQueue );
     210             :     registerCommand( fabric::CMD_CONFIG_SYNC_CLOCK,
     211          10 :                      ConfigFunc( this, &Config::_cmdSyncClock ), 0 );
     212             :     registerCommand( fabric::CMD_CONFIG_SWAP_OBJECT,
     213          10 :                      ConfigFunc( this, &Config::_cmdSwapObject ), 0 );
     214          10 : }
     215             : 
     216          10 : void Config::notifyAttached()
     217             : {
     218          10 :     fabric::Object::notifyAttached();
     219          10 :     LBASSERT( !_impl->appNode )
     220          10 :     LBASSERT( getAppNodeID().isUUID() )
     221          10 :     co::LocalNodePtr localNode = getLocalNode();
     222          10 :     _impl->appNode = localNode->connect( getAppNodeID( ));
     223          10 :     if( !_impl->appNode )
     224           0 :         LBWARN << "Connection to application node failed -- misconfigured "
     225           0 :                << "connections on appNode?" << std::endl;
     226          10 : }
     227             : 
     228          10 : void Config::notifyDetach()
     229             : {
     230             :     {
     231          10 :         ClientPtr client = getClient();
     232          20 :         lunchbox::ScopedFastWrite mutex( _impl->latencyObjects );
     233          20 :         while( !_impl->latencyObjects->empty() )
     234             :         {
     235           0 :             LatencyObject* latencyObject = _impl->latencyObjects->back();
     236           0 :             _impl->latencyObjects->pop_back();
     237           0 :             client->deregisterObject( latencyObject );
     238           0 :             delete latencyObject;
     239           0 :             latencyObject = 0;
     240          10 :         }
     241             :     }
     242             : 
     243          10 :     getClient()->removeListeners( _impl->connections );
     244          10 :     _impl->connections.clear();
     245          10 :     _exitMessagePump();
     246          10 :     Super::notifyDetach();
     247          10 : }
     248             : 
     249         111 : co::CommandQueue* Config::getMainThreadQueue()
     250             : {
     251         111 :     return getServer()->getMainThreadQueue();
     252             : }
     253             : 
     254           8 : co::CommandQueue* Config::getCommandThreadQueue()
     255             : {
     256           8 :     return getServer()->getCommandThreadQueue();
     257             : }
     258             : 
     259       14086 : ClientPtr Config::getClient()
     260             : {
     261       14086 :     return getServer()->getClient();
     262             : }
     263             : 
     264         122 : ConstClientPtr Config::getClient() const
     265             : {
     266         122 :     return getServer()->getClient();
     267             : }
     268             : 
     269           8 : co::NodePtr Config::getApplicationNode()
     270             : {
     271           8 :     return _impl->appNode;
     272             : }
     273             : 
     274           8 : bool Config::init( const uint128_t& initID )
     275             : {
     276           8 :     LBASSERT( !_impl->running );
     277           8 :     _impl->currentFrame = 0;
     278           8 :     _impl->unlockedFrame = 0;
     279           8 :     _impl->finishedFrame = 0;
     280           8 :     _impl->frameTimes.clear();
     281             : 
     282           8 :     ClientPtr client = getClient();
     283           8 :     detail::InitVisitor initVisitor( client->getActiveLayouts(),
     284          24 :                                      client->getModelUnit( ));
     285           8 :     if( accept( initVisitor ) == TRAVERSE_TERMINATE )
     286             :     {
     287           0 :         LBWARN << "Application-local initialization failed" << std::endl;
     288           0 :         return false;
     289             :     }
     290           8 :     if( initVisitor.needsUpdate( ))
     291           0 :         update();
     292             : 
     293          16 :     co::LocalNodePtr localNode = getLocalNode();
     294          16 :     lunchbox::Request< bool > request = localNode->registerRequest< bool >();
     295           8 :     send( getServer(), fabric::CMD_CONFIG_INIT ) << initID << request;
     296             : 
     297          55 :     while( !request.isReady( ))
     298          39 :         client->processCommand();
     299             : 
     300           8 :     _impl->running = request.wait();
     301           8 :     localNode->enableSendOnRegister();
     302             : 
     303           8 :     handleEvents();
     304           8 :     if( !_impl->running )
     305           0 :         LBWARN << "Config initialization failed" << std::endl
     306           0 :                << "    Consult client log for further information" << std::endl;
     307          16 :     return _impl->running;
     308             : }
     309             : 
     310           8 : bool Config::exit()
     311             : {
     312           8 :     update();
     313           8 :     finishAllFrames();
     314             : 
     315           8 :     co::LocalNodePtr localNode = getLocalNode();
     316           8 :     localNode->disableSendOnRegister();
     317             : 
     318          16 :     lunchbox::Request< bool > request = localNode->registerRequest< bool >();
     319           8 :     send( getServer(), fabric::CMD_CONFIG_EXIT ) << request;
     320             : 
     321          16 :     ClientPtr client = getClient();
     322          55 :     while( !request.isReady( ))
     323          39 :         client->processCommand();
     324           8 :     bool ret = request.wait();
     325             : 
     326          16 :     detail::ExitVisitor exitVisitor;
     327           8 :     if( accept( exitVisitor ) == TRAVERSE_TERMINATE )
     328             :     {
     329           0 :         LBWARN << "Application-local de-initialization failed" << std::endl;
     330           0 :         ret = false;
     331             :     }
     332           8 :     _impl->lastEvent.clear();
     333           8 :     _impl->eventQueue.flush();
     334           8 :     _impl->running = false;
     335          16 :     return ret;
     336             : }
     337             : 
     338        4586 : bool Config::update()
     339             : {
     340        4586 :     commit( CO_COMMIT_NEXT );
     341             : 
     342             :     // send update req to server
     343        4586 :     ClientPtr client = getClient();
     344             : 
     345             :     lunchbox::Request< uint128_t > reqVersion =
     346        9172 :         client->registerRequest< uint128_t >();
     347             :     lunchbox::Request< uint32_t > reqFinish =
     348        9172 :         client->registerRequest< uint32_t >();
     349        9172 :     lunchbox::Request< bool > request = client->registerRequest< bool >();
     350             :     send( getServer(), fabric::CMD_CONFIG_UPDATE )
     351        4586 :             << reqVersion << reqFinish << request;
     352             : 
     353             :     // wait for new version
     354        4586 :     const uint128_t& version = reqVersion.wait();
     355        4586 :     const uint32_t finishID = reqFinish.wait();
     356             : 
     357        4586 :     if( finishID == LB_UNDEFINED_UINT32 )
     358             :     {
     359        4586 :         sync( version );
     360        4586 :         client->unregisterRequest( request.getID( ));
     361        4586 :         request.relinquish();
     362        4586 :         handleEvents();
     363        4586 :         return true;
     364             :     }
     365             : 
     366           0 :     client->disableSendOnRegister();
     367           0 :     while( _impl->finishedFrame < _impl->currentFrame )
     368           0 :         client->processCommand();
     369             : 
     370           0 :     sync( version );
     371           0 :     client->ackRequest( getServer(), finishID );
     372             : 
     373           0 :     while( !request.isReady( ))
     374           0 :         client->processCommand();
     375             : 
     376           0 :     const bool result = request.wait();
     377           0 :     client->enableSendOnRegister();
     378             : #ifdef EQUALIZER_USE_GLSTATS
     379           0 :     _impl->statistics->clear();
     380             : #endif
     381           0 :     handleEvents();
     382        4586 :     return result;
     383             : }
     384             : 
     385           5 : uint32_t Config::startFrame( const uint128_t& frameID )
     386             : {
     387             :     // Update
     388           5 :     ConfigStatistics stat( Statistic::CONFIG_START_FRAME, this );
     389          10 :     detail::FrameVisitor visitor( _impl->currentFrame + 1 );
     390           5 :     accept( visitor );
     391           5 :     update();
     392             : 
     393             :     // New frame
     394           5 :     ++_impl->currentFrame;
     395           5 :     send( getServer(), fabric::CMD_CONFIG_START_FRAME ) << frameID;
     396             : 
     397           5 :     LBLOG( lunchbox::LOG_ANY ) << "---- Started Frame ---- "
     398           5 :                                << _impl->currentFrame << std::endl;
     399           5 :     stat.event.data.statistic.frameNumber = _impl->currentFrame;
     400          10 :     return _impl->currentFrame;
     401             : }
     402             : 
     403           5 : void Config::_frameStart()
     404             : {
     405           5 :     _impl->frameTimes.push_back( _impl->clock.getTime64( ));
     406          12 :     while( _impl->frameTimes.size() > getLatency() )
     407             :     {
     408           2 :         const int64_t age = _impl->frameTimes.back() -_impl->frameTimes.front();
     409           2 :         getClient()->expireInstanceData( age );
     410           2 :         _impl->frameTimes.pop_front();
     411             :     }
     412           5 : }
     413             : 
     414           4 : uint32_t Config::finishFrame()
     415             : {
     416           4 :     ClientPtr client = getClient();
     417           4 :     const uint32_t latency = getLatency();
     418           4 :     const uint32_t frameToFinish = (_impl->currentFrame >= latency) ?
     419           4 :                                        _impl->currentFrame - latency : 0;
     420             : 
     421           8 :     ConfigStatistics stat( Statistic::CONFIG_FINISH_FRAME, this );
     422           4 :     stat.event.data.statistic.frameNumber = frameToFinish;
     423             :     {
     424           4 :         ConfigStatistics waitStat( Statistic::CONFIG_WAIT_FINISH_FRAME, this );
     425           4 :         waitStat.event.data.statistic.frameNumber = frameToFinish;
     426             : 
     427             :         // local draw sync
     428           4 :         if( _needsLocalSync( ))
     429             :         {
     430          17 :             while( _impl->unlockedFrame < _impl->currentFrame )
     431           9 :                 client->processCommand();
     432           4 :             LBLOG( LOG_TASKS ) << "Local frame sync " << _impl->currentFrame
     433           4 :                                << std::endl;
     434             :         }
     435             : 
     436             :         // local node finish (frame-latency) sync
     437           4 :         const Nodes& nodes = getNodes();
     438           4 :         if( !nodes.empty( ))
     439             :         {
     440           4 :             LBASSERT( nodes.size() == 1 );
     441           4 :             const Node* node = nodes.front();
     442             : 
     443          10 :             while( node->getFinishedFrame() < frameToFinish )
     444           2 :                 client->processCommand();
     445           4 :             LBLOG( LOG_TASKS ) << "Local total sync " << frameToFinish
     446           4 :                                << " @ " << _impl->currentFrame << std::endl;
     447             :         }
     448             : 
     449             :         // global sync
     450           4 :         const uint32_t timeout = getTimeout();
     451           4 :         if( timeout == LB_TIMEOUT_INDEFINITE )
     452           1 :             _impl->finishedFrame.waitGE( frameToFinish );
     453             :         else
     454             :         {
     455           6 :             while( !_impl->finishedFrame.timedWaitGE( frameToFinish,
     456           3 :                                                       timeout ))
     457             :             {
     458             :                 send( getServer(), fabric::CMD_CONFIG_CHECK_FRAME )
     459           0 :                     << frameToFinish;
     460             :             }
     461             :         }
     462           4 :         LBLOG( LOG_TASKS ) << "Global sync " << frameToFinish << " @ "
     463           4 :                            << _impl->currentFrame << std::endl;
     464             :     }
     465             : 
     466           4 :     handleEvents();
     467           4 :     _updateStatistics();
     468           4 :     _releaseObjects();
     469             : 
     470           4 :     LBLOG( lunchbox::LOG_ANY ) << "---- Finished Frame --- " << frameToFinish
     471           4 :                                << " (" << _impl->currentFrame << ')'<<std::endl;
     472           8 :     return frameToFinish;
     473             : }
     474             : 
     475          10 : uint32_t Config::finishAllFrames()
     476             : {
     477          10 :     if( _impl->finishedFrame == _impl->currentFrame )
     478           7 :         return _impl->currentFrame;
     479             : 
     480           3 :     LBLOG( lunchbox::LOG_ANY ) << "-- Finish All Frames --" << std::endl;
     481           3 :     send( getServer(), fabric::CMD_CONFIG_FINISH_ALL_FRAMES );
     482             : 
     483           3 :     ClientPtr client = getClient();
     484           3 :     const uint32_t timeout = getTimeout();
     485          19 :     while( _impl->finishedFrame < _impl->currentFrame )
     486             :     {
     487             :         try
     488             :         {
     489          13 :             client->processCommand( timeout );
     490             :         }
     491             :         catch( const co::Exception& e )
     492             :         {
     493             :             LBWARN << e.what() << std::endl;
     494             :             break;
     495             :         }
     496             :     }
     497           3 :     handleEvents();
     498           3 :     _updateStatistics();
     499           3 :     _releaseObjects();
     500           3 :     LBLOG( lunchbox::LOG_ANY ) << "-- Finished All Frames --" << std::endl;
     501           3 :     return _impl->currentFrame;
     502             : }
     503             : 
     504           5 : void Config::releaseFrameLocal( const uint32_t frameNumber )
     505             : {
     506           5 :     _impl->unlockedFrame = frameNumber;
     507           5 : }
     508             : 
     509           0 : void Config::stopFrames()
     510             : {
     511           0 :     send( getServer(), fabric::CMD_CONFIG_STOP_FRAMES );
     512           0 : }
     513             : 
     514             : namespace
     515             : {
     516             : class ChangeLatencyVisitor : public ConfigVisitor
     517             : {
     518             : public:
     519           0 :     ChangeLatencyVisitor( const uint32_t latency ) : _latency( latency ){}
     520           0 :     virtual ~ChangeLatencyVisitor() {}
     521             : 
     522           0 :     VisitorResult visit( eq::View* view )
     523             :     {
     524           0 :         co::Object* userData = view->getUserData();
     525           0 :         if( userData && userData->isMaster( ))
     526           0 :             userData->setAutoObsolete( _latency + 1 );
     527           0 :         return TRAVERSE_CONTINUE;
     528             :     }
     529             : 
     530           0 :     VisitorResult visit( eq::Channel* channel )
     531             :     {
     532           0 :         channel->changeLatency( _latency );
     533           0 :         return TRAVERSE_CONTINUE;
     534             :     }
     535             : 
     536             : private:
     537             :     const uint32_t _latency;
     538             : };
     539             : }
     540             : 
     541           0 : void Config::setLatency( const uint32_t latency )
     542             : {
     543           0 :     if( getLatency() == latency )
     544           0 :         return;
     545             : 
     546           0 :     Super::setLatency( latency );
     547           0 :     changeLatency( latency );
     548             : }
     549             : 
     550           0 : void Config::changeLatency( const uint32_t latency )
     551             : {
     552           0 :     finishAllFrames();
     553           0 :     commit( CO_COMMIT_NEXT );
     554             : 
     555             :     // update views
     556           0 :     ChangeLatencyVisitor changeLatencyVisitor( latency );
     557           0 :     accept( changeLatencyVisitor );
     558           0 : }
     559             : 
     560          58 : void Config::sendEvent( ConfigEvent& event )
     561             : {
     562          58 :     LBASSERT( event.data.type != Event::STATISTIC ||
     563             :               event.data.statistic.type != Statistic::NONE );
     564          58 :     LBASSERT( getAppNodeID() != 0 );
     565          58 :     LBASSERT( _impl->appNode );
     566             : 
     567             :     send( _impl->appNode, fabric::CMD_CONFIG_EVENT_OLD )
     568          58 :         << event.size << co::Array< void >( &event, event.size );
     569          58 : }
     570             : 
     571             : #ifndef EQ_2_0_API
     572           0 : const ConfigEvent* Config::nextEvent()
     573             : {
     574           0 :     EventICommand command = getNextEvent( LB_TIMEOUT_INDEFINITE );
     575           0 :     const ConfigEvent* newEvent = _convertEvent( command );
     576           0 :     return newEvent ? newEvent : nextEvent();
     577             : }
     578             : 
     579           0 : const ConfigEvent* Config::tryNextEvent()
     580             : {
     581           0 :     EventICommand command = getNextEvent( 0 );
     582           0 :     if( !command.isValid( ))
     583           0 :         return 0;
     584           0 :     const ConfigEvent* newEvent = _convertEvent( command );
     585           0 :     return newEvent ? newEvent : tryNextEvent();
     586             : }
     587             : #endif
     588             : 
     589          58 : const ConfigEvent* Config::_convertEvent( co::ObjectICommand command )
     590             : {
     591          58 :     LBASSERT( command.isValid( ));
     592             : 
     593          58 :     if( command.getCommand() != fabric::CMD_CONFIG_EVENT_OLD )
     594             :     {
     595           0 :         _impl->lastEvent.clear();
     596           0 :         return 0;
     597             :     }
     598             : 
     599          58 :     _impl->lastEvent = command;
     600          58 :     const uint64_t size = command.read< uint64_t >();
     601             :     return reinterpret_cast< const ConfigEvent* >
     602          58 :                                           ( command.getRemainingBuffer( size ));
     603             : }
     604             : 
     605          58 : bool Config::handleEvent( const ConfigEvent* event )
     606             : {
     607          58 :     return _handleEvent( event->data );
     608             : }
     609             : 
     610           0 : EventOCommand Config::sendEvent( const uint32_t type )
     611             : {
     612           0 :     LBASSERT( getAppNodeID() != 0 );
     613           0 :     LBASSERT( _impl->appNode );
     614             : 
     615           0 :     EventOCommand cmd( send( _impl->appNode, fabric::CMD_CONFIG_EVENT ));
     616           0 :     cmd << type;
     617           0 :     return cmd;
     618             : }
     619             : 
     620           6 : EventOCommand Config::sendError( const uint32_t type,
     621             :                                  const uint128_t& originator,
     622             :                                  const uint32_t error )
     623             : {
     624           6 :     return Super::sendError( getApplicationNode(), type, originator, error );
     625             : }
     626             : 
     627        4667 : EventICommand Config::getNextEvent( const uint32_t timeout ) const
     628             : {
     629        4667 :     if( timeout == 0 )
     630        4667 :         return _impl->eventQueue.tryPop();
     631           0 :     return _impl->eventQueue.pop( timeout );
     632             : }
     633             : 
     634          64 : bool Config::handleEvent( EventICommand command )
     635             : {
     636          64 :     switch( command.getCommand( ))
     637             :     {
     638             :     case fabric::CMD_CONFIG_EVENT_OLD:
     639             :     {
     640          58 :         const ConfigEvent* configEvent = _convertEvent( command );
     641          58 :         LBASSERT( configEvent );
     642          58 :         if( configEvent )
     643          58 :             return handleEvent( configEvent );
     644           0 :         return false;
     645             :     }
     646             : 
     647             :     default:
     648           0 :         LBUNIMPLEMENTED;
     649             :         // no break;
     650             :     case fabric::CMD_CONFIG_EVENT:
     651           6 :         return _handleNewEvent( command );
     652             :     }
     653             : }
     654             : 
     655           0 : bool Config::checkEvent() const
     656             : {
     657           0 :     return !_impl->eventQueue.isEmpty();
     658             : }
     659             : 
     660        4667 : void Config::handleEvents()
     661             : {
     662             :     for( ;; )
     663             :     {
     664        4667 :         EventICommand event = getNextEvent( 0 );
     665        4667 :         if( !event.isValid( ))
     666        4603 :             break;
     667             : 
     668          64 :         handleEvent( event );
     669          64 :     }
     670        4603 : }
     671             : 
     672           6 : bool Config::_handleNewEvent( EventICommand& command )
     673             : {
     674           6 :     switch( command.getEventType( ))
     675             :     {
     676             :     case Event::OBSERVER_MOTION:
     677             :     {
     678           0 :         const uint128_t& originator = command.read< uint128_t >();
     679           0 :         LBASSERT( originator != 0 );
     680           0 :         Observer* observer = find< Observer >( originator );
     681           0 :         if( observer )
     682           0 :             return observer->handleEvent( command );
     683           0 :         break;
     684             :     }
     685             : 
     686             :     case Event::NODE_ERROR:
     687             :     case Event::PIPE_ERROR:
     688             :     case Event::WINDOW_ERROR:
     689             :     case Event::CHANNEL_ERROR:
     690             :     {
     691           6 :         const uint128_t& originator = command.read< uint128_t >();
     692           6 :         const Error error = Error( command.read< uint32_t >( ));
     693           6 :         LBWARN << error << " from " << originator;
     694           6 :         if( error < ERROR_CUSTOM )
     695             :         {
     696          12 :             while( command.hasData( ))
     697             :             {
     698           0 :                 const std::string& text = command.read< std::string >();
     699           0 :                 LBWARN << ": " << text;
     700           0 :             }
     701             :         }
     702           6 :         LBWARN << std::endl;
     703           6 :         return false;
     704             :     }
     705             :     }
     706           0 :     return false;
     707             : }
     708             : 
     709          58 : bool Config::_handleEvent( const Event& event )
     710             : {
     711          58 :     switch( event.type )
     712             :     {
     713             :         case Event::EXIT:
     714             :         case Event::WINDOW_CLOSE:
     715           0 :             _impl->running = false;
     716           0 :             return true;
     717             : 
     718             :         case Event::KEY_PRESS:
     719           0 :             if( event.keyPress.key == KC_ESCAPE )
     720             :             {
     721           0 :                 _impl->running = false;
     722           0 :                 return true;
     723             :             }
     724           0 :             break;
     725             : 
     726             :         case Event::WINDOW_POINTER_BUTTON_PRESS:
     727             :         case Event::CHANNEL_POINTER_BUTTON_PRESS:
     728           0 :             if( event.pointerButtonPress.buttons ==
     729             :                 ( PTR_BUTTON1 | PTR_BUTTON2 | PTR_BUTTON3 ))
     730             :             {
     731           0 :                 _impl->running = false;
     732           0 :                 return true;
     733             :             }
     734           0 :             break;
     735             : 
     736             :         case Event::STATISTIC:
     737          52 :             LBLOG( LOG_STATS ) << event << std::endl;
     738          52 :             addStatistic( event.serial, event.statistic );
     739          52 :             break;
     740             : 
     741             :         case Event::VIEW_RESIZE:
     742             :         {
     743           0 :             LBASSERT( event.originator != 0 );
     744           0 :             View* view = find< View >( event.originator );
     745           0 :             if( view )
     746           0 :                 return view->handleEvent( event );
     747           0 :             break;
     748             :         }
     749             :     }
     750             : 
     751          58 :     return false;
     752             : }
     753             : 
     754          52 : void Config::addStatistic( const uint32_t originator LB_UNUSED,
     755             :                            const Statistic& stat LB_UNUSED )
     756             : {
     757             : #ifdef EQUALIZER_USE_GLSTATS
     758          52 :     const uint32_t frame = stat.frameNumber;
     759          52 :     LBASSERT( stat.type != Statistic::NONE );
     760             : 
     761             :      // Not a frame-related stat event OR no event-type set
     762          52 :     if( frame == 0 || stat.type == Statistic::NONE )
     763          15 :         return;
     764             : 
     765          46 :     lunchbox::ScopedFastWrite mutex( _impl->statistics );
     766          89 :     GLStats::Item item;
     767          46 :     item.entity = originator;
     768          46 :     item.type = stat.type;
     769          46 :     item.frame = stat.frameNumber;
     770          46 :     item.start = stat.startTime;
     771          46 :     item.end = stat.endTime;
     772             : 
     773          89 :     GLStats::Entity entity;
     774          46 :     entity.name = stat.resourceName;
     775             : 
     776          89 :     GLStats::Type type;
     777          46 :     const Vector3f& color = Statistic::getColor( stat.type );
     778             : 
     779          46 :     type.color[0] = color[0];
     780          46 :     type.color[1] = color[1];
     781          46 :     type.color[2] = color[2];
     782          46 :     type.name = Statistic::getName( stat.type );
     783             : 
     784          46 :     switch( stat.type )
     785             :     {
     786             :       case Statistic::CHANNEL_FRAME_COMPRESS:
     787             :       case Statistic::CHANNEL_FRAME_WAIT_SENDTOKEN:
     788           0 :           type.subgroup = "transmit";
     789           0 :           item.thread = THREAD_ASYNC2;
     790             :           // no break;
     791             :       case Statistic::CHANNEL_FRAME_WAIT_READY:
     792           2 :           type.group = "channel";
     793           2 :           item.layer = 1;
     794           2 :           break;
     795             :       case Statistic::CHANNEL_CLEAR:
     796             :       case Statistic::CHANNEL_DRAW:
     797             :       case Statistic::CHANNEL_DRAW_FINISH:
     798             :       case Statistic::CHANNEL_ASSEMBLE:
     799             :       case Statistic::CHANNEL_READBACK:
     800             :       case Statistic::CHANNEL_VIEW_FINISH:
     801          28 :           type.group = "channel";
     802          28 :           break;
     803             :       case Statistic::CHANNEL_ASYNC_READBACK:
     804           2 :           type.group = "channel";
     805           2 :           type.subgroup = "transfer";
     806           2 :           item.thread = THREAD_ASYNC1;
     807           2 :           break;
     808             :       case Statistic::CHANNEL_FRAME_TRANSMIT:
     809           0 :           type.group = "channel";
     810           0 :           type.subgroup = "transmit";
     811           0 :           item.thread = THREAD_ASYNC2;
     812           0 :           break;
     813             : 
     814             :       case Statistic::WINDOW_FINISH:
     815             :       case Statistic::WINDOW_THROTTLE_FRAMERATE:
     816             :       case Statistic::WINDOW_SWAP_BARRIER:
     817             :       case Statistic::WINDOW_SWAP:
     818           4 :           type.group = "window";
     819           4 :           break;
     820             :       case Statistic::NODE_FRAME_DECOMPRESS:
     821           0 :           type.group = "node";
     822           0 :           break;
     823             : 
     824             :       case Statistic::CONFIG_WAIT_FINISH_FRAME:
     825           1 :           item.layer = 1;
     826             :           // no break;
     827             :       case Statistic::CONFIG_START_FRAME:
     828             :       case Statistic::CONFIG_FINISH_FRAME:
     829           7 :           type.group = "config";
     830           7 :           break;
     831             : 
     832             :       case Statistic::PIPE_IDLE:
     833             :       {
     834           2 :           const std::string& string = _impl->statistics->getText();
     835           2 :           const float idle = stat.idleTime * 100ll / stat.totalTime;
     836           2 :           std::stringstream text;
     837           2 :           if( string.empty( ))
     838           1 :               text <<  "Idle: " << stat.resourceName << ' ' << idle << "%";
     839             :           else
     840             :           {
     841           1 :               const size_t pos = string.find( stat.resourceName );
     842             : 
     843           1 :               if( pos == std::string::npos ) // append new pipe
     844           0 :                   text << string << ", " << stat.resourceName << ' '
     845           0 :                        << idle << "%";
     846             :               else // replace existing text
     847             :               {
     848           1 :                   const std::string& left = string.substr( pos + 1 );
     849             : 
     850           2 :                   text << string.substr( 0, pos ) << stat.resourceName << ' '
     851           3 :                        << idle << left.substr( left.find( '%' ));
     852             :               }
     853             :           }
     854           2 :           _impl->statistics->setText( text.str( ));
     855             :       }
     856             :       // no break;
     857             : 
     858             :       case Statistic::WINDOW_FPS:
     859             :       case Statistic::NONE:
     860             :       case Statistic::ALL:
     861           3 :           return;
     862             :     }
     863          43 :     switch( stat.type )
     864             :     {
     865             :       case Statistic::CHANNEL_FRAME_COMPRESS:
     866             :       case Statistic::CHANNEL_ASYNC_READBACK:
     867             :       case Statistic::CHANNEL_READBACK:
     868             :       {
     869           2 :           std::stringstream text;
     870           2 :           text << unsigned( 100.f * stat.ratio ) << '%';
     871             : 
     872           2 :           if( stat.plugins[ 0 ] > EQ_COMPRESSOR_NONE )
     873           2 :               text << " 0x" << std::hex << stat.plugins[0] << std::dec;
     874           2 :           if( stat.plugins[ 1 ] > EQ_COMPRESSOR_NONE &&
     875           0 :               stat.plugins[ 0 ] != stat.plugins[ 1 ] )
     876             :           {
     877           0 :               text << " 0x" << std::hex << stat.plugins[1] << std::dec;
     878             :           }
     879           2 :           item.text = text.str();
     880           2 :           break;
     881             :       }
     882             :       default:
     883          41 :           break;
     884             :     }
     885             : 
     886          43 :     _impl->statistics->setType( stat.type, type );
     887          43 :     _impl->statistics->setEntity( originator, entity );
     888          86 :     _impl->statistics->addItem( item );
     889             : #endif
     890             : }
     891             : 
     892           4 : bool Config::_needsLocalSync() const
     893             : {
     894           4 :     const Nodes& nodes = getNodes();
     895           4 :     if( nodes.empty( ))
     896           0 :         return true; // server sends unlock command - process it
     897             : 
     898           4 :     LBASSERT( nodes.size() == 1 );
     899           4 :     const Node* node = nodes.front();
     900           4 :     switch( node->getIAttribute( Node::IATTR_THREAD_MODEL ))
     901             :     {
     902             :         case ASYNC:
     903           0 :             return false;
     904             : 
     905             :         case DRAW_SYNC:
     906           4 :             if( !(node->getTasks() & fabric::TASK_DRAW) )
     907           0 :                 return false;
     908           4 :             break;
     909             : 
     910             :         case LOCAL_SYNC:
     911           0 :             if( node->getTasks() == fabric::TASK_NONE )
     912           0 :                 return false;
     913           0 :             break;
     914             : 
     915             :         default:
     916           0 :             LBUNIMPLEMENTED;
     917             :     }
     918             : 
     919           4 :     return true;
     920             : }
     921             : 
     922           7 : void Config::_updateStatistics()
     923             : {
     924             : #ifdef EQUALIZER_USE_GLSTATS
     925             :     // keep statistics for three frames
     926           7 :     lunchbox::ScopedFastWrite mutex( _impl->statistics );
     927           7 :     _impl->statistics->obsolete( 2 /* frames to keep */ );
     928             : #endif
     929           7 : }
     930             : 
     931           0 : GLStats::Data Config::getStatistics() const
     932             : {
     933             : #ifdef EQUALIZER_USE_GLSTATS
     934           0 :     lunchbox::ScopedFastRead mutex( _impl->statistics );
     935           0 :     return _impl->statistics.data;
     936             : #else
     937             :     return GLStats::_fakeStats;
     938             : #endif
     939             : }
     940             : 
     941          13 : uint32_t Config::getCurrentFrame() const
     942             : {
     943          13 :     return _impl->currentFrame;
     944             : }
     945             : 
     946           0 : uint32_t Config::getFinishedFrame() const
     947             : {
     948           0 :     return _impl->finishedFrame.get();
     949             : }
     950             : 
     951           2 : bool Config::isRunning() const
     952             : {
     953           2 :     return _impl->running;
     954             : }
     955             : 
     956           1 : void Config::stopRunning()
     957             : {
     958           1 :     _impl->running = false;
     959           1 : }
     960             : 
     961         134 : int64_t Config::getTime() const
     962             : {
     963         134 :     return _impl->clock.getTime64();
     964             : }
     965             : 
     966         122 : bool Config::mapViewObjects() const
     967             : {
     968             :     // only on application node...
     969         122 :     return ( getClient()->getNodeID() == getAppNodeID( ));
     970             : }
     971             : 
     972          15 : void Config::setupMessagePump( Pipe* pipe )
     973             : {
     974          15 :     const bool isThreaded = pipe->isThreaded();
     975          15 :     const WindowSystem windowSystem = pipe->getWindowSystem();
     976             : 
     977          15 :     if( isThreaded && windowSystem.getName() != "AGL" )
     978          30 :         return;
     979             : 
     980             :     // called from pipe threads - but only during init
     981           0 :     static lunchbox::Lock _lock;
     982           0 :     lunchbox::ScopedWrite mutex( _lock );
     983             : 
     984           0 :     if( _impl->eventQueue.getMessagePump( )) // Already done
     985           0 :         return;
     986             : 
     987           0 :     MessagePump* pump = pipe->createMessagePump();
     988           0 :     _impl->eventQueue.setMessagePump( pump );
     989             : 
     990           0 :     ClientPtr client = getClient();
     991           0 :     CommandQueue* queue = LBSAFECAST( CommandQueue*,
     992             :                                       client->getMainThreadQueue( ));
     993           0 :     LBASSERT( queue );
     994           0 :     LBASSERT( !queue->getMessagePump( ));
     995             : 
     996           0 :     queue->setMessagePump( pump );
     997             : }
     998             : 
     999          18 : void Config::_exitMessagePump()
    1000             : {
    1001          18 :     MessagePump* pump = _impl->eventQueue.getMessagePump();
    1002          18 :     _impl->eventQueue.setMessagePump( 0 );
    1003             : 
    1004          18 :     ClientPtr client = getClient();
    1005          18 :     CommandQueue* queue = LBSAFECAST( CommandQueue*,
    1006             :                                       client->getMainThreadQueue( ));
    1007          18 :     LBASSERT( queue );
    1008          18 :     LBASSERT( queue->getMessagePump() == pump );
    1009             : 
    1010          18 :     queue->setMessagePump( 0 );
    1011          18 :     delete pump;
    1012          18 : }
    1013             : 
    1014           0 : MessagePump* Config::getMessagePump()
    1015             : {
    1016           0 :     ClientPtr client = getClient();
    1017           0 :     CommandQueue* queue = LBSAFECAST( CommandQueue*,
    1018             :                                       client->getMainThreadQueue( ));
    1019           0 :     if( queue )
    1020           0 :         return queue->getMessagePump();
    1021           0 :     return 0;
    1022             : }
    1023             : 
    1024          10 : void Config::setupServerConnections( const std::string& connectionData )
    1025             : {
    1026          10 :     std::string data = connectionData;
    1027          20 :     co::ConnectionDescriptions descriptions;
    1028          10 :     LBCHECK( co::deserialize( data, descriptions ));
    1029          10 :     LBASSERTINFO( data.empty(), data << " left from " << connectionData );
    1030             : 
    1031          45 :     for( co::ConnectionDescriptionsCIter i = descriptions.begin();
    1032          30 :          i != descriptions.end(); ++i )
    1033             :     {
    1034           5 :         co::ConnectionPtr connection = getClient()->addListener( *i );
    1035           5 :         if( connection )
    1036           5 :             _impl->connections.push_back( connection );
    1037          15 :     }
    1038          10 : }
    1039             : 
    1040           1 : bool Config::registerObject( co::Object* object )
    1041             : {
    1042           1 :     if( !getClient()->registerObject( object ))
    1043           0 :         return false;
    1044           1 :     object->setAutoObsolete( getLatency() + 1 );
    1045           1 :     return true;
    1046             : }
    1047             : 
    1048           1 : void Config::deregisterObject( co::Object* object )
    1049             : {
    1050           1 :     LBASSERT( object )
    1051           1 :     LBASSERT( object->isMaster( ));
    1052             : 
    1053           1 :     if( !object->isAttached( )) // not registered
    1054           1 :         return;
    1055             : 
    1056           1 :     const uint32_t latency = getLatency();
    1057           1 :     ClientPtr client = getClient();
    1058           1 :     if( latency == 0 || !_impl->running || !object->isBuffered( )) // OPT
    1059             :     {
    1060           1 :         client->deregisterObject( object );
    1061           1 :         return;
    1062             :     }
    1063             : 
    1064             :     // Keep a distributed object latency frames.
    1065             :     // Replaces the object with a dummy proxy object using the
    1066             :     // existing master change manager.
    1067             :     const lunchbox::Request< void > request =
    1068           0 :         getLocalNode()->registerRequest< void >();
    1069           0 :     send( client, fabric::CMD_CONFIG_SWAP_OBJECT ) << request << object;
    1070             : }
    1071             : 
    1072          53 : bool Config::mapObject( co::Object* object, const uint128_t& id,
    1073             :                         const uint128_t& version )
    1074             : {
    1075          53 :     return mapObjectSync( mapObjectNB( object, id, version ));
    1076             : }
    1077             : 
    1078          53 : uint32_t Config::mapObjectNB( co::Object* object, const uint128_t& id,
    1079             :                               const uint128_t& version )
    1080             : {
    1081          53 :     return getClient()->mapObjectNB( object, id, version );
    1082             : }
    1083             : 
    1084           2 : uint32_t Config::mapObjectNB( co::Object* object, const uint128_t& id,
    1085             :                               const uint128_t& version, co::NodePtr master )
    1086             : {
    1087           2 :     return getClient()->mapObjectNB( object, id, version, master );
    1088             : }
    1089             : 
    1090          55 : bool Config::mapObjectSync( const uint32_t requestID )
    1091             : {
    1092          55 :     return getClient()->mapObjectSync( requestID );
    1093             : }
    1094             : 
    1095          55 : void Config::unmapObject( co::Object* object )
    1096             : {
    1097          55 :     getClient()->unmapObject( object );
    1098          55 : }
    1099             : 
    1100           0 : f_bool_t Config::syncObject( co::Object* object, co::NodePtr master,
    1101             :                              const uint128_t& id, const uint32_t instanceID )
    1102             : {
    1103           0 :     return getClient()->syncObject( object, master, id, instanceID );
    1104             : }
    1105             : 
    1106           7 : void Config::_releaseObjects()
    1107             : {
    1108           7 :     ClientPtr client = getClient();
    1109             : 
    1110          14 :     lunchbox::ScopedFastWrite mutex( _impl->latencyObjects );
    1111          14 :     while( !_impl->latencyObjects->empty() )
    1112             :     {
    1113           0 :         LatencyObject* latencyObject = _impl->latencyObjects->front();
    1114           0 :         if( latencyObject->frameNumber > _impl->currentFrame )
    1115           0 :             break;
    1116             : 
    1117           0 :         client->deregisterObject( latencyObject );
    1118           0 :         _impl->latencyObjects->erase( _impl->latencyObjects->begin() );
    1119             : 
    1120           0 :         delete latencyObject;
    1121           7 :     }
    1122           7 : }
    1123             : 
    1124             : //---------------------------------------------------------------------------
    1125             : // command handlers
    1126             : //---------------------------------------------------------------------------
    1127           8 : bool Config::_cmdCreateNode( co::ICommand& cmd )
    1128             : {
    1129           8 :     co::ObjectICommand command( cmd );
    1130             : 
    1131           8 :     LBVERB << "Handle create node " << command << std::endl;
    1132             : 
    1133           8 :     Node* node = Global::getNodeFactory()->createNode( this );
    1134           8 :     LBCHECK( mapObject( node, command.read< uint128_t >( )));
    1135           8 :     return true;
    1136             : }
    1137             : 
    1138           8 : bool Config::_cmdDestroyNode( co::ICommand& cmd )
    1139             : {
    1140           8 :     co::ObjectICommand command( cmd );
    1141             : 
    1142           8 :     LBVERB << "Handle destroy node " << command << std::endl;
    1143             : 
    1144           8 :     Node* node = _findNode( command.read< uint128_t >( ));
    1145           8 :     LBASSERT( node );
    1146           8 :     if( !node )
    1147           0 :         return true;
    1148             : 
    1149           8 :     const bool isStopped = node->isStopped();
    1150             : 
    1151           8 :     LBASSERT( node->getPipes().empty( ));
    1152           8 :     unmapObject( node );
    1153           8 :     node->send( getServer(), fabric::CMD_NODE_CONFIG_EXIT_REPLY ) << isStopped;
    1154           8 :     Global::getNodeFactory()->releaseNode( node );
    1155             : 
    1156           8 :     return true;
    1157             : }
    1158             : 
    1159           8 : bool Config::_cmdInitReply( co::ICommand& cmd )
    1160             : {
    1161           8 :     co::ObjectICommand command( cmd );
    1162             : 
    1163           8 :     LBVERB << "handle init reply " << command << std::endl;
    1164             : 
    1165           8 :     const uint128_t& version = command.read< uint128_t >();
    1166           8 :     const uint32_t requestID = command.read< uint32_t >();
    1167           8 :     const bool result = command.read< bool >();
    1168             : 
    1169           8 :     sync( version );
    1170           8 :     getLocalNode()->serveRequest( requestID, result );
    1171           8 :     return true;
    1172             : }
    1173             : 
    1174           8 : bool Config::_cmdExitReply( co::ICommand& cmd )
    1175             : {
    1176           8 :     co::ObjectICommand command( cmd );
    1177             : 
    1178           8 :     LBVERB << "handle exit reply " << command << std::endl;
    1179             : 
    1180           8 :     const uint32_t requestID = command.read< uint32_t >();
    1181           8 :     const bool result = command.read< bool >();
    1182             : 
    1183           8 :     _exitMessagePump();
    1184           8 :     getLocalNode()->serveRequest( requestID, result );
    1185           8 :     return true;
    1186             : }
    1187             : 
    1188        4586 : bool Config::_cmdUpdateVersion( co::ICommand& cmd )
    1189             : {
    1190        4586 :     co::ObjectICommand command( cmd );
    1191        4586 :     const uint128_t& version = command.read< uint128_t >();
    1192        4586 :     const uint32_t versionID = command.read< uint32_t >();
    1193        4586 :     const uint32_t finishID = command.read< uint32_t >();
    1194        4586 :     const uint32_t requestID = command.read< uint32_t >();
    1195             : 
    1196        4586 :     getClient()->serveRequest( versionID, version );
    1197        4586 :     getClient()->serveRequest( finishID, requestID );
    1198        4586 :     return true;
    1199             : }
    1200             : 
    1201           0 : bool Config::_cmdUpdateReply( co::ICommand& cmd )
    1202             : {
    1203           0 :     co::ObjectICommand command( cmd );
    1204           0 :     const uint128_t& version = command.read< uint128_t >();
    1205           0 :     const uint32_t requestID = command.read< uint32_t >();
    1206           0 :     const bool result = command.read< bool >();
    1207             : 
    1208           0 :     sync( version );
    1209           0 :     getClient()->serveRequest( requestID, result );
    1210           0 :     return true;
    1211             : }
    1212             : 
    1213           0 : bool Config::_cmdReleaseFrameLocal( co::ICommand& cmd )
    1214             : {
    1215           0 :     co::ObjectICommand command( cmd );
    1216             : 
    1217           0 :     _frameStart(); // never happened from node
    1218           0 :     releaseFrameLocal( command.read< uint32_t >( ));
    1219           0 :     return true;
    1220             : }
    1221             : 
    1222           5 : bool Config::_cmdFrameFinish( co::ICommand& cmd )
    1223             : {
    1224           5 :     co::ObjectICommand command( cmd );
    1225             : 
    1226           5 :     _impl->finishedFrame = command.read< uint32_t >();
    1227             : 
    1228           5 :     LBLOG( LOG_TASKS ) << "frame finish " << command
    1229           5 :                        << " frame " << _impl->finishedFrame << std::endl;
    1230             : 
    1231           5 :     if( _impl->unlockedFrame < _impl->finishedFrame.get( ))
    1232             :     {
    1233           0 :         LBWARN << "Finished frame " << _impl->unlockedFrame
    1234           0 :                << " was not locally unlocked, enforcing unlock" << std::endl;
    1235           0 :         _impl->unlockedFrame = _impl->finishedFrame.get();
    1236             :     }
    1237             : 
    1238          10 :     co::ICommand empty;
    1239           5 :     getMainThreadQueue()->push( empty ); // wakeup signal
    1240          10 :     return true;
    1241             : }
    1242             : 
    1243           5 : bool Config::_cmdSyncClock( co::ICommand& cmd )
    1244             : {
    1245           5 :     co::ObjectICommand command( cmd );
    1246           5 :     const int64_t time = command.read< int64_t >();
    1247             : 
    1248           5 :     LBVERB << "sync global clock to " << time << ", drift "
    1249           5 :            << time - _impl->clock.getTime64() << std::endl;
    1250             : 
    1251           5 :     _impl->clock.set( time );
    1252           5 :     return true;
    1253             : }
    1254             : 
    1255           0 : bool Config::_cmdSwapObject( co::ICommand& cmd )
    1256             : {
    1257           0 :     co::ObjectICommand command( cmd );
    1258           0 :     LBVERB << "Cmd swap object " << command << std::endl;
    1259             : 
    1260           0 :     const uint32_t requestID = command.read< uint32_t >();
    1261             :     co::Object* object =
    1262           0 :             reinterpret_cast< co::Object* >( command.read< void* >( ));
    1263             : 
    1264           0 :     LatencyObject* latencyObject = new LatencyObject( object->getChangeType(),
    1265           0 :                                                      object->chooseCompressor(),
    1266           0 :                                        _impl->currentFrame + getLatency() + 1 );
    1267           0 :     getLocalNode()->swapObject( object, latencyObject  );
    1268             :     {
    1269           0 :         lunchbox::ScopedFastWrite mutex( _impl->latencyObjects );
    1270           0 :         _impl->latencyObjects->push_back( latencyObject );
    1271             :     }
    1272           0 :     LBASSERT( requestID != LB_UNDEFINED_UINT32 );
    1273           0 :     getLocalNode()->serveRequest( requestID );
    1274           0 :     return true;
    1275             : }
    1276             : }
    1277             : 
    1278             : #include "../fabric/config.ipp"
    1279             : #include "../fabric/view.ipp"
    1280             : #include "../fabric/observer.ipp"
    1281             : template class eq::fabric::Config< eq::Server, eq::Config, eq::Observer,
    1282             :                                    eq::Layout, eq::Canvas, eq::Node,
    1283             :                                    eq::ConfigVisitor >;
    1284             : 
    1285             : /** @cond IGNORE */
    1286             : template EQFABRIC_API std::ostream& eq::fabric::operator << ( std::ostream&,
    1287             :                                                  const eq::Config::Super& );
    1288             : /** @endcond */
    1289             : 
    1290             : #define FIND_ID_TEMPLATE1( type )                                       \
    1291             :     template EQ_API void eq::Config::Super::find< type >( const uint128_t&, \
    1292             :                                                              type** );
    1293             : 
    1294             : FIND_ID_TEMPLATE1( eq::Window );
    1295             : FIND_ID_TEMPLATE1( eq::Channel );
    1296             : FIND_ID_TEMPLATE1( eq::Layout );
    1297             : FIND_ID_TEMPLATE1( eq::Observer );
    1298             : FIND_ID_TEMPLATE1( eq::Canvas );
    1299             : 
    1300             : #define FIND_ID_TEMPLATE2( type )                                       \
    1301             :     template EQ_API type* eq::Config::Super::find< type >( const uint128_t& );
    1302             : 
    1303             : FIND_ID_TEMPLATE2( eq::Window );
    1304             : FIND_ID_TEMPLATE2( eq::Observer );
    1305             : FIND_ID_TEMPLATE2( eq::Layout );
    1306             : FIND_ID_TEMPLATE2( eq::View );
    1307             : FIND_ID_TEMPLATE2( eq::Canvas );
    1308             : 
    1309             : #define CONST_FIND_ID_TEMPLATE2( type )                                       \
    1310             :     template EQ_API const type* eq::Config::Super::find< type >( const uint128_t& ) const;
    1311             : 
    1312             : CONST_FIND_ID_TEMPLATE2( eq::Window );
    1313             : CONST_FIND_ID_TEMPLATE2( eq::Observer );
    1314             : CONST_FIND_ID_TEMPLATE2( eq::Layout );
    1315             : CONST_FIND_ID_TEMPLATE2( eq::View );
    1316             : CONST_FIND_ID_TEMPLATE2( eq::Canvas );
    1317             : 
    1318             : #define FIND_NAME_TEMPLATE1( type )                                     \
    1319             :     template EQ_API void \
    1320             :     eq::Config::Super::find< type >(const std::string&, const type** ) const;
    1321             : FIND_NAME_TEMPLATE1( eq::Window );
    1322             : FIND_NAME_TEMPLATE1( eq::Layout );
    1323             : FIND_NAME_TEMPLATE1( eq::Observer );
    1324             : FIND_NAME_TEMPLATE1( eq::Canvas );
    1325             : 
    1326             : 
    1327             : #define CONST_FIND_NAME_TEMPLATE2( type )                               \
    1328             :     template EQ_API const type*                                      \
    1329             :     eq::Config::Super::find< type >( const std::string& ) const;
    1330             : 
    1331             : CONST_FIND_NAME_TEMPLATE2( eq::Window );
    1332             : CONST_FIND_NAME_TEMPLATE2( eq::Canvas );
    1333             : CONST_FIND_NAME_TEMPLATE2( eq::Channel );
    1334             : CONST_FIND_NAME_TEMPLATE2( eq::Layout );
    1335             : CONST_FIND_NAME_TEMPLATE2( eq::Observer );
    1336             : CONST_FIND_NAME_TEMPLATE2( eq::View );
    1337             : 
    1338             : #define FIND_NAME_TEMPLATE2( type )                               \
    1339             :     template EQ_API type*                                      \
    1340             :     eq::Config::Super::find< type >( const std::string& );
    1341             : 
    1342             : FIND_NAME_TEMPLATE2( eq::Window );
    1343             : FIND_NAME_TEMPLATE2( eq::Canvas );
    1344             : FIND_NAME_TEMPLATE2( eq::Channel );
    1345             : FIND_NAME_TEMPLATE2( eq::Layout );
    1346             : FIND_NAME_TEMPLATE2( eq::Observer );
    1347          36 : FIND_NAME_TEMPLATE2( eq::View );

Generated by: LCOV version 1.10