D3D12: Support feature chromium_experimental_dp4a

Bug: tint:1497
Test: dawn_end2end_tests
Change-Id: I57d5c06c15c0c366c7cc239426e5eee3a7237101
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/90028
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/dawn.json b/dawn.json
index 2e82ff3..4fa8cb9 100644
--- a/dawn.json
+++ b/dawn.json
@@ -1201,6 +1201,7 @@
             {"name": "depth clamping", "type": "bool", "default": "false"},
             {"name": "depth24 unorm stencil8", "type": "bool", "default": "false"},
             {"name": "depth32 float stencil8", "type": "bool", "default": "false"},
+            {"name": "chromium experimental dp4a", "type": "bool", "default": "false"},
             {"name": "invalid feature", "type": "bool", "default": "false"},
             {"name": "dawn internal usages", "type": "bool", "default": "false"},
             {"name": "dawn native", "type": "bool", "default": "false"},
@@ -1361,7 +1362,8 @@
             {"value": 1001, "name": "dawn shader float 16", "tags": ["dawn"]},
             {"value": 1002, "name": "dawn internal usages", "tags": ["dawn"]},
             {"value": 1003, "name": "dawn multi planar formats", "tags": ["dawn"]},
-            {"value": 1004, "name": "dawn native", "tags": ["dawn", "native"]}
+            {"value": 1004, "name": "dawn native", "tags": ["dawn", "native"]},
+            {"value": 1005, "name": "chromium experimental dp4a", "tags": ["dawn"]}
         ]
     },
     "filter mode": {
diff --git a/src/dawn/native/Device.cpp b/src/dawn/native/Device.cpp
index 1f11514..fe7b00a 100644
--- a/src/dawn/native/Device.cpp
+++ b/src/dawn/native/Device.cpp
@@ -182,6 +182,8 @@
     if (togglesDesc != nullptr) {
         ApplyToggleOverrides(togglesDesc);
     }
+
+    SetDefaultToggles();
     ApplyFeatures(descriptor);
 
     DawnCacheDeviceDescriptor defaultCacheDesc = {};
@@ -198,7 +200,6 @@
     }
 
     mFormatTable = BuildFormatTable(this);
-    SetDefaultToggles();
 
     SetWGSLExtensionAllowList();
 
@@ -1234,13 +1235,25 @@
 }
 
 bool DeviceBase::IsFeatureEnabled(Feature feature) const {
-    return mEnabledFeatures.IsEnabled(feature);
+    if (mEnabledFeatures.IsEnabled(feature)) {
+        // Currently we can only use DXC to compile HLSL shaders using float16, and
+        // ChromiumExperimentalDp4a is an experimental feature which can only be enabled with toggle
+        // "use_dxc".
+        if (feature == Feature::ChromiumExperimentalDp4a || feature == Feature::ShaderFloat16) {
+            return IsToggleEnabled(Toggle::UseDXC);
+        }
+        return true;
+    }
+    return false;
 }
 
 void DeviceBase::SetWGSLExtensionAllowList() {
     // Set the WGSL extensions allow list based on device's enabled features and other
     // propority. For example:
     //     mWGSLExtensionAllowList.insert("InternalExtensionForTesting");
+    if (IsFeatureEnabled(Feature::ChromiumExperimentalDp4a)) {
+        mWGSLExtensionAllowList.insert("chromium_experimental_dp4a");
+    }
 }
 
 WGSLExtensionSet DeviceBase::GetWGSLExtensionAllowList() const {
diff --git a/src/dawn/native/Device.h b/src/dawn/native/Device.h
index c6822de..6c66f6b 100644
--- a/src/dawn/native/Device.h
+++ b/src/dawn/native/Device.h
@@ -265,7 +265,11 @@
     QueueBase* APIGetQueue();
 
     bool APIGetLimits(SupportedLimits* limits) const;
+    // Note that we should not use this function to query the features which can only be enabled
+    // behind toggles (use IsFeatureEnabled() instead).
     bool APIHasFeature(wgpu::FeatureName feature) const;
+    // Note that we should not use this function to query the features which can only be enabled
+    // behind toggles (use IsFeatureEnabled() instead).
     size_t APIEnumerateFeatures(wgpu::FeatureName* features) const;
     void APIInjectError(wgpu::ErrorType type, const char* message);
     bool APITick();
diff --git a/src/dawn/native/Features.cpp b/src/dawn/native/Features.cpp
index c33b4af..e2b82ee 100644
--- a/src/dawn/native/Features.cpp
+++ b/src/dawn/native/Features.cpp
@@ -32,64 +32,69 @@
 using FeatureEnumAndInfoList =
     std::array<FeatureEnumAndInfo, static_cast<size_t>(Feature::EnumCount)>;
 
-static constexpr FeatureEnumAndInfoList kFeatureNameAndInfoList = {
-    {{Feature::TextureCompressionBC,
-      {"texture-compression-bc", "Support Block Compressed (BC) texture formats",
-       "https://bugs.chromium.org/p/dawn/issues/detail?id=42"},
-      &WGPUDeviceProperties::textureCompressionBC},
-     {Feature::TextureCompressionETC2,
-      {"texture-compression-etc2",
-       "Support Ericsson Texture Compressed (ETC2/EAC) texture "
-       "formats",
-       "https://bugs.chromium.org/p/dawn/issues/detail?id=955"},
-      &WGPUDeviceProperties::textureCompressionETC2},
-     {Feature::TextureCompressionASTC,
-      {"texture-compression-astc",
-       "Support Adaptable Scalable Texture Compressed (ASTC) "
-       "texture formats",
-       "https://bugs.chromium.org/p/dawn/issues/detail?id=955"},
-      &WGPUDeviceProperties::textureCompressionASTC},
-     {Feature::ShaderFloat16,
-      {"shader-float16",
-       "Support 16bit float arithmetic and declarations in uniform and storage buffers",
-       "https://bugs.chromium.org/p/dawn/issues/detail?id=426"},
-      &WGPUDeviceProperties::shaderFloat16},
-     {Feature::PipelineStatisticsQuery,
-      {"pipeline-statistics-query", "Support Pipeline Statistics Query",
-       "https://bugs.chromium.org/p/dawn/issues/detail?id=434"},
-      &WGPUDeviceProperties::pipelineStatisticsQuery},
-     {Feature::TimestampQuery,
-      {"timestamp-query", "Support Timestamp Query",
-       "https://bugs.chromium.org/p/dawn/issues/detail?id=434"},
-      &WGPUDeviceProperties::timestampQuery},
-     {Feature::DepthClamping,
-      {"depth-clamping", "Clamp depth to [0, 1] in NDC space instead of clipping",
-       "https://bugs.chromium.org/p/dawn/issues/detail?id=716"},
-      &WGPUDeviceProperties::depthClamping},
-     {Feature::Depth24UnormStencil8,
-      {"depth24unorm-stencil8", "Support depth24unorm-stencil8 texture format",
-       "https://bugs.chromium.org/p/dawn/issues/detail?id=690"},
-      &WGPUDeviceProperties::depth24UnormStencil8},
-     {Feature::Depth32FloatStencil8,
-      {"depth32float-stencil8", "Support depth32float-stencil8 texture format",
-       "https://bugs.chromium.org/p/dawn/issues/detail?id=690"},
-      &WGPUDeviceProperties::depth32FloatStencil8},
-     {Feature::DawnInternalUsages,
-      {"dawn-internal-usages",
-       "Add internal usages to resources to affect how the texture is allocated, but not "
-       "frontend validation. Other internal commands may access this usage.",
-       "https://dawn.googlesource.com/dawn/+/refs/heads/main/docs/dawn/features/"
-       "dawn_internal_usages.md"},
-      &WGPUDeviceProperties::dawnInternalUsages},
-     {Feature::MultiPlanarFormats,
-      {"multiplanar-formats", "Import and use multi-planar texture formats with per plane views",
-       "https://bugs.chromium.org/p/dawn/issues/detail?id=551"},
-      &WGPUDeviceProperties::multiPlanarFormats},
-     {Feature::DawnNative,
-      {"dawn-native", "WebGPU is running on top of dawn_native.",
-       "https://dawn.googlesource.com/dawn/+/refs/heads/main/docs/dawn/features/"
-       "dawn_native.md"},
-      &WGPUDeviceProperties::dawnNative}}};
+static constexpr FeatureEnumAndInfoList kFeatureNameAndInfoList = {{
+    {Feature::TextureCompressionBC,
+     {"texture-compression-bc", "Support Block Compressed (BC) texture formats",
+      "https://bugs.chromium.org/p/dawn/issues/detail?id=42"},
+     &WGPUDeviceProperties::textureCompressionBC},
+    {Feature::TextureCompressionETC2,
+     {"texture-compression-etc2",
+      "Support Ericsson Texture Compressed (ETC2/EAC) texture "
+      "formats",
+      "https://bugs.chromium.org/p/dawn/issues/detail?id=955"},
+     &WGPUDeviceProperties::textureCompressionETC2},
+    {Feature::TextureCompressionASTC,
+     {"texture-compression-astc",
+      "Support Adaptable Scalable Texture Compressed (ASTC) "
+      "texture formats",
+      "https://bugs.chromium.org/p/dawn/issues/detail?id=955"},
+     &WGPUDeviceProperties::textureCompressionASTC},
+    {Feature::ShaderFloat16,
+     {"shader-float16",
+      "Support 16bit float arithmetic and declarations in uniform and storage buffers",
+      "https://bugs.chromium.org/p/dawn/issues/detail?id=426"},
+     &WGPUDeviceProperties::shaderFloat16},
+    {Feature::PipelineStatisticsQuery,
+     {"pipeline-statistics-query", "Support Pipeline Statistics Query",
+      "https://bugs.chromium.org/p/dawn/issues/detail?id=434"},
+     &WGPUDeviceProperties::pipelineStatisticsQuery},
+    {Feature::TimestampQuery,
+     {"timestamp-query", "Support Timestamp Query",
+      "https://bugs.chromium.org/p/dawn/issues/detail?id=434"},
+     &WGPUDeviceProperties::timestampQuery},
+    {Feature::DepthClamping,
+     {"depth-clamping", "Clamp depth to [0, 1] in NDC space instead of clipping",
+      "https://bugs.chromium.org/p/dawn/issues/detail?id=716"},
+     &WGPUDeviceProperties::depthClamping},
+    {Feature::Depth24UnormStencil8,
+     {"depth24unorm-stencil8", "Support depth24unorm-stencil8 texture format",
+      "https://bugs.chromium.org/p/dawn/issues/detail?id=690"},
+     &WGPUDeviceProperties::depth24UnormStencil8},
+    {Feature::Depth32FloatStencil8,
+     {"depth32float-stencil8", "Support depth32float-stencil8 texture format",
+      "https://bugs.chromium.org/p/dawn/issues/detail?id=690"},
+     &WGPUDeviceProperties::depth32FloatStencil8},
+    {Feature::ChromiumExperimentalDp4a,
+     {"chromium-experimental-dp4a", "Support experimental DP4a instructions in WGSL",
+      "https://bugs.chromium.org/p/tint/issues/detail?id=1497"},
+     &WGPUDeviceProperties::chromiumExperimentalDp4a},
+    {Feature::DawnInternalUsages,
+     {"dawn-internal-usages",
+      "Add internal usages to resources to affect how the texture is allocated, but not "
+      "frontend validation. Other internal commands may access this usage.",
+      "https://dawn.googlesource.com/dawn/+/refs/heads/main/docs/dawn/features/"
+      "dawn_internal_usages.md"},
+     &WGPUDeviceProperties::dawnInternalUsages},
+    {Feature::MultiPlanarFormats,
+     {"multiplanar-formats", "Import and use multi-planar texture formats with per plane views",
+      "https://bugs.chromium.org/p/dawn/issues/detail?id=551"},
+     &WGPUDeviceProperties::multiPlanarFormats},
+    {Feature::DawnNative,
+     {"dawn-native", "WebGPU is running on top of dawn_native.",
+      "https://dawn.googlesource.com/dawn/+/refs/heads/main/docs/dawn/features/"
+      "dawn_native.md"},
+     &WGPUDeviceProperties::dawnNative},
+}};
 
 Feature FromAPIFeature(wgpu::FeatureName feature) {
     switch (feature) {
@@ -120,6 +125,8 @@
             return Feature::MultiPlanarFormats;
         case wgpu::FeatureName::DawnNative:
             return Feature::DawnNative;
+        case wgpu::FeatureName::ChromiumExperimentalDp4a:
+            return Feature::ChromiumExperimentalDp4a;
 
         case wgpu::FeatureName::IndirectFirstInstance:
             return Feature::InvalidEnum;
@@ -153,6 +160,8 @@
             return wgpu::FeatureName::DawnMultiPlanarFormats;
         case Feature::DawnNative:
             return wgpu::FeatureName::DawnNative;
+        case Feature::ChromiumExperimentalDp4a:
+            return wgpu::FeatureName::ChromiumExperimentalDp4a;
 
         case Feature::EnumCount:
             break;
diff --git a/src/dawn/native/Features.h b/src/dawn/native/Features.h
index c2439b2..a87eaea 100644
--- a/src/dawn/native/Features.h
+++ b/src/dawn/native/Features.h
@@ -36,6 +36,7 @@
     DepthClamping,
     Depth24UnormStencil8,
     Depth32FloatStencil8,
+    ChromiumExperimentalDp4a,
 
     // Dawn-specific
     DawnInternalUsages,
diff --git a/src/dawn/native/d3d12/AdapterD3D12.cpp b/src/dawn/native/d3d12/AdapterD3D12.cpp
index 5f48014..4ac4134 100644
--- a/src/dawn/native/d3d12/AdapterD3D12.cpp
+++ b/src/dawn/native/d3d12/AdapterD3D12.cpp
@@ -23,6 +23,7 @@
 #include "dawn/native/d3d12/D3D12Error.h"
 #include "dawn/native/d3d12/DeviceD3D12.h"
 #include "dawn/native/d3d12/PlatformFunctions.h"
+#include "dawn/native/d3d12/UtilsD3D12.h"
 
 namespace dawn::native::d3d12 {
 
@@ -137,6 +138,17 @@
     mSupportedFeatures.EnableFeature(Feature::Depth24UnormStencil8);
     mSupportedFeatures.EnableFeature(Feature::Depth32FloatStencil8);
 
+    if (GetBackend()->GetFunctions()->IsDXCAvailable()) {
+        uint64_t dxcVersion = 0;
+        DAWN_TRY_ASSIGN(dxcVersion, GetBackend()->GetDXCompilerVersion());
+        constexpr uint64_t kLeastMajorVersionForDP4a = 1;
+        constexpr uint64_t kLeastMinorVersionForDP4a = 4;
+        if (mDeviceInfo.supportsDP4a &&
+            dxcVersion >= MakeDXCVersion(kLeastMajorVersionForDP4a, kLeastMinorVersionForDP4a)) {
+            mSupportedFeatures.EnableFeature(Feature::ChromiumExperimentalDp4a);
+        }
+    }
+
     return {};
 }
 
diff --git a/src/dawn/native/d3d12/BackendD3D12.cpp b/src/dawn/native/d3d12/BackendD3D12.cpp
index 1232dbf..3d0b13f 100644
--- a/src/dawn/native/d3d12/BackendD3D12.cpp
+++ b/src/dawn/native/d3d12/BackendD3D12.cpp
@@ -21,6 +21,7 @@
 #include "dawn/native/d3d12/AdapterD3D12.h"
 #include "dawn/native/d3d12/D3D12Error.h"
 #include "dawn/native/d3d12/PlatformFunctions.h"
+#include "dawn/native/d3d12/UtilsD3D12.h"
 
 namespace dawn::native::d3d12 {
 
@@ -141,6 +142,21 @@
     return mDxcValidator;
 }
 
+ResultOrError<uint64_t> Backend::GetDXCompilerVersion() {
+    DAWN_TRY(EnsureDxcValidator());
+
+    ComPtr<IDxcVersionInfo> versionInfo;
+    DAWN_TRY(CheckHRESULT(mDxcValidator.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 MakeDXCVersion(compilerMajor, compilerMinor);
+}
+
 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 9a983f2..1bf1ead 100644
--- a/src/dawn/native/d3d12/BackendD3D12.h
+++ b/src/dawn/native/d3d12/BackendD3D12.h
@@ -40,6 +40,7 @@
     ComPtr<IDxcLibrary> GetDxcLibrary() const;
     ComPtr<IDxcCompiler> GetDxcCompiler() const;
     ComPtr<IDxcValidator> GetDxcValidator() const;
+    ResultOrError<uint64_t> GetDXCompilerVersion();
 
     const PlatformFunctions* GetFunctions() const;
 
diff --git a/src/dawn/native/d3d12/D3D12Info.cpp b/src/dawn/native/d3d12/D3D12Info.cpp
index b8fc896..6a4c435 100644
--- a/src/dawn/native/d3d12/D3D12Info.cpp
+++ b/src/dawn/native/d3d12/D3D12Info.cpp
@@ -75,10 +75,9 @@
         }
     }
 
-    D3D12_FEATURE_DATA_SHADER_MODEL knownShaderModels[] = {{D3D_SHADER_MODEL_6_2},
-                                                           {D3D_SHADER_MODEL_6_1},
-                                                           {D3D_SHADER_MODEL_6_0},
-                                                           {D3D_SHADER_MODEL_5_1}};
+    D3D12_FEATURE_DATA_SHADER_MODEL knownShaderModels[] = {
+        {D3D_SHADER_MODEL_6_4}, {D3D_SHADER_MODEL_6_3}, {D3D_SHADER_MODEL_6_2},
+        {D3D_SHADER_MODEL_6_1}, {D3D_SHADER_MODEL_6_0}, {D3D_SHADER_MODEL_5_1}};
     uint32_t driverShaderModel = 0;
     for (D3D12_FEATURE_DATA_SHADER_MODEL shaderModel : knownShaderModels) {
         if (SUCCEEDED(adapter.GetDevice()->CheckFeatureSupport(
@@ -118,6 +117,8 @@
             driverShaderModel >= D3D_SHADER_MODEL_6_2 && featureData4.Native16BitShaderOpsSupported;
     }
 
+    info.supportsDP4a = driverShaderModel >= D3D_SHADER_MODEL_6_4;
+
     return std::move(info);
 }
 
diff --git a/src/dawn/native/d3d12/D3D12Info.h b/src/dawn/native/d3d12/D3D12Info.h
index c0ffc47..e0f2a66 100644
--- a/src/dawn/native/d3d12/D3D12Info.h
+++ b/src/dawn/native/d3d12/D3D12Info.h
@@ -33,6 +33,7 @@
     uint32_t shaderModel;
     PerStage<std::wstring> shaderProfiles;
     bool supportsSharedResourceCapabilityTier1;
+    bool supportsDP4a;
 };
 
 ResultOrError<D3D12DeviceInfo> GatherDeviceInfo(const Adapter& adapter);
diff --git a/src/dawn/native/d3d12/DeviceD3D12.cpp b/src/dawn/native/d3d12/DeviceD3D12.cpp
index 96fbb3f..97f7128 100644
--- a/src/dawn/native/d3d12/DeviceD3D12.cpp
+++ b/src/dawn/native/d3d12/DeviceD3D12.cpp
@@ -217,9 +217,6 @@
 MaybeError Device::ApplyUseDxcToggle() {
     if (!ToBackend(GetAdapter())->GetBackend()->GetFunctions()->IsDXCAvailable()) {
         ForceSetToggle(Toggle::UseDXC, false);
-    } else if (IsFeatureEnabled(Feature::ShaderFloat16)) {
-        // Currently we can only use DXC to compile HLSL shaders using float16.
-        ForceSetToggle(Toggle::UseDXC, true);
     }
 
     if (IsToggleEnabled(Toggle::UseDXC)) {
diff --git a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
index 1a9592c..b9d4ef4 100644
--- a/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
+++ b/src/dawn/native/d3d12/ShaderModuleD3D12.cpp
@@ -31,6 +31,8 @@
 #include "dawn/native/CacheKey.h"
 #include "dawn/native/Pipeline.h"
 #include "dawn/native/TintUtils.h"
+#include "dawn/native/d3d12/AdapterD3D12.h"
+#include "dawn/native/d3d12/BackendD3D12.h"
 #include "dawn/native/d3d12/BindGroupLayoutD3D12.h"
 #include "dawn/native/d3d12/D3D12Error.h"
 #include "dawn/native/d3d12/DeviceD3D12.h"
@@ -45,19 +47,6 @@
 namespace dawn::native::d3d12 {
 
 namespace {
-ResultOrError<uint64_t> GetDXCompilerVersion(ComPtr<IDxcValidator> dxcValidator) {
-    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 GetD3DCompilerVersion() {
     return D3D_COMPILER_VERSION;
 }
@@ -222,7 +211,8 @@
         uint64_t dxcVersion = 0;
         if (device->IsToggleEnabled(Toggle::UseDXC)) {
             compiler = Compiler::DXC;
-            DAWN_TRY_ASSIGN(dxcVersion, GetDXCompilerVersion(device->GetDxcValidator()));
+            DAWN_TRY_ASSIGN(dxcVersion,
+                            ToBackend(device->GetAdapter())->GetBackend()->GetDXCompilerVersion());
         } else {
             compiler = Compiler::FXC;
         }
diff --git a/src/dawn/native/d3d12/UtilsD3D12.cpp b/src/dawn/native/d3d12/UtilsD3D12.cpp
index 0833e01..0e761f8 100644
--- a/src/dawn/native/d3d12/UtilsD3D12.cpp
+++ b/src/dawn/native/d3d12/UtilsD3D12.cpp
@@ -386,4 +386,8 @@
     object->SetPrivateData(WKPDID_D3DDebugObjectName, objectName.length(), objectName.c_str());
 }
 
+uint64_t MakeDXCVersion(uint64_t majorVersion, uint64_t minorVersion) {
+    return (majorVersion << 32) + minorVersion;
+}
+
 }  // namespace dawn::native::d3d12
diff --git a/src/dawn/native/d3d12/UtilsD3D12.h b/src/dawn/native/d3d12/UtilsD3D12.h
index 0bc5afb..1418f54 100644
--- a/src/dawn/native/d3d12/UtilsD3D12.h
+++ b/src/dawn/native/d3d12/UtilsD3D12.h
@@ -68,6 +68,8 @@
 
 void SetDebugName(Device* device, ID3D12Object* object, const char* prefix, std::string label = "");
 
+uint64_t MakeDXCVersion(uint64_t majorVersion, uint64_t minorVersion);
+
 }  // namespace dawn::native::d3d12
 
 #endif  // SRC_DAWN_NATIVE_D3D12_UTILSD3D12_H_
diff --git a/src/dawn/tests/BUILD.gn b/src/dawn/tests/BUILD.gn
index 9f86b59..e0dbdda 100644
--- a/src/dawn/tests/BUILD.gn
+++ b/src/dawn/tests/BUILD.gn
@@ -447,6 +447,7 @@
     "end2end/DrawTests.cpp",
     "end2end/DynamicBufferOffsetTests.cpp",
     "end2end/EntryPointTests.cpp",
+    "end2end/ExperimentalDP4aTests.cpp",
     "end2end/ExternalTextureTests.cpp",
     "end2end/FirstIndexOffsetTests.cpp",
     "end2end/GpuMemorySynchronizationTests.cpp",
diff --git a/src/dawn/tests/end2end/ExperimentalDP4aTests.cpp b/src/dawn/tests/end2end/ExperimentalDP4aTests.cpp
new file mode 100644
index 0000000..e789c07
--- /dev/null
+++ b/src/dawn/tests/end2end/ExperimentalDP4aTests.cpp
@@ -0,0 +1,106 @@
+// Copyright 2022 The Dawn Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <vector>
+
+#include "dawn/tests/DawnTest.h"
+#include "dawn/utils/WGPUHelpers.h"
+
+namespace {
+using RequestDP4aExtension = bool;
+DAWN_TEST_PARAM_STRUCT(ExperimentalDP4aTestsParams, RequestDP4aExtension);
+
+}  // anonymous namespace
+
+class ExperimentalDP4aTests : public DawnTestWithParams<ExperimentalDP4aTestsParams> {
+  protected:
+    std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
+        mIsDP4aSupportedOnAdapter = SupportsFeatures({wgpu::FeatureName::ChromiumExperimentalDp4a});
+        if (!mIsDP4aSupportedOnAdapter) {
+            return {};
+        }
+
+        if (GetParam().mRequestDP4aExtension) {
+            return {wgpu::FeatureName::ChromiumExperimentalDp4a};
+        }
+
+        return {};
+    }
+
+    bool IsDP4aSupportedOnAdapter() const { return mIsDP4aSupportedOnAdapter; }
+
+  private:
+    bool mIsDP4aSupportedOnAdapter = false;
+};
+
+TEST_P(ExperimentalDP4aTests, BasicDP4aFeaturesTest) {
+    const char* computeShader = R"(
+        enable chromium_experimental_dp4a;
+
+        struct Buf {
+            data1 : i32,
+            data2 : u32,
+            data3 : i32,
+            data4 : u32,
+        }
+        @group(0) @binding(0) var<storage, read_write> buf : Buf;
+
+        @stage(compute) @workgroup_size(1)
+        fn main() {
+            var a = 0xFFFFFFFFu;
+            var b = 0xFFFFFFFEu;
+            var c = 0x01020304u;
+            buf.data1 = dot4I8Packed(a, b);
+            buf.data2 = dot4U8Packed(a, b);
+            buf.data3 = dot4I8Packed(a, c);
+            buf.data4 = dot4U8Packed(a, c);
+        }
+)";
+    if (!GetParam().mRequestDP4aExtension || !IsDP4aSupportedOnAdapter() ||
+        !HasToggleEnabled("use_dxc")) {
+        ASSERT_DEVICE_ERROR(utils::CreateShaderModule(device, computeShader));
+        return;
+    }
+
+    wgpu::BufferDescriptor bufferDesc;
+    bufferDesc.size = 4 * sizeof(uint32_t);
+    bufferDesc.usage = wgpu::BufferUsage::Storage | wgpu::BufferUsage::CopySrc;
+    wgpu::Buffer bufferOut = device.CreateBuffer(&bufferDesc);
+
+    wgpu::ComputePipelineDescriptor csDesc;
+    csDesc.compute.module = utils::CreateShaderModule(device, computeShader);
+    csDesc.compute.entryPoint = "main";
+    wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&csDesc);
+
+    wgpu::BindGroup bindGroup = utils::MakeBindGroup(device, pipeline.GetBindGroupLayout(0),
+                                                     {
+                                                         {0, bufferOut},
+                                                     });
+
+    wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+    wgpu::ComputePassEncoder pass = encoder.BeginComputePass();
+    pass.SetPipeline(pipeline);
+    pass.SetBindGroup(0, bindGroup);
+    pass.DispatchWorkgroups(1);
+    pass.End();
+    wgpu::CommandBuffer commands = encoder.Finish();
+    queue.Submit(1, &commands);
+
+    uint32_t expected[] = {5, 259845, static_cast<uint32_t>(-10), 2550};
+    EXPECT_BUFFER_U32_RANGE_EQ(expected, bufferOut, 0, 4);
+}
+
+DAWN_INSTANTIATE_TEST_P(ExperimentalDP4aTests,
+                        {D3D12Backend(), D3D12Backend({"use_dxc"})},
+                        {true, false});
diff --git a/src/dawn/wire/SupportedFeatures.cpp b/src/dawn/wire/SupportedFeatures.cpp
index 8dd6d58..0e5688a 100644
--- a/src/dawn/wire/SupportedFeatures.cpp
+++ b/src/dawn/wire/SupportedFeatures.cpp
@@ -36,6 +36,7 @@
         case WGPUFeatureName_DawnShaderFloat16:
         case WGPUFeatureName_DawnInternalUsages:
         case WGPUFeatureName_DawnMultiPlanarFormats:
+        case WGPUFeatureName_ChromiumExperimentalDp4a:
             return true;
     }