这是个人关于微信小游戏系列文章的第三篇,在这系列文章里会描述 ——
测试使用的 Demo 可以通过 GitHub 下载。
小米 Note3,使用骁龙 660,算是这两年比较主流的中端芯片,虽然性能在高负荷场景下跟旗舰芯片如骁龙 835 还有一定距离,不过大部分场景下也已经够用。
设备电量在 60% 以上,处于充足状态,并使用风扇进行辅助散热,避免因为电量不足或者过热导致设备锁核降频,从而引起测试数据的波动,无法获得可以对比的测试结果。
页面在 Chrome 上运行在全屏的 WebApp 模式下,如果没有额外说明,Canvas 的渲染分辨率使用设备的屏幕分辨率 1080p。
adb shell "dumpsys SurfaceFlinger --latency 'TARGET_WINDOW_NAME'"
使用上述命令可以获取目标窗口最近 127 帧的更新时间戳,然后用脚本计算出这 127 帧渲染过程中的平均帧率。
另外代码中也通过计算 JavaScript 中每帧调用的次数和时间间隔来计算帧率,然后通过控制台打印输出类似下面的信息,实际验证两者的结果基本一致。
WebGL Aqua framerate:1.55fps, program:44, draw call:118
本文的测试数据使用第一种方法。
模拟鸟群的运动,包含大量的物理运动计算,实际上是测试 JavaScript 的计算性能。
可以对 numBoids (guimark3.js)参数进行修改,改变鸟群的数量,鸟群数量越大,JavaScript 计算的耗时就越大。
运行环境 | 250 鸟群 | 500 鸟群 |
---|---|---|
小游戏 | 58 ~ 59 | 21 ~ 22 |
Chrome | 58 ~ 60 | 20 ~ 21 |
绘制的场景有一定的复杂度,包含了约 30 个模型,使用了 44 个 Program,当参数设定为 500 条鱼时,需要调用 600 多个 Draw Call(不使用 Instance Rendering 的情况下)。
可以配置的参数如下:
运行环境 | 100 条鱼 | 200 条鱼 | 500 条鱼 | 1000 条鱼 | 2000 条鱼 |
---|---|---|---|---|---|
小游戏 | 52 ~ 53 | 52 ~ 53 | 58 ~ 59 | 58 ~ 59 | 37 ~ 38 |
Chrome (关闭抗锯齿) | 60 | 60 | 60 | 58 ~ 60 | 39 ~ 40 |
Chrome (关闭抗锯齿, 720p) | - | - | - | - | 60 |
Chrome (关闭抗锯齿, Instance) | - | - | - | - | 52 ~ 54 |
Chrome (打开抗锯齿) | 60 | 60 | 42 ~ 44 | 28 ~ 30 | 18 ~ 19 |
Chrome (打开抗锯齿, 720p) | - | - | 60 | 51 ~ 53 | 31 ~ 32 |
Chrome (打开抗锯齿, 600p) | - | - | - | 60 | 42 ~ 43 |
Chrome (打开抗锯齿, Instance) | - | - | 56 ~ 60 | 47 ~ 51 | 35 ~ 36 |
Chrome (打开抗锯齿, Instance, 720p) | - | - | - | - | 58 ~ 60 |
- 小游戏不支持抗锯齿,无论设置 antialias 参数为 true 或者 false,结果都是 false,Chrome 默认是打开抗锯齿,需要显式关闭;
- 小游戏目前并不支持 WebGL2,WebGL2 新增的 API 并没有实现;
- 小游戏只能使用屏幕像素大小的渲染分辨率;
- 小游戏在 100 ~ 200 条鱼时帧率反而更低,反复验证过几次均是如此,怀疑踩到了什么坑,应该不是性能瓶颈;
- 小游戏最高帧率不会达到 60,最多就是 58 ~ 59,或许是 requestAnimationFrame 的实现有些问题;
类似雷电的小游戏,多个小位图的重复绘制,主要测试 Canvas.drawImage 的性能,跟微信开发工具自带的样例游戏类似。
可以对 enemiesCount(guimark3.js),改变敌机的数量,从而增加或者减少 drawImage 的调用次数。
运行环境 | ~1000 drawImage | ~2000 | ~4000 |
---|---|---|---|
小游戏 | 58 ~ 59 | 58 ~ 59 | 51 ~ 53 |
Chrome | 60 | 60 | 30 ~ 31 |
在 Chrome 渲染流水线里面,Canvas 元素的更新跟其他 DOM 元素的内容更新一样,都需要走非合成器动画的渲染流水线。而非合成器动画渲染流水线过于复杂和冗长,比较小游戏简单和直接的渲染流水线,会有较多的 Overhead。
不过假设网页的运行条件跟小游戏一样,页面只有一个 Canvas 元素而不存在其他 DOM 元素,这些 Overhead 其实每个环节的耗时都很小,加上 Chrome 多线程高并发的流水线设计,实际上大部分开销都可以忽略不计,对整体性能的影响微乎其微。
WebGL Compute 的测试结果也验证了这一点,该 Demo 只有一个 Draw Call,所以我们基本可以忽略绘制部分的影响,JavaScript 计算的开销也可以认为是基本相同,在小游戏和 Chrome 的性能测试结果基本一致的情况下,我们可以推断出渲染流水线本身不会造成明显的性能差异。
关于 Chrome 非合成器动画的渲染流水线可以参考我的文章 - 浏览器渲染流水线解析与网页动画性能优化。
我们把 JavaScript Computing 定义为除了 Native API(2D Canvas,WebGL,etc…)外的其它纯 JavaScript 代码运行的耗时。
小游戏和 Chrome 都使用 v8 虚拟机运行 JavaScript 代码,理论上 JavaScript 计算的性能不会存在较大差异,些微的差别可能来源自 v8 的版本差异,WebGL Compute 的测试结果也验证了这一点。
Chrome 对比小游戏 WebGL 绘制的差别在于:
在 WebGL Aqua 这个 Demo 中,计算部分的开销很小,大部分是绘制的开销,Chrome 的多线程模型并没有带来多少并发的优势,只是抵消了 CommandBuffer 机制带来的一些 Overhead,不过额外的 Render Target 切换和缓存拷贝的影响看起来也很小,Chrome 和小游戏的性能基本持平,甚至 Chrome 还稍微好一些。如果是计算和绘制开销比较平均的场景,Chrome 可能会有更大的性能优势。
Chrome 对比小游戏 2D Canvas 绘制的差别在于:
因为 Chrome 运行环境中较高的 per drawImage 的开销,我们可以在 Canvas Bitmap 测试中看到当 drawImage 的调用次数非常高时,Chrome 的 Renderer 线程会被严重阻塞而导致帧率下降幅度大大高于小游戏的下降幅度。
WebGL 理论上 Chrome 也会多一些 Overhead,只是 WebGL API 相比 2D Canvas API 的实现要简单很多,所以这些 Oveahead 实际影响非常小,并没有 2D Canvas 那么明显。
如果觉得本文的内容对你有帮助,请麻烦点下赞