版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2018.11.10 星期六 |
前言
很多做視頻和圖像的码撰,相信對這個框架都不是很陌生较性,它渲染高級3D圖形呵晚,并使用GPU執(zhí)行數(shù)據(jù)并行計算瘩欺。接下來的幾篇我們就詳細(xì)的解析這個框架必盖。感興趣的看下面幾篇文章拌牲。
1. Metal框架詳細(xì)解析(一)—— 基本概覽
2. Metal框架詳細(xì)解析(二) —— 器件和命令(一)
3. Metal框架詳細(xì)解析(三) —— 渲染簡單的2D三角形(一)
4. Metal框架詳細(xì)解析(四) —— 關(guān)于GPU Family 4(一)
5. Metal框架詳細(xì)解析(五) —— 關(guān)于GPU Family 4之關(guān)于Imageblocks(二)
6. Metal框架詳細(xì)解析(六) —— 關(guān)于GPU Family 4之關(guān)于Tile Shading(三)
7. Metal框架詳細(xì)解析(七) —— 關(guān)于GPU Family 4之關(guān)于光柵順序組(四)
8. Metal框架詳細(xì)解析(八) —— 關(guān)于GPU Family 4之關(guān)于增強的MSAA和Imageblock采樣覆蓋控制(五)
9. Metal框架詳細(xì)解析(九) —— 關(guān)于GPU Family 4之關(guān)于線程組共享(六)
10. Metal框架詳細(xì)解析(十) —— 基本組件(一)
11. Metal框架詳細(xì)解析(十一) —— 基本組件之器件選擇 - 圖形渲染的器件選擇(二)
12. Metal框架詳細(xì)解析(十二) —— 基本組件之器件選擇 - 計算處理的設(shè)備選擇(三)
13. Metal框架詳細(xì)解析(十三) —— 計算處理(一)
14. Metal框架詳細(xì)解析(十四) —— 計算處理之你好,計算(二)
15. Metal框架詳細(xì)解析(十五) —— 計算處理之關(guān)于線程和線程組(三)
16. Metal框架詳細(xì)解析(十六) —— 計算處理之計算線程組和網(wǎng)格大懈柚唷(四)
17. Metal框架詳細(xì)解析(十七) —— 工具塌忽、分析和調(diào)試(一)
18. Metal框架詳細(xì)解析(十八) —— 工具、分析和調(diào)試之Metal GPU Capture(二)
19. Metal框架詳細(xì)解析(十九) —— 工具失驶、分析和調(diào)試之GPU活動監(jiān)視器(三)
20. Metal框架詳細(xì)解析(二十) —— 工具土居、分析和調(diào)試之關(guān)于Metal著色語言文件名擴展名、使用Metal的命令行工具構(gòu)建庫和標(biāo)記Metal對象和命令(四)
21. Metal框架詳細(xì)解析(二十一) —— 基本課程之基本緩沖區(qū)(一)
22. Metal框架詳細(xì)解析(二十二) —— 基本課程之基本紋理(二)
23. Metal框架詳細(xì)解析(二十三) —— 基本課程之CPU和GPU同步(三)
24. Metal框架詳細(xì)解析(二十四) —— 基本課程之參數(shù)緩沖 - 基本參數(shù)緩沖(四)
25. Metal框架詳細(xì)解析(二十五) —— 基本課程之參數(shù)緩沖 - 帶有數(shù)組和資源堆的參數(shù)緩沖區(qū)(五)
26. Metal框架詳細(xì)解析(二十六) —— 基本課程之參數(shù)緩沖 - 具有GPU編碼的參數(shù)緩沖區(qū)(六)
27. Metal框架詳細(xì)解析(二十七) —— 高級技術(shù)之圖層選擇的反射(一)
28. Metal框架詳細(xì)解析(二十八) —— 高級技術(shù)之使用專用函數(shù)的LOD(一)
29. Metal框架詳細(xì)解析(二十九) —— 高級技術(shù)之具有參數(shù)緩沖區(qū)的動態(tài)地形(一)
30. Metal框架詳細(xì)解析(三十) —— 延遲照明(一)
31. Metal框架詳細(xì)解析(三十一) —— 在視圖中混合Metal和OpenGL渲染(一)
32. Metal框架詳細(xì)解析(三十二) —— Metal渲染管道教程(一)
33. Metal框架詳細(xì)解析(三十三) —— Metal渲染管道教程(二)
34. Metal框架詳細(xì)解析(三十四) —— Hello Metal突勇! 一個簡單的三角形的實現(xiàn)(一)
35. Metal框架詳細(xì)解析(三十五) —— Hello Metal! 一個簡單的三角形的實現(xiàn)(二)
36. Metal框架詳細(xì)解析(三十六) —— Metal編程指南之概覽(一)
37. Metal框架詳細(xì)解析(三十七) —— Metal編程指南之基本Metal概念(二)
38. Metal框架詳細(xì)解析(三十八) —— Metal編程指南之命令組織和執(zhí)行模型(三)
39. Metal框架詳細(xì)解析(三十九) —— Metal編程指南之資源對象:緩沖區(qū)和紋理(四)
40. Metal框架詳細(xì)解析(四十) —— Metal編程指南之函數(shù)和庫(五)
41. Metal框架詳細(xì)解析(四十一) —— Metal編程指南之圖形渲染:渲染命令編碼器之Part 1(六)
Specifying Resources for a Render Command Encoder - 為渲染命令編碼器指定資源
本節(jié)中討論的MTLRenderCommandEncoder方法指定用作頂點和片段著色器函數(shù)的參數(shù)的資源坷虑,這些函數(shù)由MTLRenderPipelineState對象中的vertexFunction
和fragmentFunction
屬性指定甲馋。 這些方法將著色器資源(緩沖區(qū),紋理和采樣器)分配給渲染命令編碼器中對應(yīng)的參數(shù)表索引(atIndex)
迄损,如圖5-3所示定躏。
以下setVertex *
方法將一個或多個資源分配給頂點著色器函數(shù)的相應(yīng)參數(shù)。
- setVertexBuffer:offset:atIndex:
- setVertexBuffers:offsets:withRange:
- setVertexTexture:atIndex:
- setVertexTextures:withRange:
- setVertexSamplerState:atIndex:
- setVertexSamplerState:lodMinClamp:lodMaxClamp:atIndex:
- setVertexSamplerStates:withRange:
- setVertexSamplerStates:lodMinClamps:lodMaxClamps:withRange:
這些setFragment *
方法類似地將一個或多個資源分配給片段著色器函數(shù)的相應(yīng)參數(shù)芹敌。
- setFragmentBuffer:offset:atIndex:
- setFragmentBuffers:offsets:withRange:
- setFragmentTexture:atIndex:
- setFragmentTextures:withRange:
- setFragmentSamplerState:atIndex:
- setFragmentSamplerState:lodMinClamp:lodMaxClamp:atIndex:
- setFragmentSamplerStates:withRange:
- setFragmentSamplerStates:lodMinClamps:lodMaxClamps:withRange:
緩沖區(qū)參數(shù)表中最多有31個條目痊远,紋理參數(shù)表中有31個條目,采樣器狀態(tài)參數(shù)表中有16個條目氏捞。
在Metal著色語言源代碼中指定資源位置的屬性限定符必須與Metal框架方法中的參數(shù)表索引匹配碧聪。 在Listing 5-7
中,為頂點著色器定義了兩個分別為索引0和1的緩沖區(qū)(posBuf
和texCoordBuf
)
Listing 5-7 Metal Framework: Specifying Resources for a Vertex Function
[renderEnc setVertexBuffer:posBuf offset:0 atIndex:0];
[renderEnc setVertexBuffer:texCoordBuf offset:0 atIndex:1];
在Listing 5-8
中液茎,函數(shù)簽名具有與屬性限定符buffer(0)
和buffer(1)
相對應(yīng)的參數(shù)逞姿。
Listing 5-8 Metal Shading Language: Vertex Function Arguments Match the Framework Argument Table Indices
vertex VertexOutput metal_vert(float4 *posData [[ buffer(0) ]],
float2 *texCoordData [[ buffer(1) ]])
類似地,在Listing 5-9
中捆等,為片段著色器定義了一個緩沖區(qū)滞造,一個紋理和一個采樣器(分別為fragmentColorBuf
,shadeTex
和sampler
)栋烤,它們都具有索引0谒养。
Listing 5-9 Metal Framework: Specifying Resources for a Fragment Function
[renderEnc setFragmentBuffer:fragmentColorBuf offset:0 atIndex:0];
[renderEnc setFragmentTexture:shadeTex atIndex:0];
[renderEnc setFragmentSamplerState:sampler atIndex:0];
在Listing 5-10
中,函數(shù)簽名分別具有屬性限定符buffer(0)
明郭,texture(0)
和sampler(0)
的對應(yīng)參數(shù)买窟。
Listing 5-10 Metal Shading Language: Fragment Function Arguments Match the Framework Argument Table Indices
fragment float4 metal_frag(VertexOutput in [[stage_in]],
float4 *fragColorData [[ buffer(0) ]],
texture2d<float> shadeTexValues [[ texture(0) ]],
sampler samplerValues [[ sampler(0) ]])
1. Vertex Descriptor for Data Organization - 數(shù)據(jù)組織的頂點描述符
在Metal框架代碼中,每個管道狀態(tài)可以有一個MTLVertexDescriptor薯定,用于描述輸入到頂點著色器函數(shù)的數(shù)據(jù)的組織蔑祟,并在著色語言和框架代碼之間共享資源位置信息。
在Metal著色語言代碼中沉唠,每個頂點輸入(例如標(biāo)量或整數(shù)或浮點值向量)可以組織在一個結(jié)構(gòu)中疆虚,該結(jié)構(gòu)可以在一個使用[[stage_in]]
屬性限定符聲明的參數(shù)中傳遞 ,如Listing 5-11
中示例頂點函數(shù)vertexMath
的VertexInput
結(jié)構(gòu)中所示。 每頂點輸入結(jié)構(gòu)的每個字段都有[[attribute(index)]]
限定符径簿,它指定頂點屬性參數(shù)表中的索引罢屈。
Listing 5-11 Metal Shading Language: Vertex Function Inputs with Attribute Indices
struct VertexInput {
float2 position [[ attribute(0) ]];
float4 color [[ attribute(1) ]];
float2 uv1 [[ attribute(2) ]];
float2 uv2 [[ attribute(3) ]];
};
struct VertexOutput {
float4 pos [[ position ]];
float4 color;
};
vertex VertexOutput vertexMath(VertexInput in [[ stage_in ]])
{
VertexOutput out;
out.pos = float4(in.position.x, in.position.y, 0.0, 1.0);
float sum1 = in.uv1.x + in.uv2.x;
float sum2 = in.uv1.y + in.uv2.y;
out.color = in.color + float4(sum1, sum2, 0.0f, 0.0f);
return out;
}
要使用[[stage_in]]
限定符引用著色器函數(shù)輸入,請描述MTLVertexDescriptor對象篇亭,然后將其設(shè)置為MTLRenderPipelineState的vertexDescriptor屬性缠捌。 MTLVertexDescriptor
有兩個屬性:attributes和layouts。
MTLVertexDescriptor
的attributes屬性是一個MTLVertexAttributeDescriptorArray對象译蒂,它定義每個頂點屬性在映射到頂點函數(shù)參數(shù)的緩沖區(qū)中的組織方式曼月。 attributes
屬性可以支持訪問在同一緩沖區(qū)中交錯的多個屬性(例如頂點坐標(biāo),曲面法線和紋理坐標(biāo))柔昼。著色語言代碼中成員的順序不必保留在框架代碼的緩沖區(qū)中哑芹。數(shù)組中的每個頂點屬性描述符都具有以下屬性,這些屬性提供頂點著色器函數(shù)信息以定位和加載參數(shù)數(shù)據(jù):
-
bufferIndex捕透,它是緩沖區(qū)參數(shù)表的索引聪姿,用于指定訪問哪個
MTLBuffer
。在 Specifying Resources for a Render Command Encoder中討論了緩沖區(qū)參數(shù)表乙嘀。 -
format末购,指定如何在框架代碼中解釋數(shù)據(jù)。如果數(shù)據(jù)類型不是精確類型匹配虎谢,則可以轉(zhuǎn)換或擴展它盟榴。例如,如果著色語言類型為
half4
且框架格式為MTLVertexFormatFloat2婴噩,那么當(dāng)數(shù)據(jù)用作頂點函數(shù)的參數(shù)時曹货,它可以從float
轉(zhuǎn)換為一半并從兩個元素擴展為四個元素(使用0.0,最后兩個元素中的1.0)讳推。 - offset顶籽,指定從頂點的開頭可以找到數(shù)據(jù)的位置。
圖5-4說明了Metal框架代碼中的MTLVertexAttributeDescriptorArray银觅,它實現(xiàn)了一個交錯緩沖區(qū)礼饱,該緩沖區(qū)對應(yīng)于Listing 5-11中著色語言代碼中頂點函數(shù)vertexMath
的輸入。
Listing 5-12
顯示了與圖5-4中所示的交錯緩沖區(qū)相對應(yīng)的Metal框架代碼究驴。
Listing 5-12 Metal Framework: Using a Vertex Descriptor to Access Interleaved Data
id <MTLFunction> vertexFunc = [library newFunctionWithName:@"vertexMath"];
MTLRenderPipelineDescriptor* pipelineDesc =
[[MTLRenderPipelineDescriptor alloc] init];
MTLVertexDescriptor* vertexDesc = [[MTLVertexDescriptor alloc] init];
vertexDesc.attributes[0].format = MTLVertexFormatFloat2;
vertexDesc.attributes[0].bufferIndex = 0;
vertexDesc.attributes[0].offset = 0;
vertexDesc.attributes[1].format = MTLVertexFormatFloat4;
vertexDesc.attributes[1].bufferIndex = 0;
vertexDesc.attributes[1].offset = 2 * sizeof(float); // 8 bytes
vertexDesc.attributes[2].format = MTLVertexFormatFloat2;
vertexDesc.attributes[2].bufferIndex = 0;
vertexDesc.attributes[2].offset = 8 * sizeof(float); // 32 bytes
vertexDesc.attributes[3].format = MTLVertexFormatFloat2;
vertexDesc.attributes[3].bufferIndex = 0;
vertexDesc.attributes[3].offset = 6 * sizeof(float); // 24 bytes
vertexDesc.layouts[0].stride = 10 * sizeof(float); // 40 bytes
vertexDesc.layouts[0].stepFunction = MTLVertexStepFunctionPerVertex;
pipelineDesc.vertexDescriptor = vertexDesc;
pipelineDesc.vertexFunction = vertFunc;
MTLVertexDescriptor對象的attributes數(shù)組中的每個MTLVertexAttributeDescriptor對象對應(yīng)于著色器函數(shù)中VertexInput
中的索引結(jié)構(gòu)成員镊绪。 attributes [1] .bufferIndex = 0
指定在參數(shù)表中使用索引0處的緩沖區(qū)。 (在此示例中洒忧,每個MTLVertexAttributeDescriptor具有相同的bufferIndex蝴韭,因此每個引用參數(shù)表中索引0處的相同頂點緩沖區(qū)。)熙侍。offset指定頂點內(nèi)數(shù)據(jù)的位置榄鉴,因此attributes[1].offset = 2 * sizeof(float)
定位從緩沖區(qū)起始處開始的相應(yīng)數(shù)據(jù)的8個字節(jié)履磨。選擇format值以匹配著色器函數(shù)中的數(shù)據(jù)類型,因此attributes[1].format = MTLVertexFormatFloat4
指定使用四個浮點值庆尘。
MTLVertexDescriptor
的layouts屬性是MTLVertexBufferLayoutDescriptorArray剃诅。對于layouts中的每個MTLVertexBufferLayoutDescriptor,屬性指定在Metal繪制基元時如何從參數(shù)表中的相應(yīng)MTLBuffer獲取頂點和屬性數(shù)據(jù)驶忌。 (有關(guān)繪制圖元的更多信息矛辕,請參見Drawing Geometric Primitives。)付魔。MTLVertexBufferLayoutDescriptor
的stepFunction屬性確定是為每個頂點聊品,某些實例獲取屬性數(shù)據(jù),還是僅獲取一次几苍。如果將stepFunction
設(shè)置為獲取某些實例的屬性數(shù)據(jù)翻屈,則MTLVertexBufferLayoutDescriptor
的stepRate屬性將確定實例數(shù)。 stride屬性指定兩個頂點的數(shù)據(jù)之間的距離(以字節(jié)為單位)擦剑。
圖5-5描述了MTLVertexBufferLayoutDescriptor妖胀,它對應(yīng)于 Listing 5-12中的代碼芥颈。 layouts [0]
指定如何從緩沖區(qū)參數(shù)表中的相應(yīng)索引0獲取頂點數(shù)據(jù)惠勒。 layouts [0] .stride
指定兩個頂點的數(shù)據(jù)之間的距離為40個字節(jié)。 layouts [0] .stepFunction
爬坑,MTLVertexStepFunctionPerVertex的值指定在繪制時為每個頂點提取屬性數(shù)據(jù)纠屋。如果stepFunction
的值為MTLVertexStepFunctionPerInstance,則stepRate
屬性確定獲取屬性數(shù)據(jù)的頻率盾计。例如售担,如果stepRate
為1,則為每個實例提取數(shù)據(jù)署辉;如果stepRate
為2族铆,則每兩個實例,依此類推哭尝。
Performing Fixed-Function Render Command Encoder Operations - 執(zhí)行固定功能渲染命令編碼器操作
使用這些MTLRenderCommandEncoder方法設(shè)置固定功能圖形狀態(tài)值:
- setViewport:以屏幕坐標(biāo)指定區(qū)域哥攘,該區(qū)域是虛擬3D世界投影的目標(biāo)。視口是3D材鹦,因此它包含深度值逝淹;有關(guān)詳細(xì)信息,請參閱 Working with Viewport and Pixel Coordinate Systems桶唐。
-
setTriangleFillMode:確定是否使用直線(MTLTriangleFillModeLines)或填充三角形(MTLTriangleFillModeFill)柵格化三角形和三角形條帶基元栅葡。默認(rèn)值為
MTLTriangleFillModeFill
。 -
setCullMode:和setFrontFacingWinding:一起用于確定是否以及如何應(yīng)用剔除尤泽。您可以在某些幾何模型上使用剔除隱藏曲面去除欣簇,例如使用實心三角形渲染的可定向球體规脸。 (如果其基元始終以順時針或逆時針順序繪制,則表面可定向醉蚁。)
-
setFrontFacingWinding:的值指示正面基元是否以順時針(MTLWindingClockwise)或逆時針(MTLWindingCounterClockwise)順序繪制頂點燃辖。默認(rèn)值為
MTLWindingClockwise
。 - setCullMode:的值確定是否執(zhí)行剔除(MTLCullModeNone网棍,如果禁用剔除)或者要剔除哪種類型的原語(MTLCullModeFront或MTLCullModeBack)黔龟。
-
setFrontFacingWinding:的值指示正面基元是否以順時針(MTLWindingClockwise)或逆時針(MTLWindingCounterClockwise)順序繪制頂點燃辖。默認(rèn)值為
使用以下MTLRenderCommandEncoder方法對固定函數(shù)狀態(tài)更改命令進行編碼:
- setScissorRect:指定2D剪刀矩形。位于指定剪刀矩形之外的碎片將被丟棄滥玷。
- setDepthStencilState:設(shè)置深度和模板測試狀態(tài)氏身,如 Depth and Stencil States中所述。
- setStencilReferenceValue:指定模板參考值惑畴。
- setDepthBias:slopeScale:clamp:指定用于將陰影貼圖與片段著色器輸出的深度值進行比較的調(diào)整蛋欣。
- setVisibilityResultMode:offset:確定是否監(jiān)視任何樣本是否通過深度和模板測試。如果設(shè)置為MTLVisibilityResultModeBoolean如贷,則如果任何樣本通過深度和模板測試陷虎,則會將非零值寫入由MTLRenderPassDescriptor的visibilityResultBuffer屬性指定的緩沖區(qū),如Creating a Render Pass Descriptor中所述杠袱。
您可以使用此模式執(zhí)行遮擋測試尚猿。如果繪制邊界框并且沒有樣本通過,則可以得出結(jié)論楣富,該邊界框內(nèi)的任何對象都被遮擋凿掂,因此不需要渲染。
- setBlendColorRed:green:blue:alpha:指定常量混合顏色和alpha值纹蝴,詳見Configuring Blending in a Render Pipeline Attachment Descriptor庄萎。
1. Working with Viewport and Pixel Coordinate Systems - 使用Viewport和像素坐標(biāo)系
Metal將其標(biāo)準(zhǔn)化設(shè)備坐標(biāo)(Normalized Device Coordinate - NDC)
系統(tǒng)定義為2x2x1
立方體,其中心位于(0,0,0.5)
塘安。 NDC系統(tǒng)的x和y的左側(cè)和底部分別指定為-1糠涛。 NDC系統(tǒng)的x和y的右側(cè)和頂部分別指定為+1。
視口指定從NDC
到窗口坐標(biāo)的轉(zhuǎn)換兼犯。 Metal視口是由MTLRenderCommandEncoder的setViewport:方法指定的3D轉(zhuǎn)換忍捡。 窗口坐標(biāo)的原點位于左上角。
在Metal中免都,像素中心偏移(0.5,0.5)
锉罐。 例如,原點處的像素的中心位于(0.5,0.5)
; 右邊相鄰像素的中心是(1.5,0.5)
绕娘。 紋理也是如此脓规。
2. Performing Depth and Stencil Operations - 執(zhí)行深度和模板操作
深度和模板操作是您指定的片段操作,如下所示:
- 指定包含深度/模板狀態(tài)設(shè)置的自定義MTLDepthStencilDescriptor對象险领。創(chuàng)建自定義
MTLDepthStencilDescriptor
對象可能需要創(chuàng)建一個或兩個適用于前向基元和后向基元的TLStencilDescriptor對象侨舆。 - 通過使用深度/模板狀態(tài)描述符調(diào)用
MTDDevice
的newDepthStencilStateWithDescriptor:方法來創(chuàng)建MTLDepthStencilState對象秒紧。 - 要設(shè)置深度/模板狀態(tài),請使用
MTLRenderCommandEncoder
的帶有MTLDepthStencilState值的setDepthStencilState:方法挨下。 - 如果正在使用模板測試熔恢,請調(diào)用setStencilReferenceValue:以指定模板參考值。
如果啟用了深度測試臭笆,則渲染管道狀態(tài)必須包含深度附件以支持寫入深度值叙淌。要執(zhí)行模板測試,渲染管道狀態(tài)必須包含模板附件愁铺。要配置附件鹰霍,請參閱Creating and Configuring a Render Pipeline Descriptor。
如果要定期更改深度/模板狀態(tài)茵乱,則可能需要重用狀態(tài)描述符對象茂洒,根據(jù)需要修改其屬性值以創(chuàng)建更多狀態(tài)對象。
注意:要從著色器函數(shù)中的深度格式紋理進行采樣瓶竭,請在著色器中實施采樣操作督勺,而不使用
MTLSamplerState
。
使用MTLDepthStencilDescriptor對象的屬性斤贰,如下所示設(shè)置深度和模板狀態(tài):
- 要將深度值寫入深度附件智哀,請將depthWriteEnabled設(shè)置為
YES
。 -
depthCompareFunction指定深度測試的執(zhí)行方式腋舌。如果片段的深度值未通過深度測試盏触,則丟棄片段渗蟹。例如块饺,常用的
MTLCompareFunctionLess
函數(shù)導(dǎo)致比(先前寫入的)像素深度值更遠(yuǎn)離觀察者的片段值無法進行深度測試;也就是說雌芽,片段被較早的深度值視為被遮擋授艰。 -
frontFaceStencil和backFaceStencil屬性均為前向和后向基元指定單獨的MTLStencilDescriptor對象。要對前置和后置基元使用相同的模板狀態(tài)世落,可以為frontFaceStencil和backFaceStencil屬性分配相同的MTLStencilDescriptor淮腾。要顯式禁用一個或兩個面的模板測試,請將相應(yīng)的屬性設(shè)置為
nil
(默認(rèn)值)屉佳。
不必顯式禁用模板狀態(tài)谷朝。 Metal根據(jù)是否為有效的模板操作配置模板描述符來確定是否啟用模板測試。
Listing 5-13顯示了創(chuàng)建和使用MTLDepthStencilDescriptor對象以創(chuàng)建MTLDepthStencilState對象的示例武花,該對象隨后與渲染命令編碼器一起使用圆凰。 在此示例中,從深度/模板狀態(tài)描述符的frontFaceStencil屬性訪問前置基元的模板狀態(tài)体箕。 對于背面基元专钉,顯式禁用模板測試
Listing 5-13 Creating and Using a Depth/Stencil Descriptor
MTLDepthStencilDescriptor *dsDesc = [[MTLDepthStencilDescriptor alloc] init];
if (dsDesc == nil)
exit(1); // if the descriptor could not be allocated
dsDesc.depthCompareFunction = MTLCompareFunctionLess;
dsDesc.depthWriteEnabled = YES;
dsDesc.frontFaceStencil.stencilCompareFunction = MTLCompareFunctionEqual;
dsDesc.frontFaceStencil.stencilFailureOperation = MTLStencilOperationKeep;
dsDesc.frontFaceStencil.depthFailureOperation = MTLStencilOperationIncrementClamp;
dsDesc.frontFaceStencil.depthStencilPassOperation =
MTLStencilOperationIncrementClamp;
dsDesc.frontFaceStencil.readMask = 0x1;
dsDesc.frontFaceStencil.writeMask = 0x1;
dsDesc.backFaceStencil = nil;
id <MTLDepthStencilState> dsState = [device
newDepthStencilStateWithDescriptor:dsDesc];
[renderEnc setDepthStencilState:dsState];
[renderEnc setStencilReferenceValue:0xFF];
以下屬性在MTLStencilDescriptor中定義模板測試:
- readMask是一個位掩碼挑童;GPU使用模板參考值和存儲的模板值計算此掩碼的按位AND。模板測試是在得到的掩碼參考值和掩碼存儲值之間的比較跃须。
- writeMask是一個位掩碼站叼,用于限制模板操作將哪些模板值寫入模板附件。
-
stencilCompareFunction指定如何對片段執(zhí)行模板測試菇民。在
Listing 5-13
中尽楔,模板比較函數(shù)是MTLCompareFunctionEqual,因此如果掩碼的參考值等于已經(jīng)存儲在片段位置的掩碼模板值第练,則模板測試通過翔试。 -
stencilFailureOperation, depthFailureOperation
和depthStencilPassOperation指定如何對模板附件中存儲的模板值進行三種不同的測試結(jié)果:如果模板測試失敗,如果模板測試通過复旬,如果深度測試失敗垦缅,或者如果模板和深度測試分別成功 。在前面的示例中驹碍,如果模板測試失敗壁涎,則模板值不變(MTLStencilOperationKeep),但如果模板測試通過則模板值會增加志秃,除非模板值已經(jīng)是最大可能值(MTLStencilOperationIncrementClamp)怔球。
Drawing Geometric Primitives - 繪制幾何圖元
建立管道狀態(tài)和固定功能狀態(tài)后,可以調(diào)用以下MTLRenderCommandEncoder方法來繪制幾何圖元浮还。這些繪制方法引用資源(例如包含頂點坐標(biāo)竟坛,紋理坐標(biāo),曲面法線和其他數(shù)據(jù)的緩沖區(qū))來執(zhí)行具有著色器函數(shù)的管道以及先前使用 MTLRenderCommandEncoder
建立的其他狀態(tài)钧舌。
-
drawPrimitives:vertexStart:vertexCount:instanceCount:使用連續(xù)數(shù)組元素中的頂點數(shù)據(jù)呈現(xiàn)基元的多個實例
(instanceCount)
担汤,從索引vertexStart
處數(shù)組元素的第一個頂點開始,到索引vertexStart + vertexCount - 1
處的數(shù)組元素結(jié)束洼冻。 -
drawPrimitives:vertexStart:vertexCount:與
instanceCount
為1的前一個方法相同崭歧。 -
drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:instanceCount:使用
MTLBuffer
對象indexBuffer
中指定的索引列表呈現(xiàn)基元的多個實例(instanceCount)
。indexCount
確定索引的數(shù)量撞牢。索引列表從索引開始率碾,索引是indexBuffer
中數(shù)據(jù)中的indexBufferOffset
字節(jié)偏移量。indexBufferOffset
必須是索引大小的倍數(shù)屋彪,由indexType
決定所宰。 -
drawIndexedPrimitives:indexCount:indexType:indexBuffer:indexBufferOffset:類似于上一個方法,
instanceCount
為1畜挥。
對于上面列出的每個基本渲染方法仔粥,第一個輸入值使用MTLPrimitiveType
值之一確定基元類型。其他輸入值確定用于組合基元的頂點砰嘁。對于所有這些方法件炉,instanceStart
輸入值確定要繪制的第一個實例勘究,而instanceCount
輸入值確定要繪制的實例數(shù)。
如前所述斟冕,setTriangleFillMode:確定三角形是渲染為填充還是線框口糕,setCullMode:和setFrontFacingWinding:設(shè)置確定GPU在渲染過程中是否剔除三角形。有關(guān)更多信息磕蛇,請參閱Fixed-Function State Operations)景描。
渲染點基元時,頂點函數(shù)的著色器語言代碼必須提供[[point_size]]
屬性秀撇,或者點大小未定義超棺。
渲染具有平面著色的三角形圖元時,第一個頂點(也稱為激發(fā)頂點)的屬性用于整個三角形呵燕。頂點函數(shù)的著色器語言代碼必須提供[[flat]]
插值限定符棠绘。
有關(guān)所有Metal著色語言屬性和限定符的詳細(xì)信息,請參見Metal Shading Language Guide
再扭。
Ending a Rendering Pass - 結(jié)束渲染過程
要終止渲染過程氧苍,請在渲染命令編碼器上調(diào)用endEncoding。 在結(jié)束上一個命令編碼器之后泛范,您可以創(chuàng)建任何類型的新命令編碼器让虐,以將其他命令編碼到命令緩沖區(qū)中。
Code Example: Drawing a Triangle - 代碼示例:繪制三角形
Listing 5-14中所示的以下步驟描述了渲染三角形的基本過程罢荡。
- 1) 創(chuàng)建一個MTLCommandQueue并使用它來創(chuàng)建MTLCommandBuffer赡突。
- 2) 創(chuàng)建一個MTLRenderPassDescriptor,它指定一組附件区赵,這些附件用作命令緩沖區(qū)中編碼的渲染命令的目標(biāo)惭缰。
在此示例中,僅設(shè)置和使用第一個顏色附件惧笛。 (假設(shè)變量currentTexture
包含用于顏色附件的MTLTexture从媚。)然后MTLRenderPassDescriptor用于創(chuàng)建新的MTLRenderCommandEncoder逞泄。
- 3) 創(chuàng)建兩個MTLBuffer對象焚挠,
posBuf
和colBuf
炫欺,并調(diào)用newBufferWithBytes:length:options:分別將頂點坐標(biāo)和頂點顏色數(shù)據(jù)posData
和colData
復(fù)制到緩沖區(qū)存儲中。 - 4) 調(diào)用MTLRenderCommandEncoder的setVertexBuffer:offset:atIndex:方法兩次以指定坐標(biāo)和顏色。
setVertexBuffer:offset:atIndex:方法的atIndex
輸入值對應(yīng)于頂點函數(shù)的源代碼中的屬性緩沖區(qū)(atIndex)
峡钓。
-
5) 創(chuàng)建MTLRenderPipelineDescriptor并在管道描述符中建立頂點和片段函數(shù):
- 使用
progSrc
中的源代碼創(chuàng)建一個MTLLibrary,它被假定為包含Metal著色器源代碼的字符串包晰。 - 然后調(diào)用MTLLibrary的newFunctionWithName:方法創(chuàng)建MTLFunction
vertFunc
齐邦,它表示名為hello_vertex
的函數(shù),并創(chuàng)建表示名為hello_fragment
的函數(shù)的MTLFunctionfragFunc
憔四。 - 最后膀息,使用這些
MTLFunction
對象設(shè)置MTLRenderPipelineDescriptor的vertexFunction和fragmentFunction屬性般眉。
- 使用
6) 通過調(diào)用newRenderPipelineStateWithDescriptor:error:或MTLDevice的類似方法,從MTLRenderPipelineDescriptor創(chuàng)建MTLRenderPipelineState潜支。然后甸赃,MTLRenderCommandEncoder的setRenderPipelineState:方法使用創(chuàng)建的管道狀態(tài)進行渲染。
7) 調(diào)用MTLRenderCommandEncoder的drawPrimitives:vertexStart:vertexCount:方法來附加命令以執(zhí)行填充三角形的渲染(類型MTLPrimitiveTypeTriangle)冗酿。
8) 調(diào)用endEncoding方法以結(jié)束此呈現(xiàn)過程的編碼埠对。并調(diào)用MTLCommandBuffer的commit方法來執(zhí)行設(shè)備上的命令。
Listing 5-14 Metal Code for Drawing a Triangle
id <MTLDevice> device = MTLCreateSystemDefaultDevice();
id <MTLCommandQueue> commandQueue = [device newCommandQueue];
id <MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
MTLRenderPassDescriptor *renderPassDesc
= [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDesc.colorAttachments[0].texture = currentTexture;
renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0,1.0,1.0,1.0);
id <MTLRenderCommandEncoder> renderEncoder =
[commandBuffer renderCommandEncoderWithDescriptor:renderPassDesc];
static const float posData[] = {
0.0f, 0.33f, 0.0f, 1.f,
-0.33f, -0.33f, 0.0f, 1.f,
0.33f, -0.33f, 0.0f, 1.f,
};
static const float colData[] = {
1.f, 0.f, 0.f, 1.f,
0.f, 1.f, 0.f, 1.f,
0.f, 0.f, 1.f, 1.f,
};
id <MTLBuffer> posBuf = [device newBufferWithBytes:posData
length:sizeof(posData) options:nil];
id <MTLBuffer> colBuf = [device newBufferWithBytes:colorData
length:sizeof(colData) options:nil];
[renderEncoder setVertexBuffer:posBuf offset:0 atIndex:0];
[renderEncoder setVertexBuffer:colBuf offset:0 atIndex:1];
NSError *errors;
id <MTLLibrary> library = [device newLibraryWithSource:progSrc options:nil
error:&errors];
id <MTLFunction> vertFunc = [library newFunctionWithName:@"hello_vertex"];
id <MTLFunction> fragFunc = [library newFunctionWithName:@"hello_fragment"];
MTLRenderPipelineDescriptor *renderPipelineDesc
= [[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDesc.vertexFunction = vertFunc;
renderPipelineDesc.fragmentFunction = fragFunc;
renderPipelineDesc.colorAttachments[0].pixelFormat = currentTexture.pixelFormat;
id <MTLRenderPipelineState> pipeline = [device
newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&errors];
[renderEncoder setRenderPipelineState:pipeline];
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
vertexStart:0 vertexCount:3];
[renderEncoder endEncoding];
[commandBuffer commit];
在Listing 5-14
中裁替,MTLFunction對象表示名為hello_vertex
的著色器函數(shù)项玛。MTLRenderCommandEncoder的方法setVertexBuffer:offset:atIndex:用于指定作為參數(shù)傳遞給 hello_vertex
的頂點資源(在本例中為兩個緩沖區(qū)對象)。setVertexBuffer:offset:atIndex:方法的atIndex
輸入值對應(yīng)頂點函數(shù)源代碼中的屬性 buffer(atIndex)
弱判,如Listing 5-15
所示襟沮。
Listing 5-15 Corresponding Shader Function Declaration
vertex VertexOutput hello_vertex(
const global float4 *pos_data [[ buffer(0) ]],
const global float4 *color_data [[ buffer(1) ]])
{
...
}
Encoding a Single Rendering Pass Using Multiple Threads - 使用多個線程編碼單個渲染通道
在某些情況下,單個渲染過程的編碼命令的單CPU工作負(fù)載可能會限制應(yīng)用程序的性能昌腰。但是臣嚣,嘗試通過將工作負(fù)載分成多個CPU線程上編碼的多個渲染通道來繞過此瓶頸也會對性能產(chǎn)生負(fù)面影響,因為每個渲染過程都需要其自己的中間附件存儲和加載操作來保留渲染目標(biāo)內(nèi)容剥哑。
而是使用MTLParallelRenderCommandEncoder對象硅则,該對象管理共享相同命令緩沖區(qū)和渲染傳遞描述符的多個從屬MTLRenderCommandEncoder
對象。并行渲染命令編碼器確保附件加載和存儲操作僅在整個渲染過程的開始和結(jié)束時發(fā)生株婴,而不是在每個從屬渲染命令編碼器的命令集的開始和結(jié)束時發(fā)生怎虫。使用此體系結(jié)構(gòu),您可以以安全且高性能的方式并行地將每個MTLRenderCommandEncoder
對象分配給其自己的線程困介。
要創(chuàng)建并行渲染命令編碼器大审,請使用MTLCommandBuffer
對象的parallelRenderCommandEncoderWithDescriptor:方法。要創(chuàng)建從屬渲染命令編碼器座哩,請為要執(zhí)行命令編碼的每個CPU線程調(diào)用一次MTLParallelRenderCommandEncoder
對象的renderCommandEncoder
方法徒扶。從同一并行渲染命令編碼器創(chuàng)建的所有從屬命令編碼器將命令編碼到同一命令緩沖區(qū)。命令按照創(chuàng)建渲染命令編碼器的順序編碼到命令緩沖區(qū)根穷。要結(jié)束特定渲染命令編碼器的編碼姜骡,請調(diào)用MTLRenderCommandEncoder
的endEncoding方法。在并行渲染命令編碼器創(chuàng)建的所有渲染命令編碼器上結(jié)束編碼后屿良,調(diào)用MTLParallelRenderCommandEncoder
的endEncoding方法以結(jié)束渲染過程圈澈。
Listing 5-16
顯示MTLParallelRenderCommandEncoder
創(chuàng)建三個MTLRenderCommandEncoder
對象:rCE1,rCE2和rCE3
尘惧。
Listing 5-16 A Parallel Rendering Encoder with Three Render Command Encoders
MTLRenderPassDescriptor *renderPassDesc
= [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDesc.colorAttachments[0].texture = currentTexture;
renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0,0.0,0.0,1.0);
id <MTLParallelRenderCommandEncoder> parallelRCE = [commandBuffer
parallelRenderCommandEncoderWithDescriptor:renderPassDesc];
id <MTLRenderCommandEncoder> rCE1 = [parallelRCE renderCommandEncoder];
id <MTLRenderCommandEncoder> rCE2 = [parallelRCE renderCommandEncoder];
id <MTLRenderCommandEncoder> rCE3 = [parallelRCE renderCommandEncoder];
// not shown: rCE1, rCE2, and rCE3 call methods to encode graphics commands
//
// rCE1 commands are processed first, because it was created first
// even though rCE2 and rCE3 end earlier than rCE1
[rCE2 endEncoding];
[rCE3 endEncoding];
[rCE1 endEncoding];
// all MTLRenderCommandEncoders must end before MTLParallelRenderCommandEncoder
[parallelRCE endEncoding];
命令編碼器調(diào)用endEncoding的順序與命令編碼和附加到MTLCommandBuffer的順序無關(guān)康栈。 對于MTLParallelRenderCommandEncoder,MTLCommandBuffer始終按照創(chuàng)建從屬渲染命令編碼器的順序包含命令,如圖5-6所示啥么。
后記
本篇主要講述了圖形渲染:渲染命令編碼器登舞,感興趣的給個贊或者關(guān)注~~~