D3D12: Support Root Signature 1.1 behind a toggle

This patch adds the support of creating D3D12 Root Signature Version
1.1 behind a toggle, which is enabled by default when the current
driver supports D3D12 Root Signature Version 1.1. With D3D12 Root
Signature Version 1.1, we can set proper flags on the items in the
root signatures to make additional guarantees about the descriptors
in a descriptor heap and the data pointed to by the descriptors so
that the drivers can make better optimizations on them.

Bug: tint:1890
Test: dawn_end2end_tests
Change-Id: I54009945676d2efe0c5c2409d0ba96a130f723e9
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/133967
Reviewed-by: Austin Eng <enga@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Rafael Cintron <rafael.cintron@microsoft.com>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
diff --git a/src/dawn/native/Toggles.cpp b/src/dawn/native/Toggles.cpp
index 0d0709c..d1cea8f 100644
--- a/src/dawn/native/Toggles.cpp
+++ b/src/dawn/native/Toggles.cpp
@@ -422,6 +422,12 @@
       "Clears some R8-like textures to full 0 bits as soon as they are created. This Toggle is "
       "enabled on Intel Gen12 GPUs due to a mesa driver issue.",
       "https://crbug.com/chromium/1361662", ToggleStage::Device}},
+    {Toggle::D3D12UseRootSignatureVersion1_1,
+     {"d3d12_use_root_signature_version_1_1",
+      "Use D3D12 Root Signature Version 1.1 to make additional guarantees about the descriptors in "
+      "a descriptor heap and the data pointed to by the descriptors so that the drivers can make "
+      "better optimizations on them.",
+      "https://crbug.com/tint/1890", 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 b0bb95d..9596e51 100644
--- a/src/dawn/native/Toggles.h
+++ b/src/dawn/native/Toggles.h
@@ -99,6 +99,7 @@
     D3D12ReplaceAddWithMinusWhenDstFactorIsZeroAndSrcFactorIsDstAlpha,
     D3D12PolyfillReflectVec2F32,
     VulkanClearGen12TextureWithCCSAmbiguateOnCreation,
+    D3D12UseRootSignatureVersion1_1,
 
     // Unresolved issues.
     NoWorkaroundSampleMaskBecomesZeroForAllButLastColorTarget,
diff --git a/src/dawn/native/d3d12/BindGroupLayoutD3D12.cpp b/src/dawn/native/d3d12/BindGroupLayoutD3D12.cpp
index 9e5abad..97f094a 100644
--- a/src/dawn/native/d3d12/BindGroupLayoutD3D12.cpp
+++ b/src/dawn/native/d3d12/BindGroupLayoutD3D12.cpp
@@ -92,14 +92,49 @@
                 ? mSamplerDescriptorCount++
                 : mCbvUavSrvDescriptorCount++;
 
-        D3D12_DESCRIPTOR_RANGE range;
+        D3D12_DESCRIPTOR_RANGE1 range;
         range.RangeType = descriptorRangeType;
         range.NumDescriptors = 1;
         range.BaseShaderRegister = GetShaderRegister(bindingIndex);
         range.RegisterSpace = kRegisterSpacePlaceholder;
         range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
 
-        std::vector<D3D12_DESCRIPTOR_RANGE>& descriptorRanges =
+        // In Dawn we always use the descriptors as static ones, which means the descriptors in a
+        // descriptor heap pointed to by a root descriptor table have been initialized by the time
+        // the descriptor table is set on a command list (during recording), and the descriptors
+        // cannot be changed until the command list has finished executing for the last time, so we
+        // don't need to set DESCRIPTORS_VOLATILE for any binding types.
+        switch (bindingInfo.bindingType) {
+            // Sampler descriptor ranges don't support DATA_* flags at all since samplers do not
+            // point to data.
+            case BindingInfoType::Sampler:
+                range.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE;
+                break;
+
+            // In Dawn it's allowed to do state transitions on the buffers or textures after binding
+            // them on the current command list, which indicates a change to its data (or possibly
+            // resource metadata), so we cannot bind them as DATA_STATIC.
+            // We cannot bind them as DATA_STATIC_WHILE_SET_AT_EXECUTE either because it is required
+            // to be rebound to the command list before the next (this) Draw/Dispatch call, while
+            // currently we may not rebind these resources if the current bind group is not changed.
+            case BindingInfoType::Buffer:
+                range.Flags =
+                    D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS |
+                    D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
+                break;
+            case BindingInfoType::Texture:
+            case BindingInfoType::StorageTexture:
+                range.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DATA_VOLATILE;
+                break;
+
+            // ExternalTexture bindings are decayed in the frontend and backends shouldn't need to
+            // handle them.
+            case BindingInfoType::ExternalTexture:
+            default:
+                UNREACHABLE();
+                break;
+        }
+        std::vector<D3D12_DESCRIPTOR_RANGE1>& descriptorRanges =
             descriptorRangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER ? mSamplerDescriptorRanges
                                                                        : mCbvUavSrvDescriptorRanges;
 
@@ -107,7 +142,7 @@
         // of the previous. This is possible because the binding infos in the base type are
         // sorted.
         if (descriptorRanges.size() >= 2) {
-            D3D12_DESCRIPTOR_RANGE& previous = descriptorRanges.back();
+            D3D12_DESCRIPTOR_RANGE1& previous = descriptorRanges.back();
             if (previous.RangeType == range.RangeType &&
                 previous.BaseShaderRegister + previous.NumDescriptors == range.BaseShaderRegister) {
                 previous.NumDescriptors += range.NumDescriptors;
@@ -170,11 +205,11 @@
     return mSamplerDescriptorCount;
 }
 
-const std::vector<D3D12_DESCRIPTOR_RANGE>& BindGroupLayout::GetCbvUavSrvDescriptorRanges() const {
+const std::vector<D3D12_DESCRIPTOR_RANGE1>& BindGroupLayout::GetCbvUavSrvDescriptorRanges() const {
     return mCbvUavSrvDescriptorRanges;
 }
 
-const std::vector<D3D12_DESCRIPTOR_RANGE>& BindGroupLayout::GetSamplerDescriptorRanges() const {
+const std::vector<D3D12_DESCRIPTOR_RANGE1>& BindGroupLayout::GetSamplerDescriptorRanges() const {
     return mSamplerDescriptorRanges;
 }
 
diff --git a/src/dawn/native/d3d12/BindGroupLayoutD3D12.h b/src/dawn/native/d3d12/BindGroupLayoutD3D12.h
index f045492..288597f 100644
--- a/src/dawn/native/d3d12/BindGroupLayoutD3D12.h
+++ b/src/dawn/native/d3d12/BindGroupLayoutD3D12.h
@@ -59,8 +59,8 @@
     uint32_t GetCbvUavSrvDescriptorCount() const;
     uint32_t GetSamplerDescriptorCount() const;
 
-    const std::vector<D3D12_DESCRIPTOR_RANGE>& GetCbvUavSrvDescriptorRanges() const;
-    const std::vector<D3D12_DESCRIPTOR_RANGE>& GetSamplerDescriptorRanges() const;
+    const std::vector<D3D12_DESCRIPTOR_RANGE1>& GetCbvUavSrvDescriptorRanges() const;
+    const std::vector<D3D12_DESCRIPTOR_RANGE1>& GetSamplerDescriptorRanges() const;
 
   private:
     BindGroupLayout(Device* device,
@@ -82,8 +82,8 @@
     uint32_t mCbvUavSrvDescriptorCount;
     uint32_t mSamplerDescriptorCount;
 
-    std::vector<D3D12_DESCRIPTOR_RANGE> mCbvUavSrvDescriptorRanges;
-    std::vector<D3D12_DESCRIPTOR_RANGE> mSamplerDescriptorRanges;
+    std::vector<D3D12_DESCRIPTOR_RANGE1> mCbvUavSrvDescriptorRanges;
+    std::vector<D3D12_DESCRIPTOR_RANGE1> mSamplerDescriptorRanges;
 
     SlabAllocator<BindGroup> mBindGroupAllocator;
 
diff --git a/src/dawn/native/d3d12/D3D12Info.cpp b/src/dawn/native/d3d12/D3D12Info.cpp
index b9811b1..203f2ab 100644
--- a/src/dawn/native/d3d12/D3D12Info.cpp
+++ b/src/dawn/native/d3d12/D3D12Info.cpp
@@ -86,6 +86,16 @@
         }
     }
 
+    info.supportsRootSignatureVersion1_1 = false;
+    D3D12_FEATURE_DATA_ROOT_SIGNATURE featureDataRootSignature = {};
+    featureDataRootSignature.HighestVersion = D3D_ROOT_SIGNATURE_VERSION_1_1;
+    if (SUCCEEDED(physicalDevice.GetDevice()->CheckFeatureSupport(
+            D3D12_FEATURE_ROOT_SIGNATURE, &featureDataRootSignature,
+            sizeof(featureDataRootSignature)))) {
+        info.supportsRootSignatureVersion1_1 =
+            featureDataRootSignature.HighestVersion >= D3D_ROOT_SIGNATURE_VERSION_1_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}};
diff --git a/src/dawn/native/d3d12/D3D12Info.h b/src/dawn/native/d3d12/D3D12Info.h
index 8c0a047..048bf77 100644
--- a/src/dawn/native/d3d12/D3D12Info.h
+++ b/src/dawn/native/d3d12/D3D12Info.h
@@ -36,6 +36,7 @@
     bool supportsDP4a;
     bool supportsCastingFullyTypedFormat;
     uint32_t programmableSamplePositionsTier;
+    bool supportsRootSignatureVersion1_1;
 };
 
 ResultOrError<D3D12DeviceInfo> GatherDeviceInfo(const PhysicalDevice& physicalDevice);
diff --git a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
index 0b9c14c..e843434 100644
--- a/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
+++ b/src/dawn/native/d3d12/PhysicalDeviceD3D12.cpp
@@ -479,6 +479,10 @@
     // By default use the maximum shader-visible heap size allowed.
     deviceToggles->Default(Toggle::UseD3D12SmallShaderVisibleHeapForTesting, false);
 
+    // By default use D3D12 Root Signature Version 1.1 when possible
+    deviceToggles->Default(Toggle::D3D12UseRootSignatureVersion1_1,
+                           GetDeviceInfo().supportsRootSignatureVersion1_1);
+
     uint32_t deviceId = GetDeviceId();
     uint32_t vendorId = GetVendorId();
 
diff --git a/src/dawn/native/d3d12/PipelineLayoutD3D12.cpp b/src/dawn/native/d3d12/PipelineLayoutD3D12.cpp
index 1b972f9..82912e7 100644
--- a/src/dawn/native/d3d12/PipelineLayoutD3D12.cpp
+++ b/src/dawn/native/d3d12/PipelineLayoutD3D12.cpp
@@ -71,6 +71,74 @@
     }
 }
 
+HRESULT SerializeRootParameter1_0(Device* device,
+                                  const D3D12_VERSIONED_ROOT_SIGNATURE_DESC& rootSignature1_1,
+                                  ID3DBlob** ppBlob,
+                                  ID3DBlob** ppErrorBlob) {
+    std::vector<std::vector<D3D12_DESCRIPTOR_RANGE>> allDescriptorRanges1_0;
+    std::vector<D3D12_ROOT_PARAMETER> rootParameters1_0(rootSignature1_1.Desc_1_1.NumParameters);
+    for (size_t i = 0; i < rootParameters1_0.size(); ++i) {
+        const D3D12_ROOT_PARAMETER1& rootParameter1_1 = rootSignature1_1.Desc_1_1.pParameters[i];
+
+        rootParameters1_0[i].ParameterType = rootParameter1_1.ParameterType;
+        rootParameters1_0[i].ShaderVisibility = rootParameter1_1.ShaderVisibility;
+
+        switch (rootParameters1_0[i].ParameterType) {
+            case D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS:
+                rootParameters1_0[i].Constants = rootParameter1_1.Constants;
+                break;
+
+            case D3D12_ROOT_PARAMETER_TYPE_CBV:
+            case D3D12_ROOT_PARAMETER_TYPE_SRV:
+            case D3D12_ROOT_PARAMETER_TYPE_UAV:
+                rootParameters1_0[i].Descriptor.RegisterSpace =
+                    rootParameter1_1.Descriptor.RegisterSpace;
+                rootParameters1_0[i].Descriptor.ShaderRegister =
+                    rootParameter1_1.Descriptor.ShaderRegister;
+                break;
+
+            case D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE:
+                rootParameters1_0[i].DescriptorTable.NumDescriptorRanges =
+                    rootParameter1_1.DescriptorTable.NumDescriptorRanges;
+                if (rootParameters1_0[i].DescriptorTable.NumDescriptorRanges > 0) {
+                    std::vector<D3D12_DESCRIPTOR_RANGE> descriptorRanges1_0(
+                        rootParameters1_0[i].DescriptorTable.NumDescriptorRanges);
+                    for (uint32_t index = 0;
+                         index < rootParameter1_1.DescriptorTable.NumDescriptorRanges; ++index) {
+                        const D3D12_DESCRIPTOR_RANGE1& descriptorRange1_1 =
+                            rootParameter1_1.DescriptorTable.pDescriptorRanges[index];
+                        descriptorRanges1_0[index].BaseShaderRegister =
+                            descriptorRange1_1.BaseShaderRegister;
+                        descriptorRanges1_0[index].NumDescriptors =
+                            descriptorRange1_1.NumDescriptors;
+                        descriptorRanges1_0[index].OffsetInDescriptorsFromTableStart =
+                            descriptorRange1_1.OffsetInDescriptorsFromTableStart;
+                        descriptorRanges1_0[index].RangeType = descriptorRange1_1.RangeType;
+                        descriptorRanges1_0[index].RegisterSpace = descriptorRange1_1.RegisterSpace;
+                    }
+                    allDescriptorRanges1_0.push_back(descriptorRanges1_0);
+                    rootParameters1_0[i].DescriptorTable.pDescriptorRanges =
+                        allDescriptorRanges1_0.back().data();
+                }
+                break;
+
+            default:
+                UNREACHABLE();
+                break;
+        }
+    }
+
+    D3D12_ROOT_SIGNATURE_DESC rootSignatureDescriptor;
+    rootSignatureDescriptor.NumParameters = rootParameters1_0.size();
+    rootSignatureDescriptor.pParameters = rootParameters1_0.data();
+    rootSignatureDescriptor.NumStaticSamplers = 0;
+    rootSignatureDescriptor.pStaticSamplers = nullptr;
+    rootSignatureDescriptor.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+
+    return device->GetFunctions()->d3d12SerializeRootSignature(
+        &rootSignatureDescriptor, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob);
+}
+
 }  // anonymous namespace
 
 ResultOrError<Ref<PipelineLayout>> PipelineLayout::Create(
@@ -85,7 +153,7 @@
     Device* device = ToBackend(GetDevice());
     // Parameters are D3D12_ROOT_PARAMETER_TYPE which is either a root table, constant, or
     // descriptor.
-    std::vector<D3D12_ROOT_PARAMETER> rootParameters;
+    std::vector<D3D12_ROOT_PARAMETER1> rootParameters;
 
     size_t rangesCount = 0;
     for (BindGroupIndex group : IterateBitSet(GetBindGroupLayoutsMask())) {
@@ -95,7 +163,7 @@
     }
 
     // We are taking pointers to `ranges`, so we cannot let it resize while we're pushing to it.
-    std::vector<D3D12_DESCRIPTOR_RANGE> ranges(rangesCount);
+    std::vector<D3D12_DESCRIPTOR_RANGE1> ranges(rangesCount);
 
     uint32_t rangeIndex = 0;
 
@@ -106,13 +174,13 @@
         // bind group index Returns whether or not the parameter was set. A root parameter is
         // not set if the number of ranges is 0
         auto SetRootDescriptorTable =
-            [&](const std::vector<D3D12_DESCRIPTOR_RANGE>& descriptorRanges) -> bool {
+            [&](const std::vector<D3D12_DESCRIPTOR_RANGE1>& descriptorRanges) -> bool {
             auto rangeCount = descriptorRanges.size();
             if (rangeCount == 0) {
                 return false;
             }
 
-            D3D12_ROOT_PARAMETER rootParameter = {};
+            D3D12_ROOT_PARAMETER1 rootParameter = {};
             rootParameter.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
             rootParameter.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
             rootParameter.DescriptorTable.NumDescriptorRanges = rangeCount;
@@ -151,12 +219,17 @@
                 continue;
             }
 
-            D3D12_ROOT_PARAMETER rootParameter = {};
+            D3D12_ROOT_PARAMETER1 rootParameter = {};
 
             // Setup root descriptor.
-            D3D12_ROOT_DESCRIPTOR rootDescriptor;
+            D3D12_ROOT_DESCRIPTOR1 rootDescriptor;
             rootDescriptor.ShaderRegister = bindGroupLayout->GetShaderRegister(dynamicBindingIndex);
             rootDescriptor.RegisterSpace = static_cast<uint32_t>(group);
+            // Using D3D12_ROOT_DESCRIPTOR_FLAG_NONE means using DATA_STATIC_WHILE_SET_AT_EXECUTE
+            // for CBV/SRV and using DATA_VOLATILE for UAV, which is allowed because currently in
+            // Dawn the views with dynamic offsets are always re-applied every time before a draw or
+            // a dispatch call.
+            rootDescriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE;
 
             // Set root descriptors in root signatures.
             rootParameter.Descriptor = rootDescriptor;
@@ -176,7 +249,7 @@
     // |ranges| will have resized and the pointers in the |rootParameter|s will be invalid.
     ASSERT(rangeIndex == rangesCount);
 
-    D3D12_ROOT_PARAMETER renderOrComputeInternalConstants{};
+    D3D12_ROOT_PARAMETER1 renderOrComputeInternalConstants{};
     renderOrComputeInternalConstants.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
     renderOrComputeInternalConstants.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
     // Always allocate 3 constants for either:
@@ -227,7 +300,7 @@
     }
 
     if (dynamicStorageBufferLengthsShaderRegisterOffset > 0) {
-        D3D12_ROOT_PARAMETER dynamicStorageBufferLengthConstants{};
+        D3D12_ROOT_PARAMETER1 dynamicStorageBufferLengthConstants{};
         dynamicStorageBufferLengthConstants.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
         dynamicStorageBufferLengthConstants.ParameterType =
             D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
@@ -244,16 +317,24 @@
             kInvalidDynamicStorageBufferLengthsParameterIndex;
     }
 
-    D3D12_ROOT_SIGNATURE_DESC rootSignatureDescriptor;
-    rootSignatureDescriptor.NumParameters = rootParameters.size();
-    rootSignatureDescriptor.pParameters = rootParameters.data();
-    rootSignatureDescriptor.NumStaticSamplers = 0;
-    rootSignatureDescriptor.pStaticSamplers = nullptr;
-    rootSignatureDescriptor.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
+    D3D12_VERSIONED_ROOT_SIGNATURE_DESC versionedRootSignatureDescriptor = {};
+    versionedRootSignatureDescriptor.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
+    versionedRootSignatureDescriptor.Desc_1_1.NumParameters = rootParameters.size();
+    versionedRootSignatureDescriptor.Desc_1_1.pParameters = rootParameters.data();
+    versionedRootSignatureDescriptor.Desc_1_1.NumStaticSamplers = 0;
+    versionedRootSignatureDescriptor.Desc_1_1.pStaticSamplers = nullptr;
+    versionedRootSignatureDescriptor.Desc_1_1.Flags =
+        D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
 
     ComPtr<ID3DBlob> error;
-    HRESULT hr = device->GetFunctions()->d3d12SerializeRootSignature(
-        &rootSignatureDescriptor, D3D_ROOT_SIGNATURE_VERSION_1, &mRootSignatureBlob, &error);
+    HRESULT hr;
+    if (device->IsToggleEnabled(Toggle::D3D12UseRootSignatureVersion1_1)) {
+        hr = device->GetFunctions()->d3d12SerializeVersionedRootSignature(
+            &versionedRootSignatureDescriptor, &mRootSignatureBlob, &error);
+    } else {
+        hr = SerializeRootParameter1_0(device, versionedRootSignatureDescriptor,
+                                       &mRootSignatureBlob, &error);
+    }
     if (DAWN_UNLIKELY(FAILED(hr))) {
         std::ostringstream messageStream;
         if (error) {
diff --git a/src/dawn/tests/end2end/BindGroupTests.cpp b/src/dawn/tests/end2end/BindGroupTests.cpp
index 1b14e79..401154f 100644
--- a/src/dawn/tests/end2end/BindGroupTests.cpp
+++ b/src/dawn/tests/end2end/BindGroupTests.cpp
@@ -1596,6 +1596,7 @@
 DAWN_INSTANTIATE_TEST(BindGroupTests,
                       D3D11Backend(),
                       D3D12Backend(),
+                      D3D12Backend({}, {"d3d12_use_root_signature_version_1_1"}),
                       MetalBackend(),
                       OpenGLBackend(),
                       OpenGLESBackend(),
diff --git a/src/dawn/tests/end2end/DynamicBufferOffsetTests.cpp b/src/dawn/tests/end2end/DynamicBufferOffsetTests.cpp
index 63abeaf..c2415f5 100644
--- a/src/dawn/tests/end2end/DynamicBufferOffsetTests.cpp
+++ b/src/dawn/tests/end2end/DynamicBufferOffsetTests.cpp
@@ -673,6 +673,7 @@
 DAWN_INSTANTIATE_TEST(DynamicBufferOffsetTests,
                       D3D11Backend(),
                       D3D12Backend(),
+                      D3D12Backend({}, {"d3d12_use_root_signature_version_1_1"}),
                       MetalBackend(),
                       OpenGLBackend(),
                       OpenGLESBackend(),
@@ -681,7 +682,8 @@
 // Only instantiate on D3D12 / Metal where we are sure of the robustness implementation.
 // Tint injects clamping in the shader. OpenGL(ES) / Vulkan robustness is less constrained.
 DAWN_INSTANTIATE_TEST_P(ClampedOOBDynamicBufferOffsetTests,
-                        {D3D12Backend(), MetalBackend()},
+                        {D3D12Backend(), D3D12Backend({}, {"d3d12_use_root_signature_version_1_1"}),
+                         MetalBackend()},
                         {wgpu::BufferUsage::Uniform, wgpu::BufferUsage::Storage},
                         {false, true},
                         {false, true});
diff --git a/src/dawn/tests/end2end/ExternalTextureTests.cpp b/src/dawn/tests/end2end/ExternalTextureTests.cpp
index d32bace..b01355f 100644
--- a/src/dawn/tests/end2end/ExternalTextureTests.cpp
+++ b/src/dawn/tests/end2end/ExternalTextureTests.cpp
@@ -998,6 +998,7 @@
 DAWN_INSTANTIATE_TEST(ExternalTextureTests,
                       D3D11Backend(),
                       D3D12Backend(),
+                      D3D12Backend({}, {"d3d12_use_root_signature_version_1_1"}),
                       MetalBackend(),
                       OpenGLBackend(),
                       OpenGLESBackend(),
diff --git a/src/dawn/tests/end2end/PipelineLayoutTests.cpp b/src/dawn/tests/end2end/PipelineLayoutTests.cpp
index b75e506..f4c8440 100644
--- a/src/dawn/tests/end2end/PipelineLayoutTests.cpp
+++ b/src/dawn/tests/end2end/PipelineLayoutTests.cpp
@@ -149,6 +149,7 @@
 DAWN_INSTANTIATE_TEST(PipelineLayoutTests,
                       D3D11Backend(),
                       D3D12Backend(),
+                      D3D12Backend({}, {"d3d12_use_root_signature_version_1_1"}),
                       MetalBackend(),
                       OpenGLBackend(),
                       OpenGLESBackend(),