Reputation: 21
I'm trying to create Direct3D 10/11 application with support of full screen mode. In order to do so, I have to provide list of available video modes to user. Also, it would be great to choose current desktop settings as default video mode in order to minimize video mode changing.
It was very simple to do it in Direct3D 9. For example, here is my mode list, supplied by Direct3D 9:
Current mode: 1920x1080x60Hz 32bit X8R8G8B8
Available modes:
Front buffer format 32bit X8R8G8B8: 35
1: 1920x1080x60Hz
2: 640x480x60Hz
3: 640x480x72Hz
4: 640x480x75Hz
5: 720x480x56Hz
6: 720x480x60Hz
7: 720x480x72Hz
8: 720x480x75Hz
9: 720x576x56Hz
10: 720x576x60Hz
11: 720x576x72Hz
12: 720x576x75Hz
13: 800x600x56Hz
14: 800x600x60Hz
15: 800x600x72Hz
16: 800x600x75Hz
17: 1024x768x60Hz
18: 1024x768x70Hz
19: 1024x768x75Hz
20: 1152x864x75Hz
21: 1280x720x60Hz
22: 1280x768x60Hz
23: 1280x800x60Hz
24: 1280x960x60Hz
25: 1280x1024x60Hz
26: 1280x1024x75Hz
27: 1360x768x60Hz
28: 1366x768x60Hz
29: 1600x900x59Hz
30: 1600x900x60Hz
31: 1600x1024x59Hz
32: 1600x1024x60Hz
33: 1680x1050x59Hz
34: 1680x1050x60Hz
35: 1440x900x60Hz
But doing the same simple thing via DXGI is a little bit complicated. What confuses me the most, is the fact, that IDXGIOutpit.GetDisplayModeList method returns up to 3 copies of the same video mode. The difference is in scaling mode provided:
DXGI_MODE_SCALING_UNSPECIFIED = 0
DXGI_MODE_SCALING_CENTERED = 1
DXGI_MODE_SCALING_STRETCHED = 2
Here it is:
List of modes for format 32bit R8G8B8A8 UNorm:
640x480x60Hz Progressive Unspecified
640x480x72Hz Progressive Unspecified
640x480x75Hz Progressive Unspecified
720x480x56Hz Progressive Unspecified
720x480x56Hz Progressive Centered
720x480x56Hz Progressive Stretched
720x480x60Hz Progressive Unspecified
720x480x60Hz Progressive Centered
720x480x60Hz Progressive Stretched
720x480x72Hz Progressive Unspecified
720x480x72Hz Progressive Centered
720x480x72Hz Progressive Stretched
720x480x75Hz Progressive Unspecified
720x480x75Hz Progressive Centered
720x480x75Hz Progressive Stretched
720x576x56Hz Progressive Unspecified
720x576x56Hz Progressive Centered
720x576x56Hz Progressive Stretched
720x576x60Hz Progressive Unspecified
720x576x60Hz Progressive Centered
720x576x60Hz Progressive Stretched
720x576x72Hz Progressive Unspecified
720x576x72Hz Progressive Centered
720x576x72Hz Progressive Stretched
720x576x75Hz Progressive Unspecified
720x576x75Hz Progressive Centered
720x576x75Hz Progressive Stretched
800x600x56Hz Progressive Unspecified
800x600x60Hz Progressive Unspecified
800x600x72Hz Progressive Unspecified
800x600x75Hz Progressive Unspecified
1024x768x60Hz Progressive Unspecified
1024x768x70Hz Progressive Unspecified
1024x768x75Hz Progressive Unspecified
1152x864x75Hz Progressive Unspecified
1280x720x60Hz Progressive Unspecified
1280x768x59Hz Progressive Unspecified
1280x768x59Hz Progressive Centered
1280x768x59Hz Progressive Stretched
1280x800x59Hz Progressive Unspecified
1280x960x60Hz Progressive Unspecified
1280x1024x60Hz Progressive Unspecified
1280x1024x75Hz Progressive Unspecified
1360x768x59Hz Progressive Unspecified
1360x768x59Hz Progressive Centered
1360x768x59Hz Progressive Stretched
1366x768x59Hz Progressive Unspecified
1366x768x59Hz Progressive Centered
1366x768x59Hz Progressive Stretched
1440x900x59Hz Progressive Unspecified
1600x900x59Hz Progressive Unspecified
1600x900x59Hz Progressive Centered
1600x900x59Hz Progressive Stretched
1600x1024x59Hz Progressive Unspecified
1600x1024x59Hz Progressive Centered
1600x1024x59Hz Progressive Stretched
1680x1050x59Hz Progressive Unspecified
1920x1080x60Hz Progressive Unspecified
First I thought, that DXGI_MODE_SCALING_STRETCHED = this mode requires stretching (back buffer is smaller, then front one, resolution may be not physical), DXGI_MODE_SCALING_CENTERED = in this mode image may not occupy the whole screen (back buffer is smaller, then front one, but physical resolution is preserved), DXGI_MODE_SCALING_UNSPECIFIED = "normal mode" (sizes of back and front buffer match, but physical resolution is not guaranteed). I.e. I should show list only those modes, that has Scaling = DXGI_MODE_SCALING_UNSPECIFIED.
But then I tried to determine the current mode. According to MSDN, when using IDXGIOutput.FindClosestMatchingMode method, if you don't specify one of the parameters, then this method gravitates towards current desktop settings, prioritizing parameters, that are set and using some sort of priority (ScanlineOrdering>Scaling>Format>Resolution>RefreshRate) to choose other ones. So I created the device (in order to be able to specify format as DXGI_FORMAT_UNKNOWN) and passed fully undetermined mode to this method (including Scaling = DXGI_MODE_SCALING_UNSPECIFIED).
Here is the result:
Suggested mode: 32bit B8G8R8A8 UNorm 1600x1024x59Hz Progressive Stretched
Suggested mode 1.1: 32bit B8G8R8A8 UNorm 1600x1024x59Hz Progressive Stretched Mono
As you can see, it doesn't match the current desktop mode, which is 1920x1080x60Hz. I've tried to change current desktop mode to different one and found out, that IDXGIOutput.FindClosestMatchingMode tends to choose closest available mode with parameters, that are close to desktop parameters, but with Scaling = DXGI_MODE_SCALING_STRETCHED, simply ignoring Scaling = DXGI_MODE_SCALING_UNSPECIFIED, specified by me.
Current mode: 32bit B8G8R8A8 UNorm 1024x768x75Hz Progressive Unspecified
Suggested mode: 32bit B8G8R8A8 UNorm 1280x768x59Hz Progressive Stretched
Suggested mode 1.1: 32bit B8G8R8A8 UNorm 1280x768x59Hz Progressive Stretched Mono
This leaded me to a stunning conclusion, that DXGI_MODE_SCALING_UNSPECIFIED is treated as invalid value for Scaling parameter at least for IDXGIFactory.CreateSwapChain method (otherwise why IDXGIOutput.FindClosestMatchingMode, which is used to choose modes, that will be supplied to IDXGIFactory.CreateSwapChain in most cases, refuses to choose 1920x1080x60Hz?).
I guess that IDXGIFactory.CreateSwapChain even calls IDXGIOutput.FindClosestMatchingMode internally to determine, which "physical" mode to use. But then... What does it mean? I can't provide modes, that doesn't have Scaling = DXGI_MODE_SCALING_CENTERED or DXGI_MODE_SCALING_STRETCHED to user, cuz this modes are not "physical" ones - i.e. IDXGIFactory.CreateSwapChain will choose other mode anyway?
But then why DXGI_MODE_SCALING_UNSPECIFIED is returned in list of available modes? If Scaling parameter is used only when calling IDXGIFactory.CreateSwapChain method to specify whether I want to center image or scale it, if supplied mode doesn't match any "physical" one and it's unused when calling IDXGISwapChain.ResizeTarget, cuz this method requires "physical" modes only, then why Scaling parameters are mixed in one list, returned by IDXGIOutpit.GetDisplayModeList?
What modes should I show to user? Only those, that have Scaling <> DXGI_MODE_SCALING_UNSPECIFIED? Or should I do the opposite thing? And how to determine current mode via DXGI itself, instead of using legacy Win API?
Can anyone explain it to me? Cuz there is nothing clarified about it in MSDN.
Upvotes: 1
Views: 1092
Reputation: 21
This problem have been blowing my brain for a long time already, but suddenly, when I decided to ask somebody else about this question, I got an insight and answered my question by myself. My initial assumptions were right - the problem is in strange behaviour of DXGI or my video card's driver.
The problem is in fact, that for some unknown reasons DXGI or my video driver always treats my current desktop mode as DXGI_MODE_SCALING_STRETCHED instead of DXGI_MODE_SCALING_UNSPECIFIED. This is the root of all problems, cuz when "gravitate towards current desktop mode" comes into effect, the fact, that modes are being filtered by Scaling parameter fist, causes terrible result.
This is what happens:
My current desktop mode is
32bit B8G8R8A8 UNorm 1920x1080x60Hz Progressive Stretched (instead of Unspecified)
IDXGIOutput.FindClosestMatchingMode tries to find mode, closest to it, but filters by Scaling mode first. The problem is in fact, that there is no 1920x1080x60Hz mode with Scaling = DXGI_MODE_SCALING_STRETCHED. That's why instead of choosing 1920x1080x60Hz, it chooses closest mode with DXGI_MODE_SCALING_STRETCHED, which is 1600x1024x59Hz.
Upvotes: 1