Enable D3D12 render pass and use PRESERVE usage on null RTV slots

This patch enables the use of D3D12 render pass by checking
`D3D12_FEATURE_DATA_D3D12_OPTIONS18.RenderPassesValid` and uses
`PRESERVE` usage instead of `NO_ACCESS` on null RTV slots because
using `NO_ACCESS` means the null RTV will not be bound for raster
and consume the slots, thus the non-null RTVs will be bound to
wrong slots.

Fixed: chromium:347282485
Test: dawn_end2end_tests
Change-Id: Id1adf1cd65a4a2dfa02b70cb7b18cb115400ca23
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/212254
Reviewed-by: Corentin Wallez <cwallez@google.com>
Commit-Queue: Jiawei Shao <jiawei.shao@intel.com>
Reviewed-by: Loko Kung <lokokung@google.com>
Reviewed-by: Rafael Cintron <rafael.cintron@microsoft.com>
diff --git a/src/dawn/native/d3d12/D3D12Info.cpp b/src/dawn/native/d3d12/D3D12Info.cpp
index cd818fa..558146b 100644
--- a/src/dawn/native/d3d12/D3D12Info.cpp
+++ b/src/dawn/native/d3d12/D3D12Info.cpp
@@ -92,14 +92,11 @@
         info.supportsNative16BitShaderOps = featureOptions4.Native16BitShaderOpsSupported;
     }
 
-    // Per https://microsoft.github.io/DirectX-Specs/d3d/RenderPasses.html#checking-for-support,
-    // render passes on Windows originally shipped in an incomplete form that drivers could not take
-    // advantage of. The feature has been repaired now but to detect whether you're getting the
-    // fixed version, you need to query for the D3D12_FEATURE_DATA_D3D12_OPTIONS18 structure and
-    // check the RenderPassesValid field inside. Until we upgrade Dawn to use a version of the
-    // header file with the structure, we force render passes to be disabled. See
-    // https://issues.chromium.org/issues/348202695 for additional information.
-    info.supportsRenderPass = false;
+    D3D12_FEATURE_DATA_D3D12_OPTIONS18 featureOptions18 = {};
+    if (SUCCEEDED(physicalDevice.GetDevice()->CheckFeatureSupport(
+            D3D12_FEATURE_D3D12_OPTIONS18, &featureOptions18, sizeof(featureOptions18)))) {
+        info.supportsRenderPass = featureOptions18.RenderPassesValid;
+    }
 
     // D3D12_HEAP_FLAG_CREATE_NOT_ZEROED is available anytime that ID3D12Device8 is exposed, or a
     // check for D3D12_FEATURE_D3D12_OPTIONS7 succeeds.
diff --git a/src/dawn/native/d3d12/RenderPassBuilderD3D12.cpp b/src/dawn/native/d3d12/RenderPassBuilderD3D12.cpp
index c985790..e86e8ee 100644
--- a/src/dawn/native/d3d12/RenderPassBuilderD3D12.cpp
+++ b/src/dawn/native/d3d12/RenderPassBuilderD3D12.cpp
@@ -133,11 +133,14 @@
             mHighestColorAttachmentIndexPlusOne,
             ColorAttachmentIndex{static_cast<uint8_t>(static_cast<uint8_t>(attachmentIndex) + 1u)});
     } else {
-        // Null views should not be accessed
+        // Null views must be marked as preserved so that they keep using attachment slots.
+        // Otherwise the holes in the attachments would get compacted by D3D12.
+        // See the chapter "surfaces-that-beginrenderpass-binds-for-raster" in
+        // https://microsoft.github.io/DirectX-Specs/d3d/RenderPasses.html for more information.
         mRenderPassRenderTargetDescriptors[attachmentIndex].BeginningAccess.Type =
-            D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_NO_ACCESS;
+            D3D12_RENDER_PASS_BEGINNING_ACCESS_TYPE_PRESERVE;
         mRenderPassRenderTargetDescriptors[attachmentIndex].EndingAccess.Type =
-            D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS;
+            D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_PRESERVE;
     }
 }