版本記錄
版本號(hào) | 時(shí)間 |
---|---|
V1.0 | 2018.11.11 星期日 |
前言
很多做視頻和圖像的,相信對(duì)這個(gè)框架都不是很陌生,它渲染高級(jí)3D圖形,并使用GPU執(zhí)行數(shù)據(jù)并行計(jì)算。接下來的幾篇我們就詳細(xì)的解析這個(gè)框架。感興趣的看下面幾篇文章。
1. Metal框架詳細(xì)解析(一)—— 基本概覽
2. Metal框架詳細(xì)解析(二) —— 器件和命令(一)
3. Metal框架詳細(xì)解析(三) —— 渲染簡(jiǎn)單的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)于增強(qiáng)的MSAA和Imageblock采樣覆蓋控制(五)
9. Metal框架詳細(xì)解析(九) —— 關(guān)于GPU Family 4之關(guān)于線程組共享(六)
10. Metal框架詳細(xì)解析(十) —— 基本組件(一)
11. Metal框架詳細(xì)解析(十一) —— 基本組件之器件選擇 - 圖形渲染的器件選擇(二)
12. Metal框架詳細(xì)解析(十二) —— 基本組件之器件選擇 - 計(jì)算處理的設(shè)備選擇(三)
13. Metal框架詳細(xì)解析(十三) —— 計(jì)算處理(一)
14. Metal框架詳細(xì)解析(十四) —— 計(jì)算處理之你好,計(jì)算(二)
15. Metal框架詳細(xì)解析(十五) —— 計(jì)算處理之關(guān)于線程和線程組(三)
16. Metal框架詳細(xì)解析(十六) —— 計(jì)算處理之計(jì)算線程組和網(wǎng)格大小(四)
17. Metal框架詳細(xì)解析(十七) —— 工具、分析和調(diào)試(一)
18. Metal框架詳細(xì)解析(十八) —— 工具、分析和調(diào)試之Metal GPU Capture(二)
19. Metal框架詳細(xì)解析(十九) —— 工具、分析和調(diào)試之GPU活動(dòng)監(jiān)視器(三)
20. Metal框架詳細(xì)解析(二十) —— 工具、分析和調(diào)試之關(guān)于Metal著色語言文件名擴(kuò)展名、使用Metal的命令行工具構(gòu)建庫和標(biāo)記Metal對(duì)象和命令(四)
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ì)解析(二十七) —— 高級(jí)技術(shù)之圖層選擇的反射(一)
28. Metal框架詳細(xì)解析(二十八) —— 高級(jí)技術(shù)之使用專用函數(shù)的LOD(一)
29. Metal框架詳細(xì)解析(二十九) —— 高級(jí)技術(shù)之具有參數(shù)緩沖區(qū)的動(dòng)態(tài)地形(一)
30. Metal框架詳細(xì)解析(三十) —— 延遲照明(一)
31. Metal框架詳細(xì)解析(三十一) —— 在視圖中混合Metal和OpenGL渲染(一)
32. Metal框架詳細(xì)解析(三十二) —— Metal渲染管道教程(一)
33. Metal框架詳細(xì)解析(三十三) —— Metal渲染管道教程(二)
34. Metal框架詳細(xì)解析(三十四) —— Hello Metal! 一個(gè)簡(jiǎn)單的三角形的實(shí)現(xiàn)(一)
35. Metal框架詳細(xì)解析(三十五) —— Hello Metal! 一個(gè)簡(jiǎn)單的三角形的實(shí)現(xiàn)(二)
36. Metal框架詳細(xì)解析(三十六) —— Metal編程指南之概覽(一)
37. Metal框架詳細(xì)解析(三十七) —— Metal編程指南之基本Metal概念(二)
38. Metal框架詳細(xì)解析(三十八) —— Metal編程指南之命令組織和執(zhí)行模型(三)
39. Metal框架詳細(xì)解析(三十九) —— Metal編程指南之資源對(duì)象:緩沖區(qū)和紋理(四)
40. Metal框架詳細(xì)解析(四十) —— Metal編程指南之函數(shù)和庫(五)
41. Metal框架詳細(xì)解析(四十一) —— Metal編程指南之圖形渲染:渲染命令編碼器之Part 1(六)
42. Metal框架詳細(xì)解析(四十二) —— Metal編程指南之圖形渲染:渲染命令編碼器之Part 2(七)
43. Metal框架詳細(xì)解析(四十三) —— Metal編程指南之?dāng)?shù)據(jù)并行計(jì)算處理:計(jì)算命令編碼器(八)
44. Metal框架詳細(xì)解析(四十四) —— Metal編程指南之緩沖和紋理操作:Blit命令編碼器(九)
45. Metal框架詳細(xì)解析(四十五) —— Metal編程指南之Metal工具(十)
Tessellation
可用于:iOS_GPUFamily3_v2
,OSX_GPUFamily1_v2
Tessellation
用于從由控制點(diǎn)組成的四邊形或三角形補(bǔ)片構(gòu)造的初始表面計(jì)算更詳細(xì)的表面。 為了逼近高階曲面,GPU使用每個(gè)補(bǔ)丁tessellation
因子將每個(gè)補(bǔ)丁細(xì)分為三角形
Metal Tessellation Pipeline - Metal Tessellation管道
圖12-1顯示了Metal tessellation
管道,它使用計(jì)算機(jī)內(nèi)核,tessellator
和post-tessellation
頂點(diǎn)函數(shù)。
Tessellation
對(duì)貼片進(jìn)行操作,每個(gè)貼片表示由一組控制點(diǎn)定義的任意幾何排列。 每個(gè)補(bǔ)丁tessellation
因子,每補(bǔ)丁用戶數(shù)據(jù)和補(bǔ)丁控制點(diǎn)數(shù)據(jù)均存儲(chǔ)在單獨(dú)的MTLBuffer對(duì)象中。
1. Compute Kernel - 計(jì)算內(nèi)核
計(jì)算內(nèi)核是執(zhí)行以下操作的內(nèi)核函數(shù)(kernel function)
:
- 計(jì)算
per-patch tessellation
因子。 - (可選)計(jì)算每個(gè)修補(bǔ)程序的用戶數(shù)據(jù)。
- (可選)計(jì)算或修改補(bǔ)丁控制點(diǎn)數(shù)據(jù)。
注意:計(jì)算內(nèi)核不需要每幀執(zhí)行,以計(jì)算每個(gè)補(bǔ)丁程序的
tessellation
,每個(gè)補(bǔ)丁程序用戶數(shù)據(jù)或補(bǔ)丁控制點(diǎn)數(shù)據(jù)。 只要您在需要時(shí)向tessellator
和post-tessellation
頂點(diǎn)函數(shù)提供所需數(shù)據(jù),您就可以每n
幀,離線或任何其他運(yùn)行時(shí)方式計(jì)算此數(shù)據(jù)。
2. Tessellator
tessellator
是一個(gè)固定功能的流水線階段,它創(chuàng)建補(bǔ)丁表面的采樣模式并生成連接這些樣本的圖形基元。tessellator
在規(guī)范化坐標(biāo)系中平鋪規(guī)范域,范圍從0.0到1.0。
tessellator
配置為渲染管道的一部分,使用MTLRenderPipelineDescriptor對(duì)象構(gòu)建MTLRenderPipelineState對(duì)象。tessellator
的輸入是每個(gè)補(bǔ)丁tessellator
因子。
Tessellator Primitive Generation
tessellator
每個(gè)補(bǔ)丁運(yùn)行一次,消耗輸入補(bǔ)丁并生成一組新的三角形。這些三角形是通過根據(jù)提供的每個(gè)補(bǔ)丁tessellator
細(xì)分補(bǔ)丁而產(chǎn)生的。由tessellator
生成的每個(gè)三角形頂點(diǎn)在標(biāo)準(zhǔn)化參數(shù)空間中具有關(guān)聯(lián)的(u,v)
或(u,v,w)
位置,每個(gè)參數(shù)值的范圍從0.0到1.0。 (請(qǐng)注意,細(xì)分是以與實(shí)現(xiàn)相關(guān)的方式執(zhí)行的。)
3. Post-Tessellation Vertex Function - Post-Tessellation頂點(diǎn)函數(shù)
post-tessellation
頂點(diǎn)函數(shù)是頂點(diǎn)函數(shù),其計(jì)算由tessellator
生成的每個(gè)補(bǔ)片表面樣本的頂點(diǎn)數(shù)據(jù)。post-tessellation
頂點(diǎn)函數(shù)的輸入是:
- 補(bǔ)丁上的標(biāo)準(zhǔn)化頂點(diǎn)坐標(biāo)(由
tessellator
輸出)。 - 每個(gè)補(bǔ)丁用戶數(shù)據(jù)(可選擇由計(jì)算內(nèi)核輸出)。
- 補(bǔ)丁控制點(diǎn)數(shù)據(jù)(可選地由計(jì)算內(nèi)核輸出)。
- 任何其他頂點(diǎn)函數(shù)輸入,例如紋理和緩沖區(qū)。
post-tessellation
頂點(diǎn)函數(shù)生成tessellator
三角形的最終頂點(diǎn)數(shù)據(jù)。在post-tessellation
頂點(diǎn)函數(shù)完成執(zhí)行之后,對(duì)細(xì)分的圖元進(jìn)行柵格化,并且渲染管線的其余階段正常執(zhí)行。
Per-Patch Tessellation Factors
每個(gè)補(bǔ)丁tessellation
因子指定tessellator
對(duì)每個(gè)補(bǔ)丁進(jìn)行細(xì)分的程度。 每個(gè)貼片tessellation
由四邊形貼片的MTLQuadTessellationFactorsHalf結(jié)構(gòu)或三角形貼片的MTLTriangleTessellationFactorsHalf結(jié)構(gòu)描述。
注意:雖然結(jié)構(gòu)成員的類型為
uint16_t
,但是提供給tessellator
的每個(gè)補(bǔ)丁tessellation
因子必須是half
的一半。
1. Understanding Quad Patches - 了解四邊形補(bǔ)丁
對(duì)于四邊形貼片,貼片中的位置是(u,v)
笛卡爾坐標(biāo),指示頂點(diǎn)相對(duì)于四邊形貼片邊界的水平和垂直位置,如圖12-2所示。 (u,v)
值各自為0.0到1.0。
Interpreting the MTLQuadTessellationFactorsHalf structure - 解釋MTLQuadTessellationFactorsHalf結(jié)構(gòu)
MTLQuadTessellationFactorsHalf結(jié)構(gòu)定義如下:
typedef struct {
uint16_t edgeTessellationFactor[4];
uint16_t insideTessellationFactor[2];
} MTLQuadTessellationFactorsHalf;
結(jié)構(gòu)中的每個(gè)值都提供特定的tessellation
因子:
-
edgeTessellationFactor [0]
提供補(bǔ)丁邊緣的tessellation
因子,其中u = 0(邊0)。 -
edgeTessellationFactor [1]
提供補(bǔ)丁邊緣的tessellation
因子,其中v = 0(邊緣1)。 -
edgeTessellationFactor [2]
提供補(bǔ)丁邊緣的tessellation
因子,其中u = 1(邊2)。 -
edgeTessellationFactor [3]
提供補(bǔ)丁邊緣的tessellation
因子,其中v = 1(邊3)。 -
insideTessellationFactor [0]
為v的所有內(nèi)部值提供水平tessellation
因子。 -
insideTessellationFactor [1]
為u的所有內(nèi)部值提供垂直tessellation
因子。
2. Understanding Triangle Patches - 了解三角形補(bǔ)丁
對(duì)于三角形貼片,貼片中的位置是(u,v,w)
重心坐標(biāo),表示三角形的三個(gè)頂點(diǎn)對(duì)頂點(diǎn)位置的相對(duì)影響,如圖12-3所示。(u,v,w)
值的范圍從0.0到1.0,其中u + v + w =?? 1.0
。
Interpreting the MTLTriangleTessellationFactorsHalf structure - 解釋MTLTriangleTessellationFactorsHalf結(jié)構(gòu)
MTLTriangleTessellationFactorsHalf結(jié)構(gòu)定義如下:
typedef struct {
uint16_t edgeTessellationFactor[3];
uint16_t insideTessellationFactor;
} MTLTriangleTessellationFactorsHalf;
結(jié)構(gòu)中的每個(gè)值都提供特定的tessellation
因子:
-
edgeTessellationFactor [0]
提供補(bǔ)丁邊緣的曲面細(xì)分因子,其中u = 0(邊0)。 -
edgeTessellationFactor [1]
提供補(bǔ)丁邊緣的曲面細(xì)分因子,其中v = 0(邊緣1)。 -
edgeTessellationFactor [2]
提供補(bǔ)丁邊緣的曲面細(xì)分因子,其中w = 1(邊2)。 -
insideTessellationFactor
提供內(nèi)部tessellation
因子。
3. Rules for Discarding Patches - 丟棄補(bǔ)丁的規(guī)則
如果邊緣tessellation
因子的值為負(fù),零或?qū)?yīng)于浮點(diǎn)NaN
,則tessellator
將丟棄該補(bǔ)丁。如果內(nèi)部tessellation
因子的值為負(fù),則tessellation
因子將被限制在tessellationPartitionMode屬性定義的范圍內(nèi),并且tessellator
不會(huì)丟棄該修補(bǔ)程序。
如果未丟棄補(bǔ)丁且tessellationFactorScaleEnabled屬性設(shè)置為YES
,則tessellator
將邊緣和內(nèi)部tessellation
因子乘以setTessellationFactorScale:方法中指定的比例因子。
當(dāng)丟棄補(bǔ)丁時(shí),不會(huì)生成新的基元,post-tessellation
頂點(diǎn)函數(shù)不會(huì)執(zhí)行,并且不會(huì)為該補(bǔ)丁生成可見的輸出。
4. Specifying the Per-Patch Tessellation Factors Buffer - 指定Per-Patch Tessellation Factors緩沖區(qū)
每個(gè)補(bǔ)丁tessellation
被寫入MTLBuffer對(duì)象,并通過調(diào)用setTessellationFactorBuffer:offset:instanceStride:方法作為輸入傳遞給tessellator
。在對(duì)同一MTLRenderCommandEncoder對(duì)象發(fā)出補(bǔ)丁繪制調(diào)用之前,必須調(diào)用此方法。
Patch Functions - Patch 函數(shù)
本節(jié)總結(jié)了支持tessellation
的Metal著色語言的主要更改。 有關(guān)詳細(xì)信息,請(qǐng)參閱Metal Shading Language Guide
的Functions, Variables, and Qualifiers
一章。
1. Creating a Compute Kernel - 創(chuàng)建計(jì)算內(nèi)核
計(jì)算內(nèi)核是使用現(xiàn)有kernel
函數(shù)限定符標(biāo)識(shí)的內(nèi)核函數(shù)。 Listing 12-1
是計(jì)算內(nèi)核函數(shù)簽名的示例。
Listing 12-1 Compute kernel function signature
kernel void my_compute_kernel(...) {...}
Metal著色語言的現(xiàn)有功能完全支持計(jì)算內(nèi)核。 計(jì)算內(nèi)核函數(shù)的輸入和輸出與常規(guī)內(nèi)核函數(shù)相同。
2. Creating a Post-Tessellation Vertex Function - 創(chuàng)建Post-Tessellation頂點(diǎn)函數(shù)
post-tessellation
頂點(diǎn)函數(shù)是使用現(xiàn)有vertex
函數(shù)限定符標(biāo)識(shí)的頂點(diǎn)函數(shù)。 另外,新的[[patch(patch-type),N]]
屬性用于指定補(bǔ)丁類型(patch-type)
和patch (N)
中的控制點(diǎn)數(shù)。 Listing 12-2是一個(gè)post-tessellation
頂點(diǎn)函數(shù)簽名的示例。
Listing 12-2 Post-tessellation vertex function signature
[[patch(quad, 16)]]
vertex float4 my_post_tessellation_vertex_function(...) {...}
注意:在OS X中,必須始終指定修補(bǔ)程序中的控制點(diǎn)數(shù)。 在iOS和tvOS中,指定此值是可選的。 如果指定了此值,則它必須與補(bǔ)丁繪制調(diào)用的
numberOfPatchControlPoints
參數(shù)的值匹配。
Post-Tessellation Vertex Function Inputs - Post-Tessellation頂點(diǎn)函數(shù)輸入
post-tessellation
頂點(diǎn)函數(shù)的所有輸入都作為以下一個(gè)或多個(gè)參數(shù)傳遞:
- 緩沖區(qū)(在
device
或constant
地址空間中聲明),紋理或采樣器等資源。 - 每個(gè)補(bǔ)丁數(shù)據(jù)和補(bǔ)丁控制點(diǎn)數(shù)據(jù)。 這些可以直接從緩沖區(qū)中讀取,也可以作為使用
[[stage_in]]
限定符聲明的輸入傳遞給post-tessellation
頂點(diǎn)函數(shù)。 - 內(nèi)置變量,如表12-1所示。
Post-Tessellation Vertex Function Outputs - Post-Tessellation頂點(diǎn)函數(shù)輸出
post-tessellation
頂點(diǎn)函數(shù)的輸出與常規(guī)頂點(diǎn)函數(shù)相同。 如果post-tessellation
頂點(diǎn)函數(shù)寫入緩沖區(qū),則其返回類型必須為void
。
Tessellation Pipeline State - Tessellation管道狀態(tài)
本節(jié)總結(jié)了支持tessellation
的Metal框架API的主要更改,這些更改與tessellation
管道狀態(tài)有關(guān)。
1. Building a Compute Pipeline - 構(gòu)建計(jì)算管道
在構(gòu)建MTLComputePipelineState對(duì)象時(shí),計(jì)算內(nèi)核被指定為計(jì)算管道的一部分,如Listing 12-3所示。 為獲得最佳性能,應(yīng)在幀中盡早執(zhí)行計(jì)算內(nèi)核。 (為了支持計(jì)算內(nèi)核或tessellation
,現(xiàn)有計(jì)算管道API沒有變化。)
Listing 12-3 Building a compute pipeline with a compute kernel
// Fetch the compute kernel from the library
id <MTLFunction> computeKernel = [_library newFunctionWithName:@"my_compute_kernel"];
// Build the compute pipeline
NSError *pipelineError = NULL;
_computePipelineState = [_device newComputePipelineStateWithFunction:computeKernel error:&pipelineError];
if (!_computePipelineState) {
NSLog(@"Failed to create compute pipeline state, error: %@", pipelineError);
}
2. Building a Render Pipeline - 構(gòu)建渲染管道
tessellator
配置為渲染管道的一部分,使用MTLRenderPipelineDescriptor對(duì)象構(gòu)建MTLRenderPipelineState對(duì)象。 使用vertexFunction屬性指定post-tessellation
頂點(diǎn)函數(shù)。 Listing 12-4演示了如何使用tessellator
和post-tessellation
頂點(diǎn)函數(shù)配置和構(gòu)建渲染管道。 有關(guān)詳細(xì)信息,請(qǐng)參閱MTLRenderPipelineDescriptor類引用的Specifying Tessellation State
和MTLTessellationFactorStepFunction部分。
Listing 12-4 Building a render pipeline with a tessellator and a post-tessellation vertex function
// Fetch the post-tessellation vertex function from the library
id <MTLFunction> postTessellationVertexFunction = [_library newFunctionWithName:@"my_post_tessellation_vertex_function"];
// Fetch the fragment function from the library
id <MTLFunction> fragmentFunction = [_library newFunctionWithName:@"my_fragment_function"];
// Configure the render pipeline, using the default tessellation values
MTLRenderPipelineDescriptor *renderPipelineDescriptor = [MTLRenderPipelineDescriptor new];
renderPipelineDescriptor.colorAttachments[0].pixelFormat = _view.colorPixelFormat;
renderPipelineDescriptor.fragmentFunction = fragmentFunction;
renderPipelineDescriptor.vertexFunction = postTessellationVertexFunction;
renderPipelineDescriptor.maxTessellationFactor = 16;
renderPipelineDescriptor.tessellationFactorScaleEnabled = NO;
renderPipelineDescriptor.tessellationFactorFormat = MTLTessellationFactorFormatHalf;
renderPipelineDescriptor.tessellationControlPointIndexType = MTLTessellationControlPointIndexTypeNone;
renderPipelineDescriptor.tessellationFactorStepFunction = MTLTessellationFactorStepFunctionConstant;
renderPipelineDescriptor.tessellationOutputWindingOrder = MTLWindingClockwise;
renderPipelineDescriptor.tessellationPartitionMode = MTLTessellationPartitionModePow2;
// Build the render pipeline
NSError *pipelineError = NULL;
_renderPipelineState = [_device newRenderPipelineStateWithDescriptor:renderPipelineDescriptor error:&pipelineError];
if (!_renderPipelineState) {
NSLog(@"Failed to create render pipeline state, error %@", pipelineError);
}
Patch Draw Calls - Patch繪制調(diào)用
本節(jié)總結(jié)了支持tessellation
的Metal框架API的主要更改,與補(bǔ)丁繪制調(diào)用有關(guān)。
1. Drawing Tessellated Patches - 繪制Tessellated補(bǔ)丁
要呈現(xiàn)tessellated
補(bǔ)丁的大量實(shí)例,請(qǐng)調(diào)用以下MTLRenderCommandEncoder方法之一:
- drawPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:instanceCount:baseInstance:
- drawPatches:patchIndexBuffer:patchIndexBufferOffset:indirectBuffer:indirectBufferOffset:
- drawIndexedPatches:patchStart:patchCount:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:instanceCount:baseInstance:
- drawIndexedPatches:patchIndexBuffer:patchIndexBufferOffset:controlPointIndexBuffer:controlPointIndexBufferOffset:indirectBuffer:indirectBufferOffset:
注意:只有將vertexFunction屬性設(shè)置為
post-tessellation
頂點(diǎn)函數(shù)時(shí),才能調(diào)用這些補(bǔ)丁繪制調(diào)用。調(diào)用非補(bǔ)丁繪制調(diào)用會(huì)導(dǎo)致驗(yàn)證層報(bào)告錯(cuò)誤。
Patch
繪制調(diào)用不支持基本重啟功能。
對(duì)于所有補(bǔ)丁繪制調(diào)用,每個(gè)補(bǔ)丁數(shù)據(jù)和一個(gè)補(bǔ)丁控制點(diǎn)數(shù)組被組織起來,用于在連續(xù)數(shù)組元素中進(jìn)行渲染,從baseInstance
參數(shù)中指定的值開始。有關(guān)每個(gè)參數(shù)的詳細(xì)信息,請(qǐng)參閱MTLRenderCommandEncoder協(xié)議參考的Drawing Tessellated Patches
部分。
為了呈現(xiàn)補(bǔ)丁數(shù)據(jù),補(bǔ)丁繪制調(diào)用每補(bǔ)丁數(shù)據(jù)和補(bǔ)丁控制點(diǎn)數(shù)據(jù)。補(bǔ)丁數(shù)據(jù)通常一起存儲(chǔ)在一個(gè)或多個(gè)緩沖區(qū)中的一個(gè)或多個(gè)網(wǎng)格的所有補(bǔ)丁中。執(zhí)行計(jì)算內(nèi)核以生成依賴于場(chǎng)景的per-patch tessellation
;計(jì)算內(nèi)核可能決定僅為未被丟棄的補(bǔ)丁生成因子,在這種情況下補(bǔ)丁不是連續(xù)的。因此,補(bǔ)丁索引緩沖區(qū)用于標(biāo)識(shí)要繪制的補(bǔ)丁的補(bǔ)丁ID
。
來自[patchStart,patchStart + patchCount-1]
的緩沖區(qū)索引(drawPatchIndex)
用于引用數(shù)據(jù)。如果用于獲取每個(gè)補(bǔ)丁數(shù)據(jù)和補(bǔ)丁控制點(diǎn)數(shù)據(jù)的補(bǔ)丁索引不是連續(xù)的,則drawPatchIndex
可以引用patchIndexBuffer
,如圖12-4所示。
patchIndexBuffer
的每個(gè)元素都包含一個(gè)32位patchIndex
值,該值引用每個(gè)補(bǔ)丁數(shù)據(jù)和補(bǔ)丁控制點(diǎn)數(shù)據(jù)。 從patchIndexBuffer
獲取的patchIndex
位于:(drawPatchIndex * 4)+ patchIndexBufferOffset
。
補(bǔ)丁的控制點(diǎn)索引通過以下方式計(jì)算:
patchIndex * numberOfPatchControlPoints *((patchIndex + 1)* numberOfPatchControlPoints) - 1
patchIndexBuffer
還使用于讀取每個(gè)補(bǔ)丁數(shù)據(jù)和補(bǔ)丁控制點(diǎn)數(shù)據(jù)的patchIndex
與用于讀取每補(bǔ)丁tessellation
因子的索引不同。 對(duì)于tessellator
,drawPatchIndex
直接用作獲取每個(gè)補(bǔ)丁tessellation
因子的索引。
如果patchIndexBuffer
為NULL
,則drawPatchIndex
和patchIndex
的值相同,如圖12-5所示。
如果控制點(diǎn)在補(bǔ)丁之間共享或補(bǔ)丁控制點(diǎn)數(shù)據(jù)不連續(xù),請(qǐng)使用drawIndexedPatches
方法。 patchIndex
引用一個(gè)指定的controlPointIndexBuffer
,它包含一個(gè)補(bǔ)丁的控制點(diǎn)索引,如圖12-6所示。 (tessellationControlPointIndexType描述controlPointIndexBuffer
中控制點(diǎn)索引的大小,并且必須是MTLTessellationControlPointIndexTypeUInt16或MTLTessellationControlPointIndexTypeUInt32。)
controlPointIndexBuffer
中第一個(gè)控制點(diǎn)索引的實(shí)際位置計(jì)算如下:
controlPointIndexBufferOffset +(patchIndex * numberOfPatchControlPoints * controlPointIndexType == UInt16?2:4)
幾個(gè)(numberOfPatchControlPoints
)控制點(diǎn)索引必須連續(xù)存儲(chǔ)在controlPointIndexBuffer
中,從第一個(gè)控制點(diǎn)索引的位置開始。
Sample Code - 示例代碼
有關(guān)如何設(shè)置基本tessellation
的示例,請(qǐng)參閱MetalBasicTessellation
示例。
Porting DirectX 11-Style Tessellation Shaders to Metal - 將DirectX 11樣式Tessellation著色器移植到Metal
本節(jié)介紹如何將DirectX 11
樣式tessellation
頂點(diǎn)和外殼著色器移植到Metal
計(jì)算內(nèi)核。
注意:
Metal tessellator
執(zhí)行DirectX 11
的tessellator
的等效計(jì)算。Metal post-tessellation
頂點(diǎn)函數(shù)執(zhí)行DirectX 11
域著色器的等效計(jì)算。
在DirectX 11
中,為補(bǔ)丁的每個(gè)控制點(diǎn)執(zhí)行HLSL
頂點(diǎn)著色器。 HLSL
外殼著色器由兩個(gè)函數(shù)指定:一個(gè)為補(bǔ)丁的每個(gè)控制點(diǎn)執(zhí)行的函數(shù),另一個(gè)執(zhí)行每個(gè)補(bǔ)丁的函數(shù)。 頂點(diǎn)著色器的輸出是構(gòu)成外殼著色器的這兩個(gè)函數(shù)的輸入。
Listing 12-5
顯示了一個(gè)簡(jiǎn)單的HLSL頂點(diǎn)和外殼著色器
Listing 12-5 Simple HLSL vertex and hull shader
struct VertexIn
{
float3 PosL;
float3 NormalL;
float3 TangentL;
float2 Tex;
};
struct VertexOut
{
float3 PosW : POSITION;
float3 NormalW : NORMAL;
float3 TangentW : TANGENT;
float2 Tex : TEXCOORD;
float TessFactor : TESS;
};
VertexOut VS(VertexIn vin)
{
VertexOut vout;
// Transform to world space space.
vout.PosW = mul(float4(vin.PosL, 1.0f), gWorld).xyz;
vout.NormalW = mul(vin.NormalL, (float3x3)gWorldInvTranspose);
vout.TangentW = mul(vin.TangentL, (float3x3)gWorld);
// Output vertex attributes for interpolation across triangle.
vout.Tex = mul(float4(vin.Tex, 0.0f, 1.0f), gTexTransform).xy;
float d = distance(vout.PosW, gEyePosW);
// Normalized tessellation factor.
// The tessellation is
// 0 if d >= gMinTessDistance and
// 1 if d <= gMaxTessDistance.
float tess = saturate( (gMinTessDistance - d) /
(gMinTessDistance - gMaxTessDistance) );
// Rescale [0,1] --> [gMinTessFactor, gMaxTessFactor].
vout.TessFactor = gMinTessFactor + tess*(gMaxTessFactor-gMinTessFactor);
return vout;
}
struct HullOut
{
float3 PosW : POSITION;
float3 NormalW : NORMAL;
float3 TangentW : TANGENT;
float2 Tex : TEXCOORD;
};
[domain("tri")]
[partitioning("fractional_odd")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("PatchHS")]
HullOut HS(InputPatch<VertexOut,3> p,
uint i : SV_OutputControlPointID,
uint patchId : SV_PrimitiveID)
{
HullOut hout;
// Pass through shader.
hout.PosW = p[i].PosW;
hout.NormalW = p[i].NormalW;
hout.TangentW = p[i].TangentW;
hout.Tex = p[i].Tex;
return hout;
}
struct PatchTess
{
float EdgeTess[3] : SV_TessFactor;
float InsideTess : SV_InsideTessFactor;
};
PatchTess PatchHS(InputPatch<VertexOut,3> patch,
uint patchID : SV_PrimitiveID)
{
PatchTess pt;
// Average tess factors along edges, and pick an edge tess factor for
// the interior tessellation. It is important to do the tess factor
// calculation based on the edge properties so that edges shared by
// more than one triangle will have the same tessellation factor.
// Otherwise, gaps can appear.
pt.EdgeTess[0] = 0.5f*(patch[1].TessFactor + patch[2].TessFactor);
pt.EdgeTess[1] = 0.5f*(patch[2].TessFactor + patch[0].TessFactor);
pt.EdgeTess[2] = 0.5f*(patch[0].TessFactor + patch[1].TessFactor);
pt.InsideTess = pt.EdgeTess[0];
return pt;
}
這些簡(jiǎn)單的HLSL
頂點(diǎn)和外殼著色器可以移植到Metal
函數(shù),并且可以創(chuàng)建一個(gè)調(diào)用這些Metal函數(shù)的計(jì)算內(nèi)核,將這些函數(shù)作為單個(gè)內(nèi)核執(zhí)行。 移植的頂點(diǎn)和控制點(diǎn)外殼函數(shù)在計(jì)算內(nèi)核中被稱為每線程(per-thread)
,后跟一個(gè)線程組阻塞,然后每個(gè)補(bǔ)丁程序的外殼函數(shù)由線程組中的線程子集執(zhí)行。 能夠直接在內(nèi)核中調(diào)用已轉(zhuǎn)換的頂點(diǎn)和外殼函數(shù),使開發(fā)人員可以輕松地將其頂點(diǎn)和外殼著色器從DirectX 11
移植到Metal
。
簡(jiǎn)單的HLSL頂點(diǎn)和外殼著色器可以移植到Listing 12-6
中所示的Metal
函數(shù)
Listing 12-6 Simple HLSL vertex and hull shader ported to Metal functions
struct VertexIn
{
float3 PosL [[ attribute(0) ]];
float3 NormalL [[ attribute(1) ]];
float3 TangentL [[ attribute(2) ]];
float2 Tex [[ attribute(3) ]];
};
struct VertexOut
{
float3 PosW [[ position ]];
float3 NormalW;
float3 TangentW;
float2 Tex;
float TessFactor;
};
struct ConstantData {
…;
}
// The vertex control point function
VertexOut
VS(VertexIn vin,
constant ConstantData &c)
{
VertexOut vout;
// Transform to world space space.
vout.PosW = mul(float4(vin.PosL, 1.0f), c.gWorld).xyz;
vout.NormalW = mul(vin.NormalL, (float3x3)c.gWorldInvTranspose);
vout.TangentW = mul(vin.TangentL, (float3x3)c.gWorld);
// Output vertex attributes for interpolation across triangle.
vout.Tex = mul(float4(vin.Tex, 0.0f, 1.0f), c.gTexTransform).xy;
float d = distance(vout.PosW, gEyePosW);
// Normalized tessellation factor.
// The tessellation is
// 0 if d >= gMinTessDistance and
// 1 if d <= gMaxTessDistance.
float tess = saturate( (c.gMinTessDistance - d) /
(c.gMinTessDistance - c.gMaxTessDistance) );
// Rescale [0,1] --> [gMinTessFactor, gMaxTessFactor].
vout.TessFactor = c.gMinTessFactor +
tess * (c.gMaxTessFactor - c.gMinTessFactor);
return vout;
}
struct HullOut
{
float3 PosW [[ position ]];
float3 NormalW;
float3 TangentW;
float2 Tex;
}
// The patch control point function
HullOut
HS(VertexOut p)
{
HullOut hout;
// Pass through shader.
hout.PosW = p.PosW;
hout.NormalW = p.NormalW;
hout.TangentW = p.TangentW;
hout.Tex = p.Tex;
return hout;
}
struct PatchTess
{
packed_half3 EdgeTess;
half InsideTess;
};
// The per-patch function
PatchTess
PatchHS(threadgroup VertexOut *patch)
{
PatchTess pt;
// Average tess factors along edges, and pick an edge tess factor for
// the interior tessellation. It is important to do the tess factor
// calculation based on the edge properties so that edges shared by
// more than one triangle will have the same tessellation factor.
// Otherwise, gaps can appear.
pt.EdgeTess[0] = 0.5f*(patch[1].TessFactor + patch[2].TessFactor);
pt.EdgeTess[1] = 0.5f*(patch[2].TessFactor + patch[0].TessFactor);
pt.EdgeTess[2] = 0.5f*(patch[0].TessFactor + patch[1].TessFactor);
pt.InsideTess = pt.EdgeTess[0];
return pt;
}
A compute kernel that calls these vertex and hull functions can be:
struct KernelPatchInfo {
uint numPatches; // total number of patches to process.
// we need this because this value may
// not be a multiple of threadgroup size.
ushort numPatchesInThreadGroup; // number of patches processed by a
// thread-group
ushort numControlPointsPerPatch;
}; // passed as a constant buffer using setBytes by the runtime
kernel void
PatchKernel(VertexIn vIn [[ stage_in ]],
constant ConstantData &c [[ buffer(1) ]],
constant KernelPatchInfo &patchInfo [[ buffer(2) ]],
PatchTess *tessellationFactorBuffer [[ buffer(3) ]],
device HullOut *hullOutputBuffer [[ buffer(4) ]],
threadgroup HullOut *hullOutputTGBuffer [[ threadgroup(0) ]],
uint tID [[ thread_position_in_grid ]],
ushort lID [[ thread_position_in_threadgroup ]],
ushort lSize [[ threads_in_threadgroup ]],
ushort groupID [[ threadgroup_position_in_grid ]])
{
ushort n = patchInfo.numControlPointsPerPatch;
uint patchGroupID = groupID * patchInfo.numPatchesInThreadGroup;
// execute the vertex and control-point hull function per-thread
if ( (lID <= (patchInfo.numPatchesInThreadGroup * n) &&
(tID <= (patchInfo.numPatches * n)) )
{
uint controlPointID = patchGroupID * n + lID;
VertexOut vOut = VS(vIn, c);
HullOut hOut = HS(vOut);
hullOutputTGBuffer[lID] = hOut;
hullOutputBuffer[controlPointID] = hOut;
}
threadgroup_barrier(mem_flags::mem_threadgroup);
// execute the per-patch hull function
if (lID < patchInfo.numPatchesInThreadGroup)
{
uint patchID = patchGroupID + lID;
tessellationFactorBuffer[patchID] = PatchHS(
hullOutputTGBuffer[lID*n]);
}
}
注意:
- 線程組大小應(yīng)設(shè)置為
SIMD
大小或SIMD
大小的倍數(shù)。- 線程組中的補(bǔ)丁數(shù)由補(bǔ)丁中的
threadgroup size / number of control points
給出。- 每個(gè)補(bǔ)丁的控制點(diǎn)數(shù)量在
HLSL
外殼著色器中描述。- 在此移植示例中,輸入和輸出控制點(diǎn)的數(shù)量是相同的。 通過對(duì)計(jì)算內(nèi)核的一些修改,也可以支持輸入和輸出控制點(diǎn)的數(shù)量不相同的情況。
后記
本篇主要講述了Metal編程指南之Tessellation,感興趣的給個(gè)贊或者關(guān)注~~~