Maico De Blasio
Maico De Blasio

Reputation: 308

Is it possible to combine HDR with MSAA in a DirectX 12 desktop application?

Using the DirectX Tool Kit for DirectX 12, I'm able to successfully compile and run the individual MSAA and HDR tutorial samples. When I combined the relevant code for the MSAA and HDR components together into a single Game.cpp file however, compilation fails with the debug layer message:

D3D12 ERROR : ID3D12CommandList::ResolveSubresource : The specified format is not compatible with the source resource.Format : R10G10B10A2_UNORM, Source Resource Format : R16G16B16A16_FLOAT [RESOURCE_MANIPULATION ERROR #878: RESOLVESUBRESOURCE_INVALID_FORMAT]

I am using the HDR sample code for an SDR display monitor, and therefore need to apply tone mapping. With respect to the order in which calls are made, I make a call to end the HDR scene before attempting to resolve the MSAA render target:

// 3d rendering completed
m_hdrScene->EndScene(commandList);

if (m_msaa)
{
    // Resolve the MSAA render target.
    //PIXBeginEvent(commandList, PIX_COLOR_DEFAULT, L"Resolve");

    auto backBuffer = m_deviceResources->GetRenderTarget();
    ...

Then following the MSAA resolve block, I place the tone mapping statement as follows:

// Unbind depth/stencil for sprites (UI)
auto rtvDescriptor = m_deviceResources->GetRenderTargetView();
commandList->OMSetRenderTargets(1, &rtvDescriptor, FALSE, nullptr);

// set texture descriptor heap in prep for sprite drawing
commandList->SetDescriptorHeaps(static_cast<UINT>(std::size(heaps)), heaps);

// apply tonemapping to hdr scene
switch (m_deviceResources->GetColorSpace())
{
default:
    m_toneMap->Process(commandList);
    break;
...

I found that attempting to tone map before setting the descriptor heap for drawing 2D sprites (over the 3D scene) would result in the error:

D3D12 ERROR: CGraphicsCommandList::SetGraphicsRootDescriptorTable: The descriptor heap (0x0000025428203230:'DescriptorHeap') containing handle 0x80000253a82ff205 is different from currently set descriptor heap 0x0000025428203540:'EffectTextureFactory'. [ EXECUTION ERROR #708: SET_DESCRIPTOR_TABLE_INVALID] D3D12: BREAK enabled for the previous message, which was: [ ERROR EXECUTION #708: SET_DESCRIPTOR_TABLE_INVALID ]

I admit this was a rather naive first attempt to combine HDR and MSAA, but I'm concerned that these features could be incompatible and/or mutually exclusive in DirectX 12. I understand why a resource compatibility issue arises during MSAA resolve, as we need to use floating point render targets for HDR. I should note that my program will run and render correctly with HDR if I skip the MSAA code blocks by setting my m_msaa boolean to false.

Looking forward to any advice anyone may have. If sufficient code or other details about the program are required, I'll be happy to update my post.

Upvotes: 0

Views: 732

Answers (2)

Maico De Blasio
Maico De Blasio

Reputation: 308

To successfully render a HDR scene with 4xMSAA, I made the following revisions:

  1. In CreateWindowSizeDependentResources(), the MSAA render target (and view) are defined with the same format as the HDR render texture:

     // Create an MSAA render target.
     D3D12_RESOURCE_DESC msaaRTDesc = CD3DX12_RESOURCE_DESC::Tex2D(
     //m_deviceResources->GetBackBufferFormat(),
     m_hdrScene->GetFormat(), // set matching format to HDR target (_R16G16B16A16_FLOAT)
     backBufferWidth,
     backBufferHeight,
     1, // This render target view has only one texture.
     1, // Use a single mipmap level
     4  // <--- Use 4x MSAA
     );
     ...
    
  2. The next major change is in Render(), where the MSAA resolve to the HDR target occurs after ending the HDR scene render and before the tone mapping process:

     // Resolve the MSAA render target.
     auto backBuffer = m_deviceResources->GetRenderTarget();
     auto hdrBuffer = m_hdrScene->GetResource(); // HDR destination texture
    
     {
         D3D12_RESOURCE_BARRIER barriers[2] =
         {
             // transition msaa texture from target to resolve source
             CD3DX12_RESOURCE_BARRIER::Transition(
                 m_msaaRenderTarget.Get(),
                 D3D12_RESOURCE_STATE_RENDER_TARGET,
                 D3D12_RESOURCE_STATE_RESOLVE_SOURCE),
             // transition hdr texture from pixel shader resource to resolve destination
             CD3DX12_RESOURCE_BARRIER::Transition(
                 hdrBuffer,
                 D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
                 D3D12_RESOURCE_STATE_RESOLVE_DEST)
         };
    
         commandList->ResourceBarrier(2, barriers);
     }
    
     //commandList->ResolveSubresource(backBuffer, 0, m_msaaRenderTarget.Get(), 0,
     //    m_deviceResources->GetBackBufferFormat());
    
     // resolve MSAA to the single sample 16FP resource destination
     commandList->ResolveSubresource(hdrBuffer, 0, m_msaaRenderTarget.Get(), 0,
         m_hdrScene->GetFormat());
    
     // prepare backbuffer for 2D sprite drawing, typically rendered without MSAA
     {
         D3D12_RESOURCE_BARRIER barriers[2] =
         {
             // transition hdr texture from resolve destination back to p.s resource
             CD3DX12_RESOURCE_BARRIER::Transition(
                 hdrBuffer,
                 D3D12_RESOURCE_STATE_RESOLVE_DEST,
                 D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE),
             // transition backbuffer from Present to render target (for sprite drawing after the MSAA resolve)
             CD3DX12_RESOURCE_BARRIER::Transition(
                 backBuffer,
                 D3D12_RESOURCE_STATE_PRESENT,
                 D3D12_RESOURCE_STATE_RENDER_TARGET)
         };
         commandList->ResourceBarrier(2, barriers);
     }
    
     ... do tone mapping
     ... do 2D sprite drawing
    

Output was to a conventional 1080p display (no HDR10 or V-Sync). The LHS screen capture is a HDR scene without MSAA, whereas the RHS capture shows the smoothing effect of 4xMSAA on the 3D wireframe objects, kettle & earth models, and triangle billboard. The cat and 'Hello World' text are 2D sprites drawn to the backbuffer after MSAA resolve and tone mapping.

Thanks again to @ChuckWalbourn for pointing me in the right direction, and I look forward to progressing my projects with the DirectX Tool Kit.

Upvotes: 1

Chuck Walbourn
Chuck Walbourn

Reputation: 41127

ResolveSubresource cannot do the conversion from 16fp to 10:10:10:2 HDR10.

Generally you need to:

  1. Render to MSAA floating-point in High Dynamic Range (linear color space)
  2. Resolve MSAA to single-sample floating-point. (Many games choose to use advanced software antialiasing techniques as part of this process such as FXAA, SMAA, etc.)
  3. Perform the tone-map and Rec.2020 colorspace conversion from floating-point to 10:10:10:2
  4. Display HDR10

Rendering the UI sometimes happen before step 3, other times after. If done before, you typically have to 'scale up' the UI colors to make them stand out.

See the SimpleMSAA DX12 and SimpleHDR DX12 samples for the technical details.

DirectX Tool Kit includes a PostProcess class which can perform the HDR10 tone-map. See this tutorial.

Upvotes: 0

Related Questions