Graphics & Games 进阶 20m
用 C++ 编写 Metal 程序:metal-cpp 指南
Program Metal in C++ with metal-cpp
2022年6月6日
一句话判断
metal-cpp 是一个零开销的 C++ 头文件库,对 Metal 的 Objective-C API 做了一对一映射——C++ 游戏引擎现在可以直接调用 Metal,不需要写一行 Objective-C。
这场 Session 讲了什么
Metal 原本用 Objective-C 设计。如果你的代码库是 C++,需要一层桥接才能使用 Metal。metal-cpp 就是这层桥接——一个 header-only 库,提供 100% 的 Metal API 覆盖率,每个 C++ 调用直接映射到对应的 Objective-C 方法。
Session 重点讲解了 C++ 和 Objective-C 在对象生命周期管理上的差异。metal-cpp 对象使用手动引用计数(MRR),不使用 ARC。你需要遵循 Cocoa 的命名规则:以 alloc、new、copy、mutableCopy、create 开头的方法返回的对象你拥有,需要手动 release。其他方法返回的对象你不拥有,不需要 release。
Xcode 14 和 metal-cpp 提供了一些工具来简化内存管理,包括 NS::SharedPtr 智能指针和 autorelease pool 的 C++ 封装。
值得深挖的点
- 零开销的实现原理:metal-cpp 用 C 直接调用 Objective-C runtime——这和 Objective-C 编译器执行方法调用的机制完全一样。不会引入额外的虚函数表或间接调用开销。
- 内存管理的陷阱:C++ 开发者习惯用 new/delete 管理对象,但 metal-cpp 对象必须用 Cocoa 的引用计数规则。用 new 创建 metal-cpp 对象是错误的,用 delete 释放也是错误的。
- NS::SharedPtr 的使用:metal-cpp 提供了自己的智能指针,支持
NS::Transfer(转移所有权)和NS::Retain(共享所有权)。这比手动 retain/release 更安全。 - 开发工具的完整支持:GPU Frame Capture、Xcode Debugger 等工具完全支持 metal-cpp 代码,因为底层调用的还是 Objective-C runtime。
代码片段
// metal-cpp 的基本使用
#define NS_PRIVATE_IMPLEMENTATION
#define CA_PRIVATE_IMPLEMENTATION
#define MTL_PRIVATE_IMPLEMENTATION
#include <Metal/Metal.hpp>
// 创建命令缓冲区
MTL::Device* device = MTL::CreateSystemDefaultDevice();
MTL::CommandQueue* commandQueue = device->newCommandQueue();
MTL::CommandBuffer* commandBuffer = commandQueue->commandBuffer();
// 创建渲染命令编码器
MTL::RenderCommandEncoder* encoder = commandBuffer->renderCommandEncoder(
renderPassDescriptor
);
// 设置渲染管线状态
encoder->setRenderPipelineState(pipelineState);
// 编码绘制调用
encoder->drawPrimitives(MTL::PrimitiveTypeTriangle, 0, 3);
// 结束编码
encoder->endEncoding();
// 提交命令缓冲区
commandBuffer->commit();
// 内存管理:使用 NS::SharedPtr
auto devicePtr = NS::TransferPtr(MTL::CreateSystemDefaultDevice());
// devicePtr 离开作用域时自动 release
// 手动引用计数示例
auto texture = device->newTexture(descriptor);
// newTexture 返回的对象你拥有,需要在使用完后 release
texture->release();
最佳实践
- 在唯一一个 .cpp 文件中定义 NS/CA/MTL_PRIVATE_IMPLEMENTATION 宏,避免重复定义错误
- 使用 NS::SharedPtr 管理对象生命周期,减少手动 retain/release 的出错概率
- 不要对 metal-cpp 对象使用 C++ 的 new/delete
- 项目需要设置 C++17 或更高版本的方言
- 在 Xcode 中添加 Foundation、QuartzCore 和 Metal 三个框架
还有什么值得关注
- metal-cpp 在 Apple Developer 网站上可以下载,Apache 2 开源许可
- Deferred Lighting 示例项目提供了 metal-cpp 的完整实战参考
- 增量式 C++ 示例系列从基础到高级逐步讲解 Metal API
- metal-cpp 与 Metal 3 的所有新功能(快速资源加载、Mesh Shaders 等)完全兼容
WWDC 2022