Line data Source code
1 :
2 : /* Copyright (c) 2007-2017, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : *
5 : * This library is free software; you can redistribute it and/or modify it under
6 : * the terms of the GNU Lesser General Public License version 2.1 as published
7 : * by the Free Software Foundation.
8 : *
9 : * This library is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 : * details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public License
15 : * along with this library; if not, write to the Free Software Foundation, Inc.,
16 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 : */
18 :
19 : #include "compoundUpdateOutputVisitor.h"
20 :
21 : #include "config.h"
22 : #include "frame.h"
23 : #include "frameData.h"
24 : #include "log.h"
25 : #include "server.h"
26 : #include "tileQueue.h"
27 : #include "window.h"
28 :
29 : #include "tiles/zigzagStrategy.h"
30 :
31 : #include <eq/fabric/iAttribute.h>
32 : #include <eq/fabric/tile.h>
33 :
34 : namespace eq
35 : {
36 : namespace server
37 : {
38 28 : CompoundUpdateOutputVisitor::CompoundUpdateOutputVisitor(const uint32_t frame)
39 28 : : _frameNumber(frame)
40 : {
41 28 : }
42 :
43 72 : VisitorResult CompoundUpdateOutputVisitor::visit(Compound* compound)
44 : {
45 72 : if (!compound->isActive())
46 28 : return TRAVERSE_PRUNE;
47 :
48 44 : _updateQueues(compound);
49 44 : _updateFrames(compound);
50 44 : _updateSwapBarriers(compound);
51 :
52 44 : return TRAVERSE_CONTINUE;
53 : }
54 :
55 44 : void CompoundUpdateOutputVisitor::_updateQueues(Compound* compound)
56 : {
57 44 : const TileQueues& queues = compound->getOutputTileQueues();
58 44 : for (TileQueuesCIter i = queues.begin(); i != queues.end(); ++i)
59 : {
60 : //----- Check uniqueness of output queue name
61 0 : TileQueue* queue = *i;
62 0 : const std::string& name = queue->getName();
63 :
64 0 : if (_outputTileQueues.find(name) != _outputTileQueues.end())
65 : {
66 0 : LBWARN << "Multiple output queues of the same name are unsupported"
67 0 : << ", ignoring output queue " << name << std::endl;
68 0 : queue->unsetData();
69 0 : continue;
70 : }
71 :
72 0 : queue->cycleData(_frameNumber, compound);
73 :
74 : //----- Generate tile task commands
75 0 : _generateTiles(queue, compound);
76 0 : _outputTileQueues[name] = queue;
77 : }
78 44 : }
79 :
80 44 : void CompoundUpdateOutputVisitor::_updateFrames(Compound* compound)
81 : {
82 44 : const Frames& outputFrames = compound->getOutputFrames();
83 44 : if (outputFrames.empty())
84 40 : compound->unsetInheritTask(fabric::TASK_READBACK);
85 :
86 44 : const Channel* channel = compound->getChannel();
87 44 : if (!compound->testInheritTask(fabric::TASK_READBACK) || !channel)
88 40 : return;
89 :
90 8 : for (FramesCIter i = outputFrames.begin(); i != outputFrames.end(); ++i)
91 : {
92 : //----- Check uniqueness of output frame name
93 4 : Frame* frame = *i;
94 4 : const std::string& name = frame->getName();
95 :
96 4 : if (_outputFrames.find(name) != _outputFrames.end())
97 : {
98 0 : LBWARN << "Multiple output frames of the same name are unsupported"
99 0 : << ", ignoring output frame " << name << std::endl;
100 0 : frame->unsetData();
101 0 : continue;
102 : }
103 :
104 : //----- compute readback area
105 4 : const Viewport& frameVP = frame->getViewport();
106 4 : const PixelViewport& inheritPVP = compound->getInheritPixelViewport();
107 4 : PixelViewport framePVP(inheritPVP);
108 4 : framePVP.apply(frameVP);
109 :
110 4 : if (!framePVP.hasArea()) // output frame has no pixels
111 : {
112 0 : LBINFO << "Skipping output frame " << name << ", no pixels"
113 0 : << std::endl;
114 0 : frame->unsetData();
115 0 : continue;
116 : }
117 :
118 : //----- Create new frame datas
119 : // * one frame data used for each eye pass
120 : // * data is set only on master frame data (will copy to all others)
121 4 : frame->cycleData(_frameNumber, compound);
122 4 : FrameData* frameData = frame->getMasterData();
123 4 : LBASSERT(frameData);
124 :
125 4 : LBLOG(LOG_ASSEMBLY)
126 0 : << lunchbox::disableFlush << "Output frame \"" << name << "\" id "
127 4 : << frame->getID() << " v" << frame->getVersion() + 1 << " data id "
128 4 : << frameData->getID() << " v" << frameData->getVersion() + 1
129 0 : << " on channel \"" << channel->getName() << "\" tile pos "
130 12 : << framePVP.x << ", " << framePVP.y;
131 :
132 : //----- Set frame data parameters:
133 : // 1) offset is position wrt destination view, used only by input frames
134 4 : const bool tiled = !compound->getInputTileQueues().empty();
135 8 : frameData->setOffset(tiled ? Vector2i(0, 0)
136 8 : : Vector2i(framePVP.x, framePVP.y));
137 :
138 : // 2) pvp is area within channel
139 4 : framePVP.x = static_cast<int32_t>(frameVP.x * inheritPVP.w);
140 4 : framePVP.y = static_cast<int32_t>(frameVP.y * inheritPVP.h);
141 4 : frameData->setPixelViewport(framePVP);
142 :
143 : // 3) image buffers and storage type
144 4 : const Frame::Buffer buffers = frame->getBuffers();
145 :
146 4 : frameData->setType(frame->getType());
147 4 : frameData->setBuffers(buffers == Frame::Buffer::undefined
148 : ? compound->getInheritBuffers()
149 4 : : buffers);
150 :
151 : // 4) (source) render context
152 4 : frameData->setContext(compound->setupRenderContext(EYE_CYCLOP));
153 :
154 : //----- Set frame parameters:
155 : // 1) offset is position wrt window, i.e., the channel position
156 4 : if (compound->getInheritChannel() == channel)
157 0 : frame->setOffset(Vector2i(inheritPVP.x, inheritPVP.y));
158 : else
159 : {
160 4 : const PixelViewport& nativePVP = channel->getPixelViewport();
161 4 : frame->setOffset(Vector2i(nativePVP.x, nativePVP.y));
162 : }
163 :
164 : // 2) zoom
165 4 : _updateZoom(compound, frame);
166 :
167 : //----- Commit
168 4 : frame->commitData();
169 :
170 4 : _outputFrames[name] = frame;
171 4 : LBLOG(LOG_ASSEMBLY)
172 0 : << " buffers " << frameData->getBuffers() << " read area "
173 0 : << framePVP << " readback " << frame->getZoom() << " assemble "
174 4 : << frameData->getZoom() << lunchbox::enableFlush << std::endl;
175 : }
176 : }
177 :
178 0 : void CompoundUpdateOutputVisitor::_generateTiles(TileQueue* queue,
179 : Compound* compound)
180 : {
181 0 : const Vector2i& tileSize = queue->getTileSize();
182 0 : const PixelViewport pvp = compound->getInheritPixelViewport();
183 0 : if (!pvp.hasArea())
184 0 : return;
185 :
186 0 : const Vector2i dim(pvp.w / tileSize.x() + ((pvp.w % tileSize.x()) ? 1 : 0),
187 0 : pvp.h / tileSize.y() + ((pvp.h % tileSize.y()) ? 1 : 0));
188 :
189 0 : std::vector<Vector2i> tiles;
190 0 : tiles.reserve(dim.x() * dim.y());
191 :
192 0 : tiles::generateZigzag(tiles, dim);
193 0 : _addTilesToQueue(queue, compound, tiles);
194 : }
195 :
196 0 : void CompoundUpdateOutputVisitor::_addTilesToQueue(
197 : TileQueue* queue, Compound* compound, const std::vector<Vector2i>& tiles)
198 : {
199 0 : const Vector2i& tileSize = queue->getTileSize();
200 0 : PixelViewport pvp = compound->getInheritPixelViewport();
201 0 : const double xFraction = 1.0 / pvp.w;
202 0 : const double yFraction = 1.0 / pvp.h;
203 :
204 0 : for (std::vector<Vector2i>::const_iterator i = tiles.begin();
205 0 : i != tiles.end(); ++i)
206 : {
207 0 : const Vector2i& tile = *i;
208 0 : PixelViewport tilePVP(tile.x() * tileSize.x(), tile.y() * tileSize.y(),
209 0 : tileSize.x(), tileSize.y());
210 :
211 0 : if (tilePVP.x + tileSize.x() > pvp.w) // no full tile
212 0 : tilePVP.w = pvp.w - tilePVP.x;
213 :
214 0 : if (tilePVP.y + tileSize.y() > pvp.h) // no full tile
215 0 : tilePVP.h = pvp.h - tilePVP.y;
216 :
217 0 : const Viewport tileVP(tilePVP.x * xFraction, tilePVP.y * yFraction,
218 0 : tilePVP.w * xFraction, tilePVP.h * yFraction);
219 :
220 0 : for (fabric::Eye eye = fabric::EYE_CYCLOP; eye < fabric::EYES_ALL;
221 0 : eye = fabric::Eye(eye << 1))
222 : {
223 0 : if (!(compound->getInheritEyes() & eye) ||
224 0 : !compound->isInheritActive(eye))
225 : {
226 0 : continue;
227 : }
228 :
229 0 : Tile tileItem(tilePVP, tileVP);
230 : compound->computeTileFrustum(tileItem.frustum, eye, tileItem.vp,
231 0 : false);
232 : compound->computeTileFrustum(tileItem.ortho, eye, tileItem.vp,
233 0 : true);
234 0 : queue->addTile(tileItem, eye);
235 : }
236 : }
237 0 : }
238 :
239 4 : void CompoundUpdateOutputVisitor::_updateZoom(const Compound* compound,
240 : Frame* frame)
241 : {
242 4 : Zoom zoom = frame->getNativeZoom();
243 4 : Zoom zoom_1;
244 :
245 4 : if (!zoom.isValid()) // if zoom is not set, auto-calculate from parent
246 : {
247 4 : zoom_1 = compound->getInheritZoom();
248 4 : LBASSERT(zoom_1.isValid());
249 4 : zoom.x() = 1.0f / zoom_1.x();
250 4 : zoom.y() = 1.0f / zoom_1.y();
251 : }
252 : else
253 : {
254 0 : zoom_1.x() = 1.0f / zoom.x();
255 0 : zoom_1.y() = 1.0f / zoom.y();
256 : }
257 :
258 4 : if (frame->getType() == Frame::TYPE_TEXTURE)
259 : {
260 0 : FrameData* frameData = frame->getMasterData();
261 0 : frameData->setZoom(zoom_1); // textures are zoomed by input frame
262 0 : frame->setZoom(Zoom::NONE);
263 : }
264 : else
265 : {
266 4 : Zoom inputZoom;
267 : /* Output frames downscale pixel data during readback, and upscale it on
268 : * the input frame by setting the input frame's inherit zoom. */
269 4 : if (zoom.x() > 1.0f)
270 : {
271 0 : inputZoom.x() = zoom_1.x();
272 0 : zoom.x() = 1.f;
273 : }
274 4 : if (zoom.y() > 1.0f)
275 : {
276 0 : inputZoom.y() = zoom_1.y();
277 0 : zoom.y() = 1.f;
278 : }
279 :
280 4 : FrameData* frameData = frame->getMasterData();
281 4 : frameData->setZoom(inputZoom);
282 4 : frame->setZoom(zoom);
283 : }
284 4 : }
285 :
286 44 : void CompoundUpdateOutputVisitor::_updateSwapBarriers(Compound* compound)
287 : {
288 44 : SwapBarrierConstPtr swapBarrier = compound->getSwapBarrier();
289 44 : if (!swapBarrier)
290 44 : return;
291 :
292 0 : Window* window = compound->getWindow();
293 0 : LBASSERT(window);
294 0 : if (!window)
295 0 : return;
296 :
297 0 : if (swapBarrier->isNvSwapBarrier())
298 : {
299 0 : if (!window->hasNVSwapBarrier())
300 : {
301 0 : const std::string name("__NV_swap_group_protection_barrier__");
302 0 : _swapBarriers[name] =
303 0 : window->joinNVSwapBarrier(swapBarrier, _swapBarriers[name]);
304 : }
305 : }
306 : else
307 : {
308 0 : const std::string& name = swapBarrier->getName();
309 0 : _swapBarriers[name] = window->joinSwapBarrier(_swapBarriers[name]);
310 : }
311 : }
312 : }
313 60 : }
|