Merge pull request #1497 from billhollings/apple-silicon-deviceID

On Apple Silicon, set VkPhysicalDeviceProperties::deviceID from GPU capabilities.
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index 61e3e02..77f021c 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -20,6 +20,7 @@
 
 - Support building MoltenVK with static Vulkan linkage symbols hidden.
 - 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`.
 - 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.
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
index c4be1d2..89ca384 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h
@@ -391,7 +391,7 @@
 	void initCounterSets();
 	MVKArrayRef<MVKQueueFamily*> getQueueFamilies();
 	void initPipelineCacheUUID();
-	uint32_t getHighestMTLFeatureSet();
+	uint32_t getHighestGPUCapability();
 	uint32_t getMoltenVKGitRevision();
 	void populate(VkPhysicalDeviceIDProperties* pDevIdProps);
 	void logGPUInfo();
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index a1e09a1..e9376a3 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -37,6 +37,8 @@
 
 #import "CAMetalLayer+MoltenVK.h"
 
+#include <cmath>
+
 using namespace std;
 
 
@@ -504,11 +506,10 @@
 	*(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(mvkVersion);
 	uuidComponentOffset += sizeof(mvkVersion);
 
-	// Next 4 bytes contains highest Metal feature set supported by this device
-	uint32_t mtlFeatSet = getHighestMTLFeatureSet();
-	*(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(mtlFeatSet);
-	uuidComponentOffset += sizeof(mtlFeatSet);
-
+	// Next 4 bytes contains highest GPU capability supported by this device
+	uint32_t gpuCap = getHighestGPUCapability();
+	*(uint32_t*)&uuid[uuidComponentOffset] = NSSwapHostIntToBig(gpuCap);
+	uuidComponentOffset += sizeof(gpuCap);
 
 	// ---- LUID ignored for Metal devices ------------------------
 	mvkClear(pDevIdProps->deviceLUID, VK_LUID_SIZE);
@@ -2228,31 +2229,23 @@
 
 void MVKPhysicalDevice::initGPUInfoProperties() {
 
-	bool isFound = false;
-
 	bool isIntegrated = getHasUnifiedMemory();
 	_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);
 
-	if (supportsMTLGPUFamily(Apple5)) {
-		// This is an Apple GPU. It won't have a 'device-id' property, so fill it in like on iOS/tvOS.
-		// Test for Apple5 first instead of Apple7 to support Xcode 11.7 builds.
+	// For Apple Silicon, the Device ID is determined by the highest
+	// GPU capability, which is a combination of OS version and GPU type.
+	// 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;
-#if MVK_XCODE_12
-		if (supportsMTLGPUFamily(Apple7)) {
-			_properties.deviceID = 0xa140;
-		} else if (supportsMTLGPUFamily(Apple6)) {
-			_properties.deviceID = 0xa130;
-		} else
-#endif
-		{
-			_properties.deviceID = 0xa120;
-		}
+		_properties.deviceID = getHighestGPUCapability();
 		return;
 	}
 
 	// 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.
+	bool isFound = false;
 	io_registry_entry_t entry;
 	uint64_t regID = mvkGetRegistryID(_mtlDevice);
 	if (regID) {
@@ -2294,58 +2287,16 @@
 
 #endif	//MVK_MACOS
 
-#if MVK_IOS
-
-// For iOS 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.
+#if MVK_IOS_OR_TVOS
+// For Apple Silicon, the Device ID is determined by the highest
+// GPU capability, which is a combination of OS version and GPU type.
 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.deviceID = devID;
+	_properties.deviceID = getHighestGPUCapability();
 	_properties.deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU;
 	strlcpy(_properties.deviceName, _mtlDevice.name.UTF8String, VK_MAX_PHYSICAL_DEVICE_NAME_SIZE);
 }
-#endif	//MVK_IOS
-
-#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
+#endif	//MVK_IOS_OR_TVOS
 
 #pragma mark VkPhysicalDeviceLimits - List of feature limits available on the device
 
@@ -2482,10 +2433,10 @@
 	*(uint32_t*)&_properties.pipelineCacheUUID[uuidComponentOffset] = NSSwapHostIntToBig(mvkRev);
 	uuidComponentOffset += sizeof(mvkRev);
 
-	// Next 4 bytes contains highest Metal feature set supported by this device
-	uint32_t mtlFeatSet = getHighestMTLFeatureSet();
-	*(uint32_t*)&_properties.pipelineCacheUUID[uuidComponentOffset] = NSSwapHostIntToBig(mtlFeatSet);
-	uuidComponentOffset += sizeof(mtlFeatSet);
+	// Next 4 bytes contains highest GPU capability supported by this device
+	uint32_t gpuCap = getHighestGPUCapability();
+	*(uint32_t*)&_properties.pipelineCacheUUID[uuidComponentOffset] = NSSwapHostIntToBig(gpuCap);
+	uuidComponentOffset += sizeof(gpuCap);
 
 	// Next 4 bytes contains flags based on enabled Metal features that
 	// might affect the contents of the pipeline cache (mostly MSL content).
@@ -2495,42 +2446,38 @@
 	uuidComponentOffset += sizeof(mtlFeatures);
 }
 
-uint32_t MVKPhysicalDevice::getHighestMTLFeatureSet() {
+uint32_t MVKPhysicalDevice::getHighestGPUCapability() {
 
-	// On newer OS's, combine highest Metal version with highest GPU family
-	// (Mac & Apple GPU lists should be mutex on platform)
-	uint32_t mtlVer = 0;
-#if MVK_IOS_OR_TVOS
-	if (mvkOSVersionIsAtLeast(13.0)) { mtlVer = 0x30000; }
-	if (mvkOSVersionIsAtLeast(14.0)) { mtlVer = 0x40000; }
-#endif
-#if MVK_MACOS
-	if (mvkOSVersionIsAtLeast(10.15)) { mtlVer = 0x30000; }
-	if (mvkOSVersionIsAtLeast(10.16)) { mtlVer = 0x40000; }
-#endif
+	// On newer OS's, combine OS version with highest GPU family.
+	// On macOS, Apple GPU fam takes precedence over others.
+	MTLGPUFamily gpuFam = MTLGPUFamily(0);
+	if (supportsMTLGPUFamily(Mac1)) { gpuFam = MTLGPUFamilyMac1; }
+	if (supportsMTLGPUFamily(Mac2)) { gpuFam = MTLGPUFamilyMac2; }
 
-	MTLGPUFamily mtlFam = MTLGPUFamily(0);
-	if (supportsMTLGPUFamily(Mac1)) { mtlFam = MTLGPUFamilyMac1; }
-	if (supportsMTLGPUFamily(Mac2)) { mtlFam = MTLGPUFamilyMac2; }
-
-	if (supportsMTLGPUFamily(Apple1)) { mtlFam = MTLGPUFamilyApple1; }
-	if (supportsMTLGPUFamily(Apple2)) { mtlFam = MTLGPUFamilyApple2; }
-	if (supportsMTLGPUFamily(Apple3)) { mtlFam = MTLGPUFamilyApple3; }
-	if (supportsMTLGPUFamily(Apple4)) { mtlFam = MTLGPUFamilyApple4; }
-	if (supportsMTLGPUFamily(Apple5)) { mtlFam = MTLGPUFamilyApple5; }
+	if (supportsMTLGPUFamily(Apple1)) { gpuFam = MTLGPUFamilyApple1; }
+	if (supportsMTLGPUFamily(Apple2)) { gpuFam = MTLGPUFamilyApple2; }
+	if (supportsMTLGPUFamily(Apple3)) { gpuFam = MTLGPUFamilyApple3; }
+	if (supportsMTLGPUFamily(Apple4)) { gpuFam = MTLGPUFamilyApple4; }
+	if (supportsMTLGPUFamily(Apple5)) { gpuFam = MTLGPUFamilyApple5; }
 #if MVK_IOS || (MVK_MACOS && MVK_XCODE_12)
-	if (supportsMTLGPUFamily(Apple6)) { mtlFam = MTLGPUFamilyApple6; }
+	if (supportsMTLGPUFamily(Apple6)) { gpuFam = MTLGPUFamilyApple6; }
 #endif
 #if (MVK_IOS || MVK_MACOS) && MVK_XCODE_12
-	if (supportsMTLGPUFamily(Apple7)) { mtlFam = MTLGPUFamilyApple7; }
+	if (supportsMTLGPUFamily(Apple7)) { gpuFam = MTLGPUFamilyApple7; }
 #endif
 #if MVK_IOS && MVK_XCODE_13
-	if (supportsMTLGPUFamily(Apple8)) { mtlFam = MTLGPUFamilyApple8; }
+	if (supportsMTLGPUFamily(Apple8)) { gpuFam = MTLGPUFamilyApple8; }
 #endif
 
-	// Not explicitly guaranteed to be unique...but close enough without spilling over
-	uint32_t mtlFS = (mtlVer << 8) + (uint32_t)mtlFam;
-	if (mtlFS) { return mtlFS; }
+	// Combine OS major (8 bits), OS minor (8 bits), and GPU family (16 bits)
+	// into one 32-bit value summarizing highest GPU capability.
+	if (gpuFam) {
+		float fosMaj, fosMin;
+		fosMin = modf(mvkOSVersion(), &fosMaj);
+		uint8_t osMaj = (uint8_t)fosMaj;
+		uint8_t osMin = (uint8_t)(fosMin * 100);
+		return (osMaj << 24) + (osMin << 16) + (uint16_t)gpuFam;
+	}
 
 	// Fall back to legacy feature sets on older OS's
 #if MVK_IOS