Skip to content

Commit 2e164b2

Browse files
WebGPURenderer: Remove per-draw WeakMap.set allocation in pipeline dedup.
`WebGPUPipelineUtils.setPipeline` tracked the active pipeline per pass encoder via a WeakMap. Pass encoders are created fresh every frame, so each pipeline change fired `_activePipelines.set( pass, pipeline )` — allocating a new entry hundreds of times per second. Sampled heap profile attributed ~64 KB / 10 s to this one line on webgpu_backdrop_water. We already track the active pipeline in `currentSets.pipeline` (render) and can do the same on the compute group's data entry. Inline the dedup at both call sites, delete the WeakMap, delete the method. Bonus: use an Array for `currentSets.attributes` instead of `{}` and reset with `.length = 0` — avoids the `for…in / delete` loop in `_resetCurrentSets` that caused hidden-class transitions. Measured on webgpu_backdrop_water (Inspector stripped, 10 s, 1 KB sampling): `update @ Animation.js:70` subtree 402 KB → 341 KB (−15%). `animate` child subtree 135 KB → 61 KB (−55%). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 04f1d1a commit 2e164b2

2 files changed

Lines changed: 18 additions & 37 deletions

File tree

src/renderers/webgpu/WebGPUBackend.js

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const _depthViewOptions = { dimension: undefined, arrayLayerCount: undefined, ba
5050

5151
function _resetCurrentSets( sets ) {
5252

53-
for ( const key in sets.attributes ) delete sets.attributes[ key ];
53+
sets.attributes.length = 0;
5454
sets.bindingGroups.length = 0;
5555
sets.pipeline = null;
5656
sets.index = null;
@@ -908,7 +908,7 @@ class WebGPUBackend extends Backend {
908908

909909
} else {
910910

911-
bundleSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null };
911+
bundleSets = { attributes: [], bindingGroups: [], pipeline: null, index: null };
912912
renderContextData.bundleSets[ i ] = bundleSets;
913913

914914
}
@@ -952,7 +952,7 @@ class WebGPUBackend extends Backend {
952952

953953
} else {
954954

955-
renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null };
955+
renderContextData.currentSets = { attributes: [], bindingGroups: [], pipeline: null, index: null };
956956

957957
}
958958

@@ -1603,13 +1603,19 @@ class WebGPUBackend extends Backend {
16031603
compute( computeGroup, computeNode, bindings, pipeline, dispatchSize = null ) {
16041604

16051605
const computeNodeData = this.get( computeNode );
1606-
const { passEncoderGPU } = this.get( computeGroup );
1606+
const groupData = this.get( computeGroup );
1607+
const { passEncoderGPU } = groupData;
16071608

16081609
// pipeline
16091610

16101611
const pipelineGPU = this.get( pipeline ).pipeline;
16111612

1612-
this.pipelineUtils.setPipeline( passEncoderGPU, pipelineGPU );
1613+
if ( groupData.currentPipeline !== pipelineGPU ) {
1614+
1615+
passEncoderGPU.setPipeline( pipelineGPU );
1616+
groupData.currentPipeline = pipelineGPU;
1617+
1618+
}
16131619

16141620
// bind groups
16151621

@@ -1736,8 +1742,12 @@ class WebGPUBackend extends Backend {
17361742
const hasIndex = ( index !== null );
17371743

17381744
// pipeline
1739-
this.pipelineUtils.setPipeline( passEncoderGPU, pipelineGPU );
1740-
currentSets.pipeline = pipelineGPU;
1745+
if ( currentSets.pipeline !== pipelineGPU ) {
1746+
1747+
passEncoderGPU.setPipeline( pipelineGPU );
1748+
currentSets.pipeline = pipelineGPU;
1749+
1750+
}
17411751

17421752
// bind groups
17431753
const currentBindingGroups = currentSets.bindingGroups;
@@ -2365,7 +2375,7 @@ class WebGPUBackend extends Backend {
23652375

23662376
} else {
23672377

2368-
renderContextData._bundleCurrentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null };
2378+
renderContextData._bundleCurrentSets = { attributes: [], bindingGroups: [], pipeline: null, index: null };
23692379

23702380
}
23712381

src/renderers/webgpu/utils/WebGPUPipelineUtils.js

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -38,35 +38,6 @@ class WebGPUPipelineUtils {
3838
*/
3939
this.backend = backend;
4040

41-
/**
42-
* A Weak Map that tracks the active pipeline for render or compute passes.
43-
*
44-
* @private
45-
* @type {WeakMap<(GPURenderPassEncoder|GPUComputePassEncoder),(GPURenderPipeline|GPUComputePipeline)>}
46-
*/
47-
this._activePipelines = new WeakMap();
48-
49-
}
50-
51-
/**
52-
* Sets the given pipeline for the given pass. The method makes sure to only set the
53-
* pipeline when necessary.
54-
*
55-
* @param {(GPURenderPassEncoder|GPUComputePassEncoder)} pass - The pass encoder.
56-
* @param {(GPURenderPipeline|GPUComputePipeline)} pipeline - The pipeline.
57-
*/
58-
setPipeline( pass, pipeline ) {
59-
60-
const currentPipeline = this._activePipelines.get( pass );
61-
62-
if ( currentPipeline !== pipeline ) {
63-
64-
pass.setPipeline( pipeline );
65-
66-
this._activePipelines.set( pass, pipeline );
67-
68-
}
69-
7041
}
7142

7243
/**

0 commit comments

Comments
 (0)