SSBO 和图像加载/存储之间的区别



"着色器存储缓冲区对象"(SSBO)和图像加载存储操作之间有什么区别

什么时候应该使用一个而不是另一个?

它们

都可以进行原子操作,我假设它们存储在相同类型的内存中。无论它们是否存储在相同类型的内存中,它们是否具有相同的性能特征?

编辑:最初的问题是在SSBO和

统一缓冲区对象之间提出的,它应该在SSBO和图像加载存储之间。

着色器存储缓冲区对象和图像纹理之间的区别以及为什么要使用它们,因为它们可以使用接口块。

图像只是纹理,这意味着数据结构中只有vec4。不仅 vec4,它还可以有其他格式,而且数据结构将是一种数据类型的许多。

其中,SSBO 是通用的。他们可以在单个接口块中使用 int、float、vec3 数组的组合。

因此,SSBO比图像纹理灵活得多。

您的问题已经在 http://www.opengl.org/wiki/Shader_Storage_Buffer_Object 或多或少得到了明确的回答。 它说:

SSBO 很像统一缓冲区对象。着色器存储块是由接口块 (GLSL) 以几乎与统一相同的方式定义块。存储 SSBO 的缓冲区对象绑定到 SSBO 绑定点,就像制服的缓冲区对象绑定到 UBO 绑定一样点。等等。

它们之间的主要区别是:

  1. SSBO可以更大。所需的最小 UBO 大小为 16KB;所需的最小 SSBO 大小为 16MB,典型大小为与 GPU 内存的大小相同。

  2. SSBO 是可写的,甚至是原子的;最终受益人是制服。 SSBO 读取和写入使用不连贯的内存访问,因此它们需要适当的障碍,就像图像加载存储操作一样。

  3. SSBO 可以具有无限存储,最多为缓冲区范围;最终受益人必须具有特定的固定存储大小。这意味着您可以在 SSBO 中具有任意长度的数组。的实际大小数组,根据缓冲区边界的范围,可以在着色器中的运行时使用无界的长度函数数组变量。

正如其他人所提到的,SSBO 具有更大的存储空间并支持原子操作,公认的答案还提到 SSBO 是通用的,因为它们允许用户组合不同类型的内容。但就个人而言,我只想指出,我认为这通常是不好的,在 SSBO 中使用接口块或结构并不总是理想的。下面是一个示例:

假设您在C++中有一个结构,如下所示:

struct Foo {
    glm::vec4 position;
    glm::vec4 velocity;
    glm::vec4 padding_and_range;  // range is a float padded to a vec4
};

它对应于 glsl 中的 SSBO 缓冲区:

struct Foo {
    vec4 position;
    vec4 velocity;
    vec4 padding_and_range;  // range is a float padded to a vec4
};
layout(std430, binding = 0) readonly buffer SSBO {
    Foo data[];
} foo;

虽然SSBO缓冲区能够容纳一个struct Foo数组,但请注意,根据std430内存布局,必须将填充float range填充到vec4,然后使用foo.data[i].padding_and_range.w来访问它。这很容易出错,更不用说内存空间的浪费了,尤其是当您的 SSBO 很大(用于计算着色器)并且您的Foo结构很复杂(需要大量填充)时。除此之外,您通常需要在循环中填写缓冲区数据,如下所示:

Foo* foos = reinterpret_cast<Foo*>(glMapNamedBufferRange(ssbo, offset, size, GL_MAP_READ_BIT));
for (int i = 0; i < n_foos; i++) {
    Foo& foo = foos[i];
    foo.position          = glm::vec4(1.0f);
    foo.velocity          = glm::vec4(2.0f);
    foo.padding_and_range = glm::vec4(glm::vec3(0.0f), 3.5f);
}
glUnmapNamedBuffer(ssbo);

而不是简单地使用 glNamedBufferDataglNamedBufferSubData 一次性将数据写入其中。

处理结构的更好方法是将每个结构元素存储到单独的 SSBO 中,以便每个 SSBO 缓冲数组紧密打包且均匀。尽管性能可能没有更好,但它有助于保持代码干净且更具可读性。Rarher比使用结构体,你会想要使用:

layout(std430, binding = 0) buffer FooPosition {
  vec4 position[];
};
layout(std430, binding = 1) buffer FooVelocity {
  vec4 velocity[];
};
layout(std430, binding = 2) buffer FooRange {
  float range[];
};

相关内容

  • 没有找到相关文章