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