Line data Source code
1 :
2 : /* Copyright (c) 2007-2013, Stefan Eilemann <eile@equalizergraphics.com>
3 : * 2011-2012, Daniel Nachbaur <danielnachbaur@gmail.com>
4 : * 2010, Cedric Stalder <cedric.stalder@gmail.com>
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 "channelUpdateVisitor.h"
21 :
22 : #include "colorMask.h"
23 : #include "compound.h"
24 : #include "frame.h"
25 : #include "node.h"
26 : #include "observer.h"
27 : #include "pipe.h"
28 : #include "segment.h"
29 : #include "view.h"
30 : #include "window.h"
31 : #include "tileQueue.h"
32 :
33 : #include <eq/client/log.h>
34 :
35 : #include <eq/fabric/commands.h>
36 : #include <eq/fabric/paths.h>
37 :
38 : #include <set>
39 :
40 : #ifndef GL_BACK_LEFT
41 : # define GL_FRONT_LEFT 0x0400
42 : # define GL_FRONT_RIGHT 0x0401
43 : # define GL_BACK_LEFT 0x0402
44 : # define GL_BACK_RIGHT 0x0403
45 : # define GL_FRONT 0x0404
46 : # define GL_BACK 0x0405
47 : #endif
48 :
49 : namespace eq
50 : {
51 : namespace server
52 : {
53 :
54 : using fabric::QUAD;
55 :
56 : namespace
57 : {
58 : static bool _setDrawBuffers();
59 : static uint32_t _drawBuffer[2][2][NUM_EYES];
60 9 : static bool _drawBufferInit = _setDrawBuffers();
61 9 : bool _setDrawBuffers()
62 : {
63 9 : const int32_t cyclop = lunchbox::getIndexOfLastBit( EYE_CYCLOP );
64 9 : const int32_t left = lunchbox::getIndexOfLastBit( EYE_LEFT );
65 9 : const int32_t right = lunchbox::getIndexOfLastBit( EYE_RIGHT );
66 :
67 : // [stereo][doublebuffered][eye]
68 9 : _drawBuffer[0][0][ cyclop ] = GL_FRONT;
69 9 : _drawBuffer[0][0][ left ] = GL_FRONT;
70 9 : _drawBuffer[0][0][ right ] = GL_FRONT;
71 :
72 9 : _drawBuffer[0][1][ cyclop ] = GL_BACK;
73 9 : _drawBuffer[0][1][ left ] = GL_BACK;
74 9 : _drawBuffer[0][1][ right ] = GL_BACK;
75 :
76 9 : _drawBuffer[1][0][ cyclop ] = GL_FRONT;
77 9 : _drawBuffer[1][0][ left ] = GL_FRONT_LEFT;
78 9 : _drawBuffer[1][0][ right ] = GL_FRONT_RIGHT;
79 :
80 9 : _drawBuffer[1][1][ cyclop ] = GL_BACK;
81 9 : _drawBuffer[1][1][ left ] = GL_BACK_LEFT;
82 9 : _drawBuffer[1][1][ right ] = GL_BACK_RIGHT;
83 :
84 9 : return true;
85 : }
86 : }
87 :
88 31 : ChannelUpdateVisitor::ChannelUpdateVisitor( Channel* channel,
89 : const uint128_t frameID,
90 : const uint32_t frameNumber )
91 : : _channel( channel )
92 : , _eye( EYE_CYCLOP )
93 : , _frameID( frameID )
94 : , _frameNumber( frameNumber )
95 31 : , _updated( false )
96 31 : {}
97 :
98 227 : bool ChannelUpdateVisitor::_skipCompound( const Compound* compound )
99 : {
100 258 : return ( compound->getChannel() != _channel ||
101 258 : !compound->isInheritActive( _eye ) ||
102 258 : compound->getInheritTasks() == fabric::TASK_NONE );
103 : }
104 :
105 173 : VisitorResult ChannelUpdateVisitor::visitPre( const Compound* compound )
106 : {
107 173 : if( !compound->isInheritActive( _eye ))
108 72 : return TRAVERSE_PRUNE;
109 :
110 101 : _updateDrawFinish( compound );
111 :
112 101 : if( _skipCompound( compound ))
113 97 : return TRAVERSE_CONTINUE;
114 :
115 4 : RenderContext context;
116 4 : _setupRenderContext( compound, context );
117 :
118 4 : _updateFrameRate( compound );
119 4 : _updateViewStart( compound, context );
120 :
121 4 : if( compound->testInheritTask( fabric::TASK_CLEAR ))
122 4 : _sendClear( context );
123 4 : return TRAVERSE_CONTINUE;
124 : }
125 :
126 25 : VisitorResult ChannelUpdateVisitor::visitLeaf( const Compound* compound )
127 : {
128 25 : if( !compound->isInheritActive( _eye ))
129 18 : return TRAVERSE_CONTINUE;
130 :
131 7 : if( _skipCompound( compound ))
132 : {
133 2 : _updateDrawFinish( compound );
134 2 : return TRAVERSE_CONTINUE;
135 : }
136 :
137 : // OPT: Send render context once before task commands?
138 5 : RenderContext context;
139 5 : _setupRenderContext( compound, context );
140 5 : _updateFrameRate( compound );
141 5 : _updateViewStart( compound, context );
142 5 : _updateDraw( compound, context );
143 5 : _updateDrawFinish( compound );
144 5 : _updatePostDraw( compound, context );
145 5 : return TRAVERSE_CONTINUE;
146 : }
147 :
148 101 : VisitorResult ChannelUpdateVisitor::visitPost( const Compound* compound )
149 : {
150 101 : if( _skipCompound( compound ))
151 97 : return TRAVERSE_CONTINUE;
152 :
153 4 : RenderContext context;
154 4 : _setupRenderContext( compound, context );
155 4 : _updatePostDraw( compound, context );
156 :
157 4 : return TRAVERSE_CONTINUE;
158 : }
159 :
160 13 : void ChannelUpdateVisitor::_setupRenderContext( const Compound* compound,
161 : RenderContext& context )
162 : {
163 13 : const Channel* destChannel = compound->getInheritChannel();
164 13 : LBASSERT( destChannel );
165 :
166 13 : context.frameID = _frameID;
167 13 : context.pvp = compound->getInheritPixelViewport();
168 13 : context.overdraw = compound->getInheritOverdraw();
169 13 : context.vp = compound->getInheritViewport();
170 13 : context.range = compound->getInheritRange();
171 13 : context.pixel = compound->getInheritPixel();
172 13 : context.subpixel = compound->getInheritSubPixel();
173 13 : context.zoom = compound->getInheritZoom();
174 13 : context.period = compound->getInheritPeriod();
175 13 : context.phase = compound->getInheritPhase();
176 13 : context.offset.x() = context.pvp.x;
177 13 : context.offset.y() = context.pvp.y;
178 13 : context.eye = _eye;
179 13 : context.buffer = _getDrawBuffer( compound );
180 13 : context.bufferMask = _getDrawBufferMask( compound );
181 13 : context.view = destChannel->getViewVersion();
182 13 : context.taskID = compound->getTaskID();
183 :
184 13 : const View* view = destChannel->getView();
185 13 : LBASSERT( context.view == view );
186 :
187 13 : if( view )
188 : {
189 : // compute inherit vp (part of view covered by segment/view channel)
190 13 : const Segment* segment = destChannel->getSegment();
191 13 : LBASSERT( segment );
192 :
193 13 : const PixelViewport& pvp = destChannel->getPixelViewport();
194 13 : if( pvp.hasArea( ))
195 13 : context.vp.applyView( segment->getViewport(), view->getViewport(),
196 26 : pvp, destChannel->getOverdraw( ));
197 : }
198 :
199 13 : if( _channel != destChannel )
200 : {
201 2 : const PixelViewport& nativePVP = _channel->getPixelViewport();
202 2 : context.pvp.x = nativePVP.x;
203 2 : context.pvp.y = nativePVP.y;
204 : }
205 : // TODO: pvp size overcommit check?
206 :
207 13 : compound->computeFrustum( context, _eye );
208 13 : }
209 :
210 5 : void ChannelUpdateVisitor::_updateDraw( const Compound* compound,
211 : const RenderContext& context )
212 : {
213 5 : if( compound->hasTiles( ))
214 : {
215 0 : _updateDrawTiles( compound, context );
216 5 : return;
217 : }
218 :
219 5 : if( compound->testInheritTask( fabric::TASK_CLEAR ))
220 5 : _sendClear( context );
221 :
222 5 : if( compound->testInheritTask( fabric::TASK_DRAW ))
223 : {
224 5 : const bool finish = _channel->hasListeners(); // finish for eq stats
225 5 : _channel->send( fabric::CMD_CHANNEL_FRAME_DRAW ) << context << finish;
226 5 : _updated = true;
227 5 : LBLOG( LOG_TASKS ) << "TASK draw " << _channel->getName() << " "
228 5 : << finish << std::endl;
229 : }
230 : }
231 :
232 0 : void ChannelUpdateVisitor::_updateDrawTiles( const Compound* compound,
233 : const RenderContext& context )
234 : {
235 0 : Frames frames;
236 0 : co::ObjectVersions frameIDs;
237 0 : const Frames& outputFrames = compound->getOutputFrames();
238 0 : for( FramesCIter i = outputFrames.begin(); i != outputFrames.end(); ++i)
239 : {
240 0 : Frame* frame = *i;
241 :
242 0 : if( !frame->hasData( _eye )) // TODO: filter: buffers, vp, eye
243 0 : continue;
244 :
245 0 : frames.push_back( frame );
246 0 : frameIDs.push_back( co::ObjectVersion( frame ));
247 : }
248 :
249 0 : const Channel* destChannel = compound->getInheritChannel();
250 0 : const TileQueues& inputQueues = compound->getInputTileQueues();
251 0 : for( TileQueuesCIter i = inputQueues.begin(); i != inputQueues.end(); ++i )
252 : {
253 0 : const TileQueue* inputQueue = *i;
254 0 : const TileQueue* outputQueue = inputQueue->getOutputQueue( context.eye);
255 0 : const uint128_t& id = outputQueue->getQueueMasterID( context.eye );
256 0 : LBASSERT( id != 0 );
257 :
258 0 : const bool isLocal = (_channel == destChannel);
259 0 : const uint32_t tasks = compound->getInheritTasks() &
260 : ( eq::fabric::TASK_CLEAR | eq::fabric::TASK_DRAW |
261 0 : eq::fabric::TASK_READBACK );
262 :
263 : _channel->send( fabric::CMD_CHANNEL_FRAME_TILES )
264 0 : << context << isLocal << id << tasks << frameIDs;
265 0 : _updated = true;
266 0 : LBLOG( LOG_TASKS ) << "TASK tiles " << _channel->getName() << " "
267 0 : << std::endl;
268 0 : }
269 0 : }
270 :
271 108 : void ChannelUpdateVisitor::_updateDrawFinish( const Compound* compound ) const
272 : {
273 108 : const Compound* lastDrawCompound = _channel->getLastDrawCompound();
274 108 : if( lastDrawCompound && lastDrawCompound != compound )
275 99 : return;
276 :
277 : // Only pass if this is the last eye pass of this compound
278 9 : if( !compound->isLastInheritEye( _eye ))
279 2 : return;
280 :
281 7 : if( !lastDrawCompound )
282 2 : _channel->setLastDrawCompound( compound );
283 :
284 : // Channel::frameDrawFinish
285 7 : Node* node = _channel->getNode();
286 :
287 7 : node->send( fabric::CMD_CHANNEL_FRAME_DRAW_FINISH, _channel->getID( ))
288 14 : << _frameID << _frameNumber;
289 7 : LBLOG( LOG_TASKS ) << "TASK channel draw finish " << _channel->getName()
290 0 : << " frame " << _frameNumber
291 7 : << " id " << _frameID << std::endl;
292 :
293 : // Window::frameDrawFinish
294 7 : Window* window = _channel->getWindow();
295 7 : const Channel* lastDrawChannel = window->getLastDrawChannel();
296 :
297 7 : if( lastDrawChannel && lastDrawChannel != _channel )
298 0 : return;
299 :
300 7 : window->setLastDrawChannel( _channel ); // in case not set
301 :
302 7 : node->send( fabric::CMD_WINDOW_FRAME_DRAW_FINISH, window->getID( ))
303 14 : << _frameID << _frameNumber;
304 7 : LBLOG( LOG_TASKS ) << "TASK window draw finish " << window->getName()
305 0 : << " frame " << _frameNumber
306 7 : << " id " << _frameID << std::endl;
307 :
308 : // Pipe::frameDrawFinish
309 7 : Pipe* pipe = _channel->getPipe();
310 7 : const Window* lastDrawWindow = pipe->getLastDrawWindow();
311 7 : if( lastDrawWindow && lastDrawWindow != window )
312 0 : return;
313 :
314 7 : pipe->setLastDrawWindow( window ); // in case not set
315 :
316 7 : node->send( fabric::CMD_PIPE_FRAME_DRAW_FINISH, pipe->getID( ))
317 14 : << _frameID << _frameNumber;
318 7 : LBLOG( LOG_TASKS ) << "TASK pipe draw finish " << pipe->getName()
319 0 : << " frame " << _frameNumber
320 7 : << " id " << _frameID << std::endl;
321 :
322 : // Node::frameDrawFinish
323 7 : const Pipe* lastDrawPipe = node->getLastDrawPipe();
324 7 : if( lastDrawPipe && lastDrawPipe != pipe )
325 2 : return;
326 :
327 5 : node->setLastDrawPipe( pipe ); // in case not set
328 :
329 5 : node->send( fabric::CMD_NODE_FRAME_DRAW_FINISH, node->getID( ))
330 10 : << _frameID << _frameNumber;
331 5 : LBLOG( LOG_TASKS ) << "TASK node draw finish " << node->getName() << " "
332 5 : << std::endl;
333 : }
334 :
335 9 : void ChannelUpdateVisitor::_sendClear( const RenderContext& context )
336 : {
337 9 : _channel->send( fabric::CMD_CHANNEL_FRAME_CLEAR ) << context;
338 9 : _updated = true;
339 9 : LBLOG( LOG_TASKS ) << "TASK clear " << _channel->getName() << " "
340 9 : << std::endl;
341 9 : }
342 :
343 9 : void ChannelUpdateVisitor::_updateFrameRate( const Compound* compound ) const
344 : {
345 9 : const float maxFPS = compound->getInheritMaxFPS();
346 9 : Window* window = _channel->getWindow();
347 :
348 9 : if( maxFPS < window->getMaxFPS())
349 0 : window->setMaxFPS( maxFPS );
350 9 : }
351 :
352 13 : uint32_t ChannelUpdateVisitor::_getDrawBuffer( const Compound* compound ) const
353 : {
354 13 : const DrawableConfig& dc = _channel->getWindow()->getDrawableConfig();
355 13 : const int32_t eye = lunchbox::getIndexOfLastBit( _eye );
356 :
357 13 : if( compound->getInheritIAttribute(Compound::IATTR_STEREO_MODE) == QUAD )
358 0 : return _drawBuffer[ dc.stereo ][ dc.doublebuffered ][ eye ];
359 13 : return _drawBuffer[ 0 ][ dc.doublebuffered ][ eye ];
360 : }
361 :
362 13 : eq::ColorMask ChannelUpdateVisitor::_getDrawBufferMask(const Compound* compound)
363 : const
364 : {
365 13 : if( compound->getInheritIAttribute( Compound::IATTR_STEREO_MODE ) !=
366 : fabric::ANAGLYPH )
367 : {
368 0 : return ColorMask::ALL;
369 : }
370 :
371 13 : switch( _eye )
372 : {
373 : case EYE_LEFT:
374 : return ColorMask(
375 : compound->getInheritIAttribute(
376 0 : Compound::IATTR_STEREO_ANAGLYPH_LEFT_MASK ));
377 : case EYE_RIGHT:
378 : return ColorMask(
379 : compound->getInheritIAttribute(
380 0 : Compound::IATTR_STEREO_ANAGLYPH_RIGHT_MASK ));
381 : default:
382 13 : return ColorMask::ALL;
383 : }
384 : }
385 :
386 9 : void ChannelUpdateVisitor::_updatePostDraw( const Compound* compound,
387 : const RenderContext& context )
388 : {
389 9 : _updateAssemble( compound, context );
390 9 : _updateReadback( compound, context );
391 9 : _updateViewFinish( compound, context );
392 9 : }
393 :
394 9 : void ChannelUpdateVisitor::_updateAssemble( const Compound* compound,
395 : const RenderContext& context )
396 : {
397 9 : if( !compound->testInheritTask( fabric::TASK_ASSEMBLE ))
398 14 : return;
399 :
400 2 : const Frames& inputFrames = compound->getInputFrames();
401 2 : LBASSERT( !inputFrames.empty( ));
402 :
403 2 : co::ObjectVersions frames;
404 12 : for( Frames::const_iterator iter = inputFrames.begin();
405 8 : iter != inputFrames.end(); ++iter )
406 : {
407 2 : Frame* frame = *iter;
408 :
409 2 : if( !frame->hasData( _eye )) // TODO: filter: buffers, vp, eye
410 0 : continue;
411 :
412 2 : LBLOG( LOG_ASSEMBLY ) << *frame << std::endl;
413 2 : frames.push_back( co::ObjectVersion( frame ));
414 : }
415 :
416 2 : if( frames.empty( ))
417 0 : return;
418 :
419 : // assemble task
420 2 : LBLOG( LOG_ASSEMBLY | LOG_TASKS )
421 0 : << "TASK assemble " << _channel->getName()
422 2 : << " nFrames " << frames.size() << std::endl;
423 : _channel->send( fabric::CMD_CHANNEL_FRAME_ASSEMBLE )
424 2 : << context << frames;
425 2 : _updated = true;
426 : }
427 :
428 9 : void ChannelUpdateVisitor::_updateReadback( const Compound* compound,
429 : const RenderContext& context )
430 : {
431 18 : if( !compound->testInheritTask( fabric::TASK_READBACK ) ||
432 2 : ( compound->hasTiles() && compound->isLeaf( )))
433 : {
434 14 : return;
435 : }
436 :
437 2 : const std::vector< Frame* >& outputFrames = compound->getOutputFrames();
438 2 : LBASSERT( !outputFrames.empty( ));
439 :
440 2 : co::ObjectVersions frames;
441 4 : for( FramesCIter i = outputFrames.begin(); i != outputFrames.end(); ++i )
442 : {
443 2 : Frame* frame = *i;
444 :
445 2 : if( !frame->hasData( _eye )) // TODO: filter: buffers, vp, eye
446 0 : continue;
447 :
448 2 : frames.push_back( co::ObjectVersion( frame ));
449 2 : LBLOG( LOG_ASSEMBLY ) << *frame << std::endl;
450 : }
451 :
452 2 : if( frames.empty() )
453 0 : return;
454 :
455 : // readback task
456 : _channel->send( fabric::CMD_CHANNEL_FRAME_READBACK )
457 2 : << context << frames;
458 2 : _updated = true;
459 2 : LBLOG( LOG_ASSEMBLY | LOG_TASKS )
460 0 : << "TASK readback " << _channel->getName()
461 2 : << " nFrames " << frames.size() << std::endl;
462 : }
463 :
464 9 : void ChannelUpdateVisitor::_updateViewStart( const Compound* compound,
465 : const RenderContext& context )
466 : {
467 9 : LBASSERT( !_skipCompound( compound ));
468 9 : if( !compound->testInheritTask( fabric::TASK_VIEW ))
469 13 : return;
470 :
471 : // view start task
472 5 : LBLOG( LOG_TASKS ) << "TASK view start " << _channel->getName()
473 5 : << std::endl;
474 5 : _channel->send( fabric::CMD_CHANNEL_FRAME_VIEW_START ) << context;
475 : }
476 :
477 9 : void ChannelUpdateVisitor::_updateViewFinish( const Compound* compound,
478 : const RenderContext& context )
479 : {
480 9 : LBASSERT( !_skipCompound( compound ));
481 9 : if( !compound->testInheritTask( fabric::TASK_VIEW ))
482 13 : return;
483 :
484 : // view finish task
485 5 : LBLOG( LOG_TASKS ) << "TASK view finish " << _channel->getName() << " "
486 5 : << std::endl;
487 5 : _channel->send( fabric::CMD_CHANNEL_FRAME_VIEW_FINISH ) << context;
488 : }
489 :
490 : }
491 27 : }
492 :
|