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);
}
};