Search code examples
c++c++11opengl3dopengl-4

Why is my glBindBufferRange offset alignment incorrect?


I'm having difficulty understanding how glBindBufferRange offset / alignment works in the Nvidia example project gl_commandlist_basic. I've read that the offset needs to be a multiple of GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT which is 256 and/or that offset and alignment is very important with glBindBuffer range.. I have an example UBO that works with mat4/vec4 and a non-working example with mat4/mat3/vec4. The UBO doesn't add up to be a multiple of 256 in either case. I'm try to send vec4(0.f, 1.f, 0.f, 1.f).

If mat4 = 64 bytes, mat3 = 36 bytes, vec4 = 16 bytes then the working example has 64+16=80 bytes, which isn't a multiple of 256. The non-working example has 64+36+16 = 116 bytes.

NV uses an inline called uboAligned which is defined as

inline size_t uboAligned(size_t size) { return ((size + 255) / 256) * 256; }

Removing this from the working/non made no difference either way.

I assume I need to add some "padding" to the UBO in the form of a float/vec2/vec3/vec4, etc. How do I determine the correct amount of padding I need if I want to use the mat4/mat3/vec4 UBO?

/* APPLICATION */
typedef struct
{
    glm::mat4 MM;
    // glm::mat3 NM;
    glm::vec4 Cs;
} myData0;

Gluint objectUBO;
glCreateBuffers(1, &objectUBO);
glNamedBufferData(objectUBO, uboAligned(sizeof(abjObjectData) * 2), 0, GL_STATIC_DRAW); //

for (unsigned int i = 0; i < allObj.size(); ++i)
{
    myData0 myDataTemp;
    myDataTemp.Cs = glm::vec4(0.f, 1.f, 0.f, 1.f);
    glNamedBufferSubData(objectUBO, sizeof(abjObjectData) * i, sizeof(abjObjectData), &objDataInit);
}

//hot loop
for (unsigned int i = 0; i < allObj.size(); ++i)
{
    glBindBufferRange(GL_UNIFORM_BUFFER, 1, objectUBO, uboAligned(sizeof(abjObjectData)) * i, sizeof(abjObjectData));
    //draw
}

/* HW */
out vec4 Ci;

struct ObjectData
{
    mat4 MM;
    // mat3 NM;
    vec4 Cs;
};

layout (std140, binding = 1) uniform objectBuffer { ObjectData object; };

void main()
{
    Ci = object.Cs;
}

Solution

  • Simple typo with glNamedBufferData. Changing from

    glNamedBufferData(objectUBO, uboAligned(sizeof(abjObjectData) * 2), 0, GL_STATIC_DRAW);
    

    to

    glNamedBufferData(objectUBO, uboAligned(sizeof(abjObjectData)) * 2, 0, GL_STATIC_DRAW);
    

    fixes the offset / alignment problems.