spirv-val: Allow ArrayStrideIdEXT on structs with descriptors (#6705)
Per `SPV_EXT_descriptor_heap`, `ArrayStrideIdEXT` must be allowed on
arrays containing descriptor types. This includes composites that
contain descriptors, not only arrays whose element type is directly a
descriptor.
**Root Cause**:
The validator only checked whether the array element type itself was a
descriptor type.
For
[RuntimeArray<Material>](https://github.com/KhronosGroup/glslang/pull/4272/changes#diff-3142250076641bab8379f6637d480636190a14c9f31e0f7915cb4e76fc1d840e),
the direct element type is `OpTypeStruct`, so validation rejected it
even though `Material` contains `OpTypeBufferEXT`.
**Solution**:
Recursively inspect the array element type when validating
`ArrayStrideIdEXT`, so structs and other composites containing
descriptor types are accepted.
**Test**:
Added a validator regression test covering a runtime array of a struct
containing `OpTypeBufferEXT`.
Co-authored-by: guangxu2 <guangxu2@amd.com>
diff --git a/source/val/validate_annotation.cpp b/source/val/validate_annotation.cpp
index 037bbfd..be5cc38 100644
--- a/source/val/validate_annotation.cpp
+++ b/source/val/validate_annotation.cpp
@@ -403,10 +403,15 @@
}
}
- // Strip array and should be the descriptor type
+ const auto is_descriptor_type = [&_](const Instruction* type_inst) {
+ return _.IsDescriptorType(type_inst->opcode());
+ };
+
+ // Strip the array. The element may be a descriptor type directly, or a
+ // composite containing a descriptor type.
const uint32_t element_type =
_.FindDef(target_id)->GetOperandAs<uint32_t>(1);
- if (!_.IsDescriptorType(element_type)) {
+ if (!_.ContainsType(element_type, is_descriptor_type, true)) {
return _.diag(SPV_ERROR_INVALID_ID, inst)
<< "ArrayStrideIdEXT decoration must only be applied to"
<< " array type containing a Descriptor type.";
diff --git a/test/val/val_extension_spv_ext_descriptor_heap.cpp b/test/val/val_extension_spv_ext_descriptor_heap.cpp
index ce6c1fe..55bda50 100644
--- a/test/val/val_extension_spv_ext_descriptor_heap.cpp
+++ b/test/val/val_extension_spv_ext_descriptor_heap.cpp
@@ -1560,6 +1560,33 @@
"array type containing a Descriptor type."));
}
+TEST_F(ValidateSpvEXTDescriptorHeap, ArrayStrideStructContainingDescriptor) {
+ const std::string str = R"(
+ OpCapability Shader
+ OpCapability DescriptorHeapEXT
+ OpExtension "SPV_EXT_descriptor_heap"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpDecorateId %_runtimearr_Material ArrayStrideIdEXT %uint_16
+ %void = OpTypeVoid
+ %3 = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %uint_16 = OpConstant %uint 16
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+ %buffer = OpTypeBufferEXT StorageBuffer
+ %Material = OpTypeStruct %v4float %buffer
+%_runtimearr_Material = OpTypeRuntimeArray %Material
+ %main = OpFunction %void None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+ )";
+ CompileSuccessfully(str.c_str(), SPV_ENV_VULKAN_1_3);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+}
+
TEST_F(ValidateSpvEXTDescriptorHeap, MemberDecorateIdArrayStrideIdEXT) {
const std::string str = R"(
OpCapability Shader