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

How to mix GDI and Direct3D #269

Closed
elishacloud opened this issue Dec 6, 2023 · 17 comments
Closed

How to mix GDI and Direct3D #269

elishacloud opened this issue Dec 6, 2023 · 17 comments

Comments

@elishacloud
Copy link

There is a long standing issue that was caused in an update to Windows 10 a few years ago (specifically in Windows 10 Fall Creators Edition) and still manifests itself in Windows 11. The issue is that once you call Present() onto a window from Direct3D9 when running in exclusive fullscreen mode it will overwrite all GDI on the screen. Even if later you try and draw things in GDI then it will not be seen at all.

This used to work, and according to the Microsoft documentation this should work. It also works fine on Direct3D8 (and older) and on DirectDraw (as you know). But the issue only manifests itself if using Direct3D9 and exclusive fullscreen mode. The reason this is an issue is because I have been working to convert older Direct3D into Direct3D9 and some games play their video or show text on the screen using GDI, which completely disappears when upgrading it to Direct3D9.

I have already tried setting DisableMaxWindowedMode, which I thought should solve it but it does not. The only solution I have been able to come up with is to build a fullscreen windowed mode option. But this causes other issues.

There are some additional details about this here and in this thread starting here.

I know you are not an expert at Direct3D, but this question is not directly related to DirectD3, rather the interaction between things created in GDI vs Direct3D.

Any ideas or thoughts you have here would be appreciated.

@narzoul
Copy link
Owner

narzoul commented Dec 6, 2023

I thought that GDI hasn't worked in exclusive fullscreen mode since DWM was introduced, or at least not since Windows 8 when DWM became mandatory and borderless fullscreen mode was added for ddraw/D3D8. I don't have a way to verify this anymore, but I guess in Vista and 7 it worked because DWM could turn itself off, and on Windows 8+ it still works because ddraw and D3D8 run in borderless fullscreen mode by default. However, this is not the case for D3D9 according to this post:
https://www.vogons.org/viewtopic.php?p=624073#p624073

Unfortunately, I found no way to enable the same kind of borderless windowed presentation mode for D3D9 either. The shim and the registry settings don't seem to do anything.

I can reproduce the problem with Indiana Jones and the Emperor's Tomb. According to PresentMon, with native D3D8 it uses "Composed: Copy with GPU GDI", but with d3d8to9 it uses "Hardware Composed: Independent Flip", no matter what I do.

For comparison, DirectDraw natively also uses "Composed: Copy with GPU GDI" and can display GDI content and other top-level windows in fullscreen mode. With the DXPrimaryEmulation -DisableMaxWindowedMode shim, the process doesn't show up in PresentMon, so I'm not quite sure what it uses, but I think it should be "Hardware: Legacy Flip", based on my memory from very old testing. In this mode, neither GDI rendering on the fullscreen window itself, nor any other top level windows above it are displayed (e.g. dialog windows or popup menus).

"Hardware Composed: Independent Flip" seems a bit different in that it allows other top level windows to show up, but I'm guessing it still prevents GDI from drawing on any window that uses a Direct3D 9 swapchain. Most likely, Independent Flip mode simply wasn't activated in older Windows versions, and now it seems rather difficult to get rid of.

There is some more info about the various presentation modes here: https://wiki.special-k.info/en/SwapChain

@narzoul
Copy link
Owner

narzoul commented Dec 6, 2023

I followed the registry changes (except for the GameDVR_FSEBehavior key, which I don't have) here:
https://www.reddit.com/r/pcgaming/comments/ck13z9/psa_windows_10_1903_will_now_ignore_the_disable/

After restarting my PC (not sure if needed), Indiana Jones now uses "Hardware: Legacy Flip" mode with d3d8to9, and indeed a top-level window is no longer visible above it (but the cursor still changes, so I know it's there). Unless the top-level window was already above the game window around the time when the game entered fullscreen mode, in which case it uses "Hardware Composed: Independent Flip" instead, and the other top-level window becomes visible again. What a mess...

However, I still couldn't figure out how to enable maximized windowed mode for D3D9.

@elishacloud
Copy link
Author

elishacloud commented Dec 6, 2023

I still couldn't figure out how to enable maximized windowed mode for D3D9

Here is some code I made to set maximized windowed mode for D3D9.

Edit: I tested this code and it did work in disabling maximized windowed mode.

@elishacloud
Copy link
Author

BTW: I also noticed that D3D9 creates a new window and puts that window at the top of all other windows. I caught this by hooking the CreateWindowEx() functions.

@narzoul
Copy link
Owner

narzoul commented Dec 7, 2023

Here is some code I made to set maximized windowed mode for D3D9.

Edit: I tested this code and it did work in disabling maximized windowed mode.

I mean we're looking for a way to enable it, not disable it. It should be disabled by default. With disabled, GDI won't work I think. It doesn't work with DirectDraw either, except in maximized windowed mode.

@elishacloud
Copy link
Author

I thought you could just call Direct3D9EnableMaximizedWindowedModeShim to enable it? When I looked at the code in a debugger it was set to '1' by default. When I set it to '0' it disables it. When I tested it last I could see a difference between the two modes.

@elishacloud
Copy link
Author

Maybe it has to do with the Direct3D9SetMaximizedWindowedModeShim?

@elishacloud
Copy link
Author

elishacloud commented Dec 7, 2023

Deleted.

@elishacloud
Copy link
Author

Sorry for the mistake in the last message. If I call Direct3D9SetSwapEffectUpgradeShim with a parameter of 0. Then the game runs and GDI can be seen on fullscreen exclusive mode.

@narzoul
Copy link
Owner

narzoul commented Dec 7, 2023

Well, I have no idea anymore. I've never heard of these shims before. What shim is supposed to call this function? I can't find any references to it. Does it change the presentation mode according to PresentMon?

@elishacloud
Copy link
Author

First of all, thank you for the response and looking into this. Your comments helped me search for this solution. I have never heard of these extra shims either.

PresentMon is showing as "Hardware: Legacy Flip" when I call Direct3D9SetSwapEffectUpgradeShim(0).

@elishacloud
Copy link
Author

Closing this for now. Thanks for your help here!

@elishacloud
Copy link
Author

Closing

@mirh
Copy link

mirh commented Dec 8, 2023

First time I hear about this shim.. Though I guess it makes sense it exists, considering microsoft wanted to uplift everything to flip.
Though, you should always interpret any windows 10 behaviour detail to be just a data point, only applying to the specific version/build that was tested (and even then with not that much of a strong confidence, considering just how contrived some conditional checks can be). See for instance the lost big epic of d3d8 exclusive fullscreen.

@elishacloud
Copy link
Author

only applying to the specific version/build that was tested (and even then with not that much of a strong confidence, considering just how contrived some conditional checks can be

Yeah. For this I check the following:

  1. Make sure it is a System32 dll.
  2. Load the address with the specific ordinal.
  3. Make sure the address is going to an unnamed ordinal.
  4. Add a dxwrapper option to disable this if needed in the future.

Hopefully, Microsoft will not remove this function and add a different hidden function with the same ordinal as this one was. I don't see that as very likely. I suspect if Microsoft creates other unnamed functions they will give them different ordinal numbers. There are plenty of numbers out there to use...

@mirh
Copy link

mirh commented Dec 10, 2023

I meant the conditions that triggers such or such behaviors to begin with (i.e. when conversely the fixes are required)
Not something that would concern you implementation-wise.
(I just mentioned the d3d8 thing because the linked comment in the second post wasn't exactly fresh)

@elishacloud
Copy link
Author

I meant the conditions that triggers such or such behaviors to begin with (i.e. when conversely the fixes are required)

When a game tries to display GDI (like a bik movie) to the screen when it is in Direct3D9 fullscreen exclusive mode then it just shows a black screen and nothing can be seen. This could also happen when a game writes text to the screen using GDI rather than DirectX and then game is in Direct3D9 fullscreen exclusive mode.

However, the issue here is that I need to call this Direct3D9SetSwapEffectUpgradeShim(0) before creating the d3d9 device, which also happens to be before the issue happens. Meaning I need to call this API before knowing whether I need to call it.

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

No branches or pull requests

3 participants