应该如何使用SetDescriptorHeaps?

问题描述 投票:0回答:1

我正在尝试DirectX12中的新功能。到目前为止,我真的很喜欢其中的一些更改,例如,管道状态。同时,其他一些更改也会使您感到困惑,例如描述符堆。

让我们从快速的背景开始,以便您更好地理解我的要求。

在DirectX11中,我们创建了不同着色器的对象,然后在设置绘制调用时必须在实际运行时分别绑定它们。这是一个伪示例:

deviceContext->VSSetShader(...);
deviceContext->HSSetShader(...);
deviceContext->DSSetShader(...);
deviceContext->PSSetShader(...);

在DirectX12中,他们已经非常聪明地实现了这一点,因为现在我们可以在初始化期间配置管道状态,然后通过一个API调用设置以上所有条件:

commandList->SetPipelineState(...);

非常简单,优雅,快捷。最重要的是,这非常合乎逻辑。现在让我们来看一下描述符堆。我有点希望它遵循相同的优雅模式,这基本上就是我的问题。

在DirectX11中,我们创建了具有不同描述符(视图)的对象,然后在设置绘制调用时,在实际运行时必须分别为每个着色器绑定它们。再次是一个伪示例:

deviceContext->PSSetConstantBuffers(0, n, ...);
deviceContext->PSSetShaderResources(0, n, ...);
deviceContext->PSSetSamplers(0, n, ...);

在DirectX12中,他们实现了称为描述符堆的东西。基本上,它们是包含我们要绑定的所有描述符的内存块,我们也可以在初始化期间进行设置。到目前为止,它看起来和管道状态一样优雅,因为我们可以使用单个API调用来设置所有内容:

commandList->SetDescriptorHeaps(n, ...);

或者我们可以吗?这是引起混乱的地方,因为在搜索后我发现this question指出:

交换描述符堆是您要不惜一切代价避免的昂贵操作。

同时,MSDN documentationSetDesciptorHeaps并没有说明这种方法特别昂贵。

考虑到他们设计流水线状态的优雅程度,我有点希望能够做到这一点:

commandList->SetPipelineState(...);
commandList->SetDescriptorHeaps(n, ...);
commandList->DrawInstanced(...);

commandList->SetPipelineState(...);
commandList->SetDescriptorHeaps(n, ...);
commandList->DrawInstanced(...);

commandList->SetPipelineState(...);
commandList->SetDescriptorHeaps(n, ...);
commandList->DrawInstanced(...);

但是如果SetDescriptorHeaps实际上那么贵,这很可能会提供非常差的性能。还是会?如前所述,我在MSDN上找不到任何关于这实际上是个坏主意的陈述。

所以我的问题是:

  • 如果上述做法被认为是不良做法,则应如何使用SetDescriptorHeaps
  • 如果这是仅Nvidia的性能问题,为什么他们不修复驱动程序?

基本上,我想为每个管道状态创建两个描述符堆(CBV / SRV / UAV +采样器)。从更改管道状态的便宜程度来看,更改描述符堆同样便宜是合乎逻辑的。流水线状态和描述符堆是非常紧密相关的,即更改流水线状态很可能需要一组不同的描述符。

我知道为每种类型的描述符使用一个庞大的描述符堆的策略。但是考虑到跟踪每个单独的描述符索引所需的所有工作,这种方法感觉太过复杂了。最重要的是,描述符表中的描述符在堆中必须是连续的。

directx-12
1个回答
0
投票

描述符堆独立于管道;他们不必每次抽奖/派遣都绑定。您也可以只拥有一个大的描述符堆,然后绑定它。然后应通过根签名对此进行更正。它应该指向此描述符堆中的正确偏移量。这意味着您可以在一个堆中拥有唯一的纹理,并将根签名指向正确的描述符。您也可以将当前堆再分配为一个巨型堆。

© www.soinside.com 2019 - 2024. All rights reserved.