NGUI源码剖析之提高GPU性能
来源:互联网 发布:分析家数据接口 编辑:程序博客网 时间:2024/06/10 14:12
一.使用NGUI
NGUI和UGUI比起来我更喜欢NGUI,因为NGUI可将图片打成图集,而且它和texturepacker配合使用会十分的方便,高效。texturepacker导出一张合图和一个文本,使用NGUI创建一个Atlas,拖拽上去即可。
二.NGUI性能提升。
首先来一段源码:这是UIPanel里面的代码。
void FillAllDrawCalls (){for (int i = 0; i < drawCalls.Count; ++i)UIDrawCall.Destroy(drawCalls[i]);drawCalls.Clear();Material mat = null;Texture tex = null;Shader sdr = null;UIDrawCall dc = null;int count = 0;if (mSortWidgets) SortWidgets();for (int i = 0; i < widgets.Count; ++i){UIWidget w = widgets[i];if (w.isVisible && w.hasVertices)//遍历所有的widget,如果可见就获取该widget的材质、图片、shader{Material mt = w.material;Texture tx = w.mainTexture;Shader sd = w.shader;if (mat != mt || tex != tx || sdr != sd)//如果当前的这三个属性和上次循环有一个不一样,说明是一个新的{//Atlas,并将上次新建的DrawCall对象添加到链表里面。if (dc != null && dc.verts.size != 0){drawCalls.Add(dc);dc.UpdateGeometry(count);//更新刚刚添加的那个drawcall信息dc.onRender = mOnRender;//注册渲染回调mOnRender = null;count = 0;dc = null;//将dc赋值为空,很关键。}mat = mt;//给当前drawcall做标记,好做下一次循环判断tex = tx;sdr = sd;}if (mat != null || sdr != null || tex != null){if (dc == null){dc = UIDrawCall.Create(this, mat, tex, sdr);//如果dc为空,说明遇到新的图集,需新建一个drawcalldc.depthStart = w.depth;dc.depthEnd = dc.depthStart;dc.panel = this;}else{int rd = w.depth;//如果dc不为空,那就将他和上次循环那个共享一个if (rd < dc.depthStart) dc.depthStart = rd;//DrawCall,不需要新建。if (rd > dc.depthEnd) dc.depthEnd = rd;}w.drawCall = dc;++count;if (generateNormals) w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, dc.norms, dc.tans);//将信息写入缓冲区else w.WriteToBuffers(dc.verts, dc.uvs, dc.cols, null, null);if (w.mOnRender != null){if (mOnRender == null) mOnRender = w.mOnRender;else mOnRender += w.mOnRender;}}}else w.drawCall = null;}if (dc != null && dc.verts.size != 0){drawCalls.Add(dc);//将最后一个drawcall添加到渲染列表。因为如果最后一个和上一个属于同一个图集,不会进入dc.UpdateGeometry(count);//下一个循环,也就不会将最后一个drawcall添加到渲染列表。dc.onRender = mOnRender;mOnRender = null;}}
1.通过阅读代码,我们发现NGUI的渲染算法是这样的。
比如我们的ui界面(6个Sprite)由下面几个图集组成的界面:(depth从小到大)
Atlas1/Atlas2/Atlas2/Atlas3/Atlas2/Atlas1
2.按照上面的算法,NGUI会生成多少个DrawCall对象呢(将UIDrawCall类里面的#define SHOW_HIDDEN_OBJECTS注释取消可以看到有多少个)?首先Atlas1是一个,到Atlas2时,由于两个图集使用的图片不一样,材质也不一样,因此NGUI会新建一个DrawCall对象,到了第三个,由于上一个也是Atlas2,就不需要新建一个DrawCall对象。因此就少一个Drawcall,这样下来,一共可以生成5个Drawcall对象。Drawcall对象越多,GPU消耗也就越多。所以我们可以通过以下这种排列来减少Drawcall对象:
Atlas1/Atlas1/Atlas2/Atlas2/Atlas2/Atlas3
哦?这样好像只剩下3个DrawCall了。所以争取把同一个图集的图片让他们的depth相挨着是一个简单的解决办法。但是,我还有另外一个解决办法。
Atlas1/Atlas1/Atlas1/Atlas1/Atlas1/Atlas1
3.这个办法就是将一个界面下的ui图片打到同一个图集里面。这样就只有一个DrawCall对象了。但是,这样会有一个问题。如果另外一个界面用到了相同的图片,你需要将它复制到新的图集里面,这样会造成内存浪费。所以需要将通用的图片打到一起,组成一个CommonAtlas,比如说UI的一些九宫格的通用图片。其他小图片就复制就复制了,它无非就是在内存和渲染之间找临界点。一般一个界面下来5-10个DrawCall是比较正常的(如果图集较多时)。
三 总结。
1.合理安排depth可以减少DrawCall数量。
2.将一个界面的多个元素打到同一个图集里面可以减少DrawCall数量。
3..不要将动态图和静态图安置到同一个DrawCall里面,因为动态图(比如Spine做的骨骼动画)经常需要传递给GPU运算,每次变化都要这样做,如果和静态图放到了同一个DrawCall,它会将静态UI的顶点、材质信息也传送给GPU。有种拖人(静态ui)下水的意思。
- NGUI源码剖析之提高GPU性能
- 【NGUI源码剖析】NGUI的drawcall
- NGUI 的grid提高显示性能
- 【NGUI源码剖析】NGUI如何优化drawcall数量
- 【NGUI源码剖析】深入理解NGUI的drawcall
- NGUI源码剖析——动画(UITweener)
- NGUI源码剖析——动画(UITweener)
- NGUI源码分析之----UIDrawCall
- NGUI的事件通知架构和源码剖析
- NGUI的事件通知架构和源码剖析
- NGUI的事件通知架构和源码剖析--UICamera
- 第22课:Spark性能调优之使用更高性能算子及其源码剖析
- fork之源码剖析
- ThreadPoolExecutor 源码剖析之
- 源码剖析之poll
- [UnityUI]NGUI性能优化之ScrollView
- 《GPU高性能运算之CUDA》勘误表
- 《GPU高性能计算之CUDA》勘误表
- 128.给你的TableView一个最合适的布局
- UOJ300吉夫特
- c++成员函数指针
- zoj-1004Anagrams by Stack(栈和向量)
- this 的作用 用法 static的作用和用法
- NGUI源码剖析之提高GPU性能
- git--分支管理策略
- 帧内预测和帧间预测的关系
- [LeetCode] 495. Teemo Attacking
- 适配器stack和queue的使用
- hdu 2037 今年暑假不AC
- linux使用:CentOS安装jdk
- Android_播放视屏
- (初识)斜率dp