本项目提供了一个高级 Swift 框架,用于处理 Metal 计算着色器。它简化了使用 Apple 的 Metal API 在 GPU 上设置和执行计算任务的过程。
本项目从 Apple 在 iOS 17 和 macOS Sonoma 中引入的 SwiftUI 着色器中汲取灵感。SwiftUI 着色器展示了如何使 GPU 操作对开发者更易于访问,从而通过简单的 Swift 代码实现复杂的视觉效果。“Compute” 旨在为 Metal 计算着色器提供类似程度的抽象,从而更轻松地在 GPU 上执行数据并行计算。
这是一个如何使用 Metal Compute Framework 执行基本计算的快速示例
import Compute
import Metal
// Example usage that adds two arrays of integers using Compute.
// Metal shader source code
let source = """
#include <metal_stdlib>
using namespace metal;
kernel void add(device int* inA [[buffer(0)]],
device int* inB [[buffer(1)]],
device int* result [[buffer(2)]],
uint id [[thread_position_in_grid]]) {
result[id] = inA[id] + inB[id];
}
"""
// Set up the compute environment
let device = MTLCreateSystemDefaultDevice()!
let compute = try Compute(device: device)
// Create input data
let count = 1000
let inA = [Int32](repeating: 1, count: count)
let inB = [Int32](repeating: 2, count: count)
var result = [Int32](repeating: 0, count: count)
// Create Metal buffers
let bufferA = device.makeBuffer(bytes: inA, length: MemoryLayout<Int32>.stride * count, options: [])!
let bufferB = device.makeBuffer(bytes: inB, length: MemoryLayout<Int32>.stride * count, options: [])!
let bufferResult = device.makeBuffer(length: MemoryLayout<Int32>.stride * count, options: [])!
// Create a shader library and function
let library = ShaderLibrary.source(source)
let function = library.add
// Create a compute pipeline and bind arguments.
var pipeline = try compute.makePipeline(function: function)
pipeline.arguments.inA = .buffer(bufferA)
pipeline.arguments.inB = .buffer(inB)
pipeline.arguments.result = .buffer(bufferResult)
// Run the compute pipeline
try compute.run(pipeline: pipeline, width: count)
// Read back the results
result = bufferResult.contents().withUnsafeBytes { $0.bindMemory(to: Int32.self) }
// Verify the results
for i in 0..<count {
assert(result[i] == inA[i] + inB[i], "Computation error at index \(i)")
}
Compute 当前需要 macOS 15/iOS 17(截至撰写本文时,这些系统仍处于 beta 阶段)。这是因为 Compute 使用了 Metal 3.2 中的新 metal 日志记录功能。可以在早期版本的 macOS/iOS 上使用 Compute,但您需要修改代码以使用较旧的 Metal API。欢迎提交 Pull Request 以使其在较旧的操作系统上工作。
要使用 Swift Package Manager 将 Metal Compute Framework 集成到您的 Xcode 项目中,请将其添加到 Package.swift
文件的 dependencies 值中。
dependencies: [
.package(url: "https://github.com/schwa/Compute.git", .from(from: "0.0.1"))
]
然后,将其指定为您的目标的依赖项
targets: [
.target(name: "YourTarget", dependencies: ["MetalComputeFramework"]),
]
Compute 旨在减少使用 Metal 计算着色器所需的样板设置代码量。它提供了一个高级 API,用于创建计算管线、绑定参数以及在 GPU 上执行计算任务。
Compute 为 Metal 计算编程带来了类型安全和 Swift 友好的语法。它使用 Swift 枚举和结构体来表示 Metal 对象和类型,从而更轻松地使用 Metal 缓冲区、纹理和其他资源。
Compute 在资源创建、着色器编译和计算管线执行时处理并抛出错误。这使得在您的代码中捕获和处理错误变得更容易。
Compute 还自动向大多数 Metal 资源添加标签,以帮助调试。
此屏幕截图显示了使用 Compute 的代码与使用“原生” Metal 的代码的比较
本项目根据 MIT 许可证获得许可。有关详细信息,请参阅 LICENSE 文件。
欢迎为 Compute Framework 做出贡献。
注意:我们的一些初始文档和测试是由 AI 生成的。
Apple 的主要 Metal 文档。
《Metal 着色语言规范》书籍。这是编写 Metal 着色器的权威指南。
《Metal 功能集表》书籍。这是关于哪些功能在哪些设备/Metal 版本上可用的参考。
Warren Moore 的博客是学习 Metal 编程的最佳资源。
Warren 有一些关于 Metal 中的 Compute 编程的帖子,但它们有点过时了。尽管如此,它们仍然是一个很好的起点。
SwiftUI 的 Shader 是本项目的主要灵感来源。
如何计算线程组和网格大小。这是 Metal 计算编程中的一个关键概念。