Metal框架詳細解析(四十一) —— Metal編程指南之圖形渲染:渲染命令編碼器之Part 1(六)

版本記錄

版本號 時間
V1.0 2018.11.10 星期六

前言

很多做視頻和圖像的,相信對這個框架都不是很陌生,它渲染高級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同步(三)
24. Metal框架詳細解析(二十四) —— 基本課程之參數緩沖 - 基本參數緩沖(四)
25. Metal框架詳細解析(二十五) —— 基本課程之參數緩沖 - 帶有數組和資源堆的參數緩沖區(五)
26. Metal框架詳細解析(二十六) —— 基本課程之參數緩沖 - 具有GPU編碼的參數緩沖區(六)
27. Metal框架詳細解析(二十七) —— 高級技術之圖層選擇的反射(一)
28. Metal框架詳細解析(二十八) —— 高級技術之使用專用函數的LOD(一)
29. Metal框架詳細解析(二十九) —— 高級技術之具有參數緩沖區的動態地形(一)
30. Metal框架詳細解析(三十) —— 延遲照明(一)
31. Metal框架詳細解析(三十一) —— 在視圖中混合Metal和OpenGL渲染(一)
32. Metal框架詳細解析(三十二) —— Metal渲染管道教程(一)
33. Metal框架詳細解析(三十三) —— Metal渲染管道教程(二)
34. Metal框架詳細解析(三十四) —— Hello Metal! 一個簡單的三角形的實現(一)
35. Metal框架詳細解析(三十五) —— Hello Metal! 一個簡單的三角形的實現(二)
36. Metal框架詳細解析(三十六) —— Metal編程指南之概覽(一)
37. Metal框架詳細解析(三十七) —— Metal編程指南之基本Metal概念(二)
38. Metal框架詳細解析(三十八) —— Metal編程指南之命令組織和執行模型(三)
39. Metal框架詳細解析(三十九) —— Metal編程指南之資源對象:緩沖區和紋理(四)
40. Metal框架詳細解析(四十) —— Metal編程指南之函數和庫(五)

Graphics Rendering: Render Command Encoder - 圖形渲染:渲染命令編碼器

本章介紹如何創建和使用MTLRenderCommandEncoderMTLParallelRenderCommandEncoder對象,這些對象用于將圖形渲染命令編碼到命令緩沖區中。 MTLRenderCommandEncoder命令描述圖形渲染管道,如圖5-1所示。

Figure 5-1 Metal Graphics Rendering Pipeline

MTLRenderCommandEncoder對象表示單個渲染命令編碼器。 MTLParallelRenderCommandEncoder對象允許將單個呈現過程分解為多個單獨的MTLRenderCommandEncoder對象,每個對象可以分配給不同的線程。 然后將來自不同渲染命令編碼器的命令鏈接在一起并以一致,可預測的順序執行,如 Multiple Threads for a Rendering Pass中所述。


Creating and Using a Render Command Encoder - 創建和使用渲染命令編碼器

要創建,初始化和使用單個渲染命令編碼器:

1. Creating a Render Pass Descriptor - 創建渲染管道描述符

MTLRenderPassDescriptor對象表示編碼的渲染命令的目標,該命令是附件(attachments)的集合。渲染通道描述符的屬性可以包括用于顏色像素數據的多達四個附件的陣列,一個附件用于深度像素數據,以及一個附件用于模板像素數據。 renderPassDescriptor便捷方法使用默認附件狀態創建具有顏色,深度和模板附件屬性的MTLRenderPassDescriptor對象。 visibilityResultBuffer屬性指定設備可以更新的緩沖區,以指示是否有任何樣本通過深度和模板測試 - 有關詳細信息,請參閱Fixed-Function State Operations

每個單獨的附件,包括將要寫入的紋理,由附件描述符表示。對于附件描述符,必須適當地選擇相關紋理的像素格式以存儲顏色,深度或模板數據。對于顏色附件描述符MTLRenderPassColorAttachmentDescriptor,使用顏色可渲染像素格式。對于深度附加描述符MTLRenderPassDepthAttachmentDescriptor,使用深度可渲染像素格式,例如MTLPixelFormatDepth32Float。對于模板附件描述符MTLRenderPassStencilAttachmentDescriptor,使用模板可渲染像素格式,例如MTLPixelFormatStencil8

紋理實際上在設備上每個像素使用的內存量并不總是與Metal框架代碼中紋理的像素格式的大小相匹配,因為設備添加了填充以用于對齊或其他目的。有關每種像素格式實際使用的內存量以及附件大小和數量的限制,請參閱Metal Feature Set Tables一章。

Load and Store Actions - 加載和存儲操作

附件描述符的loadActionstoreAction屬性指定在呈現過程的開始或結束時執行的操作。 (對于MTLParallelRenderCommandEncoder,加載和存儲操作發生在整個命令的邊界,而不是每個MTLRenderCommandEncoder對象。有關詳細信息,請參閱Multiple Threads for a Rendering Pass。)

可能的loadAction值包括:

如果您的應用程序將呈現給定幀的附件的所有像??素,請使用默認加載操作MTLLoadActionDontCareMTLLoadActionDontCare操作允許GPU避免加載紋理的現有內容,從而確保最佳性能。否則,您可以使用MTLLoadActionClear操作清除附件的先前內容,或使用MTLLoadActionLoad操作來保留它們。 MTLLoadActionClear操作還可以避免加載現有紋理內容,但是會產生使用純色填充目標的成本。

可能的storeAction值包括:

對于顏色附件,MTLStoreActionStore操作是默認的存儲操作,因為應用程序幾乎總是在渲染過程結束時保留附件中的最終顏色值。對于深度和模板附件,MTLStoreActionDontCare是默認的存儲操作,因為在渲染傳遞完成后通常不需要保留這些附件。

Specifying the Clear Load Action - 指定Clear Load Action

如果附件描述符的loadAction屬性設置為MTLLoadActionClear,則在渲染過程開始時將清除值寫入指定附件描述符中的每個像素。清除值屬性取決于附件的類型。

Example: Creating a Render Pass Descriptor with Load and Store Actions - 示例:使用Load and Store Actions創建渲染通道描述符

Listing 5-1創建了一個帶有顏色和深度附件的簡單渲染過程描述符。 首先,創建兩個紋理對象,一個具有可顏色渲染的像素格式,另一個具有深度像素格式。 接下來,MTLRenderPassDescriptorrenderPassDescriptor便捷方法創建默認的渲染通道描述符。 然后通過MTLRenderPassDescriptor的屬性訪問顏色和深度附件。 紋理和動作在colorAttachments [0]中設置,它表示第一個顏色附件(在數組中的索引0處)和深度附件。

Listing 5-1  Creating a Render Pass Descriptor with Color and Depth Attachments

MTLTextureDescriptor *colorTexDesc = [MTLTextureDescriptor
           texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
           width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];
id <MTLTexture> colorTex = [device newTextureWithDescriptor:colorTexDesc];
 
MTLTextureDescriptor *depthTexDesc = [MTLTextureDescriptor
           texture2DDescriptorWithPixelFormat:MTLPixelFormatDepth32Float
           width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];
id <MTLTexture> depthTex = [device newTextureWithDescriptor:depthTexDesc];
 
MTLRenderPassDescriptor *renderPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDesc.colorAttachments[0].texture = colorTex;
renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDesc.colorAttachments[0].storeAction = MTLStoreActionStore;
renderPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0,1.0,0.0,1.0);
 
renderPassDesc.depthAttachment.texture = depthTex;
renderPassDesc.depthAttachment.loadAction = MTLLoadActionClear;
renderPassDesc.depthAttachment.storeAction = MTLStoreActionStore;
renderPassDesc.depthAttachment.clearDepth = 1.0;

Example: Creating a Render Pass Descriptor for Multisampled Rendering - 示例:為多重采樣渲染創建渲染通道描述符

要使用MTLStoreActionMultisampleResolve操作,必須將texture屬性設置為多重采樣類型紋理,resolveTexture屬性將包含多重采樣解析操作的結果。 (如果texture不支持多重采樣,則多重采樣解析操作的結果未定義。)resolveLevelresolveSliceresolveDepthPlane屬性也可用于多重采樣解析操作,以指定多重采樣紋理的mipmap級別,立方體切片和深度平面。在大多數情況下,resolveLevelresolveSliceresolveDepthPlane的默認值都是可用的。 在Listing 5-2中,最初創建了一個附件,然后將其loadActionstoreActiontextureresolveTexture屬性設置為支持多重采樣解析。

Listing 5-2  Setting Properties for an Attachment with Multisample Resolve

MTLTextureDescriptor *colorTexDesc = [MTLTextureDescriptor
           texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
           width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];
id <MTLTexture> colorTex = [device newTextureWithDescriptor:colorTexDesc];
 
MTLTextureDescriptor *msaaTexDesc = [MTLTextureDescriptor
           texture2DDescriptorWithPixelFormat:MTLPixelFormatRGBA8Unorm
           width:IMAGE_WIDTH height:IMAGE_HEIGHT mipmapped:NO];
msaaTexDesc.textureType = MTLTextureType2DMultisample;
msaaTexDesc.sampleCount = sampleCount;  //  must be > 1
id <MTLTexture> msaaTex = [device newTextureWithDescriptor:msaaTexDesc];
 
MTLRenderPassDescriptor *renderPassDesc = [MTLRenderPassDescriptor renderPassDescriptor];
renderPassDesc.colorAttachments[0].texture = msaaTex;
renderPassDesc.colorAttachments[0].resolveTexture = colorTex;
renderPassDesc.colorAttachments[0].loadAction = MTLLoadActionClear;
renderPassDesc.colorAttachments[0].storeAction = MTLStoreActionMultisampleResolve;
renderPassDesc.colorAttachments[0].clearColor = MTLClearColorMake(0.0,1.0,0.0,1.0);

2. Using the Render Pass Descriptor to Create a Render Command Encoder - 使用渲染通道描述符創建渲染命令編碼器

在創建渲染過程描述符并指定其屬性后,使用MTLCommandBuffer對象的renderCommandEncoderWithDescriptor:方法創建渲染命令編碼器,如Listing 5-3所示。

Listing 5-3  Creating a Render Command Encoder with the Render Pass Descriptor

id <MTLRenderCommandEncoder> renderCE = [commandBuffer
                    renderCommandEncoderWithDescriptor:renderPassDesc];

Displaying Rendered Content with Core Animation - 使用Core Animation顯示渲染內容

Core Animation定義了CAMetalLayer類,該類專為使用Metal渲染內容的圖層支持視圖的特殊行為而設計。 CAMetalLayer對象表示有關內容幾何(位置和大小),其可視屬性(背景顏色,邊框和陰影)的信息,以及Metal用于在顏色附件中顯示內容的資源。它還封裝了內容呈現的時間,以便內容可以在可用時或在指定時間顯示。有關Core Animation的更多信息,請參閱Core Animation Programming Guide

Core Animation還為可顯示資源的對象定義了CAMetalDrawable協議。 CAMetalDrawable協議擴展了MTLDrawable并提供了符合MTLTexture協議的對象,因此它可以用作渲染命令的目標。要渲染到CAMetalLayer對象中,您應該為每個渲染過程獲取一個新的CAMetalDrawable對象,獲取它提供的MTLTexture對象,并使用該紋理創建顏色附件。與顏色附件(attachment)不同,深度或模板附件的創建和破壞是昂貴的。如果需要深度或模板附件,請創建一次,然后在每次渲染幀時重復使用它們。

通常,您使用layerClass方法將CAMetalLayer指定為您自己的自定義UIView子類的支持層類型,如Listing 5-4所示。否則,您可以使用其init方法創建CAMetalLayer,并將該圖層包含在現有視圖中

Listing 5-4  Using CAMetalLayer as the backing layer for a UIView subclass

+ (id) layerClass {
    return [CAMetalLayer class];
}

要顯示圖層中Metal渲染的內容,您必須從CAMetalLayer對象獲取可顯示資源(CAMetalDrawable對象),然后通過將其附加到MTLRenderPassDescriptor對象來渲染到此資源中的紋理。為此,首先設置描述其提供的可繪制資源的CAMetalLayer對象的屬性,然后在每次開始渲染新幀時調用其nextDrawable方法。如果未設置CAMetalLayer屬性,則nextDrawable方法調用將失敗。以下CAMetalLayer屬性描述了可繪制對象:

  • device屬性聲明從中創建資源的MTLDevice對象。
  • pixelFormat屬性聲明紋理的像素格式。支持的值是MTLPixelFormatBGRA8Unorm(默認值)和MTLPixelFormatBGRA8Unorm_sRGB
  • drawableSize屬性聲明設備像素中紋理的尺寸。要確保您的應用以顯示的精確尺寸呈現內容(在某些設備上無需額外的采樣階段),請在計算圖層所需的大小時考慮目標屏幕的nativeScalenativeBounds屬性。
  • framebufferOnly屬性聲明紋理是僅可用作附件(YES)還是也可用于紋理采樣和像素讀/寫操作(NO)。如果是YES,則圖層對象可以優化紋理以供顯示。對于大多數應用,建議值為YES。
  • presentsWithTransaction屬性聲明是否使用標準Core Animation事務機制(YES)更新圖層渲染資源的更改,或者是否異步更新為常規圖層更新(NO,默認值)。

如果nextDrawable方法成功,則返回具有以下只讀屬性的CAMetalDrawable對象:

重要說明:只有一小部分可繪制資源,因此長幀渲染時間可能暫時耗盡這些資源并導致nextDrawable方法調用阻塞其CPU線程,直到方法完成。為了避免昂貴的CPU停頓,在調用CAMetalLayer對象的nextDrawable方法之前,執行所有不需要可繪制資源的每幀操作。

要在渲染完成后顯示可繪制對象的內容,必須通過調用drawable對象的present方法將其提交給Core Animation。要同步drawable的表示和完成負責其呈現的命令緩沖區,可以在MTLCommandBuffer對象上調用presentDrawable:presentDrawable:atTime:便利方法。這些方法使用調度處理程序(請參閱Registering Handler Blocks for Command Buffer Execution)來調用drawablepresent方法,該方法涵蓋大多數方案。 presentDrawable:atTime:方法提供了對drawable何時呈現的進一步控制。


Creating a Render Pipeline State - 創建渲染管道狀態

要使用MTLRenderCommandEncoder對象對渲染命令進行編碼,必須首先指定MTLRenderPipelineState對象以定義任何繪制調用的圖形狀態。 渲染管道狀態對象是一個長期存在的持久對象,可以在渲染命令編碼器之外創建,預先緩存,并在多個渲染命令編碼器中重用。 在描述相同的圖形狀態集時,重用先前創建的渲染管線狀態對象可以避免重新評估并將指定狀態轉換為GPU命令的昂貴操作。

渲染管道狀態是不可變對象。 要創建渲染管道狀態,首先要創建并配置一個可變MTLRenderPipelineDescriptor對象,該對象描述渲染管道狀態的屬性。 然后,使用描述符創建MTLRenderPipelineState對象。

1. Creating and Configuring a Render Pipeline Descriptor - 創建和配置渲染管道描述符

要創建渲染管道狀態,首先要創建一個MTLRenderPipelineDescriptor對象,該對象具有描述在渲染過程中要使用的圖形渲染管道狀態的屬性,如圖5-2所示。 新MTLRenderPipelineDescriptor對象的colorAttachments屬性包含一個MTLRenderPipelineColorAttachmentDescriptor對象數組,每個描述符表示一個顏色附加狀態,指定該附件的混合操作和因子,詳見Configuring Blending in a Render Pipeline Attachment Descriptor。 附件描述符還指定附件的像素格式,該格式必須與渲染管道描述符的紋理的像素格式與相應的附件索引匹配,否則會發生錯誤。

Figure 5-2 Creating a Render Pipeline State from a Descriptor

除了配置顏色附件外,還要為MTLRenderPipelineDescriptor對象設置以下屬性:

2. Creating a Render Pipeline State from a Descriptor - 從描述符創建渲染管道狀態

在創建渲染管道描述符并指定其屬性后,使用它來創建MTLRenderPipelineState對象。因為創建渲染管道狀態需要對圖形狀態進行昂貴的評估以及可能編譯指定的圖形著色器,所以您可以使用阻塞或異步方法以最適合您的應用程序設計的方式調度此類工作。

創建MTLRenderPipelineState對象時,您還可以選擇創建反射數據,以顯示管道著色器函數及其參數的詳細信息。newRenderPipelineStateWithDescriptor:options:reflection:error:newRenderPipelineStateWithDescriptor:options:completionHandler:提供此數據。 如果不使用反射數據,請避免獲取反射數據。 有關如何分析反射數據的更多信息,請參閱Determining Function Details at Runtime

創建MTLRenderPipelineState
對象后,調用MTLRenderCommandEncodersetRenderPipelineState:方法將渲染管道狀態與命令編碼器關聯以用于渲染。

Listing 5-5演示了如何創建一個名為pipeline的渲染管道狀態對象。

Listing 5-5  Creating a Simple Pipeline State

MTLRenderPipelineDescriptor *renderPipelineDesc =
                             [[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDesc.vertexFunction = vertFunc;
renderPipelineDesc.fragmentFunction = fragFunc;
renderPipelineDesc.colorAttachments[0].pixelFormat = MTLPixelFormatRGBA8Unorm;
 
// Create MTLRenderPipelineState from MTLRenderPipelineDescriptor
NSError *errors = nil;
id <MTLRenderPipelineState> pipeline = [device
         newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&errors];
assert(pipeline && !errors);
 
// Set the pipeline state for MTLRenderCommandEncoder
[renderCE setRenderPipelineState:pipeline];

變量vertFuncfragFunc是著色器函數,它們被指定為渲染管道狀態描述符的屬性,稱為renderPipelineDesc。 調用MTLDevice對象的newRenderPipelineStateWithDescriptor:error:的方法同步使用管道狀態描述符來創建渲染管道狀態對象。 調用MTLRenderCommandEncodersetRenderPipelineState:方法指定要與渲染命令編碼器一起使用的MTLRenderPipelineState對象。

注意:因為MTLRenderPipelineState對象的創建成本很高,所以只要您想使用相同的圖形狀態,就應該重復使用它。

3. Configuring Blending in a Render Pipeline Attachment Descriptor - 在渲染管道附件描述符中配置混合

Blending使用高度可配置的混合操作將片段函數(源)返回的輸出與附件(目標)中的像素值混合。混合操作確定源和目標值如何與混合因子組合。

要配置顏色附件的混合,請設置以下MTLRenderPipelineColorAttachmentDescriptor屬性:

Understanding Blending Factors and Operations - 了解混合因子和操作

四個混合因子指的是恒定的混合顏色值:MTLBlendFactorBlendColorMTLBlendFactorOneMinusBlendColorMTLBlendFactorBlendAlphaMTLBlendFactorOneMinusBlendAlpha。 調用MTLRenderCommandEncodersetBlendColorRed:green:blue:alpha:方法,以指定與這些混合因子一起使用的常量顏色和alpha值,如Fixed-Function State Operations中所述。

某些混合操作通過將源值乘以源MTLBlendFactor值(縮寫為SBF),將目標值乘以目標混合因子(DBF),并使用MTLBlendOperation值指示的算法組合結果來組合片段值。 (如果混合操作是MTLBlendOperationMinMTLBlendOperationMax,則忽略SBFDBF混合因子。)例如,rgbBlendOperationalphaBlendOperation屬性的MTLBlendOperationAdd為RGB和Alpha值定義以下額外的混合操作:

RGB = (Source.rgb * sourceRGBBlendFactor) + (Dest.rgb * destinationRGBBlendFactor)
Alpha = (Source.a * sourceAlphaBlendFactor) + (Dest.a * destinationAlphaBlendFactor)

在默認的混合行為中,源完全覆蓋目標。 此行為相當于將sourceRGBBlendFactorsourceAlphaBlendFactor都設置為MTLBlendFactorOne,將destinationRGBBlendFactordestinationAlphaBlendFactor設置為MTLBlendFactorZero。 此行為在數學上表示為:

RGB = (Source.rgb * 1.0) + (Dest.rgb * 0.0)
A = (Source.a * 1.0) + (Dest.a * 0.0)

另一種常用的混合操作,其中源alpha定義目標顏色的剩余量,可以用數學方式表示為:

RGB = (Source.rgb * 1.0) + (Dest.rgb * (1 - Source.a))
A = (Source.a * 1.0) + (Dest.a * (1 - Source.a))

Using a Custom Blending Configuration - 使用自定義混合配置

Listing 5-6顯示了自定義混合配置的代碼,使用混合操作MTLBlendOperationAdd,源混合因子MTLBlendFactorOne和目標混合因子MTLBlendFactorOneMinusSourceAlphacolorAttachments [0]是一個MTLRenderPipelineColorAttachmentDescriptor對象,其屬性指定混合配置

Listing 5-6  Specifying a Custom Blending Configuration

MTLRenderPipelineDescriptor *renderPipelineDesc = 
                             [[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDesc.colorAttachments[0].blendingEnabled = YES; 
renderPipelineDesc.colorAttachments[0].rgbBlendOperation = MTLBlendOperationAdd;
renderPipelineDesc.colorAttachments[0].alphaBlendOperation = MTLBlendOperationAdd;
renderPipelineDesc.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactorOne;
renderPipelineDesc.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactorOne;
renderPipelineDesc.colorAttachments[0].destinationRGBBlendFactor = 
       MTLBlendFactorOneMinusSourceAlpha;
renderPipelineDesc.colorAttachments[0].destinationAlphaBlendFactor = 
       MTLBlendFactorOneMinusSourceAlpha;

NSError *errors = nil;
id <MTLRenderPipelineState> pipeline = [device 
         newRenderPipelineStateWithDescriptor:renderPipelineDesc error:&errors];

后記

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

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容