Line data Source code
1 :
2 : /* Copyright (c) 2010-2016, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : * Cedric Stalder <cedric.stalder@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 "pipe.h"
21 :
22 : #include "commands.h"
23 : #include "elementVisitor.h"
24 : #include "leafVisitor.h"
25 : #include "log.h"
26 : #include "task.h"
27 :
28 : #include <co/dataIStream.h>
29 : #include <co/dataOStream.h>
30 : #include <co/objectICommand.h>
31 :
32 : namespace eq
33 : {
34 : namespace fabric
35 : {
36 : namespace
37 : {
38 : #define MAKE_PIPE_ATTR_STRING(attr) (std::string("EQ_PIPE_") + #attr)
39 100 : std::string _iPipeAttributeStrings[] = {
40 100 : MAKE_PIPE_ATTR_STRING(IATTR_HINT_THREAD),
41 100 : MAKE_PIPE_ATTR_STRING(IATTR_HINT_AFFINITY),
42 250 : };
43 : }
44 :
45 : template <class N, class P, class W, class V>
46 1152 : Pipe<N, P, W, V>::Pipe(N* parent)
47 : : _node(parent)
48 : , _port(LB_UNDEFINED_UINT32)
49 1152 : , _device(LB_UNDEFINED_UINT32)
50 : {
51 1152 : memset(_iAttributes, 0xff, IATTR_ALL * sizeof(int32_t));
52 1152 : parent->_addPipe(static_cast<P*>(this));
53 1152 : LBLOG(LOG_INIT) << "New " << lunchbox::className(this) << std::endl;
54 1152 : }
55 :
56 : template <class N, class P, class W, class V>
57 1150 : Pipe<N, P, W, V>::~Pipe()
58 : {
59 1150 : LBLOG(LOG_INIT) << "Delete " << lunchbox::className(this) << std::endl;
60 4134 : while (!_windows.empty())
61 : {
62 1492 : W* window = _windows.back();
63 1492 : _removeWindow(window);
64 1492 : delete window;
65 : }
66 1150 : _node->_removePipe(static_cast<P*>(this));
67 2300 : }
68 :
69 : template <class N, class P, class W, class V>
70 4 : void Pipe<N, P, W, V>::backup()
71 : {
72 4 : Object::backup();
73 4 : _backup = _data;
74 4 : }
75 :
76 : template <class N, class P, class W, class V>
77 0 : void Pipe<N, P, W, V>::restore()
78 : {
79 0 : _data = _backup;
80 0 : Object::restore();
81 0 : notifyPixelViewportChanged();
82 0 : setDirty(DIRTY_PIXELVIEWPORT);
83 0 : }
84 :
85 : template <class N, class P, class W, class V>
86 6 : void Pipe<N, P, W, V>::attach(const uint128_t& id, const uint32_t instanceID)
87 : {
88 6 : Object::attach(id, instanceID);
89 :
90 6 : co::CommandQueue* queue = _node->getConfig()->getMainThreadQueue();
91 6 : LBASSERT(queue);
92 :
93 6 : registerCommand(CMD_PIPE_NEW_WINDOW,
94 : CmdFunc(this, &Pipe<N, P, W, V>::_cmdNewWindow), queue);
95 6 : registerCommand(CMD_PIPE_NEW_WINDOW_REPLY,
96 : CmdFunc(this, &Pipe<N, P, W, V>::_cmdNewWindowReply), 0);
97 6 : }
98 :
99 : template <class N, class P, class W, class V>
100 20 : uint128_t Pipe<N, P, W, V>::commit(const uint32_t incarnation)
101 : {
102 20 : if (Serializable::isDirty(DIRTY_WINDOWS))
103 16 : commitChildren<W>(_windows, CMD_PIPE_NEW_WINDOW, incarnation);
104 20 : return Object::commit(incarnation);
105 : }
106 :
107 : template <class N, class P, class W, class V>
108 18 : void Pipe<N, P, W, V>::serialize(co::DataOStream& os, const uint64_t dirtyBits)
109 : {
110 18 : Object::serialize(os, dirtyBits);
111 18 : if (dirtyBits & DIRTY_ATTRIBUTES)
112 4 : os << co::Array<int32_t>(_iAttributes, IATTR_ALL);
113 18 : if (dirtyBits & DIRTY_WINDOWS && isMaster())
114 : {
115 14 : os << _mapNodeObjects();
116 14 : os.serializeChildren(_windows);
117 : }
118 18 : if (dirtyBits & DIRTY_PIXELVIEWPORT)
119 10 : os << _data.pvp;
120 18 : if (dirtyBits & DIRTY_MEMBER)
121 4 : os << _port << _device;
122 18 : }
123 :
124 : template <class N, class P, class W, class V>
125 13 : void Pipe<N, P, W, V>::deserialize(co::DataIStream& is,
126 : const uint64_t dirtyBits)
127 : {
128 13 : Object::deserialize(is, dirtyBits);
129 13 : if (dirtyBits & DIRTY_ATTRIBUTES)
130 2 : is >> co::Array<int32_t>(_iAttributes, IATTR_ALL);
131 13 : if (dirtyBits & DIRTY_WINDOWS)
132 : {
133 9 : if (isMaster())
134 4 : syncChildren(_windows);
135 : else
136 : {
137 5 : const bool useChildren = is.read<bool>();
138 5 : if (useChildren && _mapNodeObjects())
139 : {
140 0 : Windows result;
141 0 : is.deserializeChildren(this, _windows, result);
142 0 : _windows.swap(result);
143 0 : LBASSERT(_windows.size() == result.size());
144 : }
145 : else // consume unused ObjectVersions
146 5 : is.read<co::ObjectVersions>();
147 : }
148 : }
149 13 : if (dirtyBits & DIRTY_PIXELVIEWPORT)
150 : {
151 8 : PixelViewport pvp;
152 8 : is >> pvp;
153 8 : setPixelViewport(pvp);
154 : }
155 13 : if (dirtyBits & DIRTY_MEMBER)
156 2 : is >> _port >> _device;
157 13 : }
158 :
159 : template <class N, class P, class W, class V>
160 59328 : void Pipe<N, P, W, V>::setDirty(const uint64_t dirtyBits)
161 : {
162 59328 : Object::setDirty(dirtyBits);
163 59328 : _node->setDirty(N::DIRTY_PIPES);
164 59328 : }
165 :
166 : template <class N, class P, class W, class V>
167 6 : void Pipe<N, P, W, V>::notifyDetach()
168 : {
169 6 : Object::notifyDetach();
170 6 : while (!_windows.empty())
171 : {
172 4 : W* window = _windows.back();
173 4 : if (!window->isAttached())
174 : {
175 4 : LBASSERT(isMaster());
176 4 : return;
177 : }
178 :
179 0 : LBASSERT(!isMaster());
180 :
181 0 : getLocalNode()->unmapObject(window);
182 0 : _removeWindow(window);
183 0 : _node->getServer()->getNodeFactory()->releaseWindow(window);
184 : }
185 : }
186 :
187 : template <class N, class P, class W, class V>
188 0 : void Pipe<N, P, W, V>::create(W** window)
189 : {
190 0 : *window = _node->getServer()->getNodeFactory()->createWindow(
191 : static_cast<P*>(this));
192 0 : (*window)->init(); // not in ctor, virtual method
193 0 : }
194 :
195 : template <class N, class P, class W, class V>
196 0 : void Pipe<N, P, W, V>::release(W* window)
197 : {
198 0 : _node->getServer()->getNodeFactory()->releaseWindow(window);
199 0 : }
200 :
201 : namespace
202 : {
203 : template <class P, class V>
204 33356 : VisitorResult _accept(P* pipe, V& visitor)
205 : {
206 33356 : VisitorResult result = visitor.visitPre(pipe);
207 33356 : if (result != TRAVERSE_CONTINUE)
208 0 : return result;
209 :
210 33356 : const typename P::Windows& windows = pipe->getWindows();
211 197970 : for (typename P::Windows::const_iterator i = windows.begin();
212 131980 : i != windows.end(); ++i)
213 : {
214 38046 : switch ((*i)->accept(visitor))
215 : {
216 : case TRAVERSE_TERMINATE:
217 5412 : return TRAVERSE_TERMINATE;
218 :
219 : case TRAVERSE_PRUNE:
220 0 : result = TRAVERSE_PRUNE;
221 0 : break;
222 :
223 : case TRAVERSE_CONTINUE:
224 : default:
225 32634 : break;
226 : }
227 : }
228 :
229 27944 : switch (visitor.visitPost(pipe))
230 : {
231 : case TRAVERSE_TERMINATE:
232 0 : return TRAVERSE_TERMINATE;
233 :
234 : case TRAVERSE_PRUNE:
235 0 : return TRAVERSE_PRUNE;
236 :
237 : case TRAVERSE_CONTINUE:
238 : default:
239 27944 : break;
240 : }
241 :
242 27944 : return result;
243 : }
244 : }
245 :
246 : template <class N, class P, class W, class V>
247 33356 : VisitorResult Pipe<N, P, W, V>::accept(V& visitor)
248 : {
249 33356 : return _accept(static_cast<P*>(this), visitor);
250 : }
251 :
252 : template <class N, class P, class W, class V>
253 0 : VisitorResult Pipe<N, P, W, V>::accept(V& visitor) const
254 : {
255 0 : return _accept(static_cast<const P*>(this), visitor);
256 : }
257 :
258 : template <class N, class P, class W, class V>
259 4 : PipePath Pipe<N, P, W, V>::getPath() const
260 : {
261 4 : const N* node = getNode();
262 4 : LBASSERT(node);
263 4 : PipePath path(node->getPath());
264 :
265 4 : const typename std::vector<P*>& pipes = node->getPipes();
266 : typename std::vector<P*>::const_iterator i =
267 4 : std::find(pipes.begin(), pipes.end(), this);
268 4 : LBASSERT(i != pipes.end());
269 4 : path.pipeIndex = std::distance(pipes.begin(), i);
270 4 : return path;
271 : }
272 :
273 : template <class N, class P, class W, class V>
274 2320 : void Pipe<N, P, W, V>::setIAttribute(const IAttribute attr, const int32_t value)
275 : {
276 2320 : if (_iAttributes[attr] == value)
277 1150 : return;
278 :
279 1170 : _iAttributes[attr] = value;
280 1170 : setDirty(DIRTY_ATTRIBUTES);
281 : }
282 :
283 : template <class N, class P, class W, class V>
284 128 : void Pipe<N, P, W, V>::setDevice(const uint32_t device)
285 : {
286 128 : _device = device;
287 128 : setDirty(DIRTY_MEMBER);
288 128 : }
289 :
290 : template <class N, class P, class W, class V>
291 4 : void Pipe<N, P, W, V>::setPort(const uint32_t port)
292 : {
293 4 : _port = port;
294 4 : setDirty(DIRTY_MEMBER);
295 4 : }
296 :
297 : template <class N, class P, class W, class V>
298 1496 : void Pipe<N, P, W, V>::_addWindow(W* window)
299 : {
300 1496 : LBASSERT(window->getPipe() == this);
301 1496 : _windows.push_back(window);
302 1496 : setDirty(DIRTY_WINDOWS);
303 1496 : }
304 :
305 : template <class N, class P, class W, class V>
306 2986 : bool Pipe<N, P, W, V>::_removeWindow(W* window)
307 : {
308 : typename Windows::iterator i =
309 2986 : find(_windows.begin(), _windows.end(), window);
310 2986 : if (i == _windows.end())
311 1492 : return false;
312 :
313 1494 : _windows.erase(i);
314 1494 : setDirty(DIRTY_WINDOWS);
315 1494 : if (!isMaster())
316 1494 : postRemove(window);
317 1494 : return true;
318 : }
319 :
320 : template <class N, class P, class W, class V>
321 2 : W* Pipe<N, P, W, V>::_findWindow(const uint128_t& id)
322 : {
323 6 : for (typename Windows::const_iterator i = _windows.begin();
324 4 : i != _windows.end(); ++i)
325 : {
326 2 : W* window = *i;
327 2 : if (window->getID() == id)
328 2 : return window;
329 : }
330 0 : return 0;
331 : }
332 :
333 : template <class N, class P, class W, class V>
334 1222 : const std::string& Pipe<N, P, W, V>::getIAttributeString(const IAttribute attr)
335 : {
336 1222 : return _iPipeAttributeStrings[attr];
337 : }
338 :
339 : //----------------------------------------------------------------------
340 : // viewport
341 : //----------------------------------------------------------------------
342 : template <class N, class P, class W, class V>
343 12 : void Pipe<N, P, W, V>::setPixelViewport(const PixelViewport& pvp)
344 : {
345 12 : if (pvp == _data.pvp || !pvp.hasArea())
346 6 : return;
347 :
348 6 : _data.pvp = pvp;
349 6 : notifyPixelViewportChanged();
350 6 : LBVERB << "Pipe pvp set: " << _data.pvp << std::endl;
351 : }
352 :
353 : template <class N, class P, class W, class V>
354 6 : void Pipe<N, P, W, V>::notifyPixelViewportChanged()
355 : {
356 6 : const Windows& windows = getWindows();
357 18 : for (typename Windows::const_iterator i = windows.begin();
358 12 : i != windows.end(); ++i)
359 : {
360 0 : (*i)->notifyViewportChanged();
361 : }
362 6 : setDirty(DIRTY_PIXELVIEWPORT);
363 6 : LBVERB << getName() << " pvp update: " << _data.pvp << std::endl;
364 6 : }
365 :
366 : //----------------------------------------------------------------------
367 : // ICommand handlers
368 : //----------------------------------------------------------------------
369 : template <class N, class P, class W, class V>
370 0 : bool Pipe<N, P, W, V>::_cmdNewWindow(co::ICommand& cmd)
371 : {
372 0 : co::ObjectICommand command(cmd);
373 :
374 0 : W* window = 0;
375 0 : create(&window);
376 0 : LBASSERT(window);
377 :
378 0 : getLocalNode()->registerObject(window);
379 0 : LBASSERT(window->isAttached());
380 :
381 0 : send(command.getRemoteNode(), CMD_PIPE_NEW_WINDOW_REPLY)
382 0 : << command.read<uint32_t>() << window->getID();
383 :
384 0 : return true;
385 : }
386 :
387 : template <class N, class P, class W, class V>
388 0 : bool Pipe<N, P, W, V>::_cmdNewWindowReply(co::ICommand& cmd)
389 : {
390 0 : co::ObjectICommand command(cmd);
391 :
392 0 : const uint32_t requestID = command.read<uint32_t>();
393 0 : const uint128_t& result = command.read<uint128_t>();
394 :
395 0 : getLocalNode()->serveRequest(requestID, result);
396 :
397 0 : return true;
398 : }
399 :
400 : template <class N, class P, class W, class V>
401 580 : std::ostream& operator<<(std::ostream& os, const Pipe<N, P, W, V>& pipe)
402 : {
403 580 : os << lunchbox::disableFlush << lunchbox::disableHeader << "pipe"
404 : << std::endl;
405 580 : os << "{" << std::endl << lunchbox::indent;
406 :
407 580 : const std::string& name = pipe.getName();
408 580 : if (!name.empty())
409 90 : os << "name \"" << name << "\"" << std::endl;
410 :
411 580 : if (pipe.getPort() != LB_UNDEFINED_UINT32)
412 8 : os << "port " << pipe.getPort() << std::endl;
413 :
414 580 : if (pipe.getDevice() != LB_UNDEFINED_UINT32)
415 70 : os << "device " << pipe.getDevice() << std::endl;
416 :
417 580 : const PixelViewport& pvp = pipe.getPixelViewport();
418 580 : if (pvp.hasArea())
419 8 : os << "viewport " << pvp << std::endl;
420 :
421 580 : pipe.output(os);
422 580 : os << std::endl;
423 :
424 580 : const typename P::Windows& windows = pipe.getWindows();
425 3996 : for (typename P::Windows::const_iterator i = windows.begin();
426 2664 : i != windows.end(); ++i)
427 : {
428 752 : os << **i;
429 : }
430 :
431 1160 : os << lunchbox::exdent << "}" << std::endl
432 580 : << lunchbox::enableHeader << lunchbox::enableFlush;
433 580 : return os;
434 : }
435 : }
436 : }
|