0

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;
}
Makogan
  • 8,208
  • 7
  • 44
  • 112

1 Answers1

1

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.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • I edited my question to show the glsl shader I was converting. Not that that shader has mat2's which are 16 bytes. So it seems I am missing something in my HLSL declaration to have feature parity with glsl – Makogan Mar 07 '23 at 00:37
  • 1
    @Makogan: ... do you not see what is different between the GLSL and HLSL versions? It's sitting right there in the GLSL definition. Are you asking for some way to make the HLSL do the same thing? – Nicol Bolas Mar 07 '23 at 00:51
  • Yes, I think so. – Makogan Mar 07 '23 at 00:52