Case Studies & ProjectsSystems Researcher
Bloodborne on macOS — Apple Silicon Porting Research
By Burhan Moin
Background
Bloodborne remains a PlayStation-exclusive title with no official PC or Mac port. The game's internal engine (a modified Havok-based engine built for the PS4's GNM graphics API) is a significant distance from macOS and Metal. This project documents my attempt to understand what it would take to run Bloodborne natively on Apple Silicon — not through emulation, but through compatibility layer research and binary analysis.
This is exploratory systems research. No retail game assets are distributed. The work is documented at: github.com/burhanmoin1/bloodborne-macos-native
The PS4 Execution Environment
Architecture
The PS4 uses a modified FreeBSD kernel with a custom x86-64 ABI. The GPU is an AMD GCN 1.1 part addressed through the proprietary GNM/GNMX graphics API. Bloodborne's executable is an ORBIS ELF (Sony's modified ELF format).
Getting from an ORBIS ELF on FreeBSD/x86-64 + GNM to a Mach-O on macOS/ARM64 + Metal involves:
1. Binary format translation (ORBIS ELF → Mach-O)
2. ISA translation (x86-64 → ARM64)
3. Graphics API translation (GNM → Metal)
4. OS API shim (FreeBSD syscalls → macOS equivalents)
Phase 1 — Binary Analysis
I loaded the ORBIS ELF through a custom loader that remaps PS4-specific segment types. LLDB on macOS can attach to x86-64 processes via Rosetta, giving a debugging path for the x86-64 layer before ARM translation is considered.
# Inspect ORBIS ELF structure
readelf -h eboot.bin
readelf -S eboot.bin | grep -E ".text|.data|.rodata|.got"
# Symbol extraction
nm -D eboot.bin | grep -i "render\|shader\|gnm\|draw" | head -50The binary's symbol table (partially stripped but recoverable through the dynamic export table) revealed the GNM command-buffer building functions — the layer I needed to intercept for graphics translation.
Phase 2 — Shader Translation Research
GCN to Metal Shading Language
PS4 shaders are compiled GCN ISA binaries. Metal requires either MSL (Metal Shading Language) source or AIR (Apple Intermediate Representation) bytecode. The translation path I researched was GCN ISA → GLSL (via existing GCN disassemblers) → MSL (via SPIRV-Cross).
GCN ISA binary
↓ gcn-disasm (open source GCN disassembler)
GLSL source
↓ glslang → SPIRV
SPIR-V bytecode
↓ SPIRV-Cross
Metal Shading Language
↓ xcrun metal
AIR bytecode (ready for Metal GPU)I tested this pipeline on isolated shader binaries extracted from game assets. Simple vertex and fragment shaders translated correctly. Complex geometry shaders and compute shaders used GCN-specific wave intrinsics (ds_swizzle, v_cndmask) with no direct MSL equivalent — these required manual mapping.
Phase 3 — GPU Command Buffer Translation
GNM command buffers are a list of PM4 packets — a command protocol shared with AMD's public GPU architecture. I wrote a C++ interceptor that walks a captured GNM command buffer and maps PM4 packets to their Metal equivalents:
// Simplified PM4 → Metal command mapping
void translateDrawIndexAuto(const PM4Packet* pkt, id<MTLRenderCommandEncoder> enc) {
// GNM: DRAW_INDEX_AUTO — indexed draw with auto-generated indices
NSUInteger vertexCount = pkt->count;
[enc drawPrimitives:MTLPrimitiveTypeTriangle
vertexStart:0
vertexCount:vertexCount];
}Performance on M1 Pro
Using a compatibility harness with Rosetta for the x86-64 game logic and a Metal backend for rendering, I measured performance on an M1 Pro MacBook Pro:
Scene: Yharnam opening area (outdoor)
Resolution: 1920×1200 (native display)
Rosetta x86-64 + Metal (translated shaders):
Average FPS: 34
1% low FPS: 21
VRAM usage: 3.8 GB / 16 GB unified
Bottleneck: Rosetta JIT translation overhead on the render thread (~40% CPU overhead vs native ARM64 estimate)Native ARM64 recompilation of the game logic (via ahead-of-time translation with a custom x86-64 → ARM64 recompiler) is the next research direction — expected to push the frame rate above 60 on M1 Pro.
Current Status
The project is ongoing. The shader translation pipeline handles ~70% of Bloodborne's shaders automatically. The remaining 30% (wave-level operations, async compute) require hand-written Metal equivalents. CPU-side is functional via Rosetta. The long-term goal is a full native ARM64 build.
[ Gameplay screenshots and performance graphs to be added here ]
Full documentation and source: github.com/burhanmoin1/bloodborne-macos-native