Uniform Buffers and BindBufferRange

Hey everyone!

I’m currently playing around with glBindBufferBase. Let’s assume I have a uniform buffer of size 4 * 16 * sizeof(GLfloat), where one collection of uniforms has the size 1 * 16 * sizeof(GLfloat). Now I’m rendering 4 objects and I want to bind one collection at a time and use it within the active shader with the following block declaration:



layout(std140) uniform Collection
{
  vec4 c0;
  vec4 c1;
  vec4 c2;
  vec4 c3;
}


Since my driver reports an offset alignment of 256 machine units, I get an INVALID_VALUE error when binding buffer range like this:


glBindBufferRange(GL_UNIFORM_BUFFER, buffer_index, offset, 16 * sizeof(GLfloat));

with offset = i * 16 * sizeof(GLfloat) and i € {0, 1, 2, 3}.

Do I have to face facts and realize that I can only bind a collection which has a size equal to the offset alignment, or am I terribly missing somethin here?

Do I need to resort to indexing into an array of structs within the UB and use a constant size (which totally defeats the purpose), or go back to using glUniform*() which will result in a massive increase in API calls with more then just a few objects?

I’m using OpenGL 3.3 Core. Thank you!

Edit: BTW, gDEBugger confirmed that the buffer is setup correctly and so is the uniform block binding.

Honestly, I was going to tell you to look at the reference docs, but sadly, they are incomplete on this point.

When you use glBindBufferRange on uniform buffers, the offset parameter must be aligned to an implementation-dependent value: GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT. Also, the size bound must be a minimum of GL_UNIFORM_BLOCK_SIZE_DATA.

So you need to fetch these values, then build your buffer objects based on them:


GLint uniformBufferAlignSize = 0;
GLint uniformBufferMinSize = 0;
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniformBufferAlignSize);
glGetIntegerv(GL_UNIFORM_BLOCK_SIZE_DATA, &uniformBufferMinSize);

OT: I always do my best to check every available reference BEFORE posting in a board. I checked the core spec, the ARB extension spec, the GL wiki. However, you could not have guessed that.

I already mentioned the offset alignment of 256 bytes (in my case), so I’m aware of this. Also, since I’m using the std140 layout, my block size is known in advance and I did of course match the size of each collection to the block size.

My point is: If I have to honor this limitation, the minimal collection of uniforms I can bind at a time would have to span 256 bytes. Right?

This is what I don’t get. It basically seems to render uniform blocks with small uniform collections unusable, unless you bind it using BindBufferBase and use some indexing scheme within a shader.

Am I right or simply too stupid?

Afaik, the original alignment was 64, and was recently changed for future-proof with VAX AVX and stuff (why??). 64 was a nice number: a mat4 for world-pos, or mat4x3 for worldpos and a vec4 for something else.
But anyway the update to 256-byte alignment isn’t that bad, imho: At most you’ll lose 192 bytes per object; and if there are 50k bigger objects in the scene, you’ll waste only 9MB. For many tiny instanced objects, usually you’ll keep instance-consts in 3-4 floats, and index into an array.

I’d have loved to have 4-byte alignment, though.

Correction: ARB_map_buffer_alignment.txt was speaking about 256 bits instead of bytes, so the 256 alignment you’re seeing is a somewhat arbitrary limitation an IHV has decided upon.

My point is: If I have to honor this limitation, the minimal collection of uniforms I can bind at a time would have to span 256 bytes. Right?

No; that’s just the required alignment for binding.

If your uniform block is less than this size, then there will simply be extra space at the end. If your uniform block is only 64 bytes, then you need to allocate chunks in your buffer to the required alignment.

So your buffer would look like this:


---------- 0 bytes
block data
block data
---------- 64 bytes: end of block data you care about
unused
unused
unused
---------- 1*alignment bytes: end of *actual* block data.
block data
block data
---------- 1*alignment + 64 bytes
unused
unused
unused
---------- 2*alignment: end of second block data.
...

Your uniform block definition in GLSL does not need to have the unused area in padding. That is, it doesn’t need extra unused fields. This padding is all about how much room you give each section in your buffer object.

Man, thank you guys so much! Works like a charm.

With my current setup I’m losing 10 vec4s per object which is not a problem at all. I had suspected I needed to waste a bit of memory, but I got way to caught up in it.

Hello,

That’s OK for me, written in the spec.

I couldn’t find any other reference to this, neither in the spec (3.3 core) nor even in any result from Google (which actually returns only this thread as its only search result). Could you tell me more about it? Was it removed? Is it a future feature?

Thanks.

I couldn’t find any other reference to this, neither in the spec (3.3 core) nor even in any result from Google (which actually returns only this thread as its only search result).

The bottom of page 73 and the top of page 74 of the 3.3 core OpenGL specification. Are you using an up-to-date PDF reader with search capabilities?