diff options
Diffstat (limited to 'indra/llimage')
-rw-r--r-- | indra/llimage/llimage.cpp | 276 | ||||
-rw-r--r-- | indra/llimage/llimage.h | 97 | ||||
-rw-r--r-- | indra/llimage/llimagebmp.cpp | 20 | ||||
-rw-r--r-- | indra/llimage/llimagebmp.h | 8 | ||||
-rw-r--r-- | indra/llimage/llimagedimensionsinfo.cpp | 2 | ||||
-rw-r--r-- | indra/llimage/llimagedxt.cpp | 15 | ||||
-rw-r--r-- | indra/llimage/llimagefilter.cpp | 4 | ||||
-rw-r--r-- | indra/llimage/llimagej2c.cpp | 45 | ||||
-rw-r--r-- | indra/llimage/llimagejpeg.cpp | 12 | ||||
-rw-r--r-- | indra/llimage/llimagejpeg.h | 2 | ||||
-rw-r--r-- | indra/llimage/llimagepng.cpp | 8 | ||||
-rw-r--r-- | indra/llimage/llimagetga.cpp | 15 | ||||
-rw-r--r-- | indra/llimage/llimageworker.cpp | 29 | ||||
-rw-r--r-- | indra/llimage/llimageworker.h | 2 | ||||
-rw-r--r-- | indra/llimage/llpngwrapper.cpp | 22 | ||||
-rw-r--r-- | indra/llimage/llpngwrapper.h | 6 | ||||
-rw-r--r-- | indra/llimage/tests/llimageworker_test.cpp | 4 |
17 files changed, 449 insertions, 118 deletions
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index f9393dea54..625dcf7410 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -31,6 +31,7 @@ #include "llmath.h" #include "v4coloru.h" +#include "v3color.h" #include "llimagebmp.h" #include "llimagetga.h" @@ -614,7 +615,6 @@ const std::string& LLImage::getLastError() //static void LLImage::setLastError(const std::string& message) { - LLMutexLock m(sMutex); sLastErrorMessage = message; } @@ -754,7 +754,7 @@ U8* LLImageBase::reallocateData(S32 size) return mData; } -const U8* LLImageBase::getData() const +const U8* LLImageBase::getData() const { if(mBadBufferAllocation) { @@ -765,7 +765,7 @@ const U8* LLImageBase::getData() const return mData; } // read only -U8* LLImageBase::getData() +U8* LLImageBase::getData() { if(mBadBufferAllocation) { @@ -778,7 +778,7 @@ U8* LLImageBase::getData() bool LLImageBase::isBufferInvalid() const { - return mBadBufferAllocation || mData == NULL ; + return mBadBufferAllocation || mData == NULL; } void LLImageBase::setSize(S32 width, S32 height, S32 ncomponents) @@ -854,6 +854,8 @@ LLImageRaw::~LLImageRaw() // virtual U8* LLImageRaw::allocateData(S32 size) { + LLImageDataLock lock(this); + U8* res = LLImageBase::allocateData(size); return res; } @@ -861,12 +863,16 @@ U8* LLImageRaw::allocateData(S32 size) // virtual U8* LLImageRaw::reallocateData(S32 size) { + LLImageDataLock lock(this); + U8* res = LLImageBase::reallocateData(size); return res; } void LLImageRaw::releaseData() { + LLImageDataLock lock(this); + LLImageBase::setSize(0, 0, 0); LLImageBase::setDataAndSize(nullptr, 0); } @@ -874,11 +880,15 @@ void LLImageRaw::releaseData() // virtual void LLImageRaw::deleteData() { + LLImageDataLock lock(this); + LLImageBase::deleteData(); } void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components) -{ +{ + LLImageDataLock lock(this); + if(data == getData()) { return ; @@ -892,6 +902,8 @@ void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components) bool LLImageRaw::resize(U16 width, U16 height, S8 components) { + LLImageDataLock lock(this); + if ((getWidth() == width) && (getHeight() == height) && (getComponents() == components) && !isBufferInvalid()) { return true; @@ -907,6 +919,8 @@ bool LLImageRaw::resize(U16 width, U16 height, S8 components) bool LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height, const U8 *data, U32 stride, bool reverse_y) { + LLImageDataLock lock(this); + if (!getData()) { return false; @@ -934,6 +948,9 @@ bool LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height, void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a) { llassert( getComponents() <= 4 ); + + LLImageDataLock lock(this); + // This is fairly bogus, but it'll do for now. if (isBufferInvalid()) { @@ -974,6 +991,8 @@ void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a) // Reverses the order of the rows in the image void LLImageRaw::verticalFlip() { + LLImageDataLock lock(this); + S32 row_bytes = getWidth() * getComponents(); llassert(row_bytes > 0); std::vector<U8> line_buffer(row_bytes); @@ -989,8 +1008,32 @@ void LLImageRaw::verticalFlip() } +bool LLImageRaw::checkHasTransparentPixels() +{ + if (getComponents() != 4) + { + return false; + } + + U8* data = getData(); + U32 pixels = getWidth() * getHeight(); + + // check alpha channel for all 255 + for (U32 i = 0; i < pixels; ++i) + { + if (data[i * 4 + 3] != 255) + { + return true; + } + } + + return false; +} + bool LLImageRaw::optimizeAwayAlpha() { + LLImageDataLock lock(this); + if (getComponents() == 4) { U8* data = getData(); @@ -1026,8 +1069,38 @@ bool LLImageRaw::optimizeAwayAlpha() return false; } +bool LLImageRaw::makeAlpha() +{ + if (getComponents() == 3) + { + U8* data = getData(); + U32 pixels = getWidth() * getHeight(); + + // alpha channel doesn't exist, make a new copy of data with alpha channel + U8* new_data = (U8*) ll_aligned_malloc_16(getWidth() * getHeight() * 4); + + for (U32 i = 0; i < pixels; ++i) + { + U32 di = i * 4; + U32 si = i * 3; + for (U32 j = 0; j < 3; ++j) + { + new_data[di+j] = data[si+j]; + } + } + + setDataAndSize(new_data, getWidth(), getHeight(), 3); + + return true; + } + + return false; +} + void LLImageRaw::expandToPowerOfTwo(S32 max_dim, bool scale_image) { + LLImageDataLock lock(this); + // Find new sizes S32 new_width = expandDimToPowerOfTwo(getWidth(), max_dim); S32 new_height = expandDimToPowerOfTwo(getHeight(), max_dim); @@ -1037,6 +1110,8 @@ void LLImageRaw::expandToPowerOfTwo(S32 max_dim, bool scale_image) void LLImageRaw::contractToPowerOfTwo(S32 max_dim, bool scale_image) { + LLImageDataLock lock(this); + // Find new sizes S32 new_width = contractDimToPowerOfTwo(getWidth(), MIN_IMAGE_SIZE); S32 new_height = contractDimToPowerOfTwo(getHeight(), MIN_IMAGE_SIZE); @@ -1086,6 +1161,8 @@ S32 LLImageRaw::contractDimToPowerOfTwo(S32 curr_dim, S32 min_dim) void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim) { + LLImageDataLock lock(this); + // Find new sizes S32 new_width = biasedDimToPowerOfTwo(getWidth(),max_dim); S32 new_height = biasedDimToPowerOfTwo(getHeight(),max_dim); @@ -1093,6 +1170,7 @@ void LLImageRaw::biasedScaleToPowerOfTwo(S32 max_dim) scale( new_width, new_height ); } +// static // Calculates (U8)(255*(a/255.f)*(b/255.f) + 0.5f). Thanks, Jim Blinn! inline U8 LLImageRaw::fastFractionalMult( U8 a, U8 b ) { @@ -1101,16 +1179,19 @@ inline U8 LLImageRaw::fastFractionalMult( U8 a, U8 b ) } -void LLImageRaw::composite( LLImageRaw* src ) +void LLImageRaw::composite( const LLImageRaw* src ) { LLImageRaw* dst = this; // Just for clarity. + LLImageDataSharedLock lockIn(src); + LLImageDataLock lockOut(this); + if (!validateSrcAndDst("LLImageRaw::composite", src, dst)) { return; } - llassert(3 == src->getComponents()); + llassert((3 == src->getComponents()) || (4 == src->getComponents())); llassert(3 == dst->getComponents()); if( 3 == dst->getComponents() ) @@ -1143,12 +1224,14 @@ void LLImageRaw::composite( LLImageRaw* src ) // Src and dst can be any size. Src has 4 components. Dst has 3 components. -void LLImageRaw::compositeScaled4onto3(LLImageRaw* src) +void LLImageRaw::compositeScaled4onto3(const LLImageRaw* src) { LL_INFOS() << "compositeScaled4onto3" << LL_ENDL; LLImageRaw* dst = this; // Just for clarity. + LLImageDataLock lock(this); + llassert( (4 == src->getComponents()) && (3 == dst->getComponents()) ); S32 temp_data_size = src->getWidth() * dst->getHeight() * src->getComponents(); @@ -1170,14 +1253,16 @@ void LLImageRaw::compositeScaled4onto3(LLImageRaw* src) // Src and dst are same size. Src has 4 components. Dst has 3 components. -void LLImageRaw::compositeUnscaled4onto3( LLImageRaw* src ) +void LLImageRaw::compositeUnscaled4onto3( const LLImageRaw* src ) { LLImageRaw* dst = this; // Just for clarity. + LLImageDataLock lock(this); + llassert( (3 == src->getComponents()) || (4 == src->getComponents()) ); llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); - U8* src_data = src->getData(); + const U8* src_data = src->getData(); U8* dst_data = dst->getData(); S32 pixels = getWidth() * getHeight(); while( pixels-- ) @@ -1207,10 +1292,13 @@ void LLImageRaw::compositeUnscaled4onto3( LLImageRaw* src ) } -void LLImageRaw::copyUnscaledAlphaMask( LLImageRaw* src, const LLColor4U& fill) +void LLImageRaw::copyUnscaledAlphaMask( const LLImageRaw* src, const LLColor4U& fill) { LLImageRaw* dst = this; // Just for clarity. + LLImageDataSharedLock lockIn(src); + LLImageDataLock lockOut(this); + if (!validateSrcAndDst("LLImageRaw::copyUnscaledAlphaMask", src, dst)) { return; @@ -1221,7 +1309,7 @@ void LLImageRaw::copyUnscaledAlphaMask( LLImageRaw* src, const LLColor4U& fill) llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); S32 pixels = getWidth() * getHeight(); - U8* src_data = src->getData(); + const U8* src_data = src->getData(); U8* dst_data = dst->getData(); for ( S32 i = 0; i < pixels; i++ ) { @@ -1238,6 +1326,8 @@ void LLImageRaw::copyUnscaledAlphaMask( LLImageRaw* src, const LLColor4U& fill) // Fill the buffer with a constant color void LLImageRaw::fill( const LLColor4U& color ) { + LLImageDataLock lock(this); + if (isBufferInvalid()) { LL_WARNS() << "Invalid image buffer" << LL_ENDL; @@ -1268,6 +1358,30 @@ void LLImageRaw::fill( const LLColor4U& color ) } } +void LLImageRaw::tint( const LLColor3& color ) +{ + llassert( (3 == getComponents()) || (4 == getComponents()) ); + if (isBufferInvalid()) + { + LL_WARNS() << "Invalid image buffer" << LL_ENDL; + return; + } + + S32 pixels = getWidth() * getHeight(); + const S32 components = getComponents(); + U8* data = getData(); + for( S32 i = 0; i < pixels; i++ ) + { + const float c0 = data[0] * color.mV[0]; + const float c1 = data[1] * color.mV[1]; + const float c2 = data[2] * color.mV[2]; + data[0] = llclamp((U8)c0, 0, 255); + data[1] = llclamp((U8)c1, 0, 255); + data[2] = llclamp((U8)c2, 0, 255); + data += components; + } +} + LLPointer<LLImageRaw> LLImageRaw::duplicate() { if(getNumRefs() < 2) @@ -1275,16 +1389,21 @@ LLPointer<LLImageRaw> LLImageRaw::duplicate() return this; //nobody else refences to this image, no need to duplicate. } + LLImageDataSharedLock lock(this); + //make a duplicate LLPointer<LLImageRaw> dup = new LLImageRaw(getData(), getWidth(), getHeight(), getComponents()); return dup; } // Src and dst can be any size. Src and dst can each have 3 or 4 components. -void LLImageRaw::copy(LLImageRaw* src) +void LLImageRaw::copy(const LLImageRaw* src) { LLImageRaw* dst = this; // Just for clarity. + LLImageDataSharedLock lockIn(src); + LLImageDataLock lockOut(this); + if (!validateSrcAndDst("LLImageRaw::copy", src, dst)) { return; @@ -1330,10 +1449,12 @@ void LLImageRaw::copy(LLImageRaw* src) } // Src and dst are same size. Src and dst have same number of components. -void LLImageRaw::copyUnscaled(LLImageRaw* src) +void LLImageRaw::copyUnscaled(const LLImageRaw* src) { LLImageRaw* dst = this; // Just for clarity. + LLImageDataLock lock(this); + llassert( (1 == src->getComponents()) || (3 == src->getComponents()) || (4 == src->getComponents()) ); llassert( src->getComponents() == dst->getComponents() ); llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); @@ -1343,7 +1464,7 @@ void LLImageRaw::copyUnscaled(LLImageRaw* src) // Src and dst can be any size. Src has 3 components. Dst has 4 components. -void LLImageRaw::copyScaled3onto4(LLImageRaw* src) +void LLImageRaw::copyScaled3onto4(const LLImageRaw* src) { llassert( (3 == src->getComponents()) && (4 == getComponents()) ); @@ -1355,7 +1476,7 @@ void LLImageRaw::copyScaled3onto4(LLImageRaw* src) // Src and dst can be any size. Src has 4 components. Dst has 3 components. -void LLImageRaw::copyScaled4onto3(LLImageRaw* src) +void LLImageRaw::copyScaled4onto3(const LLImageRaw* src) { llassert( (4 == src->getComponents()) && (3 == getComponents()) ); @@ -1367,15 +1488,17 @@ void LLImageRaw::copyScaled4onto3(LLImageRaw* src) // Src and dst are same size. Src has 4 components. Dst has 3 components. -void LLImageRaw::copyUnscaled4onto3( LLImageRaw* src ) +void LLImageRaw::copyUnscaled4onto3( const LLImageRaw* src ) { LLImageRaw* dst = this; // Just for clarity. + LLImageDataLock lock(this); + llassert( (3 == dst->getComponents()) && (4 == src->getComponents()) ); llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); S32 pixels = getWidth() * getHeight(); - U8* src_data = src->getData(); + const U8* src_data = src->getData(); U8* dst_data = dst->getData(); for( S32 i=0; i<pixels; i++ ) { @@ -1389,15 +1512,18 @@ void LLImageRaw::copyUnscaled4onto3( LLImageRaw* src ) // Src and dst are same size. Src has 3 components. Dst has 4 components. -void LLImageRaw::copyUnscaled3onto4( LLImageRaw* src ) +void LLImageRaw::copyUnscaled3onto4( const LLImageRaw* src ) { LLImageRaw* dst = this; // Just for clarity. + + LLImageDataLock lock(this); + llassert( 3 == src->getComponents() ); llassert( 4 == dst->getComponents() ); llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); S32 pixels = getWidth() * getHeight(); - U8* src_data = src->getData(); + const U8* src_data = src->getData(); U8* dst_data = dst->getData(); for( S32 i=0; i<pixels; i++ ) { @@ -1412,10 +1538,13 @@ 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 ) +void LLImageRaw::copyScaled( const LLImageRaw* src ) { LLImageRaw* dst = this; // Just for clarity. + LLImageDataSharedLock lockIn(src); + LLImageDataLock lockOut(this); + if (!validateSrcAndDst("LLImageRaw::copyScaled", src, dst)) { return; @@ -1457,6 +1586,8 @@ void LLImageRaw::copyScaled( LLImageRaw* src ) bool LLImageRaw::scale( S32 new_width, S32 new_height, bool scale_image_data ) { + LLImageDataLock lock(this); + S32 components = getComponents(); if (components != 1 && components != 3 && components != 4) { @@ -1543,6 +1674,8 @@ LLPointer<LLImageRaw> LLImageRaw::scaled(S32 new_width, S32 new_height) { LLPointer<LLImageRaw> result; + LLImageDataLock lock(this); + S32 components = getComponents(); if (components != 1 && components != 3 && components != 4) { @@ -1588,7 +1721,7 @@ LLPointer<LLImageRaw> LLImageRaw::scaled(S32 new_width, S32 new_height) return result; } -void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ) +void LLImageRaw::copyLineScaled( const U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ) { const S32 components = getComponents(); llassert( components >= 1 && components <= 4 ); @@ -1615,7 +1748,7 @@ void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixe S32 t0 = x * out_pixel_step * components; S32 t1 = index0 * in_pixel_step * components; U8* outp = out + t0; - U8* inp = in + t1; + const U8* inp = in + t1; for (S32 i = 0; i < components; ++i) { *outp = *inp; @@ -1703,7 +1836,7 @@ void LLImageRaw::copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixe } } -void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len ) +void LLImageRaw::compositeRowScaled4onto3( const U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len ) { llassert( getComponents() == 3 ); @@ -1799,8 +1932,78 @@ void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S3 } } -bool LLImageRaw::validateSrcAndDst(std::string func, LLImageRaw* src, LLImageRaw* dst) + +void LLImageRaw::addEmissive(LLImageRaw* src) +{ + LLImageRaw* dst = this; // Just for clarity. + + if (!validateSrcAndDst(__FUNCTION__, src, dst)) + { + return; + } + + llassert((3 == src->getComponents()) || (4 == src->getComponents())); + llassert(3 == dst->getComponents()); + + if( 3 == dst->getComponents() ) + { + if( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ) + { + addEmissiveUnscaled(src); + } + else + { + addEmissiveScaled(src); + } + } +} + +void LLImageRaw::addEmissiveUnscaled(LLImageRaw* src) { + LLImageRaw* dst = this; // Just for clarity. + + llassert((3 == src->getComponents()) || (4 == src->getComponents())); + llassert((3 == dst->getComponents()) || (4 == dst->getComponents())); + llassert( (src->getWidth() == dst->getWidth()) && (src->getHeight() == dst->getHeight()) ); + + U8* const src_data = src->getData(); + U8* const dst_data = dst->getData(); + for(S32 y = 0; y < dst->getHeight(); ++y) + { + const S32 src_row_offset = src->getComponents() * src->getWidth() * y; + const S32 dst_row_offset = dst->getComponents() * dst->getWidth() * y; + for (S32 x = 0; x < dst->getWidth(); ++x) + { + const S32 src_offset = src_row_offset + (x * src->getComponents()); + const S32 dst_offset = dst_row_offset + (x * dst->getComponents()); + U8* const src_pixel = src_data + src_offset; + U8* const dst_pixel = dst_data + dst_offset; + dst_pixel[0] = llmin(255, dst_pixel[0] + src_pixel[0]); + dst_pixel[1] = llmin(255, dst_pixel[1] + src_pixel[1]); + dst_pixel[2] = llmin(255, dst_pixel[2] + src_pixel[2]); + } + } +} + +void LLImageRaw::addEmissiveScaled(LLImageRaw* src) +{ + LLImageRaw* dst = this; // Just for clarity. + + llassert( (4 == src->getComponents()) && (3 == dst->getComponents()) ); + + LLImageRaw temp(dst->getWidth(), dst->getHeight(), dst->getComponents()); + llassert_always(temp.getDataSize() > 0); + temp.copyScaled(src); + + dst->addEmissiveUnscaled(&temp); +} + +// static +bool LLImageRaw::validateSrcAndDst(std::string func, const LLImageRaw* src, const LLImageRaw* dst) +{ + LLImageDataSharedLock lockIn(src); + LLImageDataLock lockOut(dst); + if (!src || !dst || src->isBufferInvalid() || dst->isBufferInvalid()) { LL_WARNS() << func << ": Source: "; @@ -2113,6 +2316,8 @@ bool LLImageFormatted::decodeChannels(LLImageRaw* raw_image,F32 decode_time, S3 // virtual U8* LLImageFormatted::allocateData(S32 size) { + LLImageDataLock lock(this); + U8* res = LLImageBase::allocateData(size); // calls deleteData() sGlobalFormattedMemory += getDataSize(); return res; @@ -2121,6 +2326,8 @@ U8* LLImageFormatted::allocateData(S32 size) // virtual U8* LLImageFormatted::reallocateData(S32 size) { + LLImageDataLock lock(this); + sGlobalFormattedMemory -= getDataSize(); U8* res = LLImageBase::reallocateData(size); sGlobalFormattedMemory += getDataSize(); @@ -2130,6 +2337,12 @@ U8* LLImageFormatted::reallocateData(S32 size) // virtual void LLImageFormatted::deleteData() { + LLImageDataLock lock(this); + + if (mDecoding) + { + LL_ERRS() << "LLImageFormatted::deleteData() is called during decoding" << LL_ENDL; + } sGlobalFormattedMemory -= getDataSize(); LLImageBase::deleteData(); } @@ -2155,6 +2368,8 @@ void LLImageFormatted::sanityCheck() bool LLImageFormatted::copyData(U8 *data, S32 size) { + LLImageDataLock lock(this); + if ( data && ((data != getData()) || (size != getDataSize())) ) { deleteData(); @@ -2167,6 +2382,8 @@ bool LLImageFormatted::copyData(U8 *data, S32 size) // LLImageFormatted becomes the owner of data void LLImageFormatted::setData(U8 *data, S32 size) { + LLImageDataLock lock(this); + if (data && data != getData()) { deleteData(); @@ -2180,6 +2397,8 @@ void LLImageFormatted::appendData(U8 *data, S32 size) { if (data) { + LLImageDataLock lock(this); + if (!getData()) { setData(data, size); @@ -2221,6 +2440,9 @@ bool LLImageFormatted::load(const std::string &filename, int load_size) { load_size = file_size; } + + LLImageDataLock lock(this); + bool res; U8 *data = allocateData(load_size); if (data) @@ -2258,7 +2480,9 @@ bool LLImageFormatted::save(const std::string &filename) setLastError("Unable to open file for writing", filename); return false; } - + + LLImageDataSharedLock lock(this); + S32 result = outfile.write(getData(), getDataSize()); outfile.close() ; return (result != 0); diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 8f9e1b3c54..e3fbe68d7b 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -33,7 +33,7 @@ #include "lltrace.h" const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2 -const S32 MAX_IMAGE_MIP = 11; // 2048x2048 +const S32 MAX_IMAGE_MIP = 12; // 4096x4096 // *TODO : Use MAX_IMAGE_MIP as max discard level and modify j2c management so that the number // of levels is read from the header's file, not inferred from its size. @@ -44,7 +44,7 @@ const S32 MAX_DISCARD_LEVEL = 5; // and declared right here. Some come from the JPEG2000 spec, some conventions specific to SL. const S32 MAX_DECOMPOSITION_LEVELS = 32; // Number of decomposition levels cannot exceed 32 according to jpeg2000 spec const S32 MIN_DECOMPOSITION_LEVELS = 5; // the SL viewer will *crash* trying to decode images with fewer than 5 decomposition levels (unless image is small that is) -const S32 MAX_PRECINCT_SIZE = 2048; // No reason to be bigger than MAX_IMAGE_SIZE +const S32 MAX_PRECINCT_SIZE = 4096; // No reason to be bigger than MAX_IMAGE_SIZE const S32 MIN_PRECINCT_SIZE = 4; // Can't be smaller than MIN_BLOCK_SIZE const S32 MAX_BLOCK_SIZE = 64; // Max total block size is 4096, hence 64x64 when using square blocks const S32 MIN_BLOCK_SIZE = 4; // Min block dim is 4 according to jpeg2000 spec @@ -52,11 +52,11 @@ const S32 MIN_LAYER_SIZE = 2000; // Size of the first quality layer (after hea const S32 MAX_NB_LAYERS = 64; // Max number of layers we'll entertain in SL (practical limit) const S32 MIN_IMAGE_SIZE = (1<<MIN_IMAGE_MIP); // 4, only used for expand/contract power of 2 -const S32 MAX_IMAGE_SIZE = (1<<MAX_IMAGE_MIP); // 2048 +const S32 MAX_IMAGE_SIZE = (1<<MAX_IMAGE_MIP); // 4096 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; //2048 * 2048 * 8 = 16 MB +const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS; //4096 * 4096 * 8 = 128 MB // Note! These CANNOT be changed without modifying simulator code // *TODO: change both to 1024 when SIM texture fetching is deprecated @@ -71,6 +71,7 @@ const S32 HTTP_PACKET_SIZE = 1496; class LLImageFormatted; class LLImageRaw; class LLColor4U; +class LLColor3; typedef enum e_image_codec { @@ -116,7 +117,11 @@ class LLImageBase { protected: virtual ~LLImageBase(); - + + virtual void deleteData(); + virtual U8* allocateData(S32 size = -1); + virtual U8* reallocateData(S32 size = -1); + public: LLImageBase(); @@ -126,10 +131,6 @@ public: TYPE_AVATAR_BAKE = 1, }; - virtual void deleteData(); - virtual U8* allocateData(S32 size = -1); - virtual U8* reallocateData(S32 size = -1); - virtual void dump(); virtual void sanityCheck(); @@ -171,10 +172,27 @@ private: S8 mComponents; - bool mBadBufferAllocation ; - bool mAllowOverSize ; + bool mBadBufferAllocation; + bool mAllowOverSize; + +private: + mutable LLSharedMutex mDataMutex; + +public: + template<bool SHARED> + class DataLock : LLSharedMutexLockTemplate<SHARED> + { + public: + DataLock(const LLImageBase* image) + : LLSharedMutexLockTemplate<SHARED>(image ? &image->mDataMutex : nullptr) + { + } + }; }; +using LLImageDataLock = LLImageBase::DataLock<false>; +using LLImageDataSharedLock = LLImageBase::DataLock<true>; + // Raw representation of an image (used for textures, and other uncompressed formats class LLImageRaw : public LLImageBase { @@ -209,9 +227,13 @@ public: void verticalFlip(); + // Returns true if the image is not fully opaque + bool checkHasTransparentPixels(); // if the alpha channel is all 100% opaque, delete it // returns true if alpha channel was deleted bool optimizeAwayAlpha(); + // Create an alpha channel if this image doesn't have one + bool makeAlpha(); static S32 biasedDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE); static S32 expandDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE); @@ -225,57 +247,66 @@ public: // Fill the buffer with a constant color void fill( const LLColor4U& color ); + // Multiply this raw image by the given color + void tint( const LLColor3& color ); + // Copy operations //duplicate this raw image if refCount > 1. LLPointer<LLImageRaw> duplicate(); // Src and dst can be any size. Src and dst can each have 3 or 4 components. - void copy( LLImageRaw* src ); + void copy( const LLImageRaw* src ); // Src and dst are same size. Src and dst have same number of components. - void copyUnscaled( LLImageRaw* src ); + void copyUnscaled( const LLImageRaw* src ); // Src and dst are same size. Src has 4 components. Dst has 3 components. - void copyUnscaled4onto3( LLImageRaw* src ); + void copyUnscaled4onto3( const LLImageRaw* src ); // Src and dst are same size. Src has 3 components. Dst has 4 components. - void copyUnscaled3onto4( LLImageRaw* src ); + void copyUnscaled3onto4( const LLImageRaw* src ); // Src and dst are same size. Src has 1 component. Dst has 4 components. // Alpha component is set to source alpha mask component. // RGB components are set to fill color. - void copyUnscaledAlphaMask( LLImageRaw* src, const LLColor4U& fill); + void copyUnscaledAlphaMask( const LLImageRaw* src, const LLColor4U& fill); // Src and dst can be any size. Src and dst have same number of components. - void copyScaled( LLImageRaw* src ); - - // Src and dst can be any size. Src has 3 components. Dst has 4 components. - void copyScaled3onto4( LLImageRaw* src ); - - // Src and dst can be any size. Src has 4 components. Dst has 3 components. - void copyScaled4onto3( LLImageRaw* src ); + void copyScaled( const LLImageRaw* src ); // Composite operations // Src and dst can be any size. Src and dst can each have 3 or 4 components. - void composite( LLImageRaw* src ); - + void composite( const LLImageRaw* src ); + + // Emissive operations used by minimap + // Roughly emulates GLTF emissive texture, but is not GLTF-compliant + // *TODO: Remove in favor of shader + void addEmissive(LLImageRaw* src); + void addEmissiveScaled(LLImageRaw* src); + void addEmissiveUnscaled(LLImageRaw* src); +protected: // Src and dst can be any size. Src has 4 components. Dst has 3 components. - void compositeScaled4onto3( LLImageRaw* src ); + void compositeScaled4onto3( const LLImageRaw* src ); // Src and dst are same size. Src has 4 components. Dst has 3 components. - void compositeUnscaled4onto3( LLImageRaw* src ); + void compositeUnscaled4onto3( const LLImageRaw* src ); + + // Src and dst can be any size. Src has 3 components. Dst has 4 components. + void copyScaled3onto4( const LLImageRaw* src ); + + // Src and dst can be any size. Src has 4 components. Dst has 3 components. + void copyScaled4onto3( const LLImageRaw* src ); -protected: // Create an image from a local file (generally used in tools) //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 ); + void copyLineScaled( const U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step ); + void compositeRowScaled4onto3( const U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len ); - U8 fastFractionalMult(U8 a,U8 b); + static U8 fastFractionalMult(U8 a, U8 b); void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ; @@ -283,7 +314,7 @@ public: static S32 sRawImageCount; private: - bool validateSrcAndDst(std::string func, LLImageRaw* src, LLImageRaw* dst); + static bool validateSrcAndDst(std::string func, const LLImageRaw* src, const LLImageRaw* dst); }; // Compressed representation of image. @@ -356,7 +387,7 @@ protected: S8 mDecoded; // unused, but changing LLImage layout requires recompiling static Mac/Linux libs. 2009-01-30 JC S8 mDiscardLevel; // Current resolution level worked on. 0 = full res, 1 = half res, 2 = quarter res, etc... S8 mLevels; // Number of resolution levels in that image. Min is 1. 0 means unknown. - + public: static S32 sGlobalFormattedMemory; }; diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp index cdea0da68d..d0881bb9ff 100644 --- a/indra/llimage/llimagebmp.cpp +++ b/indra/llimage/llimagebmp.cpp @@ -96,6 +96,8 @@ bool LLImageBMP::updateData() { resetLastError(); + LLImageDataLock lock(this); + // Check to make sure that this instance has been initialized with data U8* mdata = getData(); if (!mdata || (0 == getDataSize())) @@ -337,8 +339,11 @@ bool LLImageBMP::decode(LLImageRaw* raw_image, F32 decode_time) resetLastError(); + LLImageDataLock lockIn(this); + LLImageDataLock lockOut(raw_image); + // Check to make sure that this instance has been initialized with data - U8* mdata = getData(); + const U8* mdata = getData(); if (!mdata || (0 == getDataSize())) { setLastError("llimagebmp trying to decode an image with no data!"); @@ -351,7 +356,7 @@ bool LLImageBMP::decode(LLImageRaw* raw_image, F32 decode_time) return false; } - U8* src = mdata + mBitmapOffset; + const U8* src = mdata + mBitmapOffset; U8* dst = raw_image->getData(); bool success = false; @@ -398,7 +403,7 @@ U32 LLImageBMP::countTrailingZeros( U32 m ) } -bool LLImageBMP::decodeColorMask16( U8* dst, U8* src ) +bool LLImageBMP::decodeColorMask16( U8* dst, const U8* src ) { llassert( 16 == mBitsPerPixel ); @@ -434,7 +439,7 @@ bool LLImageBMP::decodeColorMask16( U8* dst, U8* src ) return true; } -bool LLImageBMP::decodeColorMask32( U8* dst, U8* src ) +bool LLImageBMP::decodeColorMask32( U8* dst, const U8* src ) { // Note: alpha is not supported @@ -478,7 +483,7 @@ bool LLImageBMP::decodeColorMask32( U8* dst, U8* src ) } -bool LLImageBMP::decodeColorTable8( U8* dst, U8* src ) +bool LLImageBMP::decodeColorTable8( U8* dst, const U8* src ) { llassert( (8 == mBitsPerPixel) && (mColorPaletteColors >= 256) ); @@ -508,7 +513,7 @@ bool LLImageBMP::decodeColorTable8( U8* dst, U8* src ) } -bool LLImageBMP::decodeTruecolor24( U8* dst, U8* src ) +bool LLImageBMP::decodeTruecolor24( U8* dst, const U8* src ) { llassert( 24 == mBitsPerPixel ); llassert( 3 == getComponents() ); @@ -542,6 +547,9 @@ bool LLImageBMP::encode(const LLImageRaw* raw_image, F32 encode_time) resetLastError(); + LLImageDataSharedLock lockIn(raw_image); + LLImageDataLock lockOut(this); + S32 src_components = raw_image->getComponents(); S32 dst_components = ( src_components < 3 ) ? 1 : 3; diff --git a/indra/llimage/llimagebmp.h b/indra/llimage/llimagebmp.h index 6a5fa4697d..295f96e541 100644 --- a/indra/llimage/llimagebmp.h +++ b/indra/llimage/llimagebmp.h @@ -45,10 +45,10 @@ public: /*virtual*/ bool encode(const LLImageRaw* raw_image, F32 encode_time); protected: - bool decodeColorTable8( U8* dst, U8* src ); - bool decodeColorMask16( U8* dst, U8* src ); - bool decodeTruecolor24( U8* dst, U8* src ); - bool decodeColorMask32( U8* dst, U8* src ); + bool decodeColorTable8( U8* dst, const U8* src ); + bool decodeColorMask16( U8* dst, const U8* src ); + bool decodeTruecolor24( U8* dst, const U8* src ); + bool decodeColorMask32( U8* dst, const U8* src ); U32 countTrailingZeros( U32 m ); diff --git a/indra/llimage/llimagedimensionsinfo.cpp b/indra/llimage/llimagedimensionsinfo.cpp index 9dd69ff132..c5e4b76012 100644 --- a/indra/llimage/llimagedimensionsinfo.cpp +++ b/indra/llimage/llimagedimensionsinfo.cpp @@ -201,7 +201,7 @@ bool LLImageDimensionsInfo::getImageDimensionsJpeg() jpeg_create_decompress (&cinfo); jpeg_stdio_src (&cinfo, fp); - jpeg_read_header (&cinfo, TRUE); + jpeg_read_header (&cinfo, true); cinfo.out_color_space = JCS_RGB; jpeg_start_decompress (&cinfo); diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index ae76c5243f..07e44c615c 100644 --- a/indra/llimage/llimagedxt.cpp +++ b/indra/llimage/llimagedxt.cpp @@ -176,6 +176,8 @@ bool LLImageDXT::updateData() { resetLastError(); + LLImageDataLock lock(this); + U8* data = getData(); S32 data_size = getDataSize(); @@ -268,7 +270,10 @@ bool LLImageDXT::decode(LLImageRaw* raw_image, F32 time) LL_WARNS() << "Attempt to decode compressed LLImageDXT to Raw (unsupported)" << LL_ENDL; return false; } - + + LLImageDataSharedLock lockIn(this); + LLImageDataLock lockOut(raw_image); + S32 width = getWidth(), height = getHeight(); S32 ncomponents = getComponents(); U8* data = NULL; @@ -309,6 +314,9 @@ bool LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard) { LL_ERRS() << "Request for invalid discard level" << LL_ENDL; } + + LLImageDataSharedLock lock(this); + U8* data = getData() + getMipOffset(discard); S32 width = 0; S32 height = 0; @@ -339,6 +347,8 @@ bool LLImageDXT::encodeDXT(const LLImageRaw* raw_image, F32 time, bool explicit_ return 0; } + LLImageDataLock lock(this); + S32 width = raw_image->getWidth(); S32 height = raw_image->getHeight(); @@ -430,6 +440,9 @@ bool LLImageDXT::convertToDXR() return false; } mFileFormat = newformat; + + LLImageDataLock lock(this); + S32 width = getWidth(), height = getHeight(); S32 nmips = calcNumMips(width,height); S32 total_bytes = getDataSize(); diff --git a/indra/llimage/llimagefilter.cpp b/indra/llimage/llimagefilter.cpp index 41adc7be9a..61c2e1d742 100644 --- a/indra/llimage/llimagefilter.cpp +++ b/indra/llimage/llimagefilter.cpp @@ -87,7 +87,9 @@ LLImageFilter::~LLImageFilter() void LLImageFilter::executeFilter(LLPointer<LLImageRaw> raw_image) { mImage = raw_image; - + + LLImageDataLock lock(mImage); + //std::cout << "Filter : size = " << mFilterData.size() << std::endl; for (S32 i = 0; i < mFilterData.size(); ++i) { diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 68598589b8..382da40dcf 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -107,6 +107,8 @@ bool LLImageJ2C::updateData() bool res = true; resetLastError(); + LLImageDataLock lock(this); + // Check to make sure that this instance has been initialized with data if (!getData() || (getDataSize() < 16)) { @@ -157,36 +159,48 @@ bool LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LLTimer elapsed; - bool res = true; - resetLastError(); - // Check to make sure that this instance has been initialized with data - if (!getData() || (getDataSize() < 16)) + bool res; { - setLastError("LLImageJ2C uninitialized"); - res = true; // done - } - else - { - // Update the raw discard level - updateRawDiscardLevel(); + LLImageDataLock lock(this); + mDecoding = true; - res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count); + // Check to make sure that this instance has been initialized with data + if (!getData() || (getDataSize() < 16)) + { + setLastError("LLImageJ2C uninitialized"); + res = true; // done + } + else + { + // Update the raw discard level + updateRawDiscardLevel(); + res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count); + } } - + if (res) { if (!mDecoding) { // Failed raw_imagep->deleteData(); + res = false; } else { mDecoding = false; } } + else + { + if (mDecoding) + { + LL_WARNS() << "decodeImpl failed but mDecoding is true" << LL_ENDL; + mDecoding = false; + } + } if (!mLastError.empty()) { @@ -406,9 +420,10 @@ bool LLImageJ2C::loadAndValidate(const std::string &filename) bool LLImageJ2C::validate(U8 *data, U32 file_size) { - resetLastError(); - + + LLImageDataLock lock(this); + setData(data, file_size); bool res = updateData(); diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp index 32a5472ec8..a35171601a 100644 --- a/indra/llimage/llimagejpeg.cpp +++ b/indra/llimage/llimagejpeg.cpp @@ -50,6 +50,8 @@ bool LLImageJPEG::updateData() { resetLastError(); + LLImageDataLock lock(this); + // Check to make sure that this instance has been initialized with data if (!getData() || (0 == getDataSize())) { @@ -188,7 +190,10 @@ bool LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time) llassert_always(raw_image); resetLastError(); - + + LLImageDataLock lockIn(this); + LLImageDataLock lockOut(raw_image); + // Check to make sure that this instance has been initialized with data if (!getData() || (0 == getDataSize())) { @@ -408,6 +413,8 @@ void LLImageJPEG::encodeTermDestination( j_compress_ptr cinfo ) { LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; + LLImageDataLock lock(self); + S32 file_bytes = (S32)(self->mOutputBufferSize - cinfo->dest->free_in_buffer); self->allocateData(file_bytes); @@ -484,6 +491,9 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time ) resetLastError(); + LLImageDataSharedLock lockIn(raw_image); + LLImageDataLock lockOut(this); + switch( raw_image->getComponents() ) { case 1: diff --git a/indra/llimage/llimagejpeg.h b/indra/llimage/llimagejpeg.h index 7a849a8421..d674b40b8f 100644 --- a/indra/llimage/llimagejpeg.h +++ b/indra/llimage/llimagejpeg.h @@ -73,8 +73,6 @@ public: static void errorEmitMessage(j_common_ptr cinfo, int msg_level); static void errorOutputMessage(j_common_ptr cinfo); - static bool decompress(LLImageJPEG* imagep); - protected: U8* mOutputBuffer; // temp buffer used during encoding S32 mOutputBufferSize; // bytes in mOuputBuffer diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp index c4b98d8260..5d956bfb4e 100644 --- a/indra/llimage/llimagepng.cpp +++ b/indra/llimage/llimagepng.cpp @@ -51,6 +51,8 @@ bool LLImagePNG::updateData() { resetLastError(); + LLImageDataLock lock(this); + // Check to make sure that this instance has been initialized with data if (!getData() || (0 == getDataSize())) { @@ -87,6 +89,9 @@ bool LLImagePNG::decode(LLImageRaw* raw_image, F32 decode_time) resetLastError(); + LLImageDataSharedLock lockIn(this); + LLImageDataLock lockOut(raw_image); + // Check to make sure that this instance has been initialized with data if (!getData() || (0 == getDataSize())) { @@ -119,6 +124,9 @@ bool LLImagePNG::encode(const LLImageRaw* raw_image, F32 encode_time) resetLastError(); + LLImageDataSharedLock lockIn(raw_image); + LLImageDataLock lockOut(this); + // Image logical size setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents()); diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp index 152a7f309c..0201cc6413 100644 --- a/indra/llimage/llimagetga.cpp +++ b/indra/llimage/llimagetga.cpp @@ -108,6 +108,8 @@ bool LLImageTGA::updateData() { resetLastError(); + LLImageDataLock lock(this); + // Check to make sure that this instance has been initialized with data if (!getData() || (0 == getDataSize())) { @@ -327,7 +329,10 @@ bool LLImageTGA::updateData() bool LLImageTGA::decode(LLImageRaw* raw_image, F32 decode_time) { llassert_always(raw_image); - + + LLImageDataSharedLock lockIn(this); + LLImageDataLock lockOut(raw_image); + // Check to make sure that this instance has been initialized with data if (!getData() || (0 == getDataSize())) { @@ -643,7 +648,10 @@ bool LLImageTGA::decodeColorMap( LLImageRaw* raw_image, bool rle, bool flipped ) bool LLImageTGA::encode(const LLImageRaw* raw_image, F32 encode_time) { llassert_always(raw_image); - + + LLImageDataSharedLock lockIn(raw_image); + LLImageDataLock lockOut(this); + deleteData(); setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents()); @@ -1062,6 +1070,9 @@ bool LLImageTGA::decodeAndProcess( LLImageRaw* raw_image, F32 domain, F32 weight // --+---Input-------------------------------- // | + LLImageDataSharedLock lockIn(this); + LLImageDataLock lockOut(raw_image); + if (!getData() || (0 == getDataSize())) { setLastError("LLImageTGA trying to decode an image with no data!"); diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index fd59daad3d..f97d991ca6 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -36,7 +36,7 @@ class ImageRequest public: ImageRequest(const LLPointer<LLImageFormatted>& image, S32 discard, - BOOL needs_aux, + bool needs_aux, const LLPointer<LLImageDecodeThread::Responder>& responder, U32 request_id); virtual ~ImageRequest(); @@ -51,12 +51,12 @@ private: LLPointer<LLImageFormatted> mFormattedImage; S32 mDiscardLevel; U32 mRequestId; - BOOL mNeedsAux; + bool mNeedsAux; // output LLPointer<LLImageRaw> mDecodedImageRaw; LLPointer<LLImageRaw> mDecodedImageAux; - BOOL mDecodedRaw; - BOOL mDecodedAux; + bool mDecodedRaw; + bool mDecodedAux; LLPointer<LLImageDecodeThread::Responder> mResponder; }; @@ -91,7 +91,7 @@ size_t LLImageDecodeThread::getPending() LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage( const LLPointer<LLImageFormatted>& image, S32 discard, - BOOL needs_aux, + bool needs_aux, const LLPointer<LLImageDecodeThread::Responder>& responder) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; @@ -127,14 +127,14 @@ LLImageDecodeThread::Responder::~Responder() ImageRequest::ImageRequest(const LLPointer<LLImageFormatted>& image, S32 discard, - BOOL needs_aux, + bool needs_aux, const LLPointer<LLImageDecodeThread::Responder>& responder, U32 request_id) : mFormattedImage(image), mDiscardLevel(discard), mNeedsAux(needs_aux), - mDecodedRaw(FALSE), - mDecodedAux(FALSE), + mDecodedRaw(false), + mDecodedAux(false), mResponder(responder), mRequestId(request_id) { @@ -154,9 +154,18 @@ ImageRequest::~ImageRequest() bool ImageRequest::processRequest() { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + + if (mFormattedImage.isNull()) + return true; + const F32 decode_time_slice = 0.f; //disable time slicing bool done = true; - if (!mDecodedRaw && mFormattedImage.notNull()) + + LLImageDataLock lockFormatted(mFormattedImage); + LLImageDataLock lockDecodedRaw(mDecodedImageRaw); + LLImageDataLock lockDecodedAux(mDecodedImageAux); + + if (!mDecodedRaw) { // Decode primary channels if (mDecodedImageRaw.isNull()) @@ -182,7 +191,7 @@ bool ImageRequest::processRequest() // some decoders are removing data when task is complete and there were errors mDecodedRaw = done && mDecodedImageRaw->getData(); } - if (done && mNeedsAux && !mDecodedAux && mFormattedImage.notNull()) + if (done && mNeedsAux && !mDecodedAux) { // Decode aux channel if (!mDecodedImageAux) diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h index b4ab9432e6..e7ad7ed4d0 100644 --- a/indra/llimage/llimageworker.h +++ b/indra/llimage/llimageworker.h @@ -49,7 +49,7 @@ public: // meant to resemble LLQueuedThread::handle_t typedef U32 handle_t; handle_t decodeImage(const LLPointer<LLImageFormatted>& image, - S32 discard, BOOL needs_aux, + S32 discard, bool needs_aux, const LLPointer<Responder>& responder); size_t getPending(); size_t update(F32 max_time_ms); diff --git a/indra/llimage/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp index cad7c00042..baf1330011 100644 --- a/indra/llimage/llpngwrapper.cpp +++ b/indra/llimage/llpngwrapper.cpp @@ -70,7 +70,7 @@ LLPngWrapper::~LLPngWrapper() } // Checks the src for a valid PNG header -BOOL LLPngWrapper::isValidPng(U8* src) +bool LLPngWrapper::isValidPng(U8* src) { const int PNG_BYTES_TO_CHECK = 8; @@ -78,10 +78,10 @@ BOOL LLPngWrapper::isValidPng(U8* src) if (sig != 0) { mErrorMessage = "Invalid or corrupt PNG file"; - return FALSE; + return false; } - return TRUE; + return true; } // Called by the libpng library when a fatal encoding or decoding error @@ -134,7 +134,7 @@ void LLPngWrapper::writeFlush(png_structp png_ptr) // The scanline also begins at the bottom of // the image (per SecondLife conventions) instead of at the top, so we // must assign row-pointers in "reverse" order. -BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInfo *infop) +bool LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInfo *infop) { try { @@ -173,6 +173,8 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf // data space if (rawImage != NULL) { + LLImageDataLock lock(rawImage); + if (!rawImage->resize(static_cast<U16>(mWidth), static_cast<U16>(mHeight), mChannels)) { @@ -208,18 +210,18 @@ BOOL LLPngWrapper::readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInf { mErrorMessage = msg.what(); releaseResources(); - return (FALSE); + return (false); } catch (std::bad_alloc&) { mErrorMessage = "LLPngWrapper"; releaseResources(); - return (FALSE); + return (false); } // Clean up and return releaseResources(); - return (TRUE); + return (true); } // Do transformations to normalize the input to 8-bpp RGBA @@ -281,7 +283,7 @@ void LLPngWrapper::updateMetaData() // Method to write raw image into PNG at dest. The raw scanline begins // at the bottom of the image per SecondLife conventions. -BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest, size_t destSize) +bool LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest, size_t destSize) { try { @@ -362,11 +364,11 @@ BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest, size_t destSiz { mErrorMessage = msg.what(); releaseResources(); - return (FALSE); + return (false); } releaseResources(); - return TRUE; + return true; } // Cleanup various internal structures diff --git a/indra/llimage/llpngwrapper.h b/indra/llimage/llpngwrapper.h index 8d42317b0f..b17e8d1f40 100644 --- a/indra/llimage/llpngwrapper.h +++ b/indra/llimage/llpngwrapper.h @@ -43,9 +43,9 @@ public: S8 mComponents; }; - BOOL isValidPng(U8* src); - BOOL readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInfo *infop = NULL); - BOOL writePng(const LLImageRaw* rawImage, U8* dst, size_t destSize); + bool isValidPng(U8* src); + bool readPng(U8* src, S32 dataSize, LLImageRaw* rawImage, ImageInfo *infop = NULL); + bool writePng(const LLImageRaw* rawImage, U8* dst, size_t destSize); U32 getFinalSize(); const std::string& getErrorMessage(); diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp index ffcd7d257f..5bd884874b 100644 --- a/indra/llimage/tests/llimageworker_test.cpp +++ b/indra/llimage/tests/llimageworker_test.cpp @@ -98,7 +98,7 @@ namespace tut done = res; *done = false; } - virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux, U32) + virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux, U32 request_id) { *done = true; } @@ -150,7 +150,7 @@ namespace tut ensure("LLImageDecodeThread: threaded constructor failed", mThread != NULL); // Insert something in the queue bool done = false; - LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, 0, FALSE, new responder_test(&done)); + LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, 0, false, new responder_test(&done)); // Verifies we get back a valid handle ensure("LLImageDecodeThread: threaded decodeImage(), returned handle is null", decodeHandle != 0); // Wait till the thread has time to handle the work order (though it doesn't do much per work order...) |