From 47ee4aff475e5086bc532acf1b79a86adcb70d73 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Tue, 9 Aug 2022 11:34:09 -0700 Subject: [PATCH 1/4] SL-17005: Fix crash in initDX when no factory --- indra/llwindow/llwindowwin32.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 20443988ab..6e5c1e504a 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -4619,7 +4619,10 @@ void LLWindowWin32::LLWindowWin32Thread::initDX() } } - pFactory->Release(); + if (pFactory) + { + pFactory->Release(); + } } } From eac4540fc359b1390c8828f92c5ba75d44fd1308 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Tue, 9 Aug 2022 11:48:51 -0700 Subject: [PATCH 2/4] SL-17005: (WIP) (DEBUG) Add logging for graphics adapters --- indra/llwindow/llwindowwin32.cpp | 67 ++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 6e5c1e504a..9e7ea15cd7 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -4598,10 +4598,77 @@ private: std::string mPrev; }; +// Print hardware debug info about available graphics adapters in ordinal order +void debugEnumerateGraphicsAdapters() +{ + LL_INFOS("Window") << "Enumerating graphics adapters..." << LL_ENDL; + + IDXGIFactory1* factory; + HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory); + if (FAILED(res) || !factory) + { + LL_WARNS() << "CreateDXGIFactory1 failed: 0x" << std::hex << res << LL_ENDL; + } + else + { + UINT graphics_adapter_index = 0; + IDXGIAdapter3* dxgi_adapter; + while (true) + { + res = factory->EnumAdapters(graphics_adapter_index, reinterpret_cast(&dxgi_adapter)); + if (FAILED(res)) + { + if (graphics_adapter_index == 0) + { + LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL; + } + else + { + LL_INFOS("Window") << "Done enumerating graphics adapters" << LL_ENDL; + } + } + else + { + DXGI_ADAPTER_DESC desc; + dxgi_adapter->GetDesc(&desc); + std::wstring description_w((wchar_t*)desc.Description); + std::string description(description_w.begin(), description_w.end()); + LL_INFOS("Window") << "Graphics adapter index: " << graphics_adapter_index << ", " + << "Description: " << description << ", " + << "DeviceId: " << desc.DeviceId << ", " + << "SubSysId: " << desc.SubSysId << ", " + << "AdapterLuid: " << desc.AdapterLuid.HighPart << "_" << desc.AdapterLuid.LowPart << ", " + << "DedicatedVideoMemory: " << desc.DedicatedVideoMemory / 1024 / 1024 << ", " + << "DedicatedSystemMemory: " << desc.DedicatedSystemMemory / 1024 / 1024 << ", " + << "SharedSystemMemory: " << desc.SharedSystemMemory / 1024 / 1024 << LL_ENDL; + } + + if (dxgi_adapter) + { + dxgi_adapter->Release(); + dxgi_adapter = NULL; + } + else + { + break; + } + + graphics_adapter_index++; + } + } + + if (factory) + { + factory->Release(); + } +} + void LLWindowWin32::LLWindowWin32Thread::initDX() { if (mDXGIAdapter == NULL) { + debugEnumerateGraphicsAdapters(); + IDXGIFactory4* pFactory = nullptr; HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&pFactory); From c790bf7f49328b479f1bcbfe0268ca0bec6e2376 Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Thu, 11 Aug 2022 11:10:25 -0700 Subject: [PATCH 3/4] SL-17005: (WIP) (Debug) Add logging and debug settings to assist in understanding Windows 8 failure modes. Most of this should be removed later --- indra/llwindow/llwindowwin32.cpp | 32 ++++++++++++++++++++++--- indra/newview/app_settings/settings.xml | 23 ++++++++++++++++++ indra/newview/pipeline.cpp | 4 ++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 9e7ea15cd7..9e2e07102e 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -48,6 +48,8 @@ #include "llthreadsafequeue.h" #include "stringize.h" #include "llframetimer.h" +#include "commoncontrol.h" // TODO: Remove after testing +#include "llsd.h" // TODO: Remove after testing // System includes #include @@ -416,7 +418,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool std::atomic mAvailableVRAM; + bool mTryUseDXGIAdapter; // TODO: Remove after testing IDXGIAdapter3* mDXGIAdapter = nullptr; + bool mTryUseD3DDevice; // TODO: Remove after testing LPDIRECT3D9 mD3D = nullptr; LPDIRECT3DDEVICE9 mD3DDevice = nullptr; }; @@ -4549,6 +4553,14 @@ U32 LLWindowWin32::getAvailableVRAMMegabytes() inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE) { + const LLSD skipDXGI{ LL::CommonControl::get("Global", "DisablePrimaryGraphicsMemoryAccounting") }; // TODO: Remove after testing + LL_WARNS() << "DisablePrimaryGraphicsMemoryAccounting: " << skipDXGI << ", as boolean: " << skipDXGI.asBoolean() << LL_ENDL; + mTryUseDXGIAdapter = !skipDXGI.asBoolean(); + LL_WARNS() << "mTryUseDXGIAdapter: " << mTryUseDXGIAdapter << LL_ENDL; + const LLSD skipD3D{ LL::CommonControl::get("Global", "DisableSecondaryGraphicsMemoryAccounting") }; // TODO: Remove after testing + LL_WARNS() << "DisableSecondaryGraphicsMemoryAccounting: " << skipD3D << ", as boolean: " << skipD3D.asBoolean() << LL_ENDL; + mTryUseD3DDevice = !skipD3D.asBoolean(); + LL_WARNS() << "mTryUseD3DDevice: " << mTryUseD3DDevice << LL_ENDL; ThreadPool::start(); } @@ -4665,7 +4677,7 @@ void debugEnumerateGraphicsAdapters() void LLWindowWin32::LLWindowWin32Thread::initDX() { - if (mDXGIAdapter == NULL) + if (mDXGIAdapter == NULL && mTryUseDXGIAdapter) { debugEnumerateGraphicsAdapters(); @@ -4684,6 +4696,10 @@ void LLWindowWin32::LLWindowWin32Thread::initDX() { LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL; } + else + { + LL_INFOS() << "EnumAdapters success" << LL_ENDL; + } } if (pFactory) @@ -4695,7 +4711,7 @@ void LLWindowWin32::LLWindowWin32Thread::initDX() void LLWindowWin32::LLWindowWin32Thread::initD3D() { - if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandle != 0) + if (mDXGIAdapter == NULL && mD3DDevice == NULL && mTryUseD3DDevice && mWindowHandle != 0) { mD3D = Direct3DCreate9(D3D_SDK_VERSION); @@ -4705,7 +4721,16 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D() d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; - mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice); + HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice); + + if (FAILED(res)) + { + LL_WARNS() << "(fallback) CreateDevice failed: 0x" << std::hex << res << LL_ENDL; + } + else + { + LL_INFOS() << "(fallback) CreateDevice success" << LL_ENDL; + } } } @@ -4768,6 +4793,7 @@ void LLWindowWin32::LLWindowWin32Thread::run() if (mWindowHandle != 0) { // lazily call initD3D inside this loop to catch when mWindowHandle has been set + // *TODO: Shutdown if this fails when mWindowHandle exists initD3D(); MSG msg; diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index bc4945eca5..afa8217af2 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3387,6 +3387,29 @@ Value 0 + + DisablePrimaryGraphicsMemoryAccounting + + Comment + Disable the first method used to detect GPU memory use + Persist + 1 + Type + Boolean + Value + 0 + + DisableSecondaryGraphicsMemoryAccounting + + Comment + Disable the second method used to detect GPU memory use, used as a fallback when the first method fails + Persist + 1 + Type + Boolean + Value + 0 + DisableTextHyperlinkActions Comment diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 9ec3418132..d4e667bcc6 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -434,6 +434,7 @@ void LLPipeline::connectRefreshCachedSettingsSafe(const std::string name) void LLPipeline::init() { + LL_WARNS() << "Begin pipeline initialization" << LL_ENDL; // TODO: Remove after testing refreshCachedSettings(); gOctreeMaxCapacity = gSavedSettings.getU32("OctreeMaxNodeCapacity"); @@ -450,6 +451,7 @@ void LLPipeline::init() mInitialized = true; stop_glerror(); + LL_WARNS() << "No GL errors yet. Pipeline initialization will continue." << LL_ENDL; // TODO: Remove after testing //create render pass pools getPool(LLDrawPool::POOL_ALPHA); @@ -510,7 +512,9 @@ void LLPipeline::init() // Enable features + LL_WARNS() << "Shader initialization start" << LL_ENDL; // TODO: Remove after testing LLViewerShaderMgr::instance()->setShaders(); + LL_WARNS() << "Shader initialization end" << LL_ENDL; // TODO: Remove after testing stop_glerror(); From 9bee2a92d2eb1f48f8ca0061e546c5e9df38fe79 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Fri, 26 Aug 2022 10:51:42 -0500 Subject: [PATCH 4/4] SL-17997 Follow up from beta breakers results. --- indra/llrender/llimagegl.cpp | 17 ---------- indra/llrender/llimagegl.h | 5 ++- indra/llwindow/llwindowwin32.cpp | 55 +++++++++++++++++++++++--------- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index ae10142e7a..7ba0cc2fde 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -54,7 +54,6 @@ const F32 MIN_TEXTURE_LIFETIME = 10.f; U32 wpo2(U32 i); -#if LL_DARWIN // texture memory accounting (for OS X) static LLMutex sTexMemMutex; static std::unordered_map sTextureAllocs; @@ -119,22 +118,6 @@ U64 LLImageGL::getTextureBytesAllocated() return sTextureBytes; } -#else - -#define alloc_tex_image(width, height, pixformat) (void) width; (void) height; (void) pixformat; -#define free_tex_image(texName) (void) texName; -#define free_tex_images(count, texNames) (void) count; (void) texNames; -#define free_cur_tex_image() - -// static -U64 LLImageGL::getTextureBytesAllocated() -{ - // UNIMPLEMENTED OUTSIDE OF OS X, DO NOT CALL - llassert(false); - return 0; -} -#endif - //statics U32 LLImageGL::sUniqueCount = 0; diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 619421e68a..1bcdd040e0 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -53,7 +53,10 @@ class LLImageGL : public LLRefCount friend class LLTexUnit; public: - // For OS X use only -- get an estimate of how many bytes have been allocated in vram for textures + // Get an estimate of how many bytes have been allocated in vram for textures. + // Does not include mipmaps. + // NOTE: multiplying this number by two gives a good estimate for total + // video memory usage based on testing in lagland against an NVIDIA GPU. static U64 getTextureBytesAllocated(); // These 2 functions replace glGenTextures() and glDeleteTextures() diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 20443988ab..656439e71e 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -414,6 +414,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool HWND mWindowHandle = NULL; HDC mhDC = 0; + // best guess at available video memory in MB std::atomic mAvailableVRAM; IDXGIAdapter3* mDXGIAdapter = nullptr; @@ -4644,44 +4645,68 @@ void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage() LL_PROFILE_ZONE_SCOPED; if (mDXGIAdapter != nullptr) { + // NOTE: what lies below is hand wavy math based on compatibility testing and observation against a variety of hardware + // It doesn't make sense, but please don't refactor it to make sense. -- davep + DXGI_QUERY_VIDEO_MEMORY_INFO info; mDXGIAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info); - // try to use no more than the available reserve minus 10% - U32 target = info.Budget / 1024 / 1024; +#if 0 // debug 0 budget and 0 CU + info.Budget = 0; + info.CurrentUsage = 0; +#endif - // EXPERIMENTAL - // Trying to zero in on a good target usage, code here should be tuned against observed behavior - // of various hardware. - if (target > 4096) // if 4GB are installed, try to leave 2GB free + U32 budget_mb = info.Budget / 1024 / 1024; + U32 afr_mb = info.AvailableForReservation / 1024 / 1024; + // correct for systems that misreport budget + if (budget_mb == 0) + { + // fall back to available for reservation clamped between 512MB and 2GB + budget_mb = llclamp(afr_mb, (U32) 512, (U32) 2048); + } + + U32 cu_mb = info.CurrentUsage / 1024 / 1024; + + // get an estimated usage based on texture bytes allocated + U32 eu_mb = LLImageGL::getTextureBytesAllocated() * 2 / 1024 / 1024; + + if (cu_mb == 0) + { // current usage is sometimes unreliable on Intel GPUs, fall back to estimated usage + cu_mb = llmax((U32)1, eu_mb); + } + F32 eu_error = (F32)((S32)eu_mb - (S32)cu_mb) / (F32)cu_mb; + + U32 target_mb = info.Budget / 1024 / 1024; + + if (target_mb > 4096) // if 4GB are installed, try to leave 2GB free { - target -= 2048; + target_mb -= 2048; } else // if less than 4GB are installed, try not to use more than half of it { - target /= 2; + target_mb /= 2; } - U32 used_vram = info.CurrentUsage / 1024 / 1024; - - mAvailableVRAM = used_vram < target ? target - used_vram : 0; + mAvailableVRAM = cu_mb < target_mb ? target_mb - cu_mb : 0; LL_INFOS("Window") << "\nLocal\nAFR: " << info.AvailableForReservation / 1024 / 1024 << "\nBudget: " << info.Budget / 1024 / 1024 << "\nCR: " << info.CurrentReservation / 1024 / 1024 - << "\nCU: " << info.CurrentUsage / 1024 / 1024 << LL_ENDL; + << "\nCU: " << info.CurrentUsage / 1024 / 1024 + << "\nEU: " << eu_mb << llformat(" (%.2f)", eu_error) + << "\nTU: " << target_mb + << "\nAM: " << mAvailableVRAM << LL_ENDL; - mDXGIAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &info); + /*mDXGIAdapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_NON_LOCAL, &info); LL_INFOS("Window") << "\nNon-Local\nAFR: " << info.AvailableForReservation / 1024 / 1024 << "\nBudget: " << info.Budget / 1024 / 1024 << "\nCR: " << info.CurrentReservation / 1024 / 1024 - << "\nCU: " << info.CurrentUsage / 1024 / 1024 << LL_ENDL; + << "\nCU: " << info.CurrentUsage / 1024 / 1024 << LL_ENDL;*/ } else if (mD3DDevice != NULL) { // fallback to D3D9 mAvailableVRAM = mD3DDevice->GetAvailableTextureMem() / 1024 / 1024; } - } void LLWindowWin32::LLWindowWin32Thread::run()