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

Fullscreen mode drops to windowed mode #5

Open
jsdpag opened this issue Dec 22, 2021 · 1 comment
Open

Fullscreen mode drops to windowed mode #5

jsdpag opened this issue Dec 22, 2021 · 1 comment

Comments

@jsdpag
Copy link

jsdpag commented Dec 22, 2021

StimServer.exe attempts to place its window in full-screen mode:

hr = pSwapChain->SetFullscreenState(TRUE, pOutput);

But there are many conditions in which full screen mode is automatically disabled by the OS, Windows. This is done whenever a window moves, even partially, onto the second monitor that has the StimServer.exe output screen. Even tooltips can trigger a drop to windowed mode.

A similar problem is described in a post to StackOverflow, called DirectX11 Swapchain and window losing fullscreen status.

Chuck Walbourn replies that:

This sounds like expected behavior. If you have a full screen 'exclusive' mode swapchain and the associated window loses focus, the system automatically switches the application out of full screen mode back to windowed mode by design.

as seemingly corroborated by blog D3D11 refusing to stay in full screen mode:

The particular battle I've been fighting this evening is DXGI "helpfully" detecting that another window has appeared on top and popping out of full screen mode. This avoids the common bug in Direct3D 9 where the program doesn't notice and keeps drawing over the entire screen even though it has lost foreground status.

and forum post SetFullScreenState fails:

full-screen mode switches back to windowed mode exactly on the next Present after setting the full-screen state.
The result of this present call was:
DXGI_STATUS_OCCLUDED: The target window or output has been occluded. The application should suspend rendering operations if possible. (142213121)

Hence, MS Windows is the culprit. This seems to be the quality of design that Microsoft developers aspire to.

Chuck goes on to say that ...

For a Windows desktop apps you have three choices for a full screen style experience:

  1. Use the traditional full screen 'exclusive' mode with a window sized to fill the display, along with setting the display mode which may not be what the user has set for Windows generally. Here you have IsWindowed = false.
  2. You set the window size to fill the full display (i.e. maximized). You can use windows styles to ensure that the window has no frame which results in a full screen style experience (WS_POPUP). Here you have IsWindowed = true, and you should be sure to set DXGI_MWA_NO_ALT_ENTER to avoid allowing DXGI to try to take you to use the 1 case.

2 ... allow[s] system notifications and other pop-ups to show up over the game and not force a mode switch. 2 ... also work[s] a lot better in multi-monitor setups where you can play your game on one display and use other apps on another display.

So, what is DXGI_MWA_NO_ALT_ENTER then?

We find information about this in IDXGIFactory::MakeWindowAssociation:

Allows DXGI to monitor an application's message queue for the alt-enter key sequence (which causes the application to switch from windowed to full screen or vice versa).

HRESULT MakeWindowAssociation(
  HWND WindowHandle,
  UINT Flags
);

Flags

Type: UINT

One or more of the following values.

  • DXGI_MWA_NO_WINDOW_CHANGES - Prevent DXGI from monitoring an applications message queue; this makes DXGI unable to respond to mode changes.
  • DXGI_MWA_NO_ALT_ENTER - Prevent DXGI from responding to an alt-enter sequence.
  • DXGI_MWA_NO_PRINT_SCREEN - Prevent DXGI from responding to a print-screen key.

Applications that want to handle mode changes or Alt+Enter themselves should call MakeWindowAssociation with the DXGI_MWA_NO_WINDOW_CHANGES flag after swap chain creation. The WindowHandle argument, if non-NULL, specifies that the application message queues will not be handled by the DXGI runtime for all swap chains of a particular target HWND. Calling MakeWindowAssociation with the DXGI_MWA_NO_WINDOW_CHANGES flag after swapchain creation ensures that DXGI will not interfere with application's handling of window mode changes or Alt+Enter.

This all sounds very promising.

Use of MakeWindowAssociation might be the solution, perhaps after fullscreen mode is invoked?

hr = pSwapChain->SetFullscreenState(TRUE, pOutput);

Chuck recommends flag DXGI_MWA_NO_ALT_ENTER, while MS recommends DXGI_MWA_NO_WINDOW_CHANGES. The latter sounds like a more fail-safe solution. But if the former works then it may be preferable, akin to using the lowest level of permissions that are required for an action.

As an aside, and as far as I can tell, MakeWindowAssociation is not used by either the Window's port of PsychToolbox using PsychOSOpenOnscreenWindow nor StimServer.exe in DisplayProcedure. Both appear to apply the same window attribute flags, though. Hence, it would be interesting to test whether a PsychToolbox window also flips out of fullscreen mode under the conditions that trigger this for StimServer.

NOTE: I'm told that even PsychToolbox windows pop out of fullscreen.

For debugging StimServer in my setup, I can use MessageBox( ) to generate feedback. It appears that MakeWindowAssociation( ) reports S_OK.

Of potential use ...

@jsdpag
Copy link
Author

jsdpag commented Jan 28, 2022

Right, so both myself and Michael tested:

hr = pFactory->MakeWindowAssociation( m_DirectXWnd.m_hWnd , DXGI_MWA_NO_WINDOW_CHANGES ) ;

It didn't work in either case (separate machines, VS 2019 & VS 2022). But perhaps there is something else that we haven't accounted for.

See https://docs.microsoft.com/en-us/windows/win32/direct3darticles/dxgi-best-practices

Multiple Monitors

When using DXGI with multiple monitors, there are two rules to follow.

The first rule applies to the creation of two or more full-screen swap chains on multiple monitors. When creating such swap chains, it is best to create all swap chains as windowed, and then to set them to full-screen. If swap chains are created in full-screen mode, the creation of a second swap chain causes a mode change to be sent to the first swap chain, which could cause termination of full-screen mode.

The second rule applies to outputs. Be watchful of outputs used when creating swap chains. With DXGI, the IDXGIOutput object controls which monitor the swap chain uses when becoming full-screen. Unlike DXGI, Direct3D 9 had no concept of outputs.

Although this is a different situation from what we face, it begs the question as to whether or not our swap-chain is created as windowed or full-screen, and whether this makes any difference at all.

I notice some other symptoms of our problem. A window that triggers this drop out of fullscreen mode remains behind what remains of the Stim Server window. Indeed, the z-order of the Stim Server window appears to remain above that of the window that triggers its mode change. Secondly, before dropping from fullscreen, the Stim Server window appears in the Alt + Tab list of windows. After the mode change, it is not in the Alt + Tab list.

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

1 participant