Reputation: 731
I am trying to figure out how to clear a shader storage buffer efficiently. The ssb looks like this in my shader:
struct Type{
vec4 A, B, C;
};
layout (std430, binding = 1) buffer TypeBuffer {
Type items[];
};
I write to this buffer once per frame and need it to be cleared at the beginning of the next frame. The specs offer a convenient function to do it:
glClearNamedBufferData(GLuint buffer, GLenum internalformat, GLenum format, GLenum type, const void *data);
Unfortunately, no internalFormat enum corresponds to the format of Type. To me it seems this function is not suited to clear arbitrary SSBO's, although it explicitly offers to clear them in the specs.
At the moment I am sticking to this method:
//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);
Assuming I could use glClearNamedBufferData, would there be even a difference in performance between those two clearing methods? Is there a faster way to clear the SSBO every frame compared to my current solution?
Upvotes: 4
Views: 2451
Reputation: 473407
It doesn't matter if there is no internalformat
value that matches exactly your Type
declarations. What is a Type
, at it's core?
It's 12 floats.
There is an internalformat
that matches a float. Indeed, your manual clearing of the buffer does exactly that: it creates not a Type
array, but a float
array. It fills them with zeros, and writes them to the buffer. So just tell OpenGL to do it:
float val = 0.0f;
glCreatNamedBufferData(buff, GL_R32F, GL_RED, GL_FLOAT, &val);
Indeed, it doesn't even have to be that complicated. Since you know that IEEE-754 floats represent the 0.0 value as a sequence of bytes containing all zeros, you could just clear the buffer to all zero bytes:
GLubyte val = 0;
glClearNamedBufferData(buff, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE, &val);
Is there a faster way to clear the SSBO every frame compared to my current solution?
In terms of executing the clearing operation, almost certainly.
Upvotes: 2
Reputation: 45332
glClear[Named]BufferData
does not directly handle compound data types like structures. It does treat the buffer as a an array of basic types, and sets every single array element to the same value. So if you wanted to use a structure containing for example two floats a
and b
, and you would want to initialize the buffer so that every entry's a
is set to 0.0f
, but every b
to 1.0f
, it would be impossible to do so with that function.
However, since your buffer contains just a sequence of floats, so you can clear it as such with internalFormat
set to GL_R32F
. Since you use vec4
's, the "most matching" format would actually be GL_RGBA32F
.
Assuming I could use
glClearNamedBufferData
, would there be even a difference in performance between those two clearing methods?
Very likely yes. The glBufferData
will have to retransfer the complete array, while the glClear[Named]BufferData
variant just needs to transfer the data for one pixel. If the buffer is bigger than just a few elements, it will be much faster.
There is another difference, though. glBufferData
does not just overwrite the contents of the buffer (glBufferSubData
would do that), but it creates a completely new data storage for it. This can also have some impact on performance, in one way or the other. For example, the glClear[Named]BufferData
call might have to be delayed until the GL is done processed the current contents of this buffer. The actual depenencies between your operations regarding that buffer, and the implicit or explicit synchronizations these may require, will greatly influence the performance for the different scenarios.
Conceptually, glClearNamedBufferData
is the correct approach for your use case. You may still need to consider combining it with explicit buffer oprhaning or using some double- or tipple-buffering strategy.
Upvotes: 1