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 <cwallez@chromium.org>
Reviewed-by: Jiawei Shao <jiawei.shao@intel.com>
Commit-Queue: Hao Li <hao.x.li@intel.com>
This commit is contained in:
Hao Li 2020-10-12 11:47:22 +00:00 committed by Commit Bot service account
parent 6c3da3dc5b
commit 936ef0a5f2
3 changed files with 69 additions and 21 deletions

View File

@ -23,6 +23,7 @@
#include "dawn_native/metal/ComputePipelineMTL.h" #include "dawn_native/metal/ComputePipelineMTL.h"
#include "dawn_native/metal/DeviceMTL.h" #include "dawn_native/metal/DeviceMTL.h"
#include "dawn_native/metal/PipelineLayoutMTL.h" #include "dawn_native/metal/PipelineLayoutMTL.h"
#include "dawn_native/metal/QuerySetMTL.h"
#include "dawn_native/metal/RenderPipelineMTL.h" #include "dawn_native/metal/RenderPipelineMTL.h"
#include "dawn_native/metal/SamplerMTL.h" #include "dawn_native/metal/SamplerMTL.h"
#include "dawn_native/metal/TextureMTL.h" #include "dawn_native/metal/TextureMTL.h"
@ -736,11 +737,39 @@ namespace dawn_native { namespace metal {
} }
case Command::ResolveQuerySet: { case Command::ResolveQuerySet: {
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation."); ResolveQuerySetCmd* cmd = mCommands.NextCommand<ResolveQuerySetCmd>();
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: { case Command::WriteTimestamp: {
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation."); WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
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: { case Command::InsertDebugMarker: {
@ -872,7 +901,17 @@ namespace dawn_native { namespace metal {
} }
case Command::WriteTimestamp: { case Command::WriteTimestamp: {
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation."); WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
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: { default: {
@ -1263,7 +1302,17 @@ namespace dawn_native { namespace metal {
} }
case Command::WriteTimestamp: { case Command::WriteTimestamp: {
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation."); WriteTimestampCmd* cmd = mCommands.NextCommand<WriteTimestampCmd>();
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: { default: {

View File

@ -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. // DrawIndirect.
TEST_P(BufferZeroInitTest, IndirectBufferForDrawIndirect) { TEST_P(BufferZeroInitTest, IndirectBufferForDrawIndirect) {
// Bind the whole buffer as an indirect buffer. // 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. // DrawIndexedIndirect.
TEST_P(BufferZeroInitTest, IndirectBufferForDrawIndexedIndirect) { TEST_P(BufferZeroInitTest, IndirectBufferForDrawIndexedIndirect) {
// Bind the whole buffer as an indirect buffer. // 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. // DispatchIndirect.
TEST_P(BufferZeroInitTest, IndirectBufferForDispatchIndirect) { TEST_P(BufferZeroInitTest, IndirectBufferForDispatchIndirect) {
// Bind the whole buffer as an indirect buffer. // 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) { TEST_P(BufferZeroInitTest, ResolveQuerySet) {
// Timestamp query is not supported on OpenGL // Timestamp query is not supported on OpenGL
DAWN_SKIP_TEST_IF(IsOpenGL()); DAWN_SKIP_TEST_IF(IsOpenGL());
// TODO(hao.x.li@intel.com): Remove it after timestamp query is implementated on Metal // TODO(hao.x.li@intel.com): Crash occurs if we only call WriteTimestamp in a command encoder
DAWN_SKIP_TEST_IF(IsMetal()); // 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 // Skip if timestamp extension is not supported on device
DAWN_SKIP_TEST_IF(!SupportsExtensions({"timestamp_query"})); DAWN_SKIP_TEST_IF(!SupportsExtensions({"timestamp_query"}));

View File

@ -141,8 +141,9 @@ TEST_P(TimestampQueryTests, QuerySetCreation) {
// Test calling timestamp query from command encoder // Test calling timestamp query from command encoder
TEST_P(TimestampQueryTests, TimestampOnCommandEncoder) { TEST_P(TimestampQueryTests, TimestampOnCommandEncoder) {
// TODO(hao.x.li@intel.com): Waiting for timestamp query implementation on Metal // TODO(hao.x.li@intel.com): Crash occurs if we only call WriteTimestamp in a command encoder
DAWN_SKIP_TEST_IF(IsMetal()); // 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 uint32_t kQueryCount = 2;
@ -161,9 +162,6 @@ TEST_P(TimestampQueryTests, TimestampOnCommandEncoder) {
// Test calling timestamp query from render pass encoder // Test calling timestamp query from render pass encoder
TEST_P(TimestampQueryTests, TimestampOnRenderPass) { 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; constexpr uint32_t kQueryCount = 2;
wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount); wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount);
@ -184,9 +182,6 @@ TEST_P(TimestampQueryTests, TimestampOnRenderPass) {
// Test calling timestamp query from compute pass encoder // Test calling timestamp query from compute pass encoder
TEST_P(TimestampQueryTests, TimestampOnComputePass) { 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; constexpr uint32_t kQueryCount = 2;
wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount); wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount);
@ -206,11 +201,14 @@ TEST_P(TimestampQueryTests, TimestampOnComputePass) {
// Test resolving timestamp query to one slot in the buffer // Test resolving timestamp query to one slot in the buffer
TEST_P(TimestampQueryTests, ResolveToBufferWithOffset) { 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(IsWindows() && IsIntel() && IsVulkan());
DAWN_SKIP_TEST_IF(IsIntel() && IsMetal());
// TODO(hao.x.li@intel.com): Waiting for timestamp query implementation on Metal // TODO(hao.x.li@intel.com): Crash occurs if we only call WriteTimestamp in a command encoder
DAWN_SKIP_TEST_IF(IsMetal()); // 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 uint32_t kQueryCount = 2;
constexpr uint64_t kZero = 0; constexpr uint64_t kZero = 0;