bo3b / 3Dmigoto

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

Upscaling eye sync issue with RoT and GTAV #73

Open ColAngel opened 7 years ago

ColAngel commented 7 years ago

After somebody from the geforce forum posted that the rise of tomb raider (the newest build) works but breaks 3d (practically disables it). I ve tried to figure it out why. Used with normal 3d vision one of the3d vision glasses (left side) is always closed (no light come through) and right side shows the picture. (Sorry for cumbersome explanation) I ve expirienced similar issue with far cry 4 with upscaling mode 1 but was able to fix it by forcing the fake swap chain (that goes to the game) not to infuence the window (removing the DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH flag) on creation and on resize buffer for it. My guess it has something to do with the game itself support 3d vision pipeline. They seems not to use 3d vision automatic or do it differently. Question have you run into similar problems already? Maybe some of you guys have an idea what it could be?

ColAngel commented 7 years ago

It seems there is another issue with this game. Even if everything is disabled (upscaling and sbs shader). Disabling 3d (Ctrl + T) causes the game to crash (freeze). Without 3dmigot d3d11.dll everything works how it should.

ColAngel commented 7 years ago

After some experimenting i found out how to force the game to upscale in stereo. ROTR seems to use something between direct mode and automatic. To enable the stereo upscaling i was forced to update the present function: NvAPI_Stereo_SetActiveEye(mHackerDevice->mStereoHandle, NVAPI_STEREO_EYE_LEFT); if (!(Flags & DXGI_PRESENT_TEST)) { // Every presented frame, we want to take some CPU time to run our actions, // which enables hunting, and snapshots, and aiming overrides and other inputs RunFrameActions(); }

NvAPI_Stereo_SetActiveEye(mHackerDevice->mStereoHandle, NVAPI_STEREO_EYE_RIGHT);
if (!(Flags & DXGI_PRESENT_TEST)) {
    // Every presented frame, we want to take some CPU time to run our actions,
    // which enables hunting, and snapshots, and aiming overrides and other inputs
    RunFrameActions();
}

HRESULT hr = mOrigSwapChain->Present(SyncInterval, Flags);

NvAPI_Stereo_SetActiveEye(mHackerDevice->mStereoHandle, NVAPI_STEREO_EYE_LEFT);
if (!(Flags & DXGI_PRESENT_TEST)) {
    // Update the stereo params texture just after the present so that we
    // get the new values for the current frame:
    UpdateStereoParams(mHackerDevice, mHackerContext);

    // Run the post present command list now, which can be used to restore
    // state changed in the pre-present command list, or to perform some
    // action at the start of a frame:
    RunCommandList(mHackerDevice, mHackerContext, &G->post_present_command_list, NULL, true);
}

NvAPI_Stereo_SetActiveEye(mHackerDevice->mStereoHandle, NVAPI_STEREO_EYE_RIGHT);

if (!(Flags & DXGI_PRESENT_TEST)) {
    // Update the stereo params texture just after the present so that we
    // get the new values for the current frame:
    UpdateStereoParams(mHackerDevice, mHackerContext);

    // Run the post present command list now, which can be used to restore
    // state changed in the pre-present command list, or to perform some
    // action at the start of a frame:
    RunCommandList(mHackerDevice, mHackerContext, &G->post_present_command_list, NULL, true);
}

Basically i force 3dmigoto to do its stuff twice. However it is not very nice solution. It also stop working after changing the game resolution within the game. In this case one eye gets upscaled and the other not. I guess the main problem is I need to run the upscaling shader twice. (or change it in the similar way the sbs shader works and add my one interpolation.) I would appriciate if somebody of you guy would take a look at it. (when the time allows it). Or maybe one of you have an idea... Thanks in advance.

DarkStarSword commented 7 years ago

I recall in one of the games that used direct mode I was able to identify a shader through frame analysis that was run last that we could key off to run anything that needed to occur in both eyes.

Your solution above was one I considered to get the 3DMigoto overlay to render in both eyes, but I hadn't got around to trying it yet (also, you will need to restrict that to only happen in direct mode and you can't make assumptions on which eye is active at the time of the present call since the game can do it in either order, or may have even set the mono eye to disable 3D).

For some games it might actually be worthwhile adding a command list that can be called when the game calls SetActiveEye since that may be an indicator of when the game has started / finished rendering to each eye... but since that call only switches the active back buffer on the swap chain it doesn't actually give us any guarantees as to what the game is up to at the time (e.g. a game could have rendered to it's own buffers well in advance and only be calling that to copy to the back buffer at the end of the frame, or a game might call that in advance and render directly to each back buffer as it goes, or potentially a game may make multiple calls to that throughout the frame to render individual items to both eyes as it goes...). This is something I wanted to investigate more closely what various games do in practice before making a call on, and it may be that we need to leave some wiggle room here to make a game by game decision.

ColAngel commented 7 years ago

Ok thanks for the reply, it was only research, would not add it anyway to the code in this form. My idea behind that was that every game has to call present once to force the swap chain update ect. (I didn know that there are ways to do it differently), and the upscaling shader is running just like the sbs shader within the present call. But maybe we could find a more or less general solution for this case (maybe via the additional commands in the ini).

ColAngel commented 7 years ago

Independendly of the direct mode, I m planning to add upscaling code for the D3d11CreateDeviceAndSwapChain. Unfortunatelly i dont have time for it just right know! I hope ill be able to do it at the week end. Since you guys have seen many games can you name one cheap game that uses the function to create swap chain for me to test the feature? My all games with directx 11 use the DXGIFactory::CreateSwapChain. Thank you in advance!

bo3b commented 7 years ago

@ColAngel: Contact PirateGuyBrush on the forums and ask for access to the ShaderHacker shared games. There will be something in there that will use CreateDeviceAndSwapChain, and save you from needing to buy something. All Unity games use the DXGIFactory. IIRC Just Cause 3 will use CreateDeviceAndSwapChain.


When you make an update, please also fix the logging for normal mode. We are getting a spurious error, even though upscaling=0.

 *** HackerDXGIFactory::CreateSwapChain(class HackerDXGIFactory1@0000000007D233C0) called with parameters 
  Device = class HackerDevice@000000000143B250 
  SwapChain = 0000000004164CD0 
  Description = 00000000012FF200 
At least one of provided upscaling paramters is invalid!
Please check the d3d11.ini file!
Upscaling is disabled!
     Windowed = 1 
     Width = 1680 
     Height = 1050 
     Refresh rate = 0.000000 
HackerDevice::GetHackerContext returns 0000000001516D40
Overlay::Overlay created for 00000000074CB110: class HackerDXGISwapChain 
  on HackerDevice: 000000000143B250, HackerContext: 0000000001516D40 
->HackerDXGISwapChain 00000000074CB110 created to wrap 0000000007838340 
Got resolution from swap chain: 1680x1050
->return value = 0 
ColAngel commented 7 years ago

Ok, ill do it! Before i open a new issue: I cant run any game with debug build it always crashes as soon as geometry shader are active (cant name the exact position need in code need to test it). Maybe i m doing something wrong? Is there any additional compiler, preprocessor flags or d3d11.ini cmd line that have be used to prevent that? Thank you!

bo3b commented 7 years ago

No, that would be a bug. I've used it in debug mode with other games that had geometry shaders and it didn't crash. Geometry shaders won't decompile properly however.

At a minimum, just the existence of an active geometry shader should have no impact, because nothing should change it's behavior. This might something where upscaling or SBS shader is damaging something that it uses.

DarkStarSword commented 7 years ago

@ColAngel - I've just coordinated with pirateguybrush to give access to the email address you have been using to commit code. He's overseas right now, so if you have any problems with it let me know.

ColAngel commented 7 years ago

Got it :-) Thank you!

ColAngel commented 7 years ago

To the debug bug: Tested it again and still get the crash. It happens here: HackerContext.cpp in the Dispatch function:
mOrigContext->Dispatch(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ); The way i get the crash: Build solution in debug x64 mode copy dlls to the game folder together with fixed_shader and default .ini (no witcher fix from the helix mod used) upscaling and other stuff is disabled
Im using the witcher 3 to test it, but happens with other games too.

bo3b commented 7 years ago

For that debug crash, is there anything in the Visual Studio log from the Debug Layer? This is different logging than normal 3Dmigoto logging. When debug is built, we enable the Debug Layer, and it reports broken DX11 calls or setup.

You can pause at the start of debugging by adding an undocumented waitfordebugger=1 in the Logging section of d3dx.ini. That allows you to attach VS.

That Dispatch suggests that we have some sort of a race condition, multi-threading issue.

ColAngel commented 7 years ago

i was always inserting system("pause") in the first line of migoto entry point (or else where i need it), debug flag is nicer solution of cause. It just crashes without any errors printed to VS or .log. Maybe i have some special magic hardware configuration that causes this issue. However i still can test my stuff with simple demo code that does not use geometry shader and dispatch function. About that, since friday, I m fighting with the upscaling in d3d11createdeviceandswapchain. It works for the fake buffer (upscale_mode = 0) but denies to work with second swap chain (created with the d3d11createdeviceandswapchain). The error occurs in the Present function while calling the UpdateStereoTexture (during creation of the staging stereo texture). The error is pretty strange: 0x887a005 (DXGI_ERROR_DEVICE_REMOVED). Do somebody of you know why this can happen? The description of the issue on msd is pretty weird: https://msdn.microsoft.com/en-us/library/windows/desktop/bb509553(v=vs.85).aspx They suggest to destroy and to recreate device. Did not tried it yet, but it seems to me not to be a very clean solution anyway. (and i dont believe that it would help anyway, there still be 2 swap chaines). I would be happy over any help :-) Thank you in advance! Should i still commit it? (maybe with redirecting everthing to fake buffer mode)

bo3b commented 7 years ago

That sounds like the object you are saving and passing is the wrong one, or at least doesn't match the one that DX11 is expecting. If the DXGI device (SwapChain) doesn't match the D3Device, it will think the DXGI was removed.

This would be like a monitor being unplugged. But most likely it's that the objects are mismatched by a bug.

bo3b commented 7 years ago

For the Debug problem, you have something wrong with your system.

I just tested this using the Debug x64 build of 1.2.64, top of tree, and it builds and runs correctly using the GOG version of Witcher3. Win7, driver 378.92.

If I attach to the game, I get the VS output, including tracking of all objects created by DX11.

There are exceptions that happen, but are caught correctly by VS, at AfterDraw. These are because our fix damages the pipeline, and the Debug Layer is correctly noting that the VertexShader output does not match the PixelShader input. It can be ignored with a skip list like:

            D3D11_MESSAGE_ID skip[] =
            {
                D3D11_MESSAGE_ID_DEVICE_SHADER_LINKAGE_REGISTERMASK,
                // Add more message IDs here as needed 
            };
            D3D11_INFO_QUEUE_FILTER filter;
            memset(&filter, 0, sizeof(filter));
            filter.DenyList.NumIDs = _countof(skip);
            filter.DenyList.pIDList = skip;
            d3dInfoQueue->AddStorageFilterEntries(&filter);

I'm not getting crashes, and everything seems to be working correctly in Debug mode. BTW, using Debug Layer for your new Upscaling would be extremely valuable as a sanity check, looking for possible bugs.

If it seems like your problem is timing related, you can try setting force_cpu_affinity=1 which can sometimes show whether there are re-entrancy problems. I think this is unlikely, because we would have probably heard about this problem from some end users.

ColAngel commented 7 years ago

" you can try setting force_cpu_affinity=1" already done it before does not help. I guess i need to reinstall all windows sdks. I was messing around with the version 8.0 and 8.1 while trying to get migoto VS 2013 to work with VS2015 at the very beginning. I guess i have broken something. But thanks anyway for your hints and help. About the swap chain issue: yeah it seems it is impossible to create second swap chain with the D3D11CreateDeviceAndSwapChain because of different devices, without deeper hacking in to the software. (Simplest way i can thing of is to redirect the call two separate calls to create device and then the swap chain via factory etc.) I ll play around with this stuff. Maybe i find a way. For now I ll commit the updated code with better error handling and logging plus the fake texture version for the D3D11CreateDeviceAndSwapChain.

ColAngel commented 7 years ago

There is a similar issue i get with upscaling with dreamfall chapter and just cause 3. If the upscaling feature is used and the game resolution is changed (in game) then it breaks the upscaling in the similar way like in rise of tomb raider. (one eye is upscaled and one not and the game have to be restarted in order to play with new resolution). Could you please test it with dream fall at least. Im really at the end :-) of my possibilities, i dont know how to fix it. Maybe one of you has an idea? At least what exactly could cause such behavior. Thanks in advance!

DarkStarSword commented 6 years ago

There is a similar issue i get with upscaling with dreamfall chapter and just cause 3. If the upscaling feature is used and the game resolution is changed (in game) then it breaks the upscaling in the similar way like in rise of tomb raider.

Might be worth checking if the alt+enter fix that went into 1.2.70 did anything here. Haven't checked - just noting this now while I think of it.

ColAngel commented 6 years ago

i ll check it tonight