Line data Source code
1 :
2 : /* Copyright (c) 2006-2016, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : * Cedric Stalder <cedric.stalder@gmail.com>
5 : * Enrique <egparedes@ifi.uzh.ch>
6 : *
7 : * This library is free software; you can redistribute it and/or modify it under
8 : * the terms of the GNU Lesser General Public License version 2.1 as published
9 : * by the Free Software Foundation.
10 : *
11 : * This library is distributed in the hope that it will be useful, but WITHOUT
12 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14 : * details.
15 : *
16 : * You should have received a copy of the GNU Lesser General Public License
17 : * along with this library; if not, write to the Free Software Foundation, Inc.,
18 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 : */
20 :
21 : #include "frameData.h"
22 :
23 : #include "nodeStatistics.h"
24 : #include "channelStatistics.h"
25 : #include "exception.h"
26 : #include "image.h"
27 : #include "log.h"
28 : #include "pixelData.h"
29 : #include "roiFinder.h"
30 :
31 : #include <eq/fabric/drawableConfig.h>
32 : #include <eq/fabric/frameData.h>
33 : #include <eq/util/objectManager.h>
34 : #include <co/commandFunc.h>
35 : #include <co/connectionDescription.h>
36 : #include <co/dataIStream.h>
37 : #include <co/dataOStream.h>
38 : #include <lunchbox/monitor.h>
39 : #include <lunchbox/scopedMutex.h>
40 : #include <pression/plugins/compressor.h>
41 :
42 : #include <boost/foreach.hpp>
43 :
44 : #include <algorithm>
45 :
46 : namespace eq
47 : {
48 : typedef lunchbox::Monitor< uint64_t > Monitor;
49 : typedef std::vector< FrameData::Listener* > Listeners;
50 :
51 : namespace detail
52 : {
53 1 : class FrameData
54 : {
55 : public:
56 1 : FrameData()
57 1 : : version( co::VERSION_NONE.low( ))
58 : , useAlpha( true )
59 : , colorQuality( 1.f )
60 : , depthQuality( 1.f )
61 : , colorCompressor( EQ_COMPRESSOR_AUTO )
62 2 : , depthCompressor( EQ_COMPRESSOR_AUTO )
63 1 : {}
64 :
65 : Images images;
66 : Images imageCache;
67 : lunchbox::Lock imageCacheLock;
68 :
69 : ROIFinder roiFinder;
70 :
71 : Images pendingImages;
72 :
73 : uint64_t version; //!< The current version
74 :
75 : /** Data ready monitor for output->input synchronization. */
76 : Monitor readyVersion;
77 :
78 : /** External monitors for readiness synchronization. */
79 : lunchbox::Lockable< Listeners, lunchbox::SpinLock > listeners;
80 :
81 : bool useAlpha;
82 : float colorQuality;
83 : float depthQuality;
84 :
85 : uint32_t colorCompressor;
86 : uint32_t depthCompressor;
87 : };
88 : }
89 :
90 : typedef co::CommandFunc< FrameData > CmdFunc;
91 :
92 1 : FrameData::FrameData()
93 1 : : _impl( new detail::FrameData )
94 1 : {}
95 :
96 3 : FrameData::~FrameData()
97 : {
98 1 : clear();
99 :
100 4 : for( Image* image : _impl->imageCache )
101 : {
102 9 : LBLOG( LOG_BUG ) << "Unflushed image in FrameData destructor"
103 9 : << std::endl;
104 3 : delete image;
105 : }
106 1 : _impl->imageCache.clear();
107 :
108 1 : delete _impl;
109 2 : }
110 :
111 22 : const Images& FrameData::getImages() const
112 : {
113 22 : return _impl->images;
114 : }
115 :
116 0 : void FrameData::setAlphaUsage( const bool useAlpha )
117 : {
118 0 : _impl->useAlpha = useAlpha;
119 0 : }
120 :
121 0 : bool FrameData::isReady() const
122 : {
123 0 : return _impl->readyVersion.get() >= _impl->version;
124 : }
125 :
126 0 : void FrameData::setQuality( Frame::Buffer buffer, float quality )
127 : {
128 0 : if( buffer != Frame::BUFFER_COLOR )
129 : {
130 0 : LBASSERT( buffer == Frame::BUFFER_DEPTH );
131 0 : _impl->depthQuality = quality;
132 0 : return;
133 : }
134 :
135 0 : _impl->colorQuality = quality;
136 : }
137 :
138 0 : void FrameData::useCompressor( const Frame::Buffer buffer, const uint32_t name )
139 : {
140 0 : if( buffer != Frame::BUFFER_COLOR )
141 : {
142 0 : LBASSERT( buffer == Frame::BUFFER_DEPTH );
143 0 : _impl->depthCompressor = name;
144 0 : return;
145 : }
146 :
147 0 : _impl->colorCompressor = name;
148 : }
149 :
150 0 : void FrameData::getInstanceData( co::DataOStream& os )
151 : {
152 0 : LBUNREACHABLE;
153 0 : serialize( os );
154 0 : }
155 :
156 0 : void FrameData::applyInstanceData( co::DataIStream& is )
157 : {
158 0 : clear();
159 0 : deserialize( is );
160 0 : LBLOG( LOG_ASSEMBLY ) << "applied " << this << std::endl;
161 0 : }
162 :
163 2 : void FrameData::clear()
164 : {
165 2 : _impl->imageCacheLock.set();
166 : _impl->imageCache.insert( _impl->imageCache.end(), _impl->images.begin(),
167 2 : _impl->images.end( ));
168 2 : _impl->imageCacheLock.unset();
169 2 : _impl->images.clear();
170 2 : }
171 :
172 0 : void FrameData::flush()
173 : {
174 0 : clear();
175 :
176 0 : for( ImagesCIter i = _impl->imageCache.begin();
177 0 : i != _impl->imageCache.end(); ++i )
178 : {
179 0 : Image* image = *i;
180 0 : image->flush();
181 0 : delete image;
182 : }
183 :
184 0 : _impl->imageCache.clear();
185 0 : }
186 :
187 0 : void FrameData::deleteGLObjects( util::ObjectManager& om )
188 : {
189 0 : for( Image* image : _impl->images )
190 0 : image->deleteGLObjects( om );
191 0 : for( Image* image : _impl->imageCache )
192 0 : image->deleteGLObjects( om );
193 0 : }
194 :
195 0 : void FrameData::resetPlugins()
196 : {
197 0 : BOOST_FOREACH( Image* image, _impl->images )
198 0 : image->resetPlugins();
199 0 : BOOST_FOREACH( Image* image, _impl->imageCache )
200 0 : image->resetPlugins();
201 0 : }
202 :
203 6 : Image* FrameData::newImage( const eq::Frame::Type type,
204 : const DrawableConfig& config )
205 : {
206 6 : Image* image = _allocImage( type, config, true /* set quality */ );
207 6 : _impl->images.push_back( image );
208 6 : return image;
209 : }
210 :
211 6 : Image* FrameData::_allocImage( const eq::Frame::Type type,
212 : const DrawableConfig& config,
213 : const bool setQuality_ )
214 : {
215 : Image* image;
216 6 : _impl->imageCacheLock.set();
217 :
218 6 : if( _impl->imageCache.empty( ))
219 : {
220 3 : _impl->imageCacheLock.unset();
221 3 : image = new Image;
222 : }
223 : else
224 : {
225 3 : image = _impl->imageCache.back();
226 3 : _impl->imageCache.pop_back();
227 3 : _impl->imageCacheLock.unset();
228 :
229 3 : image->reset();
230 : }
231 :
232 6 : image->setAlphaUsage( _impl->useAlpha );
233 6 : image->setStorageType( type );
234 6 : if( setQuality_ )
235 : {
236 6 : image->setQuality( Frame::BUFFER_COLOR, _impl->colorQuality );
237 6 : image->setQuality( Frame::BUFFER_DEPTH, _impl->depthQuality );
238 : }
239 :
240 6 : image->useCompressor( Frame::BUFFER_COLOR, _impl->colorCompressor );
241 6 : image->useCompressor( Frame::BUFFER_DEPTH, _impl->depthCompressor );
242 :
243 : image->setInternalFormat( Frame::BUFFER_DEPTH,
244 6 : EQ_COMPRESSOR_DATATYPE_DEPTH );
245 6 : switch( config.colorBits )
246 : {
247 : case 16:
248 : image->setInternalFormat( Frame::BUFFER_COLOR,
249 0 : EQ_COMPRESSOR_DATATYPE_RGBA16F );
250 0 : break;
251 : case 32:
252 : image->setInternalFormat( Frame::BUFFER_COLOR,
253 0 : EQ_COMPRESSOR_DATATYPE_RGBA32F );
254 0 : break;
255 : case 10:
256 : image->setInternalFormat( Frame::BUFFER_COLOR,
257 0 : EQ_COMPRESSOR_DATATYPE_RGB10_A2 );
258 0 : break;
259 : default:
260 : image->setInternalFormat( Frame::BUFFER_COLOR,
261 6 : EQ_COMPRESSOR_DATATYPE_RGBA );
262 : }
263 :
264 6 : return image;
265 : }
266 :
267 0 : Images FrameData::startReadback( const Frame& frame,
268 : util::ObjectManager& glObjects,
269 : const DrawableConfig& config,
270 : const PixelViewports& regions,
271 : const RenderContext& context )
272 : {
273 0 : if( _buffers == Frame::BUFFER_NONE )
274 0 : return Images();
275 :
276 0 : const Zoom& frameZoom = frame.getZoom();
277 0 : if( !frameZoom.isValid( ))
278 : {
279 0 : LBWARN << "Invalid zoom factor, skipping frame" << std::endl;
280 0 : return Images();
281 : }
282 :
283 0 : const eq::PixelViewport& framePVP = getPixelViewport();
284 0 : const PixelViewport absPVP = framePVP + frame.getOffset();
285 0 : if( !absPVP.isValid( ))
286 0 : return Images();
287 :
288 0 : Images images;
289 :
290 : // readback the whole screen when using textures
291 0 : if( getType() == eq::Frame::TYPE_TEXTURE )
292 : {
293 0 : Image* image = newImage( getType(), config );
294 0 : if( image->startReadback( getBuffers(), absPVP, context,
295 0 : frameZoom, glObjects ))
296 : {
297 0 : images.push_back( image );
298 : }
299 0 : image->setOffset( 0, 0 );
300 0 : return images;
301 : }
302 : //else read only required regions
303 :
304 : #if 0
305 : // TODO: issue #85: move automatic ROI detection to eq::Channel
306 : PixelViewports regions;
307 : if( buffers & Frame::BUFFER_DEPTH && frameZoom == Zoom::NONE )
308 : regions = _impl->roiFinder->findRegions( buffers, absPVP, frameZoom,
309 : frame.getAssemblyStage(),
310 : frame.getFrameID(), glObjects);
311 : else
312 : regions.push_back( absPVP );
313 : #endif
314 :
315 0 : LBASSERT( getType() == eq::Frame::TYPE_MEMORY );
316 :
317 0 : for( uint32_t i = 0; i < regions.size(); ++i )
318 : {
319 0 : PixelViewport pvp = regions[ i ] + frame.getOffset();
320 0 : pvp.intersect( absPVP );
321 0 : if( !pvp.hasArea( ))
322 0 : continue;
323 :
324 0 : Image* image = newImage( getType(), config );
325 0 : if( image->startReadback( getBuffers(), pvp, context, frameZoom, glObjects ))
326 0 : images.push_back( image );
327 :
328 0 : pvp -= frame.getOffset();
329 0 : pvp.apply( frameZoom );
330 0 : image->setOffset( (pvp.x - framePVP.x) * context.pixel.w,
331 0 : (pvp.y - framePVP.y) * context.pixel.h );
332 : }
333 0 : return images;
334 : }
335 :
336 0 : void FrameData::setVersion( const uint64_t version )
337 : {
338 0 : LBASSERTINFO( _impl->version <= version, _impl->version << " > "
339 : << version );
340 0 : _impl->version = version;
341 0 : LBLOG( LOG_ASSEMBLY ) << "New v" << version << std::endl;
342 0 : }
343 :
344 21 : void FrameData::waitReady( const uint32_t timeout ) const
345 : {
346 21 : if( !_impl->readyVersion.timedWaitGE( _impl->version, timeout ))
347 0 : throw Exception( Exception::TIMEOUT_INPUTFRAME );
348 21 : }
349 :
350 0 : void FrameData::setReady()
351 : {
352 0 : _setReady( _impl->version );
353 0 : }
354 :
355 0 : void FrameData::setReady( const co::ObjectVersion& frameData,
356 : const fabric::FrameData& data )
357 : {
358 0 : clear();
359 0 : LBASSERT( frameData.version.high() == 0 );
360 0 : LBASSERT( _impl->readyVersion < frameData.version.low( ));
361 0 : LBASSERT( _impl->readyVersion == 0 ||
362 : _impl->readyVersion + 1 == frameData.version.low( ));
363 0 : LBASSERT( _impl->version == frameData.version.low( ));
364 :
365 0 : _impl->images.swap( _impl->pendingImages );
366 0 : fabric::FrameData::operator = ( data );
367 0 : _setReady( frameData.version.low());
368 :
369 0 : LBLOG( LOG_ASSEMBLY ) << this << " applied v"
370 0 : << frameData.version.low() << std::endl;
371 0 : }
372 :
373 0 : void FrameData::_setReady( const uint64_t version )
374 : {
375 0 : LBASSERTINFO( _impl->readyVersion <= version,
376 : "v" << _impl->version << " ready " << _impl->readyVersion
377 : << " new " << version );
378 :
379 0 : lunchbox::ScopedMutex< lunchbox::SpinLock > mutex( _impl->listeners );
380 0 : if( _impl->readyVersion >= version )
381 0 : return;
382 :
383 0 : _impl->readyVersion = version;
384 0 : LBLOG( LOG_ASSEMBLY ) << "set ready " << this << ", "
385 0 : << _impl->listeners->size() << " monitoring"
386 0 : << std::endl;
387 :
388 0 : BOOST_FOREACH( Listener* listener, _impl->listeners.data )
389 0 : ++(*listener);
390 : }
391 :
392 0 : void FrameData::addListener( Listener& listener )
393 : {
394 0 : lunchbox::ScopedFastWrite mutex( _impl->listeners );
395 :
396 0 : _impl->listeners->push_back( &listener );
397 0 : if( _impl->readyVersion >= _impl->version )
398 0 : ++listener;
399 0 : }
400 :
401 0 : void FrameData::removeListener( Listener& listener )
402 : {
403 0 : lunchbox::ScopedFastWrite mutex( _impl->listeners );
404 :
405 0 : Listeners::iterator i = lunchbox::find( _impl->listeners.data, &listener );
406 0 : LBASSERT( i != _impl->listeners->end( ));
407 0 : _impl->listeners->erase( i );
408 0 : }
409 :
410 0 : bool FrameData::addImage( const co::ObjectVersion& frameDataVersion,
411 : const PixelViewport& pvp, const Zoom& zoom,
412 : const RenderContext& context, const uint32_t buffers_,
413 : const bool useAlpha, uint8_t* data )
414 : {
415 0 : LBASSERT( _impl->readyVersion < frameDataVersion.version.low( ));
416 0 : if( _impl->readyVersion >= frameDataVersion.version.low( ))
417 0 : return false;
418 :
419 : Image* image = _allocImage( Frame::TYPE_MEMORY, DrawableConfig(),
420 0 : false /* set quality */ );
421 :
422 0 : image->setPixelViewport( pvp );
423 0 : image->setAlphaUsage( useAlpha );
424 :
425 0 : Frame::Buffer buffers[] = { Frame::BUFFER_COLOR, Frame::BUFFER_DEPTH };
426 0 : for( unsigned i = 0; i < 2; ++i )
427 : {
428 0 : const Frame::Buffer buffer = buffers[i];
429 :
430 0 : if( buffers_ & buffer )
431 : {
432 0 : PixelData pixelData;
433 0 : const ImageHeader* header = reinterpret_cast<ImageHeader*>( data );
434 0 : data += sizeof( ImageHeader );
435 :
436 0 : pixelData.internalFormat = header->internalFormat;
437 0 : pixelData.externalFormat = header->externalFormat;
438 0 : pixelData.pixelSize = header->pixelSize;
439 0 : pixelData.pvp = header->pvp;
440 0 : pixelData.compressorFlags = header->compressorFlags;
441 :
442 0 : const uint32_t compressor = header->compressorName;
443 0 : if( compressor > EQ_COMPRESSOR_NONE )
444 : {
445 0 : pression::CompressorChunks chunks;
446 0 : const uint32_t nChunks = header->nChunks;
447 0 : chunks.reserve( nChunks );
448 :
449 0 : for( uint32_t j = 0; j < nChunks; ++j )
450 : {
451 0 : const uint64_t size = *reinterpret_cast< uint64_t*>( data );
452 0 : data += sizeof( uint64_t );
453 :
454 0 : chunks.push_back( pression::CompressorChunk( data, size ));
455 0 : data += size;
456 : }
457 0 : pixelData.compressedData =
458 0 : pression::CompressorResult( compressor, chunks );
459 : }
460 : else
461 : {
462 0 : const uint64_t size = *reinterpret_cast< uint64_t*>( data );
463 0 : data += sizeof( uint64_t );
464 :
465 0 : pixelData.pixels = data;
466 0 : data += size;
467 0 : LBASSERT( size == pixelData.pvp.getArea()*pixelData.pixelSize );
468 : }
469 :
470 0 : image->setZoom( zoom );
471 0 : image->setContext( context );
472 0 : image->setQuality( buffer, header->quality );
473 0 : image->setPixelData( buffer, pixelData );
474 : }
475 : }
476 :
477 0 : _impl->pendingImages.push_back( image );
478 0 : return true;
479 : }
480 :
481 0 : std::ostream& operator << ( std::ostream& os, const FrameData& data )
482 : {
483 0 : return os << "frame data id " << data.getID() << "." << data.getInstanceID()
484 0 : << " v" << data.getVersion() << ' ' << data.getImages().size()
485 0 : << " images, ready " << ( data.isReady() ? 'y' :'n' ) << " "
486 0 : << data.getZoom();
487 : }
488 :
489 42 : }
|