diff options
Diffstat (limited to 'indra/llimage')
-rw-r--r-- | indra/llimage/CMakeLists.txt | 67 | ||||
-rw-r--r-- | indra/llimage/llimage.cpp | 453 | ||||
-rw-r--r-- | indra/llimage/llimage.h | 123 | ||||
-rw-r--r-- | indra/llimage/llimagebmp.cpp | 48 | ||||
-rw-r--r-- | indra/llimage/llimagebmp.h | 40 | ||||
-rw-r--r-- | indra/llimage/llimagedimensionsinfo.cpp | 133 | ||||
-rw-r--r-- | indra/llimage/llimagedimensionsinfo.h | 133 | ||||
-rw-r--r-- | indra/llimage/llimagedxt.cpp | 58 | ||||
-rw-r--r-- | indra/llimage/llimagedxt.h | 45 | ||||
-rw-r--r-- | indra/llimage/llimagej2c.cpp | 249 | ||||
-rw-r--r-- | indra/llimage/llimagej2c.h | 53 | ||||
-rw-r--r-- | indra/llimage/llimagejpeg.cpp | 80 | ||||
-rw-r--r-- | indra/llimage/llimagejpeg.h | 48 | ||||
-rw-r--r-- | indra/llimage/llimagepng.cpp | 55 | ||||
-rw-r--r-- | indra/llimage/llimagepng.h | 45 | ||||
-rw-r--r-- | indra/llimage/llimagetga.cpp | 76 | ||||
-rw-r--r-- | indra/llimage/llimagetga.h | 40 | ||||
-rw-r--r-- | indra/llimage/llimageworker.cpp | 242 | ||||
-rw-r--r-- | indra/llimage/llimageworker.h | 129 | ||||
-rw-r--r-- | indra/llimage/llmapimagetype.h | 35 | ||||
-rw-r--r-- | indra/llimage/llpngwrapper.cpp | 50 | ||||
-rw-r--r-- | indra/llimage/llpngwrapper.h | 43 | ||||
-rw-r--r-- | indra/llimage/tests/llimageworker_test.cpp | 254 |
23 files changed, 1667 insertions, 832 deletions
diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt new file mode 100644 index 0000000000..a69621a57b --- /dev/null +++ b/indra/llimage/CMakeLists.txt @@ -0,0 +1,67 @@ +# -*- cmake -*- + +project(llimage) + +include(00-Common) +include(LLAddBuildTest) +include(LLCommon) +include(LLImage) +include(LLMath) +include(LLVFS) +include(ZLIB) + +include_directories( + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLVFS_INCLUDE_DIRS} + ${PNG_INCLUDE_DIRS} + ${ZLIB_INCLUDE_DIRS} + ) + +set(llimage_SOURCE_FILES + llimagebmp.cpp + llimage.cpp + llimagedimensionsinfo.cpp + llimagedxt.cpp + llimagej2c.cpp + llimagejpeg.cpp + llimagepng.cpp + llimagetga.cpp + llimageworker.cpp + llpngwrapper.cpp + ) + +set(llimage_HEADER_FILES + CMakeLists.txt + + llimage.h + llimagebmp.h + llimagedimensionsinfo.h + llimagedxt.h + llimagej2c.h + llimagejpeg.h + llimagepng.h + llimagetga.h + llimageworker.h + llmapimagetype.h + llpngwrapper.h + ) + +set_source_files_properties(${llimage_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND llimage_SOURCE_FILES ${llimage_HEADER_FILES}) + +add_library (llimage ${llimage_SOURCE_FILES}) +# Libraries on which this library depends, needed for Linux builds +# Sort by high-level to low-level +target_link_libraries(llimage + llcommon + llimagej2coj # *HACK: In theory a noop for KDU builds? + ${JPEG_LIBRARIES} + ${PNG_LIBRARIES} + ${ZLIB_LIBRARIES} + ) + +# Add tests +#ADD_BUILD_TEST(llimageworker llimage) diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index db19bd6ec6..5c33b675ca 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -2,30 +2,25 @@ * @file llimage.cpp * @brief Base class for images. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,10 +35,47 @@ #include "llimagebmp.h" #include "llimagetga.h" #include "llimagej2c.h" -#if JPEG_SUPPORT #include "llimagejpeg.h" -#endif +#include "llimagepng.h" #include "llimagedxt.h" +#include "llimageworker.h" + +//--------------------------------------------------------------------------- +// LLImage +//--------------------------------------------------------------------------- + +//static +std::string LLImage::sLastErrorMessage; +LLMutex* LLImage::sMutex = NULL; + +//static +void LLImage::initClass() +{ + sMutex = new LLMutex(NULL); + LLImageJ2C::openDSO(); +} + +//static +void LLImage::cleanupClass() +{ + LLImageJ2C::closeDSO(); + delete sMutex; + sMutex = NULL; +} + +//static +const std::string& LLImage::getLastError() +{ + static const std::string noerr("No Error"); + return sLastErrorMessage.empty() ? noerr : sLastErrorMessage; +} + +//static +void LLImage::setLastError(const std::string& message) +{ + LLMutexLock m(sMutex); + sLastErrorMessage = message; +} //--------------------------------------------------------------------------- // LLImageBase @@ -55,6 +87,8 @@ LLImageBase::LLImageBase() mWidth(0), mHeight(0), mComponents(0), + mBadBufferAllocation(false), + mAllowOverSize(false), mMemType(LLMemType::MTYPE_IMAGEBASE) { } @@ -95,21 +129,6 @@ void LLImageBase::sanityCheck() } } -LLString LLImageBase::sLastErrorMessage; -BOOL LLImageBase::sSizeOverride = FALSE; - -BOOL LLImageBase::setLastError(const LLString& message, const LLString& filename) -{ - sLastErrorMessage = message; - if (filename != "") - { - sLastErrorMessage += LLString(" FILE:"); - sLastErrorMessage += filename; - } - llwarns << sLastErrorMessage << llendl; - return FALSE; -} - // virtual void LLImageBase::deleteData() { @@ -121,30 +140,42 @@ void LLImageBase::deleteData() // virtual U8* LLImageBase::allocateData(S32 size) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); if (size < 0) { 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,(S32)mComponents) << llendl; } } - else if (size <= 0 || (size > 4096*4096*16 && sSizeOverride == FALSE)) + + //make this function thread-safe. + static const U32 MAX_BUFFER_SIZE = 4096 * 4096 * 16 ; //256 MB + if (size < 1 || size > MAX_BUFFER_SIZE) { - llerrs << "LLImageBase::allocateData: bad size: " << size << llendl; + llinfos << "width: " << mWidth << " height: " << mHeight << " components: " << mComponents << llendl ; + if(mAllowOverSize) + { + llinfos << "Oversize: " << size << llendl ; + } + else + { + llerrs << "LLImageBase::allocateData: bad size: " << size << llendl; + } } - - resetLastError(); - if (!mData || size != mDataSize) { deleteData(); // virtual + mBadBufferAllocation = false ; mData = new U8[size]; if (!mData) { - llerrs << "allocate image data: " << size << llendl; + llwarns << "allocate image data: " << size << llendl; + size = 0 ; + mWidth = mHeight = 0 ; + mBadBufferAllocation = true ; } mDataSize = size; } @@ -155,7 +186,7 @@ U8* LLImageBase::allocateData(S32 size) // virtual U8* LLImageBase::reallocateData(S32 size) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); U8 *new_datap = new U8[size]; if (!new_datap) { @@ -173,6 +204,30 @@ U8* LLImageBase::reallocateData(S32 size) return mData; } +const U8* LLImageBase::getData() const +{ + if(mBadBufferAllocation) + { + llerrs << "Bad memory allocation for the image buffer!" << llendl ; + } + + return mData; +} // read only + +U8* LLImageBase::getData() +{ + if(mBadBufferAllocation) + { + llerrs << "Bad memory allocation for the image buffer!" << llendl ; + } + + return mData; +} + +bool LLImageBase::isBufferInvalid() +{ + return mBadBufferAllocation || mData == NULL ; +} void LLImageBase::setSize(S32 width, S32 height, S32 ncomponents) { @@ -205,7 +260,7 @@ LLImageRaw::LLImageRaw(U16 width, U16 height, S8 components) : LLImageBase() { mMemType = LLMemType::MTYPE_IMAGERAW; - llassert( S32(width) * S32(height) * S32(components) <= MAX_IMAGE_DATA_SIZE ); + //llassert( S32(width) * S32(height) * S32(components) <= MAX_IMAGE_DATA_SIZE ); allocateDataSize(width, height, components); ++sRawImageCount; } @@ -214,12 +269,14 @@ LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components) : LLImageBase() { mMemType = LLMemType::MTYPE_IMAGERAW; - allocateDataSize(width, height, components); - memcpy(getData(), data, width*height*components); + if(allocateDataSize(width, height, components)) + { + memcpy(getData(), data, width*height*components); + } ++sRawImageCount; } -LLImageRaw::LLImageRaw(const LLString &filename, bool j2c_lowest_mip_only) +LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only) : LLImageBase() { createFromFile(filename, j2c_lowest_mip_only); @@ -257,6 +314,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)) @@ -273,7 +345,7 @@ BOOL LLImageRaw::resize(U16 width, U16 height, S8 components) U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); U8 *data = new U8[width*height*getComponents()]; // Should do some simple bounds checking @@ -356,24 +428,19 @@ void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a) // Reverses the order of the rows in the image void LLImageRaw::verticalFlip() { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(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<U8> 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; } @@ -460,8 +527,8 @@ void LLImageRaw::composite( LLImageRaw* src ) { LLImageRaw* dst = this; // Just for clarity. - llassert( (3 == src->getComponents()) || (4 == src->getComponents()) ); - llassert( (3 == dst->getComponents()) || (4 == dst->getComponents()) ); + llassert(3 == src->getComponents()); + llassert(3 == dst->getComponents()); if( 3 == dst->getComponents() ) { @@ -489,39 +556,33 @@ void LLImageRaw::composite( LLImageRaw* src ) } } } - else - { - // 4 == dst->mComponents - llassert(0); // not implemented yet. - } } // Src and dst can be any size. Src has 4 components. Dst has 3 components. void LLImageRaw::compositeScaled4onto3(LLImageRaw* src) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); llinfos << "compositeScaled4onto3" << llendl; LLImageRaw* dst = this; // Just for clarity. 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<U8> 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; } @@ -610,10 +671,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()) ) { @@ -659,7 +723,7 @@ void LLImageRaw::copyUnscaled(LLImageRaw* src) { LLImageRaw* dst = this; // Just for clarity. - llassert( (3 == src->getComponents()) || (4 == src->getComponents()) ); + llassert( (1 == src->getComponents()) || (3 == src->getComponents()) || (4 == src->getComponents()) ); llassert( src->getComponents() == dst->getComponents() ); llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); @@ -739,11 +803,11 @@ void LLImageRaw::copyUnscaled3onto4( LLImageRaw* src ) // Src and dst can be any size. Src and dst have same number of components. void LLImageRaw::copyScaled( LLImageRaw* src ) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); LLImageRaw* dst = this; // Just for clarity. - llassert( (3 == src->getComponents()) || (4 == src->getComponents()) ); - llassert( src->getComponents() == dst->getComponents() ); + llassert_always( (1 == src->getComponents()) || (3 == src->getComponents()) || (4 == src->getComponents()) ); + llassert_always( src->getComponents() == dst->getComponents() ); if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ) { @@ -751,48 +815,94 @@ void LLImageRaw::copyScaled( LLImageRaw* src ) return; } - // Vertical S32 temp_data_size = src->getWidth() * dst->getHeight() * getComponents(); - U8* temp_buffer = new U8[ temp_data_size ]; + llassert_always(temp_data_size > 0); + std::vector<U8> 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(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 ; +} -void LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) +BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) { - LLMemType mt1((LLMemType::EMemType)mMemType); - llassert( (3 == getComponents()) || (4 == getComponents()) ); + LLMemType mt1(mMemType); + llassert((1 == getComponents()) || (3 == getComponents()) || (4 == getComponents()) ); S32 old_width = getWidth(); S32 old_height = getHeight(); if( (old_width == new_width) && (old_height == new_height) ) { - return; // Nothing to do. + return TRUE; // Nothing to do. } // Reallocate the data buffer. 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<U8> 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(); @@ -802,23 +912,15 @@ void 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) - { - llerrs << "Out of memory in LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )" << llendl; - return; - } - memcpy(temp_buffer, getData(), temp_data_size); /* Flawfinder: ignore */ + std::vector<U8> 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()); @@ -827,7 +929,7 @@ void 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 @@ -840,10 +942,9 @@ void 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 ; } void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ) @@ -1063,7 +1164,7 @@ void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S3 static struct { const char* exten; - S8 codec; + EImageCodec codec; } file_extensions[] = { @@ -1078,27 +1179,27 @@ file_extensions[] = { "dxt", IMG_CODEC_DXT }, { "png", IMG_CODEC_PNG } }; -#define NUM_FILE_EXTENSIONS sizeof(file_extensions)/sizeof(file_extensions[0]) +#define NUM_FILE_EXTENSIONS LL_ARRAY_SIZE(file_extensions) -static LLString find_file(LLString &name, S8 *codec) +static std::string find_file(std::string &name, S8 *codec) { - LLString tname; + std::string tname; for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++) { - tname = name + "." + LLString(file_extensions[i].exten); - llifstream ifs(tname.c_str(), llifstream::binary); + tname = name + "." + std::string(file_extensions[i].exten); + llifstream ifs(tname, llifstream::binary); if (ifs.is_open()) { ifs.close(); if (codec) *codec = file_extensions[i].codec; - return LLString(file_extensions[i].exten); + return std::string(file_extensions[i].exten); } } - return LLString(""); + return std::string(""); } -static S8 get_codec(const LLString& exten) +EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten) { for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++) { @@ -1108,20 +1209,20 @@ static S8 get_codec(const LLString& exten) return IMG_CODEC_INVALID; } -bool LLImageRaw::createFromFile(const LLString &filename, bool j2c_lowest_mip_only) +bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip_only) { - LLString name = filename; + std::string name = filename; size_t dotidx = name.rfind('.'); S8 codec = IMG_CODEC_INVALID; - LLString exten; + std::string exten; deleteData(); // delete any existing data - if (dotidx != LLString::npos) + if (dotidx != std::string::npos) { exten = name.substr(dotidx+1); - LLString::toLower(exten); - codec = get_codec(exten); + LLStringUtil::toLower(exten); + codec = getCodecFromExtension(exten); } else { @@ -1133,7 +1234,7 @@ bool LLImageRaw::createFromFile(const LLString &filename, bool j2c_lowest_mip_on return false; // format not recognized } - llifstream ifs(name.c_str(), llifstream::binary); + llifstream ifs(name, llifstream::binary); if (!ifs.is_open()) { // SJB: changed from llinfos to lldebugs to reduce spam @@ -1165,11 +1266,9 @@ bool LLImageRaw::createFromFile(const LLString &filename, bool j2c_lowest_mip_on case IMG_CODEC_TGA: image = new LLImageTGA(); break; -#if JPEG_SUPPORT case IMG_CODEC_JPEG: image = new LLImageJPEG(); break; -#endif case IMG_CODEC_J2C: image = new LLImageJ2C(); break; @@ -1182,28 +1281,31 @@ bool LLImageRaw::createFromFile(const LLString &filename, bool j2c_lowest_mip_on llassert(image.notNull()); U8 *buffer = image->allocateData(length); - ifs.read ((char*)buffer, length); /* Flawfinder: ignore */ + ifs.read ((char*)buffer, length); ifs.close(); - image->updateData(); - - if (j2c_lowest_mip_only && codec == IMG_CODEC_J2C) + BOOL success; + + success = image->updateData(); + if (success) { - S32 width = image->getWidth(); - S32 height = image->getHeight(); - S32 discard_level = 0; - while (width > 1 && height > 1 && discard_level < MAX_DISCARD_LEVEL) + if (j2c_lowest_mip_only && codec == IMG_CODEC_J2C) { - width >>= 1; - height >>= 1; - discard_level++; + S32 width = image->getWidth(); + S32 height = image->getHeight(); + S32 discard_level = 0; + while (width > 1 && height > 1 && discard_level < MAX_DISCARD_LEVEL) + { + width >>= 1; + height >>= 1; + discard_level++; + } + ((LLImageJ2C *)((LLImageFormatted*)image))->setDiscardLevel(discard_level); } - ((LLImageJ2C *)((LLImageFormatted*)image))->setDiscardLevel(discard_level); + success = image->decode(this, 100000.0f); } - - BOOL success = image->decode(this, 100000.0f); - image = NULL; // deletes image + image = NULL; // deletes image if (!success) { deleteData(); @@ -1226,7 +1328,7 @@ LLImageFormatted::LLImageFormatted(S8 codec) mCodec(codec), mDecoding(0), mDecoded(0), - mDiscardLevel(0) + mDiscardLevel(-1) { mMemType = LLMemType::MTYPE_IMAGEFORMATTED; } @@ -1241,6 +1343,23 @@ LLImageFormatted::~LLImageFormatted() //---------------------------------------------------------------------------- +//virtual +void LLImageFormatted::resetLastError() +{ + LLImage::setLastError(""); +} + +//virtual +void LLImageFormatted::setLastError(const std::string& message, const std::string& filename) +{ + std::string error = message; + if (!filename.empty()) + error += std::string(" FILE: ") + filename; + LLImage::setLastError(error); +} + +//---------------------------------------------------------------------------- + // static LLImageFormatted* LLImageFormatted::createFromType(S8 codec) { @@ -1253,11 +1372,12 @@ LLImageFormatted* LLImageFormatted::createFromType(S8 codec) case IMG_CODEC_TGA: image = new LLImageTGA(); break; -#if JPEG_SUPPORT case IMG_CODEC_JPEG: image = new LLImageJPEG(); break; -#endif + case IMG_CODEC_PNG: + image = new LLImagePNG(); + break; case IMG_CODEC_J2C: image = new LLImageJ2C(); break; @@ -1272,11 +1392,11 @@ LLImageFormatted* LLImageFormatted::createFromType(S8 codec) } // static -LLImageFormatted* LLImageFormatted::createFromExtension(const LLString& instring) +LLImageFormatted* LLImageFormatted::createFromExtension(const std::string& instring) { - LLString exten; + std::string exten; size_t dotidx = instring.rfind('.'); - if (dotidx != LLString::npos) + if (dotidx != std::string::npos) { exten = instring.substr(dotidx+1); } @@ -1284,7 +1404,7 @@ LLImageFormatted* LLImageFormatted::createFromExtension(const LLString& instring { exten = instring; } - S8 codec = get_codec(exten); + S8 codec = getCodecFromExtension(exten); return createFromType(codec); } //---------------------------------------------------------------------------- @@ -1340,7 +1460,7 @@ S32 LLImageFormatted::calcDiscardLevelBytes(S32 bytes) //---------------------------------------------------------------------------- // Subclasses that can handle more than 4 channels should override this function. -BOOL LLImageFormatted::decode(LLImageRaw* raw_image,F32 decode_time, S32 first_channel, S32 max_channel) +BOOL LLImageFormatted::decodeChannels(LLImageRaw* raw_image,F32 decode_time, S32 first_channel, S32 max_channel) { llassert( (first_channel == 0) && (max_channel == 4) ); return decode( raw_image, decode_time ); // Loads first 4 channels by default. @@ -1427,18 +1547,21 @@ void LLImageFormatted::appendData(U8 *data, S32 size) S32 newsize = cursize + size; reallocateData(newsize); memcpy(getData() + cursize, data, size); + delete[] data; } } } //---------------------------------------------------------------------------- -BOOL LLImageFormatted::load(const LLString &filename) +BOOL LLImageFormatted::load(const std::string &filename) { resetLastError(); S32 file_size = 0; - apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_RB, &file_size); + LLAPRFile infile ; + infile.open(filename, LL_APR_RB, NULL, &file_size); + apr_file_t* apr_file = infile.getFileHandle(); if (!apr_file) { setLastError("Unable to open file for reading", filename); @@ -1447,7 +1570,6 @@ BOOL LLImageFormatted::load(const LLString &filename) if (file_size == 0) { setLastError("File is empty",filename); - apr_file_close(apr_file); return FALSE; } @@ -1465,25 +1587,24 @@ BOOL LLImageFormatted::load(const LLString &filename) { res = updateData(); } - apr_file_close(apr_file); - + return res; } -BOOL LLImageFormatted::save(const LLString &filename) +BOOL LLImageFormatted::save(const std::string &filename) { resetLastError(); - apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_WB); - if (!apr_file) + LLAPRFile outfile ; + outfile.open(filename, LL_APR_WB); + if (!outfile.getFileHandle()) { - setLastError("Unable to open file for reading", filename); + setLastError("Unable to open file for writing", filename); return FALSE; } - ll_apr_file_write(apr_file, getData(), getDataSize()); - apr_file_close(apr_file); - + outfile.write(getData(), getDataSize()); + outfile.close() ; return TRUE; } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 65a7c54a50..bca7e915fa 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -2,30 +2,25 @@ * @file llimage.h * @brief Object for managing images and their textures. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,8 +29,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 @@ -46,9 +42,10 @@ const S32 MAX_IMAGE_SIZE = (1<<MAX_IMAGE_MIP); // 2048 const S32 MIN_IMAGE_AREA = MIN_IMAGE_SIZE * MIN_IMAGE_SIZE; const S32 MAX_IMAGE_AREA = MAX_IMAGE_SIZE * MAX_IMAGE_SIZE; const S32 MAX_IMAGE_COMPONENTS = 8; -const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS; +const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS; //2048 * 2048 * 8 = 16 MB -// Note! These CANNOT be changed without invalidating the viewer VFS files, I think? +// Note! These CANNOT be changed without modifying simulator code +// *TODO: change both to 1024 when SIM texture fetching is deprecated const S32 FIRST_PACKET_SIZE = 600; const S32 MAX_IMG_PACKET_SIZE = 1000; @@ -60,7 +57,7 @@ class LLImageFormatted; class LLImageRaw; class LLColor4U; -enum +typedef enum e_image_codec { IMG_CODEC_INVALID = 0, IMG_CODEC_RGB = 1, @@ -71,9 +68,27 @@ enum IMG_CODEC_DXT = 6, IMG_CODEC_PNG = 7, IMG_CODEC_EOF = 8 +} EImageCodec; + +//============================================================================ +// library initialization class + +class LLImage +{ +public: + static void initClass(); + static void cleanupClass(); + + static const std::string& getLastError(); + static void setLastError(const std::string& message); + +protected: + static LLMutex* sMutex; + static std::string sLastErrorMessage; }; //============================================================================ +// Image base class class LLImageBase : public LLThreadSafeRefCount { @@ -101,29 +116,28 @@ public: S8 getComponents() const { return mComponents; } S32 getDataSize() const { return mDataSize; } - const U8 *getData() const { return mData; } // read only - U8 *getData() { return mData; } - + const U8 *getData() const ; + U8 *getData() ; + bool isBufferInvalid() ; + void setSize(S32 width, S32 height, S32 ncomponents); U8* allocateDataSize(S32 width, S32 height, S32 ncomponents, S32 size = -1); // setSize() + allocateData() + void enableOverSize() {mAllowOverSize = true ;} + void disableOverSize() {mAllowOverSize = false; } 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 const LLString& getLastError() {return sLastErrorMessage;}; - static void resetLastError() {sLastErrorMessage = LLString("No Error"); }; - static BOOL setLastError(const LLString& message, const LLString& filename = LLString()); // returns FALSE - static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels); // Function for calculating the download priority for textures // <= 0 priority means that there's no need for more data. static F32 calc_download_priority(F32 virtual_size, F32 visible_area, S32 bytes_sent); - static void setSizeOverride(BOOL enabled) { sSizeOverride = enabled; } - + static EImageCodec getCodecFromExtension(const std::string& exten); + private: U8 *mData; S32 mDataSize; @@ -133,12 +147,10 @@ private: S8 mComponents; + bool mBadBufferAllocation ; + bool mAllowOverSize ; public: - S16 mMemType; // debug - - static LLString sLastErrorMessage; - - static BOOL sSizeOverride; + LLMemType::DeclareMemType& mMemType; // debug }; // Raw representation of an image (used for textures, and other uncompressed formats @@ -152,7 +164,7 @@ public: LLImageRaw(U16 width, U16 height, S8 components); LLImageRaw(U8 *data, U16 width, U16 height, S8 components); // Construct using createFromFile (used by tools) - LLImageRaw(const LLString& filename, bool j2c_lowest_mip_only = false); + LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false); /*virtual*/ void deleteData(); /*virtual*/ U8* allocateData(S32 size = -1); @@ -171,7 +183,8 @@ public: void expandToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE); void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE); void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE); - void scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE ); + 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 ); @@ -213,13 +226,15 @@ public: protected: // Create an image from a local file (generally used in tools) - bool createFromFile(const LLString& filename, bool j2c_lowest_mip_only = false); + bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false); void copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ); void compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len ); U8 fastFractionalMult(U8 a,U8 b); + void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ; + public: static S32 sGlobalRawMemory; static S32 sRawImageCount; @@ -231,7 +246,7 @@ class LLImageFormatted : public LLImageBase { public: static LLImageFormatted* createFromType(S8 codec); - static LLImageFormatted* createFromExtension(const LLString& instring); + static LLImageFormatted* createFromExtension(const std::string& instring); protected: /*virtual*/ ~LLImageFormatted(); @@ -240,7 +255,6 @@ public: LLImageFormatted(S8 codec); // LLImageBase -public: /*virtual*/ void deleteData(); /*virtual*/ U8* allocateData(S32 size = -1); /*virtual*/ U8* reallocateData(S32 size); @@ -249,7 +263,8 @@ public: /*virtual*/ void sanityCheck(); // New methods -public: + // subclasses must return a prefered file extension (lowercase without a leading dot) + virtual std::string getExtension() = 0; // calcHeaderSize() returns the maximum size of header; // 0 indicates we don't know have a header and have to lead the entire file virtual S32 calcHeaderSize() { return 0; }; @@ -260,19 +275,19 @@ public: // getRawDiscardLevel()by default returns mDiscardLevel, but may be overridden (LLImageJ2C) virtual S8 getRawDiscardLevel() { return mDiscardLevel; } - BOOL load(const LLString& filename); - BOOL save(const LLString& filename); + BOOL load(const std::string& filename); + BOOL save(const std::string& filename); virtual BOOL updateData() = 0; // pure virtual void setData(U8 *data, S32 size); void appendData(U8 *data, S32 size); // Loads first 4 channels. - virtual BOOL decode(LLImageRaw* raw_image, F32 decode_time=0.0) = 0; + virtual BOOL decode(LLImageRaw* raw_image, F32 decode_time) = 0; // Subclasses that can handle more than 4 channels should override this function. - virtual BOOL decode(LLImageRaw* raw_image, F32 decode_time, S32 first_channel, S32 max_channel); + virtual BOOL decodeChannels(LLImageRaw* raw_image, F32 decode_time, S32 first_channel, S32 max_channel); - virtual BOOL encode(const LLImageRaw* raw_image, F32 encode_time=0.0) = 0; + virtual BOOL encode(const LLImageRaw* raw_image, F32 encode_time) = 0; S8 getCodec() const; BOOL isDecoding() const { return mDecoding ? TRUE : FALSE; } @@ -280,15 +295,19 @@ public: void setDiscardLevel(S8 discard_level) { mDiscardLevel = discard_level; } S8 getDiscardLevel() const { return mDiscardLevel; } + // setLastError needs to be deferred for J2C images since it may be called from a DLL + virtual void resetLastError(); + virtual void setLastError(const std::string& message, const std::string& filename = std::string()); + protected: BOOL copyData(U8 *data, S32 size); // calls updateData() protected: S8 mCodec; S8 mDecoding; - S8 mDecoded; + S8 mDecoded; // unused, but changing LLImage layout requires recompiling static Mac/Linux libs. 2009-01-30 JC S8 mDiscardLevel; - + public: static S32 sGlobalFormattedMemory; }; diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp index f8423000a8..60b1c628d7 100644 --- a/indra/llimage/llimagebmp.cpp +++ b/indra/llimage/llimagebmp.cpp @@ -1,30 +1,25 @@ /** * @file llimagebmp.cpp * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -552,7 +547,10 @@ BOOL LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time) int file_bytes = line_bytes*getHeight() + header_bytes; // Allocate the new buffer for the data. - allocateData(file_bytes); + if(!allocateData(file_bytes)) //memory allocation failed + { + return FALSE ; + } magic[0] = 'B'; magic[1] = 'M'; magic[2] = (U8) file_bytes; @@ -644,10 +642,10 @@ BOOL LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time) break; } - for( S32 i = 0; i < alignment_bytes; i++ ) - { - *dst++ = 0; - } + } + for( S32 i = 0; i < alignment_bytes; i++ ) + { + *dst++ = 0; } } diff --git a/indra/llimage/llimagebmp.h b/indra/llimage/llimagebmp.h index 2924ff412c..db0b45def0 100644 --- a/indra/llimage/llimagebmp.h +++ b/indra/llimage/llimagebmp.h @@ -2,30 +2,25 @@ * @file llimagebmp.h * @brief Image implementation for BMP. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,9 +39,10 @@ protected: public: LLImageBMP(); + /*virtual*/ std::string getExtension() { return std::string("bmp"); } /*virtual*/ BOOL updateData(); - /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 time=0.0); - /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 time=0.0); + /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 decode_time); + /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 encode_time); protected: BOOL decodeColorTable8( U8* dst, U8* src ); diff --git a/indra/llimage/llimagedimensionsinfo.cpp b/indra/llimage/llimagedimensionsinfo.cpp new file mode 100644 index 0000000000..5ea4a236b5 --- /dev/null +++ b/indra/llimage/llimagedimensionsinfo.cpp @@ -0,0 +1,133 @@ +/** + * @file llimagedimensionsinfo.cpp + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "stdtypes.h" + +#include "llimagejpeg.h" + +#include "llimagedimensionsinfo.h" + +bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec) +{ + clean(); + + mSrcFilename = src_filename; + + S32 file_size = 0; + apr_status_t s = mInfile.open(src_filename, LL_APR_RB, NULL, &file_size); + + if (s != APR_SUCCESS) + { + setLastError("Unable to open file for reading", src_filename); + return false; + } + + if (file_size == 0) + { + setLastError("File is empty",src_filename); + return false; + } + + switch (codec) + { + case IMG_CODEC_BMP: + return getImageDimensionsBmp(); + case IMG_CODEC_TGA: + return getImageDimensionsTga(); + case IMG_CODEC_JPEG: + return getImageDimensionsJpeg(); + case IMG_CODEC_PNG: + return getImageDimensionsPng(); + default: + return false; + + } +} + + +bool LLImageDimensionsInfo::getImageDimensionsBmp() +{ + const S32 BMP_FILE_HEADER_SIZE = 14; + + mInfile.seek(APR_CUR,BMP_FILE_HEADER_SIZE+4); + mWidth = read_reverse_s32(); + mHeight = read_reverse_s32(); + + return true; +} + +bool LLImageDimensionsInfo::getImageDimensionsTga() +{ + const S32 TGA_FILE_HEADER_SIZE = 12; + + mInfile.seek(APR_CUR,TGA_FILE_HEADER_SIZE); + mWidth = read_byte() | read_byte() << 8; + mHeight = read_byte() | read_byte() << 8; + + return true; +} + +bool LLImageDimensionsInfo::getImageDimensionsPng() +{ + const S32 PNG_FILE_MARKER_SIZE = 8; + + mInfile.seek(APR_CUR,PNG_FILE_MARKER_SIZE + 8/*header offset+chunk length+chunk type*/); + mWidth = read_s32(); + mHeight = read_s32(); + + return true; +} + + +bool LLImageDimensionsInfo::getImageDimensionsJpeg() +{ + clean(); + FILE *fp = fopen (mSrcFilename.c_str(), "rb"); + if (fp == NULL) + { + setLastError("Unable to open file for reading", mSrcFilename); + return false; + } + /* Init jpeg */ + jpeg_error_mgr jerr; + jpeg_decompress_struct cinfo; + cinfo.err = jpeg_std_error(&jerr); + + jpeg_create_decompress (&cinfo); + jpeg_stdio_src (&cinfo, fp); + jpeg_read_header (&cinfo, TRUE); + cinfo.out_color_space = JCS_RGB; + jpeg_start_decompress (&cinfo); + + mHeight = cinfo.output_width; + mHeight = cinfo.output_height; + + jpeg_destroy_decompress(&cinfo); + fclose(fp); + + return true; +} + diff --git a/indra/llimage/llimagedimensionsinfo.h b/indra/llimage/llimagedimensionsinfo.h new file mode 100644 index 0000000000..5384faf3f4 --- /dev/null +++ b/indra/llimage/llimagedimensionsinfo.h @@ -0,0 +1,133 @@ +/** + * @file llimagedimentionsinfo.h + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + + +#ifndef LL_LLIMAGEDIMENSIONSINFO_H +#define LL_LLIMAGEDIMENSIONSINFO_H + +//----------------------------------------------------------------------------- +// LLImageDimensionsInfo +// helper class to get image dimensions WITHOUT loading image to memore +// usefull when image may be too large... +//----------------------------------------------------------------------------- +class LLImageDimensionsInfo +{ +public: + LLImageDimensionsInfo(): + mData(NULL) + ,mHeight(0) + ,mWidth(0) + {} + ~LLImageDimensionsInfo() + { + clean(); + } + + bool load(const std::string& src_filename,U32 codec); + S32 getWidth() const { return mWidth;} + S32 getHeight() const { return mHeight;} + + const std::string& getLastError() + { + return mLastError; + } +protected: + + void clean() + { + mInfile.close(); + delete[] mData; + mData = NULL; + mWidth = 0; + mHeight = 0; + } + + U8* getData() + { + return mData; + } + + + void setLastError(const std::string& message, const std::string& filename) + { + std::string error = message; + if (!filename.empty()) + error += std::string(" FILE: ") + filename; + mLastError = error; + } + + + bool getImageDimensionsBmp(); + bool getImageDimensionsTga(); + bool getImageDimensionsPng(); + bool getImageDimensionsJpeg(); + + S32 read_s32() + { + char p[4]; + mInfile.read(&p[0],4); + S32 temp = (((S32)p[3]) & 0x000000FF) | + (((S32)p[2] << 8 ) & 0x0000FF00) | + (((S32)p[1] << 16) & 0x00FF0000) | + (((S32)p[0] << 24) & 0xFF000000); + + return temp; + } + S32 read_reverse_s32() + { + char p[4]; + mInfile.read(&p[0],4); + S32 temp = (((S32)p[0]) & 0x000000FF) | + (((S32)p[1] << 8 ) & 0x0000FF00) | + (((S32)p[2] << 16) & 0x00FF0000) | + (((S32)p[3] << 24) & 0xFF000000); + + return temp; + } + + U8 read_byte() + { + U8 bt; + mInfile.read(&bt,1); + return bt; + } + + U16 read_short() + { + return read_byte() << 8 | read_byte(); + } + +protected: + LLAPRFile mInfile ; + std::string mSrcFilename; + + std::string mLastError; + + U8* mData; + + S32 mWidth; + S32 mHeight; +}; +#endif diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index 6feece4ad9..4bd3efddaa 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -1,30 +1,25 @@ /** * @file llimagedxt.cpp * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -263,6 +258,8 @@ void LLImageDXT::setFormat() // virtual BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time) { + // *TODO: Test! This has been tweaked since its intial inception, + // but we don't use it any more! llassert_always(raw_image); if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5) @@ -273,8 +270,17 @@ BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time) S32 width = getWidth(), height = getHeight(); S32 ncomponents = getComponents(); + U8* data = NULL; + if (mDiscardLevel >= 0) + { + data = getData() + getMipOffset(mDiscardLevel); + calcDiscardWidthHeight(mDiscardLevel, mFileFormat, width, height); + } + else + { + data = getData() + getMipOffset(0); + } S32 image_size = formatBytes(mFileFormat, width, height); - U8* data = getData() + getMipOffset(0); if ((!getData()) || (data + image_size > getData() + getDataSize())) { @@ -299,16 +305,14 @@ BOOL LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard) llerrs << "Request for invalid discard level" << llendl; } U8* data = getData() + getMipOffset(discard); - // I'm not sure these are the correct initial values for height and width, - // but previously they were being used uninitialized. JC - S32 width = raw->getWidth(); - S32 height = raw->getHeight(); + S32 width = 0; + S32 height = 0; calcDiscardWidthHeight(discard, mFileFormat, width, height); raw = new LLImageRaw(data, width, height, getComponents()); return TRUE; } -BOOL LLImageDXT::encode(const LLImageRaw* raw_image, F32 time, bool explicit_mips) +BOOL LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_mips) { llassert_always(raw_image); @@ -396,7 +400,7 @@ BOOL LLImageDXT::encode(const LLImageRaw* raw_image, F32 time, bool explicit_mip // virtual BOOL LLImageDXT::encode(const LLImageRaw* raw_image, F32 time) { - return encode(raw_image, time, false); + return encodeDXT(raw_image, time, false); } // virtual diff --git a/indra/llimage/llimagedxt.h b/indra/llimage/llimagedxt.h index 23a5047f0d..a8756ba8ed 100644 --- a/indra/llimage/llimagedxt.h +++ b/indra/llimage/llimagedxt.h @@ -1,30 +1,25 @@ /** * @file llimagedxt.h * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,6 +27,7 @@ #define LL_LLIMAGEDXT_H #include "llimage.h" +#include "llpointer.h" // This class decodes and encodes LL DXT files (which may unclude uncompressed RGB or RGBA mipped data) @@ -95,15 +91,18 @@ public: protected: /*virtual*/ ~LLImageDXT(); + +private: + BOOL encodeDXT(const LLImageRaw* raw_image, F32 decode_time, bool explicit_mips); public: LLImageDXT(); + /*virtual*/ std::string getExtension() { return std::string("dxt"); } /*virtual*/ BOOL updateData(); - /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 time=0.0); - BOOL encode(const LLImageRaw* raw_image, F32 time, bool explicit_mips); - /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 time=0.0); + /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 decode_time); + /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 encode_time); /*virtual*/ S32 calcHeaderSize(); /*virtual*/ S32 calcDataSize(S32 discard_level = 0); diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 0911c43674..c8c866b7f2 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -1,36 +1,31 @@ /** * @file llimagej2c.cpp * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" -#include <apr-1/apr_pools.h> -#include <apr-1/apr_dso.h> +#include "apr_pools.h" +#include "apr_dso.h" #include "lldir.h" #include "llimagej2c.h" @@ -177,8 +172,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 @@ -194,6 +189,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 @@ -219,59 +220,86 @@ LLImageJ2C::~LLImageJ2C() } // virtual +void LLImageJ2C::resetLastError() +{ + mLastError.clear(); +} + +//virtual +void LLImageJ2C::setLastError(const std::string& message, const std::string& filename) +{ + mLastError = message; + if (!filename.empty()) + mLastError += std::string(" FILE: ") + filename; +} + +// virtual S8 LLImageJ2C::getRawDiscardLevel() { return mRawDiscardLevel; } BOOL LLImageJ2C::updateData() -{ +{ + BOOL res = TRUE; resetLastError(); // Check to make sure that this instance has been initialized with data if (!getData() || (getDataSize() < 16)) { setLastError("LLImageJ2C uninitialized"); - return FALSE; + res = FALSE; + } + else + { + res = mImpl->getMetadata(*this); } - if (!mImpl->getMetadata(*this)) + if (res) { - return FALSE; + // SJB: override discard based on mMaxBytes elsewhere + S32 max_bytes = getDataSize(); // mMaxBytes ? mMaxBytes : getDataSize(); + S32 discard = calcDiscardLevelBytes(max_bytes); + setDiscardLevel(discard); } - // SJB: override discard based on mMaxBytes elsewhere - S32 max_bytes = getDataSize(); // mMaxBytes ? mMaxBytes : getDataSize(); - S32 discard = calcDiscardLevelBytes(max_bytes); - setDiscardLevel(discard); - return TRUE; + if (!mLastError.empty()) + { + LLImage::setLastError(mLastError); + } + return res; } BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time) { - return decode(raw_imagep, decode_time, 0, 4); + return decodeChannels(raw_imagep, decode_time, 0, 4); } -BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count ) +// Returns TRUE to mean done, whether successful or not. +BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count ) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); + BOOL res = TRUE; + resetLastError(); // Check to make sure that this instance has been initialized with data if (!getData() || (getDataSize() < 16)) { setLastError("LLImageJ2C uninitialized"); - return FALSE; + res = TRUE; // done } - - // Update the raw discard level - updateRawDiscardLevel(); - - mDecoding = TRUE; - BOOL res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count); + else + { + // Update the raw discard level + updateRawDiscardLevel(); + mDecoding = TRUE; + res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count); + } + if (res) { if (!mDecoding) @@ -283,9 +311,14 @@ BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time, S32 first_chann { mDecoding = FALSE; } - return TRUE; // done } - return FALSE; + + if (!mLastError.empty()) + { + LLImage::setLastError(mLastError); + } + + return res; } @@ -297,14 +330,20 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, F32 encode_time) BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time) { - LLMemType mt1((LLMemType::EMemType)mMemType); - return mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time, mReversible); + LLMemType mt1(mMemType); + resetLastError(); + BOOL res = mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time, mReversible); + if (!mLastError.empty()) + { + LLImage::setLastError(mLastError); + } + return res; } //static S32 LLImageJ2C::calcHeaderSizeJ2C() { - return 600; //2048; // ??? hack... just needs to be >= actual header size... + return FIRST_PACKET_SIZE; // Hack. just needs to be >= actual header size... } //static @@ -329,9 +368,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) @@ -374,58 +449,82 @@ void LLImageJ2C::setReversible(const BOOL reversible) } -BOOL LLImageJ2C::loadAndValidate(const LLString &filename) +BOOL LLImageJ2C::loadAndValidate(const std::string &filename) { + BOOL res = TRUE; + resetLastError(); S32 file_size = 0; - apr_file_t* apr_file = ll_apr_file_open(filename, LL_APR_RB, &file_size); + LLAPRFile infile ; + infile.open(filename, LL_APR_RB, NULL, &file_size); + apr_file_t* apr_file = infile.getFileHandle() ; if (!apr_file) { setLastError("Unable to open file for reading", filename); - return FALSE; + res = FALSE; } - if (file_size == 0) + else if (file_size == 0) { setLastError("File is empty",filename); - apr_file_close(apr_file); - return FALSE; + res = FALSE; + } + else + { + U8 *data = new U8[file_size]; + apr_size_t bytes_read = file_size; + apr_status_t s = apr_file_read(apr_file, data, &bytes_read); // modifies bytes_read + infile.close() ; + + if (s != APR_SUCCESS || (S32)bytes_read != file_size) + { + delete[] data; + setLastError("Unable to read entire file"); + res = FALSE; + } + else + { + res = validate(data, file_size); + } } - U8 *data = new U8[file_size]; - apr_size_t bytes_read = file_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 (!mLastError.empty()) { - delete[] data; - setLastError("Unable to read entire file"); - return FALSE; + LLImage::setLastError(mLastError); } - apr_file_close(apr_file); - - return validate(data, file_size); + + return res; } BOOL LLImageJ2C::validate(U8 *data, U32 file_size) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); + resetLastError(); + setData(data, file_size); + BOOL res = updateData(); - if ( !res ) + if ( res ) { - return FALSE; + // Check to make sure that this instance has been initialized with data + if (!getData() || (0 == getDataSize())) + { + setLastError("LLImageJ2C uninitialized"); + res = FALSE; + } + else + { + res = mImpl->getMetadata(*this); + } } - - // Check to make sure that this instance has been initialized with data - if (!getData() || (0 == getDataSize())) + + if (!mLastError.empty()) { - setLastError("LLImageJ2C uninitialized"); - return FALSE; + LLImage::setLastError(mLastError); } - - return mImpl->getMetadata(*this); + return res; } void LLImageJ2C::decodeFailed() diff --git a/indra/llimage/llimagej2c.h b/indra/llimage/llimagej2c.h index 35b4d6b8b4..cdb3faa207 100644 --- a/indra/llimage/llimagej2c.h +++ b/indra/llimage/llimagej2c.h @@ -2,30 +2,25 @@ * @file llimagej2c.h * @brief Image implmenation for jpeg2000. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,20 +40,25 @@ public: LLImageJ2C(); // Base class overrides + /*virtual*/ std::string getExtension() { return std::string("j2c"); } /*virtual*/ BOOL updateData(); - /*virtual*/ BOOL decode(LLImageRaw *raw_imagep, F32 decode_time=0.0); - /*virtual*/ BOOL decode(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count); - /*virtual*/ BOOL encode(const LLImageRaw *raw_imagep, F32 encode_time=0.0); + /*virtual*/ BOOL decode(LLImageRaw *raw_imagep, F32 decode_time); + /*virtual*/ BOOL decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count); + /*virtual*/ BOOL encode(const LLImageRaw *raw_imagep, F32 encode_time); /*virtual*/ S32 calcHeaderSize(); /*virtual*/ S32 calcDataSize(S32 discard_level = 0); /*virtual*/ S32 calcDiscardLevelBytes(S32 bytes); /*virtual*/ S8 getRawDiscardLevel(); + // Override these so that we don't try to set a global variable from a DLL + /*virtual*/ void resetLastError(); + /*virtual*/ void setLastError(const std::string& message, const std::string& filename = std::string()); + // Encode with comment text BOOL encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time=0.0); BOOL validate(U8 *data, U32 file_size); - BOOL loadAndValidate(const LLString &filename); + BOOL loadAndValidate(const std::string &filename); // Encode accessors void setReversible(const BOOL reversible); // Use non-lossy? @@ -81,10 +81,15 @@ 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; LLImageJ2CImpl *mImpl; + std::string mLastError; }; // Derive from this class to implement JPEG2000 decoding diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp index f9b36bd1f6..b70f84efc8 100644 --- a/indra/llimage/llimagejpeg.cpp +++ b/indra/llimage/llimagejpeg.cpp @@ -1,30 +1,25 @@ /** * @file llimagejpeg.cpp * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,12 +30,13 @@ #include "llerror.h" -LLImageJPEG::LLImageJPEG() +jmp_buf LLImageJPEG::sSetjmpBuffer ; +LLImageJPEG::LLImageJPEG(S32 quality) : LLImageFormatted(IMG_CODEC_JPEG), mOutputBuffer( NULL ), mOutputBufferSize( 0 ), - mEncodeQuality( 75 ) // on a scale from 1 to 100 + mEncodeQuality( quality ) // on a scale from 1 to 100 { } @@ -76,7 +72,16 @@ BOOL LLImageJPEG::updateData() jerr.error_exit = &LLImageJPEG::errorExit; // Error exit handler: does not return to caller jerr.emit_message = &LLImageJPEG::errorEmitMessage; // Conditionally emit a trace or warning message jerr.output_message = &LLImageJPEG::errorOutputMessage; // Routine that actually outputs a trace or error message - + + // + //try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error + //so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao + // + if(setjmp(sSetjmpBuffer)) + { + jpeg_destroy_decompress(&cinfo); + return FALSE; + } try { // Now we can initialize the JPEG decompression object. @@ -177,6 +182,7 @@ void LLImageJPEG::decodeTermSource (j_decompress_ptr cinfo) } +// Returns true when done, whether or not decode was successful. BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) { llassert_always(raw_image); @@ -187,7 +193,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) if (!getData() || (0 == getDataSize())) { setLastError("LLImageJPEG trying to decode an image with no data!"); - return FALSE; + return TRUE; // done } S32 row_stride = 0; @@ -208,7 +214,15 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) jerr.emit_message = &LLImageJPEG::errorEmitMessage; // Conditionally emit a trace or warning message jerr.output_message = &LLImageJPEG::errorOutputMessage; // Routine that actually outputs a trace or error message - + // + //try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error + //so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao + // + if(setjmp(sSetjmpBuffer)) + { + jpeg_destroy_decompress(&cinfo); + return TRUE; // done + } try { // Now we can initialize the JPEG decompression object. @@ -301,7 +315,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) catch (int) { jpeg_destroy_decompress(&cinfo); - return FALSE; + return TRUE; // done } // Check to see whether any corrupt-data warnings occurred @@ -309,7 +323,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) { // TODO: extract the warning to find out what went wrong. setLastError( "Unable to decode JPEG image."); - return FALSE; + return TRUE; // done } return TRUE; @@ -402,7 +416,7 @@ void LLImageJPEG::errorExit( j_common_ptr cinfo ) jpeg_destroy(cinfo); // Return control to the setjmp point - throw 1; + longjmp(sSetjmpBuffer, 1) ; } // Decide whether to emit a trace or warning message. @@ -447,7 +461,8 @@ void LLImageJPEG::errorOutputMessage( j_common_ptr cinfo ) char buffer[JMSG_LENGTH_MAX]; /* Flawfinder: ignore */ (*cinfo->err->format_message) (cinfo, buffer); - ((LLImageJPEG*) cinfo->client_data)->setLastError( buffer ); + std::string error = buffer ; + LLImage::setLastError(error); BOOL is_decode = (cinfo->is_decompressor != 0); llwarns << "LLImageJPEG " << (is_decode ? "decode " : "encode ") << " failed: " << buffer << llendl; @@ -500,8 +515,11 @@ BOOL LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time ) jerr.emit_message = &LLImageJPEG::errorEmitMessage; // Conditionally emit a trace or warning message jerr.output_message = &LLImageJPEG::errorOutputMessage; // Routine that actually outputs a trace or error message - // Establish the setjmp return context mSetjmpBuffer. Used by library to abort. - if( setjmp(mSetjmpBuffer) ) + // + //try/catch will crash on Mac and Linux if LLImageJPEG::errorExit throws an error + //so as instead, we use setjmp/longjmp to avoid this crash, which is the best we can get. --bao + // + if( setjmp(sSetjmpBuffer) ) { // If we get here, the JPEG code has signaled an error. // We need to clean up the JPEG object, close the input file, and return. diff --git a/indra/llimage/llimagejpeg.h b/indra/llimage/llimagejpeg.h index 0be4002791..7ac7f5d2e0 100644 --- a/indra/llimage/llimagejpeg.h +++ b/indra/llimage/llimagejpeg.h @@ -2,37 +2,32 @@ * @file llimagejpeg.h * @brief This class compresses and decompresses JPEG files * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LL_LLIMAGEJPEG_H #define LL_LLIMAGEJPEG_H -#include <setjmp.h> +#include <csetjmp> #include "llimage.h" @@ -52,11 +47,12 @@ protected: virtual ~LLImageJPEG(); public: - LLImageJPEG(); + LLImageJPEG(S32 quality = 75); + /*virtual*/ std::string getExtension() { return std::string("jpg"); } /*virtual*/ BOOL updateData(); - /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 time=0.0); - /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 time=0.0); + /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 decode_time); + /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 encode_time); void setEncodeQuality( S32 q ) { mEncodeQuality = q; } // on a scale from 1 to 100 S32 getEncodeQuality() { return mEncodeQuality; } @@ -83,8 +79,8 @@ protected: S32 mOutputBufferSize; // bytes in mOuputBuffer S32 mEncodeQuality; // on a scale from 1 to 100 - - jmp_buf mSetjmpBuffer; // To allow the library to abort. +private: + static jmp_buf sSetjmpBuffer; // To allow the library to abort. }; #endif // LL_LLIMAGEJPEG_H diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp index 3e0414fd78..8d493ecde0 100644 --- a/indra/llimage/llimagepng.cpp +++ b/indra/llimage/llimagepng.cpp @@ -2,30 +2,25 @@ * @file llimagepng.cpp * @brief LLImageFormatted glue to encode / decode PNG files. * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,17 +36,12 @@ // LLImagePNG // --------------------------------------------------------------------------- LLImagePNG::LLImagePNG() - : LLImageFormatted(IMG_CODEC_PNG), - mTmpWriteBuffer(NULL) + : LLImageFormatted(IMG_CODEC_PNG) { } LLImagePNG::~LLImagePNG() { - if (mTmpWriteBuffer) - { - delete[] mTmpWriteBuffer; - } } // Virtual @@ -122,27 +112,24 @@ BOOL LLImagePNG::encode(const LLImageRaw* raw_image, F32 encode_time) // Temporary buffer to hold the encoded image. Note: the final image // size should be much smaller due to compression. - if (mTmpWriteBuffer) - { - delete[] mTmpWriteBuffer; - } U32 bufferSize = getWidth() * getHeight() * getComponents() + 1024; - U8* mTmpWriteBuffer = new U8[ bufferSize ]; + U8* tmpWriteBuffer = new U8[ bufferSize ]; // Delegate actual encoding work to wrapper LLPngWrapper pngWrapper; - if (! pngWrapper.writePng(raw_image, mTmpWriteBuffer)) + if (! pngWrapper.writePng(raw_image, tmpWriteBuffer)) { setLastError(pngWrapper.getErrorMessage()); + delete[] tmpWriteBuffer; return FALSE; } // Resize internal buffer and copy from temp U32 encodedSize = pngWrapper.getFinalSize(); allocateData(encodedSize); - memcpy(getData(), mTmpWriteBuffer, encodedSize); + memcpy(getData(), tmpWriteBuffer, encodedSize); - delete[] mTmpWriteBuffer; + delete[] tmpWriteBuffer; return TRUE; } diff --git a/indra/llimage/llimagepng.h b/indra/llimage/llimagepng.h index 7a8e1f93b1..1fbd850a2e 100644 --- a/indra/llimage/llimagepng.h +++ b/indra/llimage/llimagepng.h @@ -1,30 +1,25 @@ /* * @file llimagepng.h * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,12 +37,10 @@ protected: public: LLImagePNG(); - BOOL updateData(); - BOOL decode(LLImageRaw* raw_image, F32 decode_time = 0.0); - BOOL encode(const LLImageRaw* raw_image, F32 encode_time = 0.0); - -private: - U8* mTmpWriteBuffer; + /*virtual*/ std::string getExtension() { return std::string("png"); } + /*virtual*/ BOOL updateData(); + /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 decode_time); + /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 encode_time); }; #endif diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp index 805297f8ee..58426d31fa 100644 --- a/indra/llimage/llimagetga.cpp +++ b/indra/llimage/llimagetga.cpp @@ -1,38 +1,36 @@ /** * @file llimagetga.cpp * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" #include "llimagetga.h" + +#include "lldir.h" #include "llerror.h" #include "llmath.h" +#include "llpointer.h" // For expanding 5-bit pixel values to 8-bit with best rounding // static @@ -63,11 +61,34 @@ LLImageTGA::LLImageTGA() mColorMapStart( 0 ), mColorMapLength( 0 ), mColorMapBytesPerEntry( 0 ), - mIs15Bit( FALSE ) + mIs15Bit( FALSE ), + + mAttributeBits(0), + mColorMapDepth(0), + mColorMapIndexHi(0), + mColorMapIndexLo(0), + mColorMapLengthHi(0), + mColorMapLengthLo(0), + mColorMapType(0), + mDataOffset(0), + mHeightHi(0), + mHeightLo(0), + mIDLength(0), + mImageType(0), + mInterleave(0), + mOriginRightBit(0), + mOriginTopBit(0), + mPixelSize(0), + mWidthHi(0), + mWidthLo(0), + mXOffsetHi(0), + mXOffsetLo(0), + mYOffsetHi(0), + mYOffsetLo(0) { } -LLImageTGA::LLImageTGA(const LLString& file_name) +LLImageTGA::LLImageTGA(const std::string& file_name) : LLImageFormatted(IMG_CODEC_TGA), mColorMap( NULL ), mColorMapStart( 0 ), @@ -80,7 +101,7 @@ LLImageTGA::LLImageTGA(const LLString& file_name) LLImageTGA::~LLImageTGA() { - delete mColorMap; + delete [] mColorMap; } BOOL LLImageTGA::updateData() @@ -1113,7 +1134,7 @@ BOOL LLImageTGA::decodeAndProcess( LLImageRaw* raw_image, F32 domain, F32 weight } // Reads a .tga file and creates an LLImageTGA with its data. -bool LLImageTGA::loadFile( const LLString& path ) +bool LLImageTGA::loadFile( const std::string& path ) { S32 len = path.size(); if( len < 5 ) @@ -1121,14 +1142,13 @@ bool LLImageTGA::loadFile( const LLString& path ) return false; } - LLString extension = path.substr( len - 4, 4 ); - LLString::toLower(extension); - if( ".tga" != extension ) + std::string extension = gDirUtilp->getExtension(path); + if( "tga" != extension ) { return false; } - FILE* file = LLFile::fopen(path.c_str(), "rb"); /* Flawfinder: ignore */ + LLFILE* file = LLFile::fopen(path, "rb"); /* Flawfinder: ignore */ if( !file ) { llwarns << "Couldn't open file " << path << llendl; diff --git a/indra/llimage/llimagetga.h b/indra/llimage/llimagetga.h index 3bfe4e6e21..5da3525149 100644 --- a/indra/llimage/llimagetga.h +++ b/indra/llimage/llimagetga.h @@ -2,30 +2,25 @@ * @file llimagetga.h * @brief Image implementation to compresses and decompressed TGA files. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,8 +38,9 @@ protected: public: LLImageTGA(); - LLImageTGA(const LLString& file_name); + LLImageTGA(const std::string& file_name); + /*virtual*/ std::string getExtension() { return std::string("tga"); } /*virtual*/ BOOL updateData(); /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 decode_time=0.0); /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 encode_time=0.0); @@ -70,7 +66,7 @@ private: void decodeColorMapPixel24(U8* dst, const U8* src); void decodeColorMapPixel32(U8* dst, const U8* src); - bool loadFile(const LLString& file_name); + bool loadFile(const std::string& file_name); private: // Class specific data diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index 61b15b2092..d1c74b6fa1 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -2,30 +2,25 @@ * @file llimageworker.cpp * @brief Base class for images. * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,152 +31,143 @@ //---------------------------------------------------------------------------- -//static -LLWorkerThread* LLImageWorker::sWorkerThread = NULL; -S32 LLImageWorker::sCount = 0; +// MAIN THREAD +LLImageDecodeThread::LLImageDecodeThread(bool threaded) + : LLQueuedThread("imagedecode", threaded) +{ + mCreationMutex = new LLMutex(getAPRPool()); +} + +// MAIN THREAD +// virtual +S32 LLImageDecodeThread::update(U32 max_time_ms) +{ + LLMutexLock lock(mCreationMutex); + for (creation_list_t::iterator iter = mCreationList.begin(); + iter != mCreationList.end(); ++iter) + { + creation_info& info = *iter; + ImageRequest* req = new ImageRequest(info.handle, info.image, + 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); + return res; +} -//static -void LLImageWorker::initClass(LLWorkerThread* workerthread) +LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image, + U32 priority, S32 discard, BOOL needs_aux, Responder* responder) { - sWorkerThread = workerthread; + LLMutexLock lock(mCreationMutex); + handle_t handle = generateHandle(); + mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder)); + return handle; } -//static -void LLImageWorker::cleanupClass() +// Used by unit test only +// Returns the size of the mutex guarded list as an indication of sanity +S32 LLImageDecodeThread::tut_size() +{ + LLMutexLock lock(mCreationMutex); + S32 res = mCreationList.size(); + return res; +} + +LLImageDecodeThread::Responder::~Responder() { } //---------------------------------------------------------------------------- -LLImageWorker::LLImageWorker(LLImageFormatted* image, U32 priority, - S32 discard, - LLPointer<LLResponder> responder) - : LLWorkerClass(sWorkerThread, "Image"), +LLImageDecodeThread::ImageRequest::ImageRequest(handle_t handle, LLImageFormatted* image, + U32 priority, S32 discard, BOOL needs_aux, + LLImageDecodeThread::Responder* responder) + : LLQueuedThread::QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE), mFormattedImage(image), - mDecodedType(-1), mDiscardLevel(discard), - mPriority(priority), + mNeedsAux(needs_aux), + mDecodedRaw(FALSE), + mDecodedAux(FALSE), mResponder(responder) { - ++sCount; } -LLImageWorker::~LLImageWorker() +LLImageDecodeThread::ImageRequest::~ImageRequest() { - mDecodedImage = NULL; + mDecodedImageRaw = NULL; + mDecodedImageAux = NULL; mFormattedImage = NULL; - --sCount; } //---------------------------------------------------------------------------- -//virtual, main thread -void LLImageWorker::startWork(S32 param) -{ - llassert_always(mDecodedImage.isNull()); - mDecodedType = -1; -} -bool LLImageWorker::doWork(S32 param) +// Returns true when done, whether or not decode was successful. +bool LLImageDecodeThread::ImageRequest::processRequest() { - bool decoded = false; - if(mDecodedImage.isNull()) + const F32 decode_time_slice = .1f; + bool done = true; + if (!mDecodedRaw && mFormattedImage.notNull()) { - if (!mFormattedImage->updateData()) - { - mDecodedType = -2; // failed - return true; - } - if (mDiscardLevel >= 0) - { - mFormattedImage->setDiscardLevel(mDiscardLevel); - } - if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents())) + // Decode primary channels + if (mDecodedImageRaw.isNull()) { - decoded = true; // failed - } - else - { - mDecodedImage = new LLImageRaw(); // allow possibly smaller size set during decoding + // parse formatted header + if (!mFormattedImage->updateData()) + { + return true; // done (failed) + } + if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents())) + { + return true; // done (failed) + } + if (mDiscardLevel >= 0) + { + mFormattedImage->setDiscardLevel(mDiscardLevel); + } + mDecodedImageRaw = new LLImageRaw(mFormattedImage->getWidth(), + mFormattedImage->getHeight(), + mFormattedImage->getComponents()); } + done = mFormattedImage->decode(mDecodedImageRaw, decode_time_slice); // 1ms + mDecodedRaw = done; } - if (!decoded) + if (done && mNeedsAux && !mDecodedAux && mFormattedImage.notNull()) { - if (param == 0) + // Decode aux channel + if (!mDecodedImageAux) { - // Decode primary channels - decoded = mFormattedImage->decode(mDecodedImage, .1f); // 1ms - } - else - { - // Decode aux channel - decoded = mFormattedImage->decode(mDecodedImage, .1f, param, param); // 1ms - } - } - if (decoded) - { - // Call the callback immediately; endWork doesn't get called until ckeckWork - if (mResponder.notNull()) - { - bool success = (!wasAborted() && mDecodedImage.notNull() && mDecodedImage->getDataSize() != 0); - mResponder->completed(success); + mDecodedImageAux = new LLImageRaw(mFormattedImage->getWidth(), + mFormattedImage->getHeight(), + 1); } + done = mFormattedImage->decodeChannels(mDecodedImageAux, decode_time_slice, 4, 4); // 1ms + mDecodedAux = done; } - return decoded; -} -void LLImageWorker::endWork(S32 param, bool aborted) -{ - if (mDecodedType != -2) - { - mDecodedType = aborted ? -2 : param; - } + return done; } -//---------------------------------------------------------------------------- - - -BOOL LLImageWorker::requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard) +void LLImageDecodeThread::ImageRequest::finishRequest(bool completed) { - // For most codecs, only mDiscardLevel data is available. - // (see LLImageDXT for exception) - if (discard >= 0 && discard != mFormattedImage->getDiscardLevel()) + if (mResponder.notNull()) { - llerrs << "Request for invalid discard level" << llendl; - } - checkWork(); - if (mDecodedType == -2) - { - return TRUE; // aborted, done - } - if (mDecodedType != channel) - { - if (!haveWork()) - { - addWork(channel, mPriority); - } - return FALSE; - } - else - { - llassert_always(!haveWork()); - llassert_always(mDecodedType == channel); - raw = mDecodedImage; // smart pointer acquires ownership of data - mDecodedImage = NULL; - return TRUE; + bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux); + mResponder->completed(success, mDecodedImageRaw, mDecodedImageAux); } + // Will automatically be deleted } -BOOL LLImageWorker::requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard) +// Used by unit test only +// Checks that a responder exists for this instance so that something can happen when completion is reached +bool LLImageDecodeThread::ImageRequest::tut_isOK() { - if (mFormattedImage->getCodec() == IMG_CODEC_DXT) - { - // special case - LLImageDXT* imagedxt = (LLImageDXT*)((LLImageFormatted*)mFormattedImage); - return imagedxt->getMipData(raw, discard); - } - else - { - return requestDecodedAuxData(raw, 0, discard); - } + return mResponder.notNull(); } diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h index f9c592fa51..c3c92ec832 100644 --- a/indra/llimage/llimageworker.h +++ b/indra/llimage/llimageworker.h @@ -2,30 +2,25 @@ * @file llimageworker.h * @brief Object for managing images and their textures. * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,49 +28,75 @@ #define LL_LLIMAGEWORKER_H #include "llimage.h" +#include "llpointer.h" #include "llworkerthread.h" -class LLImageWorker : public LLWorkerClass +class LLImageDecodeThread : public LLQueuedThread { public: - static void initClass(LLWorkerThread* workerthread); - static void cleanupClass(); - static LLWorkerThread* getWorkerThread() { return sWorkerThread; } + class Responder : public LLThreadSafeRefCount + { + protected: + virtual ~Responder(); + public: + virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) = 0; + }; - // LLWorkerThread -public: - LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard, - LLPointer<LLResponder> responder); - ~LLImageWorker(); + class ImageRequest : public LLQueuedThread::QueuedRequest + { + protected: + virtual ~ImageRequest(); // use deleteRequest() + + public: + ImageRequest(handle_t handle, LLImageFormatted* image, + U32 priority, S32 discard, BOOL needs_aux, + LLImageDecodeThread::Responder* responder); - // called from WORKER THREAD, returns TRUE if done - /*virtual*/ bool doWork(S32 param); - - BOOL requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard = -1); - BOOL requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard = -1); - void releaseDecodedData(); - void cancelDecode(); - -private: - // called from MAIN THREAD - /*virtual*/ void startWork(S32 param); // called from addWork() - /*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() + /*virtual*/ bool processRequest(); + /*virtual*/ void finishRequest(bool completed); -protected: - LLPointer<LLImageFormatted> mFormattedImage; - LLPointer<LLImageRaw> mDecodedImage; - S32 mDecodedType; - S32 mDiscardLevel; - -private: - U32 mPriority; - LLPointer<LLResponder> mResponder; + // Used by unit tests to check the consitency of the request instance + bool tut_isOK(); + + private: + // input + LLPointer<LLImageFormatted> mFormattedImage; + S32 mDiscardLevel; + BOOL mNeedsAux; + // output + LLPointer<LLImageRaw> mDecodedImageRaw; + LLPointer<LLImageRaw> mDecodedImageAux; + BOOL mDecodedRaw; + BOOL mDecodedAux; + LLPointer<LLImageDecodeThread::Responder> mResponder; + }; -protected: - static LLWorkerThread* sWorkerThread; - public: - static S32 sCount; + LLImageDecodeThread(bool threaded = true); + handle_t decodeImage(LLImageFormatted* image, + U32 priority, S32 discard, BOOL needs_aux, + Responder* responder); + S32 update(U32 max_time_ms); + + // Used by unit tests to check the consistency of the thread instance + S32 tut_size(); + +private: + struct creation_info + { + handle_t handle; + LLPointer<LLImageFormatted> image; + U32 priority; + S32 discard; + BOOL needs_aux; + LLPointer<Responder> responder; + creation_info(handle_t h, LLImageFormatted* i, U32 p, S32 d, BOOL aux, Responder* r) + : handle(h), image(i), priority(p), discard(d), needs_aux(aux), responder(r) + {} + }; + typedef std::list<creation_info> creation_list_t; + creation_list_t mCreationList; + LLMutex* mCreationMutex; }; #endif diff --git a/indra/llimage/llmapimagetype.h b/indra/llimage/llmapimagetype.h index b9d20d10c6..0a040d3db9 100644 --- a/indra/llimage/llmapimagetype.h +++ b/indra/llimage/llmapimagetype.h @@ -1,30 +1,25 @@ /** * @file llmapimagetype.h * - * $LicenseInfo:firstyear=2003&license=viewergpl$ - * - * Copyright (c) 2003-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp index 74a09b2106..fe737e2072 100644 --- a/indra/llimage/llpngwrapper.cpp +++ b/indra/llimage/llpngwrapper.cpp @@ -2,30 +2,25 @@ * @file llpngwrapper.cpp * @brief Encapsulates libpng read/write functionality. * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,17 +37,22 @@ LLPngWrapper::LLPngWrapper() : mReadPngPtr( NULL ), - mReadInfoPtr( NULL ), + mReadInfoPtr( NULL ), mWritePngPtr( NULL ), mWriteInfoPtr( NULL ), mRowPointers( NULL ), + mWidth( 0 ), + mHeight( 0 ), mBitDepth( 0 ), mColorType( 0 ), mChannels( 0 ), mInterlaceType( 0 ), mCompressionType( 0 ), mFilterMethod( 0 ), - mFinalSize( 0 ) + mFinalSize( 0 ), + mHasBKGD(false), + mBackgroundColor(), + mGamma(0.f) { } @@ -210,7 +210,7 @@ void LLPngWrapper::normalizeImage() } if (mColorType == PNG_COLOR_TYPE_GRAY && mBitDepth < 8) { - png_set_gray_1_2_4_to_8(mReadPngPtr); + png_set_expand_gray_1_2_4_to_8(mReadPngPtr); } if (mColorType == PNG_COLOR_TYPE_GRAY || mColorType == PNG_COLOR_TYPE_GRAY_ALPHA) @@ -358,7 +358,7 @@ void LLPngWrapper::releaseResources() { if (mReadPngPtr || mReadInfoPtr) { - png_destroy_read_struct(&mReadPngPtr, &mReadInfoPtr, png_infopp_NULL); + png_destroy_read_struct(&mReadPngPtr, &mReadInfoPtr, NULL); mReadPngPtr = NULL; mReadInfoPtr = NULL; } @@ -384,7 +384,7 @@ U32 LLPngWrapper::getFinalSize() } // Get last error message, if any -LLString LLPngWrapper::getErrorMessage() +const std::string& LLPngWrapper::getErrorMessage() { return mErrorMessage; } diff --git a/indra/llimage/llpngwrapper.h b/indra/llimage/llpngwrapper.h index 1c66b8a31c..47a4207d66 100644 --- a/indra/llimage/llpngwrapper.h +++ b/indra/llimage/llpngwrapper.h @@ -1,37 +1,32 @@ /* * @file llpngwrapper.h * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LL_LLPNGWRAPPER_H #define LL_LLPNGWRAPPER_H -#include "libpng12/png.h" +#include "png.h" #include "llimage.h" class LLPngWrapper @@ -52,7 +47,7 @@ public: BOOL readPng(U8* src, LLImageRaw* rawImage, ImageInfo *infop = NULL); BOOL writePng(const LLImageRaw* rawImage, U8* dst); U32 getFinalSize(); - LLString getErrorMessage(); + const std::string& getErrorMessage(); protected: void normalizeImage(); @@ -93,12 +88,12 @@ private: U32 mFinalSize; - BOOL mHasBKGD; + bool mHasBKGD; png_color_16p mBackgroundColor; F64 mGamma; - LLString mErrorMessage; + std::string mErrorMessage; }; #endif diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp new file mode 100644 index 0000000000..a109276709 --- /dev/null +++ b/indra/llimage/tests/llimageworker_test.cpp @@ -0,0 +1,254 @@ +/** + * @file llimageworker_test.cpp + * @author Merov Linden + * @date 2009-04-28 + * + * $LicenseInfo:firstyear=2006&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +// Precompiled header: almost always required for newview cpp files +#include <list> +#include <map> +#include <algorithm> +// Class to test +#include "../llimageworker.h" +// For timer class +#include "../llcommon/lltimer.h" +// Tut header +#include "../test/lltut.h" + +// ------------------------------------------------------------------------------------------- +// Stubbing: Declarations required to link and run the class being tested +// Notes: +// * Add here stubbed implementation of the few classes and methods used in the class to be tested +// * Add as little as possible (let the link errors guide you) +// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code) +// * A simulator for a class can be implemented here. Please comment and document thoroughly. + +LLImageBase::LLImageBase() {} +LLImageBase::~LLImageBase() {} +void LLImageBase::dump() { } +void LLImageBase::sanityCheck() { } +void LLImageBase::deleteData() { } +U8* LLImageBase::allocateData(S32 size) { return NULL; } +U8* LLImageBase::reallocateData(S32 size) { return NULL; } + +LLImageRaw::LLImageRaw(U16 width, U16 height, S8 components) { } +LLImageRaw::~LLImageRaw() { } +void LLImageRaw::deleteData() { } +U8* LLImageRaw::allocateData(S32 size) { return NULL; } +U8* LLImageRaw::reallocateData(S32 size) { return NULL; } + +// End Stubbing +// ------------------------------------------------------------------------------------------- + +// ------------------------------------------------------------------------------------------- +// TUT +// ------------------------------------------------------------------------------------------- + +namespace tut +{ + // Test wrapper declarations + + // Note: We derive the responder class for 2 reasons: + // 1. It's a pure virtual class and we can't compile without completed() being implemented + // 2. We actually need a responder to test that the thread work test completed + // We implement this making no assumption on what's done in the thread or worker + // though, just that the responder's completed() method is called in the end. + // Note on responders: responders are ref counted and *will* be deleted by the request they are + // attached to when the queued request is deleted. The recommended way of using them is to + // create them when creating a request, put a callback method in completed() and not rely on + // anything to survive in the responder object once completed() has been called. Let the request + // do the deletion and clean up itself. + class responder_test : public LLImageDecodeThread::Responder + { + public: + responder_test(bool* res) + { + done = res; + *done = false; + } + virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) + { + *done = true; + } + private: + // This is what can be thought of as the minimal implementation of a responder + // Done will be switched to true when completed() is called and can be tested + // outside the responder. A better way of doing this is to store a callback here. + bool* done; + }; + + // Test wrapper declaration : decode thread + struct imagedecodethread_test + { + // Instance to be tested + LLImageDecodeThread* mThread; + + // Constructor and destructor of the test wrapper + imagedecodethread_test() + { + mThread = NULL; + } + ~imagedecodethread_test() + { + delete mThread; + } + }; + + // Test wrapper declaration : image worker + // Note: this class is not meant to be instantiated outside an LLImageDecodeThread instance + // but it's not a bad idea to get its public API a good shake as part of a thorough unit test set. + // Some gotcha with the destructor though (see below). + struct imagerequest_test + { + // Instance to be tested + LLImageDecodeThread::ImageRequest* mRequest; + bool done; + + // Constructor and destructor of the test wrapper + imagerequest_test() + { + done = false; + mRequest = new LLImageDecodeThread::ImageRequest(0, 0, + LLQueuedThread::PRIORITY_NORMAL, 0, FALSE, + new responder_test(&done)); + } + ~imagerequest_test() + { + // We should delete the object *but*, because its destructor is protected, that cannot be + // done from outside an LLImageDecodeThread instance... So we leak memory here... It's fine... + //delete mRequest; + } + }; + + // Tut templating thingamagic: test group, object and test instance + typedef test_group<imagedecodethread_test> imagedecodethread_t; + typedef imagedecodethread_t::object imagedecodethread_object_t; + tut::imagedecodethread_t tut_imagedecodethread("LLImageDecodeThread"); + + typedef test_group<imagerequest_test> imagerequest_t; + typedef imagerequest_t::object imagerequest_object_t; + tut::imagerequest_t tut_imagerequest("LLImageRequest"); + + // --------------------------------------------------------------------------------------- + // Test functions + // Notes: + // * Test as many as you possibly can without requiring a full blown simulation of everything + // * The tests are executed in sequence so the test instance state may change between calls + // * Remember that you cannot test private methods with tut + // --------------------------------------------------------------------------------------- + + // --------------------------------------------------------------------------------------- + // Test the LLImageDecodeThread interface + // --------------------------------------------------------------------------------------- + // + // Note on Unit Testing Queued Thread Classes + // + // Since methods on such a class are called on a separate loop and that we can't insert tut + // ensure() calls in there, we exercise the class with 2 sets of tests: + // - 1: Test as a single threaded instance: We declare the class but ask for no thread + // to be spawned (easy with LLThreads since there's a boolean argument on the constructor + // just for that). We can then unit test each public method like we do on a normal class. + // - 2: Test as a threaded instance: We let the thread launch and check that its external + // behavior is as expected (i.e. it runs, can accept a work order and processes + // it). Typically though there's no guarantee that this exercises all the methods of the + // class which is why we also need the previous "non threaded" set of unit tests for + // complete coverage. + // + // --------------------------------------------------------------------------------------- + + template<> template<> + void imagedecodethread_object_t::test<1>() + { + // Test a *non threaded* instance of the class + mThread = new LLImageDecodeThread(false); + ensure("LLImageDecodeThread: non threaded constructor failed", mThread != NULL); + // Test that we start with an empty list right at creation + ensure("LLImageDecodeThread: non threaded init state incorrect", mThread->tut_size() == 0); + // Insert something in the queue + bool done = false; + LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, LLQueuedThread::PRIORITY_NORMAL, 0, FALSE, new responder_test(&done)); + // Verifies we got a valid handle + ensure("LLImageDecodeThread: non threaded decodeImage(), returned handle is null", decodeHandle != 0); + // Verifies that we do now have something in the queued list + ensure("LLImageDecodeThread: non threaded decodeImage() insertion in threaded list failed", mThread->tut_size() == 1); + // Trigger queue handling "manually" (on a threaded instance, this is done on the thread loop) + S32 res = mThread->update(0); + // Verifies that we successfully handled the list + ensure("LLImageDecodeThread: non threaded update() list handling test failed", res == 0); + // Verifies that the list is now empty + ensure("LLImageDecodeThread: non threaded update() list emptying test failed", mThread->tut_size() == 0); + } + + template<> template<> + void imagedecodethread_object_t::test<2>() + { + // Test a *threaded* instance of the class + mThread = new LLImageDecodeThread(true); + ensure("LLImageDecodeThread: threaded constructor failed", mThread != NULL); + // Test that we start with an empty list right at creation + ensure("LLImageDecodeThread: threaded init state incorrect", mThread->tut_size() == 0); + // Insert something in the queue + bool done = false; + LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, LLQueuedThread::PRIORITY_NORMAL, 0, FALSE, new responder_test(&done)); + // Verifies we get back a valid handle + ensure("LLImageDecodeThread: threaded decodeImage(), returned handle is null", decodeHandle != 0); + // Wait a little so to simulate the main thread doing something on its main loop... + ms_sleep(500); // 500 milliseconds + // Verifies that the responder has *not* been called yet in the meantime + ensure("LLImageDecodeThread: responder creation failed", done == false); + // Ask the thread to update: that means tells the queue to check itself and creates work requests + mThread->update(1); + // Wait till the thread has time to handle the work order (though it doesn't do much per work order...) + const U32 INCREMENT_TIME = 500; // 500 milliseconds + const U32 MAX_TIME = 20 * INCREMENT_TIME; // Do the loop 20 times max, i.e. wait 10 seconds but no more + U32 total_time = 0; + while ((done == false) && (total_time < MAX_TIME)) + { + ms_sleep(INCREMENT_TIME); + total_time += INCREMENT_TIME; + } + // Verifies that the responder has now been called + ensure("LLImageDecodeThread: threaded work unit not processed", done == true); + } + + // --------------------------------------------------------------------------------------- + // Test the LLImageDecodeThread::ImageRequest interface + // --------------------------------------------------------------------------------------- + + template<> template<> + void imagerequest_object_t::test<1>() + { + // Test that we start with a correct request at creation + ensure("LLImageDecodeThread::ImageRequest::ImageRequest() constructor test failed", mRequest->tut_isOK()); + bool res = mRequest->processRequest(); + // Verifies that we processed the request successfully + ensure("LLImageDecodeThread::ImageRequest::processRequest() processing request test failed", res == true); + // Check that we can call the finishing call safely + try { + mRequest->finishRequest(false); + } catch (...) { + fail("LLImageDecodeThread::ImageRequest::finishRequest() test failed"); + } + } +} |