Article / 2026/05/29

MTLDevice API 完整指南

MTLDevice 是 Metal 框架的核心接口,代表系统中的 GPU 设备。它是创建所有 Metal 对象的工厂,负责管理 GPU 资源、内存分配和命令执行。

🚀 MTLDevice API 完整指南

MTLDevice 是 Metal 框架的核心接口,代表系统中的 GPU 设备。它是创建所有 Metal 对象的工厂,负责管理 GPU 资源、内存分配和命令执行。

目录

设备获取和基本信息

MTLCreateSystemDefaultDevice()

func MTLCreateSystemDefaultDevice() -> MTLDevice?
  • 用途: 获取系统默认的 Metal 设备
  • 返回值: 系统默认 GPU 设备,如果不支持 Metal 则返回 nil
  • 示例:
guard let device = MTLCreateSystemDefaultDevice() else {
    fatalError("Metal is not supported on this device")
}

MTLCopyAllDevices()

func MTLCopyAllDevices() -> [MTLDevice]
  • 用途: 获取系统中所有可用的 Metal 设备
  • 平台: 仅 macOS
  • 返回值: 所有可用设备的数组
  • 示例:
#if os(macOS)
let allDevices = MTLCopyAllDevices()
for device in allDevices {
    print("Device: \(device.name)")
}
#endif

name

var name: String { get }
  • 用途: 获取设备名称
  • 示例:
print("GPU: \(device.name)")

registryID

var registryID: UInt64 { get }
  • 用途: 获取设备的唯一标识符
  • 示例:
let deviceID = device.registryID

location

@available(macOS 10.15, *)
var location: MTLDeviceLocation { get }
  • 用途: 获取设备位置信息(内置、外部等)
  • 平台: macOS 10.15+
  • 示例:
#if os(macOS)
if #available(macOS 10.15, *) {
    print("Device location: \(device.location)")
}
#endif

locationNumber

@available(macOS 10.15, *)
var locationNumber: Int { get }
  • 用途: 获取设备位置编号
  • 平台: macOS 10.15+

maxThreadgroupMemoryLength

var maxThreadgroupMemoryLength: Int { get }
  • 用途: 获取线程组共享内存的最大大小
  • 示例:
let maxThreadgroupMemory = device.maxThreadgroupMemoryLength

maxThreadsPerThreadgroup

var maxThreadsPerThreadgroup: MTLSize { get }
  • 用途: 获取每个线程组的最大线程数
  • 示例:
let maxThreads = device.maxThreadsPerThreadgroup
print("Max threads per threadgroup: \(maxThreads.width)x\(maxThreads.height)x\(maxThreads.depth)")

缓冲区管理

makeBuffer(length:options:)

func makeBuffer(length: Int, options: MTLResourceOptions = []) -> MTLBuffer?
  • 用途: 创建指定大小的缓冲区
  • 参数:
    • length: 缓冲区大小(字节)
    • options: 资源选项
  • 示例:
// 创建 1024 字节的缓冲区
let buffer = device.makeBuffer(length: 1024, options: .storageModeShared)

makeBuffer(bytes:length:options:)

func makeBuffer(bytes pointer: UnsafeRawPointer, length: Int, options: MTLResourceOptions = []) -> MTLBuffer?
  • 用途: 从现有数据创建缓冲区
  • 示例:
let vertices: [Float] = [0.0, 1.0, -1.0, -1.0, 1.0, -1.0]
let vertexBuffer = vertices.withUnsafeBytes { bytes in
    device.makeBuffer(bytes: bytes.baseAddress!, length: bytes.count, options: .storageModeShared)
}

makeBuffer(bytesNoCopy:length:options:deallocator:)

func makeBuffer(bytesNoCopy pointer: UnsafeMutableRawPointer, 
                length: Int, 
                options: MTLResourceOptions = [], 
                deallocator: ((UnsafeMutableRawPointer, Int) -> Void)? = nil) -> MTLBuffer?
  • 用途: 创建不复制数据的缓冲区,直接使用提供的内存
  • 注意: 内存管理需要特别小心
  • 示例:
let dataPointer = UnsafeMutableRawPointer.allocate(byteCount: 1024, alignment: 16)
let buffer = device.makeBuffer(bytesNoCopy: dataPointer, length: 1024) { pointer, length in
    pointer.deallocate()
}

纹理管理

makeTexture(descriptor:)

func makeTexture(descriptor: MTLTextureDescriptor) -> MTLTexture?
  • 用途: 创建纹理对象
  • 示例:
let textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(
    pixelFormat: .rgba8Unorm,
    width: 512,
    height: 512,
    mipmapped: false
)
textureDescriptor.usage = [.shaderRead, .shaderWrite]

let texture = device.makeTexture(descriptor: textureDescriptor)

makeTexture(descriptor:iosurface:plane:)

@available(iOS 11.0, macOS 10.11, *)
func makeTexture(descriptor: MTLTextureDescriptor, 
                iosurface: IOSurfaceRef, 
                plane: Int) -> MTLTexture?
  • 用途: 从 IOSurface 创建纹理
  • 用途: 用于与其他图形 API 共享纹理数据

makeSharedTexture(descriptor:)

@available(iOS 13.0, macOS 10.14, *)
func makeSharedTexture(descriptor: MTLTextureDescriptor) -> MTLTexture?
  • 用途: 创建可在进程间共享的纹理
  • 示例:
let descriptor = MTLTextureDescriptor.texture2DDescriptor(
    pixelFormat: .rgba8Unorm,
    width: 256,
    height: 256,
    mipmapped: false
)
let sharedTexture = device.makeSharedTexture(descriptor: descriptor)

makeSharedTexture(handle:)

@available(iOS 13.0, macOS 10.14, *)
func makeSharedTexture(handle: MTLSharedTextureHandle) -> MTLTexture?
  • 用途: 从共享句柄创建纹理

渲染状态对象

makeRenderPipelineState(descriptor:)

func makeRenderPipelineState(descriptor: MTLRenderPipelineDescriptor) throws -> MTLRenderPipelineState
  • 用途: 创建渲染管线状态对象
  • 示例:
let pipelineDescriptor = MTLRenderPipelineDescriptor()
pipelineDescriptor.vertexFunction = vertexFunction
pipelineDescriptor.fragmentFunction = fragmentFunction
pipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm

do {
    let pipelineState = try device.makeRenderPipelineState(descriptor: pipelineDescriptor)
} catch {
    print("Failed to create render pipeline state: \(error)")
}

makeRenderPipelineState(descriptor:completionHandler:)

func makeRenderPipelineState(descriptor: MTLRenderPipelineDescriptor, 
                           completionHandler: @escaping (MTLRenderPipelineState?, Error?) -> Void)
  • 用途: 异步创建渲染管线状态对象
  • 示例:
device.makeRenderPipelineState(descriptor: pipelineDescriptor) { pipelineState, error in
    if let error = error {
        print("Pipeline creation failed: \(error)")
        return
    }
    // 使用 pipelineState
}

makeRenderPipelineState(descriptor:options:reflection:)

func makeRenderPipelineState(descriptor: MTLRenderPipelineDescriptor, 
                           options: MTLPipelineOption, 
                           reflection: AutoreleasingUnsafeMutablePointer<MTLRenderPipelineReflection?>?) throws -> MTLRenderPipelineState
  • 用途: 创建渲染管线状态并获取反射信息
  • 示例:
var reflection: MTLRenderPipelineReflection?
let pipelineState = try device.makeRenderPipelineState(
    descriptor: pipelineDescriptor,
    options: .argumentInfo,
    reflection: &reflection
)

// 使用反射信息
if let reflection = reflection {
    print("Vertex arguments: \(reflection.vertexArguments)")
    print("Fragment arguments: \(reflection.fragmentArguments)")
}

makeDepthStencilState(descriptor:)

func makeDepthStencilState(descriptor: MTLDepthStencilDescriptor) -> MTLDepthStencilState?
  • 用途: 创建深度模板状态对象
  • 示例:
let depthStencilDescriptor = MTLDepthStencilDescriptor()
depthStencilDescriptor.depthCompareFunction = .less
depthStencilDescriptor.isDepthWriteEnabled = true

let depthStencilState = device.makeDepthStencilState(descriptor: depthStencilDescriptor)

计算状态对象

makeComputePipelineState(function:)

func makeComputePipelineState(function: MTLFunction) throws -> MTLComputePipelineState
  • 用途: 从计算函数创建计算管线状态
  • 示例:
do {
    let computePipelineState = try device.makeComputePipelineState(function: computeFunction)
} catch {
    print("Failed to create compute pipeline state: \(error)")
}

makeComputePipelineState(function:completionHandler:)

func makeComputePipelineState(function: MTLFunction, 
                            completionHandler: @escaping (MTLComputePipelineState?, Error?) -> Void)
  • 用途: 异步创建计算管线状态
  • 示例:
device.makeComputePipelineState(function: computeFunction) { pipelineState, error in
    if let error = error {
        print("Compute pipeline creation failed: \(error)")
        return
    }
    // 使用 pipelineState
}

makeComputePipelineState(function:options:reflection:)

func makeComputePipelineState(function: MTLFunction, 
                            options: MTLPipelineOption, 
                            reflection: AutoreleasingUnsafeMutablePointer<MTLComputePipelineReflection?>?) throws -> MTLComputePipelineState
  • 用途: 创建计算管线状态并获取反射信息
  • 示例:
var reflection: MTLComputePipelineReflection?
let computePipelineState = try device.makeComputePipelineState(
    function: computeFunction,
    options: .argumentInfo,
    reflection: &reflection
)

makeComputePipelineState(descriptor:options:reflection:)

@available(iOS 9.0, macOS 10.11, *)
func makeComputePipelineState(descriptor: MTLComputePipelineDescriptor, 
                            options: MTLPipelineOption, 
                            reflection: AutoreleasingUnsafeMutablePointer<MTLComputePipelineReflection?>?) throws -> MTLComputePipelineState
  • 用途: 使用描述符创建计算管线状态

命令队列和同步

makeCommandQueue()

func makeCommandQueue() -> MTLCommandQueue?
  • 用途: 创建命令队列
  • 示例:
let commandQueue = device.makeCommandQueue()

makeCommandQueue(maxCommandBufferCount:)

func makeCommandQueue(maxCommandBufferCount: Int) -> MTLCommandQueue?
  • 用途: 创建指定最大命令缓冲区数量的命令队列
  • 示例:
let commandQueue = device.makeCommandQueue(maxCommandBufferCount: 64)

makeFence()

@available(iOS 10.0, macOS 10.13, *)
func makeFence() -> MTLFence?
  • 用途: 创建用于同步的围栏对象
  • 示例:
let fence = device.makeFence()

makeEvent()

@available(iOS 12.0, macOS 10.14, *)
func makeEvent() -> MTLEvent?
  • 用途: 创建事件对象用于GPU同步
  • 示例:
let event = device.makeEvent()

makeSharedEvent()

@available(iOS 12.0, macOS 10.14, *)
func makeSharedEvent() -> MTLSharedEvent?
  • 用途: 创建可跨进程共享的事件对象
  • 示例:
let sharedEvent = device.makeSharedEvent()

makeSharedEvent(handle:)

@available(iOS 12.0, macOS 10.14, *)
func makeSharedEvent(handle: MTLSharedEventHandle) -> MTLSharedEvent?
  • 用途: 从共享句柄创建事件对象

采样器和函数库

makeSamplerState(descriptor:)

func makeSamplerState(descriptor: MTLSamplerDescriptor) -> MTLSamplerState?
  • 用途: 创建采样器状态对象
  • 示例:
let samplerDescriptor = MTLSamplerDescriptor()
samplerDescriptor.minFilter = .linear
samplerDescriptor.magFilter = .linear
samplerDescriptor.sAddressMode = .repeat
samplerDescriptor.tAddressMode = .repeat

let samplerState = device.makeSamplerState(descriptor: samplerDescriptor)

makeDefaultLibrary()

func makeDefaultLibrary() -> MTLLibrary?
  • 用途: 创建默认的函数库(包含应用中编译的所有着色器)
  • 示例:
guard let defaultLibrary = device.makeDefaultLibrary() else {
    fatalError("Failed to create default library")
}

let vertexFunction = defaultLibrary.makeFunction(name: "vertexShader")
let fragmentFunction = defaultLibrary.makeFunction(name: "fragmentShader")

makeDefaultLibrary(bundle:)

@available(iOS 10.0, macOS 10.12, *)
func makeDefaultLibrary(bundle: Bundle) -> MTLLibrary?
  • 用途: 从指定 Bundle 创建默认函数库
  • 示例:
let library = device.makeDefaultLibrary(bundle: Bundle.main)

makeLibrary(filepath:)

func makeLibrary(filepath: String) throws -> MTLLibrary
  • 用途: 从文件路径加载预编译的函数库
  • 示例:
do {
    let library = try device.makeLibrary(filepath: "/path/to/library.metallib")
} catch {
    print("Failed to load library: \(error)")
}

makeLibrary(data:)

func makeLibrary(data: __DispatchData) throws -> MTLLibrary
  • 用途: 从数据创建函数库
  • 示例:
let libraryData = // ... 从某处获取的库数据
do {
    let library = try device.makeLibrary(data: libraryData)
} catch {
    print("Failed to create library from data: \(error)")
}

makeLibrary(source:options:)

func makeLibrary(source: String, options: MTLCompileOptions?) throws -> MTLLibrary
  • 用途: 从 Metal 着色器源代码编译函数库
  • 示例:
let shaderSource = """
#include <metal_stdlib>
using namespace metal;

vertex float4 vertexShader(uint vertexID [[ vertex_id ]]) {
    return float4(0.0, 0.0, 0.0, 1.0);
}
"""

do {
    let library = try device.makeLibrary(source: shaderSource, options: nil)
} catch {
    print("Shader compilation failed: \(error)")
}

makeLibrary(source:options:completionHandler:)

func makeLibrary(source: String, 
                options: MTLCompileOptions?, 
                completionHandler: @escaping (MTLLibrary?, Error?) -> Void)
  • 用途: 异步编译着色器源代码
  • 示例:
device.makeLibrary(source: shaderSource, options: nil) { library, error in
    if let error = error {
        print("Async shader compilation failed: \(error)")
        return
    }
    // 使用编译好的库
}

堆内存管理

makeHeap(descriptor:)

@available(iOS 10.0, macOS 10.13, *)
func makeHeap(descriptor: MTLHeapDescriptor) -> MTLHeap?
  • 用途: 创建内存堆用于高效的资源分配
  • 示例:
let heapDescriptor = MTLHeapDescriptor()
heapDescriptor.size = 1024 * 1024 // 1MB
heapDescriptor.storageMode = .private

let heap = device.makeHeap(descriptor: heapDescriptor)

heapTextureSizeAndAlign(descriptor:)

@available(iOS 10.0, macOS 10.13, *)
func heapTextureSizeAndAlign(descriptor: MTLTextureDescriptor) -> MTLSizeAndAlign
  • 用途: 获取指定纹理描述符的堆内存大小和对齐要求
  • 示例:
let textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(
    pixelFormat: .rgba8Unorm,
    width: 512,
    height: 512,
    mipmapped: false
)

let sizeAndAlign = device.heapTextureSizeAndAlign(descriptor: textureDescriptor)
print("Texture size: \(sizeAndAlign.size), align: \(sizeAndAlign.align)")

heapBufferSizeAndAlign(length:options:)

@available(iOS 10.0, macOS 10.13, *)
func heapBufferSizeAndAlign(length: Int, options: MTLResourceOptions) -> MTLSizeAndAlign
  • 用途: 获取指定缓冲区的堆内存大小和对齐要求
  • 示例:
let sizeAndAlign = device.heapBufferSizeAndAlign(length: 1024, options: .storageModePrivate)

参数缓冲区

makeArgumentEncoder(arguments:)

@available(iOS 11.0, macOS 10.13, *)
func makeArgumentEncoder(arguments: [MTLArgumentDescriptor]) -> MTLArgumentEncoder?
  • 用途: 创建参数编码器
  • 示例:
let argumentDescriptors = [
    MTLArgumentDescriptor(),
    MTLArgumentDescriptor()
]
argumentDescriptors[0].index = 0
argumentDescriptors[0].dataType = .texture
argumentDescriptors[1].index = 1
argumentDescriptors[1].dataType = .sampler

let argumentEncoder = device.makeArgumentEncoder(arguments: argumentDescriptors)

makeIndirectCommandBuffer(descriptor:maxCommandCount:options:)

@available(iOS 12.0, macOS 10.14, *)
func makeIndirectCommandBuffer(descriptor: MTLIndirectCommandBufferDescriptor, 
                             maxCommandCount: Int, 
                             options: MTLResourceOptions) -> MTLIndirectCommandBuffer?
  • 用途: 创建间接命令缓冲区
  • 示例:
let icbDescriptor = MTLIndirectCommandBufferDescriptor()
icbDescriptor.commandTypes = .draw
icbDescriptor.inheritBuffers = false
icbDescriptor.maxVertexBufferBindCount = 8
icbDescriptor.maxFragmentBufferBindCount = 8

let indirectCommandBuffer = device.makeIndirectCommandBuffer(
    descriptor: icbDescriptor,
    maxCommandCount: 100,
    options: .storageModePrivate
)

光线追踪

makeAccelerationStructure(size:)

@available(iOS 14.0, macOS 11.0, *)
func makeAccelerationStructure(size: Int) -> MTLAccelerationStructure?
  • 用途: 创建加速结构用于光线追踪
  • 示例:
let accelerationStructure = device.makeAccelerationStructure(size: 1024 * 1024)

makeAccelerationStructure(descriptor:)

@available(iOS 15.0, macOS 12.0, *)
func makeAccelerationStructure(descriptor: MTLAccelerationStructureDescriptor) -> MTLAccelerationStructure?
  • 用途: 使用描述符创建加速结构
  • 示例:
let descriptor = MTLInstanceAccelerationStructureDescriptor()
descriptor.instanceCount = 100

let accelerationStructure = device.makeAccelerationStructure(descriptor: descriptor)

accelerationStructureSizes(descriptor:)

@available(iOS 15.0, macOS 12.0, *)
func accelerationStructureSizes(descriptor: MTLAccelerationStructureDescriptor) -> MTLAccelerationStructureSizes
  • 用途: 获取加速结构的内存大小要求

能力查询

supportsFeatureSet(_:)

func supportsFeatureSet(_ featureSet: MTLFeatureSet) -> Bool
  • 用途: 检查设备是否支持指定的功能集
  • 示例:
if device.supportsFeatureSet(.iOS_GPUFamily3_v1) {
    print("Supports iOS GPU Family 3 v1")
}

supportsFamily(_:)

@available(iOS 13.0, macOS 10.15, *)
func supportsFamily(_ gpuFamily: MTLGPUFamily) -> Bool
  • 用途: 检查设备是否支持指定的 GPU 系列
  • 示例:
if device.supportsFamily(.apple4) {
    print("Supports Apple GPU Family 4")
}

readWriteTextureSupport

@available(iOS 11.0, macOS 10.13, *)
var readWriteTextureSupport: MTLReadWriteTextureTier { get }
  • 用途: 获取读写纹理支持等级
  • 示例:
let rwTextureSupport = device.readWriteTextureSupport
print("Read-write texture support: \(rwTextureSupport)")

argumentBuffersSupport

@available(iOS 11.0, macOS 10.13, *)
var argumentBuffersSupport: MTLArgumentBuffersTier { get }
  • 用途: 获取参数缓冲区支持等级

rasterOrderGroupsSupport

@available(iOS 11.0, macOS 10.13, *)
var rasterOrderGroupsSupport: MTLRasterOrderGroupsTier { get }
  • 用途: 获取光栅化顺序组支持等级

currentAllocatedSize

@available(iOS 12.0, macOS 10.13, *)
var currentAllocatedSize: Int { get }
  • 用途: 获取当前设备分配的内存大小
  • 示例:
let allocatedMemory = device.currentAllocatedSize
print("Currently allocated: \(allocatedMemory) bytes")

recommendedMaxWorkingSetSize

@available(iOS 12.0, macOS 10.13, *)
var recommendedMaxWorkingSetSize: Int { get }
  • 用途: 获取推荐的最大工作集大小
  • 示例:
let maxWorkingSet = device.recommendedMaxWorkingSetSize

hasUnifiedMemory

@available(iOS 13.0, macOS 10.15, *)
var hasUnifiedMemory: Bool { get }
  • 用途: 检查设备是否使用统一内存架构
  • 示例:
if device.hasUnifiedMemory {
    print("Device uses unified memory")
}

peerGroupID

@available(macOS 10.15, *)
var peerGroupID: UInt64 { get }
  • 用途: 获取设备的对等组ID
  • 平台: 仅 macOS

peerIndex

@available(macOS 10.15, *)
var peerIndex: UInt32 { get }
  • 用途: 获取设备在对等组中的索引

peerCount

@available(macOS 10.15, *)
var peerCount: UInt32 { get }
  • 用途: 获取对等组中设备的数量

minimumLinearTextureAlignment(for:)

@available(iOS 12.0, macOS 10.13, *)
func minimumLinearTextureAlignment(for pixelFormat: MTLPixelFormat) -> Int
  • 用途: 获取指定像素格式的最小线性纹理对齐

minimumTextureBufferAlignment(for:)

@available(iOS 12.0, macOS 10.13, *)
func minimumTextureBufferAlignment(for pixelFormat: MTLPixelFormat) -> Int
  • 用途: 获取指定像素格式的最小纹理缓冲区对齐

maxBufferLength

@available(iOS 12.0, macOS 10.14, *)
var maxBufferLength: Int { get }
  • 用途: 获取缓冲区的最大长度限制

areProgrammableSamplePositionsSupported

@available(iOS 11.0, macOS 10.13, *)
var areProgrammableSamplePositionsSupported: Bool { get }
  • 用途: 检查是否支持可编程采样位置

areRasterOrderGroupsSupported

@available(iOS 11.0, macOS 10.13, *)
var areRasterOrderGroupsSupported: Bool { get }
  • 用途: 检查是否支持光栅化顺序组

使用示例

基本设备设置和资源创建

import Metal

class MetalRenderer {
    let device: MTLDevice
    let commandQueue: MTLCommandQueue
    var vertexBuffer: MTLBuffer?
    var pipelineState: MTLRenderPipelineState?
    
    init() {
        // 1. 获取 Metal 设备
        guard let device = MTLCreateSystemDefaultDevice() else {
            fatalError("Metal is not supported")
        }
        self.device = device
        
        print("Using GPU: \(device.name)")
        print("Max threadgroup memory: \(device.maxThreadgroupMemoryLength)")
        print("Max threads per threadgroup: \(device.maxThreadsPerThreadgroup)")
        
        // 2. 创建命令队列
        guard let commandQueue = device.makeCommandQueue() else {
            fatalError("Failed to create command queue")
        }
        self.commandQueue = commandQueue
        
        // 3. 设置资源
        setupResources()
        setupPipeline()
    }
    
    private func setupResources() {
        // 创建顶点缓冲区
        let vertices: [Float] = [
             0.0,  1.0, 0.0,
            -1.0, -1.0, 0.0,
             1.0, -1.0, 0.0
        ]
        
        vertexBuffer = vertices.withUnsafeBytes { bytes in
            device.makeBuffer(bytes: bytes.baseAddress!,
                            length: bytes.count,
                            options: .storageModeShared)
        }
        
        // 创建纹理
        let textureDescriptor = MTLTextureDescriptor.texture2DDescriptor(
            pixelFormat: .rgba8Unorm,
            width: 512,
            height: 512,
            mipmapped: false
        )
        textureDescriptor.usage = [.shaderRead, .renderTarget]
        
        let texture = device.makeTexture(descriptor: textureDescriptor)
        
        // 创建采样器
        let samplerDescriptor = MTLSamplerDescriptor()
        samplerDescriptor.minFilter = .linear
        samplerDescriptor.magFilter = .linear
        let sampler = device.makeSamplerState(descriptor: samplerDescriptor)
    }
    
    private func setupPipeline() {
        // 获取默认库
        guard let library = device.makeDefaultLibrary() else {
            fatalError("Failed to create default library")
        }
        
        // 获取着色器函数
        guard let vertexFunction = library.makeFunction(name: "vertexShader"),
              let fragmentFunction = library.makeFunction(name: "fragmentShader") else {
            fatalError("Failed to find shader functions")
        }
        
        // 创建渲染管线描述符
        let pipelineDescriptor = MTLRenderPipelineDescriptor()
        pipelineDescriptor.vertexFunction = vertexFunction
        pipelineDescriptor.fragmentFunction = fragmentFunction
        pipelineDescriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
        
        // 创建管线状态
        do {
            pipelineState = try device.makeRenderPipelineState(descriptor: pipelineDescriptor)
        } catch {
            fatalError("Failed to create render pipeline state: \(error)")
        }
        
        // 创建深度状态
        let depthStencilDescriptor = MTLDepthStencilDescriptor()
        depthStencilDescriptor.depthCompareFunction = .less
        depthStencilDescriptor.isDepthWriteEnabled = true
        let depthState = device.makeDepthStencilState(descriptor: depthStencilDescriptor)
    }
}

高级内存管理示例

class AdvancedMemoryManager {
    let device: MTLDevice
    var heap: MTLHeap?
    
    init(device: MTLDevice) {
        self.device = device
        setupHeap()
    }
    
    private func setupHeap() {
        // 检查设备能力
        if #available(iOS 10.0, macOS 10.13, *) {
            let heapDescriptor = MTLHeapDescriptor()
            heapDescriptor.size = 16 * 1024 * 1024 // 16MB
            heapDescriptor.storageMode = .private
            
            heap = device.makeHeap(descriptor: heapDescriptor)
            print("Created heap with size: \(heapDescriptor.size)")
        }
    }
    
    func createOptimizedTexture(width: Int, height: Int) -> MTLTexture? {
        let descriptor = MTLTextureDescriptor.texture2DDescriptor(
            pixelFormat: .rgba8Unorm,
            width: width,
            height: height,
            mipmapped: false
        )
        
        if #available(iOS 10.0, macOS 10.13, *), let heap = heap {
            // 使用堆分配
            let sizeAndAlign = device.heapTextureSizeAndAlign(descriptor: descriptor)
            
            if heap.maxAvailableSize(alignment: Int(sizeAndAlign.align)) >= sizeAndAlign.size {
                return heap.makeTexture(descriptor: descriptor)
            }
        }
        
        // 回退到常规分配
        return device.makeTexture(descriptor: descriptor)
    }
    
    func checkMemoryUsage() {
        if #available(iOS 12.0, macOS 10.13, *) {
            let allocated = device.currentAllocatedSize
            let recommended = device.recommendedMaxWorkingSetSize
            
            print("Current allocated: \(allocated / (1024*1024))MB")
            print("Recommended max: \(recommended / (1024*1024))MB")
            
            if allocated > recommended {
                print("⚠️ Memory usage exceeds recommendation")
            }
        }
    }
}

计算着色器使用示例

class ComputeShaderManager {
    let device: MTLDevice
    let commandQueue: MTLCommandQueue
    var computePipelineState: MTLComputePipelineState?
    
    init(device: MTLDevice) {
        self.device = device
        self.commandQueue = device.makeCommandQueue()!
        setupComputePipeline()
    }
    
    private func setupComputePipeline() {
        let source = """
        #include <metal_stdlib>
        using namespace metal;
        
        kernel void addArrays(const device float* arrayA [[ buffer(0) ]],
                             const device float* arrayB [[ buffer(1) ]],
                             device float* result [[ buffer(2) ]],
                             uint index [[ thread_position_in_grid ]]) {
            result[index] = arrayA[index] + arrayB[index];
        }
        """
        
        do {
            let library = try device.makeLibrary(source: source, options: nil)
            guard let addFunction = library.makeFunction(name: "addArrays") else {
                fatalError("Failed to find compute function")
            }
            
            computePipelineState = try device.makeComputePipelineState(function: addFunction)
        } catch {
            fatalError("Failed to create compute pipeline: \(error)")
        }
    }
    
    func addArrays(_ arrayA: [Float], _ arrayB: [Float]) -> [Float] {
        guard arrayA.count == arrayB.count else {
            fatalError("Arrays must have same length")
        }
        
        let bufferA = arrayA.withUnsafeBytes { bytes in
            device.makeBuffer(bytes: bytes.baseAddress!, 
                            length: bytes.count, 
                            options: .storageModeShared)!
        }
        
        let bufferB = arrayB.withUnsafeBytes { bytes in
            device.makeBuffer(bytes: bytes.baseAddress!, 
                            length: bytes.count, 
                            options: .storageModeShared)!
        }
        
        let resultBuffer = device.makeBuffer(length: arrayA.count * MemoryLayout<Float>.size, 
                                           options: .storageModeShared)!
        
        let commandBuffer = commandQueue.makeCommandBuffer()!
        let computeEncoder = commandBuffer.makeComputeCommandEncoder()!
        
        computeEncoder.setComputePipelineState(computePipelineState!)
        computeEncoder.setBuffer(bufferA, offset: 0, index: 0)
        computeEncoder.setBuffer(bufferB, offset: 0, index: 1)
        computeEncoder.setBuffer(resultBuffer, offset: 0, index: 2)
        
        let threadsPerThreadgroup = MTLSize(width: 64, height: 1, depth: 1)
        let threadgroupsPerGrid = MTLSize(
            width: (arrayA.count + threadsPerThreadgroup.width - 1) / threadsPerThreadgroup.width,
            height: 1,
            depth: 1
        )
        
        computeEncoder.dispatchThreadgroups(threadgroupsPerGrid, 
                                          threadsPerThreadgroup: threadsPerThreadgroup)
        computeEncoder.endEncoding()
        commandBuffer.commit()
        commandBuffer.waitUntilCompleted()
        
        let resultPointer = resultBuffer.contents().bindMemory(to: Float.self, capacity: arrayA.count)
        return Array(UnsafeBufferPointer(start: resultPointer, count: arrayA.count))
    }
}

能力检测和适配示例

class DeviceCapabilityManager {
    let device: MTLDevice
    
    init(device: MTLDevice) {
        self.device = device
        analyzeCapabilities()
    }
    
    private func analyzeCapabilities() {
        print("=== Device Information ===")
        print("Name: \(device.name)")
        print("Registry ID: \(device.registryID)")
        
        // 基本能力检测
        print("\n=== Basic Capabilities ===")
        print("Max threadgroup memory: \(device.maxThreadgroupMemoryLength) bytes")
        print("Max threads per threadgroup: \(device.maxThreadsPerThreadgroup)")
        
        if #available(iOS 12.0, macOS 10.14, *) {
            print("Max buffer length: \(device.maxBufferLength / (1024*1024))MB")
        }
        
        if #available(iOS 13.0, macOS 10.15, *) {
            print("Has unified memory: \(device.hasUnifiedMemory)")
        }
        
        // GPU 系列检测
        print("\n=== GPU Family Support ===")
        if #available(iOS 13.0, macOS 10.15, *) {
            let families: [MTLGPUFamily] = [.apple1, .apple2, .apple3, .apple4, .apple5, .apple6, .apple7]
            for family in families {
                if device.supportsFamily(family) {
                    print("✅ Supports \(family)")
                }
            }
        }
        
        // 功能等级检测
        print("\n=== Feature Tiers ===")
        if #available(iOS 11.0, macOS 10.13, *) {
            print("Read-write texture support: \(device.readWriteTextureSupport)")
            print("Argument buffers support: \(device.argumentBuffersSupport)")
            print("Programmable sample positions: \(device.areProgrammableSamplePositionsSupported)")
        }
        
        // 内存信息
        if #available(iOS 12.0, macOS 10.13, *) {
            let allocated = device.currentAllocatedSize
            let recommended = device.recommendedMaxWorkingSetSize
            print("\n=== Memory Information ===")
            print("Current allocated: \(allocated / (1024*1024))MB")
            print("Recommended max working set: \(recommended / (1024*1024))MB")
        }
        
        // macOS 特有信息
        #if os(macOS)
        if #available(macOS 10.15, *) {
            print("\n=== macOS Specific ===")
            print("Location: \(device.location)")
            print("Location number: \(device.locationNumber)")
            print("Peer group ID: \(device.peerGroupID)")
            print("Peer index: \(device.peerIndex)")
            print("Peer count: \(device.peerCount)")
        }
        #endif
    }
    
    func getOptimalConfiguration() -> (sampleCount: Int, useHeaps: Bool, useIndirectCommands: Bool) {
        var sampleCount = 1
        var useHeaps = false
        var useIndirectCommands = false
        
        // 根据 GPU 系列确定 MSAA 级别
        if #available(iOS 13.0, macOS 10.15, *) {
            if device.supportsFamily(.apple4) || device.supportsFamily(.apple5) {
                sampleCount = 4
            } else if device.supportsFamily(.apple6) || device.supportsFamily(.apple7) {
                sampleCount = 8
            }
        }
        
        // 检查堆支持
        if #available(iOS 10.0, macOS 10.13, *) {
            useHeaps = true
        }
        
        // 检查间接命令支持
        if #available(iOS 12.0, macOS 10.14, *) {
            useIndirectCommands = true
        }
        
        return (sampleCount: sampleCount, useHeaps: useHeaps, useIndirectCommands: useIndirectCommands)
    }
    
    func recommendedPixelFormat() -> MTLPixelFormat {
        // 根据设备能力推荐像素格式
        if #available(iOS 13.0, macOS 10.15, *) {
            if device.supportsFamily(.apple6) || device.supportsFamily(.apple7) {
                return .rgba16Float // 支持更高精度
            }
        }
        return .rgba8Unorm // 默认格式
    }
}

异步操作和错误处理示例

class AsyncMetalOperations {
    let device: MTLDevice
    let commandQueue: MTLCommandQueue
    
    init(device: MTLDevice) {
        self.device = device
        self.commandQueue = device.makeCommandQueue()!
    }
    
    func compileShaderAsync(source: String, completion: @escaping (MTLLibrary?, Error?) -> Void) {
        device.makeLibrary(source: source, options: nil) { library, error in
            DispatchQueue.main.async {
                completion(library, error)
            }
        }
    }
    
    func createPipelineAsync(vertexFunction: MTLFunction, 
                           fragmentFunction: MTLFunction,
                           completion: @escaping (MTLRenderPipelineState?, Error?) -> Void) {
        let descriptor = MTLRenderPipelineDescriptor()
        descriptor.vertexFunction = vertexFunction
        descriptor.fragmentFunction = fragmentFunction
        descriptor.colorAttachments[0].pixelFormat = .bgra8Unorm
        
        device.makeRenderPipelineState(descriptor: descriptor) { pipelineState, error in
            DispatchQueue.main.async {
                completion(pipelineState, error)
            }
        }
    }
    
    func performComplexOperation() {
        // 示例:链式异步操作
        let shaderSource = """
        #include <metal_stdlib>
        using namespace metal;
        
        vertex float4 vertexMain(uint vertexID [[ vertex_id ]]) {
            return float4(0.0, 0.0, 0.0, 1.0);
        }
        
        fragment float4 fragmentMain() {
            return float4(1.0, 0.0, 0.0, 1.0);
        }
        """
        
        compileShaderAsync(source: shaderSource) { [weak self] library, error in
            guard let self = self, let library = library else {
                print("Shader compilation failed: \(error?.localizedDescription ?? "Unknown error")")
                return
            }
            
            guard let vertexFunction = library.makeFunction(name: "vertexMain"),
                  let fragmentFunction = library.makeFunction(name: "fragmentMain") else {
                print("Failed to find shader functions")
                return
            }
            
            self.createPipelineAsync(vertexFunction: vertexFunction, 
                                   fragmentFunction: fragmentFunction) { pipelineState, error in
                if let pipelineState = pipelineState {
                    print("✅ Pipeline created successfully")
                    // 使用 pipelineState...
                } else {
                    print("Pipeline creation failed: \(error?.localizedDescription ?? "Unknown error")")
                }
            }
        }
    }
}

性能优化建议

1. 资源创建优化

  • 预先创建和缓存昂贵的对象(管线状态、库等)
  • 使用堆分配来减少内存碎片
  • 合理选择存储模式(shared vs private)

2. 内存管理

  • 监控 currentAllocatedSize 避免内存超限
  • 及时释放不需要的资源
  • 使用 autoreleasepool 管理临时对象

3. 异步操作

  • 使用异步 API 避免阻塞主线程
  • 合理安排着色器编译时机
  • 利用后台队列进行资源准备

4. 设备能力适配

  • 根据 GPU 系列调整渲染参数
  • 检测功能支持情况进行降级处理
  • 合理使用设备特有功能

注意事项

  1. 线程安全: MTLDevice 是线程安全的,可在多线程中使用
  2. 资源生命周期: 确保设备对象的生命周期覆盖所有相关资源
  3. 错误处理: 始终检查返回值,处理可能的失败情况
  4. 内存管理: 注意循环引用,特别是在闭包中使用 weak self
  5. 平台差异: 某些 API 仅在特定平台或版本上可用
  6. 性能监控: 定期检查内存使用情况,避免过度分配

MTLDevice 是 Metal 编程的基础,掌握其 API 对于高效的 GPU 编程至关重要。建议根据具体需求选择合适的 API,并注意性能优化和错误处理。

Giscus 未启用:请在 src/site.config.ts 中配置 repoId 与 categoryId。