Line data Source code
1 :
2 : /* Copyright (c) 2010-2013, Stefan Eilemann <eile@equalizergraphics.com>
3 : * 2010, Cedric Stalder <cedric.stalder@gmail.com>
4 : * 2010-2014, Daniel Nachbaur <danielnachbaur@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 "window.h"
21 :
22 : #include "channel.h"
23 : #include "commands.h"
24 : #include "elementVisitor.h"
25 : #include "leafVisitor.h"
26 : #include "log.h"
27 : #include "task.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 : namespace
39 : {
40 : #define MAKE_WINDOW_ATTR_STRING( attr ) ( std::string("EQ_WINDOW_") + #attr )
41 42 : std::string _iAttributeStrings[] = {
42 : MAKE_WINDOW_ATTR_STRING( IATTR_HINT_STEREO ),
43 : MAKE_WINDOW_ATTR_STRING( IATTR_HINT_DOUBLEBUFFER ),
44 : MAKE_WINDOW_ATTR_STRING( IATTR_HINT_FULLSCREEN ),
45 : MAKE_WINDOW_ATTR_STRING( IATTR_HINT_DECORATION ),
46 : MAKE_WINDOW_ATTR_STRING( IATTR_HINT_SWAPSYNC ),
47 : MAKE_WINDOW_ATTR_STRING( IATTR_HINT_DRAWABLE ),
48 : MAKE_WINDOW_ATTR_STRING( IATTR_HINT_STATISTICS ),
49 : MAKE_WINDOW_ATTR_STRING( IATTR_HINT_SCREENSAVER ),
50 : MAKE_WINDOW_ATTR_STRING( IATTR_HINT_GRAB_POINTER ),
51 : MAKE_WINDOW_ATTR_STRING( IATTR_HINT_WIDTH ),
52 : MAKE_WINDOW_ATTR_STRING( IATTR_HINT_HEIGHT ),
53 : MAKE_WINDOW_ATTR_STRING( IATTR_PLANES_COLOR ),
54 : MAKE_WINDOW_ATTR_STRING( IATTR_PLANES_ALPHA ),
55 : MAKE_WINDOW_ATTR_STRING( IATTR_PLANES_DEPTH ),
56 : MAKE_WINDOW_ATTR_STRING( IATTR_PLANES_STENCIL ),
57 : MAKE_WINDOW_ATTR_STRING( IATTR_PLANES_ACCUM ),
58 : MAKE_WINDOW_ATTR_STRING( IATTR_PLANES_ACCUM_ALPHA ),
59 : MAKE_WINDOW_ATTR_STRING( IATTR_PLANES_SAMPLES )
60 21 : };
61 : }
62 :
63 : template< class P, class W, class C, class Settings >
64 1039 : Window< P, W, C, Settings >::Window( P* parent )
65 1039 : : _pipe( parent )
66 : {
67 1039 : LBASSERT( parent );
68 1039 : parent->_addWindow( static_cast< W* >( this ) );
69 1039 : LBLOG( LOG_INIT ) << "New " << lunchbox::className( this ) << std::endl;
70 1039 : }
71 :
72 : template< class P, class W, class C, class Settings >
73 2078 : Window< P, W, C, Settings >::BackupData::BackupData()
74 2078 : : fixedVP( true )
75 : {
76 2078 : }
77 :
78 : template< class P, class W, class C, class Settings >
79 768 : Window< P, W, C, Settings >::~Window( )
80 : {
81 768 : LBLOG( LOG_INIT ) << "Delete " << lunchbox::className( this ) << std::endl;
82 3006 : while( !_channels.empty( ))
83 : {
84 1470 : C* channel = _channels.back();
85 :
86 1470 : LBASSERT( channel->getWindow() == this );
87 1470 : _removeChannel( channel );
88 1470 : delete channel;
89 : }
90 768 : _pipe->_removeWindow( static_cast< W* >( this ) );
91 1536 : }
92 :
93 : template< class P, class W, class C, class Settings >
94 748 : void Window< P, W, C, Settings >::init()
95 : {
96 748 : notifyViewportChanged();
97 748 : unsetDirty( DIRTY_VIEWPORT );
98 748 : }
99 :
100 : template< class P, class W, class C, class Settings >
101 38 : void Window< P, W, C, Settings >::attach( const uint128_t& id,
102 : const uint32_t instanceID )
103 : {
104 38 : Object::attach( id, instanceID );
105 38 : co::CommandQueue* queue = _pipe->getMainThreadQueue();
106 38 : LBASSERT( queue );
107 :
108 38 : registerCommand( CMD_WINDOW_NEW_CHANNEL,
109 : CmdFunc( this, &Window< P, W, C, Settings >::_cmdNewChannel ),
110 : queue );
111 38 : registerCommand( CMD_WINDOW_NEW_CHANNEL_REPLY,
112 : CmdFunc( this, &Window< P, W, C, Settings >::_cmdNewChannelReply ),
113 : 0 );
114 38 : }
115 :
116 : template< class P, class W, class C, class Settings >
117 23 : void Window< P, W, C, Settings >::backup()
118 : {
119 23 : Object::backup();
120 23 : _backup = _data;
121 23 : }
122 :
123 : template< class P, class W, class C, class Settings >
124 2 : void Window< P, W, C, Settings >::restore()
125 : {
126 2 : _data = _backup;
127 2 : _data.drawableConfig = DrawableConfig();
128 :
129 2 : Object::restore();
130 2 : notifyViewportChanged();
131 2 : setDirty( DIRTY_VIEWPORT );
132 2 : }
133 :
134 : template< class P, class W, class C, class Settings >
135 61 : uint128_t Window< P, W, C, Settings >::commit( const uint32_t incarnation )
136 : {
137 61 : if( Serializable::isDirty( DIRTY_CHANNELS ))
138 40 : commitChildren< C >( _channels, CMD_WINDOW_NEW_CHANNEL, incarnation );
139 61 : return Object::commit( incarnation );
140 : }
141 :
142 : template< class P, class W, class C, class Settings >
143 65 : void Window< P, W, C, Settings >::serialize( co::DataOStream& os,
144 : const uint64_t dirtyBits )
145 : {
146 65 : Object::serialize( os, dirtyBits );
147 65 : if( dirtyBits & DIRTY_SETTINGS )
148 49 : _data.windowSettings.serialize( os );
149 65 : if( dirtyBits & DIRTY_CHANNELS && isMaster( ))
150 : {
151 43 : os << _mapNodeObjects();
152 43 : os.serializeChildren( _channels );
153 : }
154 65 : if( dirtyBits & DIRTY_VIEWPORT )
155 41 : os << _data.vp << _data.pvp << _data.fixedVP;
156 65 : if( dirtyBits & DIRTY_DRAWABLECONFIG )
157 45 : os << _data.drawableConfig;
158 65 : }
159 :
160 : template< class P, class W, class C, class Settings >
161 46 : void Window< P, W, C, Settings >::deserialize( co::DataIStream& is,
162 : const uint64_t dirtyBits )
163 : {
164 46 : Object::deserialize( is, dirtyBits );
165 46 : if( dirtyBits & DIRTY_SETTINGS )
166 38 : _data.windowSettings.deserialize( is );
167 46 : if( dirtyBits & DIRTY_CHANNELS )
168 : {
169 29 : if( isMaster( ))
170 5 : syncChildren( _channels );
171 : else
172 : {
173 24 : const bool useChildren = is.read< bool >();
174 24 : if( useChildren && _mapNodeObjects( ))
175 : {
176 0 : Channels result;
177 0 : is.deserializeChildren( this, _channels, result );
178 0 : _channels.swap( result );
179 0 : LBASSERT( _channels.size() == result.size( ));
180 : }
181 : else // consume unused ObjectVersions
182 24 : is.read< co::ObjectVersions >();
183 : }
184 : }
185 46 : if( dirtyBits & DIRTY_VIEWPORT )
186 : {
187 : // Ignore data from master (server) if we have local changes
188 35 : if( !Serializable::isDirty( DIRTY_VIEWPORT ) || isMaster( ))
189 : {
190 33 : is >> _data.vp >> _data.pvp >> _data.fixedVP;
191 33 : notifyViewportChanged();
192 : }
193 : else // consume unused data
194 2 : is.getRemainingBuffer( sizeof( _data.vp ) + sizeof( _data.pvp ) +
195 2 : sizeof( _data.fixedVP ));
196 : }
197 :
198 46 : if( dirtyBits & DIRTY_DRAWABLECONFIG )
199 35 : is >> _data.drawableConfig;
200 46 : }
201 :
202 : template< class P, class W, class C, class Settings >
203 29033 : void Window< P, W, C, Settings >::setDirty( const uint64_t dirtyBits )
204 : {
205 29033 : Object::setDirty( dirtyBits );
206 29033 : _pipe->setDirty( P::DIRTY_WINDOWS );
207 29033 : }
208 :
209 : template< class P, class W, class C, class Settings >
210 38 : void Window< P, W, C, Settings >::notifyDetach()
211 : {
212 38 : Object::notifyDetach();
213 38 : co::LocalNodePtr node = getLocalNode();
214 :
215 38 : if( isMaster( ))
216 : {
217 327 : for( typename Channels::const_iterator i = _channels.begin();
218 218 : i != _channels.end(); ++i )
219 : {
220 86 : node->releaseObject( *i );
221 : }
222 : }
223 : else
224 : {
225 30 : while( !_channels.empty( ))
226 : {
227 0 : C* channel = _channels.back();
228 0 : LBASSERT( channel->isAttached( ));
229 :
230 0 : node->releaseObject( channel );
231 0 : _removeChannel( channel );
232 0 : _pipe->getServer()->getNodeFactory()->releaseChannel( channel );
233 : }
234 38 : }
235 38 : }
236 :
237 : template< class P, class W, class C, class Settings >
238 0 : void Window< P, W, C, Settings >::create( C** channel )
239 : {
240 0 : *channel = _pipe->getServer()->getNodeFactory()->createChannel(
241 : static_cast< W* >( this ));
242 0 : (*channel)->init(); // not in ctor, virtual method
243 0 : }
244 :
245 : template< class P, class W, class C, class Settings >
246 0 : void Window< P, W, C, Settings >::release( C* channel )
247 : {
248 0 : _pipe->getServer()->getNodeFactory()->releaseChannel( channel );
249 0 : }
250 :
251 : template< class P, class W, class C, class Settings >
252 2297 : void Window< P, W, C, Settings >::_addChannel( C* channel )
253 : {
254 2297 : LBASSERT( channel->getWindow() == this );
255 2297 : _channels.push_back( channel );
256 2297 : setDirty( DIRTY_CHANNELS );
257 2297 : }
258 :
259 : template< class P, class W, class C, class Settings >
260 2955 : bool Window< P, W, C, Settings >::_removeChannel( C* channel )
261 : {
262 2955 : typename Channels::iterator i = lunchbox::find( _channels, channel );
263 2955 : if( i == _channels.end( ))
264 1470 : return false;
265 :
266 1485 : _channels.erase( i );
267 1485 : setDirty( DIRTY_CHANNELS );
268 1485 : if( !isMaster( ))
269 1485 : postRemove( channel );
270 1485 : return true;
271 : }
272 :
273 : template< class P, class W, class C, class Settings >
274 15 : C* Window< P, W, C, Settings >::_findChannel( const uint128_t& id )
275 : {
276 45 : for( typename Channels::const_iterator i = _channels.begin();
277 30 : i != _channels.end(); ++i )
278 : {
279 15 : C* channel = *i;
280 15 : if( channel->getID() == id )
281 15 : return channel;
282 : }
283 0 : return 0;
284 : }
285 :
286 : template< class P, class W, class C, class Settings >
287 13777 : void Window< P, W, C, Settings >::setIAttribute( const WindowSettings::IAttribute attr,
288 : const int32_t value )
289 : {
290 13777 : if( _data.windowSettings.setIAttribute( attr, value ))
291 8782 : setDirty( DIRTY_SETTINGS );
292 13777 : }
293 :
294 : template< class P, class W, class C, class Settings > int32_t
295 7587 : Window< P, W, C, Settings >::getIAttribute( const WindowSettings::IAttribute attr ) const
296 : {
297 7587 : return _data.windowSettings.getIAttribute( attr );
298 : }
299 :
300 : template< class P, class W, class C, class Settings > const std::string&
301 6481 : Window< P, W, C, Settings >::getIAttributeString( const WindowSettings::IAttribute attr )
302 : {
303 6481 : return _iAttributeStrings[attr];
304 : }
305 :
306 : template< class P, class W, class C, class Settings >
307 0 : Settings& Window< P, W, C, Settings >::_getSettings()
308 : {
309 0 : return _data.windowSettings;
310 : }
311 :
312 : template< class P, class W, class C, class Settings >
313 17 : const Settings& Window< P, W, C, Settings >::getSettings() const
314 : {
315 17 : return _data.windowSettings;
316 : }
317 :
318 : template< class P, class W, class C, class Settings >
319 0 : WindowPath Window< P, W, C, Settings >::getPath() const
320 : {
321 0 : const P* pipe = getPipe();
322 0 : LBASSERT( pipe );
323 0 : WindowPath path( pipe->getPath( ));
324 :
325 0 : const typename std::vector< W* >& windows = pipe->getWindows();
326 : typename std::vector< W* >::const_iterator i = std::find( windows.begin(),
327 : windows.end(),
328 0 : this );
329 0 : LBASSERT( i != windows.end( ));
330 0 : path.windowIndex = std::distance( windows.begin(), i );
331 0 : return path;
332 : }
333 :
334 : namespace
335 : {
336 : template< class W, class V >
337 19453 : VisitorResult _accept( W* window, V& visitor )
338 : {
339 19453 : VisitorResult result = visitor.visitPre( window );
340 19453 : if( result != TRAVERSE_CONTINUE )
341 0 : return result;
342 :
343 19453 : const typename W::Channels& channels = window->getChannels();
344 236454 : for( typename W::Channels::const_iterator i = channels.begin();
345 157636 : i != channels.end(); ++i )
346 : {
347 62283 : switch( (*i)->accept( visitor ))
348 : {
349 : case TRAVERSE_TERMINATE:
350 2918 : return TRAVERSE_TERMINATE;
351 :
352 : case TRAVERSE_PRUNE:
353 360 : result = TRAVERSE_PRUNE;
354 360 : break;
355 :
356 : case TRAVERSE_CONTINUE:
357 : default:
358 59005 : break;
359 : }
360 : }
361 :
362 16535 : switch( visitor.visitPost( window ))
363 : {
364 : case TRAVERSE_TERMINATE:
365 0 : return TRAVERSE_TERMINATE;
366 :
367 : case TRAVERSE_PRUNE:
368 0 : return TRAVERSE_PRUNE;
369 :
370 : case TRAVERSE_CONTINUE:
371 : default:
372 16535 : break;
373 : }
374 :
375 16535 : return result;
376 : }
377 : }
378 :
379 : template< class P, class W, class C, class Settings >
380 19453 : VisitorResult Window< P, W, C, Settings >::accept( Visitor& visitor )
381 : {
382 19453 : return _accept( static_cast< W* >( this ), visitor );
383 : }
384 :
385 : template< class P, class W, class C, class Settings >
386 0 : VisitorResult Window< P, W, C, Settings >::accept( Visitor& visitor ) const
387 : {
388 0 : return _accept( static_cast< const W* >( this ), visitor );
389 : }
390 :
391 : template< class P, class W, class C, class Settings >
392 2604 : const PixelViewport& Window< P, W, C, Settings >::getPixelViewport() const
393 : {
394 2604 : return _data.windowSettings.getPixelViewport();
395 : }
396 :
397 : template< class P, class W, class C, class Settings >
398 283 : void Window< P, W, C, Settings >::setName( const std::string& name )
399 : {
400 283 : Object::setName( name );
401 283 : if( _data.windowSettings.getName() == name )
402 283 : return;
403 283 : _data.windowSettings.setName( name );
404 283 : setDirty( DIRTY_SETTINGS );
405 : }
406 :
407 : template< class P, class W, class C, class Settings >
408 327 : void Window< P, W, C, Settings >::setPixelViewport( const PixelViewport& pvp )
409 : {
410 327 : LBASSERTINFO( pvp.isValid(), pvp );
411 327 : if( !pvp.isValid( ))
412 0 : return;
413 :
414 327 : _data.fixedVP = false;
415 :
416 327 : if( pvp == _data.pvp && _data.vp.hasArea( ))
417 17 : return;
418 :
419 310 : _data.pvp = pvp;
420 310 : _data.vp.invalidate();
421 310 : _data.windowSettings.setPixelViewport( pvp );
422 :
423 310 : notifyViewportChanged();
424 310 : setDirty( DIRTY_VIEWPORT );
425 310 : setDirty( DIRTY_SETTINGS );
426 : }
427 :
428 : template< class P, class W, class C, class Settings >
429 480 : void Window< P, W, C, Settings >::setViewport( const Viewport& vp )
430 : {
431 480 : if( !vp.hasArea())
432 153 : return;
433 :
434 327 : _data.fixedVP = true;
435 :
436 327 : if( vp == _data.vp && _data.pvp.hasArea( ))
437 0 : return;
438 327 : _data.vp = vp;
439 327 : _data.pvp.invalidate();
440 327 : _data.windowSettings.setPixelViewport( PixelViewport( ));
441 :
442 327 : setDirty( DIRTY_VIEWPORT );
443 327 : setDirty( DIRTY_SETTINGS );
444 327 : notifyViewportChanged();
445 : }
446 :
447 : template< class P, class W, class C, class Settings >
448 1425 : void Window< P, W, C, Settings >::notifyViewportChanged()
449 : {
450 1425 : const PixelViewport pipePVP = _pipe->getPixelViewport();
451 :
452 1425 : if( _data.fixedVP ) // update pixel viewport
453 : {
454 1093 : const PixelViewport oldPVP = _data.pvp;
455 1093 : _data.pvp = pipePVP;
456 1093 : _data.pvp.apply( _data.vp );
457 1093 : if( oldPVP != _data.pvp )
458 : {
459 243 : _data.windowSettings.setPixelViewport( _data.pvp );
460 243 : setDirty( DIRTY_VIEWPORT );
461 243 : setDirty( DIRTY_SETTINGS );
462 : }
463 : }
464 : else // update viewport
465 : {
466 332 : const Viewport oldVP = _data.vp;
467 332 : _data.vp = _data.pvp / pipePVP;
468 332 : if( oldVP != _data.vp )
469 318 : setDirty( DIRTY_VIEWPORT );
470 : }
471 :
472 4479 : for( typename Channels::const_iterator i = _channels.begin();
473 2986 : i != _channels.end(); ++i )
474 : {
475 68 : (*i)->notifyViewportChanged();
476 : }
477 1425 : LBVERB << getName() << " viewport update: " << _data.vp << ":" << _data.pvp
478 0 : << std::endl;
479 1425 : }
480 :
481 : template< class P, class W, class C, class Settings >
482 15 : void Window< P, W, C, Settings >::_setDrawableConfig(const DrawableConfig& drawableConfig)
483 : {
484 15 : _data.drawableConfig = drawableConfig;
485 15 : setDirty( DIRTY_DRAWABLECONFIG );
486 15 : }
487 :
488 : //----------------------------------------------------------------------
489 : // ICommand handlers
490 : //----------------------------------------------------------------------
491 : template< class P, class W, class C, class Settings >
492 0 : bool Window< P, W, C, Settings >::_cmdNewChannel( co::ICommand& cmd )
493 : {
494 0 : co::ObjectICommand command( cmd );
495 :
496 0 : C* channel = 0;
497 0 : create( &channel );
498 0 : LBASSERT( channel );
499 :
500 0 : getLocalNode()->registerObject( channel );
501 0 : LBASSERT( channel->isAttached() );
502 :
503 0 : send( command.getRemoteNode(), CMD_WINDOW_NEW_CHANNEL_REPLY )
504 0 : << command.read< uint32_t >() << channel->getID();
505 0 : LBASSERT( channel->isAttached( ));
506 :
507 0 : return true;
508 : }
509 :
510 : template< class P, class W, class C, class Settings >
511 0 : bool Window< P, W, C, Settings >::_cmdNewChannelReply( co::ICommand& cmd )
512 : {
513 0 : co::ObjectICommand command( cmd );
514 :
515 0 : const uint32_t requestID = command.read< uint32_t >();
516 0 : const uint128_t& result = command.read< uint128_t >();
517 :
518 0 : getLocalNode()->serveRequest( requestID, result );
519 :
520 0 : return true;
521 : }
522 :
523 : template< class P, class W, class C, class Settings >
524 409 : std::ostream& operator << ( std::ostream& os, const Window< P, W, C, Settings >& window )
525 : {
526 818 : os << lunchbox::disableFlush << lunchbox::disableHeader
527 409 : << "window" << std::endl;
528 409 : os << "{" << std::endl << lunchbox::indent;
529 :
530 409 : const std::string& name = window.getName();
531 409 : if( !name.empty( ))
532 173 : os << "name \"" << name << "\"" << std::endl;
533 :
534 409 : const Viewport& vp = window.getViewport();
535 409 : const PixelViewport& pvp = window.getPixelViewport();
536 409 : if( vp.isValid( ) && window.hasFixedViewport( ))
537 : {
538 256 : if( pvp.hasArea( ))
539 16 : os << "viewport " << pvp << std::endl;
540 256 : os << "viewport " << vp << std::endl;
541 : }
542 153 : else if( pvp.hasArea( ))
543 : {
544 153 : if( vp != Viewport::FULL && vp.isValid( ))
545 153 : os << "viewport " << vp << std::endl;
546 153 : os << "viewport " << pvp << std::endl;
547 : }
548 :
549 409 : window.output( os );
550 :
551 409 : const typename W::Channels& channels = window.getChannels();
552 3807 : for( typename W::Channels::const_iterator i = channels.begin();
553 2538 : i != channels.end(); ++i )
554 : {
555 860 : os << **i;
556 : }
557 :
558 409 : os << lunchbox::exdent << "}" << std::endl << lunchbox::enableHeader
559 : << lunchbox::enableFlush;
560 409 : return os;
561 : }
562 :
563 : }
564 : }
|