I'm trying my hand at shader storage buffer objects (aka Buffer Blocks) and there are a couple of things I don't fully grasp. What I'm trying to do is to store the (simplified) data of an indeterminate number of lights n
in them, so my shader can iterate through them and perform calculations.
Let me start by saying that I get the correct results, and no errors from OpenGL. However, it bothers me not to know why it is working.
So, in my shader, I got the following:
struct PointLight {
vec3 pos;
float intensity;
};
layout (std430, binding = 0) buffer PointLights {
PointLight pointLights[];
};
void main() {
PointLight light;
for (int i = 0; i < pointLights.length(); i++) {
light = pointLights[i];
// etc
}
}
and in my application:
struct PointLightData {
glm::vec3 pos;
float intensity;
};
class PointLight {
// ...
PointLightData data;
// ...
};
std::vector<PointLight*> pointLights;
glGenBuffers(1, &BBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, BBO);
glNamedBufferStorage(BBO, n * sizeof(PointLightData), NULL, GL_DYNAMIC_STORAGE_BIT);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, BBO);
...
for (unsigned int i = 0; i < pointLights.size(); i++) {
glNamedBufferSubData(BBO, i * sizeof(PointLightData), sizeof(PointLightData), &(pointLights[i]->data));
}
In this last loop I'm storing a PointLightData
struct with an offset equal to its size times the number of them I've already stored (so offset 0
for the first one).
So, as I said, everything seems correct. Binding points are correctly set to the zeroeth, I have enough memory allocated for my objects, etc. The graphical results are OK.
Now to my questions. I am using std430
as the layout - in fact, if I change it to std140
as I originally did it breaks. Why is that? My hypothesis is that the layout generated by std430
for the shader's PointLights
buffer block happily matches that generated by the compiler for my application's PointLightData
struct (as you can see in that loop I'm blindingly storing one after the other). Do you think that's the case?
Now, assuming I'm correct in that assumption, the obvious solution would be to do the mapping for the sizes and offsets myself, querying opengl with glGetUniformIndices
and glGetActiveUniformsiv
(the latter called with GL_UNIFORM_SIZE
and GL_UNIFORM_OFFSET
), but I got the sneaking suspicion that these two guys only work with Uniform Blocks and not Buffer Blocks like I'm trying to do. At least, when I do the following OpenGL throws a tantrum, gives me back a 1281
error and returns a very weird number as the indices (something like 3432898282
or whatever):
const char * names[2] = {
"pos", "intensity"
};
GLuint indices[2];
GLint size[2];
GLint offset[2];
glGetUniformIndices(shaderProgram->id, 2, names, indices);
glGetActiveUniformsiv(shaderProgram->id, 2, indices, GL_UNIFORM_SIZE, size);
glGetActiveUniformsiv(shaderProgram->id, 2, indices, GL_UNIFORM_OFFSET, offset);
Am I correct in saying that glGetUniformIndices
and glGetActiveUniformsiv
do not apply to buffer blocks?
If they do not, or the fact that it's working is like I imagine just a coincidence, how could I do the mapping manually? I checked appendix H of the programming guide and the wording for array of structures is somewhat confusing. If I can't query OpenGL for sizes/offsets for what I'm tryind to do, I guess I could compute them manually (cumbersome as it is) but I'd appreciate some help in there, too.
std140
for this exact definition ofPointLight
structure? In this particular case, there should not be a difference betweenstd140
andstd430
. Now, if you remove theintensity
member for instance, there would be a difference. – Grope3*4 + 1 *4
) and alignment is 12 bytes (3*4
, i.e., the size of thevec3
). Is that correct? – Chloestd140
andstd430
even if you remove theintensity
member. The alignment ofstruct PointLight
is still 16 bytes, enforced by rule 3, that says the alignment of vec3 is the same as that of ver4. – Gropevec3
takes up 12 bytes (according to the exception in rule 7) but is aligned on 16, as per rule 3. – Chloestd140
andstd430
. The difference is that withstd140
, array elements get rounded up to 16 bytes just because, while withstd430
it only happens if that array element contains a member with such an alignment. – Grope