Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[d3d11] With DXVK d3d objects may become doubly wrapped leading to a crash #846

Open
werman opened this issue Dec 8, 2022 · 10 comments
Open
Labels

Comments

@werman
Copy link
Contributor

werman commented Dec 8, 2022

I saw this issue when tried to capture "Resident Evil 3" and "Injustice 2" running on DXVK.

How it happens:

  • Game calls IDXGIDevice4::GetParent(IID_IDXGIAdapter)
  • WrapIDXGIDevice4::GetParent is called
  • It calls dxvk::D3D11DXGIDevice::GetParent
  • Which calls WrapIDXGIAdapter4::QueryInterface
#0  WrapIDXGIAdapter4::QueryInterface (this=0x8982d0, riid=..., ppvObj=0x6bbc3ed8) at wrappers/dxgitrace.cpp:62353
#1  0x000000003b45ee6b in dxvk::D3D11DXGIDevice::GetParent (this=0x970050, riid=..., ppParent=0x6bbc3ed8) at src/d3d11/d3d11_device.cpp:3250
#2  0x000000020f7c58b5 in WrapIDXGIDevice4::GetParent (this=0x4d6a6350, riid=..., ppParent=0x6bbc3ed8) at wrappers/dxgitrace.cpp:57442
#3  0x0000000141b97ce0 in DCF2Game

QueryInterface wraps object once, and then WrapIDXGIDevice4::GetParent
wraps it for the second time.

I made a change to prevent the double wrapping of the objects, though not sure it's a good one: 7fbc86b

@jrfonseca
Copy link
Member

Something's amiss here, as DXVK should never have accessed apitrace's wrapper objects, therefore calls from DXVK back into apitrace should never have happened.

7fbc86b might workaround the issue, but it's papering over the root problem, whatever it may be.

I see two possible explanations:

  1. Apitrace is inadvertently intercepting internal DXVK calls. Maybe DXVK is using public interfaces, and dxvk's DLLs should be added to
    /* Leave these modules alone.
    *
    * Hooking other injection DLLs easily leads to infinite recursion (and
    * stack overflow), especially when those libraries use techniques like
    * modifying the hooked functions prolog (instead of patching IAT like we
    * do).
    *
    * See also:
    * - http://www.nynaeve.net/?p=62
    */
    if (stricmp(szBaseName, "kernel32.dll") == 0 ||
    stricmp(szBaseName, "AcLayers.dll") == 0 ||
    stricmp(szBaseName, "ConEmuHk.dll") == 0 ||
    stricmp(szBaseName, "gameoverlayrenderer.dll") == 0 ||
    stricmp(szBaseName, "gameoverlayrenderer64.dll") == 0 ||
    stricmp(szBaseName, "nvoglv32.dll") == 0 ||
    stricmp(szBaseName, "nvoglv64.dll") == 0) {
    return;
    }
  2. Apitrace is inadvertently passing wrapped pointers to DXVK (instead of unwrapping them as it should.)
    I think explanation 1 is the most likely.

That said, I think it would be good to have the warning from 7fbc86b , to easily diagnose the issue.

@jrfonseca
Copy link
Member

The more I look at dxvk's source code, the more I belive explanation 1 is the right one.

I suspect what's happening is that call DXVK is internally calling D3D11CoreCreateDevice and this call is being intercepted by apitrace, when it shouldn't. Try breakpoing (or add asm("__int3") on DXVK's D3D11CoreCreateDevice code), and I'm sure we'll see apitrace double-intercepting in the call stack.

@werman
Copy link
Contributor Author

werman commented Dec 9, 2022

The issue is a bit earlier:

#0  dxvk::createDxgiFactory (Flags=5174976, riid=..., ppFactory=0x1e77170) at ../../../src/dxgi/dxgi_main.cpp:8
#1  0x000000002779848a in CreateDXGIFactory1 (riid=..., ppFactory=0x4ef7d8) at ../../../src/dxgi/dxgi_main.cpp:31
#2  0x000000020f74288c in _get_CreateDXGIFactory1 (riid=..., ppFactory=0x4ef7d8) at wrappers/dxgitrace.cpp:108
#3  0x000000020f9b3e36 in CreateDXGIFactory1 (riid=..., ppFactory=0x4ef7d8) at wrappers/dxgitrace.cpp:186050
#4  0x000000003b465113 in D3D11InternalCreateDeviceAndSwapChain (pAdapter=0x1, DriverType=5175600, Software=0x3b8d5898 <vtable for std::basic_ofstream<char, std::char_traits<char> >+24>, Flags=999117984, 
    pFeatureLevels=0x3b8d54a0 <vtable for std::basic_filebuf<char, std::char_traits<char> >+16>, FeatureLevels=0, SDKVersion=9764944, pSwapChainDesc=0x950050, ppSwapChain=0x0, ppDevice=0x7f62084cbe60, 
    pFeatureLevel=0x4ef870, ppImmediateContext=0x7b61c1f9 <GetBinaryTypeW+73>) at ../../../src/d3d11/d3d11_main.cpp:141

So internal to DXVK IDXGIFactory gets wrapped after that the result of dxgiFactory->EnumAdapters gets wrapped, so later on the GetParent is called on wrapped adapter.

@werman
Copy link
Contributor Author

werman commented Dec 9, 2022

  1. Apitrace is inadvertently intercepting internal DXVK calls. Maybe DXVK is using public interfaces, and dxvk's DLLs should be added to

Adding dxgi.dll, d3d11.dll, d3d9.dll to the ignore list doesn't change anything. D3D11InternalCreateDeviceAndSwapChain still calls CreateDXGIFactory1 from the apitrace.

@jrfonseca
Copy link
Member

I'll probably need to reproduce this myself.

I don't understand though, why just these games are affected. If all D3D11InternalCreateDeviceAndSwapChain -> CreateDXGIFactory1 were affected then I'd expect this to happen all the time.

Can you confirm how you're capturing this? You're capturing as described in https://github.com/apitrace/apitrace/wiki/WINE#pure-wine ? Or something different?

@werman
Copy link
Contributor Author

werman commented Dec 11, 2022

@jrfonseca I'm just copying dxgi and d3d11 apitrace dlls near game's executable.

@jrfonseca
Copy link
Member

I'm just copying dxgi and d3d11 apitrace dlls near game's executable.

Hmm, I wouldn't expect this approach to ever work. But indeed this is what's recommended on https://github.com/doitsujin/dxvk/wiki/Using-Apitrace#on-linux

Please remove any apitrace DLL from the game directory, and try following the instructions on https://github.com/apitrace/apitrace/wiki/WINE#windows-native if you haven't already.

Instead of d3d9.dll, you'll need to set WINEDLLOVERRIDES environment variable to Z:\path\to\apitrace\build\mingw32\wrappers\dxgi.dll=n;Z:\path\to\apitrace\build\mingw32\wrappers\d3d11.dll=n, replacing Z:\path\to\apitrace to the full WINE path of apitrace binaries.

@jrfonseca
Copy link
Member

Also note that https://github.com/doitsujin/dxvk/wiki/Using-Apitrace#on-linux also states:

  • Before the next step, make sure you disable or get rid of DXVK files first, as it's preferred that you use WineD3D to make an apitrace.

That's probably what's going on. The DXVK DLLs interfere with apitrace wrappers, so it's better not to use both at the same time.

@werman
Copy link
Contributor Author

werman commented Dec 12, 2022

Please remove any apitrace DLL from the game directory, and try following the instructions on https://github.com/apitrace/apitrace/wiki/WINE#windows-native if you haven't already.

Ok, I'll try. The method of dropping the dlls near executable worked for 2+ years, so I didn't expected it to fail this time =)

Before the next step, make sure you disable or get rid of DXVK files first, as it's preferred that you use WineD3D to make an apitrace.

That's too cryptic of a warning (it's likely there to safeguard against embedding corrupted render results into the trace). In my case I don't try to capture any issue, but capture a trace to replay it on my arm board with Turnip driver in order to find issues in it.

Anyway, I'll try to follow your instructions, if it helps I'll suggest an update to dxvk docs.

@werman
Copy link
Contributor Author

werman commented Dec 19, 2022

The good part is that when following your guide there is no crash. The bad part is that there is only a black screen during the replay.

The calls in both traces looks similar, with the difference that one lacks internal DXVK calls, but I probably missing something...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants