Properly Handling Alt-Enter / Alt-Tab Fullscreen Resolution
Asked Answered
A

2

6

The MSDN page on DXGI gives instructions on how to handle fullscreen resolutions different from the desktop resolution. It says to call IDXGISwapChain::ResizeTargets() before calling IDXGISwapChain::SetFullscreenState() to prevent flickering, among other things.

It does not say how to handle Alt-Enter, which calls IDXGISwapChain::SetFullscreenState() before the program is given a chance to make its own call to IDXGISwapChain::ResizeTargets(). If the latter method is called upon a WM_SIZE message, another WM_SIZE message will be sent, possibly causing an infinite loop. How can I ensure that the latter will be called before the former when alt-enter or alt-tab are pressed, and that mode switching occurs painlessly in general?

Autodidact answered 18/8, 2014 at 17:52 Comment(0)
T
10

This is going to be really tricky ... the right way how this is supposed to be handled is IDXGIFactory::MakeWindowAssociation, which, as far as I know, nobody has managed to use successfully. You may want to try it anyway.

The "right" answer is to manually handle Alt+Enter. So, disable Alt+Enter using MakeWindowAssociation and get your hands dirty. First, there is no need to capture WM_SIZE. Instead, listen on WM_ENTERSIZEMOVE, WM_CAPTURECHANGED, WM_WINDOWPOSCHANGED and WM_EXITSIZEMOVE. This will prevent you from having to deal with WM_SIZE and still get all relevant window resizing events. (When doing this, read this question as well: WM_ENTERSIZEMOVE / WM_EXITSIZEMOVE - when using menu, not always paired)

Ok, so assuming everything went fine, for Alt+Enter, you have to do the following: You set your swap chain to full screen using IDXGISwapChain::SetFullscreenState and then resize your swap chain (IDXGISwapChain::ResizeBuffers). By default, you'll get a swap chain which is as close as possible to the current resolution of your window before resizing. The way you do this properly is to enumerate the full screen resolutions first, and upon going fullscreen, forcing the resolution you want to have. This sounds ugly, but it seems to be the most robust way to solve the problem.

In general, real, exclusive fullscreen mode is not worth the trouble, as you will always get flickering when someone goes Alt+Tab (you can't avoid it if a mode switch happens, as the screen itself will have to readjust.) A much better solution is to use a fullscreen borderless window. You simply create a window class without any decoration, make it full-screen, place it such that it covers the whole screen and be done with it. Then you don't have to worry about Alt+Enter and Alt+Tab at all. It also allows people to continue working on a second screen without flickering. Performance wise, this is pretty ok'ish (most new games support this as "borderless fullscreen".)

There might be a silver bullet which solves all of this correctly, but I haven't seen it yet. If there is a cleaner/nicer solution, I'd be really curious to hear it. "Borderless fullscreen" seems to be the current standard though, IIRC, Unity 5 will only allow "borderless fullscreen" for Direct3D 11.

Tinct answered 18/8, 2014 at 18:5 Comment(5)
Just an update - I was able to accomplish what I wanted with just WM_SIZE. There is a bit of a hack involved, but it's only one line and doesn't really hurt. When WM_SIZE is called, I check if the render target view exists before adjusting the buffers. This way, I don't run into null pointer errors on window creation. Everything else was done as you said, though.Autodidact
How exactly do you handle ALT+Enter though? You said to disable ALT+ENTER in MakeWindowAssociation, but ALT+ENTER does not trigger any of the messages mentioned in your answer.Towrope
For keyboard input use the "Normal" stuff, i.e. either WM_*KEYDOWN or Raw input. It doesn't require a special message.Tinct
"exclusive fullscreen mode is not worth the trouble" It is worth the trouble for the players. It is a must for any fast-paced games: you don't want Desktop Window Manager to force that VSync with triple buffering on your players and inability to switch to true fullscreen. Windowed or Borderless Windowed is an abomination for any app where you need to do something quickly. Don't do your player base like that. Always add true fullscreen support if they ever have to react to anything in your game or just do something quickly.Industrials
The "FLIP" presentation model allows you to bypass the DWM even when you're running in borderless window mode, so you're not getting any benefits from exclusive. The only reason to worry about exclusive is when you need to toggle HDR and you can't rely on the desktop being in HDR mode.Tinct
A
3

I just want to add an update on this issue - I've written a small windowing library that I believe handles DXGI pretty well - no debug messages, no error messages, and everything behaves as intended, at least on my Windows environment. The full solution to this problem is much too complex to explain in a single answer, since it requires a lot of precisely placed method calls (DXGI is really, really rigid as it turns out), but I have my code up on github if anyone wants to take a look at it. Specifically, this file and this file are the ones you want to look at - the latter being an aggregate object of the former.

Note that I have disabled ALT+ENTER in favor of F11, but the functionality is exactly the same.

If you want to use that library, by the way, I am releasing it as free software and will provide documentation soon.

Autodidact answered 6/7, 2015 at 16:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.