Line data Source code
1 :
2 : /* Copyright (c) 2009-2017, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : *
5 : * This library is free software; you can redistribute it and/or modify it under
6 : * the terms of the GNU Lesser General Public License version 2.1 as published
7 : * by the Free Software Foundation.
8 : *
9 : * This library is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 : * details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public License
15 : * along with this library; if not, write to the Free Software Foundation, Inc.,
16 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 : */
18 :
19 : #include "layout.h"
20 :
21 : #include "commands.h"
22 : #include "elementVisitor.h"
23 : #include "leafVisitor.h"
24 : #include "log.h"
25 : #include "nameFinder.h"
26 : #include "observer.h"
27 : #include "paths.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 : template <class C, class L, class V>
38 651 : Layout<C, L, V>::Layout(C* config)
39 651 : : _config(config)
40 : {
41 651 : LBASSERT(config);
42 651 : static_cast<L*>(this)->_config->_addLayout(static_cast<L*>(this));
43 651 : LBLOG(LOG_INIT) << "New " << lunchbox::className(this) << std::endl;
44 651 : }
45 :
46 : template <class C, class L, class V>
47 649 : Layout<C, L, V>::~Layout()
48 : {
49 649 : LBLOG(LOG_INIT) << "Delete " << lunchbox::className(this) << std::endl;
50 2069 : while (!_views.empty())
51 : {
52 710 : V* view = _views.back();
53 710 : LBCHECK(_removeChild(view));
54 710 : release(view);
55 : }
56 :
57 649 : _config->_removeLayout(static_cast<L*>(this));
58 1298 : }
59 :
60 : template <class C, class L, class V>
61 21 : void Layout<C, L, V>::attach(const uint128_t& id, const uint32_t instanceID)
62 : {
63 21 : Object::attach(id, instanceID);
64 :
65 21 : co::CommandQueue* queue = _config->getMainThreadQueue();
66 21 : LBASSERT(queue);
67 :
68 21 : registerCommand(CMD_LAYOUT_NEW_VIEW,
69 : CmdFunc(this, &Layout<C, L, V>::_cmdNewView), queue);
70 21 : registerCommand(CMD_LAYOUT_NEW_VIEW_REPLY,
71 : CmdFunc(this, &Layout<C, L, V>::_cmdNewViewReply), 0);
72 21 : }
73 :
74 : template <class C, class L, class V>
75 98 : uint128_t Layout<C, L, V>::commit(const uint32_t incarnation)
76 : {
77 : // Always traverse views: view proxy objects may be dirty
78 98 : commitChildren<V>(_views, CMD_LAYOUT_NEW_VIEW, incarnation);
79 98 : return Object::commit(incarnation);
80 : }
81 :
82 : template <class C, class L, class V>
83 94 : void Layout<C, L, V>::serialize(co::DataOStream& os, const uint64_t dirtyBits)
84 : {
85 94 : Object::serialize(os, dirtyBits);
86 :
87 94 : if (dirtyBits & DIRTY_VIEWS && isMaster())
88 86 : os.serializeChildren(_views);
89 94 : if (dirtyBits & DIRTY_VIEWPORT)
90 50 : os << _pvp;
91 94 : }
92 :
93 : template <class C, class L, class V>
94 41 : void Layout<C, L, V>::deserialize(co::DataIStream& is, const uint64_t dirtyBits)
95 : {
96 41 : Object::deserialize(is, dirtyBits);
97 :
98 41 : if (dirtyBits & DIRTY_VIEWS)
99 : {
100 41 : if (isMaster())
101 16 : syncChildren(_views);
102 : else
103 : {
104 50 : Views result;
105 25 : is.deserializeChildren(this, _views, result);
106 25 : _views.swap(result);
107 : }
108 : }
109 41 : if (dirtyBits & DIRTY_VIEWPORT)
110 : {
111 7 : is >> _pvp;
112 7 : notifyViewportChanged();
113 : }
114 41 : }
115 :
116 : template <class C, class L, class V>
117 1854 : void Layout<C, L, V>::setDirty(const uint64_t dirtyBits)
118 : {
119 1854 : Object::setDirty(dirtyBits);
120 1854 : _config->setDirty(C::DIRTY_LAYOUTS);
121 1854 : }
122 :
123 : template <class C, class L, class V>
124 21 : void Layout<C, L, V>::notifyDetach()
125 : {
126 21 : Object::notifyDetach();
127 21 : releaseChildren<L, V>(_views);
128 21 : }
129 :
130 : template <class C, class L, class V>
131 7 : void Layout<C, L, V>::create(V** view)
132 : {
133 7 : *view = getConfig()->getServer()->getNodeFactory()->createView(
134 : static_cast<L*>(this));
135 7 : }
136 :
137 : template <class C, class L, class V>
138 717 : void Layout<C, L, V>::release(V* view)
139 : {
140 717 : getConfig()->getServer()->getNodeFactory()->releaseView(view);
141 717 : }
142 :
143 : template <class C, class L, class V>
144 0 : const PixelViewport& Layout<C, L, V>::getPixelViewport() const
145 : {
146 0 : return _pvp;
147 : }
148 :
149 : template <class C, class L, class V>
150 0 : void Layout<C, L, V>::setPixelViewport(const PixelViewport& pvp)
151 : {
152 0 : if (_pvp == pvp)
153 0 : return;
154 0 : _pvp = pvp;
155 0 : setDirty(DIRTY_VIEWPORT);
156 : }
157 :
158 : namespace
159 : {
160 : template <class L, class V>
161 19949 : VisitorResult _accept(L* layout, V& visitor)
162 : {
163 19949 : VisitorResult result = visitor.visitPre(layout);
164 19949 : if (result != TRAVERSE_CONTINUE)
165 1683 : return result;
166 :
167 18266 : const typename L::Views& views = layout->getViews();
168 38628 : for (typename L::Views::const_iterator i = views.begin(); i != views.end();
169 : ++i)
170 : {
171 20366 : switch ((*i)->accept(visitor))
172 : {
173 : case TRAVERSE_TERMINATE:
174 4 : return TRAVERSE_TERMINATE;
175 :
176 : case TRAVERSE_PRUNE:
177 0 : result = TRAVERSE_PRUNE;
178 0 : break;
179 :
180 : case TRAVERSE_CONTINUE:
181 : default:
182 20362 : break;
183 : }
184 : }
185 :
186 18262 : switch (visitor.visitPost(layout))
187 : {
188 : case TRAVERSE_TERMINATE:
189 0 : return TRAVERSE_TERMINATE;
190 :
191 : case TRAVERSE_PRUNE:
192 0 : return TRAVERSE_PRUNE;
193 :
194 : case TRAVERSE_CONTINUE:
195 : default:
196 18262 : break;
197 : }
198 :
199 18262 : return result;
200 : }
201 : }
202 :
203 : template <class C, class L, class V>
204 19949 : VisitorResult Layout<C, L, V>::accept(Visitor& visitor)
205 : {
206 19949 : return _accept(static_cast<L*>(this), visitor);
207 : }
208 :
209 : template <class C, class L, class V>
210 0 : VisitorResult Layout<C, L, V>::accept(Visitor& visitor) const
211 : {
212 0 : return _accept(static_cast<const L*>(this), visitor);
213 : }
214 :
215 : template <class C, class L, class V>
216 719 : void Layout<C, L, V>::_addChild(V* view)
217 : {
218 719 : LBASSERT(view);
219 719 : LBASSERT(view->getLayout() == this);
220 719 : _views.push_back(view);
221 719 : setDirty(DIRTY_VIEWS);
222 719 : }
223 :
224 : template <class C, class L, class V>
225 1434 : bool Layout<C, L, V>::_removeChild(V* view)
226 : {
227 1434 : typename Views::iterator i = lunchbox::find(_views, view);
228 1434 : if (i == _views.end())
229 717 : return false;
230 :
231 717 : LBASSERT(view->getLayout() == this);
232 717 : _views.erase(i);
233 717 : setDirty(DIRTY_VIEWS);
234 717 : if (!isMaster())
235 717 : postRemove(view);
236 717 : return true;
237 : }
238 :
239 : template <class C, class L, class V>
240 : template <class O>
241 0 : void Layout<C, L, V>::_removeObserver(const O* observer)
242 : {
243 0 : for (typename Views::const_iterator i = _views.begin(); i != _views.end();
244 : ++i)
245 : {
246 0 : V* view = *i;
247 0 : if (view->getObserver() == observer)
248 : {
249 0 : LBINFO << "Removing " << lunchbox::disableHeader << *observer
250 0 : << " used by " << *view << std::endl
251 0 : << lunchbox::enableHeader;
252 0 : view->setObserver(0);
253 : }
254 : }
255 0 : }
256 :
257 : template <class C, class L, class V>
258 7 : bool Layout<C, L, V>::isActive() const
259 : {
260 7 : const typename C::Canvases& canvases = _config->getCanvases();
261 39 : for (typename C::Canvases::const_iterator i = canvases.begin();
262 26 : i != canvases.end(); ++i)
263 : {
264 7 : if ((*i)->getActiveLayout() == this)
265 1 : return true;
266 : }
267 6 : return false;
268 : }
269 :
270 : template <class C, class L, class V>
271 2906 : V* Layout<C, L, V>::getView(const ViewPath& path)
272 : {
273 2906 : LBASSERTINFO(_views.size() > path.viewIndex,
274 : _views.size() << " <= " << path.viewIndex << " " << this);
275 :
276 2906 : if (_views.size() <= path.viewIndex)
277 0 : return 0;
278 :
279 2906 : return _views[path.viewIndex];
280 : }
281 :
282 : template <class C, class L, class V>
283 928 : LayoutPath Layout<C, L, V>::getPath() const
284 : {
285 928 : LBASSERT(_config);
286 928 : const std::vector<L*>& layouts = _config->getLayouts();
287 : typename std::vector<L*>::const_iterator i =
288 928 : std::find(layouts.begin(), layouts.end(), this);
289 928 : LBASSERT(i != layouts.end());
290 :
291 928 : LayoutPath path;
292 928 : path.layoutIndex = std::distance(layouts.begin(), i);
293 928 : return path;
294 : }
295 :
296 : template <class C, class L, class V>
297 2 : V* Layout<C, L, V>::findView(const std::string& name)
298 : {
299 4 : NameFinder<V, Visitor> finder(name);
300 2 : accept(finder);
301 4 : return finder.getResult();
302 : }
303 :
304 : //----------------------------------------------------------------------
305 : // ICommand handlers
306 : //----------------------------------------------------------------------
307 : template <class C, class L, class V>
308 0 : bool Layout<C, L, V>::_cmdNewView(co::ICommand& cmd)
309 : {
310 0 : co::ObjectICommand command(cmd);
311 :
312 0 : V* view = 0;
313 0 : create(&view);
314 0 : LBASSERT(view);
315 :
316 0 : getLocalNode()->registerObject(view);
317 0 : view->setAutoObsolete(_config->getLatency() + 1);
318 0 : LBASSERT(view->isAttached());
319 :
320 0 : send(command.getRemoteNode(), CMD_LAYOUT_NEW_VIEW_REPLY)
321 0 : << command.read<uint32_t>() << view->getID();
322 :
323 0 : return true;
324 : }
325 :
326 : template <class C, class L, class V>
327 0 : bool Layout<C, L, V>::_cmdNewViewReply(co::ICommand& cmd)
328 : {
329 0 : co::ObjectICommand command(cmd);
330 0 : const uint32_t requestID = command.read<uint32_t>();
331 0 : const uint128_t& result = command.read<uint128_t>();
332 :
333 0 : getLocalNode()->serveRequest(requestID, result);
334 :
335 0 : return true;
336 : }
337 :
338 : template <class C, class L, class V>
339 342 : std::ostream& operator<<(std::ostream& os, const Layout<C, L, V>& layout)
340 : {
341 342 : os << lunchbox::disableFlush << lunchbox::disableHeader << "layout"
342 : << std::endl;
343 342 : os << "{" << std::endl << lunchbox::indent;
344 :
345 342 : const std::string& name = layout.getName();
346 342 : if (!name.empty())
347 180 : os << "name \"" << name << "\"" << std::endl;
348 :
349 342 : const std::vector<V*>& views = layout.getViews();
350 2154 : for (typename std::vector<V*>::const_iterator i = views.begin();
351 1436 : i != views.end(); ++i)
352 : {
353 376 : os << **i;
354 : }
355 684 : os << lunchbox::exdent << "}" << std::endl
356 342 : << lunchbox::enableHeader << lunchbox::enableFlush;
357 342 : return os;
358 : }
359 : }
360 : }
|