《Metal》官方文檔翻譯006--函數和庫

函數和庫

本章介紹如何創建一個MTLFunction對象作為Metal著色器或計算函數的參考,以及如何組織和訪問具有MTLLibrary對象的函數。

MTLFunction表示著色器或計算功能

一個MTLFunction對象表示一個單獨的功能,它以Metal著色語言編寫,并在GPU上作為圖形或計算流水線的一部分執行。有關Metal著色語言的詳細信息,請參閱“ Metal著色語言指南”

要在Metal運行時間和以Metal著色語言編寫的圖形或計算函數之間傳遞數據或狀態,請為紋理,緩沖區和采樣器分配參數索引。參數索引標識由Metal運行時和Metal著色代碼引用的紋理,緩沖區或采樣器。

對于渲染遍,您可以在MTLFunction對象中指定一個用作頂點或片段著色器的MTLRenderPipelineDescriptor對象,如創建渲染管道狀態中所述。對于計算過程,您可以MTLFunction在MTLComputePipelineState為目標設備創建對象時指定對象,如“ 為計算命令編碼器指定計算狀態和資源”所述

一個Library就是一個函數庫

一個MTLLibrary對象表示的一個或多個儲存庫MTLFunction對象。單個MTLFunction對象表示使用著色語言編寫的一個Metal函數。在Metal著色語言源代碼,使用一個Metal函數限定符任何功能(vertex,fragment,或kernel)可以通過一個代表MTLFunction在一個庫中的對象。沒有這些函數限定符之一的Metal函數不能由MTLFunction對象直接表示,盡管它可以由著色器中的另一個函數調用。

MTLFunction可以從以下任一來源創建庫中的對象:

  • Metal著色語言代碼,在應用程序構建過程中被編譯成二進制庫格式。

  • 包含由運行時應用程序編譯的Metal著色語言源代碼的文本字符串。

從編譯代碼創建庫

為了獲得最佳性能,請在您的應用程序的Xcode構建過程中將Metal著色語言源代碼編譯成庫文件,從而避免在應用程序運行時編譯函數源的費用。要從MTLLibrary庫二進制創建對象,請調用以下方法之一MTLDevice

  • newDefaultLibrary 檢索為主包構建的庫,其中包含應用程序的Xcode項目中的所有著色器和計算函數。

  • newLibraryWithFile:error:將路徑傳遞給庫文件,并返回一個MTLLibrary包含存儲在該庫文件中的所有函數的對象。

  • newLibraryWithData:error:使用二進制blob包含庫中函數的代碼并返回一個MTLLibrary對象。

有關在構建過程中編譯Metal著色語言源代碼的更多信息,請參閱
在應用程序構建過程中創建庫

從源代碼創建庫

要從MTLLibrary可能包含多個函數的Metal著色語言源代碼字符串創建一個,請調用以下方法之一MTLDevice。這些方法在創建庫時編譯源代碼。要指定要使用的編譯器選項,請設置MTLCompileOptions對象中的屬性。

從Library獲取功能

返回具有請求名稱的對象的newFunctionWithName:方法。如果在庫中找不到使用Metal著色語言功能限定符的函數的名稱,則返回。MTLLibraryMTLFunctionnewFunctionWithName:nil

清單4-1使用通過其完整路徑名定位庫文件的newLibraryWithFile:error:方法,MTLDevice并使用其內容創建MTLLibrary具有一個或多個MTLFunction對象的對象。加載文件時出現任何錯誤error。然后創建一個表示在源代碼中調用的函數的對象的newFunctionWithName:方法。返回的函數對象現在可以在應用程序中使用。MTLLibraryMTLFunctionmy_funcmyFunc

清單4-1 從庫訪問函數

NSError *errors;

id <MTLLibrary> library = [device newLibraryWithFile:@"myarchive.metallib"

error:&errors];

id <MTLFunction> myFunc = [library newFunctionWithName:@"my_func"];

在運行時確定功能詳細信息

由于MTLFunction對象的實際內容由MTLFunction創建對象之前可以編譯的圖形著色器或計算函數定義,因此其源代碼可能無法直接用于該應用程序。您可以MTLFunction在運行時查詢以下屬性:

MTLFunction不提供對函數參數的訪問。在創建流水線狀態期間,可以獲得反映物體(MTLRenderPipelineReflectionMTLComputePipelineReflection根據命令編碼器的類型)來顯示著色器或計算函數參數的細節。有關創建管道狀態和反射對象的詳細信息,請參閱創建渲染管道狀態創建計算管道狀態。如果不使用反射數據,請避免使用。

反射對象包含MTLArgument命令編碼器支持的每種類型功能的對象數組。因為MTLComputeCommandEncoder,屬性中MTLComputePipelineReflection有一個對應于其計算函數的參數的MTLArgument對象數組arguments。為MTLRenderCommandEncoderMTLRenderPipelineReflection具有兩個屬性,vertexArguments并且fragmentArguments,這是分別對應于頂點函數參數和片段函數參數,陣列。

不是函數的所有參數都存在于反射對象中。反射對象僅包含具有關聯資源的參數,但不包含使用[[ stage_in ]]限定符或內置[[ vertex_id ]]或[[ attribute_id ]]限定符聲明的參數。

清單4-2顯示了如何獲取反射對象(在本示例中MTLComputePipelineReflection),然后遍歷MTLArgumentarguments屬性中的對象。

清單4-2 通過函數參數進行迭代

MTLComputePipelineReflection* reflection;
id <MTLComputePipelineState> computePS = [device
          newComputePipelineStateWithFunction:func
          options:MTLPipelineOptionArgumentInfo
          reflection:&reflection error:&error];
for (MTLArgument *arg in reflection.arguments) {
//  process each MTLArgument
}

MTLArgument特性揭示參數傳遞給著色語言功能的細節。

  • name屬性僅僅是參數的名稱。
  • active 是一個布爾值,指示參數是否可以被忽略。
  • index是在其對應的參數表中的基于零的位置。例如,for [[ buffer(2) ]],index是2。
  • access描述任何訪問限制,例如讀取或寫入訪問限定符。
  • type由著色語言限定符指示的,例如,[[ buffer(n) ]],[[ texture(n) ]],[[ sampler(n) ]],或[[ threadgroup(n) ]]。

type確定哪些其他MTLArgument屬性是相關的。

如果緩沖區參數是一個結構(即,bufferDataType是MTLDataTypeStruct),則bufferStructType屬性包含MTLStructType表示該結構,和bufferDataSize包含該結構的大小,以字節為單位。如果緩沖區參數是數組(或指向數組的指針),則bufferDataType表示元素的數據類型,并bufferDataSize包含一個數組元素的大小(以字節為單位)。

清單4-3向下鉆取一個MTLStructType對象,以檢查結構體成員的細節,每個由MTLStructMember對象表示。結構體成員可以是簡單類型,數組或嵌套結構體。如果該成員是一個嵌套的結構體,那么調用structType方法MTLStructMember來獲取一個MTLStructType代表結構體的對象,然后遞歸深入分析它。如果該成員是一個數組,請使用該arrayType方法MTLStructMember獲取MTLArrayType表示該數組的方法。然后檢查它的elementType屬性MTLArrayType。如果elementType是MTLDataTypeStruct,請調用該elementStructType方法來獲取結構,并繼續深入其成員。如果elementType是MTLDataTypeArray,請調用elementArrayType方法獲取子陣列并進一步分析。

清單4-3 處理結構參數

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
}
}

下一頁

上一頁

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

推薦閱讀更多精彩內容