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 */
|