Continuation 实验室的高级软件工程师Gabriel Cuvillier使用WebAssembly将标志性的《毁灭战士 3》游戏移植到了浏览器上。为期 7 周的全职投入,展示了当前 WebAssembly 在无缝运行重量级桌面应用程序和游戏方面的性能潜力和缺失的部分。InfoQ 就使用 WebAssembly 移植桌面应用程序所面临的技术挑战及需要吸取的经验教训等问题,采访了 Cuvillier。
《毁灭战士 3》是一款恐怖的第一人称射击游戏,最初于 2004 年在微软的Windows系统上发行。《毁灭战士 3》使用了id Tech 4游戏引擎,该引擎是于 2011 年根据GNU通用公共许可证协议发布的。这款游戏获得了巨大的商业成功,销量超过了 350 万份。
InfoQ:是什么驱使您使用 WebAssembly 将《毁灭战士 3》移植到浏览器上的呢?
Gabriel Cuvillier:自从两年前 WebAssembly MVP 在主流浏览器上广泛使用以来,我感觉围绕这项技术的热炒周期已经开始了:人们对它赞不绝口,到处都在做相关的精彩演示和演讲等等。但是,实际上,除了一些小型的还不错的基准测试和示例演示之外,很少有公开研究和展示的真实用例。
因此,为了让我自己相信 WebAssembly 能够实现它的承诺,我决定移植一个真正的程序,将它推进到下一个阶段。
我发现《毁灭战士 3》游戏是做这件事的一个理想选择:它是一个真实的大型 C++程序,以前成功的 AAA 级游戏,代码开源(质量非常好得到了公认),并且早在 2004 年游戏发行的时候,它还是真正的前沿技术,众所周知,那时游戏引擎和图形的热度远超桌面系统。
此外,这款游戏还有一个非常好的特点,这也是我决定专注于这款游戏的关键:id Tech 4 引擎可能是可以在单执行线程中运行的最先进的游戏引擎之一。或者,换句话说,虽然现在大多数引擎都是为多 CPU 核心系统而设计的,但《毁灭战士 3》是最后一款设计成在单 CPU 核心系统上运行的“高端”游戏。由于 Web 上还没有多线程(主要是因为 Spectre/Meltdown 安全漏洞),从我项目的开始阶段,这个单线程特性就是一个强制性的要求。
因此,到 2018 年底,我决定将《毁灭战士 3》移植到 Web 上,并最终说服自己,WebAssembly 是未来 10 年需要认真考虑的一项技术。
InfoQ:您提到《毁灭战士 3》是一款在浏览器中运行要求很高的游戏。为什么会这样呢?有哪些性能驱动程序,是在本地桌面操作系统中存在,而现在在桌面浏览器中缺失的呢?
Cuvillier:《毁灭战士 3》在浏览器中是一款要求很高的游戏,那是因为 (1) 它本身就是一款要求很高的游戏,(2) 它在浏览器中运行时还必须带着一些附加的约束,而这些约束在本机版本中不需要。
关于(1) ,正如我在前面的回答中所说,它本身是一款要求很高的游戏,是因为它提供了良好的图像质量水平,同时运行在单个执行线程上。这意味着,在试图保持每帧 16 毫秒的情况下,需要按顺序计算的量是非常庞大的:具有动态逐像素照明和实时阴影的统一照明模型、骨骼动画、刚体物理、人工智能、网络等等。
在这种情况下,关于(2) ,第一个约束是 WebAssembly 首先是一个低级虚拟机,因此最终需要使用专用程序解释字节码。这与执行自己本机指令集的通用 CPU 性能不匹配!如果没有即时编译器,由于这个原因将至少损失 2 倍的性能(当然,这是我根据个人的观察得出的一个经验数据。不排除可能有一些关于这个问题的更准确的学术研究)。
第二个约束比较难理解;在 Web 环境中,以 WebAssembly 的角度来看,“外部世界”中发生的一切或多或少都与 JavaScript 有关,并且最终与浏览器及其安全沙箱有关。这里“外部世界”包括图形和音频 API。因此,当 Wasm 代码调用图形 API 时,它不会像在本机版本中那样直接调用图形显卡驱动程序。相反,每次调用正确的“Web API”时,都会使用到一个小的 JavaScript 层,然后浏览器在完成一系列检查和验证之后,将 Web API 调用转换成对图形驱动程序的调用。逃离“安全沙箱”是有代价的。
所有这些最终都带来了很大的开销。因此,如果你的程序对 CPU 和“外部世界”都有很大的压力(例如,在每帧中都执行很多图形 API 调用),那么你最终将面临要求苛刻的情景。
InfoQ:是否还有其他的桌面游戏已经通过 WebAssembly 移植到浏览器上了呢?性能方面是否与《毁灭战士 3》类似?
Cuvillier:据我所知,到 2019 年为止,还没有其他商业游戏像《毁灭战士 3》那样,移植到 Web 上需要如此高的要求。有一些不错的技术示例,但还没有完整的AAA级游戏。请注意,我可能说得不对,毕竟我没有在网上做全面的检索!但是无耻的插头是另一个很好的游戏移植实验,是一个我之前轻松地移植到 WebAssembly 上的完整商业视频游戏:《地城英雄志》。它是一个 2002 年的电子游戏,比《毁灭战士 3》要丑一些,不过也很有趣。可以在这里测试示例。
这个移植背后的故事可以追溯到我之前使用一种称为 PNaCl (Portable Native Client)的技术来运行本机应用程序的早期实验,该技术或多或少是 WebAssembly 的先驱之一。它运行得很好,但是在谷歌决定放弃该技术来支持 WebAssembly 之后,我决定将移植迁移到使用 WebAssembly 上来,这也是学习新技术的一种方式。
InfoQ:集成在所有现代浏览器的 WebAssembly 未来将有很多特性:SIMD支持、动态链接、64位寻址、OffscreenCanvas ,您会选哪个?
Cuvillier:现在对我来说,WebAssembly 最重要的事情不在该列表中。
它是可以挂起/恢复 WebAssembly 运行时的能力。
原因很难在简短的采访中解释清楚,但基本上我们已经将所有典型的同步的 C/C++代码都嵌入到了一个完全异步的环境中。而 WebAssembly 却常常不能很好地兼容;一些通常很简单的事情现在很难实现,比如同步 I/O 操作。
例如,我们必须认识到“从持久存储中同步读取大文件”(例如,从磁盘中读取游戏资产)在 Web 上已经是不可能的了。自编程诞生之时,这件非常简单的事情就被认为是理所当然的,但现在却不再是那么回事了!说实话,这真让人伤心。
好吧,我们确实有一些方法可以解决这个问题,但所有这些方法都是要付出代价的:要么我们人为地“屏蔽所有东西”(包括浏览器选项卡),这在 Web 上不是一个很好的实践;要么我们依靠昂贵的解决方法,如将所有文件系统、资产存储在 RAM 中(考虑到我们持久存储解决方案的规模,这是一种浪费),或者使用特定的编译器标志,但这些标志对代码有非常严苛的要求,并且对编译后的二进制文件有影响。
当然,将同步代码重写为异步代码是最好的解决方案,但是对于像《毁灭战士 3》这样的大型代码库,根本不可能在合理的时限内实现。
因此,允许挂起/恢复 WebAssembly 运行时,可以重新引入一些自 25 年前以来我们所使用的同步 I/O 范例(至少从 C/C++代码的角度来看是“同步”的)。
希望Emscripten项目的开发人员已经研究了各种编译器端的解决方案来解决这个问题,这些解决方案的名称都很有趣,比如“Asyncify”和“Emterpreter”。我在《毁灭战士 3》的移植中使用了它们来简化移植过程。下一个迭代可能会被称为“Bysyncify”,我已经等不及想要试用它了。
好吧,如果真要我从你的列表中选择一项,我会选择 Offscreen Canvas。虽然它与 WebAssembly 无关,但它更多与尚未全部实现该特性的浏览器实现(特别是 Safari)相关。但事实是,这种“选择”与前一点有关:Offscreen Canvas 允许图形应用程序的主 WebAssembly 代码在 Web Worker 中运行,而在 Web Worker 中,同步/异步问题的相关性要小得多。
InfoQ:您花了 6 到 7 周的时间全职投入该移植工作,并将任务描述为相当复杂。在您看来,开发人员应该开始时就尝试将主要应用程序移植到浏览器上呢,还是等到技术成熟后再移植呢,哪种选择比较明智呢?
Cuvillier:我发现这项技术本身已经非常成熟了,我对它印象深刻。当然,如果有人需要在 Web 上运行 CPU 密集型的应用程序,那么完全没有理由不使用 WebAssembly 来开发它。比如,它可以是电子游戏、CAD 软件或大数据。我目前正在做一个长期的项目来说明在 3D CAD 软件中如何使用 WebAssembly,最近我在一个即将推出的产品上做了一些合约工作,工作内容和上面提到的例子相关。虽然目前我无法透露更多细节,但可以肯定的是,2020 年将会有一系列与 Wasm 相关的惊喜。
此外,WebAssembly 生态系统(无论是编译器、Wasm 运行时还是编译环境)的工作人员在各自的领域都非常专业熟练。我们完全可以期望将来会有一个非常好的软件平台。
不过,请注意:在 Web 中使用 WebAssembly 有一个学习曲线很陡的技术栈,它边缘粗糙,并且它的目标在快速变化。最后一点可以解释为什么目前仍然很难有一本关于这个平台的最新的深入的书籍。实际上,可以做很多事情,但必须有足够的资金、时间、知识资源。但对于那些已经准备好为此付出精力的人来说,他们肯定不会失望!
原文链接:
Iconic Doom3 Game Now in Browsers With WebAssembly: Q&A With Gabriel Cuvillier
评论 1 条评论