Files
spoopyghosty0--frameport/docs/PLAYBOOK.md
T

46 KiB
Raw Permalink Blame History

Porting playbook: symptom → cause → fix

Everything here was hit while porting Quest and Rift games to the Steam Frame (Sept–Oct 2026; 38 catalog recipes). The machine-readable version is catalog/triage.yaml (used by frameport test / the Job screen); keep both in sync.

Fast path for a new game

  1. frameport scan <folder> → check the suggested recipe (frameport show <pkg>). Direct-VrApi engines get the bridge.
  2. frameport build <pkg> → all static checks must pass (32-bit-only → stop, it can't run).
  3. frameport install <pkg> → frameport test <pkg>: want RUNNING + "Submitting frames" at ~72 fps.
  4. Put the headset on and look. Headless tests can't judge visuals (no FOCUSED state without the headset worn).
  5. Fix by symptom below, rebuild, repeat. When it's good: Save as known-good (GUI) / add a catalog YAML.

Startup failures (visible in launch.log)

Symptom Cause Fix
One eye (usually the right) shimmers or jitters in the 3D view while menus and panels look steady; pacing is clean (GitHub #69, e.g. RTCWQuest, Moss) Valve's eye-tracked foveation layer (VALVE_fdm_injection) moves its low-density regions with each eye's gaze, and the right eye's gaze filter restarts often (CEyePoseUKF R: Large dt … Bootstrapped in ~/.local/share/Steam/logs/eyetracking.txt) Customize → "Eye-tracked foveation (Valve)" (device.foveation): Fixed (FDM_DEBUG=disable_offsets, keeps the GPU saving) or Off (VK_INSTANCE_LAYERS=""); catalog field foveation:
A Unity OpenXR game closes right after the OpenXR instance is created: F VrApiLoader: vrapi_SetPropertyInt was called before vrapi_Initialize()!, SIGABRT on UnityMain (GitHub #62, Jurassic World Aftermath) the APK still ships Meta's VrApi loader; OVRPlugin (1.89, on OpenXR) calls it without starting VrApi and Meta's loader aborts. The VrApi bridge can't replace it (39 of the loader's 114 functions: OVRPlugin wouldn't link) frame.vrapi_stub (same exports, each returns 0); triage vrapi-before-init
A VrApi game exits at once: UnsatisfiedLinkError … dlopen failed: cannot locate symbol "vrapi_PollEvent" (GitHub #57, BlazeRush) the engine imports a VrApi function the VrApi bridge didn't implement the bridge has vrapi_PollEvent, RecenterPose, SetDisplayRefreshRate, GetSystemPropertyFloatArray (rebuild the game); the static check "VrApi functions resolvable" names any other missing one; triage vrapi-symbol-missing
A Team Beef port (Lambda1VR, RTCWQuest, …) exits at once: UnsatisfiedLinkError: dlopen failed: library "libopenxr_loader_valve.so" not found (GitHub #59) TBXR loads openxr_loader_<Build.MANUFACTURER> (Lepton: valve) and takes the Meta path only when strstr(OPENXR_HMD, "meta") matches, else Pico's frame.tbxr_vendor (empty libopenxr_loader_valve.so + the "meta" literal → "alve"). Game data (xash/, …) goes to /sdcard: upload it with the Files tab to the game's storage. Black eyes with TBXR: Incomplete frame buffer object: GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: TBXR always uses multisampled render-to-texture (even --msaa 1); frame.tbxr_vendor links the GL shim, which hands it single-sampled versions (log GL shim: multisampled render-to-texture … drawn single-sampled)
Logos and a loading animation, then black (no crash, frames keep coming) in a game whose OBB folder has extra *.pak files (GitHub #61, Star Wars: Tales from the Galaxy's Edge: seasons + Wwise banks) the game asks Meta's platform for these asset files (ovr_AssetFile_GetList / DownloadById); OVRPort's loader doesn't know them, so the content never "arrives" frame.asset_files (native/langpack lists the data's *.pak as installed default assets, IAP free, and answers DownloadById at once with the path; off: env FRAMEPORT_ASSET_FILES=0)
cannot locate symbol "ovrPeerConnectionState_ToString" (or another ovr<Enum>_ToString) at start (BlazeRush, GitHub #57) OVRPort's platform loader lacks several Platform SDK enum helpers frame.ovrstubs now stubs them too; *_ToString stubs return "" (not NULL)
Exits right after the OpenXR instance is created: Failed to create XR session: -50 (XR_ERROR_GRAPHICS_REQUIREMENTS_CALL_MISSING, Lambda1VR) the game skips xrGet*GraphicsRequirementsKHR; Meta's runtime tolerates it, SteamVR's doesn't. Lambda1VR's TBXR doesn't even enable XR_KHR_opengl_es_enable (only XR_EXT_local_floor) FrameBridge adds XR_KHR_opengl_es_enable when an app enables no graphics API extension, asks for the requirements on the game's behalf and retries xrCreateSession once (logs added XR_KHR_opengl_es_enable …, the app skipped …; asked for it; every launch logs the final extension list xrCreateInstance with N extension(s)); triage graphics-requirements-missing. Verified headless: Lambda1VR runs at 72 fps
Exits at start: OVRAvatar-Loader: DisplayErrorAndExit: Failed to launch SystemActivities after ovrAvatar_Initialize: Failed to load AvatarSDK driver (BlazeRush, GitHub #57) Meta's avatar loader needs Horizon; it then tries Meta's error screen and aborts frame.avatar_stub (same exports, do nothing); triage avatar-driver-missing. Games that ship the library but don't start avatars at launch (Lucky's Tale, BattleSisters, Arcsmith) don't need it
Frame freezes or the game is killed (OOM) on the first controller vibration (e.g. Lucky's Tale's save slots, BattleSisters) OVRPort runtimes up to 3.4.3-23204ea read the haptic envelope's duration (ns) as seconds and allocate gigabytes of samples (GitHub #9, ovrport/app#73) adapter.haptic_fix (envelope → one plain vibration in native/xrshim). Fixed in runtime 3.4.3-aa54c3f: builds made with it leave the workaround out by themselves (log "not needed: adapter.haptic_fix", frameport show "last build left out"); rebuild an older build to switch
Controller vibrations much stronger than on a Quest (The Boys VR, Jurassic World, BONELAB, …) OVRPlugin games send amplitude envelopes; haptic_fix turned each into one vibration at the envelope's peak for its whole duration (a short fading pulse became a long full-strength buzz) haptic_fix now uses the envelope's RMS; Game settings → "Vibration strength" (haptic_scale, 0-1) scales every vibration in FrameBridge; launch.log shows the first requests (haptic: …). OVRPlugin stops a vibration with amplitude 0 (2 s duration): FrameBridge turns that into xrStopHapticFeedback (without it the last buzz ran its full 2 s)
Play or a launch test fails at once: Game files missing at <path> (storage not mounted?) in launch.log, or "… files are on a drive that isn't inserted" (GitHub #90) the game was installed or moved to a microSD card (<mount>/FramePort/<pkg>) that isn't inserted or mounted now insert the card; or move the game back (game menu → Move to…, frameport frame move <pkg> --to internal) once the card is back. frameport frame drives shows what the agent sees (exFAT/NTFS cards are refused: format in SteamOS)
A Linux app started from Desktop Mode's menu closes after ~2 s, or opens on the wrong display (GitHub #84) its launcher predates agent v63: the "Steam parent gone" watchdog ended it when Plasma's launcher exited, and it took gamescope's DISPLAY from Steam connect FramePort once (agent v63's upgrade_launchers adds the FRAMEPORT_DESKTOP checks; the menu entry runs env FRAMEPORT_DESKTOP=1 <anchor>/launch.sh). Game Mode controller problems in such apps are Steam Input's (a separate issue)
Every game suddenly fails to start: crun: create keyring …: Disk quota exceeded, is not a running context rootless podman leaked a kernel keyring per launch; 200-key quota exhausted keyring = false in ~/.config/containers/containers.conf (FramePort agent does it), then reboot the Frame once
A Unity app's text field shows a caret for a moment and loses focus; no keyboard appears (e.g. Stremio VR login) Unity's TMP_InputField/InputField wait for Android's on-screen keyboard and close themselves without one (Lepton has none); headless VR apps also have no focused Android window, so no key press reaches them frame.unity_text_input (Cpp2IL finds TouchScreenKeyboardShouldBeUsed/isKeyboardUsingEvents, rewritten to false/true) + device.text_input_window (lepton-show-flatscreen: Steam's keyboard and Type on Frame work)
Play gives Steam's "Game configuration unavailable"; Steam's console_log: GameAction [AppID <id>] … RequestingLicense → UpdatingAppInfo → LaunchApp failed with AppError_9 this Frame's Steam never loaded FramePort's shortcuts.vdf entry (it treats the id as a store app); cause unknown (GitHub #21/#30) automatic since agent v43: Play registers the game through Steam's devkit interface ("Devkit Game: …", devkit_register) and starts that; uninstall removes it. Agent v58: a devkit entry Steam forgot after a restart is added again live on Play (no NOT_IN_LIBRARY → no Steam restart), and installs/art updates of devkit games only copy art (no Steam restart, GitHub #41)
Steam's Exit game leaves the game running (container lepton-steamlaunch-<appid> still up) Steam stopped only its reaper; launch.sh and Lepton (setsid) never got a signal (GitHub #36) agent v44: launch.sh's 2 s loop ends the game when its parent is gone (upgrade_launchers adds it to existing launchers); by hand: podman kill lepton-steamlaunch-<appid>
Black screen at start while audio/ExoPlayer runs; log xrEndFrame: dropped N unusable layer(s), a quad layer with swapchain 0x0 (e.g. I Am Monkey's intro video) The game plays video into an Android-surface swapchain (XR_KHR_android_surface_swapchain); the Frame's runtime lists the extension but returns FUNCTION_UNSUPPORTED adapter surface_emul (default on): FrameBridge gives the player a SurfaceTexture-backed Surface and copies each frame into an ordinary swapchain (log surface_emul: …)
The game quits right after start: Something failed to initialize. Quitting! / We don't have write permission to …/files/cloud/data (e.g. SUPERHOT) The game created a save folder with mode 1700; inside Lepton the app writes through the folder's group launch.sh fix_perms adds owner + group write to every folder in the game's storage (agent 41); reinstall to get the new launcher
The whole Frame slows to a halt, then the game is killed (Out of memory: Killed process … anon-rss:10+ GB), e.g. Lucky's Tale The game's own memory grows ~1 GB/s on Unity's Loading.PreloadManager thread (perf page-fault profile); not the flat window, not the text-input patches none yet: mark unsupported; profile with perf record -p <pid> -e page-faults --call-graph fp (works as steamos, perf_event_paranoid 2)
A Linux app exits at once: cannot execute binary file: Exec format error in launch.log an x86_64 program started directly (installed before FramePort ran x86 builds through FEX, or by hand) reinstall it: x86_64 Linux apps install FEX on the Frame and start through it (agent v61, kind: linux_x86; FEX also needs STEAM_COMPAT_DATA_PATH: "No compat data path?" in launch.log = an agent v60 launcher, reinstall); triage linux-x86-no-fex. Prefer an arm64 build when the app offers one
APP_ACTIVITY is empty, nothing starts Manifest has category INFO only; Lepton needs LAUNCHER frame.launcher (automatic)
PC VR game on the Frame shows as a flat window / Revive: Unable to load LibOVRRT DLL / LoaderInstance::CreateInstance chained CreateInstance call failed Frame SteamVR runtime rejects OpenXR apiVersion 1.1 (XR_ERROR_API_VERSION_UNSUPPORTED), which Proton 11's VR helper requests pcvr.xr_timefix (Frame OpenXR layer, default on): retries xrCreateInstance as 1.0
Unreal PC VR game on the Frame runs as a flat window although OpenXR works (no LogHMD OVRPlugin lines; Unreal logs nothing when it skips the Oculus plugin) / launch.log: FramePort oculushmd: could not create the OculusHMDConnected event UE's OculusHMD (and LibOVR's ovr_Detect) only start when the Windows event OculusHMDConnected exists and is signalled; on a PC the Oculus service creates it. Revive hooks OpenEventW for it, but that relies on Detours patching Wine's (ARM64EC) kernelbase pcvr.oculus_unreal (default for Unreal Rift games; PC VR counterpart of overport's patch_oculus_unreal): launch.sh runs the injector through fp_oculushmd.exe, which provides the real event until the game exits
PC VR game runs as a flat 2D window (no VR) SteamVR was not running, so Revive/LibOVR had no runtime to bind to FramePort now auto-starts SteamVR on Play; make sure your headset/SteamVR come up before the game
PC VR game crashed launching via Steam on the OpenXR backend Revive's newer OpenXR backend was less reliable PC now defaults to Revive's OpenVR (SteamVR) backend; reinstall to apply
Oculus PC VR game: Unable to load LibOVRRT DLL / -3001 on the Frame The game can't find a VR runtime (Revive's LoadLibrary hook doesn't work under Proton-arm64) pcvr.libovr_redirect (default on) symlinks Revive's runtime as LibOVRRT{64,32}_1.dll in the exe dir — pure substitution; a build that checks the runtime signature then hits -3021 (not bypassed)
Oculus Rift game won't run on the Steam Frame Oculus/LibOVR game: needs Revive, whose hooks don't work under Proton-arm64, and FramePort won't defeat the Oculus runtime signature check Play it on this PC (SteamVR + Revive). Only OpenVR/OpenXR-native Rift games run on the Frame
Un-cracked Oculus PC VR game: "Initializing OVR session" then exits / signature check on the runtime Revive's hooks don't install on Proton-arm64; the Oculus shim rejects the unsigned Revive runtime Not runnable on the Frame without the repack's crack extracted (not done by FramePort); use the PC version
PC VR game: Failed to initialize Oculus API (-3001) / Unable to load LibOVRRT DLL Revive's LoadLibrary hook doesn't work under Proton arm64 (ARM64EC kernelbase); the game's LibOVR shim finds no runtime DLL Symlink LibOVRRT64_1.dll → Revive's DLL in the prefix's system32 (manual so far) → then -3021 (runtime signature check; open)
Uploads to the Frame are slow (~15 MB/s) PC and Frame both on Wi-Fi through the home router Connect the PC to the Frame's own hotspot (or a USB cable): FramePort uses the direct link automatically (~80-100 MB/s); job log line "Transfer link"
PC VR game exits right away: Unhandled Exception: 0xc06d007e (after FOnlineSubsystemOculus::InitWithWindowsPlatform) Delay-loaded LibOVRPlatform64_1.dll (Oculus Platform SDK, installed with the Oculus app) is missing None on the Frame (entitlement check; FramePort doesn't replace it). PC mode with the Oculus app
Unreal PC VR game opens the crash reporter instead of closing UE starts CrashReportClient.exe on a crash pcvr.no_crash_reporter (default for Unreal Rift games): -nocrashreports + CrashReportClient.exe renamed .disabled in the Frame copy
A backup's game was added without its data (library data_dir null, data_bytes 0) although the folder has .obb files The OBBs sit in a layout the scan didn't know: <game>/obb/<package>/, Android/obb/<package>/, or SideQuest-style <game>/apk/x.apk + <game>/obb/<package>/ sources/quest_dump.find_data_dir finds a <package> folder with .obb files ≤3 levels below the APK's folder or ≤2 below its parent (skipping neighbouring folders with APKs: other games); an apk/apks folder counts as part of its game folder. Add the folder again (Analyze again doesn't look for data)
Unreal game: JNI_OnLoad (OVRPlugin), then silence: no OpenXR instance, no crash, no frames (GitHub #85 TRIANGLE STRATEGY; launch-test finding missing-obb) Installed without its OBB: the manifest says com.epicgames.ue4.GameActivity.bHasOBBFiles = true (UE5: com.epicgames.unreal.…) but the library has no data folder (data_dir null, data_bytes 0) Put the .obb files in a <package> (or obb/) folder next to the APK, add the folder again, reinstall. Analysis extra.expects_obb; the game page, the install question and frameport scan/install warn; launch tests that sent no frames get the missing-obb finding from the library (the game logs nothing). Unity split-binary builds have no reliable sign in the APK
INSTALL_FAILED_NO_MATCHING_ABIS 32-bit-only APK; Frame has no AArch32 None. PC/Rift version via Revive
Crash at start: NoClassDefFoundError: … Landroid/window/OnBackInvokedCallback; or NoSuchMethodError: No static method storeStoreFence()V in class Ljava/lang/invoke/VarHandle; (GitHub #71/#72, triage android-too-new) The APK needs Android 13+ (minSdk 33 or more; those were 34) and calls its classes at start; Lepton's Android is 11 (API 30). OVRPort lowers minSdk to 29, so it installs anyway. minSdk ≤ 32 (Quest's Android 12L) is fine: 16 working catalog games declare 32 None (analysis extra.min_sdk > 32 → a warning on the game page/CLI and in the recipe notes; never unsupported from the manifest alone, the launch test's triage decides). Waits for Valve to update Lepton's Android
Nothing opens; TWALauncherActivity: Using URL from Manifest (https://…), Creating TwaLauncher for com.oculus.browser, NameNotFoundException: com.oculus.browser (GitHub #86 Mahjong Table VR, triage web-wrapper) The APK is a Trusted Web Activity (Bubblewrap / Meta's PWA packaging): a website that opens in Meta's browser, which Lepton doesn't have None: open the URL in a browser. Analysis extra.web_wrapper (manifest meta-data android.support.customtabs.trusted.DEFAULT_URL, resolved through resources.arsc, or androidbrowserhelper's LauncherActivity) → a warning with the URL (not unsupported: the manifest alone never decides)
UnsatisfiedLinkError / cannot locate symbol "ovr_…" overport's platform loader lacks Meta platform functions frame.ovrstubs (automatic, generated stubs)
missing ovrMessageType_ToString same, but the game needs a real string frame.ovrplatformcompat (automatic)
The game stays in its built-in language or waits at start although its OBB / files hold language packs (<tag>.lang, e.g. de.lang) overport's platform loader answers ovr_LanguagePack_GetCurrent/SetCurrent with request id 0, so the game never gets the pack's path frame.langpacks (opt-in, experimental, shown for games whose data has *.lang; native/langpack, build it with python native/build.py --only langpack). Default pack: the one the game applies, else env FRAMEPORT_LANGPACK=<tag>, else the only pack; search path override FRAMEPORT_LANGPACK_DIRS. Unreal games (Deadpool VR) grey out a pack whose asset Metadata differs from the game's version string: the patch writes the APK's versionName as Metadata (env FRAMEPORT_LANGPACK_META overrides) and reports the pack under the /storage/emulated/0/Android/obb/<pkg>/ spelling of its path; with /sdcard/… the text switched but the dialogue stayed silent (verified in the headset with Deadpool VR)
ClassNotFoundException com.oculus.os.AnalyticsEvent → abort Quest telemetry lookup in Meta XR Audio (Unreal build) or native code frame.metaxr_telemetry + frame.oculusos (automatic)
JNI DETECTED ERROR, GetStringUTFChars … NULL CheckJNI is on because overport marks the app debuggable frame.nodebug
Unreal game quits a few seconds after start (System.exit) ForceQuit after a failed Quest platform check alternate build with patch_remove_unreal_force_quit (use_alt)
Unreal game crashes a few seconds after the logo with no backtrace (Unreal's own signal handler hides it: logcat-crash.log empty, Zygote exited due to signal 11); the crashing thread is GameThread, pc in libaaudio.so, lr libovrplatformloader.so (ovr_Microphone_GetOutputBufferMaxSize+0x10); the last platform call is ovr_Microphone_Create (e.g. The Walking Dead: Saints & Sinners Ch. 2) OVRPort's platform loader opens the microphone's AAudio stream only in ovr_Microphone_Start, but GetOutputBufferMaxSize reads that stream unchecked; Unreal's Oculus voice asks for the size right after Create frame.ovr_microphone (NULL check rewritten in place; size 0 until the microphone starts). OVRPort runtime 3.4.3-aa54c3f has the check itself: builds made with it leave the patch out (log "not needed: frame.ovr_microphone", patches/upstream.py)
xrCreateSwapchain -26 / format unsupported (GLES) Frame takes only sRGB formats, no MSAA adapter swapchain_fix (default on)
Frames rejected, "Waiting…" forever a layer uses a failed swapchain or an extension that isn't enabled (e.g. equirect2) adapter layer_fix (default on)
xrConvert…TimeKHR FUNCTION_UNSUPPORTED spam; VrApi bridge stalls before recenter runtime lacks timespec conversion current adapter emulates it
Crash on the first frame, backtrace libVkLayer_fossilize.so ← FVulkanRenderPass::FVulkanRenderPass (crash logcat) the engine leaves the pNext of unused Vulkan attachment references uninitialized; Lepton always loads Steam's Fossilize layer (guest is userdebug, so even a non-debuggable APK gets it), which follows the pointer frame.vk_sanitize (default on for Unreal; Vulkan shim libfp_vk.so; triage fossilize-renderpass), e.g. Deadpool VR
SIGABRT right after start, backtrace libopenxr_loader.so (xrCreateSwapchain+…) overport's dispatcher aborts on swapchains > 4096 px ("Wrong createInfo size"); video players use 7680×3840 theatre textures frame.swapchain_limit (default on; guard → 16384 px; triage swapchain-size-abort), e.g. 4XVR
Video/menu panel missing, log dropped N unusable layer(s) with cylinder (1000017000) or equirect2 (1000091000) layers the Frame runtime lacks XR_KHR_composition_layer_cylinder/equirect(2)/cube (its SteamVR runtime only composites quad + projection layers) adapter shows cylinders as flat strips (setting cylinder_strips, default on); 360° equirect layers (theatres, 360° videos): adapter.equirect_emul (GLES only, per game)
360° theatre / 360° video black or missing (e.g. 4XVR) equirect layers dropped adapter.equirect_emul=1: a worker thread with a shared GLES context converts each 360° image to a cube map when it changes and draws one adapter projection layer from it for every frame with exactly that frame's views; it replaces the 360° layers in place, so the game's own projection layer (balcony, controllers, 360° videos it draws itself) stays on top. Quads can't be used: the Frame draws quad layers above every projection layer whatever the order. Log: first 360 view ready, in 5 s: N 360 image update(s) … M view redraw(s). Upside down / mirrored / behind you: equirect_flip 1/2/4 (frameport settings <pkg> equirect_flip=1, no rebuild). Never Vulkan (a Vulkan renderer hung the Frame's GPU in AC Nexus)
Unity game hangs right after its first frames, no pacing: lines; SIGQUIT dump shows UnityMain in a game library's JNI_OnLoad → usleep (e.g. SKYBOX: libskybox.so, SignatureChecker) the game checks its APK signing certificate; every port is re-signed can't be fixed without defeating anti-tamper (FramePort doesn't): mark "Can't run". Diagnose hangs: podman exec <container> kill -3 <pid> writes all thread stacks to launch.log
Video player doesn't list sent videos (e.g. 4XVR "Internal Storage" only shows some) the player lists its own /sdcard folder (4XVR: /sdcard/4XPlayer), not /sdcard/Movies; Android's media index doesn't work in Lepton GUI game page "Add videos" / "Add videos & files…" (Videos + the app's own folder, hard links) or frameport frame send <files> --app <pkg>
One eye grey in a stereo video, log xrCreateSwapchain … result=-10 the runtime refused a swapchain (XR_ERROR_LIMIT_REACHED) fewer/smaller swapchains: lower equirect_res; unresolved
Menu/screen jumps to where you look (e.g. 4XVR) the app re-creates LOCAL spaces (4XVR: every 2–4 s) and the Frame places them at the current head yaw, or the app recentres after the Frame's brief focus dips turn on adapter.layer_debug, check that LOCAL space sits at … deg vs focus_hold: hid a … ms focus dip; fixes: adapter.stable_local (new LOCAL spaces line up with the first) / adapter.focus_hold (hides dips < 600 ms after 3 s focused; never at start-up: a global debounce broke AC Nexus)
Pointer misses menu items the Frame's aim pose differs from Touch's adapter.layer_debug logs aim in grip … pitch/yaw; correct with aim_pitch/aim_yaw/aim_forward (frameport settings, no rebuild)
Video stutters although fps is steady video frame rate doesn't divide the refresh rate (30 fps at 72 Hz) adapter.refresh_rate (e.g. 90 for 30 fps, 72 for 24 fps); layer_debug logs the offered rates and the app's own requests
PC VR game judders/stutters although the GPU keeps up; vrcompositor.txt "Timed out. N total" high or frames dropped the game misses the headset's refresh (e.g. 96 Hz = 10.4 ms; Stormland's slow frames take 10.7 ms) pcvr.steamvr_tuning (default on): next Play sets SteamVR per-app preferredRefreshRate + motionSmoothingOverride via fp_vrsettings.exe
Quest app keeps recentering / snapping the view when you turn your head; log shows session state 5→4→3→4→5 within a second the Frame briefly takes focus; the app recenters on focus changes unfixed: hiding the dips (debounce) made AC Nexus stay black, so it was removed
Video player / app finds no local videos; MediaProvider "Requested path /home/steamos/... doesn't appear under ..." Lepton's /sdcard is a symlink to a host path, so Android's media index rejects every file upload in the Files tab (Videos = /sdcard/Movies) and browse folders in the app
Batman: Arkham Shadow closes during smoke-bomb effects; later input-tree corruption Meta XR Audio Wwise deletes queued metadata still referenced by the current audio frame, then writes through the stale pointer FrameBridge automatically retires metadata after current-frame references disappear, for the verified AArch64 SDK build only; see AUDIO_METADATA.md
Game stays on a loading or "Waiting" box although it reached FOCUSED; log FrameBridge: xrEndFrame failed -25 then no more pacing: lines (e.g. PowerWash Simulator on some Frames, GitHub #39) The eye image rect ends a few pixels past its swapchain (Unity rounds the swapchain width, the runtime's recommended size differs per Frame); SteamVR rejects every frame with XR_ERROR_SWAPCHAIN_RECT_INVALID FrameBridge clamps every projection/quad image rect to its swapchain (rect_clamp, default on since 0.11.0; log rect_clamp: view N image rect clamped): rebuild + reinstall the game
Game (Unity, GLES) freezes, zink: DEVICE LOST multisampled render-to-texture hangs the GPU frame.unity_no_msaa; if it persists: unfixable → PC version
Only the Android home screen shows; the log has Unity's VR device as None (e.g. Accounting+, Unity 2017) Unity 2017–2018 built-in Oculus support starts VR only when com.oculus.systemactivities is installed; Lepton has no Meta system apps, so Unity falls back to non-VR frame.unity_oculus_check: that package name in libunity.so → android, plus native/ovrpshim (libfp_ovrp.so): Unity 2017's legacy frame loop (ovrp_Update2/ovrp_BeginFrame) never calls ovrp_WaitToBeginFrame, so without the shim no xrWaitFrame happens, CompositorOpenXR::Update … outside of frame bounds floods the log and the dashboard freezes. With it: log ovrp frame loop shim: waited for frame N, ~71 fps. Accounting+ then stops at "press any button" although its OVRInput gets clean input (INPUT_PROBE in the patch logs connected controllers/buttons/input focus per call) — unresolved
Black flat window, then a GPU hang: kernel hangcheck detected gpu lockup (offending task the game), zink: DEVICE LOST, Unity render-thread crash; outside of frame bounds thousands of times a second (e.g. BattleSisters, Unity 2019.4) Unity 2019 on its built-in VR (no libOculusXRPlugin.so) uses the same legacy frame loop as Unity 2017: no xrWaitFrame, the render thread floods the GPU frame.unity_oculus_check adds the ovrpshim frame wait for these too (revision 2)
Unreal game stuck on a loading image after the intro, frames keep coming (72 fps), no crash (e.g. Vader Immortal) suspect: a Meta Platform SDK request no message ever answers diagnostics: frame.ovr_trace (opt-in) logs every ovr_* call, the answers ovr_PopMessage returns and every 10 s the unanswered requests (fp_ovrtrace in launch.log). Never fake an entitlement answer
Own-engine game crashes in libVkLayer_fossilize.so (Fossilize's recording thread, e.g. Roblox) same as Deadpool VR: uninitialised pointers in what Fossilize records frame.vk_sanitize now also covers own-engine libraries that load libvulkan.so by name
Crash right after the game gets focus, in vrclient.so … UpdateActionStateInternal / sxr_xrSyncActions (e.g. Myst) a race in the Frame runtime's input code on the first sync after focus (not every launch) adapter sync_guard (input syncs one at a time with event polling, paused 250 ms after FOCUSED)
View jumps sideways / game pauses or freezes for a moment every few seconds (e.g. Blade & Sorcery, BattleGlide) the Frame drops focus for ~0.5 s (FOCUSED→VISIBLE→SYNCHRONIZED); games pause or re-align the player (OnVRPresence … Teleport) adapter focus_hold
SDL / LÖVE app crashes at start: NullPointerException … ClipboardManager.addPrimaryClipChangedListener in SDLClipboardHandler.<init> (e.g. Dramatic Shape) Lepton's Android has no clipboard service (service check clipboard: not found) frame.sdl_clipboard (that call → nops in classes.dex, in place, apk/dex.py); reproduced and verified with LÖVE for Android 11.5
Controllers do nothing (e.g. stuck on a setup screen); log: xrSuggestInteractionProfileBindings … XR_ERROR_PATH_UNSUPPORTED the game only suggests bindings for Meta's newer profiles (Touch Plus / Touch Pro); the Frame's Android runtime knows oculus/touch_controller, not those adapter profile_remap (default on): the bindings are suggested again for Touch (log: controller profile … -> oculus/touch_controller)
Some buttons do nothing or the wrong thing (e.g. a Quest game's X/Y on the Frame's left controller) the game binds only Quest Touch and SteamVR maps Touch onto the Frame controllers with its own remap (Touch left X/Y land on the d-pad, right X and Y repeat B), or the runtime rejected a profile or an input call turn on adapter input_diag (diagnostics, off by default; frameport settings <pkg> input_diag=1) and look for input_diag: lines: bindings: <profile> accepted or unsupported: interaction profile <profile> -> <result> with the rejected paths, bindings: /user/hand/<hand> uses <profile>, unsupported: function <name>, unsupported: xrCreateAction -> <result> (<action>)
Unity game hangs or the whole Frame restarts (e.g. in a menu); log: The current MSAA level is 0, but the recommended MSAA level is 4. Switching to the recommended level. (e.g. Lucky's Tale) Meta's OVRManager (useRecommendedMSAALevel) turns 4x MSAA on at runtime, past QualitySettings; multisampled render-to-texture on GLES/Zink hangs the GPU frame.unity_runtime_msaa_off (Cpp2IL: OVRDisplay.get_recommendedMSAALevel → 0)
Unity game: one eye shows only effects or grey, the other is fine (e.g. I Am Cat, Oculus XR Plugin on GLES) the game's single-pass multiview rendering goes wrong for array slice 1 (the adapter submits both slices correctly) frame.unity_multipass (Cpp2IL: OculusSettings.GetStereoRenderingMode → MultiPass); swap_eyes=1 tells whether the game or the adapter is at fault
Setup/intro loops every launch (Espire 2) save folders created without write permission launcher repairs permissions every 2 s (built in)
VrApi bridge: never enters VR Frame reaches FOCUSED later than Quest; tracking only when worn bridge waits 30 s; test in the headset

Picture problems (headset on)

Symptom Cause Fix
2D Android app: Steam says it's running but nothing shows Lepton runs apps headless unless the app folder has lepton-show-flatscreen FramePort adds it for apps without VR (agent v28+); reinstall apps installed before
A phone/tablet app shows nothing in the headset, or a VR app opens as a flat window FramePort's VR/2D guess (vr_kind) is wrong for this app patch device.display_mode → Flat window or VR (Customize → "Show as VR or as a flat window"), then Update on Frame
"Install with FrameDrop" button opens FrameDrop (or nothing) instead of FramePort another program owns framedrop://, or the switch is off, or macOS (Flet can't receive links there) Settings → Install links → Use FramePort for these links; else Add games → Install from a link… (paste the button's address)
2D Android app: back/home/recents buttons cover the app's own buttons Android's navigation bar patch device.hide_navbar (on by default for apps without VR) sets qemu.hw.mainkeys=1; reinstall to apply
Black screen, audio works, GLES engine with direct VrApi Mesa rejects Quest-style GLSL frame.gl_shim (logs GLShim: SHADER COMPILE FAILED + source lines)
Black screen, audio works, log Unsupported VrApi layer type N bridge drops frames containing that layer extend the bridge (cylinder=3 is converted to a quad already)
Only some draws visible (e.g. controllers) + glGetError 0x502 multiview shaders used on single-view FBOs GL shim gl_hide_multiview=1 (default)
Upside-down image in a GL bridge game GL images start at the bottom row fixed in the bridge (swap angleUp/Down for GL chains)
UI panels upside down (AC Nexus) XrCompositionLayerImageLayoutFB VERTICAL_FLIP unsupported adapter flip_emul=1 (default); rotating quads makes them vanish
Passthrough black (BAM) XR_FB_passthrough missing adapter passthrough_emul=1 (default) + patch_force_passthrough for MR-only games
Quest Touch controllers (or none) shown in a game that uses Meta's runtime controller models XR_FB_render_model missing on the Frame adapter controller_models=1: the agent converts the Frame's SteamVR controller models to glb at install, the adapter serves them. Games with their own controller meshes aren't affected (none of the 34 catalog games use runtime models)
overportOXR: Unknown proc addr: xr… for a function the adapter emulates overport's dispatcher only forwards functions in its own table route the plugin's lookups through native/xrshim (done for XR_FB_render_model when controller_models=1)
MR game stuck waiting for room data (Demeter) no Meta scene API adapter scene_emul=1 (+ frame.meta_permissions)
Hand-tracking game janky (Silhouette) Frame synthesizes hands from controllers controller_fix=0 passes hands through; not really fixable
Eye distortion while moving (Arcsmith, Time Stall) unknown (not eye swap, tracking, Valve layers, depth or pacing) unresolved
One eye grey / only effects (I Am Cat, Unity Oculus XR Plugin on GLES) the game's multiview pass draws array slice 1 wrong on Zink frame.unity_multipass (also rewrites the getter's inlined read in OculusLoader.Initialize; check for two array=1 eye swapchains)
View vibrates even when holding still after frame.unity_multipass (I Am Cat) poses/times are consistent, but two passes on Zink make every frame one period late, and the game clamps its physics step to 10 ms not fixed (scale 0.8 didn't help); next ideas: fix multiview instead, or the game's fixed timestep
Game freezes / pauses for 0.5-2 s now and then, no flicker (e.g. Blade & Sorcery, Lucky's Tale) the headset's wear sensor flickers off while worn (logs/eyetracking.txt HMD off, stopping eye tracking … HMD on), the Frame turns it into a focus loss and Quest games that pause on focus loss pause adapter focus_hold (on by default since 2026-10-05, dips up to focus_hold_ms = 5000 ms are hidden; longer ones still pause)
Minor glitches on some objects (Myst, Unreal Vulkan) unknown; not application space warp (turning it off changed nothing and ran worse) unresolved
Graphics crash in vkCreateInstance with pc == fault address, from the game's own Vulkan hooks (BONELAB 1.2974 libSLZQuestNative) a pointer into memory freed with OVRPlugin's pre-init OpenXR instance; not the runtime (vrclient.so) or Fossilize being unloaded (keeping both loaded with RTLD_NODELETE didn't help) unresolved
Unity game shows a picture but the player body is frozen: no head tracking, the controllers stay on the model, no buttons, although OpenXR input works (BONELAB 1.2068, Oculus XR Plugin) OVRPlugin reports the headset as not worn (ovrp_GetUserPresent2 → 0) a few seconds after start, and the game's rig only follows a present user (Marrow XRHMD.IsUserPresent = Unity's HMD UserPresence) frame.unity_user_presence (the Oculus XR Plugin's lookup → libfp_ovrp.so, reports present; log user presence: OVRPlugin 0 …)
Unreal 5 game crashes at its first render pass, backtrace vulkan.freedreno.so ← libVkLayer_fossilize.so ← libfp_vk.so (create_render_pass2) (Metro Awakening) a subpass without a depth attachment names a depth/stencil resolve attachment; the Frame's Turnip reads the missing depth attachment (NULL) the Vulkan shim drops that resolve (always, FramePort after 0.11.0; log dropped the depth resolve of subpass N (no depth attachment)); triage unreal-vulkan-driver-crash
Unreal 5 game crashes in vulkan.freedreno.so called straight from libUnreal.so right after its swapchains, or a few seconds into the first frames (Metro Awakening) Unreal turns on fragment-density-map foveation because Turnip offers VK_EXT_fragment_density_map, then records barriers (to FRAGMENT_DENSITY_MAP_OPTIMAL) and image views (2D array R8G8) for a density map the Frame never provides (VK_NULL_HANDLE); Turnip dereferences it adapter vk_hide_fdm=1 (the game doesn't see the extension) + vk_spec_fixes=1 (leaves out null-image barriers, refuses null-image views); triage unreal-fdm-missing. Found by disassembling the driver at the crash pc: the struct offsets (0x58 = VkSubpassDescription2, 0x48/0x60 = image barriers, viewType/format in registers) name the call
Own-engine game crashes in je_free from its own library on the first frames (Roblox) the game frees memory it doesn't own; not the Vulkan shim or the format fallback unsupported

Live view (Live view tab, install/livestream.py)

Symptom Cause Fix
Status line says "software encoder" (30 fps, the Frame's CPU busier) fp_venc --probe failed (missing upload, encoder busy or refused a format: exit 4) or the helper couldn't be put on the Frame on the Frame: ~/.local/share/frameport/bin/fp_venc --probe; echo $? and --selftest; the app log names upload failures. FP_VENC_DISABLE=1 forces the fallback for tests
Picture drifts out of sync with the sound the hardware path relies on one H.264 frame per fps slot (ffmpeg -framerate); fp_venc: stats … skipped= > 0 on stderr means slots were skipped see the stats line (every 10 s); a stopped/suspended Frame skips slots on purpose
Viewer joins only after several seconds the keyframe request (k on the channel) didn't reach the encoder; the viewer then waits for the next regular keyframe (4 s) check live: encoder=hardware came first (requests are sent only then)

Debugging techniques that worked

  • A user's problem report: frameport diag inspect <FramePort-diag-*.zip> re-triages its launch log with the current signatures; the zip has the recipe, analysis, ELF/PE imports, Frame logs and versions (docs/DIAGNOSTICS.md).
  • Read <base>/launch.log (logcat mirror). Filter the game's pid: Start proc <pid>:<package>.
  • Monitor tab (GUI, while a game runs): fps from FrameBridge's pacing lines next to GPU busy %, the hottest sensor, memory pressure and per-process CPU/GPU/memory. A memory runaway (Lucky's Tale, Vader Immortal) shows as rising memory + "waiting" before the OOM kill; a GPU-bound game as GPU near 100 % with fps under target; heat as the temperature tile turning amber/red. Sources and costs: FRAME_RUNTIME.md "Monitoring sources".
  • The adapter logs as FrameBridge (settings, xrCreateInstance result, swapchain retries, pacing fps).
  • For GLES/GLAD engines, wrap eglGetProcAddress to see shader compile errors (build the shim with -DGLSHIM_TRACE for per-FBO draw counts and draw-call errors; the bridge has -DOVP_GL_DIAG for eye-image readback).
  • Anything visual needs one headset session per iteration — batch hypotheses into each build.
  • Headless launch tests never get focus: they prove startup, not play. Crashes right after FOCUSED (Myst), focus dips and judder only show up in a headset session: ask for one, then frameport diag collect <pkg> (it contains the headset sessions too, plus this boot's kernel log).
  • Which library a stale pointer belonged to: turn on the Android linker's log for one run by adding debug.ld.app.<pkg>=dlopen as an extra line of LEPTON_GFXRECON_FP_PROPS (first line 0) in the game's launch.sh on the Frame (back it up, restore it after) and look for dlclose: unloading "…".
  • Memory runaways / busy loops: perf works as steamos (perf_event_paranoid 2, user space only; ptrace_scope 1 blocks eu-stack/gdb/debuggerd). perf record -p <pid> -e page-faults -c 64 --call-graph fp names the thread touching new memory (perf script -F comm,tid,ip,dso); -t <tid> -F 499 samples one thread. Map IL2CPP addresses with a full Cpp2IL diffable-cs dump (method Offset = address − the r-xp mapping of libil2cpp.so). Sample memory per mapping name from /proc/<pid>/smaps ([anon:libc_malloc] = native heap).
  • Unity catches native crashes itself: no debuggerd backtrace in Lepton's logcat-crash.log, but a tombstone_00 in the game's Android/data/<pkg>/files/ with the memory map (map pc/lr/registers to libraries).
  • Focus losses: the game sees FOCUSED→VISIBLE→SYNCHRONIZED (OVRPlugin [XR_SESSION], FrameBridge focus_hold: lines); the cause is on the host: ~/.local/share/Steam/logs/vrserver.txt (HMD off/on, entering standby, SystemButtonDown in vrclient_vrcompositor.txt) and XRService ([UserPresence], IMUFallback). Compare the times (Lepton logs UTC, host logs local time).
  • A Unity getter patch that changes nothing: the compiler may have inlined it (no BL to its address in libil2cpp.so) — patch the field read in the caller (Il2cppReturnPatch.field_loads).
  • Fixes found by users count: a reporter's shader capture (VR4) became the vk_shader_fix recipe data (match by size
    • SHA-256, insert words); verify on the device that the log shows the module being fixed.
  • Don't install or test on the Frame while the owner is playing: adding a library entry restarts Steam (FramePort now skips the restart when the shortcut is unchanged and waits while a game runs), and a launch test starts a game.
  • Catalog YAML: a : inside an unquoted value breaks the file and the loader skipped it silently (the game vanished from the list); tests/test_catalog_files.py now catches it.
  • Keep the known-good APK and roll back if a change regresses (PATCHED/_known-good-*).

When it can't run on the Frame

Stream PC VR instead: native Steam version if one exists (Espire 1: 669290; HITMAN WoA: 1659040; Sniper Elite VR), or the Rift version through Revive (Journey of the Gods, Shadow Point). The catalog stores these as pcvr_alternative. FramePort handles Rift games itself (next section).

Oculus Rift (PC VR) games

Scan a folder with Rift game dumps (Windows game folders) like Quest dumps; they get ids rift.<slug> and the "PC VR (Revive / Proton)" patch group. Two ways to run them:

  • This PC (--to pc, GUI "Install on this PC"): a non-Steam shortcut in the local Windows Steam runs ReviveInjector.exe /openxr "<game.exe>" (FramePort's portable Revive; on WSL copied to %LOCALAPPDATA%\FramePort). Play on the Frame by streaming from SteamVR.
  • The Frame (GUI "Install on Frame (Proton)"): game + Revive are uploaded to ~/Applications/quest-frame/rift.*, and launch.sh runs them with the Frame's ARM64 Proton (Frame → Install Proton first). Experimental.
Symptom Cause Fix
"Proton isn't installed on the Frame yet" ARM64 Proton / Steam Linux Runtime 4 (arm64) not downloaded Frame → Install Proton (confirm in the headset) or "Install without confirming" (frameport frame proton --install --unattended)
Game quits at once; ovrPlatformInitialize_NotEntitled / entitlement failed Oculus Platform SDK entitlement check (FramePort flags these: "Uses the Oculus Platform SDK") PC mode with the Oculus app installed and a license you own. FramePort doesn't bypass entitlement checks
Failed to create process in ReviveInjector.txt wrong exe, or 32/64-bit mismatch check the detected exe on the game page; rescan
XR_ERROR_RUNTIME_UNAVAILABLE / no OpenXR runtime (PC) SteamVR not running / not the OpenXR runtime start SteamVR, set it as OpenXR runtime; or pcvr.revive_openvr
XR_ERROR_EXTENSION_NOT_PRESENT / xrConvertTimespecTimeToTimeKHR failed (Frame) ReviveXR needs XR_KHR_win32_convert_performance_counter_time; wineopenxr builds it on the host's timespec conversion. The Frame's Linux runtime supports it (2026-09-29), unlike its Android runtime pcvr.xr_timefix (off by default): FramePort's timefix OpenXR layer emulates it like the Quest adapter
Proton game hangs at start in a headless/SSH launch; log no driver could be loaded / explorer process failed to start no display session (DISPLAY/GAMESCOPE_WAYLAND_DISPLAY) the Proton launch.sh takes them from the running Steam (built in)
Unreal game starts (window created) then CrashReportClient runs the game crashed under Proton; often no VR runtime reached it (Revive off) keep pcvr.revive on (repacks' bundled LibRevive64.dll isn't loaded by itself); read the game log + crash summary in the launch log
VK_ERROR_DEVICE_LOST under DXVK freedreno GPU hang pcvr.proton_log to capture; PC mode