Uniform Buffers

Still learning to work with UBOs, I’ve successfully used it to set V/P matrices, however I’m trying to set another, separate UB block in my fragment shader, but my data isn’t coming as expected. I’ve queried UNIFORM_BUFFER_OFFSET_ALIGNMENT and it requires multiples of 256, I’ve hardcoded in my sizes/offsets for simplicity of the example.

//foreach shader
    glUniformBlockBinding(shader->id(), glGetUniformBlockIndex(shader->id(), "Transforms"), 0);
    glUniformBlockBinding(shader->id(), glGetUniformBlockIndex(shader->id(), "LightCounter"), 1);
//endfor
//...
glBufferData(GL_UNIFORM_BUFFER, 512, NULL, GL_STATIC_DRAW);
//...
glBindBufferRange(GL_UNIFORM_BUFFER, 0, programId_, 0, 256);
glBindBufferRange(GL_UNIFORM_BUFFER, 1, programId_, 256, 256);
//...
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), glm::value_ptr(projection));
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(view));

uint32_t tmp = 5;
glBufferSubData(GL_UNIFORM_BUFFER, 256, sizeof(uint32_t), &tmp);
uint32_t tmp2 = 8;
glBufferSubData(GL_UNIFORM_BUFFER, 256 + sizeof(uint32_t), sizeof(uint32_t), &tmp2);




//vertex shader
layout(std140) uniform Transforms
{
    mat4 projection;
    mat4 view;
};

//fragment shader
layout(std140) uniform LightCounter
{
    uint lightCount[64];
};

As previously stated, my mat4’s in my vertex shader populate correctly, but in my fragment shader, lightCount[16] is set to 5, and none of the rest of the valuse are set to 8. I’m sure there is just something I’m not understanding about UBs or the std140 layout. If anyone can help, that would be greatly appreciated.

Thanks.

This has the same layout as

layout(std140) uniform LightCounter
{
    uvec4 lightCount[64];
};

IOW, every element is stored as four integers, with three of them being padding.

The std140 layout rounds up array elements to a multiple of the size of a vec4. Hardware isn’t required to be capable of indexing uniform arrays using a stride smaller than a vec4. If you want to avoid wasting space, you can use e.g.

layout(std140) uniform LightCounter
{
    uvec4 lightCount[64/4];
};

while accessing elements as lightCount[i/4][i%4]. Or you can use a SSBO (OpenGL 4.3 or the ARB_shader_storage_buffer_object extension) with the std430 layout, or a buffer texture.(OpenGL 3.1 or the ARB_texture_buffer_object extension`), or a regular texture.

Hey, thanks for the reply.

Actually, my intent was to just have

layout(std140) uniform LightCounter
{
    uint lightCount;
}

It was just that I wasn’t getting my expected value, so I tried making it an array to see what all the values in the buffer were. I tried using the uvec4 lightCount[64/4] approach you suggested, however the values didn’t show up anywhere in the array. I then tried uvec4 lightCount[64] and my first value is still at lightCount[16][0] and the 2nd value is at lightCount[16][1]

I’m really just curious how to store 2 uint’s in the buffer and pull them back out. The behavior still seems very puzzling to me, that it starts at element 16 even when declaring a uvec4 array. Is there any more clarity you could provide on this? I would really appreciate it, thanks!

After further investigating, I’ve noticed that the reason for the offset is that the entire buffer is being passed to my LightCounter block. I must be misunderstanding how the buffers work with glBindBufferRange() (or I have a mistake in my code that I have yet to notice), because I was expecting that only the range I specified would be bound to the LightCounter block, but it is in fact binding everything, starting with my V/P matrices. Using

layout(std140) uniform LightCounter
{
    uvec4 lightCount[64];
}

the value in lightCount[0][0] is the top left value of my projection matrix, which is meant to be bound to a different UB Block. This make the fact that the uint I was looking for is in lightCount[16][0], since it’s offset by 256 bytes, (16 elements * 4 values * 4 bytes per value), I just don’t understand why it’s loading the whole buffer into the UB block.

glBindBufferRange is supposed to bind the specified region of the buffer. That’s the point of glBindBufferRange as opposed to glBindBufferBase (which binds the entire buffer).

Are you checking for errors? Has the program linked successfully at the point you call glGetUniformBlockIndex?

I am doing debugging output as well as other error checks and I received none, however your question pushed me to step through my logic again and somehow I missed a mistake that was causing the problem to be hidden. Indeed, my shader wasn’t loaded at the time I tried to do the glUniformBlockBinding(), which resulted in the interesting behavior I was getting. I’ve fixed that and it seems to be working more as expected.

Thanks for your responses, your earlier explanations did provide some good insight, I’ll continue on and see if I can manage.