LCOV - code coverage report
Current view: top level - eq - config.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 187 635 29.4 %
Date: 2016-09-29 05:02:09 Functions: 34 85 40.0 %

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

Generated by: LCOV version 1.11