From 247ca1660bf4029d4e5bb701654433f14c785ab5 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 18 Aug 2010 11:33:01 -0600
Subject: [PATCH] EXT-8673: FIXED: UDP texture loading is slower in 2.x viewers
 than 1.23.5 Improved the following: 1, make sure the texture callback queue
 is properly handled and cleaned in time; 2, estimate the LLVOTree pixel area
 more accurately; 3, eliminate the possibility of back and forth
 stopping/restarting a texture fetching

---
 indra/newview/app_settings/settings.xml | 183 +++++++++---------------
 indra/newview/llface.cpp                |  65 ++++-----
 indra/newview/llface.h                  |   3 +-
 indra/newview/lltexturefetch.cpp        |   2 +-
 indra/newview/llviewertexture.cpp       | 136 ++++++++++++------
 indra/newview/llviewertexture.h         |   2 +
 indra/newview/llvoavatarself.cpp        |  21 +--
 indra/newview/llvotree.cpp              |  33 +++--
 indra/newview/llwearable.cpp            |   7 +-
 9 files changed, 236 insertions(+), 216 deletions(-)

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 4c52fb015fd..2130713d50c 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1741,6 +1741,17 @@
 		<key>Value</key>
 		<integer>0</integer>
 	</map>
+  <key>DebugAvatarLocalTexLoadedTime</key>
+  <map>
+    <key>Comment</key>
+    <string>Display time for loading avatar local textures.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
     <key>DebugBeaconLineWidth</key>
     <map>
       <key>Comment</key>
@@ -5373,6 +5384,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>MultipleAttachments</key>
+    <map>
+      <key>Comment</key>
+      <string>Allow multiple objects to be attached to a single attachment point.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
    <key>MuteAmbient</key>
     <map>
       <key>Comment</key>
@@ -6737,7 +6759,7 @@
     <key>Type</key>
     <string>U32</string>
     <key>Value</key>
-    <integer>200</integer>
+    <integer>60</integer>
   </map>
   <key>RenderSSAOFactor</key>
   <map>
@@ -7112,64 +7134,6 @@
     <real>0.01</real>
   </map>
 
-  <key>RenderShadowBiasError</key>
-  <map>
-    <key>Comment</key>
-    <string>Error scale for shadow bias (based on altitude).</string>
-    <key>Persist</key>
-    <integer>1</integer>
-    <key>Type</key>
-    <string>F32</string>
-    <key>Value</key>
-    <real>0</real>
-  </map>
-  <key>RenderShadowOffsetError</key>
-  <map>
-    <key>Comment</key>
-    <string>Error scale for shadow offset (based on altitude).</string>
-    <key>Persist</key>
-    <integer>1</integer>
-    <key>Type</key>
-    <string>F32</string>
-    <key>Value</key>
-    <real>0</real>
-  </map>
-  
-  <key>RenderSpotLightsInNondeferred</key>
-  <map>
-    <key>Comment</key>
-    <string>Whether to support projectors as spotlights when Lighting and Shadows is disabled</string>
-    <key>Persist</key>
-    <integer>1</integer>
-    <key>Type</key>
-    <string>Boolean</string>
-    <key>Value</key>
-    <integer>0</integer>
-  </map>
-
-  <key>RenderSpotShadowBias</key>
-  <map>
-    <key>Comment</key>
-    <string>Bias value for shadows (prevent shadow acne).</string>
-    <key>Persist</key>
-    <integer>1</integer>
-    <key>Type</key>
-    <string>F32</string>
-    <key>Value</key>
-    <real>0.0</real>
-  </map>
-  <key>RenderSpotShadowOffset</key>
-  <map>
-    <key>Comment</key>
-    <string>Offset value for shadows (prevent shadow acne).</string>
-    <key>Persist</key>
-    <integer>1</integer>
-    <key>Type</key>
-    <string>F32</string>
-    <key>Value</key>
-    <real>0.04</real>
-  </map>
-
   <key>RenderShadowResolutionScale</key>
   <map>
     <key>Comment</key>
@@ -7182,6 +7146,8 @@
     <real>1.0</real>
   </map>
 
+
+
   <key>RenderDeferredTreeShadowBias</key>
   <map>
     <key>Comment</key>
@@ -7303,7 +7269,7 @@
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>8</real>
+    <real>1</real>
   </map>
 
   <key>RenderDeferred</key>
@@ -7318,6 +7284,18 @@
     <integer>0</integer>
   </map>
 
+  <key>RenderDeferredShadow</key>
+  <map>
+    <key>Comment</key>
+    <string>Enable shadows in deferred renderer.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
+
   <key>RenderDeferredGI</key>
   <map>
     <key>Comment</key>
@@ -7330,10 +7308,10 @@
     <integer>0</integer>
   </map>
 
-  <key>RenderDeferredSun</key>
+  <key>RenderDeferredSunShadow</key>
   <map>
     <key>Comment</key>
-    <string>Execute sunlight shader in deferred renderer.</string>
+    <string>Generate shadows from the sun.</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
@@ -7342,10 +7320,10 @@
     <integer>1</integer>
   </map>
 
-  <key>RenderDeferredAtmospheric</key>
+  <key>RenderDeferredSun</key>
   <map>
     <key>Comment</key>
-    <string>Execute atmospheric shader in deferred renderer.</string>
+    <string>Execute sunlight shader in deferred renderer.</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
@@ -7354,10 +7332,10 @@
     <integer>1</integer>
   </map>
 
-  <key>RenderDeferredSSAO</key>
+  <key>RenderDeferredAtmospheric</key>
   <map>
     <key>Comment</key>
-    <string>Execute screen space ambient occlusion shader in deferred renderer.</string>
+    <string>Execute atmospheric shader in deferred renderer.</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
@@ -7616,10 +7594,10 @@
       <key>Value</key>
       <real>256.0</real>
     </map>
-    <key>RenderAutoMaskAlphaNonDeferred</key>
+    <key>RenderFastAlpha</key>
     <map>
       <key>Comment</key>
-      <string>Use alpha masks where appropriate, in the non-deferred (non-'Lighting and Shadows') graphics mode</string>
+      <string>Use lossy alpha rendering optimization (opaque/nonexistent small alpha faces).</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -7627,17 +7605,6 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>RenderAutoMaskAlphaDeferred</key>
-    <map>
-      <key>Comment</key>
-      <string>Use alpha masks where appropriate, in the deferred ('Lighting and Shadows') graphics mode</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>1</integer>
-    </map>
     <key>RenderFastUI</key>
     <map>
       <key>Comment</key>
@@ -7899,6 +7866,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>RenderLightingDetail</key>
+    <map>
+      <key>Comment</key>
+      <string>Amount of detail for lighting objects/avatars/terrain (0=sun/moon only, 1=enable local lights)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
     <key>RenderMaxPartCount</key>
     <map>
       <key>Comment</key>
@@ -7998,18 +7976,6 @@
       <key>Value</key>
       <integer>2</integer>
     </map>
-    <key>RenderShadowDetail</key>
-    <map>
-      <key>Comment</key>
-      <string>Detail of shadows.</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>S32</string>
-      <key>Value</key>
-      <integer>2</integer>
-    </map>
-
     <key>RenderReflectionRes</key>
     <map>
       <key>Comment</key>
@@ -8140,7 +8106,7 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>1</integer>
+      <integer>0</integer>
     </map>
     <key>RenderUIBuffer</key>
     <map>
@@ -8296,6 +8262,17 @@
       <key>Value</key>
       <integer>512</integer>
     </map>
+    <key>RenderWaterReflections</key>
+    <map>
+      <key>Comment</key>
+      <string>Reflect the environment in the water.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>RotateRight</key>
     <map>
       <key>Comment</key>
@@ -9495,28 +9472,6 @@
       <key>Value</key>
       <integer>75</integer>
     </map>
-    <key>SnapshotSharingEnabled</key>
-    <map>
-      <key>Comment</key>
-      <string>Enable uploading of snapshots to a web service.</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>0</integer>
-    </map>
-    <key>SnapshotConfigURL</key>
-    <map>
-      <key>Comment</key>
-      <string>URL to fetch Snapshot Sharing configuration data from.</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>String</string>
-      <key>Value</key>
-      <string>http://photos.apps.staging.avatarsunited.com/viewer_config</string>
-    </map>
     <key>SnapshotTextureLastResolution</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index cfe8b4c9a47..db3d90e0a03 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -862,26 +862,6 @@ void LLFace::updateRebuildFlags()
 	}
 }
 
-
-bool LLFace::canRenderAsMask()
-{
-	const LLTextureEntry* te = getTextureEntry();
-	return (
-		(
-		 (LLPipeline::sRenderDeferred && LLPipeline::sAutoMaskAlphaDeferred) ||
-		 
-		 (!LLPipeline::sRenderDeferred && LLPipeline::sAutoMaskAlphaNonDeferred)		 
-		 ) // do we want masks at all?
-		&&
-		(te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha
-		!(LLPipeline::sRenderDeferred && te->getFullbright()) && // hack: alpha masking renders fullbright faces invisible in deferred rendering mode, need to figure out why - for now, avoid
-		(te->getGlow() == 0.f) && // glowing masks are hard to implement - don't mask
-
-		getTexture()->getIsAlphaMask() // texture actually qualifies for masking (lazily recalculated but expensive)
-		);
-}
-
-
 static LLFastTimer::DeclareTimer FTM_FACE_GET_GEOM("Face Geom");
 
 BOOL LLFace::getGeometryVolume(const LLVolume& volume,
@@ -1412,24 +1392,13 @@ F32 LLFace::getTextureVirtualSize()
 		face_area =  mPixelArea / llclamp(texel_area, 0.015625f, 128.f);
 	}
 
-	if(face_area > LLViewerTexture::sMaxSmallImageSize)
+	face_area = LLFace::adjustPixelArea(mImportanceToCamera, face_area) ;
+	if(face_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping.
 	{
-		if(mImportanceToCamera < LEAST_IMPORTANCE) //if the face is not important, do not load hi-res.
-		{
-			static const F32 MAX_LEAST_IMPORTANCE_IMAGE_SIZE = 128.0f * 128.0f ;
-			face_area = llmin(face_area * 0.5f, MAX_LEAST_IMPORTANCE_IMAGE_SIZE) ;
-		}
-		else if(face_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping.
-		{
-			if(mImportanceToCamera < LEAST_IMPORTANCE_FOR_LARGE_IMAGE)//if the face is not important, do not load hi-res.
-			{
-				face_area = LLViewerTexture::sMinLargeImageSize ;
-			}	
-			else if(mTexture.notNull() && mTexture->isLargeImage())
-			{		
-				face_area *= adjustPartialOverlapPixelArea(cos_angle_to_view_dir, radius );
-			}			
-		}
+		if(mImportanceToCamera > LEAST_IMPORTANCE_FOR_LARGE_IMAGE && mTexture.notNull() && mTexture->isLargeImage())
+		{		
+			face_area *= adjustPartialOverlapPixelArea(cos_angle_to_view_dir, radius );
+		}	
 	}
 
 	setVirtualSize(face_area) ;
@@ -1556,6 +1525,28 @@ F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist)
 	return importance ;
 }
 
+//static 
+F32 LLFace::adjustPixelArea(F32 importance, F32 pixel_area)
+{
+	if(pixel_area > LLViewerTexture::sMaxSmallImageSize)
+	{
+		if(importance < LEAST_IMPORTANCE) //if the face is not important, do not load hi-res.
+		{
+			static const F32 MAX_LEAST_IMPORTANCE_IMAGE_SIZE = 128.0f * 128.0f ;
+			pixel_area = llmin(pixel_area * 0.5f, MAX_LEAST_IMPORTANCE_IMAGE_SIZE) ;
+		}
+		else if(pixel_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping.
+		{
+			if(importance < LEAST_IMPORTANCE_FOR_LARGE_IMAGE)//if the face is not important, do not load hi-res.
+			{
+				pixel_area = LLViewerTexture::sMinLargeImageSize ;
+			}				
+		}
+	}
+
+	return pixel_area ;
+}
+
 BOOL LLFace::verify(const U32* indices_array) const
 {
 	BOOL ok = TRUE;
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index b20ecfe2b8e..8f17bc31781 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -138,10 +138,10 @@ class LLFace
 	void			unsetFaceColor(); // switch back to material color
 	const LLColor4&	getFaceColor() const { return mFaceColor; } 
 	const LLColor4& getRenderColor() const;
+	
 
 	//for volumes
 	void updateRebuildFlags();
-	bool canRenderAsMask(); // logic helper
 	BOOL getGeometryVolume(const LLVolume& volume,
 						const S32 &f,
 						const LLMatrix4& mat_vert, const LLMatrix3& mat_normal,
@@ -214,6 +214,7 @@ class LLFace
 	BOOL        calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) ;
 public:
 	static F32  calcImportanceToCamera(F32 to_view_dir, F32 dist);
+	static F32 LLFace::adjustPixelArea(F32 importance, F32 pixel_area) ;
 
 public:
 	
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index f4899d0d5d6..bd0a43cd547 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -597,7 +597,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			return true; // abort
 		}
 	}
-	if(mImagePriority < 1.0f)
+	if(mImagePriority < F_ALMOST_ZERO)
 	{
 		if (mState == INIT || mState == LOAD_FROM_NETWORK || mState == LOAD_FROM_SIMULATOR)
 		{
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 9b3243a1bc5..7a0f77a7e46 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1489,59 +1489,63 @@ void LLViewerFetchedTexture::setKnownDrawSize(S32 width, S32 height)
 //virtual
 void LLViewerFetchedTexture::processTextureStats()
 {
-	if(mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0) //force to refetch the texture.
-	{
-		mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel) ;
-	}
-
 	if(mFullyLoaded)
 	{		
-		if(mDesiredDiscardLevel <= mMinDesiredDiscardLevel)//already loaded
+		if(mDesiredDiscardLevel > mMinDesiredDiscardLevel)//need to load more
 		{
-			return ;
+			mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel) ;
+			mFullyLoaded = FALSE ;
 		}
-		mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel) ;
-		mFullyLoaded = FALSE ;
-		return ;
-	}
-
-	updateVirtualSize() ;
-	
-	static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes");
-	
-	if (textures_fullres)
-	{
-		mDesiredDiscardLevel = 0;
-	}
-	else if(!mFullWidth || !mFullHeight)
-	{
-		mDesiredDiscardLevel = 	getMaxDiscardLevel() ;
 	}
 	else
-	{	
-		if(!mKnownDrawWidth || !mKnownDrawHeight || mFullWidth <= mKnownDrawWidth || mFullHeight <= mKnownDrawHeight)
+	{
+		updateVirtualSize() ;
+		
+		static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes");
+		
+		if (textures_fullres)
 		{
-			if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
+			mDesiredDiscardLevel = 0;
+		}
+		else if(!mFullWidth || !mFullHeight)
+		{
+			mDesiredDiscardLevel = 	getMaxDiscardLevel() ;
+		}
+		else
+		{	
+			if(!mKnownDrawWidth || !mKnownDrawHeight || mFullWidth <= mKnownDrawWidth || mFullHeight <= mKnownDrawHeight)
 			{
-				mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048
+				if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
+				{
+					mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048
+				}
+				else
+				{
+					mDesiredDiscardLevel = 0;
+				}
 			}
-			else
+			else if(mKnownDrawSizeChanged)//known draw size is set
+			{			
+				mDesiredDiscardLevel = (S8)llmin(log((F32)mFullWidth / mKnownDrawWidth) / log_2, 
+													 log((F32)mFullHeight / mKnownDrawHeight) / log_2) ;
+				mDesiredDiscardLevel = 	llclamp(mDesiredDiscardLevel, (S8)0, (S8)getMaxDiscardLevel()) ;
+				mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel) ;
+			}
+			mKnownDrawSizeChanged = FALSE ;
+		
+			if(getDiscardLevel() >= 0 && (getDiscardLevel() <= mDesiredDiscardLevel))
 			{
-				mDesiredDiscardLevel = 0;
+				mFullyLoaded = TRUE ;
 			}
 		}
-		else if(mKnownDrawSizeChanged)//known draw size is set
-		{			
-			mDesiredDiscardLevel = (S8)llmin(log((F32)mFullWidth / mKnownDrawWidth) / log_2, 
-					                             log((F32)mFullHeight / mKnownDrawHeight) / log_2) ;
-			mDesiredDiscardLevel = 	llclamp(mDesiredDiscardLevel, (S8)0, (S8)getMaxDiscardLevel()) ;
-			mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, mMinDesiredDiscardLevel) ;
-		}
-		mKnownDrawSizeChanged = FALSE ;
-		
-		if(getDiscardLevel() >= 0 && (getDiscardLevel() <= mDesiredDiscardLevel))
+	}
+
+	if(mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0) //force to refetch the texture.
+	{
+		mDesiredDiscardLevel = llmin(mDesiredDiscardLevel, (S8)mDesiredSavedRawDiscardLevel) ;
+		if(getDiscardLevel() < 0 || getDiscardLevel() > mDesiredDiscardLevel)
 		{
-			mFullyLoaded = TRUE ;
+			mFullyLoaded = FALSE ;
 		}
 	}
 }
@@ -1724,6 +1728,11 @@ void LLViewerFetchedTexture::setDecodePriority(F32 priority)
 	llassert(!mInImageList); 
     
 	mDecodePriority = priority;
+
+	if(mDecodePriority < F_ALMOST_ZERO)
+	{
+		mStopFetchingTimer.reset() ;
+	}
 }
 
 void LLViewerFetchedTexture::setAdditionalDecodePriority(F32 priority)
@@ -1915,7 +1924,12 @@ bool LLViewerFetchedTexture::updateFetch()
 // 				llinfos << "Calling updateRequestPriority() with decode_priority = 0.0f" << llendl;
 // 				calcDecodePriority();
 // 			}
-			LLAppViewer::getTextureFetch()->updateRequestPriority(mID, decode_priority);
+			static const F32 MAX_HOLD_TIME = 5.0f ; //seconds to wait before canceling fecthing if decode_priority is 0.f.
+			if(decode_priority > 0.0f || mStopFetchingTimer.getElapsedTimeF32() > MAX_HOLD_TIME)
+			{
+				mStopFetchingTimer.reset() ;
+				LLAppViewer::getTextureFetch()->updateRequestPriority(mID, decode_priority);
+			}
 		}
 	}
 
@@ -2075,6 +2089,36 @@ void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_call
 	}
 }
 
+void LLViewerFetchedTexture::clearCallbackEntryList()
+{
+	if(mLoadedCallbackList.empty())
+	{
+		return ;
+	}
+
+	for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
+			iter != mLoadedCallbackList.end(); )
+	{
+		LLLoadedCallbackEntry *entryp = *iter;
+			
+		// 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);
+		iter = mLoadedCallbackList.erase(iter) ;
+		delete entryp;
+	}
+	gTextureList.mCallbackList.erase(this);
+		
+	mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1;
+	mLoadedCallbackDesiredDiscardLevel = S8_MAX ;
+	if(mForceToSaveRawImage)
+	{
+		destroySavedRawImage() ;
+	}
+
+	return ;
+}
+
 void LLViewerFetchedTexture::deleteCallbackEntry(const LLLoadedCallbackEntry::source_callback_list_t* callback_list)
 {
 	if(mLoadedCallbackList.empty() || !callback_list)
@@ -2082,7 +2126,7 @@ void LLViewerFetchedTexture::deleteCallbackEntry(const LLLoadedCallbackEntry::so
 		return ;
 	}
 
-	S32 desired_discard = INVALID_DISCARD_LEVEL ;
+	S32 desired_discard = S8_MAX ;
 	S32 desired_raw_discard = INVALID_DISCARD_LEVEL ;
 	for(callback_list_t::iterator iter = mLoadedCallbackList.begin();
 			iter != mLoadedCallbackList.end(); )
@@ -2652,6 +2696,12 @@ void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard, bool from_
 }
 void LLViewerFetchedTexture::destroySavedRawImage()
 {
+	clearCallbackEntryList() ;
+	//if(mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0 && mDesiredSavedRawDiscardLevel < getDiscardLevel())
+	//{
+	//	return ; //can not destroy the saved raw image before it is fully fetched, otherwise causing callbacks hanging there.
+	//}
+
 	mSavedRawImage = NULL ;
 	mForceToSaveRawImage  = FALSE ;
 	mSavedRawDiscardLevel = -1 ;
@@ -2902,7 +2952,7 @@ BOOL LLViewerLODTexture::isUpdateFrozen()
 void LLViewerLODTexture::processTextureStats()
 {
 	updateVirtualSize() ;
-
+	
 	static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes");
 	
 	if (textures_fullres)
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 1f0d760daf6..6adfd2bae41 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -392,6 +392,7 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	void unpauseLoadedCallbacks(const LLLoadedCallbackEntry::source_callback_list_t* callback_list);
 	bool doLoadedCallbacks();
 	void deleteCallbackEntry(const LLLoadedCallbackEntry::source_callback_list_t* callback_list);
+	void clearCallbackEntryList() ;
 
 	void addToCreateTexture();
 
@@ -562,6 +563,7 @@ class LLViewerFetchedTexture : public LLViewerTexture
 
 	// Timers
 	LLFrameTimer mLastPacketTimer;		// Time since last packet.
+	LLFrameTimer mStopFetchingTimer;	// Time since mDecodePriority == 0.f.
 
 	BOOL  mInImageList;				// TRUE if image is in list (in which case don't reset priority!)
 	BOOL  mNeedsCreateTexture;	
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index bddde08ca98..338b3155cc4 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1067,7 +1067,7 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view
 	// Should just be the last object added
 	if (attachment->isObjectAttached(viewer_object))
 	{
-		const LLUUID& attachment_id = viewer_object->getItemID();
+		const LLUUID& attachment_id = viewer_object->getAttachmentItemID();
 		LLAppearanceMgr::instance().registerAttachment(attachment_id);
 	}
 
@@ -1077,7 +1077,7 @@ const LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *view
 //virtual
 BOOL LLVOAvatarSelf::detachObject(LLViewerObject *viewer_object)
 {
-	const LLUUID attachment_id = viewer_object->getItemID();
+	const LLUUID attachment_id = viewer_object->getAttachmentItemID();
 	if (LLVOAvatar::detachObject(viewer_object))
 	{
 		// the simulator should automatically handle permission revocation
@@ -1625,15 +1625,15 @@ void LLVOAvatarSelf::setLocalTexture(ETextureIndex type, LLViewerTexture* src_te
 					if (isSelf())
 					{
 						if (gAgentAvatarp->isUsingBakedTextures())
-					{
-						requestLayerSetUpdate(type);
-					}
+						{
+							requestLayerSetUpdate(type);
+						}
 						else
-					{
-						LLVisualParamHint::requestHintUpdates();
+						{
+							LLVisualParamHint::requestHintUpdates();
+						}
 					}
 				}
-				}
 				else
 				{					
 					tex->setLoadedCallback(onLocalTextureLoaded, desired_discard, TRUE, FALSE, new LLAvatarTexData(getID(), type), NULL);
@@ -2145,6 +2145,11 @@ void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid )
 
 void LLVOAvatarSelf::outputRezDiagnostics() const
 {
+	if(!gSavedSettings.getBOOL("DebugAvatarLocalTexLoadedTime"))
+	{
+		return ;
+	}
+
 	const F32 final_time = mDebugSelfLoadTimer.getElapsedTimeF32();
 	llinfos << "REZTIME: Myself rez stats:" << llendl;
 	llinfos << "\t Time from avatar creation to load wearables: " << (S32)mDebugTimeWearablesLoaded << llendl;
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index 0efe6682be6..9c08c0eec11 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -448,22 +448,35 @@ void LLVOTree::render(LLAgent &agent)
 
 void LLVOTree::setPixelAreaAndAngle(LLAgent &agent)
 {
-	// First calculate values as for any other object (for mAppAngle)
-	LLViewerObject::setPixelAreaAndAngle(agent);
-
-	// Re-calculate mPixelArea accurately
+	LLVector3 center = getPositionAgent();//center of tree.
+	LLVector3 viewer_pos_agent = gAgentCamera.getCameraPositionAgent();
+	LLVector3 lookAt = center - viewer_pos_agent;
+	F32 dist = lookAt.normVec() ;	
+	F32 cos_angle_to_view_dir = lookAt * LLViewerCamera::getInstance()->getXAxis() ;	
 	
-	// This should be the camera's center, as soon as we move to all region-local.
-	LLVector3 relative_position = getPositionAgent() - gAgentCamera.getCameraPositionAgent();
-	F32 range_squared = relative_position.lengthSquared() ;				
+	F32 range = dist - getMinScale()/2;
+	if (range < F_ALMOST_ZERO || isHUDAttachment())		// range == zero
+	{
+		mAppAngle = 180.f;
+	}
+	else
+	{
+		mAppAngle = (F32) atan2( getMaxScale(), range) * RAD_TO_DEG;		
+	}
 
 	F32 max_scale = mBillboardScale * getMaxScale();
 	F32 area = max_scale * (max_scale*mBillboardRatio);
-
 	// Compute pixels per meter at the given range
-	F32 pixels_per_meter = LLViewerCamera::getInstance()->getViewHeightInPixels() / tan(LLViewerCamera::getInstance()->getView());
+	F32 pixels_per_meter = LLViewerCamera::getInstance()->getViewHeightInPixels() / (tan(LLViewerCamera::getInstance()->getView()) * dist);
+	mPixelArea = pixels_per_meter * pixels_per_meter * area ;	
+
+	F32 importance = LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist) ;
+	mPixelArea = LLFace::adjustPixelArea(importance, mPixelArea) ;
+	if (mPixelArea > LLViewerCamera::getInstance()->getScreenPixelArea())
+	{
+		mAppAngle = 180.f;
+	}
 
-	mPixelArea = (pixels_per_meter) * (pixels_per_meter) * area / range_squared;
 #if 0
 	// mAppAngle is a bit of voodoo;
 	// use the one calculated LLViewerObject::setPixelAreaAndAngle above
diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp
index c5042ca0165..1209b60679f 100644
--- a/indra/newview/llwearable.cpp
+++ b/indra/newview/llwearable.cpp
@@ -52,6 +52,7 @@
 #include "llvoavatarself.h"
 #include "llvoavatardefines.h"
 #include "llwearable.h"
+#include "llviewercontrol.h"
 
 using namespace LLVOAvatarDefines;
 
@@ -444,8 +445,10 @@ BOOL LLWearable::importFile( LLFILE* file )
 			delete mSavedTEMap[te];
 		}
 
-		image->setLoadedCallback(LLVOAvatarSelf::debugOnTimingLocalTexLoaded,0,TRUE,FALSE, new LLVOAvatarSelf::LLAvatarTexData(id, (LLVOAvatarDefines::ETextureIndex)te), NULL);
-
+		if(gSavedSettings.getBOOL("DebugAvatarLocalTexLoadedTime"))
+		{
+			image->setLoadedCallback(LLVOAvatarSelf::debugOnTimingLocalTexLoaded,0,TRUE,FALSE, new LLVOAvatarSelf::LLAvatarTexData(id, (LLVOAvatarDefines::ETextureIndex)te), NULL);
+		}
 		LLUUID textureid(text_buffer);
 		mTEMap[te] = new LLLocalTextureObject(image, textureid);
 		mSavedTEMap[te] = new LLLocalTextureObject(image, textureid);
-- 
GitLab