From dea5450d789cb876856db8fc0159e1df34009c19 Mon Sep 17 00:00:00 2001
From: andreykproductengine <andreykproductengine@lindenlab.com>
Date: Tue, 20 Nov 2018 19:47:00 +0200
Subject: SL-4730 Prevent viewer from getting more texture details when low on
 memory

---
 indra/newview/llviewertexture.cpp | 129 +++++++++++++++++++++-----------------
 indra/newview/llviewertexture.h   |   7 ++-
 2 files changed, 78 insertions(+), 58 deletions(-)

diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index d2157f33cf..db3adcec2b 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -100,7 +100,7 @@ const S32 MAX_CACHED_RAW_TERRAIN_IMAGE_AREA = 128 * 128;
 const S32 DEFAULT_ICON_DIMENTIONS = 32;
 S32 LLViewerTexture::sMinLargeImageSize = 65536; //256 * 256.
 S32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA;
-BOOL LLViewerTexture::sFreezeImageScalingDown = FALSE;
+bool LLViewerTexture::sFreezeImageUpdates = false;
 F32 LLViewerTexture::sCurrentTime = 0.0f;
 F32  LLViewerTexture::sTexelPixelRatio = 1.0f;
 
@@ -484,53 +484,68 @@ static LLTrace::BlockTimerStatHandle FTM_TEXTURE_MEMORY_CHECK("Memory Check");
 //static 
 bool LLViewerTexture::isMemoryForTextureLow()
 {
-	static LLFrameTimer timer;
-	static bool low_mem = false;
+    // Note: we need to figure out a better source for 'min' values,
+    // what is free for low end at minimal settings is 'nothing left'
+    // for higher end gpus at high settings.
+    const S32Megabytes MIN_FREE_TEXTURE_MEMORY(20);
+    const S32Megabytes MIN_FREE_MAIN_MEMORY(100);
 
-	if(timer.getElapsedTimeF32() < GPU_MEMORY_CHECK_WAIT_TIME) //call this once per second.
-	{
-		return low_mem;
-	}
-	timer.reset();
+    S32Megabytes gpu;
+    S32Megabytes physical;
+    getGPUMemoryForTextures(gpu, physical);
 
-	LL_RECORD_BLOCK_TIME(FTM_TEXTURE_MEMORY_CHECK);
+    return (gpu < MIN_FREE_TEXTURE_MEMORY) || (physical < MIN_FREE_MAIN_MEMORY);
+}
 
-	const S32Megabytes MIN_FREE_TEXTURE_MEMORY(20); //MB Changed to 20 MB per MAINT-6882
-	const S32Megabytes MIN_FREE_MAIN_MEMORY(100); //MB	
+//static
+bool LLViewerTexture::isMemoryForTextureSuficientlyFree()
+{
+    const S32Megabytes DESIRED_FREE_TEXTURE_MEMORY(50);
+    const S32Megabytes DESIRED_FREE_MAIN_MEMORY(200);
 
-	low_mem = false;
-	if (gGLManager.mHasATIMemInfo)
-	{
-		S32 meminfo[4];
-		glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
+    S32Megabytes gpu;
+    S32Megabytes physical;
+    getGPUMemoryForTextures(gpu, physical);
 
-		if((S32Megabytes)meminfo[0] < MIN_FREE_TEXTURE_MEMORY)
-		{
-			low_mem = true;
-		}
+    return (gpu > DESIRED_FREE_TEXTURE_MEMORY) && (physical > DESIRED_FREE_MAIN_MEMORY);
+}
 
-		if(!low_mem) //check main memory, only works for windows.
-		{
-			LLMemory::updateMemoryInfo();
-			if(LLMemory::getAvailableMemKB() < MIN_FREE_TEXTURE_MEMORY)
-			{
-				low_mem = true;
-			}
-		}
-	}
-	//Enabled this branch per MAINT-6882
-	else if (gGLManager.mHasNVXMemInfo)
-	{
-		S32 free_memory;
-		glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory);
-		
-		if ((S32Megabytes)(free_memory / 1024) < MIN_FREE_TEXTURE_MEMORY)
-		{
-			low_mem = true;
-		}
-	}
+//static
+void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical)
+{
+    static LLFrameTimer timer;
+    static S32Megabytes gpu_res = S32Megabytes(S32_MAX);
+    static S32Megabytes physical_res = S32Megabytes(S32_MAX);
+
+    if (timer.getElapsedTimeF32() < GPU_MEMORY_CHECK_WAIT_TIME) //call this once per second.
+    {
+        gpu = gpu_res;
+        physical = physical_res;
+        return;
+    }
+    timer.reset();
+
+    LL_RECORD_BLOCK_TIME(FTM_TEXTURE_MEMORY_CHECK);
+
+    if (gGLManager.mHasATIMemInfo)
+    {
+        S32 meminfo[4];
+        glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
+        gpu_res = (S32Megabytes)meminfo[0];
+
+        //check main memory, only works for windows.
+        LLMemory::updateMemoryInfo();
+        physical_res = LLMemory::getAvailableMemKB();
+    }
+    else if (gGLManager.mHasNVXMemInfo)
+    {
+        S32 free_memory;
+        glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory);
+        gpu_res = (S32Megabytes)(free_memory / 1024);
+    }
 
-	return low_mem;
+    gpu = gpu_res;
+    physical = physical_res;
 }
 
 static LLTrace::BlockTimerStatHandle FTM_TEXTURE_UPDATE_MEDIA("Media");
@@ -575,17 +590,18 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity
 	}
 	else if(isMemoryForTextureLow())
 	{
-		// Note: isMemoryForTextureLow() uses 1s delay, make sure we waited enough for it to restore
+		// Note: isMemoryForTextureLow() uses 1s delay, make sure we waited enough for it to recheck
 		if (sEvaluationTimer.getElapsedTimeF32() > GPU_MEMORY_CHECK_WAIT_TIME)
 		{
 			sDesiredDiscardBias += discard_bias_delta;
 			sEvaluationTimer.reset();
 		}
 	}
-	else if (sDesiredDiscardBias > 0.0f &&
-			 sBoundTextureMemory < sMaxBoundTextureMemory * texmem_lower_bound_scale &&
-			 sTotalTextureMemory < sMaxTotalTextureMem * texmem_lower_bound_scale)
-	{			 
+	else if (sDesiredDiscardBias > 0.0f
+			 && sBoundTextureMemory < sMaxBoundTextureMemory * texmem_lower_bound_scale
+			 && sTotalTextureMemory < sMaxTotalTextureMem * texmem_lower_bound_scale
+			 && isMemoryForTextureSuficientlyFree())
+	{
 		// If we are using less texture memory than we should,
 		// scale down the desired discard level
 		if (sEvaluationTimer.getElapsedTimeF32() > discard_delta_time)
@@ -595,14 +611,8 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity
 		}
 	}
 	sDesiredDiscardBias = llclamp(sDesiredDiscardBias, desired_discard_bias_min, desired_discard_bias_max);
-	
-	F32 camera_moving_speed = LLViewerCamera::getInstance()->getAverageSpeed();
-	F32 camera_angular_speed = LLViewerCamera::getInstance()->getAverageAngularSpeed();
-	sCameraMovingBias = llmax(0.2f * camera_moving_speed, 2.0f * camera_angular_speed - 1);
-	sCameraMovingDiscardBias = (S8)(sCameraMovingBias);
 
-	LLViewerTexture::sFreezeImageScalingDown = (sBoundTextureMemory < 0.75f * sMaxBoundTextureMemory * texmem_middle_bound_scale) &&
-				(sTotalTextureMemory < 0.75f * sMaxTotalTextureMem * texmem_middle_bound_scale);
+	LLViewerTexture::sFreezeImageUpdates = sDesiredDiscardBias > (desired_discard_bias_max - 1.0f);
 }
 
 //end of static functions
@@ -3126,9 +3136,9 @@ S8 LLViewerLODTexture::getType() const
 	return LLViewerTexture::LOD_TEXTURE;
 }
 
-BOOL LLViewerLODTexture::isUpdateFrozen()
+bool LLViewerLODTexture::isUpdateFrozen()
 {
-	return LLViewerTexture::sFreezeImageScalingDown && !getDiscardLevel();
+	return LLViewerTexture::sFreezeImageUpdates;
 }
 
 // This is gauranteed to get called periodically for every texture
@@ -3254,9 +3264,16 @@ void LLViewerLODTexture::processTextureStats()
 				(!getBoundRecently() || mDesiredDiscardLevel >= mCachedRawDiscardLevel))
 			{
 				scaleDown();
-				
 			}
 		}
+
+		if (isUpdateFrozen() // we are out of memory and nearing max allowed bias
+			&& mBoostLevel < LLGLTexture::BOOST_SCULPTED
+			&& mDesiredDiscardLevel < current_discard)
+		{
+			// stop requesting more
+			mDesiredDiscardLevel = current_discard;
+		}
 	}
 
 	if(mForceToSaveRawImage && mDesiredSavedRawDiscardLevel >= 0)
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 5d89f9f029..7cbcc931b1 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -186,6 +186,9 @@ private:
 	virtual void switchToCachedImage();
 	
 	static bool isMemoryForTextureLow() ;
+	static bool isMemoryForTextureSuficientlyFree();
+	static void getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical);
+
 protected:
 	LLUUID mID;
 	S32 mTextureListType; // along with mID identifies where to search for this texture in TextureList
@@ -227,7 +230,7 @@ public:
 	static S32 sMaxSculptRez ;
 	static S32 sMinLargeImageSize ;
 	static S32 sMaxSmallImageSize ;
-	static BOOL sFreezeImageScalingDown ;//do not scale down image res if set.
+	static bool sFreezeImageUpdates;
 	static F32  sCurrentTime ;
 
 	enum EDebugTexels
@@ -543,7 +546,7 @@ public:
 	/*virtual*/ S8 getType() const;
 	// Process image stats to determine priority/quality requirements.
 	/*virtual*/ void processTextureStats();
-	BOOL isUpdateFrozen() ;
+	bool isUpdateFrozen() ;
 
 private:
 	void init(bool firstinit) ;
-- 
cgit v1.2.3