[v11] Verify Hud: double render and autoClear juggling on WebGPU
What it does
src/core/Portal/Hud/Hud.tsx:14-30 renders the scene twice per frame and toggles renderer state between the two:
oldCLear = renderer.autoClear
if (renderPriority === 1) {
renderer.autoClear = true
renderer.render(defaultScene, defaultCamera)
}
renderer.autoClear = false
renderer.clearDepth()
renderer.render(scene, camera)
renderer.autoClear = oldCLearWhat to check
autoCleartoggled between two renders. WebGPU records into command encoders and resolves render passes differently from WebGL's immediate-mode framebuffer clears. Whether flippingautoClearbetween tworender()calls produces the same layering needs confirming, not assuming.clearDepth()specifically — does it affect the second pass on WebGPU the way it does on WebGL? This is what makes the HUD draw on top.oldCLearis declaredletin the component body rather than a ref, so it resets on every re-render. Probably harmless since it is written and read inside oneuseFrame, but worth a look while you are in there. (Also spelledoldCLear.)
Related
#2402 — "GizmoHelper Hud Takes over RenderLoop Breaking Postprocessing w/EffectComposer (Legacy)" is an existing report against exactly this double-render. Worth reading the two together; the WebGPU answer may inform the WebGL one.
Shared context (identical across all seven)
These components are classified agnostic — they live in core/, so they are assumed to work on both renderers. That assumption held for 104 of the 106 agnostic components when swept: 73 never touch the renderer at all, and 31 touch only members both renderers have. These seven are different: they drive their own render calls, and that is where semantics diverge even when the API surface matches. See #2818.
setRenderTarget(renderTarget, activeCubeFace = 0, activeMipmapLevel = 0) has an identical signature on both (Renderer.js:2578 vs WebGLRenderer.js:2890), so that part is fine.
render() is where they differ — three/src/renderers/common/Renderer.js:1362:
render( scene, camera ) {
if ( this._initialized === false ) {
throw new Error( 'THREE.Renderer: .render() called before the backend is initialized. Use "await renderer.init();" before rendering.' );
}
this._renderScene( scene, camera );
}WebGL has no such gate. A render() that happens before the backend is ready throws on WebGPU and silently works on WebGL.
This is the class of bug that produced #2809: Preload calls gl.compile(), which on WebGPU is a getter aliasing compileAsync — same name, returns an unawaited promise, so preloading never happens. Grep cannot find these; they need reading.
Acceptance
Read the component against the WebGPU Renderer implementation and either confirm it is correct or fix it and say what was wrong. A story exercising the render path on WebGPU is the evidence — note Setup sets frameloop: 'never' under test, so useFrame does not run there and a green story proves nothing about this.
Source: pmndrs/drei