Add buffer lazy initialization before resolve queries on D3D12

- Reomve buffer initialization at buffer creation in end2end tests,
and implement lazy initialization when resolving queries to buffer
on D3D12 backend.
- Add buffer lazy zero init tests for resolveQuerySet on D3D12.
- For other backends, buffer lazy initialization will be added when
its resolve method is implemented.

Bug: dawn:434
Change-Id: Ib91c004b37ca912135a1c2fbb53bbd16e2d4eac6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/28461
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Hao Li <hao.x.li@intel.com>
diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
index 4efb9cf..fb7e08e 100644
--- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp
+++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp
@@ -892,6 +892,12 @@
                     QuerySet* querySet = ToBackend(cmd->querySet.Get());
                     Buffer* destination = ToBackend(cmd->destination.Get());
 
+                    DAWN_TRY(destination->EnsureDataInitializedAsDestination(
+                        commandContext, cmd->destinationOffset,
+                        cmd->queryCount * sizeof(uint64_t)));
+                    destination->TrackUsageAndTransitionNow(commandContext,
+                                                            wgpu::BufferUsage::CopyDst);
+
                     commandList->ResolveQueryData(
                         querySet->GetQueryHeap(), D3D12QueryType(querySet->GetQueryType()),
                         cmd->firstQuery, cmd->queryCount, destination->GetD3D12Resource(),
diff --git a/src/tests/end2end/BufferZeroInitTests.cpp b/src/tests/end2end/BufferZeroInitTests.cpp
index 807f4a2..abb181c 100644
--- a/src/tests/end2end/BufferZeroInitTests.cpp
+++ b/src/tests/end2end/BufferZeroInitTests.cpp
@@ -44,6 +44,15 @@
 }  // anonymous namespace
 
 class BufferZeroInitTest : public DawnTest {
+  protected:
+    std::vector<const char*> GetRequiredExtensions() override {
+        std::vector<const char*> requiredExtensions = {};
+        if (SupportsExtensions({"timestamp_query"})) {
+            requiredExtensions.push_back("timestamp_query");
+        }
+        return requiredExtensions;
+    }
+
   public:
     wgpu::Buffer CreateBuffer(uint64_t size,
                               wgpu::BufferUsage usage,
@@ -1160,6 +1169,72 @@
     }
 }
 
+// Test the buffer will be lazily intialized correctly when its first use is in resolveQuerySet
+TEST_P(BufferZeroInitTest, ResolveQuerySet) {
+    // Timestamp query is not supported on OpenGL
+    DAWN_SKIP_TEST_IF(IsOpenGL());
+
+    // TODO(hao.x.li@intel.com): Remove it after timestamp query is implementated on Vulkan and
+    // Metal
+    DAWN_SKIP_TEST_IF(IsVulkan() || IsMetal());
+
+    // Skip if timestamp extension is not supported on device
+    DAWN_SKIP_TEST_IF(!SupportsExtensions({"timestamp_query"}));
+
+    constexpr uint64_t kBufferSize = 16u;
+    constexpr wgpu::BufferUsage kBufferUsage =
+        wgpu::BufferUsage::QueryResolve | wgpu::BufferUsage::CopyDst;
+
+    wgpu::QuerySetDescriptor descriptor;
+    descriptor.count = 2u;
+    descriptor.type = wgpu::QueryType::Timestamp;
+    wgpu::QuerySet querySet = device.CreateQuerySet(&descriptor);
+
+    // Resolve data to the whole buffer doesn't need lazy initialization.
+    {
+        constexpr uint32_t kQueryCount = 2u;
+        constexpr uint64_t kDestinationOffset = 0u;
+
+        wgpu::Buffer destination = CreateBuffer(kBufferSize, kBufferUsage);
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        encoder.WriteTimestamp(querySet, 0);
+        encoder.WriteTimestamp(querySet, 1);
+        encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, kDestinationOffset);
+        wgpu::CommandBuffer commands = encoder.Finish();
+
+        EXPECT_LAZY_CLEAR(0u, queue.Submit(1, &commands));
+    }
+
+    // Resolve data to partial of the buffer needs lazy initialization.
+    // destinationOffset == 0 and destinationOffset + 8 * queryCount < kBufferSize
+    {
+        constexpr uint32_t kQueryCount = 1u;
+        constexpr uint64_t kDestinationOffset = 0u;
+
+        wgpu::Buffer destination = CreateBuffer(kBufferSize, kBufferUsage);
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        encoder.WriteTimestamp(querySet, 0);
+        encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, kDestinationOffset);
+        wgpu::CommandBuffer commands = encoder.Finish();
+
+        EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
+    }
+
+    // destinationOffset > 0 and destinationOffset + 8 * queryCount <= kBufferSize
+    {
+        constexpr uint32_t kQueryCount = 1;
+        constexpr uint64_t kDestinationOffset = 8u;
+
+        wgpu::Buffer destination = CreateBuffer(kBufferSize, kBufferUsage);
+        wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
+        encoder.WriteTimestamp(querySet, 0);
+        encoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, kDestinationOffset);
+        wgpu::CommandBuffer commands = encoder.Finish();
+
+        EXPECT_LAZY_CLEAR(1u, queue.Submit(1, &commands));
+    }
+}
+
 DAWN_INSTANTIATE_TEST(BufferZeroInitTest,
                       D3D12Backend({"nonzero_clear_resources_on_creation_for_testing"}),
                       MetalBackend({"nonzero_clear_resources_on_creation_for_testing"}),
diff --git a/src/tests/end2end/QueryTests.cpp b/src/tests/end2end/QueryTests.cpp
index 47ccdd0..00522af 100644
--- a/src/tests/end2end/QueryTests.cpp
+++ b/src/tests/end2end/QueryTests.cpp
@@ -28,13 +28,7 @@
         descriptor.size = size;
         descriptor.usage = wgpu::BufferUsage::QueryResolve | wgpu::BufferUsage::CopySrc |
                            wgpu::BufferUsage::CopyDst;
-        wgpu::Buffer buffer = device.CreateBuffer(&descriptor);
-
-        // Initialize the buffer values to 0.
-        std::vector<uint64_t> myData = {0, 0};
-        device.GetDefaultQueue().WriteBuffer(buffer, 0, myData.data(), size);
-
-        return buffer;
+        return device.CreateBuffer(&descriptor);
     }
 };