#2825·drei

[v11] Verify useDepthBuffer: core and webgpu implementations both exist

Author: DennisSmolekCreated Sep 2, 2026Updated Sep 2, 2026
Labelswebgpuv11

What it does

src/core/Helpers/useDepthBuffer/useDepthBuffer.ts:21-25:

typescript
useFrame((state) => {
  ...
  state.gl.setRenderTarget(depthFBO)
  state.gl.render(state.scene, state.camera)
  state.gl.setRenderTarget(null)
})

Note this hook also has a WebGPU implementation at src/webgpu/Helpers/useDepthBuffer/useDepthBuffer.ts, which uses TSL. So there are two live implementations and the core one is what the root entry serves — including to WebGPU users.

What to check

  • Which implementation actually reaches a WebGPU user, and whether that is intended. If the WebGPU one is the correct implementation, the core one reaching WebGPU through the root entry is the bug.
  • Depth textures are the least portable part of the render-target API. Confirm the FBO's depth attachment is created correctly under the WebGPU build and that sampling it produces the same values — ContactShadows and MeshReflectorMaterial both consume depth this way.
  • setRenderTarget(null) restores to the default framebuffer rather than the previous target, same concern as the cameras.
  • state.gl vs state.renderer — deprecated accessor, warns every frame.

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:

javascript
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.