LCOV - code coverage report
Current view: top level - eq/server/equalizers - treeEqualizer.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 1 372 0.3 %
Date: 2017-12-16 05:07:20 Functions: 2 16 12.5 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2008-2013, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                    2010, Cedric Stalder <cedric.stalder@gmail.com>
       4             :  *
       5             :  * This library is free software; you can redistribute it and/or modify it under
       6             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       7             :  * by the Free Software Foundation.
       8             :  *
       9             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      10             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      11             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      12             :  * details.
      13             :  *
      14             :  * You should have received a copy of the GNU Lesser General Public License
      15             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      16             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      17             :  */
      18             : 
      19             : #include "treeEqualizer.h"
      20             : 
      21             : #include "../compound.h"
      22             : #include "../log.h"
      23             : 
      24             : #include <eq/fabric/statistic.h>
      25             : #include <lunchbox/debug.h>
      26             : 
      27             : namespace eq
      28             : {
      29             : namespace server
      30             : {
      31             : std::ostream& operator<<(std::ostream& os, const TreeEqualizer::Node*);
      32             : 
      33             : // The tree load balancer organizes the children in a binary tree. At each
      34             : // level, a relative split position is determined by balancing the left subtree
      35             : // against the right subtree.
      36             : 
      37           0 : TreeEqualizer::TreeEqualizer()
      38           0 :     : _tree(0)
      39             : {
      40           0 :     LBINFO << "New TreeEqualizer @" << (void*)this << std::endl;
      41           0 : }
      42             : 
      43           0 : TreeEqualizer::TreeEqualizer(const TreeEqualizer& from)
      44             :     : Equalizer(from)
      45             :     , ChannelListener(from)
      46           0 :     , _tree(0)
      47             : {
      48           0 : }
      49             : 
      50           0 : TreeEqualizer::~TreeEqualizer()
      51             : {
      52           0 :     _clearTree(_tree);
      53           0 :     delete _tree;
      54           0 :     _tree = 0;
      55           0 : }
      56             : 
      57           0 : void TreeEqualizer::notifyUpdatePre(Compound* compound,
      58             :                                     const uint32_t /*frame*/)
      59             : {
      60           0 :     if (isFrozen() || !compound->isActive() || !isActive())
      61           0 :         return;
      62             : 
      63           0 :     if (!_tree)
      64             :     {
      65           0 :         LBASSERT(compound == getCompound());
      66           0 :         const Compounds& children = compound->getChildren();
      67           0 :         switch (children.size())
      68             :         {
      69             :         case 0:
      70           0 :             return; // no leaf compound, can't do anything.
      71             :         case 1:     // one child, 'balance' it:
      72           0 :             if (getMode() == MODE_DB)
      73           0 :                 children.front()->setRange(Range());
      74             :             else
      75           0 :                 children.front()->setViewport(Viewport());
      76           0 :             return;
      77             :         default:
      78           0 :             _tree = _buildTree(children);
      79             :         }
      80             :     }
      81             : 
      82             :     // compute new data
      83           0 :     _update(_tree);
      84           0 :     _split(_tree);
      85           0 :     _assign(_tree, Viewport(), Range());
      86           0 :     LBLOG(LOG_LB2) << "LB tree: " << _tree;
      87             : }
      88             : 
      89           0 : TreeEqualizer::Node* TreeEqualizer::_buildTree(const Compounds& compounds)
      90             : {
      91           0 :     Node* node = new Node;
      92             : 
      93           0 :     const size_t size = compounds.size();
      94           0 :     if (size == 1)
      95             :     {
      96           0 :         Compound* compound = compounds.front();
      97             : 
      98           0 :         node->compound = compound;
      99             : 
     100           0 :         Channel* channel = compound->getChannel();
     101           0 :         LBASSERT(channel);
     102           0 :         channel->addListener(this);
     103           0 :         return node;
     104             :     }
     105             : 
     106           0 :     const size_t middle = size >> 1;
     107             : 
     108           0 :     Compounds left;
     109           0 :     for (size_t i = 0; i < middle; ++i)
     110           0 :         left.push_back(compounds[i]);
     111             : 
     112           0 :     Compounds right;
     113           0 :     for (size_t i = middle; i < size; ++i)
     114           0 :         right.push_back(compounds[i]);
     115             : 
     116           0 :     node->left = _buildTree(left);
     117           0 :     node->right = _buildTree(right);
     118           0 :     return node;
     119             : }
     120             : 
     121           0 : void TreeEqualizer::_clearTree(Node* node)
     122             : {
     123           0 :     if (!node)
     124           0 :         return;
     125             : 
     126           0 :     if (node->compound)
     127             :     {
     128           0 :         Channel* channel = node->compound->getChannel();
     129           0 :         LBASSERTINFO(channel, node->compound);
     130           0 :         channel->removeListener(this);
     131             :     }
     132             :     else
     133             :     {
     134           0 :         _clearTree(node->left);
     135           0 :         _clearTree(node->right);
     136             :     }
     137             : }
     138             : 
     139           0 : void TreeEqualizer::notifyLoadData(Channel* channel, const uint32_t /*frame*/,
     140             :                                    const Statistics& statistics,
     141             :                                    const Viewport& /*region*/)
     142             : {
     143           0 :     _notifyLoadData(_tree, channel, statistics);
     144           0 : }
     145             : 
     146           0 : void TreeEqualizer::_notifyLoadData(Node* node, Channel* channel,
     147             :                                     const Statistics& statistics)
     148             : {
     149           0 :     if (!node)
     150           0 :         return;
     151             : 
     152           0 :     _notifyLoadData(node->left, channel, statistics);
     153           0 :     _notifyLoadData(node->right, channel, statistics);
     154             : 
     155           0 :     if (!node->compound || node->compound->getChannel() != channel)
     156           0 :         return;
     157             : 
     158             :     // gather relevant load data
     159           0 :     const uint32_t taskID = node->compound->getTaskID();
     160           0 :     int64_t startTime = std::numeric_limits<int64_t>::max();
     161           0 :     int64_t endTime = 0;
     162           0 :     bool loadSet = false;
     163           0 :     int64_t timeTransmit = 0;
     164           0 :     for (size_t i = 0; i < statistics.size() && !loadSet; ++i)
     165             :     {
     166           0 :         const Statistic& stat = statistics[i];
     167           0 :         if (stat.task != taskID) // from different compound
     168           0 :             continue;
     169             : 
     170           0 :         switch (stat.type)
     171             :         {
     172             :         case Statistic::CHANNEL_CLEAR:
     173             :         case Statistic::CHANNEL_DRAW:
     174             :         case Statistic::CHANNEL_READBACK:
     175           0 :             startTime = LB_MIN(startTime, stat.startTime);
     176           0 :             endTime = LB_MAX(endTime, stat.endTime);
     177           0 :             break;
     178             : 
     179             :         case Statistic::CHANNEL_ASYNC_READBACK:
     180             :         case Statistic::CHANNEL_FRAME_TRANSMIT:
     181           0 :             timeTransmit += stat.endTime - stat.startTime;
     182           0 :             break;
     183             : 
     184             :         // assemble blocks on input frames, stop using subsequent data
     185             :         case Statistic::CHANNEL_ASSEMBLE:
     186           0 :             loadSet = true;
     187           0 :             break;
     188             : 
     189             :         default:
     190           0 :             break;
     191             :         }
     192             :     }
     193             : 
     194           0 :     if (startTime == std::numeric_limits<int64_t>::max())
     195           0 :         return;
     196             : 
     197           0 :     node->time = endTime - startTime;
     198           0 :     node->time = LB_MAX(node->time, 1);
     199           0 :     node->time = LB_MAX(node->time, timeTransmit);
     200             : }
     201             : 
     202           0 : void TreeEqualizer::_update(Node* node)
     203             : {
     204           0 :     if (!node)
     205           0 :         return;
     206             : 
     207           0 :     const Compound* compound = node->compound;
     208           0 :     if (compound)
     209             :     {
     210           0 :         const Channel* channel = compound->getChannel();
     211           0 :         const PixelViewport& pvp = channel->getPixelViewport();
     212           0 :         LBASSERT(channel);
     213             : 
     214           0 :         LBASSERT(node->mode != MODE_2D);
     215           0 :         node->resources = compound->isActive() ? compound->getUsage() : 0.f;
     216           0 :         node->maxSize.x() = pvp.w;
     217           0 :         node->maxSize.y() = pvp.h;
     218           0 :         node->boundaryf = getBoundaryf();
     219           0 :         node->boundary2i = getBoundary2i();
     220           0 :         node->resistancef = getResistancef();
     221           0 :         node->resistance2i = getResistance2i();
     222           0 :         return;
     223             :     }
     224             :     // else
     225             : 
     226           0 :     LBASSERT(node->left);
     227           0 :     LBASSERT(node->right);
     228             : 
     229           0 :     node->left->mode = node->right->mode = node->mode = getMode();
     230             : 
     231           0 :     if (node->mode == MODE_2D)
     232           0 :         node->mode = MODE_VERTICAL;
     233             : 
     234           0 :     if (node->left->mode == MODE_2D)
     235             :     {
     236           0 :         LBASSERT(node->right->mode == MODE_2D);
     237             : 
     238           0 :         node->left->mode =
     239           0 :             (node->mode == MODE_VERTICAL) ? MODE_HORIZONTAL : MODE_VERTICAL;
     240           0 :         node->right->mode = node->left->mode;
     241             :     }
     242             : 
     243           0 :     _update(node->left);
     244           0 :     _update(node->right);
     245             : 
     246           0 :     node->resources = node->left->resources + node->right->resources;
     247             : 
     248           0 :     if (node->left->resources == 0.f)
     249             :     {
     250           0 :         node->maxSize = node->right->maxSize;
     251           0 :         node->boundary2i = node->right->boundary2i;
     252           0 :         node->boundaryf = node->right->boundaryf;
     253           0 :         node->resistance2i = node->right->resistance2i;
     254           0 :         node->resistancef = node->right->resistancef;
     255           0 :         node->time = node->right->time;
     256             :     }
     257           0 :     else if (node->right->resources == 0.f)
     258             :     {
     259           0 :         node->maxSize = node->left->maxSize;
     260           0 :         node->boundary2i = node->left->boundary2i;
     261           0 :         node->boundaryf = node->left->boundaryf;
     262           0 :         node->resistance2i = node->left->resistance2i;
     263           0 :         node->resistancef = node->left->resistancef;
     264           0 :         node->time = node->left->time;
     265             :     }
     266             :     else
     267             :     {
     268           0 :         switch (node->mode)
     269             :         {
     270             :         case MODE_VERTICAL:
     271           0 :             node->maxSize.x() =
     272           0 :                 node->left->maxSize.x() + node->right->maxSize.x();
     273           0 :             node->maxSize.y() =
     274           0 :                 LB_MIN(node->left->maxSize.y(), node->right->maxSize.y());
     275           0 :             node->boundary2i.x() =
     276           0 :                 node->left->boundary2i.x() + node->right->boundary2i.x();
     277           0 :             node->boundary2i.y() =
     278           0 :                 LB_MAX(node->left->boundary2i.y(), node->right->boundary2i.y());
     279           0 :             node->boundaryf =
     280           0 :                 LB_MAX(node->left->boundaryf, node->right->boundaryf);
     281           0 :             node->resistance2i.x() = LB_MAX(node->left->resistance2i.x(),
     282             :                                             node->right->resistance2i.x());
     283           0 :             node->resistance2i.y() = LB_MAX(node->left->resistance2i.y(),
     284             :                                             node->right->resistance2i.y());
     285           0 :             node->resistancef =
     286           0 :                 LB_MAX(node->left->resistancef, node->right->resistancef);
     287           0 :             break;
     288             :         case MODE_HORIZONTAL:
     289           0 :             node->maxSize.x() =
     290           0 :                 LB_MIN(node->left->maxSize.x(), node->right->maxSize.x());
     291           0 :             node->maxSize.y() =
     292           0 :                 node->left->maxSize.y() + node->right->maxSize.y();
     293           0 :             node->boundary2i.x() =
     294           0 :                 LB_MAX(node->left->boundary2i.x(), node->right->boundary2i.x());
     295           0 :             node->boundary2i.y() =
     296           0 :                 node->left->boundary2i.y() + node->right->boundary2i.y();
     297           0 :             node->boundaryf =
     298           0 :                 LB_MAX(node->left->boundaryf, node->right->boundaryf);
     299           0 :             node->resistance2i.x() = LB_MAX(node->left->resistance2i.x(),
     300             :                                             node->right->resistance2i.x());
     301           0 :             node->resistance2i.y() = LB_MAX(node->left->resistance2i.y(),
     302             :                                             node->right->resistance2i.y());
     303           0 :             node->resistancef =
     304           0 :                 LB_MAX(node->left->resistancef, node->right->resistancef);
     305           0 :             break;
     306             :         case MODE_DB:
     307           0 :             node->boundary2i.x() =
     308           0 :                 LB_MAX(node->left->boundary2i.x(), node->right->boundary2i.x());
     309           0 :             node->boundary2i.y() =
     310           0 :                 LB_MAX(node->left->boundary2i.y(), node->right->boundary2i.y());
     311           0 :             node->boundaryf = node->left->boundaryf + node->right->boundaryf;
     312           0 :             node->resistance2i.x() = LB_MAX(node->left->resistance2i.x(),
     313             :                                             node->right->resistance2i.x());
     314           0 :             node->resistance2i.y() = LB_MAX(node->left->resistance2i.y(),
     315             :                                             node->right->resistance2i.y());
     316           0 :             node->resistancef =
     317           0 :                 LB_MAX(node->left->resistancef, node->right->resistancef);
     318           0 :             break;
     319             :         default:
     320           0 :             LBUNIMPLEMENTED;
     321             :         }
     322             : 
     323           0 :         node->time = node->left->time + node->right->time;
     324             :     }
     325             : }
     326             : 
     327           0 : void TreeEqualizer::_split(Node* node)
     328             : {
     329           0 :     if (node->compound)
     330           0 :         return;
     331           0 :     LBASSERT(node->left && node->right);
     332             : 
     333           0 :     Node* left = node->left;
     334           0 :     Node* right = node->right;
     335             :     // easy outs
     336           0 :     if (left->resources == 0.f)
     337             :     {
     338           0 :         node->split = 0.f;
     339           0 :         return;
     340             :     }
     341           0 :     if (right->resources == 0.f)
     342             :     {
     343           0 :         node->split = 1.f;
     344           0 :         return;
     345             :     }
     346             : 
     347             :     // new split
     348           0 :     const float target = node->time * left->resources / node->resources;
     349           0 :     const float leftTime = float(left->time);
     350           0 :     float split = 0.f;
     351           0 :     const float rightTime = float(right->time);
     352             : 
     353           0 :     if (leftTime >= target)
     354           0 :         split = target / leftTime * node->split;
     355             :     else
     356             :     {
     357           0 :         const float timeLeft = target - leftTime;
     358           0 :         split = node->split + timeLeft / rightTime * (1.f - node->split);
     359             :     }
     360             : 
     361           0 :     LBLOG(LOG_LB2) << "Should split at " << split << " (" << target << ": "
     362           0 :                    << leftTime << " by " << left->resources << "/" << rightTime
     363           0 :                    << " by " << right->resources << ")" << std::endl;
     364           0 :     node->split = (1.f - getDamping()) * split + getDamping() * node->split;
     365           0 :     LBLOG(LOG_LB2) << "Dampened split at " << node->split << std::endl;
     366             : 
     367           0 :     _split(left);
     368           0 :     _split(right);
     369             : }
     370             : 
     371           0 : void TreeEqualizer::_assign(Node* node, const Viewport& vp, const Range& range)
     372             : {
     373           0 :     LBLOG(LOG_LB2) << "assign " << vp << ", " << range << " time " << node->time
     374           0 :                    << " split " << node->split << std::endl;
     375           0 :     LBASSERTINFO(vp.isValid(), vp);
     376           0 :     LBASSERTINFO(range.isValid(), range);
     377           0 :     LBASSERTINFO(node->resources > 0.f || !vp.hasArea() || !range.hasData(),
     378             :                  "Assigning work to unused compound: " << vp << ", " << range);
     379             : 
     380           0 :     Compound* compound = node->compound;
     381           0 :     if (compound)
     382             :     {
     383           0 :         LBASSERTINFO(vp == Viewport::FULL || range == Range::ALL,
     384             :                      "Mixed 2D/DB load-balancing not implemented");
     385             : 
     386           0 :         compound->setViewport(vp);
     387           0 :         compound->setRange(range);
     388           0 :         LBLOG(LOG_LB2) << compound->getChannel()->getName() << " set " << vp
     389           0 :                        << ", " << range << std::endl;
     390           0 :         return;
     391             :     }
     392             : 
     393           0 :     switch (node->mode)
     394             :     {
     395             :     case MODE_VERTICAL:
     396             :     {
     397             :         // Ensure minimum size
     398           0 :         const Compound* root = getCompound();
     399           0 :         const float pvpW = float(root->getInheritPixelViewport().w);
     400           0 :         const float end = vp.getXEnd();
     401           0 :         const float boundary = float(node->boundary2i.x()) / pvpW;
     402           0 :         float absoluteSplit = vp.x + vp.w * node->split;
     403             : 
     404           0 :         if (node->left->resources == 0.f)
     405           0 :             absoluteSplit = vp.x;
     406           0 :         else if (node->right->resources == 0.f)
     407           0 :             absoluteSplit = end;
     408           0 :         else if (boundary > 0)
     409             :         {
     410           0 :             const float right = vp.getXEnd() - absoluteSplit;
     411           0 :             const float left = absoluteSplit - vp.x;
     412           0 :             const float maxRight = float(node->right->maxSize.x()) / pvpW;
     413           0 :             const float maxLeft = float(node->left->maxSize.x()) / pvpW;
     414             : 
     415           0 :             if (right > maxRight)
     416           0 :                 absoluteSplit = end - maxRight;
     417           0 :             else if (left > maxLeft)
     418           0 :                 absoluteSplit = vp.x + maxLeft;
     419             : 
     420           0 :             if ((absoluteSplit - vp.x) < boundary)
     421           0 :                 absoluteSplit = vp.x + boundary;
     422           0 :             if ((end - absoluteSplit) < boundary)
     423           0 :                 absoluteSplit = end - boundary;
     424             : 
     425           0 :             const uint32_t ratio = uint32_t(absoluteSplit / boundary + .5f);
     426           0 :             absoluteSplit = ratio * boundary;
     427             :         }
     428             : 
     429           0 :         absoluteSplit = LB_MAX(absoluteSplit, vp.x);
     430           0 :         absoluteSplit = LB_MIN(absoluteSplit, end);
     431             : 
     432           0 :         const float newPixelW = pvpW * node->split;
     433           0 :         const float oldPixelW = pvpW * node->oldsplit;
     434           0 :         if (int(fabs(newPixelW - oldPixelW)) < node->resistance2i.x())
     435             :         {
     436           0 :             absoluteSplit = vp.x + vp.w * node->oldsplit;
     437           0 :             node->split = node->oldsplit;
     438             :         }
     439             :         else
     440             :         {
     441           0 :             node->split = (absoluteSplit - vp.x) / vp.w;
     442           0 :             node->oldsplit = node->split;
     443             :         }
     444             : 
     445           0 :         LBLOG(LOG_LB2) << "Constrained split " << vp << " at X " << node->split
     446           0 :                        << std::endl;
     447             : 
     448             :         // traverse children
     449           0 :         Viewport childVP = vp;
     450           0 :         childVP.w = (absoluteSplit - vp.x);
     451           0 :         _assign(node->left, childVP, range);
     452             : 
     453           0 :         childVP.x = childVP.getXEnd();
     454           0 :         childVP.w = end - childVP.x;
     455             : 
     456             :         // Fix 2994111: Rounding errors with 2D LB and 16 sources
     457             :         //   Floating point rounding may create a width for the 'right'
     458             :         //   child which is slightly below the parent width. Correct it.
     459           0 :         while (childVP.getXEnd() < end)
     460           0 :             childVP.w += std::numeric_limits<float>::epsilon();
     461             : 
     462           0 :         _assign(node->right, childVP, range);
     463           0 :         break;
     464             :     }
     465             : 
     466             :     case MODE_HORIZONTAL:
     467             :     {
     468             :         // Ensure minimum size
     469           0 :         const Compound* root = getCompound();
     470           0 :         const float pvpH = float(root->getInheritPixelViewport().h);
     471           0 :         const float end = vp.getYEnd();
     472           0 :         const float boundary = float(node->boundary2i.y()) / pvpH;
     473           0 :         float absoluteSplit = vp.y + vp.h * node->split;
     474             : 
     475           0 :         if (node->left->resources == 0.f)
     476           0 :             absoluteSplit = vp.y;
     477           0 :         else if (node->right->resources == 0.f)
     478           0 :             absoluteSplit = end;
     479           0 :         else if (boundary > 0)
     480             :         {
     481           0 :             const float right = vp.getYEnd() - absoluteSplit;
     482           0 :             const float left = absoluteSplit - vp.y;
     483           0 :             const float maxRight = float(node->right->maxSize.y()) / pvpH;
     484           0 :             const float maxLeft = float(node->left->maxSize.y()) / pvpH;
     485             : 
     486           0 :             if (right > maxRight)
     487           0 :                 absoluteSplit = end - maxRight;
     488           0 :             else if (left > maxLeft)
     489           0 :                 absoluteSplit = vp.y + maxLeft;
     490             : 
     491           0 :             if ((absoluteSplit - vp.y) < boundary)
     492           0 :                 absoluteSplit = vp.y + boundary;
     493           0 :             if ((end - absoluteSplit) < boundary)
     494           0 :                 absoluteSplit = end - boundary;
     495             : 
     496           0 :             const uint32_t ratio = uint32_t(absoluteSplit / boundary + .5f);
     497           0 :             absoluteSplit = ratio * boundary;
     498             :         }
     499             : 
     500           0 :         absoluteSplit = LB_MAX(absoluteSplit, vp.y);
     501           0 :         absoluteSplit = LB_MIN(absoluteSplit, end);
     502             : 
     503           0 :         const float newPixelH = pvpH * node->split;
     504           0 :         const float oldPixelH = pvpH * node->oldsplit;
     505           0 :         if (int(fabs(newPixelH - oldPixelH)) < node->resistance2i.y())
     506             :         {
     507           0 :             absoluteSplit = vp.x + vp.w * node->oldsplit;
     508           0 :             node->split = node->oldsplit;
     509             :         }
     510             :         else
     511             :         {
     512           0 :             node->split = (absoluteSplit - vp.y) / vp.h;
     513           0 :             node->oldsplit = node->split;
     514             :         }
     515             : 
     516           0 :         LBLOG(LOG_LB2) << "Constrained split " << vp << " at X " << node->split
     517           0 :                        << std::endl;
     518             : 
     519             :         // traverse children
     520           0 :         Viewport childVP = vp;
     521           0 :         childVP.h = (absoluteSplit - vp.y);
     522           0 :         _assign(node->left, childVP, range);
     523             : 
     524           0 :         childVP.y = childVP.getYEnd();
     525           0 :         childVP.h = end - childVP.y;
     526             : 
     527             :         // Fix 2994111: Rounding errors with 2D LB and 16 sources
     528             :         //   Floating point rounding may create a width for the 'right'
     529             :         //   child which is slightly below the parent width. Correct it.
     530           0 :         while (childVP.getYEnd() < end)
     531           0 :             childVP.h += std::numeric_limits<float>::epsilon();
     532             : 
     533           0 :         _assign(node->right, childVP, range);
     534           0 :         break;
     535             :     }
     536             : 
     537             :     case MODE_DB:
     538             :     {
     539           0 :         LBASSERT(vp == Viewport::FULL);
     540           0 :         const float end = range.end;
     541             :         float absoluteSplit =
     542           0 :             range.start + (range.end - range.start) * node->split;
     543             : 
     544           0 :         const float boundary(node->boundaryf);
     545           0 :         if (node->left->resources == 0.f)
     546           0 :             absoluteSplit = range.start;
     547           0 :         else if (node->right->resources == 0.f)
     548           0 :             absoluteSplit = end;
     549             : 
     550           0 :         const uint32_t ratio = uint32_t(absoluteSplit / boundary + .5f);
     551           0 :         absoluteSplit = ratio * boundary;
     552           0 :         if ((absoluteSplit - range.start) < boundary)
     553           0 :             absoluteSplit = range.start;
     554           0 :         if ((end - absoluteSplit) < boundary)
     555           0 :             absoluteSplit = end;
     556             : 
     557             :         const float oldSplit =
     558           0 :             range.start + (range.end - range.start) * node->oldsplit;
     559           0 :         if (fabs(absoluteSplit - oldSplit) < node->resistancef)
     560             :         {
     561           0 :             absoluteSplit = oldSplit;
     562           0 :             node->split = node->oldsplit;
     563             :         }
     564             :         else
     565             :         {
     566           0 :             node->split =
     567           0 :                 (absoluteSplit - range.start) / (range.end - range.start);
     568           0 :             node->oldsplit = node->split;
     569             :         }
     570             : 
     571           0 :         LBLOG(LOG_LB2) << "Constrained split " << range << " at pos "
     572           0 :                        << node->split << std::endl;
     573             : 
     574           0 :         Range childRange = range;
     575           0 :         childRange.end = absoluteSplit;
     576           0 :         _assign(node->left, vp, childRange);
     577             : 
     578           0 :         childRange.start = childRange.end;
     579           0 :         childRange.end = range.end;
     580           0 :         _assign(node->right, vp, childRange);
     581           0 :         break;
     582             :     }
     583             : 
     584             :     default:
     585           0 :         LBUNIMPLEMENTED;
     586             :     }
     587             : }
     588             : 
     589           0 : std::ostream& operator<<(std::ostream& os, const TreeEqualizer::Node* node)
     590             : {
     591           0 :     if (!node)
     592           0 :         return os;
     593             : 
     594           0 :     os << lunchbox::disableFlush;
     595             : 
     596           0 :     if (node->compound)
     597           0 :         os << node->compound->getChannel()->getName() << " resources "
     598           0 :            << node->resources << " max size " << node->maxSize << std::endl;
     599             :     else
     600           0 :         os << "split " << node->mode << " @ " << node->split << " resources "
     601           0 :            << node->resources << " max size " << node->maxSize << std::endl
     602           0 :            << lunchbox::indent << node->left << node->right << lunchbox::exdent;
     603             : 
     604           0 :     os << lunchbox::enableFlush;
     605           0 :     return os;
     606             : }
     607             : 
     608           0 : std::ostream& operator<<(std::ostream& os, const TreeEqualizer* lb)
     609             : {
     610           0 :     if (!lb)
     611           0 :         return os;
     612             : 
     613           0 :     os << lunchbox::disableFlush << "tree_equalizer" << std::endl
     614           0 :        << '{' << std::endl
     615           0 :        << "    mode    " << lb->getMode() << std::endl;
     616             : 
     617           0 :     if (lb->getDamping() != 0.5f)
     618           0 :         os << "    damping " << lb->getDamping() << std::endl;
     619             : 
     620           0 :     if (lb->getBoundary2i() != Vector2i(1, 1))
     621           0 :         os << "    boundary [ " << lb->getBoundary2i().x() << " "
     622           0 :            << lb->getBoundary2i().y() << " ]" << std::endl;
     623             : 
     624           0 :     if (lb->getBoundaryf() != std::numeric_limits<float>::epsilon())
     625           0 :         os << "    boundary " << lb->getBoundaryf() << std::endl;
     626             : 
     627           0 :     if (lb->getResistance2i() != Vector2i(0, 0))
     628           0 :         os << "    resistance [ " << lb->getResistance2i().x() << " "
     629           0 :            << lb->getResistance2i().y() << " ]" << std::endl;
     630             : 
     631           0 :     if (lb->getResistancef() != .0f)
     632           0 :         os << "    resistance " << lb->getResistancef() << std::endl;
     633             : 
     634           0 :     os << '}' << std::endl << lunchbox::enableFlush;
     635           0 :     return os;
     636             : }
     637             : }
     638          60 : }

Generated by: LCOV version 1.11