LCOV - code coverage report
Current view: top level - eq/fabric - window.ipp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 215 268 80.2 %
Date: 2014-06-18 Functions: 47 75 62.7 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2010-2013, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                    2010, Cedric Stalder <cedric.stalder@gmail.com>
       4             :  *               2010-2014, Daniel Nachbaur <danielnachbaur@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 "window.h"
      21             : 
      22             : #include "channel.h"
      23             : #include "commands.h"
      24             : #include "elementVisitor.h"
      25             : #include "leafVisitor.h"
      26             : #include "log.h"
      27             : #include "task.h"
      28             : 
      29             : #include <co/dataIStream.h>
      30             : #include <co/dataOStream.h>
      31             : #include <co/objectICommand.h>
      32             : 
      33             : namespace eq
      34             : {
      35             : namespace fabric
      36             : {
      37             : 
      38             : namespace
      39             : {
      40             : #define MAKE_WINDOW_ATTR_STRING( attr ) ( std::string("EQ_WINDOW_") + #attr )
      41          42 : std::string _iAttributeStrings[] = {
      42             :     MAKE_WINDOW_ATTR_STRING( IATTR_HINT_STEREO ),
      43             :     MAKE_WINDOW_ATTR_STRING( IATTR_HINT_DOUBLEBUFFER ),
      44             :     MAKE_WINDOW_ATTR_STRING( IATTR_HINT_FULLSCREEN ),
      45             :     MAKE_WINDOW_ATTR_STRING( IATTR_HINT_DECORATION ),
      46             :     MAKE_WINDOW_ATTR_STRING( IATTR_HINT_SWAPSYNC ),
      47             :     MAKE_WINDOW_ATTR_STRING( IATTR_HINT_DRAWABLE ),
      48             :     MAKE_WINDOW_ATTR_STRING( IATTR_HINT_STATISTICS ),
      49             :     MAKE_WINDOW_ATTR_STRING( IATTR_HINT_SCREENSAVER ),
      50             :     MAKE_WINDOW_ATTR_STRING( IATTR_HINT_GRAB_POINTER ),
      51             :     MAKE_WINDOW_ATTR_STRING( IATTR_HINT_WIDTH ),
      52             :     MAKE_WINDOW_ATTR_STRING( IATTR_HINT_HEIGHT ),
      53             :     MAKE_WINDOW_ATTR_STRING( IATTR_PLANES_COLOR ),
      54             :     MAKE_WINDOW_ATTR_STRING( IATTR_PLANES_ALPHA ),
      55             :     MAKE_WINDOW_ATTR_STRING( IATTR_PLANES_DEPTH ),
      56             :     MAKE_WINDOW_ATTR_STRING( IATTR_PLANES_STENCIL ),
      57             :     MAKE_WINDOW_ATTR_STRING( IATTR_PLANES_ACCUM ),
      58             :     MAKE_WINDOW_ATTR_STRING( IATTR_PLANES_ACCUM_ALPHA ),
      59             :     MAKE_WINDOW_ATTR_STRING( IATTR_PLANES_SAMPLES )
      60          21 : };
      61             : }
      62             : 
      63             : template< class P, class W, class C, class Settings >
      64        1039 : Window< P, W, C, Settings >::Window( P* parent )
      65        1039 :         : _pipe( parent )
      66             : {
      67        1039 :     LBASSERT( parent );
      68        1039 :     parent->_addWindow( static_cast< W* >( this ) );
      69        1039 :     LBLOG( LOG_INIT ) << "New " << lunchbox::className( this ) << std::endl;
      70        1039 : }
      71             : 
      72             : template< class P, class W, class C, class Settings >
      73        2078 : Window< P, W, C, Settings >::BackupData::BackupData()
      74        2078 :         : fixedVP( true )
      75             : {
      76        2078 : }
      77             : 
      78             : template< class P, class W, class C, class Settings >
      79         768 : Window< P, W, C, Settings >::~Window( )
      80             : {
      81         768 :     LBLOG( LOG_INIT ) << "Delete " << lunchbox::className( this ) << std::endl;
      82        3006 :     while( !_channels.empty( ))
      83             :     {
      84        1470 :         C* channel = _channels.back();
      85             : 
      86        1470 :         LBASSERT( channel->getWindow() == this );
      87        1470 :         _removeChannel( channel );
      88        1470 :         delete channel;
      89             :     }
      90         768 :     _pipe->_removeWindow( static_cast< W* >( this ) );
      91        1536 : }
      92             : 
      93             : template< class P, class W, class C, class Settings >
      94         748 : void Window< P, W, C, Settings >::init()
      95             : {
      96         748 :     notifyViewportChanged();
      97         748 :     unsetDirty( DIRTY_VIEWPORT );
      98         748 : }
      99             : 
     100             : template< class P, class W, class C, class Settings >
     101          38 : void Window< P, W, C, Settings >::attach( const uint128_t& id,
     102             :                                 const uint32_t instanceID )
     103             : {
     104          38 :     Object::attach( id, instanceID );
     105          38 :     co::CommandQueue* queue = _pipe->getMainThreadQueue();
     106          38 :     LBASSERT( queue );
     107             : 
     108          38 :     registerCommand( CMD_WINDOW_NEW_CHANNEL,
     109             :                      CmdFunc( this, &Window< P, W, C, Settings >::_cmdNewChannel ),
     110             :                      queue );
     111          38 :     registerCommand( CMD_WINDOW_NEW_CHANNEL_REPLY,
     112             :                      CmdFunc( this, &Window< P, W, C, Settings >::_cmdNewChannelReply ),
     113             :                      0 );
     114          38 : }
     115             : 
     116             : template< class P, class W, class C, class Settings >
     117          23 : void Window< P, W, C, Settings >::backup()
     118             : {
     119          23 :     Object::backup();
     120          23 :     _backup = _data;
     121          23 : }
     122             : 
     123             : template< class P, class W, class C, class Settings >
     124           2 : void Window< P, W, C, Settings >::restore()
     125             : {
     126           2 :     _data = _backup;
     127           2 :     _data.drawableConfig = DrawableConfig();
     128             : 
     129           2 :     Object::restore();
     130           2 :     notifyViewportChanged();
     131           2 :     setDirty( DIRTY_VIEWPORT );
     132           2 : }
     133             : 
     134             : template< class P, class W, class C, class Settings >
     135          61 : uint128_t Window< P, W, C, Settings >::commit( const uint32_t incarnation )
     136             : {
     137          61 :     if( Serializable::isDirty( DIRTY_CHANNELS ))
     138          40 :         commitChildren< C >( _channels, CMD_WINDOW_NEW_CHANNEL, incarnation );
     139          61 :     return Object::commit( incarnation );
     140             : }
     141             : 
     142             : template< class P, class W, class C, class Settings >
     143          65 : void Window< P, W, C, Settings >::serialize( co::DataOStream& os,
     144             :                                    const uint64_t dirtyBits )
     145             : {
     146          65 :     Object::serialize( os, dirtyBits );
     147          65 :     if( dirtyBits & DIRTY_SETTINGS )
     148          49 :         _data.windowSettings.serialize( os );
     149          65 :     if( dirtyBits & DIRTY_CHANNELS && isMaster( ))
     150             :     {
     151          43 :         os << _mapNodeObjects();
     152          43 :         os.serializeChildren( _channels );
     153             :     }
     154          65 :     if( dirtyBits & DIRTY_VIEWPORT )
     155          41 :         os << _data.vp << _data.pvp << _data.fixedVP;
     156          65 :     if( dirtyBits & DIRTY_DRAWABLECONFIG )
     157          45 :         os << _data.drawableConfig;
     158          65 : }
     159             : 
     160             : template< class P, class W, class C, class Settings >
     161          46 : void Window< P, W, C, Settings >::deserialize( co::DataIStream& is,
     162             :                                      const uint64_t dirtyBits )
     163             : {
     164          46 :     Object::deserialize( is, dirtyBits );
     165          46 :     if( dirtyBits & DIRTY_SETTINGS )
     166          38 :         _data.windowSettings.deserialize( is );
     167          46 :     if( dirtyBits & DIRTY_CHANNELS )
     168             :     {
     169          29 :         if( isMaster( ))
     170           5 :             syncChildren( _channels );
     171             :         else
     172             :         {
     173          24 :             const bool useChildren = is.read< bool >();
     174          24 :             if( useChildren && _mapNodeObjects( ))
     175             :             {
     176           0 :                 Channels result;
     177           0 :                 is.deserializeChildren( this, _channels, result );
     178           0 :                 _channels.swap( result );
     179           0 :                 LBASSERT( _channels.size() == result.size( ));
     180             :             }
     181             :             else // consume unused ObjectVersions
     182          24 :                 is.read< co::ObjectVersions >();
     183             :         }
     184             :     }
     185          46 :     if( dirtyBits & DIRTY_VIEWPORT )
     186             :     {
     187             :         // Ignore data from master (server) if we have local changes
     188          35 :         if( !Serializable::isDirty( DIRTY_VIEWPORT ) || isMaster( ))
     189             :         {
     190          33 :             is >> _data.vp >> _data.pvp >> _data.fixedVP;
     191          33 :             notifyViewportChanged();
     192             :         }
     193             :         else // consume unused data
     194           2 :             is.getRemainingBuffer( sizeof( _data.vp ) + sizeof( _data.pvp ) +
     195           2 :                                    sizeof( _data.fixedVP ));
     196             :     }
     197             : 
     198          46 :     if( dirtyBits & DIRTY_DRAWABLECONFIG )
     199          35 :         is >> _data.drawableConfig;
     200          46 : }
     201             : 
     202             : template< class P, class W, class C, class Settings >
     203       29033 : void Window< P, W, C, Settings >::setDirty( const uint64_t dirtyBits )
     204             : {
     205       29033 :     Object::setDirty( dirtyBits );
     206       29033 :     _pipe->setDirty( P::DIRTY_WINDOWS );
     207       29033 : }
     208             : 
     209             : template< class P, class W, class C, class Settings >
     210          38 : void Window< P, W, C, Settings >::notifyDetach()
     211             : {
     212          38 :     Object::notifyDetach();
     213          38 :     co::LocalNodePtr node = getLocalNode();
     214             : 
     215          38 :     if( isMaster( ))
     216             :     {
     217         327 :         for( typename Channels::const_iterator i = _channels.begin();
     218         218 :              i != _channels.end(); ++i )
     219             :         {
     220          86 :             node->releaseObject( *i );
     221             :         }
     222             :     }
     223             :     else
     224             :     {
     225          30 :         while( !_channels.empty( ))
     226             :         {
     227           0 :             C* channel = _channels.back();
     228           0 :             LBASSERT( channel->isAttached( ));
     229             : 
     230           0 :             node->releaseObject( channel );
     231           0 :             _removeChannel( channel );
     232           0 :             _pipe->getServer()->getNodeFactory()->releaseChannel( channel );
     233             :         }
     234          38 :     }
     235          38 : }
     236             : 
     237             : template< class P, class W, class C, class Settings >
     238           0 : void Window< P, W, C, Settings >::create( C** channel )
     239             : {
     240           0 :     *channel = _pipe->getServer()->getNodeFactory()->createChannel(
     241             :         static_cast< W* >( this ));
     242           0 :     (*channel)->init(); // not in ctor, virtual method
     243           0 : }
     244             : 
     245             : template< class P, class W, class C, class Settings >
     246           0 : void Window< P, W, C, Settings >::release( C* channel )
     247             : {
     248           0 :     _pipe->getServer()->getNodeFactory()->releaseChannel( channel );
     249           0 : }
     250             : 
     251             : template< class P, class W, class C, class Settings >
     252        2297 : void Window< P, W, C, Settings >::_addChannel( C* channel )
     253             : {
     254        2297 :     LBASSERT( channel->getWindow() == this );
     255        2297 :     _channels.push_back( channel );
     256        2297 :     setDirty( DIRTY_CHANNELS );
     257        2297 : }
     258             : 
     259             : template< class P, class W, class C, class Settings >
     260        2955 : bool Window< P, W, C, Settings >::_removeChannel( C* channel )
     261             : {
     262        2955 :     typename Channels::iterator i = lunchbox::find( _channels, channel );
     263        2955 :     if( i == _channels.end( ))
     264        1470 :         return false;
     265             : 
     266        1485 :     _channels.erase( i );
     267        1485 :     setDirty( DIRTY_CHANNELS );
     268        1485 :     if( !isMaster( ))
     269        1485 :         postRemove( channel );
     270        1485 :     return true;
     271             : }
     272             : 
     273             : template< class P, class W, class C, class Settings >
     274          15 : C* Window< P, W, C, Settings >::_findChannel( const uint128_t& id )
     275             : {
     276          45 :     for( typename Channels::const_iterator i = _channels.begin();
     277          30 :          i != _channels.end(); ++i )
     278             :     {
     279          15 :         C* channel = *i;
     280          15 :         if( channel->getID() == id )
     281          15 :             return channel;
     282             :     }
     283           0 :     return 0;
     284             : }
     285             : 
     286             : template< class P, class W, class C, class Settings >
     287       13777 : void Window< P, W, C, Settings >::setIAttribute( const WindowSettings::IAttribute attr,
     288             :                                        const int32_t value )
     289             : {
     290       13777 :     if( _data.windowSettings.setIAttribute( attr, value ))
     291        8782 :         setDirty( DIRTY_SETTINGS );
     292       13777 : }
     293             : 
     294             : template< class P, class W, class C, class Settings > int32_t
     295        7587 : Window< P, W, C, Settings >::getIAttribute( const WindowSettings::IAttribute attr ) const
     296             : {
     297        7587 :     return _data.windowSettings.getIAttribute( attr );
     298             : }
     299             : 
     300             : template< class P, class W, class C, class Settings > const std::string&
     301        6481 : Window< P, W, C, Settings >::getIAttributeString( const WindowSettings::IAttribute attr )
     302             : {
     303        6481 :     return _iAttributeStrings[attr];
     304             : }
     305             : 
     306             : template< class P, class W, class C, class Settings >
     307           0 : Settings& Window< P, W, C, Settings >::_getSettings()
     308             : {
     309           0 :     return _data.windowSettings;
     310             : }
     311             : 
     312             : template< class P, class W, class C, class Settings >
     313          17 : const Settings& Window< P, W, C, Settings >::getSettings() const
     314             : {
     315          17 :     return _data.windowSettings;
     316             : }
     317             : 
     318             : template< class P, class W, class C, class Settings >
     319           0 : WindowPath Window< P, W, C, Settings >::getPath() const
     320             : {
     321           0 :     const P* pipe = getPipe();
     322           0 :     LBASSERT( pipe );
     323           0 :     WindowPath path( pipe->getPath( ));
     324             : 
     325           0 :     const typename std::vector< W* >& windows = pipe->getWindows();
     326             :     typename std::vector< W* >::const_iterator i = std::find( windows.begin(),
     327             :                                                               windows.end(),
     328           0 :                                                               this );
     329           0 :     LBASSERT( i != windows.end( ));
     330           0 :     path.windowIndex = std::distance( windows.begin(), i );
     331           0 :     return path;
     332             : }
     333             : 
     334             : namespace
     335             : {
     336             : template< class W, class V >
     337       19453 : VisitorResult _accept( W* window, V& visitor )
     338             : {
     339       19453 :     VisitorResult result = visitor.visitPre( window );
     340       19453 :     if( result != TRAVERSE_CONTINUE )
     341           0 :         return result;
     342             : 
     343       19453 :     const typename W::Channels& channels = window->getChannels();
     344      236454 :     for( typename W::Channels::const_iterator i = channels.begin();
     345      157636 :          i != channels.end(); ++i )
     346             :     {
     347       62283 :         switch( (*i)->accept( visitor ))
     348             :         {
     349             :             case TRAVERSE_TERMINATE:
     350        2918 :                 return TRAVERSE_TERMINATE;
     351             : 
     352             :             case TRAVERSE_PRUNE:
     353         360 :                 result = TRAVERSE_PRUNE;
     354         360 :                 break;
     355             : 
     356             :             case TRAVERSE_CONTINUE:
     357             :             default:
     358       59005 :                 break;
     359             :         }
     360             :     }
     361             : 
     362       16535 :     switch( visitor.visitPost( window ))
     363             :     {
     364             :         case TRAVERSE_TERMINATE:
     365           0 :             return TRAVERSE_TERMINATE;
     366             : 
     367             :         case TRAVERSE_PRUNE:
     368           0 :             return TRAVERSE_PRUNE;
     369             : 
     370             :         case TRAVERSE_CONTINUE:
     371             :         default:
     372       16535 :             break;
     373             :     }
     374             : 
     375       16535 :     return result;
     376             : }
     377             : }
     378             : 
     379             : template< class P, class W, class C, class Settings >
     380       19453 : VisitorResult Window< P, W, C, Settings >::accept( Visitor& visitor )
     381             : {
     382       19453 :     return _accept( static_cast< W* >( this ), visitor );
     383             : }
     384             : 
     385             : template< class P, class W, class C, class Settings >
     386           0 : VisitorResult Window< P, W, C, Settings >::accept( Visitor& visitor  ) const
     387             : {
     388           0 :     return _accept( static_cast< const W* >( this ), visitor );
     389             : }
     390             : 
     391             : template< class P, class W, class C, class Settings >
     392        2604 : const PixelViewport& Window< P, W, C, Settings >::getPixelViewport() const
     393             : {
     394        2604 :     return _data.windowSettings.getPixelViewport();
     395             : }
     396             : 
     397             : template< class P, class W, class C, class Settings >
     398         283 : void Window< P, W, C, Settings >::setName( const std::string& name )
     399             : {
     400         283 :     Object::setName( name );
     401         283 :     if( _data.windowSettings.getName() == name )
     402         283 :         return;
     403         283 :     _data.windowSettings.setName( name );
     404         283 :     setDirty( DIRTY_SETTINGS );
     405             : }
     406             : 
     407             : template< class P, class W, class C, class Settings >
     408         327 : void Window< P, W, C, Settings >::setPixelViewport( const PixelViewport& pvp )
     409             : {
     410         327 :     LBASSERTINFO( pvp.isValid(), pvp );
     411         327 :     if( !pvp.isValid( ))
     412           0 :         return;
     413             : 
     414         327 :     _data.fixedVP = false;
     415             : 
     416         327 :     if( pvp == _data.pvp && _data.vp.hasArea( ))
     417          17 :         return;
     418             : 
     419         310 :     _data.pvp = pvp;
     420         310 :     _data.vp.invalidate();
     421         310 :     _data.windowSettings.setPixelViewport( pvp );
     422             : 
     423         310 :     notifyViewportChanged();
     424         310 :     setDirty( DIRTY_VIEWPORT );
     425         310 :     setDirty( DIRTY_SETTINGS );
     426             : }
     427             : 
     428             : template< class P, class W, class C, class Settings >
     429         480 : void Window< P, W, C, Settings >::setViewport( const Viewport& vp )
     430             : {
     431         480 :     if( !vp.hasArea())
     432         153 :         return;
     433             : 
     434         327 :     _data.fixedVP = true;
     435             : 
     436         327 :     if( vp == _data.vp && _data.pvp.hasArea( ))
     437           0 :         return;
     438         327 :     _data.vp = vp;
     439         327 :     _data.pvp.invalidate();
     440         327 :     _data.windowSettings.setPixelViewport( PixelViewport( ));
     441             : 
     442         327 :     setDirty( DIRTY_VIEWPORT );
     443         327 :     setDirty( DIRTY_SETTINGS );
     444         327 :     notifyViewportChanged();
     445             : }
     446             : 
     447             : template< class P, class W, class C, class Settings >
     448        1425 : void Window< P, W, C, Settings >::notifyViewportChanged()
     449             : {
     450        1425 :     const PixelViewport pipePVP = _pipe->getPixelViewport();
     451             : 
     452        1425 :     if( _data.fixedVP ) // update pixel viewport
     453             :     {
     454        1093 :         const PixelViewport oldPVP = _data.pvp;
     455        1093 :         _data.pvp = pipePVP;
     456        1093 :         _data.pvp.apply( _data.vp );
     457        1093 :         if( oldPVP != _data.pvp )
     458             :         {
     459         243 :             _data.windowSettings.setPixelViewport( _data.pvp );
     460         243 :             setDirty( DIRTY_VIEWPORT );
     461         243 :             setDirty( DIRTY_SETTINGS );
     462             :         }
     463             :     }
     464             :     else           // update viewport
     465             :     {
     466         332 :         const Viewport oldVP = _data.vp;
     467         332 :         _data.vp = _data.pvp / pipePVP;
     468         332 :         if( oldVP != _data.vp )
     469         318 :             setDirty( DIRTY_VIEWPORT );
     470             :     }
     471             : 
     472        4479 :     for( typename Channels::const_iterator i = _channels.begin();
     473        2986 :          i != _channels.end(); ++i )
     474             :     {
     475          68 :         (*i)->notifyViewportChanged();
     476             :     }
     477        1425 :     LBVERB << getName() << " viewport update: " << _data.vp << ":" << _data.pvp
     478           0 :            << std::endl;
     479        1425 : }
     480             : 
     481             : template< class P, class W, class C, class Settings >
     482          15 : void Window< P, W, C, Settings >::_setDrawableConfig(const DrawableConfig& drawableConfig)
     483             : {
     484          15 :     _data.drawableConfig = drawableConfig;
     485          15 :     setDirty( DIRTY_DRAWABLECONFIG );
     486          15 : }
     487             : 
     488             : //----------------------------------------------------------------------
     489             : // ICommand handlers
     490             : //----------------------------------------------------------------------
     491             : template< class P, class W, class C, class Settings >
     492           0 : bool Window< P, W, C, Settings >::_cmdNewChannel( co::ICommand& cmd )
     493             : {
     494           0 :     co::ObjectICommand command( cmd );
     495             : 
     496           0 :     C* channel = 0;
     497           0 :     create( &channel );
     498           0 :     LBASSERT( channel );
     499             : 
     500           0 :     getLocalNode()->registerObject( channel );
     501           0 :     LBASSERT( channel->isAttached() );
     502             : 
     503           0 :     send( command.getRemoteNode(), CMD_WINDOW_NEW_CHANNEL_REPLY )
     504           0 :             << command.read< uint32_t >() << channel->getID();
     505           0 :     LBASSERT( channel->isAttached( ));
     506             : 
     507           0 :     return true;
     508             : }
     509             : 
     510             : template< class P, class W, class C, class Settings >
     511           0 : bool Window< P, W, C, Settings >::_cmdNewChannelReply( co::ICommand& cmd )
     512             : {
     513           0 :     co::ObjectICommand command( cmd );
     514             : 
     515           0 :     const uint32_t requestID = command.read< uint32_t >();
     516           0 :     const uint128_t& result = command.read< uint128_t >();
     517             : 
     518           0 :     getLocalNode()->serveRequest( requestID, result );
     519             : 
     520           0 :     return true;
     521             : }
     522             : 
     523             : template< class P, class W, class C, class Settings >
     524         409 : std::ostream& operator << ( std::ostream& os, const Window< P, W, C, Settings >& window )
     525             : {
     526         818 :     os << lunchbox::disableFlush << lunchbox::disableHeader
     527         409 :        << "window" << std::endl;
     528         409 :     os << "{" << std::endl << lunchbox::indent;
     529             : 
     530         409 :     const std::string& name = window.getName();
     531         409 :     if( !name.empty( ))
     532         173 :         os << "name     \"" << name << "\"" << std::endl;
     533             : 
     534         409 :     const Viewport& vp = window.getViewport();
     535         409 :     const PixelViewport& pvp = window.getPixelViewport();
     536         409 :     if( vp.isValid( ) && window.hasFixedViewport( ))
     537             :     {
     538         256 :         if( pvp.hasArea( ))
     539          16 :             os << "viewport " << pvp << std::endl;
     540         256 :         os << "viewport " << vp << std::endl;
     541             :     }
     542         153 :     else if( pvp.hasArea( ))
     543             :     {
     544         153 :         if( vp != Viewport::FULL && vp.isValid( ))
     545         153 :             os << "viewport " << vp << std::endl;
     546         153 :         os << "viewport " << pvp << std::endl;
     547             :     }
     548             : 
     549         409 :     window.output( os );
     550             : 
     551         409 :     const typename W::Channels& channels = window.getChannels();
     552        3807 :     for( typename W::Channels::const_iterator i = channels.begin();
     553        2538 :          i != channels.end(); ++i )
     554             :     {
     555         860 :         os << **i;
     556             :     }
     557             : 
     558         409 :     os << lunchbox::exdent << "}" << std::endl << lunchbox::enableHeader
     559             :        << lunchbox::enableFlush;
     560         409 :     return os;
     561             : }
     562             : 
     563             : }
     564             : }

Generated by: LCOV version 1.10