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