diff options
| author | Alexander Gavriliuk <alexandrgproductengine@lindenlab.com> | 2023-12-15 18:26:14 +0100 | 
|---|---|---|
| committer | Guru <alexandrgproductengine@lindenlab.com> | 2023-12-21 19:12:52 +0100 | 
| commit | 74c8b028d42a8c5b080bb861e427f38cedd4ad7c (patch) | |
| tree | 067f8e85fd7b4f91903ad2aa32630b7dd0364099 /indra | |
| parent | e104f7ce0291ed1f7ab170714e319408bf076221 (diff) | |
SL-20743 Use LLMutex in LLImageBase for internal data thread-safety
Diffstat (limited to 'indra')
53 files changed, 631 insertions, 137 deletions
| diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h index e3444efcf6..787235b235 100644 --- a/indra/llappearance/llavatarappearance.h +++ b/indra/llappearance/llavatarappearance.h @@ -232,7 +232,7 @@ public:  	//--------------------------------------------------------------------  public:  	void 	addMaskedMorph(LLAvatarAppearanceDefines::EBakedTextureIndex index, LLVisualParam* morph_target, BOOL invert, std::string layer); -	virtual void	applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES) = 0; +	virtual void	applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES) = 0;  /**                    Rendering   **                                                                            ** diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp index 965b999bd4..223b2b7f1c 100644 --- a/indra/llappearance/llpolymorph.cpp +++ b/indra/llappearance/llpolymorph.cpp @@ -659,7 +659,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )  //-----------------------------------------------------------------------------  // applyMask()  //----------------------------------------------------------------------------- -void	LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert) +void	LLPolyMorphTarget::applyMask(const U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert)  {  	LLVector4a *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL; @@ -780,7 +780,7 @@ LLPolyVertexMask::~LLPolyVertexMask()  //-----------------------------------------------------------------------------  // generateMask()  //----------------------------------------------------------------------------- -void LLPolyVertexMask::generateMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights) +void LLPolyVertexMask::generateMask(const U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights)  {  // RN debug output that uses Image Debugger (http://www.cs.unc.edu/~baxter/projects/imdebug/)  //	BOOL debugImg = FALSE;  diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h index 29cd373636..954f01811a 100644 --- a/indra/llappearance/llpolymorph.h +++ b/indra/llappearance/llpolymorph.h @@ -84,7 +84,7 @@ public:  	LLPolyVertexMask(const LLPolyVertexMask& pOther);  	~LLPolyVertexMask(); -	void generateMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights); +	void generateMask(const U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights);  	F32* getMorphMaskWeights(); @@ -170,7 +170,7 @@ public:  	/*virtual*/ const LLVector4a*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh);  	/*virtual*/ const LLVector4a*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh); -	void	applyMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert); +	void	applyMask(const U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert);  	void	addPendingMorphMask() { mNumMorphMasksPending++; }      void    applyVolumeChanges(F32 delta_weight); // SL-315 - for resetSkeleton() diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index ff894eeed3..e426615f1c 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -528,7 +528,7 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height,  	gGL.setSceneBlendType(LLRender::BT_ALPHA);  } -void LLTexLayerSet::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components) +void LLTexLayerSet::applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components)  {  	mAvatarAppearance->applyMorphMask(tex_data, width, height, num_components, mBakedTexIndex);  } diff --git a/indra/llappearance/lltexlayer.h b/indra/llappearance/lltexlayer.h index 74b421d3ee..ff95d7f5e9 100644 --- a/indra/llappearance/lltexlayer.h +++ b/indra/llappearance/lltexlayer.h @@ -203,7 +203,7 @@ public:  	void						renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target = nullptr, bool forceClear = false);  	BOOL						isBodyRegion(const std::string& region) const; -	void						applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components); +	void						applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components);  	BOOL						isMorphValid() const;  	virtual void				requestUpdate() = 0;  	void						invalidateMorphMasks(); diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 575c524219..834b0e7a3a 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -571,7 +571,7 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb  }  //static -S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) +S32 LLAPRFile::writeEx(const std::string& filename, const void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool)  {      LL_PROFILE_ZONE_SCOPED;  	apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 565d7cfb63..f5717ea75e 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -193,7 +193,7 @@ public:  	// Returns bytes read/written, 0 if read/write fails:  	static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);	 -	static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append +	static S32 writeEx(const std::string& filename, const void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append  //*******************************************************************************************************************************  }; diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index 0273dd5970..f56c2d08a6 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -29,19 +29,20 @@  #include "llthread.h"  #include "lltimer.h" -//============================================================================ +//--------------------------------------------------------------------- +// +// LLMutex +//  LLMutex::LLMutex() :   mCount(0)  {  } -  LLMutex::~LLMutex()  {  } -  void LLMutex::lock()  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD @@ -112,7 +113,7 @@ LLThread::id_t LLMutex::lockingThread() const  bool LLMutex::trylock()  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD -	if(isSelfLocked()) +	if (isSelfLocked())  	{ //redundant lock  		mCount++;  		return true; @@ -135,19 +136,185 @@ bool LLMutex::trylock()  	return true;  } -//============================================================================ +//--------------------------------------------------------------------- +// +// LLSharedMutex +// +LLSharedMutex::LLSharedMutex() +: mLockingThreads(2) // Reserve 2 slots in the map hash table +, mIsShared(false) +{ +} + +bool LLSharedMutex::isLocked() const +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD +    std::lock_guard<std::mutex> lock(mLockMutex); + +    return !mLockingThreads.empty(); +} + +bool LLSharedMutex::isThreadLocked() const +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD +    LLThread::id_t current_thread = LLThread::currentID(); +    std::lock_guard<std::mutex> lock(mLockMutex); + +    const_iterator it = mLockingThreads.find(current_thread); +    return it != mLockingThreads.end(); +} + +void LLSharedMutex::lockShared() +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD +    LLThread::id_t current_thread = LLThread::currentID(); + +    mLockMutex.lock(); +    iterator it = mLockingThreads.find(current_thread); +    if (it != mLockingThreads.end()) +    { +        it->second++; +    } +    else +    { +        // Acquire the mutex immediately if the mutex is not locked exclusively +        // or enter a locking state if the mutex is already locked exclusively +        mLockMutex.unlock(); +        mSharedMutex.lock_shared(); +        mLockMutex.lock(); +        // Continue after acquiring the mutex +        mLockingThreads.emplace(std::make_pair(current_thread, 1)); +        mIsShared = true; +    } +    mLockMutex.unlock(); +} + +void LLSharedMutex::lockExclusive() +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD +    LLThread::id_t current_thread = LLThread::currentID(); + +    mLockMutex.lock(); +    if (mLockingThreads.size() == 1 && mLockingThreads.begin()->first == current_thread) +    { +        mLockingThreads.begin()->second++; +    } +    else +    { +        // Acquire the mutex immediately if mLockingThreads is empty +        // or enter a locking state if mLockingThreads is not empty +        mLockMutex.unlock(); +        mSharedMutex.lock(); +        mLockMutex.lock(); +        // Continue after acquiring the mutex (and possible quitting the locking state) +        mLockingThreads.emplace(std::make_pair(current_thread, 1)); +        mIsShared = false; +    } +    mLockMutex.unlock(); +} + +bool LLSharedMutex::trylockShared() +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD +    LLThread::id_t current_thread = LLThread::currentID(); +    std::lock_guard<std::mutex> lock(mLockMutex); + +    iterator it = mLockingThreads.find(current_thread); +    if (it != mLockingThreads.end()) +    { +        it->second++; +    } +    else +    { +        if (!mSharedMutex.try_lock_shared()) +            return false; + +        mLockingThreads.emplace(std::make_pair(current_thread, 1)); +        mIsShared = true; +    } + +    return true; +} + +bool LLSharedMutex::trylockExclusive() +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD +    LLThread::id_t current_thread = LLThread::currentID(); +    std::lock_guard<std::mutex> lock(mLockMutex); + +    if (mLockingThreads.size() == 1 && mLockingThreads.begin()->first == current_thread) +    { +        mLockingThreads.begin()->second++; +    } +    else +    { +        if (!mSharedMutex.try_lock()) +            return false; + +        mLockingThreads.emplace(std::make_pair(current_thread, 1)); +        mIsShared = false; +    } + +    return true; +} + +void LLSharedMutex::unlockShared() +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD +    LLThread::id_t current_thread = LLThread::currentID(); +    std::lock_guard<std::mutex> lock(mLockMutex); + +    iterator it = mLockingThreads.find(current_thread); +    if (it != mLockingThreads.end()) +    { +        if (it->second > 1) +        { +            it->second--; +        } +        else +        { +            mLockingThreads.erase(it); +            mSharedMutex.unlock_shared(); +        } +    } +} + +void LLSharedMutex::unlockExclusive() +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD +    LLThread::id_t current_thread = LLThread::currentID(); +    std::lock_guard<std::mutex> lock(mLockMutex); + +    iterator it = mLockingThreads.find(current_thread); +    if (it != mLockingThreads.end()) +    { +        if (it->second > 1) +        { +            it->second--; +        } +        else +        { +            mLockingThreads.erase(it); +            mSharedMutex.unlock(); +        } +    } +} + + +//--------------------------------------------------------------------- +// +// LLCondition +//  LLCondition::LLCondition() :  	LLMutex()  {  } -  LLCondition::~LLCondition()  {  } -  void LLCondition::wait()  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD @@ -168,7 +335,10 @@ void LLCondition::broadcast()  } - +//--------------------------------------------------------------------- +// +// LLMutexTrylock +//  LLMutexTrylock::LLMutexTrylock(LLMutex* mutex)      : mMutex(mutex),      mLocked(false) diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h index 0d70da6178..077f810d61 100644 --- a/indra/llcommon/llmutex.h +++ b/indra/llcommon/llmutex.h @@ -32,6 +32,8 @@  #include <boost/noncopyable.hpp>  #include "mutex.h" +#include <shared_mutex> +#include <unordered_map>  #include <condition_variable>  //============================================================================ @@ -66,6 +68,45 @@ protected:  #endif  }; +//============================================================================ + +class LL_COMMON_API LLSharedMutex +{ +public: +    LLSharedMutex(); + +    bool isLocked() const; +    bool isThreadLocked() const; +    bool isShared() const { return mIsShared; } + +    void lockShared(); +    void lockExclusive(); +    template<bool SHARED> void lock(); +    template<> void lock<true>() { lockShared(); } +    template<> void lock<false>() { lockExclusive(); } + +    bool trylockShared(); +    bool trylockExclusive(); +    template<bool SHARED> bool trylock(); +    template<> bool trylock<true>() { return trylockShared(); } +    template<> bool trylock<false>() { return trylockExclusive(); } + +    void unlockShared(); +    void unlockExclusive(); +    template<bool SHARED> void unlock(); +    template<> void unlock<true>() { unlockShared(); } +    template<> void unlock<false>() { unlockExclusive(); } + +private: +    std::shared_mutex mSharedMutex; +    mutable std::mutex mLockMutex; +    std::unordered_map<LLThread::id_t, U32> mLockingThreads; +    bool mIsShared; + +    using iterator = std::unordered_map<LLThread::id_t, U32>::iterator; +    using const_iterator = std::unordered_map<LLThread::id_t, U32>::const_iterator; +}; +  // Actually a condition/mutex pair (since each condition needs to be associated with a mutex).  class LL_COMMON_API LLCondition : public LLMutex  { @@ -81,27 +122,57 @@ protected:  	std::condition_variable mCond;  }; +//============================================================================ +  class LLMutexLock  {  public:  	LLMutexLock(LLMutex* mutex)  	{  		mMutex = mutex; -		 -		if(mMutex) + +		if (mMutex)  			mMutex->lock();  	} +  	~LLMutexLock()  	{ -		if(mMutex) +		if (mMutex)  			mMutex->unlock();  	} +  private:  	LLMutex* mMutex;  };  //============================================================================ +template<bool SHARED> +class LLSharedMutexLockTemplate +{ +public: +    LLSharedMutexLockTemplate(LLSharedMutex* mutex) +    : mSharedMutex(mutex) +    { +        if (mSharedMutex) +            mSharedMutex->lock<SHARED>(); +    } + +    ~LLSharedMutexLockTemplate() +    { +        if (mSharedMutex) +            mSharedMutex->unlock<SHARED>(); +    } + +private: +    LLSharedMutex* mSharedMutex; +}; + +using LLSharedMutexLock = LLSharedMutexLockTemplate<true>; +using LLExclusiveMutexLock = LLSharedMutexLockTemplate<false>; + +//============================================================================ +  // Scoped locking class similar in function to LLMutexLock but uses  // the trylock() method to conditionally acquire lock without  // blocking.  Caller resolves the resulting condition by calling @@ -127,6 +198,8 @@ private:  	bool		mLocked;  }; +//============================================================================ +  /**  * @class LLScopedLock  * @brief Small class to help lock and unlock mutexes. diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 7ac80825b5..520d7b4fd9 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -614,7 +614,6 @@ const std::string& LLImage::getLastError()  //static  void LLImage::setLastError(const std::string& message)  { -	LLMutexLock m(sMutex);  	sLastErrorMessage = message;  } @@ -754,7 +753,7 @@ U8* LLImageBase::reallocateData(S32 size)  	return mData;  } -const U8* LLImageBase::getData() const	 +const U8* LLImageBase::getData() const  {   	if(mBadBufferAllocation)  	{ @@ -765,7 +764,7 @@ const U8* LLImageBase::getData() const  	return mData;   } // read only -U8* LLImageBase::getData()				 +U8* LLImageBase::getData()  {   	if(mBadBufferAllocation)  	{ @@ -778,7 +777,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 +853,8 @@ LLImageRaw::~LLImageRaw()  // virtual  U8* LLImageRaw::allocateData(S32 size)  { +	LLImageDataLock lock(this); +  	U8* res = LLImageBase::allocateData(size);  	return res;  } @@ -861,12 +862,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 +879,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 +901,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 +918,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 +947,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 +990,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); @@ -991,6 +1009,8 @@ void LLImageRaw::verticalFlip()  bool LLImageRaw::optimizeAwayAlpha()  { +    LLImageDataLock lock(this); +      if (getComponents() == 4)      {          U8* data = getData(); @@ -1028,6 +1048,8 @@ bool LLImageRaw::optimizeAwayAlpha()  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 +1059,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 +1110,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 +1119,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,10 +1128,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; @@ -1143,12 +1173,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 +1202,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 +1241,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 +1258,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 +1275,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; @@ -1275,16 +1314,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 +1374,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 +1389,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 +1401,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 +1413,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 +1437,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 +1463,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 +1511,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 +1599,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 +1646,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 +1673,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 +1761,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 +1857,12 @@ void LLImageRaw::compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S3  	}  } -bool LLImageRaw::validateSrcAndDst(std::string func, LLImageRaw* src, LLImageRaw* dst) +// 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 +2175,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 +2185,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 +2196,8 @@ U8* LLImageFormatted::reallocateData(S32 size)  // virtual  void LLImageFormatted::deleteData()  { +    LLImageDataLock lock(this); +      if (mDecoding)      {          LL_ERRS() << "LLImageFormatted::deleteData() is called during decoding" << LL_ENDL; @@ -2159,6 +2227,8 @@ void LLImageFormatted::sanityCheck()  bool LLImageFormatted::copyData(U8 *data, S32 size)  { +	LLImageDataLock lock(this); +  	if ( data && ((data != getData()) || (size != getDataSize())) )  	{  		deleteData(); @@ -2171,6 +2241,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(); @@ -2184,6 +2256,8 @@ void LLImageFormatted::appendData(U8 *data, S32 size)  {  	if (data)  	{ +		LLImageDataLock lock(this); +  		if (!getData())  		{  			setData(data, size); @@ -2225,6 +2299,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) @@ -2262,8 +2339,10 @@ bool LLImageFormatted::save(const std::string &filename)  		setLastError("Unable to open file for writing", filename);  		return false;  	} -	 -	outfile.write(getData(), 	getDataSize()); + +	LLImageDataSharedLock lock(this); + +	outfile.write(getData(), getDataSize());  	outfile.close() ;  	return true;  } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 8f9e1b3c54..cc6a58f417 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -116,7 +116,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 +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  { @@ -231,51 +248,51 @@ 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 ); +	void composite( const 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 +300,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 +373,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 90b7272efa..d26d160537 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())) @@ -336,8 +338,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!"); @@ -350,7 +355,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; @@ -397,7 +402,7 @@ U32 LLImageBMP::countTrailingZeros( U32 m )  } -bool LLImageBMP::decodeColorMask16( U8* dst, U8* src ) +bool LLImageBMP::decodeColorMask16( U8* dst, const U8* src )  {  	llassert( 16 == mBitsPerPixel ); @@ -433,7 +438,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 @@ -477,7 +482,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) ); @@ -507,7 +512,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() ); @@ -541,6 +546,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/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp index 36317a5ba8..f4bb3bb120 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 a4957466d4..a06c461107 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))  	{ @@ -158,22 +160,26 @@ bool LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir  	LLTimer elapsed;  	resetLastError(); -	mDecoding = true;  	bool res; -	// 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); +		LLImageDataLock lock(this); + +		mDecoding = true; +		// 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) @@ -414,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 88bdae9b80..290c0da4bf 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()))  	{ @@ -326,7 +328,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()))  	{ @@ -642,7 +647,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()); @@ -1061,6 +1069,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 c1ee052997..44749343e1 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -149,9 +149,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()) @@ -177,7 +186,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/llpngwrapper.cpp b/indra/llimage/llpngwrapper.cpp index cad7c00042..27e23b577b 100644 --- a/indra/llimage/llpngwrapper.cpp +++ b/indra/llimage/llpngwrapper.cpp @@ -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))  			{ diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index 6c06c6de38..482d2a2c8a 100644 --- a/indra/llimagej2coj/llimagej2coj.cpp +++ b/indra/llimagej2coj/llimagej2coj.cpp @@ -489,6 +489,9 @@ public:      bool encode(const LLImageRaw& rawImageIn, LLImageJ2C &compressedImageOut)      { +        LLImageDataSharedLock lockIn(&rawImageIn); +        LLImageDataLock lockOut(&compressedImageOut); +          setImage(rawImageIn);          encoder = opj_create_compress(OPJ_CODEC_J2K); @@ -733,6 +736,9 @@ bool LLImageJ2COJ::initEncode(LLImageJ2C &base, LLImageRaw &raw_image, int block  bool LLImageJ2COJ::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)  { +    LLImageDataLock lockIn(&base); +    LLImageDataLock lockOut(&raw_image); +      JPEG2KDecode decoder(0);      U32 image_channels = 0; @@ -820,6 +826,8 @@ bool LLImageJ2COJ::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, con  bool LLImageJ2COJ::getMetadata(LLImageJ2C &base)  { +    LLImageDataLock lock(&base); +      JPEG2KDecode decode(0);      S32 width = 0; diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index d96cd105dd..8b34592535 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -277,6 +277,8 @@ void transfer_bytes(kdu_byte *dest, kdu_line_buf &src, int gap, int precision);  // as well, when that still existed, with keep_codestream true and MODE_FAST.  void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECodeStreamMode mode)  { +	LLImageDataLock lock(&base); +  	S32 data_size = base.getDataSize();  	S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size); @@ -512,6 +514,10 @@ bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco  bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + +	LLImageDataLock lockIn(&base); +	LLImageDataLock lockOut(&raw_image); +  	ECodeStreamMode mode = MODE_FAST;  	bool limit_time = decode_time > 0.0f; @@ -529,7 +535,7 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco  	// These can probably be grabbed from what's saved in the class.  	kdu_dims dims; -	mCodeStreamp->get_dims(0,dims); +	mCodeStreamp->get_dims(0, dims);  	// Now we are ready to walk through the tiles processing them one-by-one.  	kdu_byte *buffer = raw_image.getData(); @@ -579,7 +585,7 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco  															mCodeStreamp.get()));  				}  				// Do the actual processing -				F32 remaining_time = limit_time ? static_cast<F32>(decode_time - decode_timer.getElapsedTimeF32()) : 0.0f; +				F32 remaining_time = limit_time ? decode_time - decode_timer.getElapsedTimeF32().value() : 0.0f;  				// This is where we do the actual decode.  If we run out of time, return false.  				if (mDecodeState->processTileDecode(remaining_time, limit_time))  				{ diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index 254288a86e..26bd925f03 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -111,6 +111,9 @@ void LLCubeMap::initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages  	// Yes, I know that this is inefficient! - djs 08/08/02  	for (int i = 0; i < 6; i++)  	{ +		LLImageDataSharedLock lockIn(rawimages[i]); +		LLImageDataLock lockOut(mRawImages[i]); +  		const U8 *sd = rawimages[i]->getData();  		U8 *td = mRawImages[i]->getData(); diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index e964d1586f..11a379d70f 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -669,6 +669,7 @@ U8 LLFontFreetype::getStyle() const  void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride) const  {  	LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num); +	LLImageDataLock lock(image_raw);  	llassert(!mIsFallback);  	llassert(image_raw && (image_raw->getComponents() == 2)); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index c6fd824c4e..bbedcf360c 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1887,6 +1887,8 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre  	}  	//----------------------------------------------------------------------------------------------- +	LLImageDataLock lock(imageraw); +  	if (is_compressed)  	{  		LLGLint glbytes; diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index a0ce0ef6cf..77a196380b 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -849,11 +849,14 @@ void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerFetchedTextu  void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nrm_image)  { +	LLImageDataSharedLock lockIn(src); +	LLImageDataLock lockOut(nrm_image); +  	U8* nrm_data = nrm_image->getData();  	S32 resX = src->getWidth();  	S32 resY = src->getHeight(); -	U8* src_data = src->getData(); +	const U8* src_data = src->getData();  	S32 src_cmp = src->getComponents(); @@ -911,6 +914,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI  	{          LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; +		LLImageDataSharedLock lock(src);  		bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries );  		bump_image_map_t::iterator iter = entries_list.find(source_asset_id); @@ -933,7 +937,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI  			U8* dst_data = dst_image->getData();  			S32 dst_data_size = dst_image->getDataSize(); -			U8* src_data = src->getData(); +			const U8* src_data = src->getData();  			S32 src_data_size = src->getDataSize();  			S32 src_components = src->getComponents(); diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 5b8ca6c49c..9cf9f45bfb 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -448,6 +448,8 @@ void saveChart(const std::string& label, const char* suffix, LLImageRaw* scratch  	// disable use of glReadPixels which messes up nVidia nSight graphics debugging  	if (!LLRender::sNsightDebugSupport)  	{ +		LLImageDataSharedLock lock(scratch); +  		//read result back into raw image  		glReadPixels(0, 0, 1024, 512, GL_RGB, GL_UNSIGNED_BYTE, scratch->getData()); diff --git a/indra/newview/llfloater360capture.cpp b/indra/newview/llfloater360capture.cpp index 2c638fa959..a0890b7f9d 100644 --- a/indra/newview/llfloater360capture.cpp +++ b/indra/newview/llfloater360capture.cpp @@ -360,6 +360,8 @@ void LLFloater360Capture::encodeAndSave(LLPointer<LLImageRaw> raw_image, const s      int jpeg_encode_quality = gSavedSettings.getU32("360CaptureJPEGEncodeQuality");      LLPointer<LLImageJPEG> jpeg_image = new LLImageJPEG(jpeg_encode_quality); +    LLImageDataSharedLock lock(raw_image); +      // Actually encode the JPEG image. This is where a lot of time      // is spent now that the snapshot capture process has been      // optimized.  The encode_time parameter doesn't appear to be @@ -410,6 +412,8 @@ void LLFloater360Capture::suspendForAFrame()  // Probably not needed anymore but saving here just in case.  void LLFloater360Capture::mockSnapShot(LLImageRaw* raw)  { +    LLImageDataLock lock(raw); +      unsigned int width = raw->getWidth();      unsigned int height = raw->getHeight();      unsigned int depth = raw->getComponents(); diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp index 9813156bf2..6996224dcb 100644 --- a/indra/newview/llfloaterauction.cpp +++ b/indra/newview/llfloaterauction.cpp @@ -190,6 +190,8 @@ void LLFloaterAuction::onClickSnapshot(void* data)  	if (success)  	{ +		LLImageDataLock lock(raw); +  		self->mTransactionID.generate();  		self->mImageID = self->mTransactionID.makeAssetID(gAgent.getSecureSessionID()); diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp index ba91277c79..af96fdbcfd 100644 --- a/indra/newview/llfloatercolorpicker.cpp +++ b/indra/newview/llfloatercolorpicker.cpp @@ -135,6 +135,8 @@ void LLFloaterColorPicker::createUI ()  	// create RGB type area (not really RGB but it's got R,G & B in it.,..  	LLPointer<LLImageRaw> raw = new LLImageRaw ( mRGBViewerImageWidth, mRGBViewerImageHeight, mComponents ); +	LLImageDataLock lock(raw); +  	U8* bits = raw->getData();  	S32 linesize = mRGBViewerImageWidth * mComponents;  	for ( S32 y = 0; y < mRGBViewerImageHeight; ++y ) diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index ba0f97e2e1..5e7978e224 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -789,6 +789,7 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance)  	if (imagep)  	{ +		LLImageDataSharedLock lock(imagep);  		mVolume->sculpt(imagep->getWidth(), imagep->getHeight(), imagep->getComponents(), imagep->getData(), 0, false);  	} diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index c8ac73b838..e966514955 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -70,7 +70,7 @@ void modify_outfit(BOOL append, const LLUUID& cat_id, LLInventoryModel* model)      if (items.size() > max_items())      {          LLSD args; -        args["AMOUNT"] = llformat("%d", static_cast<U32>(max_items)); +        args["AMOUNT"] = llformat("%u", max_items());          LLNotificationsUtil::add("TooManyWearables", args);          return;      } diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 5e78e15c72..415543eb37 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -3424,6 +3424,8 @@ void LLMaterialEditor::inventoryChanged(LLViewerObject* object,  void LLMaterialEditor::saveTexture(LLImageJ2C* img, const std::string& name, const LLUUID& asset_id, upload_callback_f cb)  { +    LLImageDataSharedLock lock(img); +      if (asset_id.isNull()          || img == nullptr          || img->getDataSize() == 0) diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 01d6469010..2622c23314 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -2360,17 +2360,19 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)  				std::stringstream texture_str;  				if (texture != NULL && include_textures && mUploadTextures)  				{ -					if(texture->hasSavedRawImage()) -					{											 +					if (texture->hasSavedRawImage()) +					{ +						LLImageDataLock lock(texture->getSavedRawImage()); +  						LLPointer<LLImageJ2C> upload_file =  							LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());  						if (!upload_file.isNull() && upload_file->getDataSize())  						{ -						texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize()); +							texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize()); +						}  					}  				} -				}  				if (texture != NULL &&  					mUploadTextures && @@ -2514,17 +2516,19 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)  				std::stringstream texture_str;  				if (texture != NULL && include_textures && mUploadTextures)  				{ -					if(texture->hasSavedRawImage()) -					{											 +					if (texture->hasSavedRawImage()) +					{ +						LLImageDataLock lock(texture->getSavedRawImage()); +  						LLPointer<LLImageJ2C> upload_file =  							LLViewerTextureList::convertToUploadFile(texture->getSavedRawImage());  						if (!upload_file.isNull() && upload_file->getDataSize())  						{ -						texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize()); +							texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize()); +						}  					}  				} -				}  				if (texture != NULL &&  					mUploadTextures && diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 0ba3c3d691..e7f9d0e5df 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -345,6 +345,7 @@ void LLNetMap::draw()  			mObjectImageCenterGlobal = viewPosToGlobal(llfloor(new_center.mV[VX]), llfloor(new_center.mV[VY]));  			// Create the base texture. +			LLImageDataLock lock(mObjectRawImagep);  			U8 *default_texture = mObjectRawImagep->getData();  			memset( default_texture, 0, mObjectImagep->getWidth() * mObjectImagep->getHeight() * mObjectImagep->getComponents() ); @@ -915,6 +916,7 @@ void LLNetMap::renderPoint(const LLVector3 &pos_local, const LLColor4U &color,  		return;  	} +	LLImageDataLock lock(mObjectRawImagep);  	U8 *datap = mObjectRawImagep->getData();  	S32 neg_radius = diameter / 2; diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index b7a1832b17..bb7c73b59f 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -766,6 +766,8 @@ void LLSnapshotLivePreview::prepareFreezeFrame()      // Get the decoded version of the formatted image      getEncodedImage(); +    LLImageDataSharedLock lock(mPreviewImageEncoded); +      // We need to scale that a bit for display...      LLPointer<LLImageRaw> scaled = new LLImageRaw(          mPreviewImageEncoded->getData(), @@ -825,13 +827,15 @@ LLPointer<LLImageRaw> LLSnapshotLivePreview::getEncodedImage()  {  	if (!mPreviewImageEncoded)  	{ +		LLImageDataSharedLock lock(mPreviewImage); +  		mPreviewImageEncoded = new LLImageRaw; -     +  		mPreviewImageEncoded->resize(              mPreviewImage->getWidth(),              mPreviewImage->getHeight(),              mPreviewImage->getComponents()); -         +          if (getSnapshotType() == LLSnapshotModel::SNAPSHOT_TEXTURE)  		{              // We don't store the intermediate formatted image in mFormattedImage in the J2C case  @@ -978,6 +982,8 @@ void LLSnapshotLivePreview::getSize(S32& w, S32& h) const  void LLSnapshotLivePreview::saveTexture(BOOL outfit_snapshot, std::string name)  { +	LLImageDataSharedLock lock(mPreviewImage); +  	LL_DEBUGS("Snapshot") << "saving texture: " << mPreviewImage->getWidth() << "x" << mPreviewImage->getHeight() << LL_ENDL;  	// gen a new uuid for this asset  	LLTransactionID tid; diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index a14d4f7a30..dfaeeaab62 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -96,7 +96,7 @@ private:  public:  	LLTextureCacheWorker(LLTextureCache* cache, const LLUUID& id, -						 U8* data, S32 datasize, S32 offset, +						 const U8* data, S32 datasize, S32 offset,  						 S32 imagesize, // for writes  						 LLTextureCache::Responder* responder)  		: LLWorkerClass(cache, "LLTextureCacheWorker"), @@ -145,7 +145,7 @@ protected:  	LLUUID	mID;  	U8* mReadData; -	U8* mWriteData; +    const U8* mWriteData;  	S32 mDataSize;  	S32 mOffset;  	S32 mImageSize; @@ -239,7 +239,7 @@ class LLTextureCacheRemoteWorker : public LLTextureCacheWorker  {  public:  	LLTextureCacheRemoteWorker(LLTextureCache* cache, const LLUUID& id, -						 U8* data, S32 datasize, S32 offset, +						 const U8* data, S32 datasize, S32 offset,  						 S32 imagesize, // for writes  						 LLPointer<LLImageRaw> raw, S32 discardlevel,  						 LLTextureCache::Responder* responder)  @@ -1961,7 +1961,7 @@ bool LLTextureCache::readComplete(handle_t handle, bool abort)  }  LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, -													  U8* data, S32 datasize, S32 imagesize, +													  const U8* data, S32 datasize, S32 imagesize,  													  LLPointer<LLImageRaw> rawimage, S32 discardlevel,  													  WriteResponder* responder)  { @@ -2047,6 +2047,9 @@ LLPointer<LLImageRaw> LLTextureCache::readFromFastCache(const LLUUID& id, S32& d  bool LLTextureCache::writeToFastCache(LLUUID image_id, S32 id, LLPointer<LLImageRaw> raw, S32 discardlevel)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + +	LLImageDataSharedLock lock(raw); +  	//rescale image if needed  	if (raw.isNull() || raw->isBufferInvalid() || !raw->getData())  	{ diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index 43e91b3e4c..cba45393f9 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -125,7 +125,7 @@ public:  	handle_t readFromCache(const LLUUID& id, S32 offset, S32 size,  						   ReadResponder* responder);  	bool readComplete(handle_t handle, bool abort); -	handle_t writeToCache(const LLUUID& id, U8* data, S32 datasize, S32 imagesize, LLPointer<LLImageRaw> rawimage, S32 discardlevel, +	handle_t writeToCache(const LLUUID& id, const U8* data, S32 datasize, S32 imagesize, LLPointer<LLImageRaw> rawimage, S32 discardlevel,  						  WriteResponder* responder);  	LLPointer<LLImageRaw> readFromFastCache(const LLUUID& id, S32& discardlevel);  	bool writeComplete(handle_t handle, bool abort = false); diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 38c9b3717d..4ecabf666b 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1699,7 +1699,9 @@ bool LLTextureFetchWorker::doWork(S32 param)  					mFormattedImage = new LLImageJ2C; // default  				}  			} -						 + +			LLImageDataLock lock(mFormattedImage); +  			if (mHaveAllData) //the image file is fully loaded.  			{  				mFileSize = total_size; @@ -1857,6 +1859,9 @@ bool LLTextureFetchWorker::doWork(S32 param)  			//return false;              return doWork(param);  		} + +		LLImageDataSharedLock lock(mFormattedImage); +  		S32 datasize = mFormattedImage->getDataSize();  		if(mFileSize < datasize)//This could happen when http fetching and sim fetching mixed.  		{ diff --git a/indra/newview/lltinygltfhelper.cpp b/indra/newview/lltinygltfhelper.cpp index 999be07dba..cee18489f0 100644 --- a/indra/newview/lltinygltfhelper.cpp +++ b/indra/newview/lltinygltfhelper.cpp @@ -31,7 +31,7 @@  #include "llviewertexture.h"  #include "llviewertexturelist.h" -void strip_alpha_channel(LLPointer<LLImageRaw>& img) +static void strip_alpha_channel(LLPointer<LLImageRaw>& img)  {      if (img->getComponents() == 4)      { @@ -45,13 +45,13 @@ void strip_alpha_channel(LLPointer<LLImageRaw>& img)  // PRECONDITIONS:  // dst_img must be 3 component  // src_img and dst_image must have the same dimensions -void copy_red_channel(LLPointer<LLImageRaw>& src_img, LLPointer<LLImageRaw>& dst_img) +static void copy_red_channel(const LLPointer<LLImageRaw>& src_img, LLPointer<LLImageRaw>& dst_img)  {      llassert(src_img->getWidth() == dst_img->getWidth() && src_img->getHeight() == dst_img->getHeight());      llassert(dst_img->getComponents() == 3);      U32 pixel_count = dst_img->getWidth() * dst_img->getHeight(); -    U8* src = src_img->getData(); +    const U8* src = src_img->getData();      U8* dst = dst_img->getData();      S8 src_components = src_img->getComponents(); @@ -95,6 +95,8 @@ void LLTinyGLTFHelper::initFetchedTextures(tinygltf::Material& material,              int mr_idx = material.pbrMetallicRoughness.metallicRoughnessTexture.index;              if (occlusion_idx != mr_idx)              { +                LLImageDataLock lockIn(occlusion_img); +                LLImageDataLock lockOut(mr_img);                  //scale occlusion image to match resolution of mr image                  occlusion_img->scale(mr_img->getWidth(), mr_img->getHeight()); @@ -104,6 +106,7 @@ void LLTinyGLTFHelper::initFetchedTextures(tinygltf::Material& material,      }      else if (occlusion_img)      { +        LLImageDataSharedLock lock(occlusion_img);          //no mr but occlusion exists, make a white mr_img and copy occlusion red channel over          mr_img = new LLImageRaw(occlusion_img->getWidth(), occlusion_img->getHeight(), 3);          mr_img->clear(255, 255, 255); diff --git a/indra/newview/llviewerassetupload.cpp b/indra/newview/llviewerassetupload.cpp index a2b0b04092..dcb14eb383 100644 --- a/indra/newview/llviewerassetupload.cpp +++ b/indra/newview/llviewerassetupload.cpp @@ -654,6 +654,8 @@ LLBufferedAssetUploadInfo::LLBufferedAssetUploadInfo(LLUUID itemId, LLPointer<LL  {      setItemId(itemId); +    LLImageDataSharedLock lock(image); +      EImageCodec codec = static_cast<EImageCodec>(image->getCodec());      switch (codec) diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index 785c84c38d..e1f372d396 100755 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -344,6 +344,8 @@ void LLViewerParcelOverlay::updateOverlayTexture()  	const LLColor4U for_sale  = LLUIColorTable::instance().getColor("PropertyColorForSale").get();  	const LLColor4U auction  = LLUIColorTable::instance().getColor("PropertyColorAuction").get(); +	LLImageDataLock lock(mImageRaw); +  	// Create the base texture.  	U8 *raw = mImageRaw->getData();  	const S32 COUNT = mParcelGridsPerEdge * mParcelGridsPerEdge; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index ec6f2c848f..820a051782 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -285,6 +285,7 @@ LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(const U32 wid  LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture(const LLImageRaw* raw, FTType type, bool usemipmaps)  { +    LLImageDataSharedLock lock(raw);      LLViewerFetchedTexture* ret = new LLViewerFetchedTexture(raw, type, usemipmaps);      gTextureList.addImage(ret, TEX_LIST_STANDARD);      return ret; @@ -2905,6 +2906,8 @@ void LLViewerFetchedTexture::saveRawImage()  		return;  	} +    LLImageDataSharedLock lock(mRawImage); +  	mSavedRawDiscardLevel = mRawDiscardLevel;      if (mBoostLevel == LLGLTexture::BOOST_ICON)      { diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index f898fb7142..7931b74b11 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1252,6 +1252,8 @@ bool LLViewerTextureList::createUploadFile(LLPointer<LLImageRaw> raw_image,  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; +    LLImageDataSharedLock lock(raw_image); +      // make a copy, since convertToUploadFile scales raw image      LLPointer<LLImageRaw> scale_image = new LLImageRaw(          raw_image->getData(), @@ -1357,6 +1359,8 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename,  LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImageRaw> raw_image, const S32 max_image_dimentions, bool force_square, bool force_lossless)  {  	LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; +    LLImageDataLock lock(raw_image); +      if (force_square)      {          S32 biggest_side = llmax(raw_image->getWidth(), raw_image->getHeight()); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index ba2b6e1c7c..27ec8d9376 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -4890,6 +4890,7 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei  	{  		return FALSE;  	} +  	//check if there is enough memory for the snapshot image  	if(image_width * image_height > (1 << 22)) //if snapshot image is larger than 2K by 2K  	{ @@ -5008,6 +5009,9 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei  		image_buffer_x = llfloor(snapshot_width  * scale_factor) ;  		image_buffer_y = llfloor(snapshot_height * scale_factor) ;  	} + +	LLImageDataLock lock(raw); +  	if ((image_buffer_x > 0) && (image_buffer_y > 0))  	{  		raw->resize(image_buffer_x, image_buffer_y, 3); @@ -5266,6 +5270,8 @@ BOOL LLViewerWindow::simpleSnapshot(LLImageRaw* raw, S32 image_width, S32 image_          display(do_rebuild, zoom, subfield, for_snapshot);      } +    LLImageDataSharedLock lock(raw); +      glReadPixels(          0, 0,          image_width, diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index fee00eb6f4..8ab7cda28c 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -8894,7 +8894,7 @@ void LLVOAvatar::clearChat()  } -void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index) +void LLVOAvatar::applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index)  {  	if (index >= BAKED_NUM_INDICES)  	{ @@ -9770,6 +9770,8 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture  	{  		if(aux_src && aux_src->getComponents() == 1)  		{ +			LLImageDataSharedLock lock(aux_src); +  			if (!aux_src->getData())  			{  				LL_ERRS() << "No auxiliary source (morph mask) data for image id " << id << LL_ENDL; diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 48bfd5293a..759d02959c 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -590,7 +590,7 @@ public:  	// Morph masks  	//--------------------------------------------------------------------  public: -	/*virtual*/ void	applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES); +	/*virtual*/ void	applyMorphMask(const U8* tex_data, S32 width, S32 height, S32 num_components, LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES);  	BOOL 		morphMaskNeedsUpdate(LLAvatarAppearanceDefines::EBakedTextureIndex index = LLAvatarAppearanceDefines::BAKED_NUM_INDICES); diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp index 20621665fa..db197335f2 100644 --- a/indra/newview/llvosky.cpp +++ b/indra/newview/llvosky.cpp @@ -166,6 +166,7 @@ S32 LLSkyTex::getWhich(const BOOL curr)  void LLSkyTex::initEmpty(const S32 tex)  { +	LLImageDataLock lock(mImageRaw[tex]);  	U8* data = mImageRaw[tex]->getData();  	for (S32 i = 0; i < SKYTEX_RESOLUTION; ++i)  	{ @@ -187,7 +188,8 @@ void LLSkyTex::initEmpty(const S32 tex)  void LLSkyTex::create()  { -	U8* data = mImageRaw[sCurrent]->getData(); +	LLImageDataSharedLock lock(mImageRaw[sCurrent]); +	const U8* data = mImageRaw[sCurrent]->getData();  	for (S32 i = 0; i < SKYTEX_RESOLUTION; ++i)  	{  		for (S32 j = 0; j < SKYTEX_RESOLUTION; ++j) diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h index 5941ab6e3b..509ad97786 100644 --- a/indra/newview/llvosky.h +++ b/indra/newview/llvosky.h @@ -101,6 +101,7 @@ protected:  	void setPixel(const LLColor4U &col, const S32 i, const S32 j)  	{ +		LLImageDataSharedLock lock(mImageRaw[sCurrent]);  		S32 offset = (i * SKYTEX_RESOLUTION + j) * SKYTEX_COMPONENTS;  		U32* pix = (U32*) &(mImageRaw[sCurrent]->getData()[offset]);  		*pix = col.asRGBA(); @@ -109,6 +110,7 @@ protected:  	LLColor4U getPixel(const S32 i, const S32 j)  	{  		LLColor4U col; +		LLImageDataSharedLock lock(mImageRaw[sCurrent]);  		S32 offset = (i * SKYTEX_RESOLUTION + j) * SKYTEX_COMPONENTS;  		U32* pix = (U32*) &(mImageRaw[sCurrent]->getData()[offset]);  		col.fromRGBA( *pix ); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index ec2f490742..8846e30145 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1311,11 +1311,13 @@ void LLVOVolume::sculpt()  			}  		}  		else -		{					 +		{ +			LLImageDataSharedLock lock(raw_image); +  			sculpt_height = raw_image->getHeight();  			sculpt_width = raw_image->getWidth();  			sculpt_components = raw_image->getComponents();		 -					    +  			sculpt_data = raw_image->getData();  			if(LLViewerTextureManager::sTesterp) diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index f2d7e4585a..ade9bbd847 100644 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -239,10 +239,12 @@ LLCore::BufferArray::ptr_t LLWebProfile::buildPostData(const LLSD &data, LLPoint          << "Content-Disposition: form-data; name=\"file\"; filename=\"snapshot.png\"\r\n"          << "Content-Type: image/png\r\n\r\n"; +    LLImageDataSharedLock lock(image); +      // Insert the image data.      //char *datap = (char *)(image->getData());      //bas.write(datap, image->getDataSize()); -    U8* image_data = image->getData(); +    const U8* image_data = image->getData();      for (S32 i = 0; i < image->getDataSize(); ++i)      {          bas << image_data[i]; | 
