D3D12: Disable resource suballocation on new Win11 with old Intel drivers

This patch disables resource suballocation on newer version of Windows 11
with older version of Intel drivers because of an issue in Windows 11 OS.

Bug: dawn:2308
Change-Id: Id12a246e0683664ad061aa221e997af5da3f2c02
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/171580
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/d3d/PlatformFunctions.cpp b/src/dawn/native/d3d/PlatformFunctions.cpp
index f3b836e..4815df2 100644
--- a/src/dawn/native/d3d/PlatformFunctions.cpp
+++ b/src/dawn/native/d3d/PlatformFunctions.cpp
@@ -28,11 +28,13 @@
 #include "dawn/native/d3d/PlatformFunctions.h"
 
 #include <comdef.h>
+#include <versionhelpers.h>
 
 #include <algorithm>
 #include <array>
 #include <sstream>
 #include <utility>
+#include <vector>
 
 namespace dawn::native::d3d {
 namespace {
@@ -106,15 +108,36 @@
 
     return ostream.str();
 }
+
+// Referenced from base/win/registry.cc in Chromium
+uint64_t ReadFromSZRegistryKey(HKEY registerKey, const char* registerKeyName) {
+    DWORD valueType;
+    DWORD returnSize;
+    if (RegQueryValueExA(registerKey, registerKeyName, nullptr, &valueType, nullptr, &returnSize) !=
+        ERROR_SUCCESS) {
+        return 0;
+    }
+    std::vector<char> returnStringValue(returnSize);
+    auto hr = RegQueryValueExA(registerKey, registerKeyName, nullptr, &valueType,
+                               reinterpret_cast<LPBYTE>(returnStringValue.data()), &returnSize);
+    if (hr != ERROR_SUCCESS || valueType != REG_SZ) {
+        return 0;
+    }
+    constexpr int32_t kRadix = 10;
+    return strtol(returnStringValue.data(), nullptr, kRadix);
+}
+
 }  // anonymous namespace
 
-PlatformFunctions::PlatformFunctions() = default;
+PlatformFunctions::PlatformFunctions() : mCurrentBuildNumber(0) {}
+
 PlatformFunctions::~PlatformFunctions() = default;
 
 MaybeError PlatformFunctions::LoadFunctions() {
     DAWN_TRY(LoadDXGI());
     LoadDXCLibraries();
     DAWN_TRY(LoadFXCompiler());
+    InitWindowsVersion();
     return {};
 }
 
@@ -218,6 +241,31 @@
     return {};
 }
 
+void PlatformFunctions::InitWindowsVersion() {
+    // Currently we only care about the build number of Windows 10 and Windows 11.
+    if (!IsWindows10OrGreater()) {
+        return;
+    }
+
+    // Referenced from base/win/windows_version.cc in Chromium
+    constexpr wchar_t kRegKeyWindowsNTCurrentVersion[] =
+        L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
+
+    HKEY hKey;
+    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, kRegKeyWindowsNTCurrentVersion, 0, KEY_QUERY_VALUE,
+                      &hKey) != ERROR_SUCCESS) {
+        return;
+    }
+
+    mCurrentBuildNumber = ReadFromSZRegistryKey(hKey, "CurrentBuildNumber");
+
+    RegCloseKey(hKey);
+}
+
+uint64_t PlatformFunctions::GetWindowsBuildNumber() const {
+    return mCurrentBuildNumber;
+}
+
 // Use Backend::IsDXCAvailable if possible, which also check the DXC is no older than a given
 // version
 bool PlatformFunctions::IsDXCBinaryAvailable() const {
diff --git a/src/dawn/native/d3d/PlatformFunctions.h b/src/dawn/native/d3d/PlatformFunctions.h
index 55ca52a..f966e40 100644
--- a/src/dawn/native/d3d/PlatformFunctions.h
+++ b/src/dawn/native/d3d/PlatformFunctions.h
@@ -49,6 +49,7 @@
     MaybeError LoadFunctions();
     bool IsPIXEventRuntimeLoaded() const;
     bool IsDXCBinaryAvailable() const;
+    uint64_t GetWindowsBuildNumber() const;
 
     // Functions from dxgi.dll
     using PFN_DXGI_GET_DEBUG_INTERFACE1 = HRESULT(WINAPI*)(UINT Flags,
@@ -78,11 +79,14 @@
     void LoadDXCompiler(const std::string& baseWindowsSDKPath);
     MaybeError LoadFXCompiler();
     void LoadPIXRuntime();
+    void InitWindowsVersion();
 
     DynamicLib mDXGILib;
     DynamicLib mDXILLib;
     DynamicLib mDXCompilerLib;
     DynamicLib mFXCompilerLib;
+
+    uint64_t mCurrentBuildNumber;
 };
 
 }  // namespace dawn::native::d3d
diff --git a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
index 1a43eb8..66de589 100644
--- a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
+++ b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
@@ -712,6 +712,19 @@
     if (gpu_info::IsIntel(vendorId) && !deviceToggles->IsEnabled(Toggle::UseDXC)) {
         deviceToggles->Default(Toggle::D3D12PolyfillReflectVec2F32, true);
     }
+
+    // Currently this workaround is needed on old Intel drivers and newer version of Windows 11.
+    // See http://crbug.com/dawn/2308 for more information.
+    if (gpu_info::IsIntel(vendorId)) {
+        constexpr uint64_t kAffectedMinimumWindowsBuildNumber = 25957u;
+        const gpu_info::DriverVersion kAffectedMaximumDriverVersion = {27, 20, 100, 9664};
+        if (GetBackend()->GetFunctions()->GetWindowsBuildNumber() >=
+                kAffectedMinimumWindowsBuildNumber &&
+            gpu_info::CompareWindowsDriverVersion(vendorId, GetDriverVersion(),
+                                                  kAffectedMaximumDriverVersion) <= 0) {
+            deviceToggles->Default(Toggle::DisableResourceSuballocation, true);
+        }
+    }
 }
 
 ResultOrError<Ref<DeviceBase>> PhysicalDevice::CreateDeviceImpl(