我正在对一个已有的引擎进行命中检测的优化,想寻找一些新思路。目标平台是 GBA,也就是运行大多数 16 位代码的 32 位 ARMv7 处理器,内部 RAM 使用 32 位数据总线,ROM 和外部 RAM 使用 16 位总线。
起初,我打算先从基础入手——清理代码、删减不必要的指令、确保流水线组织良好、限制条件分支,必要时重新编写一些算术运算。如果只做这些,我发现收效甚微。虽然我还没有完全弄清这个程序的全部细节,但似乎面临两个截然不同的挑战。
地形碰撞检测的瓶颈在于它大量依赖于对从 ROM 中取出的采样正弦波进行乘法运算。它通过获取该波形的偏移值、与对象坐标相乘,然后右移来计算分数值。几个显著特点是:仅使用对象坐标,不涉及碰撞箱数据,并且引用了一个粗糙的可碰撞地形瓦片地图。我猜程序在计算对象与碰撞地图之间的瓦片间距,因为在这款游戏中地形碰撞相当细腻。
有没有什么通用技巧可以用来优化这种乘法密集的流程?是否有办法在不完全重新绘制所有碰撞地图的前提下改进?或许可以实现一个仅供子弹使用的更粗糙、乘法更少的碰撞例程?甚至可以根据对象数量,在达到某个阈值后才使用该例程。
碰撞箱检测例程相对直接,但似乎主要受限于大量的内存访问和条件分支。我认为主要问题在于所有对象数据都存放在外部 RAM,而外部 RAM 只有 16 位总线,导致程序不断读取 32 位值后再把它们右移成 16 位放入不同寄存器。在这种情况下,单独读取每个半字(halfword)会不会更快?切换到 32 位模式处理这些数据能带来多少性能提升?
看起来大多数操作本可以合并为复合指令,只是我需要学习如何构造完整宽度的 ARM 指令(是的,我知道手册存在并会去使用)。把整个例程加载到 IWRAM(32 位总线)并保留在那里也很有意义,因为它在每帧会被每个屏幕上的对象多次调用。但如果瓶颈主要来自内存访问的等待状态,这真的能帮助多少?从 IWRAM 取指比从 ROM 快,应该能减轻因条件分支导致的流水线中断带来的等待。我还看到另一个潜在好处:可以使用 LDMIA 将数据直接装入高位寄存器并立即进行运算,从而消除一些指令。但同样受限于 16 位数据总线!也许只在 IWRAM 中使用 Thumb 代码并进行半字加载就能达到同样的效果。
总之,对那些完全看不懂的朋友——无论是新手还是老手——表示抱歉。把这些写下来其实很有帮助,我感觉已经有了一个初步的方案。希望能得到一些想法或见解,帮助我确定方向,因为我们都知道如果以后需要大幅改动指针结构,将会是非常艰巨的任务。
评论 (0)