Description
Initializing the WebGPURenderer is quite a bit heavier than it needs to be due to a mix of bandwidth requirements & TSL build times. To a point where users are looking into ways to prebuild shaders from TSL offline to reduce download and initialization times. My impression has been that one of the hopes for a node-based architecture and a renderer rewrite was that it would remove some of the monolithic shader code that's unconditionally included in the bundle to reduce file sizes so I wanted to outline some of the issues and potential improvements here.
Note that all numbers are tested with an AI worker running esbuild and stubbing some imports to adjust the imported dependencies. It's testing a single file that imports just the WebGPURenderer and treeshakes the remaining content - so the should be treated as rough numbers. And of course with the caveat that the impact of these changes depend on the features users are using in their project:
WebGLBackend is unconditionally included
Right now the WebGLBackend is included in every instance of WebGPURenderer even when it's not used (or can even run the features the user is using), which is a fairly large waste, especially as the fallback backend is becoming less and less needed.
Remove the WebGLBackend could apparently save ~24.7Kb gzipped or 11.8% of the 209.4Kb of the original size.
Implicit inclusion of lighting nodes
Lighting & tonemapping nodes are automatically registered in the StandardNodeLibrary.js file regardless of whether those lights or tonemapping effects are used at all. Removing these from being automatically included reportedly saves 9.8Kb or 4.7% of the file.
Implicit inclusion of material node structures
Likewise the full set of material graphs is registered in StandardNodeLibrary.js regardless of whether the materials are used. This reportedly takes saves ~11.2Kb or 5.3%.
The above three changes total ~45.8KB or 21.9% of the file size.
Node chaining implicitly includes nodes even if they're not needed
The calls to "addMethodChaining" likely breaks treeshaking for the node being modified. Likewise all nodes that are being created / referenced for chaining will be included even if the chained methods are not used. I haven't tested how significant this is so it's not clear how much of any impact this is having.
--
Related to #33821, discussing TSL compilation time.
Solution
And some potential suggestions on how to address some of the issues:
WebGLBackend is unconditionally included
Require the user to manually register the WebGLBackend:
const renderer = new WebGPURenderer();
renderer.setWebGLBackend( new WebGLBackend() );
Or even more transparent - the renderer could use dynamic imports to implicitly load the WebGLBackend only if it's discovered if it's needed. A similar pattern could be used for WebXRManager, which is also always included even when not needed.
Implicit inclusion of lighting nodes
Right now tone mapping, etc are always included even when not used. Instead of registering them on the WebGPURenderer itself the individual nodes could be associated with the light itself. Tonemapping constants could also include the nodes on them, as well, so the user is impilcitly providing the node structure when setting the tonemapping constant:
const light = new PointLight();
// all lights carry their own TSL node definition so node content is not included unless imported and used.
// light.lightNode = PointLightNode;
Implicit inclusion of material node structures
Similar to the last one, if the original material instances carried & declared their associated node material equivalents on them then these pre registrations could be removed, as well.
--
I understand the last two points would have some bundle size implications for WebGLRenderer - but perhaps we can think through some way to make these kinds of improvements without having an impact on existing WebGL users.
Alternatives
Tolerate large bundles or look into custom machinery to reduce the bundle size manually.
Additional context
No response
Description
Initializing the WebGPURenderer is quite a bit heavier than it needs to be due to a mix of bandwidth requirements & TSL build times. To a point where users are looking into ways to prebuild shaders from TSL offline to reduce download and initialization times. My impression has been that one of the hopes for a node-based architecture and a renderer rewrite was that it would remove some of the monolithic shader code that's unconditionally included in the bundle to reduce file sizes so I wanted to outline some of the issues and potential improvements here.
Note that all numbers are tested with an AI worker running esbuild and stubbing some imports to adjust the imported dependencies. It's testing a single file that imports just the WebGPURenderer and treeshakes the remaining content - so the should be treated as rough numbers. And of course with the caveat that the impact of these changes depend on the features users are using in their project:
WebGLBackend is unconditionally included
Right now the WebGLBackend is included in every instance of WebGPURenderer even when it's not used (or can even run the features the user is using), which is a fairly large waste, especially as the fallback backend is becoming less and less needed.
Remove the WebGLBackend could apparently save ~24.7Kb gzipped or 11.8% of the 209.4Kb of the original size.
Implicit inclusion of lighting nodes
Lighting & tonemapping nodes are automatically registered in the
StandardNodeLibrary.jsfile regardless of whether those lights or tonemapping effects are used at all. Removing these from being automatically included reportedly saves 9.8Kb or 4.7% of the file.Implicit inclusion of material node structures
Likewise the full set of material graphs is registered in
StandardNodeLibrary.jsregardless of whether the materials are used. This reportedly takes saves ~11.2Kb or 5.3%.The above three changes total ~45.8KB or 21.9% of the file size.
Node chaining implicitly includes nodes even if they're not needed
The calls to "addMethodChaining" likely breaks treeshaking for the node being modified. Likewise all nodes that are being created / referenced for chaining will be included even if the chained methods are not used. I haven't tested how significant this is so it's not clear how much of any impact this is having.
--
Related to #33821, discussing TSL compilation time.
Solution
And some potential suggestions on how to address some of the issues:
WebGLBackend is unconditionally included
Require the user to manually register the WebGLBackend:
Or even more transparent - the renderer could use dynamic imports to implicitly load the WebGLBackend only if it's discovered if it's needed. A similar pattern could be used for WebXRManager, which is also always included even when not needed.
Implicit inclusion of lighting nodes
Right now tone mapping, etc are always included even when not used. Instead of registering them on the WebGPURenderer itself the individual nodes could be associated with the light itself. Tonemapping constants could also include the nodes on them, as well, so the user is impilcitly providing the node structure when setting the tonemapping constant:
Implicit inclusion of material node structures
Similar to the last one, if the original material instances carried & declared their associated node material equivalents on them then these pre registrations could be removed, as well.
--
I understand the last two points would have some bundle size implications for WebGLRenderer - but perhaps we can think through some way to make these kinds of improvements without having an impact on existing WebGL users.
Alternatives
Tolerate large bundles or look into custom machinery to reduce the bundle size manually.
Additional context
No response