Enable use of SPIR-V 1.4 in Dawn

Bug: 422425111

* Add Dawn support to use SPIR-V 1.4
  * updates SPIR-V validation environment
  * changes SPIR-V version in Tint
  * Adds toggle for eventual finch trial

Change-Id: I8a9ef6e58dea754e513e9048897c09a41a8bda9a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/248095
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Alan Baker <alanbaker@google.com>
Auto-Submit: Alan Baker <alanbaker@google.com>
diff --git a/include/dawn/platform/DawnPlatform.h b/include/dawn/platform/DawnPlatform.h
index 016de1a..337e759 100644
--- a/include/dawn/platform/DawnPlatform.h
+++ b/include/dawn/platform/DawnPlatform.h
@@ -102,6 +102,7 @@
     kWebGPUUseTintIR,
     kWebGPUUseVulkanMemoryModel,
     kWebGPUEnableRangeAnalysisForRobustness,
+    kWebGPUUseSpirv14,
 };
 
 class DAWN_PLATFORM_EXPORT Platform {
diff --git a/src/dawn/native/ShaderModule.cpp b/src/dawn/native/ShaderModule.cpp
index c22a863..019d892 100644
--- a/src/dawn/native/ShaderModule.cpp
+++ b/src/dawn/native/ShaderModule.cpp
@@ -1410,7 +1410,8 @@
 
 #ifdef DAWN_ENABLE_SPIRV_VALIDATION
         MaybeError validationResult =
-            ValidateSpirv(req.logEmitter.UnsafeGetValue(), spirvCode.data(), spirvCode.size());
+            ValidateSpirv(req.logEmitter.UnsafeGetValue(), spirvCode.data(), spirvCode.size(),
+                          deviceInfo.toggles.Has(Toggle::UseSpirv14));
         // If SpirV validation error occurs, store it into outputParseResult and return.
         if (validationResult.IsError()) {
             outputParseResult.SetValidationError(validationResult.AcquireError());
diff --git a/src/dawn/native/SpirvValidation.cpp b/src/dawn/native/SpirvValidation.cpp
index 3c2d2ce0..263b3e4 100644
--- a/src/dawn/native/SpirvValidation.cpp
+++ b/src/dawn/native/SpirvValidation.cpp
@@ -35,8 +35,11 @@
 
 namespace dawn::native {
 
-MaybeError ValidateSpirv(LogEmitter* logEmitter, const uint32_t* spirv, size_t wordCount) {
-    spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_1);
+MaybeError ValidateSpirv(LogEmitter* logEmitter,
+                         const uint32_t* spirv,
+                         size_t wordCount,
+                         bool spv14) {
+    spvtools::SpirvTools spirvTools(spv14 ? SPV_ENV_VULKAN_1_1_SPIRV_1_4 : SPV_ENV_VULKAN_1_1);
     spirvTools.SetMessageConsumer([logEmitter](spv_message_level_t level, const char*,
                                                const spv_position_t& position,
                                                const char* message) {
@@ -85,7 +88,8 @@
                spvtools::SpirvTools* spirvTools) {
     std::unique_ptr<spvtools::SpirvTools> inplaceSpirvTools;
     if (spirvTools == nullptr) {
-        inplaceSpirvTools = std::make_unique<spvtools::SpirvTools>(SPV_ENV_VULKAN_1_1);
+        // Use the newest environment Dawn supports because disassembly supports older versions.
+        inplaceSpirvTools = std::make_unique<spvtools::SpirvTools>(SPV_ENV_VULKAN_1_1_SPIRV_1_4);
         spirvTools = inplaceSpirvTools.get();
     }
 
diff --git a/src/dawn/native/SpirvValidation.h b/src/dawn/native/SpirvValidation.h
index 9cb703c..e5deccf 100644
--- a/src/dawn/native/SpirvValidation.h
+++ b/src/dawn/native/SpirvValidation.h
@@ -37,7 +37,10 @@
 
 namespace dawn::native {
 
-MaybeError ValidateSpirv(LogEmitter* logEmitter, const uint32_t* spirv, size_t wordCount);
+MaybeError ValidateSpirv(LogEmitter* logEmitter,
+                         const uint32_t* spirv,
+                         size_t wordCount,
+                         bool spv14);
 
 void DumpSpirv(LogEmitter* logEmitter,
                const uint32_t* spirv,
diff --git a/src/dawn/native/Toggles.cpp b/src/dawn/native/Toggles.cpp
index 7ab0247..98bc478 100644
--- a/src/dawn/native/Toggles.cpp
+++ b/src/dawn/native/Toggles.cpp
@@ -660,6 +660,9 @@
       "Compute the range of the index with Integer Range Analysis in the robustness transform and "
       "skip doing index clamping when the out of bound access cannot happen.",
       "https://crbug.com/348701956", ToggleStage::Device}},
+    {Toggle::UseSpirv14,
+     {"use_spirv_1_4", "Use SPIR-V 1.4 if available", "https://crbug.com/422421915",
+      ToggleStage::Device}},
     {Toggle::NoWorkaroundSampleMaskBecomesZeroForAllButLastColorTarget,
      {"no_workaround_sample_mask_becomes_zero_for_all_but_last_color_target",
       "MacOS 12.0+ Intel has a bug where the sample mask is only applied for the last color "
diff --git a/src/dawn/native/Toggles.h b/src/dawn/native/Toggles.h
index 4650c45..6e8707f 100644
--- a/src/dawn/native/Toggles.h
+++ b/src/dawn/native/Toggles.h
@@ -157,6 +157,7 @@
     VulkanDirectVariableAccessTransformHandle,
     VulkanAddWorkToEmptyResolvePass,
     EnableIntegerRangeAnalysisInRobustness,
+    UseSpirv14,
 
     // Unresolved issues.
     NoWorkaroundSampleMaskBecomesZeroForAllButLastColorTarget,
diff --git a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
index f3d3140..d3dc40e 100644
--- a/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
+++ b/src/dawn/native/vulkan/PhysicalDeviceVk.cpp
@@ -981,6 +981,13 @@
     deviceToggles->Default(
         Toggle::EnableIntegerRangeAnalysisInRobustness,
         platform->IsFeatureEnabled(platform::Features::kWebGPUEnableRangeAnalysisForRobustness));
+
+    if (GetDeviceInfo().HasExt(DeviceExt::Spirv14)) {
+        deviceToggles->Default(Toggle::UseSpirv14,
+                               platform->IsFeatureEnabled(platform::Features::kWebGPUUseSpirv14));
+    } else {
+        deviceToggles->ForceSet(Toggle::UseSpirv14, false);
+    }
 }
 
 ResultOrError<Ref<DeviceBase>> PhysicalDevice::CreateDeviceImpl(
diff --git a/src/dawn/native/vulkan/ShaderModuleVk.cpp b/src/dawn/native/vulkan/ShaderModuleVk.cpp
index b2f44aa..6d5df11 100644
--- a/src/dawn/native/vulkan/ShaderModuleVk.cpp
+++ b/src/dawn/native/vulkan/ShaderModuleVk.cpp
@@ -283,6 +283,9 @@
         GetDevice()->IsToggleEnabled(Toggle::ScalarizeMaxMinClamp);
     req.tintOptions.use_vulkan_memory_model =
         GetDevice()->IsToggleEnabled(Toggle::UseVulkanMemoryModel);
+    req.tintOptions.spirv_version = GetDevice()->IsToggleEnabled(Toggle::UseSpirv14)
+                                        ? tint::spirv::writer::SpvVersion::kSpv14
+                                        : tint::spirv::writer::SpvVersion::kSpv13;
     req.tintOptions.dva_transform_handle =
         GetDevice()->IsToggleEnabled(Toggle::VulkanDirectVariableAccessTransformHandle);
     // Pass matrices to user functions by pointer on Qualcomm devices to workaround a known bug.
@@ -383,7 +386,9 @@
 
 #ifdef DAWN_ENABLE_SPIRV_VALIDATION
     // Validate and if required dump the compiled SPIR-V code.
-    DAWN_TRY(ValidateSpirv(GetDevice(), compilation->spirv.data(), compilation->spirv.size()));
+    const bool spv14 = GetDevice()->IsToggleEnabled(Toggle::UseSpirv14);
+    DAWN_TRY(
+        ValidateSpirv(GetDevice(), compilation->spirv.data(), compilation->spirv.size(), spv14));
     if (GetDevice()->IsToggleEnabled(Toggle::DumpShaders)) {
         DumpSpirv(GetDevice(), compilation->spirv.data(), compilation->spirv.size());
     }
diff --git a/src/dawn/native/vulkan/VulkanExtensions.cpp b/src/dawn/native/vulkan/VulkanExtensions.cpp
index 655fd12..efad9bf 100644
--- a/src/dawn/native/vulkan/VulkanExtensions.cpp
+++ b/src/dawn/native/vulkan/VulkanExtensions.cpp
@@ -171,6 +171,8 @@
      VulkanVersion_1_2},
     {DeviceExt::DrawIndirectCount, "VK_KHR_draw_indirect_count", NeverPromoted},
     {DeviceExt::VulkanMemoryModel, "VK_KHR_vulkan_memory_model", VulkanVersion_1_2},
+    {DeviceExt::ShaderFloatControls, "VK_KHR_shader_float_controls", VulkanVersion_1_2},
+    {DeviceExt::Spirv14, "VK_KHR_spirv_1_4", VulkanVersion_1_2},
 
     {DeviceExt::ShaderIntegerDotProduct, "VK_KHR_shader_integer_dot_product", VulkanVersion_1_3},
     {DeviceExt::ZeroInitializeWorkgroupMemory, "VK_KHR_zero_initialize_workgroup_memory",
@@ -215,7 +217,8 @@
 }
 
 DeviceExtSet EnsureDependencies(const DeviceExtSet& advertisedExts,
-                                const InstanceExtSet& instanceExts) {
+                                const InstanceExtSet& instanceExts,
+                                uint32_t version) {
     // This is very similar to EnsureDependencies for instanceExtSet. See comment there for
     // an explanation of what happens.
     DeviceExtSet visitedSet;
@@ -292,6 +295,8 @@
             case DeviceExt::SubgroupSizeControl:
             case DeviceExt::ShaderSubgroupExtendedTypes:
             case DeviceExt::VulkanMemoryModel:
+            case DeviceExt::CooperativeMatrix:
+            case DeviceExt::ShaderFloatControls:
                 hasDependencies = HasDep(DeviceExt::GetPhysicalDeviceProperties2);
                 break;
 
@@ -335,8 +340,9 @@
                 hasDependencies = HasDep(DeviceExt::Swapchain);
                 break;
 
-            case DeviceExt::CooperativeMatrix:
-                hasDependencies = HasDep(DeviceExt::GetPhysicalDeviceProperties2);
+            case DeviceExt::Spirv14:
+                hasDependencies =
+                    version >= VK_VERSION_1_1 && HasDep(DeviceExt::ShaderFloatControls);
                 break;
 
             case DeviceExt::EnumCount:
diff --git a/src/dawn/native/vulkan/VulkanExtensions.h b/src/dawn/native/vulkan/VulkanExtensions.h
index 8c7f080..4edffd2 100644
--- a/src/dawn/native/vulkan/VulkanExtensions.h
+++ b/src/dawn/native/vulkan/VulkanExtensions.h
@@ -109,6 +109,8 @@
     ShaderSubgroupExtendedTypes,
     DrawIndirectCount,
     VulkanMemoryModel,
+    ShaderFloatControls,
+    Spirv14,
 
     // Promoted to 1.3
     ShaderIntegerDotProduct,
@@ -161,7 +163,8 @@
 // extensions that don't have all their transitive dependencies in advertisedExts or in
 // instanceExts.
 DeviceExtSet EnsureDependencies(const DeviceExtSet& advertisedExts,
-                                const InstanceExtSet& instanceExts);
+                                const InstanceExtSet& instanceExts,
+                                uint32_t version);
 
 // The list of all known Vulkan layers.
 enum class VulkanLayer {
diff --git a/src/dawn/native/vulkan/VulkanInfo.cpp b/src/dawn/native/vulkan/VulkanInfo.cpp
index b41cbf8..e97931a 100644
--- a/src/dawn/native/vulkan/VulkanInfo.cpp
+++ b/src/dawn/native/vulkan/VulkanInfo.cpp
@@ -230,7 +230,8 @@
         }
 
         MarkPromotedExtensions(&info.extensions, info.properties.apiVersion);
-        info.extensions = EnsureDependencies(info.extensions, globalInfo.extensions);
+        info.extensions =
+            EnsureDependencies(info.extensions, globalInfo.extensions, info.properties.apiVersion);
     }
 
     // Gather general and extension features and properties
diff --git a/src/dawn/platform/DawnPlatform.cpp b/src/dawn/platform/DawnPlatform.cpp
index fa30f88..476c31a 100644
--- a/src/dawn/platform/DawnPlatform.cpp
+++ b/src/dawn/platform/DawnPlatform.cpp
@@ -109,6 +109,8 @@
             return false;
         case Features::kWebGPUEnableRangeAnalysisForRobustness:
             return true;
+        case Features::kWebGPUUseSpirv14:
+            return true;
     }
     return false;
 }