缓冲区、结构化缓冲区和字节寻址缓冲区(以及它们的RW变体)之间是否存在性能差异?

7

我尝试在各个网站上查找这个问题的答案,包括关于DirectX 11计算着色器类型的MS Docs文档;但是我没有找到任何提及这些缓冲区类型性能差异的内容。
它们在性能方面完全相同吗?
如果不是,那么在各种情况下使用每种缓冲区的最佳方式是什么?

2个回答

6

GPU/Driver组合会导致性能有所不同。

这里有一个项目,可以进行基准测试,其中线性/随机案例最有用。

如果要比较cbuffer访问与其他缓冲区访问的性能(在NVidia上,在进入昂贵的着色器之前常常需要执行缓冲区到cbuffer gpu复制),则常量访问也很有用。

https://github.com/sebbbi/perftest

请注意,不同的缓冲区(在d3d11领域)具有不同的限制,性能收益可能受到这些限制的影响。

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

1

除了接受的答案之外,

结构化缓冲区中的元素如果未对齐到128位步长[大小为float4],还会有性能损失。如果不对齐,则可能导致单个float4跨越缓存行,从而导致高达5%的性能损失。

解决此问题的示例是使用填充来重新对齐元素:

struct Foo
{
    float4 Position;
    float  Radius;
    float pad0;
    float pad1;
    float pad2;
    float4 Rotation;
};

这里是 NVIDIA 的一篇文章,详细介绍了结构化缓冲的性能


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接