compressorRLE4BU.cpp

00001 
00002 /* Copyright (c) 2009, Stefan Eilemann <eile@equalizergraphics.com>
00003  *               2009, Makhinya Maxim
00004  *
00005  * This library is free software; you can redistribute it and/or modify it under
00006  * the terms of the GNU Lesser General Public License version 2.1 as published
00007  * by the Free Software Foundation.
00008  *  
00009  * This library is distributed in the hope that it will be useful, but WITHOUT
00010  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00011  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00012  * details.
00013  * 
00014  * You should have received a copy of the GNU Lesser General Public License
00015  * along with this library; if not, write to the Free Software Foundation, Inc.,
00016  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00017  */
00018  
00019 #include "compressorRLE4BU.h"
00020 
00021 namespace
00022 {
00023  // just a random number
00024 static const uint64_t _rleMarker = 0xE3A49A3D0254B9C1ull;
00025 }
00026 
00027 #include "compressorRLE.ipp"
00028 
00029 namespace eq
00030 {
00031 namespace plugin
00032 {
00033 
00034 #define WRITE_SINGLE_OUTPUT                                             \
00035     {                                                                   \
00036         if( lastSymbol == _rleMarker )                                  \
00037         {                                                               \
00038             out[ outPos++ ] = _rleMarker;                               \
00039             out[ outPos++ ] = lastSymbol;                               \
00040             out[ outPos++ ] = nSame;                                    \
00041         }                                                               \
00042         else                                                            \
00043             switch( nSame )                                             \
00044             {                                                           \
00045                 case 0:                                                 \
00046                     EQASSERTINFO( false, "Unreachable code");           \
00047                     break;                                              \
00048                 case 3:                                                 \
00049                     out[ outPos++ ] = lastSymbol; /* fall through */    \
00050                 case 2:                                                 \
00051                     out[ outPos++ ] = lastSymbol; /* fall through */    \
00052                 case 1:                                                 \
00053                     out[ outPos++ ] = lastSymbol;                       \
00054                     break;                                              \
00055                 default:                                                \
00056                     out[ outPos++ ] = _rleMarker;                       \
00057                     out[ outPos++ ] = lastSymbol;                       \
00058                     out[ outPos++ ] = nSame;                            \
00059                     break;                                              \
00060             }                                                           \
00061         EQASSERTINFO( nWords<<1 >= outPos,                              \
00062                       "Overwrite array bounds during image compress" ); \
00063     }
00064 
00065 
00066 static uint64_t _compress( const uint64_t* data, const uint64_t nWords, 
00067                                  uint64_t* out )
00068 {
00069     out[ 0 ] = nWords;
00070 
00071     uint64_t outPos     = 1;
00072     uint64_t nSame      = 1;
00073     uint64_t lastSymbol = data[0];
00074 
00075     for( uint64_t i=1; i<nWords; ++i )
00076     {
00077         const uint64_t symbol = data[i];
00078 
00079         if( symbol == lastSymbol )
00080             ++nSame;
00081         else
00082         {
00083             WRITE_SINGLE_OUTPUT;
00084             lastSymbol = symbol;
00085             nSame      = 1;
00086         }
00087     }
00088 
00089     WRITE_SINGLE_OUTPUT;
00090     return (outPos<<3);
00091 }
00092 
00093 void CompressorRLE4BU::compress( const void* const inData,
00094                                   const eq_uint64_t nPixels,
00095                                   const bool        useAlpha )
00096 {
00097     const uint64_t size = nPixels * sizeof( uint32_t );
00098     EQASSERT( size > 0 );
00099 
00100     _setupResults( 1, size, _results );
00101 
00102     const uint64_t nElems  = (size%8) ? (size>>3)+1 : (size>>3);
00103     const ssize_t nResults = _results.size();
00104 
00105 
00106     const float width = static_cast< float >( nElems ) /
00107                         static_cast< float >( nResults );
00108 
00109     const uint64_t* const data =
00110         reinterpret_cast< const uint64_t* >( inData );
00111 
00112 #ifdef EQ_USE_OPENMP
00113 #pragma omp parallel for
00114 #endif
00115     for( ssize_t i = 0; i < nResults; ++i )
00116     {
00117         const uint64_t startIndex = static_cast< uint64_t >( i * width );
00118         const uint64_t endIndex   = static_cast< uint64_t >( (i+1) * width );
00119         uint64_t*      out        = reinterpret_cast< uint64_t* >(
00120                                                      _results[i]->getData( ));
00121 
00122         const uint64_t cSize = _compress( &data[ startIndex ],
00123                                           endIndex-startIndex, out );
00124         _results[i]->setSize( cSize );
00125     }
00126 }
00127 
00128 
00129 void CompressorRLE4BU::decompress( const void* const* inData, 
00130                                    const eq_uint64_t* const inSizes,
00131                                    const unsigned nInputs, void* const outData, 
00132                                    const eq_uint64_t nPixels, 
00133                                    const bool useAlpha )
00134 {
00135 
00136     if( nPixels == 0 )
00137         return;
00138 
00139     // Prepare table with input pointer into decompressed data
00140     //   Needed since decompress loop is parallelized
00141     uint64_t**    outTable = static_cast< uint64_t** >(
00142         alloca( nInputs * sizeof( uint64_t* )));
00143 
00144     {
00145         uint8_t* out = reinterpret_cast< uint8_t* >( outData );
00146         for( unsigned i = 0; i < nInputs; ++i )
00147         {
00148             outTable[i] = reinterpret_cast< uint64_t* >( out );
00149 
00150             const uint64_t* in  = 
00151                 reinterpret_cast< const uint64_t* >( inData[i] );
00152             const uint64_t nWords = in[0];
00153             out += nWords * sizeof( uint64_t );
00154         }
00155 
00156         EQASSERTINFO(
00157             nPixels*4 >= (uint64_t)(out-reinterpret_cast<uint8_t*>(outData)-7),
00158                 "Pixel data size does not match expected image size: "
00159                 << nPixels*4 << " ? " 
00160                 << (uint64_t)(out-reinterpret_cast<uint8_t*>(outData)-7));
00161     }
00162 
00163     // decompress each block
00164     // On OS X the loop is sometimes slower when parallelized. Investigate this!
00165 #ifdef EQ_USE_OPENMP
00166 #pragma omp parallel for
00167 #endif
00168     for( ssize_t i = 0; i < static_cast< ssize_t >( nInputs ); ++i )
00169     {
00170         const uint64_t* in  = reinterpret_cast< const uint64_t* >( inData[i] );
00171               uint64_t* out = outTable[i];
00172 
00173         uint64_t       outPos = 0;
00174         const uint64_t endPos = in[0];
00175         uint64_t       inPos  = 1;
00176 
00177         while( outPos < endPos )
00178         {
00179             const uint64_t token = in[inPos++];
00180             if( token == _rleMarker )
00181             {
00182                 const uint64_t symbol = in[inPos++];
00183                 const uint64_t nSame  = in[inPos++];
00184                 EQASSERT( outPos + nSame <= endPos );
00185 
00186                 for( uint32_t j = 0; j<nSame; ++j )
00187                     out[outPos++] = symbol;
00188             }
00189             else // symbol
00190                 out[outPos++] = token;
00191 
00192             EQASSERTINFO( ((outPos-1) << 3) <= nPixels*4,
00193                           "Overwrite array bounds during decompress" );
00194         }
00195         EQASSERT( outPos == endPos );
00196     }
00197 }
00198 
00199 }
00200 }
Generated on Mon Aug 10 18:58:32 2009 for Equalizer 0.9 by  doxygen 1.5.8