EXT_bindable_uniform: extremely buggy?

I’m trying to get bindable uniforms working properly but I had no luck, it has a very strange behaviour. This is what I do:

1- First I create the bindable uniform buffer:

GLuint buffer;
glGenBuffers(1,&buffer);
glBindBuffer(GL_UNIFORM_BUFFER_EXT,buffer);

GLfloat dat[8];
dat[0] = 1.0f;
dat[1] = 1.0f;
dat[2] = 1.0f;
dat[3] = 1.0f;
dat[4] = 1.0f;
dat[5] = 1.0f;
dat[6] = 1.0f;
dat[7] = 1.0f;
glBufferData(GL_UNIFORM_BUFFER_EXT,8*sizeof(float),dat,GL_STATIC_READ);

2- I create my fragment shader:

#extension GL_EXT_bindable_uniform: enable
bindable uniform float data[8];
void main(){
  float val = data[0];
  gl_FragColor = vec4(val,val,val,1.0); }

3- Bind the bindable uniform to the shader:

GLint loc = glGetUniformLocationARB(program_handle,location.c_str());
glBindBuffer(GL_UNIFORM_BUFFER_EXT, buffer);
glUniformBufferEXT(program_handle,loc,buffer);

4- Use the shader.

glUseProgramObjectARB(program_handle);

NOTE:

  • no opengl errors produced.

The problem is that the bindable uniform seems to be bound to the shader to the correct location (uniform variable), but I can 't get the correct values accessing to the buffer data[8]in the shader! Only data[0] and data[1] seem to work! the others data[3…7] give me 0.

I am unable to figure out what the problem is. I would really appreciate your help, because this is driving me crazy!

Thank you in advance.

(Running on WindowsXP + GeForce 8800 with the latest drivers.)

I think (I do not have compatible hw) that when you explicitly fill the buffer using buffer manipulation functions you need to write at offset returned by the glGetUniformOffsetEXT (e.g. by retrieving location of single array element using the glGetUniformLocation and using that location with the glGetUniformOffsetEXT() to get offset of the bytes corresponding to that element) and not continuously from the beginning of the buffer like your current code does.

There’s an alignment issue as Komat points out that is also commented on in this thread:

http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=242004#Post242004

Quick test would be to change from float to vec4. That is probably the alignment that the NVIDIA driver uses since that would match the DX10 alignment.

To be absolutely certain of the alignments, you’d need to do the introspection. I agree that sucks. :slight_smile:

Cass

Looks like every float is taking up the whole vec4 constant register.

Here is a sample I have written… if it helps.

http://www.g-truc.net/sample-ogl2.html#sample13

Thank you very much for your answers!

I did the trick Cass said of using vec4 instead of float as the type of my bindable uniform array and it seems to work.

However, what I really need is an array of float, because using vec4 will requiere to add more (unnecessary) complexity to my shaders :(.

Moreover, this is working on my nvidia 8800 card… but do I have to expeect this “hack” to work on ATI drivers or even on future nvidia cards?

I thought that the primary goal of OpenGL is to abstract you from the hardware, but this extension makes it too messy. I think this is by far the OpenGL extension with the worst interface.

No, you have no guarantees because the layout is undefined. The only proper way which should always work is to use the glGetUniformOffsetEXT() to determine where individual element is stored within the buffer. The specification also guarantees that offset between conscecutive array elements is constant so you can take offsets between two consecutive elements and use it as stride for entire array.

I thought that the primary goal of OpenGL is to abstract you from the hardware, but this extension makes it too messy.

The OpenGL is often looking too much forward at the cost of being clumsy to use with current, more limited, hw.

I think the thing to do is to make your sentiments known on the thread that I pointed to above.

A DX10-style packing that is consistent across all vendors would be superior to completely unspecified rules.

Eventually we should be able to specify with a pragma or option what alignment rules we want followed in the same way you can do with C++ today.

The DX10 rules are based on what vendors thought would be easiest to support. I know that on the 8800 series the packing could have been on 32 bit boundaries instead of 128, but not everybody’s hardware works that way. And in this case, consistent is probably better for now. But it does cost you 4x the uniform storage if you really just want an array of floats.