d3d11: Enable TextureZeroInitTests

To skip lazy clears if content is alrealy intialized, this checks the
subresource's state of being intialized layer by layer and level by
level before actually clearing it.

Bug: dawn:1705

Change-Id: I572471c96669668a185d7ac59bc1ba8973184447
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/138560
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Jie A Chen <jie.a.chen@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/dawn/native/d3d11/TextureD3D11.cpp b/src/dawn/native/d3d11/TextureD3D11.cpp
index ffcacc9..2fad2fe 100644
--- a/src/dawn/native/d3d11/TextureD3D11.cpp
+++ b/src/dawn/native/d3d11/TextureD3D11.cpp
@@ -400,46 +400,53 @@
             desc.dimension = wgpu::TextureViewDimension::e3D;
             break;
     }
+    // Whether content is initialized is tracked by frontend in unit of a single layer and level, so
+    // we need to check to clear layer by layer, and level by level to make sure that lazy clears
+    // won't overwrite any initialized content.
     desc.baseMipLevel = range.baseMipLevel;
     desc.mipLevelCount = range.levelCount;
-    desc.baseArrayLayer = range.baseArrayLayer;
-    desc.arrayLayerCount = range.layerCount;
+    desc.arrayLayerCount = 1u;
     desc.aspect = wgpu::TextureAspect::All;
 
-    Ref<TextureView> view = TextureView::Create(this, &desc);
+    UINT clearFlags = 0;
+    if (GetFormat().HasDepth() && range.aspects & Aspect::Depth) {
+        clearFlags |= D3D11_CLEAR_DEPTH;
+    }
+    if (GetFormat().HasStencil() && range.aspects & Aspect::Stencil) {
+        clearFlags |= D3D11_CLEAR_STENCIL;
+    }
 
-    if (GetFormat().HasDepthOrStencil()) {
-        for (uint32_t mipLevel = view->GetBaseMipLevel();
-             mipLevel < view->GetBaseMipLevel() + view->GetLevelCount(); ++mipLevel) {
-            ComPtr<ID3D11DepthStencilView> d3d11DSV;
-            DAWN_TRY_ASSIGN(d3d11DSV,
-                            view->CreateD3D11DepthStencilView(/*depthReadOnly=*/false,
-                                                              /*stencilReadOnly=*/false, mipLevel));
-            UINT clearFlags = 0;
-            if (GetFormat().HasDepth() && range.aspects & Aspect::Depth) {
-                clearFlags |= D3D11_CLEAR_DEPTH;
+    for (uint32_t arrayLayer = range.baseArrayLayer;
+         arrayLayer < range.baseArrayLayer + range.layerCount; ++arrayLayer) {
+        desc.baseArrayLayer = arrayLayer;
+        Ref<TextureView> view = TextureView::Create(this, &desc);
+        for (uint32_t mipLevel = range.baseMipLevel;
+             mipLevel < range.baseMipLevel + range.levelCount; ++mipLevel) {
+            if (clearValue == TextureBase::ClearValue::Zero &&
+                IsSubresourceContentInitialized(
+                    SubresourceRange::SingleMipAndLayer(mipLevel, arrayLayer, range.aspects))) {
+                // Skip lazy clears if already initialized.
+                continue;
             }
-            if (GetFormat().HasStencil() && range.aspects & Aspect::Stencil) {
-                clearFlags |= D3D11_CLEAR_STENCIL;
-            }
-            // Clear all layers for each 'mipLevel'.
-            d3d11DeviceContext->ClearDepthStencilView(
-                d3d11DSV.Get(), clearFlags,
-                clearValue == TextureBase::ClearValue::Zero ? 0.0f : 1.0f,
-                clearValue == TextureBase::ClearValue::Zero ? 0u : 1u);
-        }
-    } else {
-        static constexpr std::array<float, 4> kZero = {0.0f, 0.0f, 0.0f, 0.0f};
-        static constexpr std::array<float, 4> kNonZero = {1.0f, 1.0f, 1.0f, 1.0f};
+            if (GetFormat().HasDepthOrStencil()) {
+                ComPtr<ID3D11DepthStencilView> d3d11DSV;
+                DAWN_TRY_ASSIGN(d3d11DSV, view->CreateD3D11DepthStencilView(
+                                              /*depthReadOnly=*/false,
+                                              /*stencilReadOnly=*/false, mipLevel));
+                d3d11DeviceContext->ClearDepthStencilView(
+                    d3d11DSV.Get(), clearFlags,
+                    clearValue == TextureBase::ClearValue::Zero ? 0.0f : 1.0f,
+                    clearValue == TextureBase::ClearValue::Zero ? 0u : 1u);
+            } else {
+                static constexpr std::array<float, 4> kZero = {0.0f, 0.0f, 0.0f, 0.0f};
+                static constexpr std::array<float, 4> kNonZero = {1.0f, 1.0f, 1.0f, 1.0f};
 
-        for (uint32_t mipLevel = view->GetBaseMipLevel();
-             mipLevel < view->GetBaseMipLevel() + view->GetLevelCount(); ++mipLevel) {
-            ComPtr<ID3D11RenderTargetView> d3d11RTV;
-            DAWN_TRY_ASSIGN(d3d11RTV, view->CreateD3D11RenderTargetView(mipLevel));
-            // Clear all layers for each 'mipLevel'.
-            d3d11DeviceContext->ClearRenderTargetView(
-                d3d11RTV.Get(),
-                clearValue == TextureBase::ClearValue::Zero ? kZero.data() : kNonZero.data());
+                ComPtr<ID3D11RenderTargetView> d3d11RTV;
+                DAWN_TRY_ASSIGN(d3d11RTV, view->CreateD3D11RenderTargetView(mipLevel));
+                d3d11DeviceContext->ClearRenderTargetView(
+                    d3d11RTV.Get(),
+                    clearValue == TextureBase::ClearValue::Zero ? kZero.data() : kNonZero.data());
+            }
         }
     }
 
diff --git a/src/dawn/tests/end2end/TextureZeroInitTests.cpp b/src/dawn/tests/end2end/TextureZeroInitTests.cpp
index 6688bf8..4729ebd 100644
--- a/src/dawn/tests/end2end/TextureZeroInitTests.cpp
+++ b/src/dawn/tests/end2end/TextureZeroInitTests.cpp
@@ -794,6 +794,8 @@
 TEST_P(TextureZeroInitTest, StencilCopyThenDiscardAndReadBySampling) {
     // Copies to a single aspect are unsupported on OpenGL.
     DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
+    // TODO(dawn:1848): support depth-stencil texture write on D3D11.
+    DAWN_SUPPRESS_TEST_IF(IsD3D11());
 
     for (wgpu::TextureFormat format :
          {wgpu::TextureFormat::Stencil8, wgpu::TextureFormat::Depth24PlusStencil8}) {
@@ -825,6 +827,8 @@
 TEST_P(TextureZeroInitTest, StencilCopyThenDiscardAndReadByCopy) {
     // Copies to a single aspect are unsupported on OpenGL.
     DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
+    // TODO(dawn:1848): support depth-stencil texture write on D3D11.
+    DAWN_SUPPRESS_TEST_IF(IsD3D11());
 
     for (wgpu::TextureFormat format :
          {wgpu::TextureFormat::Stencil8, wgpu::TextureFormat::Depth24PlusStencil8}) {
@@ -858,6 +862,8 @@
 TEST_P(TextureZeroInitTest, StencilCopyThenDiscardAndCopyToTextureThenReadByCopy) {
     // Copies to a single aspect are unsupported on OpenGL.
     DAWN_SUPPRESS_TEST_IF(IsOpenGL() || IsOpenGLES());
+    // TODO(dawn:1848): support depth-stencil texture write on D3D11.
+    DAWN_SUPPRESS_TEST_IF(IsD3D11());
 
     for (wgpu::TextureFormat format :
          {wgpu::TextureFormat::Stencil8, wgpu::TextureFormat::Depth24PlusStencil8}) {
@@ -1187,6 +1193,8 @@
 TEST_P(TextureZeroInitTest, NonRenderableTextureClear) {
     // TODO(dawn:1877): Snorm copy failing ANGLE Swiftshader, need further investigation.
     DAWN_SUPPRESS_TEST_IF(IsANGLESwiftShader());
+    // TODO(dawn:1802): Support clearing non-renderable textures on D3D11.
+    DAWN_SUPPRESS_TEST_IF(IsD3D11());
 
     wgpu::TextureDescriptor descriptor =
         CreateTextureDescriptor(1, 1, wgpu::TextureUsage::CopySrc, kNonrenderableColorFormat);
@@ -1219,6 +1227,8 @@
 TEST_P(TextureZeroInitTest, NonRenderableTextureClearUnalignedSize) {
     // TODO(dawn:1877): Snorm copy failing ANGLE Swiftshader, need further investigation.
     DAWN_SUPPRESS_TEST_IF(IsANGLESwiftShader());
+    // TODO(dawn:1802): Support clearing non-renderable textures on D3D11.
+    DAWN_SUPPRESS_TEST_IF(IsD3D11());
 
     wgpu::TextureDescriptor descriptor =
         CreateTextureDescriptor(1, 1, wgpu::TextureUsage::CopySrc, kNonrenderableColorFormat);
@@ -1254,6 +1264,8 @@
 TEST_P(TextureZeroInitTest, NonRenderableTextureClearWithMultiArrayLayers) {
     // TODO(dawn:1877): Snorm copy failing ANGLE Swiftshader, need further investigation.
     DAWN_SUPPRESS_TEST_IF(IsANGLESwiftShader());
+    // TODO(dawn:1802): Support clearing non-renderable textures on D3D11.
+    DAWN_SUPPRESS_TEST_IF(IsD3D11());
 
     wgpu::TextureDescriptor descriptor =
         CreateTextureDescriptor(1, 2, wgpu::TextureUsage::CopySrc, kNonrenderableColorFormat);
@@ -1590,6 +1602,9 @@
     // TODO(dawn:1877): Snorm copy failing ANGLE Swiftshader, need further investigation.
     DAWN_SUPPRESS_TEST_IF(IsANGLESwiftShader());
 
+    // TODO(dawn:1802): Support clearing non-renderable textures on D3D11.
+    DAWN_SUPPRESS_TEST_IF(IsD3D11());
+
     wgpu::TextureDescriptor descriptor;
     descriptor.size.width = kUnalignedSize;
     descriptor.size.height = kUnalignedSize;
@@ -1877,6 +1892,7 @@
 
 DAWN_INSTANTIATE_TEST(
     TextureZeroInitTest,
+    D3D11Backend({"nonzero_clear_resources_on_creation_for_testing"}),
     D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"}),
     D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"}, {"use_d3d12_render_pass"}),
     OpenGLBackend({"nonzero_clear_resources_on_creation_for_testing"}),
@@ -2321,6 +2337,8 @@
 }
 
 DAWN_INSTANTIATE_TEST(CompressedTextureZeroInitTest,
+                      // TODO(dawn:1802): Support clearing non-renderable textures on D3D11.
+                      // D3D11Backend({"nonzero_clear_resources_on_creation_for_testing"}),
                       D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"}),
                       MetalBackend({"nonzero_clear_resources_on_creation_for_testing"}),
                       OpenGLBackend({"nonzero_clear_resources_on_creation_for_testing"}),