switch between fullscreen/windowed

Started by
4 comments, last by codeToad 12 years ago
I'm resuming my game programming hobby after a long hiatus. I've just gone through all the beginner D3D tutorials in the DirectX11 SDK. I'm surprised to see there is no good explanation of how to switch between full-screen and windowed modes, other than using DXUT.

I don't want to use DXUT, as it seems like it would take a long time to learn all the DXUT helper methods (rather than spending that time actually doing programming).

I was surprised to discover that in the DXSDK Tutorial 07, you can switch between full-screen and windowed by pressing alt+enter. Once in windowed mode, you can also change the window size. However, I don't see any code to handle the WMINPUT or WMSIZE events. I find that really puzzling!

Does anyone have an explanation of how the tutorial code is able to handle mode-change and window-resizing? I'd like to be able to specify the full-screen resolution when going into full-screen mode. Also, it plays the Windows "ding" sound when you press alt+enter. I'd like to disable that too.

Thanks in advance!
Advertisement
Also, I have seen a couple posts on here talking about calling d3dDevice->Reset. MSDN does not list "Reset" as a member function of ID3D11Device, and it does not show up in my intellisense either. Is this something from an earlier version of D3D?
DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH


void initD3D(HWND hWnd)
{
DXGI_SWAP_CHAIN_DESC scd; // create a struct to hold various swap chain information

ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC)); // clear out the struct for use

scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferDesc.Width = SCREEN_WIDTH; // set the back buffer width
scd.BufferDesc.Height = SCREEN_HEIGHT; // set the back buffer height
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 1; // how many multisamples
scd.SampleDesc.Quality = 0; // multisample quality level
scd.Windowed = TRUE; // windowed/full-screen mode
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching

// ...


http://www.directxtu...11/B-A/BA4.aspx

I hope this helps.
For D3D11 you should initially set DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH, as explained above.

There are then two main things you must do.

The first is to call SetFullScreenState on your swapchain object. This will just switch the display mode to fullscreen, but doesn't change anything else relating to the mode. You've still got the same height, width, format, etc as before.

The second is to call ResizeTarget and ResizeBuffers (both again on the swapchain) to actually change the mode.

Here's where things can get a little bit more complex (although it's actually simple if you follow the logic of the design).

When switching from windowed to fullscreen I've found it best to call ResizeTarget first, then call SetFullScreenState.
When going the other way (fullscreen to windowed) you call SetFullScreenState first, then call ResizeTarget.
When just switching modes (but leaving fullscreen state alone) you just need to call ResizeTarget.

These orders may not be 100% necessary (I haven't found anything in the documentation to confirm or deny) but I've found through trial, error and experimentation that they work and give predictable behaviour. Otherwise you may get extra mode changes which slow down the process, and may get weird behaviour.

In all cases, you should ensure that the mode you're switching to has been properly enumerated (via EnumAdapters/EnumOutputs/GetDisplayModeList) - it's not necessary for switching to a windowed mode, but is highly recommended for switching to a fullscreen mode, and makes things easier overall.

Following that you need to respond to WM_SIZE in your message loop; when you recieve a WM_SIZE you just need to call ResizeBuffers in response to it. That bit is optional but if you leave it out you're keeping the old framebuffer sizes, meaning that D3D11 has to do a stretch operation to the buffers, which can degrade performance and quality. If you need to destroy any old render targets/depth stencils/etc and create new ones at the new mode resolution, this is also a good place to do it.

One thing I've left out until now is that your context will hold references to render targets/etc so before calling ResizeBuffers you need to call ID3D11DeviceContext::ClearState to release those references (or you could just call OMSetRenderTargets with NULL parameters - I haven't personally tested this but logic says that it should work), then release your render target view, otherwise ResizeBuffers will fail. When done, set everything up again (you don't need to recreate anything that you don't explicitly destroy yourself though). If you're using a depth buffer also release and recreate it (both the view and the texture).

There's a pretty good writeup, with sample code and other useful info, of the process in the SDK documentation under the heading "DXGI Overview", but unfortunately the help file index seems to be - shall we say - not quite as good as it once was these days, so you may need to use the Search function. A search for ResizeBuffers should give you this article as the first hit with the June 2010 SDK.

Direct3D has need of instancing, but we do not. We have plenty of glVertexAttrib calls.

Thanks for the detailed post, mhagain. I haven't got the ResizeBuffers call working yet, but I'm sure I'll get it.
Ok - I figured out the ResizeBuffers call. Basically I looked at the InitDevice() method from tutorial 07, and moved all the calls to g_pImmediateContext->SomeMethod() into a new method called Initialize().

My Initialize() method is called both from InitDevice(), and from my WMSIZE handler. Next I will have to figure out how to use an enumerated resolution and refresh rate, rather than hardcoded values.

You're right about the SDK documentation - back in DX8 they had a sample app that showed how to do all this stuff, without any of that ugly DXUT code.smile.png

This topic is closed to new replies.

Advertisement