diff --git a/source/val/validate_scopes.cpp b/source/val/validate_scopes.cpp index ac31ec0a..8f29ae04 100644 --- a/source/val/validate_scopes.cpp +++ b/source/val/validate_scopes.cpp @@ -90,6 +90,17 @@ spv_result_t ValidateExecutionScope(ValidationState_t& _, } } + // 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 96522990..63d6c52e 100644 --- a/test/val/val_barriers_test.cpp +++ b/test/val/val_barriers_test.cpp @@ -28,18 +28,17 @@ using ::testing::Not; using ValidateBarriers = spvtest::ValidateBase; -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 @@ OpCapability Int64 %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 @@ OpFunctionEnd)"; 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 @@ OpControlBarrier %workgroup %workgroup %acquire_release_uniform_workgroup 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 @@ OpControlBarrier %device %workgroup %none "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