Metal框架詳細解析(二十三) —— 基本課程之CPU和GPU同步(三)

版本記錄

版本號 時間
V1.0 2018.10.09 星期二

前言

很多做視頻和圖像的,相信對這個框架都不是很陌生,它渲染高級3D圖形,并使用GPU執行數據并行計算。接下來的幾篇我們就詳細的解析這個框架。感興趣的看下面幾篇文章。
1. Metal框架詳細解析(一)—— 基本概覽
2. Metal框架詳細解析(二) —— 器件和命令(一)
3. Metal框架詳細解析(三) —— 渲染簡單的2D三角形(一)
4. Metal框架詳細解析(四) —— 關于GPU Family 4(一)
5. Metal框架詳細解析(五) —— 關于GPU Family 4之關于Imageblocks(二)
6. Metal框架詳細解析(六) —— 關于GPU Family 4之關于Tile Shading(三)
7. Metal框架詳細解析(七) —— 關于GPU Family 4之關于光柵順序組(四)
8. Metal框架詳細解析(八) —— 關于GPU Family 4之關于增強的MSAA和Imageblock采樣覆蓋控制(五)
9. Metal框架詳細解析(九) —— 關于GPU Family 4之關于線程組共享(六)
10. Metal框架詳細解析(十) —— 基本組件(一)
11. Metal框架詳細解析(十一) —— 基本組件之器件選擇 - 圖形渲染的器件選擇(二)
12. Metal框架詳細解析(十二) —— 基本組件之器件選擇 - 計算處理的設備選擇(三)
13. Metal框架詳細解析(十三) —— 計算處理(一)
14. Metal框架詳細解析(十四) —— 計算處理之你好,計算(二)
15. Metal框架詳細解析(十五) —— 計算處理之關于線程和線程組(三)
16. Metal框架詳細解析(十六) —— 計算處理之計算線程組和網格大小(四)
17. Metal框架詳細解析(十七) —— 工具、分析和調試(一)
18. Metal框架詳細解析(十八) —— 工具、分析和調試之Metal GPU Capture(二)
19. Metal框架詳細解析(十九) —— 工具、分析和調試之GPU活動監視器(三)
20. Metal框架詳細解析(二十) —— 工具、分析和調試之關于Metal著色語言文件名擴展名、使用Metal的命令行工具構建庫和標記Metal對象和命令(四)
21. Metal框架詳細解析(二十一) —— 基本課程之基本緩沖區(一)
22. Metal框架詳細解析(二十二) —— 基本課程之基本紋理(二)

CPU and GPU Synchronization - CPU和GPU同步

演示如何更新緩沖區數據并同步CPU和GPU之間的訪問。

在此示例中,您將學習如何正確更新和渲染CPU與圖形處理單元(GPU)之間共享的動畫資源。 特別是,您將學習如何修改每幀數據,避免數據訪問危險,并且并行執行CPU和GPU工作。


CPU/GPU Parallelism and Shared Resource Access - CPU / GPU并行和共享資源訪問

CPU和GPU是獨立的異步處理器。在Metal應用程序或游戲中,CPU對命令進行編碼,GPU執行命令。在每個幀中重復該序列,并且當CPU和GPU都完成其工作時完成全幀的工作。 CPU和GPU可以并行工作,無需等待彼此完成工作。例如,GPU可以執行幀1的命令,而CPU對幀2的命令進行編碼。

這種CPU / GPU并行性對于您的Metal應用程序或游戲具有很大的優勢,有效地使您可以同時在兩個處理器上運行。但是,這些處理器仍然可以協同工作,并且通常可以訪問相同的共享資源,例如頂點緩沖區或片段紋理。必須小心處理共享資源訪問;否則,CPU和GPU可能同時訪問共享資源,從而導致競爭條件和數據損壞。

與大多數Metal應用或游戲一樣,此示例通過更新每個幀中的頂點數據來渲染動畫內容。請考慮以下順序:

  • 1) 渲染循環啟動一個新幀。
  • 2) CPU將新頂點數據寫入頂點緩沖區。
  • 3) CPU對渲染命令進行編碼并提交命令緩沖區。
  • 4) GPU開始執行命令緩沖區。
  • 5) GPU從頂點緩沖區讀取頂點數據。
  • 6) GPU將像素渲染到drawable。
  • 7) 渲染循環完成幀。

在此序列中,CPU和GPU共享一個頂點緩沖區。 如果處理器在開始自己的工作之前等待彼此完成工作,則共享頂點緩沖區沒有訪問沖突。 此模型避免了訪問沖突,但浪費了寶貴的處理時間:當一個處理器正在工作時,另一個處理器處于空閑狀態。

Metal旨在最大化CPU和GPU并行性,因此這些處理器應該保持忙碌并且應該同時工作。 理想情況下,GPU應該讀取幀1的頂點數據,而CPU正在為幀2寫入頂點數據。但是,共享單個頂點緩沖區意味著CPU可以在GPU讀取之前覆蓋前一幀的頂點數據,從而導致難看的渲染效果。

為了減少處理器空閑時間并避免訪問沖突,可以使用多個緩沖區而不是單個緩沖區來共享頂點數據。 例如,CPU和GPU可以共享幀1的頂點緩沖區1,幀2的頂點緩沖區2,幀3的頂點緩沖區3,等等。 在此模型中,共享頂點數據在每個幀中保持一致,并且處理器同時訪問不同的頂點緩沖區。


Implement a Triple Buffer Model - 實現三重緩沖模型

此示例呈現數百個小四邊形,也稱為sprites。要為精靈設置動畫,樣本會在每個幀的開頭更新它們的位置,并將它們寫入頂點緩沖區。幀完成后,CPU和GPU不再需要該幀的頂點緩沖區。丟棄使用過的頂點緩沖區并為每個幀創建一個新的頂點緩沖區是浪費的。相反,可以使用可重用頂點緩沖區的FIFO隊列實現更可持續的模型。

隊列中的最大緩沖區數由MaxBuffersInFlight的值定義,設置為3。此常量值定義設備的任何部分可以同時處理的最大幀數;這包括應用程序,驅動程序或顯示。該應用程序僅適用于CPU或GPU中的框架,但OS本身可以在驅動程序或顯示級別的框架上工作。使用三個緩沖區可為設備提供足夠的余地,以便高效且有效地工作。緩沖區太少會導致處理器停頓和資源爭用,而緩沖區太多會導致內存開銷和幀延遲增加。

for(NSUInteger bufferIndex = 0; bufferIndex < MaxBuffersInFlight; bufferIndex++)
{
    _vertexBuffers[bufferIndex] = [_device newBufferWithLength:spriteVertexBufferSize
                                                       options:MTLResourceStorageModeShared];
}

drawInMTKView:渲染循環開始時,示例遍歷_vertexBuffer數組中的每個緩沖區,每幀只更新一個緩沖區。 在每三個幀結束時,在使用所有三個緩沖區之后,樣本循環回到數組的開始并更新_vertexBuffer [0]緩沖區的內容。


Manage the Rate of Work - 管理工作率

為避免過早覆蓋數據,樣本必須確保GPU在重新使用之前已處理緩沖區的內容。 否則,CPU可能會覆蓋先前三幀寫入但尚未被GPU讀取的頂點數據。 當CPU為GPU生成工作的速度超過GPU完成工作時,就會出現這種情況。

如果CPU在GPU之前運行得太遠,則此示例使用信號量等待全幀完成。

_inFlightSemaphore = dispatch_semaphore_create(MaxBuffersInFlight);

在渲染循環開始時,信號量檢查進行或等待信號。 如果可以使用或重用緩沖區,則CPU工作繼續進行;否則,它等待緩沖區可用。

dispatch_semaphore_wait(_inFlightSemaphore, DISPATCH_TIME_FOREVER);

GPU無法直接發信號通知信號,但它可以向CPU發出完成回調。

[commandBuffer addCompletedHandler:^(id<MTLCommandBuffer> buffer)
{
    dispatch_semaphore_signal(block_sema);
}];

addCompletedHandler:方法注冊在GPU完成命令緩沖區后立即調用的代碼塊。 此命令緩沖區與為幀提交頂點緩沖區的命令緩沖區相同,因此接收完成回調指示可以安全地重用頂點緩沖區。

后記

本篇主要講述了CPU和GPU同步,感興趣的給個贊或者關注~~~

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

推薦閱讀更多精彩內容