[MetalKit]36-Introducing-Metal-2介绍Metal2

本系列文章是对 metalkit.org 上面MetalKit内容的全面翻译和学习.c++

MetalKit系统文章目录git


今年的WWDC多是有史以来最重要的,至少目前咱们 - Metal开发者 - 终于被关注了.我能够诚心诚意地讲这是我生命中最棒的一周!github

让咱们看看Games and Graphics游戏和图形新闻.最意想不到的是,将Metal重命名为Metal 2.自从它在2014年第一次被发布后,它终于有了最显著的增长和加强,确实,但咱们必须认可:没人预见到这一变化的来临.最意想不到的奖品是新的ARKit框架.在keynote演示以后仅仅几周,就已经有了大量大胆有趣的加强现实项目放出来. ARKit融入Metal很是容易.最后,最有影响力的奖品是VR.这是由于虚拟现实如今可以实现更低延迟,更高帧率,还有更强劲的内置显卡,如今也有了外置显卡external GPUs.swift

vr.png

Model I/O, SpriteKitSceneKit框架也都添加了新特性.其它使人感兴趣的增长是用于机器学习 machine learningCoreMLVision框架.本文只关注Metal中的新特点:数组

1). MPS - Metal Performance Shaders目前在macOS上也可使用了,添加的新特性包括:网络

  • 四种新的图片处理基本体(Image Keypoints图像关键点, Bilinear Rescale双线性重缩放, Image Statistics图像统计, Element-wise Arithmetic Operations元素运算符).
  • 新的线性代数对象如MPSVector, MPSMatrixMPSTemporaryMatrix,还有*BLAS-style matrix-matrix and matrix-vector multiplication - BLAS式的矩阵-矩阵及矩阵-向量乘法,LAPACK-style triangular matrix factorization and linear solvers - LAPACK式三角矩阵分解与线性求解器`.
  • 一系列新的CNN基本体.
  • Binary二进制卷积, XNOR同或卷积, Dilated空洞卷积, Sub-pixel子像素卷积Transpose转置卷积的卷积层被添加到现有的Standard标准卷积基本体内.
  • 添加了一个新的Neural Network Graph神经网络图形API,在用过滤器和图形节点来描述神经网络时很是有用.
  • 如今也有了Recurrent Neural Networks循环神经网络,它能够改善CNNs一对一的局限性,实现一对多和多对多的关系.

2). Argument Buffers参数缓冲器/变元缓冲器 - 多是今年对框架最重要的添加.在传统的加强模型中,咱们会为每一个对象调用许多函数来设置缓冲器,纹理,线性采样,最后为该对象调用绘制命令. app

ArgumentBuffers1.png

正如你想象的那样,,当将该数量乘以物体总数量及绘制帧数时,调用数急剧增加.最终这会限制屏幕上出现的物体数量. 框架

ArgumentBuffers2.png

Argument Buffers参数缓冲器引入了一个高效的新途径来使用资源,经过采用始终存在的indirect behavior间接行为,来将其应用到纹理,采样,状态,指向其它缓冲器的指针,等等.参数缓冲器将只有每物体2个API调用:设置参数缓冲器,而后绘制.这样能够绘制更多物体. 机器学习

ArgumentBuffers3.png

参数缓冲器很容易使用,就像匹配着色器数据和主机数据同样:函数

struct Material {
    float intensity;
    texture2d<float> aTexture;
    sampler aSampler;
}

kernel void compute(constant Material &material [[ buffer(0) ]]) {
    ...
}
复制代码

CPU上,参数缓冲器是被MTLArgumentEncoder对象建立和使用的,而后它能够轻易地在CPUGPU之间作位块传送:

let function = library.makeFunction(name: "compute")
let encoder = function.makeIndirectArgumentEncoder(bufferIndex: 0)
encoder.setTexture(myTexture, index: 0)
encoder.constantData(at: 1).storeBytes(of: myPosition, as: float4)
复制代码

可是使用dynamic indexing动态索引特性的话还能够更好.举例,当渲染拥挤时,参数缓冲器数组能够将全部实例(物体)的数据打包到一块儿.而后,再也不须要每一个物体调用两次,改成每帧2个API调用:一个设置到缓冲器,一个为大量实例绘制索引的基本体!

ArgumentBuffers4.png

另外一个应用参数缓冲器的例子是,当运行粒子模拟时.对此,咱们有resource setting on the GPU特性,它的意思是有一个参数缓冲器数组,每一个粒子(线程)一个缓冲器.全部的粒子特性(位置,材料,等)在GPU上的参数缓冲器中被建立和储存的,这样当一个粒子须要某个属性时,好比材料,它将从参数缓冲器中复制出来,而再也不须要从CPU获取,这样能够避免昂贵的CPUGPU之间的复制开销.

ArgumentBuffers5.png

复制内核很简单,可让你赋值一个常数,从源对象部分复制或者彻底复制到目标对象:

kernel void reuse(constant Material &source [[ buffer(0) ]],
                  device Material &destination [[ buffer(1) ]]) {
    destination.intensity = 0.5f;
    destination.aTexture = source.aTexture;
    destination = source;
}
复制代码

最后,还有一个应用例子是引用其它参数缓冲器(multiple indirections).想象有一个instance结构体表示一个指向Material材料结构体的实例(特征),这样的话就会有许多实例指向同一个材料.一样的,想象另外一个表示一个树状节点的结构体,其中每一个节点将会有一个指针指向Instance实例结构体,起到节点中的一个实例数组的做用:

struct Instance {
    float4 position;
    device Material *material;
}

struct Node {
    device Instance *instances;
}
复制代码

注意:目前为止,只有Tier 2设置支持全部的参数缓冲器特性.从Metal 2开始,GPU设备分红了Tier 1(总体式)和Tier 2(分离式).

3). Raster Order Groups光栅扫描顺序组 - 一个新的片断着色器同步基本体,它在片断着色器访问内存时容许对顺序进行更精细的控制.例如,当使用自定义混合时,大部分图形APIs保证混合是按绘制调用顺序发生的.然而,GPU的并行线程须要一个方法来防止竞争条件.Raster Order Groups光栅扫描顺序组经过提供给咱们一个隐含的Wait命令来保证.

RasterOrderGroups.png

在传统混合模式下,要建立竞争条件:

fragment void blend(texture2d<float, access::read_write> out[[ texture(0) ]]) {
    float4 newColor = 0.5f;
    // non-atomic memory access without any synchronization
    float4 oldColor = out.read(position);
    float4 blended = someCustomBlendingFunction(newColor, oldColor);
    out.write(blended, position);
}
复制代码

须要作的就是添加Raster Order Groups属性到纹理(或资源)中来解决访问冲突:

fragment void blend(texture2d<float, access::read_write> 
				out[[texture(0), raster_order_group(0)]]) {
    float4 newColor = 0.5f;
    // the GPU now waits on first access to raster ordered memory
    float4 oldColor = out.read(position);
    float4 blended = someCustomBlendingFunction(newColor, oldColor);
    out.write(blended, position);
}
复制代码

4). ProMotion自适应刷新率 - 目前只在iPad Pro显示屏上可用.没有ProMotion时典型的帧率是60FPS(16.6ms/frame):

promotion1.png

使用ProMotion后帧率提高到120FPS(8.3ms/frame),这对于用户输入很是有用,如手指触摸或pencil使用:

promotion2.png

ProMotion也提供了弹性机制来刷新显示图片,因此咱们不须要使用固定帧率.不使用ProMotion会有图片刷新不一致,这对用户体验很很差.开发者为了实现一致性,一般会将峰值帧率强制保持在30FPS,而不是理想的48FPS(20.83ms/frame):

promotion3.png

使用ProMotion我如今能够每4ms就有一个刷新点,而再也不是每16ms(竖直的白线):

promotion4.png

ProMotion一样有助于掉帧.不使用ProMotion时,可能一帧画面花了太长时间来显示,就错过了截止期限:

promotion5.png

ProMotion经过对帧扩展4ms而不是一个完整帧(16.6ms)来解决这个问题:

promotion6.png

UIKit动画自动使用ProMotion,可是在Metal视图中使用ProMotion,你须要在项目的Info.plist文件中设置一下,禁用最小帧率.而后你就可使用3个显示APIs中的一个了.传统的present(drawable:) 将会在GPU结束渲染一帧画面(在固定帧率显示屏上为16.6ms,在ProMotion显示屏上为4ms)后直接呈现图像.第二个APIpresent(drawable, afterMinimumDuration:) 在固定帧率显示屏上提供了帧与帧之间的最大间隔.第三个APIpresent(drawable, atTime:),在建立自定义动画循环时很是有用,或者试图与其它输出,好比音频,同步时很是有用.这里是如何实现它的例子:

let targetTime = 0.1
let drawable = metalLayer.nextDrawable()
commandBuffer.present(drawable, atTime: targetTime)
// after 1-2 frames
let presentationDelay = drawable.presentedTime - targetTime
复制代码

首先,当你想要展现画面时,设置一个时间,而后渲染场景到一个命令缓冲器中.而后等待下一帧(下几帧),最后检验延迟,这样你就能够调整下一帧的时间.

5). Direct to Display直连显示屏 - 新的方式,用于将渲染器的内容以最小延迟直接发送到外置显示器(如,VR中使用的头戴显示设备).一个画面在GPU结束渲染后到最终出如今显示屏上以前会有两条路径可选.第一条是当系统将其它视图和层混合起来造成最终图像时,典型的UI方案:

DirectToDisplay1.png

当建立一个不包含混合,缩放或其它视图/图层的全屏应用程序时,第二条途径容许显示屏直接访问咱们渲染的内存,这样节省了大量系统资源,避免了不少开销:

DirectToDisplay2.png

然而,这须要知足下列条件:

  • 图层是不透明的
  • 没有遮罩或圆角
  • 全屏,或带有不透明的黑色状态栏和背景
  • 被渲染尺寸最大和显示屏尺寸同样大
  • 颜色空间和像素格式与显示屏兼容

颜色空间的要求,使得判断什么时候Direct to Display模式能使用变得简单.例如,若是你在使用P3显示屏却禁用了P3模式,当试图使用Direct to Display模式时会很容易探测出来.

6). Other Features其它特性 - 包含但不限于:

  • memory usage queries内存使用查询 - 如今有了新的APIs能够在每次分配时查询内存使用,还有设备的总GPU内存分配:
MTLResource.allocatedSize
MTLHeap.currentAllocatedSize
MTLDevice.currentAllocatedSize
复制代码
  • SIMDGroup scoped functions单指令多数据流(SIMD)群组做用域函数 - 容许数据在SIMD组内被注册者共享,避免加载/储存操做:

    SIMDGroup.png

  • non-uniform threadgroup sizes非一致性线程组尺寸 - 帮助咱们不浪费GPU循环,避免遇到边缘/边界状况:

    nonuniform.png

  • Viewport Arrays视口数组 - 在macOS上如今支持多达16视口,以供顶点函数在渲染时选择顶点,在VR中结合实例很是有用.

  • Multisample Pattern Control多重采样类型控制 - 容许选择在单个像素中MSAA处于什么采样模式,对于自定义反走样很是有用.

  • Resource Heaps资源堆 - 如今在macOS上也可使用了.它容许如下时间:控制内存分配,快速从新分配,资源混叠,快速绑定的组相关资源.

  • 其它特性,包括:

Feature特性 Description描述
Linear Textures线性纹理 MTLBuffer建立纹理,无需复制
Function Constant for Argument Indexes为参数索引的函数常量 特殊的二进制编码,供着色器参数改变绑定索引
Additional Vertex Array Formats附加顶点数组格式 添加1个/2个组件的顶点格式,及一个BGRA8顶点格式.
IOSurface Textures IO表面纹理 iOS上从IOSurfaces建立MTLTextures
Dual Source Blending双重来源混合 带有两源参数的附加混合模式

我已经为最重要的新特性制做了一张表,来讲明在最新版本的操做系统上是不是新特性.

features.png

最后,还有几行我写的代码,来测试内置与外置GPU之间的不一样点:

gpuCompare.png

全部图片都来自WWDC报告. 源代码source code已发布在Github上.

下次见!

相关文章
相关标签/搜索