Skip to content

Commit

Permalink
Support for JSON Output
Browse files Browse the repository at this point in the history
  • Loading branch information
azenla committed Nov 16, 2021
1 parent 683a791 commit f95dfb5
Show file tree
Hide file tree
Showing 3 changed files with 245 additions and 128 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ View Metal GPU information from the command-line.
$ metalgpu
Index: 0
Name: Apple M1 Max
Registry ID: 4294969670
Registry ID: 4294969661
Location: Built-in
Characteristics: Unified Memory
Features:
Expand All @@ -20,16 +20,16 @@ Index: 0
Barycentric Coordinates: Supported
Dynamic Libraries: Supported
Function Pointers: Supported
Function Pointers from Render: Supported
Primitive Motion Blur: Supported
Pull Model Interopolation: Supported
Programmable Sample Position: Supported
Pull Model Interpolation: Supported
Query Texture LOD: Supported
Ray Tracing: Supported
Ray Tracing from Render: Supported
Raster Order Groups: Supported
Shader Barycentric Coordinates: Supported
Recommended Maximum Memory Size: 42.67 GB
Max Buffer Length: 32 GB
Max Threads per Thread Group: (Width: 1024, Height: 1024, Depth: 1024)
Max Thread Group Memory Size: 32 KB
Sparse Tile Size: 16 KB
```

## Usage
Expand Down
199 changes: 199 additions & 0 deletions Sources/metalgpu/MetalGpuInfo.swift
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
)
}
}
Loading

0 comments on commit f95dfb5

Please sign in to comment.