OpenGL std140 layout for sub-structs

  c++, glsl, layout, memory, opengl

I’m trying to understand std140 alignment for sub-structs within a struct.

As far as I understood, the base alignment for a sub-struct is supposed to be the member with the largest alignment rounded to the alignment of a vec4 (which is 16 bytes aligned).
The size of the sub-struct is supposed to be the total size of all members.

The offset for the first member of the sub-struct is supposed to be the offset for the sub-struct itself (which is 16 bytes aligned).
The offset for the first member following the sub-struct is also supposed to be 16 bytes aligned.

Did I understand the rules completely wrong? Because I’ve applied them in 2 situations, which both should be valid, yet only one situation works properly. The official documentation is not exactly clear on this, while tutorials out there never cover this case or give any example.

For example, I’ve got the following case ("directional_light" is the main struct, while "layered_atlas_tile" is the offending sub-struct):

struct layered_atlas_tile // Alignment: 16 | Size: 8
{
    int Index; // Alignment: 16 | Size: 4
    uint Size; // Alignment: 4 | Size: 4
};

struct directional_light
{
    glm::vec4 Ambient; // Alignment: 16 | Size: 16
    glm::vec4 Diffuse; // Alignment: 16 | Size: 16
    glm::vec4 Specular;// Alignment: 16 | Size: 16

    glm::mat4 LightSpaceMatrix; // Alignment: 16 | Size: 64

    glm::vec3 Direction; // Alignment: 16 | Size: 12
    float Padding1;

    layered_atlas_tile ShadowMapTile; // Alignment: 16 (?) (Padding1 ensures we're 16 aligned) | Size: 8 (?)
    // Padding2 and padding3 ensure that the next member after ShadowMapTile is 16 aligned.
    // The next member, in this case, will be "Ambient" in an array of directional_light
    float Padding2;
    float Padding3;
};

Well, this case completely fails and I have no idea why. But simply moving Padding2 and Padding3 inside the sub-struct itself works perfectly:

struct layered_atlas_tile // Alignment: 16 | Size: 16
{
    int Index; // Alignment: 16 | Size: 4
    uint Size; // Alignment: 4 | Size: 4
    float Padding2;
    float Padding3;
};

struct directional_light
{
    glm::vec4 Ambient; // Alignment: 16 | Size: 16
    glm::vec4 Diffuse; // Alignment: 16 | Size: 16
    glm::vec4 Specular;// Alignment: 16 | Size: 16

    glm::mat4 LightSpaceMatrix; // Alignment: 16 | Size: 64

    glm::vec3 Direction; // Alignment: 16 | Size: 12
    float Padding1;

    layered_atlas_tile ShadowMapTile; // Alignment: 16 (?) (Padding1 ensures we're 16 aligned) | Size: 16 (?)
};

Why is this layout valid when inserting Padding2 and Padding3 directly into the "layered_atlas_tile" struct, yet it completely fails if placed outside right below the sub-struct?

Source: Windows Questions C++

LEAVE A COMMENT