首页 > 解决方案 > 为什么需要为 D3D12 中的每一帧创建 GBuffers?

问题描述

我有 D3D11 的经验并想学习 D3D12。我正在阅读官方 D3D12 多线程示例,但不明白为什么要为每一帧创建阴影贴图(在第一遍中作为 DSV 生成,在第二遍中作为 SRV 使用)(实际上只有 2 个副本,因为FrameResource被重用每 2 帧)。

创建阴影贴图资源的代码在此处,在FrameResource类中,其实例在此处创建。

实际上,每个帧都会创建另一个资源,即常量缓冲区。我有点理解常量缓冲区。因为是CPU写的(D3D11动态使用),需要保持不变直到GPU用完,所以需要2份。但是,我不明白为什么阴影贴图需要这样做,因为它仅由 GPU 修改(D3D11 默认使用),并且无论如何都有栅栏命令来分离对该纹理的读取和写入。只要 GPU 遵循围栏,单个纹理就足以让 GPU 正常工作。我哪里错了?

提前致谢。

编辑

根据下面的评论,我上面提到的“栅栏”应该更准确地称为“资源屏障”。

标签: graphics3ddirect3ddirect3d12

解决方案


关键问题是您不想让 GPU 停止以获得最佳性能。双缓冲是最低要求,但通常三缓冲更适合平滑帧到帧的渲染峰值等。

FWIW,DXGI 的默认行为Present是仅在您提交帧工作后才停止,而不是两帧。

当然,在三重缓冲和输入响应之间需要权衡取舍,但如果您保持 60 Hz 或更好的频率,则可能不会引起注意。

综上所述,通常您不需要双缓冲深度/模板缓冲区进行渲染,尽管如果您想让深度缓冲区的初始写入与先前深度缓冲区通道的读取重叠,那么您会为了性能和正确性,每帧需要不同的缓冲区。

由于在命令列表中注入了“资源屏障”,因此“写入”在 DX12 中的“读取”之前全部完成:

void FrameResource::SwapBarriers()
{
    // Transition the shadow map from writeable to readable.
    m_commandLists[CommandListMid]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_shadowTexture.Get(), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));
}

void FrameResource::Finish()
{
    m_commandLists[CommandListPost]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_shadowTexture.Get(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE));
}

请注意,此示例是旧版 DirectX SDK 示例MultithreadedRendering11的移植/重写,因此拥有两个阴影缓冲区而不仅仅是一个阴影缓冲区可能只是一种方便的工件。


推荐阅读