Backdoor to get the number of texture lazy clears for testing

Bug: dawn:145
Change-Id: Ie01b21ce490832c459e74c76a7b8d9f203552bfe
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/9400
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Natasha Lee <natlee@microsoft.com>
diff --git a/src/dawn_native/DawnNative.cpp b/src/dawn_native/DawnNative.cpp
index 08c9587..f5909eb 100644
--- a/src/dawn_native/DawnNative.cpp
+++ b/src/dawn_native/DawnNative.cpp
@@ -115,4 +115,9 @@
         return mImpl->IsBeginCaptureOnStartupEnabled();
     }
 
+    size_t GetLazyClearCountForTesting(DawnDevice device) {
+        dawn_native::DeviceBase* deviceBase = reinterpret_cast<dawn_native::DeviceBase*>(device);
+        return deviceBase->GetLazyClearCountForTesting();
+    }
+
 }  // namespace dawn_native
diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp
index 8be70b0..0901c7d 100644
--- a/src/dawn_native/Device.cpp
+++ b/src/dawn_native/Device.cpp
@@ -484,6 +484,14 @@
         return mTogglesSet.IsEnabled(toggle);
     }
 
+    size_t DeviceBase::GetLazyClearCountForTesting() {
+        return mLazyClearCountForTesting;
+    }
+
+    void DeviceBase::IncrementLazyClearCountForTesting() {
+        ++mLazyClearCountForTesting;
+    }
+
     void DeviceBase::SetDefaultToggles() {
         // Sets the default-enabled toggles
         mTogglesSet.SetToggle(Toggle::LazyClearResourceOnFirstUse, true);
diff --git a/src/dawn_native/Device.h b/src/dawn_native/Device.h
index d99f0f9..ad99a8f 100644
--- a/src/dawn_native/Device.h
+++ b/src/dawn_native/Device.h
@@ -151,6 +151,8 @@
 
         std::vector<const char*> GetTogglesUsed() const;
         bool IsToggleEnabled(Toggle toggle) const;
+        size_t GetLazyClearCountForTesting();
+        void IncrementLazyClearCountForTesting();
 
       protected:
         void SetToggle(Toggle toggle, bool isEnabled);
@@ -232,6 +234,7 @@
         FormatTable mFormatTable;
 
         TogglesSet mTogglesSet;
+        size_t mLazyClearCountForTesting = 0;
     };
 
 }  // namespace dawn_native
diff --git a/src/dawn_native/d3d12/TextureD3D12.cpp b/src/dawn_native/d3d12/TextureD3D12.cpp
index afe10f3..cc36c9d 100644
--- a/src/dawn_native/d3d12/TextureD3D12.cpp
+++ b/src/dawn_native/d3d12/TextureD3D12.cpp
@@ -513,6 +513,7 @@
             }
         }
         SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, layerCount);
+        GetDevice()->IncrementLazyClearCountForTesting();
     }
 
     void Texture::EnsureSubresourceContentInitialized(ComPtr<ID3D12GraphicsCommandList> commandList,
diff --git a/src/dawn_native/opengl/TextureGL.cpp b/src/dawn_native/opengl/TextureGL.cpp
index cdb7419..06a11bd 100644
--- a/src/dawn_native/opengl/TextureGL.cpp
+++ b/src/dawn_native/opengl/TextureGL.cpp
@@ -222,6 +222,7 @@
             }
         }
         SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, layerCount);
+        GetDevice()->IncrementLazyClearCountForTesting();
     }
 
     void Texture::EnsureSubresourceContentInitialized(uint32_t baseMipLevel,
diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp
index ba1f4b5..7512712 100644
--- a/src/dawn_native/vulkan/TextureVk.cpp
+++ b/src/dawn_native/vulkan/TextureVk.cpp
@@ -563,6 +563,7 @@
                                         clear_color, 1, &range);
         }
         SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, layerCount);
+        GetDevice()->IncrementLazyClearCountForTesting();
     }
 
     void Texture::EnsureSubresourceContentInitialized(VkCommandBuffer commands,
diff --git a/src/include/dawn_native/DawnNative.h b/src/include/dawn_native/DawnNative.h
index 356d3a0..d90abd0 100644
--- a/src/include/dawn_native/DawnNative.h
+++ b/src/include/dawn_native/DawnNative.h
@@ -143,6 +143,8 @@
     // Query the names of all the toggles that are enabled in device
     DAWN_NATIVE_EXPORT std::vector<const char*> GetTogglesUsed(DawnDevice device);
 
+    // Backdoor to get the number of lazy clears for testing
+    DAWN_NATIVE_EXPORT size_t GetLazyClearCountForTesting(DawnDevice device);
 }  // namespace dawn_native
 
 #endif  // DAWNNATIVE_DAWNNATIVE_H_
diff --git a/src/tests/DawnTest.h b/src/tests/DawnTest.h
index 4ba32c7..3aa685e 100644
--- a/src/tests/DawnTest.h
+++ b/src/tests/DawnTest.h
@@ -43,6 +43,16 @@
                           sizeof(RGBA8),                                                  \
                           new detail::ExpectEq<RGBA8>(expected, (width) * (height)))
 
+#define EXPECT_LAZY_CLEAR(N, statement)                                                   \
+    if (UsesWire()) {                                                                     \
+        statement;                                                                        \
+    } else {                                                                              \
+        size_t lazyClearsBefore = dawn_native::GetLazyClearCountForTesting(device.Get()); \
+        statement;                                                                        \
+        size_t lazyClearsAfter = dawn_native::GetLazyClearCountForTesting(device.Get());  \
+        EXPECT_EQ(N, lazyClearsAfter - lazyClearsBefore);                                 \
+    }
+
 // Should only be used to test validation of function that can't be tested by regular validation
 // tests;
 #define ASSERT_DEVICE_ERROR(statement) \
diff --git a/src/tests/end2end/TextureZeroInitTests.cpp b/src/tests/end2end/TextureZeroInitTests.cpp
index 98ce972..77e82c2 100644
--- a/src/tests/end2end/TextureZeroInitTests.cpp
+++ b/src/tests/end2end/TextureZeroInitTests.cpp
@@ -97,7 +97,7 @@
 
     // Texture's first usage is in EXPECT_PIXEL_RGBA8_EQ's call to CopyTextureToBuffer
     RGBA8 filledWithZeros(0, 0, 0, 0);
-    EXPECT_PIXEL_RGBA8_EQ(filledWithZeros, texture, 0, 0);
+    EXPECT_LAZY_CLEAR(1u, EXPECT_PIXEL_RGBA8_EQ(filledWithZeros, texture, 0, 0));
 }
 
 // Test that non-zero mip level clears subresource to Zero after first use
@@ -121,7 +121,7 @@
         pass.EndPass();
     }
     dawn::CommandBuffer commands = encoder.Finish();
-    queue.Submit(1, &commands);
+    EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
 
     uint32_t mipSize = kSize >> 2;
     std::vector<RGBA8> expected(mipSize * mipSize, {0, 0, 0, 0});
@@ -149,7 +149,7 @@
         pass.EndPass();
     }
     dawn::CommandBuffer commands = encoder.Finish();
-    queue.Submit(1, &commands);
+    EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
 
     std::vector<RGBA8> expected(kSize * kSize, {0, 0, 0, 0});
 
@@ -178,7 +178,7 @@
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copySize);
     dawn::CommandBuffer commands = encoder.Finish();
-    queue.Submit(1, &commands);
+    EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
 
     std::vector<RGBA8> expected(kSize * kSize, {100, 100, 100, 100});
 
@@ -206,7 +206,7 @@
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, &copySize);
     dawn::CommandBuffer commands = encoder.Finish();
-    queue.Submit(1, &commands);
+    EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
 
     std::vector<RGBA8> expected100((kSize / 2) * kSize, {100, 100, 100, 100});
     std::vector<RGBA8> expectedZeros((kSize / 2) * kSize, {0, 0, 0, 0});
@@ -240,7 +240,7 @@
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     encoder.CopyTextureToTexture(&srcTextureCopyView, &dstTextureCopyView, &copySize);
     dawn::CommandBuffer commands = encoder.Finish();
-    queue.Submit(1, &commands);
+    EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
 
     std::vector<RGBA8> expected(kSize * kSize, {0, 0, 0, 0});
 
@@ -290,7 +290,7 @@
     dawn::CommandEncoder encoder = device.CreateCommandEncoder();
     encoder.CopyTextureToTexture(&srcTextureCopyView, &dstTextureCopyView, &copySize);
     dawn::CommandBuffer commands = encoder.Finish();
-    queue.Submit(1, &commands);
+    EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
 
     std::vector<RGBA8> expectedWithZeros((kSize / 2) * kSize, {0, 0, 0, 0});
     std::vector<RGBA8> expectedWith100(kSize * kSize, {100, 100, 100, 100});
@@ -328,7 +328,8 @@
     pass.Draw(6, 1, 0, 0);
     pass.EndPass();
     dawn::CommandBuffer commandBuffer = encoder.Finish();
-    queue.Submit(1, &commandBuffer);
+    // Expect 2 lazy clears, one for the srcTexture and one for the depthStencilTexture
+    EXPECT_LAZY_CLEAR(2u, queue.Submit(1, &commandBuffer));
 
     // Expect the texture to be red because depth test passed.
     std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
@@ -362,7 +363,8 @@
     pass.Draw(6, 1, 0, 0);
     pass.EndPass();
     dawn::CommandBuffer commandBuffer = encoder.Finish();
-    queue.Submit(1, &commandBuffer);
+    // Expect 2 lazy clears, one for srcTexture and one for depthStencilTexture.
+    EXPECT_LAZY_CLEAR(2u, queue.Submit(1, &commandBuffer));
 
     // Expect the texture to be red because stencil test passed.
     std::vector<RGBA8> expected(kSize * kSize, {255, 0, 0, 255});
@@ -395,7 +397,8 @@
     pass.Draw(6, 1, 0, 0);
     pass.EndPass();
     dawn::CommandBuffer commandBuffer = encoder.Finish();
-    queue.Submit(1, &commandBuffer);
+    // Expect 2 lazy clears, one for srcTexture and one for depthStencilTexture.
+    EXPECT_LAZY_CLEAR(2u, 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});
@@ -416,7 +419,7 @@
     pass.EndPass();
 
     dawn::CommandBuffer commands = encoder.Finish();
-    queue.Submit(1, &commands);
+    EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
 
     std::vector<RGBA8> expected(kSize * kSize, {0, 0, 0, 0});
     EXPECT_TEXTURE_RGBA8_EQ(expected.data(), renderPass.color, 0, 0, kSize, kSize, 0, 0);
@@ -484,7 +487,8 @@
     pass.Draw(6, 1, 0, 0);
     pass.EndPass();
     dawn::CommandBuffer commands = encoder.Finish();
-    queue.Submit(1, &commands);
+    // Expect 2 lazy clears, one for the sampled texture src and one for the rendered target texture
+    EXPECT_LAZY_CLEAR(2u, queue.Submit(1, &commands));
 
     // Expect the rendered texture to be cleared
     std::vector<RGBA8> expectedWithZeros(kSize * kSize, {0, 0, 0, 0});
@@ -552,7 +556,7 @@
     pass.Dispatch(1, 1, 1);
     pass.EndPass();
     dawn::CommandBuffer commands = encoder.Finish();
-    queue.Submit(1, &commands);
+    EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
 
     // Expect the buffer to be zeroed out by the compute pass
     std::vector<uint32_t> expectedWithZeros(bufferSize, 0);