LCOV - code coverage report
Current view: top level - eq - config.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 408 639 63.8 %
Date: 2017-12-16 05:07:20 Functions: 54 84 64.3 %

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

Generated by: LCOV version 1.11