c++memoryalignmentglslvulkan

Alignment problem with UBO on CPU/GPU, GLSL/VULKAN


After adding directional lights to UBO, the light is incorrect on scene. Tried to shuffle elements around, but it doesn't help. If i correct, GLSL UBO structure should be 920 bytes in size? What is wrong with this alignments/structure?

UBO structs on CPU:

MAX_POINT_LIGHTS = 10; 
MAX_DIRECTIONAL_LIGHTS = 5; 
struct  PointLight 
{ 
    vec4 position{}; 
    vec4 color{};
};

struct  DirectionalLight {
    vec4 position{0.f};
    vec4 color{0.f};
    vec3 shadowExtent{0.f};
 // Added paddings, as try to fix problem, doesn't help
    int padding{};
    vec3 direction{0.f};
    int padding1{};
    }

struct  UBO{
    mat4 projection{ 1.f };
    mat4 view{ 1.f };
    mat4 inverseView{ 1.f };
    mat4 DirectionalShadowMatrix{ 0.f };
    vec4 ambientLightCol{ 0.f,0.f,0.1f,0.01f };
    int numPointLight{0};
    int numDirectionalLight{ 0 };
    StaticArray<PointLight, MAX_POINT_LIGHTS> pointLights;
    StaticArray<DirectionalLight, MAX_DIRECTIONAL_LIGHTS> DirectionalLights;

};`

UBO structs on GPU:

struct PointLight 
{
        vec4 position; 
        vec4 color; 
};

struct DirectionalLight
{
    vec4 position;
    vec4 color;
    vec3 shadowExtent;
    vec3 direction;
};

layout(std140, set = 0, binding = 0) uniform UBO{
mat4 projectionMatrix;
mat4 viewMatrix;
mat4 inverseViewMatrix;
mat4 DirectionalShadowMatrix;
vec4 ambientLightCol;
int numPointLights;
int numDirectionalLights;
PointLight pointLights[10];
DirectionalLight directionalLights[5];
} ubo;

Looked on alignment, and it should be valid, so have to idea why lighting is incorect.


Solution

  • The rules for std140 layout in the OpenGL specification (OpenGL 4.5, Section 7.6.2.2, page 137) have the following to say about structures and arrays of structures:

    1. If the member is a structure, the base alignment of the structure is N , where N is the largest base alignment value of any of its members, and rounded up to the base alignment of a vec4. The individual members of this sub- structure are then assigned offsets by applying this set of rules recursively, where the base offset of the first member of the sub-structure is equal to the aligned offset of the structure. The structure may have padding at the end; the base offset of the member following the sub-structure is rounded up to the next multiple of the base alignment of the structure.
    2. If the member is an array of S structures, the S elements of the array are laid out in order, according to rule (9).

    That means that pointLights is aligned and assigned offsets as pointLights[0] would. Since that is a struct containing vec4 members, the array must be aligned at 4 machine units (or 16 bytes) alignment.

    You have two int fields before pointLights so you need to add two more to satisfy the 16-byte alignment.

    As an alternative to manual padding you could add alignas(16) to the declaration of pointLights, or wrap your two int fields in a nameless union with a vec4.