一個 frame 的預算
GBA CPU 約 16.78 MHz,螢幕接近 59.73 Hz,一個 frame 約有 280,896 CPU cycles。這個數字包含遊戲邏輯、背景準備、Sprite cache、render、 audio update、input 與 VBlank commit,不只是「畫 sprite」。
Fixed timestep
邏輯累加器以 wall-clock VBlank 推進。Normal speed 保留來源節奏; 如果上一輪工作跨過 VBlank,主迴圈會消耗已發生的 IRQ,執行必要的 catch-up logic,而不是再次睡到下一個 VBlank。這避免「一次超時, 額外再停一幀」的連鎖遲滯。
Presentation defer
場景趕不及時,當前完整畫面可以再呈現一次;新 OAM、tile row 與 page flip 等到真正的 VBlank 再 commit。邏輯位置、敵人生命、武器 cooldown、 Maxmod 更新與背景 source position 不因重複畫面而停住。
先優化,再允許 drop
Drop frame 是安全網,不是第一個答案。專案仍針對實測 hot path 使用:
- Game Pak prefetch 與 3/1 waitstate;
- IWRAM/ARM code 放置;
- active bitmask 跳過無效碰撞候選;
- Sprite2 raw catalog、EWRAM L2 與 VRAM upload queue;
- 背景 row prefetch 與 bounded cache work;
- 移除 hot loop 的軟體除法與不必要的 memory write。
Branchless 並不自動更快。ARM7TDMI 沒有現代 branch predictor, 但額外乘法、全部路徑的 memory access 也可能比簡單短路分支昂貴; 每個改動都以 cycle counter 與完整 route golden 驗證。
把漏幀分到真正狀態
總 missed VBlank 會分成 gameplay、stats、game-over、frontend transition 與其他 frontend。這能分辨「Boss 計算真的重」和「選單誤做 runtime SHP 解碼」。v89 正式版使用 LOW/Normal;完整第一關 gameplay gate 為 2%,較密集的 Episode 2 stock route 為 2.5%,而 frontend、stats、 game-over 與 transition deterministic misses 仍必須為 0。