[D3D12]SRGB Buffer Format for Swap Chain

Started by
2 comments, last by DustinB 8 years, 1 month ago

Hi,

I'm trying to set up a swap chain with an SRGB buffer format using Direct3D 12. The exact same code below both works when the buffer format does not have an _SRGB suffix and fails when the buffer format does have an _SRGB suffix. The commented out section is the only thing that changes.

I've enumerated my adapters and outputs and there are definitely results being returned for DXGI_FORMAT_R8G8B8A8_UNORM_SRGB (about 40, in fact). I'm also creating the device by specifying the adapter to use, which (through enumerating) I've verified is the correct one for my card.

Is anyone aware of an issue I may have missed in the documentation that enforces new limitations on buffer formats for swap chains?

Swap chain description and setup call. For what it's worth, the below code works perfectly in my DirectX 11 initialization routine using the _SRGB format for the buffers.


                DXGI_SWAP_CHAIN_DESC swapChainDesc;
		ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
		swapChainDesc.BufferDesc.Width = clientWidth;
		swapChainDesc.BufferDesc.Height = clientHeight;
		swapChainDesc.BufferDesc.RefreshRate.Numerator = 0u;
		swapChainDesc.BufferDesc.RefreshRate.Denominator = 0u;
		swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // _SRGB
		swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
		swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
		swapChainDesc.SampleDesc.Count = 1u;
		swapChainDesc.SampleDesc.Quality = 0u;
		swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		swapChainDesc.BufferCount = m_frameCount;
		swapChainDesc.OutputWindow = window.getHWND();
		swapChainDesc.Windowed = true;
		swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
		swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;

		IDXGISwapChain* pSwapChainPtr{nullptr};
		hr = pFactory->CreateSwapChain(m_pCommandQueue.get(), &swapChainDesc, &pSwapChainPtr);
		if(FAILED(hr))
		{
			getLogger().error(L"Unable to create the IDXGISwapChain.");
			return false;
		}

Thanks,

WFP

Advertisement
There was a similar issue with DXGI 1.3 and Direct3D 11.2, though I can't find the msdn page about it immediately. Essentially the dxgi format for swapchain buffers is restricted to a few basic formats.

The solution is the same for D3D12 as it was for D3D11.2. You leave the swapchain format as DXGI_FORMAT_R8G8B8A8_UNORM, but change the render target view's format to DXGI_FORMAT_R8G8B8A8_UNORM_SRGB. Basically you tell the rendering pipeline to access the non-srgb buffer as if it was srgb.

Edit:

Tracked down the msdn page that mentions it: DXGI_MODE_DESC. The last two paragraphs note the format restrictions for flip mode swap chains, and mentions using an SRGB version of that format in the RTV for gamma correct rendering with them.

backstep - Thank you so much. I've been using DXGI_SWAP_EFFECT_DISCARD for so long now that I had never dug too far into the documentation for the FLIP models. Keeping the swap chain format without _SRGB and enabling it through the render target view works great.

Here's the code to do just that. Adding it here for future reference.

Setup swapchain to use standard format R8G8B8A8_UNORM


DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
// other settings ...

.

Create a RenderTargetView of the swapchain buffers using sRGB format.


// Setup RTV descriptor to specify sRGB format.
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;

// Create a RenderTargetView for each frame.
for (uint n = 0; n < FrameCount; n++)
{
    ThrowIfFailed (
        swapChain->GetBuffer(n, IID_PPV_ARGS(&renderTargets[n]))
    );

    device->CreateRenderTargetView(renderTargets[n].Get(), &rtvDesc, rtvHandle);
    rtvHandle.Offset(1, m_rtvDescriptorSize);
}

.

Then set the same sRGB format within the PSO.


D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
// other settings ...

This topic is closed to new replies.

Advertisement