Line data Source code
1 :
2 : /* Copyright (c) 2005-2016, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : * Julio Delgado Mangas <julio.delgadomangas@epfl.ch>
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 "channel.h"
21 :
22 : #include "channelListener.h"
23 : #include "channelUpdateVisitor.h"
24 : #include "compound.h"
25 : #include "compoundVisitor.h"
26 : #include "config.h"
27 : #include "configVisitor.h"
28 : #include "global.h"
29 : #include "log.h"
30 : #include "node.h"
31 : #include "segment.h"
32 : #include "view.h"
33 : #include "window.h"
34 :
35 : #include <eq/fabric/commands.h>
36 : #include <eq/fabric/paths.h>
37 : #include <eq/fabric/statistic.h>
38 :
39 : #include <co/objectICommand.h>
40 :
41 : #include <lunchbox/debug.h>
42 :
43 : #include <set>
44 :
45 : namespace eq
46 : {
47 : namespace server
48 : {
49 : typedef co::CommandFunc<Channel> CmdFunc;
50 : typedef fabric::Channel<Window, Channel> Super;
51 :
52 : namespace
53 : {
54 : typedef std::set<View*> ViewSet;
55 :
56 : class ViewFinder : public ConfigVisitor
57 : {
58 : public:
59 0 : explicit ViewFinder(const Channel* channel)
60 0 : : _channel(channel)
61 : {
62 0 : }
63 0 : virtual ~ViewFinder() {}
64 0 : virtual VisitorResult visit(Compound* compound)
65 : {
66 0 : Channel* channel = compound->getChannel();
67 0 : if (channel != _channel)
68 0 : return TRAVERSE_CONTINUE;
69 :
70 0 : channel = compound->getInheritChannel();
71 0 : if (channel->getView())
72 0 : _viewSet.insert(channel->getView());
73 0 : return TRAVERSE_CONTINUE;
74 : }
75 :
76 0 : ViewSet& getViews() { return _viewSet; }
77 : private:
78 : const Channel* _channel;
79 : ViewSet _viewSet;
80 : };
81 : }
82 :
83 1650 : Channel::Channel(Window* parent)
84 : : Super(parent)
85 : , _active(0)
86 : , _view(0)
87 : , _segment(0)
88 : , _state(STATE_STOPPED)
89 : , _lastDrawCompound(0)
90 1650 : , _private(0)
91 : {
92 1650 : const Global* global = Global::instance();
93 13200 : for (unsigned i = 0; i < IATTR_ALL; ++i)
94 : {
95 11550 : const IAttribute attr = static_cast<IAttribute>(i);
96 11550 : setIAttribute(attr, global->getChannelIAttribute(attr));
97 : }
98 11550 : for (unsigned i = 0; i < SATTR_ALL; ++i)
99 : {
100 9900 : const SAttribute attr = static_cast<SAttribute>(i);
101 9900 : setSAttribute(attr, global->getChannelSAttribute(attr));
102 : }
103 1650 : }
104 :
105 1224 : Channel::Channel(const Channel& from)
106 : : Super(from)
107 : , _active(0)
108 : , _view(0)
109 : , _segment(0)
110 : , _state(STATE_STOPPED)
111 : , _lastDrawCompound(0)
112 1224 : , _private(0)
113 : {
114 : // Don't copy view and segment. Will be re-set by segment copy ctor
115 1224 : }
116 :
117 18 : void Channel::attach(const uint128_t& id, const uint32_t instanceID)
118 : {
119 18 : Super::attach(id, instanceID);
120 :
121 18 : co::CommandQueue* mainQ = getMainThreadQueue();
122 18 : co::CommandQueue* cmdQ = getCommandThreadQueue();
123 :
124 18 : registerCommand(fabric::CMD_CHANNEL_CONFIG_INIT_REPLY,
125 36 : CmdFunc(this, &Channel::_cmdConfigInitReply), cmdQ);
126 18 : registerCommand(fabric::CMD_CHANNEL_CONFIG_EXIT_REPLY,
127 36 : CmdFunc(this, &Channel::_cmdConfigExitReply), cmdQ);
128 18 : registerCommand(fabric::CMD_CHANNEL_FRAME_FINISH_REPLY,
129 36 : CmdFunc(this, &Channel::_cmdFrameFinishReply), mainQ);
130 18 : }
131 :
132 5740 : Channel::~Channel()
133 : {
134 5740 : }
135 :
136 0 : void Channel::postDelete()
137 : {
138 : // Deregister server-queue command handler to avoid assertion in
139 : // command invokation after channel deletion
140 0 : registerCommand(fabric::CMD_CHANNEL_FRAME_FINISH_REPLY,
141 0 : CmdFunc(this, &Channel::_cmdNop), 0);
142 0 : }
143 :
144 618 : Config* Channel::getConfig()
145 : {
146 618 : Window* window = getWindow();
147 618 : LBASSERT(window);
148 618 : return window ? window->getConfig() : 0;
149 : }
150 :
151 4 : const Config* Channel::getConfig() const
152 : {
153 4 : const Window* window = getWindow();
154 4 : LBASSERT(window);
155 4 : return window ? window->getConfig() : 0;
156 : }
157 :
158 46 : Node* Channel::getNode()
159 : {
160 46 : Window* window = getWindow();
161 46 : LBASSERT(window);
162 46 : return window ? window->getNode() : 0;
163 : }
164 :
165 0 : const Node* Channel::getNode() const
166 : {
167 0 : const Window* window = getWindow();
168 0 : LBASSERT(window);
169 0 : return window ? window->getNode() : 0;
170 : }
171 :
172 4 : Pipe* Channel::getPipe()
173 : {
174 4 : Window* window = getWindow();
175 4 : LBASSERT(window);
176 4 : return window ? window->getPipe() : 0;
177 : }
178 :
179 0 : const Pipe* Channel::getPipe() const
180 : {
181 0 : const Window* window = getWindow();
182 0 : LBASSERT(window);
183 0 : return window ? window->getPipe() : 0;
184 : }
185 :
186 18 : ServerPtr Channel::getServer()
187 : {
188 18 : Window* window = getWindow();
189 18 : LBASSERT(window);
190 18 : return (window ? window->getServer() : 0);
191 : }
192 :
193 34 : const Canvas* Channel::getCanvas() const
194 : {
195 34 : if (!_segment)
196 0 : return 0;
197 34 : return _segment->getCanvas();
198 : }
199 :
200 4 : const Compounds& Channel::getCompounds() const
201 : {
202 4 : return getConfig()->getCompounds();
203 : }
204 :
205 18 : co::CommandQueue* Channel::getMainThreadQueue()
206 : {
207 18 : Window* window = getWindow();
208 18 : LBASSERT(window);
209 18 : return window->getMainThreadQueue();
210 : }
211 :
212 18 : co::CommandQueue* Channel::getCommandThreadQueue()
213 : {
214 18 : Window* window = getWindow();
215 18 : LBASSERT(window);
216 18 : return window->getCommandThreadQueue();
217 : }
218 :
219 650 : bool Channel::supportsView(const View* view) const
220 : {
221 650 : if (!view)
222 0 : return true;
223 :
224 650 : const uint64_t minimum = view->getMinimumCapabilities();
225 650 : const uint64_t supported = getCapabilities();
226 650 : return ((supported & minimum) == minimum);
227 : }
228 :
229 8 : void Channel::activate()
230 : {
231 8 : Window* window = getWindow();
232 8 : LBASSERT(window);
233 :
234 8 : ++_active;
235 8 : window->activate();
236 :
237 8 : LBLOG(LOG_VIEW) << "activate: " << _active << " " << (void*)this
238 8 : << std::endl;
239 8 : }
240 :
241 8 : void Channel::deactivate()
242 : {
243 8 : Window* window = getWindow();
244 8 : LBASSERT(_active != 0);
245 8 : LBASSERT(window);
246 :
247 8 : --_active;
248 8 : window->deactivate();
249 :
250 8 : LBLOG(LOG_VIEW) << "deactivate: " << _active << " " << (void*)this
251 8 : << std::endl;
252 8 : }
253 :
254 1224 : void Channel::setOutput(View* view, Segment* segment)
255 : {
256 1224 : if (_view == view && _segment == segment)
257 0 : return;
258 :
259 1224 : LBASSERT(!_view && !_segment);
260 1224 : LBASSERT(view && segment);
261 :
262 1224 : _view = view;
263 1224 : _segment = segment;
264 :
265 1224 : view->addChannel(this);
266 1224 : segment->addDestinationChannel(this);
267 :
268 1224 : co::ObjectVersion viewVersion(view);
269 1224 : if (view && view->isDirty())
270 0 : ++viewVersion.version;
271 :
272 1224 : setViewVersion(viewVersion);
273 : }
274 :
275 1222 : void Channel::unsetOutput()
276 : {
277 1222 : LBASSERT(_view && _segment);
278 :
279 1222 : LBCHECK(_view->removeChannel(this));
280 1222 : LBCHECK(_segment->removeDestinationChannel(this));
281 :
282 1222 : _view = 0;
283 1222 : _segment = 0;
284 1222 : }
285 :
286 482 : const Layout* Channel::getLayout() const
287 : {
288 482 : LBASSERT(_view);
289 482 : return _view ? _view->getLayout() : 0;
290 : }
291 :
292 126 : void Channel::addTasks(const uint32_t tasks)
293 : {
294 126 : Window* window = getWindow();
295 126 : LBASSERT(window);
296 126 : setTasks(getTasks() | tasks);
297 126 : window->addTasks(tasks);
298 126 : }
299 :
300 : //===========================================================================
301 : // Operations
302 : //===========================================================================
303 :
304 : //---------------------------------------------------------------------------
305 : // init
306 : //---------------------------------------------------------------------------
307 4 : void Channel::configInit(const uint128_t& initID, const uint32_t /*frame*/)
308 : {
309 4 : LBASSERT(_state == STATE_STOPPED);
310 4 : _state = STATE_INITIALIZING;
311 :
312 4 : LBLOG(LOG_INIT) << "Init channel" << std::endl;
313 4 : getWindow()->send(fabric::CMD_WINDOW_CREATE_CHANNEL) << getID();
314 4 : send(fabric::CMD_CHANNEL_CONFIG_INIT) << initID;
315 4 : }
316 :
317 4 : bool Channel::syncConfigInit()
318 : {
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 Channel::configExit()
338 : {
339 4 : LBASSERT(_state == STATE_RUNNING || _state == STATE_INIT_FAILED);
340 4 : _state = STATE_EXITING;
341 :
342 4 : LBLOG(LOG_INIT) << "Exit channel" << std::endl;
343 4 : send(fabric::CMD_CHANNEL_CONFIG_EXIT);
344 4 : }
345 :
346 4 : bool Channel::syncConfigExit()
347 : {
348 4 : LBASSERT(_state == STATE_EXITING || _state == STATE_EXIT_SUCCESS ||
349 : _state == STATE_EXIT_FAILED);
350 :
351 4 : _state.waitNE(STATE_EXITING);
352 4 : const bool success = (_state == STATE_EXIT_SUCCESS);
353 4 : LBASSERT(success || _state == STATE_EXIT_FAILED);
354 :
355 4 : _state = isActive() ? STATE_FAILED : STATE_STOPPED;
356 4 : return success;
357 : }
358 :
359 : //---------------------------------------------------------------------------
360 : // update
361 : //---------------------------------------------------------------------------
362 4 : void Channel::_setupRenderContext(const uint128_t& frameID,
363 : RenderContext& context)
364 : {
365 4 : context.frameID = frameID;
366 4 : context.pvp = getPixelViewport();
367 4 : context.view = _view;
368 4 : context.vp = getViewport();
369 4 : LBASSERTINFO(getNativeContext().view == context.view,
370 : getNativeContext().view << " != " << context.view << " "
371 : << getName());
372 4 : }
373 :
374 18 : bool Channel::update(const uint128_t& frameID, const uint32_t frameNumber)
375 : {
376 18 : if (!isRunning())
377 14 : return false; // not updated
378 :
379 4 : LBASSERT(isActive())
380 4 : LBASSERT(getWindow()->isActive());
381 :
382 8 : RenderContext context;
383 4 : _setupRenderContext(frameID, context);
384 8 : send(fabric::CMD_CHANNEL_FRAME_START) << context << getVersion()
385 4 : << frameNumber;
386 4 : LBLOG(LOG_TASKS) << "TASK channel " << getName() << " start frame "
387 4 : << frameNumber << std::endl;
388 :
389 4 : bool updated = false;
390 4 : const Compounds& compounds = getCompounds();
391 32 : for (Compounds::const_iterator i = compounds.begin(); i != compounds.end();
392 : ++i)
393 : {
394 28 : const Compound* compound = *i;
395 56 : ChannelUpdateVisitor visitor(this, frameID, frameNumber);
396 :
397 28 : visitor.setEye(EYE_CYCLOP);
398 28 : compound->accept(visitor);
399 :
400 28 : visitor.setEye(EYE_LEFT);
401 28 : compound->accept(visitor);
402 :
403 28 : visitor.setEye(EYE_RIGHT);
404 28 : compound->accept(visitor);
405 :
406 28 : updated |= visitor.isUpdated();
407 : }
408 :
409 4 : send(fabric::CMD_CHANNEL_FRAME_FINISH) << context << frameNumber;
410 4 : LBLOG(LOG_TASKS) << "TASK channel " << getName() << " finish frame "
411 4 : << frameNumber << std::endl;
412 4 : _lastDrawCompound = 0;
413 :
414 4 : return updated;
415 : }
416 :
417 34 : co::ObjectOCommand Channel::send(const uint32_t cmd)
418 : {
419 34 : return getNode()->send(cmd, getID());
420 : }
421 :
422 : //---------------------------------------------------------------------------
423 : // Listener interface
424 : //---------------------------------------------------------------------------
425 20 : void Channel::addListener(ChannelListener* listener)
426 : {
427 40 : LB_TS_SCOPED(_serverThread);
428 20 : LBASSERT(std::find(_listeners.begin(), _listeners.end(), listener) ==
429 : _listeners.end());
430 :
431 20 : _listeners.push_back(listener);
432 20 : }
433 :
434 20 : void Channel::removeListener(ChannelListener* listener)
435 : {
436 : ChannelListeners::iterator i =
437 20 : find(_listeners.begin(), _listeners.end(), listener);
438 20 : if (i != _listeners.end())
439 20 : _listeners.erase(i);
440 20 : }
441 :
442 4 : void Channel::_fireLoadData(const uint32_t frameNumber,
443 : const fabric::Statistics& statistics,
444 : const Viewport& region)
445 : {
446 8 : LB_TS_SCOPED(_serverThread);
447 8 : for (ChannelListener* listener : _listeners)
448 4 : listener->notifyLoadData(this, frameNumber, statistics, region);
449 4 : }
450 :
451 : //===========================================================================
452 : // command handling
453 : //===========================================================================
454 4 : bool Channel::_cmdConfigInitReply(co::ICommand& cmd)
455 : {
456 8 : co::ObjectICommand command(cmd);
457 4 : const bool result = command.read<bool>();
458 :
459 4 : LBLOG(LOG_INIT) << "handle channel configInit reply " << command
460 4 : << " result " << result << std::endl;
461 :
462 4 : _state = result ? STATE_INIT_SUCCESS : STATE_INIT_FAILED;
463 8 : return true;
464 : }
465 :
466 4 : bool Channel::_cmdConfigExitReply(co::ICommand& cmd)
467 : {
468 8 : co::ObjectICommand command(cmd);
469 4 : LBLOG(LOG_INIT) << "handle channel configExit reply " << command
470 4 : << std::endl;
471 :
472 4 : _state = command.read<bool>() ? STATE_EXIT_SUCCESS : STATE_EXIT_FAILED;
473 8 : return true;
474 : }
475 :
476 4 : bool Channel::_cmdFrameFinishReply(co::ICommand& cmd)
477 : {
478 8 : co::ObjectICommand command(cmd);
479 4 : const Viewport& region = command.read<Viewport>();
480 4 : const uint32_t frameNumber = command.read<uint32_t>();
481 8 : const Statistics& statistics = command.read<Statistics>();
482 :
483 4 : _fireLoadData(frameNumber, statistics, region);
484 8 : return true;
485 : }
486 :
487 1462 : bool Channel::omitOutput() const
488 : {
489 : // don't print generated channels for now
490 1462 : return _view || _segment;
491 : }
492 :
493 0 : void Channel::output(std::ostream& os) const
494 : {
495 0 : bool attrPrinted = false;
496 :
497 0 : for (IAttribute i = static_cast<IAttribute>(0); i < IATTR_LAST;
498 0 : i = static_cast<IAttribute>(static_cast<uint32_t>(i) + 1))
499 : {
500 0 : const int value = getIAttribute(i);
501 0 : if (value == Global::instance()->getChannelIAttribute(i))
502 0 : continue;
503 :
504 0 : if (!attrPrinted)
505 : {
506 0 : os << std::endl
507 0 : << "attributes" << std::endl
508 0 : << "{" << std::endl
509 0 : << lunchbox::indent;
510 0 : attrPrinted = true;
511 : }
512 :
513 : os << (i == IATTR_HINT_STATISTICS
514 : ? "hint_statistics "
515 0 : : i == IATTR_HINT_SENDTOKEN ? "hint_sendtoken "
516 0 : : "ERROR ")
517 0 : << static_cast<fabric::IAttribute>(value) << std::endl;
518 : }
519 0 : for (SAttribute i = static_cast<SAttribute>(0); i < SATTR_LAST;
520 0 : i = static_cast<SAttribute>(static_cast<uint32_t>(i) + 1))
521 : {
522 0 : const std::string& value = getSAttribute(i);
523 0 : if (value == Global::instance()->getChannelSAttribute(i))
524 0 : continue;
525 :
526 0 : if (!attrPrinted)
527 : {
528 0 : os << std::endl
529 0 : << "attributes" << std::endl
530 0 : << "{" << std::endl
531 0 : << lunchbox::indent;
532 0 : attrPrinted = true;
533 : }
534 :
535 : os << (i == SATTR_DUMP_IMAGE ? "dump_image " : "ERROR ") << "\""
536 0 : << value << "\"" << std::endl;
537 : }
538 :
539 0 : if (attrPrinted)
540 0 : os << lunchbox::exdent << "}" << std::endl << std::endl;
541 0 : }
542 :
543 0 : void Channel::updateCapabilities()
544 : {
545 0 : ViewFinder visitor(this);
546 0 : getConfig()->accept(visitor);
547 0 : ViewSet& views = visitor.getViews();
548 :
549 0 : for (ViewSet::const_iterator i = views.begin(); i != views.end(); ++i)
550 0 : (*i)->updateCapabilities();
551 0 : }
552 : }
553 : }
554 :
555 : #include "../fabric/channel.ipp"
556 : template class eq::fabric::Channel<eq::server::Window, eq::server::Channel>;
557 : /** @cond IGNORE */
558 : template std::ostream& eq::fabric::operator<<(std::ostream&,
559 60 : const eq::server::Super&);
560 : /** @endcond */
|