Fix layout validation (#5015)
* Fix layout validation
Fixes #5010
* Unless scalar block layout is enabled, no member can reside at an
offset between the end of the previous member that is a struct or
array and the next multiple of that alignment
* Remove a dead if that was introduced
Co-authored-by: David Neto <dneto@google.com>
diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp
index ef9753d..f9c8435 100644
--- a/source/val/validate_decorations.cpp
+++ b/source/val/validate_decorations.cpp
@@ -633,10 +633,10 @@
}
}
nextValidOffset = offset + size;
- if (!scalar_block_layout && blockRules &&
+ if (!scalar_block_layout &&
(spv::Op::OpTypeArray == opcode || spv::Op::OpTypeStruct == opcode)) {
- // Uniform block rules don't permit anything in the padding of a struct
- // or array.
+ // Non-scalar block layout rules don't permit anything in the padding of
+ // a struct or array.
nextValidOffset = align(nextValidOffset, alignment);
}
}
diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp
index ff62f4b..04d373a 100644
--- a/test/val/val_decoration_test.cpp
+++ b/test/val/val_decoration_test.cpp
@@ -4523,6 +4523,48 @@
// #version 450
// layout (set=0,binding=0) buffer S {
// uvec3 arr[2][2]; // first 3 elements are 16 bytes, last is 12
+ // uint i; // Can't have offset 60 = 3x16 + 12
+ // } B;
+ // void main() {}
+
+ std::string spirv = R"(
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %1 "main"
+ OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
+ OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
+ OpMemberDecorate %_struct_4 0 Offset 0
+ OpMemberDecorate %_struct_4 1 Offset 64
+ OpDecorate %_struct_4 BufferBlock
+ OpDecorate %5 DescriptorSet 0
+ OpDecorate %5 Binding 0
+ %void = OpTypeVoid
+ %7 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %v3uint = OpTypeVector %uint 3
+ %uint_2 = OpConstant %uint 2
+%_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
+%_arr__arr_v3uint_uint_2_uint_2 = OpTypeArray %_arr_v3uint_uint_2 %uint_2
+ %_struct_4 = OpTypeStruct %_arr__arr_v3uint_uint_2_uint_2 %uint
+%_ptr_Uniform__struct_4 = OpTypePointer Uniform %_struct_4
+ %5 = OpVariable %_ptr_Uniform__struct_4 Uniform
+ %1 = OpFunction %void None %7
+ %12 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+
+ CompileSuccessfully(spirv);
+ EXPECT_EQ(SPV_SUCCESS,
+ ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
+}
+
+TEST_F(ValidateDecorations, StorageBufferArraySizeCalculationPackGoodScalar) {
+ // Original GLSL
+
+ // #version 450
+ // layout (set=0,binding=0) buffer S {
+ // uvec3 arr[2][2]; // first 3 elements are 16 bytes, last is 12
// uint i; // Can have offset 60 = 3x16 + 12
// } B;
// void main() {}
@@ -4554,6 +4596,7 @@
OpFunctionEnd
)";
+ options_->scalar_block_layout = true;
CompileSuccessfully(spirv);
EXPECT_EQ(SPV_SUCCESS,
ValidateAndRetrieveValidationState(SPV_ENV_VULKAN_1_0));
@@ -4569,7 +4612,7 @@
OpDecorate %_arr_v3uint_uint_2 ArrayStride 16
OpDecorate %_arr__arr_v3uint_uint_2_uint_2 ArrayStride 32
OpMemberDecorate %_struct_4 0 Offset 0
- OpMemberDecorate %_struct_4 1 Offset 56
+ OpMemberDecorate %_struct_4 1 Offset 60
OpDecorate %_struct_4 BufferBlock
OpDecorate %5 DescriptorSet 0
OpDecorate %5 Binding 0
@@ -4595,8 +4638,8 @@
EXPECT_THAT(getDiagnosticString(),
HasSubstr("Structure id 4 decorated as BufferBlock for variable "
"in Uniform storage class must follow standard storage "
- "buffer layout rules: member 1 at offset 56 overlaps "
- "previous member ending at offset 59"));
+ "buffer layout rules: member 1 at offset 60 overlaps "
+ "previous member ending at offset 63"));
}
TEST_F(ValidateDecorations, UniformBufferArraySizeCalculationPackGood) {