Metal 4 核心要点:新的核心API到底改变了什么
Metal 4 不是一次重写。Apple 将其作为与原有 Metal 类型并行的API表面发布,新类型带有MTL4前缀,因此应用可以在不重写现有渲染代码的情况下,逐步采用新的核心API。1 这种定位很重要:Metal 框架本身已发布多年;在 WWDC25 上发生变化的是 Metal 4 核心API。
新核心API实际上为应用开发者带来了三方面的改变:
- 多线程命令缓冲区编码成为一等模式。
- 计算编码器将 blit 和加速结构编码器吸收到一个统一的表面中。
- 机器学习作为一等通道类型,与渲染和计算并列,在GPU时间轴上执行 Core ML 模型,无需往返到 CPU。
下面的章节将逐一介绍这三项变化在实践中的形态、开发者使用的新类型,以及 Apple 文档为它们的设计形态给出的理由。
TL;DR
MTL4CommandQueue、MTL4CommandBuffer、MTL4RenderCommandEncoder、MTL4ComputeCommandEncoder、MTL4MachineLearningCommandEncoder是新增的类型。1 原有的MTL前缀类型仍然保留。您可以混合使用两者来逐步采用。- 命令缓冲区从独立的
MTL4CommandAllocator获取工作内存,这使得多个线程可以并行地向多个缓冲区编码。一次commit:count:调用即可将批次提交到队列。1 MTL4ComputeCommandEncoder取代了三个早先的编码器:MTLBlitCommandEncoder、MTLComputeCommandEncoder和MTLAccelerationStructureCommandEncoder。1 一个编码器,三种工作。MTL4MachineLearningCommandEncoder在 Metal 命令缓冲区内运行 Core ML 模型。2 系统会为每个模型选择GPU或 Apple Neural Engine。张量承载输入和输出;同一个命令缓冲区将 ML 推理与渲染和计算工作混合在一起。- 资源绑定改为通过参数表(
MTL4ArgumentTable),而不是按编码器调用绑定方法。所有资源均不进行追踪;您需要使用显式屏障进行同步。1
为什么采用并行的API表面
Apple 文档原文对并行类型设计的阐述如下:”Metal 4 引入了若干带有 MTL4 前缀的类型,它们与所替代的原始 MTL 类型完全独立,例如MTL4CommandQueue与MTLCommandQueue。其他类型则在 Metal 的所有版本中通用。”1
运行时检测很简单:应用检测系统是否支持 Metal 4,如果支持则创建MTL4CommandQueue,否则回退到MTLCommandQueue。应用创建的队列类型决定了渲染代码的其余部分使用哪一族类型。1
设计的另一半让两个家族能够互操作。MTLEvent和MTLSharedEvent可在MTLCommandQueue和MTL4CommandQueue实例之间进行同步。1 一款带有大量 Metal 1 代码库的应用,可以将单个子系统切换到 Metal 4,而不会破坏应用其余部分所依赖的同步模式。
这回答了应用开发者自 WWDC25 以来一直在问的问题:我需要重写我的 Metal 代码吗?不需要。API的形态鼓励按子系统逐步采用。
多线程命令缓冲区编码
最重要的运行时改进是:命令缓冲区内存来自配套类型MTL4CommandAllocator,而不是来自队列。每个线程都可以使用自己的分配器将工作编码到自己的命令缓冲区中,队列则将这些缓冲区作为批次提交。
Apple 的API形态:1
let device: MTLDevice = ...
let commandQueue: MTL4CommandQueue = device.makeMTL4CommandQueue()
var commandAllocators: [MTL4CommandAllocator] = ...
let commandBuffer: MTL4CommandBuffer = device.makeCommandBuffer()
// Per frame:
let frameAllocator = commandAllocators[frameNumber % kMaxFramesInFlight]
frameAllocator.reset()
commandBuffer.beginCommandBuffer(allocator: frameAllocator)
// ...encode commands to commandBuffer...
commandBuffer.endCommandBuffer()
commandQueue.commit(commandBuffer, count: 1)
相对于原API的两项操作变化:
命令缓冲区可重用。 Apple 文档:”您可以无限地重用和重新利用每个命令缓冲区,方法是重新开始、编码新命令并再次提交,而不是分配一个新的缓冲区。”1 早期的 Metal 要求每次提交都使用一个全新的临时缓冲区。
不再自动保留资源。 “每个MTL4CommandBuffer实例不会对资源创建强引用。”1 此行为与旧API中的makeCommandBufferWithUnretainedReferences()类似。应用需要显式地管理资源生命周期,以确保资源在GPU完成工作之前保持存活。
Apple 在其示例代码中提供的帧分配器模式,针对每个在飞行中的帧使用一个分配器(示例使用三个),并在帧通过编码 → 渲染 → 显示生命周期推进时轮换使用它们。1 在每帧开始时调用分配器的reset(),会将其内存返回到池中以供重用。
统一的计算编码器
MTL4ComputeCommandEncoder是”一个新类型,它合并了其三个前身的功能:MTLBlitCommandEncoder、MTLComputeCommandEncoder、MTLAccelerationStructureCommandEncoder“。1
早期的API要求应用根据工作形态切换编码器类型:blit 用于资源拷贝和纹理传输,compute 用于内核分派,acceleration-structure 用于光线追踪场景管理。Metal 4 将这三者合并到一个表面中。一款应用在编码一帧时若需构建加速结构、分派降噪内核并将纹理拷贝到呈现缓冲区,现在可以通过单一编码器类型完成全部三项任务。
渲染编码器也获得了一项行为变化。MTL4RenderCommandEncoder支持跨命令缓冲区编码渲染通道:在一个渲染编码器结束时挂起工作,在序列中下一个编码器开始之后恢复。1 Apple 的阐述:”这一技术在概念上替代了MTLParallelRenderCommandEncoder协议,并简化了使用多线程并行编码渲染通道的过程,因为每个线程都可以拥有自己的渲染编码器,而不必将所有线程都绑定到单个渲染编码器上。”1
模式始终一致:并行编码成为自然形态,API不再要求一个单一的协调者类型。
参数表替代按编码器的资源绑定
原始的 Metal 编码器API在每个编码器上暴露了诸如setVertexBuffer(_:offset:index:)和setFragmentTexture(_:index:)等方法,每个阶段在编码器内部都有独立的绑定表。1 Metal 4 用显式的MTL4ArgumentTable实例取代了这一模式。
Apple 对设计收益的阐述:”Metal 4 编码器不需要为每个阶段的每种资源类型存储绑定表的内存。每个表只占用其存储资源绑定所需的内存。”1
流程:1
let descriptor = MTL4ArgumentTableDescriptor()
descriptor.maxBufferBindCount = ...
descriptor.maxTextureBindCount = ...
let argumentTable = device.makeArgumentTable(descriptor: descriptor)
argumentTable.setResource(buffer, bufferIndex: 0)
argumentTable.setSamplerState(sampler, index: 0)
renderEncoder.setArgumentTable(argumentTable, stages: [.vertex, .fragment])
只要其绑定的资源对所有编码器都适用,单个参数表就可以服务于多个编码器,包括位于不同命令缓冲区上的编码器。Apple 文档指出:”您的编码器共享的每一项公共资源、每次将参数表分配给新编码器时,内存与运行时的节省都会累积。”1
这里有一个权衡。早期版本的 Metal 支持对通过MTLTextureDescriptor.hazardTrackingMode或MTLHeapDescriptor.hazardTrackingMode选择加入的纹理和堆进行 hazard 追踪。1 在 Metal 4 中,”框架将所有资源视为未追踪。如果这些管线中的任何 shader 修改某项资源,您需要同步可能并发访问该资源的管线阶段。”1 应用通过添加显式屏障来延迟一个阶段,直到前一阶段完成。这比旧版的可选加入式追踪需要更多代码,作为交换,您可以获得可预测的性能和更低的运行时开销。
机器学习作为一等通道
MTL4MachineLearningCommandEncoder是架构上最具意义的新增内容。Apple 的阐述:2
“Metal 4 引入了在 Metal 工作流内高效运行 CoreML 模型的能力。这对于需要在 Metal 上下文中应用模型输出的应用非常有用,例如渲染场景或运行计算分派。”
两件事同时发生。第一,ML 推理在GPU时间轴上运行,与渲染和计算工作位于同一个命令缓冲区中。应用不会在模型推理与消费其输出的渲染通道之间往返到 CPU。第二,系统会选择推理引擎:”系统会为每个机器学习模型自动选择推理引擎,例如设备的GPU或 Apple Neural Engine(ANE)。当系统选择在 ANE 上运行模型时,GPU可以与GPU一起运行额外的、独立的渲染或计算工作。”2
开发流程:2
- 使用
metal-package-builder将 Core ML 模型转换为 Metal ML 包,该工具包含在 Xcode 26 的捆绑工具中。 - 将 Metal ML 包添加到 Xcode 工程。Xcode 会在构建时将其编译为 Metal 库。
- 在运行时,应用从该库创建一个
MTL4MachineLearningPipelineState。 - 编码器接受管线状态、用作 scratch 内存的
MTLHeap,以及作为输入和输出的MTLTensor实例。
MTLTensor是用于多维数据数组的新资源类型。2 Apple 文档指出,该类型可与int8和fp16等常见的 ML 权重类型一起使用。张量将输入带入模型,将输出带出模型;对于推理调用之间的临时数据,Metal Shading Language 添加了直接驻留在GPU上的张量类型:2
tensor_handle:在 CPU 上创建的MTLTensor的句柄tensor_inline:在GPU上定义的张量,作为对张量或缓冲区的视图cooperative_tensor:将其元素分配给与之协作的线程之间的张量
cooperative_tensor类型针对延迟敏感的场景:”协作张量通过将其数据平均分配给与该张量协作的线程,为临时张量提供临时内存。这种内存分配通过从线程私有或线程组私有地址空间分配内存来减少内存带宽,这对于延迟关键的机器学习算法非常重要。”2
MSL 还获得了在 shader 代码中直接工作的张量运算符:卷积、矩阵乘法、归约。2 需要在推理通道之间操纵权重的应用,可以无需将张量拷回 CPU 内存或运行单独的计算通道即可完成;这些运算符可融入正常的 MSL 内核中。
有一个边界值得引用:”机器学习编码器运行 Core ML 模型,但它们无法构建新的网络或修改现有网络的层和输入;对于这些任务,请参阅 Core ML 和 Metal Performance Shaders Graph。”2 Metal 4 的 ML 编码器用于发布推理,而非训练或模型构建。
Metal 4 对 Apple 技术栈意味着什么
为计划采用 Metal 4 的应用开发者总结三点要义:
- 按子系统逐步采用。 并行的
MTL4前缀类型以及与原API基于事件的互操作性,是为部分迁移而设计的。挑选一个具有明确性能压力的子系统(一条渲染路径、一条计算管线、一个模型推理循环)并率先迁移。1 - 多线程编码是新常态。 每线程一个分配器的模式、
commit:count:批次提交,以及挂起/恢复渲染通道机制,都假设并行编码是高性能应用将采用的形态。单线程编码仍然有效,但框架的运行时收益会随着多线程采用而累积。1 - ML 与其他工作运行在同一个命令缓冲区中。 对于将设备端模型推理与渲染或计算结合的应用(通过 Core ML 模型进行过滤的图像处理管线、依赖分类器输出的实时效果、渲染依赖于每帧推理结果的 AR 体验),能够将 ML 推理编码到与消费其输出的渲染通道相同的命令缓冲区中,是一项质的变化。2
Metal Shading Language 的新增内容值得专文论述。shader 代码中的张量类型和运算符,加上自定义运算的运算描述符,改变了 Metal 内核所能表达的内容。这是另一篇文章的话题。
完整的 Apple 生态系统集群:Foundation Models 设备端LLM介绍运行在此栈之上的框架;自定义适配器生命周期介绍开发者管理的特化;Core ML 设备端推理介绍其模型现可由 Metal 4 内联运行的 ML 框架。中心枢纽位于 Apple 生态系统系列。
FAQ
Metal 4 是与 Metal 分开的框架吗?
不是。框架仍然是 Metal。Apple 文档将 Metal 4 描述为”Metal 4 核心API”:一组带有MTL4前缀的新类型,与原有的MTL类型在同一框架中一同发布。1 应用通过在运行时检测 Metal 4 支持并创建相应的队列类型,逐步采用新类型。
我需要 iOS 26 才能使用 Metal 4 吗?
Metal 框架支持 iOS 8+,但 Metal 4 核心API是 Apple 在 WWDC25 上引入的版本。请运行运行时检测,根据设备所支持的版本创建MTL4CommandQueue或MTLCommandQueue。1
Metal 4 ML 通道与 Foundation Models 之间是什么关系?
它们运行在不同的栈上。MTL4MachineLearningCommandEncoder运行转换为 Metal ML 包的 Core ML 模型,与渲染和计算工作位于同一个命令缓冲区中。2 Foundation Models 是一个独立的框架,运行 Apple 的设备端系统语言模型,拥有自己的会话API,详见 Foundation Models 设备端LLM一文。两者互补:应用可以使用 Foundation Models 进行文本生成,并在其渲染循环内使用 Metal 4 ML 通道进行视觉或音频模型推理。
为什么计算编码器现在被统一了?
Apple 文档将MTLBlitCommandEncoder、MTLComputeCommandEncoder和MTLAccelerationStructureCommandEncoder合并为MTL4ComputeCommandEncoder。1 其理由是操作上而非仅出于性能:用单一编码器类型处理 compute、blit 和 acceleration-structure 工作,简化了管线管理,并减少了在交错执行三者的应用中的编码器切换。
Metal 4 中是否仍可使用 store-action 选项?
MTL4RenderCommandEncoder不支持。Apple 文档指出:”Store-action 选项(参见MTLStoreActionOptions)不可用,因为它们不适用于 Apple silicon GPU。”1 这一架构决策反映了 Apple 对 Metal 4 核心API的GPU专用目标定位。
我必须使用参数表吗?
在 Metal 4 中,是的。编码器协议不暴露按资源的绑定方法。您在MTL4ArgumentTable上配置资源绑定,并将该表分配给一个或多个编码器阶段。1 运行时收益在于:表只为它实际使用的绑定分配内存,而不是在每个编码器上都使用固定大小的按阶段表。
参考资料
-
Apple Developer,“Understanding the Metal 4 core API”。类型层级对比(
MTL4与MTL)、命令队列与缓冲区行为、命令分配器模式、编码器统一、参数表、hazard 追踪、挂起/恢复渲染通道。检索于 2026-05-04。 ↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩↩ -
Apple Developer,“Machine learning passes”。
MTL4MachineLearningCommandEncoder、MTLTensor、MSL 张量类型(tensor_handle、tensor_inline、cooperative_tensor)、metal-package-builder、系统推理引擎选择(GPU/ANE)、MSL 张量运算符。检索于 2026-05-04。 ↩↩↩↩↩↩↩↩↩↩↩