Initial public release: OVRPlugin→OpenXR interoperability shim

An independent reimplementation of Meta's libOVRPlugin ABI on top of OpenXR, so
VrApi-era Meta Quest VR titles can run on non-Meta OpenXR runtimes (Monado,
Steam Frame) instead of being locked to Meta hardware. Original code only — no
Meta/Epic/Capcom binaries, headers, or assets. Includes a desktop harness that
drives the shim against Monado headless.

Scope/legal: interoperability; entitlement handling is out of scope. See README
for the legal/scope section and docs/ for the research trail and design notes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D6sFYGXZPsq3v7xtcDES6g
This commit is contained in:
Daniel LynchandClaude Opus 4.8 committed 2026-06-29 00:48:48 -04:00
commit a72a79ad29
57 files changed
+9304

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
# Reverse-engineering notes — libOVRPlugin.so
Pinned version: OVRPlugin **1.51** / pkg `ovrplugin-android-universal:19.0.0.449.531`.
Cross-reference header: public **OVRPlugin.cs @ v1.51** (Unity Oculus Integration,
many GitHub mirrors) — gives ovrp_ signatures + [StructLayout] struct layouts.
## RE pipeline (working)
Headless Ghidra 12.1.2, driven by `ghidra_scripts/DumpOvrp.java`:
```
export JAVA_HOME=~/dev/re4vr-port/tools/jdk-21.0.11+10 # portable Temurin JDK
tools/ghidra_12.1.2_PUBLIC/support/analyzeHeadless ghidra_proj re4vr \
-import dump/apk_libs/lib/arm64-v8a/libOVRPlugin.so \
-scriptPath ghidra_scripts -postScript DumpOvrp.java -deleteProject
```
Gotchas solved: Ghidra needs a JDK (JREs rejected) -> portable Temurin in tools/.
Ghidra 12 dropped bundled Jython -> scripts must be Java, not .py.
Output: `analysis/ovrp_decomp.txt` (537 ovrp_ sigs, 27 core bodies).
## Key structural finding
Exported ovrp_* are THIN THUNKS: `(*PTR_ovrp_X)()` jumping to the real impl,
which calls internal C++ `OVR::Util::Compositor::*` (partially symbolized).
=> The game (Java System.loadLibrary + dlsym) calls the EXPORTED symbols. So the
SHIM just re-exports the same ovrp_ symbol names backed by OpenXR and replaces
libOVRPlugin.so wholesale. We do NOT reverse the internal Compositor C++.
Decompilation = reference for semantics + struct sizes only.
## ABI confirmed (triangulation: Ghidra shape + v1.51 header types = MATCH)
ovrp_GetNodePoseState3(ovrpStep, int frameIndex, ovrpNode, ovrpPoseStatef* out):
- null out -> returns 0xfffffc17 = -1001 (ovrpFailure_InvalidParameter)
- not init -> returns 0xfffffc16 = -1002 (ovrpFailure_NotInitialized)
- success -> memcpy(out, ..., 0x58) then return 0
- **ovrpPoseStatef = 0x58 = 88 bytes** == public layout:
ovrpPosef(28) + 4x ovrpVector3f(48) + double Time(8) -> pad 88. EXACT MATCH.
=> Public OVRPlugin.cs v1.51 struct layouts are TRUSTWORTHY for this binary.
ovrpResult error-code convention confirmed (-1001 invalid, -1002 not-init).
## Layer structs reversed (2026-06-23, analysis/struct_layouts.txt)
Ghidra recovered C++ type NAMES from demangled symbols but empty layouts (no DWARF);
real offsets came from decompiling OVR::Util::Compositor methods.
- Two compositor backends: CompositorVRAPI_OpenGL + CompositorVRAPI_Vulkan (RE4=Vulkan).
- **ovrpLayerDesc = 0x7c (124B)** [VERIFIED]: ImportLayerDesc memset's 0x7c; switch on
+0x00 = ovrpShape (cases 0,1,2,4,5 overlays; case 3 = EyeFov projection). Three
historical copy sizes 0x68/0x6c/0x7c = base / +DepthFormat / +MotionVector. Full
field layout written to header, offsets confirmed (Fov@0x20, VisibleRect@0x40,
DepthFormat@0x68).
- **ovrpLayerSubmit = 0x130 (304B)** [VERIFIED]: EndFrame4 allocs count*0x130. Header
fields (LayerId, TextureStage, ViewportRect[2], Pose@0x28, Flags) = public layout;
per-shape union tail still [TODO] (reserved bytes for now). Stored internally as
ovrpLayerSubmitUnion in a std::map<int,pair<union,int>>.
Header now has _Static_asserts sizeof(ovrpLayerDesc)==124 && ovrpLayerSubmit==304;
both pass, shim rebuilds (239 symbols).
## Next RE passes (when continuing)
- Dedup the export-thunk vs impl entries in the dump (script polish).
- For each CORE fn: pair Ghidra arg-shape with v1.51 C# sig -> finalized C header
for the shim (ovrp types + struct layouts).
- Reverse outliers NOT in the public header (e.g. SpaceWarp/ASW property paths the
binary references, any custom Armature behavior).
- Entitlement (libovrplatformloader's ovr_* surface) is out of scope for this repo:
no replacement ships and nothing is circumvented (see README "Legal / scope").