问答 DrawInstance 和完全不做合批情况下的性能差异

侑虎科技 · March 31, 2021 · 720 hits

1)DrawInstance 和完全不做合批情况下的性能差异
​2)UWA 报告中检测出工程没有的资源
3)精灵设置九宫后,如何不在界面中显示出来
4)关于 AssetBundle 资源的卸载问题
5)Total Mono 突然上涨的原因


这是第 236 篇 UWA 技术知识分享的推送。今天我们继续为大家精选了若干和开发、优化相关的问题,建议阅读时间 10 分钟,认真读完必有收获。

UWA 问答社区:answer.uwa4d.com
UWA QQ 群 2:793972859(原群已满员)

Rendering

Q:我做了个测试,环境:Unity 2019.4.15 ,机型:小米 5X,绘制 1000 个物体(顶点数>300,不动态合批),测试顺序是:Unity 默认渲染(20 FPS)–>Update 中通过 Graphics.DrawInstance(16.5 FPS)–>通过 CommandBuffer 实现的 DrawInstance(21.5 FPS),对于第二个测试 DrawInstance 性能反而降低了不太理解,有大佬帮忙解答吗?

图片和测试工程可通过以下链接下载:
链接:https://share.weiyun.com/ZFOlW1of
密码:ip37rr

A:1.Instancing 耗时更高主要原因还是 GPU 压力比较大,见下面的测试案例:

测试 1:1000 个物体(顶点数 88,关闭动态合批)


Default:子线程 Camera.Render(14.59 ms)、Gfx.PresentFrame(3.94 ms)


Instancing:子线程 Camera.Render(7.1 ms)、Gfx.PresentFrame(4.70 ms)


测试 2:1000 个物体(顶点数 1278)


Default:子线程 Camera.Render(15.02 ms)、Gfx.PresentFrame(9.01 ms)


Instancing:子线程 Camera.Render(8.21 ms)、Gfx.PresentFrame(19.15 ms)


Instancing 是能够明显降低 CPU 渲染(Camera.Render)耗时的,但 GPU 调用 DrawInstanced() 比 Draw() 的性能似乎差一些,导致 CPU 端等待耗时较高。所以 Instancing 总体帧率有所下降主要是 GPU 的压力较大导致的。



2.如下图 Graphics.DrawMeshInstanced 在 Update 中每帧调用存在脚本耗时明显 DrawInstancing 更高(在 Update 中准备相关 DrawInstance 参数),Demo 渲染的是静态物体,使用 CommandBuffer 实现 DrawInstancing 可优化这部分耗时,同时在 Update 中的逻辑也会有 New XXX[] 数组这样的 Mono 堆内存频繁的分配,也会有 GC 影响(这部分影响较小)。


结论:Instancing 可以降低 CPU 渲染耗时,但 GPU API 性能会有所降低,帧耗时还是受到 CPU 渲染耗时及 GPU 耗时的综合影响,不同的机型可能表现的会有所差异。

Instancing 的使用:推荐绘制大量静态物体时使用 CommandBuffer 的实现,例如草海之类的。

感谢羽飞@UWA问答社区提供了回答

Texture

Q:请问一下:性能报告中,RGBA32 的图片有一些在工程中没有,但是在报告中却体现,请教一下这些是哪里产生的?

A:截图中的 Background、UIMask、UISprite 是由 UGUI 中默认的 UI 元素引入的,如下图中的 ScrollView:













UnityNormalMap 这个是由于 Shader 中的纹理使用 Bump 作为默认的值,但是在材质球中又没有给这个纹理赋值导致的。对于这种空纹理的资源,在 UWA 本地资源检测中是可以检测出来的。


感谢 Xuan@UWA 问答社区提供了回答

UGUI

Q:导入一张 171*41 的图片,设置完九宫信息后创建 UI 图片。然后设置图片宽高为 0,并设置图片模式为 Sliced。但是还是能看到图片显示出来了。个人感觉上是 UV 计算错误了。如果切换到 Simple 则图片正常不显示。请问大佬这是什么原理?

测试工程可在原问答下载(版本:Unity 2018.4.23)

A:这个和九宫格图片的实现原理有关,可以看看下面这个图片:


当你选择 Sliced 模式,他有一个最小的绘制区域,也就是四个角:1、3、7 和 9,必须绘制出来。当你设置的 Rect 大于 1、3、7、9 四个角组成的区域时,那么 2 和 8 则是在 x 方向进行缩放,y 方向不变,而 4 和 6 则是在 y 方向缩放,x 方向不变;而 5 则是 x 和 y 方向都会进行缩放。当你选择 Simple 模式,则是根据你设置的 Rect 范围决定的,如果 Rect 比原始尺寸大,那么就拉伸,反之则缩小;这也就是你可以不显示的原因。

感谢李星@UWA问答社区提供了回答

AssetBundle

Q1:公共资源 public.ab 做全局预加载,常驻内存。某特定资源 A 引用了 public.ab 里的一张大图纹理,以及另外一个 a.ab 里的资源。在没加载 A 时,public.ab 即使常驻内存也不会实际将那张大图纹理实例化。

现在的问题是,当加载并用完 A 资源后,想把 A 彻底从内存中清理出去时,对 a.ab 进行 Unload(true) 可以把 a.ab 清理掉,但是 public.ab 里的那张大图,在不对 public.ab 进行 Unload(true) 的前提下,是没有任何其它办法能将它从内存中清掉吗?

A1:如果能拿到那张 Texture 的引用,可以尝试使用Resources.UnloadAsset

但个人认为既然是公共资源,说明有可能被很多地方引用到,应做好 public.ab 里面的资源都常驻内存的内存预算准备。否则,按照你例子中的说法,可能把这张大纹理单独拿出来会好一些。

感谢范君@UWA问答社区提供了回答

Q2:由于该大图纹理被多个 UI 预置体引用,因此放到了 public.ab 里,但这些 UI 预置体,在游戏大部分时间(比如挂机战斗时)不会打开,因此也是不需要用到的,故而想卸载。看来还是只能再拆分出一类不常驻内存的公共资源,来解决这类问题了?

A2:既然要作为公共资源,常驻内存,那么就是从 App 的开始到 App 的结束都是不会去卸载的。如果你想原来在公共资源里的小图只有特定场景下才会使用到,平时不用时想卸载,可以参考下这个运行时动态图集,动态将小图合并到常驻内存的图集中,不用时在动态剔除回收。

《Unity 运行时动态图集的实现》

感谢 Coyote@UWA 问答社区提供了回答

Mono

Q:现象:在 Total Mono 突然撑大的那几帧中,Used Mono 并没有上涨,如图:





Used 在 50MB 左右时,Total 突然分配到 140MB,这是为什么?

A:很有可能是一帧中分配了大量的堆内存,将 Total 撑大了,但本身的堆内存是可以 GC 掉的,所以 Used 并没有太大的变化。

该问答由 UWA 提供

封面图来自网络


今天的分享就到这里。当然,生有涯而知无涯。在漫漫的开发周期中,您看到的这些问题也许都只是冰山一角,我们早已在 UWA 问答网站上准备了更多的技术话题等你一起来探索和分享。欢迎热爱进步的你加入,也许你的方法恰能解别人的燃眉之急;而他山之 “石”,也能攻你之 “玉”。

官网:www.uwa4d.com
官方技术博客:blog.uwa4d.com
官方问答社区:answer.uwa4d.com
UWA 学堂:edu.uwa4d.com
官方技术 QQ 群:793972859(原群已满员)

No Reply at the moment.
需要 Sign In 后方可回复, 如果你还没有账号请点击这里 Sign Up