Issue with glBindBufferRange() OpenGL 3.1
Asked Answered
S

1

5

My vertex shader is ,

uniform Block1{    vec4 offset_x1;   vec4 offset_x2;}block1;

out float value;

in vec4 position;

void main()
{
    value = block1.offset_x1.x + block1.offset_x2.x;            

    gl_Position = position;
}

The code I am using to pass values is :

GLfloat color_values[8];// contains valid values

glGenBuffers(1,&buffer_object);

glBindBuffer(GL_UNIFORM_BUFFER,buffer_object);

glBufferData(GL_UNIFORM_BUFFER,sizeof(color_values),color_values,GL_STATIC_DRAW);

glUniformBlockBinding(psId,blockIndex,0);

glBindBufferRange(GL_UNIFORM_BUFFER,0,buffer_object,0,16);                                              

glBindBufferRange(GL_UNIFORM_BUFFER,0,buffer_object,16,16);

Here what I am expecting is, to pass 16 bytes for each vec4 uniform. I get GL_INVALID_VALUE error for offset=16 , size = 16. I am confused with offset value. Spec says it is corresponding to "buffer_object".

Saccharide answered 23/10, 2012 at 10:52 Comment(0)
O
9

There is an alignment restriction for UBOs when binding. Any glBindBufferRange/Base's offset must be a multiple of GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT. This alignment could be anything, so you have to query it before building your array of uniform buffers. That means you can't do it directly in compile-time C++ logic; it has to be runtime logic.

Speaking of querying things at runtime, your code is horribly broken in many other ways. You did not define a layout qualifier for your uniform block; therefore, the default is used: shared. And you cannot use `shared* layout without querying the layout of each block's members from OpenGL. Ever.

If you had done a query, you would have quickly discovered that your uniform block is at least 32 bytes in size, not 16. And since you only provided 16 bytes in your range, undefined behavior (which includes the possibility of program termination) results.

If you want to be able to define C/C++ objects that map exactly to the uniform block definition, you need to use std140 layout and follow the rules of std140's layout in your C/C++ object.

Openhearth answered 23/10, 2012 at 18:19 Comment(4)
Thanks a lot for the answer ! I wasn't aware about GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT. I had already queried my Uniform Block for its size (32 bytes), but I thought by specifying 16 bytes I could supply data for the second "vec4" component of Uniform Block, which I presume is wrong. I think I should treat the second "vec4" component as an individual uniform. Just to add information , if layout is not std140 then offset has to be a multiple of GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT. Consequently the bound buffer also has to be a multiple of GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT in size .Saccharide
Cont. - Consequently the bound buffer also has to be a multiple of GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT in size provided we are using a single buffer object to supply data to multiple uniform blocks.Saccharide
"if layout is not std140 then offset has to be a multiple of GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT." No; the offset always must be a multiple of that. std140 layout just means you don't have to query the buffer's size or the offset of any individual uniforms, because you can compute them directly. The buffer can be whatever size you want, but when you bind a range, the offset must be a multiple of that alignment.Openhearth
Still a bit confused. Lets say my shader contains 2 uniform blocks: uniform Block1{ vec4 offset_x1; }block1; uniform Block2{ vec4 offset_x3; vec4 offset_x4;}block2; And I want to supply data to both of them using a single buffer object. What will be my glBindBufferRange() call in that case ? Assume I am using std140 layout in shader.Saccharide

© 2022 - 2024 — McMap. All rights reserved.