val: Fix CullPrimitiveEXT array of bool (#6155)
* val: Fix CullPrimitiveEXT array of bool
* val: Add CullPrimitiveEXT Block case
diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp
index 11d926f..d25ebaf 100644
--- a/source/val/validate_builtins.cpp
+++ b/source/val/validate_builtins.cpp
@@ -590,6 +590,9 @@
spv_result_t ValidateBool(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag);
+ spv_result_t ValidateBlockBoolOrArrayedBool(
+ const Decoration& decoration, const Instruction& inst,
+ const std::function<spv_result_t(const std::string& message)>& diag);
spv_result_t ValidateI(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag);
@@ -820,6 +823,30 @@
return SPV_SUCCESS;
}
+spv_result_t BuiltInsValidator::ValidateBlockBoolOrArrayedBool(
+ const Decoration& decoration, const Instruction& inst,
+ const std::function<spv_result_t(const std::string& message)>& diag) {
+ uint32_t underlying_type = 0;
+ if (spv_result_t error =
+ GetUnderlyingType(_, decoration, inst, &underlying_type)) {
+ return error;
+ }
+ // Strip the array, if present.
+ if (_.GetIdOpcode(underlying_type) == spv::Op::OpTypeArray) {
+ underlying_type = _.FindDef(underlying_type)->word(2u);
+ } else if (!_.HasDecoration(inst.id(), spv::Decoration::Block)) {
+ // If not in array, and bool is in a struct, must be in a Block struct
+ return diag(GetDefinitionDesc(decoration, inst) +
+ " Scalar boolean must be in a Block.");
+ }
+
+ if (!_.IsBoolScalarType(underlying_type)) {
+ return diag(GetDefinitionDesc(decoration, inst) + " is not a bool scalar.");
+ }
+
+ return SPV_SUCCESS;
+}
+
spv_result_t BuiltInsValidator::ValidateI(
const Decoration& decoration, const Instruction& inst,
const std::function<spv_result_t(const std::string& message)>& diag) {
@@ -4339,7 +4366,7 @@
}
break;
case spv::BuiltIn::CullPrimitiveEXT:
- if (spv_result_t error = ValidateBool(
+ if (spv_result_t error = ValidateBlockBoolOrArrayedBool(
decoration, inst,
[this, &inst, &decoration,
&vuid](const std::string& message) -> spv_result_t {
@@ -4350,8 +4377,8 @@
<< _.grammar().lookupOperandName(
SPV_OPERAND_TYPE_BUILT_IN,
(uint32_t)decoration.builtin())
- << " variable needs to be a boolean value "
- "array."
+ << " variable needs to be a either a boolean or an "
+ "array of booleans."
<< message;
})) {
return error;
diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp
index d2a77e2..2032ff2 100644
--- a/test/val/val_builtins_test.cpp
+++ b/test/val/val_builtins_test.cpp
@@ -5255,6 +5255,50 @@
EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
}
+TEST_F(ValidateBuiltIns, VulkanBuiltinCullPrimitiveEXTMissingBlock) {
+ const std::string text = R"(
+ OpCapability MeshShadingEXT
+ OpExtension "SPV_EXT_mesh_shader"
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint MeshEXT %main "main" %gl_MeshPrimitivesEXT
+ OpExecutionModeId %main LocalSizeId %uint_32 %uint_1 %uint_1
+ OpExecutionMode %main OutputVertices 81
+ OpExecutionMode %main OutputPrimitivesEXT 32
+ OpExecutionMode %main OutputTrianglesEXT
+ OpSource GLSL 450
+ OpSourceExtension "GL_EXT_mesh_shader"
+ OpName %main "main"
+ OpName %gl_MeshPerPrimitiveEXT "gl_MeshPerPrimitiveEXT"
+ OpMemberName %gl_MeshPerPrimitiveEXT 0 "gl_CullPrimitiveEXT"
+ OpName %gl_MeshPrimitivesEXT "gl_MeshPrimitivesEXT"
+ OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 BuiltIn CullPrimitiveEXT
+ OpMemberDecorate %gl_MeshPerPrimitiveEXT 0 PerPrimitiveEXT
+%void = OpTypeVoid
+ %3 = OpTypeFunction %void
+%uint = OpTypeInt 32 0
+%uint_32 = OpConstant %uint 32
+%uint_1 = OpConstant %uint 1
+%int = OpTypeInt 32 1
+%bool = OpTypeBool
+%gl_MeshPerPrimitiveEXT = OpTypeStruct %bool
+%_arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypeArray %gl_MeshPerPrimitiveEXT %uint_32
+%_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 = OpTypePointer Output %_arr_gl_MeshPerPrimitiveEXT_uint_32
+%gl_MeshPrimitivesEXT = OpVariable %_ptr_Output__arr_gl_MeshPerPrimitiveEXT_uint_32 Output
+%main = OpFunction %void None %3
+ %5 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-07036"));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("Scalar boolean must be in a Block"));
+}
+
TEST_F(ValidateBuiltIns, BadVulkanBuiltinCullPrimitiveEXTType) {
const std::string text = R"(
OpCapability MeshShadingEXT
@@ -5298,6 +5342,108 @@
AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-07036"));
}
+// from https://github.com/KhronosGroup/SPIRV-Tools/issues/5980
+TEST_F(ValidateBuiltIns, VulkanBuiltinCullPrimitiveArrayOfBool) {
+ const std::string text = R"(
+ OpCapability MeshShadingEXT
+ OpExtension "SPV_EXT_mesh_shader"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint MeshEXT %main "main" %gl_LocalInvocationIndex %gl_Position %4 %5
+ OpExecutionMode %main LocalSize 2 1 1
+ OpExecutionMode %main OutputTrianglesEXT
+ OpExecutionMode %main OutputVertices 2
+ OpExecutionMode %main OutputPrimitivesEXT 2
+ OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+ OpDecorate %gl_Position BuiltIn Position
+ OpDecorate %4 BuiltIn PrimitiveTriangleIndicesEXT
+ OpDecorate %5 BuiltIn CullPrimitiveEXT
+ OpDecorate %5 PerPrimitiveEXT
+ %uint = OpTypeInt 32 0
+ %uint_2 = OpConstant %uint 2
+ %bool = OpTypeBool
+ %false = OpConstantFalse %bool
+%_ptr_Input_uint = OpTypePointer Input %uint
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
+%_ptr_Output__arr_v4float_uint_2 = OpTypePointer Output %_arr_v4float_uint_2
+ %v3uint = OpTypeVector %uint 3
+%_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
+%_ptr_Output__arr_v3uint_uint_2 = OpTypePointer Output %_arr_v3uint_uint_2
+%_arr_bool_uint_2 = OpTypeArray %bool %uint_2
+%_ptr_Output__arr_bool_uint_2 = OpTypePointer Output %_arr_bool_uint_2
+ %void = OpTypeVoid
+ %21 = OpTypeFunction %void
+%_ptr_Output_bool = OpTypePointer Output %bool
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%gl_Position = OpVariable %_ptr_Output__arr_v4float_uint_2 Output
+ %4 = OpVariable %_ptr_Output__arr_v3uint_uint_2 Output
+ %5 = OpVariable %_ptr_Output__arr_bool_uint_2 Output
+ %main = OpFunction %void None %21
+ %23 = OpLabel
+ %24 = OpLoad %uint %gl_LocalInvocationIndex
+ OpSetMeshOutputsEXT %uint_2 %uint_2
+ %25 = OpAccessChain %_ptr_Output_bool %5 %24
+ OpStore %25 %false
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+}
+
+TEST_F(ValidateBuiltIns, BadVulkanBuiltinCullPrimitiveArrayOfBool) {
+ const std::string text = R"(
+ OpCapability MeshShadingEXT
+ OpExtension "SPV_EXT_mesh_shader"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint MeshEXT %main "main" %gl_LocalInvocationIndex %gl_Position %4 %5
+ OpExecutionMode %main LocalSize 2 1 1
+ OpExecutionMode %main OutputTrianglesEXT
+ OpExecutionMode %main OutputVertices 2
+ OpExecutionMode %main OutputPrimitivesEXT 2
+ OpDecorate %gl_LocalInvocationIndex BuiltIn LocalInvocationIndex
+ OpDecorate %gl_Position BuiltIn Position
+ OpDecorate %4 BuiltIn PrimitiveTriangleIndicesEXT
+ OpDecorate %5 BuiltIn CullPrimitiveEXT
+ OpDecorate %5 PerPrimitiveEXT
+ %uint = OpTypeInt 32 0
+ %uint_2 = OpConstant %uint 2
+ %bool = OpTypeBool
+ %false = OpConstantFalse %bool
+%_ptr_Input_uint = OpTypePointer Input %uint
+ %float = OpTypeFloat 32
+ %v4float = OpTypeVector %float 4
+%_arr_v4float_uint_2 = OpTypeArray %v4float %uint_2
+%_ptr_Output__arr_v4float_uint_2 = OpTypePointer Output %_arr_v4float_uint_2
+ %v3uint = OpTypeVector %uint 3
+%_arr_v3uint_uint_2 = OpTypeArray %v3uint %uint_2
+%_ptr_Output__arr_v3uint_uint_2 = OpTypePointer Output %_arr_v3uint_uint_2
+%_arr_uint_uint_2 = OpTypeArray %uint %uint_2
+%_ptr_Output__arr_uint_uint_2 = OpTypePointer Output %_arr_uint_uint_2
+ %void = OpTypeVoid
+ %21 = OpTypeFunction %void
+%_ptr_Output_uint = OpTypePointer Output %uint
+%gl_LocalInvocationIndex = OpVariable %_ptr_Input_uint Input
+%gl_Position = OpVariable %_ptr_Output__arr_v4float_uint_2 Output
+ %4 = OpVariable %_ptr_Output__arr_v3uint_uint_2 Output
+ %5 = OpVariable %_ptr_Output__arr_uint_uint_2 Output
+ %main = OpFunction %void None %21
+ %23 = OpLabel
+ %24 = OpLoad %uint %gl_LocalInvocationIndex
+ OpSetMeshOutputsEXT %uint_2 %uint_2
+ %25 = OpAccessChain %_ptr_Output_uint %5 %24
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(text, SPV_ENV_VULKAN_1_3);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_3));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-CullPrimitiveEXT-CullPrimitiveEXT-07036"));
+}
+
TEST_F(ValidateBuiltIns, BadVulkanBuiltinCullPrimitiveEXTStorageClass) {
const std::string text = R"(
OpCapability MeshShadingEXT