Line data Source code
1 :
2 : /* Copyright (c) 2010-2013, Stefan Eilemann <eile@eyescale.ch>
3 : * 2012, Daniel Nachbaur <danielnachbaur@gmail.com>
4 : *
5 : * This library is free software; you can redistribute it and/or modify it under
6 : * the terms of the GNU Lesser General Public License version 2.1 as published
7 : * by the Free Software Foundation.
8 : *
9 : * This library is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 : * details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public License
15 : * along with this library; if not, write to the Free Software Foundation, Inc.,
16 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 : */
18 :
19 : #include "canvas.h"
20 :
21 : #include "commands.h"
22 : #include "elementVisitor.h"
23 : #include "leafVisitor.h"
24 : #include "log.h"
25 : #include "nameFinder.h"
26 : #include "paths.h"
27 : #include "segment.h"
28 :
29 : #include <co/dataIStream.h>
30 : #include <co/dataOStream.h>
31 : #include <co/objectICommand.h>
32 :
33 : namespace eq
34 : {
35 : namespace fabric
36 : {
37 :
38 : template< class CFG, class C, class S, class L >
39 233 : Canvas< CFG, C, S, L >::Canvas( CFG* config )
40 233 : : _config( config )
41 : {
42 233 : LBASSERT( config );
43 233 : setWall( Wall( )); // default frustum
44 233 : config->_addCanvas( static_cast< C* >( this ));
45 233 : LBLOG( LOG_INIT ) << "New " << lunchbox::className( this ) << std::endl;
46 233 : }
47 :
48 : template< class CFG, class C, class S, class L >
49 232 : Canvas< CFG, C, S, L >::~Canvas()
50 : {
51 232 : LBLOG( LOG_INIT ) << "Delete " << lunchbox::className( this ) << std::endl;
52 838 : while( !_segments.empty( ))
53 : {
54 374 : S* segment = _segments.back();
55 374 : _removeChild( segment );
56 374 : release( segment );
57 : }
58 :
59 232 : _data.activeLayout = 0;
60 232 : _layouts.clear();
61 232 : _config->_removeCanvas( static_cast< C* >( this ));
62 464 : }
63 :
64 : template< class CFG, class C, class S, class L >
65 10 : void Canvas< CFG, C, S, L >::backup()
66 : {
67 10 : _backup = _data;
68 10 : Object::backup();
69 10 : Frustum::backup();
70 10 : }
71 :
72 : template< class CFG, class C, class S, class L >
73 2 : void Canvas< CFG, C, S, L >::restore()
74 : {
75 2 : Frustum::restore();
76 2 : Object::restore();
77 2 : activateLayout( _backup.activeLayout );
78 2 : _data = _backup;
79 2 : setDirty( DIRTY_LAYOUT );
80 2 : }
81 :
82 : template< class CFG, class C, class S, class L >
83 20 : void Canvas< CFG, C, S, L >::attach( const uint128_t& id,
84 : const uint32_t instanceID )
85 : {
86 20 : Object::attach( id, instanceID );
87 :
88 20 : co::CommandQueue* queue = _config->getMainThreadQueue();
89 20 : LBASSERT( queue );
90 :
91 20 : registerCommand( CMD_CANVAS_NEW_SEGMENT,
92 : CmdFunc( this, &Canvas< CFG, C, S, L >::_cmdNewSegment ),
93 : queue );
94 20 : registerCommand( CMD_CANVAS_NEW_SEGMENT_REPLY,
95 : CmdFunc( this, &Canvas< CFG, C, S, L >::_cmdNewSegmentReply ),
96 : 0 );
97 20 : }
98 :
99 : template< class CFG, class C, class S, class L >
100 9219 : uint128_t Canvas< CFG, C, S, L >::commit( const uint32_t incarnation )
101 : {
102 9219 : if( Serializable::isDirty( DIRTY_SEGMENTS ))
103 19 : commitChildren< S >( _segments, CMD_CANVAS_NEW_SEGMENT, incarnation );
104 9219 : return Object::commit( incarnation );
105 : }
106 :
107 : template< class CFG, class C, class S, class L >
108 38 : void Canvas< CFG, C, S, L >::serialize( co::DataOStream& os,
109 : const uint64_t dirtyBits )
110 : {
111 38 : Object::serialize( os, dirtyBits );
112 :
113 38 : if( dirtyBits & DIRTY_LAYOUT )
114 21 : os << _data.activeLayout;
115 38 : if( dirtyBits & DIRTY_SEGMENTS && isMaster( ))
116 30 : os.serializeChildren( _segments );
117 38 : if( dirtyBits & DIRTY_LAYOUTS )
118 21 : os.serializeChildren( _layouts );
119 38 : if( dirtyBits & DIRTY_FRUSTUM )
120 37 : Frustum::serialize( os );
121 38 : }
122 :
123 : template< class CFG, class C, class S, class L >
124 27 : void Canvas< CFG, C, S, L >::deserialize( co::DataIStream& is,
125 : const uint64_t dirtyBits )
126 : {
127 27 : Object::deserialize( is, dirtyBits );
128 :
129 27 : if( dirtyBits & DIRTY_LAYOUT )
130 : {
131 : uint32_t index;
132 10 : is >> index;
133 10 : activateLayout( index );
134 : }
135 :
136 27 : if( dirtyBits & DIRTY_SEGMENTS )
137 : {
138 27 : if( isMaster( ))
139 8 : syncChildren( _segments );
140 : else
141 : {
142 19 : Segments result;
143 19 : is.deserializeChildren( this, _segments, result );
144 19 : _segments.swap( result );
145 19 : LBASSERT( _segments.size() == result.size( ));
146 : }
147 : }
148 :
149 27 : if( dirtyBits & DIRTY_LAYOUTS )
150 : {
151 10 : _layouts.clear();
152 10 : co::ObjectVersions layouts;
153 10 : is >> layouts;
154 219 : for( co::ObjectVersions::const_iterator i = layouts.begin();
155 146 : i != layouts.end(); ++i )
156 : {
157 63 : const uint128_t& id = (*i).identifier;
158 :
159 63 : if( id == 0 )
160 0 : _layouts.push_back( 0 );
161 : else
162 : {
163 63 : L* layout = 0;
164 63 : _config->find( id, &layout );
165 63 : LBASSERT( layout );
166 63 : _layouts.push_back( layout );
167 : }
168 : }
169 :
170 10 : _config->updateCanvas( static_cast< C* >( this ));
171 : }
172 27 : if( dirtyBits & DIRTY_FRUSTUM )
173 26 : Frustum::deserialize( is );
174 27 : }
175 :
176 : template< class CFG, class C, class S, class L >
177 2397 : void Canvas< CFG, C, S, L >::setDirty( const uint64_t dirtyBits )
178 : {
179 2397 : Object::setDirty( dirtyBits );
180 2397 : _config->setDirty( CFG::DIRTY_CANVASES );
181 2397 : }
182 :
183 : template< class CFG, class C, class S, class L >
184 10 : void Canvas< CFG, C, S, L >::create( S** segment )
185 : {
186 10 : *segment = _config->getServer()->getNodeFactory()->createSegment(
187 : static_cast< C* >( this ));
188 10 : }
189 :
190 : template< class CFG, class C, class S, class L >
191 384 : void Canvas< CFG, C, S, L >::release( S* segment )
192 : {
193 384 : _config->getServer()->getNodeFactory()->releaseSegment( segment );
194 384 : }
195 :
196 : template< class CFG, class C, class S, class L >
197 20 : void Canvas< CFG, C, S, L >::notifyDetach()
198 : {
199 20 : Object::notifyDetach();
200 20 : releaseChildren< C, S >( _segments );
201 20 : }
202 :
203 : template< class CFG, class C, class S, class L >
204 385 : void Canvas< CFG, C, S, L >::_addChild( S* segment )
205 : {
206 385 : LBASSERT( segment );
207 385 : LBASSERT( segment->getCanvas() == this );
208 385 : _segments.push_back( segment );
209 385 : setDirty( DIRTY_SEGMENTS );
210 385 : }
211 :
212 : template< class CFG, class C, class S, class L >
213 768 : bool Canvas< CFG, C, S, L >::_removeChild( S* segment )
214 : {
215 768 : typename Segments::iterator i = lunchbox::find( _segments, segment );
216 768 : if( i == _segments.end( ))
217 384 : return false;
218 :
219 384 : LBASSERT( segment->getCanvas() == this );
220 384 : _segments.erase( i );
221 384 : setDirty( DIRTY_SEGMENTS );
222 384 : if( isAttached() && !isMaster( ))
223 10 : postRemove( segment );
224 384 : return true;
225 : }
226 :
227 : template< class CFG, class C, class S, class L >
228 10 : bool Canvas< CFG, C, S, L >::_mapViewObjects()
229 : {
230 10 : return static_cast< typename CFG::Super* >( _config )->mapViewObjects();
231 : }
232 :
233 : template< class CFG, class C, class S, class L >
234 819 : CanvasPath Canvas< CFG, C, S, L >::getPath() const
235 : {
236 819 : const CFG* config = getConfig();
237 819 : LBASSERT( config );
238 :
239 819 : const Canvases& canvases = config->getCanvases();
240 : typename Canvases::const_iterator i = std::find( canvases.begin(),
241 : canvases.end(),
242 819 : this );
243 819 : LBASSERT( i != canvases.end( ));
244 :
245 819 : CanvasPath path;
246 819 : path.canvasIndex = std::distance( canvases.begin(), i );
247 819 : return path;
248 : }
249 :
250 : template< class CFG, class C, class S, class L >
251 0 : S* Canvas< CFG, C, S, L >::findSegment( const std::string& name )
252 : {
253 0 : NameFinder< S, Visitor > finder( name );
254 0 : accept( finder );
255 0 : return finder.getResult();
256 : }
257 :
258 : template< class CFG, class C, class S, class L >
259 0 : const S* Canvas< CFG, C, S, L >::findSegment( const std::string& name ) const
260 : {
261 0 : NameFinder< const S, Visitor > finder( name );
262 0 : accept( finder );
263 0 : return finder.getResult();
264 : }
265 :
266 : template< class CFG, class C, class S, class L >
267 386 : void Canvas< CFG, C, S, L >::addLayout( L* layout )
268 : {
269 386 : LBASSERT( lunchbox::find( _layouts, layout ) == _layouts.end( ));
270 :
271 : // dest channel creation is done be Config::addCanvas
272 386 : _layouts.push_back( layout );
273 386 : setDirty( DIRTY_LAYOUTS );
274 386 : }
275 :
276 : template< class CFG, class C, class S, class L >
277 0 : bool Canvas< CFG, C, S, L >::removeLayout( L* layout )
278 : {
279 0 : typename Layouts::iterator i = lunchbox::find( _layouts, layout );
280 0 : if( i == _layouts.end( ))
281 0 : return false;
282 :
283 0 : if( getActiveLayout() == layout )
284 : {
285 0 : _data.activeLayout = 0;
286 0 : setDirty( DIRTY_LAYOUT );
287 : }
288 :
289 0 : _layouts.erase( i );
290 0 : setDirty( DIRTY_LAYOUTS );
291 0 : return true;
292 : }
293 :
294 : template< class CFG, class C, class S, class L >
295 39 : const L* Canvas< CFG, C, S, L >::getActiveLayout() const
296 : {
297 39 : LBASSERTINFO( _data.activeLayout < _layouts.size(),
298 : _data.activeLayout << " >= " << _layouts.size( ));
299 39 : return _layouts[ _data.activeLayout ];
300 : }
301 :
302 : template< class CFG, class C, class S, class L >
303 0 : bool Canvas< CFG, C, S, L >::useLayout( const uint32_t index )
304 : {
305 0 : LBASSERT( index < _layouts.size( ));
306 0 : if( _data.activeLayout == index )
307 0 : return false;
308 :
309 0 : _data.activeLayout = index;
310 0 : setDirty( DIRTY_LAYOUT );
311 0 : return true;
312 : }
313 :
314 : template< class CFG, class C, class S, class L >
315 2 : void Canvas< CFG, C, S, L >::setSwapBarrier( SwapBarrierPtr barrier )
316 : {
317 2 : if( barrier.isValid() && barrier->getName().empty( ))
318 : {
319 1 : const std::string& name = getName();
320 1 : std::stringstream out;
321 1 : out << "barrier.canvas.";
322 1 : if( name.empty( ))
323 1 : if( getConfig( ))
324 1 : out << getPath().canvasIndex;
325 : else
326 0 : out << (void*)this;
327 : else
328 0 : out << name;
329 :
330 1 : barrier->setName( out.str( ));
331 : }
332 :
333 2 : _swapBarrier = barrier;
334 2 : }
335 :
336 : namespace
337 : {
338 : template< class C, class V >
339 1783 : VisitorResult _accept( C* canvas, V& visitor )
340 : {
341 1783 : VisitorResult result = visitor.visitPre( canvas );
342 1783 : if( result != TRAVERSE_CONTINUE )
343 16 : return result;
344 :
345 1767 : const typename C::Segments& segments = canvas->getSegments();
346 16881 : for( typename C::Segments::const_iterator i = segments.begin();
347 11254 : i != segments.end(); ++i )
348 : {
349 3860 : switch( (*i)->accept( visitor ))
350 : {
351 : case TRAVERSE_TERMINATE:
352 0 : return TRAVERSE_TERMINATE;
353 :
354 : case TRAVERSE_PRUNE:
355 0 : result = TRAVERSE_PRUNE;
356 0 : break;
357 :
358 : case TRAVERSE_CONTINUE:
359 : default:
360 3860 : break;
361 : }
362 : }
363 :
364 1767 : switch( visitor.visitPost( canvas ))
365 : {
366 : case TRAVERSE_TERMINATE:
367 0 : return TRAVERSE_TERMINATE;
368 :
369 : case TRAVERSE_PRUNE:
370 0 : return TRAVERSE_PRUNE;
371 :
372 : case TRAVERSE_CONTINUE:
373 : default:
374 1767 : break;
375 : }
376 :
377 1767 : return result;
378 : }
379 : }
380 :
381 : template< class CFG, class C, class S, class L >
382 1783 : VisitorResult Canvas< CFG, C, S, L >::accept( Visitor& visitor )
383 : {
384 1783 : return _accept( static_cast< C* >( this ), visitor );
385 : }
386 :
387 : template< class CFG, class C, class S, class L >
388 0 : VisitorResult Canvas< CFG, C, S, L >::accept( Visitor& visitor ) const
389 : {
390 0 : return _accept( static_cast< const C* >( this ), visitor );
391 : }
392 :
393 : template< class CFG, class C, class S, class L >
394 444 : void Canvas< CFG, C, S, L >::setWall( const Wall& wall )
395 : {
396 444 : if( getWall() == wall && getCurrentType() == TYPE_WALL )
397 597 : return;
398 :
399 291 : Frustum::setWall( wall );
400 291 : setDirty( DIRTY_FRUSTUM );
401 873 : for( typename Segments::const_iterator i = _segments.begin();
402 582 : i != _segments.end(); ++i )
403 : {
404 0 : (*i)->inheritFrustum();
405 : }
406 : }
407 :
408 : template< class CFG, class C, class S, class L >
409 0 : void Canvas< CFG, C, S, L >::setProjection( const Projection& projection )
410 : {
411 0 : if( getProjection() == projection && getCurrentType() == TYPE_PROJECTION )
412 0 : return;
413 :
414 0 : Frustum::setProjection( projection );
415 0 : setDirty( DIRTY_FRUSTUM );
416 0 : for( typename Segments::const_iterator i = _segments.begin();
417 0 : i != _segments.end(); ++i )
418 : {
419 0 : (*i)->inheritFrustum();
420 : }
421 : }
422 :
423 : template< class CFG, class C, class S, class L >
424 0 : void Canvas< CFG, C, S, L >::unsetFrustum()
425 : {
426 0 : if( getCurrentType() == TYPE_NONE )
427 0 : return;
428 :
429 0 : Frustum::unsetFrustum();
430 0 : setDirty( DIRTY_FRUSTUM );
431 : }
432 :
433 : //----------------------------------------------------------------------
434 : // ICommand handlers
435 : //----------------------------------------------------------------------
436 : template< class CFG, class C, class S, class L > bool
437 0 : Canvas< CFG, C, S, L >::_cmdNewSegment( co::ICommand& cmd )
438 : {
439 0 : co::ObjectICommand command( cmd );
440 :
441 0 : S* segment = 0;
442 0 : create( &segment );
443 0 : LBASSERT( segment );
444 :
445 0 : getLocalNode()->registerObject( segment );
446 0 : segment->setAutoObsolete( _config->getLatency() + 1 );
447 0 : LBASSERT( segment->isAttached() );
448 :
449 0 : send( command.getRemoteNode(), CMD_CANVAS_NEW_SEGMENT_REPLY )
450 0 : << command.read< uint32_t >() << segment->getID();
451 :
452 0 : return true;
453 : }
454 :
455 : template< class CFG, class C, class S, class L > bool
456 0 : Canvas< CFG, C, S, L >::_cmdNewSegmentReply( co::ICommand& cmd )
457 : {
458 0 : co::ObjectICommand command( cmd );
459 :
460 0 : const uint32_t requestID = command.read< uint32_t >();
461 0 : const uint128_t& result = command.read< uint128_t >();
462 :
463 0 : getLocalNode()->serveRequest( requestID, result );
464 :
465 0 : return true;
466 : }
467 :
468 : template< class CFG, class C, class S, class L >
469 124 : std::ostream& operator << ( std::ostream& os,
470 : const Canvas< CFG, C, S, L >& canvas )
471 : {
472 124 : os << lunchbox::disableFlush << lunchbox::disableHeader << "canvas"
473 : << std::endl;
474 124 : os << "{" << std::endl << lunchbox::indent;
475 :
476 124 : const std::string& name = canvas.getName();
477 124 : if( !name.empty( ))
478 3 : os << "name \"" << name << "\"" << std::endl;
479 :
480 124 : const std::vector< L* >& layouts = canvas.getLayouts();
481 1227 : for( typename std::vector< L* >::const_iterator i = layouts.begin();
482 818 : i != layouts.end(); ++i )
483 : {
484 285 : L* layout = *i;
485 285 : if( layout )
486 : {
487 284 : const CFG* config = layout->getConfig();
488 284 : const std::string& layoutName = layout->getName();
489 284 : const L* foundLayout = 0;
490 284 : config->find( layoutName, &foundLayout );
491 284 : if( foundLayout == layout )
492 283 : os << "layout \"" << layoutName << "\"" << std::endl;
493 : else
494 1 : os << layout->getPath() << std::endl;
495 : }
496 : else
497 1 : os << "layout OFF" << std::endl;
498 : }
499 :
500 124 : if( canvas.getSwapBarrier().isValid( ))
501 1 : os << *canvas.getSwapBarrier();
502 124 : os << static_cast< const Frustum& >( canvas );
503 :
504 124 : const std::vector< S* >& segments = canvas.getSegments();
505 972 : for( typename std::vector< S* >::const_iterator i = segments.begin();
506 648 : i != segments.end(); ++i )
507 : {
508 200 : os << **i;
509 : }
510 124 : os << lunchbox::exdent << "}" << std::endl << lunchbox::enableHeader
511 : << lunchbox::enableFlush;
512 124 : return os;
513 : }
514 :
515 : }
516 : }
|