LCOV - code coverage report
Current view: top level - eq/server - view.cpp (source / functions) Hit Total Coverage
Test: Equalizer Lines: 121 248 48.8 %
Date: 2017-12-16 05:07:20 Functions: 20 39 51.3 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2009-2016, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *                          Daniel Nachbaur <danielnachbaur@gmail.com>
       4             :  *                          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 "view.h"
      21             : 
      22             : #include "canvas.h"
      23             : #include "channel.h"
      24             : #include "compound.h"
      25             : #include "config.h"
      26             : #include "configDestCompoundVisitor.h"
      27             : #include "equalizers/equalizer.h"
      28             : #include "equalizers/tileEqualizer.h"
      29             : #include "global.h"
      30             : #include "layout.h"
      31             : #include "log.h"
      32             : #include "observer.h"
      33             : #include "segment.h"
      34             : #include "tileQueue.h"
      35             : 
      36             : #include <eq/fabric/commands.h>
      37             : #include <eq/fabric/paths.h>
      38             : 
      39             : #include <co/dataIStream.h>
      40             : #include <co/dataOStream.h>
      41             : #include <co/iCommand.h>
      42             : 
      43             : namespace eq
      44             : {
      45             : namespace server
      46             : {
      47             : typedef fabric::View<Layout, View, Observer> Super;
      48             : typedef co::CommandFunc<View> ViewFunc;
      49             : 
      50         712 : View::View(Layout* parent)
      51             :     : Super(parent)
      52         712 :     , _private(0)
      53             : {
      54         712 :     const Global* global = Global::instance();
      55        5696 :     for (unsigned i = 0; i < SATTR_ALL; ++i)
      56             :     {
      57        4984 :         const SAttribute attr = static_cast<SAttribute>(i);
      58        4984 :         setSAttribute(attr, global->getViewSAttribute(attr));
      59             :     }
      60         712 : }
      61             : 
      62        2130 : View::~View()
      63             : {
      64             :     // Use copy - Channel::unsetOutput modifies vector
      65        1420 :     Channels channels = _channels;
      66         710 :     for (Channels::const_iterator i = channels.begin(); i != channels.end();
      67             :          ++i)
      68             :     {
      69           0 :         Channel* channel = *i;
      70           0 :         channel->unsetOutput();
      71             :     }
      72             : 
      73         710 :     LBASSERT(_channels.empty());
      74         710 :     _channels.clear();
      75        1420 : }
      76             : 
      77             : namespace
      78             : {
      79             : class FrustumUpdater : public ConfigVisitor
      80             : {
      81             : public:
      82         118 :     FrustumUpdater(const Channels& channels, const Vector3f& eye,
      83             :                    const float ratio)
      84         118 :         : _channels(channels)
      85             :         , _eye(eye)
      86         118 :         , _ratio(ratio)
      87             :     {
      88         118 :     }
      89         118 :     virtual ~FrustumUpdater() {}
      90        1652 :     virtual VisitorResult visit(Compound* compound)
      91             :     {
      92        1652 :         const Channel* channel = compound->getChannel();
      93        1652 :         if (!channel)
      94         826 :             return TRAVERSE_CONTINUE;
      95             : 
      96         826 :         if (!compound->isDestination())
      97           0 :             return TRAVERSE_PRUNE; // only change destination compounds
      98             : 
      99        1652 :         if (std::find(_channels.begin(), _channels.end(), channel) !=
     100        1652 :             _channels.end()) // our destination channel
     101             :         {
     102         118 :             compound->updateFrustum(_eye, _ratio);
     103             :         }
     104             : 
     105         826 :         return TRAVERSE_PRUNE;
     106             :     }
     107             : 
     108             : private:
     109             :     const Channels& _channels;
     110             :     const Vector3f& _eye;
     111             :     const float _ratio;
     112             : };
     113             : 
     114             : class CapabilitiesUpdater : public ConfigVisitor
     115             : {
     116             : public:
     117           0 :     explicit CapabilitiesUpdater(View* view)
     118           0 :         : _view(view)
     119           0 :         , _capabilities(_view->getMaximumCapabilities())
     120             :     {
     121           0 :     }
     122             : 
     123           0 :     virtual ~CapabilitiesUpdater() {}
     124           0 :     virtual VisitorResult visit(Compound* compound)
     125             :     {
     126           0 :         const Channel* dest = compound->getInheritChannel();
     127           0 :         if (!dest || dest->getView() != _view)
     128           0 :             return TRAVERSE_CONTINUE;
     129             : 
     130           0 :         const Channel* src = compound->getChannel();
     131           0 :         if (!src->supportsView(_view))
     132           0 :             return TRAVERSE_CONTINUE;
     133             : 
     134           0 :         const uint64_t supported = src->getCapabilities();
     135           0 :         _capabilities &= supported;
     136           0 :         return TRAVERSE_CONTINUE;
     137             :     }
     138             : 
     139           0 :     uint64_t getCapabilities() const { return _capabilities; }
     140             : private:
     141             :     View* const _view;
     142             :     uint64_t _capabilities;
     143             : };
     144             : 
     145           0 : class UseEqualizerVisitor : public ConfigVisitor
     146             : {
     147             : public:
     148           0 :     explicit UseEqualizerVisitor(const View* view)
     149           0 :         : _view(view)
     150             :     {
     151           0 :     }
     152             : 
     153             :     // No need to go down on nodes.
     154           0 :     VisitorResult visitPre(Node*) override { return TRAVERSE_PRUNE; }
     155           0 :     VisitorResult visit(Compound* compound) override
     156             :     {
     157           0 :         const Channel* dest = compound->getInheritChannel();
     158           0 :         if (!dest)
     159           0 :             return TRAVERSE_CONTINUE;
     160             : 
     161           0 :         if (dest->getView() != _view)
     162           0 :             return TRAVERSE_PRUNE;
     163             : 
     164           0 :         Equalizers equalizers = compound->getEqualizers();
     165           0 :         for (EqualizersCIter i = equalizers.begin(); i != equalizers.end(); ++i)
     166             :         {
     167           0 :             Equalizer* equalizer = *i;
     168           0 :             const uint32_t bitmask = _view->getEqualizers();
     169           0 :             equalizer->setActive((equalizer->getType() & bitmask) != 0);
     170             :         }
     171           0 :         return TRAVERSE_CONTINUE;
     172             :     }
     173             : 
     174             : private:
     175             :     const View* const _view;
     176             : };
     177             : 
     178           0 : class UpdateEqualizersVisitor : public ConfigVisitor
     179             : {
     180             : public:
     181           0 :     explicit UpdateEqualizersVisitor(const View* view)
     182           0 :         : _view(view)
     183             :     {
     184           0 :     }
     185             : 
     186             :     // No need to go down on nodes.
     187           0 :     VisitorResult visitPre(Node*) override { return TRAVERSE_PRUNE; }
     188           0 :     VisitorResult visit(Compound* compound) override
     189             :     {
     190           0 :         const Channel* dest = compound->getInheritChannel();
     191           0 :         if (!dest)
     192           0 :             return TRAVERSE_CONTINUE;
     193             : 
     194           0 :         if (dest->getView() != _view)
     195           0 :             return TRAVERSE_PRUNE;
     196             : 
     197           0 :         const TileQueues& queues = compound->getOutputTileQueues();
     198           0 :         for (TileQueuesCIter i = queues.begin(); i != queues.end(); ++i)
     199             :         {
     200           0 :             TileQueue* queue = *i;
     201           0 :             queue->setTileSize(_view->getEqualizer().getTileSize());
     202             :         }
     203             : 
     204           0 :         Equalizers equalizers = compound->getEqualizers();
     205           0 :         for (EqualizersIter i = equalizers.begin(); i != equalizers.end(); ++i)
     206           0 :             *(*i) = _view->getEqualizer();
     207             : 
     208           0 :         return TRAVERSE_CONTINUE;
     209             :     }
     210             : 
     211             : private:
     212             :     const View* const _view;
     213             : };
     214             : }
     215             : 
     216        6310 : void View::setDirty(const uint64_t bits)
     217             : {
     218        6310 :     if (bits == 0 || !isAttached())
     219        6248 :         return;
     220             : 
     221          62 :     Super::setDirty(bits);
     222          62 :     _updateChannels();
     223             : }
     224             : 
     225          76 : void View::_updateChannels() const
     226             : {
     227          76 :     LBASSERT(isMaster());
     228          76 :     co::ObjectVersion version(this);
     229          76 :     if (isDirty())
     230          62 :         ++version.version;
     231             : 
     232         152 :     for (Channels::const_iterator i = _channels.begin(); i != _channels.end();
     233             :          ++i)
     234             :     {
     235          76 :         Channel* channel = *i;
     236          76 :         channel->setViewVersion(version);
     237             :     }
     238          76 : }
     239             : 
     240          16 : void View::deserialize(co::DataIStream& is, const uint64_t dirtyBits)
     241             : {
     242          16 :     LBASSERT(isMaster());
     243          16 :     Super::deserialize(is, dirtyBits);
     244             : 
     245          16 :     if (dirtyBits & (DIRTY_FRUSTUM | DIRTY_OVERDRAW | DIRTY_MODELUNIT))
     246           0 :         updateFrusta();
     247          16 :     if (dirtyBits & DIRTY_EQUALIZER)
     248             :     {
     249           0 :         UpdateEqualizersVisitor visitor(this);
     250           0 :         getConfig()->accept(visitor);
     251             :     }
     252          16 :     if (dirtyBits & DIRTY_EQUALIZERS)
     253             :     {
     254           0 :         UseEqualizerVisitor visitor(this);
     255           0 :         getConfig()->accept(visitor);
     256           0 :         getConfig()->postNeedsFinish(); // @bug? Why?
     257             :     }
     258          16 : }
     259             : 
     260         176 : Config* View::getConfig()
     261             : {
     262         176 :     Layout* layout = getLayout();
     263         176 :     LBASSERT(layout);
     264         176 :     return layout ? layout->getConfig() : 0;
     265             : }
     266             : 
     267           0 : const Config* View::getConfig() const
     268             : {
     269           0 :     const Layout* layout = getLayout();
     270           0 :     LBASSERT(layout);
     271           0 :     return layout ? layout->getConfig() : 0;
     272             : }
     273             : 
     274          14 : ServerPtr View::getServer()
     275             : {
     276          14 :     Config* config = getConfig();
     277          14 :     LBASSERT(config);
     278          14 :     return config ? config->getServer() : 0;
     279             : }
     280             : 
     281        1224 : void View::addChannel(Channel* channel)
     282             : {
     283        1224 :     _channels.push_back(channel);
     284        1224 : }
     285             : 
     286        1222 : bool View::removeChannel(Channel* channel)
     287             : {
     288        1222 :     Channels::iterator i = lunchbox::find(_channels, channel);
     289             : 
     290        1222 :     LBASSERT(i != _channels.end());
     291        1222 :     if (i == _channels.end())
     292           0 :         return false;
     293             : 
     294        1222 :     _channels.erase(i);
     295        1222 :     return true;
     296             : }
     297             : 
     298         636 : ViewPath View::getPath() const
     299             : {
     300         636 :     const Layout* layout = getLayout();
     301         636 :     LBASSERT(layout);
     302         636 :     ViewPath path(layout->getPath());
     303             : 
     304         636 :     const Views& views = layout->getViews();
     305         636 :     Views::const_iterator i = std::find(views.begin(), views.end(), this);
     306         636 :     LBASSERT(i != views.end());
     307         636 :     path.viewIndex = std::distance(views.begin(), i);
     308         636 :     return path;
     309             : }
     310             : 
     311          14 : void View::init()
     312             : {
     313             :     // All contributors to the same view must share the same Deflect ID for
     314             :     // streaming to the same target.
     315          14 :     if (!getenv("DEFLECT_ID") && getSAttribute(View::SATTR_DEFLECT_ID).empty())
     316             :     {
     317             :         setSAttribute(View::SATTR_DEFLECT_ID,
     318          42 :                       getName().empty() ? "View " + getID().getShortString()
     319          14 :                                         : getName());
     320             :     }
     321          14 : }
     322             : 
     323           4 : void View::trigger(const Canvas* canvas, const bool active)
     324             : {
     325           4 :     const Mode mode = getMode();
     326           4 :     Config* config = getConfig();
     327             : 
     328             :     // (De)activate destination compounds for canvas/eye(s)
     329           8 :     for (Channels::const_iterator i = _channels.begin(); i != _channels.end();
     330             :          ++i)
     331             :     {
     332           4 :         Channel* channel = *i;
     333           4 :         const Canvas* channelCanvas = channel->getCanvas();
     334           4 :         const Layout* canvasLayout = channelCanvas->getActiveLayout();
     335             : 
     336           4 :         if ((canvas && channelCanvas != canvas) ||
     337           0 :             (!canvas && canvasLayout != getLayout()))
     338             :         {
     339           0 :             continue;
     340             :         }
     341             : 
     342           4 :         const Segment* segment = channel->getSegment();
     343           4 :         const uint32_t segmentEyes = segment->getEyes();
     344           4 :         const uint32_t eyes = (mode == MODE_MONO) ? EYE_CYCLOP & segmentEyes
     345           4 :                                                   : EYES_STEREO & segmentEyes;
     346           4 :         if (eyes == 0)
     347           0 :             continue;
     348             : 
     349           8 :         ConfigDestCompoundVisitor visitor(channel, true /*activeOnly*/);
     350           4 :         config->accept(visitor);
     351             : 
     352           4 :         const Compounds& compounds = visitor.getResult();
     353          24 :         for (Compounds::const_iterator j = compounds.begin();
     354          16 :              j != compounds.end(); ++j)
     355             :         {
     356           4 :             Compound* compound = *j;
     357           4 :             if (active)
     358             :             {
     359           2 :                 compound->activate(eyes);
     360           2 :                 LBLOG(LOG_VIEW) << "Activate " << compound->getName()
     361           2 :                                 << std::endl;
     362             :             }
     363             :             else
     364             :             {
     365           2 :                 compound->deactivate(eyes);
     366           2 :                 LBLOG(LOG_VIEW) << "Deactivate " << compound->getName()
     367           2 :                                 << std::endl;
     368             :             }
     369             :         }
     370             :     }
     371           4 : }
     372             : 
     373           0 : void View::activateMode(const Mode mode)
     374             : {
     375           0 :     if (getMode() == mode)
     376           0 :         return;
     377             : 
     378           0 :     Config* config = getConfig();
     379           0 :     if (config->isRunning())
     380             :     {
     381           0 :         config->postNeedsFinish();
     382           0 :         trigger(0, false);
     383             :     }
     384             : 
     385           0 :     Super::activateMode(mode);
     386             : 
     387           0 :     if (config->isRunning())
     388           0 :         trigger(0, true);
     389             : }
     390             : 
     391           0 : void View::updateCapabilities()
     392             : {
     393           0 :     CapabilitiesUpdater visitor(this);
     394           0 :     getConfig()->accept(visitor);
     395           0 :     setCapabilities(visitor.getCapabilities());
     396           0 : }
     397             : 
     398         118 : void View::updateFrusta()
     399             : {
     400         118 :     const Channels& channels = getChannels();
     401         118 :     Vector3f eye;
     402         118 :     const float ratio = _computeFocusRatio(eye);
     403             : 
     404         118 :     Config* config = getConfig();
     405         236 :     FrustumUpdater updater(channels, eye, ratio);
     406             : 
     407         118 :     config->accept(updater);
     408         118 : }
     409             : 
     410         118 : float View::_computeFocusRatio(Vector3f& eye)
     411             : {
     412         118 :     eye = Vector3f();
     413         118 :     const Observer* observer = getObserver();
     414             :     const FocusMode mode =
     415         118 :         observer ? observer->getFocusMode() : FOCUSMODE_FIXED;
     416         118 :     if (mode == FOCUSMODE_FIXED)
     417         118 :         return 1.f;
     418             : 
     419           0 :     const Channels& channels = getChannels();
     420           0 :     if (channels.empty())
     421           0 :         return 1.f;
     422             : 
     423           0 :     Vector4f view4(Vector3f::forward());
     424           0 :     if (mode == FOCUSMODE_RELATIVE_TO_OBSERVER)
     425             :     {
     426           0 :         view4 = observer->getHeadMatrix() * view4;
     427           0 :         eye = observer->getEyeWorld(EYE_CYCLOP);
     428             :     }
     429           0 :     Vector3f view = view4;
     430           0 :     view.normalize();
     431             : 
     432           0 :     float distance = std::numeric_limits<float>::max();
     433           0 :     if (getCurrentType() != Frustum::TYPE_NONE) // frustum from view
     434             :     {
     435           0 :         const Wall& wall = getWall();
     436           0 :         const Vector3f w = wall.getW();
     437           0 :         const float denom = view.dot(w);
     438           0 :         if (denom != 0.f) // view parallel to wall
     439             :         {
     440           0 :             const float d = (wall.bottomLeft - eye).dot(w) / denom;
     441           0 :             if (d > 0.f)
     442           0 :                 distance = d;
     443             :         }
     444             :     }
     445             :     else
     446             :     {
     447             :         // Find closest segment and its distance from cyclop eye
     448           0 :         for (ChannelsCIter i = channels.begin(); i != channels.end(); ++i)
     449             :         {
     450           0 :             Segment* segment = (*i)->getSegment();
     451           0 :             segment->inheritFrustum();
     452           0 :             if (segment->getCurrentType() == Frustum::TYPE_NONE)
     453           0 :                 continue;
     454             : 
     455             :             // http://en.wikipedia.org/wiki/Line-plane_intersection
     456           0 :             const Wall& wall = segment->getWall();
     457           0 :             const Vector3f w = wall.getW();
     458           0 :             const float denom = view.dot(w);
     459           0 :             if (denom == 0.f) // view parallel to wall
     460           0 :                 continue;
     461             : 
     462           0 :             const float d = (wall.bottomLeft - eye).dot(w) / denom;
     463           0 :             if (d > distance || d <= 0.f) // further away or behind
     464           0 :                 continue;
     465             : 
     466           0 :             distance = d;
     467             :             // LBINFO << "Eye " << eye << " is " << d << " from " << wall
     468             :             // << std::endl;
     469             :         }
     470             :     }
     471             : 
     472           0 :     float focusDistance = observer->getFocusDistance();
     473           0 :     if (mode == FOCUSMODE_RELATIVE_TO_ORIGIN)
     474             :     {
     475           0 :         eye = observer->getEyeWorld(EYE_CYCLOP);
     476             : 
     477           0 :         if (distance != std::numeric_limits<float>::max())
     478             :         {
     479           0 :             distance += eye.z();
     480           0 :             focusDistance += eye.z();
     481           0 :             if (fabsf(distance) <= std::numeric_limits<float>::epsilon())
     482           0 :                 distance = 2.f * std::numeric_limits<float>::epsilon();
     483             :         }
     484             :     }
     485             : 
     486           0 :     if (distance == std::numeric_limits<float>::max())
     487           0 :         return 1.f;
     488           0 :     return focusDistance / distance;
     489             : }
     490             : }
     491             : }
     492             : 
     493             : #include "../fabric/view.ipp"
     494             : 
     495             : template class eq::fabric::View<eq::server::Layout, eq::server::View,
     496             :                                 eq::server::Observer>;
     497             : /** @cond IGNORE */
     498             : template std::ostream& eq::fabric::operator<<(
     499             :     std::ostream&, const eq::fabric::View<eq::server::Layout, eq::server::View,
     500          60 :                                           eq::server::Observer>&);
     501             : /** @endcond */

Generated by: LCOV version 1.11