Skip to content

Experimental macOS (x86_64) port -- Mono + XQuartz, unlocks waterbox (DS) on macOS#4785

Open
DarthMDev wants to merge 10 commits into
TASEmulators:masterfrom
DarthMDev:macos-x86_64-port
Open

Experimental macOS (x86_64) port -- Mono + XQuartz, unlocks waterbox (DS) on macOS#4785
DarthMDev wants to merge 10 commits into
TASEmulators:masterfrom
DarthMDev:macos-x86_64-port

Conversation

@DarthMDev

@DarthMDev DarthMDev commented Jun 25, 2026

Copy link
Copy Markdown

Draft / RFC — experimental, not asking for a support commitment.

Revives a macOS port by running the existing x86_64 build under Mono + XQuartz
(natively on Intel, via Rosetta 2 on Apple silicon). Verified working: EmuHawk GUI,
Lua, GB/GBC (Gambatte), GBA (mGBA), and Nintendo DS (melonDS) — Pokémon
SoulSilver boots and runs at full speed from a real save. All changes are OS-gated; no
behavioural change on Windows/Linux.

Highlights

  • waterboxhost on macOS: file-backed (not shm) block handle so guest code can be mapped
    executable; SIGBUS handling for dirty-detection; a macOS %gs/TSD trampoline
    (interop_macos.s) since the GS base can't be repointed under Rosetta. All 26
    cargo test --target x86_64-apple-darwin pass.
  • EmuHawk: OSTailoredCode.DllExtension, MemoryBlock MAP_ANON fix, SDL2 GLX-not-EGL on
    macOS, and host-GL reported unavailable (XQuartz GL is broken/2.1) so cores fall back to
    software rendering.
  • EmuHawkMonoMacOS.sh launcher, Dist/stage-macos-dylibs.sh, build-release-macos.sh,
    and a README section with setup + an experimental/maintainer warning.

Scope/limitations: source-only (native dylibs are build artifacts; build with the
included scripts + Homebrew). Software (GdiPlus) video only -- no hardware GL / HD
upscaling. Requires macOS 14+ (Homebrew dep floor).

Refs #1430, #3697, #4052. Discussion: DarthMDev#1

image

Port the waterbox host to build and run on macOS x86_64 (natively on Intel,
under Rosetta 2 on Apple silicon). All `cargo test --target x86_64-apple-darwin`
pass and melonDS boots and runs.

- memory_block/pal.rs: use an unlinked temp file (mkstemp) instead of
  memfd_create/shm for the block handle. macOS forbids mprotect-ing a MAP_SHARED
  shm region executable (EACCES), but a regular file maps executable like a
  dylib, so the existing mirror/W^X model works unchanged. Also handle the
  macOS errno location (__error) and that MAP_FIXED_NOREPLACE is Linux-only.
- memory_block/tripguard.rs: also hook SIGBUS (macOS raises SIGBUS, not SIGSEGV,
  for protection violations on mapped memory) and read the faulting access type
  from the macOS mcontext (__es.__err); drop the Linux-only sa_restorer field.
- context/interop_macos.s (+ generated interop_macos.bin), context/mod.rs:
  macOS can't repoint the %gs base (no arch_prctl; rdgsbase/wrgsbase #UD under
  Rosetta) and %gs is the OS TSD. The guest only reads its Context ptr from
  gs:0x18; the macOS trampoline leaves gs:0x08/0x10 (errno/mig_reply) alone and
  swaps only gs:0x18 against a free TSD slot at each host/guest boundary.
- host.rs, threading.rs: wrap std::intrinsics::breakpoint in unsafe (newer
  nightly).
- build-release-macos.sh: cross-build the dylib (pinned nightly, low
  deployment target).
OS-gated changes so EmuHawk runs under Mono on macOS; no behavioural change on
Windows/Linux.

- OSTailoredCode: add DllExtension (".dll"/".dylib"/".so"); WaterboxHost uses it
  to load libwaterboxhost.dylib on macOS.
- MemoryBlockLinuxPal: MAP_ANON is 0x20 on Linux/BSD but 0x1000 on macOS; pick
  the right flag (the previous hardcoded 0x22 made mmap fail on macOS).
- SDL2OpenGLContext: still force the x11 video driver on macOS (Mono WinForms is
  X11/XQuartz), but don't force EGL there — XQuartz provides GLX, not EGL.
- OpenGLProvider: report no host OpenGL on macOS. XQuartz's GL is the legacy
  Apple GLX bridge (capped at 2.1, aborts under Rosetta); probing it crashes, so
  cores (melonDS, N64, ...) fall back to their software renderers.
- Assets/EmuHawkMonoMacOS.sh: launcher for macOS. Runs the x86_64 Mono directly
  (NOT via `arch`, which is SIP-protected and strips DYLD_*), forces the X11
  WinForms driver (MONO_MWF_MAC_FORCE_X11) and GdiPlus video (--gdi), and sets
  up DYLD paths incl. /opt/X11/lib for XQuartz.
- Dist/stage-macos-dylibs.sh: symlink the Homebrew-provided deps and the
  Linux-soname aliases (libX11.so.6, etc.) into output/dll, all pointing at one
  consistent Homebrew libX11.
- README: add an experimental macOS (x86_64) section with Intel + Apple silicon
  setup and a clear "not officially supported, don't file issues unless
  reproducible on Win/Linux" warning for maintainers.
- .gitignore: ignore the Mono launcher's captured stdout/stderr logs.
@DarthMDev DarthMDev marked this pull request as draft June 25, 2026 16:19
@DarthMDev DarthMDev marked this pull request as ready for review June 25, 2026 16:40
@YoshiRulz YoshiRulz added the re: Multiplatform Relating to porting to Linux (or macOS, etc.), or porting to other host architectures label Jun 25, 2026

@YoshiRulz YoshiRulz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HYPE

Comment thread Assets/EmuHawkMonoMacOS.sh Outdated
Comment thread Assets/EmuHawkMonoMacOS.sh Outdated
Comment thread Assets/EmuHawkMonoMacOS.sh Outdated
Comment thread Dist/stage-macos-dylibs.sh Outdated
Comment thread Dist/stage-macos-dylibs.sh Outdated
Comment thread src/BizHawk.Common/MemoryBlock/MemoryBlockLinuxPal.cs Outdated
Comment thread src/BizHawk.Common/OSTailoredCode.cs Outdated
Comment thread .gitignore Outdated
Comment thread src/BizHawk.Emulation.Cores/Waterbox/WaterboxHost.cs Outdated
- Merge EmuHawkMonoMacOS.sh into EmuHawkMono.sh via a `uname` case branch;
  use PATH for Mono (respects e.g. a Nix install) instead of a hardcoded path.
- Centralise the [DllImport]-style native library naming in
  DynamicLibraryImportResolver.PlatformFileName(); drop OSTailoredCode.DllExtension
  and use it from WaterboxHost.
- SDL2OpenGLContext: split the macOS branch out from the generic Unix one.
- MemoryBlockLinuxPal: hoist MAP_PRIVATE/MAP_ANON to named consts.
- X11KeyMouseInput: drop the OS check (XOpenDisplay fails cleanly elsewhere; X11
  works under XQuartz on macOS).
- Revert the .gitignore entries (those logs only appear if run from Assets/).
@DarthMDev

Copy link
Copy Markdown
Author

Do we also want to wait for #4784 to be merged? And see how that plays out before this is merged?

@DarthMDev

This comment was marked as resolved.

@YoshiRulz

This comment was marked as resolved.

DarthMDev and others added 5 commits June 26, 2026 18:35
…FileName

- Dist/.BuildInConfigX.sh: on macOS, run stage-macos-dylibs.sh after the build, since
  the build overwrites output/dll and doesn't create the native-library symlinks.
- Dist/.InvokeCLIOnMainSln.sh: read MainVersion with sed instead of `grep -Po`, which is
  GNU-only and absent on macOS/BSD.
- Encore: resolve the core via DynamicLibraryImportResolver.PlatformFileName("encore").
Hopefully fixing CI build
XQuartz's OpenGL is Apple's legacy GLX bridge (capped at GL 2.1 and crashes under
Rosetta), so default DispMethod to the GdiPlus software renderer on macOS instead of
OpenGL. Avoids needing to force --gdi at launch.
The Homebrew/XQuartz deps and the Linux-soname aliases (libX11.so.6, etc.) BizHawk's
P/Invokes and Mono expect can't be shipped as symlinks (they point at the user's Homebrew
install), so create them in ./dll on each launch instead, like the NixOS launch script.
Doing it in the launcher also means they survive a rebuild overwriting output/dll.

- Assets/EmuHawkMono.sh: add the symlink setup to the macOS branch; drop the --gdi force
  (the display method now defaults to GdiPlus on macOS in Config.cs).
- Remove Dist/stage-macos-dylibs.sh and the macOS post-build step in Dist/.BuildInConfigX.sh
  (Package.sh runs in CI and can't make user-specific symlinks).
- README: update the macOS deps (X11 client libs) and launch instructions.
@DarthMDev DarthMDev requested a review from YoshiRulz June 26, 2026 15:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

re: Multiplatform Relating to porting to Linux (or macOS, etc.), or porting to other host architectures

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants