OpenGL 4.5 - Shader storage buffer objects layout

3.5k Views Asked by At

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.

0

There are 0 best solutions below