版本記錄
版本號 | 時間 |
---|---|
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框架詳細解析(二十二) —— 基本課程之基本紋理(二)
23. Metal框架詳細解析(二十三) —— 基本課程之CPU和GPU同步(三)
Argument Buffers - 參數緩沖
學習如何使用參數緩沖區。
-
- 演示如何使用參數緩沖區管理資源組。
-
Argument Buffers with Arrays and Resource Heaps
- 演示如何使用數組定義參數緩沖區,并通過將參數緩沖區與資源堆組合來減少CPU開銷。
-
Argument Buffers with GPU Encoding
- 演示如何使用計算傳遞對參數緩沖區進行編碼,然后在后續渲染過程中訪問其參數。
Basic Argument Buffers - 基本參數緩沖區
演示如何使用參數緩沖區管理資源組。
參數緩沖區表示一組資源,可以將這些資源共同指定為圖形或計算功能的參數。 您可以使用參數緩沖區來降低CPU開銷,簡化資源管理并實現GPU驅動的管道。
在此示例中,您將學習如何在參數緩沖區中指定,編碼,設置和訪問資源。 特別是,您將了解在參數緩沖區中管理資源組而不是單個資源的優勢。 該示例使用紋理,采樣器,緩沖區和常量編碼到參數緩沖區中呈現靜態四邊形。
CPU Overhead and Argument Buffers - CPU開銷和參數緩沖區
Metal命令是高效的,當應用程序訪問GPU時,會產生最小的CPU開銷。 但是,每個命令都會產生一些開銷;要進一步減少金額,請使用以下策略:
- 使用更少的CPU命令執行更多GPU工作。
- 避免重復昂貴的CPU命令。
Metal的參數緩沖區功能可以減少應用程序關鍵路徑中CPU命令的數量和性能成本(例如,在應用程序的渲染循環中)。 參數緩沖區允許您在單個緩沖區內對多個資源進行分組和編碼,而不是單獨編碼每個資源。 通過使用參數緩沖區,您可以將大量的CPU開銷從應用程序的關鍵路徑轉移到其初始設置。
Individual Resources versus Argument Buffers - 個人資源與參數緩沖區
Metal應用程序,尤其是游戲,通常包含多個3D對象,每個對象都與一組資源相關聯,如紋理,采樣器,緩沖區和常量。 為了渲染每個對象,apps編碼Metal命令,在發出繪制調用之前將這些資源設置為圖形函數的參數。
您可以通過為每個資源調用MTLRenderCommandEncoder
方法(如setVertexBuffer:offset:atIndex:
或setFragmentTexture:atIndex:
)將各個資源設置為參數。
設置單個資源的命令可能變得繁多且昂貴,尤其是對于大型應用程序或游戲。 相反,您可以將相關資源分組到參數緩沖區中,然后將整個緩沖區設置為圖形函數的單個參數。 這種方法大大降低了CPU開銷,并且仍然提供對您資源的單獨GPU訪問。
參數緩沖區表示為MTLBuffer
對象。 因此,您可以通過為每個參數緩沖區調用MTLRenderCommandEncoder
方法(如setVertexBuffer:offset:atIndex:
或setFragmentBuffer:offset:atIndex:
)將它們設置為參數。
注意:要訪問參數緩沖區中的各個資源,必須為要使用的每個資源調用
useResource:usage:
方法。 有關更多信息,請參閱Enable the GPU Memory of Resources in the Argument Buffer
部分。
Define Argument Buffers - 定義參數緩沖區
參數緩沖區在Metal Shading Language
中定義為自定義結構。 每個結構元素表示一個單獨的資源,聲明為紋理,采樣器,緩沖區或常量數據類型。 結構元素還與使用[[id(n)]]
屬性限定符聲明的整數相關聯,該整數指定單個資源的索引。
此示例中的參數緩沖區被聲明為FragmentShaderArguments
結構,這是它的定義:
typedef struct FragmentShaderArguments {
texture2d<half> exampleTexture [[ id(AAPLArgumentBufferIDExampleTexture) ]];
sampler exampleSampler [[ id(AAPLArgumentBufferIDExampleSampler) ]];
device float *exampleBuffer [[ id(AAPLArgumentBufferIDExampleBuffer) ]];
uint32_t exampleConstant [[ id(AAPLArgumentBufferIDExampleConstant) ]];
} FragmentShaderArguments;
此參數緩沖區包含以下資源:
-
exampleTexture
,索引為0的2D紋理。 -
exampleSampler
,索引為1的采樣器。 -
exampleBuffer
,索引為2的浮點緩沖區。 -
exampleConstant
,一個索引為3的uint32_t
常量。
此示例的片段函數fragmentShader
使用參數緩沖區作為單個參數。
fragment float4
fragmentShader( RasterizerData in [[ stage_in ]],
device FragmentShaderArguments & fragmentShaderArgs [[ buffer(AAPLFragmentBufferIndexArguments) ]])
fragmentShaderArgs
參數是FragmentShaderArguments
類型的緩沖區。 當樣本將MTLBuffer
設置為片段函數的參數時,該函數將fragmentShaderArgs
參數中的數據解釋為具有紋理,采樣器,緩沖區和常量的參數緩沖區(由FragmentShaderArguments
結構定義)。
Encode Resources into an Argument Buffer - 將資源編碼到參數緩沖區中
在函數訪問緩沖區之前,必須將各個資源編碼到參數緩沖區中。 這是通過從使用參數緩沖區的MTLFunction
創建MTLArgumentBufferEncoder
來實現的。
此示例從fragmentShader
函數創建MTLArgumentBufferEncoder
,該函數包含fragmentShaderArgs
參數。
id <MTLFunction> fragmentFunction = [defaultLibrary newFunctionWithName:@"fragmentShader"];
id <MTLArgumentEncoder> argumentEncoder
= [fragmentFunction newArgumentEncoderWithBufferIndex:AAPLFragmentBufferIndexArguments];
argumentEncoder
的encodedLength
屬性確定包含參數緩沖區中所有資源所需的大小(以字節為單位)。 此示例使用該值創建一個新緩沖區_fragmentShaderArgumentBuffer
,其長度參數與參數緩沖區所需的大小相匹配。
NSUInteger argumentBufferLength = argumentEncoder.encodedLength;
_fragmentShaderArgumentBuffer = [_device newBufferWithLength:argumentBufferLength options:0];
然后,此示例調用setArgumentBuffer:offset:
方法以指定_fragmentShaderArgumentBuffer
是可以編碼資源的參數緩沖區。
[argumentEncoder setArgumentBuffer:_fragmentShaderArgumentBuffer offset:0];
此示例通過以下方式將各個資源編碼到參數緩沖區中:
- 為每種資源類型調用特定方法,例如
setTexture:atIndex:,setSamplerState:atIndex:
和setBuffer:offset:atIndex
。 - 將
index
參數的值與為FragmentShaderArguments
結構的每個元素聲明的[[id(n)]]
屬性限定符的值匹配。
[argumentEncoder setTexture:_texture atIndex:AAPLArgumentBufferIDExampleTexture];
[argumentEncoder setSamplerState:_sampler atIndex:AAPLArgumentBufferIDExampleSampler];
[argumentEncoder setBuffer:_indirectBuffer offset:0 atIndex:AAPLArgumentBufferIDExampleBuffer];
常量編碼有點不同;常量數據直接嵌入到參數緩沖區中,而不是駐留在參數緩沖區指向的另一個對象中。 此示例調用constantDataAtIndex:
方法以檢索常量所在的參數緩沖區中的地址。 然后,該示例在檢索到的地址處設置常量bufferElements
的實際值。
uint32_t *numElementsAddress = [argumentEncoder constantDataAtIndex:AAPLArgumentBufferIDExampleConstant];
*numElementsAddress = bufferElements;
Enable the GPU Memory of Resources in the Argument Buffer - 在參數緩沖區中啟用資源的GPU內存
Metal有效地管理GPU訪問的內存;在GPU使用任何資源之前,Metal確保GPU可以訪問資源的內存。 通過調用MTLRenderCommandEncoder
方法(例如setVertexBuffer:offset:atIndex:
或setFragmentTexture:atIndex:
)來單獨設置資源可確保GPU可以訪問資源的內存。
但是,當資源編碼到參數緩沖區中時,設置參數緩沖區不會單獨設置其每個資源。 Metal不檢查參數緩沖區以確定在其中編碼哪些資源(這種昂貴的操作會否定參數緩沖區的性能優勢)。 因此,Metal無法確定GPU可以訪問哪些資源的內存。 相反,您調用useResource:usage:
方法來顯式指示MTLRenderCommandEncoder
使GPU可訪問特定資源的內存。
注意:您只需要在
MTLRenderCommandEncoder
的生命周期內為每個資源調用一次useResource:usage:
方法,即使您在多個繪制調用中使用該資源也是如此。useResource:usage:
方法特定于參數緩沖區,但調用它比單獨設置每個資源要便宜得多。
Set Argument Buffers - 設置參數緩沖區
此示例調用useResource:usage:
方法,用于編入參數緩沖區的_texture
和_indirectBuffer
資源。 這些調用指定MTLResourceUsage
值,進一步指示對每個資源執行哪些GPU操作(對紋理進行采樣并在GPU中讀取緩沖區)。
[renderEncoder useResource:_texture usage:MTLResourceUsageSample];
[renderEncoder useResource:_indirectBuffer usage:MTLResourceUsageRead];
注意:
useResource:usage:
方法不適用于采樣器或常量,因為它們不是MTLResource
對象。
此示例僅將_fragmentShaderArgumentBuffer
設置為片段函數的參數;它不單獨設置_texture
,_indirectBuffer
,_sampler
或bufferElements
資源。 此命令允許片段函數訪問參數緩沖區及其編碼資源。
[renderEncoder setFragmentBuffer:_fragmentShaderArgumentBuffer
offset:0
atIndex:AAPLFragmentBufferIndexArguments];
Access the Resources in an Argument Buffer - 訪問參數緩沖區中的資源
在函數內,訪問參數緩沖區中編碼的資源類似于直接訪問各個資源。 主要區別在于資源是作為參數緩沖區結構的元素訪問的。
在此示例中,通過fragmentShader
函數的fragmentShaderArgs
參數訪問參數緩沖區資源。
// Get the sampler encoded in the argument buffer
sampler exampleSampler = fragmentShaderArgs.exampleSampler;
// Sample the texture encoded in the argument buffer
half4 textureSample = fragmentShaderArgs.exampleTexture.sample(exampleSampler, in.texCoord);
// Use the fragment position and the constant encoded in the argument buffer to calculate an array index
uint32_t index = (uint32_t)in.position.x % fragmentShaderArgs.exampleConstant;
// Index into the buffer encoded in the argument buffer
float colorScale = fragmentShaderArgs.exampleBuffer[index];
該示例使用參數緩沖區中的所有四個資源來生成每個片段的最終顏色。
在此示例中,您學習了如何在參數緩沖區中指定,編碼,設置和訪問資源。
后記
本篇主要講述了基本參數緩沖,感興趣的給個贊或者關注~~~