Files
Daniel LynchandClaude Opus 5 1f3dc40c07 docs+build: hygiene pass — close leak risk, de-drift docs, fix build prereqs
Repo hygiene round following a full review. No shim behaviour changes.

Leak risk:
- .gitignore: ignore CLAUDE.md (personal assistant-lane config, was one
  `git add -A` away from a public commit) and scratch_obj/.

Docs vs. reality:
- shim/README.md: rewritten. It described a pre-implementation skeleton with
  "core fns are TODO stubs returning -1005", three mutually inconsistent stub
  counts, and four completed milestones listed as open. Now carries the verified
  breakdown: 438/438 exports = 371 generated stubs + 46 core + 7 layers + 2
  Vulkan queries + 12 passthru trampolines.
- TESTING.md: dropped the self-contradicting "NOT yet" block (5 of 6 items were
  done or misstated, and contradicted the same file 45 lines above). Path B now
  points at tools/desktop-harness, which exists, instead of the orphaned
  shim/tests/harness.c. Path A prereqs marked as the record they are.
- HOST.md: corrected the runtime assumption. The OpenXR runtime inside Lepton is
  SteamVR (vendor/etc/openxr/1/active_runtime.json -> vrclient.so), not Monado.
  Favourable: SteamVR emulates Oculus Touch by default and advertises the
  XR_FB_foveation family, so the existing input and foveation paths should carry
  over. The old "remaining unknowns" are resolved by Lepton's published source
  and replaced with the items to check before a first Frame boot.
- README.md: same runtime correction.
- docs/research/RECON.md: the four passages prescribing an entitlement
  NOP/stub/bypass are corrected in place rather than merely disclaimed by the
  top banner, which they contradicted.

Build correctness:
- shim/build_android.sh: missing patchelf is now fatal. It warned and exited 0,
  producing a .so that cannot resolve the OpenXR loader at runtime.
- scripts/fetch_deps.sh + packaging/build_openxr_loader.sh: pin the OpenXR and
  Vulkan header versions (were tracking `main`), overridable via OPENXR_TAG /
  VULKAN_HEADERS_TAG; require cmake for the loader build.
- packaging/steamframe_patches.sh: use the apktool.jar that fetch_deps.sh
  downloads. Its prereq check demanded an `apktool` binary on PATH that the
  documented setup never provides, so it could not run after a clean setup.
- shim/gen_stubs.sh: it reads all_exports.txt, not shim_surface.txt; comment and
  emitted banner corrected. stubs.c regenerated (banner line only).
- shim/src/core.c: split seven `if (out) ...; return ...;` one-liners. Host
  build now compiles with zero warnings, down from seven.

Verified: host build 0 warnings; gen_stubs.sh output identical on regeneration;
bash -n clean on all edited scripts; pinned header/tarball URLs return 200 and
the tag tarball extracts to the expected directory name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 02:15:10 -04:00

4.0 KiB

libOVRPlugin.so shim (OVRPlugin v1.51 ABI -> OpenXR)

Drop-in replacement for RE4 VR's libOVRPlugin.so. It re-exports the ovrp_* C ABI the game calls and implements it on OpenXR + Vulkan instead of Meta's libvrapi.so.

Status: working. RE4 VR boots and is playable on a Quest 2 through this shim on Meta's OpenXR runtime — stereo rendering, head and controller tracking, buttons, grips, haptics, and save loading. Steam Frame is the next target; see ../HOST.md.

Export surface

The artifact exports 438/438 ovrp_* symbols, matching ../analysis/all_exports.txt exactly (0 missing, 0 extra), so any dlsym of any ovrp_ resolves even for the ~199 entry points RE4 never references.

Source Exports What
src/stubs.c (generated) 371 103 Unsupported (-1004), 67 no-op Success (0), 201 NotYetImplemented (-1005)
src/core.c 46 lifecycle, frame loop, poses, controller, system info
src/layers.c 7 SetupLayer / GetLayerTexture2 / stage count / eye layer desc
src/vk_session.c 2 the Vulkan instance/device extension queries
src/passthru.c 12 trampolines for calls the game makes that need no real impl

gen_stubs.sh regenerates src/stubs.c from ../analysis/all_exports.txt; functions prototyped in the header are skipped there (67 of them) and implemented in core.c. Regeneration is deterministic — re-running it on a clean tree produces no diff.

Layout

  • include/ovrplugin_shim.h — the ovrp_* C ABI: types, structs, core prototypes. Independently written against the observed ABI, with _Static_asserts pinning the binary-verified struct sizes so a layout mistake fails the build rather than the device.
  • src/xr_runtime.{c,h} — the OpenXR engine: instance/session lifecycle, the frame loop, swapchains, layer composition, foveation, perf levels.
  • src/vk_session.c — Vulkan graphics binding, image enumeration, the tile-memory flush.
  • src/layers.c — layer setup and eye layer geometry.
  • src/xr_input.c — action sets and controller/haptics mapping.
  • src/android_init.c — JavaVM/activity capture, xrInitializeLoaderKHR, Android instance create-info chaining.
  • src/passthru.c — the author-only A/B diagnostic (see below).
  • src/stubs.c — generated.

Roughly 48 distinct OpenXR entry points are used.

Build

The deployable artifact is Android arm64 — the game runs inside Horizon OS or Lepton:

../scripts/fetch_deps.sh      # OpenXR + Vulkan headers, NDK, JDK, build-tools
./build_android.sh            # -> build/arm64/libOVRPlugin.so

Needs the NDK (r27c) and patchelf (to add NEEDED libopenxr_loader.so). Then ../packaging/repack.sh swaps it into your own dumped APK.

Host build is compile-validation plus the desktop OpenXR harness, not a shipping artifact:

./build_host.sh               # -> ../build/host/{libOVRPlugin.so,harness}
../tools/desktop-harness/run.sh

Needs libvulkan and an OpenXR loader; without the loader it builds the objects and stops.

Debug: passthru forwarding (author-only diagnostic)

debug.re4vr.passthru=1 hands the whole OVRPlugin session to a real, SONAME-patched libOVRPlugin_real.so if one is present in the APK — an A/B harness for diffing native runtime behaviour against the shim. No such binary is included or distributed by this repo; you would have to place one from your own device dump, and without it the flag is inert. All other debug.re4vr.* props are likewise diagnostics.

Known gaps

  • Depth layer submission is gated behind debug.re4vr.depth and off by default; Meta's runtime accepts but does not use plain KHR depth for reprojection.
  • Input binds /interaction_profiles/oculus/touch_controller only.
  • Several debug.re4vr.* paths are documented dead ends kept for reference (copy-ring, render-ahead, submithook); see ../docs/research/ for what each one ruled out.

See ../docs/research/SHIM-SCOPE.md for how the surface was scoped, ../TESTING.md for the test plan, and ../docs/README.md for the research trail.