前言
- 近期任天堂直面会发布了要重制塞尔达梦见岛的消息,勾起了我想在 GBA 上玩通关梦见岛的兴趣。于是在手机上下载了几款 GBA 模拟器,发现都不太好用(主要是摇杆很反人类)
- 既然 GBA 模拟器这么难用,于是就在 GitHub 上搜有没有开源的,倒是找到了一个名为 gba4ios 的项目,但一看时间已经几年没维护了,估计对 iPhoneX 的分辨率支持也不够好,遂放弃(自我猜测)。
- 在搜的过程中,发现了一款 js 实现的 GBA 模拟器( gbajs ),遂在线试用了一下,发现电脑手机上都没有性能问题,很流畅,于是就萌生了把 GBA 模拟器移植到微信小游戏上的想法。
开始动手
-
由于之前有过小游戏开发经验,也做过 js 游戏引擎相关的开发,还是蛮相信自己能搞定的。下载了代码,作者也没写注释,只能硬着头皮猜,核心部分就是用 js 模拟了 GBA 的 32 位 CPU,GBA 解包等等这些无关语言和环境的东西,只有最后拿到 ImageData 才涉及到渲染层,看上去还挺简单,要改的东西不多。
-
于是自己花了一两个小时,把涉及到 DOM 和 BOM 都改了,渲染全部由小游戏 canvas 接管,解决了一系列 BUG 后,终于能在模拟器上看到画面了。内心很激动,感觉要成了!
-

噩梦开始
-
在模拟器出画面后,用真机调试,发现真机啥画面都没有,于是开始了 debug 之路,非常漫长,由于不知道是平台原因还是小游戏 API 不完善的原因,完全一行一行的 debug,一两个小时后,终于找到原因所在,一个 callback 导致的画面黑屏(为什么 Web 和模拟器都行,就是真机不行,小游戏&小程序的模拟器不靠谱啊)
-
搞定了上一个问题,更是兴奋,感觉离成功不远了,真机上跑了一下,怎么感觉 fps 有点低呢? drawcall 只有 2,但 fps 一直上不了 20,稳定在 12-15 左右,变成了幻灯片。用模拟器看了一下,模拟器能跑满 60fps,于是我就在想,会不会是渲染效率的原因,于是又开始了漫长的 debug。这次先找渲染层,也是一行行代码的测,因为不确定小游戏的引擎有哪些未知 BUG,所以这样来测比较细,也不会遗漏什么。这一测,就是 3 个多小时,还是完全没有头绪,各种方式都试遍了,依然保持 12fps。
-

-
本着不改好 bug 不睡觉的原则,继续刚,终于让我发现了问题所在。在 pc 端和手机浏览器上,能跑满 60fps,但小游戏不行,问题出在模拟 cpu 的核心代码上,用虚拟的 cpu 去运行 GBA 的 rom,pc 和手机浏览器只需要几 ms 的时间就能解析出一帧的画面,而到了小游戏里,则需要 80 多 ms,1000ms/80ms 约等于 12 左右,刚好解释了为什么 fps 在 12 左右波动。完全占据了 90%的性能开销。很奇怪为什么会开销这么大,这部分代码也没用到 polyfill,于是脑瓜更疼了。思来想去,于是想到,会不会是 ios 上小程序的 js 引擎并非系统的 js 引擎,而是自己实现了一套(突然想到了腾讯有自己的 x5 内核,会不会也有自己的"x5js")?带着疑问搜索了一圈,果真搜到了一篇文章,介绍了小程序的 js 引擎,是苹果的 JSC 引擎? WTF ? JSC 不是 Safari 的引擎吗?我明明用 Safari 试过没问题才准备移植的,带着疑问又上路搜关于 JSC 的资料,可算找到一个稍微靠谱的解释。
-
原来在 Safari 里,JSC 是带有 JIT 的,UIWebview 不带 JIT,也没有 Safari 那么好的优化,但具体是哪部分没有优化好,我继续在代码里找。由于小程序开发工具运行流畅,不好 debug,于是只有用真机打 log 看运行时间,又是花费一两个小时时间,终于找到了,原来是 ARM 的 STM 指令耗时,90%的时间都消耗在 STM 上了,由于鄙人能力有限,对计算机底层不太熟悉,到这一步就放弃了
结语
- 白折腾了一个通宵,顿感失落,不知道是自己能力有限,还是平台所限,虽然不是什么正经的大项目,但是自己已经很久没有出于个人兴趣搞一些工作之外的开发了。发出此文的目的除了吐槽自己在开发小游戏过程中的种种不愉快,顺便还想看看有没有大佬能够优化这些问题。