Line data Source code
1 :
2 : /* Copyright (c) 2005-2017, 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 "compound.h"
21 :
22 : #include "canvas.h"
23 : #include "channel.h"
24 : #include "colorMask.h"
25 : #include "compoundInitVisitor.h"
26 : #include "compoundListener.h"
27 : #include "compoundUpdateDataVisitor.h"
28 : #include "compoundUpdateInputVisitor.h"
29 : #include "compoundUpdateOutputVisitor.h"
30 : #include "config.h"
31 : #include "equalizers/equalizer.h"
32 : #include "frame.h"
33 : #include "frameData.h"
34 : #include "global.h"
35 : #include "layout.h"
36 : #include "log.h"
37 : #include "observer.h"
38 : #include "segment.h"
39 : #include "tileQueue.h"
40 : #include "view.h"
41 :
42 : #include <boost/foreach.hpp>
43 : #include <eq/fabric/paths.h>
44 : #include <lunchbox/algorithm.h>
45 : #include <lunchbox/os.h>
46 :
47 : #include <algorithm>
48 : #include <math.h>
49 : #include <vector>
50 :
51 : #include "compoundActivateVisitor.h"
52 : #include "compoundExitVisitor.h"
53 : #include "compoundUpdateActivateVisitor.h"
54 :
55 : namespace eq
56 : {
57 : namespace server
58 : {
59 : #define MAKE_ATTR_STRING(attr) (std::string("EQ_COMPOUND_") + #attr)
60 : ;
61 :
62 670 : Compound::Compound(Config* parent)
63 : : _config(parent)
64 : , _parent(0)
65 : , _usage(1.0f)
66 : , _taskID(0)
67 670 : , _frustum(_data.frustumData)
68 : {
69 670 : LBASSERT(parent);
70 670 : parent->addCompound(this);
71 670 : LBLOG(LOG_INIT) << "New root compound @" << (void*)this << std::endl;
72 670 : }
73 :
74 3542 : Compound::Compound(Compound* parent)
75 : : _config(0)
76 : , _parent(parent)
77 : , _usage(1.0f)
78 : , _taskID(0)
79 3542 : , _frustum(_data.frustumData)
80 : {
81 3542 : LBASSERT(parent);
82 3542 : parent->_addChild(this);
83 3542 : LBLOG(LOG_INIT) << "New compound child @" << (void*)this << std::endl;
84 3542 : }
85 :
86 12636 : Compound::~Compound()
87 : {
88 4212 : _swapBarrier = 0;
89 :
90 13518 : for (Equalizers::const_iterator i = _equalizers.begin();
91 9012 : i != _equalizers.end(); ++i)
92 : {
93 294 : Equalizer* equalizer = *i;
94 294 : equalizer->attach(0);
95 294 : delete equalizer;
96 : }
97 4212 : _equalizers.clear();
98 :
99 11296 : while (!_children.empty())
100 : {
101 3542 : Compound* compound = _children.back();
102 3542 : _removeChild(compound);
103 3542 : delete compound;
104 : }
105 :
106 4212 : if (_config)
107 670 : _config->removeCompound(this);
108 : else
109 : {
110 3542 : LBASSERT(_parent);
111 3542 : _parent->_removeChild(this);
112 : }
113 :
114 7020 : for (FramesCIter i = _inputFrames.begin(); i != _inputFrames.end(); ++i)
115 2808 : delete *i;
116 4212 : _inputFrames.clear();
117 :
118 6952 : for (FramesCIter i = _outputFrames.begin(); i != _outputFrames.end(); ++i)
119 2740 : delete *i;
120 4212 : _outputFrames.clear();
121 :
122 12636 : for (TileQueuesCIter i = _inputTileQueues.begin();
123 8424 : i != _inputTileQueues.end(); ++i)
124 : {
125 0 : delete *i;
126 : }
127 4212 : _inputTileQueues.clear();
128 :
129 12636 : for (TileQueuesCIter i = _outputTileQueues.begin();
130 8424 : i != _outputTileQueues.end(); ++i)
131 : {
132 0 : delete *i;
133 : }
134 4212 : _outputTileQueues.clear();
135 8424 : }
136 :
137 12636 : Compound::Data::Data()
138 : : channel(0)
139 : , buffers(Frame::Buffer::undefined)
140 : , eyes(EYE_UNDEFINED)
141 : , tasks(fabric::TASK_DEFAULT)
142 : , period(LB_UNDEFINED_UINT32)
143 : , phase(LB_UNDEFINED_UINT32)
144 12636 : , maxFPS(std::numeric_limits<float>::max())
145 : {
146 12636 : const Global* global = Global::instance();
147 75816 : for (int i = 0; i < IATTR_ALL; ++i)
148 63180 : iAttributes[i] =
149 63180 : global->getCompoundIAttribute(static_cast<IAttribute>(i));
150 50544 : for (size_t i = 0; i < NUM_EYES; ++i)
151 37908 : active[i] = 0;
152 12636 : }
153 :
154 3542 : void Compound::_addChild(Compound* child)
155 : {
156 3542 : LBASSERT(child->_parent == this);
157 3542 : _children.push_back(child);
158 3542 : _fireChildAdded(child);
159 3542 : }
160 :
161 7084 : bool Compound::_removeChild(Compound* child)
162 : {
163 7084 : Compounds::iterator i = lunchbox::find(_children, child);
164 7084 : if (i == _children.end())
165 3542 : return false;
166 :
167 3542 : _fireChildRemove(child);
168 3542 : _children.erase(i);
169 3542 : return true;
170 : }
171 :
172 12866 : Compound* Compound::getNext() const
173 : {
174 12866 : if (!_parent)
175 5180 : return 0;
176 :
177 7686 : Compounds& siblings = _parent->_children;
178 : Compounds::iterator result =
179 7686 : std::find(siblings.begin(), siblings.end(), this);
180 7686 : if (result == siblings.end())
181 0 : return 0;
182 7686 : ++result;
183 7686 : if (result == siblings.end())
184 3906 : return 0;
185 :
186 3780 : return *result;
187 : }
188 :
189 8 : Node* Compound::getNode()
190 : {
191 8 : Channel* channel = getChannel();
192 8 : return channel ? channel->getNode() : 0;
193 : }
194 :
195 264 : ServerPtr Compound::getServer()
196 : {
197 264 : return getConfig()->getServer();
198 : }
199 :
200 2928 : void Compound::setChannel(Channel* channel)
201 : {
202 2928 : _data.channel = channel;
203 :
204 : // Update swap barrier
205 2928 : if (!isDestination())
206 3388 : return;
207 :
208 1240 : Segment* segment = channel ? channel->getSegment() : 0;
209 1240 : if (!segment)
210 12 : return;
211 :
212 2456 : SwapBarrierPtr swapBarrier = segment->getSwapBarrier();
213 1228 : if (swapBarrier)
214 72 : setSwapBarrier(swapBarrier);
215 : }
216 :
217 15602 : const Channel* Compound::getChannel() const
218 : {
219 15602 : if (_data.channel)
220 8548 : return _data.channel;
221 7054 : if (_parent)
222 4460 : return _parent->getChannel();
223 2594 : return 0;
224 : }
225 :
226 24452 : Channel* Compound::getChannel()
227 : {
228 24452 : if (_data.channel)
229 14438 : return _data.channel;
230 10014 : if (_parent)
231 7420 : return _parent->getChannel();
232 2594 : return 0;
233 : }
234 :
235 0 : Window* Compound::getWindow()
236 : {
237 0 : Channel* channel = getChannel();
238 0 : if (channel)
239 0 : return channel->getWindow();
240 0 : return 0;
241 : }
242 :
243 0 : const Window* Compound::getWindow() const
244 : {
245 0 : const Channel* channel = getChannel();
246 0 : if (channel)
247 0 : return channel->getWindow();
248 0 : return 0;
249 : }
250 :
251 0 : Pipe* Compound::getPipe()
252 : {
253 0 : Channel* channel = getChannel();
254 0 : if (channel)
255 0 : return channel->getPipe();
256 0 : return 0;
257 : }
258 :
259 0 : const Pipe* Compound::getPipe() const
260 : {
261 0 : const Channel* channel = getChannel();
262 0 : if (channel)
263 0 : return channel->getPipe();
264 0 : return 0;
265 : }
266 :
267 294 : void Compound::addEqualizer(Equalizer* equalizer)
268 : {
269 294 : if (equalizer)
270 294 : equalizer->attach(this);
271 :
272 294 : _equalizers.push_back(equalizer);
273 294 : }
274 :
275 240 : bool Compound::isInheritActive(const Eye eye) const
276 : {
277 240 : const int32_t index = lunchbox::getIndexOfLastBit(eye);
278 240 : LBASSERT(index >= 0);
279 240 : LBASSERT(index < NUM_EYES);
280 240 : return _inherit.active[index];
281 : }
282 :
283 4 : bool Compound::isLastInheritEye(const Eye eye) const
284 : {
285 4 : int32_t index = lunchbox::getIndexOfLastBit(eye);
286 4 : LBASSERT(index >= 0);
287 :
288 20 : while (++index < NUM_EYES)
289 8 : if (_inherit.active[index])
290 0 : return false;
291 4 : return true;
292 : }
293 :
294 296 : bool Compound::isActive() const
295 : {
296 296 : bool active = false;
297 1184 : for (size_t i = 0; i < NUM_EYES; ++i)
298 888 : active = active || _inherit.active[i];
299 :
300 296 : if (!active)
301 180 : return false;
302 :
303 116 : const Channel* channel = getChannel();
304 116 : if (!channel)
305 56 : return true;
306 :
307 60 : if (!channel->isRunning())
308 0 : return false;
309 :
310 60 : LBASSERT(_inherit.channel);
311 60 : const View* view = _inherit.channel->getView();
312 60 : return channel->supportsView(view);
313 : }
314 :
315 : //---------------------------------------------------------------------------
316 : // Listener interface
317 : //---------------------------------------------------------------------------
318 294 : void Compound::addListener(CompoundListener* listener)
319 : {
320 588 : LB_TS_SCOPED(_serverThread);
321 294 : _listeners.push_back(listener);
322 294 : }
323 :
324 294 : void Compound::removeListener(CompoundListener* listener)
325 : {
326 588 : LB_TS_SCOPED(_serverThread);
327 : CompoundListeners::iterator i =
328 294 : find(_listeners.begin(), _listeners.end(), listener);
329 294 : if (i != _listeners.end())
330 294 : _listeners.erase(i);
331 294 : }
332 :
333 264 : void Compound::fireUpdatePre(const uint32_t frameNumber)
334 : {
335 528 : LB_TS_SCOPED(_serverThread);
336 :
337 300 : BOOST_FOREACH (CompoundListener* listener, _listeners)
338 36 : listener->notifyUpdatePre(this, frameNumber);
339 264 : }
340 :
341 3060 : const std::string& Compound::getIAttributeString(
342 : const Compound::IAttribute attr)
343 : {
344 : static std::string iAttributeStrings[] = {
345 12 : MAKE_ATTR_STRING(IATTR_STEREO_MODE),
346 12 : MAKE_ATTR_STRING(IATTR_STEREO_ANAGLYPH_LEFT_MASK),
347 12 : MAKE_ATTR_STRING(IATTR_STEREO_ANAGLYPH_RIGHT_MASK),
348 3102 : MAKE_ATTR_STRING(IATTR_FILL1), MAKE_ATTR_STRING(IATTR_FILL2)};
349 3060 : return iAttributeStrings[attr];
350 : }
351 :
352 3542 : void Compound::_fireChildAdded(Compound* child)
353 : {
354 7084 : LB_TS_SCOPED(_serverThread);
355 :
356 13446 : for (CompoundListeners::const_iterator i = _listeners.begin();
357 8964 : i != _listeners.end(); ++i)
358 :
359 940 : (*i)->notifyChildAdded(this, child);
360 3542 : }
361 :
362 3542 : void Compound::_fireChildRemove(Compound* child)
363 : {
364 7084 : LB_TS_SCOPED(_serverThread);
365 :
366 10626 : for (CompoundListeners::const_iterator i = _listeners.begin();
367 7084 : i != _listeners.end(); ++i)
368 :
369 0 : (*i)->notifyChildRemove(this, child);
370 3542 : }
371 :
372 : //---------------------------------------------------------------------------
373 : // I/O objects access
374 : //---------------------------------------------------------------------------
375 500 : void Compound::setSwapBarrier(SwapBarrierPtr barrier)
376 : {
377 500 : if (barrier && barrier->getName().empty())
378 : {
379 196 : const Compound* root = getRoot();
380 196 : const std::string& rootName = root->getName();
381 196 : if (rootName.empty())
382 192 : barrier->setName("barrier");
383 : else
384 4 : barrier->setName("barrier." + rootName);
385 : }
386 :
387 500 : _swapBarrier = barrier;
388 500 : }
389 :
390 2808 : void Compound::addInputFrame(Frame* frame)
391 : {
392 2808 : LBASSERT(frame);
393 2808 : if (frame->getName().empty())
394 0 : _setDefaultFrameName(frame);
395 2808 : _inputFrames.push_back(frame);
396 2808 : frame->setCompound(this);
397 2808 : }
398 :
399 2740 : void Compound::addOutputFrame(Frame* frame)
400 : {
401 2740 : if (frame->getName().empty())
402 544 : _setDefaultFrameName(frame);
403 2740 : _outputFrames.push_back(frame);
404 2740 : frame->setCompound(this);
405 2740 : }
406 :
407 0 : void Compound::addInputTileQueue(TileQueue* tileQueue)
408 : {
409 0 : LBASSERT(tileQueue);
410 0 : if (tileQueue->getName().empty())
411 0 : _setDefaultTileQueueName(tileQueue);
412 0 : _inputTileQueues.push_back(tileQueue);
413 0 : tileQueue->setCompound(this);
414 0 : }
415 :
416 0 : void Compound::removeInputTileQueue(TileQueue* tileQueue)
417 : {
418 0 : TileQueuesIter i;
419 0 : i = find(_inputTileQueues.begin(), _inputTileQueues.end(), tileQueue);
420 0 : if (i != _inputTileQueues.end())
421 0 : _inputTileQueues.erase(i);
422 0 : }
423 :
424 0 : void Compound::addOutputTileQueue(TileQueue* tileQueue)
425 : {
426 0 : if (tileQueue->getName().empty())
427 0 : _setDefaultTileQueueName(tileQueue);
428 0 : _outputTileQueues.push_back(tileQueue);
429 0 : tileQueue->setCompound(this);
430 0 : }
431 :
432 0 : void Compound::removeOutputTileQueue(TileQueue* tileQueue)
433 : {
434 0 : TileQueuesIter i;
435 0 : i = find(_outputTileQueues.begin(), _outputTileQueues.end(), tileQueue);
436 0 : if (i != _outputTileQueues.end())
437 0 : _outputTileQueues.erase(i);
438 0 : }
439 :
440 544 : void Compound::_setDefaultFrameName(Frame* frame)
441 : {
442 544 : for (Compound* compound = this; compound; compound = compound->getParent())
443 : {
444 544 : if (!compound->getName().empty())
445 : {
446 0 : frame->setName("frame." + compound->getName());
447 0 : return;
448 : }
449 :
450 544 : const Channel* channel = compound->getChannel();
451 544 : if (channel && !channel->getName().empty())
452 : {
453 544 : frame->setName("frame." + channel->getName());
454 544 : return;
455 : }
456 : }
457 0 : frame->setName("frame");
458 : }
459 :
460 0 : void Compound::_setDefaultTileQueueName(TileQueue* tileQueue)
461 : {
462 0 : for (Compound* compound = this; compound; compound = compound->getParent())
463 : {
464 0 : if (!compound->getName().empty())
465 : {
466 0 : tileQueue->setName("queue." + compound->getName());
467 0 : return;
468 : }
469 :
470 0 : const Channel* channel = compound->getChannel();
471 0 : if (channel && !channel->getName().empty())
472 : {
473 0 : tileQueue->setName("queue." + channel->getName());
474 0 : return;
475 : }
476 : }
477 0 : tileQueue->setName("queue");
478 : }
479 :
480 0 : void Compound::adopt(Compound* child)
481 : {
482 0 : if (child->_config)
483 : {
484 0 : child->_config->removeCompound(child);
485 0 : const_cast<Config*&>(child->_config) = 0;
486 : }
487 : else
488 : {
489 0 : LBASSERT(child->_parent);
490 0 : child->_parent->_removeChild(child);
491 : }
492 :
493 0 : const_cast<Compound*&>(child->_parent) = this;
494 0 : _addChild(child);
495 0 : }
496 :
497 6706 : bool Compound::isDestination() const
498 : {
499 6706 : if (!getChannel())
500 84 : return false;
501 :
502 8744 : for (const Compound* compound = getParent(); compound;
503 : compound = compound->getParent())
504 : {
505 6236 : if (compound->getChannel())
506 4114 : return false;
507 : }
508 :
509 2508 : return true;
510 : }
511 :
512 8 : bool Compound::hasDestinationChannel() const
513 : {
514 8 : return getChannel() && getChannel() == getInheritChannel();
515 : }
516 :
517 16 : RenderContext Compound::setupRenderContext(const Eye eye) const
518 : {
519 16 : RenderContext context;
520 16 : context.pvp = _inherit.pvp;
521 16 : context.overdraw = _inherit.overdraw;
522 16 : context.vp = _inherit.vp;
523 16 : context.range = _inherit.range;
524 16 : context.pixel = _inherit.pixel;
525 16 : context.subPixel = _inherit.subPixel;
526 16 : context.zoom = _inherit.zoom;
527 16 : context.period = _inherit.period;
528 16 : context.phase = _inherit.phase;
529 16 : context.offset.x() = context.pvp.x;
530 16 : context.offset.y() = context.pvp.y;
531 16 : context.eye = eye;
532 16 : context.taskID = _taskID;
533 16 : _computeFrustum(context);
534 16 : return context;
535 : }
536 :
537 : //---------------------------------------------------------------------------
538 : // frustum operations
539 : //---------------------------------------------------------------------------
540 174 : void Compound::setWall(const Wall& wall)
541 : {
542 174 : _frustum.setWall(wall);
543 174 : LBVERB << "Wall: " << _data.frustumData << std::endl;
544 174 : }
545 :
546 0 : void Compound::setProjection(const Projection& projection)
547 : {
548 0 : _frustum.setProjection(projection);
549 0 : LBVERB << "Projection: " << _data.frustumData << std::endl;
550 0 : }
551 :
552 160 : void Compound::updateFrustum(const Vector3f& eye, const float ratio)
553 : {
554 160 : if (!isDestination()) // only set view/segment frusta on destination
555 202 : return;
556 :
557 118 : Channel* channel = getChannel();
558 118 : Segment* segment = channel->getSegment();
559 118 : const View* view = channel->getView();
560 118 : if (!segment || !view)
561 0 : return;
562 :
563 118 : if (view->getCurrentType() != Frustum::TYPE_NONE) // frustum from view:
564 : {
565 : // set compound frustum =
566 : // segment frustum X channel/view coverage
567 118 : const Viewport& segmentVP = segment->getViewport();
568 118 : const Viewport& viewVP = view->getViewport();
569 118 : const Viewport coverage = viewVP.getCoverage(segmentVP);
570 :
571 118 : Wall wall(view->getWall());
572 :
573 118 : wall.apply(coverage);
574 118 : wall.moveFocus(eye, ratio);
575 118 : _updateOverdraw(wall);
576 118 : wall.scale(view->getModelUnit());
577 :
578 118 : switch (view->getCurrentType())
579 : {
580 : case Frustum::TYPE_WALL:
581 118 : setWall(wall);
582 118 : LBLOG(LOG_VIEW) << "View wall for " << channel->getName() << ": "
583 118 : << wall << std::endl;
584 236 : return;
585 :
586 : case Frustum::TYPE_PROJECTION:
587 : {
588 0 : Projection projection(view->getProjection()); // keep distance
589 0 : projection = wall;
590 0 : setProjection(projection);
591 0 : LBLOG(LOG_VIEW) << "View projection for " << channel->getName()
592 0 : << ": " << projection << std::endl;
593 0 : return;
594 : }
595 :
596 : default:
597 0 : LBUNIMPLEMENTED;
598 : }
599 : }
600 : // else frustum from segment
601 :
602 0 : segment->inheritFrustum();
603 :
604 : // set compound frustum =
605 : // segment frustum X channel/segment coverage
606 0 : const Channel* outputChannel = segment->getChannel();
607 0 : LBASSERT(outputChannel);
608 :
609 0 : const Viewport& outputVP = outputChannel->getViewport();
610 0 : const Viewport& channelVP = channel->getViewport();
611 0 : const Viewport coverage = outputVP.getCoverage(channelVP);
612 :
613 0 : Wall wall(segment->getWall());
614 0 : wall.moveFocus(eye, ratio);
615 0 : wall.apply(coverage);
616 0 : _updateOverdraw(wall);
617 0 : wall.scale(view->getModelUnit());
618 :
619 0 : switch (segment->getCurrentType())
620 : {
621 : case Frustum::TYPE_WALL:
622 : {
623 0 : setWall(wall);
624 0 : LBLOG(LOG_VIEW) << "Segment wall for " << channel->getName() << ": "
625 0 : << wall << std::endl;
626 0 : return;
627 : }
628 :
629 : case Frustum::TYPE_PROJECTION:
630 : {
631 0 : Projection projection(segment->getProjection());
632 0 : projection = wall;
633 0 : setProjection(projection);
634 0 : LBLOG(LOG_VIEW) << "Segment projection for " << channel->getName()
635 0 : << ": " << projection << std::endl;
636 0 : return;
637 : }
638 : default:
639 0 : LBUNIMPLEMENTED;
640 : }
641 : }
642 :
643 16 : void Compound::_computeFrustum(RenderContext& context) const
644 : {
645 : // compute eye position in screen space
646 16 : const Vector3f& eyeWorld = _getEyePosition(context.eye);
647 16 : const FrustumData& frustumData = _inherit.frustumData;
648 16 : const Matrix4f& xfm = frustumData.getTransform();
649 16 : const Vector3f eyeWall = xfm * eyeWorld;
650 :
651 16 : LBVERB << "Eye position world: " << eyeWorld << " wall " << eyeWall
652 16 : << std::endl;
653 16 : _computePerspective(context, eyeWall);
654 16 : _computeOrtho(context, eyeWall);
655 16 : }
656 :
657 0 : void Compound::computeTileFrustum(Frustumf& frustum, const Eye eye, Viewport vp,
658 : bool ortho) const
659 : {
660 0 : const Vector3f& eyeWorld = _getEyePosition(eye);
661 0 : const FrustumData& frustumData = _inherit.frustumData;
662 0 : const Matrix4f& xfm = frustumData.getTransform();
663 0 : const Vector3f eyeWall = xfm * eyeWorld;
664 :
665 0 : _computeFrustumCorners(frustum, frustumData, eyeWall, ortho, &vp);
666 0 : }
667 :
668 : namespace
669 : {
670 32 : static void _computeHeadTransform(Matrix4f& result, const Matrix4f& xfm,
671 : const Vector3f& eye)
672 : {
673 : // headTransform = -trans(eye) * view matrix (frustum position)
674 160 : for (int i = 0; i < 16; i += 4)
675 : {
676 128 : result.array[i] = xfm.array[i] - eye[0] * xfm.array[i + 3];
677 128 : result.array[i + 1] = xfm.array[i + 1] - eye[1] * xfm.array[i + 3];
678 128 : result.array[i + 2] = xfm.array[i + 2] - eye[2] * xfm.array[i + 3];
679 128 : result.array[i + 3] = xfm.array[i + 3];
680 : }
681 32 : }
682 : }
683 :
684 16 : void Compound::_computePerspective(RenderContext& context,
685 : const Vector3f& eye) const
686 : {
687 16 : const FrustumData& frustumData = _inherit.frustumData;
688 :
689 16 : _computeFrustumCorners(context.frustum, frustumData, eye, false);
690 16 : _computeHeadTransform(context.headTransform, frustumData.getTransform(),
691 16 : eye);
692 :
693 16 : const bool isHMD = (frustumData.getType() != Wall::TYPE_FIXED);
694 16 : if (isHMD)
695 0 : context.headTransform *= _getInverseHeadMatrix();
696 16 : }
697 :
698 16 : void Compound::_computeOrtho(RenderContext& context, const Vector3f& eye) const
699 : {
700 : // Compute corners for cyclop eye without perspective correction:
701 16 : const Vector3f& cyclopWorld = _getEyePosition(EYE_CYCLOP);
702 16 : const FrustumData& frustumData = _inherit.frustumData;
703 16 : const Matrix4f& xfm = frustumData.getTransform();
704 16 : const Vector3f cyclopWall = xfm * cyclopWorld;
705 :
706 16 : _computeFrustumCorners(context.ortho, frustumData, cyclopWall, true);
707 16 : _computeHeadTransform(context.orthoTransform, xfm, eye);
708 :
709 : // Apply stereo shearing
710 16 : context.orthoTransform.array[8] += (cyclopWall[0] - eye[0]) / eye[2];
711 16 : context.orthoTransform.array[9] += (cyclopWall[1] - eye[1]) / eye[2];
712 :
713 16 : const bool isHMD = (frustumData.getType() != Wall::TYPE_FIXED);
714 16 : if (isHMD)
715 0 : context.orthoTransform *= _getInverseHeadMatrix();
716 16 : }
717 :
718 32 : Vector3f Compound::_getEyePosition(const Eye eye) const
719 : {
720 32 : const FrustumData& frustumData = _inherit.frustumData;
721 32 : const Channel* destChannel = getInheritChannel();
722 32 : const View* view = destChannel->getView();
723 32 : const Observer* observer = view ? view->getObserver() : 0;
724 32 : const float modelUnit = view ? view->getModelUnit() : 1.f;
725 :
726 32 : if (observer)
727 32 : return modelUnit * (frustumData.getType() == Wall::TYPE_FIXED
728 : ? observer->getEyeWorld(eye)
729 32 : : observer->getEyePosition(eye));
730 :
731 : const float eyeBase_2 =
732 0 : 0.5f * modelUnit * getConfig()->getFAttribute(Config::FATTR_EYE_BASE);
733 0 : switch (eye)
734 : {
735 : case EYE_LEFT:
736 0 : return Vector3f(-eyeBase_2, 0.f, 0.f);
737 : case EYE_RIGHT:
738 0 : return Vector3f(eyeBase_2, 0.f, 0.f);
739 :
740 : default:
741 0 : LBUNIMPLEMENTED;
742 : case EYE_CYCLOP:
743 0 : return Vector3f();
744 : }
745 : }
746 :
747 0 : const Matrix4f& Compound::_getInverseHeadMatrix() const
748 : {
749 0 : const Channel* destChannel = getInheritChannel();
750 0 : const View* view = destChannel->getView();
751 : const Observer* observer =
752 0 : static_cast<const Observer*>(view ? view->getObserver() : 0);
753 :
754 0 : if (observer)
755 0 : return observer->getInverseHeadMatrix();
756 :
757 0 : static const Matrix4f identity;
758 0 : return identity;
759 : }
760 :
761 32 : void Compound::_computeFrustumCorners(Frustumf& frustum,
762 : const FrustumData& frustumData,
763 : const Vector3f& eye, const bool ortho,
764 : const Viewport* const invp) const
765 : {
766 32 : const Channel* destination = getInheritChannel();
767 32 : frustum = destination->getFrustum();
768 :
769 32 : const float ratio = ortho ? 1.0f : frustum.nearPlane() / eye.z();
770 32 : const float width_2 = frustumData.getWidth() * .5f;
771 32 : const float height_2 = frustumData.getHeight() * .5f;
772 :
773 32 : if (eye.z() > 0 || ortho)
774 : {
775 32 : frustum.left() = (-width_2 - eye.x()) * ratio;
776 32 : frustum.right() = (width_2 - eye.x()) * ratio;
777 32 : frustum.bottom() = (-height_2 - eye.y()) * ratio;
778 32 : frustum.top() = (height_2 - eye.y()) * ratio;
779 : }
780 : else // eye behind near plane - 'mirror' x
781 : {
782 0 : frustum.left() = (width_2 - eye.x()) * ratio;
783 0 : frustum.right() = (-width_2 - eye.x()) * ratio;
784 0 : frustum.bottom() = (height_2 + eye.y()) * ratio;
785 0 : frustum.top() = (-height_2 + eye.y()) * ratio;
786 : }
787 :
788 : // move frustum according to pixel decomposition
789 32 : const Pixel& pixel = getInheritPixel();
790 32 : if (pixel != Pixel::ALL && pixel.isValid())
791 : {
792 0 : const Channel* inheritChannel = getInheritChannel();
793 0 : const PixelViewport& destPVP = inheritChannel->getPixelViewport();
794 :
795 0 : if (pixel.w > 1)
796 : {
797 0 : const float frustumWidth = frustum.right() - frustum.left();
798 : const float pixelWidth =
799 0 : frustumWidth / static_cast<float>(destPVP.w);
800 0 : const float jitter = pixelWidth * pixel.x - pixelWidth * .5f;
801 :
802 0 : frustum.left() += jitter;
803 0 : frustum.right() += jitter;
804 : }
805 0 : if (pixel.h > 1)
806 : {
807 0 : const float frustumHeight = frustum.bottom() - frustum.top();
808 0 : const float pixelHeight = frustumHeight / float(destPVP.h);
809 0 : const float jitter = pixelHeight * pixel.y + pixelHeight * .5f;
810 :
811 0 : frustum.top() -= jitter;
812 0 : frustum.bottom() -= jitter;
813 : }
814 : }
815 :
816 : // adjust to viewport (screen-space decomposition)
817 : // Note: vp is computed pixel-correct by Compound::updateInheritData()
818 32 : const Viewport& vp = invp ? *invp : _inherit.vp;
819 32 : if (vp != Viewport::FULL && vp.isValid())
820 : {
821 16 : const float frustumWidth = frustum.right() - frustum.left();
822 16 : frustum.left() += frustumWidth * vp.x;
823 16 : frustum.right() = frustum.left() + frustumWidth * vp.w;
824 :
825 16 : const float frustumHeight = frustum.top() - frustum.bottom();
826 16 : frustum.bottom() += frustumHeight * vp.y;
827 16 : frustum.top() = frustum.bottom() + frustumHeight * vp.h;
828 : }
829 32 : }
830 :
831 118 : void Compound::_updateOverdraw(Wall& wall)
832 : {
833 118 : Channel* channel = getChannel();
834 118 : LBASSERT(channel);
835 118 : if (!channel)
836 0 : return;
837 :
838 118 : const Segment* segment = channel->getSegment();
839 118 : const View* view = channel->getView();
840 118 : LBASSERT(segment && view);
841 118 : if (!segment || !view)
842 0 : return;
843 :
844 118 : const Viewport& segmentVP = segment->getViewport();
845 118 : const Viewport& viewVP = view->getViewport();
846 118 : const Vector2i& overdraw = view->getOverdraw();
847 118 : Vector4i channelOverdraw;
848 :
849 : // compute overdraw
850 118 : if (overdraw.x() && viewVP.x < segmentVP.x)
851 0 : channelOverdraw.x() = overdraw.x();
852 :
853 118 : if (overdraw.x() && viewVP.getXEnd() > segmentVP.getXEnd())
854 0 : channelOverdraw.z() = overdraw.x();
855 :
856 118 : if (overdraw.y() && viewVP.y < segmentVP.y)
857 0 : channelOverdraw.y() = overdraw.y();
858 :
859 118 : if (overdraw.y() && viewVP.getYEnd() > segmentVP.getYEnd())
860 0 : channelOverdraw.w() = overdraw.y();
861 :
862 : // apply to frustum
863 118 : if (channelOverdraw.x() > 0)
864 : {
865 0 : const PixelViewport& pvp = channel->getPixelViewport();
866 0 : const float ratio = static_cast<float>(pvp.w + channelOverdraw.x()) /
867 0 : static_cast<float>(pvp.w);
868 0 : wall.resizeLeft(ratio);
869 : }
870 :
871 118 : if (channelOverdraw.z() > 0)
872 : {
873 0 : const PixelViewport& pvp = channel->getPixelViewport();
874 0 : const float ratio = static_cast<float>(pvp.w + channelOverdraw.x() +
875 0 : channelOverdraw.z()) /
876 0 : static_cast<float>(pvp.w + channelOverdraw.x());
877 0 : wall.resizeRight(ratio);
878 : }
879 :
880 118 : if (channelOverdraw.y() > 0)
881 : {
882 0 : const PixelViewport& pvp = channel->getPixelViewport();
883 0 : const float ratio = static_cast<float>(pvp.h + channelOverdraw.y()) /
884 0 : static_cast<float>(pvp.h);
885 0 : wall.resizeBottom(ratio);
886 : }
887 :
888 118 : if (channelOverdraw.w() > 0)
889 : {
890 0 : const PixelViewport& pvp = channel->getPixelViewport();
891 0 : const float ratio = static_cast<float>(pvp.h + +channelOverdraw.y() +
892 0 : channelOverdraw.w()) /
893 0 : static_cast<float>(pvp.h + channelOverdraw.y());
894 0 : wall.resizeTop(ratio);
895 : }
896 :
897 118 : channel->setOverdraw(channelOverdraw);
898 : }
899 :
900 : //---------------------------------------------------------------------------
901 : // accept
902 : //---------------------------------------------------------------------------
903 : namespace
904 : {
905 : template <class C>
906 3260 : VisitorResult _accept(C* compound, CompoundVisitor& visitor)
907 : {
908 3260 : if (compound->isLeaf())
909 14 : return visitor.visitLeaf(compound);
910 :
911 3246 : C* current = compound;
912 3246 : VisitorResult result = TRAVERSE_CONTINUE;
913 :
914 6454 : while (true)
915 : {
916 9700 : C* parent = current->getParent();
917 9700 : C* next = current->getNext();
918 :
919 9700 : const Compounds& children = current->getChildren();
920 9700 : C* child = children.empty() ? 0 : children[0];
921 :
922 : //---------- down-right traversal
923 9700 : if (!child) // leaf
924 : {
925 3986 : switch (visitor.visitLeaf(current))
926 : {
927 : case TRAVERSE_TERMINATE:
928 174 : return TRAVERSE_TERMINATE;
929 :
930 : case TRAVERSE_PRUNE:
931 1826 : result = TRAVERSE_PRUNE;
932 1826 : current = next;
933 1826 : break;
934 :
935 : case TRAVERSE_CONTINUE:
936 1986 : current = next;
937 1986 : break;
938 :
939 : default:
940 0 : LBASSERTINFO(0, "Unreachable");
941 : }
942 : }
943 : else // node
944 : {
945 5714 : switch (visitor.visitPre(current))
946 : {
947 : case TRAVERSE_TERMINATE:
948 244 : return TRAVERSE_TERMINATE;
949 :
950 : case TRAVERSE_PRUNE:
951 2072 : result = TRAVERSE_PRUNE;
952 2072 : current = next;
953 2072 : break;
954 :
955 : case TRAVERSE_CONTINUE:
956 3398 : current = child;
957 3398 : break;
958 :
959 : default:
960 0 : LBASSERTINFO(0, "Unreachable");
961 : }
962 : }
963 :
964 : //---------- up-right traversal
965 9282 : if (!current && !parent)
966 886 : return TRAVERSE_CONTINUE;
967 :
968 10844 : while (!current)
969 : {
970 3166 : current = parent;
971 3166 : parent = current->getParent();
972 3166 : next = current->getNext();
973 :
974 3166 : switch (visitor.visitPost(current))
975 : {
976 : case TRAVERSE_TERMINATE:
977 0 : return TRAVERSE_TERMINATE;
978 :
979 : case TRAVERSE_PRUNE:
980 0 : result = TRAVERSE_PRUNE;
981 0 : break;
982 :
983 : case TRAVERSE_CONTINUE:
984 3166 : break;
985 :
986 : default:
987 0 : LBASSERTINFO(0, "Unreachable");
988 : }
989 :
990 3166 : if (current == compound)
991 1942 : return result;
992 :
993 1224 : current = next;
994 : }
995 : }
996 : return result;
997 : }
998 : }
999 :
1000 3176 : VisitorResult Compound::accept(CompoundVisitor& visitor)
1001 : {
1002 3176 : return _accept(this, visitor);
1003 : }
1004 :
1005 84 : VisitorResult Compound::accept(CompoundVisitor& visitor) const
1006 : {
1007 84 : return _accept(this, visitor);
1008 : }
1009 :
1010 : //---------------------------------------------------------------------------
1011 : // Operations
1012 : //---------------------------------------------------------------------------
1013 :
1014 16 : void Compound::activate(const uint32_t eyes)
1015 : {
1016 64 : for (size_t i = 0; i < NUM_EYES; ++i)
1017 : {
1018 48 : const Eye eye = Eye(1 << i);
1019 48 : if (!(eyes & eye))
1020 50 : continue;
1021 :
1022 44 : ++_data.active[i];
1023 44 : if (!getChannel()) // non-dest root compound
1024 42 : continue;
1025 :
1026 4 : CompoundActivateVisitor channelActivate(true, eye);
1027 2 : accept(channelActivate);
1028 : }
1029 16 : }
1030 :
1031 16 : void Compound::deactivate(const uint32_t eyes)
1032 : {
1033 64 : for (size_t i = 0; i < NUM_EYES; ++i)
1034 : {
1035 48 : const fabric::Eye eye = static_cast<Eye>(1 << i);
1036 48 : if (!(eyes & eye))
1037 50 : continue;
1038 :
1039 44 : LBASSERT(_data.active[i]);
1040 44 : --_data.active[i];
1041 44 : if (!getChannel()) // non-dest root compound
1042 42 : continue;
1043 :
1044 4 : CompoundActivateVisitor channelDeactivate(false, eye);
1045 2 : accept(channelDeactivate);
1046 : }
1047 16 : }
1048 :
1049 14 : void Compound::init()
1050 : {
1051 28 : CompoundInitVisitor initVisitor;
1052 14 : accept(initVisitor);
1053 14 : }
1054 :
1055 14 : void Compound::exit()
1056 : {
1057 28 : CompoundExitVisitor visitor;
1058 14 : accept(visitor);
1059 14 : }
1060 :
1061 132 : void Compound::register_()
1062 : {
1063 264 : ServerPtr server = getServer();
1064 132 : const uint32_t latency = getConfig()->getLatency();
1065 :
1066 492 : for (Frames::const_iterator i = _outputFrames.begin();
1067 328 : i != _outputFrames.end(); ++i)
1068 : {
1069 32 : Frame* frame = *i;
1070 32 : server->registerObject(frame);
1071 32 : frame->setAutoObsolete(latency);
1072 32 : LBLOG(LOG_ASSEMBLY) << "Output frame \"" << frame->getName() << "\" id "
1073 32 : << frame->getID() << std::endl;
1074 : }
1075 :
1076 492 : for (Frames::const_iterator i = _inputFrames.begin();
1077 328 : i != _inputFrames.end(); ++i)
1078 : {
1079 32 : Frame* frame = *i;
1080 32 : server->registerObject(frame);
1081 32 : frame->setAutoObsolete(latency);
1082 32 : LBLOG(LOG_ASSEMBLY) << "Input frame \"" << frame->getName() << "\" id "
1083 32 : << frame->getID() << std::endl;
1084 : }
1085 :
1086 396 : for (TileQueuesCIter i = _inputTileQueues.begin();
1087 264 : i != _inputTileQueues.end(); ++i)
1088 : {
1089 0 : TileQueue* queue = *i;
1090 0 : server->registerObject(queue);
1091 0 : queue->setAutoObsolete(latency);
1092 0 : LBLOG(LOG_ASSEMBLY) << "Input queue \"" << queue->getName() << "\" id "
1093 0 : << queue->getID() << std::endl;
1094 : }
1095 :
1096 396 : for (TileQueuesCIter i = _outputTileQueues.begin();
1097 264 : i != _outputTileQueues.end(); ++i)
1098 : {
1099 0 : TileQueue* queue = *i;
1100 0 : server->registerObject(queue);
1101 0 : queue->setAutoObsolete(latency);
1102 0 : LBLOG(LOG_ASSEMBLY) << "Output queue \"" << queue->getName() << "\" id "
1103 0 : << queue->getID() << std::endl;
1104 : }
1105 132 : }
1106 :
1107 132 : void Compound::deregister()
1108 : {
1109 264 : ServerPtr server = getServer();
1110 :
1111 492 : for (Frames::const_iterator i = _outputFrames.begin();
1112 328 : i != _outputFrames.end(); ++i)
1113 : {
1114 32 : Frame* frame = *i;
1115 32 : frame->flush();
1116 32 : server->deregisterObject(frame);
1117 : }
1118 :
1119 492 : for (Frames::const_iterator i = _inputFrames.begin();
1120 328 : i != _inputFrames.end(); ++i)
1121 : {
1122 32 : Frame* frame = *i;
1123 32 : server->deregisterObject(frame);
1124 : }
1125 :
1126 396 : for (TileQueuesCIter i = _inputTileQueues.begin();
1127 264 : i != _inputTileQueues.end(); ++i)
1128 : {
1129 0 : TileQueue* queue = *i;
1130 0 : server->deregisterObject(queue);
1131 : }
1132 :
1133 396 : for (TileQueuesCIter i = _outputTileQueues.begin();
1134 264 : i != _outputTileQueues.end(); ++i)
1135 : {
1136 0 : TileQueue* queue = *i;
1137 0 : queue->flush();
1138 0 : server->deregisterObject(queue);
1139 : }
1140 132 : }
1141 :
1142 82 : void Compound::backup()
1143 : {
1144 82 : _backup = _data;
1145 :
1146 100 : for (EqualizersCIter i = _equalizers.begin(); i != _equalizers.end(); ++i)
1147 18 : (*i)->backup();
1148 82 : }
1149 :
1150 0 : void Compound::restore()
1151 : {
1152 0 : _data = _backup;
1153 :
1154 0 : for (EqualizersCIter i = _equalizers.begin(); i != _equalizers.end(); ++i)
1155 0 : (*i)->restore();
1156 0 : }
1157 :
1158 : //---------------------------------------------------------------------------
1159 : // pre-render compound state update
1160 : //---------------------------------------------------------------------------
1161 28 : void Compound::update(const uint32_t frameNumber)
1162 : {
1163 : // https://github.com/Eyescale/Equalizer/issues/76
1164 56 : CompoundUpdateActivateVisitor updateActivateVisitor(frameNumber);
1165 28 : accept(updateActivateVisitor);
1166 :
1167 56 : CompoundUpdateDataVisitor updateDataVisitor(frameNumber);
1168 28 : accept(updateDataVisitor);
1169 :
1170 56 : CompoundUpdateOutputVisitor updateOutputVisitor(frameNumber);
1171 28 : accept(updateOutputVisitor);
1172 :
1173 28 : const FrameMap& outputFrames = updateOutputVisitor.getOutputFrames();
1174 28 : const TileQueueMap& outputQueues = updateOutputVisitor.getOutputQueues();
1175 56 : CompoundUpdateInputVisitor updateInputVisitor(outputFrames, outputQueues);
1176 28 : accept(updateInputVisitor);
1177 :
1178 : // commit output frames after input frames have been set
1179 32 : for (FrameMapCIter i = outputFrames.begin(); i != outputFrames.end(); ++i)
1180 : {
1181 4 : Frame* frame = i->second;
1182 4 : frame->commit();
1183 : }
1184 :
1185 28 : const BarrierMap& swapBarriers = updateOutputVisitor.getSwapBarriers();
1186 28 : for (BarrierMapCIter i = swapBarriers.begin(); i != swapBarriers.end(); ++i)
1187 : {
1188 0 : co::Barrier* barrier = i->second;
1189 0 : LBASSERT(barrier->isGood());
1190 0 : if (barrier->getHeight() > 1)
1191 0 : barrier->commit();
1192 : }
1193 28 : }
1194 :
1195 660 : void Compound::updateInheritData(const uint32_t frameNumber)
1196 : {
1197 660 : _data.pixel.validate();
1198 660 : _data.subPixel.validate();
1199 660 : _data.zoom.validate();
1200 :
1201 660 : if (isRoot())
1202 70 : _updateInheritRoot();
1203 : else
1204 590 : _updateInheritNode();
1205 :
1206 660 : if (_inherit.channel)
1207 : {
1208 590 : _updateInheritStereo();
1209 590 : _updateInheritActive(frameNumber);
1210 : }
1211 :
1212 660 : if (_inherit.pvp.isValid())
1213 : {
1214 590 : _inherit.pvp.apply(_data.pixel);
1215 :
1216 : // Zoom
1217 590 : const PixelViewport unzoomedPVP(_inherit.pvp);
1218 590 : _inherit.pvp.apply(_data.zoom);
1219 :
1220 : // update inherit zoom to be pixel-correct with the integer-rounded pvp
1221 590 : const Zoom zoom = _inherit.pvp.getZoom(unzoomedPVP);
1222 590 : _inherit.zoom *= zoom;
1223 : }
1224 :
1225 : // Tasks
1226 660 : updateInheritTasks();
1227 :
1228 660 : const View* view = _inherit.channel ? _inherit.channel->getView() : 0;
1229 660 : const Channel* channel = getChannel();
1230 660 : if (channel && !channel->supportsView(view))
1231 0 : _inherit.tasks = fabric::TASK_NONE;
1232 :
1233 660 : if (!_inherit.pvp.hasArea() || !_inherit.range.hasData())
1234 : // Channels with no PVP or range do not execute tasks
1235 70 : _inherit.tasks = fabric::TASK_NONE;
1236 660 : }
1237 :
1238 70 : void Compound::_updateInheritRoot()
1239 : {
1240 70 : LBASSERT(!_parent);
1241 :
1242 70 : const PixelViewport oldPVP(_inherit.pvp);
1243 70 : _inherit = _data;
1244 70 : _inherit.pvp = oldPVP;
1245 :
1246 70 : _inherit.zoom = Zoom::NONE; // will be reapplied by parent method
1247 70 : _updateInheritPVP();
1248 :
1249 70 : if (_inherit.eyes == fabric::EYE_UNDEFINED)
1250 70 : _inherit.eyes = fabric::EYES_ALL;
1251 0 : else if (_inherit.channel)
1252 : {
1253 0 : const View* view = _inherit.channel->getView();
1254 0 : if (!view)
1255 0 : _inherit.eyes = EYE_CYCLOP;
1256 : }
1257 :
1258 70 : if (_inherit.period == LB_UNDEFINED_UINT32)
1259 70 : _inherit.period = 1;
1260 :
1261 70 : if (_inherit.phase == LB_UNDEFINED_UINT32)
1262 70 : _inherit.phase = 0;
1263 :
1264 70 : if (_inherit.buffers == Frame::Buffer::undefined)
1265 70 : _inherit.buffers = Frame::Buffer::color;
1266 :
1267 70 : if (_inherit.iAttributes[IATTR_STEREO_MODE] == UNDEFINED)
1268 70 : _inherit.iAttributes[IATTR_STEREO_MODE] = fabric::AUTO;
1269 :
1270 70 : if (_inherit.iAttributes[IATTR_STEREO_ANAGLYPH_LEFT_MASK] == UNDEFINED)
1271 70 : _inherit.iAttributes[IATTR_STEREO_ANAGLYPH_LEFT_MASK] = COLOR_MASK_RED;
1272 :
1273 70 : if (_inherit.iAttributes[IATTR_STEREO_ANAGLYPH_RIGHT_MASK] == UNDEFINED)
1274 70 : _inherit.iAttributes[IATTR_STEREO_ANAGLYPH_RIGHT_MASK] =
1275 : COLOR_MASK_GREEN | COLOR_MASK_BLUE;
1276 70 : }
1277 :
1278 590 : void Compound::_updateInheritNode()
1279 : {
1280 590 : LBASSERT(_parent);
1281 590 : const PixelViewport oldPVP(_inherit.pvp);
1282 590 : _inherit = _parent->_inherit;
1283 :
1284 590 : if (!_inherit.channel)
1285 : {
1286 70 : _inherit.pvp = oldPVP;
1287 70 : _updateInheritPVP();
1288 70 : _inherit.vp.apply(_data.vp);
1289 : }
1290 520 : else if (_inherit.pvp.isValid())
1291 : {
1292 520 : LBASSERT(_data.vp.isValid());
1293 520 : _inherit.pvp.apply(_data.vp);
1294 :
1295 : // Compute the inherit viewport to be pixel-correct with the integer-
1296 : // rounded pvp. This is needed to calculate the frustum correctly.
1297 520 : const Viewport vp = _inherit.pvp / _parent->_inherit.pvp;
1298 520 : _inherit.vp.apply(vp);
1299 :
1300 520 : _updateInheritOverdraw();
1301 : }
1302 : else
1303 : {
1304 0 : LBASSERT(!_inherit.channel->isRunning());
1305 : }
1306 :
1307 590 : if (_data.frustumData.isValid())
1308 70 : _inherit.frustumData = _data.frustumData;
1309 :
1310 590 : _inherit.range.apply(_data.range);
1311 590 : _inherit.pixel.apply(_data.pixel);
1312 590 : _inherit.subPixel.apply(_data.subPixel);
1313 :
1314 590 : if (_data.eyes != fabric::EYE_UNDEFINED)
1315 240 : _inherit.eyes = _data.eyes;
1316 350 : else if (_inherit.channel)
1317 : {
1318 350 : const View* view = _inherit.channel->getView();
1319 350 : if (!view)
1320 0 : _inherit.eyes = EYE_CYCLOP;
1321 : }
1322 :
1323 590 : if (_data.period != LB_UNDEFINED_UINT32)
1324 0 : _inherit.period = _data.period;
1325 :
1326 590 : if (_data.phase != LB_UNDEFINED_UINT32)
1327 0 : _inherit.phase = _data.phase;
1328 :
1329 590 : _inherit.maxFPS = _data.maxFPS;
1330 :
1331 590 : if (_data.buffers != Frame::Buffer::undefined)
1332 60 : _inherit.buffers = _data.buffers;
1333 :
1334 590 : if (_data.iAttributes[IATTR_STEREO_MODE] != UNDEFINED)
1335 0 : _inherit.iAttributes[IATTR_STEREO_MODE] =
1336 0 : _data.iAttributes[IATTR_STEREO_MODE];
1337 :
1338 590 : if (_data.iAttributes[IATTR_STEREO_ANAGLYPH_LEFT_MASK] != UNDEFINED)
1339 0 : _inherit.iAttributes[IATTR_STEREO_ANAGLYPH_LEFT_MASK] =
1340 0 : _data.iAttributes[IATTR_STEREO_ANAGLYPH_LEFT_MASK];
1341 :
1342 590 : if (_data.iAttributes[IATTR_STEREO_ANAGLYPH_RIGHT_MASK] != UNDEFINED)
1343 0 : _inherit.iAttributes[IATTR_STEREO_ANAGLYPH_RIGHT_MASK] =
1344 0 : _data.iAttributes[IATTR_STEREO_ANAGLYPH_RIGHT_MASK];
1345 590 : }
1346 :
1347 140 : void Compound::_updateInheritPVP()
1348 : {
1349 140 : Channel* channel = _data.channel;
1350 140 : if (!channel)
1351 140 : return;
1352 :
1353 70 : const PixelViewport oldPVP(_inherit.pvp);
1354 70 : _inherit.channel = channel;
1355 70 : _inherit.pvp = channel->getPixelViewport();
1356 :
1357 70 : View* view = channel->getView();
1358 70 : if (!view || !_inherit.pvp.isValid())
1359 : {
1360 0 : LBASSERT(channel->getOverdraw() == Vector4i());
1361 0 : return;
1362 : }
1363 70 : LBASSERT(channel == getChannel());
1364 :
1365 : // enlarge pvp by overdraw
1366 70 : const Vector4i& overdraw = channel->getOverdraw();
1367 70 : _inherit.pvp.w += overdraw.x() + overdraw.z();
1368 70 : _inherit.pvp.h += overdraw.y() + overdraw.w();
1369 :
1370 70 : if (oldPVP != _inherit.pvp) // channel PVP changed
1371 : {
1372 14 : view->updateFrusta();
1373 14 : LBASSERT(overdraw == channel->getOverdraw());
1374 : }
1375 :
1376 70 : _inherit.overdraw = overdraw;
1377 : }
1378 :
1379 520 : void Compound::_updateInheritOverdraw()
1380 : {
1381 520 : const PixelViewport& pvp = _inherit.pvp;
1382 520 : const PixelViewport& parentPVP = _parent->_inherit.pvp;
1383 :
1384 520 : _inherit.overdraw.x() -= pvp.x - parentPVP.x;
1385 520 : _inherit.overdraw.y() -= pvp.y - parentPVP.y;
1386 520 : _inherit.overdraw.z() -= parentPVP.getXEnd() - pvp.getXEnd();
1387 520 : _inherit.overdraw.w() -= parentPVP.getYEnd() - pvp.getYEnd();
1388 :
1389 520 : _inherit.overdraw.x() = LB_MAX(_inherit.overdraw.x(), 0);
1390 520 : _inherit.overdraw.y() = LB_MAX(_inherit.overdraw.y(), 0);
1391 520 : _inherit.overdraw.z() = LB_MAX(_inherit.overdraw.z(), 0);
1392 520 : _inherit.overdraw.w() = LB_MAX(_inherit.overdraw.w(), 0);
1393 :
1394 520 : _inherit.overdraw.x() = LB_MIN(_inherit.overdraw.x(), pvp.w);
1395 520 : _inherit.overdraw.y() = LB_MIN(_inherit.overdraw.y(), pvp.h);
1396 520 : _inherit.overdraw.z() = LB_MIN(_inherit.overdraw.z(), pvp.w);
1397 520 : _inherit.overdraw.w() = LB_MIN(_inherit.overdraw.w(), pvp.h);
1398 :
1399 520 : LBASSERTINFO(pvp.w >= _inherit.overdraw.x() + _inherit.overdraw.z(),
1400 : pvp.w << " < "
1401 : << _inherit.overdraw.x() + _inherit.overdraw.z());
1402 520 : LBASSERTINFO(pvp.h >= _inherit.overdraw.y() + _inherit.overdraw.w(),
1403 : pvp.h << " < "
1404 : << _inherit.overdraw.y() + _inherit.overdraw.w());
1405 520 : }
1406 :
1407 786 : void Compound::updateInheritTasks()
1408 : {
1409 786 : if (_data.tasks == fabric::TASK_DEFAULT)
1410 : {
1411 786 : if (isLeaf())
1412 : {
1413 304 : _inherit.tasks = fabric::TASK_ALL;
1414 : // check if a parent compound has cleared us
1415 1384 : for (Compound* compound = getParent(); compound;
1416 : compound = compound->getParent())
1417 : {
1418 1080 : Channel* channel = compound->getChannel();
1419 1080 : if (channel == getChannel())
1420 412 : _inherit.tasks &= ~fabric::TASK_CLEAR; // done already
1421 : }
1422 : }
1423 : else
1424 482 : _inherit.tasks = fabric::TASK_CLEAR | fabric::TASK_ASSEMBLE |
1425 : fabric::TASK_READBACK;
1426 : }
1427 : else
1428 0 : _inherit.tasks = _data.tasks;
1429 :
1430 786 : const Channel* channel = getChannel();
1431 786 : if (isDestination() && channel->getView())
1432 86 : _inherit.tasks |= fabric::TASK_VIEW;
1433 : else
1434 700 : _inherit.tasks &= ~fabric::TASK_VIEW;
1435 786 : }
1436 :
1437 590 : void Compound::_updateInheritStereo()
1438 : {
1439 590 : if (_inherit.iAttributes[IATTR_STEREO_MODE] != fabric::AUTO)
1440 520 : return;
1441 :
1442 70 : const Segment* segment = _inherit.channel->getSegment();
1443 70 : const uint32_t eyes = segment ? segment->getEyes() : _inherit.eyes;
1444 70 : const bool stereoEyes = (eyes & EYES_STEREO) == EYES_STEREO;
1445 70 : if (!stereoEyes)
1446 : {
1447 0 : _inherit.iAttributes[IATTR_STEREO_MODE] = fabric::PASSIVE;
1448 0 : return;
1449 : }
1450 :
1451 70 : const Window* window = _inherit.channel->getWindow();
1452 70 : const bool stereoWindow = window->getDrawableConfig().stereo;
1453 : const bool usesFBO =
1454 140 : window &&
1455 70 : window->getIAttribute(WindowSettings::IATTR_HINT_DRAWABLE) ==
1456 70 : fabric::FBO;
1457 :
1458 70 : if (stereoWindow && !usesFBO)
1459 0 : _inherit.iAttributes[IATTR_STEREO_MODE] = fabric::QUAD;
1460 : else
1461 70 : _inherit.iAttributes[IATTR_STEREO_MODE] = fabric::ANAGLYPH;
1462 : }
1463 :
1464 590 : void Compound::_updateInheritActive(const uint32_t frameNumber)
1465 : {
1466 : const bool phaseActive =
1467 590 : ((frameNumber % _inherit.period) == _inherit.phase);
1468 590 : const bool channelActive = _inherit.channel->isRunning(); // runtime failure
1469 :
1470 2360 : for (size_t i = 0; i < fabric::NUM_EYES; ++i)
1471 : {
1472 1770 : const uint32_t eye = 1 << i;
1473 1770 : const bool eyeActive = _inherit.eyes & eye;
1474 : const bool destActive =
1475 1770 : isDestination() ? _data.active[i] : _inherit.active[i];
1476 :
1477 1770 : if (destActive && eyeActive && phaseActive && channelActive)
1478 32 : _inherit.active[i] = 1;
1479 : else
1480 1738 : _inherit.active[i] = 0; // deactivate
1481 : }
1482 590 : }
1483 :
1484 2304 : std::ostream& operator<<(std::ostream& os, const Compound& compound)
1485 : {
1486 2304 : os << lunchbox::disableFlush << "compound" << std::endl;
1487 2304 : os << "{" << std::endl << lunchbox::indent;
1488 :
1489 2304 : const std::string& name = compound.getName();
1490 2304 : if (!name.empty())
1491 104 : os << "name \"" << name << "\"" << std::endl;
1492 :
1493 2304 : const Channel* channel = compound.getChannel();
1494 2304 : if (channel)
1495 : {
1496 2140 : Compound* parent = compound.getParent();
1497 2140 : if (!parent || parent->getChannel() != channel)
1498 : {
1499 1516 : const std::string& channelName = channel->getName();
1500 1516 : const Config* config = compound.getConfig();
1501 1516 : LBASSERT(config);
1502 :
1503 3032 : if (!channelName.empty() &&
1504 1516 : config->find<Channel>(channelName) == channel)
1505 : {
1506 878 : os << "channel \"" << channelName << "\"" << std::endl;
1507 : }
1508 : else
1509 : {
1510 638 : const Segment* segment = channel->getSegment();
1511 638 : const View* view = channel->getView();
1512 :
1513 638 : if (view && segment)
1514 : {
1515 638 : os << "channel ( ";
1516 :
1517 638 : const Canvas* canvas = segment->getCanvas();
1518 638 : const std::string& canvasName = canvas->getName();
1519 654 : if (!canvasName.empty() &&
1520 16 : config->find<Canvas>(canvasName) == canvas)
1521 : {
1522 16 : os << "canvas \"" << canvasName << "\" ";
1523 : }
1524 : else
1525 622 : os << canvas->getPath() << " ";
1526 :
1527 638 : const std::string& segmentName = segment->getName();
1528 638 : if (!segmentName.empty() &&
1529 0 : canvas->findSegment(segmentName) == segment)
1530 : {
1531 0 : os << "segment \"" << segmentName << "\" ";
1532 : }
1533 : else
1534 638 : os << "segment " << segment->getPath().segmentIndex
1535 638 : << " ";
1536 :
1537 638 : const Layout* layout = view->getLayout();
1538 638 : const std::string& layoutName = layout->getName();
1539 986 : if (!layoutName.empty() &&
1540 348 : config->find<Layout>(layoutName) == layout)
1541 : {
1542 348 : os << "layout \"" << layoutName << "\" ";
1543 : }
1544 : else
1545 290 : os << layout->getPath() << " ";
1546 :
1547 638 : const std::string& viewName = view->getName();
1548 640 : if (!viewName.empty() &&
1549 2 : config->find<View>(viewName) == view)
1550 : {
1551 2 : os << "view \"" << viewName << '\"';
1552 : }
1553 : else
1554 636 : os << "view " << view->getPath().viewIndex;
1555 :
1556 638 : os << " )" << std::endl;
1557 : }
1558 : else
1559 0 : os << "channel ( " << channel->getPath() << " )"
1560 0 : << std::endl;
1561 : }
1562 : }
1563 : }
1564 :
1565 2304 : const uint32_t tasks = compound.getTasks();
1566 2304 : if (tasks != fabric::TASK_DEFAULT)
1567 : {
1568 184 : os << "task [";
1569 184 : if (tasks & fabric::TASK_CLEAR)
1570 88 : os << " CLEAR";
1571 184 : if (compound.isLeaf() && (tasks & fabric::TASK_DRAW))
1572 4 : os << " DRAW";
1573 184 : if (tasks & fabric::TASK_ASSEMBLE)
1574 116 : os << " ASSEMBLE";
1575 184 : if (tasks & fabric::TASK_READBACK)
1576 72 : os << " READBACK";
1577 184 : os << " ]" << std::endl;
1578 : }
1579 :
1580 2304 : const fabric::Frame::Buffer buffers = compound.getBuffers();
1581 2304 : if (buffers != Frame::Buffer::undefined)
1582 : {
1583 118 : os << "buffers [";
1584 118 : if (buffers & Frame::Buffer::color)
1585 118 : os << " COLOR";
1586 118 : if (buffers & Frame::Buffer::depth)
1587 118 : os << " DEPTH";
1588 118 : os << " ]" << std::endl;
1589 : }
1590 :
1591 2304 : const Viewport& vp = compound.getViewport();
1592 2304 : if (vp.isValid() && vp != Viewport::FULL)
1593 140 : os << "viewport " << vp << std::endl;
1594 :
1595 2304 : const Range& range = compound.getRange();
1596 2304 : if (range.isValid() && range != Range::ALL)
1597 370 : os << range << std::endl;
1598 :
1599 2304 : const Pixel& pixel = compound.getPixel();
1600 2304 : if (pixel.isValid() && pixel != Pixel::ALL)
1601 46 : os << pixel << std::endl;
1602 :
1603 2304 : const SubPixel& subPixel = compound.getSubPixel();
1604 2304 : if (subPixel.isValid() && subPixel != SubPixel::ALL)
1605 30 : os << subPixel << std::endl;
1606 :
1607 2304 : const Zoom& zoom = compound.getZoom();
1608 2304 : if (zoom.isValid() && zoom != Zoom::NONE)
1609 2 : os << zoom << std::endl;
1610 :
1611 2304 : const uint32_t eye = compound.getEyes();
1612 2304 : if (eye)
1613 : {
1614 196 : os << "eye [ ";
1615 196 : if (eye & fabric::EYE_CYCLOP)
1616 94 : os << "CYCLOP ";
1617 196 : if (eye & fabric::EYE_LEFT)
1618 96 : os << "LEFT ";
1619 196 : if (eye & fabric::EYE_RIGHT)
1620 98 : os << "RIGHT ";
1621 196 : os << "]" << std::endl;
1622 : }
1623 :
1624 2304 : const uint32_t period = compound.getPeriod();
1625 2304 : const uint32_t phase = compound.getPhase();
1626 2304 : if (period != LB_UNDEFINED_UINT32)
1627 34 : os << "period " << period << " ";
1628 :
1629 2304 : if (phase != LB_UNDEFINED_UINT32)
1630 34 : os << "phase " << phase;
1631 :
1632 2304 : if (period != LB_UNDEFINED_UINT32 || phase != LB_UNDEFINED_UINT32)
1633 34 : os << std::endl;
1634 :
1635 : // attributes
1636 2304 : bool attrPrinted = false;
1637 :
1638 13824 : for (Compound::IAttribute i = static_cast<Compound::IAttribute>(0);
1639 13824 : i < Compound::IATTR_ALL;
1640 11520 : i = static_cast<Compound::IAttribute>(uint32_t(i) + 1))
1641 : {
1642 11520 : const int value = compound.getIAttribute(i);
1643 11520 : if (value == Global::instance()->getCompoundIAttribute(i))
1644 11506 : continue;
1645 :
1646 14 : if (!attrPrinted)
1647 : {
1648 10 : os << std::endl << "attributes" << std::endl;
1649 10 : os << "{" << std::endl << lunchbox::indent;
1650 10 : attrPrinted = true;
1651 : }
1652 :
1653 : os << (i == Compound::IATTR_STEREO_MODE
1654 : ? "stereo_mode "
1655 : : i == Compound::IATTR_STEREO_ANAGLYPH_LEFT_MASK
1656 12 : ? "stereo_anaglyph_left_mask "
1657 : : i == Compound::IATTR_STEREO_ANAGLYPH_RIGHT_MASK
1658 4 : ? "stereo_anaglyph_right_mask "
1659 22 : : "ERROR ");
1660 :
1661 14 : switch (i)
1662 : {
1663 : case Compound::IATTR_STEREO_MODE:
1664 6 : os << static_cast<fabric::IAttribute>(value) << std::endl;
1665 6 : break;
1666 :
1667 : case Compound::IATTR_STEREO_ANAGLYPH_LEFT_MASK:
1668 : case Compound::IATTR_STEREO_ANAGLYPH_RIGHT_MASK:
1669 8 : os << ColorMask(value) << std::endl;
1670 8 : break;
1671 :
1672 : default:
1673 0 : LBASSERTINFO(0, "unimplemented");
1674 : }
1675 : }
1676 :
1677 2304 : if (attrPrinted)
1678 10 : os << lunchbox::exdent << "}" << std::endl << std::endl;
1679 :
1680 2304 : switch (compound.getFrustumType())
1681 : {
1682 : case Frustum::TYPE_WALL:
1683 28 : os << compound.getWall() << std::endl;
1684 28 : break;
1685 : case Frustum::TYPE_PROJECTION:
1686 0 : os << compound.getProjection() << std::endl;
1687 0 : break;
1688 : default:
1689 2276 : break;
1690 : }
1691 :
1692 2304 : const Equalizers& equalizers = compound.getEqualizers();
1693 2478 : for (EqualizersCIter i = equalizers.begin(); i != equalizers.end(); ++i)
1694 174 : os << *i;
1695 :
1696 2304 : const TileQueues& outputQueues = compound.getOutputTileQueues();
1697 2304 : for (TileQueuesCIter i = outputQueues.begin(); i != outputQueues.end(); ++i)
1698 0 : os << "output" << *i;
1699 :
1700 2304 : const TileQueues& inputQueues = compound.getInputTileQueues();
1701 2304 : for (TileQueuesCIter i = inputQueues.begin(); i != inputQueues.end(); ++i)
1702 0 : os << "input" << *i;
1703 :
1704 2304 : if (compound.getSwapBarrier())
1705 232 : os << *compound.getSwapBarrier();
1706 :
1707 2304 : const Compounds& children = compound.getChildren();
1708 2304 : if (!children.empty())
1709 : {
1710 752 : os << std::endl;
1711 2700 : for (CompoundsCIter i = children.begin(); i != children.end(); ++i)
1712 1948 : os << **i;
1713 : }
1714 :
1715 2304 : const Frames& inputFrames = compound.getInputFrames();
1716 3756 : for (FramesCIter i = inputFrames.begin(); i != inputFrames.end(); ++i)
1717 1452 : os << "input" << **i << std::endl;
1718 :
1719 2304 : const Frames& outputFrames = compound.getOutputFrames();
1720 3722 : for (FramesCIter i = outputFrames.begin(); i != outputFrames.end(); ++i)
1721 1418 : os << "output" << **i << std::endl;
1722 :
1723 2304 : return os << lunchbox::exdent << "}" << std::endl << lunchbox::enableFlush;
1724 : }
1725 : }
1726 60 : }
|