diff options
author | Merov Linden <merov@lindenlab.com> | 2012-04-05 22:05:00 -0700 |
---|---|---|
committer | Merov Linden <merov@lindenlab.com> | 2012-04-05 22:05:00 -0700 |
commit | 91094d92a75b3900be15bfb8be4b9f7cc072487b (patch) | |
tree | b04053971c6f6efdb2e69409887579fc92b0b01d /indra | |
parent | 782981866a70f4a33a298c93ee80aaf138fdf459 (diff) |
SH-3060 : Implement new byte range computation, cleaned up use of compression rate as well.
Diffstat (limited to 'indra')
-rw-r--r-- | indra/llimage/llimage.cpp | 3 | ||||
-rw-r--r-- | indra/llimage/llimage.h | 4 | ||||
-rw-r--r-- | indra/llimage/llimagej2c.cpp | 55 | ||||
-rw-r--r-- | indra/llimage/llimagej2c.h | 7 | ||||
-rw-r--r-- | indra/llkdu/llimagej2ckdu.cpp | 44 | ||||
-rw-r--r-- | indra/llkdu/llimagej2ckdu.h | 1 | ||||
-rw-r--r-- | indra/newview/lltexlayer.cpp | 1 | ||||
-rw-r--r-- | indra/newview/llviewertexturelist.cpp | 1 |
8 files changed, 46 insertions, 70 deletions
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index cce03ff6e6..7f95441075 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1337,8 +1337,7 @@ LLImageFormatted::LLImageFormatted(S8 codec) mDecoding(0), mDecoded(0), mDiscardLevel(-1), - mLevels(0), - mLayers(0) + mLevels(0) { mMemType = LLMemType::MTYPE_IMAGEFORMATTED; } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index c5a7d6262e..a643e4d9f5 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -62,6 +62,7 @@ const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS; //2048 * // *TODO: change both to 1024 when SIM texture fetching is deprecated const S32 FIRST_PACKET_SIZE = 600; const S32 MAX_IMG_PACKET_SIZE = 1000; +const S32 HTTP_PACKET_SIZE = 1496; // Base classes for images. // There are two major parts for the image: @@ -320,8 +321,6 @@ public: S8 getDiscardLevel() const { return mDiscardLevel; } S8 getLevels() const { return mLevels; } void setLevels(S8 nlevels) { mLevels = nlevels; } - S32 getLayers() const { return mLayers; } - void setLayers(S32 nlayers) { mLayers = nlayers; } // setLastError needs to be deferred for J2C images since it may be called from a DLL virtual void resetLastError(); @@ -336,7 +335,6 @@ protected: S8 mDecoded; // unused, but changing LLImage layout requires recompiling static Mac/Linux libs. 2009-01-30 JC S8 mDiscardLevel; // Current resolution level worked on. 0 = full res, 1 = half res, 2 = quarter res, etc... S8 mLevels; // Number of resolution levels in that image. Min is 1. 0 means unknown. - S32 mLayers; // Number of quality layers in that image. Min is 1. 0 means unknown. public: static S32 sGlobalFormattedMemory; diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index dc5bd8b5d5..7894de0de5 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -56,10 +56,9 @@ std::string LLImageJ2C::getEngineInfo() LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), mMaxBytes(0), mRawDiscardLevel(-1), - mRate(0.0f), + mRate(DEFAULT_COMPRESSION_RATE), mReversible(FALSE), - mAreaUsedForDataSizeCalcs(0), - mLayersUsedForDataSizeCalcs(0) + mAreaUsedForDataSizeCalcs(0) { mImpl = fallbackCreateLLImageJ2CImpl(); @@ -257,33 +256,40 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, //static S32 LLImageJ2C::calcHeaderSizeJ2C() { - return FIRST_PACKET_SIZE; // Hack. just needs to be >= actual header size... + return HTTP_PACKET_SIZE; // Hack. just needs to be >= actual header size... } //static -S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, S32 nb_layers, F32 rate) +S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) { - // Note: This provides an estimation for the first quality layer of a given discard level + // Note: This provides an estimation for the first to last quality layer of a given discard level // This is however an efficient approximation, as the true discard level boundary would be // in general too big for fast fetching. // For details about the equation used here, see https://wiki.lindenlab.com/wiki/THX1138_KDU_Improvements#Byte_Range_Study - if (rate <= 0.f) rate = 1.f/8.f; - // Compute w/pow(2,discard_level) and h/pow(2,discard_level) - while (discard_level > 0) + + // Estimate the number of layers. This is consistent with what's done in j2c encoding + S32 nb_layers = 1; + S32 surface = w*h; + S32 s = 64*64; + while (surface > s) { - if (w < 1 || h < 1) - break; - w >>= 1; - h >>= 1; - discard_level--; + nb_layers++; + s *= 4; } + F32 layer_factor = 3.0f * (7 - llclamp(nb_layers,1,6)); + + // Compute w/pow(2,discard_level) and h/pow(2,discard_level) + w >>= discard_level; + h >>= discard_level; + w = llmax(w, 1); + h = llmax(h, 1); + // Temporary: compute both new and old range and pick one according to the settings TextureNewByteRange // *TODO: Take the old code out once we have enough tests done S32 bytes; - F32 layer_factor = ((nb_layers > 0) && (nb_layers < 7) ? 3.0f * (7 - nb_layers): 3.0f); S32 new_bytes = sqrt((F32)(w*h))*(F32)(comp)*rate*1000.f/layer_factor; S32 old_bytes = (S32)((F32)(w*h*comp)*rate); - llinfos << "Merov debug : calcDataSizeJ2C, layers = " << nb_layers << ", old = " << old_bytes << ", new = " << new_bytes << llendl; + //llinfos << "Merov debug : w = " << w << ", h = " << h << ", c = " << comp << ", r = " << rate << ", d = " << discard_level << ", l = " << nb_layers << ", old = " << old_bytes << ", new = " << new_bytes << llendl; bytes = (LLImage::useNewByteRange() ? new_bytes : old_bytes); bytes = llmax(bytes, calcHeaderSizeJ2C()); return bytes; @@ -298,26 +304,22 @@ S32 LLImageJ2C::calcHeaderSize() S32 LLImageJ2C::calcDataSize(S32 discard_level) { discard_level = llclamp(discard_level, 0, MAX_DISCARD_LEVEL); - + return calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), discard_level, mRate); + /* if ( mAreaUsedForDataSizeCalcs != (getHeight() * getWidth()) - || (mLayersUsedForDataSizeCalcs != getLayers()) || (mDataSizes[0] == 0)) { - if (mLayersUsedForDataSizeCalcs != getLayers()) - { - llinfos << "Merov debug : recomputing data size because " << mLayersUsedForDataSizeCalcs << " != " << getLayers() << llendl; - } mAreaUsedForDataSizeCalcs = getHeight() * getWidth(); - mLayersUsedForDataSizeCalcs = getLayers(); S32 level = MAX_DISCARD_LEVEL; // Start at the highest discard while ( level >= 0 ) { - mDataSizes[level] = calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, getLayers(), mRate); + mDataSizes[level] = calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate); level--; } } return mDataSizes[discard_level]; + */ } S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes) @@ -344,11 +346,6 @@ S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes) return discard_level; } -void LLImageJ2C::setRate(F32 rate) -{ - mRate = rate; -} - void LLImageJ2C::setMaxBytes(S32 max_bytes) { mMaxBytes = max_bytes; diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index 28e3026aac..91c344d12f 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -31,6 +31,9 @@ #include "llassettype.h" #include "llmetricperformancetester.h" +// JPEG2000 : compression rate used in j2c conversion. +const F32 DEFAULT_COMPRESSION_RATE = 1.f/8.f; + class LLImageJ2CImpl; class LLImageCompressionTester ; @@ -67,12 +70,11 @@ public: // Encode accessors void setReversible(const BOOL reversible); // Use non-lossy? - void setRate(F32 rate); void setMaxBytes(S32 max_bytes); S32 getMaxBytes() const { return mMaxBytes; } static S32 calcHeaderSizeJ2C(); - static S32 calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, S32 nb_layers = 0, F32 rate = 0.f); + static S32 calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate = DEFAULT_COMPRESSION_RATE); static std::string getEngineInfo(); @@ -88,7 +90,6 @@ protected: S32 mDataSizes[MAX_DISCARD_LEVEL+1]; // Size of data required to reach a given level U32 mAreaUsedForDataSizeCalcs; // Height * width used to calculate mDataSizes - S32 mLayersUsedForDataSizeCalcs; // Numbers of layers used to calculate mDataSizes S8 mRawDiscardLevel; F32 mRate; diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index 08d840917d..31db9d48e3 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -195,8 +195,7 @@ mRawImagep(NULL), mDecodeState(NULL), mBlocksSize(-1), mPrecinctsSize(-1), -mLevels(0), -mLayers(0) +mLevels(0) { } @@ -472,13 +471,6 @@ BOOL LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco { kdu_tile tile = mCodeStreamp->open_tile(*(mTPosp)+mTileIndicesp->pos); - int layers = mCodeStreamp->get_max_tile_layers(); - if (layers > mLayers) - { - mLayers = layers; - base.setLayers(mLayers); - } - // Find the region of the buffer occupied by this // tile. Note that we have no control over // sub-sampling factors which might have been used @@ -608,21 +600,14 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co } // Set codestream options - mLayers = 0; + int nb_layers = 0; kdu_long layer_bytes[MAX_NB_LAYERS]; U32 max_bytes = (U32)(base.getWidth() * base.getHeight() * base.getComponents()); - // Rate is the argument passed into the LLImageJ2C which - // specifies the target compression rate. The default is 8:1. - // *TODO: mRate is actually always 8:1 in the viewer. Test different values. Also force to reversible for small (< 500 bytes) textures. - if (base.mRate != 0.f) - { - max_bytes = (U32)((F32)(max_bytes) * base.mRate); - } - else - { - max_bytes = (U32)((F32)(max_bytes) / 8.0f); - } + // Rate is the argument passed into the LLImageJ2C which specifies the target compression rate. The default is 8:1. + // *TODO: mRate is actually always 8:1 in the viewer. Test different values. + llassert (base.mRate > 0.f); + max_bytes = (U32)((F32)(max_bytes) * base.mRate); // If the image is very small, code it in a lossless way. // Note: it'll also have only 1 layer which is fine as there's no point reordering blocks in that case. @@ -635,15 +620,15 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co // We're using a logarithmic spacing rule that fits with our way of fetching texture data. // Note: For more info on this layers business, read kdu_codestream::flush() doc in kdu_compressed.h U32 i = FIRST_PACKET_SIZE; - while ((i < max_bytes) && (mLayers < (MAX_NB_LAYERS-1))) + while ((i < max_bytes) && (nb_layers < (MAX_NB_LAYERS-1))) { if (i == FIRST_PACKET_SIZE * 4) { // That really just means that the first layer is FIRST_PACKET_SIZE and the second is MIN_LAYER_SIZE i = MIN_LAYER_SIZE; } - layer_bytes[mLayers] = i; - mLayers++; + layer_bytes[nb_layers] = i; + nb_layers++; i *= 4; } @@ -656,18 +641,17 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co //codestream.access_siz()->parse_string("Cycc=no"); // In the reversible case, set the last entry of that table to 0 so that all generated bits will // indeed be output by the time the last quality layer is encountered. - layer_bytes[mLayers] = 0; + layer_bytes[nb_layers] = 0; } else { // Truncate the last quality layer if necessary so to fit the set compression ratio - layer_bytes[mLayers] = max_bytes; + layer_bytes[nb_layers] = max_bytes; } - mLayers++; + nb_layers++; - std::string layer_string = llformat("Clayers=%d",mLayers); + std::string layer_string = llformat("Clayers=%d",nb_layers); codestream.access_siz()->parse_string(layer_string.c_str()); - base.setLayers(mLayers); // Set up data ordering, markers, etc... if precincts or blocks specified // Note: This code is *not* used in the encoding made by the viewer. It is currently used only @@ -720,7 +704,7 @@ BOOL LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co } // Produce the compressed output - codestream.flush(layer_bytes,mLayers); + codestream.flush(layer_bytes,nb_layers); // Cleanup delete tile; diff --git a/indra/llkdu/llimagej2ckdu.h b/indra/llkdu/llimagej2ckdu.h index fab97326d4..9ab0b9e4a7 100644 --- a/indra/llkdu/llimagej2ckdu.h +++ b/indra/llkdu/llimagej2ckdu.h @@ -75,7 +75,6 @@ private: int mBlocksSize; int mPrecinctsSize; int mLevels; - int mLayers; // Temporary variables for in-progress decodes... LLImageRaw *mRawImagep; diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp index 1693cfc9e2..467115c928 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -497,7 +497,6 @@ void LLTexLayerSetBuffer::doUpload() } LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C; - compressedImage->setRate(0.f); const char* comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // writes into baked_color_data. 5 channels (rgb, heightfield/alpha, mask) if (compressedImage->encode(baked_image, comment_text)) { diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 089f45ca89..54ae519422 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1030,7 +1030,6 @@ LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImage { raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C(); - compressedImage->setRate(0.f); if (gSavedSettings.getBOOL("LosslessJ2CUpload") && (raw_image->getWidth() * raw_image->getHeight() <= LL_IMAGE_REZ_LOSSLESS_CUTOFF * LL_IMAGE_REZ_LOSSLESS_CUTOFF)) |