PDA

View Full Version : Uniform Buffer confusion



Robinson
09-09-2011, 02:21 PM
Can someone tell me about the seemingly needlessly complicated Uniform Buffers? I've read the section in OpenGL Superbible 5, I've looked at some examples on blogs and I've read the official spec, and I still don't get it.

Specifically, all examples seem to require a shader program to begin with in order to setup the uniform buffer initially with glGetActiveUniformsiv. I don't understand this. Why doesn't the interface allow you to define the structure without referring to a shader program, validating the buffer/s formats against the program at link time? Surely if a buffer is supposed to be shared amongst programs, it's a bit of an imposition to have to validate and construct it based on any one program (perhaps the first program that would make use of it). Or have I missed something here?

Secondly, if I get the structure layout from one program, assuming the structure layout is the same for all programs that use the set of uniforms, is the structure guaranteed to have the same offsets, data sizes and so on? I would assume so.

Thirdly, I don't understand binding points. I have to call glBindBufferBase with an index, and then call glUniformBlockBinding with a block index and the index I passed into glBindBufferBase. I'm having trouble visualising exactly what's going on here, which index refers to what and why (!). Most examples I've seen feature one program and one buffer. It's hard for me to see how this works with multiple programs and multiple buffers, which is what I need to do in order to define the (abstract) interfaces my code will use to support them.

Thanks for any assistance you can give.

Ilian Dinev
09-09-2011, 05:36 PM
3)
About binding points: they're exactly like a glActiveTexture + glBindTexture() combo, and a glUniform1i(texuniform,3) . You don't bind a buffer to a program, you bind it to one of the ~16 global slots. The shader will expect to fetch buffer info from that slot.
The glUniformBlockBinding() is like the glUniform1i() for textures.
The glBindBufferBase is like the glBindTexture() for textures.

2)
There's no better way to define the structure of a buffer, than doing so in the GLSL code. Just use std140 layout, and you'll avoid confusion; and mostly you'll avoid having to manually remap data when uploading to a buffer.

1) if you use std140, you needn't query offsets and such. Only driver-dependent size/offset in std140 remains the alignment of data if you use glBindBufferRange(...., offset , ...) where offset != 0.

tksuoran
09-10-2011, 01:20 AM
I use code to build my uniform blocks:


globalUB = new UniformBlock("global");
globalUB.AddVec4("add_color");
globalUB.AddFloat("alpha");
globalUB.Seal();

After that I can query the string representation of the uniform block and add it to any shader code. Also, the uniform block has all the uniforms, types, names, sizes, offsets - no need to query from a single GL program, and yes, they are all same for all programs. Finally, when I create uniform buffer, it knows which uniform block is its 'type', enabling easy access to locate uniforms by their names.

Implementing such utility code IMHO greatly simplifies using uniform buffers, most importantly you do not need to have any program to query the structure.

I agree that binding points initially seem to be a bit silly. I only have few uniform blocks: camera, models, lighting, material, globals. Each program has some subset of these; For each program GL assigns uniform block index starting from 0:

Program 1: camera at block index 0, models at block index 1
Program 2: globals at block index 0, camera at block index 1, ...

Currently I assign a fixed binding point (number) to all uniform blocks, and simply call UniformBlockBinding(programObject, uniformBlockIndex, uniformBlock.BindingPoint) after I've linked the program and scanned for uniform blocks. There are limits to how many binding points you can use, so this will work as long as number of uniform blocks is low.

Robinson
09-10-2011, 07:00 AM
Is UniformBlock a kind-of variant struct you've implemented tk?

Robinson
09-10-2011, 07:11 AM
Well, this actually is the only sentence I needed to read to understand the whole thing:

"You don't bind a buffer to a program, you bind it to one of the ~16 global slots. The shader will expect to fetch buffer info from that slot."

Thanks for that Dinev. It's a mystery to me why nobody else seems to have written anything like that in all of the resources I've looked at!

tksuoran
09-10-2011, 08:28 AM
My UniformBlock is a class with:
List<Uniform> uniforms string Name - this is after { } block string BlockName - this is before { } block, after layout(std140) uniform int BindingPointMethods add uniforms and build the shader string like this:
public Uniform AddVec4(string name, int dimension)
{
sb.Append(" vec4 ").Append(name).Append("[").Append(dimension).Append("];\n");
while((offset % (4 * 4)) != 0) ++offset;
int uniformOffset = offset;
offset += dimension * 4 * 4;
var uniform = new Uniform(
name,
uniforms.Count,
dimension,
OpenTK.Graphics.OpenGL.ActiveUniformType.FloatVec4 ,
uniformOffset
);
uniforms.Add(uniform);
return uniform;
}Check out Shared Uniforms (http://www.arcsynthesis.org/gltut/Positioning/Tut07%20Shared%20Uniforms.htm). That tutorial explains many other things in modern OpenGL as well.