Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 3 additions & 2 deletions docs/BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ that basic build as reproduction of the full experimental Public Build.

Run `./Setup-macOS.sh` to install and check prerequisites, or
`./Setup-macOS.sh --skip-deps` to check without installing. Setup and Build's
preparation share the same checks: full Xcode with Metal, GNU Make 4+ (`gmake`),
preparation share the same checks: the Command Line Tools (`xcode-select --install`;
full Xcode is not needed, RT64's Metal shaders compile at runtime), GNU Make 4+ (`gmake`),
CMake, Ninja, Python, SDL2, PCRE2, and a `sha1sum` supporting `-c --quiet`
(Homebrew `coreutils`). The verifier is checked before ROM extraction.

Expand All @@ -188,7 +189,7 @@ Set `DKR_MAC_BUNDLE_VERSION=N[.N[.N]]` for an explicit release/CI build number
Packaging checks the version metadata copied beside the executable after linking,
so a new package label cannot silently rename a build of a different version.

With Xcode setup and Homebrew installed:
With the Command Line Tools and Homebrew installed:

```bash
./Build-macOS.sh --rom-v77 "/path/to/US 1.0.z64" --rom-v80 "/path/to/US Rev A.z64"
Expand Down
12 changes: 12 additions & 0 deletions patches/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@
{
"path": "patches/n64recomp/0002-name-recomp-context-struct.patch",
"sha256": "6cf31eebf6a5f0a9a31c2912f562f8ef977c0a43dfffd76531f3ceb94ae2bee7"
},
{
"path": "patches/n64recomp/0003-null-statement-before-instruction-hooks.patch",
"sha256": "f864ffd285ff4b09f2a3f4e453e5f0e5b2c39e345bc05dd88f47a46b01d3dac7"
}
]
},
Expand Down Expand Up @@ -226,6 +230,10 @@
{
"path": "patches/rt64/0020-ios-imgui-pixel-size.patch",
"sha256": "d346ecb854a422b3c9b0349a72b8217a08e4b0b5dc86e22f5b1ab995d25a7ca5"
},
{
"path": "patches/rt64/0021-macos-runtime-msl-shaders.patch",
"sha256": "441fe5f1dc8edf646d8f4ea3a76d25a65e86fc836aa8ae9cea637c9bde22128b"
}
]
},
Expand Down Expand Up @@ -309,6 +317,10 @@
{
"path": "patches/plume/0002-ios-metal-device-os27-upstream.patch",
"sha256": "a1c559877eaa59a5cf8878c4e0879f15aa5ffbd0455b8e5a5d593289348709ce"
},
{
"path": "patches/plume/0003-compile-msl-source-shaders.patch",
"sha256": "80947b240d7a3bd5e3f9434df7501fc54d130d4e06942e36705f2238d8fb3565"
}
]
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
diff --git a/src/recompilation.cpp b/src/recompilation.cpp
index c228433..afdfe63 100644
--- a/src/recompilation.cpp
+++ b/src/recompilation.cpp
@@ -128,7 +128,10 @@ bool process_instruction(GeneratorType& generator, const N64Recomp::Context& con

auto hook_find = func.function_hooks.find(instr_index);
if (hook_find != func.function_hooks.end()) {
- fmt::print(output_file, " {}\n", hook_find->second);
+ // The leading null statement lets a hook that declares something follow a
+ // branch label under C17 (Clang before 18 rejects it). It is not braced:
+ // hooks declare locals that later hooks in the function read.
+ fmt::print(output_file, " ; {}\n", hook_find->second);
if (indent) {
print_indent();
}
23 changes: 23 additions & 0 deletions patches/plume/0003-compile-msl-source-shaders.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
diff --git a/plume_metal.cpp b/plume_metal.cpp
index b670ed3..f0ca614 100644
--- a/plume_metal.cpp
+++ b/plume_metal.cpp
@@ -1342,8 +1342,16 @@ namespace plume {
functionName->retain();

NS::Error *error = nullptr;
- const dispatch_data_t dispatchData = dispatch_data_create(data, size, dispatch_get_main_queue(), ^{});
- library = device->mtl->newLibrary(dispatchData, &error);
+ // Precompiled libraries start with the "MTLB" magic. Anything else is MSL source,
+ // compiled by the OS so macOS builds don't need Xcode's offline Metal compiler.
+ if ((size >= 4) && (memcmp(data, "MTLB", 4) == 0)) {
+ const dispatch_data_t dispatchData = dispatch_data_create(data, size, dispatch_get_main_queue(), ^{});
+ library = device->mtl->newLibrary(dispatchData, &error);
+ }
+ else {
+ const std::string source(static_cast<const char *>(data), size);
+ library = device->mtl->newLibrary(NS::String::string(source.c_str(), NS::UTF8StringEncoding), nullptr, &error);
+ }

if (error != nullptr) {
fprintf(stderr, "MTLDevice newLibraryWithSource: failed with error %s.\n", error->localizedDescription()->utf8String());
28 changes: 28 additions & 0 deletions patches/rt64/0021-macos-runtime-msl-shaders.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 17563c1..d86dfec 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -163,17 +163,15 @@ function(build_shader_msl_impl TARGETOBJ FILENAME TARGET_NAME OUTNAME)
add_custom_command(OUTPUT ${OUTNAME}.metallib
COMMAND xcrun -sdk ${_dkr_ios_metal_sdk} metallib ${OUTNAME}.ir -o ${OUTNAME}.metallib
DEPENDS ${OUTNAME}.ir)
+ set(_dkr_msl_blob ${OUTNAME}.metallib)
else()
- add_custom_command(OUTPUT ${OUTNAME}.ir
- COMMAND xcrun -sdk macosx metal -o ${OUTNAME}.ir -c ${OUTNAME}.metal $<$<CONFIG:Debug>:-frecord-sources>
- DEPENDS ${OUTNAME}.metal)
- add_custom_command(OUTPUT ${OUTNAME}.metallib
- COMMAND xcrun -sdk macosx metallib ${OUTNAME}.ir -o ${OUTNAME}.metallib
- DEPENDS ${OUTNAME}.ir)
+ # macOS embeds the MSL source; plume compiles it at runtime, so the
+ # build needs no Xcode Metal toolchain.
+ set(_dkr_msl_blob ${OUTNAME}.metal)
Comment on lines +17 to +19

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

RasterShader calls createShader with these blobs for every new combiner/other-mode combo (src/render/rt64_raster_shader.cpp:166-167), so I think every specialized raster shader now recompiles the whole ubershader MSL, not just once at setup. The 2.66 s number only covers setup. We should watch for pop-in during gameplay on a cold cache.

Maybe keep the metallib when xcrun -sdk macosx -f metal resolves at configure time and only embed source when it doesn't? The plume patch already handles both, and CI/release builds keep the old load path and build-time shader errors.

endif()
add_custom_command(OUTPUT ${OUTNAME}.metal.c
- COMMAND file_to_c ${OUTNAME}.metallib ${TARGET_NAME}BlobMSL ${OUTNAME}.metal.c ${OUTNAME}.metal.h
- DEPENDS ${OUTNAME}.metallib file_to_c
+ COMMAND file_to_c ${_dkr_msl_blob} ${TARGET_NAME}BlobMSL ${OUTNAME}.metal.c ${OUTNAME}.metal.h
+ DEPENDS ${_dkr_msl_blob} file_to_c
BYPRODUCTS ${OUTNAME}.metal.h)
target_sources(${TARGETOBJ} PRIVATE ${OUTNAME}.metal.c)
endfunction()
2 changes: 1 addition & 1 deletion runtime-recomp/tests/build_tooling_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,7 @@ def executable(name, body="exit 0"):
p.chmod(0o755)

for name in (
"xcodebuild",
"xcrun",
"git",
"python3",
"cmake",
Expand Down
2 changes: 1 addition & 1 deletion scripts/lib/apple-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

dkr_require_macos() {
[[ "$(uname -s)" == Darwin ]] || {
echo 'Apple builds require macOS with the full Xcode application installed.' >&2
echo 'Apple builds require macOS.' >&2
return 1
}
}
Expand Down
25 changes: 16 additions & 9 deletions scripts/macos-host-tools.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,27 @@ source "${BASH_SOURCE[0]%/*}/lib/apple-build.sh"
dkr_macos_host_tools() {
local skip_deps="$1" make_version probe
dkr_require_macos || return 1
dkr_require_xcode || return 1
# Command Line Tools are enough: RT64's Metal shaders compile at runtime.
xcrun --sdk macosx --show-sdk-path >/dev/null 2>&1 || {
echo 'Install the Command Line Tools: xcode-select --install' >&2
return 1
}
if [[ "$skip_deps" -eq 0 ]]; then
command -v brew >/dev/null || {
echo 'Install Homebrew: https://brew.sh/' >&2
return 1
}
HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_UPGRADE=1 brew install --quiet cmake ninja make pcre2 python sdl2 coreutils || return 1
# Install only what is missing: on macOS releases Homebrew no longer
# bottles, reinstalling a present tool (python) means a failing source build.
Comment on lines +17 to +18

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

brew install on an already-installed formula is a no-op with HOMEBREW_NO_INSTALL_UPGRADE=1, so the failing case is really brew python missing while some other 3.11+ is on PATH. A fresh macOS 14 box with only the CLT python (3.9) still hits brew install python here. Maybe reword the comment so it doesn't read like it fixes that?

local pair missing=()
for pair in cmake:cmake ninja:ninja make:gmake pcre2:pcre2-config sdl2:sdl2-config coreutils:sha1sum; do
command -v "${pair#*:}" >/dev/null || missing+=("${pair%%:*}")
done
# tomllib needs 3.11; the Command Line Tools ship 3.9.
python3 -c 'import sys; sys.exit(sys.version_info < (3, 11))' 2>/dev/null || missing+=(python)
if [[ "${#missing[@]}" -gt 0 ]]; then
HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_UPGRADE=1 brew install --quiet "${missing[@]}" || return 1
fi
fi
dkr_require_tools git python3 cmake ninja c++ shasum sha1sum pcre2-config sdl2-config || {
echo 'Run ./Setup-macOS.sh (sha1sum is supplied by brew install coreutils).' >&2
Expand Down Expand Up @@ -39,11 +53,4 @@ dkr_macos_host_tools() {
return 1
fi
rm -rf -- "$probe"
if ! xcrun metal -v >/dev/null 2>&1; then
if [[ "$skip_deps" -eq 1 ]]; then
echo 'Install Metal: xcodebuild -downloadComponent MetalToolchain' >&2
return 1
fi
xcodebuild -downloadComponent MetalToolchain || return 1
fi
}
Loading