Skip to content

Renderer: Add NodeMaterial rebuild debug reporting#33311

Open
RenaudRohlinger wants to merge 18 commits intomrdoob:devfrom
RenaudRohlinger:features/materials_debug_rebuild
Open

Renderer: Add NodeMaterial rebuild debug reporting#33311
RenaudRohlinger wants to merge 18 commits intomrdoob:devfrom
RenaudRohlinger:features/materials_debug_rebuild

Conversation

@RenaudRohlinger
Copy link
Copy Markdown
Collaborator

@RenaudRohlinger RenaudRohlinger commented Apr 2, 2026

This adds a renderer debug path to trace when a NodeMaterial needs rebuild and why. Today it can be very hard to
understand why a material suddenly rebuilds after a scene or material change, even though that rebuild is one of the
most expensive operations in the renderer.

With this change, renderer.debug can report the material name or type, the cache contributor that changed, and readable before/after values, including scene-driven causes such as light setup changes.

A small WebGPU example is included to demonstrate the feature visually, making rebuilds much easier to track and optimize:
image

This contribution is funded by Spawn

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 2, 2026

📦 Bundle size

Full ESM build, minified and gzipped.

Before After Diff
WebGL 360.57
85.58
360.57
85.58
+0 B
+0 B
WebGPU 635.48
176.41
636.23
176.67
+745 B
+259 B
WebGPU Nodes 633.6
176.11
634.35
176.37
+745 B
+258 B

🌳 Bundle size after tree-shaking

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

Before After Diff
WebGL 492.95
120.2
492.95
120.2
+0 B
+0 B
WebGPU 707.66
191.31
708.41
191.56
+745 B
+257 B
WebGPU Nodes 656.88
178.57
657.63
178.86
+745 B
+296 B

@RenaudRohlinger RenaudRohlinger force-pushed the features/materials_debug_rebuild branch from d794fad to 6b4d65d Compare April 2, 2026 01:59
@RenaudRohlinger RenaudRohlinger added this to the r184 milestone Apr 2, 2026
@RenaudRohlinger RenaudRohlinger marked this pull request as draft April 2, 2026 11:49
@sunag
Copy link
Copy Markdown
Collaborator

sunag commented Apr 2, 2026

Do you think we can move it to the Inspector as a new tab or extension?

@RenaudRohlinger
Copy link
Copy Markdown
Collaborator Author

A new tab could definitely use it yes, but I don't think the inspector should own the feature.

Or maybe the same logic as the checkbox options such as forceWebGL?

@sunag
Copy link
Copy Markdown
Collaborator

sunag commented Apr 3, 2026

but I don't think the inspector should own the feature.

Hmm.. Why do you think that? The first impression I had was that it would be an inspection tool; a UI that would accompany any example, without needing to be recreated, would be useful.

Another thing I would suggest in this regard is, let’s say you add an option in the Console tab; when enabled, I think it’s preferable to do monkey patching on the RenderObjects.prototype.get prototype or interception through an abstraction interface so that we don’t need to add NodeMaterialDebug.js and other configurations to the core.

I’ve been adding, through the inspector, this monkey patching to prevent complex debugging code from becoming incompatible with tree-shaking, a technique similar to what the WebGL Dev Extension does.

@RenaudRohlinger RenaudRohlinger marked this pull request as ready for review April 10, 2026 02:19
@RenaudRohlinger
Copy link
Copy Markdown
Collaborator Author

image

Updated this to be inspector-owned now.

I initially explored a renderer-level before/after callback for node builds, but that felt too much like adding public
API for something that is really only inspection/debug tooling. The current version keeps the core signal small and
routes it through the existing inspector abstraction instead:

  renderer.inspector.beginNodeBuild( info );
  renderer.inspector.finishNodeBuild( info );

These are called from NodeManager.getForRender() only when a NodeBuilderState is actually missing and needs to be
built. The timing/info object is only created when an inspector exists, so normal rendering does not pay for this path.

So the console should now stay focused on messages like:

Renderer: NodeMaterial needs rebuild for "DebugPhysicalMaterial"
via material.colorNode.enabled (disabled -> enabled) [material.customProgramCacheKey] in 10.200 ms.

This also keeps the feature aligned with the earlier suggestion to make it an inspector tool rather than something each
example or renderer user has to wire manually.

/cc @sunag @Mugen87

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.

3 participants