# RE4 VR Shim — Handoff (2026-06-24 session) Entry point for the next session. Detailed investigation log: `NEXT-SESSION-LATENCY.md`. ## TL;DR - The head-motion **ghosting is frame drops** caused by the synchronous tile-memory **flush-wait serializing CPU↔GPU** (proven: removing it on the title dropped frame time 13–36ms → ~3ms and killed the ghosting). - **Shipped fix (always on): perf levels.** We were no-op'ing the game's CPU/GPU level requests; now forwarded via `XR_EXT_performance_settings`. Confirmed on device: GPU clock 305→587MHz, CPU steady 2419MHz, framerate up. The default build is playable (synchronous path + perf fix). - **Copy-ring (the real serialization fix) is built but blocked** on an MSAA-resolve interaction in gameplay — see below. Default OFF (`debug.re4vr.copyring`). - **Caveat — the title still ghosts INITIALLY in every build we tried.** Default build: title ghosting reduced by the perf fix but not gone. Copy-ring on: title ghosts at first, then "looks good after a while" (settles, not clean from frame 1). Likely cause of the *initial* ghosting in both: the title's **asset streaming / load hitches** (the ~49ms `CPU&GPU` spikes in VrApi, Stale frames), which NONE of the fixes address. So: perf fix + copy-ring attack the steady-state flush-wait drops; the initial load-driven hitching is a separate, still-open cause. ## Build / deploy ``` ./shim/build_android.sh && ./packaging/repack.sh && adb install -r packaging/out/re4vr-shim.apk adb logcat -d -s xrr # shim logs ``` Device = Quest 2 (USB serial , or wireless :5555). Package `com.Armature.VR4`, activity `com.epicgames.ue4.GameActivity`. ## Runtime debug toggles (system props; relaunch unless noted) - `debug.re4vr.copyring 1` — shim copy-ring (eye-only; gameplay black, see below) - `debug.re4vr.sscap 1` — cap supersample 1.2x→1.0x (free GPU/bandwidth) - `debug.re4vr.diag 1|2|3` — 1=projection only(drop quads), 2=force mono, 3=2x zoom (live) - `debug.re4vr.dump N` — one-shot eye-texture readback to /sdcard/Android/data/com.Armature.VR4/files/ - `debug.re4vr.depth 1` — DEAD END (UE passes None; Meta ignores plain KHR depth) - `debug.re4vr.pipeline 1` — DEAD END (render-ahead by holding OpenXR images; breaks UE stage lockstep) - `debug.re4vr.noflushwait 1` — perf probe: skip flush-wait (renders black; FPS recovers → confirms serialization) ## The open problem: copy-ring gameplay = MSAA resolve into our shim RenderDoc (offline replay over USB) showed: - UE renders the eye with **2× MSAA** into its own target, render pass **resolve attachment = our copy-ring shim** (the image we copy to OpenXR). No stage mismatch. - On the **title** that resolve lands → copy-ring works. In **gameplay** the resolved shim isn't the scene at our copy (white/garbage) → black/flashing. - So: UE's MSAA resolve into our **externally-created** shim VkImage works on the title but not in gameplay. Next suspects: the shim's `MUTABLE_FORMAT`/sRGB-vs-UNORM resolve view, create flags vs a valid resolve-dst, or Adreno tile-MSAA specifics. Single-shim made it worse (UE needs distinct per-stage images for TAA/buffering). - The fundamental tension: removing the flush-wait needs pipelining, which breaks UE's 1:1 stage↔acquire lockstep (the synchronous path relies on it). Copy-ring decouples via shim images but inherits the MSAA-resolve issue. ## RenderDoc offline-replay pipeline (set up this session — no headset needed to analyze) - App must be **debuggable**: `tools/apktool.jar` decode → add `android:debuggable="true"` → rebuild → sign (debug.keystore) → `packaging/out/re4vr-dbg.apk`. (RE-uses the shim.) - RenderDoc server installed (`org.renderdoc.renderdoccmd.arm64`). Capture over **USB** (wireless adb drops the replay; local desktop replay of an Android capture fails). - Headless analysis: `qrenderdoc --python script.py` with `adb://` → CreateRemoteServerConnection → CopyCaptureToRemote → remote.OpenCapture. Scripts + captures in `~/renderdoc-captures/` (rd_*.py, RE4/black.rdc = gameplay, RE4/title.rdc). Use `action.outputs` for RT attribution and SaveTexture (NOT GetMinMax/Typeless — it lies) for content. ## Recommended next steps 1. Chase the MSAA-resolve-into-shim failure (RenderDoc pipeline is ready): compare the title resolve (works) vs gameplay (fails) render-pass setup; try shim WITHOUT MUTABLE_FORMAT, or matching UE's exact resolve-target image create info. 2. If copy-ring stays blocked, the perf fix is the shipped win; consider lighter levers (sscap) and accept residual menu-screen ghosting. ## Notes - Diagnostic logging is still in the shim (rate-limited; strip before public release). - Depth format mapping was corrected (None=10; D16=6/D24_S8=7/D32_FP=8/D32_S824=9).