本系列文章是对 http://metalkit.org 上面MetalKit内容的全面翻译和学习.
几周前,在WWDC2016
,Apple
工程师发布了一份新的文档,Metal Best Practices Guide Metal最佳实践指南,它包含了非常有用的信息,关于如何在你的Metal
应用中组织代码来获得更好的性能.因为文档是非常全面广泛的,我们在本文中将只列出主要的概念.一个高效的Metal
应用需要:
- 低
CPU
占用. - 最佳的
GPU
性能. - 连续的处理器并行计算.
- 高效资源管理.
1 Resource Management 资源管理
1.1 Persistent Objects持久对象
最佳实践:尽早创建持久对象并重用它们.
Metal
框架提供了几个协议来管理那些贯穿你的应用整个生命周期的持久对象.这些对象创建花费很大但通常初始化一次并经常重用.不要在每个渲染循环或计算循环开始时创建这些对象.
- 先初始化你的Device和Command Queue命令队列
- 在Build Time创建时间就编译你的函数和库
- 建立Pipelines管线一次并重用它们
- 预告分配资源储存空间
要了解更多信息,查阅文档的持久对象章节Persistent Objects
1.2 Resource Options资源设置
最佳实践:为你的资源设置合理的储存模式和纹理使用设置.
Metal
资源必须被合理配置来充份利用调整内存访问和驱动器性能优化.资源储存模式允许你为MTLBuffer
和MTLTexture
对象自定义储存位置和访问权限.纹理使用设置允许明确声明你想要如何使用你的MTLTexture
对象.
- 熟悉设备内存模式
- 选择合理的资源储存模式(
iOS
和tvOS
) - 选择合理的资源储存模式(
OS X
) - 设置合理的纹理使用标志
要了解更多信息,查阅文档的资源设置章节Resource Options
1.3 Triple Buffering三重缓冲器
最佳实践:实现三重缓冲器来更新动态缓冲器数据.
动态缓冲器数据指缓冲器内储存的经常更新的数据.强烈推荐实现一个三重缓冲器模型,来避免每帧创建新的缓冲器及最小化帧间处理器闲置时间.
- 防止访问冲突,减少处理器闲置时间
- 减少内存开销和帧延迟
- 允许命令缓冲器事务时间
- 实现三重缓冲器模型
要了解更多信息,查阅文档的三重缓冲器章节 Triple Buffering
1.4 Buffer Bindings缓冲器绑定
最佳实践:用合理的方法来绑定你的缓冲器数据到图形或计算函数.
Metal
提供了若干API
设置来绑定缓冲器数据到图形或计算函数.setVertexBytes:length:atIndex: 方法是最佳选项来绑定大量小于4KB的动态缓冲器数据(瞬时缓冲器)到顶点函数.如果数据大于4KB,你应该一次性创建一个MTLBuffer并在需要时更新它的内容.
要了解更多信息,查阅文档的缓冲器绑定章节 Buffer Bindings
Display Management显示管理
2.1 Drawables可绘制对象
最佳实践:尽可能短暂的持有可绘制对象.
命令缓冲器在自己被调度执行之前,可以通过presentDrawable方法来调度drawable的显示,但是,实际上drawable自己是在命令缓冲器被执行完才显示的.
- 用MetalKit View来获取Drawable
要了解更多信息,查阅文档的可绘制对象章节Drawables section of the documentation.
2.2 Native Screen Scale (iOS and tvOS)原生屏幕比例
最佳实践:以目标显示屏的精确像素尺寸来渲染.
你的drawable的像素尺寸应该总是匹配目标显示屏的精确像素尺寸.这样可以避免离屏像素渲染,或引发额外的采样处理.
- 用MetalKit View来支持原生屏幕比例
要了解更多信息,查阅文档的原生屏幕比例章节 Native Screen Scal
2.3 Frame Rate (iOS and tvOS)帧率
最佳实践:对于那些不能维持60 FPS帧率的应用,以一个稳定的帧率显示你的drawable.
iOS
设务的屏幕刷新率是60 Hz
.不能稳定在这段时间内完成帧渲染的应用,应该设置更低的帧率来避免卡顿.tvOS
的屏幕刷新率一般是60 Hz
,但并不固定.
- 用MetalKit View来支持原生屏幕比例
要了解更多信息,查阅文档的帧率章节Frame Rate
3 Command Generation命令生成
3.1 Load and Store Actions加载与储存动作
最佳实践:为你的渲染目标设置合理的加载与储存动作.
在你的Metal
渲染对象上执行的动作必须被合理配置,来避免在渲染过程的开始()或xf昂贵或不必要的渲染工作.
- 选择合理的加载动作
- 选择合理的储存动作
- 在渲染过程中评估动作
要了解更多信息,查阅文档的加载与储存动作章节Load and Store Actions
3.2 Render Command Encoders (iOS and tvOS)渲染命令编码器
最佳实践:尽可能的合并渲染命令编码器.
消除不必要的渲染命令编码器,减少内存带宽占用并提高性能.
- 评估渲染传递顺序
- 评估采样依赖
- 评估渲染过程中的动作
要了解更多信息,查阅文档的渲染命令编码器章节Render Command Encoders
3.3 Command Buffers命令缓冲器
最佳实践:每帧提交尽可能少的命令缓冲器,充份利用GPU
.
命令缓冲器在Metal
中是提交工作的基本单位;它们由CPU
创建并被GPU
执行.这种关系允许你通过调整每帧提交的命令缓冲器数量来平衡CPU
和GPU
的工作.
要了解更多信息,查阅文档的命令缓冲器章节Command Buffers
3.4 Indirect Buffers间接缓冲器
最佳实践:如果你的绘制或调度调用参数是由GPU
动态生成的,应使用间接缓冲器.
间接缓冲器是MTLBuffer
对象,它带有一个特殊的数据布局来代表绘制或调度命令参数.
- 消除不必要的数据传输并减少处理器闲置时间
要了解更多信息,查阅文档的命令缓冲器章节Indirect Buffers
4 Compilation
4.1 Functions and Libraries函数和库
最佳实践:在build生成时编译你的函数,并生成你的库.
编译Metal Shading Language
源代码是Metal
应用中耗时的阶段之一.Metal
通过允许你在build时编译图形和计算函数并在运行时作为库加载它们,来缩短时间花费.
- 在build时生成你的库
- 将函数放在一个单一的库里面
要了解更多信息,查阅文档的函数和库章节 Functions and Libraries
4.2 Pipelines管线
最佳实践:异步build生成你的渲染和计算管线.
拥有多个渲染或计算管线允许你为特定任务使用不同的状态配置.异步生成这些管线可以提高性能和并发数.推荐你提前生成所有已知的管线,避免懒加载.
要了解更多信息,查阅文档的管线章节Pipelines
这份指南,还有Metal编程指南 Metal Programming Guide及Metal着色语言指南Metal Shading Language Guide都已经更新到iOS 10
, tvOS 10
和OS X 10.12
,它们三部文档包含了创建高性能Metal
应用所需的一切.