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.