HLSL compiled with shaderc and introspected with SPIRV-cross has wrong size?

221 Views Asked by At

I am compiling this shader

struct VSInput
{
[[vk::location(0)]] float2 Pos : POSITION0;
[[vk::location(1)]] float3 Color : COLOR0;
};

struct UBO
{
    float2x2 transform;
};

cbuffer ubo : register(b0) { UBO ubo; }

struct VSOutput
{
    float4 Pos : SV_POSITION;
    [[vk::location(0)]] float3 Color : COLOR0;
};

VSOutput main(VSInput input)
{
    VSOutput output = (VSOutput)0;
    output.Color = input.Color;
    output.Pos = float4(ubo.transform * input.Pos.xy, 0, 1);
    return output;
}

To spirv using shaderc then extracting reflection data with spirv-cross. My program thinks the ubo buffer has a total size of 32 bytes, but a 2x2 = 4 matrix of floats (4 bytes) should have 16 bytes, not 32.

Does HLSL have strict 32 byte alignment requirements or something like that?

For the record this works:

struct VSInput
{
[[vk::location(0)]] float2 Pos : POSITION0;
[[vk::location(1)]] float3 Color : COLOR0;
};

struct UBO
{
    vector<float, 4> transform;
};

ConstantBuffer<UBO> ubo : register(b0);

struct VSOutput
{
    float4 Pos : SV_POSITION;
    [[vk::location(0)]] float3 Color : COLOR0;
};

VSOutput main(VSInput input)
{
    float2x2 tmp = (float2x2) ubo.transform;
    VSOutput output = (VSOutput)0;
    output.Color = input.Color;
    
    output.Pos = float4(tmp * input.Pos.xy, 0, 1);
    return output;
}

This hlsl shader is meant to be a direct translation of this GLSL one:

#version 450
#extension GL_EXT_scalar_block_layout : enable

layout(location = 0) in vec2 inPosition;
layout(location = 1) in vec3 inColor;

layout(location = 0) out vec3 fragColor;

layout(binding = 0, scalar) uniform MatUBO
{
    mat2 transform;
};

void main() {
    gl_Position = vec4(transform * inPosition, 0.5, 1.0);
    fragColor = inColor;
}
1

There are 1 best solutions below

3
Nicol Bolas On

but a 2x2 = 4 matrix of floats (4 bytes) should have 16 bytes, not 32.

That's not how UBO alignment of arrays works. Vulkan, by default, operates under the limitations of std140 layout for uniform buffers. Therefore, the layout of uniform blocks will conform to that.

Matrices in a UBO are effectively arrays of vectors. And arrays in std140 layout always have an array stride of 16 bytes. Therefore, your UBO is 32 bytes.