转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=2826

三年前,我就曾经计划过一个KlayGE的长期研发子项目,D3D11 HLSL字节码到GLSL的编译器。两年前,在d3d1x for linux代码的帮助下,基本的字节码解析和反汇编工具已经实现。如今,这个子项目被正式命名为DXBC2GLSL,在库和工具两个层面上提供HLSL字节码(DXBC)到GLSL的转换。2013年底,DXBC2GLSL支持VS和PS初始版本已经由团队新成员林胜华完成,并提交到开发版本中。GS的支持也已经在上个月加入。当前所有KlayGE中的shader已经全部通过测试。

输入

类似的项目,比如hlsl2glsl forkmojoshader,都只支持到了SM3。对于SM4+的shader,只能自己做一个编译器。DXBC2GLSL的输入是SM5的字节码(也兼容SM4),经过解析,得到输入变量、输出变量、资源声明和shader指令等。

由于调用的是d3dcompiler.dll,shader转换的工作变成平台相关了。如果需要在Linux上做这件事情,就得用Wine来执行d3dcompiler。

输出

DXBC2GLSL包含了一个库和两个工具。用户可以在自己的程序中使用DXBC2GLSL的库进行转换,也可以调用工具进行离线转换。输出的GLSL可以是OpenGL 2.0-4.4的VS/PS/GS。HS/DS/CS,以及OpenGL ES的版本也在开发中。

和Cg的对比

原先在KlayGE中的流水线是,带有#ifdef的HLSL经过一次token转换,得到Cg源代码。经过Cg编译器转换成GLSL。在经过一次token转换,得到“现代”的GLSL。通过这样多次转换,消除了Cg编译器产生的代码对硬件的依赖。这个过程相当繁复,带来的结果是虽然稳定性有所保证,但转换速度下降了。同时由于Cg和HLSL的区别,要保证源代码兼容,很多高级的HLSL功能也都被禁止了。

使用DXBC2GLSL之后,HLSL可以完全兼容。只需要一次转换就能得到最终的GLSL。

这里比较一下KlayGE中使用DXBC2GLSL和Cg流水线的区别。编译速度和Shader性能两项,测试的是DeferredRendering例子。

DXBC2GLSL流水线 Cg流水线
Shader Model SM5 SM3和一部分SM4
转换方式 一次转换 三次转换
编译速度 5秒 9秒
Shader性能 95FPS 80FPS
Vertex Shader 完全支持 不支持gl_VertexID、gl_InstanceID…
Pixel Shader 完全支持 不支持gl_PrimitiveID、gl_SampleID…
Geometry Shader 完全支持 不支持gl_PrimitiveIDIn、gl_Layer…
Hull Shader 开发中 不支持
Domain Shader 开发中 不支持
Compute Shader 开发中 不支持
Uint系列指令 支持 不支持
Atomic系列指令 支持 不支持
Texture array 支持(但尚未在KlayGE中使用) 不支持

未来

目前的DXBC2GLSL只是打下了一个基础,以后还需要更多的测试、重构和优化。另外,这套框架在理论上甚至可以做到把compute shader转成OpenCL。