DX12 描述符堆管理

DX12 Descriptor Heaps management

所以在观看了 dx12 绑定视频并阅读了一些文档之后,我不能 100% 确定我是否正确理解了如何管理我的堆。

让我解释一下我不想在我的申请中实现什么: 在初始化过程中,我将填充两堆,一堆装有采样器,另一堆装有 SRV、CBV 和无人机。 这些堆将包含应用程序在其生命周期内将使用的所有资源。

现在开始有趣的部分。为了构建根签名,我将大部分使用根描述符表。

正如我们所知,table 将保存范围,范围是基础着色器插槽、描述符的数量和其他设置。 让我向您展示和示例:

Root Parameters
0 - root_table 
1 - root_table

0 root_table
CBV b1
CBV b6
SRV t0
SRV t2

1 root_table
Sampler s1
Sampler s4

如示例所示,可以有非顺序的范围(例如 b0、b1、b2 和 b3),但是在命令列表记录期间,我们只能这样做:

ID3D12DescriptorHeaps* heaps[2] = {mCbvSrvUavHeap,mSamplerHeap};
mCmdList->SetDescriptorHeaps(2,heaps);

mCmdList->SetGraphicsRootDescriptorTable(0, mCbvSrvUavHeapGpuHanleStart);
mCmdList->SetGraphicsRootDescriptorTable(1, mSamplerHandleHanleStart);

这意味着我们需要在 mCbvSrvUavHeapmSamplerHeap.

中正确排序描述符

例如:

mCbvSrvUavHeap 
CBV
CBV
SRV
SRV

这就是我的问题所在。正如我最初所说,我将使用应用程序的所有资源创建两个大堆,但是,我无法将这些堆设置到命令列表,因为它们将具有其他不会使用的描述符!

我该如何处理?我是否需要创建一个仅包含我将要使用的描述符的新堆?

希望我解释的很好!

你理解错了。描述符堆不是 immutable 而是一个不断变化的对象。当您绑定描述符 table 时,您实际上是从任何偏移量绑定它。交换描述符堆是一项您希望不惜一切代价避免的代价高昂的操作。

想法是在非 GPU 可见堆中准备描述符(任意多,它们只是一个 CPU 分配的对象)并按需以环形缓冲区方式复制到 GPU 可见堆中CopyDescriptorCopyDescriptorSimple 的方式。

假设你的着色器使用一个 table 和 2 个 CBV 和 2 个 SRV,它们在堆中必须是连续的,所以你将从你的堆中分配一个 4 的数组,你得到一个堆偏移量,复制所需的描述符并将其与 SetGraphicsRootDescriptorTable.

绑定

您必须注意的一件事是堆中描述符的生命周期,因为在 GPU 完成使用它们处理命令之前您不能覆盖它们。最后,如果许多着色器共享一些共同的 tables,来自相似的根签名,您可以通过分解更新来节省处理时间。