2017-07-25 95 views
0

因此,在观看dx12绑定视频并阅读某些文档后,如果我正确理解如何管理堆,我不能100%确定。DX12描述符堆管理

让我解释一下我在我的应用程序中无法达到的效果: 初始化期间,我将填充两个堆,一个拿着取样器,另一个拿着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); 

这意味着,我们必须mCbvSrvUavHeapmSamplerHeap正确下令描述。

例如:

mCbvSrvUavHeap 
CBV 
CBV 
SRV 
SRV 

这里是哪里出了问题对我来说。正如我最初所说,我将为应用程序创建两大堆,但是,我不能将这些堆设置到命令列表中,因为它们将具有其他不会使用的描述符!

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

希望我解释清楚!

+0

如果您愿意使用额外的rootig插槽,则它们不需要连续。 [Here's](https://github.com/Microsoft/DirectXTK12/blob/master/Src/Shaders/RootSig.fxh)我在[DirectX Tool Kit for DirectX 12]中使用的根目录(https://github.com/)微软/ DirectXTK12)。我不是说他们是最优的,但他们完成了工作。 –

回答

1

你对此理解错误。描述符堆不是不可变的东西,而是不断变化的对象。当你绑定一个描述符表时,你实际上是从任何偏移量来绑定它的。交换描述符堆是您想要不惜一切代价避免的代价高昂的操作。

的想法是准备在非GPU可见堆描述符(尽可能多的,只要你喜欢,他们仅仅是CPU分配的对象)和按需复制到GPU可见一个在一个环形缓冲区时尚的方式与CopyDescriptorCopyDescriptorSimple

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

你必须小心的一件事是你堆中描述符的生存期,因为你不能覆盖它们,直到GPU完成处理使用它们的命令为止。最后,如果许多着色器使用相似的根签名共享一些常用表,则可以通过分解更新来节省处理时间。

+0

这当然是一种策略,但改变描述符堆并不一定是世界末日,取决于发生了什么。是的,它会在某些硬件上导致管道刷新,但这可能并不是那么糟糕,因为您必须将其与其他供应商的最佳实践进行折衷。 –

+0

对于nvidia来说(70%的个人电脑市场),“如果你想瞄准运行并行异步计算和图形工作负载,确保只使用一个CBV/SRV/UAV /描述符堆作为所有帧的环形缓冲区,我的理解是,它们将在描述符堆之间存在障碍,这将像在每个Draw调用之间插入一个'WaitForIdle'并且放松所有并行机会。 – galop1n

+0

我想到了在后台有一个环形缓冲区的想法,所以我可以做双/三重缓冲,而不必篱笆每帧:)。感谢您的解释,这真的很有帮助。我想我会做以下事情:用SRV_UAV_CBV和另一个用于采样器的大堆(非着色器可见),然后用下一个绘制/分派的描述符构建“当前”描述符堆。一旦我完成了这个新的堆,我应该调用ID3D12Descriptorheap :: Release()对不对? – Nacho