转载请注明出处为KlayGE游戏引擎,本文地址为http://www.klayge.org/2012/02/20/kfx%e6%a0%bc%e5%bc%8f%e7%9a%84%e5%a4%8d%e6%b4%bb/
老用户一定记得,在KlayGE 3.9之前,用来表示effect的.fxml都需要通过一个python写成的编译器进行离线编译,生成.kfx格式才能给runtime使用。在 3.9里引入了rapidxml,可以直接在runtime读取xml文件,流程变短,开发效率提高了。但随着这两年shader越写越复杂,编译 shader所花的时间越来越多,在载入的时候每次都编译shader,一来浪费时间,二来浪费计算。
KlayGE的模型格式.meshml也有过这样的问题,后来通过一个JIT在载入的时候动态把xml的.meshml编译成二进制 的.model_bin,之后的载入速度就极大提高了。既不需要离线编译,也不用担心读取效率。因此,引入一个effect JIT也成了理所当然的事情。所以,事隔多年后,kfx格式原地满血复活。
原先的kfx目标是把effect的东西保存成二进制,以便runtime读取;现在的目标是减少时间和计算的浪费。因此,虽然扩展名仍是kfx, 要装的东西仍是二进制的effect,但文件格式和能力并没有也不需要和以前的兼容了。新的格式不光有原先的二进制effect部分,更是可以在同一个文 件中保存不同API编译后的shader。目前支持的有HLSL bytecode、GLSL、ESSL。不同的渲染插件可以选择自己能处理的格式读取。将来还将支持更多的二进制格式,尤其是OpenGL ES上的,以应对孱弱的OpenGL ES GLSL编译器。
顺便说说4.0上的.fxml_bin格式。因为Android上没有Cg,所以当时应急引入了.fxml_bin,把在PC上JIT好的ESSL 存在里面。这样Android上只要直接读取ESSL就可以了,不涉及Cg。但因为只是个应急方案,并没有仔细设计,每个fxml_bin只能保存一个 shader。以至于一个fxml可能编译生成许许多多不同的fxml_bin存在目录下。现在终于可以都删掉了。
现在比较一下用了新kfx后的载入速度吧。就选用Deferred Rendering这个shader最多最复杂的例子。
使用kfx之前(秒) | 使用kfx之后(秒) | 加速(秒) | |
D3D11 | 4.8 | 2.6 | 2.2 |
OpenGL | 6.0 | 2.6 | 3.4 |
OpenGL ES | 28.2 | 25.3 | 2.9 |
D3D11插件省去了组装HLSL、编译HLSL的时间,大约2.2秒。OpenGL的shader需要经历Cg->传统GLSL-> 现代GLSL的流程,用了kfx之后这些都省掉,所以省下了最多的时间。OpenGL ES和OpenGL流程一样,但ESSL较简单,所以加速没那么明显。需要注意的是OpenGL ES还需要的25秒基本上花在载入纹理上了。因为OpenGL ES模拟器不支持DXT5、SRGB等,需要在载入的时候动态转换成ABGR8,相当慢。以后可能会发展出一个Platform compiler,针对不同平台把资源离线编译出最适合的格式,从根本上解决这个问题。