Metal Performance Shaders框架詳細解析(一)—— 基本概覽

版本記錄

版本號 時間
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內核的基礎類。 如果需要,它定義所有內核的基線行為,聲明設備運行內核,一些調試選項和用戶友好的標簽。 從這個類派生的是MPSUnaryImageKernelMPSBinaryImageKernel
子類,它們為大多數圖像處理內核(過濾器)定義共享行為,例如邊緣模式,剪切和平鋪支持,用于消耗一個或兩個源紋理的圖像操作。 這些和MPSKernel 類都不是直接使用的。 它們只提供API抽象,在某些情況下可能允許對圖像內核對象進行一些級別的多態操作。

MPSUnaryImageKernelMPSBinaryImageKernel類的子類提供專門的初始化和編碼方法來將各種圖像處理原語編碼到命令緩沖區中,并且還可以自己提供附加的可配置屬性。 許多這樣的圖像過濾器是可用的,例如:

  • 卷積濾波器(Sobel,Gaussian)
  • 形態運算符(擴張,侵蝕)
  • 直方圖運算符(均衡,規范)

所有這些都直接在紋理和緩沖區對象上運行在GPU上。

作為MPSKernel,MPSUnaryImageKernelMPSBinaryImageKernel類用于將多種圖像操作統一為簡單一致的界面和調用序列以應用圖像過濾器,子類實現與規范分歧的細節。 例如,一些過濾器可能需要一小組參數(例如,卷積內核)來管理它們的功能。 然而,使用內核子類的整體順序保持不變:

  • 通過查詢 MPSSupportsMTLDevice 功能,確定Metal Performance Shaders框架是否支持您的設備。
  • 分配通常的Metal對象以驅動Metal計算流水線:MTLDevice, MTLCommandQueue
    MTLCommandBuffer。 如果您的應用程序已經寫入任何命令緩沖區,Metal Performance Shaders可以使用自己的工作負載進行編碼。
  • 創建一個適當的內核 - 例如,一個MPSImageGaussianBlur
    對象,如果你想做一個高斯模糊。 內核通常是輕量級的,但可以重復使用以節省一些安裝時間。 它們不能同時被多個線程使用,因此如果您的應用程序同時使用多個線程中的Metal,請添加額外的內核。 MPSKernel 對象遵守NSCopying協議。
  • 調用內核的編碼方法。 編碼調用的參數因內核類型而異,但操作類似。 他們創建一個命令編碼器,寫命令將內核運行到命令緩沖區,然后結束命令編碼器。 這意味著在調用內核的編碼方法之前,必須在當前命令編碼器上調用endEncoding方法。 在這一點上,您可以釋放內核或保留以備后續使用以節省一些設置成本。
  • 如果要在命令緩沖區中編碼自己的其他命令,則必須創建一個新的命令編碼器。
  • 完成命令緩沖區后,使用commit方法將其提交給設備。 然后,內核將開始在GPU上運行。 您可以使用waitUntilCompletedaddCompletedHandler:
    方法在工作完成時收到通知。

每個內核根據特定設備分配; 單個內核可能不會與多個設備一起使用。 這是必要的,因為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

2. Image Filters

  • Image Filters
    • 應用高性能過濾器,并從圖像中提取統計和直方圖數據。

3. Neural Networks

使用以前獲得的訓練數據實施和運行深入學習。

4. Matrices and Vectors

5. Base Types

6. Reference

7. Related Symbols

8. Related Documentation

后記

未完,待續~~~~

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Demo 地址已更新 https://github.com/Danny1451/MetalLutFilter Me...
    DannyLau閱讀 15,623評論 11 66
  • 本文由幣車HIT(biche.yaofache.com)大V養成計劃支持 本文首發于幣乎平臺: 獵人區塊鏈(htt...
    捕金獵人閱讀 102評論 0 0
  • 現在工作每天要寫交易日記,再來這寫就有些不情愿了,文字就像個容器,覺知著每天的變化和收獲,更想是個出口,一種傾訴,...
    _睛天閱讀 144評論 0 0
  • 最近學校里都在傳廣告系的那個萬年冰山系草談戀愛了。 許言也毫不意外的聽說了這件傳聞。 這天,還在打著游戲的許言忍不...
    伊利女王閱讀 164評論 0 2
  • 一、學習與實踐 1.付出不亞于任何人的努力 2.要謙虛,不要驕傲 3.要每天反省 4.活著,就要感謝 5.積善行,...
    grace2039閱讀 126評論 0 2