是否可以在 DirectX 12 桌面应用程序中结合使用 HDR 和 MSAA?
Is it possible to combine HDR with MSAA in a DirectX 12 desktop application?
使用适用于 DirectX 12 的 DirectX 工具包,我能够成功编译和 运行 单独的 MSAA 和 HDR 教程示例。
但是,当我将 MSAA 和 HDR 组件的相关代码合并到一个 Game.cpp 文件中时,编译失败并显示调试层消息:
D3D12 错误:ID3D12CommandList::ResolveSubresource:指定格式与源不兼容 resource.Format:R10G10B10A2_UNORM,源资源格式:R16G16B16A16_FLOAT [ RESOURCE_MANIPULATION 错误 #878:RESOLVESUBRESOURCE_INVALID_FORMAT]
我正在为 SDR 显示器使用 HDR 示例代码,因此需要应用色调映射。关于调用顺序,我在尝试解析 MSAA 渲染目标之前调用结束 HDR 场景:
// 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();
...
然后在 MSAA 解析块之后,我将色调映射语句放置如下:
// 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;
...
我发现尝试在之前设置描述符堆以绘制 2D 精灵(在 3D 场景上)会导致错误:
D3D12 错误:CGraphicsCommandList::SetGraphicsRootDescriptorTable:包含句柄 0x80000253a82ff205 的描述符堆 (0x0000025428203230:'DescriptorHeap') 与当前设置的描述符堆 0x0000025428203540:'EffectTextureFactory' 不同。 [执行错误#708:SET_DESCRIPTOR_TABLE_INVALID]
D3D12:BREAK 为上一条消息启用,它是:[ ERROR EXECUTION #708: SET_DESCRIPTOR_TABLE_INVALID ]
我承认这是结合 HDR 和 MSAA 的第一次尝试,但我担心这些功能在 DirectX 12 中可能不兼容 and/or 互斥。我理解为什么会出现资源兼容性问题在 MSAA 解析期间,因为我们需要为 HDR 使用浮点渲染目标。我应该注意,如果我通过将我的 m_msaa 布尔值设置为 false 来跳过 MSAA 代码块,我的程序将 运行 并使用 HDR 正确渲染.
期待任何人的任何建议。如果需要足够的代码或有关该程序的其他详细信息,我很乐意更新我的 post.
ResolveSubresource
无法从 16fp 转换为 10:10:10:2 HDR10。
通常您需要:
- 在高动态范围内渲染为 MSAA 浮点(线性颜色 space)
- 将 MSAA 解析为单样本浮点数。 (许多游戏选择使用高级软件抗锯齿技术作为此过程的一部分,例如 FXAA、SMAA 等)
- 执行色调映射和 Rec.2020 颜色space 从浮点到 10:10:10:2
的转换
- 显示 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.
有关技术细节,请参阅 SimpleMSAA DX12 and SimpleHDR DX12 示例。
DirectX 工具包 包括一个 PostProcess
class 可以执行 HDR10 色调映射。参见 this tutorial。
为了使用 4xMSAA 成功渲染 HDR 场景,我进行了以下修改:
在 CreateWindowSizeDependentResources() 中,MSAA 渲染目标(和视图)使用与 HDR 渲染纹理相同的格式定义:
// 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
);
...
下一个主要变化是 Render(),其中 MSAA 解析为 HDR 目标 after结束 HDR 场景渲染和在色调映射过程之前:
// 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
输出到传统的 1080p 显示器(无 HDR10 或垂直同步)。左轴屏幕截图是没有 MSAA 的 HDR 场景,而右轴截图显示了 4xMSAA 对 3D 线框对象、水壶和地球模型以及三角形广告牌的平滑效果。
猫和 'Hello World' 文本是在 MSAA 解析和色调映射之后绘制到后台缓冲区的 2D 精灵。
再次感谢@ChuckWalbourn 为我指明了正确的方向,我期待着使用 DirectX 工具包推进我的项目。
使用适用于 DirectX 12 的 DirectX 工具包,我能够成功编译和 运行 单独的 MSAA 和 HDR 教程示例。 但是,当我将 MSAA 和 HDR 组件的相关代码合并到一个 Game.cpp 文件中时,编译失败并显示调试层消息:
D3D12 错误:ID3D12CommandList::ResolveSubresource:指定格式与源不兼容 resource.Format:R10G10B10A2_UNORM,源资源格式:R16G16B16A16_FLOAT [ RESOURCE_MANIPULATION 错误 #878:RESOLVESUBRESOURCE_INVALID_FORMAT]
我正在为 SDR 显示器使用 HDR 示例代码,因此需要应用色调映射。关于调用顺序,我在尝试解析 MSAA 渲染目标之前调用结束 HDR 场景:
// 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();
...
然后在 MSAA 解析块之后,我将色调映射语句放置如下:
// 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;
...
我发现尝试在之前设置描述符堆以绘制 2D 精灵(在 3D 场景上)会导致错误:
D3D12 错误:CGraphicsCommandList::SetGraphicsRootDescriptorTable:包含句柄 0x80000253a82ff205 的描述符堆 (0x0000025428203230:'DescriptorHeap') 与当前设置的描述符堆 0x0000025428203540:'EffectTextureFactory' 不同。 [执行错误#708:SET_DESCRIPTOR_TABLE_INVALID] D3D12:BREAK 为上一条消息启用,它是:[ ERROR EXECUTION #708: SET_DESCRIPTOR_TABLE_INVALID ]
我承认这是结合 HDR 和 MSAA 的第一次尝试,但我担心这些功能在 DirectX 12 中可能不兼容 and/or 互斥。我理解为什么会出现资源兼容性问题在 MSAA 解析期间,因为我们需要为 HDR 使用浮点渲染目标。我应该注意,如果我通过将我的 m_msaa 布尔值设置为 false 来跳过 MSAA 代码块,我的程序将 运行 并使用 HDR 正确渲染.
期待任何人的任何建议。如果需要足够的代码或有关该程序的其他详细信息,我很乐意更新我的 post.
ResolveSubresource
无法从 16fp 转换为 10:10:10:2 HDR10。
通常您需要:
- 在高动态范围内渲染为 MSAA 浮点(线性颜色 space)
- 将 MSAA 解析为单样本浮点数。 (许多游戏选择使用高级软件抗锯齿技术作为此过程的一部分,例如 FXAA、SMAA 等)
- 执行色调映射和 Rec.2020 颜色space 从浮点到 10:10:10:2 的转换
- 显示 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.
有关技术细节,请参阅 SimpleMSAA DX12 and SimpleHDR DX12 示例。
DirectX 工具包 包括一个 PostProcess
class 可以执行 HDR10 色调映射。参见 this tutorial。
为了使用 4xMSAA 成功渲染 HDR 场景,我进行了以下修改:
在 CreateWindowSizeDependentResources() 中,MSAA 渲染目标(和视图)使用与 HDR 渲染纹理相同的格式定义:
// 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 ); ...
下一个主要变化是 Render(),其中 MSAA 解析为 HDR 目标 after结束 HDR 场景渲染和在色调映射过程之前:
// 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
输出到传统的 1080p 显示器(无 HDR10 或垂直同步)。左轴屏幕截图是没有 MSAA 的 HDR 场景,而右轴截图显示了 4xMSAA 对 3D 线框对象、水壶和地球模型以及三角形广告牌的平滑效果。 猫和 'Hello World' 文本是在 MSAA 解析和色调映射之后绘制到后台缓冲区的 2D 精灵。
再次感谢@ChuckWalbourn 为我指明了正确的方向,我期待着使用 DirectX 工具包推进我的项目。