Line data Source code
1 :
2 : /* Copyright (c) 2005-2015, 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 "global.h"
23 : #include "channel.h"
24 : #include "config.h"
25 : #include "compound.h"
26 : #include "log.h"
27 : #include "node.h"
28 : #include "nodeFactory.h"
29 : #include "pipe.h"
30 :
31 : #include <eq/fabric/commands.h>
32 : #include <eq/fabric/elementVisitor.h>
33 : #include <eq/fabric/leafVisitor.h>
34 : #include <eq/fabric/paths.h>
35 : #include <co/objectICommand.h>
36 :
37 : #include <boost/foreach.hpp>
38 :
39 : namespace eq
40 : {
41 : namespace server
42 : {
43 : typedef fabric::Window< Pipe, Window, Channel > Super;
44 : typedef co::CommandFunc<Window> WindowFunc;
45 :
46 1494 : Window::Window( Pipe* parent )
47 : : Super( parent )
48 : , _active( 0 )
49 : , _state( STATE_STOPPED )
50 1494 : , _maxFPS( std::numeric_limits< float >::max( ))
51 : , _nvSwapBarrier( 0 )
52 : , _nvNetBarrier( 0 )
53 : , _lastDrawChannel( 0 )
54 : , _swapFinish( false )
55 2988 : , _swap( false )
56 : {
57 1494 : const Global* global = Global::instance();
58 32868 : for( unsigned i = 0; i < WindowSettings::IATTR_ALL; ++i )
59 : {
60 31374 : const WindowSettings::IAttribute attr = static_cast< WindowSettings::IAttribute >( i );
61 31374 : setIAttribute( attr, global->getWindowIAttribute( attr ));
62 : }
63 1494 : }
64 :
65 2984 : Window::~Window()
66 : {
67 2984 : }
68 :
69 4 : void Window::attach( const uint128_t& id, const uint32_t instanceID )
70 : {
71 4 : Super::attach( id, instanceID );
72 :
73 4 : co::CommandQueue* cmdQ = getCommandThreadQueue();
74 : registerCommand( fabric::CMD_OBJECT_SYNC,
75 4 : WindowFunc( this, &Window::_cmdSync ), cmdQ );
76 : registerCommand( fabric::CMD_WINDOW_CONFIG_INIT_REPLY,
77 4 : WindowFunc( this, &Window::_cmdConfigInitReply ), cmdQ );
78 : registerCommand( fabric::CMD_WINDOW_CONFIG_EXIT_REPLY,
79 4 : WindowFunc( this, &Window::_cmdConfigExitReply ), cmdQ );
80 4 : }
81 :
82 0 : void Window::removeChild( const uint128_t& id )
83 : {
84 0 : LBASSERT( getConfig()->isRunning( ));
85 :
86 0 : Channel* channel = _findChannel( id );
87 0 : LBASSERT( channel );
88 0 : if( channel )
89 0 : channel->postDelete();
90 0 : }
91 :
92 0 : void Window::postDelete()
93 : {
94 0 : _state = State( _state.get() | STATE_DELETE );
95 0 : getConfig()->postNeedsFinish();
96 :
97 0 : const Channels& channels = getChannels();
98 0 : for( Channels::const_iterator i = channels.begin(); i!=channels.end(); ++i )
99 : {
100 0 : (*i)->postDelete();
101 : }
102 0 : }
103 :
104 0 : const Node* Window::getNode() const
105 : {
106 0 : const Pipe* pipe = getPipe();
107 0 : LBASSERT( pipe );
108 0 : return ( pipe ? pipe->getNode() : 0 );
109 : }
110 :
111 10 : Node* Window::getNode()
112 : {
113 10 : Pipe* pipe = getPipe();
114 10 : LBASSERT( pipe );
115 10 : return ( pipe ? pipe->getNode() : 0 );
116 : }
117 :
118 0 : const Config* Window::getConfig() const
119 : {
120 0 : const Pipe* pipe = getPipe();
121 0 : LBASSERT( pipe );
122 0 : return ( pipe ? pipe->getConfig() : 0);
123 : }
124 :
125 588 : Config* Window::getConfig()
126 : {
127 588 : Pipe* pipe = getPipe();
128 588 : LBASSERT( pipe );
129 588 : return ( pipe ? pipe->getConfig() : 0);
130 : }
131 :
132 12 : ServerPtr Window::getServer()
133 : {
134 12 : Pipe* pipe = getPipe();
135 12 : LBASSERT( pipe );
136 12 : return ( pipe ? pipe->getServer() : 0 );
137 : }
138 :
139 8 : co::CommandQueue* Window::getMainThreadQueue()
140 : {
141 8 : Pipe* pipe = getPipe();
142 8 : LBASSERT( pipe );
143 8 : return pipe->getMainThreadQueue();
144 : }
145 :
146 12 : co::CommandQueue* Window::getCommandThreadQueue()
147 : {
148 12 : Pipe* pipe = getPipe();
149 12 : LBASSERT( pipe );
150 12 : return pipe->getCommandThreadQueue();
151 : }
152 :
153 0 : Channel* Window::getChannel( const ChannelPath& path )
154 : {
155 0 : const Channels& channels = getChannels();
156 0 : LBASSERT( channels.size() > path.channelIndex );
157 :
158 0 : if( channels.size() <= path.channelIndex )
159 0 : return 0;
160 :
161 0 : return channels[ path.channelIndex ];
162 : }
163 :
164 2 : void Window::activate()
165 : {
166 2 : Pipe* pipe = getPipe();
167 2 : LBASSERT( pipe );
168 :
169 2 : ++_active;
170 2 : pipe->activate();
171 :
172 2 : LBLOG( LOG_VIEW ) << "activate: " << _active << std::endl;
173 2 : }
174 :
175 2 : void Window::deactivate()
176 : {
177 2 : LBASSERT( _active != 0 );
178 2 : Pipe* pipe = getPipe();
179 2 : LBASSERT( pipe );
180 :
181 2 : --_active;
182 2 : pipe->deactivate();
183 :
184 2 : LBLOG( LOG_VIEW ) << "deactivate: " << _active << std::endl;
185 2 : }
186 :
187 4 : void Window::addTasks( const uint32_t tasks )
188 : {
189 4 : Pipe* pipe = getPipe();
190 4 : LBASSERT( pipe );
191 4 : setTasks( getTasks() | tasks );
192 4 : pipe->addTasks( tasks );
193 4 : }
194 :
195 : //---------------------------------------------------------------------------
196 : // swap barrier operations
197 : //---------------------------------------------------------------------------
198 0 : void Window::_resetSwapBarriers()
199 : {
200 0 : Node* node = getNode();
201 0 : LBASSERT( node );
202 :
203 0 : BOOST_FOREACH( co::Barrier* barrier, _masterBarriers )
204 : {
205 0 : node->releaseBarrier( barrier );
206 : }
207 :
208 0 : _nvNetBarrier = 0;
209 0 : _masterBarriers.clear();
210 0 : _barriers.clear();
211 0 : }
212 :
213 0 : co::Barrier* Window::joinSwapBarrier( co::Barrier* barrier )
214 : {
215 0 : _swapFinish = true;
216 :
217 0 : if( !barrier )
218 : {
219 0 : Node* node = getNode();
220 0 : barrier = node->getBarrier();
221 0 : barrier->increase();
222 :
223 0 : _masterBarriers.push_back( barrier );
224 0 : _barriers.push_back( barrier );
225 0 : return barrier;
226 : }
227 :
228 0 : co::BarriersCIter i = lunchbox::find( _barriers, barrier );
229 0 : if( i != _barriers.end( )) // Issue #39: window already has this barrier
230 0 : return barrier;
231 :
232 0 : LBASSERT( getPipe() );
233 0 : const Windows& windows = getPipe()->getWindows();
234 0 : bool beforeSelf = true;
235 :
236 : // Check if another window in the same thread is using the swap barrier
237 0 : for( WindowsCIter j = windows.begin(); j != windows.end(); ++j )
238 : {
239 0 : Window* window = *j;
240 0 : if( window == this ) // skip self
241 : {
242 0 : beforeSelf = false;
243 0 : continue;
244 : }
245 :
246 0 : co::Barriers& barriers = window->_barriers;
247 0 : co::BarriersIter k = lunchbox::find( barriers, barrier );
248 0 : if( k == barriers.end( ))
249 0 : continue;
250 :
251 0 : if( beforeSelf ) // some earlier window will do the barrier for us
252 0 : return barrier;
253 :
254 : // else we will do the barrier, remove from later window
255 0 : barriers.erase( k );
256 0 : _barriers.push_back( barrier );
257 0 : return barrier;
258 : }
259 :
260 : // No other window on this pipe does the barrier yet
261 0 : barrier->increase();
262 0 : _barriers.push_back( barrier );
263 0 : return barrier;
264 : }
265 :
266 0 : co::Barrier* Window::joinNVSwapBarrier( SwapBarrierConstPtr swapBarrier,
267 : co::Barrier* netBarrier )
268 : {
269 0 : LBASSERTINFO( !_nvSwapBarrier,
270 : "Only one NV_swap_group barrier per window allowed" );
271 :
272 0 : _nvSwapBarrier = swapBarrier;
273 0 : _nvNetBarrier = netBarrier;
274 : // no _swapFinish = true since NV_swap_group takes care of this
275 :
276 0 : if( !_nvNetBarrier )
277 : {
278 0 : Node* node = getNode();
279 0 : _nvNetBarrier = node->getBarrier();
280 0 : _masterBarriers.push_back( _nvNetBarrier );
281 : }
282 :
283 0 : _nvNetBarrier->increase();
284 0 : _barriers.push_back( _nvNetBarrier );
285 0 : return _nvNetBarrier;
286 : }
287 :
288 :
289 6 : co::ObjectOCommand Window::send( const uint32_t cmd )
290 : {
291 6 : return getNode()->send( cmd, getID( ));
292 : }
293 :
294 : //===========================================================================
295 : // Operations
296 : //===========================================================================
297 : //---------------------------------------------------------------------------
298 : // init
299 : //---------------------------------------------------------------------------
300 2 : void Window::configInit( const uint128_t& initID, const uint32_t /*frame*/ )
301 : {
302 2 : LBASSERT( !needsDelete( ));
303 2 : LBASSERT( _state == STATE_STOPPED );
304 2 : _state = STATE_INITIALIZING;
305 :
306 2 : LBLOG( LOG_INIT ) << "Create Window" << std::endl;
307 2 : getPipe()->send( fabric::CMD_PIPE_CREATE_WINDOW ) << getID();
308 :
309 2 : LBLOG( LOG_INIT ) << "Init Window" << std::endl;
310 2 : send( fabric::CMD_WINDOW_CONFIG_INIT ) << initID;
311 2 : LBLOG( LOG_TASKS ) << "TASK window configInit " << " id " << getID()
312 2 : << std::endl;
313 2 : }
314 :
315 2 : bool Window::syncConfigInit()
316 : {
317 2 : LBASSERT( !needsDelete( ));
318 2 : LBASSERT( _state == STATE_INITIALIZING || _state == STATE_INIT_SUCCESS ||
319 : _state == STATE_INIT_FAILED );
320 :
321 2 : _state.waitNE( STATE_INITIALIZING );
322 :
323 2 : if( _state == STATE_INIT_SUCCESS )
324 : {
325 0 : _state = STATE_RUNNING;
326 0 : return true;
327 : }
328 :
329 2 : configExit();
330 2 : return false;
331 : }
332 :
333 : //---------------------------------------------------------------------------
334 : // exit
335 : //---------------------------------------------------------------------------
336 2 : void Window::configExit()
337 : {
338 2 : if( _state & STATE_EXITING )
339 2 : return;
340 :
341 2 : LBASSERT( isRunning() || _state == STATE_INIT_FAILED );
342 4 : _state =
343 4 : State( needsDelete() ? STATE_EXITING | STATE_DELETE : STATE_EXITING );
344 :
345 2 : LBLOG( LOG_INIT ) << "Exit Window" << std::endl;
346 2 : send( fabric::CMD_WINDOW_CONFIG_EXIT );
347 : }
348 :
349 2 : bool Window::syncConfigExit()
350 : {
351 2 : _state.waitNE( STATE_EXITING, State( STATE_EXITING | STATE_DELETE ));
352 2 : const bool success = ( _state & STATE_EXIT_SUCCESS );
353 2 : LBASSERT( success || _state & STATE_EXIT_FAILED );
354 :
355 : // EXIT_FAILED -> STOPPED transition
356 2 : uint32_t state = needsDelete() ? STATE_DELETE : 0;
357 2 : state |= ( isActive() ? STATE_FAILED : STATE_STOPPED );
358 2 : _state = State( state );
359 2 : _nvSwapBarrier = 0;
360 2 : return success;
361 : }
362 :
363 : //---------------------------------------------------------------------------
364 : // update
365 : //---------------------------------------------------------------------------
366 0 : void Window::updateDraw( const uint128_t& frameID, const uint32_t frameNumber )
367 : {
368 0 : if( !isRunning( ))
369 0 : return;
370 :
371 0 : LBASSERT( isActive( ))
372 :
373 : send( fabric::CMD_WINDOW_FRAME_START )
374 0 : << getVersion() << frameID << frameNumber;
375 0 : LBLOG( LOG_TASKS ) << "TASK window start frame " << frameNumber
376 0 : << " id " << frameID << std::endl;
377 :
378 0 : const Channels& channels = getChannels();
379 0 : _swap = false;
380 :
381 0 : for( ChannelsCIter i = channels.begin(); i != channels.end(); ++i )
382 : {
383 0 : Channel* channel = *i;
384 0 : if( channel->update( frameID, frameNumber ))
385 0 : _swap = true;
386 : }
387 :
388 0 : if( _lastDrawChannel )
389 0 : _lastDrawChannel = 0;
390 : else // no FrameDrawFinish sent
391 : {
392 0 : send( fabric::CMD_WINDOW_FRAME_DRAW_FINISH ) << frameID << frameNumber;
393 0 : LBLOG( LOG_TASKS ) << "TASK window draw finish " << getName()
394 0 : << " frame " << frameNumber
395 0 : << " id " << frameID << std::endl;
396 : }
397 :
398 0 : if( _swapFinish )
399 : {
400 0 : send( fabric::CMD_WINDOW_FLUSH );
401 0 : LBLOG( LOG_TASKS ) << "TASK flush " << std::endl;
402 : }
403 : }
404 :
405 0 : void Window::updatePost( const uint128_t& frameID,
406 : const uint32_t frameNumber )
407 : {
408 0 : if( !isRunning( ))
409 0 : return;
410 :
411 0 : LBASSERT( isActive( ))
412 0 : _updateSwap( frameNumber );
413 :
414 0 : send( fabric::CMD_WINDOW_FRAME_FINISH ) << frameID << frameNumber;
415 0 : LBLOG( LOG_TASKS ) << "TASK window finish frame " << frameNumber
416 0 : << " id " << frameID << std::endl;
417 : }
418 :
419 0 : void Window::_updateSwap( const uint32_t frameNumber )
420 : {
421 0 : if( _swapFinish )
422 : {
423 0 : send( fabric::CMD_WINDOW_FINISH );
424 0 : LBLOG( LOG_TASKS ) << "TASK finish " << frameNumber << std::endl;
425 0 : _swapFinish = false;
426 : }
427 :
428 0 : if( _maxFPS < std::numeric_limits< float >::max( ))
429 : {
430 0 : const float minFrameTime = 1000.0f / _maxFPS;
431 0 : send( fabric::CMD_WINDOW_THROTTLE_FRAMERATE ) << minFrameTime;
432 0 : LBLOG( LOG_TASKS ) << "TASK Throttle framerate "
433 0 : << minFrameTime << std::endl;
434 :
435 0 : _maxFPS = std::numeric_limits< float >::max();
436 : }
437 :
438 0 : for( co::BarriersCIter i = _barriers.begin(); i != _barriers.end(); ++i )
439 : {
440 0 : const co::Barrier* barrier = *i;
441 0 : if( barrier->getHeight() <= 1 )
442 : {
443 0 : LBVERB << "Ignoring swap barrier of height " << barrier->getHeight()
444 0 : << std::endl;
445 0 : continue;
446 : }
447 :
448 0 : send( fabric::CMD_WINDOW_BARRIER ) << co::ObjectVersion( barrier );
449 0 : LBLOG( LOG_TASKS ) << "TASK barrier barrier "
450 0 : << co::ObjectVersion( barrier ) << std::endl;
451 : }
452 :
453 0 : if( _nvNetBarrier )
454 : {
455 0 : if( _nvNetBarrier->getHeight() <= 1 )
456 : {
457 0 : LBWARN << "Ignoring NV swap barrier of height "
458 0 : << _nvNetBarrier->getHeight() << std::endl;
459 : }
460 : else
461 : {
462 0 : LBASSERT( _nvSwapBarrier );
463 0 : LBASSERT( _nvSwapBarrier->isNvSwapBarrier( ));
464 : // Entering the NV_swap_group. The _nvNetBarrier is also part of
465 : // _barriers, which means that the pre-join was already sync'ed
466 : // with a barrier.
467 :
468 : // Now enter the swap group and post-sync with the barrier again.
469 : send( fabric::CMD_WINDOW_NV_BARRIER )
470 0 : << co::ObjectVersion( _nvNetBarrier )
471 0 : << _nvSwapBarrier->getNVSwapGroup()
472 0 : << _nvSwapBarrier->getNVSwapBarrier();
473 : }
474 : }
475 :
476 0 : _resetSwapBarriers();
477 :
478 0 : if( _swap )
479 : {
480 0 : send( fabric::CMD_WINDOW_SWAP );
481 0 : LBLOG( LOG_TASKS ) << "TASK swap " << frameNumber << std::endl;
482 : }
483 0 : }
484 :
485 : //===========================================================================
486 : // command handling
487 : //===========================================================================
488 2 : bool Window::_cmdConfigInitReply( co::ICommand& cmd )
489 : {
490 2 : co::ObjectICommand command( cmd );
491 2 : LBVERB << "handle window configInit reply " << command << std::endl;
492 :
493 2 : LBASSERT( !needsDelete( ));
494 2 : _state = command.read< bool >() ? STATE_INIT_SUCCESS : STATE_INIT_FAILED;
495 2 : return true;
496 : }
497 :
498 2 : bool Window::_cmdConfigExitReply( co::ICommand& cmd )
499 : {
500 2 : co::ObjectICommand command( cmd );
501 2 : LBVERB << "handle window configExit reply " << command << std::endl;
502 :
503 2 : if( command.read< bool >( ))
504 4 : _state = State( needsDelete() ?
505 2 : STATE_EXIT_SUCCESS|STATE_DELETE : STATE_EXIT_SUCCESS );
506 : else
507 0 : _state = State( needsDelete() ?
508 0 : STATE_EXIT_FAILED | STATE_DELETE : STATE_EXIT_FAILED );
509 2 : return true;
510 : }
511 :
512 748 : void Window::output( std::ostream& os ) const
513 : {
514 748 : bool attrPrinted = false;
515 :
516 32912 : for( WindowSettings::IAttribute i = static_cast<WindowSettings::IAttribute>( 0 );
517 16456 : i < WindowSettings::IATTR_LAST;
518 : i = static_cast<WindowSettings::IAttribute>( static_cast<uint32_t>( i )+1))
519 : {
520 15708 : const int value = getIAttribute( i );
521 15708 : if( value == Global::instance()->getWindowIAttribute( i ))
522 15522 : continue;
523 :
524 186 : if( !attrPrinted )
525 : {
526 138 : os << std::endl << "attributes" << std::endl;
527 138 : os << "{" << std::endl << lunchbox::indent;
528 138 : attrPrinted = true;
529 : }
530 :
531 : os << ( i == WindowSettings::IATTR_HINT_CORE_PROFILE ?
532 : "hint_core_profile " :
533 : i == WindowSettings::IATTR_HINT_OPENGL_MAJOR ?
534 : "hint_opengl_major " :
535 : i == WindowSettings::IATTR_HINT_OPENGL_MINOR ?
536 : "hint_opengl_minor " :
537 : i == WindowSettings::IATTR_HINT_STEREO ?
538 : "hint_stereo " :
539 : i == WindowSettings::IATTR_HINT_DOUBLEBUFFER ?
540 : "hint_doublebuffer " :
541 : i == WindowSettings::IATTR_HINT_FULLSCREEN ?
542 : "hint_fullscreen " :
543 : i == WindowSettings::IATTR_HINT_DECORATION ?
544 : "hint_decoration " :
545 : i == WindowSettings::IATTR_HINT_SWAPSYNC ?
546 : "hint_swapsync " :
547 : i == WindowSettings::IATTR_HINT_DRAWABLE ?
548 : "hint_drawable " :
549 : i == WindowSettings::IATTR_HINT_STATISTICS ?
550 : "hint_statistics " :
551 : i == WindowSettings::IATTR_HINT_SCREENSAVER ?
552 : "hint_screensaver " :
553 : i == WindowSettings::IATTR_HINT_GRAB_POINTER ?
554 : "hint_grab_pointer " :
555 : i == WindowSettings::IATTR_PLANES_COLOR ?
556 : "planes_color " :
557 : i == WindowSettings::IATTR_PLANES_ALPHA ?
558 : "planes_alpha " :
559 : i == WindowSettings::IATTR_PLANES_DEPTH ?
560 : "planes_depth " :
561 : i == WindowSettings::IATTR_PLANES_STENCIL ?
562 : "planes_stencil " :
563 : i == WindowSettings::IATTR_PLANES_ACCUM ?
564 : "planes_accum " :
565 : i == WindowSettings::IATTR_PLANES_ACCUM_ALPHA ?
566 : "planes_accum_alpha " :
567 : i == WindowSettings::IATTR_PLANES_SAMPLES ?
568 186 : "planes_samples " : "ERROR" )
569 186 : << static_cast< fabric::IAttribute >( value ) << std::endl;
570 : }
571 :
572 748 : if( attrPrinted )
573 138 : os << lunchbox::exdent << "}" << std::endl << std::endl;
574 748 : }
575 :
576 : }
577 : }
578 :
579 : #include "../fabric/window.ipp"
580 : template class eq::fabric::Window< eq::server::Pipe, eq::server::Window,
581 : eq::server::Channel >;
582 :
583 : /** @cond IGNORE */
584 : template std::ostream& eq::fabric::operator << ( std::ostream&,
585 84 : const eq::server::Super& );
586 : /** @endcond */
|