LCOV - code coverage report
Current view: top level - eq/server/config - resources.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 312 451 69.2 %
Date: 2017-12-16 05:07:20 Functions: 23 27 85.2 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2011-2017, Stefan Eilemann <eile@eyescale.h>
       3             :  *                          Daniel Nachbaur <danielnachbaur@gmail.com>
       4             :  *                          Julio Delgado Mangas <julio.delgadomangas@epfl.ch>
       5             :  *
       6             :  * This library is free software; you can redistribute it and/or modify it under
       7             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       8             :  * by the Free Software Foundation.
       9             :  *
      10             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      11             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      12             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      13             :  * details.
      14             :  *
      15             :  * You should have received a copy of the GNU Lesser General Public License
      16             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      17             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             :  */
      19             : 
      20             : #include "resources.h"
      21             : 
      22             : #include "../compound.h"
      23             : #include "../configVisitor.h"
      24             : #include "../connectionDescription.h"
      25             : #include "../equalizers/loadEqualizer.h"
      26             : #include "../frame.h"
      27             : #include "../layout.h"
      28             : #include "../node.h"
      29             : #include "../pipe.h"
      30             : #include "../segment.h"
      31             : #include "../window.h"
      32             : 
      33             : #include <eq/fabric/configParams.h>
      34             : #include <eq/fabric/gpuInfo.h>
      35             : 
      36             : #include <hwsd/gpuInfo.h>
      37             : #include <hwsd/hwsd.h>
      38             : #include <hwsd/netInfo.h>
      39             : #ifdef EQUALIZER_USE_hwsd_gpu_cgl
      40             : #include <hwsd/gpu/cgl/module.h>
      41             : #endif
      42             : #ifdef EQUALIZER_USE_hwsd_gpu_glx
      43             : #include <hwsd/gpu/glx/module.h>
      44             : #endif
      45             : #ifdef EQUALIZER_USE_hwsd_gpu_wgl
      46             : #include <hwsd/gpu/wgl/module.h>
      47             : #endif
      48             : #ifdef EQUALIZER_USE_hwsd_gpu_dns_sd
      49             : #include <hwsd/gpu/dns_sd/module.h>
      50             : #endif
      51             : #ifdef EQUALIZER_USE_hwsd_net_sys
      52             : #include <hwsd/net/sys/module.h>
      53             : #endif
      54             : #ifdef EQUALIZER_USE_hwsd_net_dns_sd
      55             : #include <hwsd/net/dns_sd/module.h>
      56             : #endif
      57             : 
      58             : #ifdef _MSC_VER
      59             : #include <eq/os.h>
      60             : #define setenv(name, value, overwrite) _putenv_s(name, value)
      61             : #endif
      62             : 
      63             : #include <cmath>
      64             : #include <cstdio>
      65             : 
      66             : #define USE_IPv4
      67             : 
      68             : namespace eq
      69             : {
      70             : namespace server
      71             : {
      72             : namespace config
      73             : {
      74             : namespace
      75             : {
      76           0 : co::ConnectionDescriptions _findConnections(const lunchbox::uint128_t& id,
      77             :                                             const hwsd::NetInfos& netInfos)
      78             : {
      79             :     // sort connections by bandwidth
      80             :     typedef std::multimap<int32_t, co::ConnectionDescriptionPtr> Connections;
      81           0 :     Connections connections;
      82             : 
      83           0 :     for (hwsd::NetInfosCIter i = netInfos.begin(); i != netInfos.end(); ++i)
      84             :     {
      85           0 :         const hwsd::NetInfo& netInfo = *i;
      86           0 :         if (netInfo.id != id || !netInfo.up ||
      87           0 :             netInfo.type == hwsd::NetInfo::TYPE_LOOPBACK)
      88             :         {
      89           0 :             continue;
      90             :         }
      91             : 
      92           0 :         co::ConnectionDescriptionPtr desc = new ConnectionDescription;
      93           0 :         switch (netInfo.type)
      94             :         {
      95             :         case hwsd::NetInfo::TYPE_ETHERNET:
      96           0 :             desc->type = co::CONNECTIONTYPE_TCPIP;
      97           0 :             desc->bandwidth = 125000; // 1Gbit
      98           0 :             break;
      99             : 
     100             :         case hwsd::NetInfo::TYPE_INFINIBAND:
     101           0 :             desc->type = co::CONNECTIONTYPE_RDMA;
     102           0 :             desc->bandwidth = 2500000; // 20Gbit
     103           0 :             break;
     104             : 
     105             :         default:
     106           0 :             desc->type = co::CONNECTIONTYPE_NONE;
     107             :         }
     108           0 :         if (netInfo.linkspeed != hwsd::NetInfo::defaultValue)
     109           0 :             desc->bandwidth = netInfo.linkspeed * 125; // MBit -> Kbyte
     110             : #ifdef USE_IPv4
     111           0 :         desc->hostname = netInfo.inetAddress;
     112             : #else
     113             :         desc->hostname = netInfo.inet6Address;
     114             : #endif
     115           0 :         connections.insert(std::make_pair(desc->bandwidth, desc));
     116             :     }
     117             : 
     118           0 :     co::ConnectionDescriptions result;
     119           0 :     for (Connections::const_reverse_iterator i = connections.rbegin();
     120           0 :          i != connections.rend(); ++i)
     121             :     {
     122           0 :         result.push_back(i->second);
     123             :     }
     124           0 :     return result;
     125             : }
     126             : 
     127           2 : uint32_t _configureNetworkTypes(const fabric::ConfigParams& params)
     128             : {
     129           2 :     uint32_t netTypes = 0;
     130           2 :     if (params.getFlags() & fabric::ConfigParams::FLAG_NETWORK_ALL)
     131             :     {
     132           0 :         if (params.getFlags() & fabric::ConfigParams::FLAG_NETWORK_ETHERNET)
     133           0 :             netTypes |= hwsd::NetInfo::TYPE_ETHERNET;
     134           0 :         if (params.getFlags() & fabric::ConfigParams::FLAG_NETWORK_INFINIBAND)
     135           0 :             netTypes |= hwsd::NetInfo::TYPE_INFINIBAND;
     136             :     }
     137             :     else
     138           2 :         netTypes = hwsd::NetInfo::TYPE_ALL ^ hwsd::NetInfo::TYPE_UNKNOWN;
     139             : 
     140           2 :     return netTypes;
     141             : }
     142             : 
     143           2 : hwsd::GPUInfos _discoverGPUs(const fabric::ConfigParams& params,
     144             :                              hwsd::FilterPtr filter)
     145             : {
     146           4 :     hwsd::FilterPtr gpuFilter = filter | new hwsd::MirrorFilter |
     147           8 :                                 new hwsd::GPUFilter(params.getGPUFilter());
     148             : 
     149           4 :     return hwsd::discoverGPUInfos(gpuFilter);
     150             : }
     151             : 
     152           2 : hwsd::NetInfos _discoverNetworks(const fabric::ConfigParams& params,
     153             :                                  hwsd::FilterPtr filter)
     154             : {
     155             :     hwsd::FilterPtr netFilter =
     156             :         filter | new hwsd::NetFilter(params.getPrefixes(),
     157           4 :                                      _configureNetworkTypes(params));
     158             : 
     159           4 :     return hwsd::discoverNetInfos(netFilter);
     160             : }
     161             : 
     162           2 : void _configureHwsdModules()
     163             : {
     164             : #ifdef EQUALIZER_USE_hwsd_gpu_cgl
     165             :     hwsd::gpu::cgl::Module::use();
     166             : #elif defined(EQUALIZER_USE_hwsd_gpu_glx)
     167           2 :     hwsd::gpu::glx::Module::use();
     168             : #endif
     169             : #ifdef EQUALIZER_USE_hwsd_gpu_wgl
     170             :     hwsd::gpu::wgl::Module::use();
     171             : #endif
     172             : #ifdef EQUALIZER_USE_hwsd_gpu_dns_sd
     173             :     hwsd::gpu::dns_sd::Module::use();
     174             : #endif
     175             : #ifdef EQUALIZER_USE_hwsd_net_sys
     176           2 :     hwsd::net::sys::Module::use();
     177             : #endif
     178             : #ifdef EQUALIZER_USE_hwsd_net_dns_sd
     179             :     hwsd::net::dns_sd::Module::use();
     180             : #endif
     181           2 : }
     182             : 
     183           2 : void _disposeHwsdModules()
     184             : {
     185             : #ifdef EQUALIZER_USE_hwsd_gpu_cgl
     186             :     hwsd::gpu::cgl::Module::dispose();
     187             : #elif defined(EQUALIZER_USE_hwsd_gpu_glx)
     188           2 :     hwsd::gpu::glx::Module::dispose();
     189             : #endif
     190             : #ifdef EQUALIZER_USE_hwsd_gpu_wgl
     191             :     hwsd::gpu::wgl::Module::dispose();
     192             : #endif
     193             : #ifdef EQUALIZER_USE_hwsd_gpu_dns_sd
     194             :     hwsd::gpu::dns_sd::Module::dispose();
     195             : #endif
     196             : #ifdef EQUALIZER_USE_hwsd_net_sys
     197           2 :     hwsd::net::sys::Module::dispose();
     198             : #endif
     199             : #ifdef EQUALIZER_USE_hwsd_net_dns_sd
     200             :     hwsd::net::dns_sd::Module::dispose();
     201             : #endif
     202           2 : }
     203             : 
     204             : } // unnamed namespace
     205             : 
     206          20 : static lunchbox::a_int32_t _frameCounter;
     207             : 
     208           2 : bool Resources::discover(ServerPtr server, Config* config,
     209             :                          const std::string& session,
     210             :                          const fabric::ConfigParams& params)
     211             : {
     212           2 :     _configureHwsdModules();
     213             : 
     214           4 :     hwsd::FilterPtr filter = hwsd::FilterPtr(new hwsd::DuplicateFilter) |
     215           8 :                              new hwsd::SessionFilter(session);
     216             : 
     217           4 :     hwsd::GPUInfos gpuInfos = _discoverGPUs(params, filter);
     218           4 :     const hwsd::NetInfos& netInfos = _discoverNetworks(params, filter);
     219             : 
     220           2 :     _disposeHwsdModules();
     221             : 
     222           2 :     if (gpuInfos.empty())
     223             :     {
     224           0 :         if (hwsd::NodeInfo::isLocal(session))
     225             :         {
     226           0 :             LBWARN << "No local GPUs found, abort configuration" << std::endl;
     227           0 :             return false;
     228             :         }
     229           0 :         LBINFO << "No resources found for session " << session << ", aborting"
     230           0 :                << std::endl;
     231           0 :         return false;
     232             :     }
     233             : 
     234             :     typedef std::unordered_map<uint128_t, Node*> NodeMap;
     235           4 :     NodeMap nodes;
     236             : 
     237           2 :     const uint32_t flags = params.getFlags();
     238             : 
     239             :     const bool multiProcess =
     240           2 :         flags & (fabric::ConfigParams::FLAG_MULTIPROCESS |
     241           2 :                  fabric::ConfigParams::FLAG_MULTIPROCESS_DB);
     242           2 :     const bool multiNode = !hwsd::NodeInfo::isLocal(session) ||
     243           2 :                            (multiProcess && gpuInfos.size() > 1);
     244           2 :     size_t gpuCounter = 0;
     245           2 :     uint128_t appNodeID;
     246             : 
     247           4 :     std::string excludedDisplays; // for VGL_EXCLUDE
     248             : 
     249           2 :     size_t nodeCounter = 0;
     250             :     char nameFormatStr[128];
     251           2 :     std::sprintf(nameFormatStr, "node_%%0%dd",
     252           4 :                  int(std::floor(std::log(gpuInfos.size()) / std::log(10))) + 1);
     253             : 
     254           6 :     for (const hwsd::GPUInfo& info : gpuInfos)
     255             :     {
     256           4 :         if (info.flags & hwsd::GPUInfo::FLAG_VIRTUALGL_DISPLAY)
     257           0 :             continue; // ignore, default $DISPLAY gpu uses this one
     258             : 
     259           4 :         Node* mtNode = nodes[info.id];
     260           4 :         Node* mpNode = 0;
     261           4 :         if (!mtNode)
     262             :         {
     263           2 :             const bool isApplicationNode = info.nodeName.empty();
     264           2 :             if (isApplicationNode)
     265           2 :                 appNodeID = info.id;
     266           2 :             mtNode = new Node(config);
     267             :             char name[128];
     268           2 :             std::sprintf(name, nameFormatStr, ++nodeCounter);
     269           2 :             mtNode->setName(name);
     270           2 :             mtNode->setHost(info.nodeName);
     271           2 :             mtNode->setApplicationNode(isApplicationNode);
     272             : 
     273           2 :             nodes[info.id] = mtNode;
     274             : 
     275           2 :             if (multiNode)
     276             :             {
     277             :                 const co::ConnectionDescriptions& descs =
     278           0 :                     _findConnections(info.id, netInfos);
     279             : 
     280           0 :                 if (descs.empty() && !info.nodeName.empty())
     281             :                 {
     282           0 :                     LBINFO << "No suitable connection found for node "
     283           0 :                            << info.nodeName << "; node will not be used"
     284           0 :                            << std::endl;
     285           0 :                     nodes.erase(info.id);
     286           0 :                     delete mtNode;
     287           0 :                     continue;
     288             :                 }
     289             : 
     290           0 :                 for (co::ConnectionDescriptionsCIter j = descs.begin();
     291           0 :                      j != descs.end(); ++j)
     292             :                 {
     293           0 :                     mtNode->addConnectionDescription(*j);
     294             :                 }
     295             :             }
     296             :         }
     297           2 :         else if (multiProcess)
     298             :         {
     299           0 :             mpNode = new Node(config);
     300             :             char name[128];
     301           0 :             std::sprintf(name, nameFormatStr, ++nodeCounter);
     302           0 :             mpNode->setName(name);
     303           0 :             mpNode->setHost(info.nodeName);
     304             : 
     305           0 :             LBASSERT(multiNode);
     306             :             const co::ConnectionDescriptions& descs =
     307           0 :                 _findConnections(info.id, netInfos);
     308             : 
     309           0 :             if (descs.empty() && !info.nodeName.empty())
     310             :             {
     311           0 :                 LBINFO << "No suitable connection found for node "
     312           0 :                        << info.nodeName << "; node will not be used"
     313           0 :                        << std::endl;
     314           0 :                 delete mpNode;
     315           0 :                 continue;
     316             :             }
     317             : 
     318           0 :             for (co::ConnectionDescriptionsCIter j = descs.begin();
     319           0 :                  j != descs.end(); ++j)
     320             :             {
     321           0 :                 mpNode->addConnectionDescription(*j);
     322             :             }
     323             :         }
     324             : 
     325           8 :         std::stringstream name;
     326           4 :         if (info.device == LB_UNDEFINED_UINT32 &&
     327             :             // VirtualGL display redirects to local GPU (see continue above)
     328           0 :             !(info.flags & hwsd::GPUInfo::FLAG_VIRTUALGL))
     329             :         {
     330           0 :             name << "display";
     331             :         }
     332             :         else
     333             :         {
     334           4 :             name << "GPU" << ++gpuCounter;
     335           4 :             if ( // When running under VirtualGL, GPUs that are not the default
     336             :                 // display or VNC virtual devices mustn't be interposed.
     337           4 :                 info.flags & hwsd::GPUInfo::FLAG_VIRTUALGL &&
     338           0 :                 !(info.flags &
     339             :                   (hwsd::GPUInfo::FLAG_VNC | hwsd::GPUInfo::FLAG_DEFAULT)))
     340             :             {
     341           0 :                 std::ostringstream displayString;
     342           0 :                 displayString << ":" << info.port << "." << info.device;
     343           0 :                 excludedDisplays += displayString.str() + ",";
     344             :             }
     345             :         }
     346             : 
     347           4 :         if (mpNode) // multi-process resource
     348             :         {
     349           0 :             Pipe* pipe = new Pipe(mpNode);
     350           0 :             pipe->setPort(info.port);
     351           0 :             pipe->setDevice(info.device);
     352           0 :             pipe->setPixelViewport(PixelViewport(info.pvp));
     353           0 :             pipe->setName(name.str() + " mp");
     354           0 :             name << " mt"; // mark companion GPU as multi-threaded only
     355             :         }
     356             :         else
     357           4 :             name << " mt mp"; // mark GPU as multi-threaded and multi-process
     358             : 
     359           4 :         Pipe* pipe = new Pipe(mtNode); // standalone/multi-threaded resource
     360           4 :         pipe->setPort(info.port);
     361           4 :         pipe->setDevice(info.device);
     362           4 :         pipe->setPixelViewport(PixelViewport(info.pvp));
     363           4 :         pipe->setName(name.str());
     364             :     }
     365             : 
     366           2 :     Node* node = config->findAppNode();
     367           2 :     if (!node)
     368             :     {
     369           0 :         node = new Node(config);
     370             :         char name[128];
     371           0 :         std::sprintf(name, nameFormatStr, 0);
     372           0 :         node->setName(name);
     373           0 :         node->setApplicationNode(true);
     374           0 :         node->addConnectionDescription(new ConnectionDescription);
     375             :     }
     376           2 :     if (node->getPipes().empty()) // add display window
     377             :     {
     378           0 :         Pipe* pipe = new Pipe(node);
     379           0 :         pipe->setName("display");
     380             :     }
     381             : 
     382           2 :     if (config->getNodes().size() > 1) // add server connection for clusters
     383             :     {
     384           0 :         co::Connections connections;
     385             : 
     386           0 :         if (appNodeID == 0)
     387             :         {
     388           0 :             co::ConnectionDescriptionPtr desc = new co::ConnectionDescription;
     389           0 :             co::ConnectionPtr connection = server->addListener(desc);
     390           0 :             LBASSERT(connection);
     391           0 :             if (connection)
     392           0 :                 connections.push_back(connection);
     393             :             else
     394           0 :                 LBWARN << "Could not add listener " << desc->hostname
     395           0 :                        << " to server" << std::endl;
     396             :         }
     397             :         else
     398             :         {
     399             :             const co::ConnectionDescriptions& descs =
     400           0 :                 _findConnections(appNodeID, netInfos);
     401             : 
     402           0 :             for (co::ConnectionDescriptionsCIter i = descs.begin();
     403           0 :                  i != descs.end(); ++i)
     404             :             {
     405           0 :                 co::ConnectionPtr connection = server->addListener(*i);
     406           0 :                 LBASSERT(connection);
     407           0 :                 if (connection)
     408           0 :                     connections.push_back(connection);
     409             :                 else
     410           0 :                     LBWARN << "Could not add listener " << (*i)->hostname
     411           0 :                            << " to server" << std::endl;
     412             :             }
     413             :         }
     414             : 
     415           0 :         config->setServerConnections(connections);
     416             :     }
     417             : 
     418           2 :     if (!excludedDisplays.empty())
     419           0 :         ::setenv("VGL_EXCLUDE", excludedDisplays.c_str(), 1 /*overwrite*/);
     420             : 
     421           2 :     return true;
     422             : }
     423             : 
     424             : namespace
     425             : {
     426           2 : class AddSourcesVisitor : public ConfigVisitor
     427             : {
     428             : public:
     429           2 :     explicit AddSourcesVisitor(const PixelViewport& pvp)
     430           2 :         : _pvp(pvp)
     431             :     {
     432           2 :     }
     433             : 
     434           4 :     virtual VisitorResult visitPre(Pipe* pipe)
     435             :     {
     436           4 :         const Node* node = pipe->getNode();
     437           4 :         if (node->isApplicationNode() && node->getPipes().front() == pipe)
     438             :         {
     439             :             // display window has discrete 'affinity' GPU
     440           2 :             if (pipe->getName() != "display mt mp")
     441           2 :                 _channels.push_back(pipe->getChannel(ChannelPath(0)));
     442           2 :             return TRAVERSE_CONTINUE;
     443             :         }
     444             : 
     445           2 :         Window* window = new Window(pipe);
     446           2 :         if (!pipe->getPixelViewport().isValid())
     447           0 :             window->setPixelViewport(_pvp);
     448           2 :         window->setIAttribute(WindowSettings::IATTR_HINT_DRAWABLE, fabric::FBO);
     449           2 :         window->setName(pipe->getName() + " source window");
     450             : 
     451           2 :         _channels.push_back(new Channel(window));
     452           2 :         _channels.back()->setName(pipe->getName() + " source channel");
     453           2 :         return TRAVERSE_CONTINUE;
     454             :     }
     455             : 
     456           2 :     const Channels& getChannels() const { return _channels; }
     457             : private:
     458             :     const PixelViewport& _pvp;
     459             :     Channels _channels;
     460             : };
     461             : }
     462             : 
     463           2 : Channels Resources::configureSourceChannels(Config* config)
     464             : {
     465           2 :     const Node* node = config->findAppNode();
     466           2 :     LBASSERT(node);
     467           2 :     if (!node)
     468           0 :         return Channels();
     469             : 
     470           2 :     const Pipes& pipes = node->getPipes();
     471           2 :     LBASSERT(!pipes.empty());
     472           2 :     if (pipes.empty())
     473           0 :         return Channels();
     474             : 
     475           2 :     Pipe* pipe = pipes.front();
     476           2 :     PixelViewport pvp = pipe->getPixelViewport();
     477           2 :     if (pvp.isValid())
     478             :     {
     479           2 :         pvp.x = 0;
     480           2 :         pvp.y = 0;
     481             :     }
     482             :     else
     483           0 :         pvp = PixelViewport(0, 0, 1920, 1200);
     484             : 
     485           4 :     AddSourcesVisitor addSources(pvp);
     486           2 :     config->accept(addSources);
     487           2 :     return addSources.getChannels();
     488             : }
     489             : 
     490             : #if 0 // LB_GCC_4_5_OR_LATER
     491             : #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
     492             : #endif
     493           2 : void Resources::configure(const Compounds& compounds, const Channels& channels,
     494             :                           const fabric::ConfigParams& params)
     495             : {
     496           2 :     LBASSERT(!compounds.empty());
     497           2 :     if (compounds.empty() || channels.empty()) // No additional resources
     498           0 :         return;
     499             : 
     500             : #ifndef NDEBUG
     501           2 :     const Canvas* canvas = 0;
     502             : #endif
     503          16 :     for (CompoundsCIter i = compounds.begin(); i != compounds.end(); ++i)
     504             :     {
     505          14 :         const Compounds& children = (*i)->getChildren();
     506          14 :         LBASSERT(children.size() == 1);
     507          14 :         if (children.size() != 1)
     508           0 :             continue;
     509             : 
     510          14 :         Compound* segmentCompound = children.front();
     511             : #ifndef NDEBUG
     512          14 :         const Channel* channel = segmentCompound->getChannel();
     513          14 :         LBASSERT(channel);
     514          14 :         LBASSERT(!canvas || channel->getCanvas() == canvas);
     515          14 :         canvas = channel->getCanvas();
     516             : #endif
     517             : 
     518          14 :         _addMonoCompound(segmentCompound, channels, params);
     519          14 :         _addStereoCompound(segmentCompound, channels, params);
     520             :     }
     521             : }
     522             : 
     523          88 : static Channels _filter(const Channels& input, const std::string& filter)
     524             : {
     525          88 :     Channels result;
     526             : 
     527         216 :     for (ChannelsCIter i = input.begin(); i != input.end(); ++i)
     528         128 :         if ((*i)->getName().find(filter) != std::string::npos)
     529         128 :             result.push_back(*i);
     530          88 :     return result;
     531             : }
     532             : 
     533          38 : Compound* Resources::_addMonoCompound(Compound* root, const Channels& channels,
     534             :                                       const fabric::ConfigParams& params)
     535             : {
     536          38 :     const Channel* channel = root->getChannel();
     537          38 :     const Layout* layout = channel->getLayout();
     538          38 :     const std::string& name = layout->getName();
     539             : 
     540          38 :     Compound* compound = 0;
     541             :     const bool multiProcess =
     542          38 :         params.getFlags() & fabric::ConfigParams::FLAG_MULTIPROCESS;
     543             :     const bool multiProcessDB =
     544          76 :         multiProcess ||
     545          76 :         (params.getFlags() & fabric::ConfigParams::FLAG_MULTIPROCESS_DB);
     546             :     const Channels& activeChannels =
     547          76 :         _filter(channels, multiProcess ? " mp " : " mt ");
     548             :     const Channels& activeDBChannels =
     549          76 :         _filter(channels, multiProcessDB ? " mp " : " mt ");
     550             : 
     551          38 :     if (name == EQ_SERVER_CONFIG_LAYOUT_SIMPLE)
     552             :         /* nop */;
     553          66 :     else if (name == EQ_SERVER_CONFIG_LAYOUT_2D_DYNAMIC ||
     554          30 :              name == EQ_SERVER_CONFIG_LAYOUT_2D_STATIC)
     555             :     {
     556          12 :         compound = _add2DCompound(root, activeChannels, params);
     557             :     }
     558          42 :     else if (name == EQ_SERVER_CONFIG_LAYOUT_DB_DYNAMIC ||
     559          18 :              name == EQ_SERVER_CONFIG_LAYOUT_DB_STATIC)
     560             :     {
     561          12 :         compound = _addDBCompound(root, activeDBChannels, params);
     562             :     }
     563          12 :     else if (name == EQ_SERVER_CONFIG_LAYOUT_DB_DS)
     564           6 :         compound = _addDSCompound(root, activeDBChannels);
     565           6 :     else if (name == EQ_SERVER_CONFIG_LAYOUT_DB_2D)
     566             :     {
     567           0 :         LBASSERT(!multiProcess);
     568           0 :         LBASSERT(multiProcessDB);
     569           0 :         compound = _addDB2DCompound(root, channels, params);
     570             :     }
     571           6 :     else if (name == EQ_SERVER_CONFIG_LAYOUT_SUBPIXEL)
     572           6 :         compound = _addSubpixelCompound(root, activeChannels);
     573             :     else
     574             :     {
     575           0 :         LBASSERTINFO(false, "Unimplemented mode " << name);
     576             :     }
     577             : 
     578          38 :     if (compound)
     579          36 :         compound->setEyes(EYE_CYCLOP);
     580             : 
     581          76 :     return compound;
     582             : }
     583             : 
     584          14 : Compound* Resources::_addStereoCompound(Compound* root,
     585             :                                         const Channels& channels,
     586             :                                         const fabric::ConfigParams& params)
     587             : {
     588          14 :     const Channel* channel = root->getChannel();
     589          14 :     const Layout* layout = channel->getLayout();
     590          14 :     const std::string& name = layout->getName();
     591          14 :     if (name == EQ_SERVER_CONFIG_LAYOUT_SIMPLE)
     592           2 :         return 0;
     593             : 
     594          12 :     Compound* compound = new Compound(root);
     595          12 :     compound->setName("Stereo");
     596          12 :     compound->setEyes(EYE_LEFT | EYE_RIGHT);
     597             : 
     598             :     const bool multiProcess =
     599          12 :         params.getFlags() & (fabric::ConfigParams::FLAG_MULTIPROCESS |
     600          12 :                              fabric::ConfigParams::FLAG_MULTIPROCESS_DB);
     601             :     const Channels& active =
     602          12 :         name == EQ_SERVER_CONFIG_LAYOUT_DB_2D
     603             :             ? channels
     604          24 :             : _filter(channels, multiProcess ? " mp " : " mt ");
     605             : 
     606          12 :     const size_t nChannels = active.size();
     607          12 :     const ChannelsCIter split = active.begin() + (nChannels >> 1);
     608             : 
     609          24 :     Channels leftChannels(split - active.begin());
     610          12 :     std::copy(active.begin(), split, leftChannels.begin());
     611             : 
     612          24 :     Channels rightChannels(active.end() - split);
     613          12 :     std::copy(split, active.end(), rightChannels.begin());
     614             : 
     615          12 :     Compound* left = 0;
     616          24 :     if (leftChannels.empty() ||
     617          24 :         (leftChannels.size() == 1 && leftChannels.front() == channel))
     618             :     {
     619           0 :         left = new Compound(compound);
     620             :     }
     621             :     else
     622          12 :         left = _addMonoCompound(compound, leftChannels, params);
     623             : 
     624          12 :     left->setEyes(EYE_LEFT);
     625             : 
     626          12 :     Compound* right = 0;
     627          24 :     if (rightChannels.empty() ||
     628          24 :         (rightChannels.size() == 1 && rightChannels.front() == channel))
     629             :     {
     630           0 :         right = new Compound(compound);
     631             :     }
     632             :     else
     633          12 :         right = _addMonoCompound(compound, rightChannels, params);
     634             : 
     635          12 :     right->setEyes(EYE_RIGHT);
     636             : 
     637          12 :     return compound;
     638             : }
     639             : 
     640          12 : Compound* Resources::_add2DCompound(Compound* root, const Channels& channels,
     641             :                                     fabric::ConfigParams params)
     642             : {
     643          12 :     const Channel* channel = root->getChannel();
     644          12 :     const Layout* layout = channel->getLayout();
     645          12 :     const std::string& name = layout->getName();
     646             : 
     647          12 :     Compound* compound = new Compound(root);
     648          12 :     compound->setName(name);
     649          12 :     if (params.getEqualizer().getMode() == LoadEqualizer::MODE_DB)
     650           0 :         params.getEqualizer().setMode(LoadEqualizer::MODE_2D);
     651             : 
     652          12 :     LoadEqualizer* lb = new LoadEqualizer(params.getEqualizer());
     653          12 :     if (name == EQ_SERVER_CONFIG_LAYOUT_2D_STATIC)
     654           6 :         lb->setDamping(1.f);
     655          12 :     compound->addEqualizer(lb);
     656             : 
     657          12 :     _fill2DCompound(compound, channels);
     658          12 :     return compound;
     659             : }
     660             : 
     661          12 : void Resources::_fill2DCompound(Compound* compound, const Channels& channels)
     662             : {
     663          12 :     const Compounds& children = _addSources(compound, channels);
     664          12 :     const size_t step = size_t(100000.0f / float(children.size()));
     665          12 :     size_t start = 0;
     666          28 :     for (CompoundsCIter i = children.begin(); i != children.end(); ++i)
     667             :     {
     668          16 :         Compound* child = *i;
     669          16 :         if (i + 1 == children.end()) // last - correct rounding 'error'
     670             :             child->setViewport(
     671          24 :                 fabric::Viewport(float(start) / 100000.f, 0.f,
     672          24 :                                  (100000.f - float(start)) / 100000.f, 1.f));
     673             :         else
     674           8 :             child->setViewport(fabric::Viewport(float(start) / 100000.f, 0.f,
     675           8 :                                                 float(step) / 100000.f, 1.f));
     676          16 :         start += step;
     677             :     }
     678          12 : }
     679             : 
     680          12 : Compound* Resources::_addDBCompound(Compound* root, const Channels& channels,
     681             :                                     fabric::ConfigParams params)
     682             : {
     683          12 :     const Channel* channel = root->getChannel();
     684          12 :     const Layout* layout = channel->getLayout();
     685          12 :     const std::string& name = layout->getName();
     686             : 
     687          12 :     Compound* compound = new Compound(root);
     688          12 :     compound->setName(name);
     689          12 :     compound->setBuffers(Frame::Buffer::color | Frame::Buffer::depth);
     690          12 :     if (name == EQ_SERVER_CONFIG_LAYOUT_DB_DYNAMIC)
     691             :     {
     692           6 :         if (params.getEqualizer().getMode() != LoadEqualizer::MODE_DB)
     693           6 :             params.getEqualizer().setMode(LoadEqualizer::MODE_DB);
     694           6 :         compound->addEqualizer(new LoadEqualizer(params.getEqualizer()));
     695             :     }
     696             : 
     697          12 :     const Compounds& children = _addSources(compound, channels);
     698          12 :     const size_t step = size_t(100000.0f / float(children.size()));
     699          12 :     size_t start = 0;
     700          28 :     for (CompoundsCIter i = children.begin(); i != children.end(); ++i)
     701             :     {
     702          16 :         Compound* child = *i;
     703          16 :         if (i + 1 == children.end()) // last - correct rounding 'error'
     704          12 :             child->setRange(Range(float(start) / 100000.f, 1.f));
     705             :         else
     706             :             child->setRange(
     707           4 :                 Range(float(start) / 100000.f, float(start + step) / 100000.f));
     708          16 :         start += step;
     709             :     }
     710             : 
     711          12 :     return compound;
     712             : }
     713             : 
     714           6 : Compound* Resources::_addDSCompound(Compound* root, const Channels& channels)
     715             : {
     716           6 :     const Channel* channel = root->getChannel();
     717           6 :     const Layout* layout = channel->getLayout();
     718           6 :     const std::string& name = layout->getName();
     719             : 
     720           6 :     Compound* compound = new Compound(root);
     721           6 :     compound->setName(name);
     722             : 
     723           6 :     const Compounds& children = _addSources(compound, channels);
     724           6 :     const size_t step = size_t(100000.0f / float(children.size()));
     725             : 
     726           6 :     size_t start = 0;
     727          14 :     for (CompoundsCIter i = children.begin(); i != children.end(); ++i)
     728             :     {
     729           8 :         Compound* child = *i;
     730             : 
     731             :         // leaf draw + tile readback compound
     732           8 :         Compound* drawChild = new Compound(child);
     733           8 :         if (i + 1 == children.end()) // last - correct rounding 'error'
     734           6 :             drawChild->setRange(Range(float(start) / 100000.f, 1.f));
     735             :         else
     736             :             drawChild->setRange(
     737           2 :                 Range(float(start) / 100000.f, float(start + step) / 100000.f));
     738             : 
     739           8 :         size_t y = 0;
     740          20 :         for (CompoundsCIter j = children.begin(); j != children.end(); ++j)
     741             :         {
     742          12 :             if (i != j)
     743             :             {
     744           8 :                 std::ostringstream frameName;
     745           8 :                 frameName << "tile" << j - children.begin() << ".channel"
     746          12 :                           << i - children.begin();
     747           4 :                 Viewport vp;
     748           4 :                 if (j + 1 == children.end()) // last - correct rounding 'error'
     749             :                 {
     750           2 :                     vp = Viewport(0.f, static_cast<float>(y) / 100000.f, 1.f,
     751           2 :                                   static_cast<float>(100000 - y) / 100000.f);
     752             :                 }
     753             :                 else
     754           2 :                     vp = Viewport(0.f, static_cast<float>(y) / 100000.f, 1.f,
     755           2 :                                   static_cast<float>(step) / 100000.f);
     756             : 
     757           4 :                 eq::server::Frame* outputFrame = new eq::server::Frame;
     758           4 :                 outputFrame->setName(frameName.str());
     759           4 :                 outputFrame->setViewport(vp);
     760           4 :                 outputFrame->setBuffers(Frame::Buffer::color |
     761           4 :                                         Frame::Buffer::depth);
     762           4 :                 drawChild->addOutputFrame(outputFrame);
     763             : 
     764             :                 // input tiles from other channels
     765           4 :                 frameName.str("");
     766           8 :                 frameName << "tile" << i - children.begin() << ".channel"
     767          12 :                           << j - children.begin();
     768             : 
     769           4 :                 eq::server::Frame* inputFrame = new eq::server::Frame;
     770           4 :                 inputFrame->setName(frameName.str());
     771           4 :                 child->addInputFrame(inputFrame);
     772             :             }
     773             :             // else own tile, is in place
     774             : 
     775          12 :             y += step;
     776             :         }
     777             : 
     778             :         // assembled color tile output, if not already in place
     779           8 :         if (child->getChannel() != compound->getChannel())
     780             :         {
     781           4 :             Frame* output = child->getOutputFrames().front();
     782             : 
     783           4 :             Viewport vp;
     784           4 :             if (i + 1 == children.end()) // last - correct rounding 'error'
     785             :             {
     786           4 :                 vp = Viewport(0.f, static_cast<float>(start) / 100000.f, 1.f,
     787           4 :                               static_cast<float>(100000 - start) / 100000.f);
     788             :             }
     789             :             else
     790           0 :                 vp = Viewport(0.f, static_cast<float>(start) / 100000.f, 1.f,
     791           0 :                               static_cast<float>(step) / 100000.f);
     792             : 
     793           4 :             output->setViewport(vp);
     794             :         }
     795           8 :         start += step;
     796             :     }
     797             : 
     798           6 :     return compound;
     799             : }
     800             : 
     801           0 : static Channels _filterLocalChannels(const Channels& input,
     802             :                                      const Compound& filter)
     803             : {
     804           0 :     Channels result;
     805           0 :     for (ChannelsCIter i = input.begin(); i != input.end(); ++i)
     806             :     {
     807           0 :         const Node* node = (*i)->getNode();
     808           0 :         const Node* filterNode = filter.getChannel()->getNode();
     809           0 :         if (node == filterNode)
     810           0 :             result.push_back(*i);
     811             :     }
     812           0 :     return result;
     813             : }
     814             : 
     815           0 : Compound* Resources::_addDB2DCompound(Compound* root, const Channels& channels,
     816             :                                       fabric::ConfigParams params)
     817             : {
     818             :     // TODO: Optimized compositing?
     819           0 :     root->setBuffers(Frame::Buffer::color | Frame::Buffer::depth);
     820           0 :     const Channels& dbChannels = _filter(channels, " mt mp ");
     821           0 :     Compound* compound = _addDSCompound(root, dbChannels);
     822             : 
     823           0 :     const Compounds& children = compound->getChildren();
     824           0 :     for (CompoundsCIter i = children.begin(); i != children.end(); ++i)
     825             :     {
     826           0 :         Compound* child = *i;
     827           0 :         Compound* drawChild = child->getChildren().front();
     828           0 :         if (params.getEqualizer().getMode() == LoadEqualizer::MODE_DB)
     829           0 :             params.getEqualizer().setMode(LoadEqualizer::MODE_2D);
     830           0 :         drawChild->addEqualizer(new LoadEqualizer(params.getEqualizer()));
     831           0 :         drawChild->setName(EQ_SERVER_CONFIG_LAYOUT_2D_DYNAMIC);
     832             : 
     833           0 :         const Channels& localChannels = _filterLocalChannels(channels, *child);
     834           0 :         _fill2DCompound(drawChild, localChannels);
     835             :     }
     836             : 
     837           0 :     return compound;
     838             : }
     839             : 
     840           6 : Compound* Resources::_addSubpixelCompound(Compound* root,
     841             :                                           const Channels& channels)
     842             : {
     843           6 :     Compound* compound = new Compound(root);
     844           6 :     compound->setName(EQ_SERVER_CONFIG_LAYOUT_SUBPIXEL);
     845             : 
     846           6 :     const Compounds& children = _addSources(compound, channels, true);
     847           6 :     const uint32_t nChildren = uint32_t(children.size());
     848          14 :     for (CompoundsCIter i = children.begin(); i != children.end(); ++i)
     849           8 :         (*i)->setSubPixel(SubPixel(i - children.begin(), nChildren));
     850             : 
     851           6 :     return compound;
     852             : }
     853             : 
     854          36 : const Compounds& Resources::_addSources(Compound* compound,
     855             :                                         const Channels& channels,
     856             :                                         const bool destChannelFrame)
     857             : {
     858          36 :     const Channel* rootChannel = compound->getChannel();
     859          36 :     const Segment* segment = rootChannel->getSegment();
     860          36 :     const Channel* outputChannel = segment ? segment->getChannel() : 0;
     861             : 
     862          84 :     for (ChannelsCIter i = channels.begin(); i != channels.end(); ++i)
     863             :     {
     864          48 :         Channel* channel = *i;
     865          48 :         Compound* child = new Compound(compound);
     866             : 
     867          48 :         const bool isDestChannel = channel == outputChannel;
     868          48 :         if (isDestChannel && !destChannelFrame)
     869          20 :             continue;
     870          28 :         if (!isDestChannel)
     871          24 :             child->setChannel(channel);
     872             : 
     873          28 :         Frame* outFrame = new Frame;
     874          56 :         std::stringstream frameName;
     875          28 :         frameName << "Frame." << compound->getName() << '.' << ++_frameCounter;
     876          28 :         outFrame->setName(frameName.str());
     877          28 :         if (isDestChannel)
     878           4 :             outFrame->setType(Frame::TYPE_TEXTURE); // OPT
     879          28 :         child->addOutputFrame(outFrame);
     880             : 
     881          28 :         Frame* inFrame = new Frame;
     882          28 :         inFrame->setName(frameName.str());
     883          28 :         compound->addInputFrame(inFrame);
     884             :     }
     885             : 
     886          36 :     return compound->getChildren();
     887             : }
     888             : }
     889             : }
     890          60 : }

Generated by: LCOV version 1.11