diff --git a/src/dawn_native/DawnNative.cpp b/src/dawn_native/DawnNative.cpp index 08c9587f0a..f5909ebd8a 100644 --- a/src/dawn_native/DawnNative.cpp +++ b/src/dawn_native/DawnNative.cpp @@ -115,4 +115,9 @@ namespace dawn_native { return mImpl->IsBeginCaptureOnStartupEnabled(); } + size_t GetLazyClearCountForTesting(DawnDevice device) { + dawn_native::DeviceBase* deviceBase = reinterpret_cast(device); + return deviceBase->GetLazyClearCountForTesting(); + } + } // namespace dawn_native diff --git a/src/dawn_native/Device.cpp b/src/dawn_native/Device.cpp index 8be70b0283..0901c7daa7 100644 --- a/src/dawn_native/Device.cpp +++ b/src/dawn_native/Device.cpp @@ -484,6 +484,14 @@ namespace dawn_native { 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 d99f0f985c..ad99a8fecb 100644 --- a/src/dawn_native/Device.h +++ b/src/dawn_native/Device.h @@ -151,6 +151,8 @@ namespace dawn_native { std::vector GetTogglesUsed() const; bool IsToggleEnabled(Toggle toggle) const; + size_t GetLazyClearCountForTesting(); + void IncrementLazyClearCountForTesting(); protected: void SetToggle(Toggle toggle, bool isEnabled); @@ -232,6 +234,7 @@ namespace dawn_native { 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 afe10f3577..cc36c9d8b3 100644 --- a/src/dawn_native/d3d12/TextureD3D12.cpp +++ b/src/dawn_native/d3d12/TextureD3D12.cpp @@ -513,6 +513,7 @@ namespace dawn_native { namespace d3d12 { } } SetIsSubresourceContentInitialized(baseMipLevel, levelCount, baseArrayLayer, layerCount); + GetDevice()->IncrementLazyClearCountForTesting(); } void Texture::EnsureSubresourceContentInitialized(ComPtr commandList, diff --git a/src/dawn_native/opengl/TextureGL.cpp b/src/dawn_native/opengl/TextureGL.cpp index cdb7419283..06a11bd42e 100644 --- a/src/dawn_native/opengl/TextureGL.cpp +++ b/src/dawn_native/opengl/TextureGL.cpp @@ -222,6 +222,7 @@ namespace dawn_native { namespace opengl { } } 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 ba1f4b5527..7512712160 100644 --- a/src/dawn_native/vulkan/TextureVk.cpp +++ b/src/dawn_native/vulkan/TextureVk.cpp @@ -563,6 +563,7 @@ namespace dawn_native { namespace vulkan { 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 356d3a0ff1..d90abd0867 100644 --- a/src/include/dawn_native/DawnNative.h +++ b/src/include/dawn_native/DawnNative.h @@ -143,6 +143,8 @@ namespace dawn_native { // Query the names of all the toggles that are enabled in device DAWN_NATIVE_EXPORT std::vector 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 4ba32c71b4..3aa685ed44 100644 --- a/src/tests/DawnTest.h +++ b/src/tests/DawnTest.h @@ -43,6 +43,16 @@ sizeof(RGBA8), \ new detail::ExpectEq(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 98ce972342..77e82c28ca 100644 --- a/src/tests/end2end/TextureZeroInitTests.cpp +++ b/src/tests/end2end/TextureZeroInitTests.cpp @@ -97,7 +97,7 @@ TEST_P(TextureZeroInitTest, CopyTextureToBufferSource) { // 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 @@ TEST_P(TextureZeroInitTest, RenderingMipMapClearsToZero) { 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 expected(mipSize * mipSize, {0, 0, 0, 0}); @@ -149,7 +149,7 @@ TEST_P(TextureZeroInitTest, RenderingArrayLayerClearsToZero) { pass.EndPass(); } dawn::CommandBuffer commands = encoder.Finish(); - queue.Submit(1, &commands); + EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands)); std::vector expected(kSize * kSize, {0, 0, 0, 0}); @@ -178,7 +178,7 @@ TEST_P(TextureZeroInitTest, CopyBufferToTexture) { dawn::CommandEncoder encoder = device.CreateCommandEncoder(); encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©Size); dawn::CommandBuffer commands = encoder.Finish(); - queue.Submit(1, &commands); + EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands)); std::vector expected(kSize * kSize, {100, 100, 100, 100}); @@ -206,7 +206,7 @@ TEST_P(TextureZeroInitTest, CopyBufferToTextureHalf) { dawn::CommandEncoder encoder = device.CreateCommandEncoder(); encoder.CopyBufferToTexture(&bufferCopyView, &textureCopyView, ©Size); dawn::CommandBuffer commands = encoder.Finish(); - queue.Submit(1, &commands); + EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands)); std::vector expected100((kSize / 2) * kSize, {100, 100, 100, 100}); std::vector expectedZeros((kSize / 2) * kSize, {0, 0, 0, 0}); @@ -240,7 +240,7 @@ TEST_P(TextureZeroInitTest, CopyTextureToTexture) { dawn::CommandEncoder encoder = device.CreateCommandEncoder(); encoder.CopyTextureToTexture(&srcTextureCopyView, &dstTextureCopyView, ©Size); dawn::CommandBuffer commands = encoder.Finish(); - queue.Submit(1, &commands); + EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands)); std::vector expected(kSize * kSize, {0, 0, 0, 0}); @@ -290,7 +290,7 @@ TEST_P(TextureZeroInitTest, CopyTextureToTextureHalf) { dawn::CommandEncoder encoder = device.CreateCommandEncoder(); encoder.CopyTextureToTexture(&srcTextureCopyView, &dstTextureCopyView, ©Size); dawn::CommandBuffer commands = encoder.Finish(); - queue.Submit(1, &commands); + EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands)); std::vector expectedWithZeros((kSize / 2) * kSize, {0, 0, 0, 0}); std::vector expectedWith100(kSize * kSize, {100, 100, 100, 100}); @@ -328,7 +328,8 @@ TEST_P(TextureZeroInitTest, RenderingLoadingDepth) { 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 expected(kSize * kSize, {255, 0, 0, 255}); @@ -362,7 +363,8 @@ TEST_P(TextureZeroInitTest, RenderingLoadingStencil) { 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 expected(kSize * kSize, {255, 0, 0, 255}); @@ -395,7 +397,8 @@ TEST_P(TextureZeroInitTest, RenderingLoadingDepthStencil) { 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 expected(kSize * kSize, {255, 0, 0, 255}); @@ -416,7 +419,7 @@ TEST_P(TextureZeroInitTest, ColorAttachmentsClear) { pass.EndPass(); dawn::CommandBuffer commands = encoder.Finish(); - queue.Submit(1, &commands); + EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands)); std::vector 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 @@ TEST_P(TextureZeroInitTest, RenderPassSampledTextureClear) { 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 expectedWithZeros(kSize * kSize, {0, 0, 0, 0}); @@ -552,7 +556,7 @@ TEST_P(TextureZeroInitTest, ComputePassSampledTextureClear) { 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 expectedWithZeros(bufferSize, 0);