Skip to content

Commit

Permalink
Improved VRAM detection and Override capability
Browse files Browse the repository at this point in the history
Mostly for windows.
Deprecate WMI (which is a 32-bit interface and cannot return >4GB)
Add DXGI query support in its place
Allow fallback to Driver queries (already used in Linux)
All platforms
Allow override (vis prefs_>graphics->hardware)
includes a warning.
Change the estimation of available VRAM to respect the new detection/override
  • Loading branch information
beqjanus committed May 10, 2024
1 parent f866408 commit ff64dc7
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 78 deletions.
66 changes: 36 additions & 30 deletions indra/llrender/llgl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1182,8 +1182,10 @@ bool LLGLManager::initGL()
// This is called here because it depends on the setting of mIsGF2or4MX, and sets up mHasMultitexture.
initExtensions();

S32 old_vram = mVRAM;
mVRAM = 0;
// <FS:Beq> stop doing this and trust the hardware detection
// if hardware detection has all failed the this will correct for that
// S32 old_vram = mVRAM;
// mVRAM = 0;

#if LL_WINDOWS
if (mHasAMDAssociations)
Expand Down Expand Up @@ -1216,22 +1218,26 @@ bool LLGLManager::initGL()
}
#endif

#if LL_WINDOWS
if (mVRAM < 256)
{
// Something likely went wrong using the above extensions
// try WMI first and fall back to old method (from dxdiag) if all else fails
// Function will check all GPUs WMI knows of and will pick up the one with most
// memory. We need to check all GPUs because system can switch active GPU to
// weaker one, to preserve power when not under load.
S32 mem = LLDXHardware::getMBVideoMemoryViaWMI();
if (mem != 0)
{
mVRAM = mem;
LL_WARNS("RenderInit") << "VRAM Detected (WMI):" << mVRAM<< LL_ENDL;
}
}
#endif
// <FS:Beq> remove this so that we can attempt to use driver specifics
// if it fails we will pick up the `old_vram` value , which is either WMI or the combined dxdiag number
// both of which are rather useless, but it does at least respect the disable_wmi setting.
// #if LL_WINDOWS
// if (mVRAM < 256)
// {
// // Something likely went wrong using the above extensions
// // try WMI first and fall back to old method (from dxdiag) if all else fails
// // Function will check all GPUs WMI knows of and will pick up the one with most
// // memory. We need to check all GPUs because system can switch active GPU to
// // weaker one, to preserve power when not under load.
// S32 mem = LLDXHardware::getMBVideoMemoryViaWMI();
// if (mem != 0)
// {
// mVRAM = mem;
// LL_WARNS("RenderInit") << "VRAM Detected (WMI):" << mVRAM<< LL_ENDL;
// }
// }
// #endif
// </FS:Beq>

// Ultimate fallbacks for linux and mesa
if (mHasNVXMemInfo && mVRAM == 0)
Expand All @@ -1250,18 +1256,18 @@ bool LLGLManager::initGL()
mVRAM = meminfo[0] / 1024;
LL_INFOS("RenderInit") << "VRAM Detected (ATIMemInfo):" << mVRAM << LL_ENDL;
}

if (mVRAM < 256 && old_vram > 0)
{
// fall back to old method
// Note: on Windows value will be from LLDXHardware.
// Either received via dxdiag or via WMI by id from dxdiag.
mVRAM = old_vram;

// <FS:Ansariel> VRAM detection logging
LL_WARNS("RenderInit") << "VRAM detected via MemInfo OpenGL extension most likely broken. Reverting to " << mVRAM << " MB" << LL_ENDL;
}

// <FS:Beq> stop doing this and trust the hardware detection
// if (mVRAM < 256 && old_vram > 0)
// {
// // fall back to old method
// // Note: on Windows value will be from LLDXHardware.
// // Either received via dxdiag or via WMI by id from dxdiag.
// mVRAM = old_vram;

// // <FS:Ansariel> VRAM detection logging
// LL_WARNS("RenderInit") << "VRAM detected via MemInfo OpenGL extension most likely broken. Reverting to " << mVRAM << " MB" << LL_ENDL;
// }
// </FS:Beq>
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &mNumTextureImageUnits);
glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &mMaxColorTextureSamples);
glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &mMaxDepthTextureSamples);
Expand Down
41 changes: 41 additions & 0 deletions indra/llwindow/lldxhardware.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <boost/tokenizer.hpp>

#include "lldxhardware.h"
#include <dxgi.h>

#include "llerror.h"

Expand All @@ -61,6 +62,42 @@ typedef BOOL ( WINAPI* PfnCoSetProxyBlanket )( IUnknown* pProxy, DWORD dwAuthnSv
OLECHAR* pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel,
RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities );

// <FS:Beq> Deprecate WMI support
uint64_t GetVideoMemoryViaDXGI()
{
HRESULT hr;
IDXGIFactory* pFactory = nullptr;
IDXGIAdapter* pAdapter = nullptr;

// Create a DXGI Factory
hr = CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&pFactory);
if (FAILED(hr)) {
std::cerr << "Failed to create DXGI factory." << std::endl;
return 0;
}

// Enumerate adapters
UINT i = 0;
uint64_t vram_bytes = 0;
while (pFactory->EnumAdapters(i, &pAdapter) != DXGI_ERROR_NOT_FOUND)
{
if(pAdapter)
{
DXGI_ADAPTER_DESC desc;
pAdapter->GetDesc(&desc);

vram_bytes = desc.DedicatedVideoMemory;
break;
}
SAFE_RELEASE(pAdapter);
++i;
}
SAFE_RELEASE(pAdapter)
SAFE_RELEASE(pFactory)
return vram_bytes;
}
// </FS:Beq>

HRESULT GetVideoMemoryViaWMI(WCHAR* strInputDeviceID, DWORD* pdwAdapterRam)
{
HRESULT hr;
Expand Down Expand Up @@ -803,6 +840,10 @@ BOOL LLDXHardware::getInfo(BOOL vram_only, bool disable_wmi)
LL_INFOS("AppInit") << "VRAM Detected via WMI: " << mVRAM << LL_ENDL;
}
}
// <FS:Beq> Deprecate WMI use DXGI in preference.
mVRAM = GetVideoMemoryViaDXGI()/1024/1024;
LL_INFOS("AppInit") << "VRAM Detected via DXGI: " << mVRAM << "MB" << LL_ENDL;
// </FS:Beq>

if (mVRAM == 0)
{ // Get the English VRAM string
Expand Down
35 changes: 21 additions & 14 deletions indra/llwindow/llwindowwin32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4905,8 +4905,12 @@ void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage()
info.CurrentUsage = 0;
#endif

U32 budget_mb = info.Budget / 1024 / 1024;
gGLManager.mVRAM = llmax(gGLManager.mVRAM, (S32) budget_mb);
// <FS:Beq> Let's not override the detected values here.
// U32 budget_mb = info.Budget / 1024 / 1024;
// instead we clamp budget to detected values
// gGLManager.mVRAM = llmax(gGLManager.mVRAM, (S32) budget_mb);
U32 budget_mb = gGLManager.mVRAM;
// </FS:Beq>

U32 afr_mb = info.AvailableForReservation / 1024 / 1024;
// correct for systems that misreport budget
Expand All @@ -4932,21 +4936,24 @@ void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage()
}
U32 target_mb = budget_mb;

if (target_mb > 4096) // if 4GB are installed, try to leave 2GB free
{
target_mb -= 2048;
}
else // if less than 4GB are installed, try not to use more than half of it
{
target_mb /= 2;
}

mAvailableVRAM = cu_mb < target_mb ? target_mb - cu_mb : 0;

// <FS:Beq> Let's not override the detected values here.
// Stop playing nice and just let the OS and drivers deal with it.
// if (target_mb > 4096) // if 4GB are installed, try to leave 2GB free
// {
// target_mb -= 2048;
// }
// else // if less than 4GB are installed, try not to use more than half of it
// {
// target_mb /= 2;
// }

// mAvailableVRAM = cu_mb < target_mb ? target_mb - cu_mb : 0;
mAvailableVRAM = eu_mb < target_mb ? target_mb - cu_mb : 0;
// </FS:Beq>
#if 1

F32 eu_error = (F32)((S32)eu_mb - (S32)cu_mb) / (F32)cu_mb;
LL_INFOS("Window") << "\nLocal\nAFR: " << info.AvailableForReservation / 1024 / 1024
LL_DEBUGS("Window") << "\nLocal\nAFR: " << info.AvailableForReservation / 1024 / 1024
<< "\nBudget: " << info.Budget / 1024 / 1024
<< "\nCR: " << info.CurrentReservation / 1024 / 1024
<< "\nCU: " << info.CurrentUsage / 1024 / 1024
Expand Down
13 changes: 12 additions & 1 deletion indra/newview/app_settings/settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24567,12 +24567,23 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>1</integer>
</map>
<key>FSOverrideVRAMDetection</key>
<map>
<key>Comment</key>
<string>Allow user to override the vRAM detection, use the FSForcedVideoMemory setting instead- use with extreme caution.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSForcedVideoMemory</key>
<map>
<key>Comment</key>
<string>Overrides the video memory detection on Windows if a value greater 0 is passed (in case DirectX memory detection fails or is wrong)</string>
<key>Persist</key>
<integer>0</integer>
<integer>1</integer>
<key>HideFromEditor</key>
<integer>1</integer>
<key>Type</key>
Expand Down
15 changes: 9 additions & 6 deletions indra/newview/llappviewerwin32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1027,15 +1027,18 @@ bool LLAppViewerWin32::initHardwareTest()

if (gGLManager.mVRAM == 0)
{
// <FS:Ansariel> FIRE-12671: Force VRAM if DirectX detection is broken
S32 forced_video_memory;
if ((forced_video_memory = gSavedSettings.getS32("FSForcedVideoMemory")) > 0)
// <FS:Beq> Allow the user to override the VRAM detection
if ( gSavedSettings.getBOOL("FSOverrideVRAMDetection") )
{
LL_INFOS("AppInit") << "Forcing VRAM to " << forced_video_memory << " MB" << LL_ENDL;
gGLManager.mVRAM = forced_video_memory;
S32 forced_video_memory = gSavedSettings.getS32("FSForcedVideoMemory");
if ( forced_video_memory > 0 )
{
LL_INFOS("AppInit") << "Forcing VRAM to " << forced_video_memory*1024 << " MB" << LL_ENDL;
gGLManager.mVRAM = forced_video_memory*1024;
}
}
else
// </FS:Ansariel>
// </FS:Beq>
gGLManager.mVRAM = gDXHardware.getVRAM();
}

Expand Down
2 changes: 1 addition & 1 deletion indra/newview/lltextureview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ void LLGLTexMemBar::draw()
U32 texFetchLatMed = U32(recording.getMean(LLTextureFetch::sTexFetchLatency).value() * 1000.0f);
U32 texFetchLatMax = U32(recording.getMax(LLTextureFetch::sTexFetchLatency).value() * 1000.0f);

text = llformat("GL Free: %d MB Sys Free: %d MB GL Tex: %d MB FBO: %d MB Bias: %.2f Cache: %.1f/%.1f MB",
text = llformat("est. VRAM Free: %d MB Sys Free: %d MB GL Tex: %d MB FBO: %d MB Bias: %.2f Cache: %.1f/%.1f MB",
gViewerWindow->getWindow()->getAvailableVRAMMegabytes(),
LLMemory::getAvailableMemKB()/1024,
LLImageGL::getTextureBytesAllocated() / 1024 / 1024,
Expand Down
11 changes: 11 additions & 0 deletions indra/newview/llviewercontrol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,16 @@ static bool handleVolumeLODChanged(const LLSD& newvalue)

return true;
}
// <FS:Beq> Override VRAM detection support
static bool handleOverrideVRAMDetectionChanged(const LLSD& newvalue)
{
if (newvalue.asBoolean())
{
LLNotificationsUtil::add("OverrideVRAMWarning");
}
return true;
}
// </FS:Beq>

static bool handleAvatarLODChanged(const LLSD& newvalue)
{
Expand Down Expand Up @@ -1169,6 +1179,7 @@ void settings_setup_listeners()
setting_setup_signal_listener(gSavedSettings, "RenderGlowHDR", handleReleaseGLBufferChanged);
setting_setup_signal_listener(gSavedSettings, "RenderGlowNoise", handleSetShaderChanged);
setting_setup_signal_listener(gSavedSettings, "RenderGammaFull", handleSetShaderChanged);
setting_setup_signal_listener(gSavedSettings, "FSOverrideVRAMDetection", handleOverrideVRAMDetectionChanged); // <FS:Beq/> Override VRAM detection support
setting_setup_signal_listener(gSavedSettings, "RenderVolumeLODFactor", handleVolumeLODChanged);
setting_setup_signal_listener(gSavedSettings, "RenderAvatarLODFactor", handleAvatarLODChanged);
setting_setup_signal_listener(gSavedSettings, "RenderAvatarPhysicsLODFactor", handleAvatarPhysicsLODChanged);
Expand Down
26 changes: 0 additions & 26 deletions indra/newview/llviewerwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2091,32 +2091,6 @@ LLViewerWindow::LLViewerWindow(const Params& p)
gSavedSettings.setU32("RenderQualityPerformance", 0);
}

// <FS:Ansariel> Texture memory management
// On 64bit builds, allow up to 1GB texture memory on cards with 2GB video
// memory and up to 2GB texture memory on cards with 4GB video memory. Check
// is performed against a lower limit as not exactly 2 or 4GB might not be
// returned.
#if ADDRESS_SIZE == 64
LL_INFOS() << "GLManager detected " << gGLManager.mVRAM << " MB VRAM" << LL_ENDL;

if (gGLManager.mVRAM > 3584)
{
gMaxVideoRam = S32Megabytes(2048);
LL_INFOS() << "At least 4 GB video memory detected - increasing max video ram for textures to 2048 MB" << LL_ENDL;
}
else if (gGLManager.mVRAM > 1536)
{
gMaxVideoRam = S32Megabytes(1024);
LL_INFOS() << "At least 2 GB video memory detected - increasing max video ram for textures to 1024 MB" << LL_ENDL;
}
else if (gGLManager.mVRAM > 768)
{
gMaxVideoRam = S32Megabytes(768);
LL_INFOS() << "At least 1 GB video memory detected - increasing max video ram for textures to 768 MB" << LL_ENDL;
}
#endif
// </FS:Ansariel>

// <FS:Ansariel> Max texture resolution
#if ADDRESS_SIZE == 64
if (gSavedSettings.getBOOL("FSRestrictMaxTextureSize"))
Expand Down
15 changes: 15 additions & 0 deletions indra/newview/skins/default/xui/en/notifications.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13872,6 +13872,21 @@ LOD Factor >8: Has no real effect. May cause errors.
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alert.tga"
name="OverrideVRAMWarning"
type="alert">
WARNING: Overriding the VRAM detection may cause instability.

Most users should leave this setting disabled and let the viewer and
operating system determine the correct value.

This setting is intended for cases where VRAM detection is reporting
incorrect values. Use with caution, seek support advice in case of doubt.
<usetemplate
name="okbutton"
yestext="OK"/>
</notification>
<notification
icon="alertmodal.tga"
name="CurrencyURIOverrideReceived"
Expand Down
47 changes: 47 additions & 0 deletions indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,53 @@
name="16x"
value="16" />
</combo_box>

<text
type="string"
length="1"
follows="left|top"
height="12"
layout="topleft"
left="10"
name="advanced_settings"
top_pad="10"
width="308">
Advanced Settings (restart required):
</text>

<check_box
control_name="FSOverrideVRAMDetection"
height="16"
label="Override VRAM detection"
layout="topleft"
left="10"
top_pad="10"
name="FSDynamicTextureMemory"
tool_tip="Enable the user to override VRAM detection (use with extreme caution)"
width="315"
/>
<slider
control_name="FSForcedVideoMemory"
enabled_control="FSOverrideVRAMDetection"
decimal_digits="0"
follows="left|top"
height="20"
increment="1"
initial_value="2"
label="GPU Dedicated VRAM (GB):"
label_width="275"
layout="topleft"
left="10"
min_val="0"
max_val="32"
name="FSForcedVideoMemory"
tool_tip="Important: use with extreme caution.
Override the detected VRAM on your GPU.
This must not include 'shared' VRAM which is part of the system RAM.
If you do not understand the distinction then leave this control alone."
top_pad="5"
width="475"
/>
</panel>

<!--Rendering-->
Expand Down

0 comments on commit ff64dc7

Please sign in to comment.