Line data Source code
1 :
2 : /* Copyright (c) 2005-2013, Stefan Eilemann <eile@equalizergraphics.com>
3 : * 2011, Daniel Nachbaur <danielnachbaur@gmail.com>
4 : * 2013, Julio Delgado Mangas <julio.delgadomangas@epfl.ch>
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 :
21 : #include "channel.h"
22 :
23 : #include "channelListener.h"
24 : #include "channelUpdateVisitor.h"
25 : #include "compound.h"
26 : #include "compoundVisitor.h"
27 : #include "configVisitor.h"
28 : #include "config.h"
29 : #include "global.h"
30 : #include "log.h"
31 : #include "node.h"
32 : #include "segment.h"
33 : #include "view.h"
34 : #include "window.h"
35 :
36 : #include <eq/client/log.h>
37 : #include <eq/client/statistic.h>
38 :
39 : #include <eq/fabric/commands.h>
40 : #include <eq/fabric/paths.h>
41 :
42 : #include <co/objectICommand.h>
43 :
44 : #include <lunchbox/debug.h>
45 :
46 : #include <set>
47 :
48 : namespace eq
49 : {
50 : namespace server
51 : {
52 : typedef co::CommandFunc<Channel> CmdFunc;
53 : typedef fabric::Channel< Window, Channel > Super;
54 :
55 : namespace
56 : {
57 : typedef std::set< View* > ViewSet;
58 :
59 : class ViewFinder : public ConfigVisitor
60 : {
61 : public:
62 0 : ViewFinder( const Channel* channel ) : _channel( channel ) {}
63 0 : virtual ~ViewFinder(){}
64 :
65 0 : virtual VisitorResult visit( Compound* compound )
66 : {
67 0 : Channel* channel = compound->getChannel();
68 0 : if( channel != _channel )
69 0 : return TRAVERSE_CONTINUE;
70 :
71 0 : channel = compound->getInheritChannel();
72 0 : if ( channel->getView( ))
73 0 : _viewSet.insert( channel->getView( ));
74 0 : return TRAVERSE_CONTINUE;
75 : }
76 :
77 0 : ViewSet& getViews() { return _viewSet; }
78 :
79 : private:
80 : const Channel* _channel;
81 : ViewSet _viewSet;
82 : };
83 : }
84 :
85 836 : Channel::Channel( Window* parent )
86 : : Super( parent )
87 : , _active( 0 )
88 : , _view( 0 )
89 : , _segment( 0 )
90 : , _state( STATE_STOPPED )
91 836 : , _lastDrawCompound( 0 )
92 : {
93 836 : const Global* global = Global::instance();
94 6688 : for( unsigned i = 0; i < IATTR_ALL; ++i )
95 : {
96 5852 : const IAttribute attr = static_cast< IAttribute >( i );
97 5852 : setIAttribute( attr, global->getChannelIAttribute( attr ));
98 : }
99 5852 : for( unsigned i = 0; i < SATTR_ALL; ++i )
100 : {
101 5016 : const SAttribute attr = static_cast< SAttribute >( i );
102 5016 : setSAttribute( attr, global->getChannelSAttribute( attr ));
103 : }
104 836 : }
105 :
106 636 : Channel::Channel( const Channel& from )
107 : : Super( from )
108 : , _active( 0 )
109 : , _view( 0 )
110 : , _segment( 0 )
111 : , _state( STATE_STOPPED )
112 636 : , _lastDrawCompound( 0 )
113 : {
114 : // Don't copy view and segment. Will be re-set by segment copy ctor
115 636 : }
116 :
117 86 : void Channel::attach( const uint128_t& id, const uint32_t instanceID )
118 : {
119 86 : Super::attach( id, instanceID );
120 :
121 86 : co::CommandQueue* mainQ = getMainThreadQueue();
122 86 : co::CommandQueue* cmdQ = getCommandThreadQueue();
123 :
124 : registerCommand( fabric::CMD_CHANNEL_CONFIG_INIT_REPLY,
125 86 : CmdFunc( this, &Channel::_cmdConfigInitReply ), cmdQ );
126 : registerCommand( fabric::CMD_CHANNEL_CONFIG_EXIT_REPLY,
127 86 : CmdFunc( this, &Channel::_cmdConfigExitReply ), cmdQ );
128 : registerCommand( fabric::CMD_CHANNEL_FRAME_FINISH_REPLY,
129 86 : CmdFunc( this, &Channel::_cmdFrameFinishReply ), mainQ );
130 86 : }
131 :
132 2940 : Channel::~Channel()
133 : {
134 2940 : }
135 :
136 0 : void Channel::postDelete()
137 : {
138 : // Deregister server-queue command handler to avoid assertion in
139 : // command invokation after channel deletion
140 : registerCommand( fabric::CMD_CHANNEL_FRAME_FINISH_REPLY,
141 0 : CmdFunc( this, &Channel::_cmdNop ), 0 );
142 0 : }
143 :
144 349 : Config* Channel::getConfig()
145 : {
146 349 : Window* window = getWindow();
147 349 : LBASSERT( window );
148 349 : return window ? window->getConfig() : 0;
149 : }
150 :
151 7 : const Config* Channel::getConfig() const
152 : {
153 7 : const Window* window = getWindow();
154 7 : LBASSERT( window );
155 7 : return window ? window->getConfig() : 0;
156 : }
157 :
158 97 : Node* Channel::getNode()
159 : {
160 97 : Window* window = getWindow();
161 97 : LBASSERT( window );
162 97 : return window ? window->getNode() : 0;
163 : }
164 :
165 0 : const Node* Channel::getNode() const
166 : {
167 0 : const Window* window = getWindow();
168 0 : LBASSERT( window );
169 0 : return window ? window->getNode() : 0;
170 : }
171 :
172 7 : Pipe* Channel::getPipe()
173 : {
174 7 : Window* window = getWindow();
175 7 : LBASSERT( window );
176 7 : return window ? window->getPipe() : 0;
177 : }
178 :
179 0 : const Pipe* Channel::getPipe() const
180 : {
181 0 : const Window* window = getWindow();
182 0 : LBASSERT( window );
183 0 : return window ? window->getPipe() : 0;
184 : }
185 :
186 86 : ServerPtr Channel::getServer()
187 : {
188 86 : Window* window = getWindow();
189 86 : LBASSERT( window );
190 86 : return ( window ? window->getServer() : 0 );
191 : }
192 :
193 146 : const Canvas* Channel::getCanvas() const
194 : {
195 146 : if( !_segment )
196 0 : return 0;
197 146 : return _segment->getCanvas();
198 : }
199 :
200 7 : const Compounds& Channel::getCompounds() const
201 : {
202 7 : return getConfig()->getCompounds();
203 : }
204 :
205 86 : co::CommandQueue* Channel::getMainThreadQueue()
206 : {
207 86 : Window* window = getWindow();
208 86 : LBASSERT( window );
209 86 : return window->getMainThreadQueue();
210 : }
211 :
212 86 : co::CommandQueue* Channel::getCommandThreadQueue()
213 : {
214 86 : Window* window = getWindow();
215 86 : LBASSERT( window );
216 86 : return window->getCommandThreadQueue();
217 : }
218 :
219 1248 : bool Channel::supportsView( const View* view ) const
220 : {
221 1248 : if( !view )
222 0 : return true;
223 :
224 1248 : const uint64_t minimum = view->getMinimumCapabilities();
225 1248 : const uint64_t supported = getCapabilities();
226 1248 : return( (supported & minimum) == minimum );
227 : }
228 :
229 22 : void Channel::activate()
230 : {
231 22 : Window* window = getWindow();
232 22 : LBASSERT( window );
233 :
234 22 : ++_active;
235 22 : window->activate();
236 :
237 22 : LBLOG( LOG_VIEW ) << "activate: " << _active << " " << (void*)this
238 22 : << std::endl;
239 22 : }
240 :
241 22 : void Channel::deactivate()
242 : {
243 22 : Window* window = getWindow();
244 22 : LBASSERT( _active != 0 );
245 22 : LBASSERT( window );
246 :
247 22 : --_active;
248 22 : window->deactivate();
249 :
250 22 : LBLOG( LOG_VIEW ) << "deactivate: " << _active << " " << (void*)this
251 22 : << std::endl;
252 22 : }
253 :
254 636 : void Channel::setOutput( View* view, Segment* segment )
255 : {
256 636 : LBASSERT( !_view && !_segment );
257 636 : LBASSERT( view && segment );
258 :
259 636 : _view = view;
260 636 : _segment = segment;
261 :
262 636 : view->addChannel( this );
263 636 : segment->addDestinationChannel( this );
264 :
265 636 : co::ObjectVersion viewVersion( view );
266 636 : if( view && view->isDirty( ))
267 0 : ++viewVersion.version;
268 :
269 636 : setViewVersion( viewVersion );
270 636 : }
271 :
272 635 : void Channel::unsetOutput()
273 : {
274 635 : LBASSERT( _view && _segment );
275 :
276 635 : LBCHECK( _view->removeChannel( this ));
277 635 : LBCHECK( _segment->removeDestinationChannel( this ));
278 :
279 635 : _view = 0;
280 635 : _segment = 0;
281 635 : }
282 :
283 762 : const Layout* Channel::getLayout() const
284 : {
285 762 : LBASSERT( _view );
286 762 : return _view ? _view->getLayout() : 0;
287 : }
288 :
289 348 : void Channel::addTasks( const uint32_t tasks )
290 : {
291 348 : Window* window = getWindow();
292 348 : LBASSERT( window );
293 348 : setTasks( getTasks() | tasks );
294 348 : window->addTasks( tasks );
295 348 : }
296 :
297 : //===========================================================================
298 : // Operations
299 : //===========================================================================
300 :
301 : //---------------------------------------------------------------------------
302 : // init
303 : //---------------------------------------------------------------------------
304 15 : void Channel::configInit( const uint128_t& initID, const uint32_t /*frame*/ )
305 : {
306 15 : LBASSERT( _state == STATE_STOPPED );
307 15 : _state = STATE_INITIALIZING;
308 :
309 15 : LBLOG( LOG_INIT ) << "Init channel" << std::endl;
310 15 : getWindow()->send( fabric::CMD_WINDOW_CREATE_CHANNEL ) << getID();
311 15 : send( fabric::CMD_CHANNEL_CONFIG_INIT ) << initID;
312 15 : }
313 :
314 15 : bool Channel::syncConfigInit()
315 : {
316 15 : LBASSERT( _state == STATE_INITIALIZING || _state == STATE_INIT_SUCCESS ||
317 : _state == STATE_INIT_FAILED );
318 :
319 15 : _state.waitNE( STATE_INITIALIZING );
320 :
321 15 : if( _state == STATE_INIT_SUCCESS )
322 : {
323 15 : _state = STATE_RUNNING;
324 15 : return true;
325 : }
326 :
327 0 : configExit();
328 0 : return false;
329 : }
330 :
331 : //---------------------------------------------------------------------------
332 : // exit
333 : //---------------------------------------------------------------------------
334 15 : void Channel::configExit()
335 : {
336 15 : LBASSERT( _state == STATE_RUNNING || _state == STATE_INIT_FAILED );
337 15 : _state = STATE_EXITING;
338 :
339 15 : LBLOG( LOG_INIT ) << "Exit channel" << std::endl;
340 15 : send( fabric::CMD_CHANNEL_CONFIG_EXIT );
341 15 : }
342 :
343 15 : bool Channel::syncConfigExit()
344 : {
345 15 : LBASSERT( _state == STATE_EXITING || _state == STATE_EXIT_SUCCESS ||
346 : _state == STATE_EXIT_FAILED );
347 :
348 15 : _state.waitNE( STATE_EXITING );
349 15 : const bool success = ( _state == STATE_EXIT_SUCCESS );
350 15 : LBASSERT( success || _state == STATE_EXIT_FAILED );
351 :
352 15 : _state = isActive() ? STATE_FAILED : STATE_STOPPED;
353 15 : return success;
354 : }
355 :
356 : //---------------------------------------------------------------------------
357 : // update
358 : //---------------------------------------------------------------------------
359 7 : void Channel::_setupRenderContext( const uint128_t& frameID,
360 : RenderContext& context )
361 : {
362 7 : context.frameID = frameID;
363 7 : context.pvp = getPixelViewport();
364 7 : context.view = _view;
365 7 : context.vp = getViewport();
366 7 : LBASSERTINFO( getNativeContext().view == context.view,
367 : getNativeContext().view << " != " << context.view << " " <<
368 : getName( ));
369 7 : }
370 :
371 24 : bool Channel::update( const uint128_t& frameID, const uint32_t frameNumber )
372 : {
373 24 : if( !isRunning( ))
374 17 : return false; // not updated
375 :
376 7 : LBASSERT( isActive( ))
377 7 : LBASSERT( getWindow()->isActive( ));
378 :
379 7 : RenderContext context;
380 7 : _setupRenderContext( frameID, context );
381 : send( fabric::CMD_CHANNEL_FRAME_START )
382 7 : << context << getVersion() << frameNumber;
383 7 : LBLOG( LOG_TASKS ) << "TASK channel " << getName() << " start frame "
384 7 : << frameNumber << std::endl;
385 :
386 7 : bool updated = false;
387 7 : const Compounds& compounds = getCompounds();
388 114 : for( Compounds::const_iterator i = compounds.begin();
389 76 : i != compounds.end(); ++i )
390 : {
391 31 : const Compound* compound = *i;
392 31 : ChannelUpdateVisitor visitor( this, frameID, frameNumber );
393 :
394 31 : visitor.setEye( EYE_CYCLOP );
395 31 : compound->accept( visitor );
396 :
397 31 : visitor.setEye( EYE_LEFT );
398 31 : compound->accept( visitor );
399 :
400 31 : visitor.setEye( EYE_RIGHT );
401 31 : compound->accept( visitor );
402 :
403 31 : updated |= visitor.isUpdated();
404 31 : }
405 :
406 7 : send( fabric::CMD_CHANNEL_FRAME_FINISH ) << context << frameNumber;
407 7 : LBLOG( LOG_TASKS ) << "TASK channel " << getName() << " finish frame "
408 7 : << frameNumber << std::endl;
409 7 : _lastDrawCompound = 0;
410 :
411 7 : return updated;
412 : }
413 :
414 72 : co::ObjectOCommand Channel::send( const uint32_t cmd )
415 : {
416 72 : return getNode()->send( cmd, getID( ));
417 : }
418 :
419 : //---------------------------------------------------------------------------
420 : // Listener interface
421 : //---------------------------------------------------------------------------
422 8 : void Channel::addListener( ChannelListener* listener )
423 : {
424 8 : LB_TS_SCOPED( _serverThread );
425 8 : LBASSERT( std::find( _listeners.begin(), _listeners.end(), listener ) ==
426 : _listeners.end( ));
427 :
428 8 : _listeners.push_back( listener );
429 8 : }
430 :
431 8 : void Channel::removeListener( ChannelListener* listener )
432 : {
433 : ChannelListeners::iterator i = find( _listeners.begin(), _listeners.end(),
434 8 : listener );
435 8 : if( i != _listeners.end( ))
436 8 : _listeners.erase( i );
437 8 : }
438 :
439 7 : void Channel::_fireLoadData( const uint32_t frameNumber,
440 : const Statistics& statistics,
441 : const Viewport& region )
442 : {
443 7 : LB_TS_SCOPED( _serverThread );
444 :
445 21 : for( ChannelListeners::const_iterator i = _listeners.begin();
446 14 : i != _listeners.end(); ++i )
447 : {
448 0 : (*i)->notifyLoadData( this, frameNumber, statistics, region );
449 7 : }
450 7 : }
451 :
452 : //===========================================================================
453 : // command handling
454 : //===========================================================================
455 15 : bool Channel::_cmdConfigInitReply( co::ICommand& cmd )
456 : {
457 15 : co::ObjectICommand command( cmd );
458 15 : const bool result = command.read< bool >();
459 :
460 15 : LBLOG( LOG_INIT ) << "handle channel configInit reply " << command
461 15 : << " result " << result << std::endl;
462 :
463 15 : _state = result ? STATE_INIT_SUCCESS : STATE_INIT_FAILED;
464 15 : return true;
465 : }
466 :
467 15 : bool Channel::_cmdConfigExitReply( co::ICommand& cmd )
468 : {
469 15 : co::ObjectICommand command( cmd );
470 15 : LBLOG( LOG_INIT ) << "handle channel configExit reply " << command
471 15 : << std::endl;
472 :
473 15 : _state = command.read< bool >() ? STATE_EXIT_SUCCESS : STATE_EXIT_FAILED;
474 15 : return true;
475 : }
476 :
477 7 : bool Channel::_cmdFrameFinishReply( co::ICommand& cmd )
478 : {
479 7 : co::ObjectICommand command( cmd );
480 7 : const Viewport& region = command.read< Viewport >();
481 7 : const uint32_t frameNumber = command.read< uint32_t >();
482 14 : const Statistics& statistics = command.read< Statistics >();
483 :
484 7 : _fireLoadData( frameNumber, statistics, region );
485 14 : return true;
486 : }
487 :
488 860 : bool Channel::omitOutput() const
489 : {
490 : // don't print generated channels for now
491 860 : return _view || _segment;
492 : }
493 :
494 0 : void Channel::output( std::ostream& os ) const
495 : {
496 0 : bool attrPrinted = false;
497 :
498 0 : for( IAttribute i = static_cast<IAttribute>( 0 );
499 0 : i < IATTR_LAST;
500 : i = static_cast<IAttribute>( static_cast<uint32_t>(i)+1 ))
501 : {
502 0 : const int value = getIAttribute( i );
503 0 : if( value == Global::instance()->getChannelIAttribute( i ))
504 0 : continue;
505 :
506 0 : if( !attrPrinted )
507 : {
508 0 : os << std::endl << "attributes" << std::endl
509 0 : << "{" << std::endl << lunchbox::indent;
510 0 : attrPrinted = true;
511 : }
512 :
513 : os << ( i==IATTR_HINT_STATISTICS ? "hint_statistics " :
514 : i==IATTR_HINT_SENDTOKEN ? "hint_sendtoken " :
515 0 : "ERROR " )
516 0 : << static_cast< fabric::IAttribute >( value ) << std::endl;
517 : }
518 0 : for( SAttribute i = static_cast<SAttribute>( 0 );
519 0 : i < SATTR_LAST;
520 : i = static_cast<SAttribute>( static_cast<uint32_t>(i)+1 ))
521 : {
522 0 : const std::string& value = getSAttribute( i );
523 0 : if( value == Global::instance()->getChannelSAttribute( i ))
524 0 : continue;
525 :
526 0 : if( !attrPrinted )
527 : {
528 0 : os << std::endl << "attributes" << std::endl
529 0 : << "{" << std::endl << lunchbox::indent;
530 0 : attrPrinted = true;
531 : }
532 :
533 0 : os << ( i == SATTR_DUMP_IMAGE ? "dump_image " : "ERROR " )
534 0 : << "\"" << value << "\"" << std::endl;
535 0 : }
536 :
537 0 : if( attrPrinted )
538 0 : os << lunchbox::exdent << "}" << std::endl << std::endl;
539 0 : }
540 :
541 0 : void Channel::updateCapabilities()
542 : {
543 0 : ViewFinder visitor( this );
544 0 : getConfig()->accept( visitor );
545 0 : ViewSet& views = visitor.getViews();
546 :
547 0 : for( ViewSet::const_iterator i = views.begin(); i != views.end(); ++i )
548 0 : (*i)->updateCapabilities();
549 0 : }
550 :
551 : }
552 : }
553 :
554 : #include "../fabric/channel.ipp"
555 : template class eq::fabric::Channel< eq::server::Window, eq::server::Channel >;
556 : /** @cond IGNORE */
557 : template std::ostream& eq::fabric::operator << ( std::ostream&,
558 27 : const eq::server::Super& );
559 : /** @endcond */
|