From 26b03161f5d881e8fbda5f15c6db3e0c29e7b834 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 30 Jun 2010 18:21:08 -0600
Subject: fix for EXT-7839: texture console is stalled; fix for EXT-7500:
 Texture Jamming problems with http texture off;

---
 indra/newview/lldrawpoolbump.cpp      |  10 +-
 indra/newview/llpreviewtexture.cpp    |   4 +-
 indra/newview/llpreviewtexture.h      |   2 +
 indra/newview/llviewertexture.cpp     | 231 ++++++++++++++++++++++++++++------
 indra/newview/llviewertexture.h       |  72 +++++++----
 indra/newview/llviewertexturelist.cpp |   6 +-
 indra/newview/llvoavatar.cpp          | 104 +++++++++++++--
 indra/newview/llvoavatar.h            |   7 +-
 indra/newview/llvoavatarself.cpp      |   6 +-
 indra/newview/llwearable.cpp          |   5 +-
 indra/newview/llwearable.h            |   1 +
 11 files changed, 357 insertions(+), 91 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 19cdccb630..68809b0926 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -147,8 +147,9 @@ void LLStandardBumpmap::restoreGL()
 										LLViewerTexture::BOOST_NONE, 
 										LLViewerTexture::LOD_TEXTURE,
 										0, 
-										0);																								
-		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setLoadedCallback(LLBumpImageList::onSourceStandardLoaded, 0, TRUE, FALSE, NULL );
+										0);									
+		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setBoostLevel(LLViewerTexture::BOOST_BUMP) ;
+		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setLoadedCallback(LLBumpImageList::onSourceStandardLoaded, 0, TRUE, FALSE, NULL, NULL, NULL );
 		LLStandardBumpmap::sStandardBumpmapCount++;
 	}
 
@@ -817,7 +818,7 @@ void LLBumpImageList::addTextureStats(U8 bump, const LLUUID& base_image_id, F32
 	bump &= TEM_BUMP_MASK;
 	LLViewerFetchedTexture* bump_image = gStandardBumpmapList[bump].mImage;
 	if( bump_image )
-	{
+	{		
 		bump_image->addTextureStats(virtual_size);
 	}
 }
@@ -921,7 +922,8 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText
 			(*entries_list)[src_image->getID()]->setExplicitFormat(GL_ALPHA8, GL_ALPHA);			
 
 			// Note: this may create an LLImageGL immediately
-			src_image->setLoadedCallback( callback_func, 0, TRUE, FALSE, new LLUUID(src_image->getID()) );
+			src_image->setBoostLevel(LLViewerTexture::BOOST_BUMP) ;
+			src_image->setLoadedCallback( callback_func, 0, TRUE, FALSE, new LLUUID(src_image->getID()), NULL, NULL );
 			bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image
 
 //			bump_total++;
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index 22a1ef94a7..bf18c9e5e7 100644
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -87,6 +87,8 @@ LLPreviewTexture::LLPreviewTexture(const LLSD& key)
 
 LLPreviewTexture::~LLPreviewTexture()
 {
+	LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList, this) ;
+
 	if( mLoadingFullImage )
 	{
 		getWindow()->decBusyCount();
@@ -278,7 +280,7 @@ void LLPreviewTexture::saveAs()
 	mLoadingFullImage = TRUE;
 	getWindow()->incBusyCount();
 	mImage->setLoadedCallback( LLPreviewTexture::onFileLoadedForSave, 
-								0, TRUE, FALSE, new LLUUID( mItemUUID ) );
+								0, TRUE, FALSE, new LLUUID( mItemUUID ), this, &mCallbackTextureList );
 }
 
 // virtual
diff --git a/indra/newview/llpreviewtexture.h b/indra/newview/llpreviewtexture.h
index 7cd2adad56..0f29a741c1 100644
--- a/indra/newview/llpreviewtexture.h
+++ b/indra/newview/llpreviewtexture.h
@@ -99,5 +99,7 @@ private:
 	S32 mLastWidth;
 	F32 mAspectRatio;
 	BOOL mUpdateDimensions;
+
+	LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ; 
 };
 #endif  // LL_LLPREVIEWTEXTURE_H
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 9b5b210bf7..0afbce7d51 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -112,15 +112,57 @@ const F64 log_2 = log(2.0);
 LLLoadedCallbackEntry::LLLoadedCallbackEntry(loaded_callback_func cb,
 					  S32 discard_level,
 					  BOOL need_imageraw, // Needs image raw for the callback
-					  void* userdata ) 
+					  void* userdata,
+					  LLLoadedCallbackEntry::source_callback_list_t* src_callback_list,
+					  void* source,
+					  LLViewerFetchedTexture* target,
+					  BOOL pause) 
 	: mCallback(cb),
 	  mLastUsedDiscard(MAX_DISCARD_LEVEL+1),
 	  mDesiredDiscard(discard_level),
 	  mNeedsImageRaw(need_imageraw),
-	  mUserData(userdata)
+	  mUserData(userdata),
+	  mSourceCallbackList(src_callback_list),
+	  mSource(source),
+	  mPaused(pause)
+{
+	if(mSourceCallbackList)
+	{
+		mSourceCallbackList->insert(target->getID());
+	}
+}
+
+LLLoadedCallbackEntry::~LLLoadedCallbackEntry()
 {
 }
 
+void LLLoadedCallbackEntry::removeTexture(LLViewerFetchedTexture* tex)
+{
+	if(mSourceCallbackList)
+	{
+		mSourceCallbackList->erase(tex->getID()) ;
+	}
+}
+
+//static 
+void LLLoadedCallbackEntry::cleanUpCallbackList(LLLoadedCallbackEntry::source_callback_list_t* callback_list, void* src)
+{
+	//clear texture callbacks.
+	if(!callback_list->empty())
+	{
+		for(LLLoadedCallbackEntry::source_callback_list_t::iterator iter = callback_list->begin();
+				iter != callback_list->end(); ++iter)
+		{
+			LLViewerFetchedTexture* tex = gTextureList.findImage(*iter) ;
+			if(tex)
+			{
+				tex->deleteCallbackEntry(src) ;			
+			}
+		}
+		callback_list->clear() ;
+	}
+}
+
 LLViewerMediaTexture* LLViewerTextureManager::createMediaTexture(const LLUUID &media_id, BOOL usemipmaps, LLImageGL* gl_image)
 {
 	return new LLViewerMediaTexture(media_id, usemipmaps, gl_image) ;		
@@ -324,9 +366,7 @@ void LLViewerTextureManager::cleanup()
 	LLViewerFetchedTexture::sMissingAssetImagep = NULL;
 	LLViewerFetchedTexture::sWhiteImagep = NULL;
 
-	LLViewerMediaTexture::cleanup() ;	
-
-	LLViewerTexture::cleanupClass() ;
+	LLViewerMediaTexture::cleanUpClass() ;	
 }
 
 //----------------------------------------------------------------------------------------------
@@ -344,11 +384,6 @@ void LLViewerTexture::initClass()
 	}
 }
 
-// static
-void LLViewerTexture::cleanupClass()
-{
-}
-
 // static
 S32 LLViewerTexture::getTotalNumOfCategories() 
 {
@@ -492,10 +527,10 @@ void LLViewerTexture::init(bool firstinit)
 
 	mTextureState = NO_DELETE ;
 	mDontDiscard = FALSE;
-	mCanResetMaxVirtualSize = true ;
 	mMaxVirtualSize = 0.f;
 	mNeedsGLTexture = FALSE ;
-	mNeedsResetMaxVirtualSize = FALSE ;
+	mMaxVirtualSizeResetInterval = 1;
+	mMaxVirtualSizeResetCounter = 1 ;
 	mAdditionalDecodePriority = 0.f ;	
 	mParcelMedia = NULL ;
 	mNumFaces = 0 ;
@@ -510,6 +545,7 @@ S8 LLViewerTexture::getType() const
 	return LLViewerTexture::LOCAL_TEXTURE ;
 }
 
+//virtual
 void LLViewerTexture::cleanup()
 {
 	mFaceList.clear() ;
@@ -591,11 +627,6 @@ void LLViewerTexture::forceImmediateUpdate()
 {
 }
 
-void LLViewerTexture::setResetMaxVirtualSizeFlag(bool flag) 
-{
-	mCanResetMaxVirtualSize = flag ;
-}
-
 void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) const 
 {
 	if(needs_gltexture)
@@ -603,10 +634,10 @@ void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) co
 		mNeedsGLTexture = TRUE ;
 	}
 
-	if(mNeedsResetMaxVirtualSize)
+	if(!mMaxVirtualSizeResetCounter)
 	{
 		//flag to reset the values because the old values are used.
-		mNeedsResetMaxVirtualSize = FALSE ;
+		resetMaxVirtualSizeResetCounter() ;
 		mMaxVirtualSize = virtual_size;		
 		mAdditionalDecodePriority = 0.f ;	
 		mNeedsGLTexture = needs_gltexture ;
@@ -621,7 +652,7 @@ void LLViewerTexture::resetTextureStats()
 {
 	mMaxVirtualSize = 0.0f ;
 	mAdditionalDecodePriority = 0.f ;	
-	mNeedsResetMaxVirtualSize = FALSE ;
+	mMaxVirtualSizeResetCounter = 0 ;
 }
 
 //virtual 
@@ -1098,6 +1129,7 @@ void LLViewerFetchedTexture::init(bool firstinit)
 	mIsMissingAsset = FALSE;
 
 	mLoadedCallbackDesiredDiscardLevel = 0;
+	mPauseLoadedCallBacks = TRUE ;
 
 	mNeedsCreateTexture = FALSE;
 	
@@ -1144,6 +1176,7 @@ S8 LLViewerFetchedTexture::getType() const
 	return LLViewerTexture::FETCHED_TEXTURE ;
 }
 
+//virtual
 void LLViewerFetchedTexture::cleanup()
 {
 	for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
@@ -1153,6 +1186,7 @@ void LLViewerFetchedTexture::cleanup()
 		// We never finished loading the image.  Indicate failure.
 		// Note: this allows mLoadedCallbackUserData to be cleaned up.
 		entryp->mCallback( FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData );
+		entryp->removeTexture(this) ;
 		delete entryp;
 	}
 	mLoadedCallbackList.clear();
@@ -1164,6 +1198,8 @@ void LLViewerFetchedTexture::cleanup()
 	mCachedRawDiscardLevel = -1 ;
 	mCachedRawImageReady = FALSE ;
 	mSavedRawImage = NULL ;
+
+	LLViewerTexture::cleanup();
 }
 
 void LLViewerFetchedTexture::setForSculpt()
@@ -1529,6 +1565,7 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
 	F32 pixel_priority = fsqrtf(mMaxVirtualSize);
 
 	F32 priority = 0.f;
+
 	if (mIsMissingAsset)
 	{
 		priority = 0.0f;
@@ -1550,7 +1587,7 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
 	{
 		priority = 1.f;
 	}
-	else if (pixel_priority <= 0.f && !have_all_data)
+	else if (pixel_priority < 0.001f && !have_all_data)
 	{
 		// Not on screen but we might want some data
 		if (mBoostLevel > BOOST_HIGH)
@@ -1558,11 +1595,6 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
 			// Always want high boosted images
 			priority = 1.f;
 		}
-		else if(mForceToSaveRawImage)
-		{
-			//force to fetch the raw image.
-			priority = 1.f;
-		}
 		else
 		{
 			priority = -5.f; //stop fetching
@@ -1665,7 +1697,7 @@ void LLViewerFetchedTexture::setAdditionalDecodePriority(F32 priority)
 
 void LLViewerFetchedTexture::updateVirtualSize() 
 {	
-	if(mNeedsResetMaxVirtualSize)
+	if(!mMaxVirtualSizeResetCounter)
 	{
 		addTextureStats(0.f, FALSE) ;//reset
 	}
@@ -1685,9 +1717,9 @@ void LLViewerFetchedTexture::updateVirtualSize()
 		}
 	}
 
-	if(mCanResetMaxVirtualSize)
+	if(mMaxVirtualSizeResetCounter > 0)
 	{
-		mNeedsResetMaxVirtualSize = TRUE ;
+		mMaxVirtualSizeResetCounter--;
 	}
 	reorganizeFaceList() ;
 	reorganizeVolumeList();
@@ -1765,6 +1797,7 @@ bool LLViewerFetchedTexture::updateFetch()
 		if (finished)
 		{
 			mIsFetching = FALSE;
+			mLastPacketTimer.reset() ;
 		}
 		else
 		{
@@ -1794,6 +1827,7 @@ bool LLViewerFetchedTexture::updateFetch()
 					setIsMissingAsset();
 					mRawDiscardLevel = INVALID_DISCARD_LEVEL ;
 					mIsFetching = FALSE ;
+					mLastPacketTimer.reset();
 				}
 				else
 				{
@@ -1961,6 +1995,7 @@ void LLViewerFetchedTexture::setIsMissingAsset()
 		LLAppViewer::getTextureFetch()->deleteRequest(getID(), true);
 		mHasFetcher = FALSE;
 		mIsFetching = FALSE;
+		mLastPacketTimer.reset();
 		mFetchState = 0;
 		mFetchPriority = 0;
 	}
@@ -1968,7 +2003,8 @@ void LLViewerFetchedTexture::setIsMissingAsset()
 }
 
 void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_callback,
-									   S32 discard_level, BOOL keep_imageraw, BOOL needs_aux, void* userdata)
+									   S32 discard_level, BOOL keep_imageraw, BOOL needs_aux, void* userdata, void* src,
+									   LLLoadedCallbackEntry::source_callback_list_t* src_callback_list, BOOL pause)
 {
 	//
 	// Don't do ANYTHING here, just add it to the global callback list
@@ -1984,12 +2020,17 @@ void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_call
 		mLoadedCallbackDesiredDiscardLevel = llmin(mLoadedCallbackDesiredDiscardLevel, (S8)discard_level) ;
 	}
 
-	LLLoadedCallbackEntry* entryp = new LLLoadedCallbackEntry(loaded_callback, discard_level, keep_imageraw, userdata);
-	mLoadedCallbackList.push_back(entryp);
+	if(mPauseLoadedCallBacks && !pause)
+	{
+		unpauseLoadedCallbacks(src) ;
+	}
+	LLLoadedCallbackEntry* entryp = new LLLoadedCallbackEntry(loaded_callback, discard_level, keep_imageraw, userdata, src_callback_list, src, this, pause);
+	mLoadedCallbackList.push_back(entryp);	
+
 	mNeedsAux |= needs_aux;
 	if(keep_imageraw)
 	{
-		forceToSaveRawImage(discard_level) ;
+		forceToSaveRawImage(discard_level, true) ;
 	}
 	if (mNeedsAux && mAuxRawImage.isNull() && getDiscardLevel() >= 0)
 	{
@@ -1998,6 +2039,113 @@ void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_call
 	}
 }
 
+void LLViewerFetchedTexture::deleteCallbackEntry(void* src)
+{
+	if(mLoadedCallbackList.empty())
+	{
+		return ;
+	}
+
+	S32 desired_discard = INVALID_DISCARD_LEVEL ;
+	S32 desired_raw_discard = INVALID_DISCARD_LEVEL ;
+	for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
+			iter != mLoadedCallbackList.end(); )
+	{
+		LLLoadedCallbackEntry *entryp = *iter;
+		if(entryp->mSource == src)
+		{
+			// We never finished loading the image.  Indicate failure.
+			// Note: this allows mLoadedCallbackUserData to be cleaned up.
+			entryp->mCallback(FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData);
+			delete entryp;
+			iter = mLoadedCallbackList.erase(iter) ;
+		}
+		else
+		{
+			++iter;
+
+			desired_discard = llmin(desired_discard, entryp->mDesiredDiscard) ;
+			if(entryp->mNeedsImageRaw)
+			{
+				desired_raw_discard = llmin(desired_raw_discard, entryp->mDesiredDiscard) ;
+			}
+		}
+	}
+
+	mLoadedCallbackDesiredDiscardLevel = desired_discard;
+	if (mLoadedCallbackList.empty())
+	{
+		// If we have no callbacks, take us off of the image callback list.
+		gTextureList.mCallbackList.erase(this);
+		mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
+
+		if(mForceToSaveRawImage)
+		{
+			destroySavedRawImage() ;
+		}
+	}
+	else if(mForceToSaveRawImage && mBoostLevel != LLViewerTexture::BOOST_PREVIEW)
+	{
+		if(desired_raw_discard != INVALID_DISCARD_LEVEL)
+		{
+			mDesiredSavedRawDiscardLevel = desired_raw_discard ;
+		}
+		else
+		{
+			destroySavedRawImage() ;
+		}
+	}
+}
+
+void LLViewerFetchedTexture::unpauseLoadedCallbacks(void* src)
+{
+	BOOL need_raw = FALSE ;
+	for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
+			iter != mLoadedCallbackList.end(); )
+	{
+		LLLoadedCallbackEntry *entryp = *iter++;
+		if(entryp->mSource == src)
+		{
+			entryp->mPaused = FALSE ;
+			if(entryp->mNeedsImageRaw)
+			{
+				need_raw = TRUE ;
+			}
+		}
+	}
+	mPauseLoadedCallBacks = FALSE ;
+	if(need_raw)
+	{
+		mForceToSaveRawImage = TRUE ;
+	}
+}
+
+void LLViewerFetchedTexture::pauseLoadedCallbacks(void* src)
+{
+	bool paused = true ;
+
+	for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
+			iter != mLoadedCallbackList.end(); )
+	{
+		LLLoadedCallbackEntry *entryp = *iter++;
+		if(entryp->mSource == src)
+		{
+			entryp->mPaused = TRUE ;
+		}
+		else if(!entryp->mPaused)
+		{
+			paused = false ;
+		}
+	}
+
+	if(paused)
+	{
+		mPauseLoadedCallBacks = TRUE ;//when set, loaded callback is paused.
+		resetTextureStats();
+		mForceToSaveRawImage = FALSE ;
+	}
+}
+
 bool LLViewerFetchedTexture::doLoadedCallbacks()
 {
 	if (mNeedsCreateTexture)
@@ -2023,6 +2171,11 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
 		// Remove ourself from the global list of textures with callbacks
 		gTextureList.mCallbackList.erase(this);
 	}
+	if(mPauseLoadedCallBacks)
+	{
+		destroyRawImage();
+		return res; //paused
+	}
 
 	S32 gl_discard = getDiscardLevel();
 
@@ -2432,10 +2585,12 @@ void LLViewerFetchedTexture::saveRawImage()
 	mLastReferencedSavedRawImageTime = sCurrentTime ;
 }
 
-void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard) 
+void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, bool from_callback) 
 { 
 	if(!mForceToSaveRawImage || mDesiredSavedRawDiscardLevel < 0 || mDesiredSavedRawDiscardLevel > desired_discard)
 	{
+		llassert_always(from_callback || mBoostLevel == LLViewerTexture::BOOST_PREVIEW) ;
+
 		mForceToSaveRawImage = TRUE ;
 		mDesiredSavedRawDiscardLevel = desired_discard ;
 	
@@ -2882,7 +3037,7 @@ void LLViewerMediaTexture::removeMediaImplFromTexture(const LLUUID& media_id)
 }
 
 //static
-void LLViewerMediaTexture::cleanup()
+void LLViewerMediaTexture::cleanUpClass()
 {
 	sMediaMap.clear() ;
 }
@@ -3291,7 +3446,7 @@ F32 LLViewerMediaTexture::getMaxVirtualSize()
 	}
 	mUpdateVirtualSizeTime = LLFrameTimer::getFrameCount() ;
 
-	if(mNeedsResetMaxVirtualSize)
+	if(!mMaxVirtualSizeResetCounter)
 	{
 		addTextureStats(0.f, FALSE) ;//reset
 	}
@@ -3324,9 +3479,9 @@ F32 LLViewerMediaTexture::getMaxVirtualSize()
 		}
 	}
 
-	if(mCanResetMaxVirtualSize)
+	if(mMaxVirtualSizeResetCounter > 0)
 	{
-		mNeedsResetMaxVirtualSize = TRUE ;
+		mMaxVirtualSizeResetCounter--;
 	}
 	reorganizeFaceList() ;
 	reorganizeVolumeList();
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 361f56e02f..8b69408e4b 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -66,17 +66,32 @@ class LLVOVolume ;
 
 class LLLoadedCallbackEntry
 {
+public:
+	typedef std::set< LLUUID > source_callback_list_t;
+
 public:
 	LLLoadedCallbackEntry(loaded_callback_func cb,
 						  S32 discard_level,
 						  BOOL need_imageraw, // Needs image raw for the callback
-						  void* userdata );
+						  void* userdata,
+						  source_callback_list_t* src_callback_list,
+						  void* source,
+						  LLViewerFetchedTexture* target,
+						  BOOL pause);
+	~LLLoadedCallbackEntry();
+	void removeTexture(LLViewerFetchedTexture* tex) ;
 
 	loaded_callback_func	mCallback;
 	S32						mLastUsedDiscard;
 	S32						mDesiredDiscard;
 	BOOL					mNeedsImageRaw;
+	BOOL                    mPaused;
 	void*					mUserData;
+	source_callback_list_t* mSourceCallbackList;
+	void*                   mSource;
+	
+public:
+	static void cleanUpCallbackList(LLLoadedCallbackEntry::source_callback_list_t* callback_list, void* src) ;
 };
 
 class LLTextureBar;
@@ -103,22 +118,23 @@ public:
 	enum EBoostLevel
 	{
 		BOOST_NONE 			= 0,
-		BOOST_AVATAR_BAKED	= 1,
-		BOOST_AVATAR		= 2,
-		BOOST_CLOUDS		= 3,
-		BOOST_SCULPTED      = 4,
+		BOOST_AVATAR_BAKED	,
+		BOOST_AVATAR		,
+		BOOST_CLOUDS		,
+		BOOST_SCULPTED      ,
 		
 		BOOST_HIGH 			= 10,
-		BOOST_TERRAIN		= 11, // has to be high priority for minimap / low detail
-		BOOST_SELECTED		= 12,
-		BOOST_HUD			= 13,
-		BOOST_AVATAR_BAKED_SELF	= 14,
-		BOOST_ICON			= 15,
-		BOOST_UI			= 16,
-		BOOST_PREVIEW		= 17,
-		BOOST_MAP			= 18,
-		BOOST_MAP_VISIBLE	= 19,
-		BOOST_AVATAR_SELF	= 20, // needed for baking avatar
+		BOOST_BUMP          ,
+		BOOST_TERRAIN		, // has to be high priority for minimap / low detail
+		BOOST_SELECTED		,
+		BOOST_HUD			,
+		BOOST_AVATAR_BAKED_SELF	,
+		BOOST_ICON			,
+		BOOST_UI			,
+		BOOST_PREVIEW		,
+		BOOST_MAP			,
+		BOOST_MAP_VISIBLE	,
+		BOOST_AVATAR_SELF	, // needed for baking avatar
 		BOOST_MAX_LEVEL,
 
 		//other texture Categories
@@ -144,7 +160,6 @@ protected:
 
 public:	
 	static void initClass();
-	static void cleanupClass();
 	static void updateClass(const F32 velocity, const F32 angular_velocity) ;
 	
 	LLViewerTexture(BOOL usemipmaps = TRUE);
@@ -166,7 +181,8 @@ public:
 
 	void addTextureStats(F32 virtual_size, BOOL needs_gltexture = TRUE) const;
 	void resetTextureStats();	
-	void setResetMaxVirtualSizeFlag(bool flag) ;
+	void setMaxVirtualSizeResetInterval(S32 interval)const {mMaxVirtualSizeResetInterval = interval;}
+	void resetMaxVirtualSizeResetCounter()const {mMaxVirtualSizeResetCounter = mMaxVirtualSizeResetInterval;}
 
 	virtual F32  getMaxVirtualSize() ;
 
@@ -248,7 +264,7 @@ public:
 
 	/*virtual*/ void updateBindStatsForTester() ;
 protected:
-	void cleanup() ;
+	virtual void cleanup() ;
 	void init(bool firstinit) ;	
 	void reorganizeFaceList() ;
 	void reorganizeVolumeList() ;
@@ -264,10 +280,10 @@ protected:
 	S32 mFullHeight;
 	BOOL  mUseMipMaps ;
 	S8  mComponents;
-	bool mCanResetMaxVirtualSize;
-	mutable F32 mMaxVirtualSize;	// The largest virtual size of the image, in pixels - how much data to we need?
 	mutable S8  mNeedsGLTexture;
-	mutable BOOL mNeedsResetMaxVirtualSize ;
+	mutable F32 mMaxVirtualSize;	// The largest virtual size of the image, in pixels - how much data to we need?	
+	mutable S32  mMaxVirtualSizeResetCounter ;
+	mutable S32  mMaxVirtualSizeResetInterval;
 	mutable F32 mAdditionalDecodePriority;  // priority add to mDecodePriority.
 	LLFrameTimer mLastReferencedTimer;	
 
@@ -368,10 +384,13 @@ public:
 	// Set callbacks to get called when the image gets updated with higher 
 	// resolution versions.
 	void setLoadedCallback(loaded_callback_func cb,
-						   S32 discard_level, BOOL keep_imageraw, BOOL needs_aux,
-						   void* userdata);
+						   S32 discard_level, BOOL keep_imageraw, BOOL needs_aux, void* src,
+						   void* userdata, LLLoadedCallbackEntry::source_callback_list_t* src_callback_list, BOOL pause = FALSE);
 	bool hasCallbacks() { return mLoadedCallbackList.empty() ? false : true; }	
+	void pauseLoadedCallbacks(void* src);
+	void unpauseLoadedCallbacks(void* src);
 	bool doLoadedCallbacks();
+	void deleteCallbackEntry(void* src);
 
 	void addToCreateTexture();
 
@@ -449,7 +468,7 @@ public:
 	S32         getCachedRawImageLevel() const {return mCachedRawDiscardLevel;}
 	BOOL        isCachedRawImageReady() const {return mCachedRawImageReady ;}
 	BOOL        isRawImageValid()const { return mIsRawImageValid ; }	
-	void        forceToSaveRawImage(S32 desired_discard = 0) ;
+	void        forceToSaveRawImage(S32 desired_discard = 0, bool from_callback = false) ;
 	/*virtual*/ void setCachedRawImage(S32 discard_level, LLImageRaw* imageraw) ;
 	void        destroySavedRawImage() ;
 	LLImageRaw* getSavedRawImage() ;
@@ -466,7 +485,7 @@ protected:
 
 private:
 	void init(bool firstinit) ;
-	void cleanup() ;
+	/*virtual*/ void cleanup() ;
 
 	void saveRawImage() ;
 	void setCachedRawImage() ;
@@ -515,6 +534,7 @@ protected:
 
 	typedef std::list<LLLoadedCallbackEntry*> callback_list_t;
 	S8              mLoadedCallbackDesiredDiscardLevel;
+	BOOL            mPauseLoadedCallBacks;
 	callback_list_t mLoadedCallbackList;
 
 	LLPointer<LLImageRaw> mRawImage;
@@ -638,7 +658,7 @@ private:
 
 public:
 	static void updateClass() ;
-	static void cleanup() ;	
+	static void cleanUpClass() ;	
 
 	static LLViewerMediaTexture* findMediaTexture(const LLUUID& media_id) ;
 	static void removeMediaImplFromTexture(const LLUUID& media_id) ;
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 1e3311dafe..b3aff30324 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -1219,7 +1219,7 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d
 		delete [] data;
 		return;
 	}
-	image->getLastPacketTimer()->reset();
+	//image->getLastPacketTimer()->reset();
 	bool res = LLAppViewer::getTextureFetch()->receiveImageHeader(msg->getSender(), id, codec, packets, totalbytes, data_size, data);
 	if (!res)
 	{
@@ -1283,7 +1283,7 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d
 		delete [] data;
 		return;
 	}
-	image->getLastPacketTimer()->reset();
+	//image->getLastPacketTimer()->reset();
 	bool res = LLAppViewer::getTextureFetch()->receiveImagePacket(msg->getSender(), id, packet_num, data_size, data);
 	if (!res)
 	{
@@ -1406,7 +1406,7 @@ LLUIImagePtr LLUIImageList::loadUIImage(LLViewerFetchedTexture* imagep, const st
 	datap->mImageName = name;
 	datap->mImageScaleRegion = scale_rect;
 
-	imagep->setLoadedCallback(onUIImageLoaded, 0, FALSE, FALSE, datap);
+	imagep->setLoadedCallback(onUIImageLoaded, 0, FALSE, FALSE, datap, NULL, NULL);
 
 	return new_imagep;
 }
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 316588c982..86e07c3126 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -677,7 +677,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mFullyLoaded(FALSE),
 	mPreviousFullyLoaded(FALSE),
 	mFullyLoadedInitialized(FALSE),
-	mSupportsAlphaLayers(FALSE)
+	mSupportsAlphaLayers(FALSE),
+	mLoadedCallbacksPaused(FALSE)
 {
 	LLMemType mt(LLMemType::MTYPE_AVATAR);
 	//VTResume();  // VTune
@@ -847,6 +848,7 @@ void LLVOAvatar::markDead()
 		sNumVisibleChatBubbles--;
 	}
 	mVoiceVisualizer->markDead();
+	LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList, this) ;
 	LLViewerObject::markDead();
 }
 
@@ -2227,12 +2229,14 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 	{
 		llinfos << "Warning!  Idle on dead avatar" << llendl;
 		return TRUE;
-	}
+	}	
 
  	if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR)))
 	{
 		return TRUE;
 	}
+
+	checkTextureLoading() ;
 	
 	// force immediate pixel area update on avatars using last frames data (before drawable or camera updates)
 	setPixelAreaAndAngle(gAgent);
@@ -4138,6 +4142,7 @@ void LLVOAvatar::updateTextures()
 	{
 		render_avatar = isVisible() && !mCulled;
 	}
+	checkTextureLoading() ;
 
 	std::vector<BOOL> layer_baked;
 	// GL NOT ACTIVE HERE - *TODO
@@ -4178,7 +4183,7 @@ void LLVOAvatar::updateTextures()
 				}
 			}
 		}
-		if (isIndexBakedTexture((ETextureIndex) texture_index))
+		if (isIndexBakedTexture((ETextureIndex) texture_index) && render_avatar)
 		{
 			const S32 boost_level = getAvatarBakedBoostLevel();
 			imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(texture_index,0), TRUE);
@@ -4194,7 +4199,7 @@ void LLVOAvatar::updateTextures()
 										 << " on host " << getRegion()->getHost() << llendl;
 			}
 
-			addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level );
+			addBakedTextureStats( imagep, mPixelArea, texel_area_ratio, boost_level );			
 		}
 	}
 
@@ -4218,13 +4223,65 @@ void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture
 }
 
 			    
+void LLVOAvatar::checkTextureLoading()
+{
+	static const F32 MAX_INVISIBLE_WAITING_TIME = 30.f ; //seconds
+
+	BOOL pause = !isVisible() ;
+	if(mLoadedCallbacksPaused == pause)
+	{
+		return ; 
+	}
+	
+	if(mCallbackTextureList.empty())
+	{
+		mLoadedCallbacksPaused = pause ;
+		return ; //nothing to check.
+	}
+
+	if(!pause)
+	{
+		mInvisibleTimer.reset() ;
+	}
+	if(pause && mInvisibleTimer.getElapsedTimeF32() < MAX_INVISIBLE_WAITING_TIME)
+	{
+		return ;
+	}
+	
+	for(LLLoadedCallbackEntry::source_callback_list_t::iterator iter = mCallbackTextureList.begin();
+		iter != mCallbackTextureList.end(); ++iter)
+	{
+		LLViewerFetchedTexture* tex = gTextureList.findImage(*iter) ;
+		if(tex)
+		{
+			if(pause)//pause texture fetching.
+			{
+				tex->pauseLoadedCallbacks(this) ;
+			}
+			else//unpause
+			{
+				static const F32 START_AREA = 100.f ;
+
+				tex->unpauseLoadedCallbacks(this) ;
+				tex->addTextureStats(START_AREA); //jump satrt the fetching again
+			}
+		}		
+	}			
+	
+	mLoadedCallbacksPaused = pause ;
+	return ;
+}
+
 void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level)
 {
-	mMaxPixelArea = llmax(pixel_area, mMaxPixelArea);
-	mMinPixelArea = llmin(pixel_area, mMinPixelArea);
+	static const S32  MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL = 512 ; //frames	
+
 	imagep->resetTextureStats();
-	imagep->setResetMaxVirtualSizeFlag(false) ;
 	imagep->setCanUseHTTP(false) ; //turn off http fetching for baked textures.
+	imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL);
+
+	mMaxPixelArea = llmax(pixel_area, mMaxPixelArea);
+	mMinPixelArea = llmin(pixel_area, mMinPixelArea);	
 	imagep->addTextureStats(pixel_area / texel_area_ratio);
 	imagep->setBoostLevel(boost_level);
 	if(boost_level == LLViewerTexture::BOOST_AVATAR_BAKED_SELF)
@@ -6144,6 +6201,15 @@ void LLVOAvatar::updateMeshTextures()
 
 	const BOOL self_customizing = isSelf() && gAgentCamera.cameraCustomizeAvatar(); // During face edit mode, we don't use baked textures
 	const BOOL other_culled = !isSelf() && mCulled;
+	LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ;
+	void* callback_src = NULL ;
+	BOOL paused = FALSE;
+	if(!isSelf())
+	{
+		callback_src = this ;
+		src_callback_list = &mCallbackTextureList ;
+		paused = mLoadedCallbacksPaused ;
+	}
 
 	std::vector<BOOL> is_layer_baked;
 	is_layer_baked.resize(mBakedTextureDatas.size(), false);
@@ -6214,10 +6280,12 @@ void LLVOAvatar::updateMeshTextures()
 			{
 				mBakedTextureDatas[i].mIsLoaded = FALSE;
 				if ( (baked_img->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) )
-				{
-					baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ));	
+				{			
+					baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), 
+						callback_src, src_callback_list, paused);	
 				}
-				baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ) );
+				baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ), 
+					callback_src, src_callback_list, paused );
 			}
 		}
 		else if (mBakedTextureDatas[i].mTexLayerSet 
@@ -6677,6 +6745,16 @@ void LLVOAvatar::onFirstTEMessageReceived()
 	{
 		mFirstTEMessageReceived = TRUE;
 
+		LLLoadedCallbackEntry::source_callback_list_t* src_callback_list = NULL ;
+		void* callback_src = NULL ;
+		BOOL paused = FALSE ;
+		if(!isSelf())
+		{
+			callback_src = this ;
+			src_callback_list = &mCallbackTextureList ;
+			paused = mLoadedCallbacksPaused ;
+		}
+
 		for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
 		{
 			const BOOL layer_baked = isTextureDefined(mBakedTextureDatas[i].mTextureIndex);
@@ -6690,9 +6768,11 @@ void LLVOAvatar::onFirstTEMessageReceived()
 				// If we have more than one texture for the other baked layers, we'll want to call this for them too.
 				if ( (image->getID() != IMG_INVISIBLE) && ((i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER)) )
 				{
-					image->setLoadedCallback( onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ));
+					image->setLoadedCallback( onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID ), 
+						callback_src, src_callback_list, paused);
 				}
-				image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ) );
+				image->setLoadedCallback( onInitialBakedTextureLoaded, MAX_DISCARD_LEVEL, FALSE, FALSE, new LLUUID( mID ), 
+					callback_src, src_callback_list, paused );
 			}
 		}
 
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 4259bb8e73..3dad919875 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -263,6 +263,8 @@ private:
 	S32				mFullyLoadedFrameCounter;
 	LLFrameTimer	mFullyLoadedTimer;
 	LLFrameTimer	mRuthTimer;
+protected:
+	LLFrameTimer    mInvisibleTimer;
 	
 /**                    State
  **                                                                            **
@@ -499,7 +501,8 @@ protected:
 	};
 	typedef std::vector<BakedTextureData> 	bakedtexturedata_vec_t;
 	bakedtexturedata_vec_t 					mBakedTextureDatas;
-
+	LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ; 
+	BOOL mLoadedCallbacksPaused;
 	//--------------------------------------------------------------------
 	// Local Textures
 	//--------------------------------------------------------------------
@@ -519,7 +522,7 @@ private:
 	virtual const LLTextureEntry* getTexEntry(const U8 te_num) const;
 	virtual void setTexEntry(const U8 index, const LLTextureEntry &te);
 
-
+	void checkTextureLoading() ;
 	//--------------------------------------------------------------------
 	// Layers
 	//--------------------------------------------------------------------
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 982d9c375c..4edbbb7402 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1632,8 +1632,8 @@ void LLVOAvatarSelf::setLocalTexture(ETextureIndex type, LLViewerTexture* src_te
 					}
 				}
 				else
-				{
-					tex->setLoadedCallback(onLocalTextureLoaded, desired_discard, TRUE, FALSE, new LLAvatarTexData(getID(), type));
+				{					
+					tex->setLoadedCallback(onLocalTextureLoaded, desired_discard, TRUE, FALSE, new LLAvatarTexData(getID(), type), NULL, NULL);
 				}
 			}
 			tex->setMinDiscardLevel(desired_discard);
@@ -2032,7 +2032,7 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe
 			imagep->setBoostLevel(getAvatarBoostLevel());
 
 			imagep->resetTextureStats();
-			imagep->setResetMaxVirtualSizeFlag(false) ;
+			imagep->setMaxVirtualSizeResetInterval(16);
 			imagep->addTextureStats( desired_pixels / texel_area_ratio );
 			imagep->setAdditionalDecodePriority(1.0f) ;
 			imagep->forceUpdateBindStats() ;
diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp
index 2eb233ddd9..c74782162b 100644
--- a/indra/newview/llwearable.cpp
+++ b/indra/newview/llwearable.cpp
@@ -106,6 +106,7 @@ LLWearable::LLWearable(const LLAssetID& asset_id) :
 
 LLWearable::~LLWearable()
 {
+	LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList, this) ;
 }
 
 const std::string& LLWearable::getTypeLabel() const
@@ -444,8 +445,8 @@ BOOL LLWearable::importFile( LLFILE* file )
 			delete mSavedTEMap[te];
 		}
 
-		image->setLoadedCallback(LLVOAvatarSelf::debugOnTimingLocalTexLoaded,0,TRUE,FALSE, new LLVOAvatarSelf::LLAvatarTexData(id, (LLVOAvatarDefines::ETextureIndex)te));
-
+		image->setBoostLevel(LLViewerTexture::BOOST_AVATAR_SELF) ;
+		image->setLoadedCallback(LLVOAvatarSelf::debugOnTimingLocalTexLoaded,0,TRUE,FALSE, new LLVOAvatarSelf::LLAvatarTexData(id, (LLVOAvatarDefines::ETextureIndex)te), this, &mCallbackTextureList);
 
 		LLUUID textureid(text_buffer);
 		mTEMap[te] = new LLLocalTextureObject(image, textureid);
diff --git a/indra/newview/llwearable.h b/indra/newview/llwearable.h
index 6b6067fd27..34a231c4bb 100644
--- a/indra/newview/llwearable.h
+++ b/indra/newview/llwearable.h
@@ -165,6 +165,7 @@ private:
 	te_map_t mTEMap;				// maps TE to LocalTextureObject
 	te_map_t mSavedTEMap;			// last saved version of TEMap
 	LLUUID				mItemID;  // ID of the inventory item in the agent's inventory
+	LLLoadedCallbackEntry::source_callback_list_t mCallbackTextureList ; 
 };
 
 #endif  // LL_LLWEARABLE_H
-- 
cgit v1.2.3