Search code examples
shadervulkan

UBOs and their alignments in Vulkan


struct Light {

   glm::vec4 position;
   glm::vec4 color;
   glm::vec4 attenuation;

};

struct UBO {

   // View and projection matrix
   glm::mat4 view;
   glm::mat4 proj;

   // Fog
   glm::vec4 skyColor;
   float density;
   float gradient;

   // Clipping plane
   glm::vec4 clippingPlane;

   // Lights
   Light lights[4];

};

Vulkan API:

The UBO struct is updated each frame and then passed to a vertex shader each over a Uniform Buffer. The rendered image has wrong colors because the light-array is not passed properly.

Vertex shader binding:

layout (binding = 1) uniform UBO {

    // View and projection matrix
    mat4 view;
    mat4 proj;

    // Fog
    vec4 skyColor;
    float density;
    float gradient;

    // Clipping plane
    vec4 clippingPlane;

    // Lights
    Light lights[4];

} ubo;

Do I need to align the data somehow?


Solution

  • From the spec:

    Standard Uniform Buffer Layout

    The 'base alignment' of the type of an OpTypeStruct member of is defined recursively as follows:

    • A scalar of size N has a base alignment of N.

    • A two-component vector, with components of size N, has a base alignment of 2 N.

    • A three- or four-component vector, with components of size N, has a base alignment of 4 N.

    • An array has a base alignment equal to the base alignment of its element type, rounded up to a multiple of 16.

    • A structure has a base alignment equal to the largest base alignment of any of its members, rounded up to a multiple of 16.

    • A row-major matrix of C columns has a base alignment equal to the base alignment of a vector of C matrix components.

    • A column-major matrix has a base alignment equal to the base alignment of the matrix column type.

    The std140 layout in GLSL satisfies these rules.

    More about this in the 15.6.4. Offset and Stride Assignment section of the specification.