diff --git a/BUILDING_INTEL_MAC.md b/BUILDING_INTEL_MAC.md new file mode 100644 index 0000000..1557b2b --- /dev/null +++ b/BUILDING_INTEL_MAC.md @@ -0,0 +1,164 @@ +# Building on Intel Mac (AMD GPU) + +This documents the changes required to build and run `BanjoRecompiled` on an +Intel Mac with an AMD Radeon GPU. By default the app crashes at launch on this +hardware due to a bug in how Metal argument buffers are set up. + +Tested on: Intel MacBook Pro, AMD Radeon 555X (AMDMTLBronzeDriver), macOS 15.7.4. + +--- + +## Toolchain + +| Tool | Version | Use | +|------|---------|-----| +| Apple Clang (Xcode) | 16.0 | Host C++/ObjC/Metal compilation | +| Homebrew LLVM | 22 | MIPS cross-compilation for `patches/` only | +| Homebrew lld | 22 | MIPS linker for `patches/` only | +| Homebrew zlib | any | Runtime dependency for `dxc-macos` | + +Apple Clang does not include a MIPS backend, so Homebrew LLVM remains +necessary for the `patches/` directory. It is not used for any host code. + +--- + +## One-time setup + +### 1. Install Xcode + +Full Xcode (not just Command Line Tools) is required for the `metal` shader +compiler. + +```sh +# Install via xcodes (recommended) or from the App Store +brew install --cask xcodes +xcodes install # pick the latest stable release +sudo xcode-select -s /Applications/Xcode.app/Contents/Developer +``` + +### 2. Install Homebrew tools + +```sh +brew install llvm lld zlib cmake ninja +brew install rust # for bk_rom_decompress +``` + +### 3. Create the dxc libz symlink + +`dxc-macos` (the shader compiler bundled with rt64) looks for `libz.dylib` via +its rpath. macOS only ships libz in the dyld shared cache — there is no +standalone file. Create the symlink once after cloning: + +```sh +mkdir -p lib/rt64/src/contrib/dxc/bin/lib/zlib.net/v1/lib +ln -s /usr/local/opt/zlib/lib/libz.dylib \ + lib/rt64/src/contrib/dxc/bin/lib/zlib.net/v1/lib/libz.dylib +``` + +--- + +## Configure and build + +```sh +# Create the resources directory (required before first build — see note below) +mkdir -p build/resources + +cmake -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DPATCHES_C_COMPILER=/usr/local/opt/llvm/bin/clang \ + -DPATCHES_LD=/usr/local/opt/lld/bin/ld.lld + +cmake --build build --target BanjoRecompiled -j$(sysctl -n hw.ncpu) +``` + +No `CMAKE_C_COMPILER` or `CMAKE_CXX_COMPILER` flags are needed — CMake picks +up Apple Clang from Xcode automatically. + +> **Note on `mkdir -p build/resources`:** `apple_bundle.cmake` runs +> `iconutil -o resources/AppIcon.icns` without first creating the `resources/` +> directory. The directory must exist before the first build or iconutil will +> fail with "Failed to generate ICNS." + +The finished app bundle will be at `build/BanjoRecompiled.app`. + +--- + +## Source changes on this branch + +### 1. Metal rendering fix — `lib/rt64/src/contrib/plume/plume_metal.cpp` + +**Root cause:** On macOS 11+, all GPUs are reported as Metal Argument Buffers +Tier 2. The `MetalDescriptorSet` constructor therefore skips calling +`setArgumentBuffer()` on the argument encoder (because `useArgumentBuffersTier2 += true`). However, Intel Mac AMD GPUs do not support Metal3 / direct buffer +addresses (`useDirectBufferAddresses` is false). + +The original code had two distinct bugs for this hardware: + +1. **Crash** — Buffer binding called `argumentEncoder->setBuffer(...)` without + first binding a backing buffer, crashing inside + `AMDMTLBronzeDriver -[BronzeMtlIndirectArgumentBufferEncoder setBuffer:offset:atIndex:]`. + +2. **Black screen** — Texture and sampler binding wrote `gpuResourceID()` values + directly into the argument buffer (the Metal3 bindless path). Intel AMD GPUs + do not support this pattern and produce black output. Textures and samplers + must also be written via the argument encoder on non-Metal3 hardware. + +**Fix:** In `MetalDescriptorSet::setDescriptor` and `bindImmutableSamplers`, +gate all three resource-type paths on `useDirectBufferAddresses` (not on the +broader `useArgumentBuffersTier2`). For buffers, textures, and samplers alike, +call `setArgumentBuffer()` before any encode operation in the non-Metal3 path: + +```cpp +// In the else-branch of `if (device->useDirectBufferAddresses)` — +// applies to buffers, textures, and samplers +argumentBuffer.argumentEncoder->setArgumentBuffer(argumentBuffer.mtl, + argumentBuffer.offset); +// then setBuffer / setTexture / setSamplerState as appropriate +``` + +These calls are no-ops on Apple Silicon and any other Metal3-capable hardware +since those devices always take the direct-address path. + +**Upstream PR:** [renderbag/plume#94](https://github.com/renderbag/plume/pull/94) + +--- + +### 2. Patches Makefile — `patches/Makefile` + +**Root cause:** Clang 21+ promotes `-Wincompatible-pointer-types` from a +warning to a hard error in C mode. The `patches/` directory is +cross-compiled for MIPS and several files contain implicit pointer type +conversions (e.g. `Mtx *` passed where `float (*)[4]` is expected) that older +compilers accepted silently. + +**Fix:** Add `-Wno-incompatible-pointer-types` to `CFLAGS` in +`patches/Makefile`. This is consistent with the existing +`-Wno-cast-function-type-mismatch` flag already present for the same reason. + +```diff +- -Wall -Wextra ... -Wno-cast-function-type-mismatch -Werror=pointer-bool-conversion ++ -Wall -Wextra ... -Wno-cast-function-type-mismatch -Wno-incompatible-pointer-types -Werror=pointer-bool-conversion +``` + +Note: this flag is only needed with LLVM 21+. With LLVM ≤ 20 or Apple Clang +(if it ever gains a MIPS backend), the original code would compile as warnings +only. + +--- + +## What was investigated but not needed + +The following issues arose when building with Homebrew LLVM 22 + the macOS +11.1 SDK (an older approach). They are **not needed** with Apple Clang + +macOS 15 SDK: + +- **`task_id_token_t` fallback** (`MTLResource.hpp`) — introduced in macOS 13 + SDK; present in macOS 15 SDK. +- **`maximumFramesPerSecond` cast** (`plume_apple.mm`) — method undeclared in + SDK 11.1 causing return type inference as `id`; properly declared in + SDK 15. +- **`fmt/format.h` missing ``** — LLVM 22's libc++ is stricter than + Apple's libc++ about implicit inclusion. +- **`rt64_texture_cache.cpp` json iterator cast** — same LLVM 22 libc++ + strictness issue with `std::char_traits`. diff --git a/lib/rt64 b/lib/rt64 index f0d8c9f..0ee1026 160000 --- a/lib/rt64 +++ b/lib/rt64 @@ -1 +1 @@ -Subproject commit f0d8c9f29b579a143744f76c222899dc82c12e81 +Subproject commit 0ee1026fa9b4f3fb383a0540ce4d0cbb3f15d7eb diff --git a/patches/Makefile b/patches/Makefile index 189ada2..639b2b1 100644 --- a/patches/Makefile +++ b/patches/Makefile @@ -6,7 +6,7 @@ LD ?= ld.lld GBI_DEFINE := -DF3DEX_GBI CFLAGS := -target mips -mips2 -mabi=32 -O2 -G0 -mno-abicalls -mno-odd-spreg -mno-check-zero-division \ -fomit-frame-pointer -ffast-math -fno-unsafe-math-optimizations -fno-builtin-memset -funsigned-char -fno-builtin-sinf -fno-builtin-cosf \ - -Wall -Wextra -Wno-incompatible-library-redeclaration -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-variable -Wno-missing-braces -Wno-unsupported-floating-point-opt -Wno-cast-function-type-mismatch -Werror=pointer-bool-conversion + -Wall -Wextra -Wno-incompatible-library-redeclaration -Wno-unused-parameter -Wno-unknown-pragmas -Wno-unused-variable -Wno-missing-braces -Wno-unsupported-floating-point-opt -Wno-cast-function-type-mismatch -Wno-incompatible-pointer-types -Werror=pointer-bool-conversion CPPFLAGS := -nostdinc -D_LANGUAGE_C -DMIPS -I ../lib/bk-decomp/include -I ../lib/bk-decomp/include/2.0L -I ../lib/bk-decomp/include/2.0L/PR -I../lib/rt64/include -I../lib/N64ModernRuntime/ultramodern/include $(GBI_DEFINE) LDFLAGS := -nostdlib -T patches.ld -T syms.ld -Map patches.map --unresolved-symbols=ignore-all --emit-relocs