版本記錄
版本號 | 時間 |
---|---|
V1.0 | 2018.11.11 星期日 |
前言
很多做視頻和圖像的,相信對這個框架都不是很陌生,它渲染高級3D圖形丁屎,并使用GPU執(zhí)行數(shù)據(jù)并行計算。接下來的幾篇我們就詳細的解析這個框架旱眯。感興趣的看下面幾篇文章晨川。
1. Metal框架詳細解析(一)—— 基本概覽
2. Metal框架詳細解析(二) —— 器件和命令(一)
3. Metal框架詳細解析(三) —— 渲染簡單的2D三角形(一)
4. Metal框架詳細解析(四) —— 關(guān)于GPU Family 4(一)
5. Metal框架詳細解析(五) —— 關(guān)于GPU Family 4之關(guān)于Imageblocks(二)
6. Metal框架詳細解析(六) —— 關(guān)于GPU Family 4之關(guān)于Tile Shading(三)
7. Metal框架詳細解析(七) —— 關(guān)于GPU Family 4之關(guān)于光柵順序組(四)
8. Metal框架詳細解析(八) —— 關(guān)于GPU Family 4之關(guān)于增強的MSAA和Imageblock采樣覆蓋控制(五)
9. Metal框架詳細解析(九) —— 關(guān)于GPU Family 4之關(guān)于線程組共享(六)
10. Metal框架詳細解析(十) —— 基本組件(一)
11. Metal框架詳細解析(十一) —— 基本組件之器件選擇 - 圖形渲染的器件選擇(二)
12. Metal框架詳細解析(十二) —— 基本組件之器件選擇 - 計算處理的設(shè)備選擇(三)
13. Metal框架詳細解析(十三) —— 計算處理(一)
14. Metal框架詳細解析(十四) —— 計算處理之你好,計算(二)
15. Metal框架詳細解析(十五) —— 計算處理之關(guān)于線程和線程組(三)
16. Metal框架詳細解析(十六) —— 計算處理之計算線程組和網(wǎng)格大猩静颉(四)
17. Metal框架詳細解析(十七) —— 工具共虑、分析和調(diào)試(一)
18. Metal框架詳細解析(十八) —— 工具、分析和調(diào)試之Metal GPU Capture(二)
19. Metal框架詳細解析(十九) —— 工具呀页、分析和調(diào)試之GPU活動監(jiān)視器(三)
20. Metal框架詳細解析(二十) —— 工具妈拌、分析和調(diào)試之關(guān)于Metal著色語言文件名擴展名、使用Metal的命令行工具構(gòu)建庫和標(biāo)記Metal對象和命令(四)
21. Metal框架詳細解析(二十一) —— 基本課程之基本緩沖區(qū)(一)
22. Metal框架詳細解析(二十二) —— 基本課程之基本紋理(二)
23. Metal框架詳細解析(二十三) —— 基本課程之CPU和GPU同步(三)
24. Metal框架詳細解析(二十四) —— 基本課程之參數(shù)緩沖 - 基本參數(shù)緩沖(四)
25. Metal框架詳細解析(二十五) —— 基本課程之參數(shù)緩沖 - 帶有數(shù)組和資源堆的參數(shù)緩沖區(qū)(五)
26. Metal框架詳細解析(二十六) —— 基本課程之參數(shù)緩沖 - 具有GPU編碼的參數(shù)緩沖區(qū)(六)
27. Metal框架詳細解析(二十七) —— 高級技術(shù)之圖層選擇的反射(一)
28. Metal框架詳細解析(二十八) —— 高級技術(shù)之使用專用函數(shù)的LOD(一)
29. Metal框架詳細解析(二十九) —— 高級技術(shù)之具有參數(shù)緩沖區(qū)的動態(tài)地形(一)
30. Metal框架詳細解析(三十) —— 延遲照明(一)
31. Metal框架詳細解析(三十一) —— 在視圖中混合Metal和OpenGL渲染(一)
32. Metal框架詳細解析(三十二) —— Metal渲染管道教程(一)
33. Metal框架詳細解析(三十三) —— Metal渲染管道教程(二)
34. Metal框架詳細解析(三十四) —— Hello Metal蓬蝶! 一個簡單的三角形的實現(xiàn)(一)
35. Metal框架詳細解析(三十五) —— Hello Metal尘分! 一個簡單的三角形的實現(xiàn)(二)
36. Metal框架詳細解析(三十六) —— Metal編程指南之概覽(一)
37. Metal框架詳細解析(三十七) —— Metal編程指南之基本Metal概念(二)
38. Metal框架詳細解析(三十八) —— Metal編程指南之命令組織和執(zhí)行模型(三)
39. Metal框架詳細解析(三十九) —— Metal編程指南之資源對象:緩沖區(qū)和紋理(四)
40. Metal框架詳細解析(四十) —— Metal編程指南之函數(shù)和庫(五)
41. Metal框架詳細解析(四十一) —— Metal編程指南之圖形渲染:渲染命令編碼器之Part 1(六)
42. Metal框架詳細解析(四十二) —— Metal編程指南之圖形渲染:渲染命令編碼器之Part 2(七)
43. Metal框架詳細解析(四十三) —— Metal編程指南之?dāng)?shù)據(jù)并行計算處理:計算命令編碼器(八)
44. Metal框架詳細解析(四十四) —— Metal編程指南之緩沖和紋理操作:Blit命令編碼器(九)
45. Metal框架詳細解析(四十五) —— Metal編程指南之Metal工具(十)
46. Metal框架詳細解析(四十六) —— Metal編程指南之Tessellation(十一)
Resource Heaps - 資源堆
可用于:iOS_GPUFamily1_v3猜惋,iOS_GPUFamily2_v3,iOS_GPUFamily3_v2培愁,tvOS_GPUFamily1_v2
資源堆允許Metal資源由相同的內(nèi)存分配支持著摔。這些資源是從稱為堆的內(nèi)存池創(chuàng)建的,它們由捕獲和管理GPU工作依賴關(guān)系的fence
進行跟蹤竭钝。資源堆可幫助您的應(yīng)用降低以下成本:
- Resource creation - 資源創(chuàng)造梨撞。資源創(chuàng)建可能涉及分配新內(nèi)存,將其映射到您的進程香罐,并將其填充為零卧波。通過從較大的堆或由堆支持的可循環(huán)資源內(nèi)存創(chuàng)建資源,可以降低此成本庇茫。
- Fixed memory budget - 固定內(nèi)存預(yù)算港粱。如果您的某些資源在一段時間內(nèi)未使用,則虛擬內(nèi)存可能會壓縮資源內(nèi)存以節(jié)省空間旦签。這可能會導(dǎo)致額外的時間花費在再次使用此資源內(nèi)存以供下次使用查坪。通過使用少量堆,您可以將分配保持在給定的內(nèi)存預(yù)算內(nèi)宁炫,并確保這些資源不斷使用(這有助于提供更一致的性能)偿曙。
- Transient resources - 瞬態(tài)資源。為每個幀生成和消耗瞬態(tài)資源羔巢,但并非所有這些資源同時一起使用望忆。為了減少內(nèi)存消耗,未一起使用的瞬態(tài)資源可以共享由堆支持的相同內(nèi)存竿秆。
Heaps - 堆
MTLHeap對象是表示抽象內(nèi)存池的Metal資源启摄。從此堆創(chuàng)建的資源定義為可別的或不可別的(aliasable or non-aliasable)
。當(dāng)子分配的資源與另一個別名資源共享相同的堆內(nèi)存部分時幽钢,它們會被別名化歉备。
1. Creating a Heap - 創(chuàng)建堆
通過調(diào)用MTLDevice對象的newHeapWithDescriptor:方法來創(chuàng)建MTLHeap對象。 MTLHeapDescriptor對象描述堆的存儲模式匪燕,CPU緩存模式和字節(jié)大小蕾羊。從同一堆子分配的所有資源共享相同的存儲模式和CPU緩存模式。堆的字節(jié)大小必須足夠大谎懦,以便為其資源分配足夠的內(nèi)存肚豺。
通過調(diào)用setPurgeableState:方法創(chuàng)建堆后,可以使堆可以清除界拦。堆清除狀態(tài)指的是其整個后備內(nèi)存,并影響堆中的所有資源梗劫。堆是可以清除的享甸,但它們的資源不是截碴;子分配的資源僅反映堆的可清除狀態(tài)◎韧可清除性對于僅存儲渲染目標(biāo)的堆可能是有用的日丹。
2. Sub-Allocating Heap Resources - 子分配堆資源
MTLBuffer和MTLTexture對象都可以從堆中進行子分配。為此蚯嫌,請調(diào)用MTLHeap對象的以下兩種方法之一:
默認情況下哲虾,每個子分配的資源都被定義為不可別名的,這可以防止將來的子分配資源使用其內(nèi)存择示。要使子分配的資源可以別名束凑,請調(diào)用makeAliasable方法;這允許未來的子分配資源重用其內(nèi)存栅盲。
別名不會破壞可分配的子分配資源汪诉,命令編碼器仍可使用它們。這些資源擁有對其堆的強引用谈秫,只有在資源本身被銷毀時才釋放扒寄,而不是在它變?yōu)榭蓜e名的時候釋放。只有在引用它們的所有命令緩沖區(qū)都已完成執(zhí)行后拟烫,才能銷毀子分配的資源该编。
注意:堆是線程安全的,但您可能仍需要在應(yīng)用級別同步堆硕淑,以確保按預(yù)期設(shè)置別名课竣。子分配資源之間的命令依賴關(guān)系不是自動的;必須通過Fences部分中描述的MTLFence API顯式聲明和管理手動跟蹤喜颁。
Listing 13-1
顯示了使用堆進行簡單的資源子分配
Listing 13-1 Simple heap creation and resource sub-allocation
// Calculate the size and alignment of each resource
MTLSizeAndAlign albedoSizeAndAlign = [_device heapTextureSizeAndAlignWithTextureDescriptor:_albedoDescriptor];
MTLSizeAndAlign normalSizeAndAlign = [_device heapTextureSizeAndAlignWithTextureDescriptor:_normalDescriptor];
MTLSizeAndAlign glossSizeAndAlign = [_device heapTextureSizeAndAlignWithTextureDescriptor:_glossDescriptor];
// Calculate a heap size that satisfies the size requirements of all three resources
NSUInteger heapSize = albedoSizeAndAlign.size + normalSizeAndAlign.size + glossSizeAndAlign.size;
// Create a heap descriptor
MTLHeapDescriptor* heapDescriptor = [MTLHeapDescriptor new];
heapDescriptor.cpuCacheMode = MTLCPUCacheModeDefaultCache;
heapDescriptor.storageMode = MTLStorageModePrivate;
heapDescriptor.size = heapSize;
// Create a heap
id <MTLHeap> heap = [_device newHeapWithDescriptor:heapDescriptor];
// Create sub-allocated resources from the heap
id <MTLTexture> albedoTexture = [_heap newTextureWithDescriptor:_albedoDescriptor];
id <MTLTexture> normalTexture = [_heap newTextureWithDescriptor:_normalDescriptor];
id <MTLTexture> glossTexture = [_heap newTextureWithDescriptor:_glossDescriptor];
Fences
MTLFence對象用于跨命令編碼器跟蹤和管理子分配的資源依賴性稠氮。資源依賴性隨著資源由不同命令生成和使用而出現(xiàn),無論這些命令是編碼到同一隊列還是不同隊列半开。fence
捕獲GPU工作到特定時間點隔披;當(dāng)GPU遇到fence
時,它必須等到所有捕獲的工作完成后再繼續(xù)執(zhí)行寂拆。
1. Creating a Fence - 創(chuàng)建一個柵欄
通過調(diào)用MTLDevice對象的newFence方法創(chuàng)建MTLFence對象奢米。fence
主要用于跟蹤目的,僅支持GPU內(nèi)部跟蹤纠永,而不支持CPU和GPU之間的跟蹤鬓长。 MTLFence協(xié)議不提供任何方法或完成處理程序,您只能修改label屬性尝江。
注意:
Fences
可以重復(fù)更新涉波,硬件管理fence
更新以防止死鎖。
2. Tracking Fences Across Blit and Compute Command Encoders - 跟蹤Blit和計算命令編碼器的Fences
可以使用fence跟蹤MTLBlitCommandEncoder和MTLComputeCommandEncoder對象。要更新fence啤覆,請分別為每個命令編碼器調(diào)用updateFence:或updateFence:方法苍日。要等待fence
,請分別為每個命令編碼器調(diào)用waitForFence:或waitForFence:方法窗声。
當(dāng)命令緩沖區(qū)實際提交給硬件時相恃,會更新或評估fence
。這可以維護全局秩序并防止死鎖笨觅。
驅(qū)動程序可能會在命令編碼器的開頭等待fence
拦耐,驅(qū)動程序可能會延遲fence
更新,直到命令編碼器結(jié)束见剩。因此杀糯,不允許首先更新然后在同一命令編碼器中等待相同的柵欄(但是,您可以先等待然后更新)炮温。生產(chǎn)者 - 消費者關(guān)系必須分散在不同的命令編碼器中火脉。
3. Tracking Fences Across Render Command Encoders - 跟蹤渲染命令編碼器中的Fences
可以使用更精細的粒度跟蹤MTLRenderCommandEncoder對象摘完。 MTLRenderStages枚舉允許您指定更新或等待柵欄的渲染階段斑响,允許頂點和片段命令重疊執(zhí)行。調(diào)用updateFence:afterStages:方法來更新fence
并調(diào)用waitForFence:beforeStages:方法來等待fence盟猖。
4. Fence Examples - Fence示例
Listing 13-2顯示了使用fence
進行簡單跟蹤担巩。
Listing 13-2 Simple fence tracking
id <MTLFence> fence = [_device newFence];
id <MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
// Producer
id <MTLRenderCommandEncoder> renderCommandEncoder = [commandBuffer renderCommandEncoderWithDescriptor:_descriptor];
/* Draw using resources associated with 'fence' */
[renderCommandEncoder updateFence:fence afterStages:MTLRenderStageFragment];
[renderCommandEncoder endEncoding];
// Consumer
id <MTLComputeCommandEncoder> computeCommandEncoder = [commandBuffer computeCommandEncoder];
[computeCommandEncoder waitForFence:fence];
/* Dispatch using resources associated with 'fence' */
[computeCommandEncoder endEncoding];
[commandBuffer commit];
如果只有后一個命令編碼器更新fence
方援,則不能假設(shè)兩個命令編碼器將完成。 消費者命令編碼器必須明確等待將在圍欄上發(fā)生沖突的所有命令編碼器涛癌。 (GPU可能會開始執(zhí)行盡可能多的命令犯戏,除非它遇到圍柵。)Listing 13-3顯示了引入競爭條件的圍欄的錯誤使用拳话。
Listing 13-3 Incorrect fence tracking
id <MTLFence> fence = [_device newFence];
id <MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
// Producer 1
id <MTLRenderCommandEncoder> producerCommandEncoder1 = [commandBuffer renderCommandEncoderWithDescriptor:_descriptor];
/* Draw using resources associated with 'fence' */
[producerCommandEncoder1 endEncoding];
// Producer 2
id <MTLComputeCommandEncoder> producerCommandEncoder2 = [commandBuffer computeCommandEncoder];
/* Encode */
[producerCommandEncoder2 updateFence:fence];
[producerCommandEncoder2 endEncoding];
// Race condition at consumption!
// producerCommandEncoder2 updated the fence and will have completed its work
// producerCommandEncoder1 did not update the fence and therefore there is no guarantee that it will have completed its work
// Consumer
id <MTLComputeCommandEncoder> computeCommandEncoder = [commandBuffer computeCommandEncoder];
[computeCommandEncoder waitForFence:fence];
/* Dispatch using resources associated with 'fence' */
[computeCommandEncoder endEncoding];
[commandBuffer commit];
您仍負責(zé)對命令緩沖區(qū)提交隊列進行排序先匪,如Listing 13-4
所示。 但是弃衍,fences
不允許您控制隊列間命令緩沖區(qū)排序
Listing 13-4 Sequencing fences across command buffer submission queues
id <MTLFence> fence = [_device newFence];
id <MTLCommandBuffer> commandBuffer0 = [_commandQueue0 commandBuffer];
id <MTLCommandBuffer> commandBuffer1 = [_commandQueue1 commandBuffer];
// Producer
id <MTLRenderCommandEncoder> renderCommandEncoder = [commandBuffer0 renderCommandEncoderWithDescriptor:_descriptor];
/* Draw using resources associated with 'fence' */
[renderCommandEncoder updateFence:fence afterStages:MTLRenderStageFragment];
[renderCommandEncoder endEncoding];
// Consumer
id <MTLComputeCommandEncoder> computeCommandEncoder = [commandBuffer1 computeCommandEncoder];
[computeCommandEncoder waitForFence:fence];
/* Dispatch using resources associated with 'fence' */
[computeCommandEncoder endEncoding];
// Ensure 'commandBuffer0' is scheduled before 'commandBuffer1'
[commandBuffer0 addScheduledHandler:^(id <MTLCommandBuffer>) {
[commandBuffer1 commit];
}];
[commandBuffer0 commit];
Best Practices - 最佳實踐
1. Separate Heaps for Render Target Types - 為渲染目標(biāo)類型分配單獨堆
有些設(shè)備不能隨意對子分配資源進行別名呀非;例如,可壓縮深度紋理和MSAA紋理镜盯。您應(yīng)該為每種類型的渲染目標(biāo)創(chuàng)建不同的堆:顏色岸裙,深度,模板和MSAA速缆。
2. Separate Heaps for Aliasable and Non-Aliasable Resources - 為可別名和不可別名的資源分配堆
在使子分配的資源可以別名時降允,必須假定此資源將對所有將來的堆子分配進行別名。如果以后分配不可別名的資源(例如壽命較長的紋理)艺糜,那么這些資源可能會對您的臨時資源進行別名剧董,并且很難正確跟蹤幢尚。
如果保留至少兩個資源堆,則可以非常容易地跟蹤哪些可別名和哪些不可別名:一個用于可別名資源(例如送滞,渲染目標(biāo))侠草,另一個用于非別名資源(例如辱挥,資產(chǎn)紋理或頂點緩沖區(qū)) )犁嗅。
3. Separate Heaps to Reduce Fragmentation - 分開堆以減少碎片
創(chuàng)建或刪除許多不同大小的子分配資源可能會破壞內(nèi)存。碎片整理要求您從碎片堆顯式復(fù)制到另一個堆晤碘」游ⅲ或者,您可以創(chuàng)建專用于類似大小的子分配資源的多個堆园爷。
堆也可以用于棧宠蚂。當(dāng)用作棧時,不會發(fā)生碎片童社。
4. Minimize Fencing - 最小化Fencing
細粒度的柵欄很難管理求厕,它們會降低堆的跟蹤效益。避免為每個子分配資源使用圍欄扰楼;相反呀癣,使用單個圍柵來跟蹤具有相同同步要求的所有子分配資源。
5. Consider Tracking Non-Heap Resources - 考慮跟蹤非堆資源
手動數(shù)據(jù)危險跟蹤擴展到直接從MTLDevice對象創(chuàng)建的資源弦赖。在創(chuàng)建資源時指定新的MTLResourceHazardTrackingModeUntracked資源選項项栏,然后使用fence
跟蹤它。手動跟蹤可以減少許多只讀資源的自動跟蹤開銷蹬竖。
Sample Code - 示例代碼
有關(guān)如何使用堆和柵欄的示例沼沈,請參閱MetalHeapsAndFences
示例。
后記
本篇主要講述了Metal編程指南之資源堆币厕,感興趣的給個贊或者關(guān)注~~~