bo3b / 3Dmigoto

Chiri's DX11 wrapper to enable fixing broken stereoscopic effects.
Other
685 stars 109 forks source link

Compatibility issue with dual GPU laptops #106

Open DarkStarSword opened 5 years ago

DarkStarSword commented 5 years ago

DOA6 crashes on laptops with dual graphics cards if the game is set to use the dedicated GPU. Works fine on the integrated graphics card, but obvisouly performance in unacceptable.

Info from user:

OS: Windows 10 64-bit (10.0, Build 17134) Processor: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz (8 CPUs), ~2.8GHz GPU0: Intel(R) HD Graphics 630 GPU1: NVIDIA GeForce GTX 1050 Ti

i just use right click menu to run game in specify GPU.

cause i manually set game use GPU1 in nvidia driver settings, Optimus wont override my settings, right?

3 jpg d577af43426571412fe0b7e2cac18ceb 1 jpg d030b6fe609ed22efdae8ff2be8ff28d

the GPU status when i run DOA6 and crash. the peak is the time i fire my game.While i run the game with GPU0, i get fps down to 2~5,but 3DMigoto works well.

outlog d3d11_log.txt

DarkStarSword commented 5 years ago

Their log file shows two D3D11CreateDevice calls. The first one is for the default adapter, and the game appears to use this happily for some time, rendering draw calls, etc. Then we see a second D3D11CreateDevice calling for a specific adapter. The call seems to return ok, but then the log abruptly stops.

Curiously something triggered our hooking hell / hot potato defence path, though I'm not sure what that would be (the log shows neither SpecialK nor ReShade are present - could it be Optimus?):

Hooking Quirk: Unexpected call back into D3D11CreateDeviceAndSwapChain, passing through

We could possibly be looking at a device swap scenario, where the game starts using one adapter (and we start initing things using that adapter), then switches over to the other adaptor, and perhaps we are still using something created on the first. The main thing I don't like about this theory is the lack of anything after the second D3D11CreateDevice call, but even if it isn't causing the crash at this point there might be issues here - I'm thinking about shaders created on one device used on another, but potentially any D3D11DeviceChild. We have code to handle migrating resources from one device to another, but this scenario is a little different so that should be considered suspect as well (and the log is nowhere near the point where that would come into play).

bo3b commented 5 years ago

I'm not sure any of us ever looked closely at the device removed messages that can occur, because they are pretty rare. But Present can return an error of DXGI_ERROR_DEVICE_REMOVED || DXGI_ERROR_DEVICE_RESET. IIRC, we don't handle those at all, and they are likely to be the problem in this scenario.

https://docs.microsoft.com/en-us/windows/uwp/gaming/handling-device-lost-scenarios

This is also likely to be related to Optimus, because it automatically switches from Intel to dedicated depending upon demand and also configuration. I'm just guessing, but I'd expect that to happen using this device removed approach.

DarkStarSword commented 1 year ago

I finally have a laptop that can repro this issue - if both Intel + NVidia GPUs are enabled we get a crash during the splash screen on launch, if only the NVidia GPU is enabled (via PredatorSense) the game works fine. The issue is present in both top of tree 3DMigoto and geo-11, however geo-11 has an additional black screen issue with this game that does not occur in 3DMigoto, so might be worth fixing it in 3DMigoto first and forward porting to geo-11 later.

NVIDIA GPU only enabled via PredatorSense: d3d11_log - nvidia only.txt

Both GPUs enabled: d3d11_log - optimus~debug dll.txt

Like the log file from the original report we see a 2nd call to D3D11CreateDevice (with a specific adapter selected) when both GPUs are enabled and a crash shortly thereafter.

The crash is a null pointer dereference in the real d3d11.dll EnsureChildDevice() during a present call towards the end of the splash screen. At least one present call has already succeeded much earlier in the splash screen (possibly on the 1st device):

d3d11.dll!NDXGI::CDevice::EnsureChildDevice(struct IDXGIAdapter ,class ATL::CComPtr &,char const ) Unknown dxgi.dll!CDXGISwapChain::EnsureChildDeviceInternal(struct IDXGIAdapter ,enum DXGI_INTERNAL_CHILD_DEVICE_TYPE) Unknown dxgi.dll!CDXGISwapChain::PrepareWindowedBltPresent(bool,bool,unsigned int,class DXGITrack &,unsigned __int64 &) Unknown dxgi.dll!CDXGISwapChain::PresentImplCore(struct SPresentArgsCore const ,unsigned int,struct tagRECT const ,unsigned int,struct DXGI_SCROLL_RECT const ,struct IDXGIResource *,struct CDXGISwapChain::PresentResultActions &) Unknown dxgi.dll!CDXGISwapChain::PresentImpl() Unknown dxgi.dll!CDXGISwapChain::Present(unsigned int,unsigned int) Unknown GameOverlayRenderer64.dll!00007ffd25108f63() Unknown d3d11.dll!HackerSwapChain::Present(unsigned int SyncInterval, unsigned int Flags) Line 567 C++ [External Code]

I can rule out GameOverlayRenderer64.dll as the same crash occurs with that removed from Steam.

DarkStarSword commented 1 year ago

Before the present call crashes, it calls into D3D11CreateDevice, and since we hook that call in DOA6 it ends up calling back into 3DMigoto, meaning we can pass our wrapped devices back to the real DirectX - this is almost certainly the cause of our crash:

d3d11.dll!D3D11CreateDeviceAndSwapChain(IDXGIAdapter pAdapter=0x0000017afc0b5880, D3D_DRIVER_TYPE DriverType=D3D_DRIVER_TYPE_UNKNOWN, HINSTANCE__ Software=0x0000000000000000, unsigned int Flags=138, const D3D_FEATURE_LEVEL pFeatureLevels=0x00000043443feae0, unsigned int FeatureLevels=1, unsigned int SDKVersion=7, DXGI_SWAP_CHAIN_DESC pSwapChainDesc=0x0000000000000000, IDXGISwapChain ppSwapChain=0x0000000000000000, ID3D11Device ppDevice=0x00000043443feaa0, D3D_FEATURE_LEVEL pFeatureLevel=0x0000000000000000, ID3D11DeviceContext ppImmediateContext=0x0000000000000000) Line 940 C++ [External Code] d3d11.dll!D3D11CreateDevice(IDXGIAdapter pAdapter=0x0000017afc0b5880, D3D_DRIVER_TYPE DriverType=D3D_DRIVER_TYPE_UNKNOWN, HINSTANCE__ Software=0x0000000000000000, unsigned int Flags=138, const D3D_FEATURE_LEVEL pFeatureLevels=0x00000043443feae0, unsigned int FeatureLevels=1, unsigned int SDKVersion=7, ID3D11Device ppDevice=0x00000043443feaa0, D3D_FEATURE_LEVEL pFeatureLevel=0x0000000000000000, ID3D11DeviceContext * ppImmediateContext=0x0000000000000000) Line 858 C++ [External Code] d3d11.dll!HackerSwapChain::Present(unsigned int SyncInterval=1, unsigned int Flags=0) Line 567 C++ [External Code]

Enabling the hooking quirk protection around the present call resolves the crash.

DarkStarSword commented 1 year ago

I've put fixes for this in to both 3DMigoto and geo-11 (geo-11 having two additional present call sites that needed the hooking quirk protection enabled, and of course still having an additional black screen issue with this game that I haven't looked into yet). Not sure if we want to spin up a new 3DMigoto release for this (and I think there are one or two other bug fixes and pull requests we could add in), or just focus on geo-11.

I also put it in the Rename_Reformat branch thinking that had already merged into geo-11, but it seems like it hasn't yet - I got a cleaner merge from 3DMigoto/master into geo-11/master than the Rename_Reformat branch... That might have been a waste of time resolving the merge conflicts...

I'll leave the ticket open until it's released somewhere anyway.