narzoul / DDrawCompat

DirectDraw and Direct3D 1-7 compatibility, performance and visual enhancements for Windows Vista, 7, 8, 10 and 11
BSD Zero Clause License
893 stars 67 forks source link

Issue in compiling #165

Closed BEENNath58 closed 1 year ago

BEENNath58 commented 1 year ago

I am trying to build some earlier commited versions of DDC, the ones after the VC 2022 switch, but I may also build some with VC 2019, but at least the VC 2022 one keeps failing saying that it can't find a d3dumddi.h file. I installed VC2022, SDK 2019 because it didn't work with the latest one, and WDK Win10 1903 forced because the latest WDK also didn't find the header file too.

Please suggest what to do.

narzoul commented 1 year ago

I'm not sure which commit you're talking about, but you've probably installed the wrong versions of the SDK/WDK. Check WindowsTargetPlatformVersion in DDrawCompat.vcxproj for the version you're trying to build, like the Readme says. Search for that number here: https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/ and make sure to get the matching WDK version too.

You can probably build with a newer version also if you retarget the solution to whatever you have installed. Right click on the Solution in Solution Explorer and choose "Retarget solution".

BEENNath58 commented 1 year ago

Check WindowsTargetPlatformVersion in DDrawCompat.vcxproj for the version you're trying to build, like the Readme says. Search for that number here: https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/ and make sure to get the matching WDK version too.

I already did that, and downloaded the version alongwise. The required version is 10.0.19041.0

You can probably build with a newer version also if you retarget the solution to whatever you have installed. Right click on the Solution in Solution Explorer and choose "Retarget solution".

I even tried that, and the same was happening. Then I decided to delete the newer versions because I can download them again later, but the same error exists, The error in question is:

Severity    Code    Description Project File    Line    Suppression State
Error   C1083   Cannot open include file: 'd3dumddi.h': No such file or directory   DDrawCompat C:\Users\thesa\Downloads\DDrawCompat-175d7e7c530672e11642b66619f4c25b3d1a351b\DDrawCompat-175d7e7c530672e11642b66619f4c25b3d1a351b\DDrawCompat\Config\Settings\Antialiasing.cpp 2   

This issue was already discussed earlier https://github.com/narzoul/DDrawCompat/issues/57

I am going to try moving the d3dumddi.h from a newer version to the version used by DDC.

BEENNath58 commented 1 year ago

Okay I managed to find a solution. Since I couldn't find any d3dumddi.h in the specified version for DDC, I copied one I found in a newer version of WDK, and copied to the required version's Include folder.

A few commits post the "8b393ea49876f8f7ee85182304bc265583b816c4" commit output an assertion error when their build is used, specifically in the game Motorhead, for which I needed to track the version where DDC fixed the "missing HUD problem", the aforementioned "8b393ea..." commit is the one.

ghotik commented 1 year ago

I beg your pardon if I intrude myself in the thread, but I think that the idea is trying to bring some more clever tricks from DDrawCompat to DxWnd, so, in addition to be able to build old committed releases, I would rather be interested into understanding the overall idea. The mentioned commit "8b393ea49876f8f7ee85182304bc265583b816c4" seems to fix a mechanism that seems far more complex than the patch itself and that it is not present in DxWnd at all. If I understand correctly, DDrawCompat fixes Motorhead (a IDirect3D2 game) patching the shaders handling at the D3DDDI level by replacing the pfnCreateVertexShaderDecl with a DDC custom one that creates/uses/deletes shaders. Following the W-Fog patching code, I suppose I should be able to hook the pfnCreateVertexShaderDecl callback, but for sure I would need some general direction about the overall schema: I must admit that I never felt confident with shaders. By the way, I suppose that fixes like this would require some shaders-supporting video card, isn't it?

narzoul commented 1 year ago

That commit wasn't supposed to fix anything as far as I remember. It was just a rewrite of earlier vertex related fixes, so that they could be done via the GPU instead of the CPU, which I thought would be faster. Never actually benchmarked it though.

The earlier fixes were these: https://github.com/narzoul/DDrawCompat/commit/bb6092e0bded498c8b50c35a620a77a73caea80f https://github.com/narzoul/DDrawCompat/commit/324b4a77f0bb2858f3673eae31e7f705e7b08598

All they did was making sure the RHW component of pre-transformed vertices wasn't either 0 or infinite, since those caused various issues on some drivers. Technically they're not legal values anyway, so the bug is definitely in the games, it's just that some drivers tolerated them better than others.

It seems that the commit you mentioned added one additional step, to also clamp the Z coordinates between 0 and 1. I don't remember exactly why I added this. I think there were some graphical issues with negative Z coordinates or something like that, which weren't there before switching to the shader-based approach. Maybe Motorhead also has some issues with out-of-range Z coordinates then, I don't recall ever testing that game.

In theory, this can all be done without any DDI hooks, but I couldn't figure out how to properly hook all the DrawPrimitive functions in the IDirect3DDevice interfaces. The runtime sometimes replaces those vtable entries with other function pointers, and I couldn't be bothered trying to figure out when exactly those replacements happen or how many different DrawPrimitive implementations there are to be hooked. So, I hooked the DrawPrimitive functions of the DDI instead.

Implementing even the CPU based approach in the DDI is a lot more involved than a single function hook for sure, the shader-based approach even more so. Maybe I'll put together some high-level outline later, but I'd also have to go through the code to find all the pieces.

narzoul commented 1 year ago

On my NVIDIA GPU (GTX 760), the https://github.com/narzoul/DDrawCompat/commit/8b393ea49876f8f7ee85182304bc265583b816c4 commit alone did not fix the issue. I needed an additional fix from the next commit. I guess not all NVIDIA drivers are created equal. I had to add the following lines at the end of DeviceState::updateRenderTargets:

m_current.vertexShaderFunc = DELETED_RESOURCE;
m_changedStates |= CS_SHADER;

Anyway, I tracked down the real issue: it's the Z=0 coordinates used for the HUD that are getting clipped on NVIDIA for some reason, but only when using pre-transformed vertices. Replacing them with slightly higher values works, but I'm not sure how high it needs to be exactly. 0.001f works, but 0.0001f doesn't. Here is a CPU-side fix based on v0.3.2: ddraw.zip (diff.txt compared to v0.3.2)

I made the fix a little more generic, so that any Z values less than 0.001 (but >= 0) get replaced with 0.001. I wonder if this also partly solves the Z-order issue mentioned in Shadows of the Empire? Though there would likely be some Z-fighting issues due to everything being very close to the camera getting projected to the same Z-plane.

narzoul commented 1 year ago

Maybe the Direct3D 9 SDK has the answer: https://learn.microsoft.com/en-us/windows/win32/direct3d9/viewports-and-clipping

When the device receives pre-transformed and lit vertices (T&L vertices) that need to be clipped, in order to perform the clipping operation the vertices are back-transformed to the clipping space using the vertex's reciprocal homogeneous w (RHW) and the viewport information. Clipping is then performed. Not all devices are capable of performing this back-transform in order to clip T&L vertices.

The D3DPMISCCAPS_CLIPTLVERTS device capability indicates whether the device is capable of clipping T&L vertices. If this capability is not set, the application is responsible for clipping the T&L vertices that it intends to send down to the device to be rendered. The device is always capable of clipping T&L vertices in the software vertex processing mode (regardless of whether the device is created in the software vertex processing mode, or switched to the software vertex processing mode).

I checked the caps with DXCapsViewer, and D3DPMISCCAPS_CLIPTLVERTS is "No" on my AMD GPU, but "Yes" on NVIDIA. So maybe this is the reason why Z=0 is clipped on NVIDIA but not AMD (at least on my system). I'm not sure if this clipping can be disabled, maybe D3DRENDERSTATE_CLIPPING affects it?

Interestingly, the above paragraphs and the D3DRENDERSTATE_CLIPPING flag are not present in DX7, they seem to have been added with DX8. So maybe no DX7-era GPUs supported such clipping and that's why the issue didn't affect the game on release. But then the driver should be smart enough to disable clipping for DX7 and earlier runtimes for backwards compatibility.

BEENNath58 commented 1 year ago

Interestingly, the above paragraphs and the D3DRENDERSTATE_CLIPPING flag are not present in DX7, they seem to have been added with DX8. So maybe no DX7-era GPUs supported such clipping and that's why the issue didn't affect the game on release. But then the driver should be smart enough to disable clipping for DX7 and earlier runtimes for backwards compatibility.

I think that's the same reason why Digital Illusions brought out a HUD patch that I recently discovered, only for Nvidia GPUs. And it seems like Nvidia didn't bother making their drivers smarter anymore.

Andt doesn't look like the most generic fix you would add to DDC, maybe you can add this as an option in the configuration of the next release, disabled by default. For now, I tested and it's working beautifully with the problematic release of the game.