summaryrefslogtreecommitdiff
path: root/indra/newview/llfeaturemanager.cpp
diff options
context:
space:
mode:
authorErik Kundiman <erik@megapahit.org>2026-09-01 18:35:23 +0800
committerErik Kundiman <erik@megapahit.org>2026-09-04 21:58:53 +0800
commit00bb3bb6f07660bd914d29a1389342bb3060d254 (patch)
tree431f574922494d2201718f13085f17bc6bd7fb42 /indra/newview/llfeaturemanager.cpp
parenta8636720129952c10cf49ab80da21bf8b340b96c (diff)
parent4ef9f8f14b35ed388c294d53767a0dca0e890924 (diff)
Merge remote-tracking branch 'secondlife/release/26.4' into 26.4
Diffstat (limited to 'indra/newview/llfeaturemanager.cpp')
-rw-r--r--indra/newview/llfeaturemanager.cpp126
1 files changed, 120 insertions, 6 deletions
diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp
index 68443dfc5b..45d173f356 100644
--- a/indra/newview/llfeaturemanager.cpp
+++ b/indra/newview/llfeaturemanager.cpp
@@ -259,7 +259,6 @@ bool LLFeatureManager::loadFeatureTables()
// *TODO - if I or anyone else adds something else to the skipped list
// make this data driven. Put it in the feature table and parse it
// correctly
- mSkippedFeatures.insert("RenderAnisotropic");
mSkippedFeatures.insert("RenderGamma");
mSkippedFeatures.insert("RenderVBOEnable");
mSkippedFeatures.insert("RenderFogRatio");
@@ -378,6 +377,83 @@ F32 gpu_benchmark();
#if LL_WINDOWS
+bool gGPUBenchmarkMode = false;
+
+// Runs gpu_benchmark() in a subprocess (exe with --gpubenchmark).
+static F32 subprocess_gpu_benchmark()
+{
+ LLProcess::Params params;
+ params.executable = gDirUtilp->getExecutablePathAndName();
+ params.args.add("--gpubenchmark");
+ params.desc = "GPU benchmark";
+ params.autokill = true; // killed via job object if parent crashes
+ params.attached = true; // killed on LLProcessPtr destruction (timeout)
+ params.files.add(LLProcess::FileParam()); // stdin: default
+ params.files.add(LLProcess::FileParam().type("pipe")); // stdout: pipe
+ params.files.add(LLProcess::FileParam()); // stderr: default
+
+ LLProcessPtr child;
+ try
+ {
+ child = LLProcess::create(params);
+ }
+ catch (const std::exception& e)
+ {
+ LL_WARNS("RenderInit") << "subprocess_gpu_benchmark: failed to launch: "
+ << e.what() << LL_ENDL;
+ return -1.f;
+ }
+
+ if (!child)
+ {
+ LL_WARNS("RenderInit") << "subprocess_gpu_benchmark: LLProcess::create returned null." << LL_ENDL;
+ return -1.f;
+ }
+
+ LLProcess::ReadPipe& out = child->getReadPipe(LLProcess::STDOUT);
+
+ const F32 POLL_INTERVAL_S = 0.25f;
+ const F32 TOTAL_TIMEOUT_S = 120.f; // covers full viewer init + benchmark
+ LLTimer timer;
+ timer.start();
+
+ while (timer.getElapsedTimeF32() < TOTAL_TIMEOUT_S)
+ {
+ child->pump();
+
+ // Result is a single float followed by '\n'
+ if (out.contains('\n'))
+ {
+ std::string line = out.getline();
+ float parsed = 0.f;
+ if (sscanf_s(line.c_str(), "%f", &parsed) == 1 && parsed > 0.f)
+ {
+ LL_INFOS("RenderInit") << "subprocess_gpu_benchmark: result = "
+ << parsed << " GB/sec" << LL_ENDL;
+ // Let LLProcessPtr destructor handle cleanup
+ return parsed;
+ }
+ LL_WARNS("RenderInit") << "subprocess_gpu_benchmark: unparseable output: '"
+ << line << "'" << LL_ENDL;
+ return -1.f;
+ }
+
+ // If child already exited without writing anything, bail
+ if (!child->isRunning())
+ {
+ LL_WARNS("RenderInit") << "subprocess_gpu_benchmark: process exited without result." << LL_ENDL;
+ return -1.f;
+ }
+
+ ms_sleep((U32)(POLL_INTERVAL_S * 1000));
+ }
+
+ // Timeout: attached=true means LLProcessPtr destructor kills it
+ LL_WARNS("RenderInit") << "GPU benchmark subprocess timed out after "
+ << (int)TOTAL_TIMEOUT_S << " seconds; killing." << LL_ENDL;
+ return -1.f;
+}
+
F32 logExceptionBenchmark()
{
// FIXME: gpu_benchmark uses many C++ classes on the stack to control state.
@@ -458,7 +534,27 @@ bool LLFeatureManager::loadGPUClass()
try
{
#if LL_WINDOWS
- gbps = logExceptionBenchmark();
+ if (gGPUBenchmarkMode)
+ {
+ // We ARE the benchmark subprocess; run directly in-process.
+ // logExceptionBenchmark wraps with SEH so structured exceptions
+ // (e.g. access violations inside the driver) are still caught.
+ gbps = logExceptionBenchmark();
+ }
+ else
+ {
+ // Normal path: run benchmark in an isolated subprocess so a
+ // driver hang can be killed without freezing the main viewer.
+ gbps = subprocess_gpu_benchmark();
+ if (gbps == -1.f
+ && gGLManager.getRawGLString().find("Radeon") != std::string::npos
+ && checkRDNA35())
+ {
+ // Certain AMD GPUs have known issues with shader profiling and occlusion queries that can lead to hangs.
+ // If test returned -1, we are likely on a bad driver.
+ gSavedSettings.setBOOL("UseOcclusion", false);
+ }
+ }
#else
gbps = gpu_benchmark();
#endif
@@ -469,6 +565,21 @@ bool LLFeatureManager::loadGPUClass()
LL_WARNS("RenderInit") << "GPU benchmark failed: " << e.what() << LL_ENDL;
}
+#if LL_WINDOWS
+ // If we are the benchmark subprocess, write the raw result to stdout
+ // so the parent process can read it, then exit immediately.
+ if (gGPUBenchmarkMode)
+ {
+ LL_WARNS("RenderInit") << "Passing " << gbps << " to parent" << LL_ENDL;
+ char buf[64];
+ int len = snprintf(buf, sizeof(buf), "%.6f\n", gbps);
+ DWORD written = 0;
+ WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, (DWORD)len, &written, NULL);
+ FlushFileBuffers(GetStdHandle(STD_OUTPUT_HANDLE));
+ ExitProcess(0);
+ }
+#endif
+
mGPUMemoryBandwidth = gbps;
// bias by CPU speed
@@ -510,17 +621,16 @@ bool LLFeatureManager::loadGPUClass()
mGPUClass = GPU_CLASS_5;
}
- #if LL_WINDOWS
- const F32Gigabytes MIN_PHYSICAL_MEMORY(8);
-
LLMemory::updateMemoryInfo();
+ #if LL_WINDOWS || LL_LINUX
+ const F32Gigabytes MIN_PHYSICAL_MEMORY(8);
F32Gigabytes physical_mem = LLMemory::getMaxMemKB();
if (MIN_PHYSICAL_MEMORY > physical_mem && mGPUClass > GPU_CLASS_1)
{
// reduce quality on systems that don't have enough memory
mGPUClass = (EGPUClass)(mGPUClass - 1);
}
- #endif //LL_WINDOWS
+ #endif //LL_WINDOWS || LL_LINUX
} //end if benchmark
else
{
@@ -756,6 +866,10 @@ void LLFeatureManager::applyBaseMasks()
{
maskFeatures("VRAMLT2GB");
}
+ if (!gGLManager.mHasAnisotropic || 2.f > gGLManager.mMaxAnisotropy)
+ {
+ maskFeatures("AnisotropicMissing");
+ }
if (gGLManager.mGLVersion < 3.99f)
{
maskFeatures("GL3");