Repository navigation
EngineHost Overview
native/EngineHost is the native host runtime that the statically translated Halo PC 1.10 executable runs inside. The translator (see Static Translation Pipeline) turns every x86 function of halo.exe into a C function that operates on an EngineCPU register file and a flat 4 GiB guest address space; EngineHost supplies everything that the original executable expected Windows to provide: the PE loader, the guest address space and heaps, every imported Win32/DirectX API as a native "shim", threads and synchronization, and the Metal/AudioQueue/GameController back ends behind Direct3D 9, DirectSound and DirectInput. The same sources are linked two ways: into the desktop halo-host command-line binary (macOS, via the Makefile) and into the visionOS HaloVision.app (via native/EngineVision/project.yml).
This page is the map of the directory: what every file is for, how the files are assembled into translation units, how the host is built and linked, and how a run proceeds from process start to the translated game loop.
The tables below list every file in native/EngineHost. "TU" marks a file compiled as its own translation unit; everything else is a header or an .inc fragment textually included into a TU (see Inclusion structure).
| File | Lines | Kind | Role |
|---|---|---|---|
main.c |
40 | TU (desktop only) |
halo-host entry point: parses <game dir> [--quiet] [--frames N], starts the 1.5 GiB-stack game thread, services the AppKit run loop. |
host.c |
672 | TU | PE image loader, guest address space, guest heap and page allocators, handle table, import binding and dispatch of magic import addresses, guest thread contexts (TEB/TLS), crash diagnostics, host_run. See Guest Memory and Heap. |
host.h |
123 | header | Shared host API: guest memory accessors (GPTR, G32, S32...), shim calling macros (ARG, RET_STDCALL, RET_CDECL, SHIM), allocator/handle/path prototypes, HOST_ENV. |
host_path.inc |
41 | inc → host.c
|
host_path(): Windows path to case-correct host path under the game root. See Win32 Compatibility Layer. |
host_snapshot.h |
36 | inc → host.c
|
Test-only resident-memory capture at a chosen guest PC (HALO_CAPTURE_PC/HALO_CAPTURE_DIR) for instruction differential tests. |
shims_kernel32.c |
636 | TU | KERNEL32 shims: process/module, memory, TLS, time, Sleep accounting, cache-read waits, locale, files, async I/O and APCs, resources, console, sync and threads. See Win32 Compatibility Layer. |
shims_misc.c |
446 | TU | USER32 (windows, message queue, dialogs), GDI32, ADVAPI32 (registry emulation, CryptoAPI hashes, security stubs), OLE32/OLEAUT32, WINMM, VERSION, SHELL32, WININET, WinSock, DirectSound entry points, EULA/Keystone/NVCPL/Bink/Vorbis stand-ins. |
threading.c / threading.h
|
491 / 52 | TU / header | pthread-backed events, mutexes, guest threads (QoS, suspend/resume, cancellation), waits with telemetry, critical sections. See Threading and Synchronization. |
resources.c |
98 | TU | Reads PE resources from halo.exe/strings.dll on disk: LoadStringA string tables, FindResource*, and DLGTEMPLATEEX parsing that chooses which dialog button to "press". |
ddraw.c |
52 | TU | Minimal IDirectDraw7 so the game's display probing succeeds (mode list, refresh rate, device identifier). |
overrides.c |
265 | TU |
engine_dispatch_override: the hook point that lets native code replace or observe specific translated engine functions. See Engine Overrides and Hooks. |
campaign_unlock.h |
11 | header → overrides.c
|
In-memory campaign unlock (HALO_UNLOCK_CAMPAIGN=1). |
hsc_trace.inc |
172 | inc → overrides.c
|
Read-only HSC (Halo script) thread trace at the script scheduler (HALO_HSC_TRACE). |
a10_control.inc |
46 | inc → overrides.c
|
HALO_A10_TRACE main-loop/BSP/material diagnostics at engine call boundaries. |
a10_gamepad.inc |
110 | inc → overrides.c
|
HALO_A10_GAMEPAD=1 session-only default gamepad bindings written into a fresh profile's empty binding slots. See Input and Controllers. |
audio_ownership_trace.inc |
87 | inc → overrides.c
|
HALO_AUDIO_OWNERSHIP_TRACE=1 observations of the engine's sound-tag ownership around three sound functions. See Audio System. |
gather_diagnostics.h |
18 | header |
HostGatherDiagnostics counters for the native BSP gather (HALO_NATIVE_GATHER), read by the app's report. |
halo_settings.c / halo_settings.h
|
154 / 88 | TU / header | Live, lock-free presentation settings seeded from environment variables and changed by the Swift settings panel. See Runtime Settings. |
pointer.c / pointer.h
|
98 / 35 | TU / header | Gaze/head pointer: steers the engine's own menu cursor toward the gaze target and turns pinches into clicks. See Engine Overrides and Hooks. |
pointer_step.inc |
28 | inc → pointer.c and its test |
Pure servo step through the inverse of the engine's measured mouse acceleration curve. |
core_telemetry.h |
178 | header | Measurement-only Present-to-Present frame arithmetic, including the game-time tick counter read. See Diagnostics and Telemetry. |
| File | Lines | Kind | Role |
|---|---|---|---|
d3d9.c |
1003 | TU | Direct3D 9 COM objects in guest memory with native method shims; Present, device reset, resources. See Direct3D9 Bridge. |
d3d9_render.inc |
1086 | inc → d3d9.c
|
Draw/state bridge to Metal. See Direct3D9 Bridge. |
d3d9_capture.inc |
226 | inc → d3d9_render.inc
|
Opt-in render capture diagnostics. See Diagnostics and Telemetry. |
d3d9_process_vertices.inc |
53 | inc → d3d9_render.inc
|
ProcessVertices differential switch (HALO_PV_DIFFERENTIAL). See Geometry Fast Paths. |
fp_vertex_capture.inc |
104 | inc → d3d9_capture.inc
|
One-frame first-person vertex capture. |
model_vertex_capture.inc |
235 | inc → d3d9_capture.inc
|
One-frame actor model capture. |
model_capture_hooks.inc |
42 | inc → overrides.c
|
Engine-boundary side of the model capture (HALO_MODEL_CAPTURE). |
model_capture_boundary.h, model_capture_scope.h
|
12 / 25 | header | Model capture records and scope stack. |
metalrenderer.m / metalrenderer.h
|
2935 / 366 | TU (ObjC) / header | Offscreen Metal rasterizer. See Metal Renderer. |
metalshader.c / metalshader.h
|
205 / 58 | TU / header | D3D9 shader bytecode to Metal via MojoShader. See Shader Translation. |
metalwin.m / metalwin.h
|
330 / 56 | TU (ObjC, desktop only) / header | Cocoa window + CAMetalLayer that presents the framebuffer on macOS. The visionOS app supplies its own implementation of the metalwin.h API. |
texture_decode.c / texture_decode.h
|
240 / 80 | TU / header | D3D surface formats to BGRA8. See Textures and Texture Packs. |
texture_mips.h, texture_content_hash.h
|
32 / 18 | header | Box-filter mips; XXH3 texture cache keys. |
texture_mod_pack.h, texture_mod_runtime.inc
|
79 / 54 | header / inc → d3d9_render.inc
|
Replacement texture pack (HALO_TEXTURE_PACK). See Textures and Texture Packs. |
shader_mod_pack.h, shader_mod_runtime.inc
|
52 / 33 | header / inc → d3d9.c
|
Replacement shader pack (HALO_SHADER_PACK). See Shader Translation. |
stateblock.h |
70 | header | D3D9 state block recording. See Direct3D9 Bridge. |
rhw_declaration.h |
32 | header | Recognizes Halo's POSITIONT declarations as RHW layouts. |
process_vertices.h, process_vertices_skin.h, process_vertices_differential.h, vertex_shader_cpu.h
|
134 / 51 / 60 / 94 | header | CPU vertex shader execution for ProcessVertices, skinning fast path. See Geometry Fast Paths. |
visible_surfaces.h |
237 | header → overrides.c
|
Native visible-triangle marking (00553920). See Geometry Fast Paths. |
native_leaves.h, native_gather.h, native_gather_tree.h
|
454 / 205 / 218 | header → overrides.c
|
Bit-exact native replacements of hot compute-only engine functions and BSP gather loops. See Geometry Fast Paths. |
radial_fog.h |
229 | header | Bearing-invariant fog (HALO_RADIAL_FOG=1). See Radial Fog. |
| File | Lines | Kind | Role |
|---|---|---|---|
panorama.h |
137 | header | Panorama public API and status values. See Panorama System. |
panorama_hooks.inc |
690 | inc → overrides.c
|
Engine-side multi-view rendering hooks. See Panorama System. |
panorama_render.inc |
430 | inc → d3d9_render.inc
|
D3D-side panorama layer production. |
panorama_budget.h, panorama_lod.h
|
397 / 232 | header | Bearing budget and LOD. See Panorama Budget and LOD. |
panorama_overlay_scope.h |
26 | header | Camera-relative overlay entry addresses. |
frame_pacer.h, frame_pacing_hooks.inc
|
350 / 165 | header / inc → overrides.c
|
Optional 90 Hz grid publication pacing. See Frame Pacing. |
| File | Lines | Kind | Role |
|---|---|---|---|
directsound.c / directsound.h
|
882 / 120 | TU / header | DirectSound 8 COM emulation and AudioQueue output. See Audio System. |
directsound_engine_state.inc |
176 | inc → directsound.c
|
Read-only engine sound state for the device report. |
directsound_mixer.c / directsound_mixer.h
|
341 / 86 | TU / header | Float stereo mixer, 3D voices. See Audio System. |
vorbis_shim.c / vorbis_shim.h
|
137 / 8 | TU / header | The four VORBISFILE.dll calls on top of stb_vorbis. |
audio_source_identity.h |
9 | header | XXH-based audio source identity. |
dinput8.c |
721 | TU | DirectInput 8 keyboard/mouse/joystick. See Input and Controllers. |
gamecontroller.m / gamecontroller.h / gamecontroller_guard.h
|
477 / 122 / 83 | TU (ObjC) / header | Apple GameController snapshot bridge and Bluetooth link guard. See Input and Controllers. |
haptics.c / haptics.h
|
145 / 36 | TU / header | Haptics synthesized from mixed audio. See Haptics. |
| Path | Role |
|---|---|
tests/ |
111 entries: C/ObjC unit and differential tests (test_*.c, test_*.m), the Python hook-coverage check test_dispatch_interest.py, and x87 stack-model test support files. Most tests #include the production .c file directly so the fixture cannot drift from the shipped code. See Testing and Source Checks. |
third_party/xxhash/ |
Vendored xxhash.h (with LICENSE and UPSTREAM.json), used for texture content hashing and audio source identity. |
Several large subsystems are split into .inc fragments that are textually included into a single translation unit, so that they can share static state without exported symbols. The complete map, verified with grep '#include ".*\.inc"':
flowchart LR
host_c["host.c"] --> host_path["host_path.inc"]
host_c --> host_snapshot["host_snapshot.h"]
pointer_c["pointer.c"] --> pointer_step["pointer_step.inc"]
directsound_c["directsound.c"] --> ds_state["directsound_engine_state.inc"]
d3d9_c["d3d9.c"] --> d3d9_render["d3d9_render.inc"]
d3d9_c --> shader_mod["shader_mod_runtime.inc"]
d3d9_render --> d3d9_capture["d3d9_capture.inc"]
d3d9_render --> d3d9_pv["d3d9_process_vertices.inc"]
d3d9_render --> pano_render["panorama_render.inc"]
d3d9_render --> tex_mod["texture_mod_runtime.inc"]
d3d9_capture --> fp_cap["fp_vertex_capture.inc"]
d3d9_capture --> model_cap["model_vertex_capture.inc"]
overrides_c["overrides.c"] --> a10c["a10_control.inc"]
overrides_c --> a10g["a10_gamepad.inc"]
overrides_c --> hsc["hsc_trace.inc"]
overrides_c --> pano_hooks["panorama_hooks.inc"]
overrides_c --> pacing["frame_pacing_hooks.inc"]
overrides_c --> model_hooks["model_capture_hooks.inc"]
overrides_c --> audio_own["audio_ownership_trace.inc"]
overrides_c --> leaves["native_leaves.h / native_gather.h / native_gather_tree.h / visible_surfaces.h"]
| Including file | Line | Included fragment |
|---|---|---|
host.c |
55 |
host_snapshot.h (defines a static function, so it behaves as a fragment) |
host.c |
426 | host_path.inc |
pointer.c |
33 |
pointer_step.inc (also included by tests/test_pointer_step.c) |
directsound.c |
631 | directsound_engine_state.inc |
d3d9.c |
308-309 |
d3d9_render.inc, shader_mod_runtime.inc
|
d3d9_render.inc |
118-119, 194, 319 |
d3d9_capture.inc, d3d9_process_vertices.inc, panorama_render.inc, texture_mod_runtime.inc
|
d3d9_capture.inc |
224, 226 |
fp_vertex_capture.inc, model_vertex_capture.inc
|
overrides.c |
107 | visible_surfaces.h |
overrides.c |
167-177 |
a10_control.inc, a10_gamepad.inc, hsc_trace.inc, panorama_hooks.inc, frame_pacing_hooks.inc, model_capture_hooks.inc, audio_ownership_trace.inc, native_leaves.h, native_gather.h, native_gather_tree.h, gather_diagnostics.h
|
Header chains worth knowing: native_gather_tree.h includes native_gather.h, which includes native_leaves.h; both panorama_hooks.inc and frame_pacing_hooks.inc include frame_pacer.h.
The include order inside overrides.c matters: frame_pacing_hooks.inc is documented as "included after panorama_hooks.inc", and all of the hook fragments rely on the Override typedef declared just before them (overrides.c:166).
flowchart TB
subgraph gen["native/build/engine-reuse/whole-exe (generated)"]
chunks["chunk_000..031.c (include sub_XXXXXXXX.c)"]
bundle["engine_bundle.c (engine_dispatch, engine_reuse_entry)"]
imports["engine_imports.c (sections, IAT, entry point, TLS dir)"]
end
subgraph host["native/EngineHost"]
core["host.c threading.c shims_*.c overrides.c resources.c ddraw.c halo_settings.c pointer.c"]
gfx["d3d9.c metalrenderer.m metalshader.c texture_decode.c"]
av["directsound*.c vorbis_shim.c dinput8.c gamecontroller.m haptics.c"]
desk["main.c metalwin.m"]
end
mojo["third_party/mojoshader (4 files)"]
app["native/EngineVision Sources (Swift + EngineVisionRuntime.m)"]
gen --> hh["halo-host (Makefile)"]
core --> hh
gfx --> hh
av --> hh
desk --> hh
mojo --> hh
gen --> va["HaloVision.app (project.yml / Xcode)"]
core --> va
gfx --> va
av --> va
mojo --> va
app --> va
Makefile builds a macOS arm64 command-line runner.
| Variable / target | Value / effect |
|---|---|
VISION |
repository root ($(abspath ../..)) |
GEN |
$(VISION)/native/build/engine-reuse/whole-exe (generated translation output) |
OBJ |
$(GEN)/host-obj (all objects, host and generated) |
CFLAGS |
-O2 -w -std=c11 -DENGINE_FLAT_MEMORY=1 -DHALO_ARM64_FENV_FAST=1 -I. -I$(VISION)/native/EngineReuse -I$(GEN) (Makefile:6) |
CHUNKS |
every $(GEN)/chunk_*.c; each chunk object additionally depends on the sub_*.c files it includes, extracted with sed at parse time (Makefile:12) |
HOST_SRCS |
host.c threading.c haptics.c halo_settings.c pointer.c shims_kernel32.c shims_misc.c d3d9.c texture_decode.c metalshader.c dinput8.c ddraw.c directsound.c directsound_mixer.c vorbis_shim.c resources.c overrides.c main.c (Makefile:13) |
HOST_OBJC |
metalwin.m metalrenderer.m gamecontroller.m, compiled with -ObjC -fobjc-arc
|
MOJO_DEFINES / MOJO_OBJS
|
MojoShader built with every profile except Metal disabled (SUPPORT_PROFILE_*=0) and MOJOSHADER_NO_VERSION_INCLUDE=1
|
all (default) |
halo-host |
$(GEN)/engine_bundle.c |
runs tools/generate_engine_reuse.py @decompilation/c9acf0c46954/function-addresses.txt @decompilation/c9acf0c46954/extra-function-entries.txt --label whole-exe --max-functions 10000 --trap-unsupported --discover --chunks 32 (Makefile:25-26) |
$(GEN)/engine_imports.c |
runs tools/export_engine_imports.py (PE sections, import table, entry point, TLS directory) (Makefile:27-28) |
halo-host |
links chunks, engine_bundle.o, engine_imports.o, host objects and MojoShader with -lm -framework Cocoa -framework Metal -framework QuartzCore -framework GameController -framework CoreHaptics -framework AudioToolbox (Makefile:56-57) |
clean |
removes $(OBJ) and halo-host
|
The extra dependency lines at Makefile:21-23, 48-52 and 63-67 exist because of the .inc structure: overrides.o must be rebuilt when any hook fragment changes, d3d9.o when any render fragment changes, host.o when host_snapshot.h changes, and every object that uses threading.h when it changes. Generated objects also depend on engine_hooks.h, engine_cpu.h, engine_arm64_fenv_prototype.h and engine_flags.h (Makefile:30), because changing the hook list changes how every translated call site is compiled (see Engine Overrides and Hooks).
Note that the Makefile's CFLAGS do not include -frounding-math -ffp-contract=off, which the visionOS target and several source-check tests pass; see x87 Floating Point for why those flags matter to the translated code.
native/EngineVision/project.yml lists the EngineHost sources individually: host.c, shims_kernel32.c, shims_misc.c, directsound.c, directsound_mixer.c, haptics.c, halo_settings.c, pointer.c, vorbis_shim.c, d3d9.c, texture_decode.c, metalshader.c, dinput8.c, ddraw.c, resources.c, overrides.c, gamecontroller.m, threading.c, metalrenderer.m, the four MojoShader files, and the generated chunk_*.c, engine_bundle.c and engine_imports.c. It compiles them with OTHER_CFLAGS including -frounding-math -ffp-contract=off -DENGINE_FLAT_MEMORY=1 -DHALO_ARM64_FENV_FAST=1 and the MojoShader profile switches, at -O2 in Release and -O0 otherwise.
Two desktop files are deliberately absent, and the app provides replacements:
| Desktop symbol | Desktop source | visionOS replacement |
|---|---|---|
main() and host_command_line
|
main.c |
EngineVisionRuntime.m defines host_command_line as a 512-byte buffer initialised to "C:\Halo\halo.exe" -window -novideo (EngineVisionRuntime.m:29-30) and starts the engine from enginevision_start
|
metalwin_init, metalwin_present, metalwin_should_close, metalwin_poll
|
metalwin.m |
Implemented in EngineVisionRuntime.m (plus metalwin_present_gpu, metalwin_present_dropped); metalwin_should_close() returns host_quit_requested != 0 (EngineVisionRuntime.m:597) |
See visionOS App and Build System for the app side.
sequenceDiagram
participant M as main thread (main.c)
participant G as game thread (1.5 GiB stack)
participant H as host_run (host.c)
participant E as translated engine
M->>M: build command line + HALO_CMDLINE_EXTRA, parse --quiet / --frames
M->>G: pthread_create(run_thread)
loop until game_done
M->>M: CFRunLoopRunInMode(default, 0.05 s)
end
G->>H: host_run(root/halo.exe, root)
H->>H: mmap 4 GiB guest space, PROT_NONE first 64 KiB
H->>H: sigaltstack + SIGSEGV/SIGBUS handler, SIGALRM heartbeat (15 s)
H->>H: load_image (headers + sections)
H->>H: setup_imports (IAT := magic proc addresses)
H->>H: init EngineCPU, main TEB/PEB/TLS, push return token
H->>E: setjmp, engine_reuse_entry(cpu, PE entry point)
E->>E: CRT startup, WinMain, game loop (imports via shims)
E-->>H: return / host_exit longjmp / engine_fail longjmp
H->>H: dump call ring + CPU, DirectSound shutdown, audio stats
H-->>G: exit status
G->>M: game_done = 1, CFRunLoopStop
M->>M: keep window ~20 s if shown, return status
Step by step:
-
main(main.c:12-40). Requiresargv[1](the game directory containinghalo.exeandmaps/); printsusage: halo-host <game dir> [--quiet] [--frames N]and exits 2 otherwise. The guest command line ishost_command_line("C:\Halo\halo.exe" -window -novideo) withHALO_CMDLINE_EXTRAappended after a space when set.--quietsetshost_trace_imports = 0(silenceshost_trace);--frames Nsetshost_frame_limit, which makes Present callhost_exit(0)after N frames (d3d9.c:743). -
Game thread.
maincreates a thread with a 1.5 GiB native stack (pthread_attr_setstacksize(..., 1536 MiB)). Every translated guest call is also a nested native C call, so guest call depth becomes native stack depth; the source does not record how the 1.5 GiB figure was chosen, but the app refuses to start the engine with anything smaller. The main thread runsCFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.05, true)in a loop so that the Metal window, whichd3d9.ccreates from the game thread viametalwin_init, can be serviced by AppKit. If thread creation fails,host_runis called directly on the main thread. -
host_run(host.c:625-665):- line-buffers
stderr; readsHALO_TRACE_LO/HALO_TRACE_HI(hex) intoengine_trace_lo/hito enable per-instruction PC tracing over that range (engine_pc_trace, host.c:56); - sets
host_game_root; - reserves the guest space with
mmap(NULL, 0x100000000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON)and makes[0, 0x10000)PROT_NONEto trap guest null dereferences; - installs a 256 KiB alternate signal stack and a
SIGSEGV/SIGBUShandler that logs the faulting guest PC, flags a likely guest stack overflow whenesp < 0x100000, dumps theesiobject/vtable, prints a guest backtrace and_exit(4)s (host.c:605-616); - starts a
SIGALRMheartbeat every 15 s that logs PC, instruction count, heap high-water and the current import (host.c:601-604); -
load_imagecopies the first 0x1000 bytes (PE headers) to the image base and each section's raw bytes (clamped to its virtual size) to its virtual address (host.c:513-525); -
setup_importsbinds every IAT slot (see Import resolution); - initialises the main
EngineCPU:fs_base = 0x7FFDE000, failure callbackcpu_failure, x87 init,esp = 0x00100000 + 0x00100000 - 0x100, TEB/PEB/TLS viasetup_thread_teb(..., thread id 1), pushes the return tokenMAGIC_PROC|0,eflags = 0x202; -
setjmp(host_escape)thenengine_reuse_entry(cpu, engine_pe_entry_point), which isengine_dispatch(cpu, entry)in the generated bundle. The PE entry point is the original executable's C runtime startup, which calls the CRT-facing KERNEL32 shims (GetVersionExA,GetCommandLineA,GetStartupInfoA,GetEnvironmentStrings*, heap and TLS functions) and then the game'sWinMain.
- line-buffers
-
Termination paths.
host_runreturns fromsetjmpin one of four ways (host.c:649-664):
setjmp value |
Cause | Return status |
|---|---|---|
| 0 | the entry function returned with pc == MAGIC_PROC ("entry returned normally") |
0 |
| 1 |
engine_fail → cpu_failure longjmp (unimplemented import, unsupported instruction, bad guest access, RaiseException, ...) |
1 |
| 2 |
host_exit(code) on the main context (ExitProcess, TerminateProcess(current), frame limit, quit request, fatal allocation failure) |
code |
| 3 | something dispatched to `MAGIC_PROC | 0` itself ("entry point returned") |
Except for case 2 it dumps the last 48 indirectly dispatched function addresses (engine_record ring, host.c:49-53), then always logs the CPU registers, shuts DirectSound down and logs [audio-result] frames=... nonzero=... peak=....
5. Back in main, if a window was shown (host_window_shown, set by d3d9.c when metalwin_init succeeded) the last frame stays on screen for up to 400 × 50 ms or until the window is closed.
enginevision_start(game_root) (EngineVisionRuntime.m:669) runs on the app side:
- On visionOS, it composes
-vidmode W,H,60fromHALO_VIDMODE, else from theHaloRenderResolutionuser default (accepted if it parses asWxHwithin 640x480 to 4096x3072), else2048,1536,60, and stores it inHALO_CMDLINE_EXTRA(without overwriting an existing value) (EngineVisionRuntime.m:681-695). - Chooses the zero-copy panorama GPU hand-off (
HALO_PANORAMA_GPU; on by default on visionOS, off by default on the Mac). - Appends
HALO_CMDLINE_EXTRAtohost_command_line. - Sets
host_trace_imports = 0, clearshost_quit_requested, and creates the engine worker thread with a 1.5 GiB stack atQOS_CLASS_USER_INTERACTIVE(EngineVisionRuntime.m:729-741). If visionOS refuses the stack size it fails loudly rather than starting with a smaller stack.
engine_worker (EngineVisionRuntime.m:608-667) then installs the device defaults with setenv(..., 0) (never overriding an existing variable; the same list is recorded in mods/runtime-settings.json), applies HALO_DRAW_FASTPATH, points HALO_TEXTURE_PACK/HALO_SHADER_PACK at the bundled packs, decides host_core_telemetry from HALO_CORE_TELEMETRY, and calls the same host_run(runtime_exe, runtime_root) as the desktop. The return status is turned into the app's status text. A stop request from the app sets host_quit_requested; the next Present sees metalwin_should_close() and calls host_exit(0).
flowchart TB
A["export_engine_imports.py: engine_imports[] = {IAT VA, dll, name}"] --> B["setup_imports(): for each import"]
B --> C["host_proc_address(dll, name)"]
C --> D{"(dll,name) already in procs[]?"}
D -- yes --> E["MAGIC_PROC | index"]
D -- no --> F["append to procs[] (max 8192), fn = find_shim(dll, name)"]
F --> E
E --> G["S32(IAT slot, magic)"]
H["guest: call [IAT] / COM vtable call / GetProcAddress result"] --> I["engine_dispatch(cpu, 0xFF00xxxx)"]
I --> J{"address >= 0xFE000000"}
J -- yes --> K["engine_dispatch_external()"]
K --> L{"index 0?"}
L -- yes --> M["longjmp: entry point returned"]
L -- no --> N{"procs[i].fn set?"}
N -- no --> O["log UNIMPLEMENTED import, engine_fail"]
N -- yes --> P["host_current_import = name, then fn(cpu)"]
P --> Q["shim reads ARG(i), RET_STDCALL pops args, eax = result, pc = return address"]
find_shim searches five tables in order: host_shims_kernel32, host_shims_misc, then the tables built at first use by host_shims_d3d9_build, host_shims_dinput8_build and host_shims_ddraw_build (host.c:442-449). DLL names compare case-insensitively with any .dll suffix ignored (dll_equal). COM interfaces are exposed the same way: their methods are entries named Interface::Method (for example IDirectDraw7::GetDisplayMode or IDirectSoundBuffer8::Lock), and the guest-resident vtables are filled with the magic addresses host_proc_address returns, so every COM call crosses the same checked boundary as a normal import. Details of shim calling conventions, dynamic loading (LoadLibraryA/GetProcAddress) and the full API inventory are on Win32 Compatibility Layer.
Within the generated engine_dispatch, the order of checks is: magic addresses (>= 0xFE000000) → engine_dispatch_override (hooks, see Engine Overrides and Hooks) → record in the crash call ring → binary search over the translated function entries → engine_dispatch_external once more → engine_fail("unresolved original engine boundary") (tools/generate_engine_reuse.py:220-231).
| Thread | Created by | Runs |
|---|---|---|
| Desktop main thread | process | AppKit run loop (main.c) |
| Engine thread ("game thread", "presenting thread") |
main.c or enginevision_start
|
host_run, the translated WinMain loop, every D3D9 call and Present |
| Guest threads |
CreateThread shim → host_thread_create
|
Halo's cache-file reader (00443940) and saved-game writer (00538980), each on its own native pthread with its own guest stack and TEB |
| Audio, controller, app UI, compositor threads | host frameworks | Never run guest code; communicate with the engine through locks/atomics (halo_settings, pointer queue, mixer) |
See Threading and Synchronization for the full thread model.
| Facility | Where | Notes |
|---|---|---|
host_log |
host.c:72-74 | Always on; [host] prefix on stderr. |
host_trace |
host.c:75-78 | Only when host_trace_imports is nonzero (desktop default 1; --quiet and the app set 0). |
| Import call trace | host.c:504-505 | Each import's first 8 calls and every power-of-two call count, with the first four stack arguments. |
| Guest backtrace | host.c:33-43 | Scans 128 stack dwords for values in 0x00401000..0x00639596 and names them from <game root>/halo-vision-symbols.txt (lines ADDR name, up to 16384) when present. |
| Call ring | host.c:49-53 | Thread-local ring of the last 256 dispatched addresses; only indirect calls are recorded because direct calls bypass engine_record. |
| PC trace | host.c:56, host.c:627 |
HALO_TRACE_LO/HALO_TRACE_HI hex range. |
| Test capture | host_snapshot.h | With PC tracing on, HALO_CAPTURE_PC (hex) and HALO_CAPTURE_DIR write memory.bin (resident pages above 64 KiB, up to 512 MiB) and state.json (registers, x87 state, region list, "testOnly":true) once. |
| FPCR guard | host.c:406-422 |
host_fp_environment_check() is called once per Present; if the engine thread's FPCR has a non-default rounding mode, FZ, DN, FZ16 or FIZ/AH/NEP bit, it is restored and logged once. Translated x87 code relies on the default FPCR when the guest rounds to nearest. |
- Win32 Compatibility Layer
- Threading and Synchronization
- Guest Memory and Heap
- Engine Overrides and Hooks
- Runtime Settings
- Static Translation Pipeline, EngineReuse Runtime, x87 Floating Point
- Direct3D9 Bridge, Metal Renderer, Shader Translation, Textures and Texture Packs, Geometry Fast Paths, Radial Fog
- Panorama System, Panorama Budget and LOD, Frame Pacing
- Audio System, Input and Controllers, Haptics
- visionOS App, Diagnostics and Telemetry, Build System, Testing and Source Checks
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