[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上.

下次見!

相關文章
相關標籤/搜索