Skip to main content
Alopexus
Participant
August 9, 2026
Question

Quest Pro browser: WebXR session frame production permanently drops ~13% after 20–50s

  • August 9, 2026
  • 0 replies
  • 41 views

GPU clocks pinned, per-frame GPU cost flat; coincides with tracking/localization activity resuming after session start; exiting and re-entering the session resets the cycle.

 

Environment

-----------

 

- **Device:** Meta Quest Pro

- **OS:** Horizon OS v207, Android build UP1A.231005.007.A1

- **Browser:** Meta Quest Browser 149.1.0.10.52.1018773329

- **Content:** WebXR immersive-vr session (three.js r185, WebGL2), OVR_multiview2\

stereo scene pass into a single-colour-attachment offscreen target, 72 Hz session,\

framebufferScaleFactor 0.75. App GPU cost ≈ 15 ms/frame at the test station (heavy\

scene, deliberately chosen --- the effect is easiest to see when frames sit near budget).

- Repro'd with eye tracking, natural facial expressions, and hand/body tracking **disabled**,\

and with the developer-mode boundary **disabled** --- the behaviour is unchanged.

 

Summary

-------

 

For the first ~20--50 s of an immersive session the browser produces XR frames at the rate\

the GPU allows (~55--62 fps for our ~15 ms frames, GPU utilization 96--98%). Then, within a\

few seconds, new-frame production drops ~13% (to ~44--52 fps) and **stays there for the\

remainder of the session**. During and after the drop:

 

- GPU clock level and frequency are **pinned and unchanged** (CPU4/GPU=4/4,\

1478/525MHz, DVFS=0 throughout --- no governor step).

- The app's per-frame GPU cost (App= in the VrApi stat line) is **flat across the\

drop** (e.g. 15.6 ms before → 15.4 ms after). The work per frame did not change; the\

number of frames produced did.

- GPU utilization **falls** (96--98% → 82--90%): the GPU is idling between late frames, not\

saturating.

- CPU utilization is flat (~60--67% avg, worst core ~70%), temperature flat (~23 °C),\

memory flat. No thermal event, PLS=0.

- **Exiting the immersive session and re-entering it resets the behaviour** --- another\

20--50 s of full-rate production, then the same drop. This reset-on-re-enter reproduces\

every time and is what rules out thermal/battery explanations.

 

The drop coincides, in all three captures, with the OS tracking stack resuming full\

activity after its session-start quiet period: LocalizationStateMachine transitions\

(Cooldown → FineLocalizationOnly → CoarseAndFineLocalization → LoadSubmapList),\

VegaMapLoader submap loads, in one capture a repeating\

VEGA:HM:MAP_TRACKING: Validation failed on Submap id = 1, DSP (Hexagon) vision-kernel\

telemetry, and IMU Update exceeded imu sampling period warnings. We note honestly that\

the tracking service logs continuously, so this correlation is circumstantial --- but the\

frame-production drop with pinned clocks and flat per-frame cost is constant across all\

three captures, and the timing (post-session-start cooldown expiry, reset on session\

re-enter) matches the localization state machine's cycle in each one.

 

Reproduction

------------

 

1. Load a WebXR app with GPU frame cost near budget (~13--16 ms at 72 Hz) in the Quest Pro\

browser. Enter immersive-vr.

2. Watch the per-second VrApi logcat line (or OVR Metrics: FPS + GPU utilization).

3. For the first ~20--50 s: fps ≈ 55--62, GPU ≈ 96--98%.

4. Observe the drop: fps → 44--52, GPU% → 82--90, App= unchanged, clocks unchanged.\

The state persists indefinitely.

5. Exit the session to the 2D page; re-enter. The full-rate window returns, then the drop\

repeats.

 

Evidence excerpts (capture 3 of 3 --- all three attached)

-------------------------------------------------------

 

Before (session seconds ~0--20):

 

FPS=54/72, Stale=21, CPU4/GPU=4/4, 1478/525MHz, GPU%=0.97, CPU%=0.63, App=15.05ms, Temp=23.0C, DVFS=0

 

After (~22 s onward, unchanged for the rest of the session):

 

FPS=46/72, Stale=28, CPU4/GPU=4/4, 1478/525MHz, GPU%=0.87, CPU%=0.66, App=15.21ms, Temp=23.0C, DVFS=0

 

Coincident with the transition (same seconds, Tracking pid):

 

LocalizationStateMachine updated from Cooldown to FineLocalizationOnly LocalizationStateMachine updated from FineLocalizationOnly to CoarseAndFineLocalization VegaMapLoader: BA units loaded 5/5, MapPointCount 1793 ... VEGA:HM:MAP_TRACKING: Validation failed on Submap id = 1, version = 479537200 (capture 2) IoteLogging: IMU Update exceeded imu sampling period BOLT:HexagonTelemetry: Global DSP utilization: 30.74% ... Scalar Util: 50.05%, HVX Util: 51.35%

 

One capture also recorded a system-wide scheduling symptom shortly after the drop:

 

W/Looper: Slow delivery took 98345ms android.bg h=android.os.Handler c=...VisibleActivityProcessTracker...

 

What we ruled out

-----------------

SuspectVerdictEvidence
GPU clock governor / boost expiryruled outlevels + MHz pinned all captures, DVFS=0
Thermal throttlingruled out23 °C flat; reset-on-re-enter is incompatible with thermals
App workload changeruled outApp= flat across the drop in all captures
CPU saturation in the appruled outCPU ~60–67% flat, worst core ~70%, Prd stable
Eye/face/body tracking servicesruled outdisabled in settings; behaviour unchanged (capture 3)
Guardian/boundaryruled outdeveloper-mode boundary disabled; behaviour unchanged (capture 3)

 

Questions

---------

 

1. Is the browser's XR frame loop expected to lose scheduling priority (or budget) when\

the localization pipeline resumes full activity after its session-start cooldown?

2. Is there a known contention issue between Tracking/VegaMapLoader submap operations\

(including repeated submap validation failures) and foreground app frame pacing on\

Quest Pro?

3. Is there anything a WebXR page can do to avoid or mitigate this state, given that\

XRSession.visibilityState remains visible and no WebXR-visible signal accompanies\

the drop?

 

Attachments

-----------

 

Raw 120 s logcat captures (full, unfiltered):

 

- clockwatch-2026-08-09T07-19-41-274Z.txt --- first capture; drop at ~+10 s of capture

- clockwatch-2026-08-09T07-34-34-172Z.txt --- second; includes Validation failed on Submap

- clockwatch-2026-08-09T07-51-23-265Z.txt --- third; optional tracking features + boundary\

disabled, behaviour unchanged