原文https://developer.apple.com/documentation/metal/devices_and_commands
設(shè)備和命令
展示CPU如何訪問GPU以及交互
示例代碼
概覽
Metal 提供底層和低功耗的方式去訪問用戶設(shè)備的圖像處理單元(簡稱GPU).
GPU 高效的APP .
開發(fā)一個GPU Metal APP的關(guān)鍵就是 需要理解軟件和硬件.
在這個例子中,你將要學(xué)習(xí)如何寫 通過Metal 以及 基礎(chǔ)的渲染命令 創(chuàng)建APP.
尤其是 你將學(xué)校如何包含一個Metal設(shè)備 ,配置MetalKit View 創(chuàng)建和執(zhí)行GPU命令,顯示渲染內(nèi)容.
Metal 和MetalKit 框架
示例 使用兩個框架 顯示 渲染內(nèi)容. Metal 和 MetalKit .
Metal提供訪問GPU ,MetalKit 提供一個通用的工具 讓開發(fā)者更簡單的開發(fā)Metal APP.
集成在OS 和 其他框架 ,所以你只需要關(guān)注GPU 編程.
MetalKit 框架 使用最多的特性之一 就是 MTKView
類, 這個類 是 封裝了 UIView
或 NSView
對象, 已經(jīng)配置 Metal 特定的 核心動畫 功能.
尤其是 一個MetalKit 視圖 自動設(shè)置和關(guān)鍵 持續(xù)渲染循環(huán) 為你提供 2D 和顯示的資源 ,通用的可繪畫對象, 為每一幀.
注意:
你可以直接使用 核心動畫 來開發(fā)一個Metal app ,但是使用MetlKit 框架 更簡單 更快速,更方便.
分割你的渲染循環(huán)
當(dāng)開發(fā)一個Metal APP 時候 ,經(jīng)常 去 分割 你的渲染循環(huán) 到自定義類中. 使用分離的類 ,你可以更好的管理你的初始化Metal 設(shè)置代碼 以及 每一幀 Metal 命令.
這是一個通用架構(gòu) 展示 AAPLRenderer 類 , 初始化 MetalKit view 和 設(shè)置view 的代理.
_renderer = [[AAPLRenderer alloc] initWithMetalKitView:_view];
if(!_renderer)
{
NSLog(@"Renderer failed initialization");
return;
}
_view.delegate = _renderer;
響應(yīng)視圖事件
MTKViewDelegate
對象 實現(xiàn) mtkView:drawableSizeWillChange:
and drawInMTKView:
方法,這兩個方法 通知你的MetalKit 視圖大小更改 和 繪畫事件.
- 這個視圖調(diào)用
mtkView:drawableSizeWillChange:
方法 當(dāng)Window 尺寸大小 改變時(MacOS), 或者 重新布局操作, 比如 設(shè)備方向改變 (主要發(fā)生在 iOS 和 TvOS ), 你能響應(yīng) 視圖的新尺寸 和 改變你的渲染分辨率 ,如果你需要的話.
- 視圖調(diào)用
drawInMTKView:
方法 當(dāng) 渲染新的一幀的時候, 可以指定 幀率 60 FPS ,通過preferredFramesPerSecond
屬性.
回調(diào) 通常 是 主要 事件 在 你的渲染循環(huán)開始執(zhí)行.
Metal 命令對象
MTLDevice 對象代表 GPU. 可以 通過調(diào)用MTLCreateSystemDefaultDevice ()
,包含 一個單一的MTLDevice 對象 代表 默認(rèn)的GPU 設(shè)備.
MacOS 設(shè)備 有多個GPU ,調(diào)用MTLCopyAllDevices ()
返回 設(shè)備中所有的GPU 設(shè)備數(shù)據(jù), 一個MTLDevice 對象 提供關(guān)于一個GPU的信息.
但是 主要的目的是 創(chuàng)建其他對象 能夠和GPU 互相的.
第一個對象是 所有的app 需要 和 MTLCommandQueue
交互.
_commandQueue = [_device newCommandQueue];
你使用 MTLCommandQueue
對象 去創(chuàng)建和管理MTLCommandBuffer
對象,確保 他們按照正確的順序 發(fā)送指令到GPU
每一幀 , MTLCommandBuffer
對象 是 創(chuàng)建 和 填充 命令 被GPU 執(zhí)行.
id <MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
這有不同類型的GPU , 每一個接受 和中斷命令在自己獨一無二的方法.
MTLCommandBuffer
對象 合并 這些命令 到單一的提交. 但是他們必須第一個編碼設(shè)備無關(guān)的方法 使用 MTLCommandEncoder
對象. 這是少數(shù)不同的類型 MTLCommandEncoder
類 , 每一個使用不同類型在GPU.
這示例 使用 MTLRenderCommandEncoder
子類 指定編碼渲染命令到 commandBuffer.
本示例 使用MTLRenderCommandEncoder
對象 編碼GPU命令, 渲染像素到MetalKit視圖的可繪畫對象.
渲染編碼器 必須指定 與可繪畫對象 相關(guān)聯(lián).
為了創(chuàng)建 MTLRenderCommandEncoder
你必須創(chuàng)建一個MTLRenderPassDescriptor
MTLRenderPassDescriptor
是輕量級,臨時對象, 一些配置屬性 使用 現(xiàn)存的 MTLCommandBuffer
對象 創(chuàng)建 新的 MTLRenderCommandEncoder
.
之后,MTLRenderPassDescriptor
不再需要.
下面的示意插圖 表達(dá) Metal 命令對象之間的關(guān)系,總結(jié)為:
Command Queue
創(chuàng)建Command buffers
Command encoders 將命令編碼后 傳入到 Command Buffers
Command buffers 被提交到GPU
GPU 執(zhí)行編碼命令 和將渲染后的結(jié)果顯示到可繪畫對象.
Prepare a Frame
MetalKit視圖 創(chuàng)建 新的 MTLRenderPassDescriptor
在每一幀. 提供currentRenderPassDescriptor
屬性.
該渲染管道描述 是 預(yù)編譯的 視圖指定屬性, 一些起源來自 視圖的可繪畫對象, 能夠使用容易和方便的 去創(chuàng)建 新的 MTLRenderCommandEncoder
對象.
// Obtain a renderPassDescriptor generated from the view's drawable textures
MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
// If we've gotten a renderPassDescriptor we can render to the drawable, otherwise we'll
// skip any rendering this frame because we have no drawable to draw to
if(renderPassDescriptor != nil)
{
id <MTLRenderCommandEncoder> renderEncoder =
[commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
命令編碼 到 MTLRenderCommandEncoder
對象渲染 可繪畫對象 , 默認(rèn)情況下 創(chuàng)建MTLRenderCommandEncoder
對象 默認(rèn) 編碼 清除命令(clear command) 到 GPU執(zhí)行 在 其他渲染命令之前. 清除命令(clear command
) 設(shè)置 可繪畫對象的像素 去 清除顏色 更新 在渲染循環(huán)的開始.
view.clearColor = MTLClearColorMake(color.red, color.green, color.blue, color.alpha);
Finalize a Frame
Metal app 調(diào)用MTLRenderCommandEncoder
方法 編碼明確的渲染命令 到 command buffer. 簡單來說 這個案例 不實際編碼 渲染命令. 僅僅含蓄的清除命令被編碼. 在創(chuàng)建 MTLRenderCommandEncoder
之后 , 本案例簡單的調(diào)用 endEncoding
方法 指示 編碼器已經(jīng)完成編碼操作.
因為GPU沒有直接繪制在屏幕, 防止2 繪畫像素 在完成繪制之前 執(zhí)行命令. 為了避免糟糕的用戶體驗 結(jié)果 不完全可繪畫, 你可以調(diào)用 presentDrawable :
方法. 該方法告訴Metal 等待 直到 GPU完成渲染可繪畫對象 在展示屏幕之前.
[commandBuffer presentDrawable:view.currentDrawable];
GPU 不能立即執(zhí)行命令, 調(diào)用MTLRenderCommandEncoder
或者MTLCommandBuffer
對象 執(zhí)行 在提交方法以后調(diào)用. Metal 調(diào)度 command buffer 的執(zhí)行
當(dāng)GPU 開始執(zhí)行的時候,可繪畫對象 被清理為新的顏色. 當(dāng)GPU完成執(zhí)行以后,渲染可繪畫對象唄展示到屏幕上.
[commandBuffer commit];
接下來
在本示例中, 你學(xué)習(xí)了如何利用Metal框架編寫一個app以及了解基本的渲染命令到GPU.
在 你好,三角形示例中, 你將要通過Metal框架學(xué)習(xí)基本的幾何體.