Line data Source code
1 :
2 : /* Copyright (c) 2005-2013, Stefan Eilemann <eile@equalizergraphics.com>
3 : * 2009-2011, 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 "client.h"
24 : #include "config.h"
25 : #include "error.h"
26 : #include "event.h"
27 : #include "gl.h"
28 : #include "global.h"
29 : #include "log.h"
30 : #include "node.h"
31 : #include "nodeFactory.h"
32 : #include "pipe.h"
33 : #include "server.h"
34 : #include "systemWindow.h"
35 : #include "windowStatistics.h"
36 :
37 : #include <eq/util/objectManager.h>
38 : #include <eq/fabric/commands.h>
39 : #include <eq/fabric/elementVisitor.h>
40 : #include <eq/fabric/leafVisitor.h>
41 : #include <eq/fabric/task.h>
42 :
43 : #include <co/barrier.h>
44 : #include <co/exception.h>
45 : #include <co/objectICommand.h>
46 : #include <lunchbox/sleep.h>
47 :
48 : namespace eq
49 : {
50 :
51 : typedef fabric::Window< Pipe, Window, Channel, WindowSettings > Super;
52 :
53 : /** @cond IGNORE */
54 : typedef co::CommandFunc<Window> WindowFunc;
55 : /** @endcond */
56 :
57 : namespace
58 : {
59 : const char* _smallFontKey = "eq_small_font";
60 : const char* _mediumFontKey = "eq_medium_font";
61 : }
62 :
63 285 : Window::Window( Pipe* parent )
64 : : Super( parent )
65 : , _sharedContextWindow( 0 ) // default set below
66 : , _transferWindow( 0 )
67 : , _systemWindow( 0 )
68 : , _state( STATE_STOPPED )
69 : , _objectManager( 0 )
70 : , _lastTime ( 0.0f )
71 : , _avgFPS ( 0.0f )
72 285 : , _lastSwapTime( 0 )
73 : {
74 285 : const Windows& windows = parent->getWindows();
75 285 : if( windows.empty( ))
76 0 : setSharedContextWindow( this );
77 : else
78 285 : setSharedContextWindow( windows.front( ));
79 285 : }
80 :
81 43 : Window::~Window()
82 : {
83 15 : LBASSERT( getChannels().empty( ));
84 28 : }
85 :
86 15 : void Window::attach( const uint128_t& id, const uint32_t instanceID )
87 : {
88 15 : Super::attach( id, instanceID );
89 :
90 15 : co::CommandQueue* queue = getPipeThreadQueue();
91 :
92 : registerCommand( fabric::CMD_WINDOW_CREATE_CHANNEL,
93 15 : WindowFunc( this, &Window::_cmdCreateChannel ), queue );
94 : registerCommand( fabric::CMD_WINDOW_DESTROY_CHANNEL,
95 15 : WindowFunc( this, &Window::_cmdDestroyChannel ), queue );
96 : registerCommand( fabric::CMD_WINDOW_CONFIG_INIT,
97 15 : WindowFunc( this, &Window::_cmdConfigInit ), queue );
98 : registerCommand( fabric::CMD_WINDOW_CONFIG_EXIT,
99 15 : WindowFunc( this, &Window::_cmdConfigExit ), queue );
100 : registerCommand( fabric::CMD_WINDOW_FRAME_START,
101 15 : WindowFunc( this, &Window::_cmdFrameStart ), queue );
102 : registerCommand( fabric::CMD_WINDOW_FRAME_FINISH,
103 15 : WindowFunc( this, &Window::_cmdFrameFinish ), queue );
104 : registerCommand( fabric::CMD_WINDOW_FLUSH,
105 15 : WindowFunc( this, &Window::_cmdFlush), queue );
106 : registerCommand( fabric::CMD_WINDOW_FINISH,
107 15 : WindowFunc( this, &Window::_cmdFinish), queue );
108 : registerCommand( fabric::CMD_WINDOW_THROTTLE_FRAMERATE,
109 : WindowFunc( this, &Window::_cmdThrottleFramerate ),
110 15 : queue );
111 : registerCommand( fabric::CMD_WINDOW_BARRIER,
112 15 : WindowFunc( this, &Window::_cmdBarrier ), queue );
113 : registerCommand( fabric::CMD_WINDOW_NV_BARRIER,
114 15 : WindowFunc( this, &Window::_cmdNVBarrier ), queue );
115 : registerCommand( fabric::CMD_WINDOW_SWAP,
116 15 : WindowFunc( this, &Window::_cmdSwap), queue );
117 : registerCommand( fabric::CMD_WINDOW_FRAME_DRAW_FINISH,
118 15 : WindowFunc( this, &Window::_cmdFrameDrawFinish ), queue );
119 15 : }
120 :
121 38 : void Window::notifyViewportChanged()
122 : {
123 38 : Super::notifyViewportChanged();
124 38 : if( !isRunning( ))
125 70 : return;
126 :
127 : // Commit immediately so that the server has the new data before the app
128 : // does send the startFrame() after a resize event.
129 6 : const uint128_t version = commit();
130 6 : if( version != co::VERSION_NONE )
131 5 : send( getServer(), fabric::CMD_OBJECT_SYNC );
132 : }
133 :
134 7 : void Window::_updateFPS()
135 : {
136 7 : const float curTime = float( getConfig()->getTime( ));
137 7 : const float curInterval = curTime - _lastTime;
138 7 : const bool isFirstFrame = _lastTime == 0.0f;
139 7 : _lastTime = curTime;
140 :
141 7 : if( isFirstFrame || curInterval < 1e-3f )
142 11 : return;
143 :
144 2 : const float curFPS = 1000.0f / curInterval;
145 :
146 4 : if( curFPS < 1.0f || // don't average FPS if rendering is too slow
147 : // or if current frame rate differs a lot from average (rendering loop
148 : // was paused)
149 4 : ( _avgFPS > 10.f * curFPS || 10.f * _avgFPS < curFPS ))
150 : {
151 1 : _avgFPS = curFPS;
152 1 : return;
153 : }
154 : else // average FPS over time
155 : {
156 : // We calculate weighted sum of average frame rate with current frame
157 : // rate to prevent FPS count flickering.
158 : //
159 : // Weighted sum calculation here is the following:
160 1 : _avgFPS = curFPS * ( _avgFPS + 1.f ) / ( curFPS + 1.f );
161 :
162 : // The higher current frame rate, the less it affects averaged FR. This
163 : // is equivalent of averaging over many frames, i.e. when rendering is
164 : // fast, we suppress FPS counter flickering stronger.
165 : }
166 :
167 1 : WindowStatistics stat( Statistic::WINDOW_FPS, this );
168 1 : stat.event.data.statistic.currentFPS = curFPS;
169 1 : stat.event.data.statistic.averageFPS = _avgFPS;
170 : }
171 :
172 :
173 0 : void Window::drawFPS()
174 : {
175 0 : std::ostringstream fpsText;
176 0 : fpsText << std::setprecision(3) << getFPS() << " FPS";
177 :
178 0 : const util::BitmapFont* font = getSmallFont();
179 0 : const PixelViewport& pvp = getPixelViewport();
180 :
181 0 : glLogicOp( GL_XOR );
182 0 : glEnable( GL_COLOR_LOGIC_OP );
183 0 : glRasterPos3f( pvp.w - 60.f, pvp.h - 16.f , 0.99f );
184 0 : glColor3f( .8f, .8f, .8f );
185 :
186 0 : font->draw( fpsText.str( ));
187 0 : }
188 :
189 30 : co::CommandQueue* Window::getPipeThreadQueue()
190 : {
191 30 : return getPipe()->getPipeThreadQueue();
192 : }
193 :
194 15 : co::CommandQueue* Window::getCommandThreadQueue()
195 : {
196 15 : return getPipe()->getCommandThreadQueue();
197 : }
198 :
199 20 : uint32_t Window::getCurrentFrame() const
200 : {
201 20 : return getPipe()->getCurrentFrame();
202 : }
203 :
204 0 : const Node* Window::getNode() const
205 : {
206 0 : const Pipe* pipe = getPipe();
207 0 : LBASSERT( pipe );
208 0 : return ( pipe ? pipe->getNode() : 0 );
209 : }
210 28 : Node* Window::getNode()
211 : {
212 28 : Pipe* pipe = getPipe();
213 28 : LBASSERT( pipe );
214 28 : return ( pipe ? pipe->getNode() : 0 );
215 : }
216 :
217 0 : const Config* Window::getConfig() const
218 : {
219 0 : const Pipe* pipe = getPipe();
220 0 : LBASSERT( pipe );
221 0 : return ( pipe ? pipe->getConfig() : 0 );
222 : }
223 194 : Config* Window::getConfig()
224 : {
225 194 : Pipe* pipe = getPipe();
226 194 : LBASSERT( pipe );
227 194 : return ( pipe ? pipe->getConfig() : 0 );
228 : }
229 :
230 0 : ClientPtr Window::getClient()
231 : {
232 0 : Pipe* pipe = getPipe();
233 0 : LBASSERT( pipe );
234 0 : return ( pipe ? pipe->getClient() : 0 );
235 : }
236 :
237 27 : ServerPtr Window::getServer()
238 : {
239 27 : Pipe* pipe = getPipe();
240 27 : LBASSERT( pipe );
241 27 : return ( pipe ? pipe->getServer() : 0 );
242 : }
243 :
244 : //======================================================================
245 : // pipe-thread methods
246 : //======================================================================
247 :
248 : //----------------------------------------------------------------------
249 : // render context
250 : //----------------------------------------------------------------------
251 28 : void Window::_addRenderContext( const RenderContext& context )
252 : {
253 28 : LB_TS_THREAD( _pipeThread );
254 28 : _renderContexts[BACK].push_back( context );
255 28 : }
256 :
257 0 : bool Window::getRenderContext( const int32_t x, const int32_t y,
258 : RenderContext& context ) const
259 : {
260 0 : LB_TS_THREAD( _pipeThread );
261 0 : if( !_systemWindow )
262 0 : return false;
263 :
264 0 : const DrawableConfig& drawableConfig = getDrawableConfig();
265 0 : const unsigned which = drawableConfig.doublebuffered ? FRONT : BACK;
266 :
267 : std::vector< RenderContext >::const_reverse_iterator i =
268 0 : _renderContexts[which].rbegin();
269 : std::vector< RenderContext >::const_reverse_iterator end =
270 0 : _renderContexts[which].rend();
271 :
272 : // invert y to follow GL convention
273 0 : const int32_t glY = getPixelViewport().h - y;
274 :
275 0 : for( ; i != end; ++i )
276 : {
277 0 : const RenderContext& candidate = *i;
278 0 : if( candidate.pvp.isInside( x, glY ))
279 : {
280 0 : context = candidate;
281 0 : return true;
282 : }
283 : }
284 0 : return false;
285 : }
286 :
287 285 : void Window::setSharedContextWindow( const Window* sharedContextWindow )
288 : {
289 285 : _sharedContextWindow = sharedContextWindow;
290 285 : }
291 :
292 15 : const Window* Window::getSharedContextWindow() const
293 : {
294 15 : return _sharedContextWindow;
295 : }
296 :
297 0 : uint32_t Window::getColorFormat() const
298 : {
299 0 : return getSettings().getColorFormat();
300 : }
301 :
302 7 : void Window::flush() const
303 : {
304 7 : LBASSERT( _systemWindow );
305 7 : if( _systemWindow )
306 7 : _systemWindow->flush();
307 7 : }
308 :
309 74 : void Window::finish() const
310 : {
311 74 : LBASSERT( _systemWindow );
312 74 : if( _systemWindow )
313 74 : _systemWindow->finish();
314 74 : }
315 :
316 15 : void Window::setSystemWindow( SystemWindow* window )
317 : {
318 15 : _systemWindow = window;
319 :
320 15 : if( !window )
321 15 : return;
322 :
323 : // Initialize context-specific data
324 15 : makeCurrent();
325 15 : DrawableConfig config;
326 15 : _systemWindow->queryDrawableConfig( config );
327 15 : _setDrawableConfig( config );
328 15 : _setupObjectManager();
329 : }
330 :
331 0 : const SystemPipe* Window::getSystemPipe() const
332 : {
333 0 : const Pipe* pipe = getPipe();
334 0 : LBASSERT( pipe );
335 0 : return pipe->getSystemPipe();
336 : }
337 :
338 0 : SystemPipe* Window::getSystemPipe()
339 : {
340 0 : Pipe* pipe = getPipe();
341 0 : LBASSERT( pipe );
342 0 : return pipe->getSystemPipe();
343 : }
344 :
345 7 : void Window::frameStart( const uint128_t&, const uint32_t frameNumber )
346 : {
347 7 : startFrame( frameNumber );
348 7 : }
349 :
350 7 : void Window::frameDrawFinish( const uint128_t&, const uint32_t frameNumber )
351 : {
352 7 : releaseFrameLocal( frameNumber );
353 :
354 : // https://github.com/Eyescale/Equalizer/issues/95
355 7 : if( getNode()->getPipes().size() > 1 )
356 4 : finish();
357 7 : }
358 :
359 7 : void Window::frameFinish( const uint128_t&, const uint32_t frameNumber )
360 : {
361 7 : releaseFrame( frameNumber );
362 7 : flush();
363 7 : _updateFPS();
364 7 : }
365 :
366 7 : void Window::startFrame( const uint32_t ) { /* currently nop */ }
367 7 : void Window::releaseFrame( const uint32_t ) { /* currently nop */ }
368 7 : void Window::releaseFrameLocal( const uint32_t ) { /* nop */ }
369 :
370 : //----------------------------------------------------------------------
371 : // configInit
372 : //----------------------------------------------------------------------
373 15 : bool Window::configInit( const uint128_t& initID )
374 : {
375 15 : if( !getPixelViewport().isValid( ))
376 : {
377 0 : sendError( ERROR_WINDOW_PVP_INVALID );
378 0 : return false;
379 : }
380 :
381 15 : LBASSERT( !_systemWindow );
382 :
383 15 : return configInitSystemWindow( initID ) && configInitGL( initID );
384 : }
385 :
386 15 : bool Window::configInitSystemWindow( const uint128_t& )
387 : {
388 15 : const Pipe* pipe = getPipe();
389 15 : WindowSettings settings = getSettings();
390 : const SystemWindow* sysWindow = _sharedContextWindow ?
391 15 : _sharedContextWindow->getSystemWindow() : 0;
392 15 : settings.setSharedContextWindow( sysWindow );
393 : SystemWindow* systemWindow =
394 15 : pipe->getWindowSystem().createWindow( this, settings );
395 :
396 15 : LBASSERT( systemWindow );
397 15 : if( !systemWindow->configInit( ))
398 : {
399 0 : LBWARN << "System window initialization failed" << std::endl;
400 0 : delete systemWindow;
401 0 : return false;
402 : }
403 :
404 15 : setPixelViewport( systemWindow->getPixelViewport( ));
405 15 : setSystemWindow( systemWindow );
406 15 : return true;
407 : }
408 :
409 15 : void Window::_setupObjectManager()
410 : {
411 15 : if( !glewGetContext( ))
412 15 : return;
413 :
414 15 : _releaseObjectManager();
415 :
416 15 : const Window* sharedWindow = getSharedContextWindow();
417 15 : if( sharedWindow && sharedWindow != this )
418 0 : _objectManager = sharedWindow->_objectManager;
419 : else
420 : {
421 15 : util::ObjectManager om( glewGetContext( ));
422 15 : _objectManager = om;
423 : }
424 : }
425 :
426 30 : void Window::_releaseObjectManager()
427 : {
428 30 : _objectManager.deleteEqBitmapFont( _smallFontKey );
429 30 : _objectManager.deleteEqBitmapFont( _mediumFontKey );
430 30 : if( !_objectManager.isShared( ))
431 30 : _objectManager.deleteAll();
432 30 : _objectManager.clear();
433 30 : }
434 :
435 0 : const util::BitmapFont* Window::getSmallFont()
436 : {
437 0 : util::BitmapFont* font = _objectManager.getEqBitmapFont( _smallFontKey );
438 0 : if( !font )
439 : {
440 0 : font = _objectManager.newEqBitmapFont( _smallFontKey );
441 0 : font->init( getPipe()->getWindowSystem(), "" );
442 : }
443 0 : return font;
444 : }
445 :
446 0 : const util::BitmapFont* Window::getMediumFont()
447 : {
448 0 : util::BitmapFont* font = _objectManager.getEqBitmapFont( _mediumFontKey );
449 0 : if( !font )
450 : {
451 0 : font = _objectManager.newEqBitmapFont( _mediumFontKey );
452 0 : font->init( getPipe()->getWindowSystem(), "", 20 );
453 : }
454 0 : return font;
455 : }
456 :
457 15 : bool Window::configInitGL( const uint128_t& )
458 : {
459 15 : glEnable( GL_SCISSOR_TEST ); // needed to constrain channel viewport
460 15 : glEnable( GL_DEPTH_TEST );
461 15 : glDepthFunc( GL_LESS );
462 :
463 15 : glEnable( GL_LIGHTING );
464 15 : glEnable( GL_LIGHT0 );
465 :
466 15 : glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
467 15 : glEnable( GL_COLOR_MATERIAL );
468 :
469 15 : glClearDepth( 1.f );
470 :
471 15 : glClear( GL_COLOR_BUFFER_BIT );
472 15 : swapBuffers();
473 15 : glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
474 :
475 15 : return true;
476 : }
477 :
478 2 : bool Window::createTransferWindow()
479 : {
480 2 : LBASSERT( _systemWindow );
481 :
482 2 : if( _transferWindow )
483 0 : return true;
484 :
485 : // create another (shared) osWindow with no drawable
486 2 : WindowSettings settings = getSettings();
487 2 : settings.setIAttribute( WindowSettings::IATTR_HINT_DRAWABLE, OFF );
488 : const SystemWindow* sysWindow = _sharedContextWindow ?
489 2 : _sharedContextWindow->getSystemWindow() : 0;
490 2 : settings.setSharedContextWindow( sysWindow );
491 2 : const Pipe* pipe = getPipe();
492 2 : _transferWindow = pipe->getWindowSystem().createWindow( this, settings );
493 :
494 2 : if( _transferWindow )
495 : {
496 2 : if( !_transferWindow->configInit( ))
497 : {
498 0 : LBWARN << "Transfer window initialization failed" << std::endl;
499 0 : delete _transferWindow;
500 0 : _transferWindow = 0;
501 : }
502 : else
503 2 : makeCurrentTransfer(); // #177
504 : }
505 : else
506 0 : LBERROR << "Window system " << pipe->getWindowSystem()
507 0 : << " not implemented or supported" << std::endl;
508 :
509 2 : makeCurrent();
510 :
511 2 : LBVERB << "Transfer window initialization finished" << std::endl;
512 2 : return _transferWindow != 0;
513 : }
514 :
515 2 : const GLEWContext* Window::getTransferGlewContext()
516 : {
517 2 : LBASSERT( _transferWindow );
518 2 : if( _transferWindow )
519 2 : return _transferWindow->glewGetContext();
520 0 : return 0;
521 : }
522 :
523 4 : void Window::makeCurrentTransfer( const bool useCache ) const
524 : {
525 4 : LBASSERT( _transferWindow );
526 4 : if( _transferWindow )
527 4 : _transferWindow->makeCurrent( useCache );
528 4 : }
529 :
530 :
531 2 : void Window::deleteTransferSystemWindow()
532 : {
533 2 : if( !_transferWindow )
534 2 : return;
535 :
536 2 : _transferWindow->configExit();
537 2 : delete _transferWindow;
538 2 : _transferWindow = 0;
539 : }
540 :
541 : //----------------------------------------------------------------------
542 : // configExit
543 : //----------------------------------------------------------------------
544 15 : bool Window::configExit()
545 : {
546 15 : if( !_systemWindow )
547 0 : return true;
548 :
549 15 : const bool ret = configExitGL();
550 15 : return configExitSystemWindow() && ret;
551 : }
552 :
553 15 : bool Window::configExitSystemWindow()
554 : {
555 : // _transferWindow has to be deleted from the same thread it was
556 : // initialized
557 15 : LBASSERT( !_transferWindow );
558 :
559 15 : _releaseObjectManager();
560 :
561 15 : if( _systemWindow )
562 : {
563 15 : _systemWindow->configExit( );
564 :
565 15 : delete _systemWindow;
566 15 : _systemWindow = 0;
567 : }
568 15 : return true;
569 : }
570 :
571 50 : void Window::makeCurrent( const bool useCache ) const
572 : {
573 50 : _systemWindow->makeCurrent( useCache );
574 : // _pipe->setCurrent done by SystemWindow::makeCurrent
575 50 : }
576 :
577 15 : void Window::bindFrameBuffer() const
578 : {
579 15 : _systemWindow->bindFrameBuffer( );
580 15 : }
581 :
582 19 : void Window::swapBuffers()
583 : {
584 19 : _systemWindow->swapBuffers();
585 19 : LBLOG( co::LOG_BARRIER ) << "Swap buffers done" << getName() << std::endl;
586 19 : }
587 :
588 43 : const GLEWContext* Window::glewGetContext() const
589 : {
590 43 : return _systemWindow ? _systemWindow->glewGetContext() : 0;
591 : }
592 :
593 0 : void Window::_enterBarrier( co::ObjectVersion barrier )
594 : {
595 0 : LBLOG( co::LOG_BARRIER ) << "swap barrier " << barrier << " " << getName()
596 0 : << std::endl;
597 0 : Node* node = getNode();
598 0 : co::Barrier* netBarrier = node->getBarrier( barrier );
599 0 : if( !netBarrier )
600 0 : return;
601 :
602 0 : WindowStatistics stat( Statistic::WINDOW_SWAP_BARRIER, this );
603 0 : Config* config = getConfig();
604 0 : const uint32_t timeout = config->getTimeout()/2;
605 : try
606 : {
607 0 : netBarrier->enter( timeout );
608 : }
609 : catch( const co::Exception& e )
610 : {
611 : LBWARN << e.what() << " for " << *netBarrier << std::endl;
612 0 : }
613 : }
614 :
615 15 : void Window::_updateEvent( Event& event )
616 : {
617 : // TODO 2.0 event interface will stream these and remove them from Event
618 15 : event.time = getConfig()->getTime();
619 15 : event.originator = getID();
620 15 : event.serial = getSerial();
621 :
622 15 : switch( event.type )
623 : {
624 : case Event::WINDOW_POINTER_MOTION:
625 : case Event::WINDOW_POINTER_BUTTON_PRESS:
626 : case Event::WINDOW_POINTER_BUTTON_RELEASE:
627 : case Event::WINDOW_POINTER_WHEEL:
628 : {
629 0 : const int32_t xPos = event.pointer.x;
630 0 : const int32_t yPos = event.pointer.y;
631 :
632 0 : if( !getRenderContext( xPos, yPos, event.context ))
633 0 : LBVERB << "No rendering context for pointer event at "
634 0 : << xPos << ", " << yPos << std::endl;
635 : }
636 : }
637 15 : }
638 :
639 :
640 : //======================================================================
641 : // event methods
642 : //======================================================================
643 :
644 6 : EventOCommand Window::sendError( const uint32_t error )
645 : {
646 6 : return getConfig()->sendError( Event::WINDOW_ERROR, getID(), error );
647 : }
648 :
649 15 : bool Window::processEvent( const Event& event )
650 : {
651 : // see comment in _updateEvent
652 15 : _updateEvent( const_cast< Event& >( event ));
653 :
654 15 : switch( event.type )
655 : {
656 : case Event::WINDOW_HIDE:
657 0 : setPixelViewport( PixelViewport( 0, 0, 0, 0 ));
658 0 : break;
659 :
660 : case Event::WINDOW_SHOW:
661 : case Event::WINDOW_RESIZE:
662 : setPixelViewport( PixelViewport( event.resize.x, event.resize.y,
663 6 : event.resize.w, event.resize.h ));
664 6 : break;
665 :
666 : case Event::KEY_PRESS:
667 : case Event::KEY_RELEASE:
668 0 : if( event.key.key == KC_VOID )
669 0 : return true; // ignore
670 : // else fall through
671 : case Event::WINDOW_EXPOSE:
672 : case Event::WINDOW_CLOSE:
673 : case Event::STATISTIC:
674 : case Event::MAGELLAN_AXIS:
675 : case Event::MAGELLAN_BUTTON:
676 5 : break;
677 :
678 : case Event::WINDOW_POINTER_GRAB:
679 0 : _grabbedChannels = _getEventChannels( event.pointer );
680 0 : break;
681 : case Event::WINDOW_POINTER_UNGRAB:
682 0 : _grabbedChannels.clear();
683 0 : break;
684 :
685 : case Event::WINDOW_POINTER_MOTION:
686 : case Event::WINDOW_POINTER_BUTTON_PRESS:
687 : case Event::WINDOW_POINTER_BUTTON_RELEASE:
688 : case Event::WINDOW_POINTER_WHEEL:
689 : {
690 0 : const Channels& channels = _getEventChannels( event.pointer );
691 0 : for( Channels::const_iterator i = channels.begin();
692 0 : i != channels.end(); ++i )
693 : {
694 0 : Channel* channel = *i;
695 0 : Event channelEvent = event;
696 0 : switch( event.type )
697 : {
698 : case Event::WINDOW_POINTER_MOTION:
699 0 : channelEvent.type = Event::CHANNEL_POINTER_MOTION;
700 0 : break;
701 : case Event::WINDOW_POINTER_BUTTON_PRESS:
702 0 : channelEvent.type = Event::CHANNEL_POINTER_BUTTON_PRESS;
703 0 : break;
704 : case Event::WINDOW_POINTER_BUTTON_RELEASE:
705 0 : channelEvent.type = Event::CHANNEL_POINTER_BUTTON_RELEASE;
706 0 : break;
707 : case Event::WINDOW_POINTER_WHEEL:
708 0 : channelEvent.type = Event::CHANNEL_POINTER_WHEEL;
709 0 : break;
710 : default:
711 0 : LBWARN << "Unhandled window event of type " << event.type
712 0 : << std::endl;
713 0 : LBUNIMPLEMENTED;
714 : }
715 :
716 : // convert y to GL notation (Channel PVP uses GL coordinates)
717 0 : const PixelViewport& pvp = getPixelViewport();
718 0 : const int32_t y = pvp.h - event.pointer.y;
719 : const PixelViewport& channelPVP =
720 0 : channel->getNativePixelViewport();
721 :
722 0 : channelEvent.originator = channel->getID();
723 0 : channelEvent.serial = channel->getSerial();
724 0 : channelEvent.pointer.x -= channelPVP.x;
725 0 : channelEvent.pointer.y = channelPVP.h - y + channelPVP.y;
726 0 : channel->processEvent( channelEvent );
727 0 : }
728 0 : break;
729 : }
730 :
731 : case Event::WINDOW_SCREENSAVER:
732 0 : switch( getIAttribute( WindowSettings::IATTR_HINT_SCREENSAVER ))
733 : {
734 : case OFF:
735 0 : return true; // screen saver stays inactive
736 : case ON:
737 0 : return false; // screen saver becomes active
738 : default: // AUTO
739 0 : if( getDrawableConfig().doublebuffered &&
740 0 : getIAttribute( WindowSettings::IATTR_HINT_DRAWABLE ) == WINDOW )
741 : {
742 0 : return true; // screen saver stays inactive
743 : }
744 0 : return false;
745 : }
746 :
747 : case Event::UNKNOWN:
748 : // unknown window-system native event, which was not handled
749 4 : return false;
750 :
751 : default:
752 0 : LBWARN << "Unhandled window event of type " << event.type
753 0 : << std::endl;
754 0 : LBUNIMPLEMENTED;
755 : }
756 :
757 11 : Config* config = getConfig();
758 11 : ConfigEvent configEvent;
759 11 : configEvent.data = event;
760 11 : config->sendEvent( configEvent );
761 11 : return true;
762 : }
763 :
764 0 : Channels Window::_getEventChannels( const PointerEvent& event )
765 : {
766 0 : if( !_grabbedChannels.empty( ))
767 0 : return _grabbedChannels;
768 :
769 0 : Channels result;
770 0 : const Channels& channels = getChannels();
771 0 : for( ChannelsCIter i = channels.begin(); i != channels.end(); ++i )
772 : {
773 0 : Channel* channel = *i;
774 0 : if( !channel->isDestination( ))
775 0 : continue;
776 :
777 0 : const PixelViewport& pvp = getPixelViewport();
778 0 : const PixelViewport& channelPVP = channel->getNativePixelViewport();
779 :
780 : // convert y to GL notation (Channel PVP uses GL coordinates)
781 0 : const int32_t y = pvp.h - event.y;
782 :
783 0 : if( channelPVP.isInside( event.x, y ))
784 0 : result.push_back( channel );
785 : }
786 0 : return result;
787 : }
788 :
789 : //---------------------------------------------------------------------------
790 : // command handlers
791 : //---------------------------------------------------------------------------
792 15 : bool Window::_cmdCreateChannel( co::ICommand& cmd )
793 : {
794 15 : co::ObjectICommand command( cmd );
795 15 : const uint128_t& channelID = command.read< uint128_t >();
796 :
797 15 : LBLOG( LOG_INIT ) << "Create channel " << command << " id " << channelID
798 15 : << std::endl;
799 :
800 15 : Channel* channel = Global::getNodeFactory()->createChannel( this );
801 15 : channel->init(); // not in ctor, virtual method
802 :
803 15 : Config* config = getConfig();
804 15 : LBCHECK( config->mapObject( channel, channelID ));
805 15 : LBASSERT( channel->getSerial() != CO_INSTANCE_INVALID );
806 :
807 15 : return true;
808 : }
809 :
810 15 : bool Window::_cmdDestroyChannel( co::ICommand& cmd )
811 : {
812 15 : co::ObjectICommand command( cmd );
813 15 : LBLOG( LOG_INIT ) << "Destroy channel " << command << std::endl;
814 :
815 15 : Channel* channel = _findChannel( command.read< uint128_t >( ));
816 15 : LBASSERT( channel );
817 :
818 15 : const bool stopped = channel->isStopped();
819 15 : Config* config = getConfig();
820 15 : config->unmapObject( channel );
821 : channel->send( getServer(), fabric::CMD_CHANNEL_CONFIG_EXIT_REPLY )
822 15 : << stopped;
823 15 : Global::getNodeFactory()->releaseChannel( channel );
824 :
825 15 : return true;
826 : }
827 :
828 15 : bool Window::_cmdConfigInit( co::ICommand& cmd )
829 : {
830 15 : co::ObjectICommand command( cmd );
831 :
832 15 : LBLOG( LOG_INIT ) << "TASK window config init " << command << std::endl;
833 :
834 15 : bool result = false;
835 15 : if( getPipe()->isRunning( ))
836 : {
837 15 : _state = STATE_INITIALIZING;
838 15 : result = configInit( command.read< uint128_t >( ));
839 15 : if( result )
840 15 : _state = STATE_RUNNING;
841 : }
842 : else
843 0 : sendError( ERROR_WINDOW_PIPE_NOTRUNNING );
844 :
845 15 : LBLOG( LOG_INIT ) << "TASK window config init reply " << std::endl;
846 :
847 15 : commit();
848 15 : send( command.getRemoteNode(), fabric::CMD_WINDOW_CONFIG_INIT_REPLY ) << result;
849 15 : return true;
850 : }
851 :
852 15 : bool Window::_cmdConfigExit( co::ICommand& cmd )
853 : {
854 15 : co::ObjectICommand command( cmd );
855 :
856 15 : LBLOG( LOG_INIT ) << "TASK window config exit " << command << std::endl;
857 :
858 15 : if( _state != STATE_STOPPED )
859 : {
860 15 : if( getPipe()->isRunning( ) && _systemWindow )
861 : {
862 15 : makeCurrent();
863 15 : getPipe()->flushFrames( _objectManager );
864 : }
865 : // else emergency exit, no context available.
866 :
867 15 : _state = configExit() ? STATE_STOPPED : STATE_FAILED;
868 : }
869 :
870 15 : getPipe()->send( getLocalNode(),
871 30 : fabric::CMD_PIPE_DESTROY_WINDOW ) << getID();
872 15 : return true;
873 : }
874 :
875 7 : bool Window::_cmdFrameStart( co::ICommand& cmd )
876 : {
877 7 : co::ObjectICommand command( cmd );
878 :
879 7 : LB_TS_THREAD( _pipeThread );
880 :
881 7 : const uint128_t& version = command.read< uint128_t >();
882 7 : const uint128_t& frameID = command.read< uint128_t >();
883 7 : const uint32_t frameNumber = command.read< uint32_t >();
884 :
885 7 : LBLOG( LOG_TASKS ) << "TASK frame start " << getName()
886 0 : << " " << command << " frame " << frameNumber
887 7 : << " id " << frameID << std::endl;
888 :
889 : //_grabFrame( frameNumber ); single-threaded
890 7 : sync( version );
891 :
892 7 : const DrawableConfig& drawableConfig = getDrawableConfig();
893 7 : if( drawableConfig.doublebuffered )
894 4 : _renderContexts[FRONT].swap( _renderContexts[BACK] );
895 7 : _renderContexts[BACK].clear();
896 :
897 7 : makeCurrent();
898 7 : frameStart( frameID, frameNumber );
899 7 : return true;
900 : }
901 :
902 7 : bool Window::_cmdFrameFinish( co::ICommand& cmd )
903 : {
904 7 : co::ObjectICommand command( cmd );
905 :
906 7 : LBVERB << "handle window frame sync " << command << std::endl;
907 :
908 7 : const uint128_t& frameID = command.read< uint128_t >();
909 7 : const uint32_t frameNumber = command.read< uint32_t >();
910 :
911 7 : makeCurrent();
912 7 : frameFinish( frameID, frameNumber );
913 7 : return true;
914 : }
915 :
916 0 : bool Window::_cmdFlush( co::ICommand& )
917 : {
918 0 : flush();
919 0 : return true;
920 : }
921 :
922 0 : bool Window::_cmdFinish( co::ICommand& )
923 : {
924 0 : WindowStatistics stat( Statistic::WINDOW_FINISH, this );
925 0 : makeCurrent();
926 0 : finish();
927 0 : return true;
928 : }
929 :
930 0 : bool Window::_cmdThrottleFramerate( co::ICommand& cmd )
931 : {
932 0 : co::ObjectICommand command( cmd );
933 :
934 0 : LBLOG( LOG_TASKS ) << "TASK throttle framerate " << getName() << " "
935 0 : << command << std::endl;
936 :
937 : // throttle to given framerate
938 0 : const int64_t elapsed = getConfig()->getTime() - _lastSwapTime;
939 0 : const float minFrameTime = command.read< float >();
940 0 : const float timeLeft = minFrameTime - static_cast<float>( elapsed );
941 :
942 0 : if( timeLeft >= 1.f )
943 : {
944 0 : WindowStatistics stat( Statistic::WINDOW_THROTTLE_FRAMERATE, this );
945 0 : lunchbox::sleep( static_cast< uint32_t >( timeLeft ));
946 : }
947 :
948 0 : _lastSwapTime = getConfig()->getTime();
949 0 : return true;
950 : }
951 :
952 0 : bool Window::_cmdBarrier( co::ICommand& cmd )
953 : {
954 0 : co::ObjectICommand command( cmd );
955 0 : const co::ObjectVersion& barrier = command.read< co::ObjectVersion >();
956 :
957 0 : LBVERB << "handle barrier " << command << " barrier " << barrier << std::endl;
958 0 : LBLOG( LOG_TASKS ) << "TASK swap barrier " << getName() << std::endl;
959 :
960 0 : _enterBarrier( barrier );
961 0 : return true;
962 : }
963 :
964 0 : bool Window::_cmdNVBarrier( co::ICommand& cmd )
965 : {
966 0 : co::ObjectICommand command( cmd );
967 :
968 0 : LBLOG( LOG_TASKS ) << "TASK join NV_swap_group" << std::endl;
969 0 : LBASSERT( _systemWindow );
970 :
971 0 : const co::ObjectVersion& netBarrier = command.read< co::ObjectVersion >();
972 0 : const uint32_t group = command.read< uint32_t >();
973 0 : const uint32_t barrier = command.read< uint32_t >();
974 :
975 0 : makeCurrent();
976 0 : _systemWindow->joinNVSwapBarrier( group, barrier );
977 0 : _enterBarrier( netBarrier );
978 0 : return true;
979 : }
980 :
981 7 : bool Window::_cmdSwap( co::ICommand& cmd )
982 : {
983 7 : co::ObjectICommand command( cmd );
984 :
985 7 : LBLOG( LOG_TASKS ) << "TASK swap buffers " << getName() << " " << command
986 7 : << std::endl;
987 :
988 7 : if( getDrawableConfig().doublebuffered )
989 : {
990 : // swap
991 4 : WindowStatistics stat( Statistic::WINDOW_SWAP, this );
992 4 : makeCurrent();
993 4 : swapBuffers();
994 : }
995 7 : return true;
996 : }
997 :
998 7 : bool Window::_cmdFrameDrawFinish( co::ICommand& cmd )
999 : {
1000 7 : co::ObjectICommand command( cmd );
1001 7 : const uint128_t& frameID = command.read< uint128_t >();
1002 7 : const uint32_t frameNumber = command.read< uint32_t >();
1003 :
1004 7 : LBLOG( LOG_TASKS ) << "TASK draw finish " << getName() << " " << command
1005 0 : << " frame " << frameNumber << " id " << frameID
1006 7 : << std::endl;
1007 :
1008 7 : frameDrawFinish( frameID, frameNumber );
1009 7 : return true;
1010 : }
1011 :
1012 : }
1013 :
1014 : #include "../fabric/window.ipp"
1015 : template class eq::fabric::Window< eq::Pipe, eq::Window, eq::Channel,
1016 : eq::WindowSettings >;
1017 :
1018 : /** @cond IGNORE */
1019 : template EQFABRIC_API std::ostream& eq::fabric::operator << ( std::ostream&,
1020 36 : const eq::Super& );
1021 : /** @endcond */
|