函數(shù)和庫(kù)
本章介紹如何創(chuàng)建一個(gè)MTLFunction對(duì)象作為Metal著色器或計(jì)算函數(shù)的參考逛漫,以及如何組織和訪問(wèn)具有MTLLibrary對(duì)象的函數(shù)伶氢。
MTLFunction表示著色器或計(jì)算功能
一個(gè)MTLFunction對(duì)象表示一個(gè)單獨(dú)的功能吭历,它以Metal著色語(yǔ)言編寫,并在GPU上作為圖形或計(jì)算流水線的一部分執(zhí)行躲因。有關(guān)Metal著色語(yǔ)言的詳細(xì)信息,請(qǐng)參閱“ Metal著色語(yǔ)言指南”忌傻。
要在Metal運(yùn)行時(shí)間和以Metal著色語(yǔ)言編寫的圖形或計(jì)算函數(shù)之間傳遞數(shù)據(jù)或狀態(tài)大脉,請(qǐng)為紋理,緩沖區(qū)和采樣器分配參數(shù)索引水孩。參數(shù)索引標(biāo)識(shí)由Metal運(yùn)行時(shí)和Metal著色代碼引用的紋理镰矿,緩沖區(qū)或采樣器。
對(duì)于渲染遍俘种,您可以在MTLFunction對(duì)象中指定一個(gè)用作頂點(diǎn)或片段著色器的MTLRenderPipelineDescriptor對(duì)象秤标,如創(chuàng)建渲染管道狀態(tài)中所述。對(duì)于計(jì)算過(guò)程宙刘,您可以MTLFunction在MTLComputePipelineState為目標(biāo)設(shè)備創(chuàng)建對(duì)象時(shí)指定對(duì)象苍姜,如“ 為計(jì)算命令編碼器指定計(jì)算狀態(tài)和資源”所述。
一個(gè)Library就是一個(gè)函數(shù)庫(kù)
一個(gè)MTLLibrary對(duì)象表示的一個(gè)或多個(gè)儲(chǔ)存庫(kù)MTLFunction對(duì)象悬包。單個(gè)MTLFunction對(duì)象表示使用著色語(yǔ)言編寫的一個(gè)Metal函數(shù)衙猪。在Metal著色語(yǔ)言源代碼,使用一個(gè)Metal函數(shù)限定符任何功能(vertex布近,fragment屈嗤,或kernel)可以通過(guò)一個(gè)代表MTLFunction在一個(gè)庫(kù)中的對(duì)象。沒(méi)有這些函數(shù)限定符之一的Metal函數(shù)不能由MTLFunction對(duì)象直接表示吊输,盡管它可以由著色器中的另一個(gè)函數(shù)調(diào)用。
MTLFunction可以從以下任一來(lái)源創(chuàng)建庫(kù)中的對(duì)象:
Metal著色語(yǔ)言代碼铁追,在應(yīng)用程序構(gòu)建過(guò)程中被編譯成二進(jìn)制庫(kù)格式季蚂。
包含由運(yùn)行時(shí)應(yīng)用程序編譯的Metal著色語(yǔ)言源代碼的文本字符串。
從編譯代碼創(chuàng)建庫(kù)
為了獲得最佳性能琅束,請(qǐng)?jiān)谀膽?yīng)用程序的Xcode構(gòu)建過(guò)程中將Metal著色語(yǔ)言源代碼編譯成庫(kù)文件扭屁,從而避免在應(yīng)用程序運(yùn)行時(shí)編譯函數(shù)源的費(fèi)用。要從MTLLibrary庫(kù)二進(jìn)制創(chuàng)建對(duì)象涩禀,請(qǐng)調(diào)用以下方法之一MTLDevice:
newDefaultLibrary 檢索為主包構(gòu)建的庫(kù)料滥,其中包含應(yīng)用程序的Xcode項(xiàng)目中的所有著色器和計(jì)算函數(shù)。
newLibraryWithFile:error:將路徑傳遞給庫(kù)文件艾船,并返回一個(gè)MTLLibrary包含存儲(chǔ)在該庫(kù)文件中的所有函數(shù)的對(duì)象葵腹。
newLibraryWithData:error:使用二進(jìn)制blob包含庫(kù)中函數(shù)的代碼并返回一個(gè)MTLLibrary對(duì)象高每。
有關(guān)在構(gòu)建過(guò)程中編譯Metal著色語(yǔ)言源代碼的更多信息,請(qǐng)參閱
在應(yīng)用程序構(gòu)建過(guò)程中創(chuàng)建庫(kù)践宴。
從源代碼創(chuàng)建庫(kù)
要從MTLLibrary可能包含多個(gè)函數(shù)的Metal著色語(yǔ)言源代碼字符串創(chuàng)建一個(gè)鲸匿,請(qǐng)調(diào)用以下方法之一MTLDevice。這些方法在創(chuàng)建庫(kù)時(shí)編譯源代碼阻肩。要指定要使用的編譯器選項(xiàng)带欢,請(qǐng)?jiān)O(shè)置MTLCompileOptions對(duì)象中的屬性。
newLibraryWithSource:options:error:從輸入字符串同步編譯源代碼以創(chuàng)建MTLFunction對(duì)象烤惊,然后返回MTLLibrary包含它們的對(duì)象乔煞。
newLibraryWithSource:options:completionHandler:從輸入字符串異步編譯源代碼以創(chuàng)建MTLFunction對(duì)象,然后返回MTLLibrary包含它們的對(duì)象柒室。completionHandler是在對(duì)象創(chuàng)建完成時(shí)調(diào)用的代碼塊渡贾。
從Library獲取功能
返回具有請(qǐng)求名稱的對(duì)象的newFunctionWithName:方法。如果在庫(kù)中找不到使用Metal著色語(yǔ)言功能限定符的函數(shù)的名稱伦泥,則返回剥啤。MTLLibraryMTLFunctionnewFunctionWithName:nil
清單4-1使用通過(guò)其完整路徑名定位庫(kù)文件的newLibraryWithFile:error:方法,MTLDevice并使用其內(nèi)容創(chuàng)建MTLLibrary具有一個(gè)或多個(gè)MTLFunction對(duì)象的對(duì)象不脯。加載文件時(shí)出現(xiàn)任何錯(cuò)誤error府怯。然后創(chuàng)建一個(gè)表示在源代碼中調(diào)用的函數(shù)的對(duì)象的newFunctionWithName:方法。返回的函數(shù)對(duì)象現(xiàn)在可以在應(yīng)用程序中使用防楷。MTLLibraryMTLFunctionmy_funcmyFunc
清單4-1 從庫(kù)訪問(wèn)函數(shù)
NSError *errors;
id <MTLLibrary> library = [device newLibraryWithFile:@"myarchive.metallib"
error:&errors];
id <MTLFunction> myFunc = [library newFunctionWithName:@"my_func"];
在運(yùn)行時(shí)確定功能詳細(xì)信息
由于MTLFunction對(duì)象的實(shí)際內(nèi)容由MTLFunction創(chuàng)建對(duì)象之前可以編譯的圖形著色器或計(jì)算函數(shù)定義牺丙,因此其源代碼可能無(wú)法直接用于該應(yīng)用程序。您可以MTLFunction在運(yùn)行時(shí)查詢以下屬性:
name一個(gè)帶有該函數(shù)名稱的字符串复局。
functionType冲簿,它指示函數(shù)是否被聲明為頂點(diǎn),片段或計(jì)算函數(shù)亿昏。
vertexAttributes峦剔,一組MTLVertexAttribute對(duì)象,描述如何將頂點(diǎn)屬性數(shù)據(jù)組織在內(nèi)存中角钩,以及如何映射到頂點(diǎn)函數(shù)參數(shù)吝沫。有關(guān)更多詳細(xì)信息,請(qǐng)參閱數(shù)據(jù)組織的頂點(diǎn)描述符递礼。
MTLFunction不提供對(duì)函數(shù)參數(shù)的訪問(wèn)惨险。在創(chuàng)建流水線狀態(tài)期間,可以獲得反映物體(MTLRenderPipelineReflection或MTLComputePipelineReflection根據(jù)命令編碼器的類型)來(lái)顯示著色器或計(jì)算函數(shù)參數(shù)的細(xì)節(jié)脊髓。有關(guān)創(chuàng)建管道狀態(tài)和反射對(duì)象的詳細(xì)信息辫愉,請(qǐng)參閱創(chuàng)建渲染管道狀態(tài)或創(chuàng)建計(jì)算管道狀態(tài)。如果不使用反射數(shù)據(jù)将硝,請(qǐng)避免使用恭朗。
反射對(duì)象包含MTLArgument命令編碼器支持的每種類型功能的對(duì)象數(shù)組屏镊。因?yàn)?a target="_blank" rel="nofollow">MTLComputeCommandEncoder,屬性中MTLComputePipelineReflection有一個(gè)對(duì)應(yīng)于其計(jì)算函數(shù)的參數(shù)的MTLArgument對(duì)象數(shù)組arguments冀墨。為MTLRenderCommandEncoder闸衫,MTLRenderPipelineReflection具有兩個(gè)屬性,vertexArguments并且fragmentArguments诽嘉,這是分別對(duì)應(yīng)于頂點(diǎn)函數(shù)參數(shù)和片段函數(shù)參數(shù)蔚出,陣列。
不是函數(shù)的所有參數(shù)都存在于反射對(duì)象中虫腋。反射對(duì)象僅包含具有關(guān)聯(lián)資源的參數(shù)骄酗,但不包含使用[[ stage_in ]]限定符或內(nèi)置[[ vertex_id ]]或[[ attribute_id ]]限定符聲明的參數(shù)。
清單4-2顯示了如何獲取反射對(duì)象(在本示例中MTLComputePipelineReflection)悦冀,然后遍歷MTLArgument其arguments屬性中的對(duì)象趋翻。
清單4-2 通過(guò)函數(shù)參數(shù)進(jìn)行迭代
MTLComputePipelineReflection* reflection;
id <MTLComputePipelineState> computePS = [device
newComputePipelineStateWithFunction:func
options:MTLPipelineOptionArgumentInfo
reflection:&reflection error:&error];
for (MTLArgument *arg in reflection.arguments) {
// process each MTLArgument
}
該MTLArgument特性揭示參數(shù)傳遞給著色語(yǔ)言功能的細(xì)節(jié)。
- 該name屬性僅僅是參數(shù)的名稱盒蟆。
- active 是一個(gè)布爾值踏烙,指示參數(shù)是否可以被忽略。
- index是在其對(duì)應(yīng)的參數(shù)表中的基于零的位置历等。例如讨惩,for [[ buffer(2) ]],index是2寒屯。
- access描述任何訪問(wèn)限制荐捻,例如讀取或?qū)懭朐L問(wèn)限定符。
- type由著色語(yǔ)言限定符指示的寡夹,例如处面,[[ buffer(n) ]],[[ texture(n) ]]菩掏,[[ sampler(n) ]]魂角,或[[ threadgroup(n) ]]。
type確定哪些其他MTLArgument屬性是相關(guān)的智绸。
如果type是MTLArgumentTypeTexture或颊,則該textureType屬性指示整體紋理類型(如texture1d_array,texture2d_ms以及texturecube在著色語(yǔ)言類型)传于,并且textureDataType屬性指示組件的數(shù)據(jù)類型(如half,float醉顽,int沼溜,或uint)。
如果type是MTLArgumentTypeThreadgroupMemory游添,則threadgroupMemoryAlignment和threadgroupMemoryDataSize性質(zhì)有關(guān)系草。
如果type是MTLArgumentTypeBuffer通熄,則bufferAlignment,bufferDataSize找都,bufferDataType唇辨,和bufferStructType屬性相關(guān)。
如果緩沖區(qū)參數(shù)是一個(gè)結(jié)構(gòu)(即能耻,bufferDataType是MTLDataTypeStruct)赏枚,則bufferStructType屬性包含MTLStructType表示該結(jié)構(gòu),和bufferDataSize包含該結(jié)構(gòu)的大小晓猛,以字節(jié)為單位饿幅。如果緩沖區(qū)參數(shù)是數(shù)組(或指向數(shù)組的指針),則bufferDataType表示元素的數(shù)據(jù)類型戒职,并bufferDataSize包含一個(gè)數(shù)組元素的大欣醵鳌(以字節(jié)為單位)。
清單4-3向下鉆取一個(gè)MTLStructType對(duì)象洪燥,以檢查結(jié)構(gòu)體成員的細(xì)節(jié)磕秤,每個(gè)由MTLStructMember對(duì)象表示。結(jié)構(gòu)體成員可以是簡(jiǎn)單類型捧韵,數(shù)組或嵌套結(jié)構(gòu)體市咆。如果該成員是一個(gè)嵌套的結(jié)構(gòu)體,那么調(diào)用structType方法MTLStructMember來(lái)獲取一個(gè)MTLStructType代表結(jié)構(gòu)體的對(duì)象纫版,然后遞歸深入分析它床绪。如果該成員是一個(gè)數(shù)組,請(qǐng)使用該arrayType方法MTLStructMember獲取MTLArrayType表示該數(shù)組的方法其弊。然后檢查它的elementType屬性MTLArrayType癞己。如果elementType是MTLDataTypeStruct,請(qǐng)調(diào)用該elementStructType方法來(lái)獲取結(jié)構(gòu)梭伐,并繼續(xù)深入其成員痹雅。如果elementType是MTLDataTypeArray,請(qǐng)調(diào)用elementArrayType方法獲取子陣列并進(jìn)一步分析糊识。
清單4-3 處理結(jié)構(gòu)參數(shù)
MTLStructType *structObj = [arg.bufferStructType];
for (MTLStructMember *member in structObj.members) {
// process each MTLStructMember
if (member.dataType == MTLDataTypeStruct) {
MTLStructType *nestedStruct = member.structType;
// recursively drill down into the nested struct
}
else if (member.dataType == MTLDataTypeArray) {
MTLStructType *memberArray = member.arrayType;
// examine the elementType and drill down, if necessary
}
else {
// member is neither struct nor array
// analyze it; no need to drill down further
}
}