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