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