Line data Source code
1 :
2 : /* Copyright (c) 2009-2013, Stefan Eilemann <eile@equalizergraphics.com>
3 : *
4 : * This library is free software; you can redistribute it and/or modify it under
5 : * the terms of the GNU Lesser General Public License version 2.1 as published
6 : * by the Free Software Foundation.
7 : *
8 : * This library is distributed in the hope that it will be useful, but WITHOUT
9 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
11 : * details.
12 : *
13 : * You should have received a copy of the GNU Lesser General Public License
14 : * along with this library; if not, write to the Free Software Foundation, Inc.,
15 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 : */
17 :
18 : #include "viewEqualizer.h"
19 :
20 : #include "../compound.h"
21 : #include "../compoundVisitor.h"
22 : #include "../config.h"
23 : #include "../log.h"
24 : #include "../pipe.h"
25 :
26 : #include <eq/client/statistic.h>
27 :
28 : #include <set>
29 :
30 : #define MIN_USAGE .1f // 10%
31 :
32 : namespace eq
33 : {
34 : namespace server
35 : {
36 :
37 16 : ViewEqualizer::ViewEqualizer()
38 16 : : _nPipes( 0 )
39 : {
40 16 : LBINFO << "New view equalizer @" << (void*)this << std::endl;
41 16 : }
42 :
43 0 : ViewEqualizer::ViewEqualizer( const ViewEqualizer& from )
44 : : Equalizer( from )
45 0 : , _nPipes( 0 )
46 0 : {}
47 :
48 48 : ViewEqualizer::~ViewEqualizer()
49 : {
50 16 : attach( 0 );
51 16 : LBINFO << "Delete view equalizer @" << (void*)this << std::endl;
52 32 : }
53 :
54 0 : ViewEqualizer::Listener::Listener()
55 : {
56 0 : }
57 :
58 0 : ViewEqualizer::Listener::~Listener()
59 : {
60 0 : }
61 :
62 48 : void ViewEqualizer::attach( Compound* compound )
63 : {
64 48 : for( Listeners::iterator i =_listeners.begin(); i != _listeners.end(); ++i )
65 0 : (*i).clear();
66 :
67 48 : _listeners.clear();
68 48 : Equalizer::attach( compound );
69 48 : }
70 :
71 0 : void ViewEqualizer::notifyUpdatePre( Compound* compound LB_UNUSED,
72 : const uint32_t frameNumber )
73 : {
74 0 : LBASSERT( compound == getCompound( ));
75 :
76 0 : _updateListeners();
77 0 : _updateResources();
78 0 : _update( frameNumber );
79 0 : }
80 :
81 : namespace
82 : {
83 0 : class SelfAssigner : public CompoundVisitor
84 : {
85 : public:
86 0 : SelfAssigner( const Pipe* self, float& nResources,
87 : lunchbox::PtrHash< Pipe*, float >& pipeUsage )
88 : : _self( self ), _nResources( nResources ), _pipeUsage( pipeUsage )
89 0 : , _numChannels( 0 ) {}
90 :
91 0 : virtual VisitorResult visitLeaf( Compound* compound )
92 : {
93 0 : if( !compound->isActive( ))
94 0 : return TRAVERSE_CONTINUE;
95 :
96 0 : Pipe* pipe = compound->getPipe();
97 0 : LBASSERT( pipe );
98 :
99 0 : if( pipe != _self )
100 0 : return TRAVERSE_CONTINUE;
101 :
102 0 : if( _pipeUsage.find( pipe ) == _pipeUsage.end( ))
103 0 : _pipeUsage[ pipe ] = 0.0f;
104 :
105 0 : float& pipeUsage = _pipeUsage[ pipe ];
106 0 : if( pipeUsage >= 1.0f )
107 : {
108 0 : compound->setUsage( 0.f );
109 0 : return TRAVERSE_TERMINATE;
110 : }
111 :
112 0 : if( pipeUsage > 0.0f ) // pipe already partly used
113 : {
114 0 : LBASSERT( pipeUsage < 1.0f );
115 :
116 0 : float use = 1.0f - pipeUsage;
117 0 : use = LB_MAX( use, MIN_USAGE );
118 :
119 0 : compound->setUsage( use );
120 0 : _nResources -= use;
121 0 : pipeUsage = 1.0f; // Don't use more than twice
122 0 : LBLOG( LOG_LB1 ) << " Use "
123 0 : << static_cast< unsigned >( use * 100.f + .5f )
124 0 : << "% of " << pipe->getName() << " task "
125 0 : << compound->getTaskID() << ", "
126 0 : << _nResources * 100.f << "% left" << std::endl;
127 : }
128 : else
129 : {
130 0 : LBASSERT( pipeUsage == 0.0f );
131 :
132 0 : float use = LB_MIN( 1.0f, _nResources );
133 :
134 0 : compound->setUsage( use );
135 0 : _nResources -= use;
136 0 : pipeUsage = use;
137 0 : LBLOG( LOG_LB1 ) << " Use "
138 0 : << static_cast< unsigned >( use * 100.f + .5f )
139 0 : << "% of " << pipe->getName() << " task "
140 0 : << compound->getTaskID() << ", "
141 0 : << _nResources * 100.f << "% left" << std::endl;
142 : }
143 0 : ++_numChannels;
144 :
145 0 : return TRAVERSE_TERMINATE;
146 : }
147 :
148 0 : uint32_t getNumChannels() const { return _numChannels; }
149 :
150 : private:
151 : const Pipe* const _self;
152 : float& _nResources;
153 : lunchbox::PtrHash< Pipe*, float >& _pipeUsage;
154 : uint32_t _numChannels;
155 : };
156 :
157 0 : class PreviousAssigner : public CompoundVisitor
158 : {
159 : public:
160 0 : PreviousAssigner( const Pipe* self, float& nResources,
161 : lunchbox::PtrHash< Pipe*, float >& pipeUsage )
162 : : _self( self ), _nResources( nResources ), _pipeUsage( pipeUsage )
163 0 : , _numChannels( 0 ) {}
164 :
165 0 : virtual VisitorResult visitLeaf( Compound* compound )
166 : {
167 0 : if( !compound->isActive( ))
168 0 : return TRAVERSE_CONTINUE;
169 :
170 0 : Pipe* pipe = compound->getPipe();
171 0 : LBASSERT( pipe );
172 :
173 0 : if( compound->getUsage() == 0.0f || // not previously used
174 0 : pipe == _self) // already assigned above
175 : {
176 0 : return TRAVERSE_CONTINUE;
177 : }
178 :
179 0 : compound->setUsage( 0.0f ); // reset to unused
180 0 : if( _nResources <= MIN_USAGE ) // done
181 0 : return TRAVERSE_CONTINUE;
182 :
183 0 : if( _pipeUsage.find( pipe ) == _pipeUsage.end( ))
184 0 : _pipeUsage[ pipe ] = 0.0f;
185 :
186 0 : float& pipeUsage = _pipeUsage[ pipe ];
187 0 : if( pipeUsage > 0.0f ) // pipe already partly used
188 0 : return TRAVERSE_CONTINUE;
189 :
190 0 : float use = LB_MIN( 1.0f, _nResources );
191 0 : if( use + MIN_USAGE > 1.0f )
192 0 : use = 1.0f;
193 :
194 0 : pipeUsage = use;
195 0 : compound->setUsage( use );
196 0 : _nResources -= use;
197 0 : ++_numChannels;
198 :
199 0 : LBLOG( LOG_LB1 ) << " Use "
200 0 : << static_cast< unsigned >( use * 100.f + .5f )
201 0 : << "% of " << pipe->getName() << " task "
202 0 : << compound->getTaskID() << ", "
203 0 : << _nResources * 100.f << "% left" << std::endl;
204 0 : return TRAVERSE_CONTINUE;
205 : }
206 :
207 0 : uint32_t getNumChannels() const { return _numChannels; }
208 :
209 : private:
210 : const Pipe* const _self;
211 : float& _nResources;
212 : lunchbox::PtrHash< Pipe*, float >& _pipeUsage;
213 : uint32_t _numChannels;
214 : };
215 :
216 0 : class NewAssigner : public CompoundVisitor
217 : {
218 : public:
219 0 : NewAssigner( float& nResources,
220 : lunchbox::PtrHash< Pipe*, float >& pipeUsage )
221 : : _nResources( nResources ), _pipeUsage( pipeUsage )
222 : , _numChannels( 0 )
223 0 : , _fallback( 0 ) {}
224 :
225 0 : virtual VisitorResult visitLeaf( Compound* compound )
226 : {
227 0 : if( !compound->isActive( ))
228 0 : return TRAVERSE_CONTINUE;
229 :
230 0 : if( !_fallback )
231 0 : _fallback = compound;
232 :
233 0 : if( compound->getUsage() != 0.0f ) // already used
234 0 : return TRAVERSE_CONTINUE;
235 :
236 0 : Pipe* pipe = compound->getPipe();
237 0 : LBASSERT( pipe );
238 :
239 0 : if( _pipeUsage.find( pipe ) == _pipeUsage.end( ))
240 0 : _pipeUsage[ pipe ] = 0.0f;
241 :
242 0 : float& pipeUsage = _pipeUsage[ pipe ];
243 0 : if( pipeUsage >= 1.0f )
244 0 : return TRAVERSE_CONTINUE;
245 :
246 0 : if( pipeUsage > 0.0f ) // pipe already partly used
247 : {
248 0 : LBASSERT( pipeUsage < 1.0f );
249 :
250 0 : float use = 1.0f - pipeUsage;
251 0 : use = LB_MAX( use, MIN_USAGE );
252 :
253 0 : compound->setUsage( use );
254 0 : _nResources -= use;
255 0 : pipeUsage = 1.0f; // Don't use more than twice
256 0 : LBLOG( LOG_LB1 ) << " Use "
257 0 : << static_cast< unsigned >( use * 100.f + .5f )
258 0 : << "% of " << pipe->getName() << " task "
259 0 : << compound->getTaskID() << ", "
260 0 : << _nResources * 100.f << "% left" << std::endl;
261 : }
262 : else
263 : {
264 0 : LBASSERT( pipeUsage == 0.0f );
265 :
266 0 : float use = LB_MIN( 1.0f, _nResources );
267 :
268 0 : compound->setUsage( use );
269 0 : _nResources -= use;
270 0 : pipeUsage = use;
271 0 : LBLOG( LOG_LB1 ) << " Use "
272 0 : << static_cast< unsigned >( use * 100.f + .5f )
273 0 : << "% of " << pipe->getName() << " task "
274 0 : << compound->getTaskID() << ", "
275 0 : << _nResources * 100.f << "% left" << std::endl;
276 : }
277 0 : ++_numChannels;
278 :
279 0 : if( _nResources <= MIN_USAGE )
280 0 : return TRAVERSE_TERMINATE; // done
281 0 : return TRAVERSE_CONTINUE;
282 : }
283 :
284 0 : uint32_t getNumChannels() const { return _numChannels; }
285 0 : Compound* getFallback() { return _fallback; }
286 :
287 : private:
288 : float& _nResources;
289 : lunchbox::PtrHash< Pipe*, float >& _pipeUsage;
290 : uint32_t _numChannels;
291 : Compound* _fallback;
292 : };
293 :
294 : }
295 :
296 0 : void ViewEqualizer::_update( const uint32_t frameNumber )
297 : {
298 0 : const uint32_t frame = _findInputFrameNumber();
299 0 : LBLOG( LOG_LB1 ) << "Using data from frame " << frame << std::endl;
300 :
301 : //----- Gather data for frame
302 0 : Loads loads;
303 0 : int64_t totalTime( 0 );
304 :
305 0 : for( Listeners::iterator i =_listeners.begin(); i != _listeners.end(); ++i )
306 : {
307 0 : Listener& listener = *i;
308 0 : const Listener::Load& load = listener.useLoad( frame );
309 :
310 0 : totalTime += load.time;
311 0 : loads.push_back( load );
312 : }
313 :
314 0 : const Compound* compound = getCompound();
315 :
316 0 : if( isFrozen() || !compound->isActive() || _nPipes == 0 )
317 : // always execute code above to not leak memory
318 0 : return;
319 :
320 0 : if( totalTime == 0 ) // no data
321 0 : totalTime = 1;
322 :
323 0 : const float resourceTime( static_cast< float >( totalTime ) /
324 0 : static_cast< float >( _nPipes ));
325 0 : LBLOG( LOG_LB1 ) << resourceTime << "ms/resource" << std::endl;
326 :
327 : //----- Assign new resource usage
328 0 : const Compounds& children = compound->getChildren();
329 0 : const size_t size( _listeners.size( ));
330 0 : LBASSERT( children.size() == size );
331 0 : lunchbox::PtrHash< Pipe*, float > pipeUsage;
332 0 : float* leftOvers = static_cast< float* >( alloca( size * sizeof( float )));
333 :
334 : // use self
335 0 : for( size_t i = 0; i < size; ++i )
336 : {
337 0 : Listener::Load& load = loads[ i ];
338 0 : LBASSERT( load.missing == 0 );
339 :
340 0 : Compound* child = children[ i ];
341 0 : if( !child->isActive( ))
342 0 : continue;
343 :
344 0 : float segmentResources( load.time / resourceTime );
345 :
346 0 : LBLOG( LOG_LB1 ) << "----- balance step 1 for view " << i << " ("
347 0 : << child->getChannel()->getName() << " "
348 0 : << child->getChannel()->getSerial() << ") using "
349 0 : << segmentResources << " resources" << std::endl;
350 0 : SelfAssigner assigner( child->getPipe(), segmentResources, pipeUsage );
351 :
352 0 : child->accept( assigner );
353 0 : load.missing = assigner.getNumChannels();
354 0 : leftOvers[ i ] = segmentResources;
355 0 : }
356 :
357 : // use previous' frames resources
358 0 : for( size_t i = 0; i < size; ++i )
359 : {
360 0 : Listener::Load& load = loads[ i ];
361 0 : Compound* child = children[ i ];
362 0 : if( !child->isActive( ))
363 0 : continue;
364 :
365 0 : float& leftOver = leftOvers[i];
366 0 : LBLOG( LOG_LB1 ) << "----- balance step 2 for view " << i << " ("
367 0 : << child->getChannel()->getName() << " "
368 0 : << child->getChannel()->getSerial() << ") using "
369 0 : << leftOver << " resources" << std::endl;
370 0 : PreviousAssigner assigner( child->getPipe(), leftOver, pipeUsage );
371 :
372 0 : child->accept( assigner );
373 0 : load.missing += assigner.getNumChannels();
374 0 : }
375 :
376 : // satisfy left-overs
377 0 : for( size_t i = 0; i < size; ++i )
378 : {
379 0 : Listener& listener = _listeners[ i ];
380 0 : LBASSERTINFO( listener.getNLoads() <= getConfig()->getLatency() + 3,
381 : listener );
382 :
383 0 : float& leftOver = leftOvers[i];
384 0 : Listener::Load& load = loads[ i ];
385 0 : Compound* child = children[ i ];
386 :
387 0 : if( !child->isActive( ))
388 0 : continue;
389 :
390 0 : if( leftOver > MIN_USAGE || load.missing == 0 )
391 : {
392 0 : LBLOG( LOG_LB1 ) << "----- balance step 3 for view " << i << " ("
393 0 : << child->getChannel()->getName() << ") using "
394 0 : << leftOver << " resources" << std::endl;
395 :
396 0 : NewAssigner assigner( leftOver, pipeUsage );
397 0 : child->accept( assigner );
398 0 : load.missing += assigner.getNumChannels();
399 :
400 0 : if( load.missing == 0 ) // assign at least one resource
401 : {
402 0 : Compound* fallback = assigner.getFallback();
403 0 : LBASSERT( fallback );
404 0 : LBASSERT( leftOver > 0 );
405 :
406 0 : fallback->setUsage( leftOver );
407 0 : load.missing = 1;
408 0 : LBLOG( LOG_LB1 ) << " Use "
409 0 : << static_cast< unsigned >( leftOver*100.f+.5f )
410 0 : << "% of " << fallback->getPipe()->getName()
411 0 : << " task " << fallback->getTaskID()
412 0 : << std::endl;
413 0 : }
414 : }
415 :
416 0 : listener.newLoad( frameNumber, load.missing );
417 0 : }
418 : }
419 :
420 0 : uint32_t ViewEqualizer::_findInputFrameNumber() const
421 : {
422 0 : LBASSERT( !_listeners.empty( ));
423 :
424 0 : uint32_t frame = std::numeric_limits< uint32_t >::max();
425 0 : const Compound* compound = getCompound();
426 0 : const Compounds& children = compound->getChildren();
427 0 : const size_t nChildren = children.size();
428 0 : LBASSERT( nChildren == _listeners.size( ));
429 :
430 0 : bool change = true;
431 0 : while( change )
432 : {
433 0 : change = false;
434 0 : for( size_t i = 0; i < nChildren; ++i )
435 : {
436 0 : const Compound* child = children[ i ];
437 0 : if( !child->isActive( ))
438 0 : continue;
439 :
440 0 : const Listener& listener = _listeners[ i ];
441 0 : const uint32_t youngest = listener.findYoungestLoad( frame );
442 0 : if( frame > youngest )
443 : {
444 0 : change = true;
445 0 : frame = youngest;
446 : }
447 : }
448 : }
449 :
450 0 : return frame;
451 : }
452 :
453 :
454 0 : void ViewEqualizer::_updateListeners()
455 : {
456 0 : if( !_listeners.empty( ))
457 : {
458 0 : LBASSERT( getCompound()->getChildren().size() == _listeners.size( ));
459 0 : return;
460 : }
461 :
462 0 : Compound* compound = getCompound();
463 0 : const Compounds& children = compound->getChildren();
464 0 : const size_t nChildren = children.size();
465 :
466 0 : _listeners.resize( nChildren );
467 0 : for( size_t i = 0; i < nChildren; ++i )
468 : {
469 0 : LBLOG( LOG_LB1 ) << lunchbox::disableFlush << "Tasks for view " << i
470 0 : << ": ";
471 0 : Listener& listener = _listeners[ i ];
472 0 : listener.update( children[i] );
473 0 : LBLOG(LOG_LB1) << std::endl << lunchbox::enableFlush;
474 : }
475 : }
476 :
477 : namespace
478 : {
479 0 : class PipeCounter : public CompoundVisitor
480 : {
481 : public:
482 0 : virtual VisitorResult visitPre( const Compound* compound )
483 0 : { return compound->isActive() ? TRAVERSE_CONTINUE : TRAVERSE_PRUNE; }
484 :
485 0 : virtual VisitorResult visitLeaf( const Compound* compound )
486 : {
487 0 : if( !compound->isActive( ))
488 0 : return TRAVERSE_PRUNE;
489 :
490 0 : const Pipe* pipe = compound->getPipe();
491 0 : LBASSERT( pipe );
492 0 : _pipes.insert( pipe );
493 0 : return TRAVERSE_CONTINUE;
494 : }
495 :
496 0 : size_t getNPipes() const { return _pipes.size(); }
497 :
498 : private:
499 : std::set< const Pipe* > _pipes;
500 : };
501 : }
502 :
503 0 : void ViewEqualizer::_updateResources()
504 : {
505 0 : PipeCounter counter;
506 0 : const Compound* compound = getCompound();
507 0 : compound->accept( counter );
508 0 : _nPipes = counter.getNPipes();
509 0 : }
510 :
511 : //---------------------------------------------------------------------------
512 : // Per-child listener implementation
513 : //---------------------------------------------------------------------------
514 : namespace
515 : {
516 0 : class LoadSubscriber : public CompoundVisitor
517 : {
518 : public:
519 0 : LoadSubscriber( ChannelListener* listener,
520 : lunchbox::PtrHash< Channel*, uint32_t >& taskIDs )
521 : : _listener( listener )
522 0 : , _taskIDs( taskIDs ) {}
523 :
524 0 : virtual VisitorResult visitLeaf( Compound* compound )
525 : {
526 0 : Channel* channel = compound->getChannel();
527 0 : LBASSERT( channel );
528 :
529 0 : if( _taskIDs.find( channel ) == _taskIDs.end( ))
530 : {
531 0 : channel->addListener( _listener );
532 0 : _taskIDs[ channel ] = compound->getTaskID();
533 0 : LBLOG( LOG_LB1 ) << _taskIDs[ channel ] << ' ';
534 : }
535 : else
536 : {
537 0 : LBASSERTINFO( 0,
538 : "View equalizer does not support using channel "<<
539 : channel->getName() <<
540 : " multiple times in one branch" );
541 : }
542 0 : return TRAVERSE_CONTINUE;
543 : }
544 :
545 : private:
546 : ChannelListener* const _listener;
547 : lunchbox::PtrHash< Channel*, uint32_t >& _taskIDs;
548 : };
549 : }
550 :
551 0 : void ViewEqualizer::Listener::update( Compound* compound )
552 : {
553 0 : LBASSERT( _taskIDs.empty( ));
554 0 : LoadSubscriber subscriber( this, _taskIDs );
555 0 : compound->accept( subscriber );
556 0 : }
557 :
558 0 : void ViewEqualizer::Listener::clear()
559 : {
560 0 : for( TaskIDHash::const_iterator i = _taskIDs.begin();
561 0 : i != _taskIDs.end(); ++i )
562 : {
563 0 : i->first->removeListener( this );
564 : }
565 0 : _taskIDs.clear();
566 0 : }
567 :
568 9 : ViewEqualizer::Listener::Load ViewEqualizer::Listener::Load::NONE( 0, 0, 1 );
569 9 : ViewEqualizer::Listener::Load::Load( const uint32_t frame_,
570 : const uint32_t missing_,
571 : const int64_t time_ )
572 : : frame( frame_ ), missing( missing_ ), nResources( missing_ )
573 9 : , time( time_ ) {}
574 :
575 0 : bool ViewEqualizer::Listener::Load::operator == ( const Load& rhs ) const
576 : {
577 0 : return ( frame == rhs.frame && missing == rhs.missing && time == rhs.time );
578 : }
579 :
580 0 : void ViewEqualizer::Listener::notifyLoadData( Channel* channel,
581 : const uint32_t frameNumber,
582 : const Statistics& statistics,
583 : const Viewport& /*region*/ )
584 : {
585 0 : Load& load = _getLoad( frameNumber );
586 0 : if( load == Load::NONE )
587 0 : return;
588 :
589 0 : LBASSERT( _taskIDs.find( channel ) != _taskIDs.end( ));
590 0 : const uint32_t taskID = _taskIDs[ channel ];
591 :
592 : // gather relevant load data
593 0 : int64_t startTime = std::numeric_limits< int64_t >::max();
594 0 : int64_t endTime = 0;
595 0 : bool loadSet = false;
596 0 : int64_t transmitTime = 0;
597 0 : for( size_t i = 0; i < statistics.size() && !loadSet; ++i )
598 : {
599 0 : const eq::Statistic& data = statistics[i];
600 0 : if( data.task != taskID ) // data from another compound
601 0 : continue;
602 :
603 0 : switch( data.type )
604 : {
605 : case eq::Statistic::CHANNEL_CLEAR:
606 : case eq::Statistic::CHANNEL_DRAW:
607 : case eq::Statistic::CHANNEL_READBACK:
608 0 : startTime = LB_MIN( startTime, data.startTime );
609 0 : endTime = LB_MAX( endTime, data.endTime );
610 0 : break;
611 :
612 : case Statistic::CHANNEL_ASYNC_READBACK:
613 : case Statistic::CHANNEL_FRAME_TRANSMIT:
614 0 : transmitTime += data.startTime - data.endTime;
615 0 : break;
616 : case Statistic::CHANNEL_FRAME_WAIT_SENDTOKEN:
617 0 : transmitTime -= data.endTime - data.startTime;
618 0 : break;
619 :
620 : // assemble blocks on input frames, stop using subsequent data
621 : case eq::Statistic::CHANNEL_ASSEMBLE:
622 0 : loadSet = true;
623 0 : break;
624 :
625 : default:
626 0 : break;
627 : }
628 : }
629 :
630 0 : if( startTime == std::numeric_limits< int64_t >::max( ))
631 0 : return;
632 :
633 0 : LBASSERTINFO( load.missing > 0, load << " for " << channel->getName() <<
634 : " " << channel->getSerial( ));
635 :
636 0 : const int64_t time = LB_MAX(endTime - startTime, transmitTime );
637 0 : load.time += time;
638 0 : --load.missing;
639 :
640 0 : if( load.missing == 0 )
641 : {
642 0 : const float rTime = float( load.time ) / float( load.nResources );
643 0 : load.time = int64_t( rTime * sqrtf( float( load.nResources )));
644 : }
645 :
646 0 : LBLOG( LOG_LB1 ) << "Task " << taskID << ", added time " << time << " to "
647 0 : << load << " from " << channel->getName() << " "
648 0 : << channel->getSerial() << std::endl;
649 : }
650 :
651 0 : uint32_t ViewEqualizer::Listener::findYoungestLoad( const uint32_t frame ) const
652 : {
653 :
654 0 : for( LoadDeque::const_iterator i = _loads.begin(); i != _loads.end(); ++i )
655 : {
656 0 : const Load& load = *i;
657 0 : if( load.missing == 0 && load.frame <= frame )
658 0 : return load.frame;
659 : }
660 0 : return 0;
661 : }
662 :
663 : const ViewEqualizer::Listener::Load&
664 0 : ViewEqualizer::Listener::useLoad( const uint32_t frame )
665 : {
666 0 : for( LoadDeque::iterator i = _loads.begin(); i != _loads.end(); ++i )
667 : {
668 0 : Load& load = *i;
669 0 : if( load.frame == frame )
670 : {
671 0 : LBASSERT( load.missing == 0 );
672 0 : if( load.time == 0 )
673 0 : load.time = 1;
674 :
675 0 : ++i;
676 0 : _loads.erase( i, _loads.end( ));
677 0 : return load;
678 : }
679 : }
680 :
681 0 : return Load::NONE;
682 : }
683 :
684 : ViewEqualizer::Listener::Load&
685 0 : ViewEqualizer::Listener::_getLoad( const uint32_t frame )
686 : {
687 0 : for( LoadDeque::iterator i = _loads.begin(); i != _loads.end(); ++i )
688 : {
689 0 : const Load& load = *i;
690 0 : if( load.frame == frame )
691 0 : return *i;
692 : }
693 :
694 0 : return Load::NONE;
695 : }
696 :
697 0 : void ViewEqualizer::Listener::newLoad( const uint32_t frameNumber,
698 : const uint32_t nChannels )
699 : {
700 0 : LBASSERT( nChannels > 0 );
701 0 : _loads.push_front( Load( frameNumber, nChannels, 0 ));
702 0 : }
703 :
704 8 : std::ostream& operator << ( std::ostream& os, const ViewEqualizer* equalizer )
705 : {
706 8 : if( equalizer )
707 8 : os << "view_equalizer {}" << std::endl;
708 8 : return os;
709 : }
710 :
711 0 : std::ostream& operator << ( std::ostream& os,
712 : const ViewEqualizer::Listener& listener )
713 : {
714 0 : os << lunchbox::disableFlush << "Listener" << std::endl
715 0 : << lunchbox::indent;
716 0 : for( ViewEqualizer::Listener::LoadDeque::const_iterator i =
717 0 : listener._loads.begin(); i != listener._loads.end(); ++i )
718 : {
719 0 : os << *i << std::endl;
720 : }
721 0 : os << lunchbox::exdent << lunchbox::enableFlush;
722 0 : return os;
723 : }
724 :
725 0 : std::ostream& operator << ( std::ostream& os,
726 : const ViewEqualizer::Listener::Load& load )
727 : {
728 0 : os << "frame " << load.frame << " missing " << load.missing << " t "
729 0 : << load.time;
730 0 : return os;
731 : }
732 :
733 : }
734 27 : }
|