LCOV - code coverage report
Current view: top level - eq/client - frameData.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 144 279 51.6 %
Date: 2014-06-18 Functions: 31 49 63.3 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2006-2014, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                    2011, 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 "frameData.h"
      21             : 
      22             : #include "nodeStatistics.h"
      23             : #include "channelStatistics.h"
      24             : #include "exception.h"
      25             : #include "image.h"
      26             : #include "log.h"
      27             : #include "pixelData.h"
      28             : #include "roiFinder.h"
      29             : 
      30             : #include <eq/fabric/drawableConfig.h>
      31             : #include <eq/util/objectManager.h>
      32             : #include <co/commandFunc.h>
      33             : #include <co/connectionDescription.h>
      34             : #include <co/dataIStream.h>
      35             : #include <co/dataOStream.h>
      36             : #include <lunchbox/monitor.h>
      37             : #include <lunchbox/scopedMutex.h>
      38             : #include <lunchbox/plugins/compressor.h>
      39             : 
      40             : #include <boost/foreach.hpp>
      41             : 
      42             : #include <algorithm>
      43             : 
      44             : namespace eq
      45             : {
      46             : typedef lunchbox::Monitor< uint64_t > Monitor;
      47             : typedef std::vector< FrameData::Listener* > Listeners;
      48             : 
      49             : namespace detail
      50             : {
      51           3 : class FrameData
      52             : {
      53             : public:
      54           3 :     FrameData()
      55           3 :         : version( co::VERSION_NONE.low( ))
      56             :         , useAlpha( true )
      57             :         , colorQuality( 1.f )
      58             :         , depthQuality( 1.f )
      59             :         , colorCompressor( EQ_COMPRESSOR_AUTO )
      60           6 :         , depthCompressor( EQ_COMPRESSOR_AUTO )
      61           3 :     {}
      62             : 
      63             :     eq::FrameData::Data data;
      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           3 : FrameData::FrameData()
      93           3 :     : _impl( new detail::FrameData )
      94           3 : {}
      95             : 
      96           9 : FrameData::~FrameData()
      97             : {
      98           3 :     clear();
      99             : 
     100           8 :     BOOST_FOREACH( Image* image, _impl->imageCache )
     101             :     {
     102           5 :         LBWARN << "Unflushed image in FrameData destructor" << std::endl;
     103           5 :         delete image;
     104             :     }
     105           3 :     _impl->imageCache.clear();
     106             : 
     107           3 :     delete _impl;
     108           6 : }
     109             : 
     110             : 
     111           6 : Frame::Type FrameData::getType() const
     112             : {
     113           6 :     return _impl->data.frameType;
     114             : }
     115             : 
     116           0 : void FrameData::setType( const Frame::Type type )
     117             : {
     118           0 :     _impl->data.frameType = type;
     119           0 : }
     120             : 
     121           6 : uint32_t FrameData::getBuffers() const
     122             : {
     123           6 :     return _impl->data.buffers;
     124             : }
     125             : 
     126           2 : void FrameData::setBuffers( const uint32_t buffers )
     127             : {
     128           2 :     _impl->data.buffers = buffers;
     129           2 : }
     130             : 
     131           0 : const Range& FrameData::getRange() const
     132             : {
     133           0 :     return _impl->data.range;
     134             : }
     135             : 
     136           0 : void FrameData::setRange( const Range& range )
     137             : {
     138           0 :     _impl->data.range = range;
     139           0 : }
     140             : 
     141          46 : const Pixel& FrameData::getPixel() const
     142             : {
     143          46 :     return _impl->data.pixel;
     144             : }
     145             : 
     146          23 : const SubPixel& FrameData::getSubPixel() const
     147             : {
     148          23 :     return _impl->data.subpixel;
     149             : }
     150             : 
     151           0 : uint32_t FrameData::getPeriod() const
     152             : {
     153           0 :     return _impl->data.period;
     154             : }
     155             : 
     156           0 : uint32_t FrameData::getPhase() const
     157             : {
     158           0 :     return _impl->data.phase;
     159             : }
     160             : 
     161          55 : const Images& FrameData::getImages() const
     162             : {
     163          55 :     return _impl->images;
     164             : }
     165             : 
     166           0 : void FrameData::setPixelViewport( const PixelViewport& pvp )
     167             : {
     168           0 :     _impl->data.pvp = pvp;
     169           0 : }
     170             : 
     171           2 : const PixelViewport& FrameData::getPixelViewport() const
     172             : {
     173           2 :     return _impl->data.pvp;
     174             : }
     175             : 
     176           0 : void FrameData::setAlphaUsage( const bool useAlpha )
     177             : {
     178           0 :     _impl->useAlpha = useAlpha;
     179           0 : }
     180             : 
     181           0 : void FrameData::setZoom( const Zoom& zoom )
     182             : {
     183           0 :     _impl->data.zoom = zoom;
     184           0 : }
     185             : 
     186          23 : const Zoom& FrameData::getZoom() const
     187             : {
     188          23 :     return _impl->data.zoom;
     189             : }
     190             : 
     191           2 : bool FrameData::isReady() const
     192             : {
     193           2 :     return _impl->readyVersion.get() >= _impl->version;
     194             : }
     195             : 
     196           0 : void FrameData::disableBuffer( const Frame::Buffer buffer )
     197             : {
     198           0 :     _impl->data.buffers &= ~buffer;
     199           0 : }
     200             : 
     201           0 : const FrameData::Data& FrameData::getData() const
     202             : {
     203           0 :     return _impl->data;
     204             : }
     205             : 
     206           0 : void FrameData::setQuality( Frame::Buffer buffer, float quality )
     207             : {
     208           0 :     if( buffer != Frame::BUFFER_COLOR )
     209             :     {
     210           0 :         LBASSERT( buffer == Frame::BUFFER_DEPTH );
     211           0 :         _impl->depthQuality = quality;
     212           0 :         return;
     213             :     }
     214             : 
     215           0 :     _impl->colorQuality = quality;
     216             : }
     217             : 
     218           0 : void FrameData::useCompressor( const Frame::Buffer buffer, const uint32_t name )
     219             : {
     220           0 :     if( buffer != Frame::BUFFER_COLOR )
     221             :     {
     222           0 :         LBASSERT( buffer == Frame::BUFFER_DEPTH );
     223           0 :         _impl->depthCompressor = name;
     224           0 :         return;
     225             :     }
     226             : 
     227           0 :     _impl->colorCompressor = name;
     228             : }
     229             : 
     230           0 : void FrameData::getInstanceData( co::DataOStream& os )
     231             : {
     232           0 :     LBUNREACHABLE;
     233           0 :     _impl->data.serialize( os );
     234           0 : }
     235             : 
     236           2 : void FrameData::applyInstanceData( co::DataIStream& is )
     237             : {
     238           2 :     clear();
     239           2 :     _impl->data.deserialize( is );
     240           2 :     LBLOG( LOG_ASSEMBLY ) << "applied " << this << std::endl;
     241           2 : }
     242             : 
     243          18 : void FrameData::Data::serialize( co::DataOStream& os ) const
     244             : {
     245          18 :     os << pvp << frameType << buffers << period << phase << range
     246          36 :        << pixel << subpixel << zoom;
     247          18 : }
     248             : 
     249           2 : void FrameData::Data::deserialize( co::DataIStream& is )
     250             : {
     251           2 :     is >> pvp >> frameType >> buffers >> period >> phase >> range
     252           4 :        >> pixel >> subpixel >> zoom;
     253           2 : }
     254             : 
     255           6 : void FrameData::clear()
     256             : {
     257           6 :     _impl->imageCacheLock.set();
     258             :     _impl->imageCache.insert( _impl->imageCache.end(), _impl->images.begin(),
     259           6 :                               _impl->images.end( ));
     260           6 :     _impl->imageCacheLock.unset();
     261           6 :     _impl->images.clear();
     262           6 : }
     263             : 
     264           0 : void FrameData::flush()
     265             : {
     266           0 :     clear();
     267             : 
     268           0 :     for( ImagesCIter i = _impl->imageCache.begin();
     269           0 :          i != _impl->imageCache.end(); ++i )
     270             :     {
     271           0 :         Image* image = *i;
     272           0 :         image->flush();
     273           0 :         delete image;
     274             :     }
     275             : 
     276           0 :     _impl->imageCache.clear();
     277           0 : }
     278             : 
     279           4 : void FrameData::deleteGLObjects( util::ObjectManager& om )
     280             : {
     281           8 :     BOOST_FOREACH( Image* image, _impl->images )
     282           4 :         image->deleteGLObjects( om );
     283           4 :     BOOST_FOREACH( Image* image, _impl->imageCache )
     284           0 :         image->deleteGLObjects( om );
     285           4 : }
     286             : 
     287           2 : void FrameData::resetPlugins()
     288             : {
     289           4 :     BOOST_FOREACH( Image* image, _impl->images )
     290           2 :         image->resetPlugins();
     291           2 :     BOOST_FOREACH( Image* image, _impl->imageCache )
     292           0 :         image->resetPlugins();
     293           2 : }
     294             : 
     295           8 : Image* FrameData::newImage( const eq::Frame::Type type,
     296             :                             const DrawableConfig& config )
     297             : {
     298           8 :     Image* image = _allocImage( type, config, true /* set quality */ );
     299           8 :     _impl->images.push_back( image );
     300           8 :     return image;
     301             : }
     302             : 
     303           8 : Image* FrameData::_allocImage( const eq::Frame::Type type,
     304             :                                const DrawableConfig& config,
     305             :                                const bool setQuality_ )
     306             : {
     307             :     Image* image;
     308           8 :     _impl->imageCacheLock.set();
     309             : 
     310           8 :     if( _impl->imageCache.empty( ))
     311             :     {
     312           5 :         _impl->imageCacheLock.unset();
     313           5 :         image = new Image;
     314             :     }
     315             :     else
     316             :     {
     317           3 :         image = _impl->imageCache.back();
     318           3 :         _impl->imageCache.pop_back();
     319           3 :         _impl->imageCacheLock.unset();
     320             : 
     321           3 :         image->reset();
     322             :     }
     323             : 
     324           8 :     image->setAlphaUsage( _impl->useAlpha );
     325           8 :     image->setStorageType( type );
     326           8 :     if( setQuality_ )
     327             :     {
     328           8 :         image->setQuality( Frame::BUFFER_COLOR, _impl->colorQuality );
     329           8 :         image->setQuality( Frame::BUFFER_DEPTH, _impl->depthQuality );
     330             :     }
     331             : 
     332           8 :     image->useCompressor( Frame::BUFFER_COLOR, _impl->colorCompressor );
     333           8 :     image->useCompressor( Frame::BUFFER_DEPTH, _impl->depthCompressor );
     334             : 
     335             :     image->setInternalFormat( Frame::BUFFER_DEPTH,
     336           8 :                               EQ_COMPRESSOR_DATATYPE_DEPTH );
     337           8 :     switch( config.colorBits )
     338             :     {
     339             :         case 16:
     340             :             image->setInternalFormat( Frame::BUFFER_COLOR,
     341           0 :                                       EQ_COMPRESSOR_DATATYPE_RGBA16F );
     342           0 :             break;
     343             :         case 32:
     344             :             image->setInternalFormat( Frame::BUFFER_COLOR,
     345           0 :                                       EQ_COMPRESSOR_DATATYPE_RGBA32F );
     346           0 :             break;
     347             :         case 10:
     348             :             image->setInternalFormat( Frame::BUFFER_COLOR,
     349           0 :                                       EQ_COMPRESSOR_DATATYPE_RGB10_A2 );
     350           0 :             break;
     351             :         default:
     352             :             image->setInternalFormat( Frame::BUFFER_COLOR,
     353           8 :                                       EQ_COMPRESSOR_DATATYPE_RGBA );
     354             :     }
     355             : 
     356           8 :     return image;
     357             : }
     358             : 
     359             : #ifndef EQ_2_0_API
     360           0 : void FrameData::readback( const Frame& frame,
     361             :                           util::ObjectManager& glObjects,
     362             :                           const DrawableConfig& config )
     363             : {
     364             :     const Images& images = startReadback( frame, glObjects, config,
     365           0 :                                        PixelViewports( 1, getPixelViewport( )));
     366             : 
     367           0 :     for( ImagesCIter i = images.begin(); i != images.end(); ++i )
     368           0 :         (*i)->finishReadback( frame.getZoom(), glObjects.glewGetContext( ));
     369           0 : }
     370             : #endif
     371             : 
     372           2 : Images FrameData::startReadback( const Frame& frame,
     373             :                                  util::ObjectManager& glObjects,
     374             :                                  const DrawableConfig& config,
     375             :                                  const PixelViewports& regions )
     376             : {
     377           2 :     if( _impl->data.buffers == Frame::BUFFER_NONE )
     378           0 :         return Images();
     379             : 
     380           2 :     const Zoom& zoom = frame.getZoom();
     381           2 :     if( !zoom.isValid( ))
     382             :     {
     383           0 :         LBWARN << "Invalid zoom factor, skipping frame" << std::endl;
     384           0 :         return Images();
     385             :     }
     386             : 
     387           2 :     const eq::PixelViewport& framePVP = getPixelViewport();
     388           2 :     const PixelViewport      absPVP   = framePVP + frame.getOffset();
     389           2 :     if( !absPVP.isValid( ))
     390           0 :         return Images();
     391             : 
     392           2 :     Images images;
     393             : 
     394             :     // readback the whole screen when using textures
     395           2 :     if( getType() == eq::Frame::TYPE_TEXTURE )
     396             :     {
     397           0 :         Image* image = newImage( getType(), config );
     398           0 :         if( image->startReadback( getBuffers(), absPVP, zoom, glObjects ))
     399           0 :             images.push_back( image );
     400           0 :         image->setOffset( 0, 0 );
     401           0 :         return images;
     402             :     }
     403             :     //else read only required regions
     404             : 
     405             : #if 0
     406             :     // TODO: issue #85: move automatic ROI detection to eq::Channel
     407             :     PixelViewports regions;
     408             :     if( _impl->data.buffers & Frame::BUFFER_DEPTH && zoom == Zoom::NONE )
     409             :         regions = _impl->roiFinder->findRegions( _impl->data.buffers, absPVP,
     410             :                                                  zoom, frame.getAssemblyStage(),
     411             :                                                  frame.getFrameID(), glObjects);
     412             :     else
     413             :         regions.push_back( absPVP );
     414             : #endif
     415             : 
     416           2 :     LBASSERT( getType() == eq::Frame::TYPE_MEMORY );
     417           2 :     const eq::Pixel& pixel = getPixel();
     418             : 
     419           4 :     for( uint32_t i = 0; i < regions.size(); ++i )
     420             :     {
     421           2 :         PixelViewport pvp = regions[ i ] + frame.getOffset();
     422           2 :         pvp.intersect( absPVP );
     423           2 :         if( !pvp.hasArea( ))
     424           0 :             continue;
     425             : 
     426           2 :         Image* image = newImage( getType(), config );
     427           2 :         if( image->startReadback( getBuffers(), pvp, zoom, glObjects ))
     428           2 :             images.push_back( image );
     429             : 
     430           2 :         pvp -= frame.getOffset();
     431           2 :         pvp.apply( zoom );
     432           2 :         image->setOffset( (pvp.x - framePVP.x) * pixel.w,
     433           4 :                           (pvp.y - framePVP.y) * pixel.h );
     434             :     }
     435           2 :     return images;
     436             : }
     437             : 
     438          10 : void FrameData::setVersion( const uint64_t version )
     439             : {
     440          10 :     LBASSERTINFO( _impl->version <= version, _impl->version << " > "
     441             :                                                             << version );
     442          10 :     _impl->version = version;
     443          10 :     LBLOG( LOG_ASSEMBLY ) << "New v" << version << std::endl;
     444          10 : }
     445             : 
     446          21 : void FrameData::waitReady( const uint32_t timeout ) const
     447             : {
     448          21 :     if( !_impl->readyVersion.timedWaitGE( _impl->version, timeout ))
     449           0 :         throw Exception( Exception::TIMEOUT_INPUTFRAME );
     450          21 : }
     451             : 
     452           2 : void FrameData::setReady()
     453             : {
     454           2 :     _setReady( _impl->version );
     455           2 : }
     456             : 
     457           0 : void FrameData::setReady( const co::ObjectVersion& frameData,
     458             :                           const FrameData::Data& data )
     459             : {
     460           0 :     clear();
     461           0 :     LBASSERT(  frameData.version.high() == 0 );
     462           0 :     LBASSERT( _impl->readyVersion < frameData.version.low( ));
     463           0 :     LBASSERT( _impl->readyVersion == 0 ||
     464             :               _impl->readyVersion + 1 == frameData.version.low( ));
     465           0 :     LBASSERT( _impl->version == frameData.version.low( ));
     466             : 
     467           0 :     _impl->images.swap( _impl->pendingImages );
     468           0 :     _impl->data = data;
     469           0 :     _setReady( frameData.version.low());
     470             : 
     471           0 :     LBLOG( LOG_ASSEMBLY ) << this << " applied v"
     472           0 :                           << frameData.version.low() << std::endl;
     473           0 : }
     474             : 
     475           2 : void FrameData::_setReady( const uint64_t version )
     476             : {
     477           2 :     LBASSERTINFO( _impl->readyVersion <= version,
     478             :                   "v" << _impl->version << " ready " << _impl->readyVersion
     479             :                       << " new " << version );
     480             : 
     481           2 :     lunchbox::ScopedMutex< lunchbox::SpinLock > mutex( _impl->listeners );
     482           2 :     if( _impl->readyVersion >= version )
     483           2 :         return;
     484             : 
     485           2 :     _impl->readyVersion = version;
     486           2 :     LBLOG( LOG_ASSEMBLY ) << "set ready " << this << ", "
     487           0 :                           << _impl->listeners->size() << " monitoring"
     488           2 :                           << std::endl;
     489             : 
     490           4 :     BOOST_FOREACH( Listener* listener, _impl->listeners.data )
     491           4 :         ++(*listener);
     492             : }
     493             : 
     494           2 : void FrameData::addListener( Listener& listener )
     495             : {
     496           2 :     lunchbox::ScopedFastWrite mutex( _impl->listeners );
     497             : 
     498           2 :     _impl->listeners->push_back( &listener );
     499           2 :     if( _impl->readyVersion >= _impl->version )
     500           0 :         ++listener;
     501           2 : }
     502             : 
     503           2 : void FrameData::removeListener( Listener& listener )
     504             : {
     505           2 :     lunchbox::ScopedFastWrite mutex( _impl->listeners );
     506             : 
     507           2 :     Listeners::iterator i = lunchbox::find( _impl->listeners.data, &listener );
     508           2 :     LBASSERT( i != _impl->listeners->end( ));
     509           2 :     _impl->listeners->erase( i );
     510           2 : }
     511             : 
     512           0 : bool FrameData::addImage( const co::ObjectVersion& frameDataVersion,
     513             :                           const PixelViewport& pvp, const Zoom& zoom,
     514             :                           const uint32_t buffers_, const bool useAlpha,
     515             :                           uint8_t* data )
     516             : {
     517           0 :     LBASSERT( _impl->readyVersion < frameDataVersion.version.low( ));
     518           0 :     if( _impl->readyVersion >= frameDataVersion.version.low( ))
     519           0 :         return false;
     520             : 
     521             :     Image* image = _allocImage( Frame::TYPE_MEMORY, DrawableConfig(),
     522           0 :                                 false /* set quality */ );
     523             : 
     524           0 :     image->setPixelViewport( pvp );
     525           0 :     image->setAlphaUsage( useAlpha );
     526             : 
     527           0 :     Frame::Buffer buffers[] = { Frame::BUFFER_COLOR, Frame::BUFFER_DEPTH };
     528           0 :     for( unsigned i = 0; i < 2; ++i )
     529             :     {
     530           0 :         const Frame::Buffer buffer = buffers[i];
     531             : 
     532           0 :         if( buffers_ & buffer )
     533             :         {
     534           0 :             PixelData pixelData;
     535           0 :             const ImageHeader* header = reinterpret_cast<ImageHeader*>( data );
     536           0 :             data += sizeof( ImageHeader );
     537             : 
     538           0 :             pixelData.internalFormat  = header->internalFormat;
     539           0 :             pixelData.externalFormat  = header->externalFormat;
     540           0 :             pixelData.pixelSize       = header->pixelSize;
     541           0 :             pixelData.pvp             = header->pvp;
     542           0 :             pixelData.compressorFlags = header->compressorFlags;
     543             : 
     544           0 :             const uint32_t compressor = header->compressorName;
     545           0 :             if( compressor > EQ_COMPRESSOR_NONE )
     546             :             {
     547           0 :                 lunchbox::CompressorChunks chunks;
     548           0 :                 const uint32_t nChunks = header->nChunks;
     549           0 :                 chunks.reserve( nChunks );
     550             : 
     551           0 :                 for( uint32_t j = 0; j < nChunks; ++j )
     552             :                 {
     553           0 :                     const uint64_t size = *reinterpret_cast< uint64_t*>( data );
     554           0 :                     data += sizeof( uint64_t );
     555             : 
     556           0 :                     chunks.push_back( lunchbox::CompressorChunk( data, size ));
     557           0 :                     data += size;
     558             :                 }
     559           0 :                 pixelData.compressedData =
     560           0 :                     lunchbox::CompressorResult( compressor, chunks );
     561             :             }
     562             :             else
     563             :             {
     564           0 :                 const uint64_t size = *reinterpret_cast< uint64_t*>( data );
     565           0 :                 data += sizeof( uint64_t );
     566             : 
     567           0 :                 pixelData.pixels = data;
     568           0 :                 data += size;
     569           0 :                 LBASSERT( size == pixelData.pvp.getArea()*pixelData.pixelSize );
     570             :             }
     571             : 
     572           0 :             image->setZoom( zoom );
     573           0 :             image->setQuality( buffer, header->quality );
     574           0 :             image->setPixelData( buffer, pixelData );
     575             :         }
     576             :     }
     577             : 
     578           0 :     _impl->pendingImages.push_back( image );
     579           0 :     return true;
     580             : }
     581             : 
     582           0 : std::ostream& operator << ( std::ostream& os, const FrameData& data )
     583             : {
     584           0 :     return os << "frame data id " << data.getID() << "." << data.getInstanceID()
     585           0 :               << " v" << data.getVersion() << ' ' << data.getImages().size()
     586           0 :               << " images, ready " << ( data.isReady() ? 'y' :'n' ) << " "
     587           0 :               << data.getZoom();
     588             : }
     589             : 
     590          36 : }

Generated by: LCOV version 1.10