Metal框架詳細解析(二) —— 器件和命令(一)

版本記錄

版本號 時間
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框架

該示例使用兩個框架來顯示呈現的內容:MetalMetalKit。 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)接受兩個最終命令:presentcommit。

由于GPU不直接繪制到屏幕上,因此在完成執行命令之前無法繪制像素。 為避免因不完整的drawable導致的糟糕用戶體驗,請調用presentDrawable:方法。 此方法告訴Metal在屏幕上顯示之前等待GPU完成渲染到drawable。

[commandBuffer presentDrawable:view.currentDrawable];

GPU也不會立即執行命令。 只有在調用commit方法后才會執行對MTLRenderCommandEncoderMTLCommandBuffer對象的調用。 然后,Metal會調度命令緩沖區(command buffer)以供執行。 GPU開始執行時,將使用新顏色清除drawable。 GPU完成執行后,渲染的drawable將顯示在屏幕上。

[commandBuffer commit];

后記

本篇主要講述了器件和命令,感興趣的給個贊或者關注~~~

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

推薦閱讀更多精彩內容