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