我试图弄清楚如何有效地清除着色器存储缓冲区。 ssb在我的着色器中看起来像这样:
struct Type{
vec4 A, B, C;
};
layout (std430, binding = 1) buffer TypeBuffer {
Type items[];
};
我每帧写入此缓冲区一次,需要在下一帧的开头清除它。 规范提供了一个方便的功能:
glClearNamedBufferData(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);
不幸的是,没有internalFormat枚举对应于 Type 的格式。对我来说,似乎这个功能不适合清除任意SSBO,虽然它明确规定在规范中清除它们。
目前我坚持这种方法:
//Do this only once!
float* nullData = new float[N * sizeof(float) * 4 * 3];
for(int i = 0; i < N * sizeof(float) * 4 * 3; i++){
nullData[i] = 0.f;
}
glGenBuffers(1, &bufferID);
//Execute this every frame
glBindBuffer(GL_SHADER_STORAGE_BUFFER, bufferID);
glBufferData(GL_SHADER_STORAGE_BUFFER, N * sizeof(float) * 4 * 3, nullData, GL_STATIC_READ);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
假设我可以使用 glClearNamedBufferData ,这两种清算方法之间的性能是否会有差异?与我目前的解决方案相比,是否有更快的方法来清除每帧的SSBO?
答案 0 :(得分:1)
glClear[Named]BufferData
不直接处理像结构这样的复合数据类型。它将缓冲区视为基本类型数组,并将每个数组元素设置为相同的值。因此,如果您想使用包含两个浮点a
和b
的结构,并且您希望初始化缓冲区,以便将每个条目a
设置为{ {1}},但每0.0f
到b
,使用该功能都无法做到这一点。
但是,由于您的缓冲区只包含一系列浮点数,因此您可以将1.0f
设置为internalFormat
来清除它。由于您使用GL_R32F
&#39; s,&#34;最匹配&#34;格式实际上是vec4
。
假设我可以使用
GL_RGBA32F
,这两种清算方法之间的性能是否会有差异?
很可能是的。 glClearNamedBufferData
必须重新传输整个数组,而glBufferData
变体只需传输一个像素的数据。如果缓冲区大于几个元素,那么速度会快得多。
但是还有另一个不同之处。 glClear[Named]BufferData
不只是覆盖缓冲区的内容(glBufferData
会这样做),但它会为它创建一个全新的数据存储。这也可能以某种方式对性能产生一些影响。例如,可能必须延迟glBufferSubData
调用,直到完成GL处理此缓冲区的当前内容。关于该缓冲区的操作与这些可能需要的隐式或显式同步之间的实际依赖性将极大地影响不同场景的性能。
从概念上讲,glClear[Named]BufferData
是您用例的正确方法。您可能仍需要考虑将其与显式缓冲区oprhaning或使用一些双重或tipple缓冲策略相结合。
答案 1 :(得分:1)
如果没有internalformat
值与您的Type
声明完全匹配,则无关紧要。什么是Type
,它的核心是什么?
这是12个花车。
是与浮动匹配的internalformat
。实际上,手动清除缓冲区正是:它不会创建Type
数组,而是创建float
数组。它用零填充它们,并将它们写入缓冲区。所以告诉OpenGL这样做:
float val = 0.0f;
glCreatNamedBufferData(buff, GL_R32F, GL_RED, GL_FLOAT, &val);
实际上,它甚至不必那么复杂。既然你知道IEEE-754浮点数代表0.0值作为包含全零的字节序列,你可以将缓冲区清除为所有零字节:
GLubyte val = 0;
glClearNamedBufferData(buff, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, &val);
与我目前的解决方案相比,是否有更快的方法来清除每帧的SSBO?
在执行清算操作方面,几乎可以肯定。