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