From b5db671f7c28eb2a9f9974df1c34cf8c025fb8cc Mon Sep 17 00:00:00 2001
From: Dave Parks <davep@lindenlab.com>
Date: Tue, 29 Nov 2022 09:15:02 -0600
Subject: [PATCH] SL-18682 WIP -- Add debug settings that aid in emulating low
 end hardware.

---
 indra/llwindow/llwindow.cpp             |  7 ++--
 indra/llwindow/llwindow.h               |  5 ++-
 indra/llwindow/llwindowwin32.cpp        | 45 ++++++++++++++++++++++---
 indra/llwindow/llwindowwin32.h          |  4 ++-
 indra/newview/app_settings/settings.xml | 33 ++++++++++++++++++
 indra/newview/llviewerobjectlist.cpp    |  3 +-
 indra/newview/llviewerwindow.cpp        | 10 +++++-
 7 files changed, 96 insertions(+), 11 deletions(-)

diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp
index f4678a70c5b..66be3efffce 100644
--- a/indra/llwindow/llwindow.cpp
+++ b/indra/llwindow/llwindow.cpp
@@ -406,7 +406,10 @@ LLWindow* LLWindowManager::createWindow(
 	BOOL enable_vsync,
 	BOOL use_gl,
 	BOOL ignore_pixel_depth,
-	U32 fsaa_samples)
+	U32 fsaa_samples,
+    U32 max_cores,
+    U32 max_vram,
+    F32 max_gl_version)
 {
 	LLWindow* new_window;
 
@@ -423,7 +426,7 @@ LLWindow* LLWindowManager::createWindow(
 #elif LL_WINDOWS
 		new_window = new LLWindowWin32(callbacks,
 			title, name, x, y, width, height, flags, 
-			fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples);
+			fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples, max_cores, max_vram, max_gl_version);
 #elif LL_DARWIN
 		new_window = new LLWindowMacOSX(callbacks,
 			title, name, x, y, width, height, flags, 
diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h
index 2c538a60c96..862897a48c9 100644
--- a/indra/llwindow/llwindow.h
+++ b/indra/llwindow/llwindow.h
@@ -302,7 +302,10 @@ class LLWindowManager
 		BOOL enable_vsync = FALSE,
 		BOOL use_gl = TRUE,
 		BOOL ignore_pixel_depth = FALSE,
-		U32 fsaa_samples = 0);
+		U32 fsaa_samples = 0,
+        U32 max_cores = 0,
+        U32 max_vram = 0,
+        F32 max_gl_version = 4.6f);
 	static BOOL destroyWindow(LLWindow* window);
 	static BOOL isWindowValid(LLWindow *window);
 };
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 950043dff2f..c0d34241417 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -418,6 +418,8 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
     // best guess at available video memory in MB
     std::atomic<U32> mAvailableVRAM;
 
+    U32 mMaxVRAM = 0; // maximum amount of vram to allow in the "budget", or 0 for no maximum (see updateVRAMUsage)
+
     IDXGIAdapter3* mDXGIAdapter = nullptr;
     LPDIRECT3D9 mD3D = nullptr;
     LPDIRECT3DDEVICE9 mD3DDevice = nullptr;
@@ -430,13 +432,36 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks,
 							 BOOL fullscreen, BOOL clearBg,
 							 BOOL enable_vsync, BOOL use_gl,
 							 BOOL ignore_pixel_depth,
-							 U32 fsaa_samples)
-	: LLWindow(callbacks, fullscreen, flags)
+							 U32 fsaa_samples,
+                             U32 max_cores,
+                             U32 max_vram,
+                             F32 max_gl_version)
+	: 
+    LLWindow(callbacks, fullscreen, flags), 
+    mMaxGLVersion(max_gl_version), 
+    mMaxCores(max_cores)
 {
     sMainThreadId = LLThread::currentID();
     mWindowThread = new LLWindowWin32Thread();
+    mWindowThread->mMaxVRAM = max_vram;
+
 	//MAINT-516 -- force a load of opengl32.dll just in case windows went sideways 
 	LoadLibrary(L"opengl32.dll");
+    
+    
+    if (mMaxCores != 0)
+    {
+        HANDLE hProcess = GetCurrentProcess();
+        mMaxCores = llmin(mMaxCores, (U32) 64);
+        DWORD_PTR mask = 0;
+
+        for (int i = 0; i < mMaxCores; ++i)
+        {
+            mask |= ((DWORD_PTR) 1) << i;
+        }
+
+        SetProcessAffinityMask(hProcess, mask);
+    }
 
 #if 0 // this is probably a bad idea, but keep it in your back pocket if you see what looks like
         // process deprioritization during profiles
@@ -1833,10 +1858,15 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw
 
 void* LLWindowWin32::createSharedContext()
 {
+    mMaxGLVersion = llclamp(mMaxGLVersion, 3.2f, 4.6f);
+
+    S32 version_major = llfloor(mMaxGLVersion);
+    S32 version_minor = llround((mMaxGLVersion-version_major)*10);
+
     S32 attribs[] =
     {
-        WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
-        WGL_CONTEXT_MINOR_VERSION_ARB, 6,
+        WGL_CONTEXT_MAJOR_VERSION_ARB, version_major,
+        WGL_CONTEXT_MINOR_VERSION_ARB, version_minor,
         WGL_CONTEXT_PROFILE_MASK_ARB,  LLRender::sGLCoreProfile ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
         WGL_CONTEXT_FLAGS_ARB, gDebugGL ? WGL_CONTEXT_DEBUG_BIT_ARB : 0,
         0
@@ -4815,6 +4845,11 @@ void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage()
             budget_mb = llclamp(afr_mb, (U32) 512, (U32) 2048);
         }
 
+        if ( mMaxVRAM != 0)
+        {
+            budget_mb = llmin(budget_mb, mMaxVRAM);
+        }
+
         U32 cu_mb = info.CurrentUsage / 1024 / 1024;
 
         // get an estimated usage based on texture bytes allocated
@@ -4826,7 +4861,7 @@ void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage()
         }
         F32 eu_error = (F32)((S32)eu_mb - (S32)cu_mb) / (F32)cu_mb;
 
-        U32 target_mb = info.Budget / 1024 / 1024;
+        U32 target_mb = budget_mb;
 
         if (target_mb > 4096)  // if 4GB are installed, try to leave 2GB free 
         {
diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h
index bd53b3e92ad..ff287a140e7 100644
--- a/indra/llwindow/llwindowwin32.h
+++ b/indra/llwindow/llwindowwin32.h
@@ -139,7 +139,7 @@ class LLWindowWin32 : public LLWindow
 	LLWindowWin32(LLWindowCallbacks* callbacks,
 		const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, 
 		BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl,
-		BOOL ignore_pixel_depth, U32 fsaa_samples);
+		BOOL ignore_pixel_depth, U32 fsaa_samples, U32 max_cores, U32 max_vram, F32 max_gl_version);
 	~LLWindowWin32();
 
 	void	initCursors();
@@ -210,6 +210,8 @@ class LLWindowWin32 : public LLWindow
 
 	F32			mCurrentGamma;
 	U32			mFSAASamples;
+    U32         mMaxCores; // for debugging only -- maximum number of CPU cores to use, or 0 for no limit
+    F32         mMaxGLVersion; // maximum OpenGL version to attempt to use (clamps to 3.2 - 4.6)
 	WORD		mPrevGammaRamp[3][256];
 	WORD		mCurrentGammaRamp[3][256];
 	BOOL		mCustomGammaSet;
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 9f10e5cac58..8c96ccd1074 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9221,6 +9221,28 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+  <key>RenderMaxOpenGLVersion</key>
+  <map>
+    <key>Comment</key>
+    <string>Maximum OpenGL version to attempt use (minimum 3.2 maximum 4.6).  Requires restart.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>4.6</real>
+  </map>
+  <key>RenderMaxVRAMBudget</key>
+  <map>
+    <key>Comment</key>
+    <string>Maximum amount of texture memory to budget for, or 0 for autodetect.  Requires restart.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
   <key>RenderMaxTextureIndex</key>
   <map>
     <key>Comment</key>
@@ -16901,5 +16923,16 @@
     <key>Value</key>
     <string></string>
   </map>
+  <key>EmulateCoreCount</key>
+  <map>
+    <key>Comment</key>
+    <string>For debugging -- number of cores to restrict the main process to, or 0 for no limit.  Requires restart.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
 </map>
 </llsd>
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 955979e6054..dc0785f9901 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -789,7 +789,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
 		max_value = llmin((S32) mObjects.size(), mCurLazyUpdateIndex + num_updates);
 	}
 
-
+#if 0
 	// Slam priorities for textures that we care about (hovered, selected, and focused)
 	// Hovered
 	// Assumes only one level deep of parenting
@@ -820,6 +820,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
 		}
 	} func;
 	LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func);
+#endif
 
 	// Iterate through some of the objects and lazy update their texture priorities
 	for (i = mCurLazyUpdateIndex; i < max_value; i++)
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 88058d11373..5bbb18ed30f 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1878,6 +1878,11 @@ LLViewerWindow::LLViewerWindow(const Params& p)
 	U32 fsaa_samples)
 	*/
 	// create window
+
+    U32 max_core_count = gSavedSettings.getU32("EmulateCoreCount");
+    U32 max_vram = gSavedSettings.getU32("RenderMaxVRAMBudget");
+    F32 max_gl_version = gSavedSettings.getF32("RenderMaxOpenGLVersion");
+    
 	mWindow = LLWindowManager::createWindow(this,
 		p.title, p.name, p.x, p.y, p.width, p.height, 0,
 		p.fullscreen, 
@@ -1885,7 +1890,10 @@ LLViewerWindow::LLViewerWindow(const Params& p)
 		gSavedSettings.getBOOL("RenderVSyncEnable"),
 		!gHeadlessClient,
 		p.ignore_pixel_depth,
-		0); //don't use window level anti-aliasing
+		0,
+        max_core_count,
+        max_vram,
+        max_gl_version); //don't use window level anti-aliasing
 
 	if (NULL == mWindow)
 	{
-- 
GitLab