因此,在观看dx12绑定视频并阅读一些文档之后,我不能100%确定我是否理解如何管理我的堆。
让我解释一下我在申请中要达到的目标: 在初始化期间,我将填充两个堆,一个拿着采样器,另一个拿着SRV,CBV和UAV。 这些堆将包含应用程序在其生命周期中将使用的所有资源。
现在开始有趣的部分。要构建根签名,我将大部分使用根描述符表。
众所周知,表格将包含范围,范围是基础着色器插槽,描述符数量和其他设置。 让我告诉你和例子:
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
这就是问题所在。正如我最初所说,我将使用应用程序的所有资源创建两个大堆,但是,我无法将这些堆设置到命令列表中,因为它们将具有其他不会被使用的描述符! / p>
我该如何处理?我是否需要创建一个仅包含我将使用的描述符的新Heap?
希望我解释得很好!
答案 0 :(得分:1)
你理解错了。描述符堆不是不可变的,而是一个始终在变化的对象。绑定描述符表时,实际上是从任何偏移量绑定它。交换描述符堆是一项昂贵的操作,您需要不惜一切代价避免这种操作。
我们的想法是在非GPU可见堆中准备描述符(尽可能多地使用它们,它们只是一个CPU分配的对象)并按照环形缓冲区的方式按需复制到GPU中{{1} }或CopyDescriptor
。
假设您的着色器使用带有2个CBV和2个SRV的表,它们必须在堆中连续,因此您将从堆中分配4个数组,获得堆偏移量,复制所需的描述符并绑定它与CopyDescriptorSimple
。
您需要注意的一件事是堆中描述符的生命周期,因为在GPU完成使用它们处理命令之前,您无法覆盖它们。最后,如果许多着色器共享一些公共表,从类似的根签名,您可以通过分解更新来节省处理。