Skip to content

GPU resources leaked on every shader rebuild #53

Description

@kmatzen

SdfMesh.rebuild() (src/engine/SdfMesh.ts:187) removes the old mesh from the scene and then allocates fresh GPU resources:

  • a ShaderMaterial (:210)
  • a BoxGeometry (:243)
  • one DataTexture per texture uniform (:197)

None of the previous ones are disposed. Three.js does not release GPU-side resources when an object leaves the scene graph — scene.remove() only unlinks it. Every structural tree edit therefore leaks one compiled shader program, one geometry, and all of that build's textures.

dispose() (:296) has the same gap: it unsubscribes and removes the mesh from the scene, but never calls this.material.dispose() or this.mesh.geometry.dispose(). Viewport.tsx:20 calls eng.dispose() on unmount, so a mount/unmount cycle compounds it — including React StrictMode's double-invoke in development.

The codebase already applies the right pattern elsewhere: OutlinePass.dispose() (:267-273) disposes correctly, and OutlinePass.update() (:280) disposes the old geometry before swapping in a new one. This is the same rule, missed in the hottest path.

Fix

Dispose the previous material, geometry, and textures at the top of rebuild(), and again in dispose(). Textures need tracking, since they live in material.uniforms rather than on the mesh — either keep a DataTexture[] field, or walk the uniforms and dispose any value that is a THREE.Texture.

Note

Worth pairing with #32 (cache compiled shaders by tree hash) — a cache changes disposal from "always free the old one" to "free only when evicted", so doing them in the wrong order means writing the disposal logic twice.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions