Line data Source code
1 :
2 : /* Copyright (c) 2010-2016, Stefan Eilemann <eile@eyescale.ch>
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 "canvas.h"
20 :
21 : #include "commands.h"
22 : #include "elementVisitor.h"
23 : #include "leafVisitor.h"
24 : #include "log.h"
25 : #include "nameFinder.h"
26 : #include "paths.h"
27 : #include "segment.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 CFG, class C, class S, class L>
38 421 : Canvas<CFG, C, S, L>::Canvas(CFG* config)
39 421 : : _config(config)
40 : {
41 421 : LBASSERT(config);
42 421 : setWall(Wall()); // default frustum
43 421 : config->_addCanvas(static_cast<C*>(this));
44 421 : LBLOG(LOG_INIT) << "New " << lunchbox::className(this) << std::endl;
45 421 : }
46 :
47 : template <class CFG, class C, class S, class L>
48 419 : Canvas<CFG, C, S, L>::~Canvas()
49 : {
50 419 : LBLOG(LOG_INIT) << "Delete " << lunchbox::className(this) << std::endl;
51 1999 : while (!_segments.empty())
52 : {
53 790 : S* segment = _segments.back();
54 790 : _removeChild(segment);
55 790 : release(segment);
56 : }
57 :
58 419 : _data.activeLayout = 0;
59 419 : _layouts.clear();
60 419 : _config->_removeCanvas(static_cast<C*>(this));
61 838 : }
62 :
63 : template <class CFG, class C, class S, class L>
64 2 : void Canvas<CFG, C, S, L>::backup()
65 : {
66 2 : _backup = _data;
67 2 : Object::backup();
68 2 : Frustum::backup();
69 2 : }
70 :
71 : template <class CFG, class C, class S, class L>
72 0 : void Canvas<CFG, C, S, L>::restore()
73 : {
74 0 : Frustum::restore();
75 0 : Object::restore();
76 0 : activateLayout(_backup.activeLayout);
77 0 : _data = _backup;
78 0 : setDirty(DIRTY_LAYOUT);
79 0 : }
80 :
81 : template <class CFG, class C, class S, class L>
82 3 : void Canvas<CFG, C, S, L>::attach(const uint128_t& id,
83 : const uint32_t instanceID)
84 : {
85 3 : Object::attach(id, instanceID);
86 :
87 3 : co::CommandQueue* queue = _config->getMainThreadQueue();
88 3 : LBASSERT(queue);
89 :
90 3 : registerCommand(CMD_CANVAS_NEW_SEGMENT,
91 : CmdFunc(this, &Canvas<CFG, C, S, L>::_cmdNewSegment),
92 : queue);
93 3 : registerCommand(CMD_CANVAS_NEW_SEGMENT_REPLY,
94 : CmdFunc(this, &Canvas<CFG, C, S, L>::_cmdNewSegmentReply),
95 : 0);
96 3 : }
97 :
98 : template <class CFG, class C, class S, class L>
99 17 : uint128_t Canvas<CFG, C, S, L>::commit(const uint32_t incarnation)
100 : {
101 17 : if (Serializable::isDirty(DIRTY_SEGMENTS))
102 3 : commitChildren<S>(_segments, CMD_CANVAS_NEW_SEGMENT, incarnation);
103 17 : return Object::commit(incarnation);
104 : }
105 :
106 : template <class CFG, class C, class S, class L>
107 7 : void Canvas<CFG, C, S, L>::serialize(co::DataOStream& os,
108 : const uint64_t dirtyBits)
109 : {
110 7 : Object::serialize(os, dirtyBits);
111 :
112 7 : if (dirtyBits & DIRTY_LAYOUT)
113 4 : os << _data.activeLayout;
114 7 : if (dirtyBits & DIRTY_SEGMENTS && isMaster())
115 6 : os.serializeChildren(_segments);
116 7 : if (dirtyBits & DIRTY_LAYOUTS)
117 4 : os.serializeChildren(_layouts);
118 7 : if (dirtyBits & DIRTY_FRUSTUM)
119 7 : Frustum::serialize(os);
120 7 : }
121 :
122 : template <class CFG, class C, class S, class L>
123 4 : void Canvas<CFG, C, S, L>::deserialize(co::DataIStream& is,
124 : const uint64_t dirtyBits)
125 : {
126 4 : Object::deserialize(is, dirtyBits);
127 :
128 4 : if (dirtyBits & DIRTY_LAYOUT)
129 : {
130 1 : uint32_t index(0);
131 1 : is >> index;
132 1 : activateLayout(index);
133 : }
134 :
135 4 : if (dirtyBits & DIRTY_SEGMENTS)
136 : {
137 4 : if (isMaster())
138 2 : syncChildren(_segments);
139 : else
140 : {
141 4 : Segments result;
142 2 : is.deserializeChildren(this, _segments, result);
143 2 : _segments.swap(result);
144 2 : LBASSERT(_segments.size() == result.size());
145 : }
146 : }
147 :
148 4 : if (dirtyBits & DIRTY_LAYOUTS)
149 : {
150 1 : _layouts.clear();
151 2 : co::ObjectVersions layouts;
152 1 : is >> layouts;
153 24 : for (co::ObjectVersions::const_iterator i = layouts.begin();
154 16 : i != layouts.end(); ++i)
155 : {
156 7 : const uint128_t& id = (*i).identifier;
157 :
158 7 : if (id == 0)
159 0 : _layouts.push_back(0);
160 : else
161 : {
162 7 : L* layout = 0;
163 7 : _config->find(id, &layout);
164 7 : LBASSERT(layout);
165 7 : _layouts.push_back(layout);
166 : }
167 : }
168 :
169 1 : _config->updateCanvas(static_cast<C*>(this));
170 : }
171 4 : if (dirtyBits & DIRTY_FRUSTUM)
172 4 : Frustum::deserialize(is);
173 4 : }
174 :
175 : template <class CFG, class C, class S, class L>
176 5065 : void Canvas<CFG, C, S, L>::setDirty(const uint64_t dirtyBits)
177 : {
178 5065 : Object::setDirty(dirtyBits);
179 5065 : _config->setDirty(CFG::DIRTY_CANVASES);
180 5065 : }
181 :
182 : template <class CFG, class C, class S, class L>
183 1 : void Canvas<CFG, C, S, L>::create(S** segment)
184 : {
185 1 : *segment = _config->getServer()->getNodeFactory()->createSegment(
186 : static_cast<C*>(this));
187 1 : }
188 :
189 : template <class CFG, class C, class S, class L>
190 791 : void Canvas<CFG, C, S, L>::release(S* segment)
191 : {
192 791 : _config->getServer()->getNodeFactory()->releaseSegment(segment);
193 791 : }
194 :
195 : template <class CFG, class C, class S, class L>
196 3 : void Canvas<CFG, C, S, L>::notifyDetach()
197 : {
198 3 : Object::notifyDetach();
199 3 : releaseChildren<C, S>(_segments);
200 3 : }
201 :
202 : template <class CFG, class C, class S, class L>
203 793 : void Canvas<CFG, C, S, L>::_addChild(S* segment)
204 : {
205 793 : LBASSERT(segment);
206 793 : LBASSERT(segment->getCanvas() == this);
207 793 : _segments.push_back(segment);
208 793 : setDirty(DIRTY_SEGMENTS);
209 793 : }
210 :
211 : template <class CFG, class C, class S, class L>
212 1582 : bool Canvas<CFG, C, S, L>::_removeChild(S* segment)
213 : {
214 1582 : typename Segments::iterator i = lunchbox::find(_segments, segment);
215 1582 : if (i == _segments.end())
216 791 : return false;
217 :
218 791 : LBASSERT(segment->getCanvas() == this);
219 791 : _segments.erase(i);
220 791 : setDirty(DIRTY_SEGMENTS);
221 791 : if (isAttached() && !isMaster())
222 1 : postRemove(segment);
223 791 : return true;
224 : }
225 :
226 : template <class CFG, class C, class S, class L>
227 1 : bool Canvas<CFG, C, S, L>::_mapViewObjects()
228 : {
229 1 : return static_cast<typename CFG::Super*>(_config)->mapViewObjects();
230 : }
231 :
232 : template <class CFG, class C, class S, class L>
233 1264 : CanvasPath Canvas<CFG, C, S, L>::getPath() const
234 : {
235 1264 : const CFG* config = getConfig();
236 1264 : LBASSERT(config);
237 :
238 1264 : const Canvases& canvases = config->getCanvases();
239 : typename Canvases::const_iterator i =
240 1264 : std::find(canvases.begin(), canvases.end(), this);
241 1264 : LBASSERT(i != canvases.end());
242 :
243 1264 : CanvasPath path;
244 1264 : path.canvasIndex = std::distance(canvases.begin(), i);
245 1264 : return path;
246 : }
247 :
248 : template <class CFG, class C, class S, class L>
249 0 : S* Canvas<CFG, C, S, L>::findSegment(const std::string& name)
250 : {
251 0 : NameFinder<S, Visitor> finder(name);
252 0 : accept(finder);
253 0 : return finder.getResult();
254 : }
255 :
256 : template <class CFG, class C, class S, class L>
257 0 : const S* Canvas<CFG, C, S, L>::findSegment(const std::string& name) const
258 : {
259 0 : NameFinder<const S, Visitor> finder(name);
260 0 : accept(finder);
261 0 : return finder.getResult();
262 : }
263 :
264 : template <class CFG, class C, class S, class L>
265 656 : void Canvas<CFG, C, S, L>::addLayout(L* layout)
266 : {
267 656 : LBASSERT(lunchbox::find(_layouts, layout) == _layouts.end());
268 :
269 : // dest channel creation is done be Config::addCanvas
270 656 : _layouts.push_back(layout);
271 656 : setDirty(DIRTY_LAYOUTS);
272 656 : }
273 :
274 : template <class CFG, class C, class S, class L>
275 0 : bool Canvas<CFG, C, S, L>::removeLayout(L* layout)
276 : {
277 0 : typename Layouts::iterator i = lunchbox::find(_layouts, layout);
278 0 : if (i == _layouts.end())
279 0 : return false;
280 :
281 0 : if (getActiveLayout() == layout)
282 : {
283 0 : _data.activeLayout = 0;
284 0 : setDirty(DIRTY_LAYOUT);
285 : }
286 :
287 0 : _layouts.erase(i);
288 0 : setDirty(DIRTY_LAYOUTS);
289 0 : return true;
290 : }
291 :
292 : template <class CFG, class C, class S, class L>
293 8 : const L* Canvas<CFG, C, S, L>::getActiveLayout() const
294 : {
295 8 : LBASSERTINFO(_data.activeLayout < _layouts.size(),
296 : _data.activeLayout << " >= " << _layouts.size());
297 8 : return _layouts[_data.activeLayout];
298 : }
299 :
300 : template <class CFG, class C, class S, class L>
301 7 : L* Canvas<CFG, C, S, L>::getActiveLayout()
302 : {
303 7 : LBASSERTINFO(_data.activeLayout < _layouts.size(),
304 : _data.activeLayout << " >= " << _layouts.size());
305 7 : return _layouts[_data.activeLayout];
306 : }
307 :
308 : template <class CFG, class C, class S, class L>
309 0 : bool Canvas<CFG, C, S, L>::useLayout(const uint32_t index)
310 : {
311 0 : LBASSERT(index < _layouts.size());
312 0 : if (_data.activeLayout == index)
313 0 : return false;
314 :
315 0 : _data.activeLayout = index;
316 0 : setDirty(DIRTY_LAYOUT);
317 0 : return true;
318 : }
319 :
320 : template <class CFG, class C, class S, class L>
321 8 : void Canvas<CFG, C, S, L>::setSwapBarrier(SwapBarrierPtr barrier)
322 : {
323 8 : if (barrier.isValid() && barrier->getName().empty())
324 : {
325 4 : const std::string& name = getName();
326 8 : std::stringstream out;
327 4 : out << "barrier.canvas.";
328 4 : if (name.empty())
329 4 : if (getConfig())
330 4 : out << getPath().canvasIndex;
331 : else
332 0 : out << (void*)this;
333 : else
334 0 : out << name;
335 :
336 4 : barrier->setName(out.str());
337 : }
338 :
339 8 : _swapBarrier = barrier;
340 8 : }
341 :
342 : namespace
343 : {
344 : template <class C, class V>
345 2551 : VisitorResult _accept(C* canvas, V& visitor)
346 : {
347 2551 : VisitorResult result = visitor.visitPre(canvas);
348 2551 : if (result != TRAVERSE_CONTINUE)
349 32 : return result;
350 :
351 2519 : const typename C::Segments& segments = canvas->getSegments();
352 32268 : for (typename C::Segments::const_iterator i = segments.begin();
353 21512 : i != segments.end(); ++i)
354 : {
355 8237 : switch ((*i)->accept(visitor))
356 : {
357 : case TRAVERSE_TERMINATE:
358 0 : return TRAVERSE_TERMINATE;
359 :
360 : case TRAVERSE_PRUNE:
361 0 : result = TRAVERSE_PRUNE;
362 0 : break;
363 :
364 : case TRAVERSE_CONTINUE:
365 : default:
366 8237 : break;
367 : }
368 : }
369 :
370 2519 : switch (visitor.visitPost(canvas))
371 : {
372 : case TRAVERSE_TERMINATE:
373 0 : return TRAVERSE_TERMINATE;
374 :
375 : case TRAVERSE_PRUNE:
376 0 : return TRAVERSE_PRUNE;
377 :
378 : case TRAVERSE_CONTINUE:
379 : default:
380 2519 : break;
381 : }
382 :
383 2519 : return result;
384 : }
385 : }
386 :
387 : template <class CFG, class C, class S, class L>
388 2551 : VisitorResult Canvas<CFG, C, S, L>::accept(Visitor& visitor)
389 : {
390 2551 : return _accept(static_cast<C*>(this), visitor);
391 : }
392 :
393 : template <class CFG, class C, class S, class L>
394 0 : VisitorResult Canvas<CFG, C, S, L>::accept(Visitor& visitor) const
395 : {
396 0 : return _accept(static_cast<const C*>(this), visitor);
397 : }
398 :
399 : template <class CFG, class C, class S, class L>
400 817 : void Canvas<CFG, C, S, L>::setWall(const Wall& wall)
401 : {
402 817 : if (getWall() == wall && getCurrentType() == TYPE_WALL)
403 290 : return;
404 :
405 527 : Frustum::setWall(wall);
406 527 : setDirty(DIRTY_FRUSTUM);
407 1581 : for (typename Segments::const_iterator i = _segments.begin();
408 1054 : i != _segments.end(); ++i)
409 : {
410 0 : (*i)->inheritFrustum();
411 : }
412 : }
413 :
414 : template <class CFG, class C, class S, class L>
415 0 : void Canvas<CFG, C, S, L>::setProjection(const Projection& projection)
416 : {
417 0 : if (getProjection() == projection && getCurrentType() == TYPE_PROJECTION)
418 0 : return;
419 :
420 0 : Frustum::setProjection(projection);
421 0 : setDirty(DIRTY_FRUSTUM);
422 0 : for (typename Segments::const_iterator i = _segments.begin();
423 0 : i != _segments.end(); ++i)
424 : {
425 0 : (*i)->inheritFrustum();
426 : }
427 : }
428 :
429 : template <class CFG, class C, class S, class L>
430 0 : void Canvas<CFG, C, S, L>::unsetFrustum()
431 : {
432 0 : if (getCurrentType() == TYPE_NONE)
433 0 : return;
434 :
435 0 : Frustum::unsetFrustum();
436 0 : setDirty(DIRTY_FRUSTUM);
437 : }
438 :
439 : //----------------------------------------------------------------------
440 : // ICommand handlers
441 : //----------------------------------------------------------------------
442 : template <class CFG, class C, class S, class L>
443 0 : bool Canvas<CFG, C, S, L>::_cmdNewSegment(co::ICommand& cmd)
444 : {
445 0 : co::ObjectICommand command(cmd);
446 :
447 0 : S* segment = 0;
448 0 : create(&segment);
449 0 : LBASSERT(segment);
450 :
451 0 : getLocalNode()->registerObject(segment);
452 0 : segment->setAutoObsolete(_config->getLatency() + 1);
453 0 : LBASSERT(segment->isAttached());
454 :
455 0 : send(command.getRemoteNode(), CMD_CANVAS_NEW_SEGMENT_REPLY)
456 0 : << command.read<uint32_t>() << segment->getID();
457 :
458 0 : return true;
459 : }
460 :
461 : template <class CFG, class C, class S, class L>
462 0 : bool Canvas<CFG, C, S, L>::_cmdNewSegmentReply(co::ICommand& cmd)
463 : {
464 0 : co::ObjectICommand command(cmd);
465 :
466 0 : const uint32_t requestID = command.read<uint32_t>();
467 0 : const uint128_t& result = command.read<uint128_t>();
468 :
469 0 : getLocalNode()->serveRequest(requestID, result);
470 :
471 0 : return true;
472 : }
473 :
474 : template <class CFG, class C, class S, class L>
475 212 : std::ostream& operator<<(std::ostream& os, const Canvas<CFG, C, S, L>& canvas)
476 : {
477 212 : os << lunchbox::disableFlush << lunchbox::disableHeader << "canvas"
478 : << std::endl;
479 212 : os << "{" << std::endl << lunchbox::indent;
480 :
481 212 : const std::string& name = canvas.getName();
482 212 : if (!name.empty())
483 6 : os << "name \"" << name << "\"" << std::endl;
484 :
485 212 : const std::vector<L*>& layouts = canvas.getLayouts();
486 1680 : for (typename std::vector<L*>::const_iterator i = layouts.begin();
487 1120 : i != layouts.end(); ++i)
488 : {
489 348 : L* layout = *i;
490 348 : if (layout)
491 : {
492 346 : const CFG* config = layout->getConfig();
493 346 : const std::string& layoutName = layout->getName();
494 346 : const L* foundLayout = 0;
495 346 : config->find(layoutName, &foundLayout);
496 346 : if (foundLayout == layout)
497 344 : os << "layout \"" << layoutName << "\"" << std::endl;
498 : else
499 2 : os << layout->getPath() << std::endl;
500 : }
501 : else
502 2 : os << "layout OFF" << std::endl;
503 : }
504 :
505 212 : if (canvas.getSwapBarrier().isValid())
506 4 : os << *canvas.getSwapBarrier();
507 212 : os << static_cast<const Frustum&>(canvas);
508 :
509 212 : const std::vector<S*>& segments = canvas.getSegments();
510 1830 : for (typename std::vector<S*>::const_iterator i = segments.begin();
511 1220 : i != segments.end(); ++i)
512 : {
513 398 : os << **i;
514 : }
515 424 : os << lunchbox::exdent << "}" << std::endl
516 212 : << lunchbox::enableHeader << lunchbox::enableFlush;
517 212 : return os;
518 : }
519 : }
520 : }
|