Use clear loadop to lazy clear depth stencil attachments

Bug: dawn:210, dawn:145
Change-Id: I1eb990266ccd7b51b4a336b0d4d37e0195c6fe69
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/11020
Commit-Queue: Natasha Lee <natlee@microsoft.com>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index a56b89a..1dcc05f 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -960,16 +960,11 @@
             if (renderPass->attachmentState->HasDepthStencilAttachment()) {
                 auto& attachmentInfo = renderPass->depthStencilAttachment;
                 Texture* texture = ToBackend(renderPass->depthStencilAttachment.view->GetTexture());
-                if ((texture->GetFormat().HasDepth() &&
-                     attachmentInfo.depthLoadOp == dawn::LoadOp::Load) ||
-                    (texture->GetFormat().HasStencil() &&
-                     attachmentInfo.stencilLoadOp == dawn::LoadOp::Load)) {
-                    texture->EnsureSubresourceContentInitialized(
-                        commandList, attachmentInfo.view->GetBaseMipLevel(),
-                        attachmentInfo.view->GetLevelCount(),
-                        attachmentInfo.view->GetBaseArrayLayer(),
-                        attachmentInfo.view->GetLayerCount());
-                }
+                TextureView* view = ToBackend(attachmentInfo.view.Get());
+                float clearDepth = attachmentInfo.clearDepth;
+                // TODO(kainino@chromium.org): investigate: should the Dawn clear
+                // stencil type be uint8_t?
+                uint8_t clearStencil = static_cast<uint8_t>(attachmentInfo.clearStencil);
 
                 // Load op - depth/stencil
                 bool doDepthClear = texture->GetFormat().HasDepth() &&
@@ -984,19 +979,35 @@
                 if (doStencilClear) {
                     clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
                 }
+                // If the depth stencil texture has not been initialized, we want to use loadop
+                // clear to init the contents to 0's
+                if (!texture->IsSubresourceContentInitialized(
+                        view->GetBaseMipLevel(), view->GetLevelCount(), view->GetBaseArrayLayer(),
+                        view->GetLayerCount())) {
+                    if (texture->GetFormat().HasDepth() &&
+                        attachmentInfo.depthLoadOp == dawn::LoadOp::Load) {
+                        clearDepth = 0.0f;
+                        clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
+                    }
+                    if (texture->GetFormat().HasStencil() &&
+                        attachmentInfo.stencilLoadOp == dawn::LoadOp::Load) {
+                        clearStencil = 0u;
+                        clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
+                    }
+                }
 
                 if (clearFlags) {
                     D3D12_CPU_DESCRIPTOR_HANDLE handle = args.dsv;
-                    // TODO(kainino@chromium.org): investigate: should the Dawn clear
-                    // stencil type be uint8_t?
-                    uint8_t clearStencil = static_cast<uint8_t>(attachmentInfo.clearStencil);
-                    commandList->ClearDepthStencilView(
-                        handle, clearFlags, attachmentInfo.clearDepth, clearStencil, 0, nullptr);
+                    commandList->ClearDepthStencilView(handle, clearFlags, clearDepth, clearStencil,
+                                                       0, nullptr);
+                }
+
+                // TODO(natlee@microsoft.com): Need to fix when storeop discard is added
+                if (attachmentInfo.depthStoreOp == dawn::StoreOp::Store &&
+                    attachmentInfo.stencilStoreOp == dawn::StoreOp::Store) {
                     texture->SetIsSubresourceContentInitialized(
-                        attachmentInfo.view->GetBaseMipLevel(),
-                        attachmentInfo.view->GetLevelCount(),
-                        attachmentInfo.view->GetBaseArrayLayer(),
-                        attachmentInfo.view->GetLayerCount());
+                        view->GetBaseMipLevel(), view->GetLevelCount(), view->GetBaseArrayLayer(),
+                        view->GetLayerCount());
                 }
             }
         }
diff --git a/src/dawn_native/opengl/CommandBufferGL.cpp b/src/dawn_native/opengl/CommandBufferGL.cpp
index 8351509..51c0624 100644
--- a/src/dawn_native/opengl/CommandBufferGL.cpp
+++ b/src/dawn_native/opengl/CommandBufferGL.cpp
@@ -391,12 +391,10 @@
         auto TransitionForPass = [](const PassResourceUsage& usages) {
             for (size_t i = 0; i < usages.textures.size(); i++) {
                 Texture* texture = ToBackend(usages.textures[i]);
-                // We count the lazy clears for non output attachment textures and depth stencil
-                // textures in order to match the backdoor lazy clear counts in Vulkan and D3D12.
+                // We count the lazy clears for non output attachment textures in order to match the
+                // backdoor lazy clear counts in Vulkan and D3D12.
                 bool isLazyClear =
-                    ((!(usages.textureUsages[i] & dawn::TextureUsage::OutputAttachment) &&
-                      texture->GetFormat().IsColor()) ||
-                     texture->GetFormat().HasDepthOrStencil());
+                    !(usages.textureUsages[i] & dawn::TextureUsage::OutputAttachment);
                 texture->EnsureSubresourceContentInitialized(
                     0, texture->GetNumMipLevels(), 0, texture->GetArrayLayers(), isLazyClear);
             }
diff --git a/src/dawn_native/vulkan/CommandBufferVk.cpp b/src/dawn_native/vulkan/CommandBufferVk.cpp
index 9ae41cf..8eaca7e 100644
--- a/src/dawn_native/vulkan/CommandBufferVk.cpp
+++ b/src/dawn_native/vulkan/CommandBufferVk.cpp
@@ -197,16 +197,33 @@
 
                 if (renderPass->attachmentState->HasDepthStencilAttachment()) {
                     auto& attachmentInfo = renderPass->depthStencilAttachment;
-                    query.SetDepthStencil(attachmentInfo.view->GetTexture()->GetFormat().format,
+                    TextureView* view = ToBackend(attachmentInfo.view.Get());
+
+                    // If the depth stencil texture has not been initialized, we want to use loadop
+                    // clear to init the contents to 0's
+                    if (!view->GetTexture()->IsSubresourceContentInitialized(
+                            view->GetBaseMipLevel(), view->GetLevelCount(),
+                            view->GetBaseArrayLayer(), view->GetLayerCount())) {
+                        if (view->GetTexture()->GetFormat().HasDepth() &&
+                            attachmentInfo.depthLoadOp == dawn::LoadOp::Load) {
+                            attachmentInfo.clearDepth = 0.0f;
+                            attachmentInfo.depthLoadOp = dawn::LoadOp::Clear;
+                        }
+                        if (view->GetTexture()->GetFormat().HasStencil() &&
+                            attachmentInfo.stencilLoadOp == dawn::LoadOp::Load) {
+                            attachmentInfo.clearStencil = 0u;
+                            attachmentInfo.stencilLoadOp = dawn::LoadOp::Clear;
+                        }
+                    }
+                    query.SetDepthStencil(view->GetTexture()->GetFormat().format,
                                           attachmentInfo.depthLoadOp, attachmentInfo.stencilLoadOp);
-                    if (attachmentInfo.depthLoadOp == dawn::LoadOp::Load ||
-                        attachmentInfo.stencilLoadOp == dawn::LoadOp::Load) {
-                        ToBackend(attachmentInfo.view->GetTexture())
-                            ->EnsureSubresourceContentInitialized(
-                                recordingContext, attachmentInfo.view->GetBaseMipLevel(),
-                                attachmentInfo.view->GetLevelCount(),
-                                attachmentInfo.view->GetBaseArrayLayer(),
-                                attachmentInfo.view->GetLayerCount());
+
+                    // TODO(natlee@microsoft.com): Need to fix when storeop discard is added
+                    if (attachmentInfo.depthStoreOp == dawn::StoreOp::Store &&
+                        attachmentInfo.stencilStoreOp == dawn::StoreOp::Store) {
+                        view->GetTexture()->SetIsSubresourceContentInitialized(
+                            view->GetBaseMipLevel(), view->GetLevelCount(),
+                            view->GetBaseArrayLayer(), view->GetLayerCount());
                     }
                 }
 
diff --git a/src/tests/end2end/TextureZeroInitTests.cpp b/src/tests/end2end/TextureZeroInitTests.cpp
index 2d244f9..3d6f3e6 100644
--- a/src/tests/end2end/TextureZeroInitTests.cpp
+++ b/src/tests/end2end/TextureZeroInitTests.cpp
@@ -321,6 +321,8 @@
     renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = dawn::LoadOp::Load;
     renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = dawn::LoadOp::Clear;
     renderPassDescriptor.cDepthStencilAttachmentInfo.clearStencil = 0;
+    renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = dawn::StoreOp::Store;
+    renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = dawn::StoreOp::Store;
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
@@ -328,8 +330,8 @@
     pass.Draw(6, 1, 0, 0);
     pass.EndPass();
     dawn::CommandBuffer commandBuffer = encoder.Finish();
-    // Expect 1 lazy clear for the depthStencilTexture
-    EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commandBuffer));
+    // Expect 0 lazy clears, depth stencil texture will clear using loadop
+    EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
 
     // Expect the texture to be red because depth test passed.
     std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
@@ -360,6 +362,8 @@
     renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = dawn::LoadOp::Clear;
     renderPassDescriptor.cDepthStencilAttachmentInfo.clearDepth = 0.0f;
     renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = dawn::LoadOp::Load;
+    renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = dawn::StoreOp::Store;
+    renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = dawn::StoreOp::Store;
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
@@ -367,8 +371,8 @@
     pass.Draw(6, 1, 0, 0);
     pass.EndPass();
     dawn::CommandBuffer commandBuffer = encoder.Finish();
-    // Expect 1 lazy clear for depthStencilTexture.
-    EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commandBuffer));
+    // Expect 0 lazy clears, depth stencil texture will clear using loadop
+    EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
 
     // Expect the texture to be red because stencil test passed.
     std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
@@ -398,6 +402,8 @@
                                                           depthStencilTexture.CreateView());
     renderPassDescriptor.cDepthStencilAttachmentInfo.depthLoadOp = dawn::LoadOp::Load;
     renderPassDescriptor.cDepthStencilAttachmentInfo.stencilLoadOp = dawn::LoadOp::Load;
+    renderPassDescriptor.cDepthStencilAttachmentInfo.depthStoreOp = dawn::StoreOp::Store;
+    renderPassDescriptor.cDepthStencilAttachmentInfo.stencilStoreOp = dawn::StoreOp::Store;
 
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     auto pass = encoder.BeginRenderPass(&renderPassDescriptor);
@@ -405,8 +411,8 @@
     pass.Draw(6, 1, 0, 0);
     pass.EndPass();
     dawn::CommandBuffer commandBuffer = encoder.Finish();
-    // Expect 1 lazy clear for depthStencilTexture.
-    EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commandBuffer));
+    // Expect 0 lazy clears, depth stencil texture will clear using loadop
+    EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commandBuffer));
 
     // Expect the texture to be red because both depth and stencil tests passed.
     std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});