Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding GLSL Uniform Buffer Block Alignment

I'm having trouble understanding the std140 layout for GLSL uniform buffer objects. I'm under the impression that in the following uniform block, the int will begin at offset 0 and the matrix will begin at offset 16. The following uniform is giving me a bad matrix, apparent because nothing draws on-screen.

layout (std140) uniform Camera
{
    int renderMode;
    mat4 projection;
} camera;

The point of renderMode is that it tells me that the uniform update code doesn't work.

I have the following code (homegrown) to help me along. This is the code that makes the Open GL calls in my C++ application. This code is inside a class called UniformBufferObject.

#define UpdateExData(o, s, d) glBindBuffer(GL_UNIFORM_BUFFER, _uboId); \
    glBufferSubData(GL_UNIFORM_BUFFER, o, s, d); \
    glBindBuffer(GL_UNIFORM_BUFFER, 0);

int Alignment(int offset, int alignment)
{
    int leftOver = offset % alignment;
    if (leftOver > 0)
    {
        return offset + (alignment - leftOver);
    }
    else
    {
        return offset;
    }
}

template<typename T, typename... Args>
void UpdateEx(int offset, const std::vector<T>& data, Args&... args)
{
    auto mySize = sizeof(T) * data.size();
    int myAlignment = Alignment(offset, 16); // fixed for vectors of vec4 for now
    UpdateExData(myAlignment, mySize, data.data());
    UpdateEx(myAlignment + mySize, args...);
}

template<typename... Args>
void UpdateEx(int offset, int& data, Args&... args)
{
    auto mySize = sizeof(int);
    int myAlignment = Alignment(offset, mySize); // assume 4 byte alignment for ints
    UpdateExData(myAlignment, mySize, &data);
    UpdateEx(myAlignment + mySize, args...);
}

template<typename... Args>
void UpdateEx(int offset, const glm::mat4& data, Args&... args)
{
    auto mySize = sizeof(glm::mat4);
    int myAlignment = Alignment(offset, 16); // assume 16-byte alignment for mat4
    UpdateExData(myAlignment, mySize, &data);
    UpdateEx(myAlignment + mySize, args...);
}

The line of code that initiates the update is as follows. m is an integer. cam is glm::mat4. The purpose of this piece is to update the camera in my shaders.

cameraUbo->UpdateEx(0, m, cam);

If I flip the uniform around such that the matrix is first, and update the call above to cameraUbo->UpdateEx(0, cam, m), the matrix updates but renderMode no longer works.

I really have no idea what's wrong and what really confuses me is that GL_UNIFORM_BLOCK_DATA_SIZE returns well beyond the 80 that I expect. I get different values, above 1000, across the 5 shaders it's in.

I do have another uniform that appears to work perfectly, and has the same size across the two shaders in appears in.

struct TowerLight
{
    vec4 position;
    vec4 color;
};

layout(std140) uniform Towers
{
    int lightCount;
    TowerLight lights[MaxLights];
};

With the following code. count is an integer and lights is std::vector<struct_of_2_vec4>.

ubo->UpdateEx(0, towerCount, lights);

[Edit]

This might be a bug in my video card driver. I have a Radeon 6870. If I use the default uniform block layout or drop my shader version to 430 from 440, I get a block size of 80 across all shaders.

like image 654
Ross Lombardi Avatar asked Oct 23 '25 17:10

Ross Lombardi


1 Answers

This page explains well how alignment works http://learnopengl.com/#!Advanced-OpenGL/Advanced-GLSL

layout (std140) uniform ExampleBlock
{
    //               // base alignment  // aligned offset
    float value;     // 4               // 0 
    vec3 vector;     // 16              // 16  (must be multiple of 16 so 4->16)
    mat4 matrix;     // 16              // 32  (column 0)
                     // 16              // 48  (column 1)
                     // 16              // 64  (column 2)
                     // 16              // 80  (column 3)
    float values[3]; // 16              // 96  (values[0])
                     // 16              // 112 (values[1])
                     // 16              // 128 (values[2])
    bool boolean;    // 4               // 144
    int integer;     // 4               // 148
}; 

Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!