On Apple Silicon, set VkPhysicalDeviceProperties::deviceID from GPU capabilities.

Previously, on Apple Silicon (iOS, tvOS & macOS M1), we tried to guess
deviceID from GPU parameters, but this is becoming harder as the types
of Apple Silicon is growing, and the actual device SoC itself is less
relevant that the GPU capabilities. So we now set deviceID from the
combination of OS version and GPU type.

Rename MVKDevice::getHighestMTLFeatureSet() to getHighestGPUCapability().
This commit is contained in:
Bill Hollings 2021-12-27 16:45:12 -05:00
parent 939d51da71
commit df043487e4
3 changed files with 47 additions and 99 deletions

View File

@ -20,6 +20,7 @@ Released TBD
- Support building MoltenVK with static Vulkan linkage symbols hidden. - Support building MoltenVK with static Vulkan linkage symbols hidden.
- Do not use `MTLEvent` for `VkSemaphore` under *Rosetta2*. - Do not use `MTLEvent` for `VkSemaphore` under *Rosetta2*.
- On *Apple Silicon (iOS, tvOS & macOS)*, set `VkPhysicalDeviceProperties::deviceID` from GPU capabilities.
- Support compiling *MSL 2.4* in runtime pipelines and `MoltenVKShaderConverterTool`. - Support compiling *MSL 2.4* in runtime pipelines and `MoltenVKShaderConverterTool`.
- Fix issue where *MSL 2.3* only available on *Apple Silicon*, even on *macOS*. - Fix issue where *MSL 2.3* only available on *Apple Silicon*, even on *macOS*.
- Fix memory leak of dummy `MTLTexture` in render subpasses that use no attachments. - Fix memory leak of dummy `MTLTexture` in render subpasses that use no attachments.

View File

@ -374,7 +374,7 @@ protected:
void initCounterSets(); void initCounterSets();
MVKArrayRef<MVKQueueFamily*> getQueueFamilies(); MVKArrayRef<MVKQueueFamily*> getQueueFamilies();
void initPipelineCacheUUID(); void initPipelineCacheUUID();
uint32_t getHighestMTLFeatureSet(); uint32_t getHighestGPUCapability();
uint32_t getMoltenVKGitRevision(); uint32_t getMoltenVKGitRevision();
void populate(VkPhysicalDeviceIDProperties* pDevIdProps); void populate(VkPhysicalDeviceIDProperties* pDevIdProps);
void logGPUInfo(); void logGPUInfo();

View File

@ -37,6 +37,8 @@
#import "CAMetalLayer+MoltenVK.h" #import "CAMetalLayer+MoltenVK.h"
#include <cmath>
using namespace std; using namespace std;
@ -504,11 +506,10 @@ void MVKPhysicalDevice::populate(VkPhysicalDeviceIDProperties* pDevIdProps) {
*(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(mvkVersion); *(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(mvkVersion);
uuidComponentOffset += sizeof(mvkVersion); uuidComponentOffset += sizeof(mvkVersion);
// Next 4 bytes contains highest Metal feature set supported by this device // Next 4 bytes contains highest GPU capability supported by this device
uint32_t mtlFeatSet = getHighestMTLFeatureSet(); uint32_t gpuCap = getHighestGPUCapability();
*(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(mtlFeatSet); *(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(gpuCap);
uuidComponentOffset += sizeof(mtlFeatSet); uuidComponentOffset += sizeof(gpuCap);
// ---- LUID ignored for Metal devices ------------------------ // ---- LUID ignored for Metal devices ------------------------
mvkClear(pDevIdProps->deviceLUID, VK_LUID_SIZE); mvkClear(pDevIdProps->deviceLUID, VK_LUID_SIZE);
@ -2209,31 +2210,23 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope
void MVKPhysicalDevice::initGPUInfoProperties() { void MVKPhysicalDevice::initGPUInfoProperties() {
bool isFound = false;
bool isIntegrated = getHasUnifiedMemory(); bool isIntegrated = getHasUnifiedMemory();
_properties.deviceType = isIntegrated ? VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU : VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU; _properties.deviceType = isIntegrated ? VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU : VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU;
strlcpy(_properties.deviceName, _mtlDevice.name.UTF8String, VK_MAX_PHYSICAL_DEVICE_NAME_SIZE); strlcpy(_properties.deviceName, _mtlDevice.name.UTF8String, VK_MAX_PHYSICAL_DEVICE_NAME_SIZE);
if (supportsMTLGPUFamily(Apple5)) { // For Apple Silicon, the Device ID is determined by the highest
// This is an Apple GPU. It won't have a 'device-id' property, so fill it in like on iOS/tvOS. // GPU capability, which is a combination of OS version and GPU type.
// Test for Apple5 first instead of Apple7 to support Xcode 11.7 builds. // We determine Apple Silicon directly from the GPU, instead
// of from the build, in case we are running Rosetta2.
if (supportsMTLGPUFamily(Apple1)) {
_properties.vendorID = kAppleVendorId; _properties.vendorID = kAppleVendorId;
#if MVK_XCODE_12 _properties.deviceID = getHighestGPUCapability();
if (supportsMTLGPUFamily(Apple7)) {
_properties.deviceID = 0xa140;
} else if (supportsMTLGPUFamily(Apple6)) {
_properties.deviceID = 0xa130;
} else
#endif
{
_properties.deviceID = 0xa120;
}
return; return;
} }
// If the device has an associated registry ID, we can use that to get the associated IOKit node. // If the device has an associated registry ID, we can use that to get the associated IOKit node.
// The match dictionary is consumed by IOServiceGetMatchingServices and does not need to be released. // The match dictionary is consumed by IOServiceGetMatchingServices and does not need to be released.
bool isFound = false;
io_registry_entry_t entry; io_registry_entry_t entry;
uint64_t regID = mvkGetRegistryID(_mtlDevice); uint64_t regID = mvkGetRegistryID(_mtlDevice);
if (regID) { if (regID) {
@ -2275,58 +2268,16 @@ void MVKPhysicalDevice::initGPUInfoProperties() {
#endif //MVK_MACOS #endif //MVK_MACOS
#if MVK_IOS #if MVK_IOS_OR_TVOS
// For Apple Silicon, the Device ID is determined by the highest
// For iOS devices, the Device ID is the SoC model (A8, A10X...), in the hex form 0xaMMX, where // GPU capability, which is a combination of OS version and GPU type.
//"a" is the Apple brand, MM is the SoC model number (8, 10...) and X is 1 for X version, 0 for other.
void MVKPhysicalDevice::initGPUInfoProperties() { void MVKPhysicalDevice::initGPUInfoProperties() {
NSUInteger coreCnt = NSProcessInfo.processInfo.processorCount;
uint32_t devID = 0xa070;
#if MVK_XCODE_13
if (supportsMTLGPUFamily(Apple8)) {
devID = 0xa150;
} else
#endif
#if MVK_XCODE_12
if (supportsMTLGPUFamily(Apple7)) {
devID = 0xa140;
} else
#endif
if (supportsMTLGPUFamily(Apple6)) {
devID = 0xa130;
} else if (supportsMTLFeatureSet(iOS_GPUFamily5_v1)) {
devID = 0xa120;
} else if (supportsMTLFeatureSet(iOS_GPUFamily4_v1)) {
devID = 0xa110;
} else if (supportsMTLFeatureSet(iOS_GPUFamily3_v1)) {
devID = coreCnt > 2 ? 0xa101 : 0xa100;
} else if (supportsMTLFeatureSet(iOS_GPUFamily2_v1)) {
devID = coreCnt > 2 ? 0xa081 : 0xa080;
}
_properties.vendorID = kAppleVendorId; _properties.vendorID = kAppleVendorId;
_properties.deviceID = devID; _properties.deviceID = getHighestGPUCapability();
_properties.deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU; _properties.deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
strlcpy(_properties.deviceName, _mtlDevice.name.UTF8String, VK_MAX_PHYSICAL_DEVICE_NAME_SIZE); strlcpy(_properties.deviceName, _mtlDevice.name.UTF8String, VK_MAX_PHYSICAL_DEVICE_NAME_SIZE);
} }
#endif //MVK_IOS #endif //MVK_IOS_OR_TVOS
#if MVK_TVOS
// For tvOS devices, the Device ID is the SoC model (A8, A10X...), in the hex form 0xaMMX, where
//"a" is the Apple brand, MM is the SoC model number (8, 10...) and X is 1 for X version, 0 for other.
void MVKPhysicalDevice::initGPUInfoProperties() {
uint32_t devID = 0xa080;
if (supportsMTLFeatureSet(tvOS_GPUFamily2_v1)) {
devID = 0xa101;
}
_properties.vendorID = kAppleVendorId;
_properties.deviceID = devID;
_properties.deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
strlcpy(_properties.deviceName, _mtlDevice.name.UTF8String, VK_MAX_PHYSICAL_DEVICE_NAME_SIZE);
}
#endif
#pragma mark VkPhysicalDeviceLimits - List of feature limits available on the device #pragma mark VkPhysicalDeviceLimits - List of feature limits available on the device
@ -2463,10 +2414,10 @@ void MVKPhysicalDevice::initPipelineCacheUUID() {
*(uint32_t*)&_properties.pipelineCacheUUID[uuidComponentOffset] = NSSwapHostIntToBig(mvkRev); *(uint32_t*)&_properties.pipelineCacheUUID[uuidComponentOffset] = NSSwapHostIntToBig(mvkRev);
uuidComponentOffset += sizeof(mvkRev); uuidComponentOffset += sizeof(mvkRev);
// Next 4 bytes contains highest Metal feature set supported by this device // Next 4 bytes contains highest GPU capability supported by this device
uint32_t mtlFeatSet = getHighestMTLFeatureSet(); uint32_t gpuCap = getHighestGPUCapability();
*(uint32_t*)&_properties.pipelineCacheUUID[uuidComponentOffset] = NSSwapHostIntToBig(mtlFeatSet); *(uint32_t*)&_properties.pipelineCacheUUID[uuidComponentOffset] = NSSwapHostIntToBig(gpuCap);
uuidComponentOffset += sizeof(mtlFeatSet); uuidComponentOffset += sizeof(gpuCap);
// Next 4 bytes contains flags based on enabled Metal features that // Next 4 bytes contains flags based on enabled Metal features that
// might affect the contents of the pipeline cache (mostly MSL content). // might affect the contents of the pipeline cache (mostly MSL content).
@ -2476,42 +2427,38 @@ void MVKPhysicalDevice::initPipelineCacheUUID() {
uuidComponentOffset += sizeof(mtlFeatures); uuidComponentOffset += sizeof(mtlFeatures);
} }
uint32_t MVKPhysicalDevice::getHighestMTLFeatureSet() { uint32_t MVKPhysicalDevice::getHighestGPUCapability() {
// On newer OS's, combine highest Metal version with highest GPU family // On newer OS's, combine OS version with highest GPU family.
// (Mac & Apple GPU lists should be mutex on platform) // On macOS, Apple GPU fam takes precedence over others.
uint32_t mtlVer = 0; MTLGPUFamily gpuFam = MTLGPUFamily(0);
#if MVK_IOS_OR_TVOS if (supportsMTLGPUFamily(Mac1)) { gpuFam = MTLGPUFamilyMac1; }
if (mvkOSVersionIsAtLeast(13.0)) { mtlVer = 0x30000; } if (supportsMTLGPUFamily(Mac2)) { gpuFam = MTLGPUFamilyMac2; }
if (mvkOSVersionIsAtLeast(14.0)) { mtlVer = 0x40000; }
#endif
#if MVK_MACOS
if (mvkOSVersionIsAtLeast(10.15)) { mtlVer = 0x30000; }
if (mvkOSVersionIsAtLeast(10.16)) { mtlVer = 0x40000; }
#endif
MTLGPUFamily mtlFam = MTLGPUFamily(0); if (supportsMTLGPUFamily(Apple1)) { gpuFam = MTLGPUFamilyApple1; }
if (supportsMTLGPUFamily(Mac1)) { mtlFam = MTLGPUFamilyMac1; } if (supportsMTLGPUFamily(Apple2)) { gpuFam = MTLGPUFamilyApple2; }
if (supportsMTLGPUFamily(Mac2)) { mtlFam = MTLGPUFamilyMac2; } if (supportsMTLGPUFamily(Apple3)) { gpuFam = MTLGPUFamilyApple3; }
if (supportsMTLGPUFamily(Apple4)) { gpuFam = MTLGPUFamilyApple4; }
if (supportsMTLGPUFamily(Apple1)) { mtlFam = MTLGPUFamilyApple1; } if (supportsMTLGPUFamily(Apple5)) { gpuFam = MTLGPUFamilyApple5; }
if (supportsMTLGPUFamily(Apple2)) { mtlFam = MTLGPUFamilyApple2; }
if (supportsMTLGPUFamily(Apple3)) { mtlFam = MTLGPUFamilyApple3; }
if (supportsMTLGPUFamily(Apple4)) { mtlFam = MTLGPUFamilyApple4; }
if (supportsMTLGPUFamily(Apple5)) { mtlFam = MTLGPUFamilyApple5; }
#if MVK_IOS || (MVK_MACOS && MVK_XCODE_12) #if MVK_IOS || (MVK_MACOS && MVK_XCODE_12)
if (supportsMTLGPUFamily(Apple6)) { mtlFam = MTLGPUFamilyApple6; } if (supportsMTLGPUFamily(Apple6)) { gpuFam = MTLGPUFamilyApple6; }
#endif #endif
#if (MVK_IOS || MVK_MACOS) && MVK_XCODE_12 #if (MVK_IOS || MVK_MACOS) && MVK_XCODE_12
if (supportsMTLGPUFamily(Apple7)) { mtlFam = MTLGPUFamilyApple7; } if (supportsMTLGPUFamily(Apple7)) { gpuFam = MTLGPUFamilyApple7; }
#endif #endif
#if MVK_IOS && MVK_XCODE_13 #if MVK_IOS && MVK_XCODE_13
if (supportsMTLGPUFamily(Apple8)) { mtlFam = MTLGPUFamilyApple8; } if (supportsMTLGPUFamily(Apple8)) { gpuFam = MTLGPUFamilyApple8; }
#endif #endif
// Not explicitly guaranteed to be unique...but close enough without spilling over // Combine OS major (8 bits), OS minor (8 bits), and GPU family (16 bits)
uint32_t mtlFS = (mtlVer << 8) + (uint32_t)mtlFam; // into one 32-bit value summarizing highest GPU capability.
if (mtlFS) { return mtlFS; } if (gpuFam) {
float fosMaj, fosMin;
fosMin = modf(mvkOSVersion(), &fosMaj);
uint8_t osMaj = (uint8_t)fosMaj;
uint8_t osMin = (uint8_t)(fosMin * 255);
return (osMaj << 24) + (osMin << 16) + (uint16_t)gpuFam;
}
// Fall back to legacy feature sets on older OS's // Fall back to legacy feature sets on older OS's
#if MVK_IOS #if MVK_IOS