Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d2c3879
docs: say that a build deletes its build files unless HOOKSHOT_KEEP_B…
itaskaev2 Nov 9, 2026
bbf849d
docs: say that frame pacing works only with frame generation on
itaskaev2 Nov 9, 2026
dbc519d
docs: document the mouse and the triggers in the in-game menu
itaskaev2 Nov 9, 2026
30f6b6b
docs: say that mouse_sens.txt is written only with HOS_MOUSE_SENS set
itaskaev2 Nov 9, 2026
b05a136
docs: say that only the Linux AppImage needs an AVX2 CPU
itaskaev2 Nov 9, 2026
1cb97a2
docs: a new test needs no workflow edit, tests/run_all.py finds it
itaskaev2 Nov 9, 2026
dbb260c
docs: take the development tools from the installed builder, not Hook…
itaskaev2 Nov 9, 2026
26ffffb
docs: point the hardware testing row at the readme's status table
itaskaev2 Nov 9, 2026
f8c527d
docs: the stack sampler runs only with HOS_PROFILE set
itaskaev2 Nov 9, 2026
6cc2e6f
docs: bring the development guide's introduction and layout up to date
itaskaev2 Nov 9, 2026
7eeddfd
docs: a reference of the switches for testing and debugging
itaskaev2 Nov 9, 2026
0fd726e
docs: the options file's keys and values
itaskaev2 Nov 9, 2026
99cb915
docs: link the contributing guide to the switch reference
itaskaev2 Nov 9, 2026
1b0f3eb
docs: design notes: the facts of sections 3, 4 and 8 that drifted fro…
itaskaev2 Nov 9, 2026
b808bf7
docs: provenance notes: the files that are gone, new or no longer the…
itaskaev2 Nov 9, 2026
9279682
docs: mark gpu/vk/VULKAN.md as mkw-recomp's log and say what moved
itaskaev2 Nov 9, 2026
67dbec9
docs: point the readme's test switches at the development guide's ref…
itaskaev2 Nov 9, 2026
bb4e410
docs: the mesh shader fallback is back since v2.0.6
itaskaev2 Nov 9, 2026
76d4076
docs: --prepare-shaders is not a build step
itaskaev2 Nov 9, 2026
aa96077
docs: the movies keep their neural upscale only on NVIDIA cards
itaskaev2 Nov 9, 2026
a99610c
docs: the write-back diff is on again, and the DLSS and Reflex switches
itaskaev2 Nov 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 16 additions & 11 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ game data, leave it out.

| | What |
|---|---|
| **Test on other hardware** | The project has been tested on one Windows PC (Ryzen 5 7600X, RTX 4060 Ti) and one Linux PC so far. Reports from AMD and Intel cards, other NVIDIA drivers, other distributions and SteamOS are useful even when everything works. |
| **Test on other hardware** | NVIDIA cards are the most tested; the README's [status table](readme.md#project-status) says what works where. Reports from AMD and Intel cards, other NVIDIA drivers, other distributions and SteamOS are useful even when everything works. |
| **Play further** | The tested area is the start of the game. Reaching new areas, cutscenes, menus and items finds problems the developer has not seen. |
| **Report what is broken** | Use the [issue forms](https://github.com/NotRexed/Hookshot/issues/new/choose): game problem, build problem or idea. Include the version, your hardware, where you were and `hookshot_log.txt`. |
| **Send a fix** | Fork, fix, test, open a pull request. Small, focused changes are easiest to review and merge. |
Expand Down Expand Up @@ -64,13 +64,15 @@ about 10 GB of RAM.
folder. Without it the build falls back to emsdk's clang at `C:\emsdk` with Visual Studio's C++ tools and the
Windows SDK (`HOOKSHOT_MSVC=1` forces that route).

3. Copy the pieces a clone does not carry from the `tools` folder of the latest `HookshotBuilder.zip`:
3. Copy the pieces a clone does not carry from the `tools` folder Hookshot Builder installs. Run `HookshotBuilder.exe`
from the latest release once (releases no longer carry a `HookshotBuilder.zip`): the folder is
`%LOCALAPPDATA%\HookshotBuilder\versions\<version>\HookshotBuilder\tools`.

| From the zip | To | Variable |
| From `tools` | To | Variable |
|---|---|---|
| `tools\cpm` | anywhere | `RX_CPM` points at it (Vulkan headers and FFmpeg; without it the Vulkan renderer is left out) |
| `tools\wgpu-native` | anywhere | `WGPU_NATIVE` points at it |
| `tools\third_party\sdl2\SDL2.dll` | `third_party\sdl2\` | |
| `tools\wgpu-native` | anywhere | `WGPU_NATIVE` points at it (the WebGPU fallback renderer; without it the game is built without one) |
| `tools\third_party` | `third_party\` | (its `.dll`, `.exe`, `.lib` and `.sha1` files, to the same places: `a64emit`, `lld-link`, `zbic` and SDL2) |
| `tools\work` | `work\` | (hot-function list, link order, profile and icon; without it the game builds but runs slower) |

4. Run everything with `python -I` from the repository root.
Expand Down Expand Up @@ -141,7 +143,7 @@ window, including one started to update a game, uses Automatic again.
| `python -I nx2/lift.py --standalone --write` | Lift the game to C in `work/sa/gen`. |
| `python -I nx2/build.py --standalone --jobs 4` | Compile `work/sa/build/hookshot.exe` and `hookshot_vk.dll`. |
| `powershell -File scripts/run-vk.ps1 -Window -Seconds 120` | Run the standalone build with the Vulkan back end and take screenshots in `work/runs/<name>/shots`. |
| `python -I scripts/prof.py <stacks file>` | Read a profile sampled with `HOS_SAMPLE` and `HOS_SAMPLE_FILE`. |
| `python -I scripts/prof.py <stacks file>` | Read a profile sampled with `HOS_PROFILE`, `HOS_SAMPLE` and `HOS_SAMPLE_FILE`. |

Use a separate `--work` folder or `OOT_WORK` if you keep more than one dump around. The lifted C and every build are
local artifacts; they are never committed.
Expand Down Expand Up @@ -181,16 +183,19 @@ These are slow and local, and they need `work/dump.txt` from `nx2/dump.py --set`
| `powershell -File scripts/run-vk.ps1 -Window` | An in-game run: screenshots, the flash detector, frame dumps and the profiler. |

For a graphics fix, look at the screenshots in `work/runs/<name>/shots` and delete them afterwards; they reach
gigabytes and are derived from the game.
gigabytes and are derived from the game. The switches for scripted input, screenshots, frame dumps and profiles are in
the development guide's [reference](docs/development.md#switches-for-testing-and-debugging).

### When you add a fix or a check

- Add a game-free test where the behavior can be tested without the dump. The existing tests are small Python files
under `tests/` or `nx2/` that read source files and run them, or compile a tiny C++ fixture.
- Wire the test into `.github/workflows/source-regressions.yml`: add a `run:` step, and add the test file and every
source file it reads to both the `push` and `pull_request` `paths` lists. Without the paths, the check does not run
when the code changes.
- Keep the test fast enough for the 10-minute CI job, and make it pass on both Ubuntu and Windows where it can.
- Name it `tests/test_*.py` or `nx2/test_*.py`: `tests/run_all.py` picks it up by itself and CI runs it on every pull
request, so there is no workflow to edit. A test that takes a compiler, headers or `spirv-val` as arguments gets an
entry in `ARGS` at the top of `tests/run_all.py`; one that cannot run in CI (a GPU, the game, one OS only) gets an
entry in `SKIP`, with the reason.
- Keep the test fast: every check shares one CI job with a 20-minute limit. Make it pass on both Ubuntu and Windows
where it can.
- If the fix is in the renderer or the runtime, say what you saw before and after, on which GPU and driver, and in
which part of the game.

Expand Down
23 changes: 13 additions & 10 deletions docs/design.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Hookshot (oot-recomp): design

A native x86-64 Windows build of the Switch 2 *The Legend of Zelda: Ocarina of Time* remake: the game's AArch64
A native x86-64 Windows and Linux build of the Switch 2 *The Legend of Zelda: Ocarina of Time* remake: the game's AArch64
code translated to C ahead of time from the user's own decrypted dump and compiled with clang, the Horizon OS and
NVN2 implemented natively, and the GPU work replayed on Vulkan. No CPU or GPU emulation at any point: the same
model as mkw-recomp (Mario Kart World), which this project forks.
Expand Down Expand Up @@ -64,10 +64,10 @@ message. OoT-specific code goes into new files where it can, so the shared files
│ a64-kit lift/a64_lift.py + nx2/insn.py + nx2/lift_fixes.py + nx2/poll.py + nx2/chunks.py
▼
one C function per guest function (work/sa/gen, ~1 GB, local), 64-bit guest window (nx2/rtgen.py)
│ clang 24 (emsdk) -O1, lld (nx2/build.py --standalone)
│ clang (llvm-mingw, emsdk or the system's) -O1, the hot functions -O2 with the play profile, lld (nx2/build.py --standalone)
▼
hookshot.exe = lifted game + host/ (Horizon: threads, SVCs, memory, fs, hid, audio, vi, gs, NVN2)
hookshot_vk.dll = the Vulkan back end (gpu/vk), loaded by host/rx_backend.c with RX_BACKEND=vulkan
hookshot_vk.dll = the Vulkan back end (gpu/vk), loaded by host/rx_backend.c unless RX_BACKEND names another renderer
```

- **Standalone from the start.** MKW went emulator-hosted first (Eglantine with a recompiled CPU backend), then
Expand All @@ -81,8 +81,8 @@ message. OoT-specific code goes into new files where it can, so the shared files
- **GPU.** `host/nvn_native.c` implements the NVN2 procs over guest memory in place: objects live where the game
puts them, command buffers record an op stream (`gpu/render/rx_nvn.h`), queue submits hand it to the back end.
`gpu/vk` replays it on Vulkan 1.3: pools imported as host memory, SM86 programs through Eden's recompiler to
SPIR-V, mesh/task programs with `VK_EXT_mesh_shader`. The WebGPU renderer (`gpu/render`) stays in the exe as the
fallback when Vulkan is missing, as in mkw-recomp.
SPIR-V, mesh/task programs with `VK_EXT_mesh_shader`. The WebGPU renderer (`gpu/render`) stays in the Windows exe as the
fallback when Vulkan is missing, as in mkw-recomp, when the build has wgpu-native (`WGPU_NATIVE`).

## 4. The lessons from MKW, as rules here

Expand All @@ -98,14 +98,17 @@ second game.
(`gpu/vk/vk_memory.cpp`, `RX_VK_CAPTURE_POOL_MB`). *Check:* the mirror sync log's live-sync count stays ~0.
3. **Texture and sampler registrations are queued in order with the submits**, never applied out of band.
4. **GPU timestamps drive dynamic resolution.** OoT is reported at 1080p-1440p docked, so it has a resolution
controller fed by timestamp reports: the fake GPU time (`host/nvn_native.c`, the 31.25 MHz tick clock) must be
controller fed by timestamp reports: the fake GPU time (the counter reports the replay writes, `gpu/vk/vk_replay.cpp`
`NOP_REPORT_COUNTER`: the 31.25 MHz tick clock since the frame's present, times `RX_VK_TS_SCALE`, 0.1 by default) must be
scaled so the controller settles where the PC is, not at its floor. *Check:* the render size it picks over time.
5. **Clears after draws, and draws that sample their own target, get passes of their own** (`vk_draw.cpp`).
5. **Clears after draws, and draws that sample a target their pass already wrote (or write one an earlier draw of the
pass sampled), get passes of their own** (`vk_draw.cpp` `clear_after_draws`, `draw_hazards`). A draw that samples
a target it writes itself stays in the pass.
6. **2D views of 3D textures need `VK_EXT_image_2d_view_of_3d`** (the RTX 4060 Ti has it).
7. **The CPU saturates first.** Ryzen 5 7600X, 6 cores / 12 threads: the game's threads, the replay, captures and
pipeline compiles share it, and extra helper threads have lowered fps before. Thread counts are measured, never
raised by default (`HOS_VCORES`, `RX_VK_CAPTURE_THREADS`, `HOS_THREAD_STATS=1`, the `HOS_SAMPLE` profiler with
`scripts/prof.py`).
raised by default (`HOS_VCORES`, `RX_VK_CAPTURE_THREADS`, `HOS_THREAD_TIMES=<seconds>`, the `HOS_SAMPLE` profiler
with `scripts/prof.py`).

Also inherited, and game-specific in MKW: MKW's frame-pacer hooks at fixed guest addresses are gated on MKW's build
id (`hos_game_is_mkw`); OoT gets its own once its pacer is found, never by address coincidence.
Expand Down Expand Up @@ -155,7 +158,7 @@ id (`hos_game_is_mkw`); OoT gets its own once its pacer is found, never by addre
edited.
- One game run at a time on this PC (mkw-recomp's runs take ~10 GB): `run-vk.ps1` refuses while `mkw.exe` or
another `hookshot.exe` runs, and while Rainbow Six Siege is open; no heavy builds while Siege is open either. Runs are
muted (`HOS_AUDIO=0`), at below-normal priority, and screenshot folders are deleted once looked at.
muted (`HOS_AUDIO=0`), at the priority `-Priority` gives (High by default), and screenshot folders are deleted once looked at.
- The lifted C and every build are GPL (suyu's translator is GPL-2.0-or-later; Eden's code is GPL-3.0).

## 9. Status
Expand Down
Loading