BlackKnightRecomp

BlackKnightRecomp is a native Windows PC port of Sonic and the Black Knight for Wii that allows playing with a controller and higher resolutions.

README

BlackKnightRecomp

A static recompilation of Sonic and the Black Knight (Wii) to native Windows x64, in the spirit of UnleashedRecomp. The goal: play it natively on PC with a normal controller instead of Wii Remote motion controls.

Supported discs: USA (RENE8P), Europe (RENP8P) and Japan (RENJ8P). One exe plays all three: it contains the recompiled code of each, and the installed disc picks which runs.

You must own the game. Nothing from the game is in this repository; the build reads your own disc image.

How it works

main.dol ──► tools/analyze.py ──► tools/recomp.py ──► generated/<release>/*.cpp ─┐
 (PowerPC)    function discovery    PPC → C++ codegen   (28k functions each)       ├─► BlackKnightRecomp.exe
 per release                                            runtime/ ──────────────────┘
  • Recompiler (tools/): decodes every Gekko/Broadway instruction (incl. paired singles and quantized loads/stores) and emits one C++ function per guest function. Guest RAM is a 4 GiB host reservation with MEM1/MEM2 mirrored at their cached/uncached addresses, so guest pointers map directly to host memory. Function names come from the disc's BLACKKNIGHT.sel symbol table and Dolphin's signature database. Each release's code is in its own namespace with its own dispatch table. The releases differ only slightly (the code is a few hundred bytes longer or shorter, so most addresses move), so the runtime refers to game functions and variables by name: tools/game_addrs.txt lists them for the USA release, and tools/game_addrs.py finds them in the others by matching code (runtime/game_addrs.inc).
  • CPU runtime (runtime/cpu): SPRs, time base / decrementer, exact fres/frsqrte tables, indirect call dispatch.
  • OS (runtime/kernel): the game's own Revolution OS (scheduler, alarms, interrupt dispatch) runs recompiled. Only the CPU-level primitives are emulated: every guest thread is a host fiber (OSSaveContext/OSLoadContext become fiber switches) and external / decrementer exceptions are delivered at safe points.
  • Hardware (runtime/hw): memory-mapped VI, PI, CP/PE, DSP/AI, EXI (RTC/SRAM), SI and the Hollywood IPC registers, modelled on Dolphin's behaviour.
  • IOS (runtime/ios): high-level /dev/di (served from the installed disc files, which the installer decrypts once with nod), /dev/fs (NAND in nand/ next to the exe; saves land in nand/title/00010000/<id>/data: 52454e45 USA, 52454e50 Europe, 52454e4a Japan), /dev/es, /dev/stm.
  • Graphics (runtime/gx): the GX command FIFO is decoded and rendered with Direct3D 11 on a separate thread (the CPU thread only fills a ring buffer, like Dolphin's dual-core mode). Vertex and pixel shaders are generated per GX state (transform/lighting/texgen and the integer-exact TEV combiner with indirect texturing, alpha test, fog, z-textures). EFB copies become render-to-texture; XFB copies are presented; CPU EFB peeks are served from a read-back snapshot. Renders at 3x internal resolution, 16:9. Compiled shaders are cached in shadercache/, and Dolphin-format HD texture packs are supported.
  • Input (runtime/input): the WPAD library is replaced at the API level; KPAD runs recompiled on top of it. XInput controllers (and the keyboard) become Wii Remotes with a Nunchuk: sword swings are synthesised as accelerometer pulses, the IR pointer comes from the mouse or right stick, and the remote speaker stream is decoded and played.
  • Audio (runtime/audio): the AX DSP microcode is replaced by a port of Dolphin's AX HLE; output goes through XAudio2.

Playing

Run BlackKnightRecomp.exe. On first run it asks for your own disc image of the game (USA RENE8P, Europe RENP8P or Japan RENJ8P; ISO, RVZ, WIA or WBFS): select it in the file dialog, wherever it is on your PC. There is no need to copy it anywhere. The launcher installs the game data from it into game/extracted/ next to the exe, which takes about a minute and 3.5 GB. After that the image is no longer needed. Mods can replace files under game/extracted/DATA/files/. To switch to another release, choose "Reinstall from disc image..." in the launcher and select that disc; each release keeps its own saves.

Steam Deck and Linux (Proton)

There is no native Linux build (see docs/linux-native.md); the Windows build runs through Proton. v1.0.0 showed a black screen under Proton while the audio played (issue #5): Wine's HLSL compiler rejected the game's vertex shaders. Later builds avoid that, and releases include precompiled shaders in shadercache/, so keep that folder next to the exe.

Tested so far: Valve's Proton Experimental, Proton 10.0 and Proton 9.0, and Wine 10.0 with DXVK 2.7.1, on desktop Linux with software Vulkan, from boot into gameplay. With Proton 10.0, shaders that the game compiles itself (those not in the bundled shadercache/) showed wrong colours in testing; the bundled ones are fine. Proton Experimental and 9.0 had no such problem, so prefer one of those. Not yet tested on a Steam Deck; reports are welcome. Setup:

  1. In Desktop Mode, unzip the release somewhere in your home folder (for example ~/Games/BlackKnightRecomp), and put your disc image there in game/ (an .iso there is offered automatically; RVZ, WIA or WBFS can be picked in the file dialog).
  2. In Steam: Games > Add a Non-Steam Game to My Library, browse to BlackKnightRecomp.exe (set the file type filter to "All files").
  3. In the shortcut's Properties > Compatibility, tick Force the use of a specific Steam Play compatibility tool and pick Proton Experimental or Proton 9.0 (see above about 10.0).
  4. Start it once in Desktop Mode: the launcher installs the game data from your image. After that it can be started from Game Mode.

Controls (Steam's defaults for non-Steam games, not checked on a Deck yet): the Deck acts as an Xbox controller, so the table under Controls applies (View = the button left of the screen, Start = the menu button right of it). In the launcher, the D-pad/left stick and A work; the touchscreen or the right trackpad act as a mouse.

If it still shows a black screen, BlackKnightRecomp.log next to the exe says why (it logs "running under Wine", the HLSL compiler in use, and any shader or D3D error); please attach it to an issue.

Building

Requirements:

  • Windows 10+
  • Visual Studio 2026 (2022 or newer; the free Build Tools are enough) with the "Desktop development with C++" workload and the "C++ Clang Compiler for Windows" component
  • CMake 3.21+ and Ninja (both included with Visual Studio)
  • Python 3.10+
  • An internet connection for the first configure: it downloads the prebuilt nod library that reads disc images
  • Optional: a newer standalone LLVM (winget install LLVM.LLVM); the presets use whichever clang-cl comes first on PATH

Run the commands from a "Developer PowerShell for VS", or use tools/dev_build.bat for the build steps, which sets that up.

  1. Configure and build the installer (before the game code is generated, only bkr_install is built):

    cmake --preset windows-clang
    cmake --build --preset windows-clang
    
  2. Install the game data of each release you have into game/<game ID>:

    out/bkr_install path/to/your/usa-disc.iso game/RENE8P
    out/bkr_install path/to/your/europe-disc.rvz game/RENP8P
    out/bkr_install path/to/your/japan-disc.rvz game/RENJ8P
    

    One is enough: the exe then contains only that release's code. game/extracted/DATA (the default destination, where the game itself installs) also counts for the release installed there.

  3. Generate the recompiled sources:

    python tools/build_generated.py
    

    It generates the code of every release whose data is there, into generated/<release>/; per-release intermediate files go to out/<game ID>/. With all three releases it also refreshes runtime/game_addrs.inc, the game addresses the runtime uses in each release. The analysis names the SDK functions (for tools/xref.py and reports) from tools/sdk_names.txt, recorded once from Dolphin's signature database; pass --dsy <totaldb.dsy> to rematch. The generated code is the same either way. Optional: the HOME menu module (hbm_part.rso) runs in the built-in interpreter unless it is recompiled too. For each release, run the game once with BKR_DUMPMEM2=1 set and open the HOME menu (it writes mem2_dump.bin next to the exe when the module is first called; move it to out/<game ID>/), then rerun python tools/build_generated.py. The runtime only uses the recompiled module if the code in memory matches it exactly.

  4. Build the game (CMake reconfigures by itself now that generated/ exists):

    cmake --build --preset windows-clang
    

    The exe is written to out/. Rebuilds are incremental, so after editing the runtime only the build command is needed (tools/dev_build.bat runs it). Other presets: windows-msvc (run it from a Visual Studio x64 Developer prompt; with VS2019 use vcvars64.bat 10.0.19041.0, its linker crashes on newer SDKs) and linux-clang, which only builds the recompiled code until the runtime is ported off D3D11/XAudio2. tools/package.ps1 collects the exe and README into dist/BlackKnightRecomp/, with a shader cache precompiled from the GX states recorded in data/shadercache/ (BlackKnightRecomp.exe --precompile-shaders <dir> compiles every recorded key that has no blob yet).

  5. Run out/BlackKnightRecomp.exe (it finds game/extracted/DATA relative to the exe or the repo root, or pass --data <dir>, e.g. --data game/RENP8P). Data extracted earlier with DolphinTool (DolphinTool extract -i RENE8P.iso -o game/extracted -g) still works; keep the .iso in game/ in that case, it is used for raw disc reads.

Controls (default)

ControllerKeyboardAction
Left stickWASDMove
ASpaceJump / homing attack
X (hold to repeat)J / left clickSlash (sword swing)
Right stick flickDirectional slash
B, then XKSoul Surge (Wii Remote B)
RBLeft Shift / right clickGuard / talk (Z)
LBQNunchuk C
YLShake Nunchuk
RT / LTU / -Thrust Remote forward / pull back
StartEnterPause (+)
View (Back)F1Settings overlay (the game keeps running)
BackspaceWii - (unused by the game; unbound on the controller by default)
View + StartHHOME menu
Right stick (in menus)MousePointer
D-padArrow keysD-pad
Left stick clickWii Remote 1
Right stick clickWii Remote 2 (e.g. deleting a save file)

Controller, keyboard and mouse bindings can be changed in the settings (launcher or in game) or in config.ini ([Input] and [Keyboard]; a keyboard action can have several keys or mouse buttons, e.g. slash = J, MOUSE1). The table shows the defaults. Controllers 2-4 become Wii Remotes 2-4 (for Battle mode) while plugged in; the keyboard always drives player 1. The Wii Remote pointer follows the mouse when it moves inside the window, otherwise the right stick moves it. Choosing "Wii Menu" in the HOME menu quits; "Reset" restarts. F11 or Alt+Enter toggles fullscreen.

Launcher and settings

The game opens a launcher on every start: Play, settings, and the game data status. It asks for your disc image only when nothing is installed yet or the installed files are damaged (each start checks that every file is present with the right size; "Check all game files" compares the hash of every file). bkr_install --verify does the full check from the command line.

In game, View (Back) or F1 opens the same settings over the running game. Changes are saved to config.ini at once and most apply immediately; frame rate, internal resolution, widescreen, language, texture packs and the graphics thread ask to restart the game. The overlay also has the Wii HOME Menu, restart and quit.

config.ini next to the executable holds the settings (it can also be edited by hand):

  • frame_rate: 30 (original) or 60. Game logic runs at a fixed 60 Hz either way, so game time and speed match the original in every stage type (see docs/progress.md).
  • internal_scale: internal resolution multiplier (default 3, about 1080p).
  • window_width, window_height, fullscreen, vsync, widescreen.
  • texture_pack, texture_pack_dir: Dolphin-format HD texture packs (for example the one in the GameBanana "Ai HD Texture Overhaul" mod). Put the pack's folder (named by the game ID, e.g. RENE8P) in textures/ next to the exe or in game/textures/; packs installed in Dolphin's Load/Textures are picked up too. A pack made for another release is used when there is none for the installed one. PNG and DDS (BC1/2/3/7) are supported. --dump-textures writes the game's textures under Dolphin's names to dump/textures.
  • anisotropy: force anisotropic filtering (1, 2, 4, 8 or 16).
  • gpu_thread: run GX command processing and rendering on a second core (default on; --single-core turns it off for debugging).
  • language: english, german, french, spanish, italian, dutch, japanese.
  • pause_on_focus_loss: freeze the game while its window is in the background.
  • rumble: controller vibration.
  • remote_speaker: play the sounds the game sends to the Wii Remote speaker (decoded from the remote's 4-bit ADPCM stream) through the PC's audio output.
  • jump, slash, wii_b, guard, ...: controller button bindings (A, B, X, Y, LB, RB, LT, RT, START, BACK, LS, RS, D-pad UP/DOWN/LEFT/RIGHT, or NONE).
  • data, iso: game file locations, if they are not in game/.

Testing

  • tools/smoke_test.ps1 [-Fps60]: boots into mission 1 with a scripted input run and checks the log (no errors, expected milestones, frame rate) and screenshots.
  • tools/gen_soak.py: random-input scripts for long stability runs (see its header).
  • --capture <frame> writes a per-draw log, textures and EFB states for one frame; --profile <start> <seconds> (plus --profile-gx) prints a sampling profile.

Status

The game is playable from boot to gameplay, with graphics, audio, saves and controller input working. See docs/progress.md.

License

BlackKnightRecomp is licensed under the GNU General Public License, version 2 only (GPL-2.0-only); see LICENSE.

Parts of the runtime are ported from or closely follow the Dolphin emulator (GPL-2.0-or-later), notably the AX audio HLE, the TEV/lighting/fog shader formulas, VI timing and the DSP/IOS behaviour. Thanks to the Dolphin team.

No game code or data is included; you need your own copy of the game.