Skip to content
antoxa2584xPublic

About

Need For Speed Underground Xbox Original port for Nintendo Switch

Resources

Stars

57 stars

Watchers

4 watching

Forks

Latest commit

 

History

14 Commits

Folders and files

Repository files navigation

Need for Speed: Underground

Xbox static recompilation for Nintendo Switch and Linux

The original Xbox (NTSC-U) release of Need for Speed: Underground, lifted instruction by instruction to C and running natively, with no emulator.

Switch Linux Vulkan OpenGL Version

Features · Playing on Switch · Building · Configuration · Status


Important

No game data is included. You need your own copy of the Xbox disc, extracted (default.xbe, FRONTEND/, CARS/, ...).

✨ Features

  • 🏁 Native code: the whole game runs as recompiled C, built with xboxrecomp
  • 🎮 Two renderers: Vulkan (NVK on Switch, recommended) and OpenGL, with render scaling up to 4x
  • ⚡ 30 fps races on Switch (the game's own cap) with the Vulkan build and raised clocks
  • 🪞 Car reflections as cube maps (Vulkan), switchable in Options → Camera → Car Reflections; Off also skips the reflection cube-face passes in races
  • 🖼️ Cleaner picture (Vulkan): mipmaps with trilinear and 16x anisotropic filtering, FXAA, square-pixel 1280x720 for the 16:9 view
  • ⚙️ Graphics options in the game (Vulkan), under Options → Camera: Resolution Scale (1x, 1.5x, 2x, 2.5x), Anti-Aliasing, Anisotropic (Off-16x) and Square Pixels, applied at once and kept in nfsu1x_options.txt
  • 🎬 Movies played by the game's own EA .mad decoder
  • 🔊 Audio through an emulated Xbox APU, with 5.1 downmixed to stereo
  • 📳 Rumble on Switch HD rumble and SDL controllers
  • ⏱️ CPU/GPU/memory clocks settable per mode (handheld and docked), kept across dock changes, HOME and sleep
  • Shares its runtime with the Underground 2 port

🕹️ Playing on Switch

  1. Copy the NRO to sdmc:/switch/nfsu1x/ (nfsu1x-vulkan.nro for the Vulkan build, nfsu1x.nro for OpenGL).
  2. Copy the extracted disc (not the ISO) to sdmc:/switch/nfsu1x/game/.
  3. Start it with title takeover: hold R while launching any game. Applet mode leaves too little memory.
sdmc:/switch/nfsu1x/
├── nfsu1x-vulkan.nro
├── nfsu1x_env.txt      optional settings, KEY=VALUE per line
├── nfsu1x_options.txt  written by the in-game options the port adds
├── save/               created on first run
└── game/
    ├── default.xbe
    └── ...

Buttons map by label (Switch A = Xbox A). Settings go in nfsu1x_env.txt (see Configuration) and the log is written to the same folder.

Recommended nfsu1x_env.txt:

RECOMP_GIL_EAGER=1
RECOMP_CULL=0
RECOMP_GL_SCALE=1.5
NFSU2_CPU_MHZ=1785
NFSU2_GPU_MHZ=768

🛠️ Building

1. Extract the disc and lift the XBE to C
python3 -m tools.xiso unpack "Need for Speed - Underground (USA).iso" /path/to/game   # from xboxrecomp/
# Writes NFSU1_GEN_DIR (default /root/nfsu1x/gen)
NFSU1_XBE=/path/to/game/default.xbe NFSU1_GEN_DIR=/path/to/gen tools/regen.sh
2a. Linux (SDL2 + OpenGL or Vulkan)
cmake -S . -B build -G Ninja -DNFSU2_GEN_DIR=/path/to/gen   # add -DNFSU2_VULKAN=ON for Vulkan
cmake --build build
NFSU2_GAME_DIR=/path/to/game build/nfsu2_recomp
2b. Nintendo Switch (devkitA64, switch-sdl2, switch-mesa)
NFSU2_GEN_DIR=/path/to/gen NFSU2_GAME_SRC=/path/to/game switch/build.sh
# Vulkan build (needs mesa-switch NVK and glslang for Switch)
VULKAN=1 JOBS=6 NFSU2_GEN_DIR=/path/to/gen switch/build.sh

CMake options and most runtime switches keep their NFSU2_* names: the glue code is shared with the Underground 2 port.

Project layout

Path What
src/main.c boot and runtime defaults
src/recomp_manual.c hand-written overrides of lifted functions (D3D, DirectSound, CRT)
src/switch_nx.c Switch log device, env file, clocks, profiler, loading screen
config/seed_functions.json entry points the static pass cannot see
xboxrecomp/ the toolkit (MIT), vendored with this port's changes: NV2A renderers (Vulkan, OpenGL), SDL audio, Switch platform layer, translator fixes
tools/regen.sh XBE → lifted C (gen/, never committed)
tools/prof_report.py Switch profiler (prof.bin) → per-thread function tables
switch/build.sh Switch NRO build + SD-card staging

⚙️ Configuration

On Linux these are ordinary environment variables. On the Switch they go in sdmc:/switch/nfsu1x/nfsu1x_env.txt, one KEY=VALUE per line (# starts a comment). The Underground 2 README lists every runtime switch; the ones that matter here:

Performance and clocks (Switch)
Variable Meaning
NFSU2_CPU_MHZ, NFSU2_GPU_MHZ, NFSU2_MEM_MHZ Clocks (closest listed rate, capped at 1785 / 921.6 / 1600 MHz). The CPU is what limits the port. Old rates come back on exit.
NFSU2_CPU_MHZ_DOCKED, NFSU2_GPU_MHZ_DOCKED, NFSU2_MEM_MHZ_DOCKED Different rates while docked (otherwise the plain keys apply in both modes).
RECOMP_GIL_EAGER=1 Hand the guest lock over by guest priority (the main thread pre-empts workers).
RECOMP_CULL=0 No off-screen batch culling (in NFSU1 it costs more than it saves).
RECOMP_VK_INSTANCE=0 Vulkan: don't merge repeated draws into instanced draws.
RECOMP_GL_THREAD=1 OpenGL: GL calls on their own thread.
RECOMP_NX_PROFILE Sampling profiler into prof.bin: 1 = busy threads, 2 = every thread above 2%.
NFSU2_NO_LOG=1 No log file, no [perf] reports, no profiler.
Graphics
Variable Meaning
RECOMP_GL_SCALE Render resolution multiple, 0.5..4 (fractions allowed). Vulkan: only until Options → Camera → Resolution Scale is changed (default there 1.5x).
RECOMP_GL_SCALE_X Vulkan: horizontal multiple, if different; overrides Square Pixels.
RECOMP_VK_MIPS=0 Vulkan: no mipmaps (distant textures shimmer, the old look).
RECOMP_VK_ANISO Vulkan: anisotropic filtering, 1..16 (default 16; 1 = off).
RECOMP_VK_LOD_BIAS Vulkan: mip bias, negative = sharper (default -0.25).
RECOMP_VK_FXAA=0 Vulkan: no FXAA (plain scaled blit to the screen).
RECOMP_VK_CUBE=0 Vulkan: no cube maps (car reflections off), whatever Options → Camera says.
RECOMP_GL_DXT=0 Decode DXT textures on the CPU instead of uploading them compressed.
RECOMP_GL_TEX_MB Texture cache budget in MB.
RECOMP_PROG_CACHE Shader/pipeline cache file (progcache.bin), =0 off.
RECOMP_GL_DUMP=<prefix>[,every] Write presented frames as BMP.
RECOMP_FPS_LOG=1 Presented frames per 10 s.
RECOMP_DRAW_STATS=1 Vulkan: draws → draw calls per frame.
Game, audio and input
Variable Meaning
NFSU2_GAME_DIR Extracted disc (Linux; default ./game). The Switch always uses sdmc:/switch/nfsu1x/game/.
NFSU2_GL=0 Use the executor's CPU renderer instead of the GPU renderer.
NFSU2_FPS_CAP=30 Keep the game's 30 fps cap (default: uncapped, up to 60 fps).
RECOMP_AUDIO_VOLUME Master volume 0..100 (default 50).
RECOMP_AUDIO=0 No host audio device.
RECOMP_PAD_SCRIPT Timed presses, e.g. 4000:start:300,9000:a:200 (ms from the first pad read).
RECOMP_PAD_LAYOUT=position Map buttons by position (Xbox layout) instead of by label.
RECOMP_RUMBLE=0 No rumble.
NFSU1_AUTOLOAD=1 At boot, load the most recent saved profile straight away (no "load?" questions) when there is one.

🚦 Status

Platform State
🐧 Linux Movies, title, menus, Quick Race at 30 fps with HUD, AI and audio
🎮 Switch hardware Menus and Quick Race at 30 fps (Vulkan, CPU 1785 MHz)

Still open: the main-menu car's rear window shows through its side windows; cube maps on OpenGL; Career mode untested.

📚 More

  • CLAUDE.md: detailed engineering notes (address map against Underground 2, fixes, performance measurements)
Need for Speed and Underground are trademarks of Electronic Arts. This is an unofficial fan project, not affiliated with or endorsed by EA or Microsoft.

About

Need For Speed Underground Xbox Original port for Nintendo Switch

Resources

Stars

57 stars

Watchers

4 watching

Forks

Releases

Packages

Contributors

Languages