diff options
-rw-r--r-- | indra/llrender/llgl.cpp | 83 | ||||
-rw-r--r-- | indra/llrender/llgl.h | 1 | ||||
-rw-r--r-- | indra/llrender/llglheaders.h | 2 | ||||
-rw-r--r-- | indra/llwindow/lldxhardware.cpp | 70 | ||||
-rw-r--r-- | indra/llwindow/lldxhardware.h | 4 | ||||
-rw-r--r-- | indra/newview/llviewertexturelist.cpp | 7 |
6 files changed, 144 insertions, 23 deletions
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index c0f0cec80b..bcc702d31f 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -49,6 +49,10 @@ #include "llglheaders.h" #include "llglslshader.h" +#if LL_WINDOWS +#include "lldxhardware.h" +#endif + #ifdef _DEBUG //#define GL_STATE_VERIFY #endif @@ -394,6 +398,8 @@ PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB = NULL; PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL; #if LL_WINDOWS +PFNWGLGETGPUIDSAMDPROC wglGetGPUIDsAMD = NULL; +PFNWGLGETGPUINFOAMDPROC wglGetGPUInfoAMD = NULL; PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL; #endif @@ -413,6 +419,7 @@ LLGLManager::LLGLManager() : mHasMultitexture(FALSE), mHasATIMemInfo(FALSE), + mHasAMDAssociations(FALSE), mHasNVXMemInfo(FALSE), mNumTextureUnits(1), mHasMipMapGeneration(FALSE), @@ -497,7 +504,16 @@ void LLGLManager::initWGL() { LL_WARNS("RenderInit") << "No ARB create context extensions" << LL_ENDL; } - + + // For retreiving information per AMD adapter, + // because we can't trust curently selected/default one when there are multiple + mHasAMDAssociations = ExtensionExists("WGL_AMD_gpu_association", gGLHExts.mSysExts); + if (mHasAMDAssociations) + { + GLH_EXT_NAME(wglGetGPUIDsAMD) = (PFNWGLGETGPUIDSAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUIDsAMD"); + GLH_EXT_NAME(wglGetGPUInfoAMD) = (PFNWGLGETGPUINFOAMDPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetGPUInfoAMD"); + } + if (ExtensionExists("WGL_EXT_swap_control", gGLHExts.mSysExts)) { GLH_EXT_NAME(wglSwapIntervalEXT) = (PFNWGLSWAPINTERVALEXTPROC)GLH_EXT_GET_PROC_ADDRESS("wglSwapIntervalEXT"); @@ -683,23 +699,78 @@ bool LLGLManager::initGL() stop_glerror(); S32 old_vram = mVRAM; + mVRAM = 0; - if (mHasATIMemInfo) +#if LL_WINDOWS + if (mHasAMDAssociations) + { + GLuint gl_gpus_count = wglGetGPUIDsAMD(0, 0); + if (gl_gpus_count > 0) + { + GLuint* ids = new GLuint[gl_gpus_count]; + wglGetGPUIDsAMD(gl_gpus_count, ids); + + GLuint mem_mb = 0; + for (U32 i = 0; i < gl_gpus_count; i++) + { + wglGetGPUInfoAMD(ids[i], + WGL_GPU_RAM_AMD, + GL_UNSIGNED_INT, + sizeof(GLuint), + &mem_mb); + if (mVRAM < mem_mb) + { + // basically pick the best AMD and trust driver/OS to know to switch + mVRAM = mem_mb; + } + } + } + if (mVRAM != 0) + { + LL_WARNS("RenderInit") << "VRAM Detected (AMDAssociations):" << mVRAM << LL_ENDL; + } + } +#endif + + if (mHasATIMemInfo && mVRAM == 0) { //ask the gl how much vram is free at startup and attempt to use no more than half of that S32 meminfo[4]; glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); - mVRAM = meminfo[0]/1024; + mVRAM = meminfo[0] / 1024; + LL_WARNS("RenderInit") << "VRAM Detected (ATIMemInfo):" << mVRAM << LL_ENDL; } - else if (mHasNVXMemInfo) + + if (mHasNVXMemInfo && mVRAM == 0) { S32 dedicated_memory; glGetIntegerv(GL_GPU_MEMORY_INFO_DEDICATED_VIDMEM_NVX, &dedicated_memory); mVRAM = dedicated_memory/1024; + LL_WARNS("RenderInit") << "VRAM Detected (NVXMemInfo):" << mVRAM << LL_ENDL; } +#if LL_WINDOWS if (mVRAM < 256) - { //something likely went wrong using the above extensions, fall back to old method + { + // 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 + + 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; } @@ -961,7 +1032,7 @@ void LLGLManager::initExtensions() mHasTextureRectangle = FALSE; #else // LL_MESA_HEADLESS //important, gGLHExts.mSysExts is uninitialized until after glh_init_extensions is called mHasMultitexture = glh_init_extensions("GL_ARB_multitexture"); - mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); + mHasATIMemInfo = ExtensionExists("GL_ATI_meminfo", gGLHExts.mSysExts); //Basic AMD method, also see mHasAMDAssociations mHasNVXMemInfo = ExtensionExists("GL_NVX_gpu_memory_info", gGLHExts.mSysExts); mHasSeparateSpecularColor = glh_init_extensions("GL_EXT_separate_specular_color"); mHasAnisotropic = glh_init_extensions("GL_EXT_texture_filter_anisotropic"); diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 4c4302d05b..6db1fe9c90 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -78,6 +78,7 @@ public: // Extensions used by everyone BOOL mHasMultitexture; BOOL mHasATIMemInfo; + BOOL mHasAMDAssociations; BOOL mHasNVXMemInfo; S32 mNumTextureUnits; BOOL mHasMipMapGeneration; diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index 722dd9050b..36fbb381bb 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -618,6 +618,8 @@ extern PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI; extern PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI; extern PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI; +extern PFNWGLGETGPUIDSAMDPROC wglGetGPUIDsAMD; +extern PFNWGLGETGPUINFOAMDPROC wglGetGPUInfoAMD; extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; // GL_ARB_occlusion_query diff --git a/indra/llwindow/lldxhardware.cpp b/indra/llwindow/lldxhardware.cpp index 9397b831f7..12a6baa3e6 100644 --- a/indra/llwindow/lldxhardware.cpp +++ b/indra/llwindow/lldxhardware.cpp @@ -61,7 +61,7 @@ typedef BOOL ( WINAPI* PfnCoSetProxyBlanket )( IUnknown* pProxy, DWORD dwAuthnSv OLECHAR* pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel, RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities ); -HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam ) +HRESULT GetVideoMemoryViaWMI(WCHAR* strInputDeviceID, DWORD* pdwAdapterRam) { HRESULT hr; bool bGotMemory = false; @@ -149,21 +149,26 @@ HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam ) if ( !pVideoControllers[iController] ) continue; - pPropName = SysAllocString( L"PNPDeviceID" ); - hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr ); + // if strInputDeviceID is set find this specific device and return memory or specific device + // if strInputDeviceID is not set return the best device + if (strInputDeviceID) + { + pPropName = SysAllocString( L"PNPDeviceID" ); + hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr ); #ifdef PRINTF_DEBUGGING - if( FAILED( hr ) ) - wprintf( L"WMI: pVideoControllers[iController]->Get PNPDeviceID failed: 0x%0.8x\n", hr ); + if( FAILED( hr ) ) + wprintf( L"WMI: pVideoControllers[iController]->Get PNPDeviceID failed: 0x%0.8x\n", hr ); #endif - if( SUCCEEDED( hr ) ) - { - if( wcsstr( var.bstrVal, strInputDeviceID ) != 0 ) - bFound = true; + if( SUCCEEDED( hr ) && strInputDeviceID) + { + if( wcsstr( var.bstrVal, strInputDeviceID ) != 0 ) + bFound = true; + } + VariantClear( &var ); + if( pPropName ) SysFreeString( pPropName ); } - VariantClear( &var ); - if( pPropName ) SysFreeString( pPropName ); - if( bFound ) + if( bFound || !strInputDeviceID ) { pPropName = SysAllocString( L"AdapterRAM" ); hr = pVideoControllers[iController]->Get( pPropName, 0L, &var, nullptr, nullptr ); @@ -175,13 +180,18 @@ HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam ) if( SUCCEEDED( hr ) ) { bGotMemory = true; - *pdwAdapterRam = var.ulVal; + *pdwAdapterRam = llmax(var.ulVal, *pdwAdapterRam); } VariantClear( &var ); if( pPropName ) SysFreeString( pPropName ); - break; } + SAFE_RELEASE( pVideoControllers[iController] ); + + if (bFound) + { + break; + } } } } @@ -207,6 +217,17 @@ HRESULT GetVideoMemoryViaWMI( WCHAR* strInputDeviceID, DWORD* pdwAdapterRam ) return E_FAIL; } +//static +S32 LLDXHardware::getMBVideoMemoryViaWMI() +{ + DWORD vram = 0; + if (SUCCEEDED(GetVideoMemoryViaWMI(NULL, &vram))) + { + return vram / (1024 * 1024);; + } + return 0; +} + //Getting the version of graphics controller driver via WMI std::string LLDXHardware::getDriverVersionWMI() { @@ -615,6 +636,8 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) IDxDiagContainer *driver_containerp = NULL; DWORD dw_device_count; + mVRAM = 0; + // CoCreate a IDxDiagProvider* LL_DEBUGS("AppInit") << "CoCreateInstance IID_IDxDiagProvider" << LL_ENDL; hr = CoCreateInstance(CLSID_DxDiagProvider, @@ -677,6 +700,8 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) } // Get device 0 + // By default 0 device is the primary one, howhever in case of various hybrid graphics + // like itegrated AMD and PCI AMD GPUs system might switch. LL_DEBUGS("AppInit") << "devices_containerp->GetChildContainer" << LL_ENDL; hr = devices_containerp->GetChildContainer(L"0", &device_containerp); if(FAILED(hr) || !device_containerp) @@ -689,12 +714,27 @@ BOOL LLDXHardware::getInfo(BOOL vram_only) WCHAR deviceID[512]; get_wstring(device_containerp, L"szDeviceID", deviceID, 512); - + // Example: searches id like 1F06 in pnp string (aka VEN_10DE&DEV_1F06) + // doesn't seem to work on some systems since format is unrecognizable + // but in such case keyDeviceID works if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID, &vram))) { mVRAM = vram/(1024*1024); } else + { + get_wstring(device_containerp, L"szKeyDeviceID", deviceID, 512); + LL_WARNS() << "szDeviceID" << deviceID << LL_ENDL; + // '+9' to avoid ENUM\\PCI\\ prefix + // Returns string like Enum\\PCI\\VEN_10DE&DEV_1F06&SUBSYS... + // and since GetVideoMemoryViaWMI searches by PNPDeviceID it is sufficient + if (SUCCEEDED(GetVideoMemoryViaWMI(deviceID + 9, &vram))) + { + mVRAM = vram / (1024 * 1024); + } + } + + if (mVRAM == 0) { // Get the English VRAM string std::string ram_str = get_string(device_containerp, L"szDisplayMemoryEnglish"); diff --git a/indra/llwindow/lldxhardware.h b/indra/llwindow/lldxhardware.h index cf33db8b37..1cb687e3b6 100644 --- a/indra/llwindow/lldxhardware.h +++ b/indra/llwindow/lldxhardware.h @@ -94,6 +94,10 @@ public: LLSD getDisplayInfo(); + // Will get memory of best GPU in MB, return memory on sucsess, 0 on failure + // Note: WMI is not accurate in some cases + static S32 getMBVideoMemoryViaWMI(); + // Find a particular device that matches the following specs. // Empty strings indicate that you don't care. // You can separate multiple devices with '|' chars to indicate you want diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 06524847d1..561319ca5d 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1385,8 +1385,6 @@ S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, fl { max_texmem = (S32Megabytes)128; } - - LL_WARNS() << "VRAM amount not detected, defaulting to " << max_texmem << " MB" << LL_ENDL; } S32Megabytes system_ram = gSysMemory.getPhysicalMemoryKB(); // In MB @@ -1428,6 +1426,11 @@ void LLViewerTextureList::updateMaxResidentTexMem(S32Megabytes mem) return; //listener will re-enter this function } + if (gGLManager.mVRAM == 0) + { + LL_WARNS() << "VRAM amount not detected, defaulting to " << mem << " MB" << LL_ENDL; + } + // TODO: set available resident texture mem based on use by other subsystems // currently max(12MB, VRAM/4) assumed... |