protonscr

[dxgi] createDxgiFactory deadlock

dxvkclosed windows
doitsujin/dxvk#4253 · opened 2024-09-11 by kasper93 · updated 2025-11-30 · 4 comments · github
1 matching comments, n / p to jump
Kkasper93 2024-09-11 github

createDxgiFactory deadlocks because, apparently, while it is being created, the Vulkan loader also attempts to create it. As we can see, DXVK uses an SRW lock for the Singleton class, which is not recursive, leading to a deadlock in this situation.

 # Child-SP          RetAddr               Call Site
00 000000ec`0eff5468 00007ffd`7fe67e55     ntdll!NtWaitForAlertByThreadId+0x14
01 000000ec`0eff5470 00007ffc`707d28d7     ntdll!RtlAcquireSRWLockExclusive+0x165
02 (Inline Function) --------`--------     dxgi!dxvk::mutex::lock+0xf [dxvk\src\util\thread.h @ 153] 
03 (Inline Function) --------`--------     dxgi!std::__1::lock_guard<dxvk::mutex>::lock_guard+0xf [include\c++\v1\__mutex\lock_guard.h @ 35] 
04 (Inline Function) --------`--------     dxgi!dxvk::Singleton<dxvk::DxvkInstance>::acquire+0xf [dxvk\src\util\util_singleton.h @ 21] 
05 000000ec`0eff54e0 00007ffc`707d59d7     dxgi!dxvk::DxgiFactory::DxgiFactory+0x37 [dxvk\src\dxgi\dxgi_factory.cpp @ 87] 
06 000000ec`0eff5590 00007ffc`9db4adfa     dxgi!dxvk::createDxgiFactory+0x27 [dxvk\src\dxgi\dxgi_main.cpp @ 10] 
07 000000ec`0eff55e0 00007ffc`9db4b6ed     vulkan_1!windows_get_registry_files+0x57a [vulkan-loader\loader\loader_windows.c @ 416] 
08 000000ec`0eff6020 00007ffc`9db3705f     vulkan_1!windows_read_data_files_in_registry+0x28d [vulkan-loader\loader\loader_windows.c @ 791] 
09 000000ec`0eff60a0 00007ffc`9db341bd     vulkan_1!loader_get_data_files+0x12f [vulkan-loader\loader\loader.c @ 3474] 
0a 000000ec`0eff6100 00007ffc`9db33fc6     vulkan_1!loader_icd_scan+0x11d [vulkan-loader\loader\loader.c @ 3701] 
0b 000000ec`0eff83b0 00007ffc`9db38fcc     vulkan_1!loader_preload_icds+0x36 [vulkan-loader\loader\loader.c @ 1990] 
0c 000000ec`0eff83f0 00007ffc`9db418b0     vulkan_1!terminator_EnumerateInstanceExtensionProperties+0x20c [vulkan-loader\loader\loader.c @ 6897] 
0d 000000ec`0effb7f0 00007ffc`708278fe     vulkan_1!vkEnumerateInstanceExtensionProperties+0x210 [vulkan-loader\loader\trampoline.c @ 249] 
0e 000000ec`0effebe0 00007ffc`707e580a     dxgi!dxvk::DxvkNameSet::enumInstanceExtensions+0x2e [dxvk\src\dxvk\dxvk_extensions.cpp @ 120] 
0f (Inline Function) --------`--------     dxgi!dxvk::DxvkInstance::createInstanceLoader+0x828 [dxvk\src\dxvk\dxvk_instance.cpp @ 160] 
10 000000ec`0effec90 00007ffc`707d292d     dxgi!dxvk::DxvkInstance::DxvkInstance+0x1a7a [dxvk\src\dxvk\dxvk_instance.cpp @ 52] 
11 (Inline Function) --------`--------     dxgi!dxvk::DxvkInstance::DxvkInstance+0x20 [dxvk\src\dxvk\dxvk_instance.cpp @ 15] 
12 (Inline Function) --------`--------     dxgi!dxvk::Singleton<dxvk::DxvkInstance>::acquire+0x65 [dxvk\src\util\util_singleton.h @ 24] 
13 000000ec`0effef60 00007ffc`707d59d7     dxgi!dxvk::DxgiFactory::DxgiFactory+0x8d [dxvk\src\dxgi\dxgi_factory.cpp @ 87] 
14 000000ec`0efff010 00007ff7`71bfc950     dxgi!dxvk::createDxgiFactory+0x27 [dxvk\src\dxgi\dxgi_main.cpp @ 10] 

System information

  • OS: Windows 11
  • GPU: not relevant
  • Driver: not relevant
  • Wine version: not relevant
  • DXVK version: v2.4-52-g1a1c3a42+

Log files

info:  Game: game.exe
info:  DXVK: v2.4-52-g1a1c3a42+
info:  Vulkan: Found vkGetInstanceProcAddr in vulkan-1.dll @ 0x7ffc9dc11230
info:  Built-in extension providers:
info:    Platform WSI
info:    OpenVR
info:    OpenXR
info:  OpenVR: could not open registry key, status 2
info:  OpenVR: Failed to locate module

Thanks,
Kacper

Ddoitsujin maintainer 2024-09-11 github

How ancient is your Vulkan loader? This was fixed upstream like four or five years ago by making sure to only load DXGI from system32, unless they reintroduced this issue very recently for whatever reason.

Either way, this cannot work. The alternative to a deadlock is a stack overflow, or we deliberately detect this case, throw an error and still have things crash in some way.

Kkasper93 2024-09-11 github

How ancient is your Vulkan loader?

This stacktrace was produced with my local build from https://github.com/KhronosGroup/Vulkan-Loader/commit/c758bac8bf1580b5018adafd3a2ec709237b0134 Date: Tue Sep 3 15:55:31 2024 -0500

Normally I use one from GPU driver, which is currently 1.3.283 and hangs the same way, but I didn't have symbols for that, so I used the build above.

This was fixed upstream like four or five years ago by making sure to only load DXGI from system32

Ok, got it, so in fact we don't want to override dxgi.dll. Wiki says we can, but clearly it doesn't work.

It is possible to work around games loading the wrong DLL by enabling DevOverride in the registry.

Not possible in fact.

Thanks, I guess not much DXVK can do here.

Aanonymix007 2025-11-29 github

This actually becomes a problem when DLL redirection is in use. As a workaround, I've copied the real C:\Windows\System32\dxgi.dll to C:\Windows\System32\dxgi_real.dll and patched the loader:

diff --git a/loader/loader_windows.c b/loader/loader_windows.c
index 31bbdfe9c..d6f65b0f3 100644
--- a/loader/loader_windows.c
+++ b/loader/loader_windows.c
@@ -83,8 +83,13 @@ void windows_initialization(void) {
 
     wchar_t systemPath[MAX_PATH] = L"";
     GetSystemDirectoryW(systemPath, MAX_PATH);
-    StringCchCatW(systemPath, MAX_PATH, L"\\dxgi.dll");
+    StringCchCatW(systemPath, MAX_PATH, L"\\dxgi_real.dll");
     HMODULE dxgi_module = LoadLibraryW(systemPath);
+    if (dxgi_module == NULL) {
+        GetSystemDirectoryW(systemPath, MAX_PATH);
+        StringCchCatW(systemPath, MAX_PATH, L"\\dxgi.dll");
+        dxgi_module = LoadLibraryW(systemPath);
+    }
     fpCreateDXGIFactory1 =
         dxgi_module == NULL ? NULL : (PFN_CreateDXGIFactory1)(void *)GetProcAddress(dxgi_module, "CreateDXGIFactory1");
 

Not sure what's the best way to fix this though. Can DXVK maybe detect this and call the real CreateDXGIFactory1?

KK0bin maintainer 2025-11-30 github

The Vulkan loader already tries to explicitly load the system DXGI.

So even if DXVK could detect this scenario (no idea how that would work), there isn't really a way to load the system DLL.

DLLs