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);
这意味着我们需要在 mCbvSrvUavHeap 和 mSamplerHeap.
中正确排序描述符
例如:
mCbvSrvUavHeap
CBV
CBV
SRV
SRV
这就是我的问题所在。正如我最初所说,我将使用应用程序的所有资源创建两个大堆,但是,我无法将这些堆设置到命令列表,因为它们将具有其他不会使用的描述符!
我该如何处理?我是否需要创建一个仅包含我将要使用的描述符的新堆?
希望我解释的很好!
你理解错了。描述符堆不是 immutable 而是一个不断变化的对象。当您绑定描述符 table 时,您实际上是从任何偏移量绑定它。交换描述符堆是一项您希望不惜一切代价避免的代价高昂的操作。
想法是在非 GPU 可见堆中准备描述符(任意多,它们只是一个 CPU 分配的对象)并按需以环形缓冲区方式复制到 GPU 可见堆中CopyDescriptor
或 CopyDescriptorSimple
的方式。
假设你的着色器使用一个 table 和 2 个 CBV 和 2 个 SRV,它们在堆中必须是连续的,所以你将从你的堆中分配一个 4 的数组,你得到一个堆偏移量,复制所需的描述符并将其与 SetGraphicsRootDescriptorTable
.
绑定
您必须注意的一件事是堆中描述符的生命周期,因为在 GPU 完成使用它们处理命令之前您不能覆盖它们。最后,如果许多着色器共享一些共同的 tables,来自相似的根签名,您可以通过分解更新来节省处理时间。
所以在观看了 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);
这意味着我们需要在 mCbvSrvUavHeap 和 mSamplerHeap.
中正确排序描述符例如:
mCbvSrvUavHeap
CBV
CBV
SRV
SRV
这就是我的问题所在。正如我最初所说,我将使用应用程序的所有资源创建两个大堆,但是,我无法将这些堆设置到命令列表,因为它们将具有其他不会使用的描述符!
我该如何处理?我是否需要创建一个仅包含我将要使用的描述符的新堆?
希望我解释的很好!
你理解错了。描述符堆不是 immutable 而是一个不断变化的对象。当您绑定描述符 table 时,您实际上是从任何偏移量绑定它。交换描述符堆是一项您希望不惜一切代价避免的代价高昂的操作。
想法是在非 GPU 可见堆中准备描述符(任意多,它们只是一个 CPU 分配的对象)并按需以环形缓冲区方式复制到 GPU 可见堆中CopyDescriptor
或 CopyDescriptorSimple
的方式。
假设你的着色器使用一个 table 和 2 个 CBV 和 2 个 SRV,它们在堆中必须是连续的,所以你将从你的堆中分配一个 4 的数组,你得到一个堆偏移量,复制所需的描述符并将其与 SetGraphicsRootDescriptorTable
.
您必须注意的一件事是堆中描述符的生命周期,因为在 GPU 完成使用它们处理命令之前您不能覆盖它们。最后,如果许多着色器共享一些共同的 tables,来自相似的根签名,您可以通过分解更新来节省处理时间。