Line data Source code
1 : /* Copyright (c) 2005-2017, Stefan Eilemann <eile@equalizergraphics.com>
2 : * Cedric Stalder <cedric.stalder@gmail.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 : // must be included before any header defining Bool
23 : #ifdef EQ_QT_USED
24 : #include "qt/window.h"
25 : #include <QThread>
26 : #endif
27 :
28 : #include "channelStatistics.h"
29 : #include "client.h"
30 : #include "compositor.h"
31 : #include "config.h"
32 : #include "detail/fileFrameWriter.h"
33 : #include "error.h"
34 : #include "frame.h"
35 : #include "frameData.h"
36 : #include "gl.h"
37 : #include "global.h"
38 : #include "image.h"
39 : #include "jitter.h"
40 : #include "log.h"
41 : #include "node.h"
42 : #include "nodeFactory.h"
43 : #include "pipe.h"
44 : #include "pixelData.h"
45 : #include "server.h"
46 : #include "systemWindow.h"
47 : #include "view.h"
48 : #include "window.h"
49 :
50 : #include <eq/fabric/commands.h>
51 : #include <eq/fabric/frameData.h>
52 : #include <eq/fabric/keyEvent.h>
53 : #include <eq/fabric/pointerEvent.h>
54 : #include <eq/fabric/sizeEvent.h>
55 : #include <eq/fabric/task.h>
56 : #include <eq/fabric/tile.h>
57 : #include <eq/util/accum.h>
58 : #include <eq/util/objectManager.h>
59 :
60 : #include <co/connectionDescription.h>
61 : #include <co/exception.h>
62 : #include <co/objectICommand.h>
63 : #include <co/queueSlave.h>
64 : #include <co/sendToken.h>
65 : #include <lunchbox/rng.h>
66 : #include <lunchbox/scopedMutex.h>
67 : #include <pression/plugins/compressor.h>
68 :
69 : #ifdef EQUALIZER_USE_GLSTATS
70 : #include "detail/statsRenderer.h"
71 : #include <GLStats/GLStats.h>
72 : #endif
73 :
74 : #include <bitset>
75 : #include <set>
76 :
77 : #include "detail/channel.ipp"
78 :
79 : #ifdef EQUALIZER_USE_DEFLECT
80 : #include "deflect/proxy.h"
81 : #endif
82 :
83 : namespace eq
84 : {
85 : /** @cond IGNORE */
86 : typedef fabric::Channel<Window, Channel> Super;
87 : typedef co::CommandFunc<Channel> CmdFunc;
88 : using detail::STATE_STOPPED;
89 : using detail::STATE_INITIALIZING;
90 : using detail::STATE_RUNNING;
91 : using detail::STATE_FAILED;
92 : /** @endcond */
93 :
94 2 : Channel::Channel(Window* parent)
95 : : Super(parent)
96 2 : , _impl(new detail::Channel)
97 : {
98 2 : }
99 :
100 4 : Channel::~Channel()
101 : {
102 2 : delete _impl;
103 2 : }
104 :
105 2 : void Channel::attach(const uint128_t& id, const uint32_t instanceID)
106 : {
107 2 : Super::attach(id, instanceID);
108 2 : co::CommandQueue* queue = getPipeThreadQueue();
109 2 : co::CommandQueue* commandQ = getCommandThreadQueue();
110 2 : co::CommandQueue* tmitQ = getNode()->getTransmitterQueue();
111 2 : co::CommandQueue* transferQ = getPipe()->getTransferThreadQueue();
112 :
113 2 : registerCommand(fabric::CMD_CHANNEL_CONFIG_INIT,
114 4 : CmdFunc(this, &Channel::_cmdConfigInit), queue);
115 2 : registerCommand(fabric::CMD_CHANNEL_CONFIG_EXIT,
116 4 : CmdFunc(this, &Channel::_cmdConfigExit), queue);
117 2 : registerCommand(fabric::CMD_CHANNEL_FRAME_START,
118 4 : CmdFunc(this, &Channel::_cmdFrameStart), queue);
119 2 : registerCommand(fabric::CMD_CHANNEL_FRAME_FINISH,
120 4 : CmdFunc(this, &Channel::_cmdFrameFinish), queue);
121 2 : registerCommand(fabric::CMD_CHANNEL_FRAME_CLEAR,
122 4 : CmdFunc(this, &Channel::_cmdFrameClear), queue);
123 2 : registerCommand(fabric::CMD_CHANNEL_FRAME_DRAW,
124 4 : CmdFunc(this, &Channel::_cmdFrameDraw), queue);
125 2 : registerCommand(fabric::CMD_CHANNEL_FRAME_DRAW_FINISH,
126 4 : CmdFunc(this, &Channel::_cmdFrameDrawFinish), queue);
127 2 : registerCommand(fabric::CMD_CHANNEL_FRAME_ASSEMBLE,
128 4 : CmdFunc(this, &Channel::_cmdFrameAssemble), queue);
129 2 : registerCommand(fabric::CMD_CHANNEL_FRAME_READBACK,
130 4 : CmdFunc(this, &Channel::_cmdFrameReadback), queue);
131 2 : registerCommand(fabric::CMD_CHANNEL_FRAME_TRANSMIT_IMAGE,
132 4 : CmdFunc(this, &Channel::_cmdFrameTransmitImage), tmitQ);
133 2 : registerCommand(fabric::CMD_CHANNEL_FRAME_SET_READY,
134 4 : CmdFunc(this, &Channel::_cmdFrameSetReady), transferQ);
135 2 : registerCommand(fabric::CMD_CHANNEL_FRAME_SET_READY_NODE,
136 4 : CmdFunc(this, &Channel::_cmdFrameSetReadyNode), tmitQ);
137 2 : registerCommand(fabric::CMD_CHANNEL_FRAME_VIEW_START,
138 4 : CmdFunc(this, &Channel::_cmdFrameViewStart), queue);
139 2 : registerCommand(fabric::CMD_CHANNEL_FRAME_VIEW_FINISH,
140 4 : CmdFunc(this, &Channel::_cmdFrameViewFinish), queue);
141 2 : registerCommand(fabric::CMD_CHANNEL_STOP_FRAME,
142 4 : CmdFunc(this, &Channel::_cmdStopFrame), commandQ);
143 2 : registerCommand(fabric::CMD_CHANNEL_FRAME_TILES,
144 4 : CmdFunc(this, &Channel::_cmdFrameTiles), queue);
145 2 : registerCommand(fabric::CMD_CHANNEL_FINISH_READBACK,
146 4 : CmdFunc(this, &Channel::_cmdFinishReadback), transferQ);
147 2 : registerCommand(fabric::CMD_CHANNEL_DELETE_TRANSFER_WINDOW,
148 4 : CmdFunc(this, &Channel::_cmdDeleteTransferWindow),
149 2 : transferQ);
150 2 : }
151 :
152 2 : co::CommandQueue* Channel::getPipeThreadQueue()
153 : {
154 2 : return getWindow()->getPipeThreadQueue();
155 : }
156 :
157 2 : co::CommandQueue* Channel::getCommandThreadQueue()
158 : {
159 2 : return getWindow()->getCommandThreadQueue();
160 : }
161 :
162 12 : uint32_t Channel::getCurrentFrame() const
163 : {
164 12 : return getPipe()->getCurrentFrame();
165 : }
166 :
167 21 : Pipe* Channel::getPipe()
168 : {
169 21 : Window* window = getWindow();
170 21 : LBASSERT(window);
171 21 : return (window ? window->getPipe() : 0);
172 : }
173 :
174 13 : const Pipe* Channel::getPipe() const
175 : {
176 13 : const Window* window = getWindow();
177 13 : LBASSERT(window);
178 13 : return (window ? window->getPipe() : 0);
179 : }
180 :
181 5 : Node* Channel::getNode()
182 : {
183 5 : Window* window = getWindow();
184 5 : LBASSERT(window);
185 5 : return (window ? window->getNode() : 0);
186 : }
187 0 : const Node* Channel::getNode() const
188 : {
189 0 : const Window* window = getWindow();
190 0 : LBASSERT(window);
191 0 : return (window ? window->getNode() : 0);
192 : }
193 :
194 39 : Config* Channel::getConfig()
195 : {
196 39 : Window* window = getWindow();
197 39 : LBASSERT(window);
198 39 : return (window ? window->getConfig() : 0);
199 : }
200 0 : const Config* Channel::getConfig() const
201 : {
202 0 : const Window* window = getWindow();
203 0 : LBASSERT(window);
204 0 : return (window ? window->getConfig() : 0);
205 : }
206 :
207 2 : ServerPtr Channel::getServer()
208 : {
209 2 : Window* window = getWindow();
210 2 : LBASSERT(window);
211 2 : return (window ? window->getServer() : 0);
212 : }
213 :
214 2 : util::ObjectManager& Channel::getObjectManager()
215 : {
216 2 : Window* window = getWindow();
217 2 : LBASSERT(window);
218 2 : return window->getObjectManager();
219 : }
220 :
221 3 : const DrawableConfig& Channel::getDrawableConfig() const
222 : {
223 3 : const Window* window = getWindow();
224 3 : LBASSERT(window);
225 3 : return window->getDrawableConfig();
226 : }
227 :
228 5 : const GLEWContext* Channel::glewGetContext() const
229 : {
230 5 : const Window* window = getWindow();
231 5 : LBASSERT(window);
232 5 : return window->glewGetContext();
233 : }
234 :
235 2 : bool Channel::configExit()
236 : {
237 : #ifdef EQUALIZER_USE_DEFLECT
238 2 : delete _impl->_deflectProxy;
239 2 : _impl->_deflectProxy = 0;
240 : #endif
241 2 : _impl->framebufferImage.flush();
242 2 : return true;
243 : }
244 :
245 2 : bool Channel::configInit(const uint128_t&)
246 : {
247 : #ifdef EQUALIZER_USE_DEFLECT
248 2 : if (getView())
249 : {
250 1 : LBASSERT(!_impl->_deflectProxy);
251 : try
252 : {
253 : // Try to create Deflect proxy from env vars or
254 : // config values, silently ignore failure
255 2 : _impl->_deflectProxy = new deflect::Proxy(*this);
256 : }
257 1 : catch (...)
258 : {
259 : }
260 : }
261 : #endif
262 2 : return true;
263 : }
264 :
265 8 : void Channel::notifyViewportChanged()
266 : {
267 8 : const PixelViewport oldPVP = getPixelViewport();
268 8 : Super::notifyViewportChanged();
269 8 : const PixelViewport& newPVP = getPixelViewport();
270 :
271 8 : if (newPVP == oldPVP)
272 5 : return;
273 :
274 3 : SizeEvent event;
275 3 : event.x = newPVP.x;
276 3 : event.y = newPVP.y;
277 3 : event.w = newPVP.w;
278 3 : event.h = newPVP.h;
279 :
280 3 : processEvent(EVENT_CHANNEL_RESIZE, event);
281 : }
282 :
283 0 : void Channel::notifyStopFrame(const uint32_t)
284 : {
285 0 : }
286 :
287 11 : void Channel::addStatistic(Statistic& event)
288 : {
289 : {
290 11 : const uint32_t frameNumber = event.frameNumber;
291 11 : const size_t index = frameNumber % _impl->statistics->size();
292 11 : LBASSERT(index < _impl->statistics->size());
293 11 : LBASSERTINFO(_impl->statistics.data[index].used > 0, frameNumber);
294 :
295 22 : lunchbox::ScopedFastWrite mutex(_impl->statistics);
296 11 : Statistics& statistics = _impl->statistics.data[index].data;
297 11 : statistics.push_back(event);
298 : }
299 11 : processEvent(event);
300 11 : }
301 :
302 : //---------------------------------------------------------------------------
303 : // operations
304 : //---------------------------------------------------------------------------
305 2 : bool Channel::waitFrameFinished(const uint32_t frame,
306 : const uint32_t timeout) const
307 : {
308 2 : return _impl->finishedFrame.timedWaitGE(frame, timeout);
309 : }
310 :
311 3 : void Channel::frameClear(const uint128_t&)
312 : {
313 3 : resetRegions();
314 3 : EQ_GL_CALL(applyBuffer());
315 3 : EQ_GL_CALL(applyViewport());
316 :
317 : #ifndef NDEBUG
318 3 : if (getenv("EQ_TAINT_CHANNELS"))
319 : {
320 0 : const Vector3ub color = getUniqueColor();
321 0 : EQ_GL_CALL(glClearColor(color.r() / 255.f, color.g() / 255.f,
322 : color.b() / 255.f, 0.f));
323 : }
324 : #endif // NDEBUG
325 :
326 3 : EQ_GL_CALL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
327 3 : }
328 :
329 0 : void Channel::frameDraw(const uint128_t&)
330 : {
331 0 : EQ_GL_CALL(applyBuffer());
332 0 : EQ_GL_CALL(applyViewport());
333 :
334 0 : const bool coreProfile = getWindow()->getIAttribute(
335 0 : WindowSettings::IATTR_HINT_CORE_PROFILE) == ON;
336 0 : if (coreProfile)
337 0 : return;
338 :
339 0 : EQ_GL_CALL(glMatrixMode(GL_PROJECTION));
340 0 : EQ_GL_CALL(glLoadIdentity());
341 0 : EQ_GL_CALL(applyFrustum());
342 :
343 0 : EQ_GL_CALL(glMatrixMode(GL_MODELVIEW));
344 0 : EQ_GL_CALL(glLoadIdentity());
345 0 : EQ_GL_CALL(applyHeadTransform());
346 : }
347 :
348 1 : void Channel::frameAssemble(const uint128_t&, const Frames& frames)
349 : {
350 1 : EQ_GL_CALL(applyBuffer());
351 1 : EQ_GL_CALL(applyViewport());
352 1 : EQ_GL_CALL(setupAssemblyState());
353 : try
354 : {
355 1 : Compositor::assembleFrames(frames, this, 0);
356 : }
357 0 : catch (const co::Exception& e)
358 : {
359 0 : LBWARN << e.what() << std::endl;
360 : }
361 1 : EQ_GL_CALL(resetAssemblyState());
362 1 : }
363 :
364 1 : void Channel::frameReadback(const uint128_t&, const Frames& frames)
365 : {
366 1 : const PixelViewport& region = getRegion();
367 1 : if (!region.hasArea())
368 0 : return;
369 :
370 1 : EQ_GL_CALL(applyBuffer());
371 1 : EQ_GL_CALL(applyViewport());
372 1 : EQ_GL_CALL(setupAssemblyState());
373 :
374 1 : util::ObjectManager& glObjects = getObjectManager();
375 1 : const DrawableConfig& drawable = getDrawableConfig();
376 :
377 2 : for (Frame* frame : frames)
378 2 : frame->startReadback(glObjects, drawable, PixelViewports(1, region),
379 2 : getContext());
380 :
381 1 : EQ_GL_CALL(resetAssemblyState());
382 : }
383 :
384 2 : void Channel::startFrame(const uint32_t)
385 : { /* nop */
386 2 : }
387 2 : void Channel::releaseFrame(const uint32_t)
388 : { /* nop */
389 2 : }
390 2 : void Channel::releaseFrameLocal(const uint32_t)
391 : { /* nop */
392 2 : }
393 :
394 2 : void Channel::frameStart(const uint128_t&, const uint32_t frameNumber)
395 : {
396 2 : resetRegions();
397 2 : startFrame(frameNumber);
398 2 : }
399 :
400 2 : void Channel::frameFinish(const uint128_t&, const uint32_t frameNumber)
401 : {
402 2 : _impl->frameFinish();
403 2 : releaseFrame(frameNumber);
404 2 : }
405 :
406 2 : void Channel::frameDrawFinish(const uint128_t&, const uint32_t frameNumber)
407 : {
408 2 : releaseFrameLocal(frameNumber);
409 2 : }
410 :
411 1 : void Channel::frameViewStart(const uint128_t&)
412 : { /* nop */
413 1 : }
414 :
415 1 : void Channel::frameViewFinish(const uint128_t& frameID)
416 : {
417 1 : frameDrawOverlay(frameID);
418 1 : _impl->frameViewFinish(*this);
419 1 : }
420 :
421 1 : void Channel::frameDrawOverlay(const uint128_t&)
422 : { /* nop */
423 1 : }
424 :
425 2 : void Channel::setupAssemblyState()
426 : {
427 2 : EQ_GL_CALL(bindFrameBuffer());
428 2 : const PixelViewport& pvp = getPixelViewport();
429 2 : const bool coreProfile = getWindow()->getIAttribute(
430 2 : WindowSettings::IATTR_HINT_CORE_PROFILE) == ON;
431 2 : if (!coreProfile)
432 2 : Compositor::setupAssemblyState(pvp, glewGetContext());
433 2 : }
434 :
435 2 : void Channel::resetAssemblyState()
436 : {
437 2 : EQ_GL_CALL(bindFrameBuffer());
438 2 : const bool coreProfile = getWindow()->getIAttribute(
439 2 : WindowSettings::IATTR_HINT_CORE_PROFILE) == ON;
440 2 : if (!coreProfile)
441 2 : Compositor::resetAssemblyState();
442 2 : }
443 :
444 9 : void Channel::_overrideContext(RenderContext& context)
445 : {
446 9 : overrideContext(context);
447 9 : Window* window = getWindow();
448 9 : window->_addRenderContext(context);
449 9 : }
450 :
451 0 : Frustumf Channel::getScreenFrustum() const
452 : {
453 0 : const Pixel& pixel = getPixel();
454 0 : PixelViewport pvp(getPixelViewport());
455 0 : const Viewport& vp(getViewport());
456 :
457 0 : pvp.x = static_cast<int32_t>(pvp.w / vp.w * vp.x);
458 0 : pvp.y = static_cast<int32_t>(pvp.h / vp.h * vp.y);
459 0 : pvp.unapply(pixel);
460 :
461 0 : return eq::Frustumf(static_cast<float>(pvp.x),
462 0 : static_cast<float>(pvp.getXEnd()),
463 0 : static_cast<float>(pvp.y),
464 0 : static_cast<float>(pvp.getYEnd()), -1.f, 1.f);
465 : }
466 :
467 5 : View* Channel::getView()
468 : {
469 5 : LB_TS_THREAD(_pipeThread);
470 5 : Pipe* pipe = getPipe();
471 5 : return pipe->getView(getContext().view);
472 : }
473 :
474 1 : const View* Channel::getView() const
475 : {
476 1 : LB_TS_THREAD(_pipeThread);
477 1 : const Pipe* pipe = getPipe();
478 1 : return pipe->getView(getContext().view);
479 : }
480 :
481 0 : co::QueueSlave* Channel::_getQueue(const uint128_t& queueID)
482 : {
483 0 : LB_TS_THREAD(_pipeThread);
484 0 : Pipe* pipe = getPipe();
485 0 : return pipe->getQueue(queueID);
486 : }
487 :
488 0 : View* Channel::getNativeView()
489 : {
490 0 : LB_TS_THREAD(_pipeThread);
491 0 : Pipe* pipe = getPipe();
492 0 : return pipe->getView(getNativeContext().view);
493 : }
494 :
495 0 : const View* Channel::getNativeView() const
496 : {
497 0 : LB_TS_THREAD(_pipeThread);
498 0 : const Pipe* pipe = getPipe();
499 0 : return pipe->getView(getNativeContext().view);
500 : }
501 :
502 2 : void Channel::changeLatency(const uint32_t latency)
503 : {
504 : #ifndef NDEBUG
505 6 : for (detail::Channel::StatisticsRBCIter i = _impl->statistics->begin();
506 4 : i != _impl->statistics->end(); ++i)
507 : {
508 0 : LBASSERT((*i).used == 0);
509 : }
510 : #endif // NDEBUG
511 2 : _impl->statistics->resize(latency + 1);
512 2 : }
513 :
514 0 : void Channel::addResultImageListener(ResultImageListener* listener)
515 : {
516 0 : _impl->addResultImageListener(listener);
517 0 : }
518 :
519 0 : void Channel::removeResultImageListener(ResultImageListener* listener)
520 : {
521 0 : _impl->removeResultImageListener(listener);
522 0 : }
523 :
524 0 : std::string Channel::getDumpImageFileName() const
525 : {
526 0 : std::stringstream name;
527 0 : name << getCurrentFrame() << ".rgb";
528 0 : return name.str();
529 : }
530 :
531 : //---------------------------------------------------------------------------
532 : // apply convenience methods
533 : //---------------------------------------------------------------------------
534 5 : void Channel::applyBuffer()
535 : {
536 5 : LB_TS_THREAD(_pipeThread);
537 5 : const Window* window = getWindow();
538 5 : if (!window->getSystemWindow()->getFrameBufferObject())
539 : {
540 3 : EQ_GL_CALL(glReadBuffer(getReadBuffer()));
541 3 : EQ_GL_CALL(glDrawBuffer(getDrawBuffer()));
542 : }
543 :
544 5 : applyColorMask();
545 5 : }
546 :
547 11 : void Channel::bindFrameBuffer()
548 : {
549 11 : LB_TS_THREAD(_pipeThread);
550 11 : const Window* window = getWindow();
551 11 : if (!window->getSystemWindow())
552 0 : return;
553 :
554 11 : if (_impl->_updateFrameBuffer)
555 : {
556 5 : window->updateFrameBuffer();
557 5 : _impl->_updateFrameBuffer = false;
558 : }
559 11 : window->bindFrameBuffer();
560 : }
561 :
562 5 : void Channel::bindDrawFrameBuffer()
563 : {
564 5 : LB_TS_THREAD(_pipeThread);
565 5 : const Window* window = getWindow();
566 5 : if (!window->getSystemWindow())
567 0 : return;
568 :
569 5 : window->bindDrawFrameBuffer();
570 5 : _impl->_updateFrameBuffer = true;
571 : }
572 :
573 5 : void Channel::applyColorMask() const
574 : {
575 5 : LB_TS_THREAD(_pipeThread);
576 5 : const ColorMask& colorMask = getDrawBufferMask();
577 5 : EQ_GL_CALL(
578 : glColorMask(colorMask.red, colorMask.green, colorMask.blue, true));
579 5 : }
580 :
581 5 : void Channel::applyViewport() const
582 : {
583 5 : LB_TS_THREAD(_pipeThread);
584 5 : const PixelViewport& pvp = getPixelViewport();
585 :
586 5 : if (!pvp.hasArea())
587 : {
588 0 : LBERROR << "Can't apply viewport " << pvp << std::endl;
589 0 : return;
590 : }
591 :
592 5 : EQ_GL_CALL(glViewport(pvp.x, pvp.y, pvp.w, pvp.h));
593 5 : EQ_GL_CALL(glScissor(pvp.x, pvp.y, pvp.w, pvp.h));
594 : }
595 :
596 0 : void Channel::applyFrustum() const
597 : {
598 0 : LB_TS_THREAD(_pipeThread);
599 0 : if (useOrtho())
600 0 : applyOrtho();
601 : else
602 0 : applyPerspective();
603 0 : }
604 :
605 0 : void Channel::applyPerspective() const
606 : {
607 0 : LB_TS_THREAD(_pipeThread);
608 0 : Frustumf frustum = getPerspective();
609 0 : const Vector2f jitter = getJitter();
610 :
611 0 : frustum.jitter(jitter);
612 0 : EQ_GL_CALL(glFrustum(frustum.left(), frustum.right(), frustum.bottom(),
613 : frustum.top(), frustum.nearPlane(),
614 : frustum.farPlane()));
615 0 : }
616 :
617 0 : void Channel::applyOrtho() const
618 : {
619 0 : LB_TS_THREAD(_pipeThread);
620 0 : Frustumf ortho = getOrtho();
621 0 : const Vector2f jitter = getJitter();
622 :
623 0 : ortho.jitter(jitter);
624 0 : EQ_GL_CALL(glOrtho(ortho.left(), ortho.right(), ortho.bottom(), ortho.top(),
625 : ortho.nearPlane(), ortho.farPlane()));
626 0 : }
627 :
628 0 : void Channel::applyScreenFrustum() const
629 : {
630 0 : LB_TS_THREAD(_pipeThread);
631 0 : const Frustumf frustum = getScreenFrustum();
632 0 : EQ_GL_CALL(glOrtho(frustum.left(), frustum.right(), frustum.bottom(),
633 : frustum.top(), frustum.nearPlane(), frustum.farPlane()));
634 0 : }
635 :
636 0 : void Channel::applyHeadTransform() const
637 : {
638 0 : LB_TS_THREAD(_pipeThread);
639 0 : if (useOrtho())
640 0 : applyOrthoTransform();
641 : else
642 0 : applyPerspectiveTransform();
643 0 : }
644 :
645 0 : void Channel::applyPerspectiveTransform() const
646 : {
647 0 : LB_TS_THREAD(_pipeThread);
648 0 : const Matrix4f& xfm = getPerspectiveTransform();
649 0 : EQ_GL_CALL(glMultMatrixf(xfm.array));
650 0 : }
651 :
652 0 : void Channel::applyOrthoTransform() const
653 : {
654 0 : LB_TS_THREAD(_pipeThread);
655 0 : const Matrix4f& xfm = getOrthoTransform();
656 0 : EQ_GL_CALL(glMultMatrixf(xfm.array));
657 0 : }
658 :
659 0 : void Channel::applyOverlayState()
660 : {
661 0 : applyBuffer();
662 0 : applyViewport();
663 0 : setupAssemblyState();
664 :
665 0 : glMatrixMode(GL_PROJECTION);
666 0 : glLoadIdentity();
667 0 : applyScreenFrustum();
668 :
669 0 : EQ_GL_CALL(glLogicOp(GL_XOR));
670 0 : EQ_GL_CALL(glEnable(GL_COLOR_LOGIC_OP));
671 0 : EQ_GL_CALL(glDisable(GL_DEPTH_TEST));
672 0 : EQ_GL_CALL(glDisable(GL_LIGHTING));
673 0 : EQ_GL_CALL(glCullFace(GL_BACK));
674 :
675 0 : EQ_GL_CALL(glColor3f(1.f, 1.f, 1.f));
676 0 : }
677 :
678 0 : void Channel::resetOverlayState()
679 : {
680 0 : EQ_GL_CALL(glDisable(GL_COLOR_LOGIC_OP));
681 0 : EQ_GL_CALL(glEnable(GL_DEPTH_TEST));
682 0 : EQ_GL_CALL(glEnable(GL_LIGHTING));
683 0 : resetAssemblyState();
684 0 : }
685 :
686 : namespace
687 : {
688 0 : static Vector2f* _lookupJitterTable(const uint32_t size)
689 : {
690 0 : switch (size)
691 : {
692 : case 2:
693 0 : return Jitter::j2;
694 : case 3:
695 0 : return Jitter::j3;
696 : case 4:
697 0 : return Jitter::j4;
698 : case 8:
699 0 : return Jitter::j8;
700 : case 15:
701 0 : return Jitter::j15;
702 : case 24:
703 0 : return Jitter::j24;
704 : case 66:
705 0 : return Jitter::j66;
706 : default:
707 0 : break;
708 : }
709 0 : return 0;
710 : }
711 : }
712 :
713 0 : Vector2f Channel::getJitter() const
714 : {
715 0 : const SubPixel& subpixel = getSubPixel();
716 0 : if (subpixel == SubPixel::ALL)
717 0 : return Vector2f();
718 :
719 : // Compute a pixel size
720 0 : const PixelViewport& pvp = getPixelViewport();
721 0 : const float pvp_w = static_cast<float>(pvp.w);
722 0 : const float pvp_h = static_cast<float>(pvp.h);
723 :
724 0 : const Frustumf& frustum = getFrustum();
725 0 : const float frustum_w = frustum.getWidth();
726 0 : const float frustum_h = frustum.getHeight();
727 :
728 0 : const float pixel_w = frustum_w / pvp_w;
729 0 : const float pixel_h = frustum_h / pvp_h;
730 :
731 0 : const Vector2f pixelSize(pixel_w, pixel_h);
732 :
733 0 : Vector2f* table = _lookupJitterTable(subpixel.size);
734 0 : Vector2f jitter;
735 0 : if (!table)
736 : {
737 0 : static lunchbox::RNG rng;
738 0 : jitter.x() = rng.get<float>();
739 0 : jitter.y() = rng.get<float>();
740 : }
741 : else
742 0 : jitter = table[subpixel.index];
743 :
744 0 : const Pixel& pixel = getPixel();
745 0 : jitter.x() /= static_cast<float>(pixel.w);
746 0 : jitter.y() /= static_cast<float>(pixel.h);
747 :
748 0 : return jitter * pixelSize;
749 : }
750 :
751 2 : bool Channel::isStopped() const
752 : {
753 2 : return _impl->state == STATE_STOPPED;
754 : }
755 :
756 0 : const Vector3ub& Channel::getUniqueColor() const
757 : {
758 0 : return _impl->color;
759 : }
760 :
761 5 : void Channel::resetRegions()
762 : {
763 5 : _impl->regions.clear();
764 5 : }
765 :
766 0 : void Channel::declareRegion(const eq::Viewport& vp)
767 : {
768 0 : eq::PixelViewport region = getPixelViewport();
769 0 : region.x = 0;
770 0 : region.y = 0;
771 :
772 0 : region.apply(vp);
773 0 : declareRegion(region);
774 0 : }
775 :
776 : namespace
777 : {
778 : #ifndef NDEBUG
779 3 : bool _hasOverlap(PixelViewports& regions)
780 : {
781 3 : if (regions.size() < 2)
782 2 : return false;
783 :
784 2 : for (size_t i = 0; i < regions.size() - 1; ++i)
785 2 : for (size_t j = i + 1; j < regions.size(); ++j)
786 : {
787 1 : PixelViewport pv = regions[j];
788 1 : pv.intersect(regions[i]);
789 1 : if (pv.hasArea())
790 0 : return true;
791 : }
792 1 : return false;
793 : }
794 : #endif
795 :
796 : /** Remove overlapping regions by merging them */
797 3 : bool _removeOverlap(PixelViewports& regions)
798 : {
799 3 : if (regions.size() < 2)
800 2 : return false;
801 :
802 2 : for (size_t i = 0; i < regions.size() - 1; ++i)
803 2 : for (size_t j = i + 1; j < regions.size(); ++j)
804 : {
805 1 : PixelViewport pvp = regions[i];
806 1 : if (!pvp.hasArea())
807 : {
808 0 : std::swap(regions[i], regions.back());
809 0 : regions.pop_back();
810 0 : return true;
811 : }
812 :
813 1 : pvp.intersect(regions[j]);
814 1 : if (pvp.hasArea())
815 : {
816 0 : regions[i].merge(regions[j]);
817 0 : std::swap(regions[j], regions.back());
818 0 : regions.pop_back();
819 0 : return true;
820 : }
821 : }
822 1 : return false;
823 : }
824 : }
825 :
826 3 : void Channel::declareRegion(const PixelViewport& region)
827 : {
828 3 : PixelViewports& regions = _impl->regions;
829 3 : PixelViewport clippedRegion = region;
830 3 : PixelViewport pvp = getPixelViewport();
831 3 : pvp.x = 0;
832 3 : pvp.y = 0;
833 :
834 3 : clippedRegion.intersect(pvp);
835 3 : if (clippedRegion.hasArea())
836 : {
837 3 : regions.push_back(clippedRegion);
838 : #ifndef NDEBUG
839 3 : const PixelViewport pvpBefore = getRegion();
840 : #endif
841 3 : while (_removeOverlap(regions))
842 : { /* nop */
843 : }
844 :
845 : #ifndef NDEBUG
846 3 : LBASSERT(!_hasOverlap(regions));
847 3 : LBASSERT(pvpBefore == getRegion());
848 : #endif
849 3 : return;
850 : }
851 :
852 0 : if (regions.empty()) // set on first declaration of empty ROI
853 0 : regions.push_back(PixelViewport(0, 0, 0, 0));
854 : }
855 :
856 11 : PixelViewport Channel::getRegion() const
857 : {
858 11 : PixelViewport region;
859 22 : for (const PixelViewport& pvp : _impl->regions)
860 11 : region.merge(pvp);
861 :
862 11 : return region;
863 : }
864 :
865 0 : const PixelViewports& Channel::getRegions() const
866 : {
867 0 : return _impl->regions;
868 : }
869 :
870 0 : EventOCommand Channel::sendError(const uint32_t error)
871 : {
872 0 : return getConfig()->sendError(EVENT_CHANNEL_ERROR, Error(error, getID()));
873 : }
874 :
875 3 : bool Channel::processEvent(const EventType type, SizeEvent& event)
876 : {
877 3 : Config* config = getConfig();
878 3 : updateEvent(event, config->getTime());
879 :
880 3 : if (type == EVENT_CHANNEL_RESIZE)
881 : {
882 3 : const uint128_t& viewID = getNativeContext().view.identifier;
883 3 : if (viewID == 0)
884 3 : return true;
885 :
886 : // transform to view event, which is meaningful for the config
887 0 : event.originator = viewID;
888 :
889 0 : event.dw = event.w / float(_impl->initialSize.x());
890 0 : event.dh = event.h / float(_impl->initialSize.y());
891 0 : config->sendEvent(EVENT_VIEW_RESIZE) << event;
892 0 : return true;
893 : }
894 :
895 0 : config->sendEvent(type) << event;
896 0 : return true;
897 : }
898 :
899 0 : bool Channel::processEvent(const EventType type, PointerEvent& event)
900 : {
901 0 : Config* config = getConfig();
902 0 : updateEvent(event, config->getTime());
903 0 : config->sendEvent(type) << event;
904 0 : return true;
905 : }
906 :
907 0 : bool Channel::processEvent(const EventType type, KeyEvent& event)
908 : {
909 0 : Config* config = getConfig();
910 0 : updateEvent(event, config->getTime());
911 0 : config->sendEvent(type) << event;
912 0 : return true;
913 : }
914 :
915 11 : bool Channel::processEvent(Statistic& event)
916 : {
917 11 : Config* config = getConfig();
918 11 : updateEvent(event, config->getTime());
919 11 : config->sendEvent(EVENT_STATISTIC) << event;
920 11 : return true;
921 : }
922 :
923 0 : void Channel::drawStatistics()
924 : {
925 0 : const PixelViewport& pvp = getPixelViewport();
926 0 : LBASSERT(pvp.hasArea());
927 0 : Window* window = getWindow();
928 : const bool coreProfile =
929 0 : window->getIAttribute(WindowSettings::IATTR_HINT_CORE_PROFILE) == ON;
930 0 : if (!pvp.hasArea() || coreProfile)
931 0 : return;
932 :
933 : //----- setup
934 0 : applyOverlayState();
935 :
936 0 : EQ_GL_CALL(glDisable(GL_COLOR_LOGIC_OP));
937 0 : EQ_GL_CALL(glEnable(GL_BLEND));
938 0 : EQ_GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
939 :
940 : #ifdef EQUALIZER_USE_GLSTATS
941 0 : const util::BitmapFont* font = window->getSmallFont();
942 0 : const Config* config = getConfig();
943 0 : const GLStats::Data& data = config->getStatistics();
944 0 : detail::StatsRenderer renderer(font);
945 0 : const Viewport& vp = getViewport();
946 0 : const uint32_t width = uint32_t(pvp.w / vp.w);
947 0 : const uint32_t height = uint32_t(pvp.h / vp.h);
948 :
949 0 : renderer.setViewport(width, height);
950 0 : renderer.draw(data);
951 : #endif
952 :
953 0 : EQ_GL_CALL(glEnable(GL_COLOR_LOGIC_OP));
954 0 : EQ_GL_CALL(glColor3f(1.f, 1.f, 1.f));
955 0 : window->drawFPS();
956 :
957 0 : EQ_GL_CALL(glDisable(GL_BLEND));
958 0 : resetOverlayState();
959 : }
960 :
961 0 : void Channel::outlineViewport()
962 : {
963 0 : const bool coreProfile = getWindow()->getIAttribute(
964 0 : WindowSettings::IATTR_HINT_CORE_PROFILE) == ON;
965 0 : if (coreProfile)
966 0 : return;
967 :
968 0 : applyOverlayState();
969 :
970 0 : const eq::PixelViewport& region = getRegion();
971 0 : glColor3f(.5f, .5f, .5f);
972 0 : glBegin(GL_LINE_LOOP);
973 : {
974 0 : glVertex3f(region.x + .5f, region.y + .5f, 0.f);
975 0 : glVertex3f(region.getXEnd() - .5f, region.y + .5f, 0.f);
976 0 : glVertex3f(region.getXEnd() - .5f, region.getYEnd() - .5f, 0.f);
977 0 : glVertex3f(region.x + .5f, region.getYEnd() - .5f, 0.f);
978 : }
979 0 : glEnd();
980 :
981 0 : const PixelViewport& pvp = getPixelViewport();
982 0 : glColor3f(1.0f, 1.0f, 1.0f);
983 0 : glBegin(GL_LINE_LOOP);
984 : {
985 0 : glVertex3f(pvp.x + .5f, pvp.y + .5f, 0.f);
986 0 : glVertex3f(pvp.getXEnd() - .5f, pvp.y + .5f, 0.f);
987 0 : glVertex3f(pvp.getXEnd() - .5f, pvp.getYEnd() - .5f, 0.f);
988 0 : glVertex3f(pvp.x + .5f, pvp.getYEnd() - .5f, 0.f);
989 : }
990 0 : glEnd();
991 :
992 0 : resetOverlayState();
993 : }
994 :
995 : namespace detail
996 : {
997 1 : struct RBStat
998 : {
999 1 : explicit RBStat(eq::Channel* channel)
1000 1 : : event(Statistic::CHANNEL_READBACK, channel)
1001 : , uncompressed(0)
1002 1 : , compressed(0)
1003 : {
1004 1 : event.statistic.plugins[0] = EQ_COMPRESSOR_NONE;
1005 1 : event.statistic.plugins[1] = EQ_COMPRESSOR_NONE;
1006 1 : LBASSERT(event.statistic.frameNumber > 0);
1007 1 : }
1008 :
1009 : lunchbox::SpinLock lock;
1010 : ChannelStatistics event;
1011 : size_t uncompressed;
1012 : size_t compressed;
1013 :
1014 2 : void ref(void*) { ++_refCount; }
1015 2 : bool unref(void*)
1016 : {
1017 2 : if (--_refCount > 0)
1018 1 : return false;
1019 :
1020 1 : if (uncompressed > 0 && compressed > 0)
1021 : {
1022 1 : event.statistic.ratio = float(compressed) / float(uncompressed);
1023 : }
1024 : else
1025 0 : event.statistic.ratio = 1.0f;
1026 1 : delete this;
1027 1 : return true;
1028 : }
1029 :
1030 : int32_t getRefCount() const { return _refCount; }
1031 : private:
1032 : a_int32_t _refCount;
1033 : };
1034 : }
1035 :
1036 : typedef lunchbox::RefPtr<detail::RBStat> RBStatPtr;
1037 :
1038 0 : void Channel::_frameTiles(RenderContext& context, const bool isLocal,
1039 : const uint128_t& queueID, const uint32_t tasks,
1040 : const co::ObjectVersions& frameIDs)
1041 : {
1042 0 : _overrideContext(context);
1043 0 : frameTilesStart(context.frameID);
1044 :
1045 0 : RBStatPtr stat;
1046 0 : Frames frames;
1047 0 : if (tasks & fabric::TASK_READBACK)
1048 : {
1049 0 : frames = _getFrames(frameIDs, true);
1050 0 : stat = new detail::RBStat(this);
1051 : }
1052 :
1053 0 : int64_t startTime = getConfig()->getTime();
1054 0 : int64_t clearTime = 0;
1055 0 : int64_t drawTime = 0;
1056 0 : int64_t readbackTime = 0;
1057 0 : bool hasAsyncReadback = false;
1058 0 : const uint32_t timeout = getConfig()->getTimeout();
1059 :
1060 0 : co::QueueSlave* queue = _getQueue(queueID);
1061 0 : LBASSERT(queue);
1062 : for (;;)
1063 : {
1064 0 : co::ObjectICommand tileCmd = queue->pop(timeout);
1065 0 : if (!tileCmd.isValid())
1066 0 : break;
1067 :
1068 0 : const Tile& tile = tileCmd.read<Tile>();
1069 0 : context.apply(tile, isLocal);
1070 0 : _overrideContext(context);
1071 :
1072 0 : if (tasks & fabric::TASK_CLEAR)
1073 : {
1074 0 : const int64_t time = getConfig()->getTime();
1075 0 : frameClear(context.frameID);
1076 0 : clearTime += getConfig()->getTime() - time;
1077 : }
1078 :
1079 0 : if (tasks & fabric::TASK_DRAW)
1080 : {
1081 0 : const int64_t time = getConfig()->getTime();
1082 0 : frameDraw(context.frameID);
1083 0 : drawTime += getConfig()->getTime() - time;
1084 : // Set to full region if application has declared nothing
1085 0 : if (!getRegion().isValid())
1086 0 : declareRegion(getPixelViewport());
1087 : }
1088 :
1089 0 : if (tasks & fabric::TASK_READBACK)
1090 : {
1091 0 : const int64_t time = getConfig()->getTime();
1092 0 : const size_t nFrames = frames.size();
1093 :
1094 0 : std::vector<size_t> nImages(nFrames, 0);
1095 0 : for (size_t i = 0; i < nFrames; ++i)
1096 : {
1097 0 : nImages[i] = frames[i]->getImages().size();
1098 0 : frames[i]->getFrameData()->setPixelViewport(getPixelViewport());
1099 : }
1100 :
1101 0 : frameReadback(context.frameID, frames);
1102 0 : readbackTime += getConfig()->getTime() - time;
1103 :
1104 0 : for (size_t i = 0; i < nFrames; ++i)
1105 : {
1106 0 : const Frame* frame = frames[i];
1107 0 : const Images& images = frame->getImages();
1108 0 : for (size_t j = nImages[i]; j < images.size(); ++j)
1109 : {
1110 0 : Image* image = images[j];
1111 0 : const PixelViewport& pvp = image->getPixelViewport();
1112 0 : image->setOffset(pvp.x + tile.pvp.x, pvp.y + tile.pvp.y);
1113 : }
1114 : }
1115 :
1116 0 : if (_asyncFinishReadback(nImages, frames))
1117 0 : hasAsyncReadback = true;
1118 : }
1119 0 : }
1120 :
1121 0 : if (tasks & fabric::TASK_CLEAR)
1122 : {
1123 0 : ChannelStatistics event(Statistic::CHANNEL_CLEAR, this);
1124 0 : event.statistic.startTime = startTime;
1125 0 : startTime += clearTime;
1126 0 : event.statistic.endTime = startTime;
1127 : }
1128 :
1129 0 : if (tasks & fabric::TASK_DRAW)
1130 : {
1131 0 : ChannelStatistics event(Statistic::CHANNEL_DRAW, this);
1132 0 : event.statistic.startTime = startTime;
1133 0 : startTime += drawTime;
1134 0 : event.statistic.endTime = startTime;
1135 : }
1136 :
1137 0 : if (tasks & fabric::TASK_READBACK)
1138 : {
1139 0 : stat->event.statistic.startTime = startTime;
1140 0 : startTime += readbackTime;
1141 0 : stat->event.statistic.endTime = startTime;
1142 :
1143 0 : _setReady(hasAsyncReadback, stat.get(), frames);
1144 : }
1145 :
1146 0 : frameTilesFinish(context.frameID);
1147 0 : resetContext();
1148 0 : }
1149 :
1150 3 : void Channel::_refFrame(const uint32_t frameNumber)
1151 : {
1152 3 : const size_t index = frameNumber % _impl->statistics->size();
1153 3 : detail::Channel::FrameStatistics& stats = _impl->statistics.data[index];
1154 3 : LBASSERTINFO(stats.used > 0, frameNumber);
1155 3 : ++stats.used;
1156 3 : }
1157 :
1158 5 : void Channel::_unrefFrame(const uint32_t frameNumber)
1159 : {
1160 5 : const size_t index = frameNumber % _impl->statistics->size();
1161 5 : detail::Channel::FrameStatistics& stats = _impl->statistics.data[index];
1162 5 : if (--stats.used != 0) // Frame still in use
1163 3 : return;
1164 :
1165 4 : send(getServer(), fabric::CMD_CHANNEL_FRAME_FINISH_REPLY)
1166 4 : << stats.region << frameNumber << stats.data;
1167 :
1168 2 : stats.data.clear();
1169 2 : stats.region = Viewport::FULL;
1170 2 : _impl->finishedFrame = frameNumber;
1171 : }
1172 :
1173 2 : Frames Channel::_getFrames(const co::ObjectVersions& frameIDs,
1174 : const bool isOutput)
1175 : {
1176 2 : LB_TS_THREAD(_pipeThread);
1177 :
1178 2 : Frames frames;
1179 4 : for (size_t i = 0; i < frameIDs.size(); ++i)
1180 : {
1181 2 : Pipe* pipe = getPipe();
1182 2 : Frame* frame = pipe->getFrame(frameIDs[i], getEye(), isOutput);
1183 2 : LBASSERTINFO(lunchbox::find(frames, frame) == frames.end(),
1184 : "frame " << i << " " << frameIDs[i]);
1185 :
1186 2 : frames.push_back(frame);
1187 : }
1188 :
1189 2 : return frames;
1190 : }
1191 :
1192 : //---------------------------------------------------------------------------
1193 : // Asynchronous image readback, compression and transmission
1194 : //---------------------------------------------------------------------------
1195 1 : void Channel::_frameReadback(const uint128_t& frameID,
1196 : const co::ObjectVersions& frameIDs)
1197 : {
1198 1 : LB_TS_THREAD(_pipeThread);
1199 :
1200 2 : RBStatPtr stat = new detail::RBStat(this);
1201 2 : const Frames& frames = _getFrames(frameIDs, true);
1202 :
1203 2 : std::vector<size_t> nImages(frames.size(), 0);
1204 2 : for (size_t i = 0; i < frames.size(); ++i)
1205 1 : nImages[i] = frames[i]->getImages().size();
1206 :
1207 1 : frameReadback(frameID, frames);
1208 1 : LBASSERT(stat->event.statistic.frameNumber > 0);
1209 1 : const bool async = _asyncFinishReadback(nImages, frames);
1210 1 : _setReady(async, stat.get(), frames);
1211 1 : }
1212 :
1213 1 : bool Channel::_asyncFinishReadback(const std::vector<size_t>& imagePos,
1214 : const Frames& frames)
1215 : {
1216 1 : LB_TS_THREAD(_pipeThread);
1217 :
1218 1 : bool hasAsyncReadback = false;
1219 1 : LBASSERT(frames.size() == imagePos.size());
1220 :
1221 2 : for (size_t i = 0; i < frames.size(); ++i)
1222 : {
1223 1 : Frame* frame = frames[i];
1224 2 : FrameDataPtr frameData = frame->getFrameData();
1225 1 : const uint32_t frameNumber = getCurrentFrame();
1226 :
1227 1 : if (frameData->getBuffers() == Frame::Buffer::none)
1228 0 : continue;
1229 :
1230 1 : const Images& images = frameData->getImages();
1231 1 : const size_t nImages = images.size();
1232 1 : const Eye eye = getEye();
1233 1 : const std::vector<uint128_t>& nodes = frame->getInputNodes(eye);
1234 1 : const co::NodeIDs& netNodes = frame->getInputNetNodes(eye);
1235 :
1236 2 : for (uint64_t j = imagePos[i]; j < nImages; ++j)
1237 : {
1238 1 : if (images[j]->hasAsyncReadback()) // finish async readback
1239 : {
1240 1 : _createTransferWindow();
1241 :
1242 1 : hasAsyncReadback = true;
1243 1 : _refFrame(frameNumber);
1244 :
1245 2 : send(getLocalNode(), fabric::CMD_CHANNEL_FINISH_READBACK)
1246 3 : << co::ObjectVersion(frameData) << j << frameNumber
1247 3 : << getTaskID() << nodes << netNodes;
1248 : }
1249 : else // transmit images asynchronously
1250 0 : _asyncTransmit(frameData, frameNumber, j, nodes, netNodes,
1251 0 : getTaskID());
1252 : }
1253 : }
1254 1 : return hasAsyncReadback;
1255 : }
1256 :
1257 1 : void Channel::_finishReadback(const co::ObjectVersion& frameDataVersion,
1258 : const uint64_t imageIndex,
1259 : const uint32_t frameNumber, const uint32_t taskID,
1260 : const std::vector<uint128_t>& nodes,
1261 : const co::NodeIDs& netNodes)
1262 : {
1263 1 : LBLOG(LOG_TASKS | LOG_ASSEMBLY) << "Finish readback" << std::endl;
1264 :
1265 1 : const Window* window = getWindow();
1266 1 : const SystemWindow* transferWindow = window->getTransferWindow();
1267 1 : LBASSERT(transferWindow);
1268 1 : transferWindow->makeCurrent();
1269 :
1270 2 : FrameDataPtr frameData = getNode()->getFrameData(frameDataVersion);
1271 1 : LBASSERT(frameData);
1272 :
1273 1 : const Images& images = frameData->getImages();
1274 1 : LBASSERT(images.size() > imageIndex);
1275 :
1276 1 : Image* image = images[imageIndex];
1277 1 : LBASSERT(image->hasAsyncReadback());
1278 :
1279 1 : const GLEWContext* glewContext = window->getTransferGlewContext();
1280 1 : image->finishReadback(glewContext);
1281 1 : LBASSERT(!image->hasAsyncReadback());
1282 :
1283 : // schedule async image tranmission
1284 1 : _asyncTransmit(frameData, frameNumber, imageIndex, nodes, netNodes, taskID);
1285 1 : }
1286 :
1287 1 : void Channel::_asyncTransmit(FrameDataPtr frame, const uint32_t frameNumber,
1288 : const uint64_t image,
1289 : const std::vector<uint128_t>& nodes,
1290 : const co::NodeIDs& netNodes, const uint32_t taskID)
1291 : {
1292 1 : LBASSERT(nodes.size() == netNodes.size());
1293 1 : co::NodeIDs::const_iterator j = netNodes.begin();
1294 3 : for (std::vector<uint128_t>::const_iterator i = nodes.begin();
1295 2 : i != nodes.end(); ++i, ++j)
1296 : {
1297 0 : _refFrame(frameNumber);
1298 :
1299 0 : LBLOG(LOG_TASKS | LOG_ASSEMBLY) << "Start transmit frame data " << frame
1300 0 : << " receiver " << *i << " on " << *j
1301 0 : << std::endl;
1302 0 : send(getLocalNode(), fabric::CMD_CHANNEL_FRAME_TRANSMIT_IMAGE)
1303 0 : << co::ObjectVersion(frame) << *i << *j << image << frameNumber
1304 0 : << taskID;
1305 : }
1306 1 : }
1307 :
1308 0 : void Channel::_transmitImage(const co::ObjectVersion& frameDataVersion,
1309 : const uint128_t& nodeID,
1310 : const co::NodeID& netNodeID,
1311 : const uint64_t imageIndex,
1312 : const uint32_t frameNumber, const uint32_t taskID)
1313 : {
1314 0 : LBLOG(LOG_TASKS | LOG_ASSEMBLY) << "Transmit" << std::endl;
1315 0 : FrameDataPtr frameData = getNode()->getFrameData(frameDataVersion);
1316 0 : LBASSERT(frameData);
1317 :
1318 0 : if (frameData->getBuffers() == Frame::Buffer::none)
1319 : {
1320 0 : LBWARN << "No buffers for frame data" << std::endl;
1321 0 : return;
1322 : }
1323 :
1324 : ChannelStatistics transmitEvent(Statistic::CHANNEL_FRAME_TRANSMIT, this,
1325 0 : frameNumber);
1326 0 : transmitEvent.statistic.task = taskID;
1327 :
1328 0 : const Images& images = frameData->getImages();
1329 0 : Image* image = images[imageIndex];
1330 0 : LBASSERT(images.size() > imageIndex);
1331 :
1332 0 : if (image->getStorageType() == Frame::TYPE_TEXTURE)
1333 : {
1334 0 : LBWARN << "Can't transmit image of type TEXTURE" << std::endl;
1335 0 : LBUNIMPLEMENTED;
1336 0 : return;
1337 : }
1338 :
1339 0 : co::LocalNodePtr localNode = getLocalNode();
1340 0 : co::NodePtr toNode = localNode->connect(netNodeID);
1341 0 : if (!toNode || !toNode->isReachable())
1342 : {
1343 0 : LBWARN << "Can't connect node " << netNodeID << " to send output frame"
1344 0 : << std::endl;
1345 0 : return;
1346 : }
1347 :
1348 0 : co::ConnectionPtr connection = toNode->getConnection();
1349 : co::ConstConnectionDescriptionPtr description =
1350 0 : connection->getDescription();
1351 :
1352 : // use compression on links up to 2 GBit/s
1353 0 : const bool useCompression = (description->bandwidth <= 262144);
1354 :
1355 0 : std::vector<const PixelData*> pixelDatas;
1356 0 : std::vector<float> qualities;
1357 :
1358 0 : Frame::Buffer commandBuffers = Frame::Buffer::none;
1359 0 : uint64_t imageDataSize = 0;
1360 : {
1361 0 : uint64_t rawSize(0);
1362 : ChannelStatistics compressEvent(Statistic::CHANNEL_FRAME_COMPRESS, this,
1363 : frameNumber,
1364 0 : useCompression ? AUTO : OFF);
1365 0 : compressEvent.statistic.task = taskID;
1366 0 : compressEvent.statistic.ratio = 1.0f;
1367 0 : compressEvent.statistic.plugins[0] = EQ_COMPRESSOR_NONE;
1368 0 : compressEvent.statistic.plugins[1] = EQ_COMPRESSOR_NONE;
1369 :
1370 : // Prepare image pixel data
1371 0 : Frame::Buffer buffers[] = {Frame::Buffer::color, Frame::Buffer::depth};
1372 :
1373 : // for each image attachment
1374 0 : for (unsigned j = 0; j < 2; ++j)
1375 : {
1376 0 : Frame::Buffer buffer = buffers[j];
1377 0 : if (image->hasPixelData(buffer))
1378 : {
1379 : // format, type, nChunks, compressor name
1380 0 : imageDataSize += sizeof(FrameData::ImageHeader);
1381 :
1382 : const PixelData& data = useCompression
1383 0 : ? image->compressPixelData(buffer)
1384 0 : : image->getPixelData(buffer);
1385 0 : pixelDatas.push_back(&data);
1386 0 : qualities.push_back(image->getQuality(buffer));
1387 :
1388 0 : if (data.compressedData.isCompressed())
1389 : {
1390 0 : imageDataSize +=
1391 0 : data.compressedData.getSize() +
1392 0 : data.compressedData.chunks.size() * sizeof(uint64_t);
1393 0 : compressEvent.statistic.plugins[j] =
1394 0 : data.compressedData.compressor;
1395 : }
1396 : else
1397 0 : imageDataSize +=
1398 0 : sizeof(uint64_t) + image->getPixelDataSize(buffer);
1399 :
1400 0 : commandBuffers |= buffer;
1401 0 : rawSize += image->getPixelDataSize(buffer);
1402 : }
1403 : }
1404 :
1405 0 : if (rawSize > 0)
1406 0 : compressEvent.statistic.ratio =
1407 0 : float(imageDataSize) / float(rawSize);
1408 : }
1409 :
1410 0 : if (pixelDatas.empty())
1411 0 : return;
1412 :
1413 : // send image pixel data command
1414 0 : co::LocalNode::SendToken token;
1415 0 : if (getIAttribute(IATTR_HINT_SENDTOKEN) == ON)
1416 : {
1417 : ChannelStatistics waitEvent(Statistic::CHANNEL_FRAME_WAIT_SENDTOKEN,
1418 0 : this, frameNumber);
1419 0 : waitEvent.statistic.task = taskID;
1420 0 : token = getLocalNode()->acquireSendToken(toNode);
1421 : }
1422 0 : LBASSERT(image->getPixelViewport().isValid());
1423 :
1424 0 : co::ObjectOCommand command(co::Connections(1, connection),
1425 : fabric::CMD_NODE_FRAMEDATA_TRANSMIT,
1426 0 : co::COMMANDTYPE_OBJECT, nodeID, CO_INSTANCE_ALL);
1427 0 : command << frameDataVersion << image->getPixelViewport() << image->getZoom()
1428 0 : << image->getContext() << commandBuffers << frameNumber
1429 0 : << image->getAlphaUsage();
1430 0 : command.sendHeader(imageDataSize);
1431 :
1432 : #ifndef NDEBUG
1433 0 : size_t sentBytes = 0;
1434 : #endif
1435 :
1436 0 : for (uint32_t j = 0; j < pixelDatas.size(); ++j)
1437 : {
1438 : #ifndef NDEBUG
1439 0 : sentBytes += sizeof(FrameData::ImageHeader);
1440 : #endif
1441 0 : const PixelData* data = pixelDatas[j];
1442 0 : const bool isCompressed = data->compressedData.isCompressed();
1443 : const uint32_t nChunks =
1444 0 : isCompressed ? uint32_t(data->compressedData.chunks.size()) : 1;
1445 :
1446 : const FrameData::ImageHeader header = {
1447 0 : data->internalFormat,
1448 0 : data->externalFormat,
1449 0 : data->pixelSize,
1450 : data->pvp,
1451 0 : isCompressed ? data->compressedData.compressor : EQ_COMPRESSOR_NONE,
1452 0 : data->compressorFlags,
1453 : nChunks,
1454 0 : qualities[j]};
1455 :
1456 0 : connection->send(&header, sizeof(header), true);
1457 :
1458 0 : if (isCompressed)
1459 : {
1460 0 : for (const auto& chunk : data->compressedData.chunks)
1461 : {
1462 0 : const uint64_t dataSize = chunk.getNumBytes();
1463 :
1464 0 : connection->send(&dataSize, sizeof(dataSize), true);
1465 0 : if (dataSize > 0)
1466 0 : connection->send(chunk.data, dataSize, true);
1467 : #ifndef NDEBUG
1468 0 : sentBytes += sizeof(dataSize) + dataSize;
1469 : #endif
1470 : }
1471 : }
1472 : else
1473 : {
1474 0 : const uint64_t dataSize = data->pvp.getArea() * data->pixelSize;
1475 0 : connection->send(&dataSize, sizeof(dataSize), true);
1476 0 : connection->send(data->pixels, dataSize, true);
1477 : #ifndef NDEBUG
1478 0 : sentBytes += sizeof(dataSize) + dataSize;
1479 : #endif
1480 : }
1481 : }
1482 : #ifndef NDEBUG
1483 0 : LBASSERTINFO(sentBytes == imageDataSize, sentBytes << " != "
1484 : << imageDataSize);
1485 : #endif
1486 : }
1487 :
1488 1 : void Channel::_setReady(const bool async, detail::RBStat* stat,
1489 : const Frames& frames)
1490 : {
1491 2 : for (FramesCIter i = frames.begin(); i != frames.end(); ++i)
1492 : {
1493 1 : Frame* frame = *i;
1494 1 : const Eye eye = getEye();
1495 1 : const std::vector<uint128_t>& nodes = frame->getInputNodes(eye);
1496 1 : const co::NodeIDs& netNodes = frame->getInputNetNodes(eye);
1497 :
1498 1 : if (async)
1499 1 : _asyncSetReady(frame->getFrameData(), stat, nodes, netNodes);
1500 : else
1501 0 : _setReady(frame->getFrameData(), stat, nodes, netNodes);
1502 : }
1503 1 : }
1504 :
1505 1 : void Channel::_asyncSetReady(const FrameDataPtr frame, detail::RBStat* stat,
1506 : const std::vector<uint128_t>& nodes,
1507 : const co::NodeIDs& netNodes)
1508 : {
1509 1 : LBASSERT(stat->event.statistic.frameNumber > 0);
1510 :
1511 1 : stat->event.statistic.type = Statistic::CHANNEL_ASYNC_READBACK;
1512 :
1513 1 : _refFrame(stat->event.statistic.frameNumber);
1514 1 : stat->ref(0);
1515 :
1516 2 : send(getLocalNode(), fabric::CMD_CHANNEL_FRAME_SET_READY)
1517 3 : << co::ObjectVersion(frame) << stat << nodes << netNodes;
1518 1 : }
1519 :
1520 1 : void Channel::_setReady(FrameDataPtr frame, detail::RBStat* stat,
1521 : const std::vector<uint128_t>& nodes,
1522 : const co::NodeIDs& netNodes)
1523 : {
1524 2 : LBLOG(LOG_TASKS | LOG_ASSEMBLY) << "Set ready " << co::ObjectVersion(frame)
1525 3 : << std::endl;
1526 1 : frame->setReady();
1527 :
1528 1 : const uint32_t frameNumber = stat->event.statistic.frameNumber;
1529 1 : _refFrame(frameNumber);
1530 :
1531 2 : send(getLocalNode(), fabric::CMD_CHANNEL_FRAME_SET_READY_NODE)
1532 3 : << co::ObjectVersion(frame) << nodes << netNodes << frameNumber;
1533 :
1534 1 : const DrawableConfig& dc = getDrawableConfig();
1535 1 : const size_t colorBytes = (3 * dc.colorBits + dc.alphaBits) / 8;
1536 :
1537 : {
1538 2 : lunchbox::ScopedFastWrite mutex(stat->lock);
1539 1 : const Images& images = frame->getImages();
1540 2 : for (ImagesCIter i = images.begin(); i != images.end(); ++i)
1541 : {
1542 1 : const Image* image = *i;
1543 1 : if (image->hasPixelData(Frame::Buffer::color))
1544 : {
1545 1 : stat->uncompressed +=
1546 1 : colorBytes * image->getPixelViewport().getArea();
1547 1 : stat->compressed +=
1548 1 : image->getPixelDataSize(Frame::Buffer::color);
1549 1 : stat->event.statistic.plugins[0] =
1550 1 : image->getDownloaderName(Frame::Buffer::color);
1551 : }
1552 1 : if (image->hasPixelData(Frame::Buffer::depth))
1553 : {
1554 0 : stat->uncompressed += 4 * image->getPixelViewport().getArea();
1555 0 : stat->compressed +=
1556 0 : image->getPixelDataSize(Frame::Buffer::depth);
1557 0 : stat->event.statistic.plugins[1] =
1558 0 : image->getDownloaderName(Frame::Buffer::depth);
1559 : }
1560 : }
1561 : }
1562 1 : }
1563 :
1564 1 : void Channel::_createTransferWindow()
1565 : {
1566 1 : if (getWindow()->getTransferWindow())
1567 0 : return;
1568 :
1569 1 : Pipe* pipe = getPipe();
1570 1 : Window* window = getWindow();
1571 1 : LBCHECK(pipe->startTransferThread());
1572 1 : LBCHECK(window->createTransferWindow());
1573 :
1574 : #ifdef EQ_QT_USED
1575 : // transfer window creation must happen in pipe thread (#177), but the
1576 : // context is used in the transfer thread and Qt requires moving the object
1577 : // to that thread.
1578 : qt::Window* qtWindow =
1579 1 : dynamic_cast<qt::Window*>(window->getTransferWindow());
1580 1 : QThread* qThread = pipe->getTransferQThread();
1581 :
1582 1 : if (qtWindow && qThread)
1583 0 : qtWindow->moveContextToThread(qThread);
1584 : #endif
1585 : }
1586 :
1587 2 : void Channel::_deleteTransferWindow()
1588 : {
1589 2 : if (!getPipe()->hasTransferThread())
1590 1 : return;
1591 :
1592 : // #510: Need to schedule deletion in transfer thread since qt::Window was
1593 : // potentially moved to this thread
1594 2 : co::LocalNodePtr localNode = getLocalNode();
1595 2 : const lunchbox::Request<void>& request = localNode->registerRequest<void>();
1596 1 : send(localNode, fabric::CMD_CHANNEL_DELETE_TRANSFER_WINDOW) << request;
1597 : }
1598 :
1599 : //---------------------------------------------------------------------------
1600 : // command handlers
1601 : //---------------------------------------------------------------------------
1602 2 : bool Channel::_cmdConfigInit(co::ICommand& cmd)
1603 : {
1604 4 : co::ObjectICommand command(cmd);
1605 :
1606 2 : LBLOG(LOG_INIT) << "TASK channel config init " << command << std::endl;
1607 :
1608 2 : const Config* config = getConfig();
1609 2 : changeLatency(config->getLatency());
1610 :
1611 2 : bool result = false;
1612 2 : const Window* window = getWindow();
1613 2 : if (window->isRunning())
1614 : {
1615 2 : _impl->state = STATE_INITIALIZING;
1616 :
1617 2 : const PixelViewport& pvp = getPixelViewport();
1618 2 : LBASSERT(pvp.hasArea());
1619 2 : _impl->initialSize.x() = pvp.w;
1620 2 : _impl->initialSize.y() = pvp.h;
1621 2 : _impl->finishedFrame = window->getCurrentFrame();
1622 :
1623 2 : result = configInit(command.read<uint128_t>());
1624 :
1625 2 : if (result)
1626 2 : _impl->state = STATE_RUNNING;
1627 : }
1628 : else
1629 0 : sendError(ERROR_CHANNEL_WINDOW_NOTRUNNING);
1630 :
1631 2 : LBLOG(LOG_INIT) << "TASK channel config init reply " << result << std::endl;
1632 2 : commit();
1633 4 : send(command.getRemoteNode(), fabric::CMD_CHANNEL_CONFIG_INIT_REPLY)
1634 2 : << result;
1635 4 : return true;
1636 : }
1637 :
1638 2 : bool Channel::_cmdConfigExit(co::ICommand& cmd)
1639 : {
1640 2 : LBLOG(LOG_INIT) << "Exit channel " << co::ObjectICommand(cmd) << std::endl;
1641 :
1642 2 : if (_impl->state != STATE_STOPPED)
1643 2 : _impl->state = configExit() ? STATE_STOPPED : STATE_FAILED;
1644 :
1645 2 : _deleteTransferWindow();
1646 4 : getWindow()->send(getLocalNode(), fabric::CMD_WINDOW_DESTROY_CHANNEL)
1647 4 : << getID();
1648 2 : return true;
1649 : }
1650 :
1651 2 : bool Channel::_cmdFrameStart(co::ICommand& cmd)
1652 : {
1653 4 : co::ObjectICommand command(cmd);
1654 :
1655 4 : RenderContext context = command.read<RenderContext>();
1656 2 : const uint128_t& version = command.read<uint128_t>();
1657 2 : const uint32_t frameNumber = command.read<uint32_t>();
1658 :
1659 2 : LBVERB << "handle channel frame start " << command << " " << context
1660 2 : << " frame " << frameNumber << std::endl;
1661 :
1662 : //_grabFrame( frameNumber ); single-threaded
1663 2 : sync(version);
1664 :
1665 2 : overrideContext(context);
1666 2 : bindFrameBuffer();
1667 2 : frameStart(context.frameID, frameNumber);
1668 :
1669 2 : const size_t index = frameNumber % _impl->statistics->size();
1670 2 : detail::Channel::FrameStatistics& statistic = _impl->statistics.data[index];
1671 2 : LBASSERTINFO(statistic.used == 0, "Frame " << frameNumber << " used "
1672 : << statistic.used);
1673 2 : LBASSERT(statistic.data.empty());
1674 2 : statistic.used = 1;
1675 :
1676 2 : resetContext();
1677 4 : return true;
1678 : }
1679 :
1680 2 : bool Channel::_cmdFrameFinish(co::ICommand& cmd)
1681 : {
1682 4 : co::ObjectICommand command(cmd);
1683 :
1684 4 : RenderContext context = command.read<RenderContext>();
1685 2 : const uint32_t frameNumber = command.read<uint32_t>();
1686 :
1687 2 : LBLOG(LOG_TASKS) << "TASK frame finish " << getName() << " " << command
1688 2 : << " " << context << std::endl;
1689 :
1690 2 : overrideContext(context);
1691 2 : frameFinish(context.frameID, frameNumber);
1692 2 : resetContext();
1693 :
1694 2 : _unrefFrame(frameNumber);
1695 4 : return true;
1696 : }
1697 :
1698 3 : bool Channel::_cmdFrameClear(co::ICommand& cmd)
1699 : {
1700 3 : LBASSERT(_impl->state == STATE_RUNNING);
1701 :
1702 6 : co::ObjectICommand command(cmd);
1703 6 : RenderContext context = command.read<RenderContext>();
1704 :
1705 3 : LBLOG(LOG_TASKS) << "TASK clear " << getName() << " " << command << " "
1706 3 : << context << std::endl;
1707 :
1708 3 : bindDrawFrameBuffer();
1709 3 : _overrideContext(context);
1710 6 : ChannelStatistics event(Statistic::CHANNEL_CLEAR, this);
1711 3 : frameClear(context.frameID);
1712 3 : resetContext();
1713 3 : bindFrameBuffer();
1714 :
1715 6 : return true;
1716 : }
1717 :
1718 2 : bool Channel::_cmdFrameDraw(co::ICommand& cmd)
1719 : {
1720 4 : co::ObjectICommand command(cmd);
1721 4 : RenderContext context = command.read<RenderContext>();
1722 2 : const bool finish = command.read<bool>();
1723 :
1724 2 : LBLOG(LOG_TASKS) << "TASK draw " << getName() << " " << command << " "
1725 2 : << context << std::endl;
1726 :
1727 2 : bindDrawFrameBuffer();
1728 2 : _overrideContext(context);
1729 2 : const uint32_t frameNumber = getCurrentFrame();
1730 : ChannelStatistics event(Statistic::CHANNEL_DRAW, this, frameNumber,
1731 4 : finish ? NICEST : AUTO);
1732 :
1733 2 : frameDraw(context.frameID);
1734 : // Set to full region if application has declared nothing
1735 2 : if (!getRegion().isValid())
1736 2 : declareRegion(getPixelViewport());
1737 2 : const size_t index = frameNumber % _impl->statistics->size();
1738 2 : _impl->statistics.data[index].region = getRegion() / getPixelViewport();
1739 :
1740 2 : resetContext();
1741 2 : bindFrameBuffer();
1742 :
1743 4 : return true;
1744 : }
1745 :
1746 2 : bool Channel::_cmdFrameDrawFinish(co::ICommand& cmd)
1747 : {
1748 4 : co::ObjectICommand command(cmd);
1749 2 : const uint128_t& frameID = command.read<uint128_t>();
1750 2 : const uint32_t frameNumber = command.read<uint32_t>();
1751 :
1752 2 : LBLOG(LOG_TASKS) << "TASK draw finish " << getName() << " " << command
1753 0 : << " frame " << frameNumber << " id " << frameID
1754 2 : << std::endl;
1755 :
1756 4 : ChannelStatistics event(Statistic::CHANNEL_DRAW_FINISH, this);
1757 2 : frameDrawFinish(frameID, frameNumber);
1758 :
1759 4 : return true;
1760 : }
1761 :
1762 1 : bool Channel::_cmdFrameAssemble(co::ICommand& cmd)
1763 : {
1764 2 : co::ObjectICommand command(cmd);
1765 2 : RenderContext context = command.read<RenderContext>();
1766 2 : const co::ObjectVersions& frameIDs = command.read<co::ObjectVersions>();
1767 :
1768 1 : LBLOG(LOG_TASKS | LOG_ASSEMBLY) << "TASK assemble " << getName() << " "
1769 0 : << command << " " << context << " nFrames "
1770 1 : << frameIDs.size() << std::endl;
1771 :
1772 1 : _overrideContext(context);
1773 :
1774 2 : ChannelStatistics event(Statistic::CHANNEL_ASSEMBLE, this);
1775 2 : const Frames& frames = _getFrames(frameIDs, false);
1776 1 : frameAssemble(context.frameID, frames);
1777 :
1778 1 : resetContext();
1779 2 : return true;
1780 : }
1781 :
1782 1 : bool Channel::_cmdFrameReadback(co::ICommand& cmd)
1783 : {
1784 2 : co::ObjectICommand command(cmd);
1785 2 : RenderContext context = command.read<RenderContext>();
1786 2 : const co::ObjectVersions& frames = command.read<co::ObjectVersions>();
1787 1 : LBLOG(LOG_TASKS | LOG_ASSEMBLY) << "TASK readback " << getName() << " "
1788 0 : << command << " " << context << " nFrames "
1789 1 : << frames.size() << std::endl;
1790 :
1791 1 : _overrideContext(context);
1792 1 : _frameReadback(context.frameID, frames);
1793 1 : resetContext();
1794 2 : return true;
1795 : }
1796 :
1797 1 : bool Channel::_cmdFinishReadback(co::ICommand& cmd)
1798 : {
1799 2 : co::ObjectICommand command(cmd);
1800 :
1801 1 : LBLOG(LOG_TASKS | LOG_ASSEMBLY) << "Finish readback " << command
1802 1 : << std::endl;
1803 :
1804 1 : const co::ObjectVersion& frameData = command.read<co::ObjectVersion>();
1805 1 : const uint64_t imageIndex = command.read<uint64_t>();
1806 1 : const uint32_t frameNumber = command.read<uint32_t>();
1807 1 : const uint32_t taskID = command.read<uint32_t>();
1808 : const std::vector<uint128_t>& nodes =
1809 2 : command.read<std::vector<uint128_t>>();
1810 2 : const co::NodeIDs& netNodes = command.read<co::NodeIDs>();
1811 :
1812 : _finishReadback(frameData, imageIndex, frameNumber, taskID, nodes,
1813 1 : netNodes);
1814 1 : _unrefFrame(frameNumber);
1815 2 : return true;
1816 : }
1817 :
1818 1 : bool Channel::_cmdFrameSetReady(co::ICommand& cmd)
1819 : {
1820 2 : co::ObjectICommand command(cmd);
1821 :
1822 : const co::ObjectVersion frameDataVersion =
1823 1 : command.read<co::ObjectVersion>();
1824 1 : detail::RBStat* stat = command.read<detail::RBStat*>();
1825 : const std::vector<uint128_t>& nodes =
1826 2 : command.read<std::vector<uint128_t>>();
1827 2 : const co::NodeIDs& netNodes = command.read<co::NodeIDs>();
1828 :
1829 1 : LBASSERT(stat->event.statistic.frameNumber > 0);
1830 :
1831 2 : FrameDataPtr frameData = getNode()->getFrameData(frameDataVersion);
1832 1 : _setReady(frameData, stat, nodes, netNodes);
1833 :
1834 1 : const uint32_t frame = stat->event.statistic.frameNumber;
1835 1 : stat->unref(0);
1836 1 : _unrefFrame(frame);
1837 2 : return true;
1838 : }
1839 :
1840 0 : bool Channel::_cmdFrameTransmitImage(co::ICommand& cmd)
1841 : {
1842 0 : co::ObjectICommand command(cmd);
1843 0 : const co::ObjectVersion& frameData = command.read<co::ObjectVersion>();
1844 0 : const uint128_t& nodeID = command.read<uint128_t>();
1845 0 : const co::NodeID& netNodeID = command.read<co::NodeID>();
1846 0 : const uint64_t imageIndex = command.read<uint64_t>();
1847 0 : const uint32_t frameNumber = command.read<uint32_t>();
1848 0 : const uint32_t taskID = command.read<uint32_t>();
1849 :
1850 0 : LBLOG(LOG_TASKS | LOG_ASSEMBLY) << "Transmit " << command << " frame data "
1851 0 : << frameData << " receiver " << nodeID
1852 0 : << " on " << netNodeID << std::endl;
1853 :
1854 : _transmitImage(frameData, nodeID, netNodeID, imageIndex, frameNumber,
1855 0 : taskID);
1856 0 : _unrefFrame(frameNumber);
1857 0 : return true;
1858 : }
1859 :
1860 1 : bool Channel::_cmdFrameSetReadyNode(co::ICommand& cmd)
1861 : {
1862 2 : co::ObjectICommand command(cmd);
1863 :
1864 : const co::ObjectVersion& frameDataVersion =
1865 1 : command.read<co::ObjectVersion>();
1866 : const std::vector<uint128_t>& nodes =
1867 2 : command.read<std::vector<uint128_t>>();
1868 2 : const co::NodeIDs& netNodes = command.read<co::NodeIDs>();
1869 1 : const uint32_t frameNumber = command.read<uint32_t>();
1870 :
1871 2 : co::LocalNodePtr localNode = getLocalNode();
1872 2 : const FrameDataPtr frameData = getNode()->getFrameData(frameDataVersion);
1873 :
1874 1 : co::NodeIDs::const_iterator j = netNodes.begin();
1875 3 : for (std::vector<uint128_t>::const_iterator i = nodes.begin();
1876 2 : i != nodes.end(); ++i, ++j)
1877 : {
1878 0 : co::NodePtr toNode = localNode->connect(*j);
1879 0 : if (!toNode)
1880 : {
1881 0 : LBERROR << "Can't connect to " << *j << " to signal ready of frame "
1882 0 : << frameNumber << std::endl;
1883 0 : continue;
1884 : }
1885 0 : co::ObjectOCommand os(co::Connections(1, toNode->getConnection()),
1886 : fabric::CMD_NODE_FRAMEDATA_READY,
1887 0 : co::COMMANDTYPE_OBJECT, *i, CO_INSTANCE_ALL);
1888 0 : os << frameDataVersion;
1889 0 : frameData->serialize(os);
1890 : }
1891 :
1892 1 : _unrefFrame(frameNumber);
1893 2 : return true;
1894 : }
1895 :
1896 1 : bool Channel::_cmdFrameViewStart(co::ICommand& cmd)
1897 : {
1898 2 : co::ObjectICommand command(cmd);
1899 2 : RenderContext context = command.read<RenderContext>();
1900 :
1901 1 : LBLOG(LOG_TASKS) << "TASK view start " << getName() << " " << command << " "
1902 1 : << context << std::endl;
1903 :
1904 1 : _overrideContext(context);
1905 1 : frameViewStart(context.frameID);
1906 1 : resetContext();
1907 :
1908 2 : return true;
1909 : }
1910 :
1911 1 : bool Channel::_cmdFrameViewFinish(co::ICommand& cmd)
1912 : {
1913 2 : co::ObjectICommand command(cmd);
1914 2 : RenderContext context = command.read<RenderContext>();
1915 :
1916 1 : LBLOG(LOG_TASKS) << "TASK view finish " << getName() << " " << command
1917 1 : << " " << context << std::endl;
1918 :
1919 1 : _overrideContext(context);
1920 : {
1921 2 : ChannelStatistics event(Statistic::CHANNEL_VIEW_FINISH, this);
1922 1 : frameViewFinish(context.frameID);
1923 : }
1924 1 : resetContext();
1925 :
1926 2 : return true;
1927 : }
1928 :
1929 0 : bool Channel::_cmdStopFrame(co::ICommand& cmd)
1930 : {
1931 0 : co::ObjectICommand command(cmd);
1932 :
1933 0 : LBLOG(LOG_TASKS) << "TASK channel stop frame " << getName() << " "
1934 0 : << command << std::endl;
1935 :
1936 0 : notifyStopFrame(command.read<uint32_t>());
1937 0 : return true;
1938 : }
1939 :
1940 0 : bool Channel::_cmdFrameTiles(co::ICommand& cmd)
1941 : {
1942 0 : co::ObjectICommand command(cmd);
1943 0 : RenderContext context = command.read<RenderContext>();
1944 0 : const bool isLocal = command.read<bool>();
1945 0 : const uint128_t& queueID = command.read<uint128_t>();
1946 0 : const uint32_t tasks = command.read<uint32_t>();
1947 0 : const co::ObjectVersions& frames = command.read<co::ObjectVersions>();
1948 :
1949 0 : LBLOG(LOG_TASKS) << "TASK channel frame tiles " << getName() << " "
1950 0 : << command << " " << context << std::endl;
1951 :
1952 0 : _frameTiles(context, isLocal, queueID, tasks, frames);
1953 0 : return true;
1954 : }
1955 :
1956 1 : bool Channel::_cmdDeleteTransferWindow(co::ICommand& cmd)
1957 : {
1958 2 : co::ObjectICommand command(cmd);
1959 1 : LBLOG(LOG_INIT) << "Delete transfer window " << command << std::endl;
1960 :
1961 1 : getWindow()->deleteTransferWindow();
1962 1 : getLocalNode()->serveRequest(command.read<uint32_t>());
1963 2 : return true;
1964 : }
1965 : }
1966 :
1967 : #include <eq/fabric/channel.ipp>
1968 : template class eq::fabric::Channel<eq::Window, eq::Channel>;
1969 :
1970 : /** @cond IGNORE */
1971 : template EQFABRIC_API std::ostream& eq::fabric::operator<<(std::ostream&,
1972 30 : const eq::Super&);
1973 : /** @endcond */
|