Line data Source code
1 :
2 : /* Copyright (c) 2010-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 "commands.h"
24 : #include "elementVisitor.h"
25 : #include "leafVisitor.h"
26 : #include "log.h"
27 : #include "task.h"
28 :
29 : #include <co/dataIStream.h>
30 : #include <co/dataOStream.h>
31 : #include <co/objectICommand.h>
32 :
33 : namespace eq
34 : {
35 : namespace fabric
36 : {
37 : namespace
38 : {
39 : #define MAKE_WINDOW_ATTR_STRING(attr) (std::string("EQ_WINDOW_") + #attr)
40 100 : std::string _iAttributeStrings[] = {
41 100 : MAKE_WINDOW_ATTR_STRING(IATTR_HINT_CORE_PROFILE),
42 100 : MAKE_WINDOW_ATTR_STRING(IATTR_HINT_OPENGL_MAJOR),
43 100 : MAKE_WINDOW_ATTR_STRING(IATTR_HINT_OPENGL_MINOR),
44 100 : MAKE_WINDOW_ATTR_STRING(IATTR_HINT_STEREO),
45 100 : MAKE_WINDOW_ATTR_STRING(IATTR_HINT_DOUBLEBUFFER),
46 100 : MAKE_WINDOW_ATTR_STRING(IATTR_HINT_FULLSCREEN),
47 100 : MAKE_WINDOW_ATTR_STRING(IATTR_HINT_DECORATION),
48 100 : MAKE_WINDOW_ATTR_STRING(IATTR_HINT_SWAPSYNC),
49 100 : MAKE_WINDOW_ATTR_STRING(IATTR_HINT_DRAWABLE),
50 100 : MAKE_WINDOW_ATTR_STRING(IATTR_HINT_STATISTICS),
51 100 : MAKE_WINDOW_ATTR_STRING(IATTR_HINT_SCREENSAVER),
52 100 : MAKE_WINDOW_ATTR_STRING(IATTR_HINT_GRAB_POINTER),
53 100 : MAKE_WINDOW_ATTR_STRING(IATTR_HINT_WIDTH),
54 100 : MAKE_WINDOW_ATTR_STRING(IATTR_HINT_HEIGHT),
55 100 : MAKE_WINDOW_ATTR_STRING(IATTR_PLANES_COLOR),
56 100 : MAKE_WINDOW_ATTR_STRING(IATTR_PLANES_ALPHA),
57 100 : MAKE_WINDOW_ATTR_STRING(IATTR_PLANES_DEPTH),
58 100 : MAKE_WINDOW_ATTR_STRING(IATTR_PLANES_STENCIL),
59 100 : MAKE_WINDOW_ATTR_STRING(IATTR_PLANES_ACCUM),
60 100 : MAKE_WINDOW_ATTR_STRING(IATTR_PLANES_ACCUM_ALPHA),
61 2050 : MAKE_WINDOW_ATTR_STRING(IATTR_PLANES_SAMPLES)};
62 : }
63 :
64 : template <class P, class W, class C, class Settings>
65 1496 : Window<P, W, C, Settings>::Window(P* parent)
66 1496 : : _pipe(parent)
67 : {
68 1496 : LBASSERT(parent);
69 1496 : parent->_addWindow(static_cast<W*>(this));
70 1496 : LBLOG(LOG_INIT) << "New " << lunchbox::className(this) << std::endl;
71 1496 : }
72 :
73 : template <class P, class W, class C, class Settings>
74 2992 : Window<P, W, C, Settings>::BackupData::BackupData()
75 2992 : : fixedVP(true)
76 : {
77 2992 : }
78 :
79 : template <class P, class W, class C, class Settings>
80 1494 : Window<P, W, C, Settings>::~Window()
81 : {
82 1494 : LBLOG(LOG_INIT) << "Delete " << lunchbox::className(this) << std::endl;
83 7234 : while (!_channels.empty())
84 : {
85 2870 : C* channel = _channels.back();
86 :
87 2870 : LBASSERT(channel->getWindow() == this);
88 2870 : _removeChannel(channel);
89 2870 : delete channel;
90 : }
91 1494 : _pipe->_removeWindow(static_cast<W*>(this));
92 2988 : }
93 :
94 : template <class P, class W, class C, class Settings>
95 1492 : void Window<P, W, C, Settings>::init()
96 : {
97 1492 : notifyViewportChanged();
98 1492 : unsetDirty(DIRTY_VIEWPORT);
99 1492 : }
100 :
101 : template <class P, class W, class C, class Settings>
102 6 : void Window<P, W, C, Settings>::attach(const uint128_t& id,
103 : const uint32_t instanceID)
104 : {
105 6 : Object::attach(id, instanceID);
106 6 : co::CommandQueue* queue = _pipe->getMainThreadQueue();
107 6 : LBASSERT(queue);
108 :
109 6 : registerCommand(CMD_WINDOW_NEW_CHANNEL,
110 : CmdFunc(this, &Window<P, W, C, Settings>::_cmdNewChannel),
111 : queue);
112 6 : registerCommand(CMD_WINDOW_NEW_CHANNEL_REPLY,
113 : CmdFunc(this,
114 : &Window<P, W, C, Settings>::_cmdNewChannelReply),
115 : 0);
116 6 : }
117 :
118 : template <class P, class W, class C, class Settings>
119 4 : void Window<P, W, C, Settings>::backup()
120 : {
121 4 : Object::backup();
122 4 : _backup = _data;
123 4 : }
124 :
125 : template <class P, class W, class C, class Settings>
126 0 : void Window<P, W, C, Settings>::restore()
127 : {
128 0 : _data = _backup;
129 0 : _data.drawableConfig = DrawableConfig();
130 :
131 0 : Object::restore();
132 0 : notifyViewportChanged();
133 0 : setDirty(DIRTY_VIEWPORT);
134 0 : }
135 :
136 : template <class P, class W, class C, class Settings>
137 19 : uint128_t Window<P, W, C, Settings>::commit(const uint32_t incarnation)
138 : {
139 19 : if (Serializable::isDirty(DIRTY_CHANNELS))
140 16 : commitChildren<C>(_channels, CMD_WINDOW_NEW_CHANNEL, incarnation);
141 19 : return Object::commit(incarnation);
142 : }
143 :
144 : template <class P, class W, class C, class Settings>
145 18 : void Window<P, W, C, Settings>::serialize(co::DataOStream& os,
146 : const uint64_t dirtyBits)
147 : {
148 18 : Object::serialize(os, dirtyBits);
149 18 : if (dirtyBits & DIRTY_SETTINGS)
150 10 : _data.windowSettings.serialize(os);
151 18 : if (dirtyBits & DIRTY_CHANNELS && isMaster())
152 : {
153 14 : os << _mapNodeObjects();
154 14 : os.serializeChildren(_channels);
155 : }
156 18 : if (dirtyBits & DIRTY_VIEWPORT)
157 7 : os << _data.vp << _data.pvp << _data.fixedVP;
158 18 : if (dirtyBits & DIRTY_DRAWABLECONFIG)
159 10 : os << _data.drawableConfig;
160 18 : }
161 :
162 : template <class P, class W, class C, class Settings>
163 13 : void Window<P, W, C, Settings>::deserialize(co::DataIStream& is,
164 : const uint64_t dirtyBits)
165 : {
166 13 : Object::deserialize(is, dirtyBits);
167 13 : if (dirtyBits & DIRTY_SETTINGS)
168 8 : _data.windowSettings.deserialize(is);
169 13 : if (dirtyBits & DIRTY_CHANNELS)
170 : {
171 9 : if (isMaster())
172 4 : syncChildren(_channels);
173 : else
174 : {
175 5 : const bool useChildren = is.read<bool>();
176 5 : if (useChildren && _mapNodeObjects())
177 : {
178 0 : Channels result;
179 0 : is.deserializeChildren(this, _channels, result);
180 0 : _channels.swap(result);
181 0 : LBASSERT(_channels.size() == result.size());
182 : }
183 : else // consume unused ObjectVersions
184 5 : is.read<co::ObjectVersions>();
185 : }
186 : }
187 13 : if (dirtyBits & DIRTY_VIEWPORT)
188 : {
189 : // Ignore data from master (server) if we have local changes
190 5 : if (!Serializable::isDirty(DIRTY_VIEWPORT) || isMaster())
191 : {
192 5 : is >> _data.vp >> _data.pvp >> _data.fixedVP;
193 5 : notifyViewportChanged();
194 : }
195 : else // consume unused data
196 0 : is.getRemainingBuffer(sizeof(_data.vp) + sizeof(_data.pvp) +
197 : sizeof(_data.fixedVP));
198 : }
199 :
200 13 : if (dirtyBits & DIRTY_DRAWABLECONFIG)
201 8 : is >> _data.drawableConfig;
202 13 : }
203 :
204 : template <class P, class W, class C, class Settings>
205 54869 : void Window<P, W, C, Settings>::setDirty(const uint64_t dirtyBits)
206 : {
207 54869 : Object::setDirty(dirtyBits);
208 54869 : _pipe->setDirty(P::DIRTY_WINDOWS);
209 54869 : }
210 :
211 : template <class P, class W, class C, class Settings>
212 6 : void Window<P, W, C, Settings>::notifyDetach()
213 : {
214 6 : Object::notifyDetach();
215 12 : co::LocalNodePtr node = getLocalNode();
216 :
217 6 : if (isMaster())
218 : {
219 66 : for (typename Channels::const_iterator i = _channels.begin();
220 44 : i != _channels.end(); ++i)
221 : {
222 18 : node->releaseObject(*i);
223 : }
224 : }
225 : else
226 : {
227 2 : while (!_channels.empty())
228 : {
229 0 : C* channel = _channels.back();
230 0 : LBASSERT(channel->isAttached());
231 :
232 0 : node->releaseObject(channel);
233 0 : _removeChannel(channel);
234 0 : _pipe->getServer()->getNodeFactory()->releaseChannel(channel);
235 : }
236 : }
237 6 : }
238 :
239 : template <class P, class W, class C, class Settings>
240 0 : void Window<P, W, C, Settings>::create(C** channel)
241 : {
242 0 : *channel = _pipe->getServer()->getNodeFactory()->createChannel(
243 : static_cast<W*>(this));
244 0 : (*channel)->init(); // not in ctor, virtual method
245 0 : }
246 :
247 : template <class P, class W, class C, class Settings>
248 0 : void Window<P, W, C, Settings>::release(C* channel)
249 : {
250 0 : _pipe->getServer()->getNodeFactory()->releaseChannel(channel);
251 0 : }
252 :
253 : template <class P, class W, class C, class Settings>
254 2876 : void Window<P, W, C, Settings>::_addChannel(C* channel)
255 : {
256 2876 : LBASSERT(channel->getWindow() == this);
257 2876 : _channels.push_back(channel);
258 2876 : setDirty(DIRTY_CHANNELS);
259 2876 : }
260 :
261 : template <class P, class W, class C, class Settings>
262 5742 : bool Window<P, W, C, Settings>::_removeChannel(C* channel)
263 : {
264 5742 : typename Channels::iterator i = lunchbox::find(_channels, channel);
265 5742 : if (i == _channels.end())
266 2870 : return false;
267 :
268 2872 : _channels.erase(i);
269 2872 : setDirty(DIRTY_CHANNELS);
270 2872 : if (!isMaster())
271 2872 : postRemove(channel);
272 2872 : return true;
273 : }
274 :
275 : template <class P, class W, class C, class Settings>
276 2 : C* Window<P, W, C, Settings>::_findChannel(const uint128_t& id)
277 : {
278 6 : for (typename Channels::const_iterator i = _channels.begin();
279 4 : i != _channels.end(); ++i)
280 : {
281 2 : C* channel = *i;
282 2 : if (channel->getID() == id)
283 2 : return channel;
284 : }
285 0 : return 0;
286 : }
287 :
288 : template <class P, class W, class C, class Settings>
289 31700 : void Window<P, W, C, Settings>::setIAttribute(
290 : const WindowSettings::IAttribute attr, const int32_t value)
291 : {
292 31700 : if (_data.windowSettings.setIAttribute(attr, value))
293 17438 : setDirty(DIRTY_SETTINGS);
294 31700 : }
295 :
296 : template <class P, class W, class C, class Settings>
297 15880 : int32_t Window<P, W, C, Settings>::getIAttribute(
298 : const WindowSettings::IAttribute attr) const
299 : {
300 15880 : return _data.windowSettings.getIAttribute(attr);
301 : }
302 :
303 : template <class P, class W, class C, class Settings>
304 12966 : const std::string& Window<P, W, C, Settings>::getIAttributeString(
305 : const WindowSettings::IAttribute attr)
306 : {
307 12966 : return _iAttributeStrings[attr];
308 : }
309 :
310 : template <class P, class W, class C, class Settings>
311 0 : void Window<P, W, C, Settings>::setSettings(const Settings& settings)
312 : {
313 0 : _data.windowSettings = settings;
314 0 : setDirty(DIRTY_SETTINGS);
315 0 : }
316 :
317 : template <class P, class W, class C, class Settings>
318 3 : const Settings& Window<P, W, C, Settings>::getSettings() const
319 : {
320 3 : return _data.windowSettings;
321 : }
322 :
323 : template <class P, class W, class C, class Settings>
324 0 : WindowPath Window<P, W, C, Settings>::getPath() const
325 : {
326 0 : const P* pipe = getPipe();
327 0 : LBASSERT(pipe);
328 0 : WindowPath path(pipe->getPath());
329 :
330 0 : const typename std::vector<W*>& windows = pipe->getWindows();
331 : typename std::vector<W*>::const_iterator i =
332 0 : std::find(windows.begin(), windows.end(), this);
333 0 : LBASSERT(i != windows.end());
334 0 : path.windowIndex = std::distance(windows.begin(), i);
335 0 : return path;
336 : }
337 :
338 : namespace
339 : {
340 : template <class W, class V>
341 38046 : VisitorResult _accept(W* window, V& visitor)
342 : {
343 38046 : VisitorResult result = visitor.visitPre(window);
344 38046 : if (result != TRAVERSE_CONTINUE)
345 0 : return result;
346 :
347 38046 : const typename W::Channels& channels = window->getChannels();
348 438102 : for (typename W::Channels::const_iterator i = channels.begin();
349 292068 : i != channels.end(); ++i)
350 : {
351 113400 : switch ((*i)->accept(visitor))
352 : {
353 : case TRAVERSE_TERMINATE:
354 5412 : return TRAVERSE_TERMINATE;
355 :
356 : case TRAVERSE_PRUNE:
357 0 : result = TRAVERSE_PRUNE;
358 0 : break;
359 :
360 : case TRAVERSE_CONTINUE:
361 : default:
362 107988 : break;
363 : }
364 : }
365 :
366 32634 : switch (visitor.visitPost(window))
367 : {
368 : case TRAVERSE_TERMINATE:
369 0 : return TRAVERSE_TERMINATE;
370 :
371 : case TRAVERSE_PRUNE:
372 0 : return TRAVERSE_PRUNE;
373 :
374 : case TRAVERSE_CONTINUE:
375 : default:
376 32634 : break;
377 : }
378 :
379 32634 : return result;
380 : }
381 : }
382 :
383 : template <class P, class W, class C, class Settings>
384 38046 : VisitorResult Window<P, W, C, Settings>::accept(Visitor& visitor)
385 : {
386 38046 : return _accept(static_cast<W*>(this), visitor);
387 : }
388 :
389 : template <class P, class W, class C, class Settings>
390 0 : VisitorResult Window<P, W, C, Settings>::accept(Visitor& visitor) const
391 : {
392 0 : return _accept(static_cast<const W*>(this), visitor);
393 : }
394 :
395 : template <class P, class W, class C, class Settings>
396 4838 : const PixelViewport& Window<P, W, C, Settings>::getPixelViewport() const
397 : {
398 4838 : return _data.windowSettings.getPixelViewport();
399 : }
400 :
401 : template <class P, class W, class C, class Settings>
402 544 : void Window<P, W, C, Settings>::setName(const std::string& name)
403 : {
404 544 : Object::setName(name);
405 544 : if (_data.windowSettings.getName() == name)
406 0 : return;
407 544 : _data.windowSettings.setName(name);
408 544 : setDirty(DIRTY_SETTINGS);
409 : }
410 :
411 : template <class P, class W, class C, class Settings>
412 696 : void Window<P, W, C, Settings>::setPixelViewport(const PixelViewport& pvp)
413 : {
414 696 : LBASSERTINFO(pvp.isValid(), pvp);
415 696 : if (!pvp.isValid())
416 0 : return;
417 :
418 696 : _data.fixedVP = false;
419 :
420 696 : if (pvp == _data.pvp && _data.vp.hasArea())
421 2 : return;
422 :
423 694 : _data.pvp = pvp;
424 694 : _data.vp.invalidate();
425 694 : _data.windowSettings.setPixelViewport(pvp);
426 :
427 694 : notifyViewportChanged();
428 694 : setDirty(DIRTY_VIEWPORT);
429 694 : setDirty(DIRTY_SETTINGS);
430 : }
431 :
432 : template <class P, class W, class C, class Settings>
433 602 : void Window<P, W, C, Settings>::setViewport(const Viewport& vp)
434 : {
435 602 : if (!vp.hasArea())
436 0 : return;
437 :
438 602 : _data.fixedVP = true;
439 :
440 602 : if (vp == _data.vp && _data.pvp.hasArea())
441 0 : return;
442 602 : _data.vp = vp;
443 602 : _data.pvp.invalidate();
444 602 : _data.windowSettings.setPixelViewport(PixelViewport());
445 :
446 602 : setDirty(DIRTY_VIEWPORT);
447 602 : setDirty(DIRTY_SETTINGS);
448 602 : notifyViewportChanged();
449 : }
450 :
451 : template <class P, class W, class C, class Settings>
452 2793 : void Window<P, W, C, Settings>::notifyViewportChanged()
453 : {
454 2793 : const PixelViewport pipePVP = _pipe->getPixelViewport();
455 :
456 2793 : if (_data.fixedVP) // update pixel viewport
457 : {
458 2095 : const PixelViewport oldPVP = _data.pvp;
459 2095 : _data.pvp = pipePVP;
460 2095 : _data.pvp.apply(_data.vp);
461 2095 : if (oldPVP != _data.pvp)
462 : {
463 407 : _data.windowSettings.setPixelViewport(_data.pvp);
464 407 : setDirty(DIRTY_VIEWPORT);
465 407 : setDirty(DIRTY_SETTINGS);
466 : }
467 : }
468 : else // update viewport
469 : {
470 698 : const Viewport oldVP = _data.vp;
471 698 : _data.vp = _data.pvp / pipePVP;
472 698 : if (oldVP != _data.vp)
473 694 : setDirty(DIRTY_VIEWPORT);
474 : }
475 :
476 2796 : for (C* channel : _channels)
477 3 : channel->notifyViewportChanged();
478 :
479 2793 : LBVERB << getName() << " viewport update: " << _data.vp << ":" << _data.pvp
480 0 : << std::endl;
481 2793 : }
482 :
483 : template <class P, class W, class C, class Settings>
484 2 : void Window<P, W, C, Settings>::_setDrawableConfig(
485 : const DrawableConfig& drawableConfig)
486 : {
487 2 : _data.drawableConfig = drawableConfig;
488 2 : setDirty(DIRTY_DRAWABLECONFIG);
489 2 : }
490 :
491 : //----------------------------------------------------------------------
492 : // ICommand handlers
493 : //----------------------------------------------------------------------
494 : template <class P, class W, class C, class Settings>
495 0 : bool Window<P, W, C, Settings>::_cmdNewChannel(co::ICommand& cmd)
496 : {
497 0 : co::ObjectICommand command(cmd);
498 :
499 0 : C* channel = 0;
500 0 : create(&channel);
501 0 : LBASSERT(channel);
502 :
503 0 : getLocalNode()->registerObject(channel);
504 0 : LBASSERT(channel->isAttached());
505 :
506 0 : send(command.getRemoteNode(), CMD_WINDOW_NEW_CHANNEL_REPLY)
507 0 : << command.read<uint32_t>() << channel->getID();
508 0 : LBASSERT(channel->isAttached());
509 :
510 0 : return true;
511 : }
512 :
513 : template <class P, class W, class C, class Settings>
514 0 : bool Window<P, W, C, Settings>::_cmdNewChannelReply(co::ICommand& cmd)
515 : {
516 0 : co::ObjectICommand command(cmd);
517 :
518 0 : const uint32_t requestID = command.read<uint32_t>();
519 0 : const uint128_t& result = command.read<uint128_t>();
520 :
521 0 : getLocalNode()->serveRequest(requestID, result);
522 :
523 0 : return true;
524 : }
525 :
526 : template <class P, class W, class C, class Settings>
527 752 : std::ostream& operator<<(std::ostream& os,
528 : const Window<P, W, C, Settings>& window)
529 : {
530 752 : os << lunchbox::disableFlush << lunchbox::disableHeader << "window"
531 : << std::endl;
532 752 : os << "{" << std::endl << lunchbox::indent;
533 :
534 752 : const std::string& name = window.getName();
535 752 : if (!name.empty())
536 278 : os << "name \"" << name << "\"" << std::endl;
537 :
538 752 : const Viewport& vp = window.getViewport();
539 752 : const PixelViewport& pvp = window.getPixelViewport();
540 752 : if (vp.hasArea() && window.hasFixedViewport())
541 : {
542 402 : if (pvp.hasArea())
543 0 : os << "viewport " << pvp << std::endl;
544 402 : os << "viewport " << vp << std::endl;
545 : }
546 350 : else if (pvp.hasArea() && !window.hasFixedViewport())
547 : {
548 350 : if (vp.hasArea())
549 4 : os << "viewport " << vp << std::endl;
550 350 : os << "viewport " << pvp << std::endl;
551 : }
552 :
553 752 : window.output(os);
554 :
555 752 : const typename W::Channels& channels = window.getChannels();
556 6642 : for (typename W::Channels::const_iterator i = channels.begin();
557 4428 : i != channels.end(); ++i)
558 : {
559 1462 : os << **i;
560 : }
561 :
562 1504 : os << lunchbox::exdent << "}" << std::endl
563 752 : << lunchbox::enableHeader << lunchbox::enableFlush;
564 752 : return os;
565 : }
566 : }
567 : }
|