Directx DX12描述符堆管理

Directx DX12描述符堆管理,directx,direct3d,Directx,Direct3d,因此,在观看了dx12绑定视频并阅读了一些文档之后,我不能100%确定我是否正确理解了如何管理我的堆 让我解释一下我不想在我的应用程序中实现的目标: 在初始化过程中,我将填充两个堆,一个装取样器,另一个装SRV、CBV和UAV。 这些堆将包含应用程序在其生命周期内使用的所有资源 现在开始有趣的部分。为了构建根签名,我将使用大部分根描述符表 正如我们所知,一个表将包含范围,范围是基本着色器槽、描述符数量和其他设置。 让我给你看一个例子: Root Parameters 0 - root_table

因此,在观看了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
这就是我的问题所在。正如我最初所说的,我将使用应用程序的所有资源创建两个大堆,但是,我不能将这些堆设置为命令列表,因为它们将有其他不使用的描述符

我该怎么办?我是否需要创建一个只包含将要使用的描述符的新堆


希望我解释得好

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

其思想是在非GPU可见堆中准备描述符(尽可能多,它们只是CPU分配的对象),并使用
CopyDescriptor
CopyDescriptorSimple
按需复制到GPU可见堆中

假设您的着色器使用一个包含2个CBV和2个SRV的表,它们在堆中必须是连续的,因此您将从堆中分配一个4的数组,获得堆偏移量,复制所需的描述符,并将其与
SetGraphicsRootDescriptable
绑定


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

这当然是一种策略,但根据其他情况,更改描述符堆不一定是世界末日。是的,它会在某些硬件上导致管道刷新,但可能没有那么糟糕,因为您必须与其他供应商的最佳实践进行权衡。例如,对于nvidia(70%的PC市场),
确保只使用一个CBV/SRV/UAV/描述符堆作为所有帧的环形缓冲区。如果您希望运行并行异步计算和图形工作负载,我的理解是,它们将在描述符堆之间设置障碍,这就像在每个Draw调用之间插入一个
WaitForIdle
,失去了所有并行性的机会。我想到了在后台有一个环形缓冲区的想法,这样我就可以在不限制每个帧的情况下进行双/三重缓冲:)。谢谢你的解释,这真的很有帮助。我想我会做以下工作:使用SRV_UAV_CBV创建一个大堆(不可见着色器),另一个用于采样器,然后使用描述符构建一个“当前”描述符堆,用于下一次绘制/分派。一旦我处理完这个新堆,我应该调用ID3D12Descriptorheap::Release()对吗?创建和销毁堆(或任何资源)比设置它们要昂贵得多。如果每帧创建一个新的heap对象,这种方法的任何价值都可能丢失……好吧,那么如果我要有一个大的heap,但我需要选择要使用的描述符,有什么建议吗?如果你愿意使用额外的rootsig插槽,它们不需要是连续的。我用过的rootsig。我不是说它们是最优的,但它们完成了任务。