Skip to content

[Bug] GraphView Bloom post-processing leaks WebGL resources on every snapshot/resize #36

@chronoai-shining

Description

@chronoai-shining

Severity: High (memory leak)

sisyphus-web/src/components/GraphView.tsx:148-174 rebuilds the bloom post-processing chain on every [snapshot, rendering, dimensions] change but never disposes the previous one.

Problem

useEffect(() => {
  const composer = new EffectComposer(...);
  composer.addPass(new RenderPass(...));
  composer.addPass(new UnrealBloomPass(...));
  // ... patch fg._animationCycle
  return () => {
    // restore _animationCycle only — no composer.dispose(), no pass.dispose()
  };
}, [snapshot, rendering, dimensions]);

Every filter switch, dimension change, or snapshot mutation creates new EffectComposer, RenderPass, UnrealBloomPass, and the bloom render targets — but the cleanup only restores fg._animationCycle. After many filter switches, GPU memory balloons.

Two more concerns:

  1. Patching fg._animationCycle (a private react-force-graph-3d API) is fragile across upstream versions.
  2. The deps array depends on snapshot and rendering, which change frequently — this effect re-runs on basically every state mutation.

Remediation

const composerRef = useRef<EffectComposer | null>(null);
const bloomPassRef = useRef<UnrealBloomPass | null>(null);

useEffect(() => {
  // create composer + passes ONCE per dimensions change
  // patch _animationCycle
  return () => {
    bloomPassRef.current?.dispose();
    composerRef.current?.dispose();
    composerRef.current = null;
    bloomPassRef.current = null;
    // restore _animationCycle
  };
}, [dimensions]);  // not [snapshot, rendering, dimensions]

If bloom intensity / radius depends on snapshot/rendering, mutate the existing pass's properties (bloomPassRef.current.strength = ...) — don't recreate.

Detection

DevTools → Memory snapshot → search for WebGLRenderTarget. Should stay constant across filter switches; today it grows monotonically.

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions