00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "image.h"
00019
00020 #include "compressor.h"
00021 #include "frame.h"
00022 #include "frameBufferObject.h"
00023 #include "frameData.h"
00024 #include "global.h"
00025 #include "pixel.h"
00026 #include "pluginRegistry.h"
00027 #include "log.h"
00028 #include "windowSystem.h"
00029
00030 #include <eq/base/memoryMap.h>
00031 #include <eq/base/omp.h>
00032 #include <eq/net/node.h>
00033
00034 #include <fstream>
00035
00036 #ifdef WIN32
00037 # include <malloc.h>
00038 # define bzero( ptr, size ) memset( ptr, 0, size );
00039 #else
00040 # include <alloca.h>
00041 #endif
00042
00043
00044 using namespace std;
00045
00046 namespace eq
00047 {
00048
00049
00050 Image::Image()
00051 : _glObjects( 0 )
00052 , _type( Frame::TYPE_MEMORY )
00053 {
00054 reset();
00055 }
00056
00057 Image::~Image()
00058 {
00059 }
00060
00061 void Image::reset()
00062 {
00063 _usePBO = false;
00064 _ignoreAlpha = false;
00065 setPixelViewport( PixelViewport( ));
00066 }
00067
00068 void Image::flush()
00069 {
00070 _color.memory.flush();
00071 _depth.memory.flush();
00072 _color.texture.flush();
00073 _depth.texture.flush();
00074 }
00075
00076 uint32_t Image::getDepth( const Frame::Buffer buffer ) const
00077 {
00078 return getNumChannels( buffer ) * getChannelSize( buffer );
00079 }
00080
00081 uint8_t Image::getNumChannels( const Frame::Buffer buffer ) const
00082 {
00083 switch( getFormat( buffer ) )
00084 {
00085 case GL_RGBA:
00086 case GL_RGBA8:
00087 case GL_BGRA:
00088 return 4;
00089
00090 case GL_RGB:
00091 case GL_BGR:
00092 return 3;
00093
00094 case GL_DEPTH_COMPONENT:
00095 case GL_DEPTH_STENCIL_NV:
00096 return 1;
00097
00098 default :
00099 EQWARN << "Unknown number of components for format "
00100 << getFormat( buffer ) << " of buffer " << buffer << endl;
00101 EQUNIMPLEMENTED;
00102 }
00103 return 0;
00104 }
00105
00106 uint8_t Image::getChannelSize( const Frame::Buffer buffer ) const
00107 {
00108 switch( getType( buffer ))
00109 {
00110 case GL_UNSIGNED_BYTE:
00111 case GL_UNSIGNED_INT_8_8_8_8_REV:
00112 return 1;
00113
00114 case GL_HALF_FLOAT:
00115 return 2;
00116
00117 case GL_FLOAT:
00118 case GL_UNSIGNED_INT:
00119 case GL_UNSIGNED_INT_24_8_NV:
00120 return 4;
00121
00122 default :
00123 EQUNIMPLEMENTED;
00124 }
00125 return 0;
00126 }
00127
00128 uint32_t Image::getInternalTextureFormat( const Frame::Buffer which ) const
00129 {
00130 switch( getFormat( which ))
00131 {
00132 case GL_RGBA:
00133 case GL_RGBA8:
00134 case GL_BGRA:
00135 return GL_RGBA;
00136
00137 case GL_RGB:
00138 case GL_BGR:
00139 return GL_RGB;
00140
00141 case GL_DEPTH_STENCIL_NV:
00142 case GL_DEPTH_COMPONENT:
00143 return GL_DEPTH_COMPONENT;
00144
00145 default :
00146 EQWARN << "Unknown format " << getFormat( which ) << " of buffer "
00147 << which << endl;
00148 EQUNIMPLEMENTED;
00149 return GL_RGBA;
00150 }
00151 }
00152
00153 void Image::setFormat( const Frame::Buffer buffer, const uint32_t format )
00154 {
00155 Memory& memory = _getAttachment( buffer ).memory;
00156 if( memory.format == format )
00157 return;
00158
00159 memory.format = format;
00160 memory.state = Memory::INVALID;
00161 allocCompressor( buffer, 0 );
00162
00163 _getAttachment( buffer ).texture.setFormat( format );
00164 }
00165
00166 void Image::setType( const Frame::Buffer buffer, const uint32_t type )
00167 {
00168 Memory& memory = _getAttachment( buffer ).memory;
00169 if( memory.type == type )
00170 return;
00171
00172 memory.type = type;
00173 memory.state = Memory::INVALID;
00174 allocCompressor( buffer, 0 );
00175 }
00176
00177 uint32_t Image::getFormat( const Frame::Buffer buffer ) const
00178 {
00179 const Memory& memory = _getAttachment( buffer ).memory;
00180 EQASSERT( memory.format );
00181 return memory.format;
00182 }
00183
00184 uint32_t Image::getType( const Frame::Buffer buffer ) const
00185 {
00186 const Memory& memory = _getAttachment( buffer ).memory;
00187 EQASSERT( memory.type );
00188 return memory.type;
00189 }
00190
00191 uint32_t Image::_getCompressorTokenType( const Frame::Buffer buffer ) const
00192 {
00193 switch( getNumChannels( buffer ))
00194 {
00195 case 4:
00196 switch( getType( buffer ))
00197 {
00198 case GL_UNSIGNED_BYTE:
00199 return EQ_COMPRESSOR_DATATYPE_4_BYTE;
00200 case GL_HALF_FLOAT:
00201 return EQ_COMPRESSOR_DATATYPE_4_HALF_FLOAT;
00202 case GL_FLOAT:
00203 return EQ_COMPRESSOR_DATATYPE_4_FLOAT;
00204 default:
00205 EQUNIMPLEMENTED;
00206 }
00207
00208 case 3:
00209 switch( getType( buffer ))
00210 {
00211 case GL_UNSIGNED_BYTE:
00212 return EQ_COMPRESSOR_DATATYPE_3_BYTE;
00213 case GL_HALF_FLOAT:
00214 return EQ_COMPRESSOR_DATATYPE_3_HALF_FLOAT;
00215 case GL_FLOAT:
00216 return EQ_COMPRESSOR_DATATYPE_3_FLOAT;
00217 default:
00218 EQUNIMPLEMENTED;
00219 }
00220
00221 case 1:
00222 switch( getType( buffer ))
00223 {
00224 case GL_FLOAT:
00225 return EQ_COMPRESSOR_DATATYPE_FLOAT;
00226 case GL_UNSIGNED_INT:
00227 EQASSERT( buffer == Frame::BUFFER_DEPTH );
00228 return EQ_COMPRESSOR_DATATYPE_UNSIGNED;
00229 default:
00230 EQUNIMPLEMENTED;
00231 }
00232
00233 default:
00234 EQUNIMPLEMENTED;
00235 };
00236
00237 return 0;
00238 }
00239
00240 bool Image::_canIgnoreAlpha( const Frame::Buffer buffer ) const
00241 {
00242 return ( buffer == Frame::BUFFER_COLOR && _ignoreAlpha &&
00243 getNumChannels( Frame::BUFFER_COLOR ) == 4 );
00244 }
00245
00246 std::vector< uint32_t > Image::findCompressors( const Frame::Buffer buffer )
00247 const
00248 {
00249 const uint32_t tokenType = _getCompressorTokenType( buffer );
00250 EQINFO << "Searching compressors for token type " << tokenType << std::endl;
00251
00252 const PluginRegistry& registry = Global::getPluginRegistry();
00253 const CompressorVector& compressors = registry.getCompressors();
00254 std::vector< uint32_t > names;
00255
00256 for( CompressorVector::const_iterator i = compressors.begin();
00257 i != compressors.end(); ++i )
00258 {
00259 const Compressor* compressor = *i;
00260 EQINFO << "Searching in DSO " << (void*)compressor << std::endl;
00261
00262 const CompressorInfoVector& infos = compressor->getInfos();
00263
00264 for( CompressorInfoVector::const_iterator j = infos.begin();
00265 j != infos.end(); ++j )
00266 {
00267 const EqCompressorInfo& info = *j;
00268 if( info.tokenType == tokenType )
00269 names.push_back( info.name );
00270 }
00271 }
00272
00273 return names;
00274 }
00275
00276 uint32_t Image::_getCompressorName( const Frame::Buffer buffer ) const
00277 {
00278 const uint32_t tokenType = _getCompressorTokenType( buffer );
00279 uint32_t name = EQ_COMPRESSOR_NONE;
00280 float ratio = 1.0f;
00281
00282 EQINFO << "Searching compressor for token type " << tokenType << std::endl;
00283
00284 const PluginRegistry& registry = Global::getPluginRegistry();
00285 const CompressorVector& compressors = registry.getCompressors();
00286 for( CompressorVector::const_iterator i = compressors.begin();
00287 i != compressors.end(); ++i )
00288 {
00289 const Compressor* compressor = *i;
00290 const CompressorInfoVector& infos = compressor->getInfos();
00291
00292 EQINFO << "Searching in DSO " << (void*)compressor << std::endl;
00293
00294 for( CompressorInfoVector::const_iterator j = infos.begin();
00295 j != infos.end(); ++j )
00296 {
00297 const EqCompressorInfo& info = *j;
00298 if( info.tokenType != tokenType )
00299 continue;
00300
00301 float infoRatio = info.ratio;
00302 if( _canIgnoreAlpha( buffer ) &&
00303 ( info.capabilities & EQ_COMPRESSOR_IGNORE_MSE ))
00304 {
00305 infoRatio *= .75f;
00306 }
00307
00308 if( ratio > infoRatio )
00309 {
00310 name = info.name;
00311 ratio = infoRatio;
00312 }
00313 }
00314 }
00315
00316 EQINFO << "Selected compressor " << name << std::endl;
00317 return name;
00318 }
00319
00320 bool Image::hasAlpha() const
00321 {
00322 switch( getFormat( Frame::BUFFER_COLOR ))
00323 {
00324 case GL_RGBA16F:
00325 case GL_RGBA32F:
00326 case GL_RGBA:
00327 case GL_RGBA8:
00328 case GL_BGRA:
00329 return true;
00330
00331 default:
00332 return false;
00333 }
00334 }
00335
00336 bool Image::hasData( const Frame::Buffer buffer ) const
00337 {
00338 if( _type == Frame::TYPE_MEMORY )
00339 return hasPixelData( buffer );
00340
00341 EQASSERT( _type == Frame::TYPE_TEXTURE );
00342 return hasTextureData( buffer );
00343 }
00344
00345 void Image::enableAlphaUsage()
00346 {
00347 if( !_ignoreAlpha )
00348 return;
00349
00350 _ignoreAlpha = false;
00351 _color.memory.isCompressed = false;
00352 _depth.memory.isCompressed = false;
00353 }
00354
00355 void Image::disableAlphaUsage()
00356 {
00357 if( _ignoreAlpha )
00358 return;
00359
00360 _ignoreAlpha = true;
00361 _color.memory.isCompressed = false;
00362 _depth.memory.isCompressed = false;
00363 }
00364
00365 bool Image::hasTextureData( const Frame::Buffer buffer ) const
00366 {
00367 return getTexture( buffer ).isValid();
00368 }
00369
00370 const Texture& Image::getTexture( const Frame::Buffer buffer ) const
00371 {
00372 return _getAttachment( buffer ).texture;
00373 }
00374
00375 const uint8_t* Image::getPixelPointer( const Frame::Buffer buffer ) const
00376 {
00377 EQASSERT( hasPixelData( buffer ));
00378 return _getAttachment( buffer ).memory.pixels.getData();
00379 }
00380
00381 uint8_t* Image::getPixelPointer( const Frame::Buffer buffer )
00382 {
00383 EQASSERT( hasPixelData( buffer ));
00384 return _getAttachment( buffer ).memory.pixels.getData();
00385 }
00386
00387 const Image::PixelData& Image::getPixelData( const Frame::Buffer buffer ) const
00388 {
00389 EQASSERT(hasPixelData(buffer));
00390 return _getAttachment( buffer ).memory;
00391 }
00392
00393 void Image::startReadback( const uint32_t buffers, const PixelViewport& pvp,
00394 const Zoom& zoom, Window::ObjectManager* glObjects )
00395 {
00396 EQASSERT( glObjects );
00397 EQASSERTINFO( !_glObjects, "Another readback in progress?" );
00398 EQLOG( LOG_ASSEMBLY ) << "startReadback " << pvp << ", buffers " << buffers
00399 << endl;
00400
00401 _glObjects = glObjects;
00402 _pvp = pvp;
00403
00404 _color.memory.state = Memory::INVALID;
00405 _depth.memory.state = Memory::INVALID;
00406
00407 if( buffers & Frame::BUFFER_COLOR )
00408 _startReadback( Frame::BUFFER_COLOR, zoom );
00409
00410 if( buffers & Frame::BUFFER_DEPTH )
00411 _startReadback( Frame::BUFFER_DEPTH, zoom );
00412
00413
00414 _pvp.apply( zoom );
00415 _pvp.x = 0;
00416 _pvp.y = 0;
00417 }
00418
00419 void Image::syncReadback()
00420 {
00421 _syncReadback( Frame::BUFFER_COLOR );
00422 _syncReadback( Frame::BUFFER_DEPTH );
00423 _glObjects = 0;
00424 }
00425
00426 void Image::Memory::resize( const uint32_t size )
00427 {
00428
00429 pixels.reserve( size+32 );
00430 pixels.resize( size );
00431 }
00432
00433 const void* Image::_getBufferKey( const Frame::Buffer buffer ) const
00434 {
00435 switch( buffer )
00436 {
00437 case Frame::BUFFER_COLOR:
00438 return ( reinterpret_cast< const char* >( this ) + 0 );
00439 case Frame::BUFFER_DEPTH:
00440 return ( reinterpret_cast< const char* >( this ) + 1 );
00441 default:
00442 EQUNIMPLEMENTED;
00443 return ( reinterpret_cast< const char* >( this ) + 2 );
00444 }
00445 }
00446
00447 void Image::_startReadback( const Frame::Buffer buffer, const Zoom& zoom )
00448 {
00449 Attachment& attachment = _getAttachment( buffer );
00450 attachment.memory.isCompressed = false;
00451
00452 if ( _type == Frame::TYPE_TEXTURE )
00453 {
00454 EQASSERTINFO( zoom == Zoom::NONE, "Texture readback zoom not "
00455 << "implemented, zoom happens during compositing" );
00456 Texture& texture = _getAttachment( buffer ).texture;
00457 texture.copyFromFrameBuffer( _pvp );
00458 return;
00459 }
00460
00461 if( _usePBO && _glObjects->supportsBuffers( ))
00462 {
00463 EQASSERTINFO( zoom == Zoom::NONE, "Not Implemented" );
00464 _startReadbackPBO( buffer );
00465 return;
00466 }
00467
00468 if( zoom == Zoom::NONE )
00469 {
00470 Memory& memory = attachment.memory;
00471 const size_t size = getPixelDataSize( buffer );
00472
00473 memory.resize( size );
00474 glReadPixels( _pvp.x, _pvp.y, _pvp.w, _pvp.h, getFormat( buffer ),
00475 getType( buffer ), memory.pixels.getData() );
00476 memory.state = Memory::VALID;
00477 return;
00478 }
00479
00480
00481 _startReadbackZoom( buffer, zoom );
00482 }
00483
00484 void Image::_startReadbackPBO( const Frame::Buffer buffer )
00485 {
00486 Memory& memory = _getAttachment( buffer ).memory;
00487 memory.state = Memory::PBO_READBACK;
00488
00489 const void* bufferKey = _getBufferKey( buffer );
00490 GLuint pbo = _glObjects->obtainBuffer( bufferKey );
00491
00492 EQ_GL_CALL( glBindBuffer( GL_PIXEL_PACK_BUFFER, pbo ));
00493
00494 const size_t size = getPixelDataSize( buffer );
00495 if( memory.pboSize < size )
00496 {
00497 EQ_GL_CALL( glBufferData( GL_PIXEL_PACK_BUFFER, size, 0,
00498 GL_DYNAMIC_READ ));
00499 memory.pboSize = size;
00500 }
00501
00502 EQ_GL_CALL( glReadPixels( _pvp.x, _pvp.y, _pvp.w, _pvp.h,
00503 getFormat( buffer ), getType( buffer ), 0 ));
00504 EQ_GL_CALL( glBindBuffer( GL_PIXEL_PACK_BUFFER, 0 ));
00505 }
00506
00507 void Image::_startReadbackZoom( const Frame::Buffer buffer, const Zoom& zoom )
00508 {
00509 EQASSERT( _glObjects );
00510 EQASSERT( _glObjects->supportsEqTexture( ));
00511 EQASSERT( _glObjects->supportsEqFrameBufferObject( ));
00512
00513 PixelViewport pvp = _pvp;
00514 pvp.apply( zoom );
00515 if( !pvp.hasArea( ))
00516 return;
00517
00518 Memory& memory = _getAttachment( buffer ).memory;
00519 memory.state = Memory::ZOOM_READBACK;
00520
00521
00522 const void* bufferKey = _getBufferKey( buffer );
00523 Texture* texture = _glObjects->obtainEqTexture( bufferKey );
00524
00525 texture->setFormat( getInternalTextureFormat( buffer ));
00526 texture->copyFromFrameBuffer( _pvp );
00527
00528
00529
00530 const void* fboKey = _getBufferKey( Frame::BUFFER_COLOR );
00531 FrameBufferObject* fbo = _glObjects->getEqFrameBufferObject( fboKey );
00532
00533 if( fbo )
00534 {
00535 EQCHECK( fbo->resize( pvp.w, pvp.h ));
00536 }
00537 else
00538 {
00539 fbo = _glObjects->newEqFrameBufferObject( fboKey );
00540 fbo->setColorFormat( getInternalTextureFormat( buffer ) );
00541 fbo->init( pvp.w, pvp.h, 24, 0 );
00542 }
00543 fbo->bind();
00544 texture->bind();
00545
00546 if ( buffer == Frame::BUFFER_COLOR )
00547 glDepthMask( false );
00548 else
00549 {
00550 EQASSERT( buffer == Frame::BUFFER_DEPTH )
00551 glColorMask( false, false, false, false );
00552 }
00553
00554 glDisable( GL_LIGHTING );
00555 glEnable( GL_TEXTURE_RECTANGLE_ARB );
00556 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00557 glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00558 glColor3f( 1.0f, 1.0f, 1.0f );
00559
00560 glBegin( GL_QUADS );
00561 glTexCoord2f( 0.0f, 0.0f );
00562 glVertex3f( 0, 0, 0.0f );
00563
00564 glTexCoord2f( static_cast< float >( _pvp.w ), 0.0f );
00565 glVertex3f( static_cast< float >( pvp.w ), 0, 0.0f );
00566
00567 glTexCoord2f( static_cast< float >( _pvp.w ),
00568 static_cast< float >( _pvp.h ));
00569 glVertex3f( static_cast< float >( pvp.w ),
00570 static_cast< float >( pvp.h ), 0.0f );
00571
00572 glTexCoord2f( 0.0f, static_cast< float >( _pvp.h ));
00573 glVertex3f( 0, static_cast< float >( pvp.h ), 0.0f );
00574 glEnd();
00575
00576
00577 glDisable( GL_TEXTURE_RECTANGLE_ARB );
00578
00579 if ( buffer == Frame::BUFFER_COLOR )
00580 glDepthMask( true );
00581 else
00582 {
00583 const ColorMask colorMask;
00584 glColorMask( colorMask.red, colorMask.green, colorMask.blue, true );
00585 }
00586
00587 fbo->unbind();
00588
00589 EQLOG( LOG_ASSEMBLY ) << "Scale " << _pvp << " -> " << pvp << std::endl;
00590 }
00591
00592 void Image::_syncReadback( const Frame::Buffer buffer )
00593 {
00594 Memory& memory = _getAttachment( buffer ).memory;
00595 switch( memory.state )
00596 {
00597 case Memory::PBO_READBACK:
00598 _syncReadbackPBO( buffer );
00599 break;
00600
00601 case Memory::ZOOM_READBACK:
00602 _syncReadbackZoom( buffer );
00603 break;
00604
00605 default:
00606 break;
00607 }
00608 }
00609
00610 void Image::_syncReadbackPBO( const Frame::Buffer buffer )
00611 {
00612
00613 EQASSERT( _usePBO );
00614 EQASSERT( _glObjects->supportsBuffers( ));
00615 EQ_GL_ERROR( "before Image::_syncReadback" );
00616
00617 const size_t size = getPixelDataSize( buffer );
00618 const void* bufferKey = _getBufferKey( buffer );
00619 GLuint pbo = _glObjects->getBuffer( bufferKey );
00620 EQASSERT( pbo != Window::ObjectManager::INVALID );
00621
00622 Memory& memory = _getAttachment( buffer ).memory;
00623 memory.resize( size );
00624
00625 EQ_GL_CALL( glBindBuffer( GL_PIXEL_PACK_BUFFER, pbo ));
00626 const void* data = glMapBuffer( GL_PIXEL_PACK_BUFFER, GL_READ_ONLY );
00627 EQ_GL_ERROR( "glMapBuffer" );
00628 EQASSERT( data );
00629
00630 memcpy( memory.pixels.getData(), data, size );
00631
00632 glUnmapBuffer( GL_PIXEL_PACK_BUFFER );
00633 glBindBuffer( GL_PIXEL_PACK_BUFFER, 0 );
00634
00635 memory.state = Memory::VALID;
00636 }
00637
00638 void Image::_syncReadbackZoom( const Frame::Buffer buffer )
00639 {
00640 Memory& memory = _getAttachment( buffer ).memory;
00641 const size_t size = getPixelDataSize( buffer );
00642 memory.resize( size );
00643
00644 const void* bufferKey = _getBufferKey( buffer );
00645 FrameBufferObject* fbo = _glObjects->getEqFrameBufferObject( bufferKey );
00646 EQASSERT( fbo != 0 );
00647
00648 switch( buffer )
00649 {
00650 case Frame::BUFFER_COLOR:
00651 fbo->getColorTextures()[0]->download( memory.pixels.getData(),
00652 getFormat( buffer ),
00653 getType( buffer ));
00654 break;
00655
00656 default:
00657 EQUNIMPLEMENTED;
00658 case Frame::BUFFER_DEPTH:
00659 fbo->getDepthTexture().download( memory.pixels.getData(),
00660 getFormat( buffer ),
00661 getType( buffer ));
00662 break;
00663 }
00664
00665 memory.state = Memory::VALID;
00666 EQLOG( LOG_ASSEMBLY ) << "Read texture " << _pvp << std::endl;
00667 }
00668
00669 void Image::setPixelViewport( const PixelViewport& pvp )
00670 {
00671 _pvp = pvp;
00672 _color.memory.state = Memory::INVALID;
00673 _depth.memory.state = Memory::INVALID;
00674 _color.memory.isCompressed = false;
00675 _depth.memory.isCompressed = false;
00676 }
00677
00678 void Image::clearPixelData( const Frame::Buffer buffer )
00679 {
00680 const ssize_t size = getPixelDataSize( buffer );
00681 if( size == 0 )
00682 return;
00683
00684 validatePixelData( buffer );
00685 Memory& memory = _getAttachment( buffer ).memory;
00686
00687 if( buffer == Frame::BUFFER_DEPTH )
00688 {
00689 memset( memory.pixels.getData(), 0xFF, size );
00690 }
00691 else
00692 {
00693 if( getDepth( Frame::BUFFER_COLOR ) == 4 )
00694 {
00695 uint8_t* data = memory.pixels.getData();
00696 #ifdef LEOPARD
00697 const unsigned char pixel[4] = { 0, 0, 0, 255 };
00698 memset_pattern4( data, &pixel, size );
00699 #else
00700 bzero( data, size );
00701
00702 if( getDepth( Frame::BUFFER_COLOR ) == 4 )
00703 #ifdef EQ_USE_OPENMP
00704 #pragma omp parallel for
00705 #endif
00706 for( ssize_t i = 3; i < size; i+=4 )
00707 data[i] = 255;
00708 #endif
00709 }
00710 else
00711 bzero( memory.pixels.getData(), size );
00712 }
00713 }
00714
00715 void Image::validatePixelData( const Frame::Buffer buffer )
00716 {
00717 Memory& memory = _getAttachment( buffer ).memory;
00718 const size_t size = getPixelDataSize( buffer );
00719
00720 memory.resize( size );
00721 memory.state = Memory::VALID;
00722 memory.isCompressed = false;
00723 }
00724
00725 void Image::setPixelData( const Frame::Buffer buffer, const uint8_t* data )
00726 {
00727 const uint32_t size = getPixelDataSize( buffer );
00728 if( size == 0 )
00729 return;
00730
00731 Memory& memory = _getAttachment( buffer ).memory;
00732
00733 memory.resize( size );
00734 memcpy( memory.pixels.getData(), data, size );
00735 memory.state = Memory::VALID;
00736 memory.isCompressed = false;
00737 }
00738
00739 void Image::setPixelData( const Frame::Buffer buffer, const PixelData& pixels )
00740 {
00741 setFormat( buffer, pixels.format );
00742 setType( buffer, pixels.type );
00743
00744 const uint32_t size = getPixelDataSize( buffer );
00745 if( size == 0 )
00746 return;
00747
00748 if( pixels.compressorName <= EQ_COMPRESSOR_NONE )
00749 {
00750 EQASSERT( size == pixels.pixels.getSize() );
00751 setPixelData( buffer, pixels.pixels.getData() );
00752 return;
00753 }
00754
00755 Attachment& attachment = _getAttachment( buffer );
00756 if( !_allocDecompressor( attachment, pixels.compressorName ))
00757 {
00758 EQASSERTINFO( 0,
00759 "Can't allocate decompressor " << pixels.compressorName <<
00760 ", mismatched compressor installation?" );
00761 return;
00762 }
00763
00764 Memory& memory = attachment.memory;
00765
00766 EQASSERT( size > 0 );
00767 memory.resize( size );
00768 memory.isCompressed = false;
00769
00770
00771 const uint64_t nBlocks = pixels.compressedSize.size();
00772 EQASSERT( nBlocks == pixels.compressedData.size( ));
00773
00774 void* outData = reinterpret_cast< uint8_t* >( memory.pixels.getData() );
00775 uint64_t outDim[4] = { _pvp.x, _pvp.w, _pvp.y, _pvp.h };
00776 uint64_t flags = EQ_COMPRESSOR_DATA_2D;
00777 if( _canIgnoreAlpha( buffer ))
00778 flags |= EQ_COMPRESSOR_IGNORE_MSE;
00779
00780 EQASSERT( attachment.compressor.plugin != 0 );
00781 EQASSERT( !attachment.compressor.isCompressor );
00782
00783 attachment.compressor.plugin->decompress( attachment.compressor.instance,
00784 attachment.compressor.name,
00785 &pixels.compressedData.front(),
00786 &pixels.compressedSize.front(),
00787 nBlocks, outData,
00788 outDim, flags );
00789 memory.state = Memory::VALID;
00790 }
00791
00792 Image::Attachment& Image::_getAttachment( const Frame::Buffer buffer )
00793 {
00794 switch( buffer )
00795 {
00796 case Frame::BUFFER_COLOR:
00797 return _color;
00798 case Frame::BUFFER_DEPTH:
00799 return _depth;
00800 default:
00801 EQUNIMPLEMENTED;
00802 }
00803 return _color;
00804 }
00805
00806 const Image::Attachment& Image::_getAttachment( const Frame::Buffer buffer )
00807 const
00808 {
00809 switch( buffer )
00810 {
00811 case Frame::BUFFER_COLOR:
00812 return _color;
00813 case Frame::BUFFER_DEPTH:
00814 return _depth;
00815 default:
00816 EQUNIMPLEMENTED;
00817 }
00818 return _color;
00819 }
00820
00821 Image::Attachment::CompressorData::CompressorData()
00822 : name( 0 )
00823 , instance( 0 )
00824 , plugin( 0 )
00825 , isCompressor( true )
00826 {}
00827
00828 void Image::Attachment::CompressorData::flush()
00829 {
00830 if( !instance )
00831 return;
00832 EQASSERT( plugin );
00833
00834 if( isCompressor )
00835 plugin->deleteCompressor( instance );
00836 else
00837 plugin->deleteDecompressor( instance );
00838
00839 plugin = 0;
00840 instance = 0;
00841 }
00842
00844 bool Image::allocCompressor( const Frame::Buffer buffer, const uint32_t name )
00845 {
00846 Attachment& attachment = _getAttachment( buffer );
00847 if( name <= EQ_COMPRESSOR_NONE )
00848 {
00849 attachment.compressor.flush();
00850 attachment.compressor.name = name;
00851 attachment.compressor.isCompressor = true;
00852 attachment.memory.isCompressed = false;
00853 return true;
00854 }
00855
00856 if( !attachment.compressor.plugin || attachment.compressor.name != name )
00857 {
00858 attachment.compressor.flush();
00859 attachment.compressor.name = name;
00860 attachment.compressor.isCompressor = true;
00861 attachment.memory.isCompressed = false;
00862
00863 #ifndef NDEBUG
00864 const std::vector< uint32_t > names( findCompressors( buffer ));
00865 EQASSERT( std::find( names.begin(), names.end(), name) != names.end( ));
00866 #endif
00867
00868 PluginRegistry& registry = Global::getPluginRegistry();
00869 attachment.compressor.plugin = registry.findCompressor( name );
00870 if( !attachment.compressor.plugin )
00871 return false;
00872
00873 attachment.compressor.instance =
00874 attachment.compressor.plugin->newCompressor( name );
00875 EQASSERT( attachment.compressor.instance );
00876 EQINFO << "Instantiated compressor of type " << name << std::endl;
00877 }
00878 return ( attachment.compressor.instance != 0 );
00879 }
00880
00882 bool Image::_allocDecompressor( Attachment& attachment, uint32_t name )
00883 {
00884 if( !attachment.compressor.plugin || attachment.compressor.name != name )
00885 {
00886 attachment.compressor.flush();
00887 attachment.compressor.name = name;
00888 attachment.compressor.isCompressor = false;
00889
00890 PluginRegistry& registry = Global::getPluginRegistry();
00891 attachment.compressor.plugin = registry.findCompressor( name );
00892 if( !attachment.compressor.plugin )
00893 return false;
00894
00895 attachment.compressor.instance =
00896 attachment.compressor.plugin->newDecompressor( name );
00897 }
00898 return true;
00899 }
00900
00901 void Image::Memory::flush()
00902 {
00903 pboSize = 0;
00904 state = INVALID;
00905 isCompressed = false;
00906 PixelData::flush();
00907 }
00908
00909 Image::PixelData::PixelData()
00910 : format( GL_FALSE )
00911 , type( GL_FALSE )
00912 , compressorName( 0 )
00913 , isCompressed( false )
00914 {}
00915
00916 void Image::PixelData::flush()
00917 {
00918 pixels.clear();
00919 format = GL_FALSE;
00920 type = GL_FALSE;
00921 compressorName = 0;
00922 isCompressed = false;
00923 compressedSize.clear();
00924 compressedData.clear();
00925 }
00926
00927 Image::PixelData::~PixelData()
00928 {
00929 flush();
00930 }
00931
00932 const Image::PixelData& Image::compressPixelData( const Frame::Buffer buffer )
00933 {
00934 EQASSERT( getPixelDataSize( buffer ) > 0 );
00935
00936 Attachment& attachment = _getAttachment( buffer );
00937 Memory& memory = attachment.memory;
00938 if( memory.isCompressed )
00939 return memory;
00940
00941 if( attachment.compressor.name == 0 )
00942 memory.compressorName = _getCompressorName( buffer );
00943 else
00944 memory.compressorName = attachment.compressor.name;
00945
00946 EQASSERT( memory.compressorName != 0 );
00947
00948 if( !allocCompressor( buffer, memory.compressorName ) ||
00949 memory.compressorName == EQ_COMPRESSOR_NONE )
00950 {
00951 EQWARN << "No compressor found for token type "
00952 << _getCompressorTokenType( buffer ) << std::endl;
00953 return memory;
00954 }
00955
00956 const uint64_t inDims[4] = { _pvp.x, _pvp.w, _pvp.y, _pvp.h};
00957
00958 EQASSERT( attachment.compressor.plugin != 0 );
00959 uint64_t flags = EQ_COMPRESSOR_DATA_2D;
00960 if( _canIgnoreAlpha( buffer ))
00961 flags |= EQ_COMPRESSOR_IGNORE_MSE;
00962
00963 attachment.compressor.plugin->compress( attachment.compressor.instance,
00964 attachment.compressor.name,
00965 memory.pixels.getData(),
00966 inDims, flags );
00967
00968 const size_t numResults = attachment.compressor.plugin->getNumResults(
00969 attachment.compressor.instance, attachment.compressor.name );
00970
00971 memory.compressedSize.resize( numResults );
00972 memory.compressedData.resize( numResults );
00973
00974 for( size_t i = 0; i < numResults ; i++ )
00975 {
00976 attachment.compressor.plugin->getResult( attachment.compressor.instance,
00977 attachment.compressor.name,
00978 i,
00979 &memory.compressedData[i],
00980 &memory.compressedSize[i] );
00981 }
00982
00983 memory.isCompressed = true;
00984 return memory;
00985 }
00986
00987
00988
00989
00990
00991
00992 void Image::writeImages( const std::string& filenameTemplate ) const
00993 {
00994 writeImage( filenameTemplate + "_color.rgb", Frame::BUFFER_COLOR );
00995 writeImage( filenameTemplate + "_depth.rgb", Frame::BUFFER_DEPTH );
00996 }
00997
00998 #define SWAP_SHORT(v) ( v = (v&0xff) << 8 | (v&0xff00) >> 8 )
00999 #define SWAP_INT(v) ( v = (v&0xff) << 24 | (v&0xff00) << 8 | \
01000 (v&0xff0000) >> 8 | (v&0xff000000) >> 24)
01001
01002 #ifdef WIN32
01003 # pragma pack(1)
01004 #endif
01005
01006 struct RGBHeader
01007 {
01008 RGBHeader()
01009 {
01010 memset( this, 0, sizeof( RGBHeader ));
01011 magic = 474;
01012 bytesPerChannel = 1;
01013 nDimensions = 3;
01014 maxValue = 255;
01015 }
01016
01021 void convert()
01022 {
01023 #if defined(__i386__) || defined(__amd64__) || defined (__ia64) || \
01024 defined(__x86_64) || defined(WIN32)
01025 SWAP_SHORT(magic);
01026 SWAP_SHORT(nDimensions);
01027 SWAP_SHORT(width);
01028 SWAP_SHORT(height);
01029 SWAP_SHORT(depth);
01030 SWAP_INT(minValue);
01031 SWAP_INT(maxValue);
01032 SWAP_INT(colorMode);
01033 #endif
01034 }
01035
01036 unsigned short magic;
01037 char compression;
01038 char bytesPerChannel;
01039 unsigned short nDimensions;
01040 unsigned short width;
01041 unsigned short height;
01042 unsigned short depth;
01043 unsigned minValue;
01044 unsigned maxValue;
01045 char unused[4];
01046 char filename[80];
01047 unsigned colorMode;
01048 char fill[404];
01049 }
01051 #ifndef WIN32
01052 __attribute__((packed))
01053 #endif
01054 ;
01055
01056 void Image::writeImage( const std::string& filename,
01057 const Frame::Buffer buffer ) const
01058 {
01059 const size_t nPixels = _pvp.w * _pvp.h;
01060 const Memory& memory = _getAttachment( buffer ).memory;
01061
01062 if( nPixels == 0 || memory.state != Memory::VALID )
01063 return;
01064
01065 ofstream image( filename.c_str(), ios::out | ios::binary );
01066 if( !image.is_open( ))
01067 {
01068 EQERROR << "Can't open " << filename << " for writing" << endl;
01069 return;
01070 }
01071
01072 RGBHeader header;
01073
01074 header.width = _pvp.w;
01075 header.height = _pvp.h;
01076
01077 header.bytesPerChannel = getChannelSize( buffer );
01078 header.depth = getNumChannels( buffer );
01079
01080 if( header.depth == 1 )
01081 {
01082 EQASSERT( (header.bytesPerChannel % 4) == 0 );
01083 header.depth = 4;
01084 header.bytesPerChannel /= 4;
01085 }
01086 EQASSERT( header.bytesPerChannel > 0 );
01087 if( header.bytesPerChannel > 2 )
01088 EQWARN << static_cast< int >( header.bytesPerChannel )
01089 << " bytes per channel not supported by RGB spec" << std::endl;
01090
01091 const uint8_t bpc = header.bytesPerChannel;
01092 const uint16_t nChannels = header.depth;
01093
01094 strncpy( header.filename, filename.c_str(), 80 );
01095
01096 header.convert();
01097 image.write( reinterpret_cast<const char *>( &header ), sizeof( header ));
01098
01099
01100 const size_t depth = nChannels * bpc;
01101 const size_t nBytes = nPixels * depth;
01102 const char* data = reinterpret_cast<const char*>( getPixelPointer( buffer));
01103
01104 switch( getFormat( buffer ))
01105 {
01106 case GL_BGR:
01107 for( size_t j = 2 * bpc; j < nBytes; j += depth )
01108 image.write( &data[j], bpc );
01109 for( size_t j = 1 * bpc; j < nBytes; j += depth )
01110 image.write( &data[j], bpc );
01111 for( size_t j = 0; j < nBytes; j += depth )
01112 image.write( &data[j], bpc );
01113 break;
01114
01115 case GL_BGRA:
01116 for( size_t j = 2 * bpc; j < nBytes; j += depth )
01117 image.write( &data[j], bpc );
01118 for( size_t j = 1 * bpc; j < nBytes; j += depth )
01119 image.write( &data[j], bpc );
01120 for( size_t j = 0; j < nBytes; j += depth )
01121 image.write( &data[j], bpc );
01122
01123 for( size_t j = 3 * bpc; j < nBytes; j += depth )
01124 {
01125 if( bpc == 1 )
01126 {
01127 const uint8_t val = 255 -
01128 *reinterpret_cast< const uint8_t* >( &data[j] );
01129 image.write( reinterpret_cast<const char*>( &val ), 1 );
01130 }
01131 else
01132 image.write(&data[j], bpc );
01133 }
01134 break;
01135
01136 default:
01137 for( size_t i = 0; i < nChannels; i += bpc )
01138 for( size_t j = i * bpc; j < nBytes; j += depth )
01139 image.write(&data[j], bpc );
01140 }
01141
01142 image.close();
01143 }
01144
01145 bool Image::readImage( const std::string& filename, const Frame::Buffer buffer )
01146 {
01147 base::MemoryMap image;
01148 const uint8_t* addr = static_cast< const uint8_t* >( image.map( filename ));
01149
01150 if( !addr )
01151 {
01152 EQERROR << "Can't open " << filename << " for reading" << endl;
01153 return false;
01154 }
01155
01156 const size_t size = image.getSize();
01157 if( size < sizeof( RGBHeader ))
01158 {
01159 EQERROR << "Image " << filename << " too small" << endl;
01160 return false;
01161 }
01162
01163 RGBHeader header;
01164 memcpy( &header, addr, sizeof( header ));
01165 addr += sizeof( header );
01166
01167 header.convert();
01168
01169 if( header.magic != 474)
01170 {
01171 EQERROR << "Bad magic number " << filename << endl;
01172 return false;
01173 }
01174 if( header.width == 0 || header.height == 0 )
01175 {
01176 EQERROR << "Zero-sized image " << filename << endl;
01177 return false;
01178 }
01179 if( header.compression != 0)
01180 {
01181 EQERROR << "Unsupported compression " << filename << endl;
01182 return false;
01183 }
01184
01185 const size_t nChannels = header.depth;
01186
01187 if( header.nDimensions != 3 ||
01188 header.minValue != 0 ||
01189 header.maxValue != 255 ||
01190 header.colorMode != 0 ||
01191 ( buffer == Frame::BUFFER_COLOR && nChannels != 3 && nChannels != 4 ) ||
01192 ( buffer == Frame::BUFFER_DEPTH && nChannels != 4 ))
01193 {
01194 EQERROR << "Unsupported image type " << filename << endl;
01195 return false;
01196 }
01197
01198 const uint8_t bpc = header.bytesPerChannel;
01199 const size_t depth = nChannels * bpc;
01200 const size_t nPixels = header.width * header.height;
01201 const size_t nBytes = nPixels * depth;
01202
01203 if( size < sizeof( RGBHeader ) + nBytes )
01204 {
01205 EQERROR << "Image " << filename << " too small" << endl;
01206 return false;
01207 }
01208 EQASSERT( size == sizeof( RGBHeader ) + nBytes );
01209
01210 switch( buffer )
01211 {
01212 case Frame::BUFFER_DEPTH:
01213 if( header.bytesPerChannel != 1 )
01214 {
01215 EQERROR << "Unsupported channel depth "
01216 << static_cast< int >( header.bytesPerChannel ) << endl;
01217 return false;
01218 }
01219
01220 setFormat( Frame::BUFFER_DEPTH, GL_DEPTH_COMPONENT );
01221 setType( Frame::BUFFER_DEPTH, GL_UNSIGNED_INT );
01222 break;
01223
01224 default:
01225 EQUNREACHABLE;
01226 case Frame::BUFFER_COLOR:
01227 setFormat( Frame::BUFFER_COLOR, (nChannels==4) ? GL_RGBA : GL_RGB );
01228 switch( header.bytesPerChannel )
01229 {
01230 case 1:
01231 setType( Frame::BUFFER_COLOR, GL_UNSIGNED_BYTE );
01232 break;
01233 case 2:
01234 setType( Frame::BUFFER_COLOR, GL_HALF_FLOAT );
01235 break;
01236 case 4:
01237 setType( Frame::BUFFER_COLOR, GL_FLOAT );
01238 break;
01239 default:
01240 EQERROR << "Unsupported channel depth "
01241 << static_cast< int >( header.bytesPerChannel )
01242 << std::endl;
01243 return false;
01244 }
01245 break;
01246 }
01247
01248 const PixelViewport pvp( 0, 0, header.width, header.height );
01249 if( pvp != getPixelViewport( ))
01250 setPixelViewport( pvp );
01251
01252 validatePixelData( buffer );
01253
01254 Memory& memory = _getAttachment( buffer ).memory;
01255 uint8_t* data = reinterpret_cast< uint8_t* >( memory.pixels.getData() );
01256 EQASSERTINFO( nBytes <= memory.pixels.getSize(),
01257 nBytes << " > " << memory.pixels.getSize() );
01258
01259
01260 for( size_t i = 0; i < depth; i += bpc )
01261 for( size_t j = i * bpc; j < nBytes; j += depth )
01262 {
01263 EQASSERT( addr + bpc - ( const uint8_t* )( image.getAddress( )) <=
01264 static_cast< ssize_t >( size ));
01265
01266 memcpy( &data[j], addr, bpc );
01267 addr += bpc;
01268 }
01269
01270 return true;
01271 }
01272
01273 std::ostream& operator << ( std::ostream& os, const Image* image )
01274 {
01275 os << "image " << image->_pvp;
01276 return os;
01277 }
01278 }