LCOV - code coverage report
Current view: top level - eq/fabric - window.ipp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 203 270 75.2 %
Date: 2016-09-29 05:02:09 Functions: 41 112 36.6 %

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

Generated by: LCOV version 1.11