LCOV - code coverage report
Current view: top level - eq/server - compound.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 744 985 75.5 %
Date: 2014-06-18 Functions: 62 76 81.6 %

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

Generated by: LCOV version 1.10