diff options
93 files changed, 1438 insertions, 352 deletions
| diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index af1f16d04d..9bc17df32a 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -5,7 +5,7 @@  #  # Platform variables:  # -#   DARWIN  - Mac OS X +#   DARWIN  - macOS  #   LINUX   - Linux  #   WINDOWS - Windows diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py index bcb9d884c3..20c0e01576 100755 --- a/indra/lib/python/indra/util/llmanifest.py +++ b/indra/lib/python/indra/util/llmanifest.py @@ -116,7 +116,7 @@ BASE_ARGUMENTS=[      dict(name='build', description='Build directory.', default=DEFAULT_SRCTREE),      dict(name='buildtype', description='Build type (i.e. Debug, Release, RelWithDebInfo).', default=None),      dict(name='bundleid', -         description="""The Mac OS X Bundle identifier.""", +         description="""The macOS Bundle identifier.""",           default="com.secondlife.indra.viewer"),      dict(name='channel',           description="""The channel to use for updates, packaging, settings name, etc.""", @@ -146,7 +146,7 @@ BASE_ARGUMENTS=[      dict(name='signature',           description="""This specifies an identity to sign the viewer with, if any.          If no value is supplied, the default signature will be used, if any. Currently -        only used on Mac OS X.""", +        only used on macOS.""",           default=None),      dict(name='source',           description='Source directory.', 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/llerror.cpp b/indra/llcommon/llerror.cpp index 414515854a..19c285ea5a 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -700,7 +700,7 @@ namespace      bool shouldLogToStderr()      {  #if LL_DARWIN -        // On Mac OS X, stderr from apps launched from the Finder goes to the +        // On macOS, stderr from apps launched from the Finder goes to the          // console log.  It's generally considered bad form to spam too much          // there. That scenario can be detected by noticing that stderr is a          // character device (S_IFCHR). diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index 0273dd5970..973ecbc87b 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,194 @@ 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(); +    iterator it = mLockingThreads.find(current_thread); +    if (it != mLockingThreads.end()) +    { +        if (mIsShared) +        { +            // The mutex is already locked in the current thread +            // but this lock is SHARED (not EXCLISIVE) +            // We can't lock it again, the lock stays shared +            // This can lead to a collision (theoretically) +            llassert_always(!"The current thread is already locked SHARED and can't be locked EXCLUSIVE"); +        } +        it->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 +344,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/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 938685bae6..d3f99a413d 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -269,9 +269,9 @@ LLOSInfo::LLOSInfo() :  #elif LL_DARWIN  	// Initialize mOSStringSimple to something like: -	// "Mac OS X 10.6.7" +	// "macOS 10.13.1"  	{ -		const char * DARWIN_PRODUCT_NAME = "Mac OS X"; +		const char * DARWIN_PRODUCT_NAME = "macOS";  		int64_t major_version, minor_version, bugfix_version = 0; @@ -294,7 +294,7 @@ LLOSInfo::LLOSInfo() :  	}  	// Initialize mOSString to something like: -	// "Mac OS X 10.6.7 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386" +	// "macOS 10.13.1 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386"  	struct utsname un;  	if(uname(&un) != -1)  	{		 diff --git a/indra/llcommon/llsys_objc.mm b/indra/llcommon/llsys_objc.mm index 3fd85fb1c9..1393ccea50 100644 --- a/indra/llcommon/llsys_objc.mm +++ b/indra/llcommon/llsys_objc.mm @@ -27,38 +27,12 @@  #import "llsys_objc.h"  #import <AppKit/AppKit.h> -static auto intAtStringIndex(NSArray *array, int index) -{ -    return [(NSString *)[array objectAtIndex:index] integerValue]; -} -  bool LLGetDarwinOSInfo(int64_t &major, int64_t &minor, int64_t &patch)  { -    if (NSAppKitVersionNumber > NSAppKitVersionNumber10_8) -    {          NSOperatingSystemVersion osVersion = [[NSProcessInfo processInfo] operatingSystemVersion];          major = osVersion.majorVersion;          minor = osVersion.minorVersion;          patch = osVersion.patchVersion; -    } -    else -    { -        NSString* versionString = [[NSDictionary dictionaryWithContentsOfFile: -                                    @"/System/Library/CoreServices/SystemVersion.plist"] objectForKey:@"ProductVersion"]; -        NSArray* versions = [versionString componentsSeparatedByString:@"."]; -        NSUInteger count = [versions count]; -        if (count > 0) -        { -            major = intAtStringIndex(versions, 0); -            if (count > 1) -            { -                minor = intAtStringIndex(versions, 1); -                if (count > 2) -                { -                    patch = intAtStringIndex(versions, 2); -                } -            } -        } -    } +      return true;  } diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 200add404f..285469f0d4 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -510,7 +510,7 @@ S32	LLUUID::getNodeID(unsigned char* node_id)  }  #elif LL_DARWIN -// Mac OS X version of the UUID generation code... +// macOS version of the UUID generation code...  /*   * Get an ethernet hardware address, if we can find it...   */ diff --git a/indra/llfilesystem/lldir_mac.cpp b/indra/llfilesystem/lldir_mac.cpp index 9ad8e274b6..0d9695e161 100644 --- a/indra/llfilesystem/lldir_mac.cpp +++ b/indra/llfilesystem/lldir_mac.cpp @@ -1,6 +1,6 @@  /**    * @file lldir_mac.cpp - * @brief Implementation of directory utilities for Mac OS X + * @brief Implementation of directory utilities for macOS   *   * $LicenseInfo:firstyear=2002&license=viewerlgpl$   * Second Life Viewer Source Code diff --git a/indra/llfilesystem/lldir_mac.h b/indra/llfilesystem/lldir_mac.h index 558727ebbc..0290fb773b 100644 --- a/indra/llfilesystem/lldir_mac.h +++ b/indra/llfilesystem/lldir_mac.h @@ -1,6 +1,6 @@  /**    * @file lldir_mac.h - * @brief Definition of directory utilities class for Mac OS X + * @brief Definition of directory utilities class for macOS   *   * $LicenseInfo:firstyear=2000&license=viewerlgpl$   * Second Life Viewer Source Code diff --git a/indra/llfilesystem/lldir_utils_objc.h b/indra/llfilesystem/lldir_utils_objc.h index 59dbeb4aec..48148aad95 100644 --- a/indra/llfilesystem/lldir_utils_objc.h +++ b/indra/llfilesystem/lldir_utils_objc.h @@ -1,6 +1,6 @@  /**    * @file lldir_utils_objc.h - * @brief Definition of directory utilities class for Mac OS X + * @brief Definition of directory utilities class for macOS   *   * $LicenseInfo:firstyear=2020&license=viewerlgpl$   * Second Life Viewer Source Code diff --git a/indra/llfilesystem/lldir_utils_objc.mm b/indra/llfilesystem/lldir_utils_objc.mm index 20540fb93c..01fe9e1f2c 100644 --- a/indra/llfilesystem/lldir_utils_objc.mm +++ b/indra/llfilesystem/lldir_utils_objc.mm @@ -1,6 +1,6 @@  /**    * @file lldir_utils_objc.mm - * @brief Cocoa implementation of directory utilities for Mac OS X + * @brief Cocoa implementation of directory utilities for macOS   *   * $LicenseInfo:firstyear=2020&license=viewerlgpl$   * Second Life Viewer Source Code diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 031471d1fe..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,12 @@ U8* LLImageFormatted::reallocateData(S32 size)  // virtual  void LLImageFormatted::deleteData()  { +    LLImageDataLock lock(this); + +    if (mDecoding) +    { +        LL_ERRS() << "LLImageFormatted::deleteData() is called during decoding" << LL_ENDL; +    }  	sGlobalFormattedMemory -= getDataSize();  	LLImageBase::deleteData();  } @@ -2155,6 +2227,8 @@ void LLImageFormatted::sanityCheck()  bool LLImageFormatted::copyData(U8 *data, S32 size)  { +	LLImageDataLock lock(this); +  	if ( data && ((data != getData()) || (size != getDataSize())) )  	{  		deleteData(); @@ -2167,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(); @@ -2180,6 +2256,8 @@ void LLImageFormatted::appendData(U8 *data, S32 size)  {  	if (data)  	{ +		LLImageDataLock lock(this); +  		if (!getData())  		{  			setData(data, size); @@ -2221,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) @@ -2258,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 8dba1641a6..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))  	{ @@ -157,36 +159,48 @@ bool LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;  	LLTimer elapsed; -	bool res = true; -	  	resetLastError(); -	// Check to make sure that this instance has been initialized with data -	if (!getData() || (getDataSize() < 16)) +	bool res;  	{ -		setLastError("LLImageJ2C uninitialized"); -		res = true; // done -	} -	else -	{ -		// Update the raw discard level -		updateRawDiscardLevel(); +		LLImageDataLock lock(this); +  		mDecoding = true; -		res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count); +		// Check to make sure that this instance has been initialized with data +		if (!getData() || (getDataSize() < 16)) +		{ +			setLastError("LLImageJ2C uninitialized"); +			res = true; // done +		} +		else +		{ +			// Update the raw discard level +			updateRawDiscardLevel(); +			res = mImpl->decodeImpl(*this, *raw_imagep, decode_time, first_channel, max_channel_count); +		}  	} -	 +  	if (res)  	{  		if (!mDecoding)  		{  			// Failed  			raw_imagep->deleteData(); +			res = false;  		}  		else  		{  			mDecoding = false;  		}  	} +	else +	{ +		if (mDecoding) +		{ +			LL_WARNS() << "decodeImpl failed but mDecoding is TRUE" << LL_ENDL; +			mDecoding = false; +		} +	}  	if (!mLastError.empty())  	{ @@ -406,9 +420,10 @@ bool LLImageJ2C::loadAndValidate(const std::string &filename)  bool LLImageJ2C::validate(U8 *data, U32 file_size)  { -  	resetLastError(); -	 + +	LLImageDataLock lock(this); +  	setData(data, file_size);  	bool res = updateData(); diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp index 32a5472ec8..a35171601a 100644 --- a/indra/llimage/llimagejpeg.cpp +++ b/indra/llimage/llimagejpeg.cpp @@ -50,6 +50,8 @@ bool LLImageJPEG::updateData()  {  	resetLastError(); +	LLImageDataLock lock(this); +  	// Check to make sure that this instance has been initialized with data  	if (!getData() || (0 == getDataSize()))  	{ @@ -188,7 +190,10 @@ bool LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)  	llassert_always(raw_image);  	resetLastError(); -	 + +	LLImageDataLock lockIn(this); +	LLImageDataLock lockOut(raw_image); +  	// Check to make sure that this instance has been initialized with data  	if (!getData() || (0 == getDataSize()))  	{ @@ -408,6 +413,8 @@ void LLImageJPEG::encodeTermDestination( j_compress_ptr cinfo )  {  	LLImageJPEG* self = (LLImageJPEG*) cinfo->client_data; +	LLImageDataLock lock(self); +  	S32 file_bytes = (S32)(self->mOutputBufferSize - cinfo->dest->free_in_buffer);  	self->allocateData(file_bytes); @@ -484,6 +491,9 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time )  	resetLastError(); +	LLImageDataSharedLock lockIn(raw_image); +	LLImageDataLock lockOut(this); +  	switch( raw_image->getComponents() )  	{  	case 1: diff --git a/indra/llimage/llimagejpeg.h b/indra/llimage/llimagejpeg.h index 7a849a8421..d674b40b8f 100644 --- a/indra/llimage/llimagejpeg.h +++ b/indra/llimage/llimagejpeg.h @@ -73,8 +73,6 @@ public:  	static void		errorEmitMessage(j_common_ptr cinfo, int msg_level);  	static void		errorOutputMessage(j_common_ptr cinfo); -	static bool		decompress(LLImageJPEG* imagep); -  protected:  	U8*				mOutputBuffer;		// temp buffer used during encoding  	S32				mOutputBufferSize;	// bytes in mOuputBuffer diff --git a/indra/llimage/llimagepng.cpp b/indra/llimage/llimagepng.cpp index c4b98d8260..5d956bfb4e 100644 --- a/indra/llimage/llimagepng.cpp +++ b/indra/llimage/llimagepng.cpp @@ -51,6 +51,8 @@ bool LLImagePNG::updateData()  {      resetLastError(); +    LLImageDataLock lock(this); +      // Check to make sure that this instance has been initialized with data      if (!getData() || (0 == getDataSize()))      { @@ -87,6 +89,9 @@ bool LLImagePNG::decode(LLImageRaw* raw_image, F32 decode_time)      resetLastError(); +    LLImageDataSharedLock lockIn(this); +    LLImageDataLock lockOut(raw_image); +      // Check to make sure that this instance has been initialized with data      if (!getData() || (0 == getDataSize()))      { @@ -119,6 +124,9 @@ bool LLImagePNG::encode(const LLImageRaw* raw_image, F32 encode_time)      resetLastError(); +	LLImageDataSharedLock lockIn(raw_image); +	LLImageDataLock lockOut(this); +  	// Image logical size  	setSize(raw_image->getWidth(), raw_image->getHeight(), raw_image->getComponents()); diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp index 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 2ad42d6b87..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,8 +514,13 @@ 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;  	LLTimer decode_timer;  	if (!mCodeStreamp->exists()) @@ -528,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(); @@ -578,16 +585,18 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco  															mCodeStreamp.get()));  				}  				// Do the actual processing -				F32 remaining_time = decode_time - decode_timer.getElapsedTimeF32(); +				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, (decode_time > 0.0f))) +				if (mDecodeState->processTileDecode(remaining_time, limit_time))  				{  					mDecodeState.reset();  				}  				else  				{  					// Not finished decoding yet. -					//					setLastError("Ran out of time while decoding"); +					base.setLastError("Ran out of time while decoding"); +					base.decodeFailed(); +					cleanupCodeStream();  					return false;  				}  			} diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index 523bcbb60d..60030bb920 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -77,7 +77,7 @@ const char* LOOPBACK_ADDRESS_STRING = "127.0.0.1";  const char* BROADCAST_ADDRESS_STRING = "255.255.255.255";  #if LL_DARWIN -	// Mac OS X returns an error when trying to set these to 400000.  Smaller values succeed. +	// macOS returns an error when trying to set these to 400000.  Smaller values succeed.  	const int	SEND_BUFFER_SIZE	= 200000;  	const int	RECEIVE_BUFFER_SIZE	= 200000;  #else // LL_DARWIN diff --git a/indra/llprimitive/llgltfmaterial.cpp b/indra/llprimitive/llgltfmaterial.cpp index 237636bd0b..12af568b7e 100644 --- a/indra/llprimitive/llgltfmaterial.cpp +++ b/indra/llprimitive/llgltfmaterial.cpp @@ -47,16 +47,49 @@ const char* const LLGLTFMaterial::GLTF_FILE_EXTENSION_TRANSFORM_ROTATION = "rota  // special UUID that indicates a null UUID in override data  const LLUUID LLGLTFMaterial::GLTF_OVERRIDE_NULL_UUID = LLUUID("ffffffff-ffff-ffff-ffff-ffffffffffff"); +LLGLTFMaterial::LLGLTFMaterial() +{ +    // IMPORTANT: since we use the hash of the member variables memory block of +    // this class to detect changes, we must ensure that all its padding bytes +    // have been zeroed out. But of course, we must leave the LLRefCount member +    // variable untouched (and skip it when hashing), and we cannot either +    // touch the local texture overrides map (else we destroy pointers, and +    // sundry private data, which would lead to a crash when using that map). +    // The variable members have therefore been arranged so that anything, +    // starting at mLocalTexDataDigest and up to the end of the members, can be +    // safely zeroed. HB +    const size_t offset = intptr_t(&mLocalTexDataDigest) - intptr_t(this); +    memset((void*)((const char*)this + offset), 0, sizeof(*this) - offset); + +    // Now that we zeroed out our member variables, we can set the ones that +    // should not be zero to their default value. HB +    mBaseColor.set(1.f, 1.f, 1.f, 1.f); +    mMetallicFactor = mRoughnessFactor = 1.f; +    mAlphaCutoff = 0.5f; +    for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) +    { +        mTextureTransform[i].mScale.set(1.f, 1.f); +#if 0 +        mTextureTransform[i].mOffset.clear(); +        mTextureTransform[i].mRotation = 0.f; +#endif     +    } +#if 0 +    mLocalTexDataDigest = 0; +    mAlphaMode = ALPHA_MODE_OPAQUE;    // This is 0 +    mOverrideDoubleSided = mOverrideAlphaMode = false; +#endif +} +  void LLGLTFMaterial::TextureTransform::getPacked(F32 (&packed)[8]) const  {      packed[0] = mScale.mV[VX];      packed[1] = mScale.mV[VY];      packed[2] = mRotation; -    // packed[3] = unused      packed[4] = mOffset.mV[VX];      packed[5] = mOffset.mV[VY]; -    // packed[6] = unused -    // packed[7] = unused +    // Not used but nonetheless zeroed for proper hashing. HB +    packed[3] = packed[6] = packed[7] = 0.f;  }  bool LLGLTFMaterial::TextureTransform::operator==(const TextureTransform& other) const @@ -89,13 +122,37 @@ LLGLTFMaterial& LLGLTFMaterial::operator=(const LLGLTFMaterial& rhs)      mOverrideDoubleSided = rhs.mOverrideDoubleSided;      mOverrideAlphaMode = rhs.mOverrideAlphaMode; -    mTrackingIdToLocalTexture = rhs.mTrackingIdToLocalTexture; - -    updateTextureTracking(); +    if (rhs.mTrackingIdToLocalTexture.empty()) +    { +        mTrackingIdToLocalTexture.clear(); +        mLocalTexDataDigest = 0; +    } +    else +    { +        mTrackingIdToLocalTexture = rhs.mTrackingIdToLocalTexture; +        updateLocalTexDataDigest(); +        updateTextureTracking(); +    }      return *this;  } +void LLGLTFMaterial::updateLocalTexDataDigest() +{ +    mLocalTexDataDigest = 0; +    if (!mTrackingIdToLocalTexture.empty()) +    { +        for (local_tex_map_t::const_iterator +                it = mTrackingIdToLocalTexture.begin(), +                end = mTrackingIdToLocalTexture.end(); +             it != end; ++it) +        { +            mLocalTexDataDigest ^= it->first.getDigest64() ^ +                                   it->second.getDigest64(); +        } +    } +} +  bool LLGLTFMaterial::operator==(const LLGLTFMaterial& rhs) const  {      return mTextureId == rhs.mTextureId && @@ -547,7 +604,7 @@ void LLGLTFMaterial::applyOverride(const LLGLTFMaterial& override_mat)  {      LL_PROFILE_ZONE_SCOPED; -    for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) +    for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)      {          LLUUID& texture_id = mTextureId[i];          const LLUUID& override_texture_id = override_mat.mTextureId[i]; @@ -588,7 +645,7 @@ void LLGLTFMaterial::applyOverride(const LLGLTFMaterial& override_mat)          mDoubleSided = override_mat.mDoubleSided;      } -    for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) +    for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)      {          if (override_mat.mTextureTransform[i].mOffset != getDefaultTextureOffset())          { @@ -606,9 +663,13 @@ void LLGLTFMaterial::applyOverride(const LLGLTFMaterial& override_mat)          }      } -    mTrackingIdToLocalTexture.insert(override_mat.mTrackingIdToLocalTexture.begin(), override_mat.mTrackingIdToLocalTexture.begin()); - -    updateTextureTracking(); +    if (!override_mat.mTrackingIdToLocalTexture.empty()) +    { +        auto it = override_mat.mTrackingIdToLocalTexture.begin(); +        mTrackingIdToLocalTexture.insert(it, it); +        updateLocalTexDataDigest(); +        updateTextureTracking(); +    }  }  void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& data) @@ -618,7 +679,7 @@ void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& d      // make every effort to shave bytes here -    for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) +    for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)      {          LLUUID& texture_id = mTextureId[i];          const LLUUID& override_texture_id = override_mat.mTextureId[i]; @@ -663,7 +724,7 @@ void LLGLTFMaterial::getOverrideLLSD(const LLGLTFMaterial& override_mat, LLSD& d          data["ds"] = override_mat.mDoubleSided;      } -    for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) +    for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)      {          if (override_mat.mTextureTransform[i].mOffset != getDefaultTextureOffset())          { @@ -767,7 +828,7 @@ void LLGLTFMaterial::applyOverrideLLSD(const LLSD& data)      const LLSD& ti = data["ti"];      if (ti.isArray())      { -        for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) +        for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)          {              const LLSD& o = ti[i]["o"];              if (o.isDefined()) @@ -793,27 +854,36 @@ void LLGLTFMaterial::applyOverrideLLSD(const LLSD& data)  LLUUID LLGLTFMaterial::getHash() const  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; -    // HACK - hash the bytes of this object but don't include the ref count -    LLUUID hash; -    HBXXH128::digest(hash, (unsigned char*)this + sizeof(LLRefCount), sizeof(*this) - sizeof(LLRefCount)); -    return hash; +    // *HACK: hash the bytes of this object but do not include the ref count +    // neither the local texture overrides (which is a map, with pointers to +    // key/value pairs that would change from one LLGLTFMaterial instance to +    // the other, even though the key/value pairs could be the same, and stored +    // elsewhere in the memory heap or on the stack). +    // Note: this does work properly to compare two LLGLTFMaterial instances +    // only because the padding bytes between their member variables have been +    // dutifully zeroed in the constructor. HB +    const size_t offset = intptr_t(&mLocalTexDataDigest) - intptr_t(this); +    return HBXXH128::digest((const void*)((const char*)this + offset), +                            sizeof(*this) - offset);  }  void LLGLTFMaterial::addLocalTextureTracking(const LLUUID& tracking_id, const LLUUID& tex_id)  {      mTrackingIdToLocalTexture[tracking_id] = tex_id; +    updateLocalTexDataDigest();  }  void LLGLTFMaterial::removeLocalTextureTracking(const LLUUID& tracking_id)  {      mTrackingIdToLocalTexture.erase(tracking_id); +    updateLocalTexDataDigest();  }  bool LLGLTFMaterial::replaceLocalTexture(const LLUUID& tracking_id, const LLUUID& old_id, const LLUUID& new_id)  {      bool res = false; -    for (int i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i) +    for (U32 i = 0; i < GLTF_TEXTURE_INFO_COUNT; ++i)      {          if (mTextureId[i] == old_id)          { @@ -834,6 +904,7 @@ bool LLGLTFMaterial::replaceLocalTexture(const LLUUID& tracking_id, const LLUUID      {          mTrackingIdToLocalTexture.erase(tracking_id);      } +    updateLocalTexDataDigest();      return res;  } diff --git a/indra/llprimitive/llgltfmaterial.h b/indra/llprimitive/llgltfmaterial.h index 02f62fb08c..9f817d6a19 100644 --- a/indra/llprimitive/llgltfmaterial.h +++ b/indra/llprimitive/llgltfmaterial.h @@ -81,7 +81,7 @@ public:          ALPHA_MODE_MASK      }; -    LLGLTFMaterial() {} +    LLGLTFMaterial();      LLGLTFMaterial(const LLGLTFMaterial& rhs);      LLGLTFMaterial& operator=(const LLGLTFMaterial& rhs); @@ -110,25 +110,6 @@ public:      static const char* const GLTF_FILE_EXTENSION_TRANSFORM_ROTATION;      static const LLUUID GLTF_OVERRIDE_NULL_UUID; -    std::array<LLUUID, GLTF_TEXTURE_INFO_COUNT> mTextureId; -    std::array<TextureTransform, GLTF_TEXTURE_INFO_COUNT> mTextureTransform; - -    // NOTE: initialize values to defaults according to the GLTF spec -    // NOTE: these values should be in linear color space -    LLColor4 mBaseColor = LLColor4(1, 1, 1, 1); -    LLColor3 mEmissiveColor = LLColor3(0, 0, 0); - -    F32 mMetallicFactor = 1.f; -    F32 mRoughnessFactor = 1.f; -    F32 mAlphaCutoff = 0.5f; - -    bool mDoubleSided = false; -    AlphaMode mAlphaMode = ALPHA_MODE_OPAQUE; - -    // override specific flags for state that can't use off-by-epsilon or UUID hack -    bool mOverrideDoubleSided = false; -    bool mOverrideAlphaMode = false; -      // get a UUID based on a hash of this LLGLTFMaterial      LLUUID getHash() const; @@ -229,10 +210,6 @@ public:      virtual bool replaceLocalTexture(const LLUUID& tracking_id, const LLUUID &old_id, const LLUUID& new_id);      virtual void updateTextureTracking(); -    // These fields are local to viewer and are a part of local bitmap support -    typedef std::map<LLUUID, LLUUID> local_tex_map_t; -    local_tex_map_t mTrackingIdToLocalTexture; -  protected:      static LLVector2 vec2FromJson(const std::map<std::string, tinygltf::Value>& object, const char* key, const LLVector2& default_value);      static F32 floatFromJson(const std::map<std::string, tinygltf::Value>& object, const char* key, const F32 default_value); @@ -249,4 +226,41 @@ protected:      void writeToTexture(tinygltf::Model& model, T& texture_info, TextureInfo texture_info_id, bool force_write = false) const;      template<typename T>      static void writeToTexture(tinygltf::Model& model, T& texture_info, const LLUUID& texture_id, const TextureTransform& transform, bool force_write = false); + +    // Used to update the digest of the mTrackingIdToLocalTexture map each time +    // it is changed; this way, that digest can be used by the fast getHash() +    // method intsead of having to hash all individual keys and values. HB +    void updateLocalTexDataDigest(); + +public: +    // These fields are local to viewer and are a part of local bitmap support +    // IMPORTANT: do not move this member down (and do not move +    // mLocalTexDataDigest either): the getHash() method does rely on the +    // current ordering. HB +    typedef std::map<LLUUID, LLUUID> local_tex_map_t; +    local_tex_map_t mTrackingIdToLocalTexture; + +    // Used to store a digest of mTrackingIdToLocalTexture when the latter is +    // not empty, or zero otherwise. HB +    U64 mLocalTexDataDigest; + +    std::array<LLUUID, GLTF_TEXTURE_INFO_COUNT> mTextureId; +    std::array<TextureTransform, GLTF_TEXTURE_INFO_COUNT> mTextureTransform; + +    // NOTE: initialize values to defaults according to the GLTF spec +    // NOTE: these values should be in linear color space +    LLColor4 mBaseColor; +    LLColor3 mEmissiveColor; + +    F32 mMetallicFactor; +    F32 mRoughnessFactor; +    F32 mAlphaCutoff; + +    AlphaMode mAlphaMode; +    bool mDoubleSided; + +    // Override specific flags for state that can't use off-by-epsilon or UUID +    // hack +    bool mOverrideDoubleSided; +    bool mOverrideAlphaMode;  }; 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/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 15fddbc99f..484fa9d82c 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -1110,7 +1110,7 @@ LLFontGL* LLFontGL::getFontDefault()  std::string LLFontGL::getFontPathSystem()  {  #if LL_DARWIN -    // HACK for Mac OS X +    // HACK for macOS      return "/System/Library/Fonts/";  #elif LL_WINDOWS diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index c6fd824c4e..6315b2cd7c 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -56,7 +56,7 @@ const F32 MIN_TEXTURE_LIFETIME = 10.f;  U32 wpo2(U32 i); -// texture memory accounting (for OS X) +// texture memory accounting (for macOS)  static LLMutex sTexMemMutex;  static std::unordered_map<U32, U64> sTextureAllocs;  static U64 sTextureBytes = 0; @@ -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/llui/llresmgr.cpp b/indra/llui/llresmgr.cpp index d65c220974..23e0842f37 100644 --- a/indra/llui/llresmgr.cpp +++ b/indra/llui/llresmgr.cpp @@ -51,14 +51,6 @@ char LLResMgr::getDecimalPoint() const  {   	char decimal = localeconv()->decimal_point[0];  -#if LL_DARWIN -	// On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. -	if(decimal == 0) -	{ -		decimal = '.'; -	} -#endif -  	return decimal;  } @@ -66,14 +58,6 @@ char LLResMgr::getThousandsSeparator() const  {  	char separator = localeconv()->thousands_sep[0];  -#if LL_DARWIN -	// On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. -	if(separator == 0) -	{ -		separator = ','; -	} -#endif -  	return separator;  } @@ -81,14 +65,6 @@ char LLResMgr::getMonetaryDecimalPoint() const  {  	char decimal = localeconv()->mon_decimal_point[0];  -#if LL_DARWIN -	// On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. -	if(decimal == 0) -	{ -		decimal = '.'; -	} -#endif -  	return decimal;  } @@ -96,14 +72,6 @@ char LLResMgr::getMonetaryThousandsSeparator() const  {  	char separator = localeconv()->mon_thousands_sep[0];  -#if LL_DARWIN -	// On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. -	if(separator == 0) -	{ -		separator = ','; -	} -#endif -  	return separator;  } @@ -115,29 +83,6 @@ std::string LLResMgr::getMonetaryString( S32 input ) const  	LLLocale locale(LLLocale::USER_LOCALE);  	struct lconv *conv = localeconv(); -	 -#if LL_DARWIN -	// On the Mac, locale support is broken before 10.4, which causes things to go all pear-shaped. -	// Fake up a conv structure with some reasonable values for the fields this function uses. -	struct lconv fakeconv; -	char fake_neg[2] = "-"; -	char fake_mon_group[4] = "\x03\x03\x00"; // commas every 3 digits -	if(conv->negative_sign[0] == 0)	// Real locales all seem to have something here... -	{ -		fakeconv = *conv;	// start with what's there. -		switch(mLocale) -		{ -			default:  			// Unknown -- use the US defaults. -			case LLLOCALE_USA:  -			case LLLOCALE_UK:	// UK ends up being the same as US for the items used here. -				fakeconv.negative_sign = fake_neg; -				fakeconv.mon_grouping = fake_mon_group; -				fakeconv.n_sign_posn = 1; // negative sign before the string -			break; -		} -		conv = &fakeconv; -	} -#endif  	char* negative_sign = conv->negative_sign;  	char separator = getMonetaryThousandsSeparator(); diff --git a/indra/llwindow/llkeyboard.h b/indra/llwindow/llkeyboard.h index dad150e3c1..2f80a9e89a 100644 --- a/indra/llwindow/llkeyboard.h +++ b/indra/llwindow/llkeyboard.h @@ -77,7 +77,7 @@ public:  	virtual BOOL	handleKeyDown(const U16 key, MASK mask) = 0;  #ifdef LL_DARWIN -	// We only actually use this for OS X. +	// We only actually use this for macOS.  	virtual void	handleModifier(MASK mask) = 0;  #endif // LL_DARWIN diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 778e5d3898..b317f00ae7 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -1249,7 +1249,7 @@ F32 LLWindowMacOSX::getNativeAspectRatio()  F32 LLWindowMacOSX::getPixelAspectRatio()  { -	//OS X always enforces a 1:1 pixel aspect ratio, regardless of video mode +	//macOS always enforces a 1:1 pixel aspect ratio, regardless of video mode  	return 1.f;  } @@ -1281,7 +1281,7 @@ void LLWindowMacOSX::afterDialog()  void LLWindowMacOSX::flashIcon(F32 seconds)  { -	// For consistency with OS X conventions, the number of seconds given is ignored and +	// For consistency with macOS conventions, the number of seconds given is ignored and  	// left up to the OS (which will actually bounce it for one second).  	requestUserAttention();  } diff --git a/indra/media_plugins/cef/mac_volume_catcher.cpp b/indra/media_plugins/cef/mac_volume_catcher.cpp index dddb9c2077..dafe545d09 100644 --- a/indra/media_plugins/cef/mac_volume_catcher.cpp +++ b/indra/media_plugins/cef/mac_volume_catcher.cpp @@ -1,6 +1,6 @@  /**    * @file mac_volume_catcher.cpp - * @brief A Mac OS X specific hack to control the volume level of all audio channels opened by a process. + * @brief A macOS specific hack to control the volume level of all audio channels opened by a process.   *   * @cond   * $LicenseInfo:firstyear=2010&license=viewerlgpl$ diff --git a/indra/media_plugins/cef/media_plugin_cef.cpp b/indra/media_plugins/cef/media_plugin_cef.cpp index 43d3a32e64..d5e17ba536 100644 --- a/indra/media_plugins/cef/media_plugin_cef.cpp +++ b/indra/media_plugins/cef/media_plugin_cef.cpp @@ -816,7 +816,7 @@ void MediaPluginCEF::receiveMessage(const char* message_string)  				S32 y = message_in.getValueS32("y");  				// only even send left mouse button events to the CEF library -				// (partially prompted by crash in OS X CEF when sending right button events) +				// (partially prompted by crash in macOS CEF when sending right button events)  				// we catch the right click in viewer and display our own context menu anyway  				S32 button = message_in.getValueS32("button");  				dullahan::EMouseButton btn = dullahan::MB_MOUSE_BUTTON_LEFT; diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 00b59f9a4d..8f651a0294 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -9022,7 +9022,7 @@     <key>RenderHiDPI</key>    <map>      <key>Comment</key> -    <string>Enable support for HiDPI displays, like Retina (MacOS X ONLY, requires restart)</string> +    <string>Enable support for HiDPI displays, like Retina (macOS ONLY, requires restart)</string>      <key>Persist</key>      <integer>1</integer>      <key>Type</key> diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 3853aaa8fd..e7234303a8 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -1473,8 +1473,9 @@ void LLAgent::pitch(F32 angle)  	// after left-clicking the mouse on the avatar and dragging down  	//  	// The issue is observed on angle below 10 degrees +	bool isMouseLookOn = mControlFlags & AGENT_CONTROL_MOUSELOOK;  	const F32 look_down_limit = 179.f * DEG_TO_RAD; -	const F32 look_up_limit   =  10.f * DEG_TO_RAD; +	const F32 look_up_limit   = (isMouseLookOn ? 1.f : 10.f) * DEG_TO_RAD;  	F32 angle_from_skyward = acos(mFrameAgent.getAtAxis() * skyward); diff --git a/indra/newview/llappviewermacosx-objc.mm b/indra/newview/llappviewermacosx-objc.mm index 17301847e8..81ab4e0feb 100644 --- a/indra/newview/llappviewermacosx-objc.mm +++ b/indra/newview/llappviewermacosx-objc.mm @@ -25,7 +25,7 @@   */   #if !defined LL_DARWIN -	#error "Use only with Mac OS X" +	#error "Use only with macOS"  #endif  #import <Cocoa/Cocoa.h> diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 8b313a321b..72e38cc1ea 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -27,7 +27,7 @@  #include "llviewerprecompiledheaders.h"  #if !defined LL_DARWIN -	#error "Use only with Mac OS X" +	#error "Use only with macOS"  #endif  #define LL_CARBON_CRASH_HANDLER 1 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/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index aa723eb3a8..d15c52cc24 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -620,7 +620,7 @@ void LLFloaterPreference::apply()  	saveAvatarProperties();  } -void LLFloaterPreference::cancel() +void LLFloaterPreference::cancel(const std::vector<std::string> settings_to_skip)  {  	LLTabContainer* tabcontainer = getChild<LLTabContainer>("pref core");  	// Call cancel() on all panels that derive from LLPanelPreference @@ -630,7 +630,7 @@ void LLFloaterPreference::cancel()  		LLView* view = *iter;  		LLPanelPreference* panel = dynamic_cast<LLPanelPreference*>(view);  		if (panel) -			panel->cancel(); +            panel->cancel(settings_to_skip);  	}  	// hide joystick pref floater  	LLFloaterReg::hideInstance("pref_joystick"); @@ -1011,15 +1011,16 @@ void LLFloaterPreference::onBtnCancel(const LLSD& userdata)  		}  		refresh();  	} -	cancel(); - +	  	if (userdata.asString() == "closeadvanced")  	{ +        cancel({"RenderQualityPerformance"});  		LLFloaterReg::hideInstance("prefs_graphics_advanced");  		updateMaxComplexity();  	}  	else  	{ +        cancel();  		closeFloater();  	}  } @@ -2206,7 +2207,7 @@ void LLPanelPreference::toggleMuteWhenMinimized()  	}  } -void LLPanelPreference::cancel() +void LLPanelPreference::cancel(const std::vector<std::string> settings_to_skip)  {  	for (control_values_map_t::iterator iter =  mSavedValues.begin();  		 iter !=  mSavedValues.end(); ++iter) @@ -2219,6 +2220,12 @@ void LLPanelPreference::cancel()  			continue;  		} +        auto found = std::find(settings_to_skip.begin(), settings_to_skip.end(), control->getName()); +        if (found != settings_to_skip.end()) +        { +            continue; +        } +  		control->set(ctrl_value);  	} @@ -2461,9 +2468,9 @@ void LLPanelPreferenceGraphics::resetDirtyChilds()  	}	  } -void LLPanelPreferenceGraphics::cancel() +void LLPanelPreferenceGraphics::cancel(const std::vector<std::string> settings_to_skip)  { -	LLPanelPreference::cancel(); +	LLPanelPreference::cancel(settings_to_skip);  }  void LLPanelPreferenceGraphics::saveSettings()  { @@ -2751,7 +2758,7 @@ void LLPanelPreferenceControls::apply()      }  } -void LLPanelPreferenceControls::cancel() +void LLPanelPreferenceControls::cancel(const std::vector<std::string> settings_to_skip)  {      for (U32 i = 0; i < LLKeyConflictHandler::MODE_COUNT - 1; ++i)      { diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index 04ac87364d..bdade3c1b9 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -79,7 +79,7 @@ public:  	~LLFloaterPreference();  	void apply(); -	void cancel(); +	void cancel(const std::vector<std::string> settings_to_skip = {});  	/*virtual*/ void draw();  	/*virtual*/ BOOL postBuild();  	/*virtual*/ void onOpen(const LLSD& key); @@ -251,7 +251,7 @@ public:  	virtual ~LLPanelPreference();  	virtual void apply(); -	virtual void cancel(); +    virtual void cancel(const std::vector<std::string> settings_to_skip = {});  	void setControlFalse(const LLSD& user_data);  	virtual void setHardwareDefaults(); @@ -294,14 +294,12 @@ class LLPanelPreferenceGraphics : public LLPanelPreference  public:  	BOOL postBuild();  	void draw(); -	void cancel(); +    void cancel(const std::vector<std::string> settings_to_skip = {});  	void saveSettings();  	void resetDirtyChilds();  	void setHardwareDefaults();  	void setPresetText(); -	static const std::string getPresetsPath(); -  protected:  	bool hasDirtyChilds(); @@ -320,7 +318,7 @@ public:  	BOOL postBuild();  	void apply(); -	void cancel(); +    void cancel(const std::vector<std::string> settings_to_skip = {});  	void saveSettings();  	void resetDirtyChilds(); diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp index a91f0ec060..f83ce868a3 100644 --- a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp @@ -93,7 +93,7 @@ void LLFloaterPreferenceGraphicsAdvanced::onClickCloseBtn(bool app_quitting)      LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences");      if (instance)      { -        instance->cancel(); +        instance->cancel({"RenderQualityPerformance"});      }      updateMaxComplexity();  } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 932a0316dd..b44fcf3e03 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -4360,12 +4360,10 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t&   items  			if (!isInboxFolder() // don't allow creation in inbox  				&& outfits_id != mUUID)  			{ -				bool menu_items_added = false;  				// Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694.  				if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat))  				{  					items.push_back(std::string("New Folder")); -					menu_items_added = true;  				}                  if (!isMarketplaceListingsFolder())                  { @@ -4383,10 +4381,6 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t&   items                          disabled_items.push_back("New Settings");                      }                  } -                if (menu_items_added) -                { -                    items.push_back(std::string("Create Separator")); -                }  			}  			getClipboardEntries(false, items, disabled_items, flags);  		} diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index 68581d04eb..7ded32cf19 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -2022,6 +2022,39 @@ void LLInventoryGallery::pasteAsLink(const LLUUID& dest,      }  } +void LLInventoryGallery::doCreate(const LLUUID& dest, const LLSD& userdata) +{ + +    LLViewerInventoryCategory* cat = gInventory.getCategory(dest); +    if (cat && mFolderID != dest) +    { +        menu_create_inventory_item(NULL, dest, userdata, LLUUID::null); +    } +    else +    { +        // todo: needs to reset current floater's filter, +        // like reset_inventory_filter() + +        LLHandle<LLPanel> handle = getHandle(); +        std::function<void(const LLUUID&)> callback_cat_created = +            [handle](const LLUUID& new_id) +            { +                gInventory.notifyObservers(); +                LLInventoryGallery* panel = static_cast<LLInventoryGallery*>(handle.get()); +                if (panel && new_id.notNull()) +                { +                    panel->clearSelection(); +                    if (panel->mItemMap.count(new_id) != 0) +                    { +                        panel->addItemSelection(new_id, true); +                    } +                } +            }; + +        menu_create_inventory_item(NULL, mFolderID, userdata, LLUUID::null, callback_cat_created); +    } +} +  void LLInventoryGallery::claimEditHandler()  {      gEditMenuHandler = this; diff --git a/indra/newview/llinventorygallery.h b/indra/newview/llinventorygallery.h index 0c52e7b713..bc4ac7db2a 100644 --- a/indra/newview/llinventorygallery.h +++ b/indra/newview/llinventorygallery.h @@ -166,6 +166,7 @@ public:      void deleteSelection();      bool canDeleteSelection();      void pasteAsLink(); +    void doCreate(const LLUUID& dest, const LLSD& userdata);      void setSortOrder(U32 order, bool update = false);      U32 getSortOrder() { return mSortOrder; }; diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index 5f4b816b99..e966514955 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -32,9 +32,11 @@  #include "llappearancemgr.h"  #include "llavataractions.h"  #include "llclipboard.h" +#include "llenvironment.h"  #include "llfloaterreg.h"  #include "llfloatersidepanelcontainer.h"  #include "llfloaterworldmap.h" +#include "llfriendcard.h"  #include "llinventorybridge.h"  #include "llinventoryfunctions.h"  #include "llinventorymodel.h" @@ -48,6 +50,41 @@  #include "llviewerwindow.h"  #include "llvoavatarself.h" + +void modify_outfit(BOOL append, const LLUUID& cat_id, LLInventoryModel* model) +{ +    LLViewerInventoryCategory* cat = model->getCategory(cat_id); +    if (!cat) return; + +    // checking amount of items to wear +    static LLCachedControl<U32> max_items(gSavedSettings, "WearFolderLimit", 125); +    LLInventoryModel::cat_array_t cats; +    LLInventoryModel::item_array_t items; +    LLFindWearablesEx not_worn(/*is_worn=*/ false, /*include_body_parts=*/ false); +    model->collectDescendentsIf(cat_id, +                                    cats, +                                    items, +                                    LLInventoryModel::EXCLUDE_TRASH, +                                    not_worn); + +    if (items.size() > max_items()) +    { +        LLSD args; +        args["AMOUNT"] = llformat("%u", max_items()); +        LLNotificationsUtil::add("TooManyWearables", args); +        return; +    } +    if (model->isObjectDescendentOf(cat_id, gInventory.getRootFolderID())) +    { +        LLAppearanceMgr::instance().wearInventoryCategory(cat, FALSE, append); +    } +    else +    { +        // Library, we need to copy content first +        LLAppearanceMgr::instance().wearInventoryCategory(cat, TRUE, append); +    } +} +  LLContextMenu* LLInventoryGalleryContextMenu::createMenu()  {      LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; @@ -57,11 +94,33 @@ LLContextMenu* LLInventoryGalleryContextMenu::createMenu()      registrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::fileUploadLocation, this, _2));      registrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH));      registrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND)); +    registrar.add("Inventory.DoCreate", [this](LLUICtrl*, const LLSD& data) +                          { +                              if (mRootFolder) +                              { +                                  mGallery->doCreate(mGallery->getRootFolder(), data); +                              } +                              else +                              { +                                  mGallery->doCreate(mUUIDs.front(), data); +                              } +                          });      std::set<LLUUID> uuids(mUUIDs.begin(), mUUIDs.end());      registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery)));      enable_registrar.add("Inventory.CanSetUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::canSetUploadLocation, this, _2)); +    enable_registrar.add("Inventory.EnvironmentEnabled", [](LLUICtrl*, const LLSD&) +                         { +                             return LLEnvironment::instance().isInventoryEnabled(); +                         }); +    enable_registrar.add("Inventory.MaterialsEnabled", [](LLUICtrl*, const LLSD&) +                         { +                             std::string agent_url = gAgent.getRegionCapability("UpdateMaterialAgentInventory"); +                             std::string task_url = gAgent.getRegionCapability("UpdateMaterialTaskInventory"); + +                             return (!agent_url.empty() && !task_url.empty()); +                         });      LLContextMenu* menu = createFromFile("menu_gallery_inventory.xml"); @@ -186,6 +245,22 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata)      {          ungroup_folder_items(mUUIDs.front());      } +    else if ("replaceoutfit" == action) +    { +        modify_outfit(FALSE, mUUIDs.front(), &gInventory); +    } +    else if ("addtooutfit" == action) +    { +        modify_outfit(TRUE, mUUIDs.front(), &gInventory); +    } +    else if ("removefromoutfit" == action) +    { +        LLViewerInventoryCategory* cat = gInventory.getCategory(mUUIDs.front()); +        if (cat) +        { +            LLAppearanceMgr::instance().takeOffOutfit(cat->getLinkedUUID()); +        } +    }      else if ("take_off" == action || "detach" == action)      {          for (LLUUID& selected_id : mUUIDs) @@ -295,6 +370,54 @@ void LLInventoryGalleryContextMenu::doToSelected(const LLSD& userdata)              preview_texture->saveAs();          }      } +    else if (("copy_to_marketplace_listings" == action) +             || ("move_to_marketplace_listings" == action)) +    { +        LLViewerInventoryItem* itemp = gInventory.getItem(mUUIDs.front()); +        bool copy_operation = "copy_to_marketplace_listings" == action; +        bool can_copy = itemp ? itemp->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID()) : false; + + +        if (can_copy) +        { +            const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); +            if (itemp) +            { +                move_item_to_marketplacelistings(itemp, marketplacelistings_id, copy_operation); +            } +        } +        else +        { +            uuid_vec_t lamdba_list = mUUIDs; +            LLNotificationsUtil::add( +                "ConfirmCopyToMarketplace", +                LLSD(), +                LLSD(), +                [lamdba_list](const LLSD& notification, const LLSD& response) +                { +                    S32 option = LLNotificationsUtil::getSelectedOption(notification, response); +                    // option == 0  Move no copy item(s) +                    // option == 1  Don't move no copy item(s) (leave them behind) +                    bool copy_and_move = option == 0; +                    const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); + +                    // main inventory only allows one item? +                    LLViewerInventoryItem* itemp = gInventory.getItem(lamdba_list.front()); +                    if (itemp) +                    { +                        if (itemp->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID(), gAgent.getGroupID())) +                        { +                            move_item_to_marketplacelistings(itemp, marketplacelistings_id, true); +                        } +                        else if (copy_and_move) +                        { +                            move_item_to_marketplacelistings(itemp, marketplacelistings_id, false); +                        } +                    } +                } +            ); +        } +    }  }  void LLInventoryGalleryContextMenu::rename(const LLUUID& item_id) @@ -388,6 +511,56 @@ bool is_inbox_folder(LLUUID item_id)      return gInventory.isObjectDescendentOf(item_id, inbox_id);  } +bool can_list_on_marketplace(const LLUUID &id) +{ +    const LLInventoryObject* obj = gInventory.getObject(id); +    bool can_list = (obj != NULL); + +    if (can_list) +    { +        const LLUUID& object_id = obj->getLinkedUUID(); +        can_list = object_id.notNull(); + +        if (can_list) +        { +            std::string error_msg; +            const LLUUID& marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); +            if (marketplacelistings_id.notNull()) +            { +                LLViewerInventoryCategory* master_folder = gInventory.getCategory(marketplacelistings_id); +                LLInventoryCategory* cat = gInventory.getCategory(id); +                if (cat) +                { +                    can_list = can_move_folder_to_marketplace(master_folder, master_folder, cat, error_msg); +                } +                else +                { +                    LLInventoryItem* item = gInventory.getItem(id); +                    can_list = (item ? can_move_item_to_marketplace(master_folder, master_folder, item, error_msg) : false); +                } +            } +            else +            { +                can_list = false; +            } +        } +    } + +    return can_list; +} + +bool check_folder_for_contents_of_type(const LLUUID &id, LLInventoryModel* model, LLInventoryCollectFunctor& is_type) +{ +    LLInventoryModel::cat_array_t cat_array; +    LLInventoryModel::item_array_t item_array; +    model->collectDescendentsIf(id, +                                cat_array, +                                item_array, +                                LLInventoryModel::EXCLUDE_TRASH, +                                is_type); +    return item_array.size() > 0; +} +  void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* menu)  {      LLUUID selected_id = mUUIDs.front(); @@ -409,6 +582,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men      bool is_in_trash = gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH));      bool is_lost_and_found = (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND));      bool is_outfits= (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS)); +    bool is_in_favorites = gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE));      //bool is_favorites= (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE));      bool is_system_folder = false; @@ -456,6 +630,49 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men              items.push_back(std::string("open_in_new_window"));              items.push_back(std::string("Open Folder Separator"));          } + +        // wearables related functionality for folders. +        LLFindWearables is_wearable; +        LLIsType is_object(LLAssetType::AT_OBJECT); +        LLIsType is_gesture(LLAssetType::AT_GESTURE); + +        if (check_folder_for_contents_of_type(selected_id, &gInventory, is_wearable) +            || check_folder_for_contents_of_type(selected_id, &gInventory, is_object) +            || check_folder_for_contents_of_type(selected_id, &gInventory, is_gesture)) +        { +            // Only enable add/replace outfit for non-system folders. +            if (!is_system_folder) +            { +                // Adding an outfit onto another (versus replacing) doesn't make sense. +                if (folder_type != LLFolderType::FT_OUTFIT) +                { +                    items.push_back(std::string("Add To Outfit")); +                    if (!LLAppearanceMgr::instance().getCanAddToCOF(selected_id)) +                    { +                        disabled_items.push_back(std::string("Add To Outfit")); +                    } +                } + +                items.push_back(std::string("Replace Outfit")); +                if (!LLAppearanceMgr::instance().getCanReplaceCOF(selected_id)) +                { +                    disabled_items.push_back(std::string("Replace Outfit")); +                } +            } +            if (is_agent_inventory) +            { +                items.push_back(std::string("Folder Wearables Separator")); +                // Note: If user tries to unwear "My Inventory", it's going to deactivate everything including gestures +                // Might be safer to disable this for "My Inventory" +                items.push_back(std::string("Remove From Outfit")); +                if (folder_type != LLFolderType::FT_ROOT_INVENTORY // Unless COF is empty, whih shouldn't be, warrantied to have worn items +                    && !LLAppearanceMgr::getCanRemoveFromCOF(selected_id)) // expensive from root! +                { +                    disabled_items.push_back(std::string("Remove From Outfit")); +                } +            } +            items.push_back(std::string("Outfit Separator")); +        }      }      else      { @@ -503,11 +720,30 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men      }      else      { +        if (is_agent_inventory && !is_inbox && !is_cof && !is_in_favorites && !is_outfits) +        { +            LLViewerInventoryCategory* category = gInventory.getCategory(selected_id); +            if (!category || !LLFriendCardsManager::instance().isCategoryInFriendFolder(category)) +            { +                items.push_back(std::string("New Folder")); +            } + +            items.push_back(std::string("create_new")); +            items.push_back(std::string("New Script")); +            items.push_back(std::string("New Note")); +            items.push_back(std::string("New Gesture")); +            items.push_back(std::string("New Material")); +            items.push_back(std::string("New Clothes")); +            items.push_back(std::string("New Body Parts")); +            items.push_back(std::string("New Settings")); +        } +          if(can_share_item(selected_id))          {              items.push_back(std::string("Share"));          } -        if (LLClipboard::instance().hasContents() && is_agent_inventory && !is_cof && !is_inbox_folder(selected_id)) + +        if (LLClipboard::instance().hasContents() && is_agent_inventory && !is_cof && !is_inbox)          {              items.push_back(std::string("Paste")); @@ -519,7 +755,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men          }          if (is_folder && is_agent_inventory)          { -            if (!is_cof && (folder_type != LLFolderType::FT_OUTFIT) && !is_outfits && !is_inbox_folder(selected_id)) +            if (!is_cof && (folder_type != LLFolderType::FT_OUTFIT) && !is_outfits && !is_inbox)              {                  if (!gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_CALLINGCARD)) && !isRootFolder())                  { @@ -706,6 +942,54 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men              disabled_items.push_back(std::string("New Folder"));              disabled_items.push_back(std::string("upload_def")); +            disabled_items.push_back(std::string("create_new")); +        } + +        if (is_agent_inventory && !mRootFolder) +        { +            items.push_back(std::string("New folder from selected")); +            items.push_back(std::string("Subfolder Separator")); +            if (!is_only_items_selected(mUUIDs) && !is_only_cats_selected(mUUIDs)) +            { +                disabled_items.push_back(std::string("New folder from selected")); +            } +        } + +        // Marketplace +        bool can_list = false; +        const LLUUID marketplacelistings_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MARKETPLACE_LISTINGS); +        if (marketplacelistings_id.notNull() && !is_inbox && !obj->getIsLinkType()) +        { +            if (is_folder) +            { +                LLViewerInventoryCategory* cat = gInventory.getCategory(selected_id); +                if (cat +                    && !LLFolderType::lookupIsProtectedType(cat->getPreferredType()) +                    && gInventory.isObjectDescendentOf(selected_id, gInventory.getRootFolderID())) +                { +                    can_list = true; +                } +            } +            else if (selected_item +                     && selected_item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()) +                     && selected_item->getPermissions().getOwner() != ALEXANDRIA_LINDEN_ID +                     && LLAssetType::AT_CALLINGCARD != selected_item->getType()) +            { +                can_list = true; +            } +        } + +        if (can_list) +        { +            items.push_back(std::string("Marketplace Separator")); +            items.push_back(std::string("Marketplace Copy")); +            items.push_back(std::string("Marketplace Move")); + +            if (!can_list_on_marketplace(selected_id)) +            { +                disabled_items.push_back(std::string("Marketplace Copy")); +                disabled_items.push_back(std::string("Marketplace Move")); +            }          }      } diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 1f5974c74d..c066a7b5c3 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -3468,6 +3468,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/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index ff33efe4aa..e3d887d943 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -39,11 +39,6 @@ LLProfileDropTarget::LLProfileDropTarget(const LLProfileDropTarget::Params& p)      mAgentID(p.agent_id)  {} -void LLProfileDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data) -{ -    LL_INFOS() << "LLProfileDropTarget::doDrop()" << LL_ENDL; -} -  BOOL LLProfileDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,                                       EDragAndDropType cargo_type,                                       void* cargo_data, diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index f182660c8e..bfde921df0 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -59,8 +59,6 @@ public:      LLProfileDropTarget(const Params&);      ~LLProfileDropTarget() {} -    void doDrop(EDragAndDropType cargo_type, void* cargo_data); -      //      // LLView functionality      virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 82f880c9ee..54121c2656 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -89,8 +89,6 @@ public:  	LLGroupDropTarget(const Params&);  	~LLGroupDropTarget() {}; -	void doDrop(EDragAndDropType cargo_type, void* cargo_data); -  	//  	// LLView functionality  	virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, @@ -114,11 +112,6 @@ LLGroupDropTarget::LLGroupDropTarget(const LLGroupDropTarget::Params& p)  	mGroupID(p.group_id)  {} -void LLGroupDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data) -{ -	LL_INFOS() << "LLGroupDropTarget::doDrop()" << LL_ENDL; -} -  BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,  									 EDragAndDropType cargo_type,  									 void* cargo_data, diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp index 20241aac24..a5a768776a 100644 --- a/indra/newview/llpanelmaininventory.cpp +++ b/indra/newview/llpanelmaininventory.cpp @@ -56,6 +56,7 @@  #include "lltrans.h"  #include "llviewermenu.h"  #include "llviewertexturelist.h" +#include "llviewerinventory.h"  #include "llsidepanelinventory.h"  #include "llfolderview.h"  #include "llradiogroup.h" diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index ffbed778c1..00fa3853f7 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -46,6 +46,7 @@  #include "lltexteditor.h"  #include "lltexturectrl.h"  #include "lltoggleablemenu.h" +#include "lltooldraganddrop.h"  #include "llgrouplist.h"  #include "llurlaction.h" @@ -1012,6 +1013,51 @@ void LLPanelProfileSecondLife::onOpen(const LLSD& key)      mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileSecondLife::onAvatarNameCache, this, _1, _2));  } + +BOOL LLPanelProfileSecondLife::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, +                                          EDragAndDropType cargo_type, +                                          void* cargo_data, +                                          EAcceptance* accept, +                                          std::string& tooltip_msg) +{ +    // Try children first +    if (LLPanelProfileTab::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg) +        && *accept != ACCEPT_NO) +    { +        return TRUE; +    } + +    // No point sharing with own profile +    if (getSelfProfile()) +    { +        return FALSE; +    } + +    // Exclude fields that look like they are editable. +    S32 child_x = 0; +    S32 child_y = 0; +    if (localPointToOtherView(x, y, &child_x, &child_y, mDescriptionEdit) +        && mDescriptionEdit->pointInView(child_x, child_y)) +    { +        return FALSE; +    } + +    if (localPointToOtherView(x, y, &child_x, &child_y, mGroupList) +        && mGroupList->pointInView(child_x, child_y)) +    { +        return FALSE; +    } + +    // Share +    LLToolDragAndDrop::handleGiveDragAndDrop(getAvatarId(), +                                             LLUUID::null, +                                             drop, +                                             cargo_type, +                                             cargo_data, +                                             accept); +    return TRUE; +} +  void LLPanelProfileSecondLife::updateData()  {      LLUUID avatar_id = getAvatarId(); diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index 11632a10ae..45655cd67b 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -78,6 +78,12 @@ public:  	void onOpen(const LLSD& key) override; +    BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, +                                   EDragAndDropType cargo_type, +                                   void* cargo_data, +                                   EAcceptance* accept, +                                   std::string& tooltip_msg) override; +  	/**  	 * LLFriendObserver trigger  	 */ diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index 2ff8f50277..863cd13678 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -768,6 +768,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(), @@ -827,13 +829,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  @@ -980,6 +984,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/llspatialpartition.h b/indra/newview/llspatialpartition.h index 758e716c00..19408ec5de 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -729,7 +729,6 @@ class LLControlAVBridge : public LLVolumeBridge  	using super = LLVolumeBridge;  public:  	LLControlAVBridge(LLDrawable* drawablep, LLViewerRegion* regionp); -	virtual void updateSpatialExtents();  };  class LLHUDBridge : public LLVolumeBridge 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/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index e35cb26ce1..dfa47e82b3 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -1414,7 +1414,7 @@ void LLViewerJoystick::setSNDefaults()  #if LL_DARWIN || LL_LINUX  	const float platformScale = 20.f;  	const float platformScaleAvXZ = 1.f; -	// The SpaceNavigator doesn't act as a 3D cursor on OS X / Linux.  +	// The SpaceNavigator doesn't act as a 3D cursor on macOS / Linux.  	const bool is_3d_cursor = false;  #else  	const float platformScale = 1.f; 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 56bba51692..c4a681f2b7 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; @@ -2902,6 +2903,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 9a6d40ab0a..daf3a5a20f 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1258,6 +1258,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(), @@ -1363,6 +1365,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 ed671fe849..f661887c65 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -4891,6 +4891,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  	{ @@ -5010,6 +5011,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); @@ -5269,6 +5273,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 9f149d21fd..c95648d62e 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)  	{ @@ -9787,6 +9787,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/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 3725510b6a..c4cd1779b7 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -5314,7 +5314,7 @@ std::string LLVivoxVoiceClient::nameFromID(const LLUUID &uuid)  	LLStringUtil::replaceChar(result, '+', '-');  	LLStringUtil::replaceChar(result, '/', '_'); -	// If you need to transform a GUID to this form on the Mac OS X command line, this will do so: +	// If you need to transform a GUID to this form on the macOS command line, this will do so:  	// echo -n x && (echo e669132a-6c43-4ee1-a78d-6c82fff59f32 |xxd -r -p |openssl base64|tr '/+' '_-')  	// The reverse transform can be done with: 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/llvotree.cpp b/indra/newview/llvotree.cpp index 36e6da802b..575b1dbe7e 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -865,6 +865,10 @@ BOOL LLVOTree::updateGeometry(LLDrawable *drawable)  		mReferenceBuffer->unmapBuffer();  		llassert(vertex_count == max_vertices);  		llassert(index_count == max_indices); +#ifndef SHOW_ASSERT +        (void)vertex_count; +        (void)index_count; +#endif  	}  	//generate tree mesh diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index ec2f490742..ad6c39de48 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) @@ -5054,30 +5056,6 @@ LLControlAVBridge::LLControlAVBridge(LLDrawable* drawablep, LLViewerRegion* regi  	mPartitionType = LLViewerRegion::PARTITION_CONTROL_AV;  } -void LLControlAVBridge::updateSpatialExtents() -{ -	LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - -	LLSpatialGroup* root = (LLSpatialGroup*)mOctree->getListener(0); - -	bool rootWasDirty = root->isDirty(); - -	super::updateSpatialExtents(); // root becomes non-dirty here - -	// SL-18251 "On-screen animesh characters using pelvis offset animations -	// disappear when root goes off-screen" -	// -	// Expand extents to include Control Avatar placed outside of the bounds -    LLControlAvatar* controlAvatar = getVObj() ? getVObj()->getControlAvatar() : NULL; -    if (controlAvatar -        && controlAvatar->mDrawable -        && controlAvatar->mDrawable->getEntry() -        && (rootWasDirty || controlAvatar->mPlaying)) -	{ -		root->expandExtents(controlAvatar->mDrawable->getSpatialExtents(), *mDrawable->getXform()); -	} -} -  bool can_batch_texture(LLFace* facep)  {  	if (facep->getTextureEntry()->getBumpmap()) 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]; diff --git a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml index d82c453e5f..feaba45cf8 100644 --- a/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_gallery_inventory.xml @@ -426,6 +426,234 @@    <menu_item_separator     layout="topleft"     name="Subfolder Separator" /> +  <menu +   label="Create new" +   layout="topleft" +   name="create_new"> +      <menu_item_call +       label="New Folder" +       layout="topleft" +       name="New Folder"> +          <menu_item_call.on_click +           function="Inventory.DoCreate" +           parameter="category" /> +      </menu_item_call> +      <menu_item_call +       label="New Script" +       layout="topleft" +       name="New Script"> +          <menu_item_call.on_click +           function="Inventory.DoCreate" +           parameter="lsl" /> +      </menu_item_call> +      <menu_item_call +       label="New Notecard" +       layout="topleft" +       name="New Note"> +          <menu_item_call.on_click +           function="Inventory.DoCreate" +           parameter="notecard" /> +      </menu_item_call> +      <menu_item_call +       label="New Gesture" +       layout="topleft" +       name="New Gesture"> +          <menu_item_call.on_click +           function="Inventory.DoCreate" +           parameter="gesture" /> +      </menu_item_call> +      <menu_item_call +       label="New Material" +       layout="topleft" +       name="New Material"> +          <menu_item_call.on_click +           function="Inventory.DoCreate" +           parameter="material" /> +          <menu_item_call.on_enable +           function="Inventory.MaterialsEnabled" /> +      </menu_item_call> +      <menu +       label="New Clothes" +       layout="topleft" +       name="New Clothes"> +          <menu_item_call +           label="New Shirt" +           layout="topleft" +           name="New Shirt"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="shirt" /> +          </menu_item_call> +          <menu_item_call +           label="New Pants" +           layout="topleft" +           name="New Pants"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="pants" /> +          </menu_item_call> +          <menu_item_call +           label="New Shoes" +           layout="topleft" +           name="New Shoes"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="shoes" /> +          </menu_item_call> +          <menu_item_call +           label="New Socks" +           layout="topleft" +           name="New Socks"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="socks" /> +          </menu_item_call> +          <menu_item_call +           label="New Jacket" +           layout="topleft" +           name="New Jacket"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="jacket" /> +          </menu_item_call> +          <menu_item_call +           label="New Skirt" +           layout="topleft" +           name="New Skirt"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="skirt" /> +          </menu_item_call> +          <menu_item_call +           label="New Gloves" +           layout="topleft" +           name="New Gloves"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="gloves" /> +          </menu_item_call> +          <menu_item_call +           label="New Undershirt" +           layout="topleft" +           name="New Undershirt"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="undershirt" /> +          </menu_item_call> +          <menu_item_call +           label="New Underpants" +           layout="topleft" +           name="New Underpants"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="underpants" /> +          </menu_item_call> +          <menu_item_call +           label="New Alpha Mask" +           layout="topleft" +           name="New Alpha Mask"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="alpha" /> +            </menu_item_call> +          <menu_item_call +           label="New Tattoo" +           layout="topleft" +           name="New Tattoo"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="tattoo" /> +          </menu_item_call> +          <menu_item_call +           label="New Universal" +           layout="topleft" +           name="New Universal"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="universal" /> +          </menu_item_call> +          <menu_item_call +           label="New Physics" +           layout="topleft" +           name="New Physics"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="physics" /> +          </menu_item_call> +      </menu> +      <menu +       label="New Body Parts" +       layout="topleft" +       name="New Body Parts"> +          <menu_item_call +           label="New Shape" +           layout="topleft" +           name="New Shape"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="shape" /> +          </menu_item_call> +          <menu_item_call +           label="New Skin" +           layout="topleft" +           name="New Skin"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="skin" /> +          </menu_item_call> +          <menu_item_call +           label="New Hair" +           layout="topleft" +           name="New Hair"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="hair" /> +          </menu_item_call> +          <menu_item_call +           label="New Eyes" +           layout="topleft" +           name="New Eyes"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="eyes" /> +          </menu_item_call> +      </menu> +      <menu +       label="New Settings" +       layout="topleft" +       name="New Settings"> +          <menu_item_call +           label="New Sky" +           layout="topleft" +           name="New Sky"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="sky"/> +              <menu_item_call.on_enable +               function="Inventory.EnvironmentEnabled" /> +          </menu_item_call> +          <menu_item_call +           label="New Water" +           layout="topleft" +           name="New Water"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="water"/> +              <menu_item_call.on_enable +               function="Inventory.EnvironmentEnabled" /> +          </menu_item_call> +          <menu_item_call +           label="New Day Cycle" +           layout="topleft" +           name="New Day Cycle"> +              <menu_item_call.on_click +               function="Inventory.DoCreate" +               parameter="daycycle"/> +              <menu_item_call.on_enable +               function="Inventory.EnvironmentEnabled" /> +          </menu_item_call> +      </menu> +  </menu>    <menu_item_call     label="Create folder from selected"     layout="topleft" | 
