Metal框架詳細(xì)解析(四十二) —— Metal編程指南之圖形渲染:渲染命令編碼器之Part 2(七)

版本記錄

版本號 時間
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對象中的vertexFunctionfragmentFunction屬性指定甲馋。 這些方法將著色器資源(緩沖區(qū),紋理和采樣器)分配給渲染命令編碼器中對應(yīng)的參數(shù)表索引(atIndex)迄损,如圖5-3所示定躏。

Figure 5-3 Argument Tables for the Render Command Encoder

以下setVertex *方法將一個或多個資源分配給頂點著色器函數(shù)的相應(yīng)參數(shù)。

這些setFragment *方法類似地將一個或多個資源分配給片段著色器函數(shù)的相應(yīng)參數(shù)芹敌。

緩沖區(qū)參數(shù)表中最多有31個條目痊远,紋理參數(shù)表中有31個條目,采樣器狀態(tài)參數(shù)表中有16個條目氏捞。

在Metal著色語言源代碼中指定資源位置的屬性限定符必須與Metal框架方法中的參數(shù)表索引匹配碧聪。 在Listing 5-7中,為頂點著色器定義了兩個分別為索引0和1的緩沖區(qū)(posBuftexCoordBuf

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ū)滞造,一個紋理和一個采樣器(分別為fragmentColorBufshadeTexsampler)栋烤,它們都具有索引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ù)vertexMathVertexInput結(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è)置為MTLRenderPipelineStatevertexDescriptor屬性缠捌。 MTLVertexDescriptor有兩個屬性:attributeslayouts

MTLVertexDescriptorattributes屬性是一個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的輸入。

Figure 5-4 Buffer Organization with Vertex Attribute Descriptors

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指定使用四個浮點值庆尘。

MTLVertexDescriptorlayouts屬性是MTLVertexBufferLayoutDescriptorArray剃诅。對于layouts中的每個MTLVertexBufferLayoutDescriptor,屬性指定在Metal繪制基元時如何從參數(shù)表中的相應(yīng)MTLBuffer獲取頂點和屬性數(shù)據(jù)驶忌。 (有關(guān)繪制圖元的更多信息矛辕,請參見Drawing Geometric Primitives。)付魔。MTLVertexBufferLayoutDescriptorstepFunction屬性確定是為每個頂點聊品,某些實例獲取屬性數(shù)據(jù),還是僅獲取一次几苍。如果將stepFunction設(shè)置為獲取某些實例的屬性數(shù)據(jù)翻屈,則MTLVertexBufferLayoutDescriptorstepRate屬性將確定實例數(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族铆,則每兩個實例,依此類推哭尝。

Figure 5-5 Buffer Organization with Vertex Buffer Layout Descriptors

Performing Fixed-Function Render Command Encoder Operations - 執(zhí)行固定功能渲染命令編碼器操作

使用這些MTLRenderCommandEncoder方法設(shè)置固定功能圖形狀態(tài)值:

使用以下MTLRenderCommandEncoder方法對固定函數(shù)狀態(tài)更改命令進行編碼:

您可以使用此模式執(zhí)行遮擋測試尚猿。如果繪制邊界框并且沒有樣本通過,則可以得出結(jié)論楣富,該邊界框內(nèi)的任何對象都被遮擋凿掂,因此不需要渲染。

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視口是由MTLRenderCommandEncodersetViewport:方法指定的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)必須包含深度附件以支持寫入深度值叙淌。要執(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)離觀察者的片段值無法進行深度測試;也就是說雌芽,片段被較早的深度值視為被遮擋授艰。
  • frontFaceStencilbackFaceStencil屬性均為前向和后向基元指定單獨的MTLStencilDescriptor對象。要對前置和后置基元使用相同的模板狀態(tài)世落,可以為frontFaceStencilbackFaceStencil屬性分配相同的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)钧舌。

對于上面列出的每個基本渲染方法仔粥,第一個輸入值使用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中所示的以下步驟描述了渲染三角形的基本過程罢荡。

在此示例中,僅設(shè)置和使用第一個顏色附件惧笛。 (假設(shè)變量currentTexture包含用于顏色附件的MTLTexture从媚。)然后MTLRenderPassDescriptor用于創(chuàng)建新的MTLRenderCommandEncoder逞泄。

setVertexBuffer:offset:atIndex:方法的atIndex輸入值對應(yīng)于頂點函數(shù)的源代碼中的屬性緩沖區(qū)(atIndex)峡钓。

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)用MTLRenderCommandEncoderendEncoding方法。在并行渲染命令編碼器創(chuàng)建的所有渲染命令編碼器上結(jié)束編碼后屿良,調(diào)用MTLParallelRenderCommandEncoderendEncoding方法以結(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)康栈。 對于MTLParallelRenderCommandEncoderMTLCommandBuffer始終按照創(chuàng)建從屬渲染命令編碼器的順序包含命令,如圖5-6所示啥么。

Figure 5-6 Ordering of Render Command Encoders in a Parallel Rendering Pass

后記

本篇主要講述了圖形渲染:渲染命令編碼器登舞,感興趣的給個贊或者關(guān)注~~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市悬荣,隨后出現(xiàn)的幾起案子逊躁,更是在濱河造成了極大的恐慌,老刑警劉巖隅熙,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件稽煤,死亡現(xiàn)場離奇詭異,居然都是意外死亡囚戚,警方通過查閱死者的電腦和手機酵熙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驰坊,“玉大人匾二,你說我怎么就攤上這事∪剑” “怎么了察藐?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長舟扎。 經(jīng)常有香客問我分飞,道長,這世上最難降的妖魔是什么睹限? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任譬猫,我火速辦了婚禮,結(jié)果婚禮上羡疗,老公的妹妹穿的比我還像新娘染服。我一直安慰自己,他們只是感情好叨恨,可當(dāng)我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布柳刮。 她就那樣靜靜地躺著,像睡著了一般痒钝。 火紅的嫁衣襯著肌膚如雪秉颗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天午乓,我揣著相機與錄音站宗,去河邊找鬼。 笑死益愈,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蒸其,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼敏释,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了摸袁?” 一聲冷哼從身側(cè)響起钥顽,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎靠汁,沒想到半個月后蜂大,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡蝶怔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年奶浦,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片踢星。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡澳叉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出沐悦,到底是詐尸還是另有隱情成洗,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布藏否,位于F島的核電站瓶殃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏副签。R本人自食惡果不足惜碌燕,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望继薛。 院中可真熱鬧修壕,春花似錦、人聲如沸遏考。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽灌具。三九已至青团,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間咖楣,已是汗流浹背督笆。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留诱贿,地道東北人娃肿。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓咕缎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親料扰。 傳聞我的和親對象是個殘疾皇子凭豪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,573評論 2 353

推薦閱讀更多精彩內(nèi)容