Unity开发——CPU优化之UI模块
CPU优化之UI模块
1.1 UGUI
UGUI遇到过的四类常见问题:
- Fragment Shader使用带来的GPU过度消耗(如填充率过高)
- 重建一个Canvas导致CPU耗时过高
- Canvas重建的数量过高
- 生成顶点消耗大量CPU时间(通常是Text产生的)
例如Image,Text等UI元素的Enable及UI元素的长、宽或Color属性的变化等。Canvas中UI Mesh顶点较多的话,则该项将会出现较高的CPU开销。虽然这是CPU篇,但是也会介绍下GPU方面的UI优化。
大家可以看看:UGUI UI重建二三事(一)和UGUI优化干货总结
两篇都对UGUI的函数源码、通知重建流程都进行讲解,我这边也对这些进行概括下:
1.1.1 网格重建流程图
Canvas Renderer:所有标准UI对象都可以在任何需要的地方附加Canvas Renderers,自定义UI对象需要自己手动添加这个组件。
- 该过程由CanvasUpdateRegistry监听Canvas的WillRenderCanvases(上图中1)而执行,主要是对前标记为dirty的layout和craphic执行rebuild。引起layout和graphic的dirty主要原因是因为Canvas树形结构下的UI元素发生了变化(例如增加删除UI对象,UI元素的顶点,rec尺寸改变等)调用了Graphic.SetDirty(实际上最终都会调用CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild)。
- 在rebuild layout之前会对Layout rebuild queue中的元素依据它们在heiarchy中的层次深度进行排序(上图中的2),排列的结果是越靠近根的节点越会被优先处理。
- rebuild layout(上图中的3),主要是执行ILayoutElement和ILayoutController接口中的方法来计算位置,Rect的大小等布局信息。
- rebulid graphic(上图中的4),主要是调用UpdateGeometry重建网格的顶点数据(上图中5)以及调用UpdateMeterial更新CanvasRender的材质信息(上图中6)。
1.1.2 canvasRenderer.cull
从上面第一点的原因可得知:引起layout和graphic的dirty主要原因是因为Canvas树形结构下的UI元素发生了变化。主要变更的值就是canvasRenderer.cull!
Graphic中的Rebuild函数会对canvasRenderer.cull进行判断,GraphicRaycaster的射线检测函数Raycast也会对graphic.canvasRenderer.cull进行判断,cull如果为true,UI的重建(顶点和材质更新)及射线RayCast的检测将会被跳过,所以在优化UGUI时,首先考虑的是尝试减少Cull属性的变更,其次,减少m_VertsDirty和m_MaterialDirty属性的变更,因为他们会导致UI数据的重新计算,也就是说,尽量减少UI脏数据的产生。
1.1.3 cull的变化原因(源码讲解)
MaskableGraphic中的Cull属性更新的实现,源码如下:
private void UpdateCull(bool cull)
{
var cullingChanged = canvasRenderer.cull != cull;
canvasRenderer.cull = cull;
if (cullingChanged)
{
m_OnCullStateChanged.Invoke(cull);
SetVerticesDirty();
}
}
UpdateCull更新方法的调用总共有两处:
public virtual void Cull(Rect clipRect, bool validRect)
{
var cull = !validRect || !clipRect.Overlaps(rootCanvasRect, true);
UpdateCull(cu