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ù)類型

紋理數(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ù)傳遞;

紋理采樣:
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ù)輸出到繪制管線中;
注意:
使用kernel 修飾的函數(shù)返回值必須是void 類型
只有圖形著?函數(shù)才可以被 vertex 和 fragment 修飾. 對于圖形著?函數(shù), 返回值類型可以辨認(rèn)出它是為 頂點做計算還是為每像素做計算. 圖形著?函數(shù)的返回值可以為 void , 但是這也就意味著該函數(shù)不產(chǎn)?數(shù) 據(jù)輸出到繪制管線; 這是?個?意義的動作;一個被函數(shù)修飾符修飾過的函數(shù),不允許在調(diào)用其他的被函數(shù)修飾過的函數(shù).
被函數(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;
}