Skip to content

Conversation

@arodic
Copy link
Contributor

@arodic arodic commented Jan 8, 2026

#Change summary

The Root Cause of #32689

  • ViewportDepthTextureNode: Uses a singleton _sharedDepthbuffer that is shared across all RenderTargets/CanvasTargets. This causes brute-force destruction and re-creation of depth buffer per reference on every rendered frame if references are not exactly the same size. This affects both CanvasTarget and RenderTarget

  • ViewporTextureNode Does not consider CanvasTarget as a reference. It simply does not do caching for CanvasTargets

  • Renderer: Uses a single _frameBufferTarget that resizes for each canvas (if not exactly the same size), triggering
    depthTexture.needsUpdate = true and causing texture recreation

The Fix for #32689

  • ViewportDepthTextureNode removed getTextureForReference() override to allow texture caching. Now it caches depth textures per reference

  • ViewportTextureNode Added check for CanvasTarget. Previous implementation considered RenderTargets only.

  • Renderer Changed _frameBufferTarget to _frameBufferTargets (Map<CanvasTarget, RenderTarget>). Each canvas target now gets its own framebuffer target instead of sharing one

This allows multi-canvas rendering with different sizes and tone mapping enabled without constant texture buffer recreation.

@arodic arodic force-pushed the fixes/sharedDepthTexture branch 2 times, most recently from 65169bc to 17ae2b6 Compare January 8, 2026 23:47
@github-actions
Copy link

github-actions bot commented Jan 8, 2026

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 355.36
84.47
355.36
84.47
+0 B
+0 B
WebGPU 621.54
172.59
621.72
172.61
+176 B
+22 B
WebGPU Nodes 620.15
172.35
620.32
172.37
+176 B
+21 B

🌳 Bundle size after tree-shaking

Minimal build including a renderer, camera, empty scene, and dependencies.

Before After Diff
WebGL 487.31
119.25
487.31
119.25
+0 B
+0 B
WebGPU 692.53
187.85
692.71
187.87
+176 B
+22 B
WebGPU Nodes 642.34
175.07
642.51
175.09
+176 B
+18 B

@arodic arodic force-pushed the fixes/sharedDepthTexture branch from 17ae2b6 to 0f44cd5 Compare January 8, 2026 23:49
@arodic arodic marked this pull request as ready for review January 9, 2026 00:09
@arodic arodic changed the title Fixes/shared depth texture Fixes framebuffer caching with multiple RenderTargets/CanvasTargets Jan 9, 2026
@arodic arodic force-pushed the fixes/sharedDepthTexture branch 2 times, most recently from 538f416 to a5ceff2 Compare January 9, 2026 00:30

if ( cacheTextures === undefined ) {

cacheTextures = new WeakMap();
Copy link
Contributor Author

@arodic arodic Jan 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this WeakMap() I just realized that ViewportTextureNode doesn't really have a way to free up GPU resources. WeakMap afaik does not free up texture memory. This is not a new issue, previous version also had a WeakMap and lacked disposal mechanism just something to keep an eye on.

@arodic arodic force-pushed the fixes/sharedDepthTexture branch 2 times, most recently from 23d839d to c7dd472 Compare January 9, 2026 01:32
@arodic arodic force-pushed the fixes/sharedDepthTexture branch 2 times, most recently from 363d659 to c2b2888 Compare January 9, 2026 07:52
@arodic arodic force-pushed the fixes/sharedDepthTexture branch from c2b2888 to 2806820 Compare January 9, 2026 07:56
@arodic
Copy link
Contributor Author

arodic commented Jan 9, 2026

I cleaned up all the slop. This should be minimal and pretty clean implementation fixing the bug. Ready for review!

@arodic arodic changed the title Fixes framebuffer caching with multiple RenderTargets/CanvasTargets Fixes framebuffer caching with multiple references of different sizes Jan 9, 2026
const canvasTarget = renderer.getCanvasTarget();

this.value = this.getTextureForReference( renderTarget );
const reference = canvasTarget ? canvasTarget : renderTarget;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line makes me think that there is underlying issue with RenderTarget/CanvasTarget API design.

@Mugen87 Can renderer have both canvasTarget and renderTarget set? If so, which case should have priority here?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renderer.getCanvasTarget() will never be null; the default canvas itself is defined in a CanvasTarget. In that sense, I think we should prioritize RenderTarget renderTarget ? renderTarget : canvasTarget, so when we have a RenderTarget, it is used as output.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants