停下来歇歇

    从9月中旬开始,我马不停蹄的开始引擎的代码编写工作到现在,有很多时候甚至晚上回家还再继续写,加上最近孩子刚刚出生,每晚睡的比较晚,有些疲惫。昨天照例回到家里打开电脑写程序,还没动手,发现引擎中的材质系统中渲染状态对象分类的一个问题,当然可以先按照目前的设计做下去,以后再改,不过以我的做事风格来说,发现了问题如果不解决,心里总是不舒服,经过仔细考虑,发现如果更改需要做较大的变化,可能需要几天的开发工作量,这样原来的引擎开发计划就受到了影响。
    其实这个问题在一开始的时候就曾经想过,是否要按照 D3D10 的标准来划分状态对象,但当时考虑只支持 DX9,所以这个念头也就放了下来,这段时间在实现 DX9 材质系统的时候,发现 DX9 的渲染状态实在是太乱,不过这并不是 MS 的开发人员的问题,本身 D3D 也在发展,这些混乱的标记也印证着 D3D 的发展历史。回头再翻 D3D10 文档,API 简洁明了,非常清晰,当然代价也是显而易见的,完全不向下兼容,从软件到硬件全部重新设计。想想也应该这样,否则 D3D 怎么能发展下去。由此,我决定引擎全面转向 D3D10,采用 D3D10 的一些先进理念设计引擎的内部结构,尤其是渲染和材质系统部分。对于 D3D9 的支持,可以通过映射来实现,毕竟这个引擎是面向两年以后的游戏,那个时候 D3D10 已经大行其道。
    再说说引擎的设计,一开始我曾想过把引擎抽象出来,做成插件形式,可以有不同的渲染 API 来实现,不过我发觉这实际上很难做到,毕竟不同渲染 API 差异很大,实现起来很困难,时间较长,而且要对各个 API 都非常了解,另外最重要的是效率问题,抽象独立的代价就是效率的降低,毕竟 3D 引擎性能很重要,前段时间看了一下 unrxxl3 的代码,也是和 D3D 混在一起,根本见不到 OGL 的影子。还有就是关于设计,也许早年受到 OO 的影响太深,总觉得抽象接口不应该依赖具体实现,但这几年写程序我发现这完全就是 OO 的谎言,OGRE 的代码我看过,为了抽象和 OO ,做了太多无用的工作,导致性能比同类引擎比要低很多,最近又听说 ATI 下一代 GPU 完全基于 D3D10 架构设计,以换取最佳的性能体验。硬件依赖于软件结构,这在以往是完全不合理的,但存在就是合理,事实上 ATI 早就放弃支持 OGL,为了提高性能,从硬件上按照 D3D 来设计,这样减少了许多无用的转换和判断开销,Driver 可以尽其优化,基于 OGL 的 DOOM3 一发售,ATI 的 OGL 问题立刻暴露出来,由此可见一斑。再说 Gamebryo 引擎,我也看过他的代码,是 For D3D9 的,这个引擎号称支持所有平台、所有渲染api,但实际上它每种平台和 3D API 都有不同的实现,抽象的部分并不多,比如 For D3D9 的,引擎代码中大量依赖了 D3DX 的库,甚至数学库干脆直接用 D3DX 的!想必也是为了性能考虑吧。
    不过尽管如此,我还是把引擎抽象了出来,目前只考虑实现两种 API:D3D9 和 D3D10,在性能方面我取了个巧:例如把 D3D9 的常量定义类型定义都原封不动的引擎的核心定义中,只是名称不同,这样就无须作类型转换和映射。在接口方面我原来是采用 D3D9 的接口方式,现在看来要转向 D3D10,这部分也要作相应更改,会更合理一些。
    说说材质系统,这段时间主要的开发量放在材质系统上了,由于引擎采用 D3D fx 格式来封装 Material ,同时为了自己管理渲染状态又不能直接使用 D3DXEffect ,所以自己从头写了 fx 脚本的解析器,重新组织渲染状态对象,这样才能自己管理渲染状态。虽然采用 FX 脚本格式,但引擎的抽象部分并没有任何依赖于 fx 细节的任何部分,我把解析全都放在了 D3D9、10 的实现中,但是这又带来了前面说的问题,为了抽象,我不得不付出性能上的代价,因为要借助中间数据结构,不能直接读入到引擎中。等做完看看性能如何,实在不行就只好直接放在引擎核心中吧。
    原来只作为最小化状态切换的 RenderTree 现在已经承担了更多的责任,什么 Full Screen PostEffect\Object PostEffect\MultiPass\Accumulate State\全都放在了这里,现在已经不是单纯的状态管理树,在保证正确绘制的前提下才会保证最小换切换,仔细想想也是这样,绘制都不正确速度再快又有何用?
    虽然创建非 pure device D3D 可以帮助开发人员 cache 渲染状态并能避免重复的状态设置,不过这毕竟是工作在 D3D Runtime 层,而且有可能还是工作在操作系统的核心层次,这样还要有在用户层到核心层上的传输开销,所以我自己实现了免除渲染状态切换的机制,并且这套机制也可以防止 fx 开发人员在写脚本时默认一些 pipeline 的渲染状态的情况,引擎能根据情况自动设置默认的渲染状态。这样带来的额外的好处是引擎就可以使用 pure device (尽管 MS 不建议这样做)。
    内存管理:自己写了一个 Memory Management,但为了记录分配情况,每次在 opertor new 中会增加记录链表节点,不过这又会调用 new,这样就形成了死循环,最终堆栈溢出。改为 malloc,好了一些,但是 stl 中的一些容器也重载了 new,总是崩溃,最后放弃。以后有时间再好好整理吧。结论:直接使用 BoundsChecker 最为方便。
    关于 D3D 文档中的错误,说实话,仔细看发现错误真的不少,甚至 SDK 代码中的注视都有错误。只能靠自己分辨了。
    STL:字符串处理使用的 STL,一些对性能不太重要的地方也用到了 STL,不过我还是自己实现了 LIST、MAP,倒不是说自己写得有多快,主要是发现 STL 在 iterate 时效率不高,每次都要生成临时对象,OGRE 中大量使用了 STL,这也是其效率低的原因之一。经过测试,自己写的优化后的 LIST MAP 在插入、删除、排序、遍历都优于 STL(Release 下),当然查找还不行,不过可以使用 Map,这是经过特殊预处理优化后的 Map,访问的时间是 O(1)。至少在这上面不会是性能杀手。
    今天给自己放假一天,仔细想想,引擎的结构、代码、功能、问题、性能………..
Advertisements
此条目发表在DreamEngine 3D 图形引擎开发分类目录。将固定链接加入收藏夹。

4 Responses to 停下来歇歇

  1. wu说道:

    呵呵,最近还是一个人写吗?
    接口层不会降低效率,这个都谈论烂了吧。
    自己解析fx,这个强啊,呵呵,把GLSL,cg也支持了算了。
    你说的ATI下一代显卡是指r600?符合d3d10的要求不一定opengl慢啊。
    现在opengl的确是慢慢退出游戏界,混乱,更新缓慢。不过也没有必要d3d和opengl都支持,如果不跨平台的话。
    内存管理还是自己做吧,好处多多,stl重载的new是带名字空间的吧。

  2. 说道:

    确实,不做跨平台完全没有必要去抽象白白损失了效率
    你做的FX脚本材质系统是不是类似OGRE里的technique啊
    我觉得材质系统能彻底开放出来,让美工去编辑可能是最好的解决方案
    就像unreal那样,和编辑器结合 🙂

  3. 说道:

    还是一个人在写,不过也自得其乐。抽象接口本身倒不会降低效率,我指的是为了包容不同系统而做出的映射和转换,这方面的开销还是不容忽视的。自己解析 fx 格式也是没办法的事,为了自己管理渲染状态,不能使用 effect,因为 Effect 在每个 BeginPass 时自动进行 State 设置。fx 格式已经很成熟,自己解析的 fx 框架基本上是参考了 D3DEffect 框架来做得,里面甚至还有 ConstantTable\\ShaderConstantPool…ATI 下一代 D3D10 显卡,从硬件上是按照 D3D10 标准来设计,MS 这次为了最大化 D3D10 的性能,在标准中要求硬件必须支持特定的性能优化,比如 State Object 的性能提升,如果只是在 Runtime 级别上来进行优化的话,D3D9 就基本已经到了尽头了。而且 D3D10 将 N 多原来 D3D9 在绘制时校验的操作移到了创建时,这些如果没有硬件的支持是根本没办法做到的。内存管理放在以后再说吧,现在没时间理它,不过我在一些基本数据结构中加入了局部的内存管理。不管怎样,尽量不要在 loop 中分配释放内存。
    关于可视化编辑材质系统,这方面上半年在盛大的时候曾经研究过,也有一些进展,不过后来没有继续下去,等引擎基本的部分完成之后再研究看看吧。不过 D3D10 中也提到,fx 在设计时优先考虑的是性能,然后才是可编辑性,我也会遵循这样的设计思路。

  4. m17说道:

    支持中国人自己的引擎 *_*

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  更改 )

Google+ photo

You are commenting using your Google+ account. Log Out /  更改 )

Twitter picture

You are commenting using your Twitter account. Log Out /  更改 )

Facebook photo

You are commenting using your Facebook account. Log Out /  更改 )

w

Connecting to %s