Buffer、StructuredBuffer 和 ByteAddressBuffer(以及它们的 RW 变体)之间是否存在性能差异?

Dan*_*hal 7 performance gpu directx-11 compute-shader

我尝试在各种网站上查找此内容,包括有关 DirectX 11 计算着色器类型的 MS Docs;但我还没有发现任何提到这些缓冲区类型的性能差异的内容。
它们的性能完全相同吗?
如果不是,在不同场景中使用每种方法的最佳方式是什么?

cat*_*ier 6

性能最终会因 GPU/驱动程序组合而异。

这里有一个项目可以对这些进行基准访问(线性/随机情况是最有用的)。

如果您想要比较 cbuffer 访问与其他缓冲区访问,恒定访问也很有用(例如,在 NVidia 上,通常会在使用昂贵的着色器之前执行缓冲区到 cbuffer gpu 的复制)。

https://github.com/sebbbi/perftest

请注意,不同的缓冲区(在 d3d11 区域中)也有不同的限制。因此,这些可能会阻碍性能优势。

  • 结构化缓冲区不能绑定为顶点/索引缓冲区。因此,如果您想使用它们,您需要执行额外的复制。(对于顶点缓冲区,您可以只从顶点 id 获取,这没有任何惩罚,索引缓冲区可以读取,但问题较多)。
  • 字节地址允许以非结构化方式存储任何内容(只是一个基本指针)。读取仍按 4 字节(int 大小)对齐。转换为浮点(读取)需要 asfloat,从浮点(写入)转换需要 asuint,但在驱动程序情况下,这通常是 nop,因此不会影响性能。
  • 字节地址(和类型化缓冲区)可用作索引缓冲区或顶点缓冲区。无需复制。
  • 类型化缓冲区不太支持互锁操作,在这种情况下,您需要使用 Structured/ByteAddress 缓冲区(请注意,您可以在小型缓冲区上使用互锁,并根据需要在类型化缓冲区上执行读/写操作)。
  • 如果您有相同类型的元素数组,则使用字节地址可能会更烦人(与 StructuredBuffer < float4x4 > 相比,即使是 float4x4 也需要相当多的代码来获取)
  • 结构化缓冲区允许您绑定“部分视图”。因此,即使您的缓冲区有 2048 个浮点,您也可以绑定 4-456 的范围(它还允许您同时绑定 500-600 作为写入,因为它们不重叠)。
  • 对于所有缓冲区,如果将它们用作只读缓冲区,请勿将它们绑定为 RW,这通常会产生相当大的损失。