關於Shader的跨平臺方案的考慮

  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如何優化作進一步分析

 
相關文章
相關標籤/搜索