Generated `OpLoad` does not respect the minimum type alignment
glslang version: 16.0.0 (SDK 1.4.328.0)
Given this shader:
GLSL code
#version 460 core
#extension GL_EXT_buffer_reference: require
#extension GL_EXT_scalar_block_layout: require
#extension GL_EXT_nonuniform_qualifier: require
struct Vertex
{
vec3 position;
vec2 texCoord;
vec3 normal;
};
layout (buffer_reference, buffer_reference_align = 4, scalar) readonly buffer VertexBuffer
{
Vertex vertex;
};
layout (buffer_reference, buffer_reference_align = 8, scalar) readonly buffer ParametersBuffer
{
VertexBuffer vertexBuffer;
};
layout(push_constant) uniform constants
{
ParametersBuffer u_params;
};
void main()
{
gl_Position = vec4(u_params.vertexBuffer.vertex.position, 1.0);
}
SPIR-V code
OpCapability Shader
OpCapability PhysicalStorageBufferAddresses
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel PhysicalStorageBuffer64 GLSL450
OpEntryPoint Vertex %4 "main" %13 %25
OpSource GLSL 460
OpSourceExtension "GL_EXT_buffer_reference"
OpSourceExtension "GL_EXT_nonuniform_qualifier"
OpSourceExtension "GL_EXT_scalar_block_layout"
OpName %4 "main"
OpName %11 "gl_PerVertex"
OpMemberName %11 0 "gl_Position"
OpMemberName %11 1 "gl_PointSize"
OpMemberName %11 2 "gl_ClipDistance"
OpMemberName %11 3 "gl_CullDistance"
OpName %13 ""
OpName %17 "constants"
OpMemberName %17 0 "u_params"
OpName %19 "ParametersBuffer"
OpMemberName %19 0 "vertexBuffer"
OpName %22 "Vertex"
OpMemberName %22 0 "position"
OpMemberName %22 1 "texCoord"
OpMemberName %22 2 "normal"
OpName %23 "VertexBuffer"
OpMemberName %23 0 "vertex"
OpName %25 ""
OpDecorate %11 Block
OpMemberDecorate %11 0 BuiltIn Position
OpMemberDecorate %11 1 BuiltIn PointSize
OpMemberDecorate %11 2 BuiltIn ClipDistance
OpMemberDecorate %11 3 BuiltIn CullDistance
OpDecorate %17 Block
OpMemberDecorate %17 0 Offset 0
OpDecorate %19 Block
OpMemberDecorate %19 0 NonWritable
OpMemberDecorate %19 0 Offset 0
OpMemberDecorate %22 0 Offset 0
OpMemberDecorate %22 1 Offset 12
OpMemberDecorate %22 2 Offset 20
OpDecorate %23 Block
OpMemberDecorate %23 0 NonWritable
OpMemberDecorate %23 0 Offset 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeVector %6 4
%8 = OpTypeInt 32 0
%9 = OpConstant %8 1
%10 = OpTypeArray %6 %9
%11 = OpTypeStruct %7 %6 %10 %10
%12 = OpTypePointer Output %11
%13 = OpVariable %12 Output
%14 = OpTypeInt 32 1
%15 = OpConstant %14 0
OpTypeForwardPointer %16 PhysicalStorageBuffer
%17 = OpTypeStruct %16
OpTypeForwardPointer %18 PhysicalStorageBuffer
%19 = OpTypeStruct %18
%20 = OpTypeVector %6 3
%21 = OpTypeVector %6 2
%22 = OpTypeStruct %20 %21 %20
%23 = OpTypeStruct %22
%18 = OpTypePointer PhysicalStorageBuffer %23
%16 = OpTypePointer PhysicalStorageBuffer %19
%24 = OpTypePointer PushConstant %17
%25 = OpVariable %24 PushConstant
%26 = OpTypePointer PushConstant %16
%29 = OpTypePointer PhysicalStorageBuffer %18
%32 = OpTypePointer PhysicalStorageBuffer %20
%35 = OpConstant %6 1.0
%40 = OpTypePointer Output %7
%4 = OpFunction %2 None %3
%5 = OpLabel
%27 = OpAccessChain %26 %25 %15
%28 = OpLoad %16 %27
%30 = OpAccessChain %29 %28 %15
%31 = OpLoad %18 %30 Aligned 4
%33 = OpAccessChain %32 %31 %15 %15
%34 = OpLoad %20 %33 Aligned 4
%36 = OpCompositeExtract %6 %34 0
%37 = OpCompositeExtract %6 %34 1
%38 = OpCompositeExtract %6 %34 2
%39 = OpCompositeConstruct %7 %36 %37 %38 %35
%41 = OpAccessChain %40 %13 %15
OpStore %41 %39
OpReturn
OpFunctionEnd
The first OpLoad loads the u_params variable.
It is loaded from push constants, so I believe the absence of alignment is expected.
The second OpLoad loads the vertexBuffer variable.
This variable being a 64-bit pointer, its load should have Aligned 8 instead of Aligned 4.
The alignment can be confirmed because:
- The implicit
ParametersBufferstruct hasbuffer_reference_align = 8 - The
vertexBuffervariable is padded to a 8-byte alignment within the struct because of its type's alignment requirement
Seems to be similar to #4024
@maxime-modulopi confirmed https://github.com/KhronosGroup/glslang/pull/4089 will fix this and produce
%31 = OpLoad %18 %30 Aligned 8
@spencer-lunarg Release 16.1.0 fixed the bug for OpLoad but it appears that it also occurs for OpStore.
I have a shader that copy a BDA pointer from one buffer to another buffer and inspecting the OpStore in SPIR-V Visualizer, I see this:
The BDA pointer is correctly loaded with alignment 8 but is stored with alignment 4.
Should I reopen this issue or create a new issue?
reopen this issue, I now know what I am doing in the glslang code to fix things quickly!
I just need some basic glsl code that is producing this and will take a look!
(also glad to see people are using SPIR-V Visualizer!)
This code reproduces the issue:
#version 460 core
#extension GL_EXT_buffer_reference: require
#extension GL_EXT_scalar_block_layout: require
layout (buffer_reference, buffer_reference_align = 4, scalar) readonly buffer DataBuffer
{
vec4 data;
};
layout (buffer_reference, buffer_reference_align = 8, scalar) buffer ParametersBuffer
{
DataBuffer src;
DataBuffer dst;
};
layout(push_constant) uniform constants
{
ParametersBuffer u_param;
};
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main()
{
u_param.dst = u_param.src;
}
Something weird I found is that setting DataBuffer's buffer_reference_align to 8 changes the OpStore alignment to 8, which should not happen because this value controls the aligment of the pointed-to memory address (i.e. the data variable), not the pointer variable's memory address.
@maxime-modulopi thanks, was able to figure it out with the example!
https://github.com/KhronosGroup/glslang/pull/4123/