版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.10.05 |
前言
很多做视频和图像的,相信对
Metal Performance Shaders
框架都不是很陌生,它向您的Metal应用程序添加低级别和高性能的内核kernel
。 利用针对每个Metal GPU
系列的独特特性进行微调的内核优化图形和计算性能。接下来几篇我们就详细的解析一下Metal Performance Shaders
。
框架基本
首先看一下该框架的基本信息。
Metal Performance Shaders
框架包含一系列高度优化的计算和图形着色器,旨在轻松高效地集成到Metal应用程序中。 这些数据并行原语被特别调整,以利用每个GPU系列的独特硬件特性来确保最佳性能。 采用Metal Performance Shaders
框架的应用程序可以确保实现最佳性能,而无需为每个新的GPU系列更新自己的手写着色器。 Metal性能着色器可以与应用程序的现有Metal资源一起使用(例如 MTLCommandBuffer, MTLTexture
MTLBuffer对象)和着色器。
在iOS 9和tvOS 9中,Metal Performance Shaders
框架引入了一系列常用的图像处理内核,用于对Metal纹理进行图像效果。
在iOS 10和tvOS 10中,Metal Performance Shaders
框架为以下内核提供了额外的支持:
- 卷积神经网络
(CNN)
使用先前获得的训练数据实现和运行深入学习。 CNN是一种机器学习技术,它尝试将视觉皮层建模为卷积,整流,合并和归一化步骤的序列。 - 图像处理进行颜色转换。
- 矩阵乘法。
1. The MPSKernel Class
MPSK
内核是所有Metal Performance Shaders
内核的基础类。 如果需要,它定义所有内核的基线行为,声明设备运行内核,一些调试选项和用户友好的标签。 从这个类派生的是MPSUnaryImageKernel和MPSBinaryImageKernel
子类,它们为大多数图像处理内核(过滤器)定义共享行为,例如边缘模式,剪切和平铺支持,用于消耗一个或两个源纹理的图像操作。 这些和MPSKernel 类都不是直接使用的。 它们只提供API抽象,在某些情况下可能允许对图像内核对象进行一些级别的多态操作。
MPSUnaryImageKernel
和MPSBinaryImageKernel
类的子类提供专门的初始化和编码方法来将各种图像处理原语编码到命令缓冲区中,并且还可以自己提供附加的可配置属性。 许多这样的图像过滤器是可用的,例如:
- 卷积滤波器(Sobel,Gaussian)
- 形态运算符(扩张,侵蚀)
- 直方图运算符(均衡,规范)
所有这些都直接在纹理和缓冲区对象上运行在GPU上。
作为MPSKernel,MPSUnaryImageKernel
和MPSBinaryImageKernel
类用于将多种图像操作统一为简单一致的界面和调用序列以应用图像过滤器,子类实现与规范分歧的细节。 例如,一些过滤器可能需要一小组参数(例如,卷积内核)来管理它们的功能。 然而,使用内核子类的整体顺序保持不变:
- 通过查询 MPSSupportsMTLDevice 功能,确定
Metal Performance Shaders
框架是否支持您的设备。 - 分配通常的
Metal
对象以驱动Metal计算流水线:MTLDevice, MTLCommandQueue
和MTLCommandBuffer。 如果您的应用程序已经写入任何命令缓冲区,Metal Performance Shaders
可以使用自己的工作负载进行编码。 - 创建一个适当的内核 - 例如,一个MPSImageGaussianBlur
对象,如果你想做一个高斯模糊。 内核通常是轻量级的,但可以重复使用以节省一些安装时间。 它们不能同时被多个线程使用,因此如果您的应用程序同时使用多个线程中的Metal,请添加额外的内核。 MPSKernel 对象遵守NSCopying
协议。 - 调用内核的编码方法。 编码调用的参数因内核类型而异,但操作类似。 他们创建一个命令编码器,写命令将内核运行到命令缓冲区,然后结束命令编码器。 这意味着在调用内核的编码方法之前,必须在当前命令编码器上调用endEncoding方法。 在这一点上,您可以释放内核或保留以备后续使用以节省一些设置成本。
- 如果要在命令缓冲区中编码自己的其他命令,则必须创建一个新的命令编码器。
- 完成命令缓冲区后,使用commit方法将其提交给设备。 然后,内核将开始在GPU上运行。 您可以使用waitUntilCompleted或 addCompletedHandler:
方法在工作完成时收到通知。
每个内核根据特定设备分配; 单个内核可能不会与多个设备一起使用。 这是必要的,因为initWithDevice:方法有时会分配缓冲区和纹理来保存作为参数传递给初始化方法的数据,并且需要一个设备来分配它们。 内核提供了一个copyWithZone:device:方法,允许它们被复制为新设备。
注意:内核对象不是完全线程安全的。 虽然它们可能在多线程上下文中使用,但您不应该尝试同时将多个内核对象写入同一个命令缓冲区。 它们在这方面与命令编码器共享限制。 在有限的情况下,同一个内核可以同时写入多个命令缓冲区。 但是,只有当内核被视为不可变对象时才有效。 也就是说,如果共享内核的子类属性更改,则更改可以反映在另一个线程上,而另一个线程对其工作进行编码,从而导致未定义的行为。 通常最安全的只是制作一个内核对象的副本,每个线程一个。
2. Tuning Hints - 调整提示
Metal Performance Shaders framework
已经针对各种设备和内核参数进行了优异的性能调整。 调整过程的重点是最小化同一命令缓冲区上的背靠背调用的CPU和GPU延迟。 然而,有可能通过将昂贵的操作引入到内核的管道中来无意中撤消此优化工作,从而导致令人失望的整体结果。
以下是避免常见错误的良好做法的一些要素:
- 在排队更多的工作之前,不要等待结果完成。 通过管道到waitUntilCompleted 方法返回的地方,可以有一个明显的延迟(高达2.5 ms)。 而是等待第一个完成时,开始对下一个命令缓冲区进行编码。 使它们也排队,所以他们可以在上一个退出GPU之后立即开始。 不要等待CPU内核注意到第一个命令缓冲区已完成,开始将其分开,最后在开始编写下一个应用程序之前对应用程序进行回调。 通过允许CPU和GPU以这种方式同时工作,吞吐量可以提高高达10倍。
- 分配缓冲区和纹理有很大的代价。 这些成本可能会使CPU淹没,从而阻止GPU的忙碌。 尽可能地预先分配和重用MTLResource对象。
- 在渲染和计算编码器之间切换是有代价的。 每次使用新的渲染编码器时,可能会有大量的GPU模式开关成本,这可能会破坏您的吞吐量。 为了避免成本,尝试一起批量计算工作。 由于使用新的命令缓冲区强制您也创建一个新的命令编码器,请尝试使用较少的命令缓冲区来进行更多的工作。
- 对于某些图像操作,特别是那些涉及多次通过(例如,将多个图像滤波器连接在一起)的图像操作,通过将工作分解成大小为约512 KB的瓦片,性能可以提高高达2倍。 使用sourceRegionForDestinationSize:方法查找每个图块所需的区域。
框架详细结构
下面我们就看一下框架的详细结构。
1. Device Support
-
MPSSupportsMTLDevice
- 决定
Metal Performance Shaders
框架是否支持Metal 器件。
- 决定
2. Image Filters
-
Image Filters
- 应用高性能过滤器,并从图像中提取统计和直方图数据。
3. Neural Networks
使用以前获得的训练数据实施和运行深入学习。
-
- 可以有多于4个通道用于卷积神经网络的纹理。
-
- 用于卷积神经网络的纹理,用于存储要立即使用和丢弃的瞬态数据。
-
Objects that Simplify the Creation of Neural Networks
- 使用滤波器,图像和状态节点的网络以简化神经网络的创建。
-
Convolutional Neural Network Kernels
- 用层建立神经网络。
-
- 创建循环神经网络。
4. Matrices and Vectors
-
Matrices and Vectors
- 求解方程组,分解矩阵和乘法矩阵和向量。
5. Base Types
-
-
Metal Performance Shaders kernels
的标准接口。
-
6. Reference
7. Related Symbols
8. Related Documentation
后记
未完,待续~~~~