From 36b6111ea0b2896134e31c02a87db8687b54ec74 Mon Sep 17 00:00:00 2001 From: McCabe Maxsted Date: Fri, 7 May 2010 18:16:10 -0700 Subject: Backported llimage changes from Viewer 2.0.0 --- linden/indra/llimage/llimage.cpp | 144 +++++++++++++++++++++------------ linden/indra/llimage/llimage.h | 10 ++- linden/indra/llimage/llimagej2c.cpp | 50 +++++++++++- linden/indra/llimage/llimagej2c.h | 6 +- linden/indra/llimage/llimageworker.cpp | 13 ++- linden/indra/llimage/llimageworker.h | 2 +- 6 files changed, 162 insertions(+), 63 deletions(-) diff --git a/linden/indra/llimage/llimage.cpp b/linden/indra/llimage/llimage.cpp index 32891e7..db983fb 100644 --- a/linden/indra/llimage/llimage.cpp +++ b/linden/indra/llimage/llimage.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2001&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2001-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -154,7 +154,7 @@ U8* LLImageBase::allocateData(S32 size) size = mWidth * mHeight * mComponents; if (size <= 0) { - llerrs << llformat("LLImageBase::allocateData called with bad dimentions: %dx%dx%d",mWidth,mHeight,mComponents) << llendl; + llerrs << llformat("LLImageBase::allocateData called with bad dimensions: %dx%dx%d",mWidth,mHeight,mComponents) << llendl; } } else if (size <= 0 || (size > 4096*4096*16 && sSizeOverride == FALSE)) @@ -311,6 +311,21 @@ void LLImageRaw::deleteData() LLImageBase::deleteData(); } +void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components) +{ + if(data == getData()) + { + return ; + } + + deleteData(); + + LLImageBase::setSize(width, height, components) ; + LLImageBase::setDataAndSize(data, width * height * components) ; + + sGlobalRawMemory += getDataSize(); +} + BOOL LLImageRaw::resize(U16 width, U16 height, S8 components) { if ((getWidth() == width) && (getHeight() == height) && (getComponents() == components)) @@ -412,22 +427,17 @@ void LLImageRaw::verticalFlip() { LLMemType mt1((LLMemType::EMemType)mMemType); S32 row_bytes = getWidth() * getComponents(); - U8* line_buffer = new U8[row_bytes]; - if (!line_buffer ) - { - llerrs << "Out of memory in LLImageRaw::verticalFlip()" << llendl; - return; - } + llassert(row_bytes > 0); + std::vector line_buffer(row_bytes); S32 mid_row = getHeight() / 2; for( S32 row = 0; row < mid_row; row++ ) { U8* row_a_data = getData() + row * row_bytes; U8* row_b_data = getData() + (getHeight() - 1 - row) * row_bytes; - memcpy( line_buffer, row_a_data, row_bytes ); /* Flawfinder: ignore */ - memcpy( row_a_data, row_b_data, row_bytes ); /* Flawfinder: ignore */ - memcpy( row_b_data, line_buffer, row_bytes ); /* Flawfinder: ignore */ + memcpy( &line_buffer[0], row_a_data, row_bytes ); + memcpy( row_a_data, row_b_data, row_bytes ); + memcpy( row_b_data, &line_buffer[0], row_bytes ); } - delete[] line_buffer; } @@ -555,22 +565,21 @@ void LLImageRaw::compositeScaled4onto3(LLImageRaw* src) llassert( (4 == src->getComponents()) && (3 == dst->getComponents()) ); - // Vertical: scale but no composite S32 temp_data_size = src->getWidth() * dst->getHeight() * src->getComponents(); - U8* temp_buffer = new U8[ temp_data_size ]; + llassert_always(temp_data_size > 0); + std::vector temp_buffer(temp_data_size); + + // Vertical: scale but no composite for( S32 col = 0; col < src->getWidth(); col++ ) { - copyLineScaled( src->getData() + (src->getComponents() * col), temp_buffer + (src->getComponents() * col), src->getHeight(), dst->getHeight(), src->getWidth(), src->getWidth() ); + copyLineScaled( src->getData() + (src->getComponents() * col), &temp_buffer[0] + (src->getComponents() * col), src->getHeight(), dst->getHeight(), src->getWidth(), src->getWidth() ); } // Horizontal: scale and composite for( S32 row = 0; row < dst->getHeight(); row++ ) { - compositeRowScaled4onto3( temp_buffer + (src->getComponents() * src->getWidth() * row), dst->getData() + (dst->getComponents() * dst->getWidth() * row), src->getWidth(), dst->getWidth() ); + compositeRowScaled4onto3( &temp_buffer[0] + (src->getComponents() * src->getWidth() * row), dst->getData() + (dst->getComponents() * dst->getWidth() * row), src->getWidth(), dst->getWidth() ); } - - // Clean up - delete[] temp_buffer; } @@ -659,10 +668,13 @@ void LLImageRaw::fill( const LLColor4U& color ) // Src and dst can be any size. Src and dst can each have 3 or 4 components. void LLImageRaw::copy(LLImageRaw* src) { - LLImageRaw* dst = this; // Just for clarity. + if (!src) + { + llwarns << "LLImageRaw::copy called with a null src pointer" << llendl; + return; + } - llassert( (3 == src->getComponents()) || (4 == src->getComponents()) ); - llassert( (3 == dst->getComponents()) || (4 == dst->getComponents()) ); + LLImageRaw* dst = this; // Just for clarity. if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ) { @@ -800,25 +812,68 @@ void LLImageRaw::copyScaled( LLImageRaw* src ) return; } - // Vertical S32 temp_data_size = src->getWidth() * dst->getHeight() * getComponents(); llassert_always(temp_data_size > 0); - U8* temp_buffer = new U8[ temp_data_size ]; + std::vector temp_buffer(temp_data_size); + + // Vertical for( S32 col = 0; col < src->getWidth(); col++ ) { - copyLineScaled( src->getData() + (getComponents() * col), temp_buffer + (getComponents() * col), src->getHeight(), dst->getHeight(), src->getWidth(), src->getWidth() ); + copyLineScaled( src->getData() + (getComponents() * col), &temp_buffer[0] + (getComponents() * col), src->getHeight(), dst->getHeight(), src->getWidth(), src->getWidth() ); } // Horizontal for( S32 row = 0; row < dst->getHeight(); row++ ) { - copyLineScaled( temp_buffer + (getComponents() * src->getWidth() * row), dst->getData() + (getComponents() * dst->getWidth() * row), src->getWidth(), dst->getWidth(), 1, 1 ); + copyLineScaled( &temp_buffer[0] + (getComponents() * src->getWidth() * row), dst->getData() + (getComponents() * dst->getWidth() * row), src->getWidth(), dst->getWidth(), 1, 1 ); } - - // Clean up - delete[] temp_buffer; } +//scale down image by not blending a pixel with its neighbors. +BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height) +{ + LLMemType mt1((LLMemType::EMemType)mMemType); + + S8 c = getComponents() ; + llassert((1 == c) || (3 == c) || (4 == c) ); + + S32 old_width = getWidth(); + S32 old_height = getHeight(); + + S32 new_data_size = old_width * new_height * c ; + llassert_always(new_data_size > 0); + + F32 ratio_x = (F32)old_width / new_width ; + F32 ratio_y = (F32)old_height / new_height ; + if( ratio_x < 1.0f || ratio_y < 1.0f ) + { + return TRUE; // Nothing to do. + } + ratio_x -= 1.0f ; + ratio_y -= 1.0f ; + + U8* new_data = new U8[new_data_size] ; + llassert_always(new_data != NULL) ; + + U8* old_data = getData() ; + S32 i, j, k, s, t; + for(i = 0, s = 0, t = 0 ; i < new_height ; i++) + { + for(j = 0 ; j < new_width ; j++) + { + for(k = 0 ; k < c ; k++) + { + new_data[s++] = old_data[t++] ; + } + t += (S32)(ratio_x * c + 0.1f) ; + } + t += (S32)(ratio_y * old_width * c + 0.1f) ; + } + + setDataAndSize(new_data, new_width, new_height, c) ; + + return TRUE ; +} BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) { @@ -837,12 +892,14 @@ BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) if (scale_image_data) { - // Vertical S32 temp_data_size = old_width * new_height * getComponents(); - U8* temp_buffer = new U8[ temp_data_size ]; + llassert_always(temp_data_size > 0); + std::vector temp_buffer(temp_data_size); + + // Vertical for( S32 col = 0; col < old_width; col++ ) { - copyLineScaled( getData() + (getComponents() * col), temp_buffer + (getComponents() * col), old_height, new_height, old_width, old_width ); + copyLineScaled( getData() + (getComponents() * col), &temp_buffer[0] + (getComponents() * col), old_height, new_height, old_width, old_width ); } deleteData(); @@ -852,25 +909,15 @@ BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) // Horizontal for( S32 row = 0; row < new_height; row++ ) { - copyLineScaled( temp_buffer + (getComponents() * old_width * row), new_buffer + (getComponents() * new_width * row), old_width, new_width, 1, 1 ); + copyLineScaled( &temp_buffer[0] + (getComponents() * old_width * row), new_buffer + (getComponents() * new_width * row), old_width, new_width, 1, 1 ); } - - // Clean up - delete[] temp_buffer; } else { // copy out existing image data S32 temp_data_size = old_width * old_height * getComponents(); - U8* temp_buffer = new U8[ temp_data_size ]; - if (!temp_buffer) - { - llwarns << "Out of memory in LLImageRaw::scale: old (w, h, c) = (" << old_width << ", " << old_height << ", " << (S32)getComponents() << - ") ; new (w, h, c) = (" << new_width << ", " << new_height << ", " << (S32)getComponents() << ")" << llendl; - - return FALSE ; - } - memcpy(temp_buffer, getData(), temp_data_size); /* Flawfinder: ignore */ + std::vector temp_buffer(temp_data_size); + memcpy(&temp_buffer[0], getData(), temp_data_size); // allocate new image data, will delete old data U8* new_buffer = allocateDataSize(new_width, new_height, getComponents()); @@ -879,7 +926,7 @@ BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) { if (row < old_height) { - memcpy(new_buffer + (new_width * row * getComponents()), temp_buffer + (old_width * row * getComponents()), getComponents() * llmin(old_width, new_width)); /* Flawfinder: ignore */ + memcpy(new_buffer + (new_width * row * getComponents()), &temp_buffer[0] + (old_width * row * getComponents()), getComponents() * llmin(old_width, new_width)); if (old_width < new_width) { // pad out rest of row with black @@ -892,9 +939,6 @@ BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) memset(new_buffer + (new_width * row * getComponents()), 0, new_width * getComponents()); } } - - // Clean up - delete[] temp_buffer; } return TRUE ; @@ -1234,7 +1278,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip llassert(image.notNull()); U8 *buffer = image->allocateData(length); - ifs.read ((char*)buffer, length); /* Flawfinder: ignore */ + ifs.read ((char*)buffer, length); ifs.close(); BOOL success; diff --git a/linden/indra/llimage/llimage.h b/linden/indra/llimage/llimage.h index be2eb08..102e779 100644 --- a/linden/indra/llimage/llimage.h +++ b/linden/indra/llimage/llimage.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2000&license=viewergpl$ * - * Copyright (c) 2000-2009, Linden Research, Inc. + * Copyright (c) 2000-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -35,8 +35,9 @@ #include "lluuid.h" #include "llstring.h" -#include "llmemory.h" +//#include "llmemory.h" #include "llthread.h" +#include "llmemtype.h" const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2 const S32 MAX_IMAGE_MIP = 11; // 2048x2048 @@ -130,7 +131,7 @@ public: protected: // special accessor to allow direct setting of mData and mDataSize by LLImageFormatted - void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; }; + void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; } public: static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels); @@ -191,6 +192,7 @@ public: void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE); void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE); BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE ); + BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ; // Fill the buffer with a constant color void fill( const LLColor4U& color ); @@ -239,6 +241,8 @@ protected: U8 fastFractionalMult(U8 a,U8 b); + void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ; + public: static S32 sGlobalRawMemory; static S32 sRawImageCount; diff --git a/linden/indra/llimage/llimagej2c.cpp b/linden/indra/llimage/llimagej2c.cpp index 1aae83e..5480c88 100644 --- a/linden/indra/llimage/llimagej2c.cpp +++ b/linden/indra/llimage/llimagej2c.cpp @@ -3,7 +3,7 @@ * * $LicenseInfo:firstyear=2001&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2001-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -178,8 +178,8 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), mMaxBytes(0), mRawDiscardLevel(-1), mRate(0.0f), - mReversible(FALSE) - + mReversible(FALSE), + mAreaUsedForDataSizeCalcs(0) { //We assume here that if we wanted to create via //a dynamic library that the approriate open calls were made @@ -195,6 +195,12 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), } mImpl = j2cimpl_create_func(); + + // Clear data size table + for( S32 i = 0; i <= MAX_DISCARD_LEVEL; i++) + { // Array size is MAX_DISCARD_LEVEL+1 + mDataSizes[i] = 0; + } } // virtual @@ -368,9 +374,45 @@ S32 LLImageJ2C::calcHeaderSize() return calcHeaderSizeJ2C(); } + +// calcDataSize() returns how many bytes to read +// to load discard_level (including header and higher discard levels) S32 LLImageJ2C::calcDataSize(S32 discard_level) { - return calcDataSizeJ2C(getWidth(), getHeight(), getComponents(), discard_level, mRate); + discard_level = llclamp(discard_level, 0, MAX_DISCARD_LEVEL); + + if ( mAreaUsedForDataSizeCalcs != (getHeight() * getWidth()) + || mDataSizes[0] == 0) + { + mAreaUsedForDataSizeCalcs = getHeight() * getWidth(); + + S32 level = MAX_DISCARD_LEVEL; // Start at the highest discard + while ( level >= 0 ) + { + 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]; } S32 LLImageJ2C::calcDiscardLevelBytes(S32 bytes) diff --git a/linden/indra/llimage/llimagej2c.h b/linden/indra/llimage/llimagej2c.h index 23f6ef5..74d1256 100644 --- a/linden/indra/llimage/llimagej2c.h +++ b/linden/indra/llimage/llimagej2c.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2001&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2001-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -87,6 +87,10 @@ protected: void updateRawDiscardLevel(); S32 mMaxBytes; // Maximum number of bytes of data to use... + + S32 mDataSizes[MAX_DISCARD_LEVEL+1]; // Size of data required to reach a given level + U32 mAreaUsedForDataSizeCalcs; // Height * width used to calculate mDataSizes + S8 mRawDiscardLevel; F32 mRate; BOOL mReversible; diff --git a/linden/indra/llimage/llimageworker.cpp b/linden/indra/llimage/llimageworker.cpp index 86d4151..558a968 100644 --- a/linden/indra/llimage/llimageworker.cpp +++ b/linden/indra/llimage/llimageworker.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2001&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2001-2010, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -54,9 +54,14 @@ S32 LLImageDecodeThread::update(U32 max_time_ms) { creation_info& info = *iter; ImageRequest* req = new ImageRequest(info.handle, info.image, - info.priority, info.discard, info.needs_aux, - info.responder); - addRequest(req); + info.priority, info.discard, info.needs_aux, + info.responder); + + bool res = addRequest(req); + if (!res) + { + llerrs << "request added after LLLFSThread::cleanupClass()" << llendl; + } } mCreationList.clear(); S32 res = LLQueuedThread::update(max_time_ms); diff --git a/linden/indra/llimage/llimageworker.h b/linden/indra/llimage/llimageworker.h index fcd3039..0260206 100644 --- a/linden/indra/llimage/llimageworker.h +++ b/linden/indra/llimage/llimageworker.h @@ -34,7 +34,7 @@ #define LL_LLIMAGEWORKER_H #include "llimage.h" -#include "llqueuedthread.h" +#include "llworkerthread.h" class LLImageDecodeThread : public LLQueuedThread { -- cgit v1.1