总体来说,iOS 14的渲染性能变差了,从下面的测试中就可以看出。
测试1:简单demo,使用egret引擎显示3000张图片(都是相同的100*100 png纹理),并逐帧旋转。 (博客园的视频播放可能有问题,视频地址:)
视频中,黑机是iOS14.0,白机是iOS13.7h5游戏引擎,均为iPhone 7plus。
虽然从视频上看iOS 14的fps更高,但实际上14明显滞后。 原因是:Egret检测到的fps是通过Web层面的requestAnimationFrame获取的,实际上并不严格等同于屏幕渲染。
相反,我使用 perfDog 从本机级别查看帧速率。 我看到iOS 14只有13fps,而旧版本有40+。 这也解释了为什么肉眼看来14的渲染似乎更加滞后。
测试2:复杂演示,使用egret引擎显示100个糖果爆炸龙骨动画。 (博客园视频播放可能有问题,视频地址:)
与上面的测试1类似,egret左上角的fps显示不准确。 通过perfDog检测,实际帧率只有7fps左右。
测试3:在复杂demo的基础上(依然是100个爆炸动画),修改egret代码,禁用混色着色器,所有元素渲染使用普通着色器。 由于龙骨设置为24fps,但实际fps为40,所以从视频中肉眼看不出延迟。 所以这里就省略视频了。
这是类似的情况。 iOS14 的渲染 fps 低于 iOS13。 iOS14只有8fps左右开发学习,而iOS13有40+fps。
测试4:
使用自主开发的简单webgl引擎(min2d)显示15,000个100*100的png。 (博客园的视频播放可能有问题,视频地址:)
情况与egret引擎类似。 iOS14还是明显卡住了。 虽然界面显示较高的fps,但实际帧率只有10fps左右。 题外话:自研引擎的性能比egret略好10%左右,但在上面的测试中可以支持15000张图片,只是因为自研引擎没有将像素密度加倍进行渲染。
可以看到iOS14 webgl的性能确实明显低于iOS13。
分析
从egret的监控来看,js层面的耗时(包括顶点计算和调用webgl)没有明显的问题。 iOS14相比iOS13甚至还有一些优化。 但iOS14的实际渲染帧率明显低于iOS13。 该问题应该是由于 Safari 内 webgl 接口的具体实现发生了一些变化。
在调试过程中,发现了两个奇怪的现象:
1.原本全帧运行,但运行一段时间后,会下降到40-50fps。
2、播放50个爆炸动画时,可以稳定在50fps,但增加到60个爆炸动画后,fps会断崖式下降到14fps左右。
从这个现象推测,显存管理的内部实现可能发生了重大变化。 可能有一些缓存。 数据达到阈值后,可能会出现重复的数据交换。
首先我们检查了几个方面:
1.drawCall如何推送顶点缓冲区(webgl.bufferData vs webgl.bufferSubData)
egret 使用 webgl.bufferData 在每次绘制调用时推送顶点数据。 该方法每次推送时都会覆盖整个bufferData; 而webgl.bufferSubData可以指定offset,仅覆盖部分数据。
但由于每次修改的数据量并不大,因此两者在理论和实际测试上并没有什么区别。
2.推送纹理、webgl初始化设置(抗锯齿等)、frameBuffer
以上几个方面,白鹭的设置都是常见做法,并无特殊之处。 而且,调整参数后,性能并没有提高。
3.去掉shader的alpha计算
没有明显变化
4.去掉blendMode处理
虽然性能提升明显,但在iOS14上的性能提升并不比iOS13更大。 BlendMode并不是iOS14速度变慢的主要因素。
而且BlendMode是游戏材质制作的必选选项,影响透明叠加效果,无法轻易去除。
针对以上几个方面,目前还没有找到解决办法。
另外,另一个游戏引擎cocos Creator官方提出在cocos引擎中使用多重drawCall优化技术来共享顶点缓冲区和索引缓冲区(也是常规的优化方法),但在iOS14中成为性能瓶颈,并已被针对已处理(对于iOS14,每个drawCall使用不同的顶点缓冲区)。
参考:
分析egret的实现,默认设置每个drawcall最多可以同时处理2048个元素。 对于一般的精灵来说,一个元素等于一张图,等于一个矩形,等于两个三角形,等于六个顶点。
此外,当egret初始化时,它会创建一个由12288个无符号short组成的索引缓冲区,然后将该缓冲区绑定到GPU。 这个过程一般只执行一次,不会再次绑定,也不会创建新的缓冲区(网格拉伸的情况除外,此时会改变indexbuffer的数据内容)。
然后,每次drawcall,无论有多少个元素,即使只有1个元素(6个顶点),都会使用这个12288长度的索引缓冲区。
从这个角度来看,确实可能存在优化的可能性。
发动机改进
从现象和分析过程可以得出,iOS14确实存在性能下降的情况h5游戏引擎,我们可以尝试从某些维度来挽回一些性能下降的情况。
目前确认可以从引擎层面改善索引缓冲区问题。
改进的策略是:判断是否是iOS14。 如果是这样,请在每次绘制调用之前推送新的索引缓冲区和顶点缓冲区数据。 这些数据只包含了本次渲染所需要的数据,没有多余的数据。
具体变化:
在WebGLRenderContext的$drawWebGL方法中,判断是否绘制Mesh。 非Mesh绘制的情况下,将vao中的indices数组和vertices数组进行拆分,取出本次drawcall需要的部分,上传到GPU。 而且,在这种情况下,drawData应该忽略offset,将其改为固定的0(offset是在顶点缓冲区包含多个drawcall数据时使用的,现在每次都是按需推送,所以不再需要offset)。
还渲染了50个爆炸龙骨动画,修改后的版本性能得到了显着提升。 如下图所示,左边一分钟是原版绘制50个爆炸龙骨动画的fps,右边是优化版本的fps。 原版平均为10fps,而优化后平均为20fps(这个帧率可能与之前的测试demo略有不同,因为iPhone渲染在一段时间后会变慢)。
调整索引缓冲区的使用确实可以解决上述爆炸龙骨动画在iOS14中的性能问题。
此外,在调查过程中开发学习,我们还发现了一些值得探索的方向:
1. 如何使用和不使用过滤器对基元进行批处理。 白鹭引擎本来就没有做批处理。 如果能够实现这个优化,龙骨的渲染drawCall将会大大减少。
2.调整像素密度绘制策略。 egret引擎默认以屏幕像素密度为倍数来绘制webgl画布,但游戏素材并没有那么大。 这种扩大的渲染对性能有影响,但视觉效果并没有改善。
第2点,特别是低端机型,比如系统版本6的Android。低一点就可以了。
比如oppo r9系统版本5.1,屏幕像素密度3,强制用密度1绘制,性能可提升30%。
除了上面提到的方向外,针对iOS14可能还会有更有针对性的优化方向,但具体场景需要一一分析。
性能结论
与iOS13及之前的版本相比,iOS14在webgl渲染性能上有明显的下降,尤其是当drawcall次数较多、渲染面积较大、或者使用了较多的混色滤镜时,下降尤为明显。
对于iOS14来说,虽然在某些方面性能可以得到提升,但是从纯JS的角度来看,webgl渲染性能无法恢复到iOS13的水平。 我们只能希望苹果官方能够自行修复底层问题(苹果论坛已经有很多反馈了)。
材料开发建议
除了从引擎底层解决iOS 14延迟问题外,还可以进行一些改变来提高游戏业务素材的渲染性能:
1.降低龙骨动画层次,减少图形元素数量;
2.避免使用混色和BlendMode;
3.避免使用大面积透明区域的图片。 您可以将图片分割成多个仅包含有效内容的小图片。
另外,iOS14在js层面监控的帧率并不是真正的webgl渲染帧率。 性能优化需要直接连接到 perfDog 进行监控。