Francis Cugler
Francis Cugler

Reputation: 7905

Vulkan Memory Alignment for Uniform Buffers

I'm following the online tutorial: vulkan-tutorial where the author is adding in the functionality for Descriptor Pools and Descriptor Sets.

I'm using Vulkan v1.2.135.0 and my Shader's are set to #version 450

I'm nearly finished this part of the tutorial and I'm able to render a spinning square and I'm getting no errors from Vulkan Layers when I compile and run in Debug mode.

I'm near the bottom of the page provided by the link above where he introduces a glm::vec2 within the UniformBufferOjbect struct and a vec2 within the same corresponding struct within shader.vert.

He changed these:

// Defined in C++ file
struct UniformBufferObject {
    glm::mat4 model;
    glm::mat4 view;
    glm::mat4 proj;
};

// Defined in shader.vert
layout(binding = 0) uniform UniformBufferObject {
    mat4 model;
    mat4 view;
    mat4 proj;
} ubo;

To the following:

// Defined in C++ file
struct UniformBufferObject {
    glm::vec2 foo;
    glm::mat4 model;
    glm::mat4 view;
    glm::mat4 proj;
};

// Defined in shader.vert
layout(binding = 0) uniform UniformBufferObject {
    vec2 foo;
    mat4 model;
    mat4 view;
    mat4 proj;
} ubo;

I followed the example and recompiled the shader using the provided tool to convert it to an SPV binary. And as he suggests there is nothing rendered on the screen as this has to do with memory-alignment that Vulkan requires...

He briefly explains the memory alignment issues by stating how to fix this issue. There were two things he suggests doing... The first is to use C++11's or greater alignas(16) modifier.

He then states that if we are to change our UniformBufferObject to the following:

// Defined in C++ file
struct UniformBufferObject {
    glm::vec2 foo;
    alignas(16) glm::mat4 model;
    glm::mat4 view;
    glm::mat4 proj;
};

Then compile and run the program again that it should render correctly, however, I'm still getting a black screen.

He also suggests using glm's #define GLM_FORCE_DEFAULT_ALIGNED_GENTYPES directive before including its header files in which I did. It is still not rendering anything to the screen...

I even modified the UniformBufferObject to:

// Defined in C++ file
struct UniformBufferObject {
    glm::vec2 foo;
    alignas(16) glm::mat4 model;
    alignas(16) glm::mat4 view;
    alignas(16) glm::mat4 proj;
};

And still, nothing is rendering. I don't know why this isn't working as suggested by the tutorial.

Upvotes: 1

Views: 2928

Answers (2)

Aiekick
Aiekick

Reputation: 48

a vec2 must have an alignement of 8

  • a float an alignement of 4
  • a vec2 an alignement of 8
  • a vec3, vec4, mat4 an alignement of 16

you must correct like that :

struct UniformBufferObject {
    alignas(8) glm::vec2 foo;
    alignas(16) glm::mat4 model;
    alignas(16) glm::mat4 view;
    alignas(16) glm::mat4 proj;
};

UBO use the rule std140, you can check this rule for know how to deal with it :)

Upvotes: 2

Viktor Latypov
Viktor Latypov

Reputation: 14467

From personal experience, the UBO structures should be vec4-aligned. Your first field of the structure breaks this alignment.

The quick(est) fix can be

struct UniformBufferObject {
    glm::vec4 foo;
    glm::mat4 model;
    glm::mat4 view;
    glm::mat4 proj;
};

In the shader just use the ubo.foo.xy swizzle to get vec2.

Of course, the shader code should also be modified to

layout(binding = 0) uniform UniformBufferObject {
    vec4 foo;
    mat4 model;
    mat4 view;
    mat4 proj;
} ubo;

Upvotes: 1

Related Questions