本章介紹如何創(chuàng)建和使用MTLRenderCommandEncoder以及MTLParallelRenderCommandEncoder用于將圖形渲染命令編碼到命令緩沖區(qū)中的對象。MTLRenderCommandEncoder命令描述了一個圖形渲染管道,如圖5-1所示。
一個MTLRenderCommandEncoder對象表示一個渲染命令編碼器。一個MTLParallelRenderCommandEncoder對象使單個渲染遍可以分解成多個單獨的MTLRenderCommandEncoder對象,每個對象可以分配給一個不同的線程。然后,來自不同渲染命令編碼器的命令被鏈接在一起并以一致且可預(yù)測的順序執(zhí)行,如針對渲染通過的多線程所述。
創(chuàng)建和使用渲染命令編碼器
要創(chuàng)建,初始化和使用單個渲染命令編碼器:
1:創(chuàng)建一個MTLRenderPassDescriptor對象來定義一個附件集合,該附件作為渲染過程的命令緩沖區(qū)中的圖形命令的渲染目的地。通常,您創(chuàng)建一個MTLRenderPassDescriptor對象一次,并在應(yīng)用程序呈現(xiàn)一幀時重用該對象。請參閱創(chuàng)建渲染通過描述符。
2:MTLRenderCommandEncoder通過調(diào)用指定的渲染遍歷描述符的renderCommandEncoderWithDescriptor:方法來創(chuàng)建對象MTLCommandBuffer。請參閱使用渲染通過描述符創(chuàng)建渲染命令編碼器。
3:創(chuàng)建一個MTLRenderPipelineState對象以定義一個或多個繪圖調(diào)用的圖形渲染管線(包括著色器,混合,多采樣和可見性測試)的狀態(tài)。要使用此渲染流水線狀態(tài)繪制圖元,請調(diào)用其setRenderPipelineState:方法
MTLRenderCommandEncoder。有關(guān)詳細(xì)信息,請參閱創(chuàng)建渲染管道狀態(tài)。
4:設(shè)置渲染命令編碼器使用的紋理,緩沖區(qū)和采樣器,如為渲染命令編碼器指定資源所述。
5:調(diào)用MTLRenderCommandEncoder方法來指定額外的固定功能狀態(tài),包括深度和模板狀態(tài),如固定功能狀態(tài)操作中所述。
6:最后,調(diào)用MTLRenderCommandEncoder繪制圖形基元的方法,如“ 圖形幾何基元”中所述。
創(chuàng)建渲染通過描述符
一個MTLRenderPassDescriptor對象表示編碼渲染命令的目的地,它是附件的集合。渲染遍歷描述符的屬性可以包括用于彩色像素數(shù)據(jù)的多達(dá)四個附件的陣列,用于深度像素數(shù)據(jù)的一個附件和用于模版像素數(shù)據(jù)的一個附件。的renderPassDescriptor便利方法創(chuàng)建一個MTLRenderPassDescriptor帶有顏色,深度,和使用默認(rèn)安裝狀態(tài)模版附件屬性對象。該visibilityResultBuffer屬性指定設(shè)備可以更新的緩沖區(qū),以指示是否有任何樣品通過深度和模板測試 - 有關(guān)詳細(xì)信息,請參閱固定功能狀態(tài)操作。
每個單獨的附件,包括將被寫入的紋理由附件描述符表示。對于附件描述符,必須適當(dāng)?shù)剡x擇關(guān)聯(lián)紋理的像素格式以存儲顏色,深度或模板數(shù)據(jù)。對于顏色附加描述符,請MTLRenderPassColorAttachmentDescriptor使用可呈現(xiàn)顏色的像素格式。對于深度附件描述符,請MTLRenderPassDepthAttachmentDescriptor使用深度可渲染像素格式,例如MTLPixelFormatDepth32Float。對于模板附件描述符,MTLRenderPassStencilAttachmentDescriptor使用模板可渲染像素格式,例如MTLPixelFormatStencil8。
紋理在設(shè)備上每個像素實際使用的內(nèi)存量并不總是與Metal框架代碼中紋理像素格式的大小匹配,因為設(shè)備添加了填充以進(jìn)行對齊或其他目的。有關(guān)每個像素格式實際使用的內(nèi)存量以及附件大小和數(shù)量的限制,請參閱“ Metal特征集表”一章。
加載和存儲操作
的loadAction和storeAction附接描述符的屬性指定在開始或一個渲染通道的端部執(zhí)行的動作。(對于MTLParallelRenderCommandEncoder,加載和存儲操作發(fā)生在整個命令的邊界,而不是每個MTLRenderCommandEncoder對象的邊界。有關(guān)詳細(xì)信息,請參閱多個線程進(jìn)行渲染傳遞。)
可能的loadAction值包括:
MTLLoadActionClear,它將相同的值寫入指定附件描述符中的每個像素。有關(guān)此操作的更多詳細(xì)信息,請參閱指定清除加載操作。
MTLLoadActionLoad,它保留紋理的現(xiàn)有內(nèi)容。
MTLLoadActionDontCare,它允許附件中的每個像素在渲染過程開始時承擔(dān)任何值。
如果您的應(yīng)用程序?qū)⒊尸F(xiàn)給定幀的附件的所有像??素,請使用默認(rèn)加載操作MTLLoadActionDontCare。該MTLLoadActionDontCare操作允許GPU避免加載紋理的現(xiàn)有內(nèi)容,確保最佳性能。否則,您可以使用該MTLLoadActionClear操作來清除附件的以前內(nèi)容或MTLLoadActionLoad保留它們的操作。該MTLLoadActionClear動作也避免了加載現(xiàn)有的紋理內(nèi)容,但是會導(dǎo)致以純色填充目的地的費用。
可能的storeAction值包括:
MTLStoreActionStore,它將渲染過程的最終結(jié)果保存到附件中。
MTLStoreActionMultisampleResolve,它將渲染目標(biāo)中的多重采樣數(shù)據(jù)解析為單個樣本值,將它們存儲在由附件屬性指定的紋理中resolveTexture,并保留附件的內(nèi)容未定義。有關(guān)詳細(xì)信息,請參閱示例:創(chuàng)建多采樣渲染的渲染通過描述符。
MTLStoreActionDontCare,其在渲染通過完成之后將附件保持在未定義的狀態(tài)。這可以提高性能,因為它使實現(xiàn)能夠避免保留渲染結(jié)果所需的任何工作。
對于顏色附件,MTLStoreActionStore操作是默認(rèn)存儲操作,因為應(yīng)用程序在渲染通過結(jié)束時幾乎總是保留附件中的最終顏色值。對于深度和模板附件,MTLStoreActionDontCare是默認(rèn)存儲操作,因為這些附件通常在渲染遍完成后通常不需要保留。
指定清除負(fù)載動作
如果loadAction附件描述符的屬性設(shè)置為MTLLoadActionClear,則在渲染過程開始時將清除值寫入指定附件描述符中的每個像素。清算價值屬性取決于附件的類型。
For MTLRenderPassColorAttachmentDescriptor,clearColor包含MTLClearColor由四個雙精度浮點RGBA組件組成的值,用于清除顏色附件。該MTLClearColorMake功能從紅色,綠色,藍(lán)色和Alpha組件創(chuàng)建一個清晰的顏色值。默認(rèn)的清除顏色是(0.0,0.0,0.0,1.0)或不透明的黑色。
For MTLRenderPassDepthAttachmentDescriptor,clearDepth包含用于清除深度附件的范圍[0.0,1.0]中的一個雙精度浮點清除值。默認(rèn)值為1.0。
For MTLRenderPassStencilAttachmentDescriptor,clearStencil包含一個32位無符號整數(shù),用于清除模板附件。默認(rèn)值為0。
示例:使用加載和存儲操作創(chuàng)建渲染傳遞描述符
清單5-1創(chuàng)建了一個帶有顏色和深度附件的簡單渲染遍歷描述符。首先,創(chuàng)建兩個紋理對象,一個具有可呈現(xiàn)顏色的像素格式,另一個具有深度像素格式。接下來renderPassDescriptor,MTLRenderPassDescriptor創(chuàng)建一個默認(rèn)渲染傳遞描述符的方便方法。然后通過屬性訪問顏色和深度附件MTLRenderPassDescriptor。紋理和動作被設(shè)置colorAttachments[0],代表第一個顏色附件(在數(shù)組的索引0)和深度附件。
清單5-1 使用顏色和深度附件創(chuàng)建渲染通過描述符
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;
示例:創(chuàng)建多采樣渲染的渲染通過描述符
要使用該MTLStoreActionMultisampleResolve操作,您必須將該texture屬性設(shè)置為多采樣類型的紋理,該resolveTexture屬性將包含多重采樣解析操作的結(jié)果。(如果texture不支持多重采樣,然后多重采樣解析操作的結(jié)果是不確定的。)的resolveLevel,resolveSlice和resolveDepthPlane性能也可以用于多重采樣解析操作來指定的mipmap水平,立方體切片,和多重采樣紋理的深度平面,分別。在大多數(shù)情況下,默認(rèn)值resolveLevel,resolveSlice以及resolveDepthPlane是可用的。在清單5-2,初始創(chuàng)建附件,然后它的loadAction,storeAction,texture,和resolveTexture屬性被設(shè)置為支持多重采樣的決心。
清單5-2 設(shè)置具有多次采樣解析的附件的屬性
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; //必須> 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);
使用渲染通過描述符創(chuàng)建渲染命令編碼器
創(chuàng)建渲染傳遞描述符并指定其屬性后,使用對象的renderCommandEncoderWithDescriptor:方法MTLCommandBuffer創(chuàng)建一個render命令編碼器,如清單5-3所示。
清單5-3 使用渲染通過描述符創(chuàng)建渲染命令編碼器
id <MTLRenderCommandEncoder> renderCE = [commandBuffer
renderCommandEncoderWithDescriptor:renderPassDesc];
用核心動畫顯示呈現(xiàn)的內(nèi)容
Core Animation定義了這個CAMetalLayer類,它是針對其內(nèi)容使用Metal呈現(xiàn)的層支持視圖的專門行為而設(shè)計的。甲CAMetalLayer對象表示關(guān)于內(nèi)容(位置和尺寸)的幾何形狀的信息,它的視覺屬性(背景色,邊框和陰影),和由Metal所使用的資源以呈現(xiàn)在彩色附件的內(nèi)容。它還封裝了內(nèi)容呈現(xiàn)的時間,以便內(nèi)容可以在可用或在指定的時間一直顯示。有關(guān)核心動畫的更多信息,請參閱核心動畫編程指南。
核心動畫還定義了CAMetalDrawable可顯示資源的對象的協(xié)議。該CAMetalDrawable協(xié)議擴(kuò)展MTLDrawable并提供符合MTLTexture協(xié)議的對象,因此可以將其用作渲染命令的目的地。要渲染成一個
CAMetalLayer對象,您應(yīng)該CAMetalDrawable為每個渲染遍獲取一個新對象,獲取MTLTexture它提供的對象,并使用該紋理創(chuàng)建顏色附件。與顏色附件不同,深度或模板附件的創(chuàng)建和銷毀是昂貴的。如果您需要深度或模板附件,請創(chuàng)建它們一次,然后在每次渲染框架時重用它們。
通常,您可以使用該layerClass方法將其指定CAMetalLayer為您自己的自定義UIView子類的后盾層類型,如清單5-4所示。否則,您可以CAMetalLayer使用其init方法創(chuàng)建一個,并將圖層包含在現(xiàn)有視圖中。
清單5-4 使用CAMetalLayer作為UIView子類的后盾層
+ (id) layerClass {
return [CAMetalLayer class];
}
要顯示由Metal在圖層中呈現(xiàn)的內(nèi)容,您必須CAMetalDrawable從CAMetalLayer對象獲取可顯示的資源(對象),然后通過將其附加到MTLRenderPassDescriptor對象來渲染到該資源中的紋理。為此,您首先設(shè)置CAMetalLayer描述其提供的可繪制資源的對象的屬性,然后在nextDrawable每次開始渲染新框架時調(diào)用其方法。如果CAMetalLayer屬性未設(shè)置,nextDrawable方法調(diào)用失敗。以下CAMetalLayer屬性描述可繪制對象:
該pixelFormat屬性聲明紋理的像素格式。支持的值是MTLPixelFormatBGRA8Unorm(默認(rèn)值)和MTLPixelFormatBGRA8Unorm_sRGB。
該drawableSize屬性聲明了設(shè)備像素中紋理的尺寸。為了確保您的應(yīng)用程序以顯示的精確尺寸呈現(xiàn)內(nèi)容(無需在某些設(shè)備上進(jìn)行附加采樣階段),請在計算圖層所需的大小時,將目標(biāo)屏幕nativeScale或nativeBounds屬性考慮在內(nèi)。
該framebufferOnly屬性聲明紋理是否只能用作附件(YES),或者它是否也可以用于紋理采樣和像素讀取/寫入操(NO)。如果YES,層對象可以優(yōu)化顯示紋理。對于大多數(shù)應(yīng)用,建議的值為YES。
該presentsWithTransaction屬性聲明是否使用標(biāo)準(zhǔn)的Core Animation事務(wù)機(jī)制(YES)更新了層渲染資源的更改,或者與異常更新(NO默認(rèn)值)異常更新。
如果nextDrawable方法成功,它返回一個CAMetalDrawable具有以下只讀屬性的對象:
- 該texture屬性保存紋理對象。在創(chuàng)建渲染管道(MTLRenderPipelineColorAttachmentDescriptor對象)時,將其用作附件。
- 該layer屬性指向CAMetalLayer該負(fù)責(zé)顯示繪制對象。
重要提示: 只有一小部分可繪制的資源,因此長幀渲染時間可能暫時耗盡這些資源,并導(dǎo)致nextDrawable方法調(diào)用阻止其CPU線程直到該方法完成。為了避免昂貴的CPU停止,請在調(diào)用對象的nextDrawable方法之前執(zhí)行不需要可繪制資源的所有每幀操作CAMetalLayer。 |
---|
要在渲染完成后顯示可繪制對象的內(nèi)容,您必須通過調(diào)用可繪制對象的present方法將其提交給Core Animation 。要同步與負(fù)責(zé)其呈現(xiàn)命令緩沖區(qū)完成一個繪制的介紹,你可以調(diào)用的presentDrawable:還是
presentDrawable:atTime:一個上方便的方法MTLCommandBuffer對象。這些方法使用調(diào)度處理程序(請參閱注冊處理程序塊進(jìn)行命令緩沖區(qū)執(zhí)行)來調(diào)用drawable的present方法,該方法涵蓋大多數(shù)場景。該presentDrawable:atTime:方法進(jìn)一步控制何時顯示可繪制。
創(chuàng)建渲染管道狀態(tài)
要使用MTLRenderCommandEncoder對象編碼渲染命令,必須首先指定一個MTLRenderPipelineState對象來定義任何繪圖調(diào)用的圖形狀態(tài)。渲染流水線狀態(tài)對象是一個長壽命的持久對象,可以在渲染命令編碼器之外創(chuàng)建,提前高速緩存,并重用于多個渲染命令編碼器。當(dāng)描述相同的圖形狀態(tài)集時,重新使用先前創(chuàng)建的渲染流水線狀態(tài)對象可以避免重新評估并將指定狀態(tài)轉(zhuǎn)換為GPU命令的昂貴的操作。
渲染管道狀態(tài)是一個不可變的對象。要創(chuàng)建渲染流水線狀態(tài),您首先創(chuàng)建并配置一個MTLRenderPipelineDescriptor描述呈現(xiàn)管道狀態(tài)的屬性的可變對象。然后,使用描述符創(chuàng)建一個MTLRenderPipelineState對象。
創(chuàng)建和配置渲染流水線描述符
要創(chuàng)建一個渲染流水線狀態(tài),首先創(chuàng)建一個MTLRenderPipelineDescriptor對象,該對象具有描述在渲染過程中要使用的圖形渲染流水線狀態(tài)的屬性,如圖5-2所示。colorAttachments新MTLRenderPipelineDescriptor對象的屬性包含一個對象數(shù)組MTLRenderPipelineColorAttachmentDescriptor,每個描述符表示一個顏色附加狀態(tài),它指定該附件的混合操作和因子,如“ 渲染流水線附件描述符中的配置混合”中所詳述。附件描述符還指定附件的像素格式,它必須與渲染流水線描述符的紋理與相應(yīng)附件索引的像素格式匹配,否則發(fā)生錯誤。
除了配置顏色附件之外,還要為MTLRenderPipelineDescriptor對象設(shè)置這些屬性:
- 設(shè)置depthAttachmentPixelFormat屬性以匹配的像素格式的紋理depthAttachment在MTLRenderPassDescriptor。
- 設(shè)置stencilAttachmentPixelFormat屬性以匹配的像素格式的紋理stencilAttachment在MTLRenderPassDescriptor。
- 要在渲染流水線狀態(tài)中指定頂點或片段著色器,請分別設(shè)置vertexFunction或fragmentFunction屬性。設(shè)置fragmentFunction于nil像素的光柵化禁用到指定顏色的附件,其通常用于深度只呈現(xiàn)或用于輸出數(shù)據(jù)到從頂點著色器的緩沖器的對象。
- 如果頂點著色器具有每頂點輸入屬性的參數(shù),請設(shè)置該vertexDescriptor屬性以描述該參數(shù)中頂點數(shù)據(jù)的組織,如數(shù)據(jù)組織頂點描述符中所述。
- 對于大多數(shù)典型的渲染任務(wù)YES,該rasterizationEnabled屬性的默認(rèn)值就足夠了。要僅使用圖形流水線的頂點階段(例如,收集在頂點著色器中轉(zhuǎn)換的數(shù)據(jù)),請將此屬性設(shè)置為NO。
- 如果附件支持多重采樣(即附件是MTLTextureType2DMultisample
類型紋理),則可以為每個像素創(chuàng)建多個樣本。要確定片段如何組合以提供像素覆蓋,請使用以下MTLRenderPipelineDescriptor屬性。- 該sampleCount屬性確定每個像素的樣本數(shù)。當(dāng)MTLRenderCommandEncoder被創(chuàng)建時,sampleCount對于紋理所有附件都必須符合這一sampleCount特性。如果附件不支持多重采樣,sampleCount則為1,也是默認(rèn)值。
- 如果alphaToCoverageEnabled設(shè)置為YES,則colorAttachments[0]讀取用于輸出的alpha通道片段,并用于確定覆蓋掩碼。
- 如果alphaToOneEnabled設(shè)置為YES,那么alpha通道片段值colorAttachments[0]被強(qiáng)制為1.0,這是最大的可表示值。(其他附件不受影響。)
從描述符創(chuàng)建渲染管道狀態(tài)
創(chuàng)建渲染流水線描述符并指定其屬性后,使用它創(chuàng)建MTLRenderPipelineState對象。因為創(chuàng)建渲染流水線狀態(tài)可能需要昂貴的圖形狀態(tài)評估和可能的指定圖形著色器的編譯,所以您可以使用阻塞或異步方法來以最適合您應(yīng)用程序設(shè)計的方式安排此類工作。
要同步創(chuàng)建渲染流水線狀態(tài)對象,請調(diào)用對象的方法newRenderPipelineStateWithDescriptor:error:或newRenderPipelineStateWithDescriptor:options:reflection:error:方法MTLDevice。當(dāng)Metal評估描述符的圖形狀態(tài)信息并編譯著色器代碼以創(chuàng)建管道狀態(tài)對象時,這些方法將阻塞當(dāng)前線程。
要異步創(chuàng)建渲染流水線狀態(tài)對象,請調(diào)用對象的方法newRenderPipelineStateWithDescriptor:completionHandler:或newRenderPipelineStateWithDescriptor:options:completionHandler:方法MTLDevice。這些方法立即返回 - Metal異步地評估描述符的圖形狀態(tài)信息,并編譯著色器代碼來創(chuàng)建管道狀態(tài)對象,然后調(diào)用完成處理程序來提供新MTLRenderPipelineState對象。
創(chuàng)建MTLRenderPipelineState對象時,您還可以選擇創(chuàng)建反映數(shù)據(jù),以顯示管道的著色器函數(shù)及其參數(shù)的詳細(xì)信息。該newRenderPipelineStateWithDescriptor:options:reflection:error:和newRenderPipelineStateWithDescriptor:options:completionHandler:方法提供這些數(shù)據(jù)。如果不使用反射數(shù)據(jù),請避免使用。有關(guān)如何分析反射數(shù)據(jù)的更多信息,請參閱在運行時確定功能詳細(xì)信息。
創(chuàng)建后MTLRenderPipelineState的對象,調(diào)用setRenderPipelineState:
的方法MTLRenderCommandEncoder來渲染管線狀態(tài)在渲染使用命令編碼器相關(guān)聯(lián)。
清單5-5演示了創(chuàng)建一個調(diào)用的渲染管道狀態(tài)對象pipeline。
MTLRenderPipelineDescriptor * renderPipelineDesc =
[[MTLRenderPipelineDescriptor alloc] init];
renderPipelineDesc.vertexFunction = vertFunc;
renderPipelineDesc.fragmentFunction = fragFunc;
renderPipelineDesc.colorAttachments [0] .pixelFormat = MTLPixelFormatRGBA8Unorm;
//從MTLRenderPipelineDescriptor創(chuàng)建MTLRenderPipelineState
NSError * errors = nil;
id <MTLRenderPipelineState> pipeline = [device
newRenderPipelineStateWithDescriptor:
renderPipelineDesc error:&errors];
assert(pipeline &&!errors);
//設(shè)置MTLRenderCommandEncoder的流水線狀態(tài)
[renderCE setRenderPipelineState:pipeline];
變量vertFunc和fragFunc是被指定為稱為渲染流水線狀態(tài)描述符的性質(zhì)著色器的功能renderPipelineDesc。同時調(diào)用對象的newRenderPipelineStateWithDescriptor:error:方法MTLDevice使用流水線狀態(tài)描述符來創(chuàng)建渲染管道狀態(tài)對象。調(diào)用指定與render命令編碼器一起使用的對象的setRenderPipelineState:方法。MTLRenderCommandEncoderMTLRenderPipelineState
注意: 因為一個MTLRenderPipelineState對象創(chuàng)建成本很高,所以當(dāng)你想要使用相同的圖形狀態(tài)時,應(yīng)該重用它。 |
---|
在渲染管道附件描述符中配置混合
混合使用高度可配置的混合操作來將片段功能(源)返回的輸出與附件(目標(biāo))中的像素值進(jìn)行混合?;旌喜僮鳑Q定了源和目標(biāo)值如何與混合因子相結(jié)合。
要為顏色附件配置混合,請設(shè)置以下MTLRenderPipelineColorAttachmentDescriptor屬性:
- 要啟用混合,請設(shè)置blendingEnabled為YES。默認(rèn)情況下禁用混合。
- writeMask識別哪些顏色通道被混合。默認(rèn)值MTLColorWriteMaskAll允許混合所有顏色通道。
- rgbBlendOperation并alphaBlendOperation分別為RGB和Alpha片段數(shù)據(jù)分配一個MTLBlendOperation值。兩個屬性的默認(rèn)值為MTLBlendOperationAdd。
- sourceRGBBlendFactor,sourceAlphaBlendFactor,destinationRGBBlendFactor,和destinationAlphaBlendFactor分配源和目標(biāo)混合因子。
了解混合因素和操作
四個交融因素是指恒定混合顏色值:MTLBlendFactorBlendColor,
MTLBlendFactorOneMinusBlendColor,MTLBlendFactorBlendAlpha,和MTLBlendFactorOneMinusBlendAlpha。調(diào)用setBlendColorRed:green:blue:alpha:的方法MTLRenderCommandEncoder,以指定與這些混合因子使用的恒定的顏色和α值,如在固定功能狀態(tài)的操作。
一些混合操作通過將源值乘以源MTLBlendFactor值(縮寫為SBF),將目標(biāo)值乘以目標(biāo)混合因子(DBF),并使用由該MTLBlendOperation值表示的算術(shù)來組合結(jié)果來組合分段值。(如果該混合操作是任一MTLBlendOperationMin或MTLBlendOperationMax下,SBF和DBF混合因子被忽略。)例如,MTLBlendOperationAdd對于既rgbBlendOperation和alphaBlendOperation性質(zhì)定義了用于RGB和α值以下添加劑混合操作:
- RGB =(Source.rgb * sourceRGBBlendFactor)+(Dest.rgb * destinationRGBBlendFactor)
- Alpha =(Source.a * sourceAlphaBlendFactor)+(Dest.a * destinationAlphaBlendFactor)
在默認(rèn)混合行為中,源會完全覆蓋目的地。這種行為等同于同時設(shè)置sourceRGBBlendFactor并sourceAlphaBlendFactor以MTLBlendFactorOne和destinationRGBBlendFactor和destinationAlphaBlendFactor到MTLBlendFactorZero。這種行為在數(shù)學(xué)上表示為:
- RGB =(Source.rgb * 1.0)+(Dest.rgb * 0.0
- A =(Source.a * 1.0)+(Dest.a * 0.0)
另一種常用的混合操作,其中源alpha定義剩余多少目的地顏色,可以用數(shù)學(xué)表達(dá)為:
- RGB =(Source.rgb * 1.0)+(Dest.rgb *(1 - Source.a))
- A =(Source.a * 1.0)+(Dest.a *(1 - Source.a))
使用自定義混合配置
清單5-6顯示了使用混合操作MTLBlendOperationAdd,源混合因子MTLBlendFactorOne和目標(biāo)混合因子的自定義混合配置的代碼MTLBlendFactorOneMinusSourceAlpha。
colorAttachments[0]是具有MTLRenderPipelineColorAttachmentDescriptor指定混合配置的屬性的對象。
清單5-6 指定自定義混合配置
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];
為渲染命令編碼器指定資源
MTLRenderCommandEncoder本節(jié)討論的方法指定用作頂點和片段著色器函數(shù)的參數(shù)的資源,它們由對象中的屬性vertexFunction和fragmentFunction屬性指定MTLRenderPipelineState。這些方法將渲染資源(緩沖區(qū),紋理和采樣器)分配給atInderender命令編碼器中的相應(yīng)參數(shù)表index(),如圖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ù)表索引相匹配。在清單5-7中,分別為頂點著色器定義了兩個分別為0和1的緩沖區(qū)(posBuf和texCoordBuf)。
列表5-7 Metal框架:為頂點函數(shù)指定資源
[renderEnc setVertexBuffer:posBuf offset:0 atIndex:0];
[renderEnc setVertexBuffer:texCoordBuf offset:0 atIndex:1];
在清單5-8中,函數(shù)簽名具有與屬性相應(yīng)的預(yù)選賽參數(shù)buffer(0)和buffer(1)。
清單5-8 Metal著色語言:頂點函數(shù)參數(shù)匹配框架參數(shù)表指數(shù)
vertex VertexOutput metal_vert(float4 *posData [[ buffer(0) ]],
float2 *texCoordData [[ buffer(1) ]])
類似地,在清單5-9,(緩沖器,紋理和一個采樣器fragmentColorBuf,shadeTex以及sampler,分別地),所有索引為0,針對片段著色器定義。
清單5-9 Metal框架:為片段函數(shù)指定資源
[renderEnc setFragmentBuffer:fragmentColorBuf offset:0 atIndex:0];
[renderEnc setFragmentTexture:shadeTex atIndex:0];
[renderEnc setFragmentSamplerState:sampler atIndex:0];
在清單5-10,函數(shù)簽名具有與屬性限定符相應(yīng)參數(shù)buffer(0),texture(0)以及sampler(0)分別。
清單5-10 Metal著色語言:片段函數(shù)參數(shù)匹配框架參數(shù)表指數(shù)
fragment float4 metal_frag(VertexOutput in [[stage_in]], float4 *fragColorData [[ buffer(0) ]], texture2d<float> shadeTexValues [[ texture(0) ]], sampler samplerValues [[ sampler(0) ]] )
數(shù)據(jù)組織的頂點描述符
在Metal框架代碼中,MTLVertexDescriptor每個流水線狀態(tài)可以有一個描述輸入到頂點著色器功能的數(shù)據(jù)的組織,并在著色語言和框架代碼之間共享資源位置信息。
在Metal著色語言代碼中,每頂點輸入(例如標(biāo)量或整數(shù)或浮點值向量)可以組織在一個結(jié)構(gòu)中,可以在一個使用[[ stage_in ]]屬性限定符聲明的參數(shù)中傳遞,如VertexInput結(jié)構(gòu)為例如頂點功能vertexMath在清單5-11。每頂點輸入結(jié)構(gòu)的每個字段都有[[ attribute(index) ]]限定符,它指定了頂點屬性參數(shù)表中的索引。
清單5-11 Metal著色語言:帶有屬性指數(shù)的頂點函數(shù)輸入
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è)置為其 vertexDescriptor屬性MTLRenderPipelineState。MTLVertexDescriptor有兩個屬性:attributes和layouts。
所述attributes的屬性MTLVertexDescriptor是一個MTLVertexAttributeDescriptorArray用于定義每一頂點屬性如何在被映射到一個頂點函數(shù)參數(shù)的緩沖器組織對象。該attributes屬性可以支持訪問在同一緩沖區(qū)內(nèi)交錯的多個屬性(如頂點坐標(biāo),表面法線和紋理坐標(biāo))。陰影語言代碼中成員的順序不必在框架代碼的緩沖區(qū)中保留。數(shù)組中的每個頂點屬性描述符具有以下屬性,它們提供了一個頂點著色器功能信息來定位和加載參數(shù)數(shù)據(jù):
bufferIndex,它是指定MTLBuffer訪問的緩沖區(qū)參數(shù)表的索引。在指定用于渲染命令編碼器的資源中討論緩沖區(qū)參數(shù)表。
format,其中規(guī)定了如何在框架代碼中解釋數(shù)據(jù)。如果數(shù)據(jù)類型不是精確類型匹配,則可能會轉(zhuǎn)換或擴(kuò)展。例如,如果著色語言類型是half4與框架format是[MTLVertexFormatFloat2(https://developer.apple.com/documentation/metal/mtlvertexformat/1515535-float2),則當(dāng)數(shù)據(jù)被用作一個參數(shù)到頂點的功能,它可以被從浮到一半轉(zhuǎn)換并從兩個到四個元件膨脹(具有在0.0,1.0最后兩個要素)。
offset,它指定從頂點開始可以找到數(shù)據(jù)的位置。
圖5-4顯示了一個MTLVertexAttributeDescriptorArrayMetal框架代碼,它實現(xiàn)了與清單5-11中vertexMath著色語言代碼中頂點函數(shù)的輸入相對應(yīng)的交錯緩沖區(qū)。
清單5-12顯示了對應(yīng)于圖5-4所示的交錯緩沖區(qū)的Metal框架代碼。
清單5-12 Metal框架:使用頂點描述符來訪問交織數(shù)據(jù)
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字節(jié)
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;
MTLVertexAttributeDescriptor對象attributes數(shù)組中的每個對象都MTLVertexDescriptor對應(yīng)VertexInput于著色器函數(shù)中的索引結(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)將相應(yīng)數(shù)據(jù)的起始位置從8啟動緩沖區(qū)。format選擇這些值以匹配著色器函數(shù)中的數(shù)據(jù)類型,因此attributes[1].format = MTLVertexFormatFloat4指定使用四個浮點值。
該layouts物業(yè)MTLVertexDescriptor是一個MTLVertexBufferLayoutDescriptorArray。對于每一個MTLVertexBufferLayoutDescriptor在layouts,屬性指定如何頂點和屬性數(shù)據(jù)是從對應(yīng)的取出MTLBuffer時Metal繪制圖元在參數(shù)表中。(有關(guān)繪圖圖元,看到繪制幾何圖元。)的stepFunction屬性的MTLVertexBufferLayoutDescriptor判斷是否獲取屬性數(shù)據(jù)的每個頂點,對于一些數(shù)量的實例,或者僅僅一次。如果stepFunction設(shè)置為獲取某些數(shù)量的實例的屬性數(shù)據(jù),則stepRate屬性MTLVertexBufferLayoutDescriptor決定了多少個實例。該stride屬性指定兩個頂點的數(shù)據(jù)之間的距離(以字節(jié)為單位)。
圖5-5描述了MTLVertexBufferLayoutDescriptor對應(yīng)于清單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,對于每兩個實例,等等。