Skip to content
Open
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
164 changes: 164 additions & 0 deletions BUILDING_INTEL_MAC.md
Original file line number Diff line number Diff line change
@@ -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 `<cstdlib>`** — 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<unsigned char>`.
2 changes: 1 addition & 1 deletion lib/rt64
Submodule rt64 updated from f0d8c9 to 0ee102
2 changes: 1 addition & 1 deletion patches/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down