轉載請注明出處為KlayGE游戲引擎,本文地址為http://www.klayge.org/2012/02/09/hlsl-bytecode-to-glsl%e7%bc%96%e8%af%91%e5%99%a8%e7%9a%84%e7%ac%ac%e4%b8%80%e6%ad%a5/
從KlayGE 4.0開始,不但有為了下一版本開發的短期任務,還有一些中長期研發的任務。其中之一就是HLSL bytecode to GLSL編譯器。 現在KlayGE里的shader主要由HLSL寫成,通過#ifdef的土辦法兼容Cg。對D3D11來說可以直接使用,但對於OpenGL和 OpenGL ES 2就得大費周折了。那種情況下,shader需要經過Cg編譯器編譯成傳統的GLSL,在經過我自己的token級別的編譯器轉換成現代的GLSL,然后 才能使用。
為什么不直接用Cg?看看Cg runtime在ATI卡上的表現吧。
為什么不用傳統的GLSL?NV的驅動有一套attribute和index之間的綁定規則,比如gl_Position一定是 0,gl_Normal一定是6(或者某個數,但是個常量),而且無法通過API來獲取預定義attribute的index。這套規則在ATI卡上是不 可用的。現代的GLSL沒有預定義的attribute和varing(除了position),所以都可以給定attribute名來獲取index, 兼容性好得多。
所以,這里更好的解決方案是把不通過Cg編譯器,就把HLSL編譯成GLSL。目前有一些能做到這件事情的庫,比如AMD的hlsl2glsl(已經停止開發),unity的hlsl2glsl fork(從AMD的發展而來),以及mojoshader。他們的問題在於,只支持到了SM3,對KlayGE來說連最低要求都沒達到。只能自己做一個編譯器。
如果需要把HLSL直接編譯成GLSL,就需要做HLSL的解析等事,既麻煩又不能保證效率。所以我選擇了把HLSL編譯產生的bytecode解 析出來,生成GLSL。因為HLSL->bytecode可以直接用現成的編譯器,省了很多麻煩。(即便是linux上,也可以用wine來執行 d3dx的HLSL編譯)
方案明確后,步驟也就能很快定義出來:
- D3D11 bytecode反匯編
- VS/PS to GLSL
- GS/HS/DS to GLSL
在參考了mesa的d3d1x for linux之后,目前已經實現了第一步,反匯編器。下面一段VS:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 void DeferredRenderingVS(float4 pos : POSITION,
#ifdef NOPERSPECTIVE_SUPPORT
out noperspective float2 oTc : TEXCOORD0,
#else
out float3 oTc : TEXCOORD0,
#endif
out float3 oViewDir : TEXCOORD1,
out float4 oPos : SV_Position)
{
oPos = mul(pos, light_volume_mvp);
oViewDir = mul(pos, light_volume_mv).xyz;
oTc.xy = oPos.xy / oPos.w * 0.5f;
oTc.y *= KLAYGE_FLIPPING;
oTc.xy += 0.5f;
#ifndef NOPERSPECTIVE_SUPPORT
oTc.z = oPos.w;
oTc.xy *= oTc.z;
#endif
}
經過fxc編譯成vs_5_0后,可以用我的disasm反匯編出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 vs_5_0
dcl_global_flags refactoringAllowed
dcl_constant_buffer cb0[12].xyzw, immediateIndexed
dcl_input v0.xyzw
dcl_output o0.xy
dcl_output o1.xyz
dcl_output_siv o2.xyzw, position
dcl_temps 2
dp4 r0.x, v0.xyzw, cb0[8].xyzw
dp4 r0.y, v0.xyzw, cb0[9].xyzw
dp4 r0.w, v0.xyzw, cb0[11].xyzw
div r1.xy, r0.xyxx, r0.wwww
mov o2.xyw, r0.xyxw
mad o0.xy, r1.xyxx, l(0.5, -0.5, 0, 0), l(0.5, 0.5, 0, 0)
dp4 o1.x, v0.xyzw, cb0[4].xyzw
dp4 o1.y, v0.xyzw, cb0[5].xyzw
dp4 o1.z, v0.xyzw, cb0[6].xyzw
dp4 o2.z, v0.xyzw, cb0[10].xyzw
ret
與fxc的反匯編結果完全一致。ps_5_0的測試也可以通過。
HLSL bytecode to GLSL編譯器的第一步算是邁出了,接下去我會開始嘗試一些GLSL VS/PS的生成工作。