Repository navigation
Architecture Overview
Master Chef (internal name Halo Vision) runs the original Halo: Combat Evolved for PC 1.10 natively on Apple Vision Pro. It does not emulate a PC. The x86 program is statically translated ahead of time into C, then compiled to ARM64. Everything the program expected from Windows is re-implemented natively: Win32, Direct3D 9, DirectSound, DirectInput, DirectDraw and Ogg Vorbis. A visionOS presenter shows the result as an immersive panorama around the player.
This page shows how the pieces fit together. Each section links to the page
that covers that subsystem in depth. Source links are pinned to commit
9f915af
(v1.0.3, build 103).
flowchart TB
subgraph Offline["Offline (on your Mac)"]
EXE["halo.exe (retail PC 1.10, SHA-256 c9acf0c4...)"]
LISTS["decompilation/c9acf0c46954 entry lists"]
GEN["tools/generate_engine_reuse.py (XWA decoder + strict lifter)"]
IMP["tools/export_engine_imports.py"]
CHUNKS["native/build/engine-reuse/whole-exe: chunk_000..031.c, engine_bundle.c, engine_imports.c"]
EXE --> GEN
LISTS --> GEN
EXE --> IMP
GEN --> CHUNKS
IMP --> CHUNKS
end
subgraph App["HaloVision.app (one visionOS process)"]
direction TB
subgraph Swift["EngineVision (SwiftUI, CompositorServices, ARKit)"]
UI["Windows: launcher, settings, diagnostics"]
PRES["Immersive presenter: curved panels, stereo, HUD"]
end
BRIDGE["EngineVisionRuntime.m (bridge, engine worker thread)"]
subgraph Guest["Translated engine"]
CODE["Generated C: one function per x86 function"]
CPU["EngineReuse: EngineCPU, EFLAGS, x87, memory macros"]
end
subgraph Host["EngineHost (native runtime)"]
W32["Win32 shims: files, registry, threads, heap, time"]
D3D["Direct3D 9 to Metal renderer"]
PANO["Panorama: 10 layers from one simulation step"]
DS["DirectSound mixer to AudioQueue"]
DI["DirectInput from GameController"]
end
UI --> BRIDGE
BRIDGE -->|host_run| CODE
CODE --> CPU
CODE -->|imports and COM calls| Host
PANO -->|GPU texture leases| PRES
DS -->|haptic events| PRES
PRES -->|head pose| PANO
end
CHUNKS -->|compiled into| CODE
DATA["Your game files: maps, Strings.dll, halo.exe image"] -->|loaded at runtime| Host
There are three layers, and they communicate only through narrow interfaces:
-
Guest code. This is the translated program, plus the small
EngineReuseCPU model it is written against. It knows nothing about Apple platforms. It only reads and writes guest memory and callsengine_dispatch. -
EngineHost. This is a C and Obj-C runtime that plays the role of
Windows. It is the same code on the Mac (
halo-host, the desktop probe) and inside the app. - EngineVision. This is the visionOS app. It imports game files, starts the engine thread, presents frames in an immersive space, feeds head pose and settings back, and records diagnostics.
| Step | Tool | Output |
|---|---|---|
| Verify the executable |
setup_halo.py, prepare_engine_vision_device.py (HALO_SHA256) |
Rejects anything except retail PC 1.10. Custom Edition, Anniversary, MCC and Xbox are not supported. |
| Decode | XWA pe_analyze and disasm (Capstone), plus tools/engine_reuse/decode.py
|
Basic blocks for every known entry, plus entries found by --discover
|
| Lift |
tools/engine_reuse/lift.py, flags.py, fpu.py, extra.py
|
One strict C function per x86 function. Unsupported instructions either fail generation or, with --trap-unsupported, trap at runtime. There are no silent no-ops. |
| Chunk | generate_engine_reuse.py --chunks 32 |
32 chunk_NNN.c files plus engine_bundle.c (dispatch table and PE metadata) |
| Imports | export_engine_imports.py |
engine_imports.c (static import table and TLS directory) |
The code bytes are translated. The executable's data is still needed at
runtime: host_run maps a 4 GiB flat guest address space and copies the PE
sections of your halo.exe into it
(host.c:513-524).
That is why the app needs the exact executable even though it never
executes x86 instructions.
Details: Static Translation Pipeline, XWA Decoder and Lifter, Function Address Lists.
-
CPU state.
EngineCPUholds the 8 general registers, EFLAGS,pc, the x87 register file and control word, and the per-thread TEB base (fs_base). Each guest thread has its ownEngineCPU. See EngineReuse Runtime. -
Memory. One flat 4 GiB
mmap. A guest address is an offset fromengine_flat_base. The first 64 KiB isPROT_NONEto catch null pointers. The host carves out a guest heap, a page space forVirtualAlloc, thread stacks, TEBs and the PEB. See Guest Memory and Heap. -
Calls. About 80% of translated call sites are emitted as
ENGINE_DIRECT: a plain C call to the target function. Indirect calls, and calls to addresses listed inengine_hooks.h, go throughengine_dispatch:
flowchart LR
CALL["call target"] --> M{"target >= 0xFE000000?"}
M -- yes --> EXT["engine_dispatch_external: Win32/COM shim"]
M -- no --> OV{"hooked? (64K-bit interest filter)"}
OV -- yes --> OVR["engine_dispatch_override: native replacement or observer"]
OV -- no --> BS["binary search over the translated entry table"]
BS --> FN["sub_XXXXXXXX(cpu)"]
OVR -->|"may call the original"| FN
-
Floating point. The x87 stack is modeled in binary64 with a
rotating register file. Rounding modes map onto the ARM64 FPCR
(
HALO_ARM64_FENV_FAST). App builds use-frounding-math -ffp-contract=offso the compiler does not fuse or reorder operations. See x87 Floating Point.
Imports. At startup, setup_imports writes a magic procedure handle
(0xFF000000 | index) into every import address table slot. When guest
code does call [IAT], the call reaches engine_dispatch_external, which
calls the named native shim. COM interfaces (D3D9, DirectSound,
DirectInput, DirectDraw) use the same mechanism. Their vtables are guest
memory filled with magic handles for names such as
"IDirect3DDevice9::DrawIndexedPrimitive". See
EngineHost Overview and
Win32 Compatibility Layer.
| Windows API | Native implementation | Page |
|---|---|---|
| KERNEL32 (files, memory, threads, sync, time, TLS, APC) |
shims_kernel32.c, threading.c (pthreads) |
Win32 Compatibility Layer, Threading and Synchronization |
| USER32, GDI32, ADVAPI32 (registry), WINMM, OLE32, VERSION, WSOCK | shims_misc.c |
Win32 Compatibility Layer |
| Direct3D 9 |
d3d9.c, d3d9_render.inc, metalrenderer.m, metalshader.c with MojoShader |
Direct3D9 Bridge, Metal Renderer, Shader Translation |
| DirectDraw 7 (display probing only) | ddraw.c |
Direct3D9 Bridge |
| DirectSound 8 |
directsound.c, directsound_mixer.c, then AudioQueue |
Audio System |
| VORBISFILE.dll |
vorbis_shim.c with stb_vorbis |
Audio System |
| DirectInput 8 |
dinput8.c with gamecontroller.m (Apple GameController) |
Input and Controllers |
Overrides. Some engine functions are replaced or wrapped natively, either for speed or for presentation:
- BSP visibility and surface gathers (
visible_surfaces.h,native_gather*.h); - hot math leaves (
native_leaves.h); - vertex skinning in
ProcessVertices; - the renderer entry
0050BEA0, which the panorama runs once per bearing; - campaign unlock;
- script (HSC) tracing.
Each native replacement keeps the translated original reachable through an environment switch for A/B comparison. See Engine Overrides and Hooks and Geometry Fast Paths.
sequenceDiagram
participant G as Guest main loop
participant P as Panorama hooks (0050BEA0)
participant D as D3D9 bridge
participant M as Metal renderer
participant B as Bridge (GPU slot pool)
participant S as Immersive presenter
participant A as DirectSound mixer
G->>P: render frame (one simulation time)
P->>P: plan bearings (budget tier, gaze prediction, LOD)
loop each scheduled bearing or eye
P->>G: run original renderer with rotated camera
G->>D: SetRenderState / SetTexture / Draw*
D->>M: pipeline + sampler + depth state, draw into the layer target
end
G->>D: Present
D->>D: pointer servo, audio watchdog, FP environment check
D->>B: publish layers (zero-copy GPU lease), carry undrawn layers
B-->>S: latest READY slot (10 layer textures + poses + epochs)
S->>S: draw curved panels per eye, feather the seams, HUD layer
S->>P: head yaw/pitch/roll for the next frame
A-->>S: haptic onset events (mailbox)
-
The game's main loop runs on the engine worker thread. The app creates this pthread with a 1.5 GiB stack at
USER_INTERACTIVEQoS (EngineVisionRuntime.m:733-751). -
When the game asks its renderer to draw the frame, the panorama hook runs the original renderer several times from the same simulation state. Each run uses the camera turned to a different bearing. The sphere is covered by 10 layers:
- a ring of six bearings;
- zenith and nadir caps;
- the HUD and interface layer;
- a right-eye centre view for stereo.
A per-frame budget decides which layers are redrawn and which keep an older picture. See Panorama System and Panorama Budget and LOD.
-
Each D3D9 draw is translated into Metal state. Pipelines, samplers and depth/stencil states are cached under bounded caches, and shaders are converted by MojoShader. Texture content is hashed with XXH3. The bundled
.hvtand.hvspacks can replace textures (by TexMod CRC) and shaders. See Textures and Texture Packs. -
At Present, the host does its per-frame chores:
- FP environment repair;
- the gaze-pointer servo;
- the audio watchdog;
- honoring a stop request.
It then publishes the frame. On the headset this is a zero-copy hand-off of layer textures into a 3-slot pool owned by the bridge. Optional Frame Pacing can delay the commit to an even 90 Hz rung.
-
The immersive presenter (CompositorServices, Metal and an ARKit world-tracking provider; no RealityKit) leases the newest complete slot. It draws each layer on curved panels with feathered joins, separately per eye, and draws the HUD on its own layer. It writes the head pose back for the next engine frame. See Immersive Presenter and Layer Alignment.
-
Audio runs independently. Sound data is copied out of guest memory at
Unlock, mixed as float stereo with head-relative panning, and played through an AudioQueue at 48 kHz. Low-frequency onsets in the mix become controller Haptics.
| Thread | Created by | Runs |
|---|---|---|
| Main (UI) thread | visionOS | SwiftUI windows, settings, asset import, diagnostics timer (200 ms) |
| Compositor render thread | CompositorServices | Immersive presenter frame loop and haptics pump |
| Engine worker | enginevision_start |
host_run, then Halo's main loop, D3D9, panorama, Present |
| Guest threads |
CreateThread shim |
Halo's own cache-reader and save-writer threads. Each is a real pthread with its own TEB and guest stack. |
| Metal pipeline workers | metalrenderer.m |
Asynchronous pipeline compilation (HALO_PIPELINE_WORKERS, default 3, max 6) |
| AudioQueue callback | AudioToolbox | Pulls mixed PCM. It never touches guest memory. |
| Audio session queue | audio_session.inc |
Activation, interruption, and media-reset recovery |
| Report writer queue | EngineDiagnosticReportWriter |
report.json, timeline and history writes off the main thread |
See Threading and Synchronization.
Three mechanisms configure the runtime:
-
Compiled launch defaults. On visionOS,
engine_workersets a fixed list ofHALO_*variables withsetenv(..., 0), so an explicit value always wins. The list includes the panorama, dense projection, world-space first-person view, native gathers, the draw fast path, pad-to-key, campaign unlock and telemetry.mods/runtime-settings.jsonrecords this list. -
Live settings (
halo_settings.c). These are lock-free atomics, seeded from the environment and changed from the SwiftUI settings window while the game runs. They cover stereo separation, panorama vertical FOV, haptics strength, backdrop brightness, target FPS, own-weapon gain, gaze pointer, layer alignment and frame pacing. Only the render resolution persists across launches. -
Diagnostic switches. More than 150 default-off
HALO_*variables for traces, captures and A/B comparisons.
See Runtime Settings and Environment Variables.
| Data | Location | Notes |
|---|---|---|
| Game payload | Bundled GamePayload (staged by setup), installed to Application Support/HaloVision/PackagedGames/<payloadID>, or a folder imported to Application Support/HaloVision/Game
|
Checked against a manifest; halo.exe checked by SHA-256 |
| Installation values (registry) |
halo-vision-registry.txt in the game root |
Private; rewritten on RegSetValueExA
|
| Saves and profiles | <game root>/Users/Player/Documents/My Games/Halo |
Win32 paths are mapped case-insensitively by host_path.inc
|
| Visual packs |
TextureMods.hvt, ShaderMods.hvs in the bundle |
Paths are passed to the host through HALO_TEXTURE_PACK and HALO_SHADER_PACK
|
| Diagnostics | App Documents/Diagnostics/
|
report.json, timeline, bounded history, deep-*.jsonl, live.json
|
See visionOS App and Diagnostics and Telemetry.
flowchart LR
ISO["Retail ISO or existing install"] --> SETUP["setup.sh / setup_halo.py"]
SETUP --> GAME["game/ + .setup/GamePayload"]
SETUP --> PACKS[".setup/VisualMods (checksum-pinned)"]
SETUP --> GENR["generate + export imports"]
GENR --> XCG["XcodeGen: project.yml"]
GAME --> XCG
PACKS --> XCG
XCG --> XCODE["Xcode: your Team, your bundle ID"]
XCODE --> AVP["Apple Vision Pro"]
The public repository contains only source. Generated engine code, game files, packs, registrations and signing material are produced locally or downloaded as release assets. They are never committed. See Setup Wizard, Build System, Device Preparation and Signing and Release Process and Hygiene.
- The original engine stays in charge. Halo's own limiter, game time, scripts and renderer run unmodified. The port only re-runs the renderer for extra bearings and observes the engine at function boundaries.
- Exactness first, then speed. Native replacements reproduce the translated routine's float operation order and guest stack stores. They are checked differentially against generated code when that code is available.
- Everything optional can be switched off. Each optimization or presentation feature has an environment switch that restores the original path. This keeps headset A/B runs possible without a rebuild.
- Bounded resources. Every cache, trace, capture and history file has a cap.
-
Honest evidence. Docs and comments separate source checks, desktop
checks, builds, installs and gameplay measurements.
docs/KNOWN_ISSUES.mdlists what has not been established, including stable combat FPS, seamless stitching and full-campaign qualification.
Documents master-chef at commit 9f915af (v1.0.3). Unofficial project, not affiliated with Microsoft, Bungie, Gearbox or Apple. Original code is MIT licensed; game content is not included.
Overview
- Architecture Overview
- Repository Layout
- Glossary
- Environment Variables
- Contributing Guide
- Open Questions
Translation
- Static Translation Pipeline
- XWA Decoder and Lifter
- Function Address Lists
- EngineReuse Runtime
- x87 Floating Point
Host runtime
- EngineHost Overview
- Win32 Compatibility Layer
- Threading and Synchronization
- Guest Memory and Heap
- Engine Overrides and Hooks
- Runtime Settings
Graphics
- Direct3D9 Bridge
- Metal Renderer
- Shader Translation
- Textures and Texture Packs
- Geometry Fast Paths
- Radial Fog
Panorama and presentation
- Panorama System
- Panorama Budget and LOD
- Frame Pacing
- visionOS App
- Immersive Presenter
- Layer Alignment
Audio and input
Tooling and process