问题描述
我有 D3D11 的经验,想学习 D3D12。我正在阅读 official D3D12 multithread example 并且不明白为什么为每一帧创建阴影贴图(在第一遍中作为 DSV 生成,在第二遍中作为 SRV 使用)(实际上只有 2 个副本,因为 { {1}} 每 2 帧重复使用一次)。
创建阴影贴图资源的代码是 here,在 FrameResource
类中,其实例创建为 here。
实际上还有一个为每一帧创建的资源,常量缓冲区。我有点理解常量缓冲区。因为是cpu写的(D3D11动态使用),需要保持不变,直到GPU用完,所以需要2份。但是,我不明白为什么阴影贴图需要做同样的事情,因为它只被 GPU 修改(D3D11 默认使用),并且无论如何都有栅栏命令来分离对该纹理的读取和写入。只要 GPU 遵循围栏,单个纹理就足以让 GPU 正常工作。我哪里错了?
提前致谢。
编辑
根据下面的评论,我上面提到的“栅栏”应该更准确地称为“资源屏障”。
解决方法
关键问题是您不想停止 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,D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,D3D12_RESOURCE_STATE_DEPTH_WRITE));
}
请注意,此示例是旧版 DirectX SDK 示例 MultithreadedRendering11 的移植/重写,因此拥有两个阴影缓冲区而不是一个阴影缓冲区可能只是一种方便的人工制品。