LCOV - code coverage report
Current view: top level - eq/server - compound.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 560 1001 55.9 %
Date: 2016-09-29 05:02:09 Functions: 47 77 61.0 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2005-2016, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                          Daniel Nachbaur <danielnachbaur@gmail.com>
       4             :  *                          Cedric Stalder <cedric.stalder@gmail.com>
       5             :  *
       6             :  * This library is free software; you can redistribute it and/or modify it under
       7             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       8             :  * by the Free Software Foundation.
       9             :  *
      10             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      11             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      12             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      13             :  * details.
      14             :  *
      15             :  * You should have received a copy of the GNU Lesser General Public License
      16             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      17             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             :  */
      19             : 
      20             : #include "compound.h"
      21             : 
      22             : #include "canvas.h"
      23             : #include "channel.h"
      24             : #include "colorMask.h"
      25             : #include "compoundInitVisitor.h"
      26             : #include "compoundListener.h"
      27             : #include "compoundUpdateDataVisitor.h"
      28             : #include "compoundUpdateInputVisitor.h"
      29             : #include "compoundUpdateOutputVisitor.h"
      30             : #include "config.h"
      31             : #include "equalizers/equalizer.h"
      32             : #include "frame.h"
      33             : #include "frameData.h"
      34             : #include "tileQueue.h"
      35             : #include "global.h"
      36             : #include "layout.h"
      37             : #include "log.h"
      38             : #include "segment.h"
      39             : #include "view.h"
      40             : #include "observer.h"
      41             : 
      42             : #include <eq/fabric/paths.h>
      43             : #include <lunchbox/os.h>
      44             : #include <lunchbox/stdExt.h>
      45             : #include <boost/foreach.hpp>
      46             : 
      47             : #include <algorithm>
      48             : #include <math.h>
      49             : #include <vector>
      50             : 
      51             : #include "compoundActivateVisitor.h"
      52             : #include "compoundExitVisitor.h"
      53             : #include "compoundUpdateActivateVisitor.h"
      54             : 
      55             : namespace eq
      56             : {
      57             : namespace server
      58             : {
      59             : #define MAKE_ATTR_STRING( attr ) ( std::string("EQ_COMPOUND_") + #attr )
      60             : ;
      61             : 
      62         680 : Compound::Compound( Config* parent )
      63             :         : _config( parent )
      64             :         , _parent( 0 )
      65             :         , _usage( 1.0f )
      66             :         , _taskID( 0 )
      67         680 :         , _frustum( _data.frustumData )
      68             : {
      69         680 :     LBASSERT( parent );
      70         680 :     parent->addCompound( this );
      71         680 :     LBLOG( LOG_INIT ) << "New root compound @" << (void*)this << std::endl;
      72         680 : }
      73             : 
      74        3420 : Compound::Compound( Compound* parent )
      75             :         : _config( 0 )
      76             :         , _parent( parent )
      77             :         , _usage( 1.0f )
      78             :         , _taskID( 0 )
      79        3420 :         , _frustum( _data.frustumData )
      80             : {
      81        3420 :     LBASSERT( parent );
      82        3420 :     parent->_addChild( this );
      83        3420 :     LBLOG( LOG_INIT ) << "New compound child @" << (void*)this << std::endl;
      84        3420 : }
      85             : 
      86       12300 : Compound::~Compound()
      87             : {
      88        4100 :     _swapBarrier = 0;
      89             : 
      90       13128 :     for( Equalizers::const_iterator i = _equalizers.begin();
      91        8752 :          i != _equalizers.end(); ++i )
      92             :     {
      93         276 :         Equalizer* equalizer = *i;
      94         276 :         equalizer->attach( 0 );
      95         276 :         delete equalizer;
      96             :     }
      97        4100 :     _equalizers.clear();
      98             : 
      99       11620 :     while( !_children.empty( ))
     100             :     {
     101        3420 :         Compound* compound = _children.back();
     102        3420 :         _removeChild( compound );
     103        3420 :         delete compound;
     104             :     }
     105             : 
     106        4100 :     if( _config )
     107         680 :         _config->removeCompound( this );
     108             :     else
     109             :     {
     110        3420 :         LBASSERT( _parent );
     111        3420 :         _parent->_removeChild( this );
     112             :     }
     113             : 
     114        6916 :     for( FramesCIter i = _inputFrames.begin(); i != _inputFrames.end(); ++i )
     115        2816 :         delete *i;
     116        4100 :     _inputFrames.clear();
     117             : 
     118        6848 :     for( FramesCIter i = _outputFrames.begin(); i != _outputFrames.end(); ++i )
     119        2748 :         delete *i;
     120        4100 :     _outputFrames.clear();
     121             : 
     122       12300 :     for( TileQueuesCIter i = _inputTileQueues.begin();
     123        8200 :          i != _inputTileQueues.end(); ++i )
     124             :     {
     125           0 :         delete *i;
     126             :     }
     127        4100 :     _inputTileQueues.clear();
     128             : 
     129       12300 :     for( TileQueuesCIter i = _outputTileQueues.begin();
     130        8200 :          i != _outputTileQueues.end(); ++i )
     131             :     {
     132           0 :         delete *i;
     133             :     }
     134        4100 :     _outputTileQueues.clear();
     135        8200 : }
     136             : 
     137       12300 : Compound::Data::Data()
     138             :         : channel( 0 )
     139             :         , overdraw( Vector4i::ZERO )
     140             :         , buffers( Frame::BUFFER_UNDEFINED )
     141             :         , eyes( EYE_UNDEFINED )
     142             :         , tasks( fabric::TASK_DEFAULT )
     143             :         , period( LB_UNDEFINED_UINT32 )
     144             :         , phase( LB_UNDEFINED_UINT32 )
     145       12300 :         , maxFPS( std::numeric_limits< float >::max( ))
     146             : {
     147       12300 :     const Global* global = Global::instance();
     148       73800 :     for( int i=0; i<IATTR_ALL; ++i )
     149             :         iAttributes[i] =
     150       61500 :             global->getCompoundIAttribute( static_cast< IAttribute >( i ));
     151       49200 :     for( size_t i = 0; i < NUM_EYES; ++i )
     152       36900 :         active[ i ] = 0;
     153       12300 : }
     154             : 
     155        3420 : void Compound::_addChild( Compound* child )
     156             : {
     157        3420 :     LBASSERT( child->_parent == this );
     158        3420 :     _children.push_back( child );
     159        3420 :     _fireChildAdded( child );
     160        3420 : }
     161             : 
     162        6840 : bool Compound::_removeChild( Compound* child )
     163             : {
     164        6840 :     Compounds::iterator i = lunchbox::find( _children, child );
     165        6840 :     if( i == _children.end( ))
     166        3420 :         return false;
     167             : 
     168        3420 :     _fireChildRemove( child );
     169        3420 :     _children.erase( i );
     170        3420 :     return true;
     171             : }
     172             : 
     173        6908 : Compound* Compound::getNext() const
     174             : {
     175        6908 :     if( !_parent )
     176        2890 :         return 0;
     177             : 
     178        4018 :     Compounds&          siblings = _parent->_children;
     179             :     Compounds::iterator result   = std::find( siblings.begin(), siblings.end(),
     180        4018 :                                               this );
     181        4018 :     if( result == siblings.end() )
     182           0 :         return 0;
     183        4018 :     ++result;
     184        4018 :     if( result == siblings.end() )
     185        1144 :         return 0;
     186             : 
     187        2874 :     return *result;
     188             : }
     189             : 
     190           0 : Node* Compound::getNode()
     191             : {
     192           0 :     Channel* channel = getChannel();
     193           0 :     return channel ? channel->getNode() : 0;
     194             : }
     195             : 
     196          16 : ServerPtr Compound::getServer()
     197             : {
     198          16 :     return getConfig()->getServer();
     199             : }
     200             : 
     201        2894 : void Compound::setChannel( Channel* channel )
     202             : {
     203        2894 :     _data.channel = channel;
     204             : 
     205             :     // Update swap barrier
     206        2894 :     if( !isDestination( ))
     207        3420 :         return;
     208             : 
     209        1190 :     Segment* segment = channel ? channel->getSegment() : 0;
     210        1190 :     if( !segment )
     211          12 :         return;
     212             : 
     213        1178 :     SwapBarrierPtr swapBarrier = segment->getSwapBarrier();
     214        1178 :     if( swapBarrier )
     215           8 :         setSwapBarrier( swapBarrier );
     216             : }
     217             : 
     218        7484 : const Channel* Compound::getChannel() const
     219             : {
     220        7484 :     if( _data.channel )
     221        5950 :         return _data.channel;
     222        1534 :     if( _parent )
     223         588 :         return _parent->getChannel();
     224         946 :     return 0;
     225             : }
     226             : 
     227        7014 : Channel* Compound::getChannel()
     228             : {
     229        7014 :     if( _data.channel )
     230        5628 :         return _data.channel;
     231        1386 :     if( _parent )
     232         280 :         return _parent->getChannel();
     233        1106 :     return 0;
     234             : }
     235             : 
     236           0 : Window* Compound::getWindow()
     237             : {
     238           0 :     Channel* channel = getChannel();
     239           0 :     if( channel )
     240           0 :         return channel->getWindow();
     241           0 :     return 0;
     242             : }
     243             : 
     244           0 : const Window* Compound::getWindow() const
     245             : {
     246           0 :     const Channel* channel = getChannel();
     247           0 :     if( channel )
     248           0 :         return channel->getWindow();
     249           0 :     return 0;
     250             : }
     251             : 
     252           0 : Pipe* Compound::getPipe()
     253             : {
     254           0 :     Channel* channel = getChannel();
     255           0 :     if( channel )
     256           0 :         return channel->getPipe();
     257           0 :     return 0;
     258             : }
     259             : 
     260           0 : const Pipe* Compound::getPipe() const
     261             : {
     262           0 :     const Channel* channel = getChannel();
     263           0 :     if( channel )
     264           0 :         return channel->getPipe();
     265           0 :     return 0;
     266             : }
     267             : 
     268         276 : void Compound::addEqualizer( Equalizer* equalizer )
     269             : {
     270         276 :     if( equalizer )
     271         276 :         equalizer->attach( this );
     272             : 
     273         276 :     _equalizers.push_back( equalizer );
     274         276 : }
     275             : 
     276           0 : bool Compound::isInheritActive( const Eye eye ) const
     277             : {
     278           0 :     const int32_t index = lunchbox::getIndexOfLastBit( eye );
     279           0 :     LBASSERT( index >= 0 );
     280           0 :     LBASSERT( index < NUM_EYES );
     281           0 :     return _inherit.active[ index ];
     282             : }
     283             : 
     284           0 : bool Compound::isLastInheritEye( const Eye eye ) const
     285             : {
     286           0 :     int32_t index = lunchbox::getIndexOfLastBit( eye );
     287           0 :     LBASSERT( index >= 0 );
     288             : 
     289           0 :     while( ++index < NUM_EYES )
     290           0 :         if( _inherit.active[ index ] )
     291           0 :             return false;
     292           0 :     return true;
     293             : }
     294             : 
     295           0 : bool Compound::isActive() const
     296             : {
     297           0 :     bool active = false;
     298           0 :     for( size_t i = 0; i < NUM_EYES; ++i )
     299           0 :         active = active || _inherit.active[ i ];
     300             : 
     301           0 :     if( !active )
     302           0 :         return false;
     303             : 
     304           0 :     const Channel* channel = getChannel();
     305           0 :     if( !channel )
     306           0 :         return true;
     307             : 
     308           0 :     if( !channel->isRunning( ))
     309           0 :         return false;
     310             : 
     311           0 :     LBASSERT( _inherit.channel );
     312           0 :     const View* view = _inherit.channel->getView();
     313           0 :     return channel->supportsView( view );
     314             : }
     315             : 
     316             : //---------------------------------------------------------------------------
     317             : // Listener interface
     318             : //---------------------------------------------------------------------------
     319         276 : void Compound::addListener( CompoundListener* listener )
     320             : {
     321         276 :     LB_TS_SCOPED( _serverThread );
     322         276 :     _listeners.push_back( listener );
     323         276 : }
     324             : 
     325         276 : void Compound::removeListener(  CompoundListener* listener )
     326             : {
     327         276 :     LB_TS_SCOPED( _serverThread );
     328             :     CompoundListeners::iterator i = find( _listeners.begin(), _listeners.end(),
     329         276 :                                           listener );
     330         276 :     if( i != _listeners.end( ))
     331         276 :         _listeners.erase( i );
     332         276 : }
     333             : 
     334           0 : void Compound::fireUpdatePre( const uint32_t frameNumber )
     335             : {
     336           0 :     LB_TS_SCOPED( _serverThread );
     337             : 
     338           0 :     BOOST_FOREACH( CompoundListener* listener, _listeners )
     339           0 :         listener->notifyUpdatePre( this, frameNumber );
     340           0 : }
     341             : 
     342        3410 : const std::string& Compound::getIAttributeString( const Compound::IAttribute attr )
     343             : {
     344             :     static std::string iAttributeStrings[] =
     345             :     {
     346             :         MAKE_ATTR_STRING( IATTR_STEREO_MODE ),
     347             :         MAKE_ATTR_STRING( IATTR_STEREO_ANAGLYPH_LEFT_MASK ),
     348             :         MAKE_ATTR_STRING( IATTR_STEREO_ANAGLYPH_RIGHT_MASK ),
     349             :         MAKE_ATTR_STRING( IATTR_FILL1 ),
     350             :         MAKE_ATTR_STRING( IATTR_FILL2 )
     351        3420 :     };
     352        3410 :     return iAttributeStrings[ attr ];
     353             : }
     354             : 
     355        3420 : void Compound::_fireChildAdded( Compound* child )
     356             : {
     357        3420 :     LB_TS_SCOPED( _serverThread );
     358             : 
     359       13008 :     for( CompoundListeners::const_iterator i = _listeners.begin();
     360        8672 :          i != _listeners.end(); ++i )
     361             : 
     362        4336 :         (*i)->notifyChildAdded( this, child );
     363        3420 : }
     364             : 
     365        3420 : void Compound::_fireChildRemove( Compound* child )
     366             : {
     367        3420 :     LB_TS_SCOPED( _serverThread );
     368             : 
     369       10260 :     for( CompoundListeners::const_iterator i = _listeners.begin();
     370        6840 :          i != _listeners.end(); ++i )
     371             : 
     372        3420 :         (*i)->notifyChildRemove( this, child );
     373        3420 : }
     374             : 
     375             : //---------------------------------------------------------------------------
     376             : // I/O objects access
     377             : //---------------------------------------------------------------------------
     378         404 : void Compound::setSwapBarrier( SwapBarrierPtr barrier )
     379             : {
     380         404 :     if( barrier && barrier->getName().empty( ))
     381             :     {
     382         196 :         const Compound* root = getRoot();
     383         196 :         const std::string& rootName = root->getName();
     384         196 :         if( rootName.empty( ))
     385         192 :             barrier->setName( "barrier" );
     386             :         else
     387           4 :             barrier->setName( "barrier." + rootName );
     388             :     }
     389             : 
     390         404 :     _swapBarrier = barrier;
     391         404 : }
     392             : 
     393        2816 : void Compound::addInputFrame( Frame* frame )
     394             : {
     395        2816 :     LBASSERT( frame );
     396        2816 :     if( frame->getName().empty() )
     397           0 :         _setDefaultFrameName( frame );
     398        2816 :     _inputFrames.push_back( frame );
     399        2816 :     frame->setCompound( this );
     400        2816 : }
     401             : 
     402        2748 : void Compound::addOutputFrame( Frame* frame )
     403             : {
     404        2748 :     if( frame->getName().empty() )
     405         562 :         _setDefaultFrameName( frame );
     406        2748 :     _outputFrames.push_back( frame );
     407        2748 :     frame->setCompound( this );
     408        2748 : }
     409             : 
     410           0 : void Compound::addInputTileQueue( TileQueue* tileQueue )
     411             : {
     412           0 :     LBASSERT( tileQueue );
     413           0 :     if( tileQueue->getName().empty() )
     414           0 :         _setDefaultTileQueueName( tileQueue );
     415           0 :     _inputTileQueues.push_back( tileQueue );
     416           0 :     tileQueue->setCompound( this );
     417           0 : }
     418             : 
     419           0 : void Compound::removeInputTileQueue( TileQueue* tileQueue )
     420             : {
     421           0 :     TileQueuesIter i;
     422           0 :     i = find (_inputTileQueues.begin(), _inputTileQueues.end(), tileQueue);
     423           0 :     if ( i != _inputTileQueues.end() )
     424           0 :         _inputTileQueues.erase( i );
     425           0 : }
     426             : 
     427           0 : void Compound::addOutputTileQueue( TileQueue* tileQueue )
     428             : {
     429           0 :     if( tileQueue->getName().empty() )
     430           0 :         _setDefaultTileQueueName( tileQueue );
     431           0 :     _outputTileQueues.push_back( tileQueue );
     432           0 :     tileQueue->setCompound( this );
     433           0 : }
     434             : 
     435           0 : void Compound::removeOutputTileQueue( TileQueue* tileQueue )
     436             : {
     437           0 :     TileQueuesIter i;
     438           0 :     i = find (_outputTileQueues.begin(), _outputTileQueues.end(), tileQueue);
     439           0 :     if ( i != _outputTileQueues.end() )
     440           0 :         _outputTileQueues.erase( i );
     441           0 : }
     442             : 
     443         562 : void Compound::_setDefaultFrameName( Frame* frame )
     444             : {
     445         562 :     for( Compound* compound = this; compound; compound = compound->getParent())
     446             :     {
     447         562 :         if( !compound->getName().empty( ))
     448             :         {
     449           0 :             frame->setName( "frame." + compound->getName( ));
     450           0 :             return;
     451             :         }
     452             : 
     453         562 :         const Channel* channel = compound->getChannel();
     454         562 :         if( channel && !channel->getName().empty( ))
     455             :         {
     456         562 :             frame->setName( "frame." + channel->getName( ));
     457         562 :             return;
     458             :         }
     459             :     }
     460           0 :     frame->setName( "frame" );
     461             : }
     462             : 
     463           0 : void Compound::_setDefaultTileQueueName( TileQueue* tileQueue )
     464             : {
     465           0 :     for( Compound* compound = this; compound; compound = compound->getParent())
     466             :     {
     467           0 :         if( !compound->getName().empty( ))
     468             :         {
     469           0 :             tileQueue->setName( "queue." + compound->getName( ));
     470           0 :             return;
     471             :         }
     472             : 
     473           0 :         const Channel* channel = compound->getChannel();
     474           0 :         if( channel && !channel->getName().empty( ))
     475             :         {
     476           0 :             tileQueue->setName( "queue." + channel->getName( ));
     477           0 :             return;
     478             :         }
     479             :     }
     480           0 :     tileQueue->setName( "queue" );
     481             : }
     482             : 
     483           0 : void Compound::adopt( Compound* child )
     484             : {
     485           0 :     if( child->_config )
     486             :     {
     487           0 :         child->_config->removeCompound( child );
     488           0 :         const_cast< Config*& >( child->_config ) = 0;
     489             :     }
     490             :     else
     491             :     {
     492           0 :         LBASSERT( child->_parent );
     493           0 :         child->_parent->_removeChild( child );
     494             :     }
     495             : 
     496           0 :     const_cast< Compound*& >( child->_parent ) = this;
     497           0 :     _addChild( child );
     498           0 : }
     499             : 
     500        2922 : bool Compound::isDestination() const
     501             : {
     502        2922 :     if( !getChannel( ))
     503           4 :         return false;
     504             : 
     505        3722 :     for( const Compound* compound = getParent(); compound;
     506             :          compound = compound->getParent( ))
     507             :     {
     508        2508 :         if( compound->getChannel( ))
     509        1704 :             return false;
     510             :     }
     511             : 
     512        1214 :     return true;
     513             : }
     514             : 
     515           0 : bool Compound::hasDestinationChannel() const
     516             : {
     517           0 :     return getChannel() && getChannel() == getInheritChannel();
     518             : }
     519             : 
     520           0 : RenderContext Compound::setupRenderContext( const Eye eye ) const
     521             : {
     522           0 :     RenderContext context;
     523           0 :     context.pvp = _inherit.pvp;
     524           0 :     context.overdraw = _inherit.overdraw;
     525           0 :     context.vp = _inherit.vp;
     526           0 :     context.range = _inherit.range;
     527           0 :     context.pixel = _inherit.pixel;
     528           0 :     context.subPixel = _inherit.subPixel;
     529           0 :     context.zoom = _inherit.zoom;
     530           0 :     context.period = _inherit.period;
     531           0 :     context.phase = _inherit.phase;
     532           0 :     context.offset.x() = context.pvp.x;
     533           0 :     context.offset.y() = context.pvp.y;
     534           0 :     context.eye = eye;
     535           0 :     context.taskID = _taskID;
     536           0 :     _computeFrustum( context );
     537           0 :     return context;
     538             : }
     539             : 
     540             : //---------------------------------------------------------------------------
     541             : // frustum operations
     542             : //---------------------------------------------------------------------------
     543          60 : void Compound::setWall( const Wall& wall )
     544             : {
     545          60 :     _frustum.setWall( wall );
     546          60 :     LBVERB << "Wall: " << _data.frustumData << std::endl;
     547          60 : }
     548             : 
     549           0 : void Compound::setProjection( const Projection& projection )
     550             : {
     551           0 :     _frustum.setProjection( projection );
     552           0 :     LBVERB << "Projection: " << _data.frustumData << std::endl;
     553           0 : }
     554             : 
     555           6 : void Compound::updateFrustum( const Vector3f& eye, const float ratio )
     556             : {
     557           6 :     if( !isDestination( )) // only set view/segment frusta on destination
     558           8 :         return;
     559             : 
     560           4 :     Channel* channel = getChannel();
     561           4 :     Segment* segment = channel->getSegment();
     562           4 :     const View* view = channel->getView();
     563           4 :     if( !segment || !view )
     564           0 :         return;
     565             : 
     566           4 :     if( view->getCurrentType() != Frustum::TYPE_NONE ) // frustum from view:
     567             :     {
     568             :         // set compound frustum =
     569             :         //         segment frustum X channel/view coverage
     570           0 :         const Viewport& segmentVP = segment->getViewport();
     571           0 :         const Viewport& viewVP    = view->getViewport();
     572           0 :         const Viewport  coverage  = viewVP.getCoverage( segmentVP );
     573             : 
     574           0 :         Wall wall( view->getWall( ));
     575             : 
     576           0 :         wall.apply( coverage );
     577           0 :         wall.moveFocus( eye, ratio );
     578           0 :         _updateOverdraw( wall );
     579           0 :         wall.scale( view->getModelUnit( ));
     580             : 
     581           0 :         switch( view->getCurrentType( ))
     582             :         {
     583             :             case Frustum::TYPE_WALL:
     584           0 :                 setWall( wall );
     585           0 :                 LBLOG( LOG_VIEW ) << "View wall for " << channel->getName()
     586           0 :                                   << ": " << wall << std::endl;
     587           0 :                 return;
     588             : 
     589             :             case Frustum::TYPE_PROJECTION:
     590             :             {
     591           0 :                 Projection projection( view->getProjection( )); // keep distance
     592           0 :                 projection = wall;
     593           0 :                 setProjection( projection );
     594           0 :                 LBLOG( LOG_VIEW ) << "View projection for " <<channel->getName()
     595           0 :                                   << ": " << projection << std::endl;
     596           0 :                 return;
     597             :             }
     598             : 
     599             :             default:
     600           0 :                 LBUNIMPLEMENTED;
     601             :         }
     602             :     }
     603             :     // else frustum from segment
     604             : 
     605           4 :     segment->inheritFrustum();
     606             : 
     607             :     // set compound frustum =
     608             :     //         segment frustum X channel/segment coverage
     609           4 :     const Channel* outputChannel = segment->getChannel();
     610           4 :     LBASSERT( outputChannel );
     611             : 
     612           4 :     const Viewport& outputVP  = outputChannel->getViewport();
     613           4 :     const Viewport& channelVP = channel->getViewport();
     614           4 :     const Viewport  coverage  = outputVP.getCoverage( channelVP );
     615             : 
     616           4 :     Wall wall( segment->getWall( ));
     617           4 :     wall.moveFocus( eye, ratio );
     618           4 :     wall.apply( coverage );
     619           4 :     _updateOverdraw( wall );
     620           4 :     wall.scale( view->getModelUnit( ));
     621             : 
     622           4 :     switch( segment->getCurrentType( ))
     623             :     {
     624             :         case Frustum::TYPE_WALL:
     625             :         {
     626           4 :             setWall( wall );
     627           4 :             LBLOG( LOG_VIEW ) << "Segment wall for " << channel->getName()
     628           4 :                               << ": " << wall << std::endl;
     629           4 :             return;
     630             :         }
     631             : 
     632             :         case Frustum::TYPE_PROJECTION:
     633             :         {
     634           0 :             Projection projection( segment->getProjection( ));
     635           0 :             projection = wall;
     636           0 :             setProjection( projection );
     637           0 :             LBLOG( LOG_VIEW ) << "Segment projection for "
     638           0 :                               << channel->getName() << ": " << projection
     639           0 :                               << std::endl;
     640           0 :             return;
     641             :         }
     642             :         default:
     643           0 :             LBUNIMPLEMENTED;
     644             :     }
     645             : }
     646             : 
     647           0 : void Compound::_computeFrustum( RenderContext& context ) const
     648             : {
     649             :     // compute eye position in screen space
     650           0 :     const Vector3f& eyeWorld = _getEyePosition( context.eye );
     651           0 :     const FrustumData& frustumData = _inherit.frustumData;
     652           0 :     const Matrix4f& xfm = frustumData.getTransform();
     653           0 :     const Vector3f eyeWall = xfm * eyeWorld;
     654             : 
     655           0 :     LBVERB << "Eye position world: " << eyeWorld << " wall " << eyeWall
     656           0 :         << std::endl;
     657           0 :     _computePerspective( context, eyeWall );
     658           0 :     _computeOrtho( context, eyeWall );
     659           0 : }
     660             : 
     661           0 : void Compound::computeTileFrustum( Frustumf& frustum, const Eye eye,
     662             :                                    Viewport vp, bool ortho ) const
     663             : {
     664           0 :     const Vector3f& eyeWorld = _getEyePosition( eye );
     665           0 :     const FrustumData& frustumData = _inherit.frustumData;
     666           0 :     const Matrix4f& xfm = frustumData.getTransform();
     667           0 :     const Vector3f eyeWall = xfm * eyeWorld;
     668             : 
     669           0 :     _computeFrustumCorners( frustum, frustumData, eyeWall, ortho, &vp );
     670           0 : }
     671             : 
     672             : namespace
     673             : {
     674           0 : static void _computeHeadTransform( Matrix4f& result, const Matrix4f& xfm,
     675             :                                    const Vector3f& eye )
     676             : {
     677             :     // headTransform = -trans(eye) * view matrix (frustum position)
     678           0 :     for( int i=0; i<16; i += 4 )
     679             :     {
     680           0 :         result.array[i]   = xfm.array[i]   - eye[0] * xfm.array[i+3];
     681           0 :         result.array[i+1] = xfm.array[i+1] - eye[1] * xfm.array[i+3];
     682           0 :         result.array[i+2] = xfm.array[i+2] - eye[2] * xfm.array[i+3];
     683           0 :         result.array[i+3] = xfm.array[i+3];
     684             :     }
     685           0 : }
     686             : }
     687             : 
     688           0 : void Compound::_computePerspective( RenderContext& context,
     689             :                                     const Vector3f& eye ) const
     690             : {
     691           0 :     const FrustumData& frustumData = _inherit.frustumData;
     692             : 
     693           0 :     _computeFrustumCorners( context.frustum, frustumData, eye, false );
     694           0 :     _computeHeadTransform( context.headTransform, frustumData.getTransform(),
     695           0 :                            eye );
     696             : 
     697           0 :     const bool isHMD = (frustumData.getType() != Wall::TYPE_FIXED);
     698           0 :     if( isHMD )
     699           0 :         context.headTransform *= _getInverseHeadMatrix();
     700           0 : }
     701             : 
     702           0 : void Compound::_computeOrtho( RenderContext& context, const Vector3f& eye) const
     703             : {
     704             :     // Compute corners for cyclop eye without perspective correction:
     705           0 :     const Vector3f& cyclopWorld = _getEyePosition( EYE_CYCLOP );
     706           0 :     const FrustumData& frustumData = _inherit.frustumData;
     707           0 :     const Matrix4f& xfm = frustumData.getTransform();
     708           0 :     const Vector3f cyclopWall = xfm * cyclopWorld;
     709             : 
     710           0 :     _computeFrustumCorners( context.ortho, frustumData, cyclopWall, true );
     711           0 :     _computeHeadTransform( context.orthoTransform, xfm, eye );
     712             : 
     713             :     // Apply stereo shearing
     714           0 :     context.orthoTransform.array[8] += (cyclopWall[0] - eye[0]) / eye[2];
     715           0 :     context.orthoTransform.array[9] += (cyclopWall[1] - eye[1]) / eye[2];
     716             : 
     717           0 :     const bool isHMD = (frustumData.getType() != Wall::TYPE_FIXED);
     718           0 :     if( isHMD )
     719           0 :         context.orthoTransform *= _getInverseHeadMatrix();
     720           0 : }
     721             : 
     722           0 : Vector3f Compound::_getEyePosition( const Eye eye ) const
     723             : {
     724           0 :     const FrustumData& frustumData = _inherit.frustumData;
     725           0 :     const Channel* destChannel = getInheritChannel();
     726           0 :     const View* view = destChannel->getView();
     727           0 :     const Observer* observer = view ? view->getObserver() : 0;
     728           0 :     const float modelUnit = view ? view->getModelUnit() : 1.f;
     729             : 
     730           0 :     if( observer )
     731             :         return modelUnit *
     732           0 :             ( frustumData.getType() == Wall::TYPE_FIXED ?
     733           0 :                 observer->getEyeWorld( eye ) : observer->getEyePosition( eye ));
     734             : 
     735           0 :     const float eyeBase_2 = 0.5f * modelUnit *
     736           0 :                            getConfig()->getFAttribute( Config::FATTR_EYE_BASE );
     737           0 :     switch( eye )
     738             :     {
     739             :       case EYE_LEFT:
     740           0 :           return Vector3f(-eyeBase_2, 0.f, 0.f );
     741             :       case EYE_RIGHT:
     742           0 :           return Vector3f( eyeBase_2, 0.f, 0.f );
     743             : 
     744             :       default:
     745           0 :           LBUNIMPLEMENTED;
     746             :       case EYE_CYCLOP:
     747           0 :           return Vector3f::ZERO;
     748             :     }
     749             : }
     750             : 
     751           0 : const Matrix4f& Compound::_getInverseHeadMatrix() const
     752             : {
     753           0 :     const Channel* destChannel = getInheritChannel();
     754           0 :     const View* view = destChannel->getView();
     755             :     const Observer* observer = static_cast< const Observer* >(
     756           0 :         view ? view->getObserver() : 0);
     757             : 
     758           0 :     if( observer )
     759           0 :         return observer->getInverseHeadMatrix();
     760             : 
     761           0 :     static const Matrix4f identity;
     762           0 :     return identity;
     763             : }
     764             : 
     765           0 : void Compound::_computeFrustumCorners( Frustumf& frustum,
     766             :                                        const FrustumData& frustumData,
     767             :                                        const Vector3f& eye,
     768             :                                        const bool ortho,
     769             :                                        const Viewport* const invp ) const
     770             : {
     771           0 :     const Channel* destination = getInheritChannel();
     772           0 :     frustum = destination->getFrustum();
     773             : 
     774           0 :     const float ratio    = ortho ? 1.0f : frustum.nearPlane() / eye.z();
     775           0 :     const float width_2  = frustumData.getWidth()  * .5f;
     776           0 :     const float height_2 = frustumData.getHeight() * .5f;
     777             : 
     778           0 :     if( eye.z() > 0 || ortho )
     779             :     {
     780           0 :         frustum.left()   =  ( -width_2  - eye.x() ) * ratio;
     781           0 :         frustum.right()  =  (  width_2  - eye.x() ) * ratio;
     782           0 :         frustum.bottom() =  ( -height_2 - eye.y() ) * ratio;
     783           0 :         frustum.top()    =  (  height_2 - eye.y() ) * ratio;
     784             :     }
     785             :     else // eye behind near plane - 'mirror' x
     786             :     {
     787           0 :         frustum.left()   =  (  width_2  - eye.x() ) * ratio;
     788           0 :         frustum.right()  =  ( -width_2  - eye.x() ) * ratio;
     789           0 :         frustum.bottom() =  (  height_2 + eye.y() ) * ratio;
     790           0 :         frustum.top()    =  ( -height_2 + eye.y() ) * ratio;
     791             :     }
     792             : 
     793             :     // move frustum according to pixel decomposition
     794           0 :     const Pixel& pixel = getInheritPixel();
     795           0 :     if( pixel != Pixel::ALL && pixel.isValid( ))
     796             :     {
     797           0 :         const Channel* inheritChannel = getInheritChannel();
     798           0 :         const PixelViewport& destPVP = inheritChannel->getPixelViewport();
     799             : 
     800           0 :         if( pixel.w > 1 )
     801             :         {
     802           0 :             const float         frustumWidth = frustum.right() - frustum.left();
     803           0 :             const float           pixelWidth = frustumWidth /
     804           0 :                 static_cast<float>( destPVP.w );
     805           0 :             const float               jitter = pixelWidth * pixel.x -
     806           0 :                 pixelWidth * .5f;
     807             : 
     808           0 :             frustum.left()  += jitter;
     809           0 :             frustum.right() += jitter;
     810             :         }
     811           0 :         if( pixel.h > 1 )
     812             :         {
     813           0 :             const float frustumHeight = frustum.bottom() - frustum.top();
     814           0 :             const float pixelHeight = frustumHeight / float( destPVP.h );
     815           0 :             const float jitter = pixelHeight * pixel.y + pixelHeight * .5f;
     816             : 
     817           0 :             frustum.top()    -= jitter;
     818           0 :             frustum.bottom() -= jitter;
     819             :         }
     820             :     }
     821             : 
     822             :     // adjust to viewport (screen-space decomposition)
     823             :     // Note: vp is computed pixel-correct by Compound::updateInheritData()
     824           0 :     const Viewport& vp = invp ? *invp : _inherit.vp;
     825           0 :     if( vp != Viewport::FULL && vp.isValid( ))
     826             :     {
     827           0 :         const float frustumWidth = frustum.right() - frustum.left();
     828           0 :         frustum.left()  += frustumWidth * vp.x;
     829           0 :         frustum.right()  = frustum.left() + frustumWidth * vp.w;
     830             : 
     831           0 :         const float frustumHeight = frustum.top() - frustum.bottom();
     832           0 :         frustum.bottom() += frustumHeight * vp.y;
     833           0 :         frustum.top()     = frustum.bottom() + frustumHeight * vp.h;
     834             :     }
     835           0 : }
     836             : 
     837           4 : void Compound::_updateOverdraw( Wall& wall )
     838             : {
     839           4 :     Channel* channel = getChannel();
     840           4 :     LBASSERT( channel );
     841           4 :     if( !channel )
     842           0 :         return;
     843             : 
     844           4 :     const Segment* segment = channel->getSegment();
     845           4 :     const View*    view    = channel->getView();
     846           4 :     LBASSERT( segment && view );
     847           4 :     if( !segment || !view )
     848           0 :         return;
     849             : 
     850           4 :     const Viewport& segmentVP = segment->getViewport();
     851           4 :     const Viewport& viewVP    = view->getViewport();
     852           4 :     const Vector2i& overdraw  = view->getOverdraw();
     853           4 :     Vector4i channelOverdraw( Vector4i::ZERO );
     854             : 
     855             :     // compute overdraw
     856           4 :     if( overdraw.x() && viewVP.x < segmentVP.x )
     857           0 :         channelOverdraw.x() = overdraw.x();
     858             : 
     859           4 :     if( overdraw.x() && viewVP.getXEnd() > segmentVP.getXEnd( ))
     860           0 :         channelOverdraw.z() = overdraw.x();
     861             : 
     862           4 :     if( overdraw.y() && viewVP.y < segmentVP.y )
     863           0 :         channelOverdraw.y() = overdraw.y();
     864             : 
     865           4 :     if( overdraw.y() && viewVP.getYEnd() > segmentVP.getYEnd( ))
     866           0 :         channelOverdraw.w() = overdraw.y();
     867             : 
     868             :     // clamp to max channel size
     869           4 :     const Vector2i& maxSize = channel->getMaxSize();
     870           4 :     if( maxSize != Vector2i::ZERO )
     871             :     {
     872           0 :         const PixelViewport& channelPVP = channel->getPixelViewport();
     873             : 
     874           0 :         const int32_t xOverdraw = channelOverdraw.x() + channelOverdraw.z();
     875           0 :         const int32_t xSize = xOverdraw + channelPVP.w;
     876           0 :         if( xSize > maxSize.x( ))
     877             :         {
     878           0 :             const uint32_t maxOverdraw = maxSize.x() - channelPVP.w;
     879           0 :             const float ratio = static_cast< float >( maxOverdraw ) /
     880           0 :                                 static_cast< float >( xOverdraw );
     881           0 :             channelOverdraw.x() = static_cast< int >(
     882           0 :                 channelOverdraw.x() * ratio + .5f );
     883           0 :             channelOverdraw.z() = maxOverdraw - channelOverdraw.x();
     884             :         }
     885             : 
     886           0 :         const int32_t yOverdraw = channelOverdraw.y() + channelOverdraw.w();
     887           0 :         const int32_t ySize = yOverdraw + channelPVP.h;
     888           0 :         if( ySize > maxSize.y( ))
     889             :         {
     890           0 :             const uint32_t maxOverdraw = maxSize.y() - channelPVP.h;
     891           0 :             const float ratio = static_cast< float >( maxOverdraw ) /
     892           0 :                                 static_cast< float >( yOverdraw );
     893           0 :             channelOverdraw.y() = static_cast< int >(
     894           0 :                 channelOverdraw.y() * ratio +.5f );
     895           0 :             channelOverdraw.w() = maxOverdraw - channelOverdraw.y();
     896             :         }
     897             :     }
     898             : 
     899             :     // apply to frustum
     900           4 :     if( channelOverdraw.x() > 0 )
     901             :     {
     902           0 :         const PixelViewport& pvp = channel->getPixelViewport();
     903           0 :         const float ratio = static_cast<float>( pvp.w + channelOverdraw.x( )) /
     904           0 :                             static_cast<float>( pvp.w );
     905           0 :         wall.resizeLeft( ratio );
     906             :     }
     907             : 
     908           4 :     if( channelOverdraw.z() > 0 )
     909             :     {
     910           0 :         const PixelViewport& pvp = channel->getPixelViewport();
     911           0 :         const float ratio = static_cast<float>( pvp.w + channelOverdraw.x( ) +
     912           0 :                                                 channelOverdraw.z( )) /
     913           0 :                             static_cast<float>( pvp.w + channelOverdraw.x( ));
     914           0 :         wall.resizeRight( ratio );
     915             :     }
     916             : 
     917           4 :     if( channelOverdraw.y() > 0 )
     918             :     {
     919           0 :         const PixelViewport& pvp = channel->getPixelViewport();
     920           0 :         const float ratio = static_cast<float>( pvp.h + channelOverdraw.y( )) /
     921           0 :                             static_cast<float>( pvp.h );
     922           0 :         wall.resizeBottom( ratio );
     923             :     }
     924             : 
     925           4 :     if( channelOverdraw.w() > 0 )
     926             :     {
     927           0 :         const PixelViewport& pvp = channel->getPixelViewport();
     928           0 :         const float ratio = static_cast<float>( pvp.h + + channelOverdraw.y( ) +
     929           0 :                                                 channelOverdraw.w( )) /
     930           0 :                             static_cast<float>( pvp.h + channelOverdraw.y( ));
     931           0 :         wall.resizeTop( ratio );
     932             :     }
     933             : 
     934           4 :     channel->setOverdraw( channelOverdraw );
     935             : }
     936             : 
     937             : //---------------------------------------------------------------------------
     938             : // accept
     939             : //---------------------------------------------------------------------------
     940             : namespace
     941             : {
     942             : template< class C >
     943        2120 : VisitorResult _accept( C* compound, CompoundVisitor& visitor )
     944             : {
     945        2120 :     if( compound->isLeaf( ))
     946          18 :         return visitor.visitLeaf( compound );
     947             : 
     948        2102 :     C* current = compound;
     949        2102 :     VisitorResult result = TRAVERSE_CONTINUE;
     950             : 
     951             :     while( true )
     952             :     {
     953        5888 :         C* parent = current->getParent();
     954        5888 :         C* next   = current->getNext();
     955             : 
     956        5888 :         const Compounds& children = current->getChildren();
     957        5888 :         C* child  = children.empty() ? 0 : children[0];
     958             : 
     959             :         //---------- down-right traversal
     960        5888 :         if ( !child ) // leaf
     961             :         {
     962        3162 :             switch( visitor.visitLeaf( current ))
     963             :             {
     964             :                 case TRAVERSE_TERMINATE:
     965         174 :                     return TRAVERSE_TERMINATE;
     966             : 
     967             :                 case TRAVERSE_PRUNE:
     968        1704 :                     result = TRAVERSE_PRUNE;
     969        1704 :                     current = next;
     970        1704 :                     break;
     971             : 
     972             :                 case TRAVERSE_CONTINUE:
     973        1284 :                     current = next;
     974        1284 :                     break;
     975             : 
     976             :                 default:
     977           0 :                     LBASSERTINFO( 0, "Unreachable" );
     978             :             }
     979             :         }
     980             :         else // node
     981             :         {
     982        2726 :             switch( visitor.visitPre( current ))
     983             :             {
     984             :                 case TRAVERSE_TERMINATE:
     985         256 :                     return TRAVERSE_TERMINATE;
     986             : 
     987             :                 case TRAVERSE_PRUNE:
     988        1218 :                     result = TRAVERSE_PRUNE;
     989        1218 :                     current = next;
     990        1218 :                     break;
     991             : 
     992             :                 case TRAVERSE_CONTINUE:
     993        1252 :                     current = child;
     994        1252 :                     break;
     995             : 
     996             :                 default:
     997           0 :                     LBASSERTINFO( 0, "Unreachable" );
     998             :             }
     999             :         }
    1000             : 
    1001             :         //---------- up-right traversal
    1002        5458 :         if( !current && !parent ) return TRAVERSE_CONTINUE;
    1003             : 
    1004        9380 :         while( !current )
    1005             :         {
    1006        1020 :             current = parent;
    1007        1020 :             parent  = current->getParent();
    1008        1020 :             next    = current->getNext();
    1009             : 
    1010        1020 :             switch( visitor.visitPost( current ))
    1011             :             {
    1012             :                 case TRAVERSE_TERMINATE:
    1013           0 :                     return TRAVERSE_TERMINATE;
    1014             : 
    1015             :                 case TRAVERSE_PRUNE:
    1016           0 :                     result = TRAVERSE_PRUNE;
    1017           0 :                     break;
    1018             : 
    1019             :                 case TRAVERSE_CONTINUE:
    1020        1020 :                     break;
    1021             : 
    1022             :                 default:
    1023           0 :                     LBASSERTINFO( 0, "Unreachable" );
    1024             :             }
    1025             : 
    1026        1020 :             if ( current == compound )
    1027         788 :                 return result;
    1028             : 
    1029         232 :             current = next;
    1030             :         }
    1031             :     }
    1032        3786 :     return result;
    1033             : }
    1034             : }
    1035             : 
    1036        2120 : VisitorResult Compound::accept( CompoundVisitor& visitor )
    1037             : {
    1038        2120 :     return _accept( this, visitor );
    1039             : }
    1040             : 
    1041           0 : VisitorResult Compound::accept( CompoundVisitor& visitor ) const
    1042             : {
    1043           0 :     return _accept( this, visitor );
    1044             : }
    1045             : 
    1046             : //---------------------------------------------------------------------------
    1047             : // Operations
    1048             : //---------------------------------------------------------------------------
    1049             : 
    1050           4 : void Compound::activate( const uint32_t eyes )
    1051             : {
    1052          16 :     for( size_t i = 0; i < NUM_EYES; ++i )
    1053             :     {
    1054          12 :         const Eye eye = Eye( 1 << i );
    1055          12 :         if( !(eyes & eye) )
    1056          14 :             continue;
    1057             : 
    1058           8 :         ++_data.active[ i ];
    1059           8 :         if( !getChannel( )) // non-dest root compound
    1060           6 :             continue;
    1061             : 
    1062           2 :         CompoundActivateVisitor channelActivate( true, eye );
    1063           2 :         accept( channelActivate );
    1064           2 :     }
    1065           4 : }
    1066             : 
    1067           4 : void Compound::deactivate( const uint32_t eyes )
    1068             : {
    1069          16 :     for( size_t i = 0; i < NUM_EYES; ++i )
    1070             :     {
    1071          12 :         const fabric::Eye eye = static_cast< Eye >( 1 << i );
    1072          12 :         if( !(eyes & eye) )
    1073          14 :             continue;
    1074             : 
    1075           8 :         LBASSERT( _data.active[ i ] );
    1076           8 :         --_data.active[ i ];
    1077           8 :         if( !getChannel( )) // non-dest root compound
    1078           6 :             continue;
    1079             : 
    1080           2 :         CompoundActivateVisitor channelDeactivate( false, eye );
    1081           2 :         accept( channelDeactivate );
    1082           2 :     }
    1083           4 : }
    1084             : 
    1085           2 : void Compound::init()
    1086             : {
    1087           2 :     CompoundInitVisitor initVisitor;
    1088           2 :     accept( initVisitor );
    1089           2 : }
    1090             : 
    1091           2 : void Compound::exit()
    1092             : {
    1093           2 :     CompoundExitVisitor visitor;
    1094           2 :     accept( visitor );
    1095           2 : }
    1096             : 
    1097           8 : void Compound::register_()
    1098             : {
    1099           8 :     ServerPtr server = getServer();
    1100           8 :     const uint32_t latency = getConfig()->getLatency();
    1101             : 
    1102          24 :     for( Frames::const_iterator i = _outputFrames.begin();
    1103          16 :          i != _outputFrames.end(); ++i )
    1104             :     {
    1105           0 :         Frame* frame = *i;
    1106           0 :         server->registerObject( frame );
    1107           0 :         frame->setAutoObsolete( latency );
    1108           0 :         LBLOG( LOG_ASSEMBLY ) << "Output frame \"" << frame->getName()
    1109           0 :                               << "\" id " << frame->getID() << std::endl;
    1110             :     }
    1111             : 
    1112          24 :     for( Frames::const_iterator i = _inputFrames.begin();
    1113          16 :          i != _inputFrames.end(); ++i )
    1114             :     {
    1115           0 :         Frame* frame = *i;
    1116           0 :         server->registerObject( frame );
    1117           0 :         frame->setAutoObsolete( latency );
    1118           0 :         LBLOG( LOG_ASSEMBLY ) << "Input frame \"" << frame->getName()
    1119           0 :                               << "\" id " << frame->getID() << std::endl;
    1120             :     }
    1121             : 
    1122          24 :     for( TileQueuesCIter i = _inputTileQueues.begin();
    1123          16 :          i != _inputTileQueues.end(); ++i )
    1124             :     {
    1125           0 :         TileQueue* queue = *i;
    1126           0 :         server->registerObject( queue );
    1127           0 :         queue->setAutoObsolete( latency );
    1128           0 :         LBLOG( LOG_ASSEMBLY ) << "Input queue \"" << queue->getName()
    1129           0 :                               << "\" id " << queue->getID() << std::endl;
    1130             :     }
    1131             : 
    1132          24 :     for( TileQueuesCIter i = _outputTileQueues.begin();
    1133          16 :          i != _outputTileQueues.end(); ++i )
    1134             :     {
    1135           0 :         TileQueue* queue = *i;
    1136           0 :         server->registerObject( queue );
    1137           0 :         queue->setAutoObsolete( latency );
    1138           0 :         LBLOG( LOG_ASSEMBLY ) << "Output queue \"" << queue->getName()
    1139           0 :                               << "\" id " << queue->getID() << std::endl;
    1140           8 :     }
    1141           8 : }
    1142             : 
    1143           8 : void Compound::deregister()
    1144             : {
    1145           8 :     ServerPtr server = getServer();
    1146             : 
    1147          24 :     for( Frames::const_iterator i = _outputFrames.begin();
    1148          16 :          i != _outputFrames.end(); ++i )
    1149             :     {
    1150           0 :         Frame* frame = *i;
    1151           0 :         frame->flush();
    1152           0 :         server->deregisterObject( frame );
    1153             :     }
    1154             : 
    1155          24 :     for( Frames::const_iterator i = _inputFrames.begin();
    1156          16 :          i != _inputFrames.end(); ++i )
    1157             :     {
    1158           0 :         Frame* frame = *i;
    1159           0 :         server->deregisterObject( frame );
    1160             :     }
    1161             : 
    1162          24 :     for( TileQueuesCIter i = _inputTileQueues.begin();
    1163          16 :         i != _inputTileQueues.end(); ++i )
    1164             :     {
    1165           0 :         TileQueue* queue = *i;
    1166           0 :         server->deregisterObject( queue );
    1167             :     }
    1168             : 
    1169          24 :     for( TileQueuesCIter i = _outputTileQueues.begin();
    1170          16 :         i != _outputTileQueues.end(); ++i )
    1171             :     {
    1172           0 :         TileQueue* queue = *i;
    1173           0 :         queue->flush();
    1174           0 :         server->deregisterObject( queue );
    1175           8 :     }
    1176           8 : }
    1177             : 
    1178           4 : void Compound::backup()
    1179             : {
    1180           4 :     _backup = _data;
    1181             : 
    1182           4 :     for( EqualizersCIter i = _equalizers.begin(); i != _equalizers.end(); ++i )
    1183           0 :         (*i)->backup();
    1184           4 : }
    1185             : 
    1186           4 : void Compound::restore()
    1187             : {
    1188           4 :     _data = _backup;
    1189             : 
    1190           4 :     for( EqualizersCIter i = _equalizers.begin(); i != _equalizers.end(); ++i )
    1191           0 :         (*i)->restore();
    1192           4 : }
    1193             : 
    1194             : //---------------------------------------------------------------------------
    1195             : // pre-render compound state update
    1196             : //---------------------------------------------------------------------------
    1197           0 : void Compound::update( const uint32_t frameNumber )
    1198             : {
    1199             :     // https://github.com/Eyescale/Equalizer/issues/76
    1200           0 :     CompoundUpdateActivateVisitor updateActivateVisitor( frameNumber );
    1201           0 :     accept( updateActivateVisitor );
    1202             : 
    1203           0 :     CompoundUpdateDataVisitor updateDataVisitor( frameNumber );
    1204           0 :     accept( updateDataVisitor );
    1205             : 
    1206           0 :     CompoundUpdateOutputVisitor updateOutputVisitor( frameNumber );
    1207           0 :     accept( updateOutputVisitor );
    1208             : 
    1209           0 :     const FrameMap& outputFrames = updateOutputVisitor.getOutputFrames();
    1210           0 :     const TileQueueMap& outputQueues = updateOutputVisitor.getOutputQueues();
    1211           0 :     CompoundUpdateInputVisitor updateInputVisitor( outputFrames, outputQueues );
    1212           0 :     accept( updateInputVisitor );
    1213             : 
    1214             :     // commit output frames after input frames have been set
    1215           0 :     for( FrameMapCIter i = outputFrames.begin(); i != outputFrames.end(); ++i )
    1216             :     {
    1217           0 :         Frame* frame = i->second;
    1218           0 :         frame->commit();
    1219             :     }
    1220             : 
    1221           0 :     const BarrierMap& swapBarriers = updateOutputVisitor.getSwapBarriers();
    1222           0 :     for( BarrierMapCIter i = swapBarriers.begin(); i != swapBarriers.end(); ++i)
    1223             :     {
    1224           0 :         co::Barrier* barrier = i->second;
    1225           0 :         LBASSERT( barrier->isGood( ));
    1226           0 :         if( barrier->getHeight() > 1 )
    1227           0 :             barrier->commit();
    1228           0 :     }
    1229           0 : }
    1230             : 
    1231           4 : void Compound::updateInheritData( const uint32_t frameNumber )
    1232             : {
    1233           4 :     _data.pixel.validate();
    1234           4 :     _data.subPixel.validate();
    1235           4 :     _data.zoom.validate();
    1236             : 
    1237           4 :     if( isRoot( ))
    1238           2 :         _updateInheritRoot();
    1239             :     else
    1240           2 :         _updateInheritNode();
    1241             : 
    1242           4 :     if( _inherit.channel )
    1243             :     {
    1244           2 :         _updateInheritStereo();
    1245           2 :         _updateInheritActive( frameNumber );
    1246             :     }
    1247             : 
    1248           4 :     if( _inherit.pvp.isValid( ))
    1249             :     {
    1250           0 :         _inherit.pvp.apply( _data.pixel );
    1251             : 
    1252             :         // Zoom
    1253           0 :         const PixelViewport unzoomedPVP( _inherit.pvp );
    1254           0 :         _inherit.pvp.apply( _data.zoom );
    1255             : 
    1256             :         // update inherit zoom to be pixel-correct with the integer-rounded pvp
    1257           0 :         const Zoom zoom = _inherit.pvp.getZoom( unzoomedPVP );
    1258           0 :         _inherit.zoom *= zoom;
    1259             :     }
    1260             : 
    1261             :     // Tasks
    1262           4 :     updateInheritTasks();
    1263             : 
    1264           4 :     const View* view = _inherit.channel ? _inherit.channel->getView() : 0;
    1265           4 :     const Channel* channel = getChannel();
    1266           4 :     if( channel && !channel->supportsView( view ))
    1267           0 :         _inherit.tasks = fabric::TASK_NONE;
    1268             : 
    1269           4 :     if( !_inherit.pvp.hasArea() || !_inherit.range.hasData( ))
    1270             :         // Channels with no PVP or range do not execute tasks
    1271           4 :         _inherit.tasks = fabric::TASK_NONE;
    1272           4 : }
    1273             : 
    1274           2 : void Compound::_updateInheritRoot()
    1275             : {
    1276           2 :     LBASSERT( !_parent );
    1277             : 
    1278           2 :     const PixelViewport oldPVP( _inherit.pvp );
    1279           2 :     _inherit = _data;
    1280           2 :     _inherit.pvp = oldPVP;
    1281             : 
    1282           2 :     _inherit.zoom = Zoom::NONE; // will be reapplied by parent method
    1283           2 :     _updateInheritPVP();
    1284             : 
    1285           2 :     if( _inherit.eyes == fabric::EYE_UNDEFINED )
    1286           2 :         _inherit.eyes = fabric::EYES_ALL;
    1287           0 :     else if( _inherit.channel )
    1288             :     {
    1289           0 :         const View* view = _inherit.channel->getView();
    1290           0 :         if( !view )
    1291           0 :             _inherit.eyes = EYE_CYCLOP;
    1292             :     }
    1293             : 
    1294           2 :     if( _inherit.period == LB_UNDEFINED_UINT32 )
    1295           2 :         _inherit.period = 1;
    1296             : 
    1297           2 :     if( _inherit.phase == LB_UNDEFINED_UINT32 )
    1298           2 :         _inherit.phase = 0;
    1299             : 
    1300           2 :     if( _inherit.buffers == Frame::BUFFER_UNDEFINED )
    1301           2 :         _inherit.buffers = Frame::BUFFER_COLOR;
    1302             : 
    1303           2 :     if( _inherit.iAttributes[IATTR_STEREO_MODE] == UNDEFINED )
    1304           2 :         _inherit.iAttributes[IATTR_STEREO_MODE] = fabric::AUTO;
    1305             : 
    1306           2 :     if( _inherit.iAttributes[IATTR_STEREO_ANAGLYPH_LEFT_MASK] == UNDEFINED )
    1307           2 :         _inherit.iAttributes[IATTR_STEREO_ANAGLYPH_LEFT_MASK] = COLOR_MASK_RED;
    1308             : 
    1309           2 :     if( _inherit.iAttributes[IATTR_STEREO_ANAGLYPH_RIGHT_MASK] == UNDEFINED )
    1310             :         _inherit.iAttributes[IATTR_STEREO_ANAGLYPH_RIGHT_MASK] =
    1311           2 :             COLOR_MASK_GREEN | COLOR_MASK_BLUE;
    1312           2 : }
    1313             : 
    1314           2 : void Compound::_updateInheritNode()
    1315             : {
    1316           2 :     LBASSERT( _parent );
    1317           2 :     const PixelViewport oldPVP( _inherit.pvp );
    1318           2 :     _inherit = _parent->_inherit;
    1319             : 
    1320           2 :     if( !_inherit.channel )
    1321             :     {
    1322           2 :         _inherit.pvp = oldPVP;
    1323           2 :         _updateInheritPVP();
    1324           2 :         _inherit.vp.apply( _data.vp );
    1325             :     }
    1326           0 :     else if( _inherit.pvp.isValid( ))
    1327             :     {
    1328           0 :         LBASSERT( _data.vp.isValid( ));
    1329           0 :         _inherit.pvp.apply( _data.vp );
    1330             : 
    1331             :         // Compute the inherit viewport to be pixel-correct with the integer-
    1332             :         // rounded pvp. This is needed to calculate the frustum correctly.
    1333           0 :         const Viewport vp = _inherit.pvp / _parent->_inherit.pvp;
    1334           0 :         _inherit.vp.apply( vp );
    1335             : 
    1336           0 :         _updateInheritOverdraw();
    1337             :     }
    1338             :     else
    1339             :     {
    1340           0 :         LBASSERT( !_inherit.channel->isRunning( ));
    1341             :     }
    1342             : 
    1343           2 :     if( _data.frustumData.isValid( ))
    1344           2 :         _inherit.frustumData = _data.frustumData;
    1345             : 
    1346           2 :     _inherit.range.apply( _data.range );
    1347           2 :     _inherit.pixel.apply( _data.pixel );
    1348           2 :     _inherit.subPixel.apply( _data.subPixel );
    1349             : 
    1350           2 :     if( _data.eyes != fabric::EYE_UNDEFINED )
    1351           0 :         _inherit.eyes = _data.eyes;
    1352           2 :     else if( _inherit.channel )
    1353             :     {
    1354           2 :         const View* view = _inherit.channel->getView();
    1355           2 :         if( !view )
    1356           0 :             _inherit.eyes = EYE_CYCLOP;
    1357             :     }
    1358             : 
    1359           2 :     if( _data.period != LB_UNDEFINED_UINT32 )
    1360           0 :         _inherit.period = _data.period;
    1361             : 
    1362           2 :     if( _data.phase != LB_UNDEFINED_UINT32 )
    1363           0 :         _inherit.phase = _data.phase;
    1364             : 
    1365           2 :     _inherit.maxFPS = _data.maxFPS;
    1366             : 
    1367           2 :     if( _data.buffers != Frame::BUFFER_UNDEFINED )
    1368           0 :         _inherit.buffers = _data.buffers;
    1369             : 
    1370           2 :     if( _data.iAttributes[IATTR_STEREO_MODE] != UNDEFINED )
    1371             :         _inherit.iAttributes[IATTR_STEREO_MODE] =
    1372           0 :             _data.iAttributes[IATTR_STEREO_MODE];
    1373             : 
    1374           2 :     if( _data.iAttributes[IATTR_STEREO_ANAGLYPH_LEFT_MASK] != UNDEFINED )
    1375             :         _inherit.iAttributes[IATTR_STEREO_ANAGLYPH_LEFT_MASK] =
    1376           0 :             _data.iAttributes[IATTR_STEREO_ANAGLYPH_LEFT_MASK];
    1377             : 
    1378           2 :     if( _data.iAttributes[IATTR_STEREO_ANAGLYPH_RIGHT_MASK] != UNDEFINED )
    1379             :         _inherit.iAttributes[IATTR_STEREO_ANAGLYPH_RIGHT_MASK] =
    1380           0 :             _data.iAttributes[IATTR_STEREO_ANAGLYPH_RIGHT_MASK];
    1381           2 : }
    1382             : 
    1383           4 : void Compound::_updateInheritPVP()
    1384             : {
    1385           4 :     Channel* channel = _data.channel;
    1386           4 :     if( !channel )
    1387           6 :         return;
    1388             : 
    1389           2 :     const PixelViewport oldPVP( _inherit.pvp );
    1390           2 :     _inherit.channel = channel;
    1391           2 :     _inherit.pvp = channel->getPixelViewport( );
    1392             : 
    1393           2 :     View* view = channel->getView();
    1394           2 :     if( !view || !_inherit.pvp.isValid( ))
    1395             :     {
    1396           2 :         LBASSERT( channel->getOverdraw() == Vector4i::ZERO );
    1397           2 :         return;
    1398             :     }
    1399           0 :     LBASSERT( channel == getChannel( ));
    1400             : 
    1401             :     // enlarge pvp by overdraw
    1402           0 :     const Vector4i& overdraw = channel->getOverdraw();
    1403           0 :     _inherit.pvp.w += overdraw.x() + overdraw.z();
    1404           0 :     _inherit.pvp.h += overdraw.y() + overdraw.w();
    1405             : 
    1406           0 :     if( oldPVP != _inherit.pvp ) // channel PVP changed
    1407             :     {
    1408           0 :         view->updateFrusta();
    1409           0 :         LBASSERT( overdraw == channel->getOverdraw( ));
    1410             :     }
    1411             : 
    1412           0 :     _inherit.overdraw = overdraw;
    1413             : }
    1414             : 
    1415           0 : void Compound::_updateInheritOverdraw()
    1416             : {
    1417           0 :     const PixelViewport& pvp = _inherit.pvp;
    1418           0 :     const PixelViewport& parentPVP = _parent->_inherit.pvp;
    1419             : 
    1420           0 :     _inherit.overdraw.x() -= pvp.x - parentPVP.x;
    1421           0 :     _inherit.overdraw.y() -= pvp.y - parentPVP.y;
    1422           0 :     _inherit.overdraw.z() -= parentPVP.getXEnd() - pvp.getXEnd();
    1423           0 :     _inherit.overdraw.w() -= parentPVP.getYEnd() - pvp.getYEnd();
    1424             : 
    1425           0 :     _inherit.overdraw.x() = LB_MAX( _inherit.overdraw.x(), 0 );
    1426           0 :     _inherit.overdraw.y() = LB_MAX( _inherit.overdraw.y(), 0 );
    1427           0 :     _inherit.overdraw.z() = LB_MAX( _inherit.overdraw.z(), 0 );
    1428           0 :     _inherit.overdraw.w() = LB_MAX( _inherit.overdraw.w(), 0 );
    1429             : 
    1430           0 :     _inherit.overdraw.x() = LB_MIN( _inherit.overdraw.x(), pvp.w );
    1431           0 :     _inherit.overdraw.y() = LB_MIN( _inherit.overdraw.y(), pvp.h );
    1432           0 :     _inherit.overdraw.z() = LB_MIN( _inherit.overdraw.z(), pvp.w );
    1433           0 :     _inherit.overdraw.w() = LB_MIN( _inherit.overdraw.w(), pvp.h );
    1434             : 
    1435           0 :     LBASSERTINFO( pvp.w >= _inherit.overdraw.x() + _inherit.overdraw.z(),
    1436             :                   pvp.w << " < " <<
    1437             :                   _inherit.overdraw.x() + _inherit.overdraw.z( ));
    1438           0 :     LBASSERTINFO( pvp.h >= _inherit.overdraw.y() + _inherit.overdraw.w(),
    1439             :                   pvp.h << " < " <<
    1440             :                   _inherit.overdraw.y() + _inherit.overdraw.w( ));
    1441           0 : }
    1442             : 
    1443           8 : void Compound::updateInheritTasks()
    1444             : {
    1445           8 :     if( _data.tasks == fabric::TASK_DEFAULT )
    1446             :     {
    1447           8 :         if( isLeaf( ))
    1448             :         {
    1449           6 :             _inherit.tasks = fabric::TASK_ALL;
    1450             :             // check if a parent compound has cleared us
    1451          12 :             for( Compound* compound = getParent(); compound;
    1452             :                  compound = compound->getParent( ))
    1453             :             {
    1454           6 :                 Channel* channel = compound->getChannel();
    1455           6 :                 if( channel == getChannel( ))
    1456           0 :                     _inherit.tasks &= ~fabric::TASK_CLEAR; // done already
    1457             :             }
    1458             :         }
    1459             :         else
    1460             :             _inherit.tasks = fabric::TASK_CLEAR | fabric::TASK_ASSEMBLE |
    1461           2 :                              fabric::TASK_READBACK;
    1462             :     }
    1463             :     else
    1464           0 :         _inherit.tasks = _data.tasks;
    1465             : 
    1466           8 :     const Channel* channel = getChannel();
    1467           8 :     if( isDestination() && channel->getView( ))
    1468           6 :         _inherit.tasks |= fabric::TASK_VIEW;
    1469             :     else
    1470           2 :         _inherit.tasks &= ~fabric::TASK_VIEW;
    1471           8 : }
    1472             : 
    1473           2 : void Compound::_updateInheritStereo()
    1474             : {
    1475           2 :     if( _inherit.iAttributes[IATTR_STEREO_MODE] != fabric::AUTO )
    1476           0 :         return;
    1477             : 
    1478           2 :     const Segment* segment = _inherit.channel->getSegment();
    1479           2 :     const uint32_t eyes = segment ? segment->getEyes() : _inherit.eyes;
    1480           2 :     const bool stereoEyes = ( eyes & EYES_STEREO ) == EYES_STEREO;
    1481           2 :     if( !stereoEyes )
    1482             :     {
    1483           0 :         _inherit.iAttributes[IATTR_STEREO_MODE] = fabric::PASSIVE;
    1484           0 :         return;
    1485             :     }
    1486             : 
    1487           2 :     const Window* window = _inherit.channel->getWindow();
    1488           2 :     const bool stereoWindow = window->getDrawableConfig().stereo;
    1489           4 :     const bool usesFBO =  window && window->getIAttribute(
    1490           4 :                 WindowSettings::IATTR_HINT_DRAWABLE ) == fabric::FBO;
    1491             : 
    1492           2 :     if( stereoWindow && !usesFBO )
    1493           0 :         _inherit.iAttributes[IATTR_STEREO_MODE] = fabric::QUAD;
    1494             :     else
    1495           2 :         _inherit.iAttributes[IATTR_STEREO_MODE] = fabric::ANAGLYPH;
    1496             : }
    1497             : 
    1498           2 : void Compound::_updateInheritActive( const uint32_t frameNumber )
    1499             : {
    1500           2 :     const bool phaseActive = ((frameNumber%_inherit.period) == _inherit.phase );
    1501           2 :     const bool channelActive = _inherit.channel->isRunning(); // runtime failure
    1502             : 
    1503           8 :     for( size_t i = 0; i < fabric::NUM_EYES; ++i )
    1504             :     {
    1505           6 :         const uint32_t eye = 1 << i;
    1506           6 :         const bool eyeActive = _inherit.eyes & eye;
    1507          12 :         const bool destActive = isDestination() ? _data.active[i] :
    1508          12 :                                                   _inherit.active[i];
    1509             : 
    1510           6 :         if( destActive && eyeActive && phaseActive && channelActive )
    1511           0 :             _inherit.active[i] = 1;
    1512             :         else
    1513           6 :             _inherit.active[i] = 0; // deactivate
    1514             :     }
    1515           2 : }
    1516             : 
    1517        2054 : std::ostream& operator << ( std::ostream& os, const Compound& compound )
    1518             : {
    1519        2054 :     os << lunchbox::disableFlush << "compound" << std::endl;
    1520        2054 :     os << "{" << std::endl << lunchbox::indent;
    1521             : 
    1522        2054 :     const std::string& name = compound.getName();
    1523        2054 :     if( !name.empty( ))
    1524           8 :         os << "name     \"" << name << "\"" << std::endl;
    1525             : 
    1526        2054 :     const Channel* channel = compound.getChannel();
    1527        2054 :     if( channel )
    1528             :     {
    1529        1916 :         Compound* parent = compound.getParent();
    1530        1916 :         if( !parent || parent->getChannel() != channel )
    1531             :         {
    1532        1444 :             const std::string& channelName = channel->getName();
    1533        1444 :             const Config*      config      = compound.getConfig();
    1534        1444 :             LBASSERT( config );
    1535             : 
    1536        2888 :             if( !channelName.empty() &&
    1537        1444 :                 config->find< Channel >( channelName ) == channel )
    1538             :             {
    1539         850 :                 os << "channel  \"" << channelName << "\"" << std::endl;
    1540             :             }
    1541             :             else
    1542             :             {
    1543         594 :                 const Segment* segment = channel->getSegment();
    1544         594 :                 const View*    view    = channel->getView();
    1545             : 
    1546         594 :                 if( view && segment )
    1547             :                 {
    1548         594 :                     os << "channel  ( ";
    1549             : 
    1550         594 :                     const Canvas* canvas = segment->getCanvas();
    1551         594 :                     const std::string& canvasName = canvas->getName();
    1552         610 :                     if( !canvasName.empty() &&
    1553          16 :                         config->find< Canvas >( canvasName ) == canvas )
    1554             :                     {
    1555          16 :                         os << "canvas \"" << canvasName << "\"  ";
    1556             :                     }
    1557             :                     else
    1558         578 :                         os << canvas->getPath() << "  ";
    1559             : 
    1560         594 :                     const std::string& segmentName = segment->getName();
    1561         594 :                     if( !segmentName.empty() &&
    1562           0 :                         canvas->findSegment( segmentName ) == segment )
    1563             :                     {
    1564           0 :                         os << "segment \"" << segmentName << "\"   ";
    1565             :                     }
    1566             :                     else
    1567         594 :                         os << "segment " << segment->getPath().segmentIndex
    1568         594 :                            << "   ";
    1569             : 
    1570         594 :                     const Layout* layout = view->getLayout();
    1571         594 :                     const std::string& layoutName = layout->getName();
    1572         882 :                     if( !layoutName.empty() &&
    1573         288 :                         config->find< Layout >( layoutName ) == layout )
    1574             :                     {
    1575         288 :                         os << "layout \"" << layoutName << "\"  ";
    1576             :                     }
    1577             :                     else
    1578         306 :                         os << layout->getPath() << "  ";
    1579             : 
    1580         594 :                     const std::string& viewName = view->getName();
    1581         596 :                     if( !viewName.empty() &&
    1582           2 :                         config->find< View >( viewName ) == view )
    1583             :                     {
    1584           2 :                         os << "view \"" << viewName << '\"';
    1585             :                     }
    1586             :                     else
    1587         592 :                         os << "view " << view->getPath().viewIndex;
    1588             : 
    1589         594 :                     os << " )" << std::endl;
    1590             :                 }
    1591             :                 else
    1592           0 :                     os << "channel  ( " << channel->getPath() << " )"
    1593           0 :                        << std::endl;
    1594             :             }
    1595             :         }
    1596             :     }
    1597             : 
    1598        2054 :     const uint32_t tasks = compound.getTasks();
    1599        2054 :     if( tasks != fabric::TASK_DEFAULT )
    1600             :     {
    1601         188 :         os << "task     [";
    1602         188 :         if( tasks &  fabric::TASK_CLEAR )    os << " CLEAR";
    1603         374 :         if( compound.isLeaf() &&
    1604         190 :             ( tasks &  fabric::TASK_DRAW ))  os << " DRAW";
    1605         188 :         if( tasks &  fabric::TASK_ASSEMBLE ) os << " ASSEMBLE";
    1606         188 :         if( tasks &  fabric::TASK_READBACK ) os << " READBACK";
    1607         188 :         os << " ]" << std::endl;
    1608             :     }
    1609             : 
    1610        2054 :     const uint32_t buffers = compound.getBuffers();
    1611        2054 :     if( buffers != Frame::BUFFER_UNDEFINED )
    1612             :     {
    1613         102 :         os << "buffers  [";
    1614         102 :         if( buffers & Frame::BUFFER_COLOR )  os << " COLOR";
    1615         102 :         if( buffers & Frame::BUFFER_DEPTH )  os << " DEPTH";
    1616         102 :         os << " ]" << std::endl;
    1617             :     }
    1618             : 
    1619        2054 :     const Viewport& vp = compound.getViewport();
    1620        2054 :     if( vp.isValid() && vp != Viewport::FULL )
    1621         128 :         os << "viewport " << vp << std::endl;
    1622             : 
    1623        2054 :     const Range& range = compound.getRange();
    1624        2054 :     if( range.isValid() && range != Range::ALL )
    1625         362 :         os << range << std::endl;
    1626             : 
    1627        2054 :     const Pixel& pixel = compound.getPixel();
    1628        2054 :     if( pixel.isValid() && pixel != Pixel::ALL )
    1629          46 :         os << pixel << std::endl;
    1630             : 
    1631        2054 :     const SubPixel& subPixel = compound.getSubPixel();
    1632        2054 :     if( subPixel.isValid() && subPixel != SubPixel::ALL )
    1633          22 :             os << subPixel << std::endl;
    1634             : 
    1635        2054 :     const Zoom& zoom = compound.getZoom();
    1636        2054 :     if( zoom.isValid() && zoom != Zoom::NONE )
    1637           2 :         os << zoom << std::endl;
    1638             : 
    1639        2054 :     const uint32_t eye = compound.getEyes();
    1640        2054 :     if( eye )
    1641             :     {
    1642         108 :         os << "eye      [ ";
    1643         108 :         if( eye & fabric::EYE_CYCLOP )
    1644          74 :             os << "CYCLOP ";
    1645         108 :         if( eye & fabric::EYE_LEFT )
    1646          52 :             os << "LEFT ";
    1647         108 :         if( eye & fabric::EYE_RIGHT )
    1648          54 :             os << "RIGHT ";
    1649         108 :         os << "]" << std::endl;
    1650             :     }
    1651             : 
    1652        2054 :     const uint32_t period = compound.getPeriod();
    1653        2054 :     const uint32_t phase  = compound.getPhase();
    1654        2054 :     if( period != LB_UNDEFINED_UINT32 )
    1655          34 :         os << "period " << period << "  ";
    1656             : 
    1657        2054 :     if( phase != LB_UNDEFINED_UINT32 )
    1658          34 :         os << "phase " << phase;
    1659             : 
    1660        2054 :     if( period != LB_UNDEFINED_UINT32 || phase != LB_UNDEFINED_UINT32 )
    1661          34 :         os << std::endl;
    1662             : 
    1663             :     // attributes
    1664        2054 :     bool attrPrinted = false;
    1665             : 
    1666       24648 :     for( Compound::IAttribute i = static_cast< Compound::IAttribute >( 0 );
    1667       12324 :          i<Compound::IATTR_ALL;
    1668             :          i = static_cast< Compound::IAttribute >( uint32_t( i ) + 1 ))
    1669             :     {
    1670       10270 :         const int value = compound.getIAttribute( i );
    1671       10270 :         if( value == Global::instance()->getCompoundIAttribute( i ))
    1672       10256 :             continue;
    1673             : 
    1674          14 :         if( !attrPrinted )
    1675             :         {
    1676          10 :             os << std::endl << "attributes" << std::endl;
    1677          10 :             os << "{" << std::endl << lunchbox::indent;
    1678          10 :             attrPrinted = true;
    1679             :         }
    1680             : 
    1681             :         os << ( i==Compound::IATTR_STEREO_MODE ?
    1682             :                     "stereo_mode                " :
    1683             :                 i==Compound::IATTR_STEREO_ANAGLYPH_LEFT_MASK ?
    1684             :                     "stereo_anaglyph_left_mask  " :
    1685             :                 i==Compound::IATTR_STEREO_ANAGLYPH_RIGHT_MASK ?
    1686          14 :                     "stereo_anaglyph_right_mask " : "ERROR " );
    1687             : 
    1688          14 :         switch( i )
    1689             :         {
    1690             :             case Compound::IATTR_STEREO_MODE:
    1691           6 :                 os << static_cast< fabric::IAttribute >( value ) << std::endl;
    1692           6 :                 break;
    1693             : 
    1694             :             case Compound::IATTR_STEREO_ANAGLYPH_LEFT_MASK:
    1695             :             case Compound::IATTR_STEREO_ANAGLYPH_RIGHT_MASK:
    1696           8 :                 os << ColorMask( value ) << std::endl;
    1697           8 :                 break;
    1698             : 
    1699             :             default:
    1700           0 :                 LBASSERTINFO( 0, "unimplemented" );
    1701             :         }
    1702             :     }
    1703             : 
    1704        2054 :     if( attrPrinted )
    1705          10 :         os << lunchbox::exdent << "}" << std::endl << std::endl;
    1706             : 
    1707        2054 :     switch( compound.getFrustumType( ))
    1708             :     {
    1709             :         case Frustum::TYPE_WALL:
    1710          28 :             os << compound.getWall() << std::endl;
    1711          28 :             break;
    1712             :         case Frustum::TYPE_PROJECTION:
    1713           0 :             os << compound.getProjection() << std::endl;
    1714           0 :             break;
    1715             :         default:
    1716        2026 :             break;
    1717             :     }
    1718             : 
    1719        2054 :     const Equalizers& equalizers = compound.getEqualizers();
    1720        2192 :     for( EqualizersCIter i = equalizers.begin(); i != equalizers.end(); ++i )
    1721         138 :         os << *i;
    1722             : 
    1723        2054 :     const TileQueues& outputQueues = compound.getOutputTileQueues();
    1724        2054 :     for( TileQueuesCIter i = outputQueues.begin(); i != outputQueues.end(); ++i)
    1725           0 :         os << "output" <<  *i;
    1726             : 
    1727        2054 :     const TileQueues& inputQueues = compound.getInputTileQueues();
    1728        2054 :     for( TileQueuesCIter i = inputQueues.begin(); i != inputQueues.end(); ++i )
    1729           0 :         os << "input" << *i;
    1730             : 
    1731        2054 :     if( compound.getSwapBarrier( ))
    1732         200 :         os << *compound.getSwapBarrier();
    1733             : 
    1734        2054 :     const Compounds& children = compound.getChildren();
    1735        2054 :     if( !children.empty( ))
    1736             :     {
    1737         602 :         os << std::endl;
    1738        2314 :         for( CompoundsCIter i = children.begin(); i != children.end(); ++i )
    1739        1712 :             os << **i;
    1740             :     }
    1741             : 
    1742        2054 :     const Frames& inputFrames = compound.getInputFrames();
    1743        3462 :     for( FramesCIter i = inputFrames.begin(); i != inputFrames.end(); ++i )
    1744        1408 :         os << "input" << **i << std::endl;
    1745             : 
    1746        2054 :     const Frames& outputFrames = compound.getOutputFrames();
    1747        3428 :     for( FramesCIter i = outputFrames.begin(); i != outputFrames.end(); ++i )
    1748        1374 :         os << "output"  << **i << std::endl;
    1749             : 
    1750        2054 :     return os << lunchbox::exdent << "}" << std::endl << lunchbox::enableFlush;
    1751             : }
    1752             : 
    1753             : }
    1754          84 : }

Generated by: LCOV version 1.11