build: native macOS support and Builder (testers needed) #1872

Open
yeetbot90 wants to merge 33 commits from yeetbot90/codex/macos-rebased-release into main
yeetbot90 commented 2026-11-10 19:01:20 +00:00 (Migrated from github.com)

macOS (Apple Silicon) port — progress

Status of the native Apple Silicon / WebGPU-Metal port that lands through
PR #1872.

How to build and run: development.md § macOS and the macOS section of
readme.md. This page is the changelog of what landed, who did it, and which PRs carry the work.

Current status (2026-11-11)

Area State
Native arm64 build + link Working (SDK via toolchain.native_target, pthread CS/CV, wgpu/SDL copy)
Hookshot Builder (macOS) Packaged, ad hoc signed; CI macos-builder / macos-posix green
Title logo / menu text / subtitles Fixed (whole-stride verts; draw base/instance/ID in c0)
Title + opening movies Fixed (NVN2 compute push constants; HMMA → linear upscale stub)
3D gameplay (black) Fixed (shared sampler made non-filtering for unfilterable depth-as-color)
3D gameplay (blown-out / white) Mitigated in tree (NVN2 SSBO table, WGSL globals, 64 KiB writeback prefix); needs Mac re-test
Metal Occluded black window Fixed (skip frame; do not reconfigure)
Save path backslashes on POSIX Fixed (/ mounts)
Spurious SDL focus loss Mitigated (focus check + click/key recovery + Apple recheck)
Depth32Float CPU uploads Fixed (clear via pass; WebGPU forbids WriteTexture into depth)
Game-free CI Green on bcf9e1a (MERGEABLE / CLEAN)

CI does not run the game. Please try a Mac Builder artifact and report chip, macOS version, steps, and log.

Thanks

This port is the work of many people. In particular, thanks to:

  • @yeetbot90 (BED) — first native macOS support (#715), the rebased #1872 branch, Builder packaging, CI, and keeping the PR mergeable against main
  • @jrldorival (Dorival Junior) — WebGPU/Metal renderer fixes that made the title, menus, movies, and sampler path work (#1088 and follow-ups)
  • @MatthewFeroz — macOS toolchain/SDK fixes, condition-variable wake fix, build copy fix, and the unfilterable shared-sampler fix that turned black 3D into a visible (if overexposed) picture (yeetbot90#4, #5)
  • @Arkex-ai (Issai) — portable offline-bake / zstd / Clang 18 work (#1931, #1954)
  • @madebyjordan — early reports and fixes carried through the #715 → #1088 line
  • Everyone who tested on Apple Silicon.

Lineage (macOS port)

PR Repo Author State What
#715 NotRexed/Hookshot yeetbot90 Closed Initial native macOS build support
#1088 NotRexed/Hookshot jrldorival Closed #715 rebased on main + WebGPU/Metal renderer fixes (title/menu/movies; 3D still white)
#4 yeetbot90/Hookshot MatthewFeroz Open (into #1872) Game builds, links, reaches the title on Apple Silicon
#5 yeetbot90/Hookshot MatthewFeroz Open (into #1872) Title, menu text, movies, and 3D picture on Apple Silicon (includes Jrldorival’s #1088 commits + sampler fix)
#1872 NotRexed/Hookshot yeetbot90 Open Current merge vehicle: #1088/#4/#5 + bake portability + gameplay/runtime follow-ups

Adjacent / unblocking work folded into #1872

PR / issue Author State Why it matters here
#1931 Arkex-ai Closed Offline bake portability tracking
#1954 Arkex-ai Merged Portable zstd + Clang 18 bake path (also carried on the #1872 branch)
#2033 hckrman101 Merged driver_cache_room on Linux; broke the display-startup fixture until #2051
#2051 NotRexed Merged Stub driver_cache_room in the display-startup test so game-free CI is green again

Progress timeline (high level)

  1. #715 — POSIX host, Metal/WebGPU path, macOS Builder scripts; closed when it drifted from main.
  2. #1088 — Rebase + Jrldorival renderer work: whole-stride vertices, c0 draw IDs, NVN2 push constants, sampler sharing past 16, Eden lower_to_maxwell.h, HMMA upscale stubs. Title/menu/movies good; 3D white. Closed for conflicts / no Mac CI.
  3. yeetbot90 #4 / #5 — Matthew’s build/runtime fixes and the shared-sampler non-filter fix (black → overexposed 3D), plus cherry-picks of the #1088 renderer commits.
  4. #1872 — Rebased onto current main (conflicts resolved), #4+#5 renderer/build commits folded in, bake portability kept, then:
    • NVN2 compute SSBO table + WGSL LoadGlobal/WriteGlobal + small/prefix dispatch writebacks (exposure)
    • CI: skip Linux-only checks on macOS; shard macOS source tests; portable inherit_errexit
    • Runtime: Occluded present, POSIX save separators, SDL focus recovery, Depth32Float clear path

What still needs a Mac

  • Confirm 3D gameplay exposure / brightness after the writeback-prefix change (was white/blown-out on M1 Max / M5 reports).
  • Confirm Occluded / focus / save-path behaviour with the window in front and when briefly covered.
  • Builder install, update, save/load, rumble, controller, and long play sessions.

Report against PR #1872: Mac model/chip, macOS version, Builder or source build, steps, and log (Metal frame capture for render bugs if you can).

# macOS (Apple Silicon) port — progress Status of the native Apple Silicon / WebGPU-Metal port that lands through [PR #1872](https://git.magicbean.dev/MagicBeanDev/Hookshot/pulls/1872). How to build and run: [development.md § macOS](development.md#macos-apple-silicon) and the macOS section of [readme.md](../readme.md). This page is the changelog of what landed, who did it, and which PRs carry the work. ## Current status (2026-11-11) | Area | State | |---|---| | Native arm64 build + link | Working (SDK via `toolchain.native_target`, pthread CS/CV, wgpu/SDL copy) | | Hookshot Builder (macOS) | Packaged, ad hoc signed; CI `macos-builder` / `macos-posix` green | | Title logo / menu text / subtitles | Fixed (whole-stride verts; draw base/instance/ID in c0) | | Title + opening movies | Fixed (NVN2 compute push constants; HMMA → linear upscale stub) | | 3D gameplay (black) | Fixed (shared sampler made non-filtering for unfilterable depth-as-color) | | 3D gameplay (blown-out / white) | Mitigated in tree (NVN2 SSBO table, WGSL globals, 64 KiB writeback prefix); **needs Mac re-test** | | Metal Occluded black window | Fixed (skip frame; do not reconfigure) | | Save path backslashes on POSIX | Fixed (`/` mounts) | | Spurious SDL focus loss | Mitigated (focus check + click/key recovery + Apple recheck) | | Depth32Float CPU uploads | Fixed (clear via pass; WebGPU forbids `WriteTexture` into depth) | | Game-free CI | Green on `bcf9e1a` (MERGEABLE / CLEAN) | CI does **not** run the game. Please try a Mac Builder artifact and report chip, macOS version, steps, and log. ## Thanks This port is the work of many people. In particular, thanks to: - **[@yeetbot90](https://github.com/yeetbot90) (BED)** — first native macOS support (#715), the rebased #1872 branch, Builder packaging, CI, and keeping the PR mergeable against `main` - **[@jrldorival](https://github.com/jrldorival) (Dorival Junior)** — WebGPU/Metal renderer fixes that made the title, menus, movies, and sampler path work (#1088 and follow-ups) - **[@MatthewFeroz](https://github.com/MatthewFeroz)** — macOS toolchain/SDK fixes, condition-variable wake fix, build copy fix, and the unfilterable shared-sampler fix that turned black 3D into a visible (if overexposed) picture ([yeetbot90#4](https://github.com/yeetbot90/Hookshot/pull/4), [#5](https://github.com/yeetbot90/Hookshot/pull/5)) - **[@Arkex-ai](https://github.com/Arkex-ai) (Issai)** — portable offline-bake / zstd / Clang 18 work ([#1931](https://git.magicbean.dev/MagicBeanDev/Hookshot/issues/1931), [#1954](https://git.magicbean.dev/MagicBeanDev/Hookshot/pulls/1954)) - **[@madebyjordan](https://github.com/madebyjordan)** — early reports and fixes carried through the #715 → #1088 line - Everyone who tested on Apple Silicon. ## Related pull requests and issues ### Lineage (macOS port) | PR | Repo | Author | State | What | |---|---|---|---|---| | [#715](https://git.magicbean.dev/MagicBeanDev/Hookshot/pulls/715) | NotRexed/Hookshot | yeetbot90 | Closed | Initial native macOS build support | | [#1088](https://git.magicbean.dev/MagicBeanDev/Hookshot/pulls/1088) | NotRexed/Hookshot | jrldorival | Closed | #715 rebased on `main` + WebGPU/Metal renderer fixes (title/menu/movies; 3D still white) | | [#4](https://github.com/yeetbot90/Hookshot/pull/4) | yeetbot90/Hookshot | MatthewFeroz | Open (into #1872) | Game builds, links, reaches the title on Apple Silicon | | [#5](https://github.com/yeetbot90/Hookshot/pull/5) | yeetbot90/Hookshot | MatthewFeroz | Open (into #1872) | Title, menu text, movies, and 3D picture on Apple Silicon (includes Jrldorival’s #1088 commits + sampler fix) | | [#1872](https://git.magicbean.dev/MagicBeanDev/Hookshot/pulls/1872) | NotRexed/Hookshot | yeetbot90 | Open | Current merge vehicle: #1088/#4/#5 + bake portability + gameplay/runtime follow-ups | ### Adjacent / unblocking work folded into #1872 | PR / issue | Author | State | Why it matters here | |---|---|---|---| | [#1931](https://git.magicbean.dev/MagicBeanDev/Hookshot/issues/1931) | Arkex-ai | Closed | Offline bake portability tracking | | [#1954](https://git.magicbean.dev/MagicBeanDev/Hookshot/pulls/1954) | Arkex-ai | Merged | Portable zstd + Clang 18 bake path (also carried on the #1872 branch) | | [#2033](https://git.magicbean.dev/MagicBeanDev/Hookshot/pulls/2033) | hckrman101 | Merged | `driver_cache_room` on Linux; broke the display-startup fixture until #2051 | | [#2051](https://git.magicbean.dev/MagicBeanDev/Hookshot/pulls/2051) | NotRexed | Merged | Stub `driver_cache_room` in the display-startup test so game-free CI is green again | ## Progress timeline (high level) 1. **#715** — POSIX host, Metal/WebGPU path, macOS Builder scripts; closed when it drifted from `main`. 2. **#1088** — Rebase + Jrldorival renderer work: whole-stride vertices, c0 draw IDs, NVN2 push constants, sampler sharing past 16, Eden `lower_to_maxwell.h`, HMMA upscale stubs. Title/menu/movies good; 3D white. Closed for conflicts / no Mac CI. 3. **yeetbot90 #4 / #5** — Matthew’s build/runtime fixes and the shared-sampler non-filter fix (black → overexposed 3D), plus cherry-picks of the #1088 renderer commits. 4. **#1872** — Rebased onto current `main` (conflicts resolved), #4+#5 renderer/build commits folded in, bake portability kept, then: - NVN2 compute SSBO table + WGSL `LoadGlobal`/`WriteGlobal` + small/prefix dispatch writebacks (exposure) - CI: skip Linux-only checks on macOS; shard macOS source tests; portable `inherit_errexit` - Runtime: Occluded present, POSIX save separators, SDL focus recovery, Depth32Float clear path ## What still needs a Mac - Confirm 3D gameplay exposure / brightness after the writeback-prefix change (was white/blown-out on M1 Max / M5 reports). - Confirm Occluded / focus / save-path behaviour with the window in front and when briefly covered. - Builder install, update, save/load, rumble, controller, and long play sessions. Report against [PR #1872](https://git.magicbean.dev/MagicBeanDev/Hookshot/pulls/1872): Mac model/chip, macOS version, Builder or source build, steps, and log (Metal frame capture for render bugs if you can).
MatthewFeroz commented 2026-11-10 19:54:54 +00:00 (Migrated from github.com)

Hey yeetbot, I'm testing this. Would love to get Hookshot running on Mac

Hey yeetbot, I'm testing this. Would love to get Hookshot running on Mac
yeetbot90 commented 2026-11-10 19:55:38 +00:00 (Migrated from github.com)

Ok this is the third part and my macbook broke so currently it needs testers. So thank you.

Ok this is the third part and my macbook broke so currently it needs testers. So thank you.
yeetbot90 commented 2026-11-10 20:23:00 +00:00 (Migrated from github.com)
NEWEST BUILD: https://github.com/NotRexed/Hookshot/actions/runs/42888979703/artifacts/13797707257
yeetbot90 commented 2026-11-10 20:52:45 +00:00 (Migrated from github.com)
NEWEST: https://github.com/NotRexed/Hookshot/actions/runs/42899038325/artifacts/13802316643
Arkex-ai commented 2026-11-10 21:10:39 +00:00 (Migrated from github.com)

I found overlap with your compiler discovery/cache work while auditing #1931, so I removed that part from my local candidate rather than opening a competing implementation.

Two complementary fixes remain: the pinned Python zstandard dependency can run the DS dictionary fixtures/reader on Windows (the existing test passes without a zstd CLI or Linux libzstd soname), and Clang 18 rejects the current unconditional-static constexpr probe with constexpr function never produces a constant expression. The actual assertion failure-path shape passes: constexpr int f(int n){if(n<0){static int x=0;return ++x;}return n;} static_assert(f(1)==1);. Both outcomes were executed on Clang 18.

I am preparing a focused bake portability PR for these two failures, retaining the Windows check. Your discovery/cache changes can stay here; please avoid the DS Windows skip if the portable reader/fixture lands first. I will link the PR once its final Linux translator/full-suite validation completes.

I found overlap with your compiler discovery/cache work while auditing #1931, so I removed that part from my local candidate rather than opening a competing implementation. Two complementary fixes remain: the pinned Python zstandard dependency can run the DS dictionary fixtures/reader on Windows (the existing test passes without a zstd CLI or Linux libzstd soname), and Clang 18 rejects the current unconditional-static constexpr probe with `constexpr function never produces a constant expression`. The actual assertion failure-path shape passes: `constexpr int f(int n){if(n<0){static int x=0;return ++x;}return n;} static_assert(f(1)==1);`. Both outcomes were executed on Clang 18. I am preparing a focused bake portability PR for these two failures, retaining the Windows check. Your discovery/cache changes can stay here; please avoid the DS Windows skip if the portable reader/fixture lands first. I will link the PR once its final Linux translator/full-suite validation completes.
yeetbot90 commented 2026-11-10 21:13:07 +00:00 (Migrated from github.com)

Ok!

Ok!
Arkex-ai commented 2026-11-10 21:32:33 +00:00 (Migrated from github.com)

Quick coordination: I see the Python reader fallback is now in this PR too. My tested #1931 candidate is ready at github.com/Arkex-ai/Hookshot@4e9ac9e941 : decoder plus dictionary fixture compression, the actual constexpr probe, and strict truncated/unknown-size frame validation. Full Windows: 321 passed / 3 failed / 21 skipped versus main 319 / 4 / 21; all DS/Mimo/skeleton checks execute and pass. Linux Clang 18 integration and the 512 MiB memory regression pass too.

Could we land that focused prerequisite first, then keep discovery/cache/macOS changes here and rebase onto it? I have held opening the PR while we align the reader overlap. The bounded scan is followed by complete-frame validation so truncated frames are rejected.

One regression to preserve during consolidation: I executed the actual Windows Python fallback at 70f226e on an authored unknown-size frame. Both readers decode the valid frame to 2,000,000 bytes. Removing its final byte makes this revision return 1,966,080 bytes without an error; 4e9ac9e rejects it with ValueError. The new regression catches this truncated-frame acceptance, so the bounded scan still needs complete-frame validation.

Quick coordination: I see the Python reader fallback is now in this PR too. My tested #1931 candidate is ready at https://github.com/Arkex-ai/Hookshot/commit/4e9ac9e941650d0add34ce694647ae4f3e8fe8c8 : decoder plus dictionary fixture compression, the actual constexpr probe, and strict truncated/unknown-size frame validation. Full Windows: 321 passed / 3 failed / 21 skipped versus main 319 / 4 / 21; all DS/Mimo/skeleton checks execute and pass. Linux Clang 18 integration and the 512 MiB memory regression pass too. Could we land that focused prerequisite first, then keep discovery/cache/macOS changes here and rebase onto it? I have held opening the PR while we align the reader overlap. The bounded scan is followed by complete-frame validation so truncated frames are rejected. One regression to preserve during consolidation: I executed the actual Windows Python fallback at `70f226e` on an authored unknown-size frame. Both readers decode the valid frame to 2,000,000 bytes. Removing its final byte makes this revision return 1,966,080 bytes without an error; `4e9ac9e` rejects it with `ValueError`. The new regression catches this truncated-frame acceptance, so the bounded scan still needs complete-frame validation.
yeetbot90 commented 2026-11-10 21:36:49 +00:00 (Migrated from github.com)

ok I understand I will try to do that

ok I understand I will try to do that
Arkex-ai commented 2026-11-10 21:37:35 +00:00 (Migrated from github.com)

Draft #1954 now has the complete focused patch and measured validation: #1954 . The overlapping reader is called out in the description so we can settle on one implementation; discovery/cache work remains with #1872.

Draft #1954 now has the complete focused patch and measured validation: https://git.magicbean.dev/MagicBeanDev/Hookshot/pulls/1954 . The overlapping reader is called out in the description so we can settle on one implementation; discovery/cache work remains with #1872.
yeetbot90 commented 2026-11-10 21:39:27 +00:00 (Migrated from github.com)

Ok, so I'll continue implementing the macOS and the implementation will stay

Ok, so I'll continue implementing the macOS and the implementation will stay
yeetbot90 commented 2026-11-10 22:14:39 +00:00 (Migrated from github.com)
https://github.com/NotRexed/Hookshot/actions/runs/42911283137/artifacts/13807017754
yeetbot90 commented 2026-11-10 22:44:22 +00:00 (Migrated from github.com)
https://github.com/NotRexed/Hookshot/actions/runs/42914986962/artifacts/13808822394
MatthewFeroz commented 2026-11-11 01:24:46 +00:00 (Migrated from github.com)

Tested on an M1 Max (macOS 27.0.1). Three errors stopped the game build in turn: 'string.h' not found reading the .nup, the link (InitializeCriticalSection / SleepConditionVariableSRW missing on macOS), and an UnboundLocalError on shutil after the link. The fixes are in yeetbot90/Hookshot#4, against this branch. With them the game builds from a .nup and boots to the title screen at 30-45 fps.

Still open, with details in that PR:

  • The title logo is missing a diagonal half, same as on the M4 Pro.
  • The window stays black whenever macOS reports it as covered (wgpu Occluded, 'rx: no surface texture (status 196609)').
  • After A on the title, frames stop reaching the window even with it in front. I'm looking into this one next.
  • The focus check drops keyboard input.
  • The save path is ~/.local/share/hookshot\save...
Tested on an M1 Max (macOS 27.0.1). Three errors stopped the game build in turn: 'string.h' not found reading the .nup, the link (InitializeCriticalSection / SleepConditionVariableSRW missing on macOS), and an UnboundLocalError on shutil after the link. The fixes are in yeetbot90/Hookshot#4, against this branch. With them the game builds from a .nup and boots to the title screen at 30-45 fps. Still open, with details in that PR: - The title logo is missing a diagonal half, same as on the M4 Pro. - The window stays black whenever macOS reports it as covered (wgpu Occluded, 'rx: no surface texture (status 196609)'). - After A on the title, frames stop reaching the window even with it in front. I'm looking into this one next. - The focus check drops keyboard input. - The save path is ~/.local/share/hookshot\save\...
yeetbot90 commented 2026-11-11 09:39:19 +00:00 (Migrated from github.com)
NEWEST BUILD: https://github.com/NotRexed/Hookshot/actions/runs/42996151783/artifacts/13844550656
github-sync changed title from WIP: build: native macOS support and Builder (testers needed) to build: native macOS support and Builder (testers needed) 2026-11-12 08:30:58 +00:00
Commenting is not possible because the repository is archived.
No description provided.