From 936ef0a5f21e5622e003257d665f049804d07516 Mon Sep 17 00:00:00 2001 From: Hao Li Date: Mon, 12 Oct 2020 11:47:22 +0000 Subject: [PATCH] Query API: Timestamp Query on Metal - Add WriteTimestamp and ResolveQuerySet on Metal - Enable end2end tests of timestamp query on Metal - Lazy initialize the distination buffer in ResolveQuerySet - Update part of end2end tests to test from render pass instead of command encoder due to we cannot write timestamp on CommandEncoder without any copy commands on Metal. Bug: dawn:434 Change-Id: Ie9217e1f5a00bc252d6293ef7521c2e343ba9259 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/29020 Reviewed-by: Corentin Wallez Reviewed-by: Jiawei Shao Commit-Queue: Hao Li --- src/dawn_native/metal/CommandBufferMTL.mm | 57 +++++++++++++++++++++-- src/tests/end2end/BufferZeroInitTests.cpp | 13 +++--- src/tests/end2end/QueryTests.cpp | 20 ++++---- 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/src/dawn_native/metal/CommandBufferMTL.mm b/src/dawn_native/metal/CommandBufferMTL.mm index dbd99437d8..3fa0b89ffe 100644 --- a/src/dawn_native/metal/CommandBufferMTL.mm +++ b/src/dawn_native/metal/CommandBufferMTL.mm @@ -23,6 +23,7 @@ #include "dawn_native/metal/ComputePipelineMTL.h" #include "dawn_native/metal/DeviceMTL.h" #include "dawn_native/metal/PipelineLayoutMTL.h" +#include "dawn_native/metal/QuerySetMTL.h" #include "dawn_native/metal/RenderPipelineMTL.h" #include "dawn_native/metal/SamplerMTL.h" #include "dawn_native/metal/TextureMTL.h" @@ -736,11 +737,39 @@ namespace dawn_native { namespace metal { } case Command::ResolveQuerySet: { - return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation."); + ResolveQuerySetCmd* cmd = mCommands.NextCommand(); + QuerySet* querySet = ToBackend(cmd->querySet.Get()); + Buffer* destination = ToBackend(cmd->destination.Get()); + + destination->EnsureDataInitializedAsDestination( + commandContext, cmd->destinationOffset, cmd->queryCount * sizeof(uint64_t)); + + if (@available(macos 10.15, iOS 14.0, *)) { + [commandContext->EnsureBlit() + resolveCounters:querySet->GetCounterSampleBuffer() + inRange:NSMakeRange(cmd->firstQuery, + cmd->firstQuery + cmd->queryCount) + destinationBuffer:destination->GetMTLBuffer() + destinationOffset:NSUInteger(cmd->destinationOffset)]; + } else { + UNREACHABLE(); + } + break; } case Command::WriteTimestamp: { - return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation."); + WriteTimestampCmd* cmd = mCommands.NextCommand(); + QuerySet* querySet = ToBackend(cmd->querySet.Get()); + + if (@available(macos 10.15, iOS 14.0, *)) { + [commandContext->EnsureBlit() + sampleCountersInBuffer:querySet->GetCounterSampleBuffer() + atSampleIndex:NSUInteger(cmd->queryIndex) + withBarrier:YES]; + } else { + UNREACHABLE(); + } + break; } case Command::InsertDebugMarker: { @@ -872,7 +901,17 @@ namespace dawn_native { namespace metal { } case Command::WriteTimestamp: { - return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation."); + WriteTimestampCmd* cmd = mCommands.NextCommand(); + QuerySet* querySet = ToBackend(cmd->querySet.Get()); + + if (@available(macos 10.15, iOS 14.0, *)) { + [encoder sampleCountersInBuffer:querySet->GetCounterSampleBuffer() + atSampleIndex:NSUInteger(cmd->queryIndex) + withBarrier:YES]; + } else { + UNREACHABLE(); + } + break; } default: { @@ -1263,7 +1302,17 @@ namespace dawn_native { namespace metal { } case Command::WriteTimestamp: { - return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation."); + WriteTimestampCmd* cmd = mCommands.NextCommand(); + QuerySet* querySet = ToBackend(cmd->querySet.Get()); + + if (@available(macos 10.15, iOS 14.0, *)) { + [encoder sampleCountersInBuffer:querySet->GetCounterSampleBuffer() + atSampleIndex:NSUInteger(cmd->queryIndex) + withBarrier:YES]; + } else { + UNREACHABLE(); + } + break; } default: { diff --git a/src/tests/end2end/BufferZeroInitTests.cpp b/src/tests/end2end/BufferZeroInitTests.cpp index c98b9e6f36..f15017e1c4 100644 --- a/src/tests/end2end/BufferZeroInitTests.cpp +++ b/src/tests/end2end/BufferZeroInitTests.cpp @@ -1120,7 +1120,7 @@ TEST_P(BufferZeroInitTest, SetIndexBuffer) { } } -// Test the buffer will be lazily intialized correctly when its first use is an indirect buffer for +// Test the buffer will be lazily initialized correctly when its first use is an indirect buffer for // DrawIndirect. TEST_P(BufferZeroInitTest, IndirectBufferForDrawIndirect) { // Bind the whole buffer as an indirect buffer. @@ -1136,7 +1136,7 @@ TEST_P(BufferZeroInitTest, IndirectBufferForDrawIndirect) { } } -// Test the buffer will be lazily intialized correctly when its first use is an indirect buffer for +// Test the buffer will be lazily initialized correctly when its first use is an indirect buffer for // DrawIndexedIndirect. TEST_P(BufferZeroInitTest, IndirectBufferForDrawIndexedIndirect) { // Bind the whole buffer as an indirect buffer. @@ -1152,7 +1152,7 @@ TEST_P(BufferZeroInitTest, IndirectBufferForDrawIndexedIndirect) { } } -// Test the buffer will be lazily intialized correctly when its first use is an indirect buffer for +// Test the buffer will be lazily initialized correctly when its first use is an indirect buffer for // DispatchIndirect. TEST_P(BufferZeroInitTest, IndirectBufferForDispatchIndirect) { // Bind the whole buffer as an indirect buffer. @@ -1168,13 +1168,14 @@ TEST_P(BufferZeroInitTest, IndirectBufferForDispatchIndirect) { } } -// Test the buffer will be lazily intialized correctly when its first use is in resolveQuerySet +// Test the buffer will be lazily initialized 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 Metal - DAWN_SKIP_TEST_IF(IsMetal()); + // TODO(hao.x.li@intel.com): Crash occurs if we only call WriteTimestamp in a command encoder + // without any copy commands on Metal on AMD GPU. See https://crbug.com/dawn/545. + DAWN_SKIP_TEST_IF(IsMetal() && IsAMD()); // Skip if timestamp extension is not supported on device DAWN_SKIP_TEST_IF(!SupportsExtensions({"timestamp_query"})); diff --git a/src/tests/end2end/QueryTests.cpp b/src/tests/end2end/QueryTests.cpp index dfcebc15d6..388eb3dc11 100644 --- a/src/tests/end2end/QueryTests.cpp +++ b/src/tests/end2end/QueryTests.cpp @@ -141,8 +141,9 @@ TEST_P(TimestampQueryTests, QuerySetCreation) { // Test calling timestamp query from command encoder TEST_P(TimestampQueryTests, TimestampOnCommandEncoder) { - // TODO(hao.x.li@intel.com): Waiting for timestamp query implementation on Metal - DAWN_SKIP_TEST_IF(IsMetal()); + // TODO(hao.x.li@intel.com): Crash occurs if we only call WriteTimestamp in a command encoder + // without any copy commands on Metal on AMD GPU. See https://crbug.com/dawn/545. + DAWN_SKIP_TEST_IF(IsMetal() && IsAMD()); constexpr uint32_t kQueryCount = 2; @@ -161,9 +162,6 @@ TEST_P(TimestampQueryTests, TimestampOnCommandEncoder) { // Test calling timestamp query from render pass encoder TEST_P(TimestampQueryTests, TimestampOnRenderPass) { - // TODO(hao.x.li@intel.com): Waiting for timestamp query implementation on Metal - DAWN_SKIP_TEST_IF(IsMetal()); - constexpr uint32_t kQueryCount = 2; wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount); @@ -184,9 +182,6 @@ TEST_P(TimestampQueryTests, TimestampOnRenderPass) { // Test calling timestamp query from compute pass encoder TEST_P(TimestampQueryTests, TimestampOnComputePass) { - // TODO(hao.x.li@intel.com): Waiting for timestamp query implementation on Metal - DAWN_SKIP_TEST_IF(IsMetal()); - constexpr uint32_t kQueryCount = 2; wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount); @@ -206,11 +201,14 @@ TEST_P(TimestampQueryTests, TimestampOnComputePass) { // Test resolving timestamp query to one slot in the buffer TEST_P(TimestampQueryTests, ResolveToBufferWithOffset) { - // TODO(hao.x.li@intel.com): Failed on old Intel Vulkan driver on Windows, need investigation. + // TODO(hao.x.li@intel.com): Fail to resolve query to buffer with offset on Windows Vulkan and + // Metal on Intel platforms, need investigation. DAWN_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan()); + DAWN_SKIP_TEST_IF(IsIntel() && IsMetal()); - // TODO(hao.x.li@intel.com): Waiting for timestamp query implementation on Metal - DAWN_SKIP_TEST_IF(IsMetal()); + // TODO(hao.x.li@intel.com): Crash occurs if we only call WriteTimestamp in a command encoder + // without any copy commands on Metal on AMD GPU. See https://crbug.com/dawn/545. + DAWN_SKIP_TEST_IF(IsMetal() && IsAMD()); constexpr uint32_t kQueryCount = 2; constexpr uint64_t kZero = 0;