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