十八、Metal著色語言

Metal Shading Language

  • Metal著?語?是?來編寫 3D 圖形渲染邏輯和并?計算核?邏輯的??編程語?。當(dāng)使? Metal 框架來完成APP 的實現(xiàn)時則需要使?Metal 編程語?;
  • Metal語言使用的是Clang 和LLVM進(jìn)行編譯處理的;
  • Metal 基于C++ 11.0 語?設(shè)計。主要?來編寫 在 GPU 上執(zhí)?的圖像渲染邏輯代碼 以及 通? 并?計算邏輯代碼;

Metal 與C++ 11.0 相愛相殺

雖然Metal基于C++,但它很蘋果,并不是支持C++11.0所以特性的,以下Metal暫時用不上,它就不支持:

  • 遞歸函數(shù)調(diào)用;
  • Lambda 表達(dá)式;
  • 動態(tài)轉(zhuǎn)換操作符
  • 類型識別
  • 對象創(chuàng)建new 和銷毀delete 操作符;
  • 操作符 noexcept;
  • goto 跳轉(zhuǎn);
  • 變量存儲修飾符register 和 thread_local;
  • 虛函數(shù)修飾符;
  • 派?類;
  • 異常處理;
  • C++ 標(biāo)準(zhǔn)庫在Metal 語?中也不可使?;

Metal使用指針的局限

  • Metal圖形和并?計算函數(shù)?到的?參數(shù); 如果是指針必須使?地址空間修飾符 (device,threadgroup,constant);
  • 不支持函數(shù)指針;
  • 函數(shù)名不能出現(xiàn)main;

Metal 像素坐標(biāo)系統(tǒng): Metal 中紋理/幀緩存區(qū)attachment 的像素使?的坐標(biāo)系統(tǒng)的原點是左上 ?;

Metal 數(shù)據(jù)類型

標(biāo)量數(shù)據(jù)類型


標(biāo)量數(shù)據(jù)類型

紋理數(shù)據(jù)類型(Texture)

紋理類型是?個句柄, 它指向?個?維/?維/三維紋理數(shù)據(jù)。 在?個函數(shù)中描述紋理對象的類型。

枚舉值: 定義了訪問權(quán)利: enum class access {sample ,read ,write};

sample : 紋理對象可以被采樣. 采樣?維這是使?或不使?采樣器從紋理中讀取數(shù)據(jù);
read : 不使?采樣器, ?個圖形渲染函數(shù)或者?個并?計算函數(shù)可以讀取紋理對象;
write: ?個圖形渲染函數(shù)或者?個并?計算函數(shù)可以向紋理對象寫?數(shù)據(jù);

texture1d<T, access a = access::sample>
texture2d<T, access a = access::sample>
texture3d<T, access a = access::sample>

T : 數(shù)據(jù)類型 設(shè)定了從紋理中讀取或是向紋理中寫?時的顏?類型. T可以是half, float, short, int 等;

void foo (texture2d<float> imgA [[ texture(0) ]] ,
          texture2d<float, access::read> imgB [[ texture(1) ]],
          texture2d<float, access::write> imgC [[ texture(2) ]]) 
{  
         // TODO:
}

采樣器類型(Samplers)

采取器類型決定了如何對?個紋理進(jìn)?采樣操作. 在Metal 框架中有?個對應(yīng)著?器語?的采樣器的對象 MTLSamplerState 這個對象作為圖形渲染著?器函數(shù)參數(shù)或是并?計算函數(shù)的參數(shù)傳遞;

采樣器狀態(tài)及默認(rèn)值

紋理采樣:enum class coord { normalized, pixel };
紋理坐標(biāo)的尋址模式:enum class address { clamp_to_zero, clamp_to_edge, repeat, mirrored_repeat };
紋理采樣過濾方式:enum class filter { nearest, linear };
注意: 在Metal 程序中初始化的采樣器必須使? constexpr 修飾符聲明

/*
constexpr:修飾符(必須寫)
sampler:類型
s:采樣器變量名稱
coord: 是否需要歸一化,不需要歸一化,用的是像素pixel
address: 地址環(huán)繞方式
filter: 過濾方式
*/
 constexpr sampler s(coord::pixel,address::clamp_to_zero,filter::linear);
 constexpr sampler a(coord::normalized);
 constexpr sampler b(address::repeat);

函數(shù)修飾符

Metal的3種函數(shù)修飾符:

  • Kernel:表示該函數(shù)是?個數(shù)據(jù)并?計算著?函數(shù). 它可以被分配在?維/?維/三維線程組中去執(zhí)?;
  • vertex:表示該函數(shù)是?個頂點著?函數(shù) , 它將為頂點數(shù)據(jù)流中的每個頂點數(shù)據(jù)執(zhí)??次然后為每個頂 點?成數(shù)據(jù)輸出到繪制管線;
  • fragment , 表示該函數(shù)是?個?元著?函數(shù), 它將為?元數(shù)據(jù)流中的每個?元 和其關(guān)聯(lián)執(zhí)??次然后 將每個?元?成的顏?數(shù)據(jù)輸出到繪制管線中;

注意:

  1. 使用kernel 修飾的函數(shù)返回值必須是void 類型
    只有圖形著?函數(shù)才可以被 vertex 和 fragment 修飾. 對于圖形著?函數(shù), 返回值類型可以辨認(rèn)出它是為 頂點做計算還是為每像素做計算. 圖形著?函數(shù)的返回值可以為 void , 但是這也就意味著該函數(shù)不產(chǎn)?數(shù) 據(jù)輸出到繪制管線; 這是?個?意義的動作;

  2. 一個被函數(shù)修飾符修飾過的函數(shù),不允許在調(diào)用其他的被函數(shù)修飾過的函數(shù).

  3. 被函數(shù)修飾符修飾過的函數(shù),只允許在客戶端對齊進(jìn)行操作. 不允許被普通的函數(shù)調(diào)用.

地址空間修飾符

它是?于變量或者參數(shù),Metal 著?器語?使?它來表示?個函數(shù)變量或者參數(shù)變量 被分配于那??內(nèi)存區(qū)域. 所有的著?函數(shù)(vertex, fragment, kernel)的參數(shù),如果是指針或是引?, 都必須帶有地址空間修飾符號;

  • 1.device
  • 2.threadgroup
  • 3.constant
  • 4.thread

對于圖形著?器函數(shù), 其指針或是引?類型的參數(shù)必須定義為 device 或是 constant 地址空間; 對于并?計算著?函數(shù), 其指針或是引?類型的參數(shù)必須定義為 device 或是 threadgrounp 或是 constant 地址空間;

Device Address Space(設(shè)備地址空間)

在設(shè)備地址空間(Device) 指向設(shè)備內(nèi)存池分配出來的緩存對象, 它是可讀也是可寫的; ?個緩存對象可 以被聲明成?個標(biāo)量,向量或是?戶?定義結(jié)構(gòu)體的指針或是引?.

注意: 紋理對象總是在設(shè)備地址空間分配內(nèi)存, device 地址空間修飾符不必出現(xiàn)在紋理類型定義中. ?個紋 理對象的內(nèi)容?法直接訪問. Metal 提供讀寫紋理的內(nèi)建函數(shù);

線程組地址空間(threadgrounp Address Space)

線程組地址空間?于為 并?計算著?函數(shù)分配內(nèi)存變量. 這些變量被?個線程組的所有線程共享. 在線 程組地址空間分配的變量不能被?于圖形繪制著?函數(shù)[頂點著?函數(shù), ?元著?函數(shù)] 在并?計算著?函數(shù)中, 在線程組地址空間分配的變量為?個線程組使?, 聲明周期和線程組相同;

函數(shù)參數(shù)與變量

圖形繪制或者并?計算著?器函數(shù)的輸?輸出都是通過參數(shù)傳遞. 除了常量地址空間變量和程序域定義 的采樣器以外.

  • device buffer- 設(shè)備緩存, ?個指向設(shè)備地址空間的任意數(shù)據(jù)類型的指針或者引?;
  • constant buffer -常量緩存區(qū), ?個指向常量地址空間的任意數(shù)據(jù)類型的指針或引?;
  • texture - 紋理對象;
  • sampler - 采樣器對象;
  • threadGrounp - 在線程組中供各線程共享的緩存.

注意: 被著?器函數(shù)的緩存(device 和 constant) 不能重名;

對于每個著?器函數(shù)來說, ?個修飾符是必須指定的. 他?來設(shè)定?個緩存,紋理, 采樣器的位置:

  • device buffers/ constant buffer --> [[buffer (index)]]
  • texture -- [[texture (index)]]
  • sampler -- [[sampler (index)]]
  • threadgroup buffer -- [[threadgroup (index)]]

index是?個unsigned integer類型的值,它表示了?個緩存、紋理、采樣器參數(shù)的位置(在函數(shù)參數(shù)索引 表中的位置)。 從語法上講,屬性修飾符的聲明位置應(yīng)該位于參數(shù)變量名之后

//并行計算著色器函數(shù)add_vectros ,實現(xiàn)2個設(shè)備地址空間中的緩存A與緩存B相加.然后將結(jié)果寫入到緩存out.
//屬性修飾符"(buffer(index))" 為著色函數(shù)參數(shù)設(shè)定了緩存的位置
// thread_position_in_grid : ?于表示當(dāng)前節(jié)點在多線程?格中的位置;
kernel void add_vectros(
                const device float4 *inA [[buffer(0)]],
                const device float4 *inB [[buffer(1)]],
                device float4 *out [[buffer(2)]]
                uint id[[thread_position_in_grid]])
{
    out[id] = inA[id] + inB[id];
}

內(nèi)建變量屬性修飾符

  • [[vertex_id]] 頂點id 標(biāo)識符;
  • [[position]] 頂點信息(float4) /? 述了?元的窗?相對坐標(biāo)(x, y, z, 1/w) ;
  • [[point_size]] 點的??(float) ;
  • [[color(m)]] 顏?, m編譯前得確定;
  • [[stage_in]] : ?元著?函數(shù)使?的單個?元輸?數(shù)據(jù)是由頂點著?函數(shù)輸出然后經(jīng)過光柵化?成的.頂 點和?元著?函數(shù)都是只能有?個參數(shù)被聲明為使?“stage_in”修飾符,對于?個使? 了“stage_in”修飾符的? 定義的結(jié)構(gòu)體,其成員可以為?個整形或浮點標(biāo)量,或是整形或浮點向量
//定義了片元輸入的結(jié)構(gòu)體,
struct MyFragmentOutput {
      // color attachment 0 顏色附著點0
     float4 clr_f [[color(0)]]; 
     // color attachment 1 顏色附著點1
     int4 clr_i [[color(1)]]; 
     // color attachment 2 顏色附著點2
     uint4 clr_ui [[color(2)]]; 
};

fragment MyFragmentOutput my_frag_shader( ... ) 
{
    MyFragmentOutput f;
    ....
    f.clr_f = ...;
    ....
    return f; 
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容