DX11 vs DX12 Swapchain Present

Started by
4 comments, last by Enzio599 4 years, 5 months ago

Hi!

I'm working on a third-party plugin/driver which renders through either D3D11 or D3D12 in either exclusive fullscreen or windowed mode.

I have performance problems with SwapChain::Present in case of D3D12.
Both for D3D11 and D3D12, I create a swap chain with 2 backbuffers with _DISCARD swapchain effect and call pSwapChain→Present (0, 0) at the end of the frame.

For the sake of the test, I do all rendering in the main thread. Looking at the threads in the task manager reveals the following:
- With D3D11, the thread crawls at maximum speed (~12% on my machine), giving very high FPS's (1000+)
- With D3D12, the thread crawls at the half of the maximum speed (~6-7%), giving much less FPS's

Using Concurrency Visualizer to determine where the thread is being blocked, I realized that swapchain::Present itself is where the blocking occurs. I just can't figure it out why. The timeline of the thread is full of ‘waiting holes’, see the attached image. The hw is a Geforce GTX 1060:

Swapchain::Present with a Geforce GTX 1060 (D3D12)


To make sure that it's not a driver problem, I ran my app on an Intel HD too, and encountered the same phenomenon. Using Concurrency Visualizer again, I got this:

Swapchain::Present with an IntelHD 530 (D3D12)

Interestingly, with this driver the Present goes through d3d11 even with d3d12, but again, there is a wait on a present mutex or something like that. It's so bad that even breaking into the rendering by pressing F12 in Visual Studio gives me the stack above in most cases, indicating it spends very much time in the blocking.

My question: why is that and how can I avoid that?
Since I create my swapchain with DXGI_SWAP_EFFECT_FLIP_DISCARD and call Present (0, 0), I'd expect to not have any blocking in the rendering process (aside from some waiting on fences during executing command lists).

Advertisement

Are you creating the swap chain with DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING?

Also, at least in DX12 you need to pass the DXGI_PRESENT_ALLOW_TEARING flag to present to be truly free from the vertical sync.

Make sure to check these settings before you do any additional testing. It might just be that you're blocked by the v-sync.

Thanks for your reply!
No, I don't create it with DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING.
My swapchaincreator code snippet is:|

DXGI_SWAP_CHAIN_DESC desc = {modeDesc, {1, 0}, DXGI_USAGE_BACK_BUFFER | DXGI_USAGE_RENDER_TARGET_OUTPUT, NUM_OF_BACKBUFFERS, renderWindow, TRUE, DXGI_SWAP_EFFECT_FLIP_DISCARD, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH };
					
pAdapterFactory->CreateSwapChain (adapter.pGraphCmdQueue->pCommandQueue, &desc, &swapchainData[idx].pSwapChain);

where NUM_OF_BACKBUFFERS == 2.

I did a quick experiment with adding DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING in create and DXGI_PRESENT_ALLOW_TEARING on Present but the result is the same.

Also, I experimentally downloaded and tried HelloD3D12 sample from github and modified its code to remove vsyncing from it, for the “animated texture” test. It runs at full speed, reaching 3800-4000 FPS's without any blocking. It also doesn't use the TEARING effect and flag, just a plain swapchain:

	DXGI_SWAP_CHAIN_DESC swapChainDesc;
	::ZeroMemory (&swapChainDesc, sizeof (swapChainDesc));

	swapChainDesc.BufferCount = GetQueueSlotCount ();
	// This is _UNORM but we'll use a _SRGB view on this. See 
	// SetupRenderTargets() for details, it must match what
	// we specify here
	swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	swapChainDesc.BufferDesc.Width = window_->GetWidth ();
	swapChainDesc.BufferDesc.Height = window_->GetHeight ();
	swapChainDesc.OutputWindow = window_->GetHWND ();
	swapChainDesc.SampleDesc.Count = 1;
	swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
	swapChainDesc.Windowed = true;

	auto renderEnv = CreateDeviceAndSwapChainHelper (nullptr, D3D_FEATURE_LEVEL_11_0,
		&swapChainDesc);

with a plain →Present (0, 0);

Hmm interesting.

I still think that you're somehow still blocked because of some weird Swapchain setup. Especially since the stall seems to happen as an internal WaitForSingleObject inside the D3D12 driver.

Have a look at the tips here to see if anything applies to your setup.

https://developer.nvidia.com/dx12-dos-and-donts#swapchains

show us ur execute call of command list…

This topic is closed to new replies.

Advertisement