D3D12: Add HLSL compiler version to key

BUG=dawn:529

Change-Id: I84d8edc6022564cda084a0f0de384a4e15e0e1a1
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/35480
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Bryan Bernhart <bryan.bernhart@intel.com>
diff --git a/src/dawn_native/d3d12/BackendD3D12.cpp b/src/dawn_native/d3d12/BackendD3D12.cpp
index 946ce7b..8d61208 100644
--- a/src/dawn_native/d3d12/BackendD3D12.cpp
+++ b/src/dawn_native/d3d12/BackendD3D12.cpp
@@ -128,6 +128,16 @@
         return mDxcCompiler.Get();
     }
 
+    ResultOrError<IDxcValidator*> Backend::GetOrCreateDxcValidator() {
+        if (mDxcValidator == nullptr) {
+            DAWN_TRY(CheckHRESULT(
+                mFunctions->dxcCreateInstance(CLSID_DxcValidator, IID_PPV_ARGS(&mDxcValidator)),
+                "DXC create validator"));
+            ASSERT(mDxcValidator != nullptr);
+        }
+        return mDxcValidator.Get();
+    }
+
     const PlatformFunctions* Backend::GetFunctions() const {
         return mFunctions.get();
     }
diff --git a/src/dawn_native/d3d12/BackendD3D12.h b/src/dawn_native/d3d12/BackendD3D12.h
index 87c2d13..0490b60 100644
--- a/src/dawn_native/d3d12/BackendD3D12.h
+++ b/src/dawn_native/d3d12/BackendD3D12.h
@@ -32,6 +32,7 @@
         ComPtr<IDXGIFactory4> GetFactory() const;
         ResultOrError<IDxcLibrary*> GetOrCreateDxcLibrary();
         ResultOrError<IDxcCompiler*> GetOrCreateDxcCompiler();
+        ResultOrError<IDxcValidator*> GetOrCreateDxcValidator();
         const PlatformFunctions* GetFunctions() const;
 
         std::vector<std::unique_ptr<AdapterBase>> DiscoverDefaultAdapters() override;
@@ -45,6 +46,7 @@
         ComPtr<IDXGIFactory4> mFactory;
         ComPtr<IDxcLibrary> mDxcLibrary;
         ComPtr<IDxcCompiler> mDxcCompiler;
+        ComPtr<IDxcValidator> mDxcValidator;
     };
 
 }}  // namespace dawn_native::d3d12
diff --git a/src/dawn_native/d3d12/DeviceD3D12.cpp b/src/dawn_native/d3d12/DeviceD3D12.cpp
index 1d15eb5..a03b048 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn_native/d3d12/DeviceD3D12.cpp
@@ -218,6 +218,10 @@
         return ToBackend(GetAdapter())->GetBackend()->GetOrCreateDxcCompiler();
     }
 
+    ResultOrError<IDxcValidator*> Device::GetOrCreateDxcValidator() const {
+        return ToBackend(GetAdapter())->GetBackend()->GetOrCreateDxcValidator();
+    }
+
     const PlatformFunctions* Device::GetFunctions() const {
         return ToBackend(GetAdapter())->GetBackend()->GetFunctions();
     }
diff --git a/src/dawn_native/d3d12/DeviceD3D12.h b/src/dawn_native/d3d12/DeviceD3D12.h
index 732e187..c35df07 100644
--- a/src/dawn_native/d3d12/DeviceD3D12.h
+++ b/src/dawn_native/d3d12/DeviceD3D12.h
@@ -74,6 +74,7 @@
         ComPtr<IDXGIFactory4> GetFactory() const;
         ResultOrError<IDxcLibrary*> GetOrCreateDxcLibrary() const;
         ResultOrError<IDxcCompiler*> GetOrCreateDxcCompiler() const;
+        ResultOrError<IDxcValidator*> GetOrCreateDxcValidator() const;
 
         ResultOrError<CommandRecordingContext*> GetPendingCommandContext();
 
diff --git a/src/dawn_native/d3d12/ShaderModuleD3D12.cpp b/src/dawn_native/d3d12/ShaderModuleD3D12.cpp
index 96bb4ba..b117e3f 100644
--- a/src/dawn_native/d3d12/ShaderModuleD3D12.cpp
+++ b/src/dawn_native/d3d12/ShaderModuleD3D12.cpp
@@ -319,9 +319,12 @@
         // layout. The pipeline layout is only required if we key from WGSL: two different pipeline
         // layouts could be used to produce different shader blobs and the wrong shader blob could
         // be loaded since the pipeline layout was missing from the key.
+        // The compiler flags or version used could also produce different HLSL source. HLSL key
+        // needs both to ensure the shader cache key is unique to the HLSL source.
         // TODO(dawn:549): Consider keying from WGSL and serialize the pipeline layout it used.
-        const PersistentCacheKey& shaderCacheKey =
-            CreateHLSLKey(entryPointName, stage, hlslSource, compileFlags);
+        PersistentCacheKey shaderCacheKey;
+        DAWN_TRY_ASSIGN(shaderCacheKey,
+                        CreateHLSLKey(entryPointName, stage, hlslSource, compileFlags));
 
         CompiledShader compiledShader = {};
         DAWN_TRY_ASSIGN(compiledShader.cachedShader,
@@ -357,10 +360,10 @@
         return {};
     }
 
-    PersistentCacheKey ShaderModule::CreateHLSLKey(const char* entryPointName,
-                                                   SingleShaderStage stage,
-                                                   const std::string& hlslSource,
-                                                   uint32_t compileFlags) const {
+    ResultOrError<PersistentCacheKey> ShaderModule::CreateHLSLKey(const char* entryPointName,
+                                                                  SingleShaderStage stage,
+                                                                  const std::string& hlslSource,
+                                                                  uint32_t compileFlags) const {
         std::stringstream stream;
 
         // Prefix the key with the type to avoid collisions from another type that could have the
@@ -383,7 +386,15 @@
 
         stream << compileFlags;
 
-        // TODO(dawn:549): add the HLSL compiler version for good measure.
+        // Add the HLSL compiler version for good measure.
+        // Prepend the compiler name to ensure the version is always unique.
+        if (GetDevice()->IsToggleEnabled(Toggle::UseDXC)) {
+            uint64_t dxCompilerVersion;
+            DAWN_TRY_ASSIGN(dxCompilerVersion, GetDXCompilerVersion());
+            stream << "DXC" << dxCompilerVersion;
+        } else {
+            stream << "FXC" << GetD3DCompilerVersion();
+        }
 
         // If the source contains multiple entry points, ensure they are cached seperately
         // per stage since DX shader code can only be compiled per stage using the same
@@ -394,4 +405,24 @@
         return PersistentCacheKey(std::istreambuf_iterator<char>{stream},
                                   std::istreambuf_iterator<char>{});
     }
+
+    ResultOrError<uint64_t> ShaderModule::GetDXCompilerVersion() const {
+        ComPtr<IDxcValidator> dxcValidator;
+        DAWN_TRY_ASSIGN(dxcValidator, ToBackend(GetDevice())->GetOrCreateDxcValidator());
+
+        ComPtr<IDxcVersionInfo> versionInfo;
+        DAWN_TRY(CheckHRESULT(dxcValidator.As(&versionInfo),
+                              "D3D12 QueryInterface IDxcValidator to IDxcVersionInfo"));
+
+        uint32_t compilerMajor, compilerMinor;
+        DAWN_TRY(CheckHRESULT(versionInfo->GetVersion(&compilerMajor, &compilerMinor),
+                              "IDxcVersionInfo::GetVersion"));
+
+        // Pack both into a single version number.
+        return (uint64_t(compilerMajor) << uint64_t(32)) + compilerMinor;
+    }
+
+    uint64_t ShaderModule::GetD3DCompilerVersion() const {
+        return D3D_COMPILER_VERSION;
+    }
 }}  // namespace dawn_native::d3d12
diff --git a/src/dawn_native/d3d12/ShaderModuleD3D12.h b/src/dawn_native/d3d12/ShaderModuleD3D12.h
index f5a94f0..1f04759 100644
--- a/src/dawn_native/d3d12/ShaderModuleD3D12.h
+++ b/src/dawn_native/d3d12/ShaderModuleD3D12.h
@@ -59,10 +59,13 @@
                                                                  SingleShaderStage stage,
                                                                  PipelineLayout* layout) const;
 
-        PersistentCacheKey CreateHLSLKey(const char* entryPointName,
-                                         SingleShaderStage stage,
-                                         const std::string& hlslSource,
-                                         uint32_t compileFlags) const;
+        ResultOrError<PersistentCacheKey> CreateHLSLKey(const char* entryPointName,
+                                                        SingleShaderStage stage,
+                                                        const std::string& hlslSource,
+                                                        uint32_t compileFlags) const;
+
+        ResultOrError<uint64_t> GetDXCompilerVersion() const;
+        uint64_t GetD3DCompilerVersion() const;
 
 #ifdef DAWN_ENABLE_WGSL
         std::unique_ptr<tint::ast::Module> mTintModule;