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