Line data Source code
1 :
2 : /* Copyright (c) 2010-2016, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : * Cedric Stalder <cedric.stalder@gmail.com>
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 : #include "pipe.h"
21 :
22 : #include "commands.h"
23 : #include "elementVisitor.h"
24 : #include "leafVisitor.h"
25 : #include "log.h"
26 : #include "task.h"
27 :
28 : #include <co/dataIStream.h>
29 : #include <co/dataOStream.h>
30 : #include <co/objectICommand.h>
31 :
32 : namespace eq
33 : {
34 : namespace fabric
35 : {
36 : namespace
37 : {
38 :
39 : #define MAKE_PIPE_ATTR_STRING( attr ) ( std::string("EQ_PIPE_") + #attr )
40 140 : std::string _iPipeAttributeStrings[] = {
41 : MAKE_PIPE_ATTR_STRING( IATTR_HINT_THREAD ),
42 : MAKE_PIPE_ATTR_STRING( IATTR_HINT_AFFINITY ),
43 70 : };
44 :
45 : }
46 :
47 : template< class N, class P, class W, class V >
48 1237 : Pipe< N, P, W, V >::Pipe( N* parent )
49 : : _node( parent )
50 : , _port( LB_UNDEFINED_UINT32 )
51 1237 : , _device( LB_UNDEFINED_UINT32 )
52 : {
53 1237 : memset( _iAttributes, 0xff, IATTR_ALL * sizeof( int32_t ));
54 1237 : parent->_addPipe( static_cast< P* >( this ) );
55 1237 : LBLOG( LOG_INIT ) << "New " << lunchbox::className( this ) << std::endl;
56 1237 : }
57 :
58 : template< class N, class P, class W, class V >
59 1145 : Pipe< N, P, W, V >::~Pipe()
60 : {
61 1145 : LBLOG( LOG_INIT ) << "Delete " << lunchbox::className( this ) << std::endl;
62 3782 : while( !_windows.empty() )
63 : {
64 1492 : W* window = _windows.back();
65 1492 : _removeWindow( window );
66 1492 : delete window;
67 : }
68 1145 : _node->_removePipe( static_cast< P* >( this ) );
69 2290 : }
70 :
71 : template< class N, class P, class W, class V >
72 4 : void Pipe< N, P, W, V >::backup()
73 : {
74 4 : Object::backup();
75 4 : _backup = _data;
76 4 : }
77 :
78 :
79 : template< class N, class P, class W, class V >
80 4 : void Pipe< N, P, W, V >::restore()
81 : {
82 4 : _data = _backup;
83 4 : Object::restore();
84 4 : notifyPixelViewportChanged();
85 4 : setDirty( DIRTY_PIXELVIEWPORT );
86 4 : }
87 :
88 : template< class N, class P, class W, class V >
89 5 : void Pipe< N, P, W, V >::attach( const uint128_t& id,
90 : const uint32_t instanceID )
91 : {
92 5 : Object::attach( id, instanceID );
93 :
94 5 : co::CommandQueue* queue = _node->getConfig()->getMainThreadQueue();
95 5 : LBASSERT( queue );
96 :
97 5 : registerCommand( CMD_PIPE_NEW_WINDOW,
98 : CmdFunc( this, &Pipe< N, P, W, V >::_cmdNewWindow ),
99 : queue );
100 5 : registerCommand( CMD_PIPE_NEW_WINDOW_REPLY,
101 : CmdFunc( this, &Pipe< N, P, W, V >::_cmdNewWindowReply ),
102 : 0 );
103 5 : }
104 :
105 : template< class N, class P, class W, class V >
106 9 : uint128_t Pipe< N, P, W, V >::commit( const uint32_t incarnation )
107 : {
108 9 : if( Serializable::isDirty( DIRTY_WINDOWS ))
109 6 : commitChildren< W >( _windows, CMD_PIPE_NEW_WINDOW, incarnation );
110 9 : return Object::commit( incarnation );
111 : }
112 :
113 : template< class N, class P, class W, class V >
114 2 : void Pipe< N, P, W, V >::serialize( co::DataOStream& os,
115 : const uint64_t dirtyBits )
116 : {
117 2 : Object::serialize( os, dirtyBits );
118 2 : if( dirtyBits & DIRTY_ATTRIBUTES )
119 2 : os << co::Array< int32_t >( _iAttributes, IATTR_ALL );
120 2 : if( dirtyBits & DIRTY_WINDOWS && isMaster( ))
121 : {
122 2 : os << _mapNodeObjects();
123 2 : os.serializeChildren( _windows );
124 : }
125 2 : if( dirtyBits & DIRTY_PIXELVIEWPORT )
126 2 : os << _data.pvp;
127 2 : if( dirtyBits & DIRTY_MEMBER )
128 2 : os << _port << _device;
129 2 : }
130 :
131 : template< class N, class P, class W, class V >
132 1 : void Pipe< N, P, W, V >::deserialize( co::DataIStream& is,
133 : const uint64_t dirtyBits )
134 : {
135 1 : Object::deserialize( is, dirtyBits );
136 1 : if( dirtyBits & DIRTY_ATTRIBUTES )
137 1 : is >> co::Array< int32_t >( _iAttributes, IATTR_ALL );
138 1 : if( dirtyBits & DIRTY_WINDOWS )
139 : {
140 1 : if( isMaster( ))
141 0 : syncChildren( _windows );
142 : else
143 : {
144 1 : const bool useChildren = is.read< bool >();
145 1 : if( useChildren && _mapNodeObjects( ))
146 : {
147 0 : Windows result;
148 0 : is.deserializeChildren( this, _windows, result );
149 0 : _windows.swap( result );
150 0 : LBASSERT( _windows.size() == result.size( ));
151 : }
152 : else // consume unused ObjectVersions
153 1 : is.read< co::ObjectVersions >();
154 : }
155 : }
156 1 : if( dirtyBits & DIRTY_PIXELVIEWPORT )
157 : {
158 1 : PixelViewport pvp;
159 1 : is >> pvp;
160 1 : setPixelViewport( pvp );
161 : }
162 1 : if( dirtyBits & DIRTY_MEMBER )
163 1 : is >> _port >> _device;
164 1 : }
165 :
166 : template< class N, class P, class W, class V >
167 59064 : void Pipe< N, P, W, V >::setDirty( const uint64_t dirtyBits )
168 : {
169 59064 : Object::setDirty( dirtyBits );
170 59064 : _node->setDirty( N::DIRTY_PIPES );
171 59064 : }
172 :
173 : template< class N, class P, class W, class V >
174 5 : void Pipe< N, P, W, V >::notifyDetach()
175 : {
176 5 : Object::notifyDetach();
177 10 : while( !_windows.empty( ))
178 : {
179 4 : W* window = _windows.back();
180 4 : if( !window->isAttached() )
181 : {
182 4 : LBASSERT( isMaster( ));
183 9 : return;
184 : }
185 :
186 0 : LBASSERT( !isMaster( ));
187 :
188 0 : getLocalNode()->unmapObject( window );
189 0 : _removeWindow( window );
190 0 : _node->getServer()->getNodeFactory()->releaseWindow( window );
191 : }
192 : }
193 :
194 : template< class N, class P, class W, class V >
195 0 : void Pipe< N, P, W, V >::create( W** window )
196 : {
197 0 : *window = _node->getServer()->getNodeFactory()->createWindow(
198 : static_cast< P* >( this ));
199 0 : (*window)->init(); // not in ctor, virtual method
200 0 : }
201 :
202 : template< class N, class P, class W, class V >
203 0 : void Pipe< N, P, W, V >::release( W* window )
204 : {
205 0 : _node->getServer()->getNodeFactory()->releaseWindow( window );
206 0 : }
207 :
208 : namespace
209 : {
210 : template< class P, class V >
211 28314 : VisitorResult _accept( P* pipe, V& visitor )
212 : {
213 28314 : VisitorResult result = visitor.visitPre( pipe );
214 28314 : if( result != TRAVERSE_CONTINUE )
215 12 : return result;
216 :
217 28302 : const typename P::Windows& windows = pipe->getWindows();
218 168900 : for( typename P::Windows::const_iterator i = windows.begin();
219 112600 : i != windows.end(); ++i )
220 : {
221 33314 : switch( (*i)->accept( visitor ))
222 : {
223 : case TRAVERSE_TERMINATE:
224 5316 : return TRAVERSE_TERMINATE;
225 :
226 : case TRAVERSE_PRUNE:
227 122 : result = TRAVERSE_PRUNE;
228 122 : break;
229 :
230 : case TRAVERSE_CONTINUE:
231 : default:
232 27876 : break;
233 : }
234 : }
235 :
236 22986 : switch( visitor.visitPost( pipe ))
237 : {
238 : case TRAVERSE_TERMINATE:
239 0 : return TRAVERSE_TERMINATE;
240 :
241 : case TRAVERSE_PRUNE:
242 2 : return TRAVERSE_PRUNE;
243 :
244 : case TRAVERSE_CONTINUE:
245 : default:
246 22984 : break;
247 : }
248 :
249 22984 : return result;
250 : }
251 : }
252 :
253 : template< class N, class P, class W, class V >
254 28314 : VisitorResult Pipe< N, P, W, V >::accept( V& visitor )
255 : {
256 28314 : return _accept( static_cast< P* >( this ), visitor );
257 : }
258 :
259 : template< class N, class P, class W, class V >
260 0 : VisitorResult Pipe< N, P, W, V >::accept( V& visitor ) const
261 : {
262 0 : return _accept( static_cast< const P* >( this ), visitor );
263 : }
264 :
265 : template< class N, class P, class W, class V >
266 92 : PipePath Pipe< N, P, W, V >::getPath() const
267 : {
268 92 : const N* node = getNode();
269 92 : LBASSERT( node );
270 92 : PipePath path( node->getPath( ));
271 :
272 92 : const typename std::vector< P* >& pipes = node->getPipes();
273 : typename std::vector< P* >::const_iterator i = std::find( pipes.begin(),
274 : pipes.end(),
275 92 : this );
276 92 : LBASSERT( i != pipes.end( ));
277 92 : path.pipeIndex = std::distance( pipes.begin(), i );
278 92 : return path;
279 : }
280 :
281 : template< class N, class P, class W, class V >
282 2312 : void Pipe< N, P, W, V >::setIAttribute( const IAttribute attr,
283 : const int32_t value )
284 : {
285 2312 : if( _iAttributes[attr] == value )
286 3458 : return;
287 :
288 1166 : _iAttributes[attr] = value;
289 1166 : setDirty( DIRTY_ATTRIBUTES );
290 : }
291 :
292 : template< class N, class P, class W, class V >
293 150 : void Pipe< N, P, W, V >::setDevice( const uint32_t device )
294 : {
295 150 : _device = device;
296 150 : setDirty( DIRTY_MEMBER );
297 150 : }
298 :
299 : template< class N, class P, class W, class V >
300 0 : void Pipe< N, P, W, V >::setPort( const uint32_t port )
301 : {
302 0 : _port = port;
303 0 : setDirty( DIRTY_MEMBER );
304 0 : }
305 :
306 : template< class N, class P, class W, class V >
307 1765 : void Pipe< N, P, W, V >::_addWindow( W* window )
308 : {
309 1765 : LBASSERT( window->getPipe() == this );
310 1765 : _windows.push_back( window );
311 1765 : setDirty( DIRTY_WINDOWS );
312 1765 : }
313 :
314 : template< class N, class P, class W, class V >
315 2985 : bool Pipe< N, P, W, V >::_removeWindow( W* window )
316 : {
317 : typename Windows::iterator i = find( _windows.begin(), _windows.end(),
318 2985 : window );
319 2985 : if ( i == _windows.end( ) )
320 1492 : return false;
321 :
322 1493 : _windows.erase( i );
323 1493 : setDirty( DIRTY_WINDOWS );
324 1493 : if( !isMaster( ))
325 1493 : postRemove( window );
326 1493 : return true;
327 : }
328 :
329 : template< class N, class P, class W, class V >
330 1 : W* Pipe< N, P, W, V >::_findWindow( const uint128_t& id )
331 : {
332 3 : for( typename Windows::const_iterator i = _windows.begin();
333 2 : i != _windows.end(); ++i )
334 : {
335 1 : W* window = *i;
336 1 : if( window->getID() == id )
337 1 : return window;
338 : }
339 0 : return 0;
340 : }
341 :
342 : template< class N, class P, class W, class V >
343 1362 : const std::string& Pipe< N, P, W, V >::getIAttributeString( const IAttribute attr )
344 : {
345 1362 : return _iPipeAttributeStrings[attr];
346 : }
347 :
348 : //----------------------------------------------------------------------
349 : // viewport
350 : //----------------------------------------------------------------------
351 : template< class N, class P, class W, class V >
352 1 : void Pipe< N, P, W, V >::setPixelViewport( const PixelViewport& pvp )
353 : {
354 1 : if( pvp == _data.pvp || !pvp.hasArea( ))
355 2 : return;
356 :
357 0 : _data.pvp = pvp;
358 0 : notifyPixelViewportChanged();
359 0 : LBVERB << "Pipe pvp set: " << _data.pvp << std::endl;
360 : }
361 :
362 : template< class N, class P, class W, class V >
363 4 : void Pipe< N, P, W, V >::notifyPixelViewportChanged()
364 : {
365 4 : const Windows& windows = getWindows();
366 24 : for( typename Windows::const_iterator i = windows.begin();
367 16 : i != windows.end(); ++i )
368 : {
369 4 : (*i)->notifyViewportChanged();
370 : }
371 4 : setDirty( DIRTY_PIXELVIEWPORT );
372 4 : LBVERB << getName() << " pvp update: " << _data.pvp << std::endl;
373 4 : }
374 :
375 : //----------------------------------------------------------------------
376 : // ICommand handlers
377 : //----------------------------------------------------------------------
378 : template< class N, class P, class W, class V > bool
379 0 : Pipe< N, P, W, V >::_cmdNewWindow( co::ICommand& cmd )
380 : {
381 0 : co::ObjectICommand command( cmd );
382 :
383 0 : W* window = 0;
384 0 : create( &window );
385 0 : LBASSERT( window );
386 :
387 0 : getLocalNode()->registerObject( window );
388 0 : LBASSERT( window->isAttached() );
389 :
390 0 : send( command.getRemoteNode(), CMD_PIPE_NEW_WINDOW_REPLY )
391 0 : << command.read< uint32_t >() << window->getID();
392 :
393 0 : return true;
394 : }
395 :
396 : template< class N, class P, class W, class V > bool
397 0 : Pipe< N, P, W, V >::_cmdNewWindowReply( co::ICommand& cmd )
398 : {
399 0 : co::ObjectICommand command( cmd );
400 :
401 0 : const uint32_t requestID = command.read< uint32_t >();
402 0 : const uint128_t& result = command.read< uint128_t >();
403 :
404 0 : getLocalNode()->serveRequest( requestID, result );
405 :
406 0 : return true;
407 : }
408 :
409 : template< class N, class P, class W, class V >
410 574 : std::ostream& operator << ( std::ostream& os, const Pipe< N, P, W, V >& pipe )
411 : {
412 574 : os << lunchbox::disableFlush << lunchbox::disableHeader << "pipe"
413 : << std::endl;
414 574 : os << "{" << std::endl << lunchbox::indent;
415 :
416 574 : const std::string& name = pipe.getName();
417 574 : if( !name.empty( ))
418 82 : os << "name \"" << name << "\"" << std::endl;
419 :
420 574 : if( pipe.getPort() != LB_UNDEFINED_UINT32 )
421 0 : os << "port " << pipe.getPort() << std::endl;
422 :
423 574 : if( pipe.getDevice() != LB_UNDEFINED_UINT32 )
424 76 : os << "device " << pipe.getDevice() << std::endl;
425 :
426 574 : const PixelViewport& pvp = pipe.getPixelViewport();
427 574 : if( pvp.hasArea( ))
428 0 : os << "viewport " << pvp << std::endl;
429 :
430 574 : pipe.output( os );
431 574 : os << std::endl;
432 :
433 574 : const typename P::Windows& windows = pipe.getWindows();
434 3966 : for( typename P::Windows::const_iterator i = windows.begin();
435 2644 : i != windows.end(); ++i )
436 : {
437 748 : os << **i;
438 : }
439 :
440 574 : os << lunchbox::exdent << "}" << std::endl << lunchbox::enableHeader
441 : << lunchbox::enableFlush;
442 574 : return os;
443 : }
444 :
445 : }
446 : }
|