Per-frame renderer.info sampler for the debug/perf surface.
Three resets renderer.info.render at the start of every render() call
(with the default autoReset), so by the time a probe reads it between
frames it holds only the LAST pass of the post-processing chain (a single
full-screen quad: calls: 1, triangles: 1). Reading it at frame-end —
emitted by the animation loop right after postProcessing.render() — sees
the whole frame's counters before the next reset. On the WebGPU backend
the counters may lag one frame; they are diagnostics, not assertions.
The two renderers' info objects disagree on field meaning, and the
snapshot normalizes them:
snapshot
WebGLRenderer
WebGPURenderer (three common/Info)
calls
render.calls (draw calls)
render.drawCalls (render.calls there
counts render() passes since startup)
frame
render.frame
render.calls
programs
programs.length
memory.programs (shader stages)
Allocation-free on the hot path: one snapshot object is mutated in place
per frame and copied only when read.
Per-frame
renderer.infosampler for the debug/perf surface.Three resets
renderer.info.renderat the start of everyrender()call (with the defaultautoReset), so by the time a probe reads it between frames it holds only the LAST pass of the post-processing chain (a single full-screen quad:calls: 1, triangles: 1). Reading it atframe-end— emitted by the animation loop right afterpostProcessing.render()— sees the whole frame's counters before the next reset. On the WebGPU backend the counters may lag one frame; they are diagnostics, not assertions.The two renderers'
infoobjects disagree on field meaning, and the snapshot normalizes them:WebGLRendererWebGPURenderer(threecommon/Info)callsrender.calls(draw calls)render.drawCalls(render.callsthererender()passes since startup)framerender.framerender.callsprogramsprograms.lengthmemory.programs(shader stages)Allocation-free on the hot path: one snapshot object is mutated in place per frame and copied only when read.