A-Frame tick() and the WebXR frame callback: which layer defines the frame budget?
0 reputation · 11 Mar 2025, 19:56 UTC
0 reputation · 11 Mar 2025, 19:56 UTC
On an A-Frame 1.x scene, the goal before optimizing is to locate the actual frame bottleneck rather than guess. Two timing sources sit at the integration boundary: the stats component, which times the ECS tick() loop on the CPU, and the WebXR session's frame callback, which delivers an XRFrame timestamp tied to the compositor's schedule.
The two loops are not guaranteed to stay in lockstep. A-Frame drives rendering through the browser's animation loop, while an immersive session schedules frames via XRSession.requestAnimationFrame; implementations differ in how the callbacks interleave, so timing taken around tick() may drift from compositor timing by up to a frame. The stats readout also covers JavaScript execution only; GPU work and compositor overhead stay invisible, which matters for shader-heavy or draw-call-heavy scenes. Behavior varies across desktop Chrome and standalone headset browsers, so version and hardware assumptions should be pinned before comparing numbers.
That leaves an unresolved instrumentation decision:
tick() level, at the XRFrame callback level, or correlated across both?29775 reputation · 11 Mar 2025, 20:25 UTC
The authoritative frame budget comes from the XRSession.requestAnimationFrame callback – the XR runtime’s compositor schedule. A‑Frame’s tick() loop only measures JavaScript/ECS work on the CPU; it does not include GPU rendering, draw submission, or compositor overhead.
XRFrame timestamp is the moment the runtime expects your frame to be ready for presentation.tick() via the browser’s requestAnimationFrame loop. The two loops can drift by up to one frame depending on the browser and device, so a fast tick() does not guarantee a frame is delivered on time.XRFrame intervals; they are invisible to tick() timing alone.performance.now() before and after the tick() call, and inside session.requestAnimationFrame log the XRFrame timestamp and the delta to the previous frame.tick() that aligns with an elongated XRFrame interval indicates a CPU‑side bottleneck. A short tick() paired with a long XRFrame gap points to GPU or compositor stalls.tick()‑to‑XRFrame drift empirically.Measure the XRFrame timestamps to establish the frame budget, and use tick() timing only as a CPU cost proxy. Correlating the two gives a clear picture of where the scene is spending time.
Because the drift between tick() and XRFrame is implementation‑dependent, a per‑session calibration is the safest approach. If you’re targeting a specific browser or headset, let us know so we can fine‑tune the recommendation.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.