DirectX 12更新描述符堆



我目前正在为DirectX12编写我自己的图形框架(我已经为个人游戏引擎编写了几个DirectX 11框架),并且我目前正在尝试复制最近的《杀手》游戏中用于资源绑定的方法。

我对处理SRV/CBV/UAV堆的每个对象资源绑定的最佳方式感到困惑。我看过几次GDC演示,它们似乎都掩盖了这一点。

一次只能绑定1个SRV/CBV/UAV堆,在命令列表中间切换当前绑定的堆可能会强制刷新,从而对某些硬件的性能造成不利影响。因此,用新描述符更新堆的最佳方法是什么?对我来说,似乎每个命令列表都会:

  1. 为自己获取一个SRV/CBV/UAV堆
  2. 对于对象子集中的每个对象,在堆上创建描述符,指向放置在单独上传堆中的每对象数据
  3. 然后,另一个命令列表获取这个填充的描述符堆并绑定它,然后发出与SetGraphicsRootDescriptorTable混合的draw调用,以便在当前描述符堆中移动

也就是说,一些在线消息来源(包括另一篇SO帖子)建议使用一个大型SRV/CBV/UAV堆,并使用CPU可见堆将其复制到其中。我假设他们没有尝试使用异步CopyDescriptors,而是使用CopyBufferRegion。我尝试使用CopyBufferRegion来更新每个对象的数据,但对我来说,由于D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFERD3D12_RESOURCE_STATE_COPY_DEST之间有太多转换,这似乎性能不佳。我是不是误解了什么?如有任何澄清,我们将不胜感激。

CopyDescriptors不是异步的,它是在CPU上立即执行的CPU操作。它可以在为易失性描述符执行命令列表之前的任何时候发生(在记录使用它的命令列表操作之后),或者必须在使用静态描述符时做好准备(根签名1.1)。

通常的方法是有一个大的描述符堆,保留一部分用于静态描述符,然后将其余部分用作环形缓冲区,根据需要分配描述符表偏移量以进行复制,并将所需的描述符用于任何绘制/计算操作。

CopyBufferRegion与此无关,请记住,映射缓冲区也是一个即时操作,因此您还可以为每个对象的常量缓冲区环形缓冲一大块内存,然后循环使用它。唯一的问题是,您需要确保在内存或描述符可能仍在使用时不会覆盖它们,因此必须进行隔离以防止这种情况发生。

最新更新