Check Query API feature support by GPU counter on Metal
Currently we use gpu family to determine whether a query extension is
supported. The official document provides a way to check the feature
support by GPU counter. Update checking following the official guide.
Bug: dawn:996
Change-Id: I09cf51ed8a8209642eed71c9e4592f6eab82bfa5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/60360
Commit-Queue: Hao Li <hao.x.li@intel.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
diff --git a/src/dawn_native/metal/BackendMTL.mm b/src/dawn_native/metal/BackendMTL.mm
index a3a1212..4cffa1b 100644
--- a/src/dawn_native/metal/BackendMTL.mm
+++ b/src/dawn_native/metal/BackendMTL.mm
@@ -28,6 +28,8 @@
# include "common/IOKitRef.h"
#endif
+#include <vector>
+
namespace dawn_native { namespace metal {
namespace {
@@ -168,6 +170,66 @@
#else
# error "Unsupported Apple platform."
#endif
+
+ bool IsCounterSamplingBoundarySupport(id<MTLDevice> device)
+ API_AVAILABLE(macos(11.0), ios(14.0)) {
+ bool isBlitBoundarySupported =
+ [device supportsCounterSampling:MTLCounterSamplingPointAtBlitBoundary];
+ bool isDispatchBoundarySupported =
+ [device supportsCounterSampling:MTLCounterSamplingPointAtDispatchBoundary];
+ bool isDrawBoundarySupported =
+ [device supportsCounterSampling:MTLCounterSamplingPointAtDrawBoundary];
+
+ return isBlitBoundarySupported && isDispatchBoundarySupported &&
+ isDrawBoundarySupported;
+ }
+
+ bool IsGPUCounterSupported(id<MTLDevice> device,
+ MTLCommonCounterSet counterSetName,
+ std::vector<MTLCommonCounter> counters)
+ API_AVAILABLE(macos(10.15), ios(14.0)) {
+ // MTLDevice’s counterSets property declares which counter sets it supports. Check
+ // whether it's available on the device before requesting a counter set.
+ id<MTLCounterSet> counterSet = nil;
+ for (id<MTLCounterSet> set in device.counterSets) {
+ if ([set.name caseInsensitiveCompare:counterSetName] == NSOrderedSame) {
+ counterSet = set;
+ break;
+ }
+ }
+
+ // The counter set is not supported.
+ if (counterSet == nil) {
+ return false;
+ }
+
+ // A GPU might support a counter set, but only support a subset of the counters in that
+ // set, check if the counter set supports all specific counters we need. Return false
+ // if there is a counter unsupported.
+ std::vector<NSString*> supportedCounters;
+ for (id<MTLCounter> counter in counterSet.counters) {
+ supportedCounters.push_back(counter.name);
+ }
+ for (const auto& counterName : counters) {
+ if (std::find(supportedCounters.begin(), supportedCounters.end(), counterName) ==
+ supportedCounters.end()) {
+ return false;
+ }
+ }
+
+ if (@available(macOS 11.0, iOS 14.0, *)) {
+ // Check whether it can read GPU counters at the specified command boundary. Apple
+ // family GPUs do not support sampling between different Metal commands, because
+ // they defer fragment processing until after the GPU processes all the primitives
+ // in the render pass.
+ if (!IsCounterSamplingBoundarySupport(device)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
} // anonymous namespace
// The Metal backend's Adapter.
@@ -224,10 +286,16 @@
#endif
if (@available(macOS 10.15, iOS 14.0, *)) {
- if ([*mDevice supportsFamily:MTLGPUFamilyMac2] ||
- [*mDevice supportsFamily:MTLGPUFamilyApple5]) {
+ if (IsGPUCounterSupported(
+ *mDevice, MTLCommonCounterSetStatistic,
+ {MTLCommonCounterVertexInvocations, MTLCommonCounterClipperInvocations,
+ MTLCommonCounterClipperPrimitivesOut, MTLCommonCounterFragmentInvocations,
+ MTLCommonCounterComputeKernelInvocations})) {
mSupportedExtensions.EnableExtension(Extension::PipelineStatisticsQuery);
+ }
+ if (IsGPUCounterSupported(*mDevice, MTLCommonCounterSetTimestamp,
+ {MTLCommonCounterTimestamp})) {
// Disable timestamp query on macOS 10.15 on AMD GPU because WriteTimestamp
// fails to call without any copy commands on MTLBlitCommandEncoder. This issue
// has been fixed on macOS 11.0. See crbug.com/dawn/545
@@ -242,6 +310,7 @@
}
}
}
+
if (@available(macOS 10.11, iOS 11.0, *)) {
mSupportedExtensions.EnableExtension(Extension::DepthClamping);
}