Query API: QuerySet on Metal

- Add query set creation on Metal backend
- Enable end2end tests for query set creation

Bug: dawn:434
Change-Id: I7fe013192ae215b6b97cfdb646a8dd6f2596d4af
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/28800
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Hao Li 2020-09-25 08:49:30 +00:00 committed by Commit Bot service account
parent eec9edfd57
commit ddef7a04a2
8 changed files with 231 additions and 9 deletions

View File

@ -388,6 +388,8 @@ source_set("dawn_native_sources") {
"metal/Forward.h",
"metal/PipelineLayoutMTL.h",
"metal/PipelineLayoutMTL.mm",
"metal/QuerySetMTL.h",
"metal/QuerySetMTL.mm",
"metal/QueueMTL.h",
"metal/QueueMTL.mm",
"metal/RenderPipelineMTL.h",

View File

@ -104,6 +104,13 @@ namespace dawn_native {
"Disables the use of sampler compare on Metal. This is unsupported before A9 "
"processors.",
"https://crbug.com/dawn/342"}},
{Toggle::MetalUseSharedModeForCounterSampleBuffer,
{"metal_use_shared_mode_for_counter_sample_buffer",
"The query set on Metal need to create MTLCounterSampleBuffer which storage mode "
"must be either MTLStorageModeShared or MTLStorageModePrivate. But the private mode "
"does not work properly on Intel platforms. The workaround is use shared mode "
"instead.",
"https://crbug.com/dawn/434"}},
{Toggle::DisableBaseVertex,
{"disable_base_vertex",
"Disables the use of non-zero base vertex which is unsupported on some platforms.",

View File

@ -36,6 +36,7 @@ namespace dawn_native {
SkipValidation,
VulkanUseD32S8,
MetalDisableSamplerCompare,
MetalUseSharedModeForCounterSampleBuffer,
DisableBaseVertex,
DisableBaseInstance,
UseD3D12SmallShaderVisibleHeapForTesting,

View File

@ -214,13 +214,16 @@ namespace dawn_native { namespace metal {
if ([mDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) {
mSupportedExtensions.EnableExtension(Extension::TextureCompressionBC);
}
if (@available(macOS 10.15, *)) {
mSupportedExtensions.EnableExtension(Extension::PipelineStatisticsQuery);
mSupportedExtensions.EnableExtension(Extension::TimestampQuery);
}
#endif
if (@available(macOS 10.15, iOS 14.0, *)) {
if ([mDevice supportsFamily:MTLGPUFamilyMac2] ||
[mDevice supportsFamily:MTLGPUFamilyApple5]) {
mSupportedExtensions.EnableExtension(Extension::PipelineStatisticsQuery);
mSupportedExtensions.EnableExtension(Extension::TimestampQuery);
}
}
mSupportedExtensions.EnableExtension(Extension::ShaderFloat16);
}

View File

@ -14,6 +14,7 @@
#include "dawn_native/metal/DeviceMTL.h"
#include "common/GPUInfo.h"
#include "common/Platform.h"
#include "dawn_native/BackendConnection.h"
#include "dawn_native/BindGroupLayout.h"
@ -25,6 +26,7 @@
#include "dawn_native/metal/CommandBufferMTL.h"
#include "dawn_native/metal/ComputePipelineMTL.h"
#include "dawn_native/metal/PipelineLayoutMTL.h"
#include "dawn_native/metal/QuerySetMTL.h"
#include "dawn_native/metal/QueueMTL.h"
#include "dawn_native/metal/RenderPipelineMTL.h"
#include "dawn_native/metal/SamplerMTL.h"
@ -106,6 +108,14 @@ namespace dawn_native { namespace metal {
// TODO(jiawei.shao@intel.com): tighten this workaround when the driver bug is fixed.
SetToggle(Toggle::AlwaysResolveIntoZeroLevelAndLayer, true);
// TODO(hao.x.li@intel.com): Use MTLStorageModeShared instead of MTLStorageModePrivate when
// creating MTLCounterSampleBuffer in QuerySet on Intel platforms, otherwise it fails to
// create the buffer. Change to use MTLStorageModePrivate when the bug is fixed.
if (@available(macOS 10.15, iOS 14.0, *)) {
bool useSharedMode = gpu_info::IsIntel(this->GetAdapter()->GetPCIInfo().vendorId);
SetToggle(Toggle::MetalUseSharedModeForCounterSampleBuffer, useSharedMode);
}
}
ResultOrError<BindGroupBase*> Device::CreateBindGroupImpl(
@ -132,7 +142,7 @@ namespace dawn_native { namespace metal {
return new PipelineLayout(this, descriptor);
}
ResultOrError<QuerySetBase*> Device::CreateQuerySetImpl(const QuerySetDescriptor* descriptor) {
return DAWN_UNIMPLEMENTED_ERROR("Waiting for implementation");
return QuerySet::Create(this, descriptor);
}
ResultOrError<RenderPipelineBase*> Device::CreateRenderPipelineImpl(
const RenderPipelineDescriptor* descriptor) {

View File

@ -0,0 +1,50 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNNATIVE_METAL_QUERYSETMTL_H_
#define DAWNNATIVE_METAL_QUERYSETMTL_H_
#include "dawn_native/QuerySet.h"
#import <Metal/Metal.h>
namespace dawn_native { namespace metal {
class Device;
class QuerySet final : public QuerySetBase {
public:
static ResultOrError<QuerySet*> Create(Device* device,
const QuerySetDescriptor* descriptor);
id<MTLBuffer> GetVisibilityBuffer() const;
id<MTLCounterSampleBuffer> GetCounterSampleBuffer() const
API_AVAILABLE(macos(10.15), ios(14.0));
private:
~QuerySet() override;
using QuerySetBase::QuerySetBase;
MaybeError Initialize();
// Dawn API
void DestroyImpl() override;
id<MTLBuffer> mVisibilityBuffer = nil;
id<MTLCounterSampleBuffer> mCounterSampleBuffer API_AVAILABLE(macos(10.15),
ios(14.0)) = nil;
};
}} // namespace dawn_native::metal
#endif // DAWNNATIVE_METAL_QUERYSETMTL_H_

View File

@ -0,0 +1,134 @@
// Copyright 2020 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_native/metal/QuerySetMTL.h"
#include "common/Math.h"
#include "common/Platform.h"
#include "dawn_native/metal/DeviceMTL.h"
namespace dawn_native { namespace metal {
namespace {
ResultOrError<id<MTLCounterSampleBuffer>> CreateCounterSampleBuffer(
Device* device,
MTLCommonCounterSet counterSet,
uint32_t count) API_AVAILABLE(macos(10.15), ios(14.0)) {
MTLCounterSampleBufferDescriptor* descriptor = [MTLCounterSampleBufferDescriptor new];
// To determine which counters are available from a device, we need to iterate through
// the counterSets property of a MTLDevice. Then configure which counters will be
// sampled by creating a MTLCounterSampleBufferDescriptor and setting its counterSet
// property to the matched one of the available set.
for (id<MTLCounterSet> set in device->GetMTLDevice().counterSets) {
if ([set.name isEqualToString:counterSet]) {
descriptor.counterSet = set;
break;
}
}
ASSERT(descriptor.counterSet != nil);
descriptor.sampleCount = count;
descriptor.storageMode = MTLStorageModePrivate;
if (device->IsToggleEnabled(Toggle::MetalUseSharedModeForCounterSampleBuffer)) {
descriptor.storageMode = MTLStorageModeShared;
}
NSError* error = nil;
id<MTLCounterSampleBuffer> counterSampleBuffer =
[device->GetMTLDevice() newCounterSampleBufferWithDescriptor:descriptor
error:&error];
if (error != nil) {
const char* errorString = [error.localizedDescription UTF8String];
return DAWN_INTERNAL_ERROR(std::string("Error creating query set: ") + errorString);
}
return counterSampleBuffer;
}
}
// static
ResultOrError<QuerySet*> QuerySet::Create(Device* device,
const QuerySetDescriptor* descriptor) {
Ref<QuerySet> queryset = AcquireRef(new QuerySet(device, descriptor));
DAWN_TRY(queryset->Initialize());
return queryset.Detach();
}
MaybeError QuerySet::Initialize() {
Device* device = ToBackend(GetDevice());
switch (GetQueryType()) {
case wgpu::QueryType::Occlusion: {
// Create buffer for writing 64-bit results.
NSUInteger bufferSize = static_cast<NSUInteger>(GetQueryCount() * sizeof(uint64_t));
mVisibilityBuffer =
[device->GetMTLDevice() newBufferWithLength:bufferSize
options:MTLResourceStorageModePrivate];
break;
}
case wgpu::QueryType::PipelineStatistics:
if (@available(macOS 10.15, iOS 14.0, *)) {
DAWN_TRY_ASSIGN(mCounterSampleBuffer,
CreateCounterSampleBuffer(device, MTLCommonCounterSetStatistic,
GetQueryCount()));
} else {
UNREACHABLE();
}
break;
case wgpu::QueryType::Timestamp:
if (@available(macOS 10.15, iOS 14.0, *)) {
DAWN_TRY_ASSIGN(mCounterSampleBuffer,
CreateCounterSampleBuffer(device, MTLCommonCounterSetTimestamp,
GetQueryCount()));
} else {
UNREACHABLE();
}
break;
default:
UNREACHABLE();
break;
}
return {};
}
id<MTLBuffer> QuerySet::GetVisibilityBuffer() const {
return mVisibilityBuffer;
}
id<MTLCounterSampleBuffer> QuerySet::GetCounterSampleBuffer() const
API_AVAILABLE(macos(10.15), ios(14.0)) {
return mCounterSampleBuffer;
}
QuerySet::~QuerySet() {
DestroyInternal();
}
void QuerySet::DestroyImpl() {
if (mVisibilityBuffer != nil) {
[mVisibilityBuffer release];
mVisibilityBuffer = nil;
}
if (@available(macOS 10.15, iOS 14.0, *)) {
if (mCounterSampleBuffer != nil) {
[mCounterSampleBuffer release];
mCounterSampleBuffer = nil;
}
}
}
}} // namespace dawn_native::metal

View File

@ -51,7 +51,7 @@ TEST_P(OcclusionQueryTests, QuerySetDestroy) {
querySet.Destroy();
}
DAWN_INSTANTIATE_TEST(OcclusionQueryTests, D3D12Backend(), VulkanBackend());
DAWN_INSTANTIATE_TEST(OcclusionQueryTests, D3D12Backend(), MetalBackend(), VulkanBackend());
class PipelineStatisticsQueryTests : public QueryTests {
protected:
@ -85,7 +85,10 @@ TEST_P(PipelineStatisticsQueryTests, QuerySetCreation) {
device.CreateQuerySet(&descriptor);
}
DAWN_INSTANTIATE_TEST(PipelineStatisticsQueryTests, D3D12Backend(), VulkanBackend());
DAWN_INSTANTIATE_TEST(PipelineStatisticsQueryTests,
D3D12Backend(),
MetalBackend(),
VulkanBackend());
class TimestampExpectation : public detail::Expectation {
public:
@ -138,6 +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());
constexpr uint32_t kQueryCount = 2;
wgpu::QuerySet querySet = CreateQuerySetForTimestamp(kQueryCount);
@ -155,6 +161,9 @@ 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);
@ -175,6 +184,9 @@ 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);
@ -197,6 +209,9 @@ TEST_P(TimestampQueryTests, ResolveToBufferWithOffset) {
// TODO(hao.x.li@intel.com): Failed on old Intel Vulkan driver on Windows, need investigation.
DAWN_SKIP_TEST_IF(IsWindows() && IsIntel() && IsVulkan());
// TODO(hao.x.li@intel.com): Waiting for timestamp query implementation on Metal
DAWN_SKIP_TEST_IF(IsMetal());
constexpr uint32_t kQueryCount = 2;
constexpr uint64_t kZero = 0;
@ -232,4 +247,4 @@ TEST_P(TimestampQueryTests, ResolveToBufferWithOffset) {
}
}
DAWN_INSTANTIATE_TEST(TimestampQueryTests, D3D12Backend(), VulkanBackend());
DAWN_INSTANTIATE_TEST(TimestampQueryTests, D3D12Backend(), MetalBackend(), VulkanBackend());