LCOV - code coverage report
Current view: top level - eq/server - channelUpdateVisitor.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 216 259 83.4 %
Date: 2014-06-18 Functions: 20 21 95.2 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2007-2013, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *               2011-2012, 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 "channelUpdateVisitor.h"
      21             : 
      22             : #include "colorMask.h"
      23             : #include "compound.h"
      24             : #include "frame.h"
      25             : #include "node.h"
      26             : #include "observer.h"
      27             : #include "pipe.h"
      28             : #include "segment.h"
      29             : #include "view.h"
      30             : #include "window.h"
      31             : #include "tileQueue.h"
      32             : 
      33             : #include <eq/client/log.h>
      34             : 
      35             : #include <eq/fabric/commands.h>
      36             : #include <eq/fabric/paths.h>
      37             : 
      38             : #include <set>
      39             : 
      40             : #ifndef GL_BACK_LEFT
      41             : #  define GL_FRONT_LEFT 0x0400
      42             : #  define GL_FRONT_RIGHT 0x0401
      43             : #  define GL_BACK_LEFT 0x0402
      44             : #  define GL_BACK_RIGHT 0x0403
      45             : #  define GL_FRONT 0x0404
      46             : #  define GL_BACK 0x0405
      47             : #endif
      48             : 
      49             : namespace eq
      50             : {
      51             : namespace server
      52             : {
      53             : 
      54             : using fabric::QUAD;
      55             : 
      56             : namespace
      57             : {
      58             : static bool _setDrawBuffers();
      59             : static uint32_t _drawBuffer[2][2][NUM_EYES];
      60           9 : static bool _drawBufferInit = _setDrawBuffers();
      61           9 : bool _setDrawBuffers()
      62             : {
      63           9 :     const int32_t cyclop = lunchbox::getIndexOfLastBit( EYE_CYCLOP );
      64           9 :     const int32_t left = lunchbox::getIndexOfLastBit( EYE_LEFT );
      65           9 :     const int32_t right = lunchbox::getIndexOfLastBit( EYE_RIGHT );
      66             : 
      67             :     // [stereo][doublebuffered][eye]
      68           9 :     _drawBuffer[0][0][ cyclop ] = GL_FRONT;
      69           9 :     _drawBuffer[0][0][ left ] = GL_FRONT;
      70           9 :     _drawBuffer[0][0][ right ] = GL_FRONT;
      71             : 
      72           9 :     _drawBuffer[0][1][ cyclop ] = GL_BACK;
      73           9 :     _drawBuffer[0][1][ left ] = GL_BACK;
      74           9 :     _drawBuffer[0][1][ right ] = GL_BACK;
      75             : 
      76           9 :     _drawBuffer[1][0][ cyclop ] = GL_FRONT;
      77           9 :     _drawBuffer[1][0][ left ] = GL_FRONT_LEFT;
      78           9 :     _drawBuffer[1][0][ right ] = GL_FRONT_RIGHT;
      79             : 
      80           9 :     _drawBuffer[1][1][ cyclop ] = GL_BACK;
      81           9 :     _drawBuffer[1][1][ left ] = GL_BACK_LEFT;
      82           9 :     _drawBuffer[1][1][ right ] = GL_BACK_RIGHT;
      83             : 
      84           9 :     return true;
      85             : }
      86             : }
      87             : 
      88          31 : ChannelUpdateVisitor::ChannelUpdateVisitor( Channel* channel,
      89             :                                             const uint128_t frameID,
      90             :                                             const uint32_t frameNumber )
      91             :         : _channel( channel )
      92             :         , _eye( EYE_CYCLOP )
      93             :         , _frameID( frameID )
      94             :         , _frameNumber( frameNumber )
      95          31 :         , _updated( false )
      96          31 : {}
      97             : 
      98         227 : bool ChannelUpdateVisitor::_skipCompound( const Compound* compound )
      99             : {
     100         258 :     return ( compound->getChannel() != _channel ||
     101         258 :              !compound->isInheritActive( _eye ) ||
     102         258 :              compound->getInheritTasks() == fabric::TASK_NONE );
     103             : }
     104             : 
     105         173 : VisitorResult ChannelUpdateVisitor::visitPre( const Compound* compound )
     106             : {
     107         173 :     if( !compound->isInheritActive( _eye ))
     108          72 :         return TRAVERSE_PRUNE;
     109             : 
     110         101 :     _updateDrawFinish( compound );
     111             : 
     112         101 :     if( _skipCompound( compound ))
     113          97 :         return TRAVERSE_CONTINUE;
     114             : 
     115           4 :     RenderContext context;
     116           4 :     _setupRenderContext( compound, context );
     117             : 
     118           4 :     _updateFrameRate( compound );
     119           4 :     _updateViewStart( compound, context );
     120             : 
     121           4 :     if( compound->testInheritTask( fabric::TASK_CLEAR ))
     122           4 :         _sendClear( context );
     123           4 :     return TRAVERSE_CONTINUE;
     124             : }
     125             : 
     126          25 : VisitorResult ChannelUpdateVisitor::visitLeaf( const Compound* compound )
     127             : {
     128          25 :     if( !compound->isInheritActive( _eye ))
     129          18 :         return TRAVERSE_CONTINUE;
     130             : 
     131           7 :     if( _skipCompound( compound ))
     132             :     {
     133           2 :         _updateDrawFinish( compound );
     134           2 :         return TRAVERSE_CONTINUE;
     135             :     }
     136             : 
     137             :     // OPT: Send render context once before task commands?
     138           5 :     RenderContext context;
     139           5 :     _setupRenderContext( compound, context );
     140           5 :     _updateFrameRate( compound );
     141           5 :     _updateViewStart( compound, context );
     142           5 :     _updateDraw( compound, context );
     143           5 :     _updateDrawFinish( compound );
     144           5 :     _updatePostDraw( compound, context );
     145           5 :     return TRAVERSE_CONTINUE;
     146             : }
     147             : 
     148         101 : VisitorResult ChannelUpdateVisitor::visitPost( const Compound* compound )
     149             : {
     150         101 :     if( _skipCompound( compound ))
     151          97 :         return TRAVERSE_CONTINUE;
     152             : 
     153           4 :     RenderContext context;
     154           4 :     _setupRenderContext( compound, context );
     155           4 :     _updatePostDraw( compound, context );
     156             : 
     157           4 :     return TRAVERSE_CONTINUE;
     158             : }
     159             : 
     160          13 : void ChannelUpdateVisitor::_setupRenderContext( const Compound* compound,
     161             :                                                 RenderContext& context )
     162             : {
     163          13 :     const Channel* destChannel = compound->getInheritChannel();
     164          13 :     LBASSERT( destChannel );
     165             : 
     166          13 :     context.frameID       = _frameID;
     167          13 :     context.pvp           = compound->getInheritPixelViewport();
     168          13 :     context.overdraw      = compound->getInheritOverdraw();
     169          13 :     context.vp            = compound->getInheritViewport();
     170          13 :     context.range         = compound->getInheritRange();
     171          13 :     context.pixel         = compound->getInheritPixel();
     172          13 :     context.subpixel      = compound->getInheritSubPixel();
     173          13 :     context.zoom          = compound->getInheritZoom();
     174          13 :     context.period        = compound->getInheritPeriod();
     175          13 :     context.phase         = compound->getInheritPhase();
     176          13 :     context.offset.x()    = context.pvp.x;
     177          13 :     context.offset.y()    = context.pvp.y;
     178          13 :     context.eye           = _eye;
     179          13 :     context.buffer        = _getDrawBuffer( compound );
     180          13 :     context.bufferMask    = _getDrawBufferMask( compound );
     181          13 :     context.view          = destChannel->getViewVersion();
     182          13 :     context.taskID        = compound->getTaskID();
     183             : 
     184          13 :     const View* view = destChannel->getView();
     185          13 :     LBASSERT( context.view == view );
     186             : 
     187          13 :     if( view )
     188             :     {
     189             :         // compute inherit vp (part of view covered by segment/view channel)
     190          13 :         const Segment* segment = destChannel->getSegment();
     191          13 :         LBASSERT( segment );
     192             : 
     193          13 :         const PixelViewport& pvp = destChannel->getPixelViewport();
     194          13 :         if( pvp.hasArea( ))
     195          13 :             context.vp.applyView( segment->getViewport(), view->getViewport(),
     196          26 :                                   pvp, destChannel->getOverdraw( ));
     197             :     }
     198             : 
     199          13 :     if( _channel != destChannel )
     200             :     {
     201           2 :         const PixelViewport& nativePVP = _channel->getPixelViewport();
     202           2 :         context.pvp.x = nativePVP.x;
     203           2 :         context.pvp.y = nativePVP.y;
     204             :     }
     205             :     // TODO: pvp size overcommit check?
     206             : 
     207          13 :     compound->computeFrustum( context, _eye );
     208          13 : }
     209             : 
     210           5 : void ChannelUpdateVisitor::_updateDraw( const Compound* compound,
     211             :                                         const RenderContext& context )
     212             : {
     213           5 :     if( compound->hasTiles( ))
     214             :     {
     215           0 :         _updateDrawTiles( compound, context );
     216           5 :         return;
     217             :     }
     218             : 
     219           5 :     if( compound->testInheritTask( fabric::TASK_CLEAR ))
     220           5 :         _sendClear( context );
     221             : 
     222           5 :     if( compound->testInheritTask( fabric::TASK_DRAW ))
     223             :     {
     224           5 :         const bool finish = _channel->hasListeners(); // finish for eq stats
     225           5 :         _channel->send( fabric::CMD_CHANNEL_FRAME_DRAW ) << context << finish;
     226           5 :         _updated = true;
     227           5 :         LBLOG( LOG_TASKS ) << "TASK draw " << _channel->getName() <<  " "
     228           5 :                            << finish << std::endl;
     229             :     }
     230             : }
     231             : 
     232           0 : void ChannelUpdateVisitor::_updateDrawTiles( const Compound* compound,
     233             :                                              const RenderContext& context )
     234             : {
     235           0 :     Frames frames;
     236           0 :     co::ObjectVersions frameIDs;
     237           0 :     const Frames& outputFrames = compound->getOutputFrames();
     238           0 :     for( FramesCIter i = outputFrames.begin(); i != outputFrames.end(); ++i)
     239             :     {
     240           0 :         Frame* frame = *i;
     241             : 
     242           0 :         if( !frame->hasData( _eye )) // TODO: filter: buffers, vp, eye
     243           0 :             continue;
     244             : 
     245           0 :         frames.push_back( frame );
     246           0 :         frameIDs.push_back( co::ObjectVersion( frame ));
     247             :     }
     248             : 
     249           0 :     const Channel* destChannel = compound->getInheritChannel();
     250           0 :     const TileQueues& inputQueues = compound->getInputTileQueues();
     251           0 :     for( TileQueuesCIter i = inputQueues.begin(); i != inputQueues.end(); ++i )
     252             :     {
     253           0 :         const TileQueue* inputQueue = *i;
     254           0 :         const TileQueue* outputQueue = inputQueue->getOutputQueue( context.eye);
     255           0 :         const uint128_t& id = outputQueue->getQueueMasterID( context.eye );
     256           0 :         LBASSERT( id != 0 );
     257             : 
     258           0 :         const bool isLocal = (_channel == destChannel);
     259           0 :         const uint32_t tasks = compound->getInheritTasks() &
     260             :                             ( eq::fabric::TASK_CLEAR | eq::fabric::TASK_DRAW |
     261           0 :                               eq::fabric::TASK_READBACK );
     262             : 
     263             :         _channel->send( fabric::CMD_CHANNEL_FRAME_TILES )
     264           0 :                 << context << isLocal << id << tasks << frameIDs;
     265           0 :         _updated = true;
     266           0 :         LBLOG( LOG_TASKS ) << "TASK tiles " << _channel->getName() <<  " "
     267           0 :                            << std::endl;
     268           0 :     }
     269           0 : }
     270             : 
     271         108 : void ChannelUpdateVisitor::_updateDrawFinish( const Compound* compound ) const
     272             : {
     273         108 :     const Compound* lastDrawCompound = _channel->getLastDrawCompound();
     274         108 :     if( lastDrawCompound && lastDrawCompound != compound )
     275          99 :         return;
     276             : 
     277             :     // Only pass if this is the last eye pass of this compound
     278           9 :     if( !compound->isLastInheritEye( _eye ))
     279           2 :         return;
     280             : 
     281           7 :     if( !lastDrawCompound )
     282           2 :         _channel->setLastDrawCompound( compound );
     283             : 
     284             :     // Channel::frameDrawFinish
     285           7 :     Node* node = _channel->getNode();
     286             : 
     287           7 :     node->send( fabric::CMD_CHANNEL_FRAME_DRAW_FINISH, _channel->getID( ))
     288          14 :             << _frameID << _frameNumber;
     289           7 :     LBLOG( LOG_TASKS ) << "TASK channel draw finish " << _channel->getName()
     290           0 :                        << " frame " << _frameNumber
     291           7 :                        << " id " << _frameID << std::endl;
     292             : 
     293             :     // Window::frameDrawFinish
     294           7 :     Window* window = _channel->getWindow();
     295           7 :     const Channel* lastDrawChannel = window->getLastDrawChannel();
     296             : 
     297           7 :     if( lastDrawChannel && lastDrawChannel != _channel )
     298           0 :         return;
     299             : 
     300           7 :     window->setLastDrawChannel( _channel ); // in case not set
     301             : 
     302           7 :     node->send( fabric::CMD_WINDOW_FRAME_DRAW_FINISH, window->getID( ))
     303          14 :             << _frameID << _frameNumber;
     304           7 :     LBLOG( LOG_TASKS ) << "TASK window draw finish "  << window->getName()
     305           0 :                            <<  " frame " << _frameNumber
     306           7 :                            << " id " << _frameID << std::endl;
     307             : 
     308             :     // Pipe::frameDrawFinish
     309           7 :     Pipe* pipe = _channel->getPipe();
     310           7 :     const Window* lastDrawWindow = pipe->getLastDrawWindow();
     311           7 :     if( lastDrawWindow && lastDrawWindow != window )
     312           0 :         return;
     313             : 
     314           7 :     pipe->setLastDrawWindow( window ); // in case not set
     315             : 
     316           7 :     node->send( fabric::CMD_PIPE_FRAME_DRAW_FINISH, pipe->getID( ))
     317          14 :             << _frameID << _frameNumber;
     318           7 :     LBLOG( LOG_TASKS ) << "TASK pipe draw finish " << pipe->getName()
     319           0 :                        << " frame " << _frameNumber
     320           7 :                        << " id " << _frameID << std::endl;
     321             : 
     322             :     // Node::frameDrawFinish
     323           7 :     const Pipe* lastDrawPipe = node->getLastDrawPipe();
     324           7 :     if( lastDrawPipe && lastDrawPipe != pipe )
     325           2 :         return;
     326             : 
     327           5 :     node->setLastDrawPipe( pipe ); // in case not set
     328             : 
     329           5 :     node->send( fabric::CMD_NODE_FRAME_DRAW_FINISH, node->getID( ))
     330          10 :             << _frameID << _frameNumber;
     331           5 :     LBLOG( LOG_TASKS ) << "TASK node draw finish " << node->getName() <<  " "
     332           5 :                        << std::endl;
     333             : }
     334             : 
     335           9 : void ChannelUpdateVisitor::_sendClear( const RenderContext& context )
     336             : {
     337           9 :     _channel->send( fabric::CMD_CHANNEL_FRAME_CLEAR ) << context;
     338           9 :     _updated = true;
     339           9 :     LBLOG( LOG_TASKS ) << "TASK clear " << _channel->getName() <<  " "
     340           9 :                        << std::endl;
     341           9 : }
     342             : 
     343           9 : void ChannelUpdateVisitor::_updateFrameRate( const Compound* compound ) const
     344             : {
     345           9 :     const float maxFPS = compound->getInheritMaxFPS();
     346           9 :     Window*     window = _channel->getWindow();
     347             : 
     348           9 :     if( maxFPS < window->getMaxFPS())
     349           0 :         window->setMaxFPS( maxFPS );
     350           9 : }
     351             : 
     352          13 : uint32_t ChannelUpdateVisitor::_getDrawBuffer( const Compound* compound ) const
     353             : {
     354          13 :     const DrawableConfig& dc = _channel->getWindow()->getDrawableConfig();
     355          13 :     const int32_t eye = lunchbox::getIndexOfLastBit( _eye );
     356             : 
     357          13 :     if( compound->getInheritIAttribute(Compound::IATTR_STEREO_MODE) == QUAD )
     358           0 :         return _drawBuffer[ dc.stereo ][ dc.doublebuffered ][ eye ];
     359          13 :     return _drawBuffer[ 0 ][ dc.doublebuffered ][ eye ];
     360             : }
     361             : 
     362          13 : eq::ColorMask ChannelUpdateVisitor::_getDrawBufferMask(const Compound* compound)
     363             :     const
     364             : {
     365          13 :     if( compound->getInheritIAttribute( Compound::IATTR_STEREO_MODE ) !=
     366             :         fabric::ANAGLYPH )
     367             :     {
     368           0 :         return ColorMask::ALL;
     369             :     }
     370             : 
     371          13 :     switch( _eye )
     372             :     {
     373             :         case EYE_LEFT:
     374             :             return ColorMask(
     375             :                 compound->getInheritIAttribute(
     376           0 :                     Compound::IATTR_STEREO_ANAGLYPH_LEFT_MASK ));
     377             :         case EYE_RIGHT:
     378             :             return ColorMask(
     379             :                 compound->getInheritIAttribute(
     380           0 :                     Compound::IATTR_STEREO_ANAGLYPH_RIGHT_MASK ));
     381             :         default:
     382          13 :             return ColorMask::ALL;
     383             :     }
     384             : }
     385             : 
     386           9 : void ChannelUpdateVisitor::_updatePostDraw( const Compound* compound,
     387             :                                             const RenderContext& context )
     388             : {
     389           9 :     _updateAssemble( compound, context );
     390           9 :     _updateReadback( compound, context );
     391           9 :     _updateViewFinish( compound, context );
     392           9 : }
     393             : 
     394           9 : void ChannelUpdateVisitor::_updateAssemble( const Compound* compound,
     395             :                                             const RenderContext& context )
     396             : {
     397           9 :     if( !compound->testInheritTask( fabric::TASK_ASSEMBLE ))
     398          14 :         return;
     399             : 
     400           2 :     const Frames& inputFrames = compound->getInputFrames();
     401           2 :     LBASSERT( !inputFrames.empty( ));
     402             : 
     403           2 :     co::ObjectVersions frames;
     404          12 :     for( Frames::const_iterator iter = inputFrames.begin();
     405           8 :          iter != inputFrames.end(); ++iter )
     406             :     {
     407           2 :         Frame* frame = *iter;
     408             : 
     409           2 :         if( !frame->hasData( _eye )) // TODO: filter: buffers, vp, eye
     410           0 :             continue;
     411             : 
     412           2 :         LBLOG( LOG_ASSEMBLY ) << *frame << std::endl;
     413           2 :         frames.push_back( co::ObjectVersion( frame ));
     414             :     }
     415             : 
     416           2 :     if( frames.empty( ))
     417           0 :         return;
     418             : 
     419             :     // assemble task
     420           2 :     LBLOG( LOG_ASSEMBLY | LOG_TASKS )
     421           0 :         << "TASK assemble " << _channel->getName()
     422           2 :         << " nFrames " << frames.size() << std::endl;
     423             :     _channel->send( fabric::CMD_CHANNEL_FRAME_ASSEMBLE )
     424           2 :             << context << frames;
     425           2 :     _updated = true;
     426             : }
     427             : 
     428           9 : void ChannelUpdateVisitor::_updateReadback( const Compound* compound,
     429             :                                             const RenderContext& context )
     430             : {
     431          18 :     if( !compound->testInheritTask( fabric::TASK_READBACK ) ||
     432           2 :         ( compound->hasTiles() && compound->isLeaf( )))
     433             :     {
     434          14 :         return;
     435             :     }
     436             : 
     437           2 :     const std::vector< Frame* >& outputFrames = compound->getOutputFrames();
     438           2 :     LBASSERT( !outputFrames.empty( ));
     439             : 
     440           2 :     co::ObjectVersions frames;
     441           4 :     for( FramesCIter i = outputFrames.begin(); i != outputFrames.end(); ++i )
     442             :     {
     443           2 :         Frame* frame = *i;
     444             : 
     445           2 :         if( !frame->hasData( _eye )) // TODO: filter: buffers, vp, eye
     446           0 :             continue;
     447             : 
     448           2 :         frames.push_back( co::ObjectVersion( frame ));
     449           2 :         LBLOG( LOG_ASSEMBLY ) << *frame << std::endl;
     450             :     }
     451             : 
     452           2 :     if( frames.empty() )
     453           0 :         return;
     454             : 
     455             :     // readback task
     456             :     _channel->send( fabric::CMD_CHANNEL_FRAME_READBACK )
     457           2 :             << context << frames;
     458           2 :     _updated = true;
     459           2 :     LBLOG( LOG_ASSEMBLY | LOG_TASKS )
     460           0 :         << "TASK readback " << _channel->getName()
     461           2 :         << " nFrames " << frames.size() << std::endl;
     462             : }
     463             : 
     464           9 : void ChannelUpdateVisitor::_updateViewStart( const Compound* compound,
     465             :                                              const RenderContext& context )
     466             : {
     467           9 :     LBASSERT( !_skipCompound( compound ));
     468           9 :     if( !compound->testInheritTask( fabric::TASK_VIEW ))
     469          13 :         return;
     470             : 
     471             :     // view start task
     472           5 :     LBLOG( LOG_TASKS ) << "TASK view start " << _channel->getName()
     473           5 :                        << std::endl;
     474           5 :     _channel->send( fabric::CMD_CHANNEL_FRAME_VIEW_START ) << context;
     475             : }
     476             : 
     477           9 : void ChannelUpdateVisitor::_updateViewFinish( const Compound* compound,
     478             :                                               const RenderContext& context )
     479             : {
     480           9 :     LBASSERT( !_skipCompound( compound ));
     481           9 :     if( !compound->testInheritTask( fabric::TASK_VIEW ))
     482          13 :         return;
     483             : 
     484             :     // view finish task
     485           5 :     LBLOG( LOG_TASKS ) << "TASK view finish " << _channel->getName() <<  " "
     486           5 :                        << std::endl;
     487           5 :     _channel->send( fabric::CMD_CHANNEL_FRAME_VIEW_FINISH ) << context;
     488             : }
     489             : 
     490             : }
     491          27 : }
     492             : 

Generated by: LCOV version 1.10