spirv-val: Add PerVertexKHR (#4807)
diff --git a/source/val/validate_annotation.cpp b/source/val/validate_annotation.cpp
index 233861a..40f2118 100644
--- a/source/val/validate_annotation.cpp
+++ b/source/val/validate_annotation.cpp
@@ -366,6 +366,11 @@
return fail(4670) << "storage class must be Input or Output";
}
break;
+ case SpvDecorationPerVertexKHR:
+ if (sc != SpvStorageClassInput) {
+ return fail(6777) << "storage class must be Input";
+ }
+ break;
default:
break;
}
diff --git a/source/val/validate_interfaces.cpp b/source/val/validate_interfaces.cpp
index 9a9a7fb..7f2d648 100644
--- a/source/val/validate_interfaces.cpp
+++ b/source/val/validate_interfaces.cpp
@@ -273,6 +273,18 @@
} else if (dec.dec_type() == SpvDecorationPerTaskNV) {
has_per_task_nv = true;
} else if (dec.dec_type() == SpvDecorationPerVertexKHR) {
+ if (!is_fragment) {
+ return _.diag(SPV_ERROR_INVALID_DATA, variable)
+ << _.VkErrorID(6777)
+ << "PerVertexKHR can only be applied to Fragment Execution "
+ "Models";
+ }
+ if (type->opcode() != SpvOpTypeArray &&
+ type->opcode() != SpvOpTypeRuntimeArray) {
+ return _.diag(SPV_ERROR_INVALID_DATA, variable)
+ << _.VkErrorID(6778)
+ << "PerVertexKHR must be declared as arrays";
+ }
has_per_vertex_khr = true;
}
}
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index 87f71ee..d9422b2 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -1937,6 +1937,10 @@
return VUID_WRAP(VUID-StandaloneSpirv-UniformConstant-06677);
case 6678:
return VUID_WRAP(VUID-StandaloneSpirv-InputAttachmentIndex-06678);
+ case 6777:
+ return VUID_WRAP(VUID-StandaloneSpirv-PerVertexKHR-06777);
+ case 6778:
+ return VUID_WRAP(VUID-StandaloneSpirv-Input-06778);
default:
return ""; // unknown id
}
diff --git a/test/val/val_decoration_test.cpp b/test/val/val_decoration_test.cpp
index 2db44a4..e7ecb61 100644
--- a/test/val/val_decoration_test.cpp
+++ b/test/val/val_decoration_test.cpp
@@ -8220,6 +8220,149 @@
"Offset decorations"));
}
+TEST_F(ValidateDecorations, PerVertexVulkanGood) {
+ const std::string spirv = R"(
+ OpCapability Shader
+ OpCapability FragmentBarycentricKHR
+ OpExtension "SPV_KHR_fragment_shader_barycentric"
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %vertexIDs
+ OpExecutionMode %main OriginUpperLeft
+ OpDecorate %vertexIDs Location 0
+ OpDecorate %vertexIDs PerVertexKHR
+ %void = OpTypeVoid
+ %func = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %uint = OpTypeInt 32 0
+%ptrFloat = OpTypePointer Input %float
+ %uint_3 = OpConstant %uint 3
+%floatArray = OpTypeArray %float %uint_3
+%ptrFloatArray = OpTypePointer Input %floatArray
+ %vertexIDs = OpVariable %ptrFloatArray Input
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %main = OpFunction %void None %func
+ %label = OpLabel
+ %access = OpAccessChain %ptrFloat %vertexIDs %int_0
+ %load = OpLoad %float %access
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
+ EXPECT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+}
+
+TEST_F(ValidateDecorations, PerVertexVulkanOutput) {
+ const std::string spirv = R"(
+ OpCapability Shader
+ OpCapability FragmentBarycentricKHR
+ OpExtension "SPV_KHR_fragment_shader_barycentric"
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %vertexIDs
+ OpExecutionMode %main OriginUpperLeft
+ OpDecorate %vertexIDs Location 0
+ OpDecorate %vertexIDs PerVertexKHR
+ %void = OpTypeVoid
+ %func = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %uint = OpTypeInt 32 0
+%ptrFloat = OpTypePointer Output %float
+ %uint_3 = OpConstant %uint 3
+%floatArray = OpTypeArray %float %uint_3
+%ptrFloatArray = OpTypePointer Output %floatArray
+ %vertexIDs = OpVariable %ptrFloatArray Output
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %main = OpFunction %void None %func
+ %label = OpLabel
+ %access = OpAccessChain %ptrFloat %vertexIDs %int_0
+ %load = OpLoad %float %access
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
+ EXPECT_EQ(SPV_ERROR_INVALID_ID, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PerVertexKHR-06777"));
+ EXPECT_THAT(getDiagnosticString(), HasSubstr("storage class must be Input"));
+}
+
+TEST_F(ValidateDecorations, PerVertexVulkanNonFragment) {
+ const std::string spirv = R"(
+ OpCapability Shader
+ OpCapability FragmentBarycentricKHR
+ OpExtension "SPV_KHR_fragment_shader_barycentric"
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Vertex %main "main" %vertexIDs
+ OpDecorate %vertexIDs Location 0
+ OpDecorate %vertexIDs PerVertexKHR
+ %void = OpTypeVoid
+ %func = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %uint = OpTypeInt 32 0
+%ptrFloat = OpTypePointer Input %float
+ %uint_3 = OpConstant %uint 3
+%floatArray = OpTypeArray %float %uint_3
+%ptrFloatArray = OpTypePointer Input %floatArray
+ %vertexIDs = OpVariable %ptrFloatArray Input
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %main = OpFunction %void None %func
+ %label = OpLabel
+ %access = OpAccessChain %ptrFloat %vertexIDs %int_0
+ %load = OpLoad %float %access
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-PerVertexKHR-06777"));
+ EXPECT_THAT(
+ getDiagnosticString(),
+ HasSubstr(
+ "PerVertexKHR can only be applied to Fragment Execution Models"));
+}
+
+TEST_F(ValidateDecorations, PerVertexVulkanNonArray) {
+ const std::string spirv = R"(
+ OpCapability Shader
+ OpCapability FragmentBarycentricKHR
+ OpExtension "SPV_KHR_fragment_shader_barycentric"
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %main "main" %vertexIDs
+ OpExecutionMode %main OriginUpperLeft
+ OpDecorate %vertexIDs Location 0
+ OpDecorate %vertexIDs PerVertexKHR
+ %void = OpTypeVoid
+ %func = OpTypeFunction %void
+ %float = OpTypeFloat 32
+ %ptrFloat = OpTypePointer Input %float
+ %vertexIDs = OpVariable %ptrFloat Input
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %main = OpFunction %void None %func
+ %label = OpLabel
+ %load = OpLoad %float %vertexIDs
+ OpReturn
+ OpFunctionEnd
+)";
+
+ CompileSuccessfully(spirv, SPV_ENV_VULKAN_1_0);
+ EXPECT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_VULKAN_1_0));
+ EXPECT_THAT(getDiagnosticString(),
+ AnyVUID("VUID-StandaloneSpirv-Input-06778"));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("PerVertexKHR must be declared as arrays"));
+}
+
} // namespace
} // namespace val
} // namespace spvtools