-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
245 additions
and
128 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
// | ||
// MetalGpuInfo.swift | ||
// metalgpu | ||
// | ||
// Created by Kenneth Endfinger on 11/15/21. | ||
// | ||
|
||
import Foundation | ||
import Metal | ||
|
||
struct MetalGpuInfo: Codable { | ||
let index: Int? | ||
let name: String | ||
let registryID: UInt64 | ||
let location: Location | ||
let characteristics: [Characteristic] | ||
let features: [Feature] | ||
let maxTransferRateBytesPerSecond: UInt64? | ||
let recommendedMaxMemorySizeBytes: UInt64? | ||
let maxBufferLengthInBytes: UInt64? | ||
let maxThreadGroupMemorySize: UInt64? | ||
let sparseTileSizeInBytes: UInt64? | ||
let maxThreadsPerThreadGroup: Size | ||
|
||
enum Location: String, Codable { | ||
case builtIn = "Built-in" | ||
case external = "External" | ||
case slot = "Slot" | ||
case unspecified = "Unspecified" | ||
} | ||
|
||
enum Characteristic: String, Codable { | ||
case lowPower = "Low Power" | ||
case headless = "Headless" | ||
case removable = "Removable" | ||
case unifiedMemory = "Unified Memory" | ||
} | ||
|
||
enum FeatureKey: String, Codable { | ||
case rayTracing = "Ray Tracing" | ||
case msaa32Bit = "32-Bit MSAA" | ||
case dynamicLibraries = "Dynamic Libraries" | ||
case functionPointers = "Function Pointers" | ||
case queryTextureLOD = "Query Texture LOD" | ||
case floatFiltering32Bit = "32-Bit Float Filtering" | ||
case pullModelInterpolation = "Pull Model Interpolation" | ||
case bcTextureCompression = "BC Texture Compression" | ||
case shaderBarycentricCoordinates = "Shader Barycentric Coordinates" | ||
case barycentricCoordinates = "Barycentric Coordinates" | ||
case rasterOrderGroups = "Raster Order Groups" | ||
case programmableSamplePosition = "Programmable Sample Position" | ||
} | ||
|
||
struct Feature: Codable { | ||
let name: String | ||
let supported: Bool | ||
|
||
public init(name: String, supported: Bool) { | ||
self.name = name | ||
self.supported = supported | ||
} | ||
} | ||
|
||
struct Size: Codable { | ||
let width: Int | ||
let height: Int | ||
let depth: Int | ||
} | ||
} | ||
|
||
@available(macOS 10.15, *) | ||
extension MTLDeviceLocation { | ||
func asMetalGpuLocation() -> MetalGpuInfo.Location { | ||
switch self { | ||
case .builtIn: return .builtIn | ||
case .external: return .external | ||
case .slot: return .slot | ||
case .unspecified: return .unspecified | ||
@unknown default: | ||
fatalError("Unknown GPU Location") | ||
} | ||
} | ||
} | ||
|
||
extension MTLDevice { | ||
func collectMetalGpuInfo(_ index: Int? = nil) -> MetalGpuInfo { | ||
var recommendedMaxMemorySize: UInt64? | ||
if #available(macOS 10.12, *) { | ||
recommendedMaxMemorySize = self.recommendedMaxWorkingSetSize | ||
} | ||
|
||
var registryID: UInt64 = 0 | ||
var maxThreadGroupMemorySize: UInt64? | ||
if #available(macOS 10.13, *) { | ||
registryID = self.registryID | ||
maxThreadGroupMemorySize = UInt64(self.maxThreadgroupMemoryLength) | ||
} | ||
|
||
var maxBufferMemorySize: UInt64? | ||
if #available(macOS 10.14, *) { | ||
maxBufferMemorySize = UInt64(self.maxBufferLength) | ||
} | ||
|
||
var location: MetalGpuInfo.Location = .unspecified | ||
var maxTransferRate: UInt64? | ||
if #available(macOS 10.15, *) { | ||
location = self.location.asMetalGpuLocation() | ||
|
||
if location != .builtIn { | ||
maxTransferRate = self.maxTransferRate | ||
} | ||
} | ||
|
||
var sparseTileSizeInBytes: UInt64? | ||
if #available(macOS 11.0, *) { | ||
sparseTileSizeInBytes = UInt64(self.sparseTileSizeInBytes) | ||
} | ||
|
||
return MetalGpuInfo( | ||
index: index, | ||
name: name, | ||
registryID: registryID, | ||
location: location, | ||
characteristics: collectGpuCharacteristics(), | ||
features: collectGpuFeatures().map { | ||
MetalGpuInfo.Feature( | ||
name: $0.key.rawValue, | ||
supported: $0.value | ||
) | ||
}.sorted { | ||
$0.name.compare($1.name) == .orderedAscending | ||
}, | ||
maxTransferRateBytesPerSecond: maxTransferRate, | ||
recommendedMaxMemorySizeBytes: recommendedMaxMemorySize, | ||
maxBufferLengthInBytes: maxBufferMemorySize, | ||
maxThreadGroupMemorySize: maxThreadGroupMemorySize, | ||
sparseTileSizeInBytes: sparseTileSizeInBytes, | ||
maxThreadsPerThreadGroup: maxThreadsPerThreadgroup.asMetalGpuSize() | ||
) | ||
} | ||
|
||
func collectGpuFeatures() -> [MetalGpuInfo.FeatureKey: Bool] { | ||
var features: [MetalGpuInfo.FeatureKey: Bool] = [:] | ||
if #available(macOS 10.13, *) { | ||
features[.rasterOrderGroups] = areRasterOrderGroupsSupported | ||
features[.programmableSamplePosition] = areProgrammableSamplePositionsSupported | ||
} | ||
|
||
if #available(macOS 10.15, *) { | ||
features[.shaderBarycentricCoordinates] = supportsShaderBarycentricCoordinates | ||
features[.barycentricCoordinates] = areBarycentricCoordsSupported | ||
} | ||
|
||
if #available(macOS 11.0, *) { | ||
features[.pullModelInterpolation] = supportsPullModelInterpolation | ||
features[.bcTextureCompression] = supportsBCTextureCompression | ||
features[.floatFiltering32Bit] = supports32BitFloatFiltering | ||
features[.queryTextureLOD] = supportsQueryTextureLOD | ||
features[.functionPointers] = supportsFunctionPointers | ||
features[.dynamicLibraries] = supportsDynamicLibraries | ||
features[.msaa32Bit] = supports32BitMSAA | ||
} | ||
return features | ||
} | ||
|
||
func collectGpuCharacteristics() -> [MetalGpuInfo.Characteristic] { | ||
var characteristics: [MetalGpuInfo.Characteristic] = [] | ||
if isLowPower { | ||
characteristics.append(.lowPower) | ||
} | ||
|
||
if isHeadless { | ||
characteristics.append(.headless) | ||
} | ||
|
||
if #available(macOS 10.13, *) { | ||
if isRemovable { | ||
characteristics.append(.removable) | ||
} | ||
} | ||
|
||
if #available(macOS 10.15, *) { | ||
if hasUnifiedMemory { | ||
characteristics.append(.unifiedMemory) | ||
} | ||
} | ||
return characteristics | ||
} | ||
} | ||
|
||
extension MTLSize { | ||
func asMetalGpuSize() -> MetalGpuInfo.Size { | ||
MetalGpuInfo.Size( | ||
width: width, | ||
height: height, | ||
depth: depth | ||
) | ||
} | ||
} |
Oops, something went wrong.