narzoul / DDrawCompat

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

DDrawCompat does not work with the Creators Update version of Windows 10 #15

Closed elishacloud closed 7 years ago

elishacloud commented 7 years ago

Hello narzoul,

I updated my system to Windows 10 Creators Update and it appears that none of the DDrawCompat versions work with the Creators Update. I tried version 2.0b, 2.1 and the experimental version. The games just show a solid black screen and you cannot see anything on the screen. Also I am not seeing any error message in the log file. I tried several games that used to work and all of them have the same result.

Note: version 2.0b seems to work partially on some games.

Thanks, Elisha

elishacloud commented 7 years ago

I did a bit of troubleshooting and it appears to be this line of code that is causing the issue:

setAppCompatData(disableMaxWindowedMode, 0);

If I rem out this line then everything works fine.

elishacloud commented 7 years ago

I realize that removing this line could lead to performance problems for fullscreen games, as described in this this thread here. But maybe Microsoft fixed the performance issues in the Creators Update?

narzoul commented 7 years ago

I've installed the new Windows 10 update before schedule now to check out this issue, but I'm unable to reproduce it. Both my dedicated AMD and integrated Intel GPUs work as before with either v0.2.1 or the experimental version on several games I've tried. Are you using NVIDIA by chance? I don't have a test system with that at the moment.

Are you sure it's the Windows update that broke things and not something else you've changed recently? Especially video recording or other overlay software like Fraps and Bandicam are known to be incompatible and cause black screens with DDrawCompat.

Have you tried reinstalling your video drivers after the update?

If you've ruled out all of the above, can you mention some game titles where you have this issue? Maybe it doesn't affect everything after all and I just got "lucky" on all my test subjects (or you got unlucky).

Can you check if the "DXPrimaryEmulation -DisableMaxWindowedMode" shim in itself (without DDrawCompat) produces similar behavior on any DirectDraw games that otherwise work fine even without DDrawCompat?


As far as I know removing that line never caused much performance issues on Windows 10, but it does on Windows 8. There's an alternative shim called "NoGDIHwAcceleration" that could be used, but I'm not sure that can be enabled via a simple ddraw.dll proxy (I haven't found a way so far).

There are also other problems with removing it, such as potentially breaking GDI interworking in some cases, as well as gamma/brightness settings in many games. Although there is a workaround for the latter via the AllowMaximizedWindowGamma shim as well that could possibly be enabled or reimplemented somehow.

Finally, it would probably remove the option to disable v-sync and potentially result in somewhat higher input latency due to the presentation being handled through desktop composition.

In short, I'd rather not remove it except maybe as a configurable option in a future version, unless it turns out that the issue is really related to this alone and there's no other way to fix it.

elishacloud commented 7 years ago

Thanks for looking into this. I am using an nVidia Geforce GTX 780 video card with an Intel i7 CPU. I will check the "DXPrimaryEmulation -DisableMaxWindowedMode" shim in itself (without DDrawCompat) and let you know what I find out.

elishacloud commented 7 years ago

Ok, I did a bit more testing on this. The first thing I should mention is that this issue does not happen with all games. About half of the games I tested did not have any issues. I was unlucky with my first tests because I tested starting in alphabetical order and the first two did not work, so I made and assumption about the rest.

To comment on a your questions, I am not completely sure it was the Windows update that caused this issue, but that is the only thing I changed. I am about 90% sure. :-)

As you suggested I reinstalled the latest version of nVidia drivers and that did not help.

I tried enabling just the "DXPrimaryEmulation -DisableMaxWindowedMode" shim itself (without DDrawCompat) and the same issue happened. So this is not an issue with DDrawCompat directly. However there is a twist here. A number of games work fine with DDrawCompat v2.0b (which has the "DXPrimaryEmulation -DisableMaxWindowedMode" shim) but do not work with the "DXPrimaryEmulation -DisableMaxWindowedMode" shim in itself (without DDrawCompat). So something in DDrawCompat v2.0b allows the games to continue to work even with the "DXPrimaryEmulation -DisableMaxWindowedMode" shim enabled.

This issue seems to mainly happen with older games (late 90's, early 2000's). The newer games seem to work fine. Most of these games I picked up off GOG on a sale.

Here is a list of games I tested that don't work:

Here is a list of games I tested that work fine:

narzoul commented 7 years ago

Thanks for the extensive testing! Indeed, I can reproduce the problem now with a few of the games on your "not working" list.

I've narrowed down the problem to games that render to the primary surface directly, instead of using a back buffer and then flipping the front/back buffers. For some reason, blitting to the front buffer doesn't update the screen in real full screen mode anymore. I've checked as low as the D3DKmtPresent call from debug logs and there doesn't seem to be anything wrong with the parameters. The function returns with success code as well. I suspect the update really may have broken something in the DirectX drivers (possibly in the kernel mode part).

I've also seen reports of some recent games producing black screen issues after the update (Mass Effect Andromeda is frequently mentioned), so the problem may not be specific to DirectDraw either. Hopefully Microsoft will release a fix soon.

The reason that games still work with v0.2.0b is because that version still uses page flipping even for direct primary surface updates. I've later changed it to use blitting instead for direct blits/locks in commit c78c7c9 because I realized that driver settings can force v-sync on for all flips. This caused an issue where multiple direct updates per screen refresh could get spread out over multiple refreshes, causing heavy stuttering in some games.

However, I think I can revert this part of the commit and just make sure that the flip interval is always set to "immediate" in D3DKmtPresent for direct updates. I think all graphics drivers override the v-sync option before this function is called, so it might be an alternative way of preventing the stuttering. I'll try to experiment with this over the weekend.

For now, if you want to try a quick fix, just make sure v-sync is not forced on by your GPU driver settings and do these changes in RealPrimarySurface::updateNow():

By the way, I'm not sure why Blood II is not working for you. It uses page flipping already and works fine for me without any changes.

Nucleoprotein commented 7 years ago

This can be related to CU game optimizations, you can disable them for any program in Windows properties on Compatibility tab. I do not know exact English name for that option but it's something like Disable full-screen optimizations, second option from bottom.

narzoul commented 7 years ago

I've tried that already, didn't help unfortunately.

elishacloud commented 7 years ago

Ok, thanks for your work on this! I tried your quick fix and it seemed to work as long as I had v-sync disabled by my GPU driver (which it was not). However I had to make a slight change to your code. I used this line:

Instead of this line:

This code change could be because I am using DDrawCompat v0.2.1 rather than the experimental version though. I am not an expert on DirectX.

As far as Blood II, the issue is that it won't work with just DDrawCompat so I am using DxWnd also. This has an Emulated Primary Buffer option that is required for Blood II to work on my computer. Given your comments above I suspect that option in DxWnd is what is causing the issue. If I try and use only DDrawCompat I get the following error and the game won't start: "Blood2: Nightmares" "ERROR - Unable to set the video mode. (6929314)". Also while your quick fix works on other games it does not work on this one, again likely due to DxWnd.

Interestingly enough I am also using DxWnd for Wargames, which is likely why this issue is happening to that game. You can see my write up on how I got Wargames to run on Windows 10 here.

narzoul commented 7 years ago

Errors related to setting video mode are usually related to the DWM 8/16 bit mitigation shim not getting applied for some reason. I've been working on a solution in DDrawCompat for that, but until that's ready you could try setting "Reduced colour mode: 16-bit (65536 colour)" on Client.exe's Compatibility properties.

elishacloud commented 7 years ago

I think you are right about the 8-bit/16-bit color mode. At one point I remember it saying that it could not set a 16-bit color mode. However I tried both "Reduced color mode: 16-bit (65536 color)" mode and "Reduced color mode: 8-bit (256 color)" mode and neither one worked for me. The only way I have been able to get it to run is using DxWnd. But even with DxWnd I need to enable the "Set 16BPP RGB565 encoding" for the game to run right.

narzoul commented 7 years ago

Black screen issue should be fixed completely, and I've also added 8/16 bit display mode handling directly to DDrawCompat now, which will hopefully fix the issue with Blood 2 for you. Check the latest experimental release and let me know if either of these fixes doesn't work properly for you.

elishacloud commented 7 years ago

Thanks for working on this! I tested all the games and the black screen issue is solved. Also Blood 2 works great, so the 8/16 bit display issue is fixed. However I did run into several issues testing the games.

Here are the issues I ran into with this experimental version:

  1. Several games crashed. Two of the games crashed when I pressed Alt+Tab or tried to switch out of the game. Warhammer 40k: Chaos Gate was probably the worst since it crashes whenever I try and start the mission so it is basically unplayable. It works fine with v0.2.1.
  2. Twice after exiting a game the font in Windows Explorer was huge, like the scaling was turned all the way up. One of the times when this happened I had to go to the scaling settings and set it up and then back down for the problem to go away. The other time it went away by itself after a few seconds. However, I am not completely sure if is this is a DDrawCompat issue or not.
  3. In Close Combat IV the "Yes" and "No" buttons are missing. It works fine with v0.2.1.

Here is what it looks like with the experimental release:

cc4 2017-07-03 21-38-11-41

Here is what v0.2.1 looks like:

cc4 2017-07-03 21-38-11-41 normal

Since the initial issue is fixed I can close these and start a new issue if you prefer.

narzoul commented 7 years ago

You can continue here or start a new issue, doesn't really matter to me. Regarding what you posted so far:

  1. Please mention the list of games and how to reproduce the crash in each case (as you did for Chaos Gate already).
  2. I've never noticed this and DDrawCompat itself is not supposed to modify any DPI or font size settings. What's your default DPI and resolution on the desktop? Which games are affected? Maybe this has something to do with the DPI awareness setting of the application. Can you check if changing the DPI scaling behavior on the Properties/Compatibility page of the affected executables makes any difference?
  3. I can reproduce the issue with the demo, but for me it's the same even with the v0.2.1 release. It looks like the buttons are briefly drawn but immediately overwritten by the background. Should be fixable, I'll look into it.
elishacloud commented 7 years ago
  1. For Chaos Gate it loads the System32 version of ddraw.dll by default so I had to do a trick to get it to load the DDrawCompat version of the dll. See my writeup here. The other two games that crashed were Alien Nations and Conquest Frontier Wars.
  2. The issue here does look like it was related to DPI. I had this issue with Conquest Frontier Wars and, I think the other one was Patrician 3. But setting DPI to per-application setting and disabling fullscreen enhancements solved the issue (it also fixed the crash in Conquest Frontier Wars).
  3. Yes, you are right. I was not testing it properly with v0.2.1 because of the black screen issue with that version. It does appear to have a similar issue with DDrawCompat v0.2.1. But this is still an issue with DDrawCompat.
RevenantBob commented 7 years ago

Does this have something to do with "Game Mode"? This is a new feature in Creator Update that messes with how games run.

narzoul commented 7 years ago

Latest experimental release should fix the issue with the invisible buttons, please check.

@RevenantBob: Game Mode is disabled on my system, so I don't think it has anything to do with the black screen issue. It seems like Intel HD actually works fine even without the fix, so it may be something driver related.

elishacloud commented 7 years ago

This only seems to partially fix the issue with Close Combat IV. The Exit buttons now work ok now. However checkboxes and radio buttons still disappear from the Options page:

Without DDrawCompat: withoutddrawcompat

With DDrawCompat Experimental Version: withddrawcompat

In addition I did some more testing on Warhammer 40k: Chaos Gate and I found out if you disable the line of code to set the CPU to single core affinity then it stops crashing (at least with v0.2.1).

narzoul commented 7 years ago

The missing checkbox/radio button icons should be fixed. About the other issues:

Conquest: Frontier Wars: I couldn't get it to crash yet. Is there anything particular you do when it crashes?

Alien Nations: Frequently crashes on the load screen when loading a map, however every time I checked the crash with a debugger, the problem was in winmm.dll and there was no DirectDraw activity at the moment. So I think the culprit is winmm.dll. Several other GOG releases have problems with it on Windows 10. Usually the games don't even start when that dll is present. Removing it seems to solve the crashes in Alien Nations, but then music doesn't work. There is a version of that wrapper floating around the net that should be compatible with Windows 10 (search for "winmm windows 10" or something like that), which might work better. I think I've even seen the source code somewhere but I can't find it now...

Warhammer 40k: Chaos Gate: This is a bit more complicated. It loads DirectDraw through CoCreateInstance or a similar function rather than calling DirectDrawCreate(Ex) directly. When doing this, it won't actually go through DirectDrawCreate to initialize the object, so DDrawCompat misses the initial install of its hooks. But it seems DirectDrawCreate does get called at a later point and when this happens, the hooks of the kernel mode thunks that now get installed won't know which driver to route the calls to because the device creation hook that records this info was not executed earlier.

I suspect enabling multiple CPU cores helps because the reloading of the device driver and unloading the previous instance are happening in parallel threads at the same time, and running on multiple cores gives a better chance of the unloading to finish before the loading thread installs the kernel thunk hooks. Although I haven't fully investigated this as I'm sure it's not the correct solution.

The proper way out of this is to hook the DllGetClassObject function of the system ddraw.dll module, which will be the first function COM must call before it can instantiate any DirectDraw interfaces. So this is another entry point where the hooks could get installed. But as you noted this would have to be implemented in a different dll because COM always loads the system ddraw.dll only, bypassing any DirectDraw wrapper in the game directory. (It actually takes the path of the loaded dll from the registry so it could be overwritten, but changing system entries in the registry just for this is certainly not the right way to go.)

dplayx.dll can work for this purpose for this specific title, but maybe not for others. I think a better pick would be dciman32.dll, which is always loaded by the system ddraw.dll itself and it looks like nothing else really uses it. It's also a legacy component so its export table is unlikely to change (looks like it hasn't changed since at least WinXP). It would actually be possible to move the entire wrapper implementation into this dll and discarding the ddraw.dll wrapper. However I think it may be better to use it only for COM instantiation support, since there is a risk that Microsoft might remove dciman32.dll in future updates (perhaps integrating the few used functions completely into ddraw.dll). It's probably also cleaner from a user perspective as it will be less likely that a leftover ddraw.dll wrapper will cause compatibility issues with DDrawCompat.

elishacloud commented 7 years ago

First of all, thanks for the great details on this!

Conquest: Frontier Wars: It crashed when I started a new game and then pressed alt+tab. But it only crashed once and after I disabled high DPI setting it did not crash again. The issue may not be related to DDrawCompat.

Alien Nations: Yeah, interestingly enough I have the Windows 10 fixed winmm.dll for GOG games on my computer and it still crashes with this game. I was able to resolve the crash by enabling fullscreen option using dxwrapper, but I know it is not a proper fix. I will see if I can update my wrapper to fix this.

Warhammer 40k: Chaos Gate: Interesting. I should be able to hook the DllGetClassObject function with my wrapper and install the hooks then. Also adding a wrapper for dciman32.dll is a great idea. I will test this out and see how it works.

elishacloud commented 7 years ago

Warhammer 40k: Chaos Gate: Hooking the DllGetClassObject function solved the issue. You can see my code change here.

I will create a dciman32.dll wrapper later.

elishacloud commented 7 years ago

Hooking DllGetClassObject solved some issues I had with other games as well, such as Gangsters Organized Crime. It seems like Warhammer 40k: Chaos Gate is not the only game that had this issue.

Also I tried creating a dciman32.dll wrapper and it did not help with Warhammer 40k: Chaos Gate because I could not get Warhammer 40k: Chaos Gate to load the local dciman32.dll wrapper. It always loaded the system one.

narzoul commented 7 years ago

Indeed, the dciman32.dll idea doesn't seem to work. I guess COM does something to alter the DLL search order for loading the dependencies of component libraries.

After searching through a lot of other alternatives, I couldn't find any DLL that could be reliably hooked as a generic solution to similar problems. Alternative solutions that could be considered:

  1. Use ACT shims: not really user friendly and has to be done separately for each game that uses COM. May also conflict with existing ACT entries for these games.
  2. Write some generic process monitor/hooking tool that runs in the background and intercepts calls to e.g. LoadLibrary(Ex) to load ddraw.dll from the correct path. I think it's a bit too intrusive and not really something I'd like to do for now, only as a last resort.
  3. Registry editing: I quickly dismissed this earlier thinking you'd have to edit existing system registry entries, but it turns out this is neither possible (can't seem to edit the existing keys even as admin), nor necessary. You can create clones of the HKLM keys under HKCU and edit those instead, luckily COM seems to prefer the latter when both are defined. The following keys would need to be copied from HKLM\SOFTWARE\Classes\WOW6432Node\CLSID to HKCU\Software\Classes\Wow6432Node\CLSID (remove the Wow6432Node part in each path on 32 bit Windows): {3C305196-50DB-11D3-9CFE-00C04FD930C5} {593817A0-7DB3-11CF-A2DE-00AA00B93356} {D7B70EE0-4340-11CF-B063-0020AFC2CD35} Then just change the path under each copy from "%SystemRoot%\system32\ddraw.dll" to simply "ddraw.dll". This should allow loading wrappers from the app directory when present and still fall back to the system path otherwise.

I think I'm going to go with this last option, as it seems like the least complicated but still generic solution. I don't expect it would cause any unwanted side effects either, unless some other ddraw wrappers used the same approach for handling COM but with different paths.

elishacloud commented 7 years ago

Wow, great research! I agree with you that the third option is the best. But it does require the user to change his registry keys and it would only affect that one user account. So if the user's profile gets corrupted and he needs to rebuild it or a second user uses the computer they will need to modify the registry again.

From my tests I don't see any single dll that can be reliably used for all games. For me I use multiple dll wrappers and just hook the ddraw APIs from any of these dlls, as long as the hooks get set before the API call everything works well. At this point I have always been able to find at least one dll that can be used for this (even if it is a different dll for different games).

BTW: the missing checkbox/radio button icons are fixed in Close Combat IV. So from my perspective everything is good for this issue. I did find a potential issue with Gangsters Organized Crime when using the experimental version, but I need to test more and see if the issue is in DDrawCompat or somewhere else. I will open a new issue on that if needed. From my perspective everything in this issue is taken care of. I am going to go ahead and close this issue. Thanks!

UCyborg commented 6 years ago

Windows 8 is the first to use absolute paths for DLLs with COM interfaces. The paths under HKLM registry branch can be easily edited, just run regedit as TrustedInstaller. Process Hacker with TrustedInstaller plugin is one way. Slower and clunkier way would be taking ownership of the key you want to edit and giving Administrators group Full control permissions then restoring original permissions and ownership after you're done. Creative ALchemy modifies similar entries to allow its dsound.dll to be used. The application (ALchemy.exe) that copies dsound.dll to desired game folders does it on first launch.