不可能移植的故事:Quake 如何移植到 Game Boy Advance

Game Boy Advance 是由任天堂开发的掌上游戏机。它于 2001 年在日本发行,是 Game Boy Color 的继任者。它有一个主频为 16.78 MHz 的 ARM7TDMI、32kb 的内部工作 RAM、256kb 的外部 RAM 和 96kb 的 VRAM。它不是最强大的机器,但有很多掌机游戏让许多人记忆犹新。一款从未出现在该设备上的游戏是 Quake 的原型端口,该游戏由 id Software 开发,帮助定义了我们今天所知的第一人称射击游戏类型。

Quake 是一款非常详细的游戏,拥有美妙的配乐和令人上瘾的游戏玩法,就像《DOOM》一样,它已被移植到几乎所有你能想到的设备上。它对 Game Boy Advance 的移植特别令人难以置信,因为它本身并不支持 3D 图形,而且任天堂专门将这款掌机推销为一种二维游戏体验。不过,这并没有阻止 Randy Linden 开发自己的端口。

Quake-on-the-Game-Boy-Advance-Analogue-Pocket-2-1024x576-1

在获得 Modern Vintage Gamer 许可的情况下使用的模拟口袋上播放 Quake 端口的照片

如果您对 Linden 不熟悉,他最出名的就是这两个 bleem 的开发者!(PlayStation 模拟器)和 DOOM 的 SNES 端口,id Software 的联合创始人约翰·罗梅罗(John Romero)曾在接受Shacknews采访时表示,他认为这是不可能的。Linden 的开发能力证明,如果有人能够让 Quake on the Game Boy Advance 成为现实,那很可能就是他。

由于林登自己通过幻觉森林项目发布了这个端口,所以这个端口已经曝光。Forest of Illusion 是一个旨在保存任天堂游戏历史的项目,Linden 伸出手来分发他在他拥有的 256MB 闪存卡上找到的 Quake 端口的副本。

我们要感谢 Randy Linden 抽出时间来回答我们的问题并确保本文的技术准确性。我们还要感谢Modern Vintage Gamer允许我们使用他视频中需要的任何剧照。该移植与 id Software 或 ZeniMax 没有官方关系,由 Linden 作为单独项目开发。

Quake 的 Game Boy Advance 端口

从技术上讲,Quake 甚至可以达到它在 Game Boy Advance 上的水平,这是一个奇迹。它以良好的帧速率运行,并保持原始 Quake 游戏的正确照明和调色板。一切都是 3D 的,包括武器和怪物。Game Boy Advance 上的游戏通常通过精灵实现 3D 图形,但这是真正的交易。它不像其他 3D 游戏在手持设备上那样使用光线投射,它甚至通过调色板改变技巧在预渲染对象上实现点照明效果,以实现动态照明的错觉。

需要明确的是,这个移植不是完整的游戏,它是 Linden 打算在完成发布后将其带到 id Software 的原型。然而,Game Boy Advance 的受欢迎程度开始下降,取而代之的是,Linden 编写的自定义引擎后来完全成为了 Linden 开发的另一款游戏的引擎——Cyboid。Linden 告诉我们,“大部分代码”仍然是来自 Game Boy Advance 版本的原始 ARM 代码。如果您想尝试 Cyboid,可以在 Google Play Store 上找到旧版本,但由于该游戏有很多低级 32 位代码,因此官方 APK 现在已在Amazon App Store上分发。

Linden 还与我们分享了他在 iPod Video 上运行的代码的视频,该视频是 Cyboid 的最早版本之一。它建立在用于将 Quake 移植到 Game Boy Advance 的相同引擎代码上。

Quake 的 Game Boy Advance 端口不包含任何游戏的官方资产,因为 Linden 没有联系 id Software 或 ZeniMax 关于分发包含官方 Quake 资产的 E1M1 版本。

目前正在分发的游戏也是一个调试版本。启动时按住 R 键将直接将玩家带到游戏的第二张地图,按住 D-pad 上的左键会将他们带到第三张地图。玩家死亡时也可以进行地图交换,怪物不会攻击玩家,直到玩家先向他们开枪。

至于音乐,演示使用公共 .S3M 文件,混音器处理立体声音乐和音效。

技术边界

当谈到 Game Boy Advance 时,存在许多界限,这使得它成为一个困难的端口。一些最大的障碍是低时钟速度、缺乏手持设备的 3D 图形功能以及缺乏浮点单元 (FPU)。在此过程中还有很多其他问题,但这些都是 Linden 向我概述的特别痛点,它们是有问题的。在我们开始之前,了解 Game Boy Advance 的布局很重要。

Game-Boy-Advance-Layout-1024x576-1

经 Modern Vintage Gamer 许可使用的屏幕截图

Game Boy Advance 具有三组 RAM — 一组是内部工作 RAM (IWRAM),另一组是外部工作 RAM (EWRAM),第三组是视频 RAM (VRAM)。32kb 的 IWRAM 用于存储 ARM 指令以便快速执行,而 256kb 的 EWRAM 最适合存储 Thumb-only 指令和更小的数据块。正如Rodrigo Copetti 所指出的,EWRAM 的访问速度可能比 IWRAM 慢六倍。尽管 Game Boy Advance 作为 32 位手持设备销售,但 EWRAM 形式的大部分内存只能通过 16 位总线访问。IWRAM 可以通过 32 位总线访问。Game Boy Advance 上的 VRAM 为 96kb,虽然它主要用于存储图形数据,但它位于 CPU 的内存映射中,也可以用作普通内存存储。

Thumb 指令是 32 位 ARM 指令的子集,是一组编码为 16 位字的指令。它们具有 32 位指令的所有优点,而不会占用太多空间,从而使它们能够高效地进行优化开发。这意味着虽然 EWRAM 访问速度较慢,但​​高效的 Thumb 指令通常仍然可以与存储在 IWRAM 中的 ARM 指令一样快,尽管 Thumb 指令的缺点是有时没有与 ARM 指令完全等效的 Thumb你想执行。EWRAM 用于存储 3D 数学转换逻辑的输出,该逻辑基本上是多边形 Edge的列表,然后由光栅化代码逐个扫描线地追踪。

正如 Linden 告诉我的,整个端口中最复杂和困难的部分是扫描线渲染器。它由超过 10,000 行高度优化的 ARM 汇编代码组成,旨在将一组像素绘制到 VRAM。扫描线渲染器使用了大部分 32kb I​​WRAM。最靠近相机的 Edge处于活动状态并被渲染,它本质上是一个大型二进制空间分区 (BSP) 树。VRAM 用于将多边形变换输出的结果存储到 Edge表中,因为没有足够的 IWRAM,但 Game Boy Advance 上的 VRAM 仍然比 EWRAM 快。图形也在这里存储和显示。

他花了很多时间专注于优化,以确保它能够获得尽可能快的执行时间。他为加快执行时间所做的三件事包括:

  • 在执行之前自行修改代码,因此需要的指令更少
  • 使用一系列查找表来查找倒数、正弦、余弦、正切等内容。
  • 切换 CPU“模式”以访问其他寄存器(类似于“变量”),而无需保存和恢复寄存器的值。

切换 CPU 模式以获得额外的寄存器是一个非常聪明的操作,它允许快速访问靠近 CPU 的值,以便可以在单个时钟周期内检索它们。正如 Linden 告诉我的那样,可以在一个时钟周期内切换寄存器并检索一个值,而不是在 Game Boy Advance 的 RAM 中存储一个值,这需要更长的时间。CPU 本身是一个 16.78 MHz 的处理器,这意味着它每秒可以完成 16780000 个周期。这听起来很多,但是当您需要计算和绘制屏幕上的每个像素时,这些很快就会加起来,因此尽可能多地减少操作变得很重要。

Registers-of-the-ARM7TDMI-1-1024x986-1

以上是 Game Boy Advance 中 ARM7TDMI 芯片组的通用寄存器列表。通常,开发人员只会在“系统和用户”模式下访问寄存器,并在此之外使用普通变量。但是,他在芯片组的所有七种模式中都使用了寄存器,最好的一点是切换模式仍然保留其他模式的寄存器中的值,因此他可以在它们之间切换。

有趣的是,Linden 还提到了他的银行切换方法如何在 Nanoboy Advance 模拟器中发现了一个错误。事实证明,该模拟器不支持使用 CPU 的其他模式来保存寄存器和切换,他的 Quake 演示是第一个真正做到这一点的已知游戏。

Linden 与我们分享了一张他创建的一些笔记的照片,并解释了他如何在没有合适的 FPU 的情况下优化他的浮点计算。

Randy-Linden-Quake-Port-Notes-768x1024-1

上图是 Linden 在笔记中与我们分享的一张,其中特别有趣的是“杂项 ARM 循环指令计数”。他设计了一种优化计算周期的方法,这样他就可以减少计算的时​​钟周期数。正如他向我描述的那样,一个时钟周期可以乘以一个 8 位数,两个时钟周期可以乘一个 16 位数,三个时钟周期可以乘一个 32 位数,四个时钟周期可以乘一个 64 位数.

“[在 ARM 处理器中] 有两个或三个执行阶段。例如,我将寄存器 1 乘以寄存器 2,然后将结果放入寄存器 3。如果我知道寄存器 2 是一个 16 位数字,而不是说寄存器 1 乘寄存器 2,我会翻转它,我会说寄存器 2 乘寄存器 1,因为这样可以节省一个时钟周期。”

他告诉我,他这样做的原因是为了从 Game Boy Advance 中榨取每一点性能,因为当执行大量计算时,在这里和那里节省的时钟周期确实加起来了。至于自修改代码,我请Linden解释一下。

“程序来自 [storage],它将程序的一大块传输到内部 RAM 中执行,因为它更快。每个 RAM 访问都要慢得多,所以我对一个大块从 ROM 到 RAM 进行 DMA [直接内存访问],然后我更改实际的程序代码。例如,ARM 具有向左或向右移动操作数的能力,或者它可以屏蔽某些位作为指令集的一部分。该指令指定您要屏蔽哪些位或要移动多少位。因此,我将生成代码,这些代码将根据我需要移动多少位来修改即将执行的内容。另一个例子是关于 3D 矩阵乘法。那里涉及到一大堆乘法。

自修改代码有其自身的缺点,尤其是在调试方面。它也消除了对分支指令的需求,其中代码将跳转到另一个执行序列,并且可以剥夺主线程宝贵的计算时间。Linden 还告诉我们,查找表在 ROM 中完全对齐,因此它们是左移 8 位值的完美倍数。查找表的大小是巨大的并且不适合 RAM,并且对齐也避免了需要额外的加载指令来获取表的基地址。

总而言之,最终的原型是在将近两年的时间里开发出来的。

Randy Linden 的 Quake 港口的未来

我问林登 Quake 端口的未来会发生什么,他告诉我他正在考虑向 ZeniMax 和 id Software 询问发布带有官方 Quake 资产的版本。他还告诉我,他会在某个时候发布源代码,但目前它还没有构建,因为它需要一台较旧的计算机。

Game-Boy-Advance-Setup-Randy-Linden-768x1024-1

Randy Linden 将 Game Boy Advance 连接到计算机进行开发的设置。

我问林登他为什么选择雷神之锤,他告诉我他喜欢这个游戏,他喜欢这个“不可能的项目”所带来的挑战,因为它在他的《DOOM》的 SNES 端口背后。他还提到,尽管由于空间限制,他不相信整个游戏都可以移植,但绝大多数游戏都可以使用同一个引擎。

原创文章,作者:校长,如若转载,请注明出处:https://www.yundongfang.com/Yun172893.html

(0)
打赏 微信扫一扫不于多少! 微信扫一扫不于多少! 支付宝扫一扫礼轻情意重 支付宝扫一扫礼轻情意重
上一篇 2022年6月17日
下一篇 2022年6月17日