(Solved) Recreated DXGI swap chain has incorrect (previous) buffer dimensions

Started by
6 comments, last by Jmu 5 years, 7 months ago

Hi everyone, here's a fun one. I've been using DX11 for ages and I've never seen anything like this happen before.

I found a bug in an application I'm developing when changing the resolution in full-screen mode. In order to handle arbitrary display mode changes (such as changes to MSAA settings), I destroy and recreate the swap chain whenever the display mode changes (rather than just using IDXGISwapChain::ResizeBuffers and IDXGISwapChain::ResizeTarget).

On application startup, the device and initial swapchain are created via D3D11CreateDeviceAndSwapChain. When the display mode changes, this initial swap chain is destroyed, and a new one is created using IDXGIFactory::CreateSwapChain, with a new DXGI_SWAP_CHAIN_DESC.

What I've found is that, despite the new DXGI_SWAP_CHAIN_DESC being correct when supplied to IDXGIFactory::CreateSwapChain, if I then retrieve the desc from the resulting swap chain, it has values from the old one. For example, if the resolution is changed, the swap chain is created with new (correct) values for BufferDesc.Width and BufferDesc.Height, but this new swap chain contains the old values which the initial (now destroyed) swap chain desc had.

Consequently the back buffer is the wrong size, which leads to obvious problems and errors.

Has anyone encountered a similar situation, or can think of anything useful to investigate?

Here's a simplified version of the code for the display mode change:


m_pDeviceContext->ClearState();
m_pDeviceContext->OMSetRenderTargets(0, nullptr, nullptr);

m_pSwapChain->Release();
m_pSwapChain = nullptr;

IDXGIFactory *pFactory = nullptr;
CheckResult(CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast<void **>(&pFactory)));

IDXGISwapChain *pSwapChain = nullptr;
DXGI_SWAP_CHAIN_DESC swapChainDesc = CreateSwapChainDesc(...); // Returns populated DXGI_SWAP_CHAIN_DESC with correct values.
CheckResult(pFactory->CreateSwapChain(impl.m_pDevice, &swapChainDesc, &pSwapChain));

DXGI_SWAP_CHAIN_DESC verifySwapChainDesc;
ZeroMemory(&verifySwapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
pSwapChain->GetDesc(&verifySwapChainDesc);

// swapChainDesc does not equal verifySwapChainDesc.

 

Advertisement

I should also add that I've gone through the best practices docs here: https://docs.microsoft.com/en-us/windows/desktop/direct3darticles/dxgi-best-practices

In particular, I've made sure to specify DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH in DXGI_SWAP_CHAIN_DESC.Flags.

The best practices docs do describe cases where DXGI may default to the desktop resolution despite the numbers supplied via DXGI_SWAP_CHAIN_DESC, which sounds pretty similar to what I'm seeing. Unfortunately though I can't see what rules I'm breaking.

My list of possible suspects:

1. Something wrong in the CreateSwapChainDesc() function;

2. You are not getting the DXGI factory from the D3D11 device.

 

Hi Aerodactyl55, thanks for your response. I'm continuing to investigate possible invalid parameters set in CreateSwapChainDesc(), but I'm interested in your second point. I'll try acquiring the IDXGIFactory through the device and report back.

Unfortunately this has not resolved the issue. I tried replacing the DXGI factory creation:


DXGIFactory *pFactory = nullptr;
CheckResult(CreateDXGIFactory(__uuidof(IDXGIFactory), reinterpret_cast<void **>(&pFactory)));

With this access code:


IDXGIDevice *pDXGIDevice = nullptr;
IDXGIAdapter *pDXGIAdapter = nullptr;
IDXGIFactory *pFactory = nullptr;
impl.m_pDevice->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void **>(&pDXGIDevice));
pDXGIDevice->GetAdapter(&pDXGIAdapter);
pDXGIAdapter->GetParent(__uuidof(IDXGIFactory), reinterpret_cast<void **>(&pFactory));

Thanks anyway! I'll continue to investigate CreateSwapChainDesc() and report back with whatever I find.

OK then, somethings to look at:

  1. Enable the debug layer (by creating your device with D3D11_CREATE_DEVICE_DEBUG flag) and see if there is any information regarding your issue (if using visual studio you may need to scroll the output window to see the messages);
  2. If you are creating your swap chain in full screen mode, try setting it to windowed mode before releasing;
  3. Assuming that somewhere in your code you created a render target view, make sure you release them before recreating the swap chain;

Honestly I don't use this approach of recreating the swap chain, I use the ResizeTarget/ResizeBuffers method. Hope that helps.

Thanks again for your help. I've found a fix/workaround based on the following advice from the documentation here: https://docs.microsoft.com/en-us/windows/desktop/api/dxgi/nf-dxgi-idxgifactory-createswapchain

Quote

Because the target output can't be chosen explicitly when the swap chain is created, we recommend not to create a full-screen swap chain. This can reduce presentation performance if the swap chain size and the output window size do not match. Here are two ways to ensure that the sizes match:

  • Create a windowed swap chain and then set it full-screen using IDXGISwapChain::SetFullscreenState.

So I now ensure that the swap chain is created in windowed mode, then set to full-screen via SetFullscreenState as a later step in the swap chain recreation function.

This seems like a soft rule however, as setting the full-screen state in DXGI_SWAP_CHAIN_DESC does work for me under some conditions.

This topic is closed to new replies.

Advertisement