Apple 推出 metal後,除了新的metal framewrok外,也多了一種新的shader語言,最近工做也作了一些metal移植的測試,主要仍是現有引擎如何能夠快速支持metal的解決方案。這裏也想對邊寫寫本身的心得。
metal shader的語法特性更接近SM5的hlsl,因此sm4或sm5的hlsl轉化成metal shader更簡單,性能跟GLES3.1類似,提供了Vextrex shader, Fragment Shader和Computer Shader。加上移動端圖形API的新特性的支持,因此使得次世代遊戲引擎面向移動端的移植成爲了可能
。
像UE4,CE3這種的大型引擎來講,自己shader代碼量就很大,要支持多平臺,若是寫多套shader,不管是在開發仍是測試上都會讓工做量成倍增長,因此都是選擇轉化shader的方式來跨平臺。
目前經常使用的shader轉化,要麼是FXC編譯HLSL的字節碼轉化,要麼就是直接源代碼之間轉化。對HLSL->GLSL而言,用字節碼轉化更簡單。但metal shader不提供字節碼的格式,因此字節碼轉化方式多是行不通了。UE4在開發時的2年裏也搜索過能解決SM5的HLSL轉化的跨平臺編譯器,結果只能本身基於Mesa3D的功能進行擴展,開發了HLSLCC。
目前的幾個HLSL->GLSL的方案:
hlsl2glslfork,由ATI的HLSL2GLSL發展而來,也基於了一部分monoshader的代碼(UE3最先就是用的monoshader),shader源代碼之間的翻譯,問題是隻支持DX9風格的HLSL,不支持DX10和DX11的一些語法,也沒有geometry shader,tesseliaton shadr和 compute shader,如今Unity3d仍是用的這個。
KlayGE的HLSL2GLSL,是從HLSL的字節碼轉化爲GLSL。
UE4的
HLSLCC,經過在他們在GDC2014上的ppt來看,也是受到
glsl-optimizer的設計的影響,這兩個都是參考Mesa3D的,不過Mesa3D只是GLSL的分析和轉化爲Mesa IR,HLSLCC改爲了SM5的HLSL的分析功能,並添加了IR->GLSL的converter。而且在UE4.3後,也加入了metal shader的支持。
接下來也是想結合HLSLCC的ppt,說一些本身的見解,HLSLCC的轉化流程,是HLSL->AST->IR->GLSL/Metal + ParameterMap,輸出使用了
glsl-optimizer一部分功能
,但實際運行UE4的HLSLCC的時候,仍是會有很多問題的。
1.
shader marco,像ue的.usf,ce的.fxc,多少會經過使用宏來作一些shader的條件編譯,靜態分支處理等等,也就相似uber shader的概念,但基本上沒有什麼轉化工具能搞定那麼複雜的工做,並且也常常會有vs,ps的多個Entry函數(Main)寫到一個usf文件裏的狀況,直接整個.usf扔給轉化工具也是不現實的,ue和ce的解決方法,仍是要通過內部的管理,把每一個入口函數的部分獨立出來,如UE4就是經過定義Golbalshader子類,本身來設置參數和入口函數名等等。而後獨立的shader入口函數進行轉化。而#include,#define,#if 一類的
宏和分支的處理,進行轉化前要經過,只留下runtime必須的部分,轉化成不一樣平臺的shader並編譯爲cache保存。
2.
OGL經過uniform從每幀從CPU->GPU傳遞參數,爲了減小API調用次數,因此DX11提供了const buffer,而ES3.0和metal也提供了uniform buffer的概念,由於對於大型遊戲來講,uniform update調用API的數量也是很大一部分消費,因此須要使用const buffer來根據參數更新頻率和順序進行組織,而在不支持這種概念的DX9上,CE3使用了模擬的const buffer來對參數進行緩存重組再進行更新,而UE4雖然直接支持的DX11,但對移動平臺ES2.0的設備,沒有uniform buffer的特性,他們使用了模擬的Uniform buffer功能(ppt裏叫shadow buffer),基於更新頻率打包到uniform array。因此,HLSLCC除了輸出GLSL外,也有生成Parameter Map的功能。
3. shader version方面,若是是DX11 HLSL的轉化,對hlslcc進行一些修改定製後就能夠,自己hlslcc也支持不一樣版本GL和metal的輸出,若是是DX9 風格HLSL的話,就須要進行一些預處理工做了,dx9和dx11的主要變化在semantic,texture和sample的使用上有些變化。例如:
Pixel Shader的input,DX11裏改成了SV_Position,output裏,COLOR被SV_Target替代
DX9:
struct vs2ps
{
float4 Pos : POSITION;
float4 TexCd : TEXCOORD0;
};
DX11:緩存
struct vs2ps
{
float4 Pos: SV_POSITION;
float4 TexCd: TEXCOORD0;
};
DX9:app
float4 PS(vs2ps In): COLOR
DX11:函數
float4 PS(vs2ps In): SV_Target
Texture Sample的定義:工具
DX9:
texture Tex <string uiname="Texture";>;
sampler Samp = sampler_state //sampler for doing the texture-lookup
{
Texture = (Tex); //apply a texture to the sampler
MipFilter = LINEAR; //sampler states
MinFilter = LINEAR;
MagFilter = LINEAR;
};
DX11:性能
Texture2D texture;
SamplerState g_samLinear
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};
若是要Sample Texture:測試
DX9:
float4 col = tex2D(Samp, In.TexCd.xy);
DX11:優化
float4 col = texture2d.Sample( g_samLinear, In.TexCd.xy);
DX9:ui
float4 col = tex2Dlod(Samp, float4(In.TexCd.xy,0,level));
DX11:spa
float4 col = texture2d.SampleLevel( g_samLinear, In.TexCd.xy,level);
DX9:.net
float4 col = tex2Dproj(Samp,screenProj.xyzw);
DX11:
float4 col = Samp.Sample(g_samLinear, .creenProj.xy / screenProj.w );
4 GLES3.1和metal裏都提供了compute shader的功能,metal shader裏叫kernel function,很惋惜,這部分UE4也還沒支持,因此HLSLCC裏也還沒實現Compute Shader的轉化,但相信不久之後也會支持了,拭目以待吧。
總結,本身這方面的工做也是剛開始,因此描述的深度也有限,隨着額工做深刻,應該會對HLSLCC和各類API如何優化作進一步分析