Add WebGPU specific validation for FrontFacing BuiltIn decoration (#2330)

Part of resolving #2276
diff --git a/source/val/validate_builtins.cpp b/source/val/validate_builtins.cpp
index 1efac90..508c26b 100644
--- a/source/val/validate_builtins.cpp
+++ b/source/val/validate_builtins.cpp
@@ -1063,12 +1063,14 @@
 
 spv_result_t BuiltInsValidator::ValidateFrontFacingAtDefinition(
     const Decoration& decoration, const Instruction& inst) {
-  if (spvIsVulkanEnv(_.context()->target_env)) {
+  if (spvIsVulkanOrWebGPUEnv(_.context()->target_env)) {
     if (spv_result_t error = ValidateBool(
             decoration, inst,
             [this, &inst](const std::string& message) -> spv_result_t {
               return _.diag(SPV_ERROR_INVALID_DATA, &inst)
-                     << "According to the Vulkan spec BuiltIn FrontFacing "
+                     << "According to the "
+                     << spvLogStringForEnv(_.context()->target_env)
+                     << " spec BuiltIn FrontFacing "
                         "variable needs to be a bool scalar. "
                      << message;
             })) {
@@ -1084,12 +1086,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 FrontFacing to be only used for "
+             << spvLogStringForEnv(_.context()->target_env)
+             << " spec allows BuiltIn FrontFacing to be only used for "
                 "variables with Input storage class. "
              << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
                                  referenced_from_inst)
@@ -1099,7 +1102,8 @@
     for (const SpvExecutionModel execution_model : execution_models_) {
       if (execution_model != SpvExecutionModelFragment) {
         return _.diag(SPV_ERROR_INVALID_DATA, &referenced_from_inst)
-               << "Vulkan spec allows BuiltIn FrontFacing to be used only with "
+               << spvLogStringForEnv(_.context()->target_env)
+               << " spec allows BuiltIn FrontFacing to be used only with "
                   "Fragment execution model. "
                << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
                                    referenced_from_inst, execution_model);
diff --git a/test/val/val_builtins_test.cpp b/test/val/val_builtins_test.cpp
index d72ab97..85459ed 100644
--- a/test/val/val_builtins_test.cpp
+++ b/test/val/val_builtins_test.cpp
@@ -599,6 +599,12 @@
             Values("Input"), Values("%bool"), Values(TestResult())));
 
 INSTANTIATE_TEST_SUITE_P(
+    FrontFacingSuccess,
+    ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
+    Combine(Values("FrontFacing"), Values("Fragment"), Values("Input"),
+            Values("%bool"), Values(TestResult())));
+
+INSTANTIATE_TEST_SUITE_P(
     FrontFacingAndHelperInvocationNotFragment,
     ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
     Combine(
@@ -610,6 +616,15 @@
                           "to be used only with Fragment execution model"))));
 
 INSTANTIATE_TEST_SUITE_P(
+    FrontFacingNotFragment,
+    ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
+    Combine(
+        Values("FrontFacing"), Values("Vertex", "GLCompute"), Values("Input"),
+        Values("%bool"),
+        Values(TestResult(SPV_ERROR_INVALID_DATA,
+                          "to be used only with Fragment execution model"))));
+
+INSTANTIATE_TEST_SUITE_P(
     FrontFacingAndHelperInvocationNotInput,
     ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
     Combine(Values("FrontFacing", "HelperInvocation"), Values("Fragment"),
@@ -620,6 +635,16 @@
                 "uses storage class Output"))));
 
 INSTANTIATE_TEST_SUITE_P(
+    FrontFacingNotInput,
+    ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
+    Combine(Values("FrontFacing"), Values("Fragment"), Values("Output"),
+            Values("%bool"),
+            Values(TestResult(
+                SPV_ERROR_INVALID_DATA,
+                "to be only used for variables with Input storage class",
+                "uses storage class Output"))));
+
+INSTANTIATE_TEST_SUITE_P(
     FrontFacingAndHelperInvocationNotBool,
     ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
     Combine(Values("FrontFacing", "HelperInvocation"), Values("Fragment"),
@@ -629,6 +654,15 @@
                               "is not a bool scalar"))));
 
 INSTANTIATE_TEST_SUITE_P(
+    FrontFacingNotBool,
+    ValidateWebGPUCombineBuiltInExecutionModelDataTypeResult,
+    Combine(Values("FrontFacing"), Values("Fragment"), Values("Input"),
+            Values("%f32", "%u32"),
+            Values(TestResult(SPV_ERROR_INVALID_DATA,
+                              "needs to be a bool scalar",
+                              "is not a bool scalar"))));
+
+INSTANTIATE_TEST_SUITE_P(
     ComputeShaderInputInt32Vec3Success,
     ValidateVulkanCombineBuiltInExecutionModelDataTypeResult,
     Combine(Values("GlobalInvocationId", "LocalInvocationId", "NumWorkgroups",