Reprinted please indicate the source for the klayge game engine, this article address for 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/
Starting from klayge 4.0, we have not only developed short-term tasks for the next version, but also some long-term R & D tasks. One of them is the HLSL bytecode to glsl compiler. Currently, the shader in klayge is mainly written in HLSL and compatible with CG through the # ifdef soil method. It can be used directly for d3d11, but for OpenGL and OpenGL ES 2, it will be a huge discount. In that case, the shader needs to be compiled into a traditional glsl by the CG compiler, and converted into a modern glsl by my own token-level compiler before it can be used.
Why not use CG directly? Let's see how CG runtime works on the ATI card.
Why not use traditional glsl? The NV driver has a set of binding rules between attribute and index. For example, gl_position must be 0, and gl_normal must be 6 (or a number, but a constant ), in addition, you cannot use the API to obtain the index of the predefined attribute. This rule is not available on the ATI card. Modern glsl does not have a predefined attribute and varing (except position). Therefore, the attribute name can be given to obtain the index, which is of much better compatibility.
Therefore, the better solution here is to compile HLSL into glsl without using the CG compiler. At present, there are some libraries that can do this, such as AMD's hlsl2glsl (which has stopped development), Unity's hlsl2glsl fork (developed from AMD), and mojoshader. Their problem is that only Sm3 is supported, and the minimum connection requirements for klayge are not met. You can only make one compiler by yourself.
If you need to directly compile HLSL into glsl, You Need To Do HLSL parsing and other things, which is both troublesome and inefficient. So I chose to parse the bytecode produced by HLSL compilation to generate glsl. Because HLSL-> bytecode can directly use off-the-shelf compilers, saving a lot of trouble. (Wine can be used to compile HLSL of d3dx even on Linux)
After the solution is clear, the steps can be quickly defined:
- D3d11 bytecode Disassembly
- VS/PS to glsl
- GS/HS/Ds to glsl
After referring to d3d1x for Linux in Mesa, the first step has been implemented. The following section:
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 } |
After fxc is compiled into vs_5_0, you can use disasm to decompile
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 |
The disassembly result is exactly the same as that of fxc. The test of ps_5_0 can also pass.
The first step of HLSL bytecode to glsl compiler is taken. Next, I will start to try generating glsl VS/PS.