版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2018.10.04 星期四 |
前言
很多做視頻和圖像的,相信對這個框架都不是很陌生,它渲染高級3D圖形,并使用GPU執行數據并行計算。接下來的幾篇我們就詳細的解析這個框架。感興趣的看下面幾篇文章。
1. Metal框架詳細解析(一)—— 基本概覽
Overview - 概覽
Metal為用戶設備的圖形處理單元(GPU)提供低級別,低開銷訪問,從而生成有效使用GPU的優秀應用程序。 開發此類應用程序的關鍵是從整體上理解底層軟件和硬件交互。
在此文中,您將學習如何編寫使用Metal的應用程序并向GPU發出基本渲染命令。 特別是,您將學習如何獲取Metal
設備,配置MetalKit
視圖,創建和執行GPU命令以及顯示渲染內容。
The Metal and MetalKit Frameworks - Metal和MetalKit框架
該示例使用兩個框架來顯示呈現的內容:Metal
和MetalKit
。 Metal提供對GPU的訪問,MetalKit提供了常用的實用程序,可以更輕松地開發Metal應用程序。 它們與OS和其他框架無縫集成,因此您可以專注于GPU編程。
MetalKit
最有用的功能之一是MTKView
類,它包裝UIView或NSView對象并配置特定于Metal的Core Animation
功能。 特別是,MetalKit視圖自動設置和管理連續渲染循環,為每個幀提供2D可顯示資源,通常稱為可繪制資源。
注意:您可以直接使用
Core Animation
開發Metal應用程序,但使用MetalKit
更容易,更快捷,更方便。
Separate Your Rendering Loop - 分離渲染循環
在開發Metal應用程序時,將渲染循環分離到自己的類中通常很有用。 使用單獨的類,您可以更好地管理初始Metal設置代碼和每幀Metal命令。 這個通用結構由AAPLRenderer
類演示,該類使用MetalKit
視圖初始化并被指定為視圖的代理。
_renderer = [[AAPLRenderer alloc] initWithMetalKitView:_view];
if(!_renderer)
{
NSLog(@"Renderer failed initialization");
return;
}
_view.delegate = _renderer;
Respond to View Events - 響應視圖事件
MTKViewDelegate
對象實現mtkView:drawableSizeWillChange:
和drawInMTKView:
方法。 這些方法通知渲染器MetalKit視圖的大小調整和繪圖事件。
每當窗口大小發生變化
(macOS)
或發生重新布局操作(例如設備方向更改)時,視圖都會調用mtkView:drawableSizeWillChange:
方法(iOS和tvOS)。 然后,您可以根據需要響應視圖的新大小并更改渲染分辨率。每當需要渲染新幀時,視圖都會調用
drawInMTKView:
方法,這是由視圖的preferredFramesPerSecond
屬性上設置的幀速率(例如,60 FPS)指定的。 此回調通常是開始執行渲染循環的主要事件。
Metal Command Objects - Metal命令對象
MTLDevice
對象表示GPU。 通常,您調用MTLCreateSystemDefaultDevice()
方法以獲取表示設備的默認GPU的單個MTLDevice對象。 MTLDevice對象提供有關GPU的信息,但其主要目的是創建可與GPU交互的其他對象。
所有應用程序需要與GPU交互的第一個對象是MTLCommandQueue
對象。
_commandQueue = [_device newCommandQueue];
您使用MTLCommandQueue
對象來創建和組織MTLCommandBuffer
對象,確保它們以正確的順序發送到GPU。
對于每個幀,創建一個新的MTLCommandBuffer
對象并填充由GPU執行的命令。
id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
有許多不同類型的GPU,每個GPU都以自己獨特的方式接受和解釋命令。 MTLCommandBuffer
對象將這些命令合并為單個提交,但必須首先使用MTLCommandEncoder
對象以與設備無關的方式對它們進行編碼。有幾種不同類型的MTLCommandEncoder
類,每種類用于在GPU上執行不同類型的任務。此示例演示了如何使用MTLRenderCommandEncoder
子類,該子類專門將渲染命令編碼到命令緩沖區中。
此示例使用MTLRenderCommandEncoder
對象對GPU命令進行編碼,這些命令將像素渲染到MetalKit
視圖的drawable
。為此,渲染命令編碼器必須與此drawable
特別關聯。
要創建MTLRenderCommandEncoder
對象,必須首先創建MTLRenderPassDescriptor
對象。 MTLRenderPassDescriptor
是一個輕量級臨時對象,具有許多可配置屬性,現有MTLCommandBuffer
對象使用這些屬性來創建新的MTLRenderCommandEncoder
對象。之后,不再需要MTLRenderPassDescriptor
對象。
下圖說明了Metal的命令對象之間的關系??偨Y一下:
- 1) 命令緩沖區
(Command buffers)
是從命令隊列(command queue)
創建的 - 2) 命令編碼器
(Command encoders)
將命令編碼到命令緩沖區中 - 3) 然后提交命令緩沖區并將其發送到GPU
- 4) GPU執行命令并將結果呈現為可繪制的
Prepare a Frame - 準備一幀
MetalKit
視圖為每個幀創建一個新的MTLRenderPassDescriptor
對象,通過currentRenderPassDescriptor
屬性提供。 此渲染過程描述符預先配置了特定于視圖的屬性,一些屬性派生自視圖的drawable
,可用于輕松方便地創建新的MTLRenderCommandEncoder
對象。
// Obtain a render pass descriptor, generated from the view's drawable
MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
// If you've successfully obtained a render pass descriptor, you can render to
// the drawable; otherwise you skip any rendering this frame because you have no
// drawable to draw to
if(renderPassDescriptor != nil)
{
id<MTLRenderCommandEncoder> renderEncoder = [commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
編碼到此MTLRenderCommandEncoder
對象中的命令呈現給視圖的drawable
。 默認情況下,創建MTLRenderCommandEncoder
對象會隱式編碼GPU在任何其他渲染命令之前執行的清除clear
命令。 clear命令將drawable
的像素設置為在渲染循環開始時為clear color
。
Color color = [self makeFancyColor];
view.clearColor = MTLClearColorMake(color.red, color.green, color.blue, color.alpha);
Finalize a Frame - 完成一幀
通常,Metal
應用程序調用許多MTLRenderCommandEncoder
方法,這些方法將顯式渲染命令編碼到命令緩沖區中。 為簡單起見,此示例實際上不編碼顯式渲染命令,只有隱式清除命令被編碼。 創建MTLRenderCommandEncoder
對象后,該示例只調用endEncoding
方法以指示編碼器已完成。
編碼器完成后,命令緩沖區(command buffer)
接受兩個最終命令:present
和commit
。
由于GPU不直接繪制到屏幕上,因此在完成執行命令之前無法繪制像素。 為避免因不完整的drawable
導致的糟糕用戶體驗,請調用presentDrawable:
方法。 此方法告訴Metal在屏幕上顯示之前等待GPU完成渲染到drawable。
[commandBuffer presentDrawable:view.currentDrawable];
GPU也不會立即執行命令。 只有在調用commit
方法后才會執行對MTLRenderCommandEncoder
或MTLCommandBuffer
對象的調用。 然后,Metal會調度命令緩沖區(command buffer)
以供執行。 GPU開始執行時,將使用新顏色清除drawable
。 GPU完成執行后,渲染的drawable
將顯示在屏幕上。
[commandBuffer commit];
后記
本篇主要講述了器件和命令,感興趣的給個贊或者關注~~~