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