2019-02-05 05:02:30 -08:00
|
|
|
|
// Copyright 2019 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.
|
|
|
|
|
|
2022-02-04 09:07:46 -08:00
|
|
|
|
#include "dawn/native/metal/BackendMTL.h"
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-02-04 04:51:25 -08:00
|
|
|
|
#include "dawn/common/CoreFoundationRef.h"
|
|
|
|
|
#include "dawn/common/GPUInfo.h"
|
2022-02-15 10:18:26 -08:00
|
|
|
|
#include "dawn/common/Log.h"
|
2022-02-04 04:51:25 -08:00
|
|
|
|
#include "dawn/common/NSRef.h"
|
|
|
|
|
#include "dawn/common/Platform.h"
|
|
|
|
|
#include "dawn/common/SystemUtils.h"
|
2022-02-04 09:07:46 -08:00
|
|
|
|
#include "dawn/native/Instance.h"
|
|
|
|
|
#include "dawn/native/MetalBackend.h"
|
|
|
|
|
#include "dawn/native/metal/BufferMTL.h"
|
|
|
|
|
#include "dawn/native/metal/DeviceMTL.h"
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-06-08 12:52:42 -07:00
|
|
|
|
#if DAWN_PLATFORM_IS(MACOS)
|
2022-05-01 07:40:55 -07:00
|
|
|
|
#import <IOKit/IOKitLib.h>
|
|
|
|
|
#include "dawn/common/IOKitRef.h"
|
2019-09-17 21:32:52 -07:00
|
|
|
|
#endif
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2021-08-26 21:20:21 -07:00
|
|
|
|
#include <vector>
|
|
|
|
|
|
2022-01-12 01:17:35 -08:00
|
|
|
|
namespace dawn::native::metal {
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
namespace {
|
2019-09-17 21:32:52 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
struct PCIIDs {
|
|
|
|
|
uint32_t vendorId;
|
|
|
|
|
uint32_t deviceId;
|
|
|
|
|
};
|
2019-07-16 18:04:50 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
struct Vendor {
|
|
|
|
|
const char* trademark;
|
|
|
|
|
uint32_t vendorId;
|
|
|
|
|
};
|
2019-07-16 18:04:50 -07:00
|
|
|
|
|
2022-06-08 12:52:42 -07:00
|
|
|
|
#if DAWN_PLATFORM_IS(MACOS)
|
2022-06-09 17:05:32 -07:00
|
|
|
|
const Vendor kVendors[] = {
|
|
|
|
|
{"AMD", gpu_info::kVendorID_AMD}, {"Apple", gpu_info::kVendorID_Apple},
|
|
|
|
|
{"Radeon", gpu_info::kVendorID_AMD}, {"Intel", gpu_info::kVendorID_Intel},
|
|
|
|
|
{"Geforce", gpu_info::kVendorID_Nvidia}, {"Quadro", gpu_info::kVendorID_Nvidia}};
|
2022-05-01 07:40:55 -07:00
|
|
|
|
|
|
|
|
|
// Find vendor ID from MTLDevice name.
|
|
|
|
|
MaybeError GetVendorIdFromVendors(id<MTLDevice> device, PCIIDs* ids) {
|
|
|
|
|
uint32_t vendorId = 0;
|
|
|
|
|
const char* deviceName = [device.name UTF8String];
|
|
|
|
|
for (const auto& it : kVendors) {
|
|
|
|
|
if (strstr(deviceName, it.trademark) != nullptr) {
|
|
|
|
|
vendorId = it.vendorId;
|
|
|
|
|
break;
|
2019-02-05 05:02:30 -08:00
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if (vendorId == 0) {
|
|
|
|
|
return DAWN_INTERNAL_ERROR("Failed to find vendor id with the device");
|
|
|
|
|
}
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// Set vendor id with 0
|
|
|
|
|
*ids = PCIIDs{vendorId, 0};
|
|
|
|
|
return {};
|
|
|
|
|
}
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// Extracts an integer property from a registry entry.
|
|
|
|
|
uint32_t GetEntryProperty(io_registry_entry_t entry, CFStringRef name) {
|
|
|
|
|
uint32_t value = 0;
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// Recursively search registry entry and its parents for property name
|
|
|
|
|
// The data should release with CFRelease
|
|
|
|
|
CFRef<CFDataRef> data = AcquireCFRef(static_cast<CFDataRef>(IORegistryEntrySearchCFProperty(
|
|
|
|
|
entry, kIOServicePlane, name, kCFAllocatorDefault,
|
|
|
|
|
kIORegistryIterateRecursively | kIORegistryIterateParents)));
|
2019-04-11 00:14:28 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if (data == nullptr) {
|
|
|
|
|
return value;
|
|
|
|
|
}
|
2019-07-16 18:04:50 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// CFDataGetBytePtr() is guaranteed to return a read-only pointer
|
|
|
|
|
value = *reinterpret_cast<const uint32_t*>(CFDataGetBytePtr(data.Get()));
|
|
|
|
|
return value;
|
|
|
|
|
}
|
2019-07-16 18:04:50 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// Queries the IO Registry to find the PCI device and vendor IDs of the MTLDevice.
|
|
|
|
|
// The registry entry correponding to [device registryID] doesn't contain the exact PCI ids
|
|
|
|
|
// because it corresponds to a driver. However its parent entry corresponds to the device
|
|
|
|
|
// itself and has uint32_t "device-id" and "registry-id" keys. For example on a dual-GPU
|
|
|
|
|
// MacBook Pro 2017 the IORegistry explorer shows the following tree (simplified here):
|
|
|
|
|
//
|
|
|
|
|
// - PCI0@0
|
|
|
|
|
// | - AppleACPIPCI
|
|
|
|
|
// | | - IGPU@2 (type IOPCIDevice)
|
|
|
|
|
// | | | - IntelAccelerator (type IOGraphicsAccelerator2)
|
|
|
|
|
// | | - PEG0@1
|
|
|
|
|
// | | | - IOPP
|
|
|
|
|
// | | | | - GFX0@0 (type IOPCIDevice)
|
|
|
|
|
// | | | | | - AMDRadeonX4000_AMDBaffinGraphicsAccelerator (type IOGraphicsAccelerator2)
|
|
|
|
|
//
|
|
|
|
|
// [device registryID] is the ID for one of the IOGraphicsAccelerator2 and we can see that
|
|
|
|
|
// their parent always is an IOPCIDevice that has properties for the device and vendor IDs.
|
|
|
|
|
MaybeError API_AVAILABLE(macos(10.13))
|
|
|
|
|
GetDeviceIORegistryPCIInfo(id<MTLDevice> device, PCIIDs* ids) {
|
|
|
|
|
// Get a matching dictionary for the IOGraphicsAccelerator2
|
|
|
|
|
CFRef<CFMutableDictionaryRef> matchingDict =
|
|
|
|
|
AcquireCFRef(IORegistryEntryIDMatching([device registryID]));
|
|
|
|
|
if (matchingDict == nullptr) {
|
|
|
|
|
return DAWN_INTERNAL_ERROR("Failed to create the matching dict for the device");
|
|
|
|
|
}
|
2019-07-16 18:04:50 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// IOServiceGetMatchingService will consume the reference on the matching dictionary,
|
|
|
|
|
// so we don't need to release the dictionary.
|
|
|
|
|
IORef<io_registry_entry_t> acceleratorEntry =
|
|
|
|
|
AcquireIORef(IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict.Detach()));
|
|
|
|
|
if (acceleratorEntry == IO_OBJECT_NULL) {
|
|
|
|
|
return DAWN_INTERNAL_ERROR("Failed to get the IO registry entry for the accelerator");
|
|
|
|
|
}
|
2019-07-16 18:04:50 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// Get the parent entry that will be the IOPCIDevice
|
|
|
|
|
IORef<io_registry_entry_t> deviceEntry;
|
|
|
|
|
if (IORegistryEntryGetParentEntry(acceleratorEntry.Get(), kIOServicePlane,
|
|
|
|
|
deviceEntry.InitializeInto()) != kIOReturnSuccess) {
|
|
|
|
|
return DAWN_INTERNAL_ERROR("Failed to get the IO registry entry for the device");
|
|
|
|
|
}
|
2019-07-16 18:04:50 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
ASSERT(deviceEntry != IO_OBJECT_NULL);
|
2019-07-16 18:04:50 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
uint32_t vendorId = GetEntryProperty(deviceEntry.Get(), CFSTR("vendor-id"));
|
|
|
|
|
uint32_t deviceId = GetEntryProperty(deviceEntry.Get(), CFSTR("device-id"));
|
2019-07-16 18:04:50 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
*ids = PCIIDs{vendorId, deviceId};
|
2019-07-16 18:04:50 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
return {};
|
|
|
|
|
}
|
2019-09-17 21:32:52 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
MaybeError GetDevicePCIInfo(id<MTLDevice> device, PCIIDs* ids) {
|
|
|
|
|
// [device registryID] is introduced on macOS 10.13+, otherwise workaround to get vendor
|
|
|
|
|
// id by vendor name on old macOS
|
|
|
|
|
if (@available(macos 10.13, *)) {
|
2022-06-09 17:05:32 -07:00
|
|
|
|
auto result = GetDeviceIORegistryPCIInfo(device, ids);
|
|
|
|
|
if (result.IsError()) {
|
|
|
|
|
dawn::WarningLog() << "GetDeviceIORegistryPCIInfo failed: "
|
|
|
|
|
<< result.AcquireError()->GetFormattedMessage();
|
|
|
|
|
} else if (ids->vendorId != 0) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
2022-06-09 17:05:32 -07:00
|
|
|
|
|
|
|
|
|
return GetVendorIdFromVendors(device, ids);
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-08 12:52:42 -07:00
|
|
|
|
#elif DAWN_PLATFORM_IS(IOS)
|
2022-08-08 10:42:41 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
MaybeError GetDevicePCIInfo(id<MTLDevice> device, PCIIDs* ids) {
|
|
|
|
|
DAWN_UNUSED(device);
|
|
|
|
|
*ids = PCIIDs{0, 0};
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-17 21:32:52 -07:00
|
|
|
|
#else
|
2022-05-01 07:40:55 -07:00
|
|
|
|
#error "Unsupported Apple platform."
|
2019-09-17 21:32:52 -07:00
|
|
|
|
#endif
|
2021-08-26 21:20:21 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
DAWN_NOINLINE 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This method has seen hard-to-debug crashes. See crbug.com/dawn/1102.
|
|
|
|
|
// For now, it is written defensively, with many potentially unnecessary guards until
|
|
|
|
|
// we narrow down the cause of the problem.
|
|
|
|
|
DAWN_NOINLINE bool IsGPUCounterSupported(id<MTLDevice> device,
|
|
|
|
|
MTLCommonCounterSet counterSetName,
|
|
|
|
|
std::vector<MTLCommonCounter> counterNames)
|
|
|
|
|
API_AVAILABLE(macos(10.15), ios(14.0)) {
|
|
|
|
|
NSPRef<id<MTLCounterSet>> counterSet = nil;
|
|
|
|
|
if (![device respondsToSelector:@selector(counterSets)]) {
|
|
|
|
|
dawn::ErrorLog() << "MTLDevice does not respond to selector: counterSets.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
NSArray<id<MTLCounterSet>>* counterSets = device.counterSets;
|
|
|
|
|
if (counterSets == nil) {
|
|
|
|
|
// On some systems, [device counterSets] may be null and not an empty array.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// MTLDevice’s counterSets property declares which counter sets it supports. Check
|
|
|
|
|
// whether it's available on the device before requesting a counter set.
|
|
|
|
|
// Note: Don't do for..in loop to avoid potentially crashy interaction with
|
|
|
|
|
// NSFastEnumeration.
|
|
|
|
|
for (NSUInteger i = 0; i < counterSets.count; ++i) {
|
|
|
|
|
id<MTLCounterSet> set = [counterSets objectAtIndex:i];
|
|
|
|
|
if ([set.name caseInsensitiveCompare:counterSetName] == NSOrderedSame) {
|
|
|
|
|
counterSet = set;
|
|
|
|
|
break;
|
2021-08-26 21:20:21 -07:00
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
2021-08-26 21:20:21 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// The counter set is not supported.
|
|
|
|
|
if (counterSet == nil) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-02-15 10:18:26 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if (![*counterSet respondsToSelector:@selector(counters)]) {
|
|
|
|
|
dawn::ErrorLog() << "MTLCounterSet does not respond to selector: counters.";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
NSArray<id<MTLCounter>>* countersInSet = (*counterSet).counters;
|
|
|
|
|
if (countersInSet == nil) {
|
|
|
|
|
// On some systems, [MTLCounterSet counters] may be null and not an empty array.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2021-08-26 21:20:21 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// 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.
|
|
|
|
|
for (MTLCommonCounter counterName : counterNames) {
|
|
|
|
|
bool found = false;
|
|
|
|
|
// Note: Don't do for..in loop to avoid potentially crashy interaction with
|
|
|
|
|
// NSFastEnumeration.
|
|
|
|
|
for (NSUInteger i = 0; i < countersInSet.count; ++i) {
|
|
|
|
|
id<MTLCounter> counter = [countersInSet objectAtIndex:i];
|
|
|
|
|
if ([counter.name caseInsensitiveCompare:counterName] == NSOrderedSame) {
|
|
|
|
|
found = true;
|
|
|
|
|
break;
|
2021-08-26 21:20:21 -07:00
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
|
|
|
|
if (!found) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-26 21:20:21 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
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;
|
2021-08-26 21:20:21 -07:00
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
2021-08-26 21:20:21 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
} // anonymous namespace
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// The Metal backend's Adapter.
|
2019-07-16 18:04:50 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
class Adapter : public AdapterBase {
|
|
|
|
|
public:
|
|
|
|
|
Adapter(InstanceBase* instance, id<MTLDevice> device)
|
|
|
|
|
: AdapterBase(instance, wgpu::BackendType::Metal), mDevice(device) {
|
|
|
|
|
mName = std::string([[*mDevice name] UTF8String]);
|
|
|
|
|
|
|
|
|
|
PCIIDs ids;
|
|
|
|
|
if (!instance->ConsumedError(GetDevicePCIInfo(device, &ids))) {
|
|
|
|
|
mVendorId = ids.vendorId;
|
|
|
|
|
mDeviceId = ids.deviceId;
|
|
|
|
|
}
|
2019-04-15 09:36:25 -07:00
|
|
|
|
|
2022-06-08 12:52:42 -07:00
|
|
|
|
#if DAWN_PLATFORM_IS(IOS)
|
2022-05-01 07:40:55 -07:00
|
|
|
|
mAdapterType = wgpu::AdapterType::IntegratedGPU;
|
|
|
|
|
const char* systemName = "iOS ";
|
2022-06-08 12:52:42 -07:00
|
|
|
|
#elif DAWN_PLATFORM_IS(MACOS)
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if ([device isLowPower]) {
|
|
|
|
|
mAdapterType = wgpu::AdapterType::IntegratedGPU;
|
|
|
|
|
} else {
|
|
|
|
|
mAdapterType = wgpu::AdapterType::DiscreteGPU;
|
|
|
|
|
}
|
|
|
|
|
const char* systemName = "macOS ";
|
2019-10-08 00:44:21 -07:00
|
|
|
|
#else
|
2022-05-01 07:40:55 -07:00
|
|
|
|
#error "Unsupported Apple platform."
|
2019-10-08 00:44:21 -07:00
|
|
|
|
#endif
|
2019-08-26 17:04:29 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
NSString* osVersion = [[NSProcessInfo processInfo] operatingSystemVersionString];
|
|
|
|
|
mDriverDescription = "Metal driver on " + std::string(systemName) + [osVersion UTF8String];
|
|
|
|
|
}
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// AdapterBase Implementation
|
|
|
|
|
bool SupportsExternalImages() const override {
|
|
|
|
|
// Via dawn::native::metal::WrapIOSurface
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2021-08-11 07:27:55 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
private:
|
|
|
|
|
ResultOrError<Ref<DeviceBase>> CreateDeviceImpl(const DeviceDescriptor* descriptor) override {
|
|
|
|
|
return Device::Create(this, mDevice, descriptor);
|
|
|
|
|
}
|
2020-04-07 08:10:17 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
MaybeError InitializeImpl() override { return {}; }
|
2021-10-19 15:52:14 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
MaybeError InitializeSupportedFeaturesImpl() override {
|
|
|
|
|
// Check compressed texture format with deprecated MTLFeatureSet way.
|
2022-06-08 12:52:42 -07:00
|
|
|
|
#if DAWN_PLATFORM_IS(MACOS)
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if ([*mDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) {
|
|
|
|
|
mSupportedFeatures.EnableFeature(Feature::TextureCompressionBC);
|
|
|
|
|
}
|
2020-09-25 01:49:30 -07:00
|
|
|
|
#endif
|
2022-06-08 12:52:42 -07:00
|
|
|
|
#if DAWN_PLATFORM_IS(IOS)
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if ([*mDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v1]) {
|
|
|
|
|
mSupportedFeatures.EnableFeature(Feature::TextureCompressionETC2);
|
|
|
|
|
}
|
|
|
|
|
if ([*mDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v1]) {
|
|
|
|
|
mSupportedFeatures.EnableFeature(Feature::TextureCompressionASTC);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Check compressed texture format with MTLGPUFamily
|
|
|
|
|
if (@available(macOS 10.15, iOS 13.0, *)) {
|
|
|
|
|
if ([*mDevice supportsFamily:MTLGPUFamilyMac1]) {
|
|
|
|
|
mSupportedFeatures.EnableFeature(Feature::TextureCompressionBC);
|
|
|
|
|
}
|
|
|
|
|
if ([*mDevice supportsFamily:MTLGPUFamilyApple2]) {
|
2022-03-29 00:58:23 -07:00
|
|
|
|
mSupportedFeatures.EnableFeature(Feature::TextureCompressionETC2);
|
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if ([*mDevice supportsFamily:MTLGPUFamilyApple3]) {
|
2022-03-29 00:58:23 -07:00
|
|
|
|
mSupportedFeatures.EnableFeature(Feature::TextureCompressionASTC);
|
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
2022-03-29 00:58:23 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if (@available(macOS 10.15, iOS 14.0, *)) {
|
|
|
|
|
if (IsGPUCounterSupported(
|
|
|
|
|
*mDevice, MTLCommonCounterSetStatistic,
|
|
|
|
|
{MTLCommonCounterVertexInvocations, MTLCommonCounterClipperInvocations,
|
|
|
|
|
MTLCommonCounterClipperPrimitivesOut, MTLCommonCounterFragmentInvocations,
|
|
|
|
|
MTLCommonCounterComputeKernelInvocations})) {
|
|
|
|
|
mSupportedFeatures.EnableFeature(Feature::PipelineStatisticsQuery);
|
2022-03-29 00:58:23 -07:00
|
|
|
|
}
|
2020-05-26 22:15:18 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if (IsGPUCounterSupported(*mDevice, MTLCommonCounterSetTimestamp,
|
|
|
|
|
{MTLCommonCounterTimestamp})) {
|
|
|
|
|
bool enableTimestampQuery = true;
|
2021-10-11 06:50:29 -07:00
|
|
|
|
|
2022-06-08 12:52:42 -07:00
|
|
|
|
#if DAWN_PLATFORM_IS(MACOS)
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// Disable timestamp query on < macOS 11.0 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.
|
|
|
|
|
if (gpu_info::IsAMD(mVendorId) && !IsMacOSVersionAtLeast(11)) {
|
|
|
|
|
enableTimestampQuery = false;
|
|
|
|
|
}
|
2021-08-05 13:35:19 -07:00
|
|
|
|
#endif
|
2021-10-11 06:50:29 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if (enableTimestampQuery) {
|
|
|
|
|
mSupportedFeatures.EnableFeature(Feature::TimestampQuery);
|
2020-09-25 01:49:30 -07:00
|
|
|
|
}
|
2020-05-26 22:15:18 -07:00
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
2021-08-26 21:20:21 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if (@available(macOS 10.11, iOS 11.0, *)) {
|
2022-07-18 13:38:05 -07:00
|
|
|
|
mSupportedFeatures.EnableFeature(Feature::DepthClipControl);
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
2021-10-19 15:52:14 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if (@available(macOS 10.11, iOS 9.0, *)) {
|
|
|
|
|
mSupportedFeatures.EnableFeature(Feature::Depth32FloatStencil8);
|
|
|
|
|
}
|
2022-01-04 17:31:16 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// Uses newTextureWithDescriptor::iosurface::plane which is available
|
|
|
|
|
// on ios 11.0+ and macOS 11.0+
|
|
|
|
|
if (@available(macOS 10.11, iOS 11.0, *)) {
|
|
|
|
|
mSupportedFeatures.EnableFeature(Feature::MultiPlanarFormats);
|
|
|
|
|
}
|
2022-03-27 23:59:22 -07:00
|
|
|
|
|
2022-05-31 23:14:07 -07:00
|
|
|
|
mSupportedFeatures.EnableFeature(Feature::IndirectFirstInstance);
|
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
return {};
|
|
|
|
|
}
|
2021-10-19 15:52:14 -07:00
|
|
|
|
|
2022-06-09 17:05:32 -07:00
|
|
|
|
void InitializeVendorArchitectureImpl() override {
|
|
|
|
|
if (@available(macOS 10.15, iOS 13.0, *)) {
|
|
|
|
|
// According to Apple's documentation:
|
|
|
|
|
// https://developer.apple.com/documentation/metal/gpu_devices_and_work_submission/detecting_gpu_features_and_metal_software_versions
|
|
|
|
|
// - "Use the Common family to create apps that target a range of GPUs on multiple
|
|
|
|
|
// platforms.""
|
|
|
|
|
// - "A GPU can be a member of more than one family; in most cases, a GPU supports one
|
|
|
|
|
// of the Common families and then one or more families specific to the build target."
|
|
|
|
|
// So we'll use the highest supported common family as the reported "architecture" on
|
|
|
|
|
// devices where a deviceID isn't available.
|
|
|
|
|
if (mDeviceId == 0) {
|
|
|
|
|
if ([*mDevice supportsFamily:MTLGPUFamilyCommon3]) {
|
|
|
|
|
mArchitectureName = "common-3";
|
|
|
|
|
} else if ([*mDevice supportsFamily:MTLGPUFamilyCommon2]) {
|
|
|
|
|
mArchitectureName = "common-2";
|
|
|
|
|
} else if ([*mDevice supportsFamily:MTLGPUFamilyCommon1]) {
|
|
|
|
|
mArchitectureName = "common-1";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mVendorName = gpu_info::GetVendorName(mVendorId);
|
|
|
|
|
if (mDeviceId != 0) {
|
|
|
|
|
mArchitectureName = gpu_info::GetArchitectureName(mVendorId, mDeviceId);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
enum class MTLGPUFamily {
|
|
|
|
|
Apple1,
|
|
|
|
|
Apple2,
|
|
|
|
|
Apple3,
|
|
|
|
|
Apple4,
|
|
|
|
|
Apple5,
|
|
|
|
|
Apple6,
|
|
|
|
|
Apple7,
|
|
|
|
|
Mac1,
|
|
|
|
|
Mac2,
|
|
|
|
|
};
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
ResultOrError<MTLGPUFamily> GetMTLGPUFamily() const {
|
|
|
|
|
// https://developer.apple.com/documentation/metal/mtldevice/detecting_gpu_features_and_metal_software_versions?language=objc
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if (@available(macOS 10.15, iOS 10.13, *)) {
|
|
|
|
|
if ([*mDevice supportsFamily:MTLGPUFamilyMac2]) {
|
|
|
|
|
return MTLGPUFamily::Mac2;
|
|
|
|
|
}
|
|
|
|
|
if ([*mDevice supportsFamily:MTLGPUFamilyMac1]) {
|
|
|
|
|
return MTLGPUFamily::Mac1;
|
|
|
|
|
}
|
|
|
|
|
if ([*mDevice supportsFamily:MTLGPUFamilyApple7]) {
|
|
|
|
|
return MTLGPUFamily::Apple7;
|
|
|
|
|
}
|
|
|
|
|
if ([*mDevice supportsFamily:MTLGPUFamilyApple6]) {
|
|
|
|
|
return MTLGPUFamily::Apple6;
|
|
|
|
|
}
|
|
|
|
|
if ([*mDevice supportsFamily:MTLGPUFamilyApple5]) {
|
|
|
|
|
return MTLGPUFamily::Apple5;
|
|
|
|
|
}
|
|
|
|
|
if ([*mDevice supportsFamily:MTLGPUFamilyApple4]) {
|
|
|
|
|
return MTLGPUFamily::Apple4;
|
|
|
|
|
}
|
|
|
|
|
if ([*mDevice supportsFamily:MTLGPUFamilyApple3]) {
|
|
|
|
|
return MTLGPUFamily::Apple3;
|
2021-10-26 09:56:36 -07:00
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if ([*mDevice supportsFamily:MTLGPUFamilyApple2]) {
|
|
|
|
|
return MTLGPUFamily::Apple2;
|
|
|
|
|
}
|
|
|
|
|
if ([*mDevice supportsFamily:MTLGPUFamilyApple1]) {
|
|
|
|
|
return MTLGPUFamily::Apple1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
|
|
|
|
#if TARGET_OS_OSX
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if (@available(macOS 10.14, *)) {
|
|
|
|
|
if ([*mDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily2_v1]) {
|
|
|
|
|
return MTLGPUFamily::Mac2;
|
2021-10-26 09:56:36 -07:00
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
2022-08-08 10:42:41 -07:00
|
|
|
|
if ([*mDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) {
|
|
|
|
|
return MTLGPUFamily::Mac1;
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
2021-10-26 09:56:36 -07:00
|
|
|
|
#elif TARGET_OS_IOS
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if (@available(iOS 10.11, *)) {
|
|
|
|
|
if ([*mDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily4_v1]) {
|
|
|
|
|
return MTLGPUFamily::Apple4;
|
2021-10-26 09:56:36 -07:00
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
|
|
|
|
if (@available(iOS 9.0, *)) {
|
|
|
|
|
if ([*mDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1]) {
|
|
|
|
|
return MTLGPUFamily::Apple3;
|
2021-10-26 09:56:36 -07:00
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
|
|
|
|
if (@available(iOS 8.0, *)) {
|
|
|
|
|
if ([*mDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily2_v1]) {
|
|
|
|
|
return MTLGPUFamily::Apple2;
|
2021-10-26 09:56:36 -07:00
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
|
|
|
|
if (@available(iOS 8.0, *)) {
|
|
|
|
|
if ([*mDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily1_v1]) {
|
|
|
|
|
return MTLGPUFamily::Apple1;
|
2021-10-26 09:56:36 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
#endif
|
|
|
|
|
return DAWN_INTERNAL_ERROR("Unsupported Metal device");
|
|
|
|
|
}
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
MaybeError InitializeSupportedLimitsImpl(CombinedLimits* limits) override {
|
|
|
|
|
struct MTLDeviceLimits {
|
|
|
|
|
uint32_t maxVertexAttribsPerDescriptor;
|
|
|
|
|
uint32_t maxBufferArgumentEntriesPerFunc;
|
|
|
|
|
uint32_t maxTextureArgumentEntriesPerFunc;
|
|
|
|
|
uint32_t maxSamplerStateArgumentEntriesPerFunc;
|
|
|
|
|
uint32_t maxThreadsPerThreadgroup;
|
|
|
|
|
uint32_t maxTotalThreadgroupMemory;
|
|
|
|
|
uint32_t maxFragmentInputComponents;
|
|
|
|
|
uint32_t max1DTextureSize;
|
|
|
|
|
uint32_t max2DTextureSize;
|
|
|
|
|
uint32_t max3DTextureSize;
|
|
|
|
|
uint32_t maxTextureArrayLayers;
|
|
|
|
|
uint32_t minBufferOffsetAlignment;
|
2022-06-13 09:48:45 -07:00
|
|
|
|
uint32_t maxColorRenderTargets;
|
2022-05-01 07:40:55 -07:00
|
|
|
|
};
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
struct LimitsForFamily {
|
|
|
|
|
uint32_t MTLDeviceLimits::*limit;
|
|
|
|
|
ityp::array<MTLGPUFamily, uint32_t, 9> values;
|
|
|
|
|
};
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// clang-format off
|
2021-10-26 09:56:36 -07:00
|
|
|
|
// https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf
|
|
|
|
|
// Apple Mac
|
|
|
|
|
// 1, 2, 3, 4, 5, 6, 7, 1, 2
|
2022-06-13 09:48:45 -07:00
|
|
|
|
constexpr LimitsForFamily kMTLLimits[13] = {
|
2021-10-26 09:56:36 -07:00
|
|
|
|
{&MTLDeviceLimits::maxVertexAttribsPerDescriptor, { 31u, 31u, 31u, 31u, 31u, 31u, 31u, 31u, 31u }},
|
|
|
|
|
{&MTLDeviceLimits::maxBufferArgumentEntriesPerFunc, { 31u, 31u, 31u, 31u, 31u, 31u, 31u, 31u, 31u }},
|
|
|
|
|
{&MTLDeviceLimits::maxTextureArgumentEntriesPerFunc, { 31u, 31u, 31u, 96u, 96u, 128u, 128u, 128u, 128u }},
|
|
|
|
|
{&MTLDeviceLimits::maxSamplerStateArgumentEntriesPerFunc, { 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u }},
|
|
|
|
|
{&MTLDeviceLimits::maxThreadsPerThreadgroup, { 512u, 512u, 512u, 1024u, 1024u, 1024u, 1024u, 1024u, 1024u }},
|
|
|
|
|
{&MTLDeviceLimits::maxTotalThreadgroupMemory, { 16352u, 16352u, 16384u, 32768u, 32768u, 32768u, 32768u, 32768u, 32768u }},
|
|
|
|
|
{&MTLDeviceLimits::maxFragmentInputComponents, { 60u, 60u, 60u, 124u, 124u, 124u, 124u, 124u, 124u }},
|
|
|
|
|
{&MTLDeviceLimits::max1DTextureSize, { 8192u, 8192u, 16384u, 16384u, 16384u, 16384u, 16384u, 16384u, 16384u }},
|
|
|
|
|
{&MTLDeviceLimits::max2DTextureSize, { 8192u, 8192u, 16384u, 16384u, 16384u, 16384u, 16384u, 16384u, 16384u }},
|
|
|
|
|
{&MTLDeviceLimits::max3DTextureSize, { 2048u, 2048u, 2048u, 2048u, 2048u, 2048u, 2048u, 2048u, 2048u }},
|
|
|
|
|
{&MTLDeviceLimits::maxTextureArrayLayers, { 2048u, 2048u, 2048u, 2048u, 2048u, 2048u, 2048u, 2048u, 2048u }},
|
|
|
|
|
{&MTLDeviceLimits::minBufferOffsetAlignment, { 4u, 4u, 4u, 4u, 4u, 4u, 4u, 256u, 256u }},
|
2022-06-13 09:48:45 -07:00
|
|
|
|
{&MTLDeviceLimits::maxColorRenderTargets, { 4u, 8u, 8u, 8u, 8u, 8u, 8u, 8u, 8u }},
|
2021-10-26 09:56:36 -07:00
|
|
|
|
};
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// clang-format on
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
MTLGPUFamily mtlGPUFamily;
|
|
|
|
|
DAWN_TRY_ASSIGN(mtlGPUFamily, GetMTLGPUFamily());
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
MTLDeviceLimits mtlLimits;
|
|
|
|
|
for (const auto& limitsForFamily : kMTLLimits) {
|
|
|
|
|
mtlLimits.*limitsForFamily.limit = limitsForFamily.values[mtlGPUFamily];
|
|
|
|
|
}
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
GetDefaultLimits(&limits->v1);
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
limits->v1.maxTextureDimension1D = mtlLimits.max1DTextureSize;
|
|
|
|
|
limits->v1.maxTextureDimension2D = mtlLimits.max2DTextureSize;
|
|
|
|
|
limits->v1.maxTextureDimension3D = mtlLimits.max3DTextureSize;
|
|
|
|
|
limits->v1.maxTextureArrayLayers = mtlLimits.maxTextureArrayLayers;
|
2022-06-13 09:48:45 -07:00
|
|
|
|
limits->v1.maxColorAttachments = mtlLimits.maxColorRenderTargets;
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
uint32_t maxBuffersPerStage = mtlLimits.maxBufferArgumentEntriesPerFunc;
|
|
|
|
|
maxBuffersPerStage -= 1; // One slot is reserved to store buffer lengths.
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
uint32_t baseMaxBuffersPerStage = limits->v1.maxStorageBuffersPerShaderStage +
|
|
|
|
|
limits->v1.maxUniformBuffersPerShaderStage +
|
|
|
|
|
limits->v1.maxVertexBuffers;
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
ASSERT(maxBuffersPerStage >= baseMaxBuffersPerStage);
|
|
|
|
|
{
|
|
|
|
|
uint32_t additional = maxBuffersPerStage - baseMaxBuffersPerStage;
|
|
|
|
|
limits->v1.maxStorageBuffersPerShaderStage += additional / 3;
|
|
|
|
|
limits->v1.maxUniformBuffersPerShaderStage += additional / 3;
|
|
|
|
|
limits->v1.maxVertexBuffers += (additional - 2 * (additional / 3));
|
|
|
|
|
}
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
uint32_t baseMaxTexturesPerStage = limits->v1.maxSampledTexturesPerShaderStage +
|
|
|
|
|
limits->v1.maxStorageTexturesPerShaderStage;
|
2021-10-26 09:56:36 -07:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
ASSERT(mtlLimits.maxTextureArgumentEntriesPerFunc >= baseMaxTexturesPerStage);
|
|
|
|
|
{
|
|
|
|
|
uint32_t additional =
|
|
|
|
|
mtlLimits.maxTextureArgumentEntriesPerFunc - baseMaxTexturesPerStage;
|
|
|
|
|
limits->v1.maxSampledTexturesPerShaderStage += additional / 2;
|
|
|
|
|
limits->v1.maxStorageTexturesPerShaderStage += (additional - additional / 2);
|
2019-08-01 17:06:38 -07:00
|
|
|
|
}
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
limits->v1.maxSamplersPerShaderStage = mtlLimits.maxSamplerStateArgumentEntriesPerFunc;
|
|
|
|
|
|
|
|
|
|
// Metal limits are per-function, so the layout limits are the same as the stage
|
|
|
|
|
// limits. Note: this should likely change if the implementation uses Metal argument
|
|
|
|
|
// buffers. Non-dynamic buffers will probably be bound argument buffers, but dynamic
|
|
|
|
|
// buffers may be set directly.
|
|
|
|
|
// Mac GPU families with tier 1 argument buffers support 64
|
|
|
|
|
// buffers, 128 textures, and 16 samplers. Mac GPU families
|
|
|
|
|
// with tier 2 argument buffers support 500000 buffers and
|
|
|
|
|
// textures, and 1024 unique samplers
|
|
|
|
|
limits->v1.maxDynamicUniformBuffersPerPipelineLayout =
|
|
|
|
|
limits->v1.maxUniformBuffersPerShaderStage;
|
|
|
|
|
limits->v1.maxDynamicStorageBuffersPerPipelineLayout =
|
|
|
|
|
limits->v1.maxStorageBuffersPerShaderStage;
|
|
|
|
|
|
|
|
|
|
// The WebGPU limit is the limit across all vertex buffers, combined.
|
|
|
|
|
limits->v1.maxVertexAttributes =
|
|
|
|
|
limits->v1.maxVertexBuffers * mtlLimits.maxVertexAttribsPerDescriptor;
|
|
|
|
|
|
|
|
|
|
limits->v1.maxInterStageShaderComponents = mtlLimits.maxFragmentInputComponents;
|
|
|
|
|
|
|
|
|
|
limits->v1.maxComputeWorkgroupStorageSize = mtlLimits.maxTotalThreadgroupMemory;
|
|
|
|
|
limits->v1.maxComputeInvocationsPerWorkgroup = mtlLimits.maxThreadsPerThreadgroup;
|
|
|
|
|
limits->v1.maxComputeWorkgroupSizeX = mtlLimits.maxThreadsPerThreadgroup;
|
|
|
|
|
limits->v1.maxComputeWorkgroupSizeY = mtlLimits.maxThreadsPerThreadgroup;
|
|
|
|
|
limits->v1.maxComputeWorkgroupSizeZ = mtlLimits.maxThreadsPerThreadgroup;
|
|
|
|
|
|
|
|
|
|
limits->v1.minUniformBufferOffsetAlignment = mtlLimits.minBufferOffsetAlignment;
|
|
|
|
|
limits->v1.minStorageBufferOffsetAlignment = mtlLimits.minBufferOffsetAlignment;
|
|
|
|
|
|
|
|
|
|
uint64_t maxBufferSize = Buffer::QueryMaxBufferLength(*mDevice);
|
|
|
|
|
|
|
|
|
|
// Metal has no documented limit on the size of a binding. Use the maximum
|
|
|
|
|
// buffer size.
|
|
|
|
|
limits->v1.maxUniformBufferBindingSize = maxBufferSize;
|
|
|
|
|
limits->v1.maxStorageBufferBindingSize = maxBufferSize;
|
|
|
|
|
|
2022-06-13 09:48:45 -07:00
|
|
|
|
// Using base limits for:
|
2022-06-24 10:30:29 -07:00
|
|
|
|
// TODO(crbug.com/dawn/685):
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// - maxBindGroups
|
|
|
|
|
// - maxVertexBufferArrayStride
|
|
|
|
|
|
2022-06-24 10:30:29 -07:00
|
|
|
|
// TODO(crbug.com/dawn/1448):
|
|
|
|
|
// - maxInterStageShaderVariables
|
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
return {};
|
|
|
|
|
}
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
NSPRef<id<MTLDevice>> mDevice;
|
|
|
|
|
};
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
// Implementation of the Metal backend's BackendConnection
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
Backend::Backend(InstanceBase* instance) : BackendConnection(instance, wgpu::BackendType::Metal) {
|
|
|
|
|
if (GetInstance()->IsBackendValidationEnabled()) {
|
|
|
|
|
setenv("METAL_DEVICE_WRAPPER_TYPE", "1", 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-09 15:22:18 -07:00
|
|
|
|
Backend::~Backend() = default;
|
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
std::vector<Ref<AdapterBase>> Backend::DiscoverDefaultAdapters() {
|
|
|
|
|
AdapterDiscoveryOptions options;
|
|
|
|
|
auto result = DiscoverAdapters(&options);
|
|
|
|
|
if (result.IsError()) {
|
|
|
|
|
GetInstance()->ConsumedError(result.AcquireError());
|
|
|
|
|
return {};
|
2021-12-06 12:58:56 -08:00
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
return result.AcquireSuccess();
|
|
|
|
|
}
|
2021-12-06 12:58:56 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
ResultOrError<std::vector<Ref<AdapterBase>>> Backend::DiscoverAdapters(
|
|
|
|
|
const AdapterDiscoveryOptionsBase* optionsBase) {
|
|
|
|
|
ASSERT(optionsBase->backendType == WGPUBackendType_Metal);
|
2021-12-06 12:58:56 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
std::vector<Ref<AdapterBase>> adapters;
|
2022-06-08 12:52:42 -07:00
|
|
|
|
#if DAWN_PLATFORM_IS(MACOS)
|
2022-08-08 10:42:41 -07:00
|
|
|
|
NSRef<NSArray<id<MTLDevice>>> devices = AcquireNSRef(MTLCopyAllDevices());
|
2019-12-17 16:08:16 -08:00
|
|
|
|
|
2022-08-08 10:42:41 -07:00
|
|
|
|
for (id<MTLDevice> device in devices.Get()) {
|
|
|
|
|
Ref<Adapter> adapter = AcquireRef(new Adapter(GetInstance(), device));
|
2022-05-01 07:40:55 -07:00
|
|
|
|
if (!GetInstance()->ConsumedError(adapter->Initialize())) {
|
|
|
|
|
adapters.push_back(std::move(adapter));
|
2019-12-17 16:08:16 -08:00
|
|
|
|
}
|
2022-05-01 07:40:55 -07:00
|
|
|
|
}
|
2019-10-08 00:44:21 -07:00
|
|
|
|
#endif
|
2022-08-08 10:42:41 -07:00
|
|
|
|
|
|
|
|
|
// iOS only has a single device so MTLCopyAllDevices doesn't exist there.
|
|
|
|
|
#if defined(DAWN_PLATFORM_IOS)
|
|
|
|
|
Ref<Adapter> adapter =
|
|
|
|
|
AcquireRef(new Adapter(GetInstance(), MTLCreateSystemDefaultDevice()));
|
|
|
|
|
if (!GetInstance()->ConsumedError(adapter->Initialize())) {
|
|
|
|
|
adapters.push_back(std::move(adapter));
|
2019-02-05 05:02:30 -08:00
|
|
|
|
}
|
2022-08-08 10:42:41 -07:00
|
|
|
|
#endif
|
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
return adapters;
|
|
|
|
|
}
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-05-01 07:40:55 -07:00
|
|
|
|
BackendConnection* Connect(InstanceBase* instance) {
|
|
|
|
|
return new Backend(instance);
|
|
|
|
|
}
|
2019-02-05 05:02:30 -08:00
|
|
|
|
|
2022-01-12 01:17:35 -08:00
|
|
|
|
} // namespace dawn::native::metal
|