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 系列调整渲染参数
- 检测功能支持情况进行降级处理
- 合理使用设备特有功能
注意事项
- 线程安全: MTLDevice 是线程安全的,可在多线程中使用
- 资源生命周期: 确保设备对象的生命周期覆盖所有相关资源
- 错误处理: 始终检查返回值,处理可能的失败情况
- 内存管理: 注意循环引用,特别是在闭包中使用
weak self - 平台差异: 某些 API 仅在特定平台或版本上可用
- 性能监控: 定期检查内存使用情况,避免过度分配
MTLDevice 是 Metal 编程的基础,掌握其 API 对于高效的 GPU 编程至关重要。建议根据具体需求选择合适的 API,并注意性能优化和错误处理。
Giscus 未启用:请在
src/site.config.ts中配置 repoId 与 categoryId。