DirectX 12 更新描述符堆
DirectX 12 Updating the Descriptor Heap
我目前正在为 DirectX12 编写自己的图形框架(我已经为个人游戏引擎编写了多个 DirectX 11 框架),并且我目前正在 trying to copy the methods used in the recent Hitman game 进行资源绑定。
我对处理 SRV/CBV/UAV 堆的每个对象资源绑定的最佳方法感到困惑。我看了几个 GDC 演示,他们似乎都在掩盖这一点。
一次只能绑定 1 个 SRV/CBV/UAV 堆,在命令列表中间切换当前绑定的堆可能会通过强制刷新对某些硬件的性能造成不利影响。因此,使用新描述符处理堆更新的最佳方法是什么?对我来说,似乎每个命令列表都会:
- 为自己获取一个 SRV/CBV/UAV 堆。
- 对于对象子集中的每个对象,在堆上创建描述符,指向放置在单独上传堆中的每个对象数据。
- 之后,另一个命令列表获取这个填充的描述符堆并绑定它,然后发出与
SetGraphicsRootDescriptorTable
混合的绘图调用,以便在当前描述符堆中移动。
这就是说,几个在线资源 () 建议使用一个大的 SRV/CBV/UAV 堆并使用 CPU-可见堆复制到其中。我假设他们没有尝试使用异步 CopyDescriptors
,而是 CopyBufferRegion
。我尝试使用 CopyBufferRegion
来更新每个对象的数据,但对我来说这似乎表现不佳,因为 D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER
和 D3D12_RESOURCE_STATE_COPY_DEST
之间有如此多的转换。我误会了什么吗?任何清晰度将不胜感激。
CopyDescriptors
不是异步的,它是一个 CPU 操作,在 CPU 上立即执行。它可以在为易失性描述符执行命令列表之前的任何时间发生(在记录使用它的命令列表操作之后),或者必须在使用静态描述符(根签名 1.1)时准备好。
通常的做法是有一个大的描述符堆,保留一部分用于静态描述符,然后将其余部分用作环形缓冲区,按需分配描述符table偏移量以复制和使用所需的描述符任何 draw/compute 操作。
CopyBufferRegion
在这里没有任何关系,记住映射缓冲区也是一个立即操作,所以你也为你的每个对象常量缓冲区环形缓冲区一大块内存,然后你循环进入它。唯一的问题是您需要确保在内存或描述符可能仍在使用时不会覆盖它们,因此您必须进行防护以防止这种情况。
我目前正在为 DirectX12 编写自己的图形框架(我已经为个人游戏引擎编写了多个 DirectX 11 框架),并且我目前正在 trying to copy the methods used in the recent Hitman game 进行资源绑定。
我对处理 SRV/CBV/UAV 堆的每个对象资源绑定的最佳方法感到困惑。我看了几个 GDC 演示,他们似乎都在掩盖这一点。
一次只能绑定 1 个 SRV/CBV/UAV 堆,在命令列表中间切换当前绑定的堆可能会通过强制刷新对某些硬件的性能造成不利影响。因此,使用新描述符处理堆更新的最佳方法是什么?对我来说,似乎每个命令列表都会:
- 为自己获取一个 SRV/CBV/UAV 堆。
- 对于对象子集中的每个对象,在堆上创建描述符,指向放置在单独上传堆中的每个对象数据。
- 之后,另一个命令列表获取这个填充的描述符堆并绑定它,然后发出与
SetGraphicsRootDescriptorTable
混合的绘图调用,以便在当前描述符堆中移动。
这就是说,几个在线资源 (CopyDescriptors
,而是 CopyBufferRegion
。我尝试使用 CopyBufferRegion
来更新每个对象的数据,但对我来说这似乎表现不佳,因为 D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER
和 D3D12_RESOURCE_STATE_COPY_DEST
之间有如此多的转换。我误会了什么吗?任何清晰度将不胜感激。
CopyDescriptors
不是异步的,它是一个 CPU 操作,在 CPU 上立即执行。它可以在为易失性描述符执行命令列表之前的任何时间发生(在记录使用它的命令列表操作之后),或者必须在使用静态描述符(根签名 1.1)时准备好。
通常的做法是有一个大的描述符堆,保留一部分用于静态描述符,然后将其余部分用作环形缓冲区,按需分配描述符table偏移量以复制和使用所需的描述符任何 draw/compute 操作。
CopyBufferRegion
在这里没有任何关系,记住映射缓冲区也是一个立即操作,所以你也为你的每个对象常量缓冲区环形缓冲区一大块内存,然后你循环进入它。唯一的问题是您需要确保在内存或描述符可能仍在使用时不会覆盖它们,因此您必须进行防护以防止这种情况。