LCOV - code coverage report
Current view: top level - eq/server/equalizers - treeEqualizer.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 1 380 0.3 %
Date: 2014-06-18 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/client/statistic.h>
      25             : #include <lunchbox/debug.h>
      26             : 
      27             : namespace eq
      28             : {
      29             : namespace server
      30             : {
      31             : 
      32             : std::ostream& operator << ( std::ostream& os, const TreeEqualizer::Node* );
      33             : 
      34             : // The tree load balancer organizes the children in a binary tree. At each
      35             : // level, a relative split position is determined by balancing the left subtree
      36             : // against the right subtree.
      37             : 
      38           0 : TreeEqualizer::TreeEqualizer()
      39           0 :         : _tree( 0 )
      40             : {
      41           0 :     LBINFO << "New TreeEqualizer @" << (void*)this << std::endl;
      42           0 : }
      43             : 
      44           0 : TreeEqualizer::TreeEqualizer( const TreeEqualizer& from )
      45             :         : Equalizer( from )
      46             :         , ChannelListener( from )
      47           0 :         , _tree( 0 )
      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           0 :           case 0: return; // no leaf compound, can't do anything.
      70             :           case 1: // one child, 'balance' it:
      71           0 :               if( getMode() == MODE_DB )
      72           0 :                   children.front()->setRange( Range( ));
      73             :               else
      74           0 :                   children.front()->setViewport( Viewport( ));
      75           0 :               return;
      76             :           default:
      77           0 :               _tree = _buildTree( children );
      78             :         }
      79             :     }
      80             : 
      81             :     // compute new data
      82           0 :     _update( _tree );
      83           0 :     _split( _tree );
      84           0 :     _assign( _tree, Viewport(), Range( ));
      85           0 :     LBLOG( LOG_LB2 ) << "LB tree: " << _tree;
      86             : }
      87             : 
      88           0 : TreeEqualizer::Node* TreeEqualizer::_buildTree( const Compounds& compounds )
      89             : {
      90           0 :     Node* node = new Node;
      91             : 
      92           0 :     const size_t size = compounds.size();
      93           0 :     if( size == 1 )
      94             :     {
      95           0 :         Compound* compound = compounds.front();
      96             : 
      97           0 :         node->compound  = compound;
      98             : 
      99           0 :         Channel* channel = compound->getChannel();
     100           0 :         LBASSERT( channel );
     101           0 :         channel->addListener( this );
     102           0 :         return node;
     103             :     }
     104             : 
     105           0 :     const size_t middle = size >> 1;
     106             : 
     107           0 :     Compounds left;
     108           0 :     for( size_t i = 0; i < middle; ++i )
     109           0 :         left.push_back( compounds[i] );
     110             : 
     111           0 :     Compounds right;
     112           0 :     for( size_t i = middle; i < size; ++i )
     113           0 :         right.push_back( compounds[i] );
     114             : 
     115           0 :     node->left  = _buildTree( left );
     116           0 :     node->right = _buildTree( right );
     117           0 :     return node;
     118             : }
     119             : 
     120           0 : void TreeEqualizer::_clearTree( Node* node )
     121             : {
     122           0 :     if( !node )
     123           0 :         return;
     124             : 
     125           0 :     if( node->compound )
     126             :     {
     127           0 :         Channel* channel = node->compound->getChannel();
     128           0 :         LBASSERTINFO( channel, node->compound );
     129           0 :         channel->removeListener( this );
     130             :     }
     131             :     else
     132             :     {
     133           0 :         _clearTree( node->left );
     134           0 :         _clearTree( node->right );
     135             :     }
     136             : }
     137             : 
     138           0 : void TreeEqualizer::notifyLoadData( Channel* channel,
     139             :                                     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 = (node->mode == MODE_VERTICAL) ? MODE_HORIZONTAL :
     239           0 :                                                            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() = node->left->maxSize.x() +
     272           0 :                                 node->right->maxSize.x();
     273           0 :             node->maxSize.y() = LB_MIN( node->left->maxSize.y(),
     274           0 :                                         node->right->maxSize.y() );
     275           0 :             node->boundary2i.x() = node->left->boundary2i.x() +
     276           0 :                                    node->right->boundary2i.x();
     277           0 :             node->boundary2i.y() = LB_MAX( node->left->boundary2i.y(),
     278           0 :                                            node->right->boundary2i.y());
     279           0 :             node->boundaryf = LB_MAX( node->left->boundaryf,
     280           0 :                                       node->right->boundaryf );
     281           0 :             node->resistance2i.x() = LB_MAX( node->left->resistance2i.x(),
     282           0 :                                              node->right->resistance2i.x( ));
     283           0 :             node->resistance2i.y() = LB_MAX( node->left->resistance2i.y(),
     284           0 :                                              node->right->resistance2i.y());
     285           0 :             node->resistancef = LB_MAX( node->left->resistancef,
     286           0 :                                         node->right->resistancef );
     287           0 :             break;
     288             :         case MODE_HORIZONTAL:
     289           0 :             node->maxSize.x() = LB_MIN( node->left->maxSize.x(),
     290           0 :                                         node->right->maxSize.x() );
     291           0 :             node->maxSize.y() = node->left->maxSize.y() +
     292           0 :                                 node->right->maxSize.y();
     293           0 :             node->boundary2i.x() = LB_MAX( node->left->boundary2i.x(),
     294           0 :                                            node->right->boundary2i.x() );
     295           0 :             node->boundary2i.y() = node->left->boundary2i.y() +
     296           0 :                                    node->right->boundary2i.y();
     297           0 :             node->boundaryf = LB_MAX( node->left->boundaryf,
     298           0 :                                       node->right->boundaryf );
     299           0 :             node->resistance2i.x() = LB_MAX( node->left->resistance2i.x(),
     300           0 :                                              node->right->resistance2i.x() );
     301           0 :             node->resistance2i.y() = LB_MAX( node->left->resistance2i.y(),
     302           0 :                                              node->right->resistance2i.y( ));
     303           0 :             node->resistancef = LB_MAX( node->left->resistancef,
     304           0 :                                       node->right->resistancef );
     305           0 :             break;
     306             :         case MODE_DB:
     307           0 :             node->boundary2i.x() = LB_MAX( node->left->boundary2i.x(),
     308           0 :                                            node->right->boundary2i.x() );
     309           0 :             node->boundary2i.y() = LB_MAX( node->left->boundary2i.y(),
     310           0 :                                            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           0 :                                            node->right->resistance2i.x() );
     314           0 :             node->resistance2i.y() = LB_MAX( node->left->resistance2i.y(),
     315           0 :                                            node->right->resistance2i.y() );
     316           0 :             node->resistancef = LB_MAX( node->left->resistancef,
     317           0 :                                         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 )
     362           0 :         << "Should split at " << split << " (" << target << ": " << leftTime
     363           0 :         << " by " << left->resources << "/" << rightTime << " by "
     364           0 :         << right->resources << ")" << std::endl;
     365           0 :     node->split = (1.f - getDamping( )) * split + getDamping() * node->split;
     366           0 :     LBLOG( LOG_LB2 ) << "Dampened split at " << node->split << std::endl;
     367             : 
     368           0 :     _split( left );
     369           0 :     _split( right );
     370             : }
     371             : 
     372           0 : void TreeEqualizer::_assign( Node* node, const Viewport& vp,
     373             :                              const Range& range )
     374             : {
     375           0 :     LBLOG( LOG_LB2 ) << "assign " << vp << ", " << range << " time "
     376           0 :                      << node->time << " split " << node->split << std::endl;
     377           0 :     LBASSERTINFO( vp.isValid(), vp );
     378           0 :     LBASSERTINFO( range.isValid(), range );
     379           0 :     LBASSERTINFO( node->resources > 0.f || !vp.hasArea() || !range.hasData(),
     380             :                   "Assigning work to unused compound: " << vp << ", " << range);
     381             : 
     382           0 :     Compound* compound = node->compound;
     383           0 :     if( compound )
     384             :     {
     385           0 :         LBASSERTINFO( vp == Viewport::FULL || range == Range::ALL,
     386             :                       "Mixed 2D/DB load-balancing not implemented" );
     387             : 
     388           0 :         compound->setViewport( vp );
     389           0 :         compound->setRange( range );
     390           0 :         LBLOG( LOG_LB2 ) << compound->getChannel()->getName() << " set " << vp
     391           0 :                          << ", " << range << std::endl;
     392           0 :         return;
     393             :     }
     394             : 
     395           0 :     switch( node->mode )
     396             :     {
     397             :     case MODE_VERTICAL:
     398             :     {
     399             :         // Ensure minimum size
     400           0 :         const Compound* root = getCompound();
     401           0 :         const float pvpW = float( root->getInheritPixelViewport().w );
     402           0 :         const float end = vp.getXEnd();
     403           0 :         const float boundary = float( node->boundary2i.x( )) / pvpW;
     404           0 :         float absoluteSplit = vp.x + vp.w * node->split;
     405             : 
     406           0 :         if( node->left->resources == 0.f )
     407           0 :             absoluteSplit = vp.x;
     408           0 :         else if( node->right->resources == 0.f )
     409           0 :             absoluteSplit = end;
     410           0 :         else if( boundary > 0 )
     411             :         {
     412           0 :             const float right = vp.getXEnd() - absoluteSplit;
     413           0 :             const float left = absoluteSplit - vp.x;
     414           0 :             const float maxRight = float( node->right->maxSize.x( )) / pvpW;
     415           0 :             const float maxLeft = float( node->left->maxSize.x( )) / pvpW;
     416             : 
     417           0 :             if( right > maxRight )
     418           0 :                 absoluteSplit = end - maxRight;
     419           0 :             else if( left > maxLeft )
     420           0 :                 absoluteSplit = vp.x + maxLeft;
     421             : 
     422           0 :             if( (absoluteSplit - vp.x) < boundary )
     423           0 :                 absoluteSplit = vp.x + boundary;
     424           0 :             if( (end - absoluteSplit) < boundary )
     425           0 :                 absoluteSplit = end - boundary;
     426             : 
     427           0 :             const uint32_t ratio = uint32_t( absoluteSplit / boundary + .5f );
     428           0 :             absoluteSplit = ratio * boundary;
     429             :         }
     430             : 
     431           0 :         absoluteSplit = LB_MAX( absoluteSplit, vp.x );
     432           0 :         absoluteSplit = LB_MIN( absoluteSplit, end);
     433             : 
     434           0 :         const float newPixelW = pvpW * node->split;
     435           0 :         const float oldPixelW = pvpW * node->oldsplit;
     436           0 :         if( int( fabs(newPixelW - oldPixelW) ) < node->resistance2i.x( ))
     437             :         {
     438           0 :             absoluteSplit = vp.x + vp.w * node->oldsplit;
     439           0 :             node->split = node->oldsplit;
     440             :         }
     441             :         else
     442             :         {
     443           0 :             node->split = (absoluteSplit - vp.x ) / vp.w;
     444           0 :             node->oldsplit = node->split;
     445             :         }
     446             : 
     447           0 :         LBLOG( LOG_LB2 ) << "Constrained split " << vp << " at X "
     448           0 :                          << node->split << std::endl;
     449             : 
     450             :         // traverse children
     451           0 :         Viewport childVP = vp;
     452           0 :         childVP.w = (absoluteSplit - vp.x);
     453           0 :         _assign( node->left, childVP, range );
     454             : 
     455           0 :         childVP.x = childVP.getXEnd();
     456           0 :         childVP.w = end - childVP.x;
     457             : 
     458             :         // Fix 2994111: Rounding errors with 2D LB and 16 sources
     459             :         //   Floating point rounding may create a width for the 'right'
     460             :         //   child which is slightly below the parent width. Correct it.
     461           0 :         while( childVP.getXEnd() < end )
     462           0 :             childVP.w += std::numeric_limits< float >::epsilon();
     463             : 
     464           0 :         _assign( node->right, childVP, range );
     465           0 :         break;
     466             :     }
     467             : 
     468             :     case MODE_HORIZONTAL:
     469             :     {
     470             :         // Ensure minimum size
     471           0 :         const Compound* root = getCompound();
     472           0 :         const float pvpH = float( root->getInheritPixelViewport().h );
     473           0 :         const float end = vp.getYEnd();
     474           0 :         const float boundary = float( node->boundary2i.y( )) / pvpH;
     475           0 :         float absoluteSplit = vp.y + vp.h * node->split;
     476             : 
     477           0 :         if( node->left->resources == 0.f )
     478           0 :             absoluteSplit = vp.y;
     479           0 :         else if( node->right->resources == 0.f )
     480           0 :             absoluteSplit = end;
     481           0 :         else if( boundary > 0 )
     482             :         {
     483           0 :             const float right = vp.getYEnd() - absoluteSplit;
     484           0 :             const float left = absoluteSplit - vp.y;
     485           0 :             const float maxRight = float( node->right->maxSize.y( )) / pvpH;
     486           0 :             const float maxLeft = float( node->left->maxSize.y( )) / pvpH;
     487             : 
     488           0 :             if( right > maxRight )
     489           0 :                 absoluteSplit = end - maxRight;
     490           0 :             else if( left > maxLeft )
     491           0 :                 absoluteSplit = vp.y + maxLeft;
     492             : 
     493           0 :             if( (absoluteSplit - vp.y) < boundary )
     494           0 :                 absoluteSplit = vp.y + boundary;
     495           0 :             if( (end - absoluteSplit) < boundary )
     496           0 :                 absoluteSplit = end - boundary;
     497             : 
     498           0 :             const uint32_t ratio = uint32_t( absoluteSplit / boundary + .5f );
     499           0 :             absoluteSplit = ratio * boundary;
     500             :         }
     501             : 
     502           0 :         absoluteSplit = LB_MAX( absoluteSplit, vp.y );
     503           0 :         absoluteSplit = LB_MIN( absoluteSplit, end);
     504             : 
     505           0 :         const float newPixelH = pvpH * node->split;
     506           0 :         const float oldPixelH = pvpH * node->oldsplit;
     507           0 :         if( int( fabs(newPixelH - oldPixelH) ) < node->resistance2i.y( ))
     508             :         {
     509           0 :             absoluteSplit = vp.x + vp.w * node->oldsplit;
     510           0 :             node->split = node->oldsplit;
     511             :         }
     512             :         else
     513             :         {
     514           0 :             node->split = (absoluteSplit - vp.y ) / vp.h;
     515           0 :             node->oldsplit = node->split;
     516             :         }
     517             : 
     518           0 :         LBLOG( LOG_LB2 ) << "Constrained split " << vp << " at X "
     519           0 :                          << node->split << std::endl;
     520             : 
     521             :         // traverse children
     522           0 :         Viewport childVP = vp;
     523           0 :         childVP.h = (absoluteSplit - vp.y);
     524           0 :         _assign( node->left, childVP, range );
     525             : 
     526           0 :         childVP.y = childVP.getYEnd();
     527           0 :         childVP.h = end - childVP.y;
     528             : 
     529             :         // Fix 2994111: Rounding errors with 2D LB and 16 sources
     530             :         //   Floating point rounding may create a width for the 'right'
     531             :         //   child which is slightly below the parent width. Correct it.
     532           0 :         while( childVP.getYEnd() < end )
     533           0 :             childVP.h += std::numeric_limits< float >::epsilon();
     534             : 
     535           0 :         _assign( node->right, childVP, range );
     536           0 :         break;
     537             :     }
     538             : 
     539             :     case MODE_DB:
     540             :     {
     541           0 :         LBASSERT( vp == Viewport::FULL );
     542           0 :         const float end = range.end;
     543           0 :         float absoluteSplit = range.start + (range.end-range.start)*node->split;
     544             : 
     545           0 :         const float boundary( node->boundaryf );
     546           0 :         if( node->left->resources == 0.f )
     547           0 :             absoluteSplit = range.start;
     548           0 :         else if( node->right->resources == 0.f )
     549           0 :             absoluteSplit = end;
     550             : 
     551           0 :         const uint32_t ratio = uint32_t( absoluteSplit / boundary + .5f );
     552           0 :         absoluteSplit = ratio * boundary;
     553           0 :         if( (absoluteSplit - range.start) < boundary )
     554           0 :             absoluteSplit = range.start;
     555           0 :         if( (end - absoluteSplit) < boundary )
     556           0 :             absoluteSplit = end;
     557             : 
     558           0 :         const float oldSplit = range.start +
     559           0 :                                (range.end-range.start)*node->oldsplit;
     560           0 :         if( fabs( absoluteSplit - oldSplit ) < node->resistancef )
     561             :         {
     562           0 :             absoluteSplit = oldSplit;
     563           0 :             node->split = node->oldsplit;
     564             :         }
     565             :         else
     566             :         {
     567           0 :             node->split = (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
     614           0 :        << "tree_equalizer" << std::endl
     615           0 :        << '{' << std::endl
     616           0 :        << "    mode    " << lb->getMode() << std::endl;
     617             : 
     618           0 :     if( lb->getDamping() != 0.5f )
     619           0 :         os << "    damping " << lb->getDamping() << std::endl;
     620             : 
     621           0 :     if( lb->getBoundary2i() != Vector2i( 1, 1 ) )
     622           0 :         os << "    boundary [ " << lb->getBoundary2i().x() << " "
     623           0 :            << lb->getBoundary2i().y() << " ]" << std::endl;
     624             : 
     625           0 :     if( lb->getBoundaryf() != std::numeric_limits<float>::epsilon() )
     626           0 :         os << "    boundary " << lb->getBoundaryf() << std::endl;
     627             : 
     628           0 :     if( lb->getResistance2i() != Vector2i( 0, 0 ) )
     629           0 :         os << "    resistance [ " << lb->getResistance2i().x() << " "
     630           0 :            << lb->getResistance2i().y() << " ]" << std::endl;
     631             : 
     632           0 :     if( lb->getResistancef() != .0f )
     633           0 :         os << "    resistance " << lb->getResistancef() << std::endl;
     634             : 
     635           0 :     os << '}' << std::endl << lunchbox::enableFlush;
     636           0 :     return os;
     637             : }
     638             : 
     639             : }
     640          27 : }

Generated by: LCOV version 1.10