Cruis'n USA DC: progress report
For a few weeks now I've been working on this Dreamcast port of the original arcade version of Cruis'n USA. As I mentioned before, this is not the N64 game, at all: it's the real arcade's graphics, sound, cars and tracks running natively on the DC. It's still a work in progress, but it already boots, plays full races and has been tested on real hardware through GDemu.
The arcade runs on Midway's V-Unit board, built around a TMS320C31 DSP and a custom polygon chip, so there's no ready-made path to the Dreamcast. The source code for the game was made public and I used it as a map, but rather than rewriting the game, the C31 machine code was first translated into C, which was then compiled for the Dreamcast's SH-4 with KallistiOS. The hottest routines (vertex transforms, polygon submission, object scanning) are rewritten by hand as native code. The V-Unit's polygon packets are converted on the fly into PowerVR polygons, and the DCS sound is pre-rendered into samples that play on the AICA. Everything is checked against a reference interpreter and against MAME, frame by frame where needed.
So yes, this was all a pain in the ass and turned out to be much more time-consuming than I initially thought, despite the source code being available, because the hardware used on the original arcade and the one inside our favourite white box are vastly different.
Some of the problems found along the way, and how they were solved:
- Floating point: the C31 uses its own float format. Every value has to be converted to and from IEEE, thousands of times per frame. A bit-exact fast path, verified against all 4 billion possible values, gave a 6.6% speed-up on its own.
- Memory: the translated code is several MB and the DC only has 16 MB of RAM. Most of it is compiled for size, with only the hot paths optimized for speed.
- Timing: the game counts vertical blanks to move everything, and some animations advance once per game loop. The port follows a clock driven by the emulated C31 cycles, falling back to real time when the DC can't keep up, so menus run at the arcade's pace and races stay at the right speed.
- Collisions: an addressing subtlety in the C31's parallel instructions scrambled every collision box. Cars hit you without touching and fences were ignored. Collision rates now match MAME. This is still the port's main weak point, though.
- Real PowerVR vs emulators: issues that Flycast and Redream don't show (stray lines on distant cars, polygon list overflows) were tracked down with diagnostic builds on real consoles. Still needs fixes, though.
- Textures: the arcade's 8-bit paletted texture pages are converted to ARGB1555 and cached in VRAM, with large textures stored at half resolution to fit.
On the other hand, some extras for this port are:
- No RAM/ROM check or Midway/Nintendo weird-looking loading screen: new, cleaner, faster custom loading screen with the game's logo.
- VMU saves and logo, Jump Pack support.
- A fade-in for objects popping up on the horizon. The original was far from perfect in the drawing distance / popping department, so this is me trying to hide or partially solve that.
- And all the arcade's hidden cars and tracks, unlockable from their menus with the X button.
Current status: races run mostly at 28.5 fps, the same rate as the arcade, with drops to 19 fps in the busiest scenes. The attract demo is still heavier, and performance work continues. Feedback from people testing on real hardware has been invaluable so far, so comments and testing reports are very welcome.
More news soon!