Add WebGPU Execution scope check (#2148)
Fixes #2069
diff --git a/source/val/validate_scopes.cpp b/source/val/validate_scopes.cpp
index ac31ec0..8f29ae0 100644
--- a/source/val/validate_scopes.cpp
+++ b/source/val/validate_scopes.cpp
@@ -90,6 +90,17 @@
}
}
+ // WebGPU Specific rules
+ if (spvIsWebGPUEnv(_.context()->target_env)) {
+ // Scope for execution must be limited to Workgroup or Subgroup
+ if (value != SpvScopeWorkgroup && value != SpvScopeSubgroup) {
+ return _.diag(SPV_ERROR_INVALID_DATA, inst)
+ << spvOpcodeString(opcode)
+ << ": in WebGPU environment Execution Scope is limited to "
+ "Workgroup and Subgroup";
+ }
+ }
+
// TODO(atgoo@github.com) Add checks for OpenCL and OpenGL environments.
// General SPIRV rules
diff --git a/test/val/val_barriers_test.cpp b/test/val/val_barriers_test.cpp
index 9652299..63d6c52 100644
--- a/test/val/val_barriers_test.cpp
+++ b/test/val/val_barriers_test.cpp
@@ -28,18 +28,17 @@
using ValidateBarriers = spvtest::ValidateBase<bool>;
-std::string GenerateShaderCode(
- const std::string& body,
- const std::string& capabilities_and_extensions = "",
- const std::string& execution_model = "GLCompute") {
+std::string GenerateShaderCodeImpl(
+ const std::string& body, const std::string& capabilities_and_extensions,
+ const std::string& definitions, const std::string& execution_model,
+ const std::string& memory_model) {
std::ostringstream ss;
ss << R"(
OpCapability Shader
-OpCapability Int64
)";
ss << capabilities_and_extensions;
- ss << "OpMemoryModel Logical GLSL450\n";
+ ss << memory_model << std::endl;
ss << "OpEntryPoint " << execution_model << " %main \"main\"\n";
if (execution_model == "Fragment") {
ss << "OpExecutionMode %main OriginUpperLeft\n";
@@ -56,16 +55,15 @@
%bool = OpTypeBool
%f32 = OpTypeFloat 32
%u32 = OpTypeInt 32 0
-%u64 = OpTypeInt 64 0
%f32_0 = OpConstant %f32 0
%f32_1 = OpConstant %f32 1
%u32_0 = OpConstant %u32 0
%u32_1 = OpConstant %u32 1
%u32_4 = OpConstant %u32 4
-%u64_0 = OpConstant %u64 0
-%u64_1 = OpConstant %u64 1
-
+)";
+ ss << definitions;
+ ss << R"(
%cross_device = OpConstant %u32 0
%device = OpConstant %u32 1
%workgroup = OpConstant %u32 2
@@ -96,6 +94,42 @@
return ss.str();
}
+std::string GenerateShaderCode(
+ const std::string& body,
+ const std::string& capabilities_and_extensions = "",
+ const std::string& execution_model = "GLCompute") {
+ const std::string int64_capability = R"(
+OpCapability Int64
+)";
+ const std::string int64_declarations = R"(
+%u64 = OpTypeInt 64 0
+%u64_0 = OpConstant %u64 0
+%u64_1 = OpConstant %u64 1
+)";
+ const std::string memory_model = "OpMemoryModel Logical GLSL450";
+ return GenerateShaderCodeImpl(
+ body, int64_capability + capabilities_and_extensions, int64_declarations,
+ execution_model, memory_model);
+}
+
+std::string GenerateWebGPUShaderCode(
+ const std::string& body,
+ const std::string& capabilities_and_extensions = "",
+ const std::string& execution_model = "GLCompute") {
+ const std::string vulkan_memory_capability = R"(
+OpCapability VulkanMemoryModelKHR
+)";
+ const std::string vulkan_memory_extension = R"(
+OpExtension "SPV_KHR_vulkan_memory_model"
+)";
+ const std::string memory_model = "OpMemoryModel Logical VulkanKHR";
+ return GenerateShaderCodeImpl(body,
+ vulkan_memory_capability +
+ capabilities_and_extensions +
+ vulkan_memory_extension,
+ "", execution_model, memory_model);
+}
+
std::string GenerateKernelCode(
const std::string& body,
const std::string& capabilities_and_extensions = "") {
@@ -212,6 +246,16 @@
ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_VULKAN_1_0));
}
+TEST_F(ValidateBarriers, OpControlBarrierWebGPUSuccess) {
+ const std::string body = R"(
+OpControlBarrier %workgroup %device %none
+OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup
+)";
+
+ CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
+ ASSERT_EQ(SPV_SUCCESS, ValidateInstructions(SPV_ENV_WEBGPU_0));
+}
+
TEST_F(ValidateBarriers, OpControlBarrierExecutionModelFragmentSpirv12) {
const std::string body = R"(
OpControlBarrier %device %device %none
@@ -322,6 +366,18 @@
"is limited to Workgroup and Subgroup"));
}
+TEST_F(ValidateBarriers, OpControlBarrierWebGPUExecutionScopeDevice) {
+ const std::string body = R"(
+OpControlBarrier %device %workgroup %none
+)";
+
+ CompileSuccessfully(GenerateWebGPUShaderCode(body), SPV_ENV_WEBGPU_0);
+ ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions(SPV_ENV_WEBGPU_0));
+ EXPECT_THAT(getDiagnosticString(),
+ HasSubstr("ControlBarrier: in WebGPU environment Execution Scope "
+ "is limited to Workgroup and Subgroup"));
+}
+
TEST_F(ValidateBarriers, OpControlBarrierVulkanMemoryScopeSubgroup) {
const std::string body = R"(
OpControlBarrier %subgroup %subgroup %none