Files
spoopyghosty0--frameport/native
spoopyghosty0 fc4aa9c8e5 Steam Frame controller models via XR_FB_render_model (adapter controller_models)
Games that ask the runtime for controller models (Meta's runtime controller
models) get the Steam Frame controllers instead of Quest Touch ones:

- adapter (render_model.c): emulates XR_FB_render_model when the runtime lacks
  it and serves files/framebridge/controller_{left,right}.glb. Off by default;
  suggested for games declaring the RENDER_MODEL permission/feature (none of
  the 34 catalog games do).
- agent v20: converts the Frame's own SteamVR render models (frame_controller
  driver, OBJ+PNG, openxr_grip -> grip space) to glb on the device at install /
  set_settings; Valve's models never leave the Frame. `frameport frame
  controller-models` lists what it finds.
- xrshim: overport's dispatcher only forwards functions in its own table
  ("Unknown proc addr"), so OVRPlugin's dlopen("libopenxr_loader.so") string
  is pointed at libframe_xrshim.so, which serves the emulated functions and
  forwards everything else to overport. Only added with controller_models=1;
  other builds differ from known-good only in the adapter binary.

Verified on the device with Toy Master: models converted, adapter emulation on,
all three render-model functions resolved through FrameBridge; launches match
the known-good build. Not yet seen rendering in a game (none requests a model).
2026-09-30 12:58:52 -04:00
..

Native components

Sources of the prebuilt binaries in ../artifacts/ (committed, with SHA256SUMS). End users never compile anything; developers rebuild with python native/build.py (downloads NDK r27c, OpenXR headers at pinned commits, d8 into native/.cache/, git-ignored). The adapter, GL shim and platform compat rebuild byte-identically; the VrApi bridge embeds debug paths (-g) and the dex depends on the d8 version, so those differ in bytes only.

Dir Artifact What / why
adapter/ {arm64-v8a,armeabi-v7a}/libopenxr_loader_generic.so FrameBridge: replaces overport's generic loader (which is renamed libopenxr_loader_original.so) and fixes Steam Frame runtime gaps. Hooks xrCreateInstance, swapchains, xrEndFrame, spaces, xrPollEvent, … everything else is forwarded by gen_forwarders.py-generated tail calls. scene_emu.c = Meta scene/spatial-entity emulation; flip_vk.c = Vulkan blit for VERTICAL_FLIP quads. render_model.c = XR_FB_render_model emulation (setting controller_models, off by default): serves files/framebridge/controller_{left,right}.glb, which the agent converts on the Frame from SteamVR's own Frame controller render models (never shipped by FramePort); tested on the host by tests/test_render_model.py. Settings: libframe_settings.so in the APK + settings.conf/framebridge.conf on the Frame. Hook technique from Quest2Frame's frame_bridge.c (GPL-3.0).
vrapi-bridge/ arm64-v8a/libvrapi.so VrApi → OpenXR bridge from Android-XR-Bridge/OVRPort native/vrapi at 5e7df52 (GPL-3.0, LICENSE.upstream), with our changes in upstream-patches/: GLES sessions + GL texture swapchains, cylinder→quad layers, GL vertical flip, UNORM↔sRGB format twins, 30 s VR-mode deadline, VALID-only recenter, loading-icon layers skipped, diagnostics behind -DOVP_GL_DIAG.
platformcompat/ arm64-v8a/libovrplatformcompat.so Real ovrMessageType_ToString (same fork, native/platform).
glshim/ arm64-v8a/libglshim.so Mesa GLSL compatibility for GLAD engines (hooks eglGetProcAddress): comments out #pragma before #extension, enables GL_EXT_shader_implicit_conversions, hides GL_OVR_multiview (gl_hide_multiview, default 1) and logs failed shaders. -DGLSHIM_TRACE adds per-FBO draw/error tracing.
xrlayer/ linux-arm64/libxr_frameport_timefix.so + XR_APILAYER_FRAMEPORT_timefix.json OpenXR API layer for Windows PC VR games under Proton on the Frame (glibc aarch64, built freestanding with the NDK's clang), on by default (patch pcvr.xr_timefix). Retries xrCreateInstance as an OpenXR 1.0 app when the runtime rejects 1.1 (the Frame's SteamVR runtime does, and Proton 11's VR helper asks for 1.1). Also emulates xrConvertTimespecTimeToTimeKHR/xrConvertTimeToTimespecTimeKHR if the runtime refuses them (the Frame's Android runtime does; its Linux runtime, used by Proton, supports them as of 2026-09-29 — so this part is only a fallback; Proton's wineopenxr needs them for XR_KHR_win32_convert_performance_counter_time, which Revive requires) with the adapter's xrWaitFrame-calibrated offset, and drops the extension from xrCreateInstance if the runtime rejects it. Enabled per game by the Proton launch.sh (XR_API_LAYER_PATH, XR_ENABLE_API_LAYERS). tests/test_xrlayer.py builds it for x86_64 and drives it via ctypes.
oculushmd/ win-x64/fp_oculushmd.exe PC VR counterpart of overport's patch_oculus_unreal (patch pcvr.oculus_unreal, default for Unreal Rift games on the Frame). Unreal's OculusHMD and LibOVR's ovr_Detect only start when the Windows named event OculusHMDConnected exists and is signalled (the Oculus service creates it). fp_oculushmd.exe <command line> creates it (manual reset, signalled), runs the command (Revive's injector) in a job object and keeps the event until every process in the job — the game and its children — has exited (fallback without job support: 3 minutes); returns the command's exit code and logs FramePort oculushmd: … to stderr (launch.log). Freestanding Windows x64 console exe (no CRT, no Windows SDK): the NDK's clang + lld-link /Brepro with a kernel32 import library generated by llvm-dlltool, so it's byte-reproducible. Tested on Windows from WSL with a build whose event name is -DEVENT_NAME=L"…" (the Oculus service owns the real event on a PC with the Oculus app).
xrshim/ arm64-v8a/libframe_xrshim.so FrameBridge extension shim, only in builds with controller_models=1. overport's dispatcher (libopenxr_loader.so) answers xrGetInstanceProcAddr from a fixed table and refuses everything else (overportOXR: Unknown proc addr: xrLoadRenderModelFB), so the adapter never sees XR_FB_render_model lookups. Meta's OVRPlugin gets the function with dlopen("libopenxr_loader.so") + dlsym, so FramePort rewrites that .rodata string in libOVRPlugin.so (same length, in place) to libframe_xrshim.so. The shim returns the adapter's emulated functions (framebridge_extension_proc) and forwards every other name to overport. A DT_NEEDED interposer does not work here (dlsym on a handle searches that library first); tried and dropped.
java-stubs/ dex/oculusos-stubs.dex No-op com.oculus.os.AnalyticsEvent / UnifiedTelemetryLogger for native code that looks them up.

The ovr_* stub library is not prebuilt: src/frameport/analysis/stubgen.py generates it per game from the exact missing symbols (no compiler needed).

After changing anything here: python native/build.py, commit artifacts + SHA256SUMS, then run frameport parity (the report marks updated binaries as "expected") and a device launch test.