diff options
Diffstat (limited to 'indra/llimage')
-rw-r--r-- | indra/llimage/llimage.cpp | 181 | ||||
-rw-r--r-- | indra/llimage/llimage.h | 78 | ||||
-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 | 144 | ||||
-rw-r--r-- | indra/llimage/llimagej2c.cpp | 52 | ||||
-rw-r--r-- | indra/llimage/llimagejpeg.cpp | 10 | ||||
-rw-r--r-- | indra/llimage/llimagejpeg.h | 2 | ||||
-rw-r--r-- | indra/llimage/llimagepng.cpp | 8 | ||||
-rw-r--r-- | indra/llimage/llimagetga.cpp | 17 | ||||
-rw-r--r-- | indra/llimage/llimageworker.cpp | 39 | ||||
-rw-r--r-- | indra/llimage/llimageworker.h | 2 | ||||
-rw-r--r-- | indra/llimage/llpngwrapper.cpp | 28 | ||||
-rw-r--r-- | indra/llimage/llpngwrapper.h | 6 | ||||
-rw-r--r-- | indra/llimage/tests/llimageworker_test.cpp | 2 |
17 files changed, 427 insertions, 187 deletions
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index da5b531857..ca8a4199e8 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -774,7 +774,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) @@ -850,6 +850,8 @@ LLImageRaw::~LLImageRaw() // virtual U8* LLImageRaw::allocateData(S32 size) { + LLImageDataLock lock(this); + U8* res = LLImageBase::allocateData(size); return res; } @@ -857,12 +859,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); } @@ -870,11 +876,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 ; @@ -888,6 +898,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; @@ -903,6 +915,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; @@ -930,6 +944,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()) { @@ -970,6 +987,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); @@ -1009,6 +1028,8 @@ bool LLImageRaw::checkHasTransparentPixels() bool LLImageRaw::optimizeAwayAlpha() { + LLImageDataLock lock(this); + if (getComponents() == 4) { U8* data = getData(); @@ -1074,6 +1095,8 @@ bool LLImageRaw::makeAlpha() 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); @@ -1083,6 +1106,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); @@ -1132,6 +1157,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); @@ -1139,6 +1166,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 ) { @@ -1147,10 +1175,13 @@ 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; @@ -1189,12 +1220,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(); @@ -1216,14 +1249,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-- ) @@ -1253,10 +1288,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; @@ -1267,7 +1305,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++ ) { @@ -1284,6 +1322,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; @@ -1345,16 +1385,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; @@ -1400,10 +1445,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()) ); @@ -1413,7 +1460,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()) ); @@ -1425,7 +1472,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()) ); @@ -1437,15 +1484,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++ ) { @@ -1459,15 +1508,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++ ) { @@ -1482,10 +1534,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; @@ -1527,6 +1582,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) { @@ -1613,6 +1670,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) { @@ -1658,7 +1717,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 ); @@ -1685,7 +1744,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; @@ -1773,7 +1832,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 ); @@ -1869,7 +1928,6 @@ void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S3 } } - void LLImageRaw::addEmissive(LLImageRaw* src) { LLImageRaw* dst = this; // Just for clarity. @@ -1935,9 +1993,11 @@ void LLImageRaw::addEmissiveScaled(LLImageRaw* src) dst->addEmissiveUnscaled(&temp); } - -bool LLImageRaw::validateSrcAndDst(std::string func, LLImageRaw* src, LLImageRaw* dst) +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: "; @@ -2171,6 +2231,61 @@ LLImageFormatted* LLImageFormatted::createFromType(S8 codec) } // static +S8 LLImageFormatted::getCodecFromMimeType(std::string_view mimetype) +{ + if (mimetype == "image/bmp") + { + return IMG_CODEC_BMP; + } + else if (mimetype == "image/tga") + { + return IMG_CODEC_TGA; + } + else if (mimetype == "image/jpeg") + { + return IMG_CODEC_JPEG; + } + else if (mimetype == "image/png") + { + return IMG_CODEC_PNG; + } + else if (mimetype == "image/j2c") + { + return IMG_CODEC_J2C; + } + else if (mimetype == "image/dxt") + { + return IMG_CODEC_DXT; + } + return IMG_CODEC_INVALID; +} + +// static +LLImageFormatted* LLImageFormatted::createFromMimeType(std::string_view mimetype) +{ + S8 codec = getCodecFromMimeType(mimetype); + return createFromType(codec); +} + +// static +LLImageFormatted* LLImageFormatted::loadFromMemory(const U8* data_in, U32 size, std::string_view mimetype) +{ + LLImageFormatted* image = createFromMimeType(mimetype); + if (image) + { + U8* data = image->allocateData(size); + memcpy(data, data_in, size); + + if (!image->updateData()) + { + delete image; + image = NULL; + } + } + return image; +} + +// static LLImageFormatted* LLImageFormatted::createFromExtension(const std::string& instring) { std::string exten; @@ -2250,6 +2365,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; @@ -2258,6 +2375,8 @@ U8* LLImageFormatted::allocateData(S32 size) // virtual U8* LLImageFormatted::reallocateData(S32 size) { + LLImageDataLock lock(this); + sGlobalFormattedMemory -= getDataSize(); U8* res = LLImageBase::reallocateData(size); sGlobalFormattedMemory += getDataSize(); @@ -2267,6 +2386,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(); } @@ -2292,6 +2417,8 @@ void LLImageFormatted::sanityCheck() bool LLImageFormatted::copyData(U8 *data, S32 size) { + LLImageDataLock lock(this); + if ( data && ((data != getData()) || (size != getDataSize())) ) { deleteData(); @@ -2304,6 +2431,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(); @@ -2317,6 +2446,8 @@ void LLImageFormatted::appendData(U8 *data, S32 size) { if (data) { + LLImageDataLock lock(this); + if (!getData()) { setData(data, size); @@ -2334,6 +2465,7 @@ void LLImageFormatted::appendData(U8 *data, S32 size) //---------------------------------------------------------------------------- + bool LLImageFormatted::load(const std::string &filename, int load_size) { resetLastError(); @@ -2358,6 +2490,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) @@ -2396,6 +2531,8 @@ bool LLImageFormatted::save(const std::string &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 9b16711b85..42eecbb97c 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -117,6 +117,10 @@ class LLImageBase protected: virtual ~LLImageBase(); + virtual void deleteData(); + virtual U8* allocateData(S32 size = -1); + virtual U8* reallocateData(S32 size = -1); + public: LLImageBase(); @@ -126,10 +130,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 +171,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 { @@ -238,42 +255,30 @@ public: 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 ); - - // Src and dst can be any size. Src has 4 components. Dst has 3 components. - void compositeScaled4onto3( LLImageRaw* src ); - - // Src and dst are same size. Src has 4 components. Dst has 3 components. - void compositeUnscaled4onto3( LLImageRaw* src ); + void composite( const LLImageRaw* src ); // Emissive operations used by minimap // Roughly emulates GLTF emissive texture, but is not GLTF-compliant @@ -282,13 +287,25 @@ public: 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( const LLImageRaw* src ); + + // Src and dst are same size. Src has 4 components. Dst has 3 components. + 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 ); + // 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) ; @@ -296,7 +313,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. @@ -305,7 +322,10 @@ class LLImageFormatted : public LLImageBase { public: static LLImageFormatted* createFromType(S8 codec); + static LLImageFormatted* loadFromMemory(const U8* data, U32 size, std::string_view mimetype); static LLImageFormatted* createFromExtension(const std::string& instring); + static LLImageFormatted* createFromMimeType(std::string_view mimetype); + static S8 getCodecFromMimeType(std::string_view mimetype); protected: /*virtual*/ ~LLImageFormatted(); diff --git a/indra/llimage/llimagebmp.cpp b/indra/llimage/llimagebmp.cpp index 08fcdf39da..2a328675c2 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 d2cbad1a49..237c3e8d53 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 997406bb7b..d4efbcfad2 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 f75b1a72df..6b960f9077 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(); @@ -269,6 +271,9 @@ bool LLImageDXT::decode(LLImageRaw* raw_image, F32 time) 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(); @@ -463,7 +476,7 @@ bool LLImageDXT::convertToDXR() // virtual S32 LLImageDXT::calcHeaderSize() { - return llmax(sizeof(dxtfile_header_old_t), sizeof(dxtfile_header_t)); + return static_cast<S32>(llmax(sizeof(dxtfile_header_old_t), sizeof(dxtfile_header_t))); } // virtual diff --git a/indra/llimage/llimagefilter.cpp b/indra/llimage/llimagefilter.cpp index 1b7835a6ff..bfcb1f76de 100644 --- a/indra/llimage/llimagefilter.cpp +++ b/indra/llimage/llimagefilter.cpp @@ -88,6 +88,8 @@ 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) { @@ -251,7 +253,7 @@ void LLImageFilter::executeFilter(LLPointer<LLImageRaw> raw_image) bool abs_value = (mFilterData[i][index++].asReal() > 0.0); for (S32 k = 0; k < NUM_VALUES_IN_MAT3; k++) for (S32 j = 0; j < NUM_VALUES_IN_MAT3; j++) - kernel.mMatrix[k][j] = mFilterData[i][index++].asReal(); + kernel.mMatrix[k][j] = (F32)mFilterData[i][index++].asReal(); convolve(kernel,normalize,abs_value); } else if (filter_name == "colortransform") @@ -260,7 +262,7 @@ void LLImageFilter::executeFilter(LLPointer<LLImageRaw> raw_image) S32 index = 1; for (S32 k = 0; k < NUM_VALUES_IN_MAT3; k++) for (S32 j = 0; j < NUM_VALUES_IN_MAT3; j++) - transform.mMatrix[k][j] = mFilterData[i][index++].asReal(); + transform.mMatrix[k][j] = (F32)mFilterData[i][index++].asReal(); transform.transpose(); colorTransform(transform); } @@ -277,32 +279,32 @@ void LLImageFilter::executeFilter(LLPointer<LLImageRaw> raw_image) void LLImageFilter::blendStencil(F32 alpha, U8* pixel, U8 red, U8 green, U8 blue) { - F32 inv_alpha = 1.0 - alpha; + F32 inv_alpha = 1.0f - alpha; switch (mStencilBlendMode) { case STENCIL_BLEND_MODE_BLEND: // Classic blend of incoming color with the background image - pixel[VRED] = inv_alpha * pixel[VRED] + alpha * red; - pixel[VGREEN] = inv_alpha * pixel[VGREEN] + alpha * green; - pixel[VBLUE] = inv_alpha * pixel[VBLUE] + alpha * blue; + pixel[VRED] = (U8)(inv_alpha * pixel[VRED] + alpha * red); + pixel[VGREEN] = (U8)(inv_alpha * pixel[VGREEN] + alpha * green); + pixel[VBLUE] = (U8)(inv_alpha * pixel[VBLUE] + alpha * blue); break; case STENCIL_BLEND_MODE_ADD: // Add incoming color to the background image - pixel[VRED] = llclampb(pixel[VRED] + alpha * red); - pixel[VGREEN] = llclampb(pixel[VGREEN] + alpha * green); - pixel[VBLUE] = llclampb(pixel[VBLUE] + alpha * blue); + pixel[VRED] = (U8)llclampb(pixel[VRED] + alpha * red); + pixel[VGREEN] = (U8)llclampb(pixel[VGREEN] + alpha * green); + pixel[VBLUE] = (U8)llclampb(pixel[VBLUE] + alpha * blue); break; case STENCIL_BLEND_MODE_ABACK: // Add back background image to the incoming color - pixel[VRED] = llclampb(inv_alpha * pixel[VRED] + red); - pixel[VGREEN] = llclampb(inv_alpha * pixel[VGREEN] + green); - pixel[VBLUE] = llclampb(inv_alpha * pixel[VBLUE] + blue); + pixel[VRED] = (U8)llclampb(inv_alpha * pixel[VRED] + red); + pixel[VGREEN] = (U8)llclampb(inv_alpha * pixel[VGREEN] + green); + pixel[VBLUE] = (U8)llclampb(inv_alpha * pixel[VBLUE] + blue); break; case STENCIL_BLEND_MODE_FADE: // Fade incoming color to black - pixel[VRED] = alpha * red; - pixel[VGREEN] = alpha * green; - pixel[VBLUE] = alpha * blue; + pixel[VRED] = (U8)(alpha * red); + pixel[VGREEN] = (U8)(alpha * green); + pixel[VBLUE] = (U8)(alpha * blue); break; } } @@ -346,7 +348,7 @@ void LLImageFilter::colorTransform(const LLMatrix3 &transform) dst.clamp(0.0f,255.0f); // Blend result - blendStencil(getStencilAlpha(i,j), dst_data, dst.mV[VRED], dst.mV[VGREEN], dst.mV[VBLUE]); + blendStencil(getStencilAlpha(i,j), dst_data, (U8)dst.mV[VRED], (U8)dst.mV[VGREEN], (U8)dst.mV[VBLUE]); dst_data += components; } } @@ -461,7 +463,7 @@ void LLImageFilter::convolve(const LLMatrix3 &kernel, bool normalize, bool abs_v dst.clamp(0.0f,255.0f); // Blend result - blendStencil(getStencilAlpha(i,j), dst_data, dst.mV[VRED], dst.mV[VGREEN], dst.mV[VBLUE]); + blendStencil(getStencilAlpha(i,j), dst_data, (U8)dst.mV[VRED], (U8)dst.mV[VGREEN], (U8)dst.mV[VBLUE]); // Next pixel dst_data += components; @@ -497,7 +499,7 @@ void LLImageFilter::filterScreen(EScreenMode mode, const F32 wave_length, const S32 width = mImage->getWidth(); S32 height = mImage->getHeight(); - F32 wave_length_pixels = wave_length * (F32)(height) / 2.0; + F32 wave_length_pixels = wave_length * (F32)(height) / 2.0f; F32 sin = sinf(angle*DEG_TO_RAD); F32 cos = cosf(angle*DEG_TO_RAD); @@ -505,7 +507,7 @@ void LLImageFilter::filterScreen(EScreenMode mode, const F32 wave_length, const U8 gamma[256]; for (S32 i = 0; i < 256; i++) { - F32 gamma_i = llclampf((float)(powf((float)(i)/255.0,1.0/4.0))); + F32 gamma_i = llclampf((float)(powf((float)(i)/255.0f,1.0f/4.0f))); gamma[i] = (U8)(255.0 * gamma_i); } @@ -523,11 +525,11 @@ void LLImageFilter::filterScreen(EScreenMode mode, const F32 wave_length, const case SCREEN_MODE_2DSINE: di = cos*i + sin*j; dj = -sin*i + cos*j; - value = (sinf(2*F_PI*di/wave_length_pixels)*sinf(2*F_PI*dj/wave_length_pixels)+1.0)*255.0/2.0; + value = (sinf(2*F_PI*di/wave_length_pixels)*sinf(2*F_PI*dj/wave_length_pixels)+1.0f)*255.0f/2.0f; break; case SCREEN_MODE_LINE: dj = sin*i - cos*j; - value = (sinf(2*F_PI*dj/wave_length_pixels)+1.0)*255.0/2.0; + value = (sinf(2*F_PI*dj/wave_length_pixels)+1.0f)*255.0f/2.0f; break; } U8 dst_value = (dst_data[VRED] >= (U8)(value) ? gamma[dst_data[VRED] - (U8)(value)] : 0); @@ -554,16 +556,16 @@ void LLImageFilter::setStencil(EStencilShape shape, EStencilBlendMode mode, F32 mStencilCenterX = (S32)(mImage->getWidth() + params[0] * (F32)(mImage->getHeight()))/2; mStencilCenterY = (S32)(mImage->getHeight() + params[1] * (F32)(mImage->getHeight()))/2; mStencilWidth = (S32)(params[2] * (F32)(mImage->getHeight()))/2; - mStencilGamma = (params[3] <= 0.0 ? 1.0 : params[3]); + mStencilGamma = (params[3] <= 0.0f ? 1.0f : params[3]); - mStencilWavelength = (params[0] <= 0.0 ? 10.0 : params[0] * (F32)(mImage->getHeight()) / 2.0); + mStencilWavelength = (params[0] <= 0.0f ? 10.0f : params[0] * (F32)(mImage->getHeight()) / 2.0f); mStencilSine = sinf(params[1]*DEG_TO_RAD); mStencilCosine = cosf(params[1]*DEG_TO_RAD); - mStencilStartX = ((F32)(mImage->getWidth()) + params[0] * (F32)(mImage->getHeight()))/2.0; - mStencilStartY = ((F32)(mImage->getHeight()) + params[1] * (F32)(mImage->getHeight()))/2.0; - F32 end_x = ((F32)(mImage->getWidth()) + params[2] * (F32)(mImage->getHeight()))/2.0; - F32 end_y = ((F32)(mImage->getHeight()) + params[3] * (F32)(mImage->getHeight()))/2.0; + mStencilStartX = ((F32)(mImage->getWidth()) + params[0] * (F32)(mImage->getHeight()))/2.0f; + mStencilStartY = ((F32)(mImage->getHeight()) + params[1] * (F32)(mImage->getHeight()))/2.0f; + F32 end_x = ((F32)(mImage->getWidth()) + params[2] * (F32)(mImage->getHeight()))/2.0f; + F32 end_y = ((F32)(mImage->getHeight()) + params[3] * (F32)(mImage->getHeight()))/2.0f; mStencilGradX = end_x - mStencilStartX; mStencilGradY = end_y - mStencilStartY; mStencilGradN = mStencilGradX*mStencilGradX + mStencilGradY*mStencilGradY; @@ -576,14 +578,14 @@ F32 LLImageFilter::getStencilAlpha(S32 i, S32 j) { // alpha is a modified gaussian value, with a center and fading in a circular pattern toward the edges // The gamma parameter controls the intensity of the drop down from alpha 1.0 (center) to 0.0 - F32 d_center_square = (i - mStencilCenterX)*(i - mStencilCenterX) + (j - mStencilCenterY)*(j - mStencilCenterY); + F32 d_center_square = (F32)((i - mStencilCenterX)*(i - mStencilCenterX) + (j - mStencilCenterY)*(j - mStencilCenterY)); alpha = powf(F_E, -(powf((d_center_square/(mStencilWidth*mStencilWidth)),mStencilGamma)/2.0f)); } else if (mStencilShape == STENCIL_SHAPE_SCAN_LINES) { // alpha varies according to a squared sine function. F32 d = mStencilSine*i - mStencilCosine*j; - alpha = (sinf(2*F_PI*d/mStencilWavelength) > 0.0 ? 1.0 : 0.0); + alpha = (sinf(2*F_PI*d/mStencilWavelength) > 0.0f ? 1.0f : 0.0f); } else if (mStencilShape == STENCIL_SHAPE_GRADIENT) { @@ -754,11 +756,11 @@ void LLImageFilter::filterGamma(F32 gamma, const LLColor3& alpha) for (S32 i = 0; i < 256; i++) { - F32 gamma_i = llclampf((float)(powf((float)(i)/255.0,1.0/gamma))); + F32 gamma_i = llclampf((float)(powf((float)(i)/255.0f,1.0f/gamma))); // Blend in with alpha values - gamma_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * 255.0 * gamma_i); - gamma_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * 255.0 * gamma_i); - gamma_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * 255.0 * gamma_i); + gamma_red_lut[i] = (U8)((1.0f - alpha.mV[0]) * (float)(i) + alpha.mV[0] * 255.0f * gamma_i); + gamma_green_lut[i] = (U8)((1.0f - alpha.mV[1]) * (float)(i) + alpha.mV[1] * 255.0f * gamma_i); + gamma_blue_lut[i] = (U8)((1.0f - alpha.mV[2]) * (float)(i) + alpha.mV[2] * 255.0f * gamma_i); } colorCorrect(gamma_red_lut,gamma_green_lut,gamma_blue_lut); @@ -779,9 +781,9 @@ void LLImageFilter::filterLinearize(F32 tail, const LLColor3& alpha) // Compute min and max counts minus tail tail = llclampf(tail); - S32 total = cumulated_histo[255]; - S32 min_c = (S32)((F32)(total) * tail); - S32 max_c = (S32)((F32)(total) * (1.0 - tail)); + U32 total = cumulated_histo[255]; + U32 min_c = (U32)((F32)(total) * tail); + U32 max_c = (U32)((F32)(total) * (1.0 - tail)); // Find min and max values S32 min_v = 0; @@ -796,9 +798,9 @@ void LLImageFilter::filterLinearize(F32 tail, const LLColor3& alpha) } // Compute linear lookup table - U8 linear_red_lut[256]; - U8 linear_green_lut[256]; - U8 linear_blue_lut[256]; + U8 linear_red_lut[256]{}; + U8 linear_green_lut[256]{}; + U8 linear_blue_lut[256]{}; if (max_v == min_v) { // Degenerated binary split case @@ -806,23 +808,23 @@ void LLImageFilter::filterLinearize(F32 tail, const LLColor3& alpha) { U8 value_i = (i < min_v ? 0 : 255); // Blend in with alpha values - linear_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); - linear_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); - linear_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); + linear_red_lut[i] = (U8)((1.0f - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); + linear_green_lut[i] = (U8)((1.0f - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); + linear_blue_lut[i] = (U8)((1.0f - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); } } else { // Linearize between min and max - F32 slope = 255.0 / (F32)(max_v - min_v); + F32 slope = 255.0f / (F32)(max_v - min_v); F32 translate = -min_v * slope; for (S32 i = 0; i < 256; i++) { U8 value_i = (U8)(llclampb((S32)(slope*i + translate))); // Blend in with alpha values - linear_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); - linear_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); - linear_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); + linear_red_lut[i] = (U8)((1.0f - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); + linear_green_lut[i] = (U8)((1.0f - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); + linear_blue_lut[i] = (U8)((1.0f - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); } } @@ -848,22 +850,22 @@ void LLImageFilter::filterEqualize(S32 nb_classes, const LLColor3& alpha) } // Compute deltas - S32 total = cumulated_histo[255]; - S32 delta_count = total / nb_classes; - S32 current_count = delta_count; - S32 delta_value = 256 / (nb_classes - 1); - S32 current_value = 0; + U32 total = cumulated_histo[255]; + U32 delta_count = total / nb_classes; + U32 current_count = delta_count; + U32 delta_value = 256 / (nb_classes - 1); + U32 current_value = 0; // Compute equalized lookup table - U8 equalize_red_lut[256]; - U8 equalize_green_lut[256]; - U8 equalize_blue_lut[256]; + U8 equalize_red_lut[256]{}; + U8 equalize_green_lut[256]{}; + U8 equalize_blue_lut[256]{}; for (S32 i = 0; i < 256; i++) { // Blend in current_value with alpha values - equalize_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * current_value); - equalize_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * current_value); - equalize_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * current_value); + equalize_red_lut[i] = (U8)((1.0f - alpha.mV[0]) * (float)(i) + alpha.mV[0] * current_value); + equalize_green_lut[i] = (U8)((1.0f - alpha.mV[1]) * (float)(i) + alpha.mV[1] * current_value); + equalize_blue_lut[i] = (U8)((1.0f - alpha.mV[2]) * (float)(i) + alpha.mV[2] * current_value); if (cumulated_histo[i] >= current_count) { current_count += delta_count; @@ -882,15 +884,15 @@ void LLImageFilter::filterColorize(const LLColor3& color, const LLColor3& alpha) U8 green_lut[256]; U8 blue_lut[256]; - F32 red_composite = 255.0 * alpha.mV[0] * color.mV[0]; - F32 green_composite = 255.0 * alpha.mV[1] * color.mV[1]; - F32 blue_composite = 255.0 * alpha.mV[2] * color.mV[2]; + F32 red_composite = 255.0f * alpha.mV[0] * color.mV[0]; + F32 green_composite = 255.0f * alpha.mV[1] * color.mV[1]; + F32 blue_composite = 255.0f * alpha.mV[2] * color.mV[2]; for (S32 i = 0; i < 256; i++) { - red_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[0]) * (F32)(i) + red_composite))); - green_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[1]) * (F32)(i) + green_composite))); - blue_lut[i] = (U8)(llclampb((S32)((1.0 - alpha.mV[2]) * (F32)(i) + blue_composite))); + red_lut[i] = (U8)(llclampb((S32)((1.0f - alpha.mV[0]) * (F32)(i) + red_composite))); + green_lut[i] = (U8)(llclampb((S32)((1.0f - alpha.mV[1]) * (F32)(i) + green_composite))); + blue_lut[i] = (U8)(llclampb((S32)((1.0f - alpha.mV[2]) * (F32)(i) + blue_composite))); } colorCorrect(red_lut,green_lut,blue_lut); @@ -902,15 +904,15 @@ void LLImageFilter::filterContrast(F32 slope, const LLColor3& alpha) U8 contrast_green_lut[256]; U8 contrast_blue_lut[256]; - F32 translate = 128.0 * (1.0 - slope); + F32 translate = 128.0f * (1.0f - slope); for (S32 i = 0; i < 256; i++) { U8 value_i = (U8)(llclampb((S32)(slope*i + translate))); // Blend in with alpha values - contrast_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); - contrast_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); - contrast_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); + contrast_red_lut[i] = (U8)((1.0f - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); + contrast_green_lut[i] = (U8)((1.0f - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); + contrast_blue_lut[i] = (U8)((1.0f - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); } colorCorrect(contrast_red_lut,contrast_green_lut,contrast_blue_lut); @@ -922,15 +924,15 @@ void LLImageFilter::filterBrightness(F32 add, const LLColor3& alpha) U8 brightness_green_lut[256]; U8 brightness_blue_lut[256]; - S32 add_value = (S32)(add * 255.0); + S32 add_value = (S32)(add * 255.0f); for (S32 i = 0; i < 256; i++) { U8 value_i = (U8)(llclampb(i + add_value)); // Blend in with alpha values - brightness_red_lut[i] = (U8)((1.0 - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); - brightness_green_lut[i] = (U8)((1.0 - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); - brightness_blue_lut[i] = (U8)((1.0 - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); + brightness_red_lut[i] = (U8)((1.0f - alpha.mV[0]) * (float)(i) + alpha.mV[0] * value_i); + brightness_green_lut[i] = (U8)((1.0f - alpha.mV[1]) * (float)(i) + alpha.mV[1] * value_i); + brightness_blue_lut[i] = (U8)((1.0f - alpha.mV[2]) * (float)(i) + alpha.mV[2] * value_i); } colorCorrect(brightness_red_lut,brightness_green_lut,brightness_blue_lut); diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 5175849ad8..5dfd8cd947 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,22 +159,25 @@ 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)) - { - setLastError("LLImageJ2C uninitialized"); - res = true; // done - } - else + bool res; { - // 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) @@ -181,12 +186,21 @@ bool LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir { // 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()) { @@ -264,13 +278,20 @@ S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 r S32 nb_layers = 1; S32 surface = w*h; S32 s = 64*64; + S32 precision = 8; // assumed bitrate per component channel, might change in future for HDR support + S32 totalbytes = (S32)(s * comp * precision * rate); // first level computed before loop while (surface > s) { + if (nb_layers <= (5 - discard_level)) + totalbytes += (S32)(s * comp * precision * rate); nb_layers++; s *= 4; } F32 layer_factor = 3.0f * (7 - llclamp(nb_layers,1,6)); + totalbytes /= 8; // to bytes + totalbytes += calcHeaderSizeJ2C(); // header + // Compute w/pow(2,discard_level) and h/pow(2,discard_level) w >>= discard_level; h >>= discard_level; @@ -283,7 +304,9 @@ S32 LLImageJ2C::calcDataSizeJ2C(S32 w, S32 h, S32 comp, S32 discard_level, F32 r S32 new_bytes = (S32) (sqrt((F32)(w*h))*(F32)(comp)*rate*1000.f/layer_factor); S32 old_bytes = (S32)((F32)(w*h*comp)*rate); bytes = (LLImage::useNewByteRange() && (new_bytes < old_bytes) ? new_bytes : old_bytes); - bytes = llmax(bytes, calcHeaderSizeJ2C()); + bytes = llmax(totalbytes, calcHeaderSizeJ2C()); + //LL_WARNS() << "calcDataSizeJ2C w-h-c-d-p " << w << "-" << h << "-" << comp << "-" << discard_level << "-" << precision + // << " Pyramid: " << (S32)totalbytes << " LayerFactored: " << new_bytes << " WJCR: " << old_bytes << LL_ENDL; return bytes; } @@ -406,9 +429,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 93f1d0cdc4..0e7ec365d4 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())) { @@ -189,6 +191,9 @@ bool LLImageJPEG::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 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 12249ad8c3..add6657117 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 4d081ce169..d75084cf08 100644 --- a/indra/llimage/llimagepng.cpp +++ b/indra/llimage/llimagepng.cpp @@ -54,6 +54,8 @@ bool LLImagePNG::updateData() try { + LLImageDataLock lock(this); + // Check to make sure that this instance has been initialized with data if (!getData() || (0 == getDataSize())) { @@ -103,6 +105,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())) { @@ -135,6 +140,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 adc98cd81d..25232b77aa 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())) { @@ -328,6 +330,9 @@ 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())) { @@ -462,7 +467,7 @@ bool LLImageTGA::decodeTruecolorNonRle( LLImageRaw* raw_image, bool &alpha_opaqu S32 pixels = getWidth() * getHeight(); - if (pixels * (mIs15Bit ? 2 : getComponents()) > getDataSize() - mDataOffset) + if (pixels * (mIs15Bit ? 2 : getComponents()) > getDataSize() - (S32)mDataOffset) { //here we have situation when data size in src less than actually needed return false; } @@ -644,6 +649,9 @@ 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!"); @@ -1168,7 +1179,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 std::string& path ) { - S32 len = path.size(); + auto len = path.size(); if( len < 5 ) { return false; @@ -1195,7 +1206,7 @@ bool LLImageTGA::loadFile( const std::string& path ) } U8* buffer = allocateData(file_size); - S32 bytes_read = fread(buffer, 1, file_size, file); + S32 bytes_read = static_cast<S32>(fread(buffer, 1, file_size, file)); if( bytes_read != file_size ) { deleteData(); diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index 8ce17b5753..bdaef0c653 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,15 +51,14 @@ 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; - std::string mErrorString; -}; + std::string mErrorString;}; //---------------------------------------------------------------------------- @@ -92,12 +91,15 @@ 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; U32 decode_id = ++mDecodeCount; + if (decode_id == 0) + decode_id = ++mDecodeCount; + // Instantiate the ImageRequest right in the lambda, why not? bool posted = mThreadPool->getQueue().post( [req = ImageRequest(image, discard, needs_aux, responder, decode_id)] @@ -128,14 +130,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) { @@ -155,10 +157,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; - mErrorString.clear(); - if (!mDecodedRaw && mFormattedImage.notNull()) + + LLImageDataLock lockFormatted(mFormattedImage); + LLImageDataLock lockDecodedRaw(mDecodedImageRaw); + LLImageDataLock lockDecodedAux(mDecodedImageAux); + + if (!mDecodedRaw) { // Decode primary channels if (mDecodedImageRaw.isNull()) @@ -166,13 +176,10 @@ bool ImageRequest::processRequest() // parse formatted header if (!mFormattedImage->updateData()) { - // Pick up errors from updateData - mErrorString = LLImage::getLastThreadError(); return true; // done (failed) } - if (0 == (mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents())) + if ((mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents()) == 0) { - mErrorString = "Invalid image size"; return true; // done (failed) } if (mDiscardLevel >= 0) diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h index 8c43a7c32c..9e01f0bacd 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 24b6d34fe2..79c201b1f4 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,25 +210,25 @@ 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); } catch (...) { mErrorMessage = "LLPngWrapper"; releaseResources(); LOG_UNHANDLED_EXCEPTION(""); - return (FALSE); + return (false); } // Clean up and return releaseResources(); - return (TRUE); + return (true); } // Do transformations to normalize the input to 8-bpp RGBA @@ -288,7 +290,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 { @@ -326,10 +328,10 @@ BOOL LLPngWrapper::writePng(const LLImageRaw* rawImage, U8* dest, size_t destSiz mWriteInfoPtr = png_create_info_struct(mWritePngPtr); // Setup write function - PngDataInfo dataPtr; + PngDataInfo dataPtr{}; dataPtr.mData = dest; dataPtr.mOffset = 0; - dataPtr.mDataSize = destSize; + dataPtr.mDataSize = static_cast<S32>(destSize); png_set_write_fn(mWritePngPtr, &dataPtr, &writeDataCallback, &writeFlush); // Setup image params @@ -369,11 +371,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 f3c3d57f70..3ada8ac7c2 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 2568adf89e..36be885912 100644 --- a/indra/llimage/tests/llimageworker_test.cpp +++ b/indra/llimage/tests/llimageworker_test.cpp @@ -151,7 +151,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...) |