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