LCOV - code coverage report
Current view: top level - eq - frameData.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 53 230 23.0 %
Date: 2016-07-30 05:04:55 Functions: 12 30 40.0 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2006-2016, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                          Daniel Nachbaur <danielnachbaur@gmail.com>
       4             :  *                          Cedric Stalder <cedric.stalder@gmail.com>
       5             :  *                          Enrique <egparedes@ifi.uzh.ch>
       6             :  *
       7             :  * This library is free software; you can redistribute it and/or modify it under
       8             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       9             :  * by the Free Software Foundation.
      10             :  *
      11             :  * This library is distributed in the hope that it will be useful, but WITHOUT
      12             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      13             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      14             :  * details.
      15             :  *
      16             :  * You should have received a copy of the GNU Lesser General Public License
      17             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      18             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      19             :  */
      20             : 
      21             : #include "frameData.h"
      22             : 
      23             : #include "nodeStatistics.h"
      24             : #include "channelStatistics.h"
      25             : #include "exception.h"
      26             : #include "image.h"
      27             : #include "log.h"
      28             : #include "pixelData.h"
      29             : #include "roiFinder.h"
      30             : 
      31             : #include <eq/fabric/drawableConfig.h>
      32             : #include <eq/fabric/frameData.h>
      33             : #include <eq/util/objectManager.h>
      34             : #include <co/commandFunc.h>
      35             : #include <co/connectionDescription.h>
      36             : #include <co/dataIStream.h>
      37             : #include <co/dataOStream.h>
      38             : #include <lunchbox/monitor.h>
      39             : #include <lunchbox/scopedMutex.h>
      40             : #include <pression/plugins/compressor.h>
      41             : 
      42             : #include <boost/foreach.hpp>
      43             : 
      44             : #include <algorithm>
      45             : 
      46             : namespace eq
      47             : {
      48             : typedef lunchbox::Monitor< uint64_t > Monitor;
      49             : typedef std::vector< FrameData::Listener* > Listeners;
      50             : 
      51             : namespace detail
      52             : {
      53           1 : class FrameData
      54             : {
      55             : public:
      56           1 :     FrameData()
      57           1 :         : version( co::VERSION_NONE.low( ))
      58             :         , useAlpha( true )
      59             :         , colorQuality( 1.f )
      60             :         , depthQuality( 1.f )
      61             :         , colorCompressor( EQ_COMPRESSOR_AUTO )
      62           2 :         , depthCompressor( EQ_COMPRESSOR_AUTO )
      63           1 :     {}
      64             : 
      65             :     Images images;
      66             :     Images imageCache;
      67             :     lunchbox::Lock imageCacheLock;
      68             : 
      69             :     ROIFinder roiFinder;
      70             : 
      71             :     Images pendingImages;
      72             : 
      73             :     uint64_t version; //!< The current version
      74             : 
      75             :     /** Data ready monitor for output->input synchronization. */
      76             :     Monitor readyVersion;
      77             : 
      78             :     /** External monitors for readiness synchronization. */
      79             :     lunchbox::Lockable< Listeners, lunchbox::SpinLock > listeners;
      80             : 
      81             :     bool useAlpha;
      82             :     float colorQuality;
      83             :     float depthQuality;
      84             : 
      85             :     uint32_t colorCompressor;
      86             :     uint32_t depthCompressor;
      87             : };
      88             : }
      89             : 
      90             : typedef co::CommandFunc< FrameData > CmdFunc;
      91             : 
      92           1 : FrameData::FrameData()
      93           1 :     : _impl( new detail::FrameData )
      94           1 : {}
      95             : 
      96           3 : FrameData::~FrameData()
      97             : {
      98           1 :     clear();
      99             : 
     100           4 :     for( Image* image : _impl->imageCache )
     101             :     {
     102           9 :         LBLOG( LOG_BUG ) << "Unflushed image in FrameData destructor"
     103           9 :                           << std::endl;
     104           3 :         delete image;
     105             :     }
     106           1 :     _impl->imageCache.clear();
     107             : 
     108           1 :     delete _impl;
     109           2 : }
     110             : 
     111          22 : const Images& FrameData::getImages() const
     112             : {
     113          22 :     return _impl->images;
     114             : }
     115             : 
     116           0 : void FrameData::setAlphaUsage( const bool useAlpha )
     117             : {
     118           0 :     _impl->useAlpha = useAlpha;
     119           0 : }
     120             : 
     121           0 : bool FrameData::isReady() const
     122             : {
     123           0 :     return _impl->readyVersion.get() >= _impl->version;
     124             : }
     125             : 
     126           0 : void FrameData::setQuality( Frame::Buffer buffer, float quality )
     127             : {
     128           0 :     if( buffer != Frame::BUFFER_COLOR )
     129             :     {
     130           0 :         LBASSERT( buffer == Frame::BUFFER_DEPTH );
     131           0 :         _impl->depthQuality = quality;
     132           0 :         return;
     133             :     }
     134             : 
     135           0 :     _impl->colorQuality = quality;
     136             : }
     137             : 
     138           0 : void FrameData::useCompressor( const Frame::Buffer buffer, const uint32_t name )
     139             : {
     140           0 :     if( buffer != Frame::BUFFER_COLOR )
     141             :     {
     142           0 :         LBASSERT( buffer == Frame::BUFFER_DEPTH );
     143           0 :         _impl->depthCompressor = name;
     144           0 :         return;
     145             :     }
     146             : 
     147           0 :     _impl->colorCompressor = name;
     148             : }
     149             : 
     150           0 : void FrameData::getInstanceData( co::DataOStream& os )
     151             : {
     152           0 :     LBUNREACHABLE;
     153           0 :     serialize( os );
     154           0 : }
     155             : 
     156           0 : void FrameData::applyInstanceData( co::DataIStream& is )
     157             : {
     158           0 :     clear();
     159           0 :     deserialize( is );
     160           0 :     LBLOG( LOG_ASSEMBLY ) << "applied " << this << std::endl;
     161           0 : }
     162             : 
     163           2 : void FrameData::clear()
     164             : {
     165           2 :     _impl->imageCacheLock.set();
     166             :     _impl->imageCache.insert( _impl->imageCache.end(), _impl->images.begin(),
     167           2 :                               _impl->images.end( ));
     168           2 :     _impl->imageCacheLock.unset();
     169           2 :     _impl->images.clear();
     170           2 : }
     171             : 
     172           0 : void FrameData::flush()
     173             : {
     174           0 :     clear();
     175             : 
     176           0 :     for( ImagesCIter i = _impl->imageCache.begin();
     177           0 :          i != _impl->imageCache.end(); ++i )
     178             :     {
     179           0 :         Image* image = *i;
     180           0 :         image->flush();
     181           0 :         delete image;
     182             :     }
     183             : 
     184           0 :     _impl->imageCache.clear();
     185           0 : }
     186             : 
     187           0 : void FrameData::deleteGLObjects( util::ObjectManager& om )
     188             : {
     189           0 :     for( Image* image : _impl->images )
     190           0 :         image->deleteGLObjects( om );
     191           0 :     for( Image* image : _impl->imageCache )
     192           0 :         image->deleteGLObjects( om );
     193           0 : }
     194             : 
     195           0 : void FrameData::resetPlugins()
     196             : {
     197           0 :     BOOST_FOREACH( Image* image, _impl->images )
     198           0 :         image->resetPlugins();
     199           0 :     BOOST_FOREACH( Image* image, _impl->imageCache )
     200           0 :         image->resetPlugins();
     201           0 : }
     202             : 
     203           6 : Image* FrameData::newImage( const eq::Frame::Type type,
     204             :                             const DrawableConfig& config )
     205             : {
     206           6 :     Image* image = _allocImage( type, config, true /* set quality */ );
     207           6 :     _impl->images.push_back( image );
     208           6 :     return image;
     209             : }
     210             : 
     211           6 : Image* FrameData::_allocImage( const eq::Frame::Type type,
     212             :                                const DrawableConfig& config,
     213             :                                const bool setQuality_ )
     214             : {
     215             :     Image* image;
     216           6 :     _impl->imageCacheLock.set();
     217             : 
     218           6 :     if( _impl->imageCache.empty( ))
     219             :     {
     220           3 :         _impl->imageCacheLock.unset();
     221           3 :         image = new Image;
     222             :     }
     223             :     else
     224             :     {
     225           3 :         image = _impl->imageCache.back();
     226           3 :         _impl->imageCache.pop_back();
     227           3 :         _impl->imageCacheLock.unset();
     228             : 
     229           3 :         image->reset();
     230             :     }
     231             : 
     232           6 :     image->setAlphaUsage( _impl->useAlpha );
     233           6 :     image->setStorageType( type );
     234           6 :     if( setQuality_ )
     235             :     {
     236           6 :         image->setQuality( Frame::BUFFER_COLOR, _impl->colorQuality );
     237           6 :         image->setQuality( Frame::BUFFER_DEPTH, _impl->depthQuality );
     238             :     }
     239             : 
     240           6 :     image->useCompressor( Frame::BUFFER_COLOR, _impl->colorCompressor );
     241           6 :     image->useCompressor( Frame::BUFFER_DEPTH, _impl->depthCompressor );
     242             : 
     243             :     image->setInternalFormat( Frame::BUFFER_DEPTH,
     244           6 :                               EQ_COMPRESSOR_DATATYPE_DEPTH );
     245           6 :     switch( config.colorBits )
     246             :     {
     247             :         case 16:
     248             :             image->setInternalFormat( Frame::BUFFER_COLOR,
     249           0 :                                       EQ_COMPRESSOR_DATATYPE_RGBA16F );
     250           0 :             break;
     251             :         case 32:
     252             :             image->setInternalFormat( Frame::BUFFER_COLOR,
     253           0 :                                       EQ_COMPRESSOR_DATATYPE_RGBA32F );
     254           0 :             break;
     255             :         case 10:
     256             :             image->setInternalFormat( Frame::BUFFER_COLOR,
     257           0 :                                       EQ_COMPRESSOR_DATATYPE_RGB10_A2 );
     258           0 :             break;
     259             :         default:
     260             :             image->setInternalFormat( Frame::BUFFER_COLOR,
     261           6 :                                       EQ_COMPRESSOR_DATATYPE_RGBA );
     262             :     }
     263             : 
     264           6 :     return image;
     265             : }
     266             : 
     267           0 : Images FrameData::startReadback( const Frame& frame,
     268             :                                  util::ObjectManager& glObjects,
     269             :                                  const DrawableConfig& config,
     270             :                                  const PixelViewports& regions,
     271             :                                  const RenderContext& context )
     272             : {
     273           0 :     if( _buffers == Frame::BUFFER_NONE )
     274           0 :         return Images();
     275             : 
     276           0 :     const Zoom& frameZoom = frame.getZoom();
     277           0 :     if( !frameZoom.isValid( ))
     278             :     {
     279           0 :         LBWARN << "Invalid zoom factor, skipping frame" << std::endl;
     280           0 :         return Images();
     281             :     }
     282             : 
     283           0 :     const eq::PixelViewport& framePVP = getPixelViewport();
     284           0 :     const PixelViewport      absPVP   = framePVP + frame.getOffset();
     285           0 :     if( !absPVP.isValid( ))
     286           0 :         return Images();
     287             : 
     288           0 :     Images images;
     289             : 
     290             :     // readback the whole screen when using textures
     291           0 :     if( getType() == eq::Frame::TYPE_TEXTURE )
     292             :     {
     293           0 :         Image* image = newImage( getType(), config );
     294           0 :         if( image->startReadback( getBuffers(), absPVP, context,
     295           0 :             frameZoom, glObjects ))
     296             :         {
     297           0 :             images.push_back( image );
     298             :         }
     299           0 :         image->setOffset( 0, 0 );
     300           0 :         return images;
     301             :     }
     302             :     //else read only required regions
     303             : 
     304             : #if 0
     305             :     // TODO: issue #85: move automatic ROI detection to eq::Channel
     306             :     PixelViewports regions;
     307             :     if( buffers & Frame::BUFFER_DEPTH && frameZoom == Zoom::NONE )
     308             :         regions = _impl->roiFinder->findRegions( buffers, absPVP, frameZoom,
     309             :                                                  frame.getAssemblyStage(),
     310             :                                                  frame.getFrameID(), glObjects);
     311             :     else
     312             :         regions.push_back( absPVP );
     313             : #endif
     314             : 
     315           0 :     LBASSERT( getType() == eq::Frame::TYPE_MEMORY );
     316             : 
     317           0 :     for( uint32_t i = 0; i < regions.size(); ++i )
     318             :     {
     319           0 :         PixelViewport pvp = regions[ i ] + frame.getOffset();
     320           0 :         pvp.intersect( absPVP );
     321           0 :         if( !pvp.hasArea( ))
     322           0 :             continue;
     323             : 
     324           0 :         Image* image = newImage( getType(), config );
     325           0 :         if( image->startReadback( getBuffers(), pvp, context, frameZoom, glObjects ))
     326           0 :             images.push_back( image );
     327             : 
     328           0 :         pvp -= frame.getOffset();
     329           0 :         pvp.apply( frameZoom );
     330           0 :         image->setOffset( (pvp.x - framePVP.x) * context.pixel.w,
     331           0 :                           (pvp.y - framePVP.y) * context.pixel.h );
     332             :     }
     333           0 :     return images;
     334             : }
     335             : 
     336           0 : void FrameData::setVersion( const uint64_t version )
     337             : {
     338           0 :     LBASSERTINFO( _impl->version <= version, _impl->version << " > "
     339             :                                                             << version );
     340           0 :     _impl->version = version;
     341           0 :     LBLOG( LOG_ASSEMBLY ) << "New v" << version << std::endl;
     342           0 : }
     343             : 
     344          21 : void FrameData::waitReady( const uint32_t timeout ) const
     345             : {
     346          21 :     if( !_impl->readyVersion.timedWaitGE( _impl->version, timeout ))
     347           0 :         throw Exception( Exception::TIMEOUT_INPUTFRAME );
     348          21 : }
     349             : 
     350           0 : void FrameData::setReady()
     351             : {
     352           0 :     _setReady( _impl->version );
     353           0 : }
     354             : 
     355           0 : void FrameData::setReady( const co::ObjectVersion& frameData,
     356             :                           const fabric::FrameData& data )
     357             : {
     358           0 :     clear();
     359           0 :     LBASSERT(  frameData.version.high() == 0 );
     360           0 :     LBASSERT( _impl->readyVersion < frameData.version.low( ));
     361           0 :     LBASSERT( _impl->readyVersion == 0 ||
     362             :               _impl->readyVersion + 1 == frameData.version.low( ));
     363           0 :     LBASSERT( _impl->version == frameData.version.low( ));
     364             : 
     365           0 :     _impl->images.swap( _impl->pendingImages );
     366           0 :     fabric::FrameData::operator = ( data );
     367           0 :     _setReady( frameData.version.low());
     368             : 
     369           0 :     LBLOG( LOG_ASSEMBLY ) << this << " applied v"
     370           0 :                           << frameData.version.low() << std::endl;
     371           0 : }
     372             : 
     373           0 : void FrameData::_setReady( const uint64_t version )
     374             : {
     375           0 :     LBASSERTINFO( _impl->readyVersion <= version,
     376             :                   "v" << _impl->version << " ready " << _impl->readyVersion
     377             :                       << " new " << version );
     378             : 
     379           0 :     lunchbox::ScopedMutex< lunchbox::SpinLock > mutex( _impl->listeners );
     380           0 :     if( _impl->readyVersion >= version )
     381           0 :         return;
     382             : 
     383           0 :     _impl->readyVersion = version;
     384           0 :     LBLOG( LOG_ASSEMBLY ) << "set ready " << this << ", "
     385           0 :                           << _impl->listeners->size() << " monitoring"
     386           0 :                           << std::endl;
     387             : 
     388           0 :     BOOST_FOREACH( Listener* listener, _impl->listeners.data )
     389           0 :         ++(*listener);
     390             : }
     391             : 
     392           0 : void FrameData::addListener( Listener& listener )
     393             : {
     394           0 :     lunchbox::ScopedFastWrite mutex( _impl->listeners );
     395             : 
     396           0 :     _impl->listeners->push_back( &listener );
     397           0 :     if( _impl->readyVersion >= _impl->version )
     398           0 :         ++listener;
     399           0 : }
     400             : 
     401           0 : void FrameData::removeListener( Listener& listener )
     402             : {
     403           0 :     lunchbox::ScopedFastWrite mutex( _impl->listeners );
     404             : 
     405           0 :     Listeners::iterator i = lunchbox::find( _impl->listeners.data, &listener );
     406           0 :     LBASSERT( i != _impl->listeners->end( ));
     407           0 :     _impl->listeners->erase( i );
     408           0 : }
     409             : 
     410           0 : bool FrameData::addImage( const co::ObjectVersion& frameDataVersion,
     411             :                           const PixelViewport& pvp, const Zoom& zoom,
     412             :                           const RenderContext& context, const uint32_t buffers_,
     413             :                           const bool useAlpha, uint8_t* data )
     414             : {
     415           0 :     LBASSERT( _impl->readyVersion < frameDataVersion.version.low( ));
     416           0 :     if( _impl->readyVersion >= frameDataVersion.version.low( ))
     417           0 :         return false;
     418             : 
     419             :     Image* image = _allocImage( Frame::TYPE_MEMORY, DrawableConfig(),
     420           0 :                                 false /* set quality */ );
     421             : 
     422           0 :     image->setPixelViewport( pvp );
     423           0 :     image->setAlphaUsage( useAlpha );
     424             : 
     425           0 :     Frame::Buffer buffers[] = { Frame::BUFFER_COLOR, Frame::BUFFER_DEPTH };
     426           0 :     for( unsigned i = 0; i < 2; ++i )
     427             :     {
     428           0 :         const Frame::Buffer buffer = buffers[i];
     429             : 
     430           0 :         if( buffers_ & buffer )
     431             :         {
     432           0 :             PixelData pixelData;
     433           0 :             const ImageHeader* header = reinterpret_cast<ImageHeader*>( data );
     434           0 :             data += sizeof( ImageHeader );
     435             : 
     436           0 :             pixelData.internalFormat  = header->internalFormat;
     437           0 :             pixelData.externalFormat  = header->externalFormat;
     438           0 :             pixelData.pixelSize       = header->pixelSize;
     439           0 :             pixelData.pvp             = header->pvp;
     440           0 :             pixelData.compressorFlags = header->compressorFlags;
     441             : 
     442           0 :             const uint32_t compressor = header->compressorName;
     443           0 :             if( compressor > EQ_COMPRESSOR_NONE )
     444             :             {
     445           0 :                 pression::CompressorChunks chunks;
     446           0 :                 const uint32_t nChunks = header->nChunks;
     447           0 :                 chunks.reserve( nChunks );
     448             : 
     449           0 :                 for( uint32_t j = 0; j < nChunks; ++j )
     450             :                 {
     451           0 :                     const uint64_t size = *reinterpret_cast< uint64_t*>( data );
     452           0 :                     data += sizeof( uint64_t );
     453             : 
     454           0 :                     chunks.push_back( pression::CompressorChunk( data, size ));
     455           0 :                     data += size;
     456             :                 }
     457           0 :                 pixelData.compressedData =
     458           0 :                     pression::CompressorResult( compressor, chunks );
     459             :             }
     460             :             else
     461             :             {
     462           0 :                 const uint64_t size = *reinterpret_cast< uint64_t*>( data );
     463           0 :                 data += sizeof( uint64_t );
     464             : 
     465           0 :                 pixelData.pixels = data;
     466           0 :                 data += size;
     467           0 :                 LBASSERT( size == pixelData.pvp.getArea()*pixelData.pixelSize );
     468             :             }
     469             : 
     470           0 :             image->setZoom( zoom );
     471           0 :             image->setContext( context );
     472           0 :             image->setQuality( buffer, header->quality );
     473           0 :             image->setPixelData( buffer, pixelData );
     474             :         }
     475             :     }
     476             : 
     477           0 :     _impl->pendingImages.push_back( image );
     478           0 :     return true;
     479             : }
     480             : 
     481           0 : std::ostream& operator << ( std::ostream& os, const FrameData& data )
     482             : {
     483           0 :     return os << "frame data id " << data.getID() << "." << data.getInstanceID()
     484           0 :               << " v" << data.getVersion() << ' ' << data.getImages().size()
     485           0 :               << " images, ready " << ( data.isReady() ? 'y' :'n' ) << " "
     486           0 :               << data.getZoom();
     487             : }
     488             : 
     489          42 : }

Generated by: LCOV version 1.11