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