From bc6f669ff41db304723428746868d79d3f3b48da Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 15 Mar 2012 13:01:14 -0700 Subject: SH-3047 : Read the number of levels from the j2c image header instead of relying on hacked computation based on width / height. --- indra/llimage/llimage.cpp | 3 ++- indra/llimage/llimage.h | 5 ++++- indra/llimage/llimagej2c.cpp | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'indra/llimage') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 56e01ac851..091e78e358 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1334,7 +1334,8 @@ LLImageFormatted::LLImageFormatted(S8 codec) mCodec(codec), mDecoding(0), mDecoded(0), - mDiscardLevel(-1) + mDiscardLevel(-1), + mLevels(0) { mMemType = LLMemType::MTYPE_IMAGEFORMATTED; } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 4469c9e860..847ba8c11c 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -313,6 +313,8 @@ public: BOOL isDecoded() const { return mDecoded ? TRUE : FALSE; } void setDiscardLevel(S8 discard_level) { mDiscardLevel = discard_level; } S8 getDiscardLevel() const { return mDiscardLevel; } + S8 getLevels() const { return mLevels; } + void setLevels(S8 nlevels) { mLevels = nlevels; } // setLastError needs to be deferred for J2C images since it may be called from a DLL virtual void resetLastError(); @@ -325,7 +327,8 @@ protected: S8 mCodec; S8 mDecoding; S8 mDecoded; // unused, but changing LLImage layout requires recompiling static Mac/Linux libs. 2009-01-30 JC - S8 mDiscardLevel; + 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. public: static S32 sGlobalFormattedMemory; diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index cc8cb66d73..fbf4b769e1 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -142,6 +142,7 @@ BOOL LLImageJ2C::updateData() BOOL LLImageJ2C::initDecode(LLImageRaw &raw_image, int discard_level, int* region) { + setDiscardLevel(discard_level != -1 ? discard_level : 0); return mImpl->initDecode(*this,raw_image,discard_level,region); } @@ -286,6 +287,8 @@ S32 LLImageJ2C::calcHeaderSize() // calcDataSize() returns how many bytes to read // to load discard_level (including header and higher discard levels) +// *TODO: This is deeply wrong. That size should be taken from the image file header or other +// relevant infos. In any case, this is only an approximation. S32 LLImageJ2C::calcDataSize(S32 discard_level) { discard_level = llclamp(discard_level, 0, MAX_DISCARD_LEVEL); -- cgit v1.2.3 From fe7a4d0183bfb19784b61124ef4c377c9a5d42d2 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 15 Mar 2012 14:07:54 -0700 Subject: SH-3047 : Add a load_size argument to llimage_libtest and allow partial image file to be loaded. --- indra/llimage/llimage.cpp | 15 ++++++++++----- indra/llimage/llimage.h | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'indra/llimage') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 091e78e358..937655a22d 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1562,7 +1562,7 @@ void LLImageFormatted::appendData(U8 *data, S32 size) //---------------------------------------------------------------------------- -BOOL LLImageFormatted::load(const std::string &filename) +BOOL LLImageFormatted::load(const std::string &filename, int load_size) { resetLastError(); @@ -1581,14 +1581,19 @@ BOOL LLImageFormatted::load(const std::string &filename) return FALSE; } + // Constrain the load size to acceptable values + if ((load_size == 0) || (load_size > file_size)) + { + load_size = file_size; + } BOOL res; - U8 *data = allocateData(file_size); - apr_size_t bytes_read = file_size; + U8 *data = allocateData(load_size); + apr_size_t bytes_read = load_size; apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read - if (s != APR_SUCCESS || (S32) bytes_read != file_size) + if (s != APR_SUCCESS || (S32) bytes_read != load_size) { deleteData(); - setLastError("Unable to read entire file",filename); + setLastError("Unable to read file",filename); res = FALSE; } else diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 847ba8c11c..eba8362f1c 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -294,7 +294,7 @@ public: // getRawDiscardLevel() by default returns mDiscardLevel, but may be overridden (LLImageJ2C) virtual S8 getRawDiscardLevel() { return mDiscardLevel; } - BOOL load(const std::string& filename); + BOOL load(const std::string& filename, int load_size = 0); BOOL save(const std::string& filename); virtual BOOL updateData() = 0; // pure virtual -- cgit v1.2.3 From df09fd8e8b5b73330e4942c2cb218a216d7aca99 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Mon, 2 Apr 2012 19:05:32 -0700 Subject: SH-3060 : Preliminary implementation of the new byte range computation, implement setting to turn it on or off --- indra/llimage/llimage.cpp | 4 +++- indra/llimage/llimage.h | 5 ++++- indra/llimage/llimagej2c.cpp | 47 +++++++++++++++----------------------------- 3 files changed, 23 insertions(+), 33 deletions(-) (limited to 'indra/llimage') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 937655a22d..7f95441075 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -48,11 +48,13 @@ //static std::string LLImage::sLastErrorMessage; LLMutex* LLImage::sMutex = NULL; +bool LLImage::sUseNewByteRange = false; LLPrivateMemoryPool* LLImageBase::sPrivatePoolp = NULL ; //static -void LLImage::initClass() +void LLImage::initClass(bool use_new_byte_range) { + sUseNewByteRange = use_new_byte_range; sMutex = new LLMutex(NULL); LLImageBase::createPrivatePool() ; diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index eba8362f1c..b757547ab8 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -89,15 +89,18 @@ typedef enum e_image_codec class LLImage { public: - static void initClass(); + static void initClass(bool use_new_byte_range = false); static void cleanupClass(); static const std::string& getLastError(); static void setLastError(const std::string& message); + static bool useNewByteRange() { return sUseNewByteRange; } + protected: static LLMutex* sMutex; static std::string sLastErrorMessage; + static bool sUseNewByteRange; }; //============================================================================ diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index fbf4b769e1..cbb6f75b43 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -262,10 +262,12 @@ S32 LLImageJ2C::calcHeaderSizeJ2C() //static S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) { - // Note: this only provides an *estimate* of the size in bytes of an image level - // *TODO: find a way to read the true size (when available) and convey the fact - // that the result is an estimate in the other cases - if (rate <= 0.f) rate = .125f; + // Note: This provides an estimation for the first 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) { if (w < 1 || h < 1) @@ -274,7 +276,13 @@ S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 r h >>= 1; discard_level--; } - S32 bytes = (S32)((F32)(w*h*comp)*rate); + // 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 + // *TODO: Replace the magic "7" by the number of quality layers in the j2c image + S32 bytes; + S32 new_bytes = sqrt((F32)(w*h))*(F32)(comp)*rate*1000.f/7.f; + S32 old_bytes = (S32)((F32)(w*h*comp)*rate); + bytes = (LLImage::useNewByteRange() ? new_bytes : old_bytes); bytes = llmax(bytes, calcHeaderSizeJ2C()); return bytes; } @@ -284,11 +292,7 @@ S32 LLImageJ2C::calcHeaderSize() return calcHeaderSizeJ2C(); } - -// calcDataSize() returns how many bytes to read -// to load discard_level (including header and higher discard levels) -// *TODO: This is deeply wrong. That size should be taken from the image file header or other -// relevant infos. In any case, this is only an approximation. +// calcDataSize() returns how many bytes to read to load discard_level (including header) S32 LLImageJ2C::calcDataSize(S32 discard_level) { discard_level = llclamp(discard_level, 0, MAX_DISCARD_LEVEL); @@ -304,25 +308,6 @@ S32 LLImageJ2C::calcDataSize(S32 discard_level) mDataSizes[level] = calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate); level--; } - - /* This is technically a more correct way to calculate the size required - for each discard level, since they should include the size needed for - lower levels. Unfortunately, this doesn't work well and will lead to - download stalls. The true correct way is to parse the header. This will - all go away with http textures at some point. - - // Calculate the size for each discard level. Lower levels (higher quality) - // contain the cumulative size of higher levels - S32 total_size = calcHeaderSizeJ2C(); - - S32 level = MAX_DISCARD_LEVEL; // Start at the highest discard - while ( level >= 0 ) - { // Add in this discard level and all before it - total_size += calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, mRate); - mDataSizes[level] = total_size; - level--; - } - */ } return mDataSizes[discard_level]; } @@ -337,8 +322,8 @@ S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes) } while (1) { - S32 bytes_needed = calcDataSize(discard_level); // virtual - if (bytes >= bytes_needed - (bytes_needed>>2)) // For J2c, up the res at 75% of the optimal number of bytes + S32 bytes_needed = calcDataSize(discard_level); + if (bytes >= bytes_needed) { break; } -- cgit v1.2.3 From c6511d9c857c079e0360f88c05328feb70a8bc0d Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Wed, 4 Apr 2012 15:59:52 -0700 Subject: SH-3075 : Fix encoding for reversible images and small textures --- indra/llimage/llimage.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/llimage') diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index b757547ab8..18f8ae2fbb 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -48,6 +48,8 @@ const S32 MAX_PRECINCT_SIZE = 2048; // No reason to be bigger than MAX_IMAGE_S const S32 MIN_PRECINCT_SIZE = 4; // Can't be smaller than MIN_BLOCK_SIZE const S32 MAX_BLOCK_SIZE = 64; // Max total block size is 4096, hence 64x64 when using square blocks const S32 MIN_BLOCK_SIZE = 4; // Min block dim is 4 according to jpeg2000 spec +const S32 MIN_LAYER_SIZE = 2000; // Size of the first quality layer (after header). Must be > to FIRST_PACKET_SIZE!! +const S32 MAX_NB_LAYERS = 64; // Max number of layers we'll entertain in SL (practical limit) const S32 MIN_IMAGE_SIZE = (1< Date: Wed, 4 Apr 2012 18:58:34 -0700 Subject: SH-3060 : New byte range implementation. Intermediate (not working) state. --- indra/llimage/llimage.cpp | 3 ++- indra/llimage/llimage.h | 3 +++ indra/llimage/llimagej2c.cpp | 20 ++++++++++++++------ indra/llimage/llimagej2c.h | 3 ++- 4 files changed, 21 insertions(+), 8 deletions(-) (limited to 'indra/llimage') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 7f95441075..cce03ff6e6 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -1337,7 +1337,8 @@ LLImageFormatted::LLImageFormatted(S8 codec) mDecoding(0), mDecoded(0), mDiscardLevel(-1), - mLevels(0) + mLevels(0), + mLayers(0) { mMemType = LLMemType::MTYPE_IMAGEFORMATTED; } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 18f8ae2fbb..c5a7d6262e 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -320,6 +320,8 @@ 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(); @@ -334,6 +336,7 @@ 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 cbb6f75b43..dc5bd8b5d5 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -58,7 +58,8 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), mRawDiscardLevel(-1), mRate(0.0f), mReversible(FALSE), - mAreaUsedForDataSizeCalcs(0) + mAreaUsedForDataSizeCalcs(0), + mLayersUsedForDataSizeCalcs(0) { mImpl = fallbackCreateLLImageJ2CImpl(); @@ -260,7 +261,7 @@ S32 LLImageJ2C::calcHeaderSizeJ2C() } //static -S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate) +S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, S32 nb_layers, F32 rate) { // Note: This provides an estimation for the first quality layer of a given discard level // This is however an efficient approximation, as the true discard level boundary would be @@ -278,10 +279,11 @@ S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 r } // 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 - // *TODO: Replace the magic "7" by the number of quality layers in the j2c image S32 bytes; - S32 new_bytes = sqrt((F32)(w*h))*(F32)(comp)*rate*1000.f/7.f; + 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; bytes = (LLImage::useNewByteRange() ? new_bytes : old_bytes); bytes = llmax(bytes, calcHeaderSizeJ2C()); return bytes; @@ -298,14 +300,20 @@ S32 LLImageJ2C::calcDataSize(S32 discard_level) discard_level = llclamp(discard_level, 0, MAX_DISCARD_LEVEL); if ( mAreaUsedForDataSizeCalcs != (getHeight() * getWidth()) - || mDataSizes[0] == 0) + || (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, mRate); + mDataSizes[level] = calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), level, getLayers(), mRate); level--; } } diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index 914174fc57..28e3026aac 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -72,7 +72,7 @@ public: S32 getMaxBytes() const { return mMaxBytes; } static S32 calcHeaderSizeJ2C(); - static S32 calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 rate = 0.f); + static S32 calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, S32 nb_layers = 0, F32 rate = 0.f); static std::string getEngineInfo(); @@ -88,6 +88,7 @@ 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; -- cgit v1.2.3 From 91094d92a75b3900be15bfb8be4b9f7cc072487b Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 5 Apr 2012 22:05:00 -0700 Subject: SH-3060 : Implement new byte range computation, cleaned up use of compression rate as well. --- indra/llimage/llimage.cpp | 3 +-- indra/llimage/llimage.h | 4 +--- indra/llimage/llimagej2c.cpp | 55 +++++++++++++++++++++----------------------- indra/llimage/llimagej2c.h | 7 +++--- 4 files changed, 32 insertions(+), 37 deletions(-) (limited to 'indra/llimage') 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; -- cgit v1.2.3 From 0539de909951e94c9c22aac9ac94835793c7bf49 Mon Sep 17 00:00:00 2001 From: Oz Linden Date: Fri, 6 Apr 2012 14:36:58 -0400 Subject: STORM-1837: check for valid png header before attempting to decode --- indra/llimage/llimagepng.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'indra/llimage') diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp index 8d493ecde0..294f68b122 100644 --- a/indra/llimage/llimagepng.cpp +++ b/indra/llimage/llimagepng.cpp @@ -60,6 +60,12 @@ BOOL LLImagePNG::updateData() // Decode the PNG data and extract sizing information LLPngWrapper pngWrapper; + if (!pngWrapper.isValidPng(getData())) + { + setLastError("LLImagePNG data does not have a valid PNG header!"); + return FALSE; + } + LLPngWrapper::ImageInfo infop; if (! pngWrapper.readPng(getData(), NULL, &infop)) { @@ -90,6 +96,12 @@ BOOL LLImagePNG::decode(LLImageRaw* raw_image, F32 decode_time) // Decode the PNG data into the raw image LLPngWrapper pngWrapper; + if (!pngWrapper.isValidPng(getData())) + { + setLastError("LLImagePNG data does not have a valid PNG header!"); + return FALSE; + } + if (! pngWrapper.readPng(getData(), raw_image)) { setLastError(pngWrapper.getErrorMessage()); -- cgit v1.2.3 From 172b45d5a217c7cdb922f49706b310edc412fc28 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Fri, 6 Apr 2012 18:28:47 -0700 Subject: SH-3060 : Complete new byte range computation, clean up and back pedal on some changes that didn't pay of. --- indra/llimage/llimagej2c.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'indra/llimage') diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 7894de0de5..69d261c9a6 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -256,7 +256,7 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, //static S32 LLImageJ2C::calcHeaderSizeJ2C() { - return HTTP_PACKET_SIZE; // Hack. just needs to be >= actual header size... + return FIRST_PACKET_SIZE; // Hack. just needs to be >= actual header size... } //static @@ -267,7 +267,7 @@ S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 r // 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 - // Estimate the number of layers. This is consistent with what's done in j2c encoding + // Estimate the number of layers. This is consistent with what's done for j2c encoding in LLImageJ2CKDU::encodeImpl(). S32 nb_layers = 1; S32 surface = w*h; S32 s = 64*64; @@ -304,8 +304,6 @@ 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()) || (mDataSizes[0] == 0)) { @@ -319,7 +317,6 @@ S32 LLImageJ2C::calcDataSize(S32 discard_level) } } return mDataSizes[discard_level]; - */ } S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes) @@ -332,8 +329,8 @@ S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes) } while (1) { - S32 bytes_needed = calcDataSize(discard_level); - if (bytes >= bytes_needed) + S32 bytes_needed = calcDataSize(discard_level); // virtual + if (bytes >= bytes_needed - (bytes_needed>>2)) // For J2c, up the res at 75% of the optimal number of bytes { break; } -- cgit v1.2.3 From c410a4e3325350e3d9a72b867dcef44df9136f54 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Thu, 12 Apr 2012 20:19:56 -0700 Subject: SH-3080 : Implement the TextureReverseByteRange setting so we can play with that parameter --- indra/llimage/llimage.cpp | 4 +++- indra/llimage/llimage.h | 4 +++- indra/llimage/llimagej2c.cpp | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'indra/llimage') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 7f95441075..6775b005f4 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -49,12 +49,14 @@ std::string LLImage::sLastErrorMessage; LLMutex* LLImage::sMutex = NULL; bool LLImage::sUseNewByteRange = false; +S32 LLImage::sMinimalReverseByteRangePercent = 75; LLPrivateMemoryPool* LLImageBase::sPrivatePoolp = NULL ; //static -void LLImage::initClass(bool use_new_byte_range) +void LLImage::initClass(bool use_new_byte_range, S32 minimal_reverse_byte_range_percent) { sUseNewByteRange = use_new_byte_range; + sMinimalReverseByteRangePercent = minimal_reverse_byte_range_percent; sMutex = new LLMutex(NULL); LLImageBase::createPrivatePool() ; diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index a643e4d9f5..46e6d1a901 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -92,18 +92,20 @@ typedef enum e_image_codec class LLImage { public: - static void initClass(bool use_new_byte_range = false); + static void initClass(bool use_new_byte_range = false, S32 minimal_reverse_byte_range_percent = 75); static void cleanupClass(); static const std::string& getLastError(); static void setLastError(const std::string& message); static bool useNewByteRange() { return sUseNewByteRange; } + static S32 getReverseByteRangePercent() { return sMinimalReverseByteRangePercent; } protected: static LLMutex* sMutex; static std::string sLastErrorMessage; static bool sUseNewByteRange; + static S32 sMinimalReverseByteRangePercent; }; //============================================================================ diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 69d261c9a6..4c5c8a9c52 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -289,7 +289,6 @@ S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 r S32 bytes; 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 : 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; @@ -329,8 +328,9 @@ S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes) } while (1) { - S32 bytes_needed = calcDataSize(discard_level); // virtual - if (bytes >= bytes_needed - (bytes_needed>>2)) // For J2c, up the res at 75% of the optimal number of bytes + S32 bytes_needed = calcDataSize(discard_level); + // Use TextureReverseByteRange percent (see settings.xml) of the optimal size to qualify as correct rendering for the given discard level + if (bytes >= (bytes_needed*LLImage::getReverseByteRangePercent()/100)) { break; } -- cgit v1.2.3 From 8778010feec5193c5ffc88d70e4a303aebaaaee4 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 13 Apr 2012 17:03:29 -0400 Subject: fix for linux build failure --- indra/llimage/llimagej2c.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 indra/llimage/llimagej2c.cpp (limited to 'indra/llimage') diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp old mode 100644 new mode 100755 index 69d261c9a6..4e08f09b4e --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -287,7 +287,7 @@ S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 r // 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; - S32 new_bytes = sqrt((F32)(w*h))*(F32)(comp)*rate*1000.f/layer_factor; + S32 new_bytes = (S32) (sqrt((F32)(w*h))*(F32)(comp)*rate*1000.f/layer_factor); S32 old_bytes = (S32)((F32)(w*h*comp)*rate); //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); -- cgit v1.2.3 From 8b3703bd03487e6d70a793427ed1587b1cd86808 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Fri, 13 Apr 2012 15:42:54 -0700 Subject: SH-3060 : Always use old byte range on low res (faster), reserve new byte range for high res. --- indra/llimage/llimagej2c.cpp | 7 +++++-- indra/llimage/llimagej2c.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'indra/llimage') diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 4c5c8a9c52..a76734e550 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -289,7 +289,7 @@ S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 r S32 bytes; S32 new_bytes = sqrt((F32)(w*h))*(F32)(comp)*rate*1000.f/layer_factor; S32 old_bytes = (S32)((F32)(w*h*comp)*rate); - bytes = (LLImage::useNewByteRange() ? new_bytes : old_bytes); + bytes = (LLImage::useNewByteRange() && (new_bytes < old_bytes) ? new_bytes : old_bytes); bytes = llmax(bytes, calcHeaderSizeJ2C()); return bytes; } @@ -473,6 +473,7 @@ LLImageCompressionTester::LLImageCompressionTester() : LLMetricPerformanceTester mTotalTimeDecompression = 0.0f; mTotalTimeCompression = 0.0f; + mRunTimeDecompression = 0.0f; } LLImageCompressionTester::~LLImageCompressionTester() @@ -555,12 +556,14 @@ void LLImageCompressionTester::updateDecompressionStats(const S32 bytesIn, const mTotalBytesInDecompression += bytesIn; mRunBytesInDecompression += bytesIn; mTotalBytesOutDecompression += bytesOut; - if (mRunBytesInDecompression > (1000000)) + //if (mRunBytesInDecompression > (1000000)) + if ((mTotalTimeDecompression - mRunTimeDecompression) >= (5.0f)) { // Output everything outputTestResults(); // Reset the decompression data of the run mRunBytesInDecompression = 0; + mRunTimeDecompression = mTotalTimeDecompression; } } diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index 91c344d12f..42093e0e64 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -163,6 +163,7 @@ class LLImageCompressionTester : public LLMetricPerformanceTesterBasic // F32 mTotalTimeDecompression; // Total time spent in computing decompression F32 mTotalTimeCompression; // Total time spent in computing compression + F32 mRunTimeDecompression; // Time in this run (we output every 5 sec in decompress) }; #endif -- cgit v1.2.3 From 5c11b6b2e59ea8042d8dac6071b8be4c81293889 Mon Sep 17 00:00:00 2001 From: Merov Linden Date: Tue, 8 May 2012 10:16:14 -0700 Subject: SH-3047 : Tweak of the performance compression data gathering code --- indra/llimage/llimagej2c.cpp | 6 +++++- indra/llimage/llimagej2c.h | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'indra/llimage') diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 4435e0d2a4..452aad25cb 100755 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -464,6 +464,7 @@ LLImageCompressionTester::LLImageCompressionTester() : LLMetricPerformanceTester addMetric("Perf Compression (kB/s)"); mRunBytesInDecompression = 0; + mRunBytesOutDecompression = 0; mRunBytesInCompression = 0; mTotalBytesInDecompression = 0; @@ -556,13 +557,16 @@ void LLImageCompressionTester::updateDecompressionStats(const S32 bytesIn, const mTotalBytesInDecompression += bytesIn; mRunBytesInDecompression += bytesIn; mTotalBytesOutDecompression += bytesOut; + mRunBytesOutDecompression += bytesOut; //if (mRunBytesInDecompression > (1000000)) - if ((mTotalTimeDecompression - mRunTimeDecompression) >= (5.0f)) + if (mRunBytesOutDecompression > (10000000)) + //if ((mTotalTimeDecompression - mRunTimeDecompression) >= (5.0f)) { // Output everything outputTestResults(); // Reset the decompression data of the run mRunBytesInDecompression = 0; + mRunBytesOutDecompression = 0; mRunTimeDecompression = mTotalTimeDecompression; } } diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index 42093e0e64..ce8195940d 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -156,7 +156,8 @@ class LLImageCompressionTester : public LLMetricPerformanceTesterBasic U32 mTotalBytesOutDecompression; // Total bytes produced by decompressor U32 mTotalBytesInCompression; // Total bytes fed to compressor U32 mTotalBytesOutCompression; // Total bytes produced by compressor - U32 mRunBytesInDecompression; // Bytes fed to decompressor in this run + U32 mRunBytesInDecompression; // Bytes fed to decompressor in this run + U32 mRunBytesOutDecompression; // Bytes produced by the decompressor in this run U32 mRunBytesInCompression; // Bytes fed to compressor in this run // // Time -- cgit v1.2.3