Dawn: Dump shader module source before checking cache if required

This CL make shader module sources always get dumped if DumpShaders
toggle enabled, regardless of in-memory or on-disk cache hit or not.
Without this CL, shader sources are dumped only if both caches missed
and ParseShaderModule get called.

This CL also fix a typo.

Bug: 42240459, 402772740
Change-Id: I23f87567e726d6055c08293d59b33ef67f549800
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/247674
Reviewed-by: Loko Kung <lokokung@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Zhaoming Jiang <zhaoming.jiang@microsoft.com>
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index 9c32973..ee22450 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -2151,7 +2151,7 @@
                                    Branch<ShaderSourceSPIRV, DawnShaderModuleSPIRVOptionsDescriptor,
                                           ShaderModuleCompilationOptions>>()));
 
-    // Module type specific validation.
+    // Module type specific validation
     switch (moduleType) {
         case wgpu::SType::ShaderSourceSPIRV: {
             DAWN_INVALID_IF(!TINT_BUILD_SPV_READER || IsToggleEnabled(Toggle::DisallowSpirv),
@@ -2169,6 +2169,11 @@
             DAWN_UNREACHABLE();
     }
 
+    // Dump shader source code if required.
+    if (IsToggleEnabled(Toggle::DumpShaders)) {
+        DumpShaderFromDescriptor(this, unpacked);
+    }
+
     // Check the cache and do actual validation and parsing if cache missed.
     ShaderModuleBase blueprint(this, unpacked, internalExtensions,
                                ApiObjectBase::kUntrackedByDevice);
diff --git a/src/dawn/native/ShaderModule.cpp b/src/dawn/native/ShaderModule.cpp
index 5f54066..c22a863 100644
--- a/src/dawn/native/ShaderModule.cpp
+++ b/src/dawn/native/ShaderModule.cpp
@@ -1370,17 +1370,38 @@
     DAWN_ASSERT(HasError());
 }
 
+void DumpShaderFromDescriptor(LogEmitter* logEmitter,
+                              const UnpackedPtr<ShaderModuleDescriptor>& shaderModuleDesc) {
+#if TINT_BUILD_SPV_READER
+    if ([[maybe_unused]] const auto* spirvDesc = shaderModuleDesc.Get<ShaderSourceSPIRV>()) {
+        // Dump SPIR-V if enabled.
+#ifdef DAWN_ENABLE_SPIRV_VALIDATION
+        DumpSpirv(logEmitter, spirvDesc->code, spirvDesc->codeSize);
+#endif  // DAWN_ENABLE_SPIRV_VALIDATION
+        return;
+    }
+#else   // TINT_BUILD_SPV_READER
+    // SPIR-V is not enabled, so the descriptor should not contain it.
+    DAWN_ASSERT(shaderModuleDesc.Get<ShaderSourceSPIRV>() == nullptr);
+#endif  // TINT_BUILD_SPV_READER
+
+    // Dump WGSL.
+    const ShaderSourceWGSL* wgslDesc = shaderModuleDesc.Get<ShaderSourceWGSL>();
+    DAWN_ASSERT(wgslDesc != nullptr);
+    std::ostringstream dumpedMsg;
+    dumpedMsg << "// Dumped WGSL:\n" << std::string_view(wgslDesc->code) << "\n";
+    logEmitter->EmitLog(wgpu::LoggingType::Info, dumpedMsg.str().c_str());
+}
+
 ResultOrError<ShaderModuleParseResult> ParseShaderModule(ShaderModuleParseRequest req) {
     ShaderModuleParseResult outputParseResult;
 
     const ShaderModuleParseDeviceInfo& deviceInfo = req.deviceInfo;
-    LogEmitter* logEmitter = req.logEmitter.UnsafeGetValue();
-    bool dumpShaders = deviceInfo.toggles.Has(Toggle::DumpShaders);
 
 #if TINT_BUILD_SPV_READER
     // Handling SPIR-V if enabled.
     if (std::holds_alternative<ShaderModuleParseSpirvDescription>(req.shaderDescription)) {
-        // SpirV toggle should have been validated before chacking cache.
+        // SpirV toggle should have been validated before checking cache.
         DAWN_ASSERT(!deviceInfo.toggles.Has(Toggle::DisallowSpirv));
 
         ShaderModuleParseSpirvDescription& spirvDesc =
@@ -1389,7 +1410,7 @@
 
 #ifdef DAWN_ENABLE_SPIRV_VALIDATION
         MaybeError validationResult =
-            ValidateSpirv(logEmitter, spirvCode.data(), spirvCode.size(), dumpShaders);
+            ValidateSpirv(req.logEmitter.UnsafeGetValue(), spirvCode.data(), spirvCode.size());
         // If SpirV validation error occurs, store it into outputParseResult and return.
         if (validationResult.IsError()) {
             outputParseResult.SetValidationError(validationResult.AcquireError());
@@ -1410,18 +1431,11 @@
     if (std::holds_alternative<ShaderModuleParseWGSLDescription>(req.shaderDescription)) {
         ShaderModuleParseWGSLDescription wgslDesc =
             std::get<ShaderModuleParseWGSLDescription>(req.shaderDescription);
-        const StringView& wgsl = wgslDesc.wgsl.UnsafeGetValue();
         const std::vector<tint::wgsl::Extension>& internalExtensions =
             wgslDesc.internalExtensions.UnsafeGetValue();
-
+        const StringView& wgsl = wgslDesc.wgsl.UnsafeGetValue();
         auto tintFile = std::make_unique<tint::Source::File>("", wgsl);
 
-        if (dumpShaders) {
-            std::ostringstream dumpedMsg;
-            dumpedMsg << "// Dumped WGSL:\n" << std::string_view(wgsl) << "\n";
-            logEmitter->EmitLog(wgpu::LoggingType::Info, dumpedMsg.str().c_str());
-        }
-
         DAWN_TRY(ParseWGSL(std::move(tintFile), deviceInfo.wgslAllowedFeatures, internalExtensions,
                            &outputParseResult));
     }
diff --git a/src/dawn/native/ShaderModule.h b/src/dawn/native/ShaderModule.h
index fe1ad33..4009fb1 100644
--- a/src/dawn/native/ShaderModule.h
+++ b/src/dawn/native/ShaderModule.h
@@ -55,6 +55,7 @@
 #include "dawn/native/Forward.h"
 #include "dawn/native/IntegerTypes.h"
 #include "dawn/native/Limits.h"
+#include "dawn/native/LogEmitter.h"
 #include "dawn/native/ObjectBase.h"
 #include "dawn/native/PerStage.h"
 #include "dawn/native/Serializable.h"
@@ -153,6 +154,9 @@
     std::string name;
 };
 
+void DumpShaderFromDescriptor(LogEmitter* logEmitter,
+                              const UnpackedPtr<ShaderModuleDescriptor>& shaderModuleDesc);
+
 // Parse a shader module from a validated ShaderModuleDescriptor, and generate reflection
 // information if required. Validation errors generated during parsing are also made cacheable and
 // returned within ShaderModuleParseResult together with compilation messages, rather than as an
diff --git a/src/dawn/native/SpirvValidation.cpp b/src/dawn/native/SpirvValidation.cpp
index 61aac75..3c2d2ce0 100644
--- a/src/dawn/native/SpirvValidation.cpp
+++ b/src/dawn/native/SpirvValidation.cpp
@@ -29,15 +29,13 @@
 
 #include <spirv-tools/libspirv.hpp>
 
+#include <memory>
 #include <sstream>
 #include <string>
 
 namespace dawn::native {
 
-MaybeError ValidateSpirv(LogEmitter* logEmitter,
-                         const uint32_t* spirv,
-                         size_t wordCount,
-                         bool dumpSpirv) {
+MaybeError ValidateSpirv(LogEmitter* logEmitter, const uint32_t* spirv, size_t wordCount) {
     spvtools::SpirvTools spirvTools(SPV_ENV_VULKAN_1_1);
     spirvTools.SetMessageConsumer([logEmitter](spv_message_level_t level, const char*,
                                                const spv_position_t& position,
@@ -71,17 +69,9 @@
     val_opts.SetFriendlyNames(false);
 
     const bool valid = spirvTools.Validate(spirv, wordCount, val_opts);
-    if (dumpSpirv || !valid) {
-        std::ostringstream dumpedMsg;
-        std::string disassembly;
-        if (spirvTools.Disassemble(
-                spirv, wordCount, &disassembly,
-                SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT)) {
-            dumpedMsg << "/* Dumped generated SPIRV disassembly */\n" << disassembly;
-        } else {
-            dumpedMsg << "/* Failed to disassemble generated SPIRV */";
-        }
-        logEmitter->EmitLog(wgpu::LoggingType::Info, dumpedMsg.str().c_str());
+    // Dump the generated SPIRV if it is invalid.
+    if (!valid) {
+        DumpSpirv(logEmitter, spirv, wordCount, &spirvTools);
     }
 
     DAWN_INVALID_IF(!valid, "Produced invalid SPIRV. Please file a bug at https://crbug.com/tint.");
@@ -89,4 +79,26 @@
     return {};
 }
 
+void DumpSpirv(LogEmitter* logEmitter,
+               const uint32_t* spirv,
+               size_t wordCount,
+               spvtools::SpirvTools* spirvTools) {
+    std::unique_ptr<spvtools::SpirvTools> inplaceSpirvTools;
+    if (spirvTools == nullptr) {
+        inplaceSpirvTools = std::make_unique<spvtools::SpirvTools>(SPV_ENV_VULKAN_1_1);
+        spirvTools = inplaceSpirvTools.get();
+    }
+
+    std::ostringstream dumpedMsg;
+    std::string disassembly;
+    if (spirvTools->Disassemble(
+            spirv, wordCount, &disassembly,
+            SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES | SPV_BINARY_TO_TEXT_OPTION_INDENT)) {
+        dumpedMsg << "/* Dumped SPIRV disassembly */\n" << disassembly;
+    } else {
+        dumpedMsg << "/* Failed to disassemble SPIRV */";
+    }
+    logEmitter->EmitLog(wgpu::LoggingType::Info, dumpedMsg.str().c_str());
+}
+
 }  // namespace dawn::native
diff --git a/src/dawn/native/SpirvValidation.h b/src/dawn/native/SpirvValidation.h
index a4c3595..9cb703c 100644
--- a/src/dawn/native/SpirvValidation.h
+++ b/src/dawn/native/SpirvValidation.h
@@ -31,12 +31,18 @@
 #include "dawn/native/Error.h"
 #include "dawn/native/LogEmitter.h"
 
+namespace spvtools {
+class SpirvTools;
+}
+
 namespace dawn::native {
 
-MaybeError ValidateSpirv(LogEmitter* logEmitter,
-                         const uint32_t* spirv,
-                         size_t wordCount,
-                         bool dumpSpirv);
+MaybeError ValidateSpirv(LogEmitter* logEmitter, const uint32_t* spirv, size_t wordCount);
+
+void DumpSpirv(LogEmitter* logEmitter,
+               const uint32_t* spirv,
+               size_t wordCount,
+               spvtools::SpirvTools* spirvTools = nullptr);
 
 }  // namespace dawn::native
 
diff --git a/src/dawn/native/vulkan/ShaderModuleVk.cpp b/src/dawn/native/vulkan/ShaderModuleVk.cpp
index ba734ad..b2f44aa 100644
--- a/src/dawn/native/vulkan/ShaderModuleVk.cpp
+++ b/src/dawn/native/vulkan/ShaderModuleVk.cpp
@@ -382,8 +382,11 @@
         "Vulkan.CompileShaderToSPIRV");
 
 #ifdef DAWN_ENABLE_SPIRV_VALIDATION
-    DAWN_TRY(ValidateSpirv(GetDevice(), compilation->spirv.data(), compilation->spirv.size(),
-                           GetDevice()->IsToggleEnabled(Toggle::DumpShaders)));
+    // Validate and if required dump the compiled SPIR-V code.
+    DAWN_TRY(ValidateSpirv(GetDevice(), compilation->spirv.data(), compilation->spirv.size()));
+    if (GetDevice()->IsToggleEnabled(Toggle::DumpShaders)) {
+        DumpSpirv(GetDevice(), compilation->spirv.data(), compilation->spirv.size());
+    }
 #endif
 
     VkShaderModuleCreateInfo createInfo;