Create nonzero_clear_resources_on_creation_for_testing toggle

Created toggle to force texture clearing to 1 bits in order to
test the logic of lazy clearing.

Bug: dawn:145
Change-Id: I83bc32f046159c709c426b77458fbdf115f7bfd0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/7120
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Natasha Lee <natlee@microsoft.com>
diff --git a/BUILD.gn b/BUILD.gn
index 44709b1..36e6301 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -643,6 +643,7 @@
     "src/tests/end2end/IndexFormatTests.cpp",
     "src/tests/end2end/InputStateTests.cpp",
     "src/tests/end2end/MultisampledRenderingTests.cpp",
+    "src/tests/end2end/NonzeroTextureCreationTests.cpp",
     "src/tests/end2end/ObjectCachingTests.cpp",
     "src/tests/end2end/PrimitiveTopologyTests.cpp",
     "src/tests/end2end/PushConstantTests.cpp",
diff --git a/src/dawn_native/Instance.cpp b/src/dawn_native/Instance.cpp
index 0eedeaa..865d15c 100644
--- a/src/dawn_native/Instance.cpp
+++ b/src/dawn_native/Instance.cpp
@@ -67,7 +67,13 @@
                "not support MTLStoreActionStoreAndMultisampleResolve. To support StoreOp::Store on "
                "those platforms, we should do MSAA resolve in another render pass after ending the "
                "previous one.",
-               "https://bugs.chromium.org/p/dawn/issues/detail?id=56"}}}};
+               "https://bugs.chromium.org/p/dawn/issues/detail?id=56"}},
+             {Toggle::NonzeroClearResourcesOnCreationForTesting,
+              {"nonzero_clear_resources_on_creation_for_testing",
+               "Clears texture to full 1 bits as soon as they are created, but doesn't update "
+               "the tracking state of the texture. This way we can test the logic of clearing "
+               "textures that use recycled memory.",
+               "https://bugs.chromium.org/p/dawn/issues/detail?id=145"}}}};
 
     }  // anonymous namespace
 
diff --git a/src/dawn_native/Toggles.h b/src/dawn_native/Toggles.h
index 5bcda4d..c60f5f9 100644
--- a/src/dawn_native/Toggles.h
+++ b/src/dawn_native/Toggles.h
@@ -22,9 +22,10 @@
 namespace dawn_native {
 
     enum class Toggle {
-        EmulateStoreAndMSAAResolve = 0,
+        EmulateStoreAndMSAAResolve,
+        NonzeroClearResourcesOnCreationForTesting,
 
-        EnumCount = 1,
+        EnumCount,
         InvalidEnum = EnumCount,
     };
 
diff --git a/src/dawn_native/vulkan/DeviceVk.cpp b/src/dawn_native/vulkan/DeviceVk.cpp
index 7b91f59..629d8f9 100644
--- a/src/dawn_native/vulkan/DeviceVk.cpp
+++ b/src/dawn_native/vulkan/DeviceVk.cpp
@@ -42,6 +42,9 @@
 
     Device::Device(Adapter* adapter, const DeviceDescriptor* descriptor)
         : DeviceBase(adapter, descriptor) {
+        if (descriptor != nullptr) {
+            ApplyToggleOverrides(descriptor);
+        }
     }
 
     MaybeError Device::Initialize() {
diff --git a/src/dawn_native/vulkan/TextureVk.cpp b/src/dawn_native/vulkan/TextureVk.cpp
index 70064ec..cfc27a6 100644
--- a/src/dawn_native/vulkan/TextureVk.cpp
+++ b/src/dawn_native/vulkan/TextureVk.cpp
@@ -319,6 +319,24 @@
                                        mMemoryAllocation.GetMemoryOffset()) != VK_SUCCESS) {
             ASSERT(false);
         }
+        if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
+            VkImageSubresourceRange range = {};
+            range.aspectMask = GetVkAspectMask();
+            range.baseMipLevel = 0;
+            range.levelCount = GetNumMipLevels();
+            range.baseArrayLayer = 0;
+            range.layerCount = GetArrayLayers();
+
+            // TODO(natlee@microsoft.com): use correct union member depending on the texture format
+            VkClearColorValue clear_color = {{1.0, 1.0, 1.0, 1.0}};
+
+            TransitionUsageNow(ToBackend(GetDevice())->GetPendingCommandBuffer(),
+                               dawn::TextureUsageBit::TransferDst);
+            ToBackend(GetDevice())
+                ->fn.CmdClearColorImage(ToBackend(GetDevice())->GetPendingCommandBuffer(),
+                                        GetHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
+                                        &clear_color, 1, &range);
+        }
     }
 
     // With this constructor, the lifetime of the resource is externally managed.
diff --git a/src/tests/DawnTest.cpp b/src/tests/DawnTest.cpp
index b0f423b..4546e36 100644
--- a/src/tests/DawnTest.cpp
+++ b/src/tests/DawnTest.cpp
@@ -293,6 +293,7 @@
     DawnDevice backendDevice;
     const char* forceEnabledWorkaround = GetParam().forceEnabledWorkaround;
     if (forceEnabledWorkaround != nullptr) {
+        ASSERT(gTestEnv->GetInstance()->GetToggleInfo(forceEnabledWorkaround) != nullptr);
         dawn_native::DeviceDescriptor deviceDescriptor = InitWorkaround(forceEnabledWorkaround);
         backendDevice = backendAdapter.CreateDevice(&deviceDescriptor);
     } else {
diff --git a/src/tests/end2end/NonzeroTextureCreationTests.cpp b/src/tests/end2end/NonzeroTextureCreationTests.cpp
new file mode 100644
index 0000000..28a9b4d
--- /dev/null
+++ b/src/tests/end2end/NonzeroTextureCreationTests.cpp
@@ -0,0 +1,99 @@
+// Copyright 2019 The Dawn Authors

+//

+// Licensed under the Apache License, Version 2.0 (the "License");

+// you may not use this file except in compliance with the License.

+// You may obtain a copy of the License at

+//

+//     http://www.apache.org/licenses/LICENSE-2.0

+//

+// Unless required by applicable law or agreed to in writing, software

+// distributed under the License is distributed on an "AS IS" BASIS,

+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+// See the License for the specific language governing permissions and

+// limitations under the License.

+

+#include "tests/DawnTest.h"

+

+#include "utils/ComboRenderPipelineDescriptor.h"

+#include "utils/DawnHelpers.h"

+

+class NonzeroTextureCreationTests : public DawnTest {

+  protected:

+    void SetUp() override {

+        DawnTest::SetUp();

+    }

+

+    constexpr static uint32_t kSize = 128;

+};

+

+// Test that texture clears to 1's because toggle is enabled.

+TEST_P(NonzeroTextureCreationTests, TextureCreationClearsOneBits) {

+    dawn::TextureDescriptor descriptor;

+    descriptor.dimension = dawn::TextureDimension::e2D;

+    descriptor.size.width = kSize;

+    descriptor.size.height = kSize;

+    descriptor.size.depth = 1;

+    descriptor.arrayLayerCount = 1;

+    descriptor.sampleCount = 1;

+    descriptor.format = dawn::TextureFormat::R8G8B8A8Unorm;

+    descriptor.mipLevelCount = 1;

+    descriptor.usage = dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::TransferSrc;

+    dawn::Texture texture = device.CreateTexture(&descriptor);

+

+    RGBA8 filledWithOnes(255, 255, 255, 255);

+    EXPECT_PIXEL_RGBA8_EQ(filledWithOnes, texture, 0, 0);

+}

+

+// Test that non-zero mip level clears to 1's because toggle is enabled.

+TEST_P(NonzeroTextureCreationTests, MipMapClears) {

+    constexpr uint32_t mipLevels = 4;

+

+    dawn::TextureDescriptor descriptor;

+    descriptor.dimension = dawn::TextureDimension::e2D;

+    descriptor.size.width = kSize;

+    descriptor.size.height = kSize;

+    descriptor.size.depth = 1;

+    descriptor.arrayLayerCount = 1;

+    descriptor.sampleCount = 1;

+    descriptor.format = dawn::TextureFormat::R8G8B8A8Unorm;

+    descriptor.mipLevelCount = mipLevels;

+    descriptor.usage = dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::TransferSrc;

+    dawn::Texture texture = device.CreateTexture(&descriptor);

+

+    std::vector<RGBA8> expected;

+    RGBA8 filledWithOnes(255, 255, 255, 255);

+    for (uint32_t i = 0; i < kSize * kSize; ++i) {

+        expected.push_back(filledWithOnes);

+    }

+    uint32_t mipSize = kSize >> 2;

+    EXPECT_TEXTURE_RGBA8_EQ(expected.data(), texture, 0, 0, mipSize, mipSize, 2, 0);

+}

+

+// Test that non-zero array layers clears to 1's because toggle is enabled.

+TEST_P(NonzeroTextureCreationTests, ArrayLayerClears) {

+    constexpr uint32_t arrayLayers = 4;

+

+    dawn::TextureDescriptor descriptor;

+    descriptor.dimension = dawn::TextureDimension::e2D;

+    descriptor.size.width = kSize;

+    descriptor.size.height = kSize;

+    descriptor.size.depth = 1;

+    descriptor.arrayLayerCount = arrayLayers;

+    descriptor.sampleCount = 1;

+    descriptor.format = dawn::TextureFormat::R8G8B8A8Unorm;

+    descriptor.mipLevelCount = 1;

+    descriptor.usage = dawn::TextureUsageBit::OutputAttachment | dawn::TextureUsageBit::TransferSrc;

+    dawn::Texture texture = device.CreateTexture(&descriptor);

+

+    std::vector<RGBA8> expected;

+    RGBA8 filledWithOnes(255, 255, 255, 255);

+    for (uint32_t i = 0; i < kSize * kSize; ++i) {

+        expected.push_back(filledWithOnes);

+    }

+

+    EXPECT_TEXTURE_RGBA8_EQ(expected.data(), texture, 0, 0, kSize, kSize, 0, 2);

+}

+

+DAWN_INSTANTIATE_TEST(NonzeroTextureCreationTests,

+                      ForceWorkaround(VulkanBackend,

+                                      "nonzero_clear_resources_on_creation_for_testing"));