From 6419bddd9b0c1869b2b6f7ae258fa177e870ba9f Mon Sep 17 00:00:00 2001 From: Hao Li Date: Thu, 17 Sep 2020 01:59:29 +0000 Subject: [PATCH] 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 Commit-Queue: Hao Li --- src/dawn_native/d3d12/CommandBufferD3D12.cpp | 6 ++ src/tests/end2end/BufferZeroInitTests.cpp | 75 ++++++++++++++++++++ src/tests/end2end/QueryTests.cpp | 8 +-- 3 files changed, 82 insertions(+), 7 deletions(-) diff --git a/src/dawn_native/d3d12/CommandBufferD3D12.cpp b/src/dawn_native/d3d12/CommandBufferD3D12.cpp index 4efb9cfb9a..fb7e08e49b 100644 --- a/src/dawn_native/d3d12/CommandBufferD3D12.cpp +++ b/src/dawn_native/d3d12/CommandBufferD3D12.cpp @@ -892,6 +892,12 @@ namespace dawn_native { namespace d3d12 { 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 807f4a2dfd..abb181c9e8 100644 --- a/src/tests/end2end/BufferZeroInitTests.cpp +++ b/src/tests/end2end/BufferZeroInitTests.cpp @@ -44,6 +44,15 @@ namespace { } // anonymous namespace class BufferZeroInitTest : public DawnTest { + protected: + std::vector GetRequiredExtensions() override { + std::vector 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_P(BufferZeroInitTest, IndirectBufferForDispatchIndirect) { } } +// 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 47ccdd06f5..00522afde2 100644 --- a/src/tests/end2end/QueryTests.cpp +++ b/src/tests/end2end/QueryTests.cpp @@ -28,13 +28,7 @@ class QueryTests : public DawnTest { 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 myData = {0, 0}; - device.GetDefaultQueue().WriteBuffer(buffer, 0, myData.data(), size); - - return buffer; + return device.CreateBuffer(&descriptor); } };