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 444 : Canvas< CFG, C, S, L >::Canvas( CFG* config )
40 444 : : _config( config )
41 : {
42 444 : LBASSERT( config );
43 444 : setWall( Wall( )); // default frustum
44 444 : config->_addCanvas( static_cast< C* >( this ));
45 444 : LBLOG( LOG_INIT ) << "New " << lunchbox::className( this ) << std::endl;
46 444 : }
47 :
48 : template< class CFG, class C, class S, class L >
49 442 : Canvas< CFG, C, S, L >::~Canvas()
50 : {
51 442 : LBLOG( LOG_INIT ) << "Delete " << lunchbox::className( this ) << std::endl;
52 1636 : while( !_segments.empty( ))
53 : {
54 752 : S* segment = _segments.back();
55 752 : _removeChild( segment );
56 752 : release( segment );
57 : }
58 :
59 442 : _data.activeLayout = 0;
60 442 : _layouts.clear();
61 442 : _config->_removeCanvas( static_cast< C* >( this ));
62 884 : }
63 :
64 : template< class CFG, class C, class S, class L >
65 4 : void Canvas< CFG, C, S, L >::backup()
66 : {
67 4 : _backup = _data;
68 4 : Object::backup();
69 4 : Frustum::backup();
70 4 : }
71 :
72 : template< class CFG, class C, class S, class L >
73 4 : void Canvas< CFG, C, S, L >::restore()
74 : {
75 4 : Frustum::restore();
76 4 : Object::restore();
77 4 : activateLayout( _backup.activeLayout );
78 4 : _data = _backup;
79 4 : setDirty( DIRTY_LAYOUT );
80 4 : }
81 :
82 : template< class CFG, class C, class S, class L >
83 6 : void Canvas< CFG, C, S, L >::attach( const uint128_t& id,
84 : const uint32_t instanceID )
85 : {
86 6 : Object::attach( id, instanceID );
87 :
88 6 : co::CommandQueue* queue = _config->getMainThreadQueue();
89 6 : LBASSERT( queue );
90 :
91 6 : registerCommand( CMD_CANVAS_NEW_SEGMENT,
92 : CmdFunc( this, &Canvas< CFG, C, S, L >::_cmdNewSegment ),
93 : queue );
94 6 : registerCommand( CMD_CANVAS_NEW_SEGMENT_REPLY,
95 : CmdFunc( this, &Canvas< CFG, C, S, L >::_cmdNewSegmentReply ),
96 : 0 );
97 6 : }
98 :
99 : template< class CFG, class C, class S, class L >
100 20 : uint128_t Canvas< CFG, C, S, L >::commit( const uint32_t incarnation )
101 : {
102 20 : if( Serializable::isDirty( DIRTY_SEGMENTS ))
103 6 : commitChildren< S >( _segments, CMD_CANVAS_NEW_SEGMENT, incarnation );
104 20 : return Object::commit( incarnation );
105 : }
106 :
107 : template< class CFG, class C, class S, class L >
108 12 : void Canvas< CFG, C, S, L >::serialize( co::DataOStream& os,
109 : const uint64_t dirtyBits )
110 : {
111 12 : Object::serialize( os, dirtyBits );
112 :
113 12 : if( dirtyBits & DIRTY_LAYOUT )
114 10 : os << _data.activeLayout;
115 12 : if( dirtyBits & DIRTY_SEGMENTS && isMaster( ))
116 12 : os.serializeChildren( _segments );
117 12 : if( dirtyBits & DIRTY_LAYOUTS )
118 10 : os.serializeChildren( _layouts );
119 12 : if( dirtyBits & DIRTY_FRUSTUM )
120 10 : Frustum::serialize( os );
121 12 : }
122 :
123 : template< class CFG, class C, class S, class L >
124 3 : void Canvas< CFG, C, S, L >::deserialize( co::DataIStream& is,
125 : const uint64_t dirtyBits )
126 : {
127 3 : Object::deserialize( is, dirtyBits );
128 :
129 3 : if( dirtyBits & DIRTY_LAYOUT )
130 : {
131 2 : uint32_t index( 0 );
132 2 : is >> index;
133 2 : activateLayout( index );
134 : }
135 :
136 3 : if( dirtyBits & DIRTY_SEGMENTS )
137 : {
138 3 : if( isMaster( ))
139 0 : syncChildren( _segments );
140 : else
141 : {
142 3 : Segments result;
143 3 : is.deserializeChildren( this, _segments, result );
144 3 : _segments.swap( result );
145 3 : LBASSERT( _segments.size() == result.size( ));
146 : }
147 : }
148 :
149 3 : if( dirtyBits & DIRTY_LAYOUTS )
150 : {
151 2 : _layouts.clear();
152 2 : co::ObjectVersions layouts;
153 2 : is >> layouts;
154 12 : for( co::ObjectVersions::const_iterator i = layouts.begin();
155 8 : i != layouts.end(); ++i )
156 : {
157 2 : const uint128_t& id = (*i).identifier;
158 :
159 2 : if( id == 0 )
160 0 : _layouts.push_back( 0 );
161 : else
162 : {
163 2 : L* layout = 0;
164 2 : _config->find( id, &layout );
165 2 : LBASSERT( layout );
166 2 : _layouts.push_back( layout );
167 : }
168 : }
169 :
170 2 : _config->updateCanvas( static_cast< C* >( this ));
171 : }
172 3 : if( dirtyBits & DIRTY_FRUSTUM )
173 2 : Frustum::deserialize( is );
174 3 : }
175 :
176 : template< class CFG, class C, class S, class L >
177 4638 : void Canvas< CFG, C, S, L >::setDirty( const uint64_t dirtyBits )
178 : {
179 4638 : Object::setDirty( dirtyBits );
180 4638 : _config->setDirty( CFG::DIRTY_CANVASES );
181 4638 : }
182 :
183 : template< class CFG, class C, class S, class L >
184 2 : void Canvas< CFG, C, S, L >::create( S** segment )
185 : {
186 2 : *segment = _config->getServer()->getNodeFactory()->createSegment(
187 : static_cast< C* >( this ));
188 2 : }
189 :
190 : template< class CFG, class C, class S, class L >
191 754 : void Canvas< CFG, C, S, L >::release( S* segment )
192 : {
193 754 : _config->getServer()->getNodeFactory()->releaseSegment( segment );
194 754 : }
195 :
196 : template< class CFG, class C, class S, class L >
197 6 : void Canvas< CFG, C, S, L >::notifyDetach()
198 : {
199 6 : Object::notifyDetach();
200 6 : releaseChildren< C, S >( _segments );
201 6 : }
202 :
203 : template< class CFG, class C, class S, class L >
204 756 : void Canvas< CFG, C, S, L >::_addChild( S* segment )
205 : {
206 756 : LBASSERT( segment );
207 756 : LBASSERT( segment->getCanvas() == this );
208 756 : _segments.push_back( segment );
209 756 : setDirty( DIRTY_SEGMENTS );
210 756 : }
211 :
212 : template< class CFG, class C, class S, class L >
213 1508 : bool Canvas< CFG, C, S, L >::_removeChild( S* segment )
214 : {
215 1508 : typename Segments::iterator i = lunchbox::find( _segments, segment );
216 1508 : if( i == _segments.end( ))
217 754 : return false;
218 :
219 754 : LBASSERT( segment->getCanvas() == this );
220 754 : _segments.erase( i );
221 754 : setDirty( DIRTY_SEGMENTS );
222 754 : if( isAttached() && !isMaster( ))
223 2 : postRemove( segment );
224 754 : return true;
225 : }
226 :
227 : template< class CFG, class C, class S, class L >
228 2 : bool Canvas< CFG, C, S, L >::_mapViewObjects()
229 : {
230 2 : return static_cast< typename CFG::Super* >( _config )->mapViewObjects();
231 : }
232 :
233 : template< class CFG, class C, class S, class L >
234 1174 : CanvasPath Canvas< CFG, C, S, L >::getPath() const
235 : {
236 1174 : const CFG* config = getConfig();
237 1174 : LBASSERT( config );
238 :
239 1174 : const Canvases& canvases = config->getCanvases();
240 : typename Canvases::const_iterator i = std::find( canvases.begin(),
241 : canvases.end(),
242 1174 : this );
243 1174 : LBASSERT( i != canvases.end( ));
244 :
245 1174 : CanvasPath path;
246 1174 : path.canvasIndex = std::distance( canvases.begin(), i );
247 1174 : 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 666 : void Canvas< CFG, C, S, L >::addLayout( L* layout )
268 : {
269 666 : LBASSERT( lunchbox::find( _layouts, layout ) == _layouts.end( ));
270 :
271 : // dest channel creation is done be Config::addCanvas
272 666 : _layouts.push_back( layout );
273 666 : setDirty( DIRTY_LAYOUTS );
274 666 : }
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 8 : const L* Canvas< CFG, C, S, L >::getActiveLayout() const
296 : {
297 8 : LBASSERTINFO( _data.activeLayout < _layouts.size(),
298 : _data.activeLayout << " >= " << _layouts.size( ));
299 8 : 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 4 : void Canvas< CFG, C, S, L >::setSwapBarrier( SwapBarrierPtr barrier )
316 : {
317 4 : if( barrier.isValid() && barrier->getName().empty( ))
318 : {
319 2 : const std::string& name = getName();
320 2 : std::stringstream out;
321 2 : out << "barrier.canvas.";
322 2 : if( name.empty( ))
323 2 : if( getConfig( ))
324 2 : out << getPath().canvasIndex;
325 : else
326 0 : out << (void*)this;
327 : else
328 0 : out << name;
329 :
330 2 : barrier->setName( out.str( ));
331 : }
332 :
333 4 : _swapBarrier = barrier;
334 4 : }
335 :
336 : namespace
337 : {
338 : template< class C, class V >
339 2389 : VisitorResult _accept( C* canvas, V& visitor )
340 : {
341 2389 : VisitorResult result = visitor.visitPre( canvas );
342 2389 : if( result != TRAVERSE_CONTINUE )
343 32 : return result;
344 :
345 2357 : const typename C::Segments& segments = canvas->getSegments();
346 26886 : for( typename C::Segments::const_iterator i = segments.begin();
347 17924 : i != segments.end(); ++i )
348 : {
349 6605 : 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 6605 : break;
361 : }
362 : }
363 :
364 2357 : 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 2357 : break;
375 : }
376 :
377 2357 : return result;
378 : }
379 : }
380 :
381 : template< class CFG, class C, class S, class L >
382 2389 : VisitorResult Canvas< CFG, C, S, L >::accept( Visitor& visitor )
383 : {
384 2389 : 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 860 : void Canvas< CFG, C, S, L >::setWall( const Wall& wall )
395 : {
396 860 : if( getWall() == wall && getCurrentType() == TYPE_WALL )
397 1172 : return;
398 :
399 548 : Frustum::setWall( wall );
400 548 : setDirty( DIRTY_FRUSTUM );
401 1644 : for( typename Segments::const_iterator i = _segments.begin();
402 1096 : 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 222 : std::ostream& operator << ( std::ostream& os,
470 : const Canvas< CFG, C, S, L >& canvas )
471 : {
472 222 : os << lunchbox::disableFlush << lunchbox::disableHeader << "canvas"
473 : << std::endl;
474 222 : os << "{" << std::endl << lunchbox::indent;
475 :
476 222 : const std::string& name = canvas.getName();
477 222 : if( !name.empty( ))
478 6 : os << "name \"" << name << "\"" << std::endl;
479 :
480 222 : const std::vector< L* >& layouts = canvas.getLayouts();
481 1668 : for( typename std::vector< L* >::const_iterator i = layouts.begin();
482 1112 : i != layouts.end(); ++i )
483 : {
484 334 : L* layout = *i;
485 334 : if( layout )
486 : {
487 332 : const CFG* config = layout->getConfig();
488 332 : const std::string& layoutName = layout->getName();
489 332 : const L* foundLayout = 0;
490 332 : config->find( layoutName, &foundLayout );
491 332 : if( foundLayout == layout )
492 330 : os << "layout \"" << layoutName << "\"" << std::endl;
493 : else
494 2 : os << layout->getPath() << std::endl;
495 : }
496 : else
497 2 : os << "layout OFF" << std::endl;
498 : }
499 :
500 222 : if( canvas.getSwapBarrier().isValid( ))
501 2 : os << *canvas.getSwapBarrier();
502 222 : os << static_cast< const Frustum& >( canvas );
503 :
504 222 : const std::vector< S* >& segments = canvas.getSegments();
505 1800 : for( typename std::vector< S* >::const_iterator i = segments.begin();
506 1200 : i != segments.end(); ++i )
507 : {
508 378 : os << **i;
509 : }
510 222 : os << lunchbox::exdent << "}" << std::endl << lunchbox::enableHeader
511 : << lunchbox::enableFlush;
512 222 : return os;
513 : }
514 :
515 : }
516 : }
|