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