OGRE针对图形API调用的效率优化
2015-10-13 19:40
218 查看
http://blog.163.com/ding_liang1989/blog/static/168788329201362005946890/
本文所针对的OGRE版本为1.65,因为本人目前公司项目使用这个版本。
本文所讲述的内容是不改变任何渲染流程,直接从最底层Direct3D API 调用上去抠OGRE的性能。
1、Shader参数的分类。这一点在后续版本中做了,但是在1.65版本中是没有的。通常来说,同一个Shader的参数可以分为以下几种:全局常量(值被手动改变或者切Shader的时候传),物件常量(一个DrawCall传一次),Light常量(一个光源传一次),这种分类能最大化利用目前网游开发需要的Shader,OGRE后续版本中加上的分类还多了一个Pass常量(用同一个Shader画一个物件多次,每画一次传一次),用于多Pass光照。传Shader参数的API是很耗时的,而且像光照之类的Shader,需求的参数又非常多,在OGRE1.65中,每个批次都要传将全部的参数传一次,这是非常耗时的,所以要将这部分代码从后续版本中移植过来。
1.5、新版本的做法其实严格来说也有一定缺陷,在切换Shader时,会传所有的GPU参数,更具体的说,切换了VS,却要去更新全部的PS参数,这显然是不合理的,这部分需要自己改进。
2、频繁的Shader切换。OGRE在调用SetXXXShader API时是没有cache机制的,也就是说,无论当前要设置的Shader和上一次设置的Shader是否相同,都会在每个批次设置一次,而SetXXXShader又是非常耗时的,且会导致所有GPU参数的传递。解决方法是根据名字判断一下,和上一次的不一样才Set。
3、SetRenderState之前会调用GetRenderState来做cache,这样比缓存一个值要慢。
4、过于简单的材质排序。OGRE的材质排序只考虑了pass的顺序和前两张贴图,对于渲染状态是一点都不顾及。一个32位的hash,pass占了4位,也就是说最多支持11个Pass,如果光照处理采用的是单Pass光照,对于物件的渲染最多2个Pass就够了,绝大多数都只需要一个Pass。所以Pass我给了1位,空出3位来可以随便根据项目具体情况找几个开销最大的状态来考虑进去,本人的做法是先把hash位数提高到64位,考虑Pass-Shader-Texture-State。
5、频繁的VertexDeclartion切换。同屏画几百个批次,顶点声明就那么几种,而OGRE的做法是每次渲染都调用SetVertexDeclartion API,而这个API是很耗时的,所以需要cache一下。
6、频繁的顶点/索引Buffer切换。如果同一个Mesh连续画一百个批次,OGRE会SetStreamSource/SetIndice一百次,如果顶点分流,还会成倍增长,而这两个API都是很耗时的,所以同样需要cache一下。
7、虽然cache了Texture,但Texture相关的StageState和SamplerState都没有cache,使得按纹理排序获得的收益降低,需要cache一下,与RenderState一样,自己cache,去掉调用API的Get函数。
以上这些是本人最近两天做优化的总结,大部分都是由于没有cache而造成的不必要的DX API调用。
本文所针对的OGRE版本为1.65,因为本人目前公司项目使用这个版本。
本文所讲述的内容是不改变任何渲染流程,直接从最底层Direct3D API 调用上去抠OGRE的性能。
1、Shader参数的分类。这一点在后续版本中做了,但是在1.65版本中是没有的。通常来说,同一个Shader的参数可以分为以下几种:全局常量(值被手动改变或者切Shader的时候传),物件常量(一个DrawCall传一次),Light常量(一个光源传一次),这种分类能最大化利用目前网游开发需要的Shader,OGRE后续版本中加上的分类还多了一个Pass常量(用同一个Shader画一个物件多次,每画一次传一次),用于多Pass光照。传Shader参数的API是很耗时的,而且像光照之类的Shader,需求的参数又非常多,在OGRE1.65中,每个批次都要传将全部的参数传一次,这是非常耗时的,所以要将这部分代码从后续版本中移植过来。
1.5、新版本的做法其实严格来说也有一定缺陷,在切换Shader时,会传所有的GPU参数,更具体的说,切换了VS,却要去更新全部的PS参数,这显然是不合理的,这部分需要自己改进。
2、频繁的Shader切换。OGRE在调用SetXXXShader API时是没有cache机制的,也就是说,无论当前要设置的Shader和上一次设置的Shader是否相同,都会在每个批次设置一次,而SetXXXShader又是非常耗时的,且会导致所有GPU参数的传递。解决方法是根据名字判断一下,和上一次的不一样才Set。
3、SetRenderState之前会调用GetRenderState来做cache,这样比缓存一个值要慢。
4、过于简单的材质排序。OGRE的材质排序只考虑了pass的顺序和前两张贴图,对于渲染状态是一点都不顾及。一个32位的hash,pass占了4位,也就是说最多支持11个Pass,如果光照处理采用的是单Pass光照,对于物件的渲染最多2个Pass就够了,绝大多数都只需要一个Pass。所以Pass我给了1位,空出3位来可以随便根据项目具体情况找几个开销最大的状态来考虑进去,本人的做法是先把hash位数提高到64位,考虑Pass-Shader-Texture-State。
5、频繁的VertexDeclartion切换。同屏画几百个批次,顶点声明就那么几种,而OGRE的做法是每次渲染都调用SetVertexDeclartion API,而这个API是很耗时的,所以需要cache一下。
6、频繁的顶点/索引Buffer切换。如果同一个Mesh连续画一百个批次,OGRE会SetStreamSource/SetIndice一百次,如果顶点分流,还会成倍增长,而这两个API都是很耗时的,所以同样需要cache一下。
7、虽然cache了Texture,但Texture相关的StageState和SamplerState都没有cache,使得按纹理排序获得的收益降低,需要cache一下,与RenderState一样,自己cache,去掉调用API的Get函数。
以上这些是本人最近两天做优化的总结,大部分都是由于没有cache而造成的不必要的DX API调用。
相关文章推荐
- 计算状态栏和导航条的高度
- android listview 取消头部分割线
- 软件测试基础知识总结
- 使用uitableview的索引功能
- OC学习之初步对象的建立
- Ubuntu环境下安装python的flask
- 写代码,请不要中断
- Objective-C中代码块的学习
- 侧滑返回功能失效解决
- UIView与CALayer的理解
- 有关圆的计算。
- centos7 matlab install
- 坚持坚持坚持
- linux上应用程序的执行机制
- Rotate Array
- 杭电acm--1040
- tomcat Manger App
- struts2拦截器问题
- 【C++】指针&引用的区别
- Xsollad电竞学院为学生和教练打开大门啦!