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