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