Add WebGPU specific validation for multiple BuiltIn decorations (#2333)
Covers NumWorkgroups, LocalInvocationId & GlobalInvocationId
Part of resolving #2276
diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp
index 729029a..efe9b09 100644
--- a/source/val/validate_builtins.cpp
+++ b/source/val/validate_builtins.cpp
@@ -2446,13 +2446,15 @@
spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtDefinition(
const Decoration& decoration, const Instruction& inst) {
- if (spvIsVulkanEnv(_.context()->target_env)) {
+ if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
if (spv_result_t error = ValidateI32Vec(
decoration, inst, 3,
[this, &decoration,
&inst](const std::string& message) -> spv_result_t {
return _.diag(SPV_ERROR_INVALID_DATA, &inst)
- << "According to the Vulkan spec BuiltIn "
+ << "According to the "
+ << spvLogStringForEnv(_.context()->target_env)
+ << " spec BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " variable needs to be a 3-component 32-bit int "
@@ -2472,12 +2474,13 @@
const Decoration& decoration, const Instruction& built_in_inst,
const Instruction& referenced_inst,
const Instruction& referenced_from_inst) {
- if (spvIsVulkanEnv(_.context()->target_env)) {
+ if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
const SpvStorageClass storage_class = GetStorageClass(referenced_from_inst);
if (storage_class != SpvStorageClassMax &&
storage_class != SpvStorageClassInput) {
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
- << "Vulkan spec allows BuiltIn "
+ << spvLogStringForEnv(_.context()->target_env)
+ << " spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " to be only used for variables with Input storage class. "
@@ -2487,11 +2490,15 @@
}
for (const SpvExecutionModel execution_model : execution_models_) {
- if (execution_model != SpvExecutionModelGLCompute &&
- execution_model != SpvExecutionModelTaskNV &&
- execution_model != SpvExecutionModelMeshNV) {
+ bool has_vulkan_model = execution_model == SpvExecutionModelGLCompute ||
+ execution_model == SpvExecutionModelTaskNV ||
+ execution_model == SpvExecutionModelMeshNV;
+ bool has_webgpu_model = execution_model == SpvExecutionModelGLCompute;
+ if ((spvIsVulkanEnv(_.context()->target_env) && !has_vulkan_model) ||
+ (spvIsWebGPUEnv(_.context()->target_env) && !has_webgpu_model)) {
return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
- << "Vulkan spec allows BuiltIn "
+ << spvLogStringForEnv(_.context()->target_env)
+ << " spec allows BuiltIn "
<< _.grammar().lookupOperandName(SPV_OPERAND_TYPE_BUILT_IN,
decoration.params()[0])
<< " to be used only with GLCompute execution model. "
diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp
index 2560b94..ac01920 100644
--- a/test/val/val_builtins_test.cpp
+++ b/test/val/val_builtins_test.cpp
@@ -745,6 +745,13 @@
Values(TestResult())));
INSTANTIATE_TEST_SUITE_P(
+ ComputeShaderInputInt32Vec3Success,
+ ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
+ Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"),
+ Values("GLCompute"), Values("Input"), Values("%u32vec3"),
+ Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
ComputeShaderInputInt32Vec3NotGLCompute,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(
@@ -757,6 +764,15 @@
"to be used only with GLCompute execution model"))));
INSTANTIATE_TEST_SUITE_P(
+ ComputeShaderInputInt32Vec3NotGLCompute,
+ ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
+ Combine(
+ Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"),
+ Values("Vertex", "Fragment"), Values("Input"), Values("%u32vec3"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "to be used only with GLCompute execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
ComputeShaderInputInt32Vec3NotInput,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups",
@@ -768,6 +784,16 @@
"uses storage class Output"))));
INSTANTIATE_TEST_SUITE_P(
+ ComputeShaderInputInt32Vec3NotInput,
+ ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
+ Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"),
+ Values("GLCompute"), Values("Output"), Values("%u32vec3"),
+ Values(TestResult(
+ SPV_ERROR_INVALID_DATA,
+ "to be only used for variables with Input storage class",
+ "uses storage class Output"))));
+
+INSTANTIATE_TEST_SUITE_P(
ComputeShaderInputInt32Vec3NotIntVector,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups",
@@ -779,6 +805,16 @@
"is not an int vector"))));
INSTANTIATE_TEST_SUITE_P(
+ ComputeShaderInputInt32Vec3NotIntVector,
+ ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
+ Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"),
+ Values("GLCompute"), Values("Input"),
+ Values("%u32arr3", "%f32vec3"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "needs to be a 3-component 32-bit int vector",
+ "is not an int vector"))));
+
+INSTANTIATE_TEST_SUITE_P(
ComputeShaderInputInt32Vec3NotIntVec3,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups",
@@ -789,6 +825,15 @@
"has 4 components"))));
INSTANTIATE_TEST_SUITE_P(
+ ComputeShaderInputInt32Vec3NotIntVec3,
+ ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
+ Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups"),
+ Values("GLCompute"), Values("Input"), Values("%u32vec4"),
+ Values(TestResult(SPV_ERROR_INVALID_DATA,
+ "needs to be a 3-component 32-bit int vector",
+ "has 4 components"))));
+
+INSTANTIATE_TEST_SUITE_P(
ComputeShaderInputInt32Vec3NotInt32Vec,
ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups",