Metal 使用教程:在 macOS 上编写并运行第一个 GPU 程序

Metal 是苹果提供的底层图形与通用计算接口,只能在 macOS 和 iOS 设备上运行。
如果你搜索 Metal 使用教程,真正要解决的问题通常是:我的设备能不能跑、需要装什么、第一个能跑起来的程序怎么写、跑不通时看哪里。
下面按这个顺序展开。

先确认设备和工具链是否就绪

Metal 依赖苹果 GPU 和系统自带的 Metal 框架,不需要单独下载 SDK。
动手前检查三件事:

  • 系统版本:打开「关于本机」,确认 macOS 版本。较老的 Intel Mac 可能不支持某些 Metal 特性,Apple Silicon 机型默认支持。
  • 开发工具:终端执行 xcode-select -p,如果提示未安装,执行 xcode-select --install 安装命令行工具。
  • 编译器:执行 xcrun -sdk macosx metal --version,能输出版本号说明 Metal 编译器可用。

如果只是写命令行程序验证计算功能,不需要完整 Xcode 工程,用 swiftc 配合 metal 编译即可。

编写并编译一个计算着色器

Metal 的 GPU 代码写在 .metal 文件里,用 Metal Shading Language 编写。
新建 add.metal:

#include 
using namespace metal;

kernel void add_arrays(device const float* inA,
                       device const float* inB,
                       device float* result,
                       uint index [[thread_position_in_grid]]) {
    result[index] = inA[index] + inB[index];
}

这个内核把两个数组逐元素相加。
用命令行编译成 .metallib:

xcrun -sdk macosx metal -c add.metal -o add.air
xcrun -sdk macosx metallib add.air -o add.metallib

两条命令分别完成前端编译和链接。
如果第一条就报语法错误,先检查 #include 和 using namespace 是否写全。

在 Swift 中加载着色器并执行

创建 main.swift,核心步骤是获取设备、加载函数、建管线、建缓冲区、编码命令、等待完成。

import Metal

let device = MTLCreateSystemDefaultDevice()!
let library = try! device.makeLibrary(URL: URL(fileURLWithPath: "add.metallib"))
let function = library.makeFunction(name: "add_arrays")!
let pipeline = try! device.makeComputePipelineState(function: function)
let queue = device.makeCommandQueue()!

let count = 1024
let byteCount = count * MemoryLayout.stride
let a = device.makeBuffer(length: byteCount)!
let b = device.makeBuffer(length: byteCount)!
let out = device.makeBuffer(length: byteCount)!

let cmd = queue.makeCommandBuffer()!
let encoder = cmd.makeComputeCommandEncoder()!
encoder.setComputePipelineState(pipeline)
encoder.setBuffer(a, offset: 0, index: 0)
encoder.setBuffer(b, offset: 0, index: 1)
encoder.setBuffer(out, offset: 0, index: 2)
let threadsPerGroup = MTLSize(width: 64, height: 1, depth: 1)
let groups = MTLSize(width: (count + 63) / 64, height: 1, depth: 1)
encoder.dispatchThreadgroups(groups, threadsPerThreadgroup: threadsPerGroup)
encoder.endEncoding()
cmd.commit()
cmd.waitUntilCompleted()

编译运行:

swiftc main.swift -o run
./run

如果程序正常退出且没有崩溃,说明管线创建和命令提交成功。
要验证计算结果,可以把 out 的内容拷回 CPU 比较。

容易踩的几个坑

  • MTLCreateSystemDefaultDevice() 返回 nil:说明当前环境没有可用 Metal 设备,常见于虚拟机或过旧硬件,先换真机测试。
  • 找不到函数名:makeFunction(name:) 里的名字必须和 .metal 中 kernel 后的函数名完全一致,大小写敏感。
  • .metallib 路径错误:命令行程序的工作目录影响相对路径,最好用绝对路径加载。
  • 线程组尺寸超限:threadsPerThreadgroup 不能超过管线对象的 maxTotalThreadsPerThreadgroup,否则编码阶段会报错。

怎么确认真的跑对了

最直接的验证是读取输出缓冲区:把 out.contents() 转成 UnsafePointer,打印前几个元素,和 CPU 端手算结果对照。
如果数值一致,说明从着色器编译到 GPU 执行的链路是通的。
另外可以在 Xcode 中给 MTLCommandBuffer 加完成回调,捕获 error 字段,比只看进程是否崩溃更容易定位问题。

Metal 使用教程的关键不在语法,而在设备、编译、加载、执行这四步是否各自成功。
先让最小内核跑通,再逐步加入纹理或更复杂的缓冲区绑定。

分享到:
上一篇
Turbopuffer 向量检索怎么用:API 建库、写入与查询验证
下一篇
Vectara 使用教程:从创建语料到 API 检索的完整流程
1
系统公告

泽御云中秋国庆双节活动上线:新购8折,拼团3.99元起

尊敬的用户:
泽御云“月满中秋·礼贺国庆”双节活动现已开启,活动时间为2026年9月23日至10月10日。 活动期间可享以下福利:
1. 常规云服务器新购使用优惠码“泽御中秋国庆同乐”,符合条件的订单享8折优惠。
2. 香港精品云服务器5人拼团低至3.99元,部分4核4G套餐3人拼团年付388元,续费同价。
3. 新用户购买年付云服务器,符合活动规则可赠送2个月使用时长。
4. 老用户续费季度赠15天,续费年度赠2个月;活动期间升级配置免收配置迁移手续费。
5. 推荐好友成功下单,符合条件的推荐人可获赠7天服务器使用时长。
6. 活动期间享宕机补偿标准翻倍、简单网站迁移协助及技术工单优先处理权益。
温馨提示:优惠码不适用于拼团套餐、活动轻量产品、年付订单及续费订单;拼团套餐为独立特价活动,不与赠时类福利叠加。赠送时长不可折现、退款或跨账户转移,具体规则以活动页面说明为准。
服务中心
客服
在线客服
24小时为您服务
咨询
联系我们
联系我们,为您的业务提供专属服务。
24/7 技术支持
如果您遇到寻求进一步的帮助,请过工单与我们进行联系。
24/7 即时支持
泽御云
售前客服
泽御云
泽御云
售后客服
泽御云
技术支持
评价
您对当前页面的整体感受是否满意?
😞
非常不满意
😕
不满意
😐
一般
🙂
满意
😊
非常满意