LCOV - code coverage report
Current view: top level - eq - frameData.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 121 230 52.6 %
Date: 2017-12-16 05:07:20 Functions: 22 30 73.3 %

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

Generated by: LCOV version 1.11