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