Skip to content

Commit bbfc6d3

Browse files
committed
Experiment: use separate buffers for the next frame
1 parent b17e40f commit bbfc6d3

1 file changed

Lines changed: 26 additions & 15 deletions

File tree

src/webgpu/p5.RendererWebGPU.js

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ function rendererWebGPU(p5, fn) {
5858
// Registry to track geometries with buffer pools
5959
this._geometriesWithPools = [];
6060

61+
// Reusable Map for uniform buffer bindings to avoid GC
62+
this._uniformBuffersForBinding = new Map();
63+
6164
// Flag to track if any draws have happened that need queue submission
6265
this._hasPendingDraws = false;
6366
this._pendingCommandEncoders = [];
@@ -584,12 +587,14 @@ function rendererWebGPU(p5, fn) {
584587
// const firstDataView = new DataView(firstData.buffer);
585588

586589
shader._uniformBufferGroups.push({
590+
group: group.group,
587591
binding: group.binding,
588592
varName: group.varName,
589593
structType: group.structType,
590594
uniforms: groupUniforms,
591595
size: alignedSize,
592596
bufferPool: [],
597+
nextBufferPool: [],
593598
// bufferPool: [{
594599
// buffer: firstGPUBuffer,
595600
// data: firstData,
@@ -1187,8 +1192,11 @@ function rendererWebGPU(p5, fn) {
11871192
_returnShaderBuffersToPool(shader) {
11881193
if (shader._uniformBufferGroups) {
11891194
for (const bufferGroup of shader._uniformBufferGroups) {
1195+
while (bufferGroup.nextBufferPool.length > 0) {
1196+
bufferGroup.bufferPool.push(bufferGroup.nextBufferPool.pop());
1197+
}
11901198
for (const bufferInfo of bufferGroup.buffersInUse.keys()) {
1191-
bufferGroup.bufferPool.push(bufferInfo);
1199+
bufferGroup.nextBufferPool.push(bufferInfo);
11921200
}
11931201
// bufferGroup.currentBuffer = null;
11941202
bufferGroup.buffersInUse.clear();
@@ -1343,7 +1351,8 @@ function rendererWebGPU(p5, fn) {
13431351
passEncoder.setVertexBuffer(location, gpuBuffer, 0);
13441352
}
13451353

1346-
const uniformBuffersForBinding = [];
1354+
// Clear and reuse the map to avoid GC
1355+
this._uniformBuffersForBinding.clear();
13471356

13481357
for (const bufferGroup of currentShader._uniformBufferGroups) {
13491358
let bufferInfo;
@@ -1368,38 +1377,37 @@ function rendererWebGPU(p5, fn) {
13681377
bufferInfo.data.byteLength
13691378
);
13701379

1371-
for (const uniform of bufferGroup.uniforms) {
1380+
currentShader.buffersDirty = currentShader.buffersDirty || {};
1381+
currentShader.buffersDirty[bufferGroup.group + ',' + bufferGroup.binding] = false;
1382+
/*for (const uniform of bufferGroup.uniforms) {
13721383
const fullUniform = currentShader.uniforms[uniform.name];
13731384
if (fullUniform) {
13741385
fullUniform.dirty = false;
13751386
}
1376-
}
1387+
}*/
13771388

13781389
// Cache this buffer and data for next frame
13791390
bufferGroup.currentBuffer = bufferInfo;
13801391
}
13811392

1382-
uniformBuffersForBinding.push({
1383-
binding: bufferGroup.binding,
1384-
buffer: bufferInfo.buffer
1385-
});
1393+
this._uniformBuffersForBinding.set(bufferGroup.binding, bufferInfo.buffer);
13861394
}
13871395

13881396
// Bind sampler/texture uniforms and uniform buffers
13891397
for (const [group, entries] of currentShader._groupEntries) {
13901398
const bgEntries = entries.map(entry => {
13911399
// Check if this is a uniform buffer binding
1392-
const uniformBuffer = uniformBuffersForBinding.find(ub => ub.binding === entry.binding);
1400+
const uniformBuffer = this._uniformBuffersForBinding.get(entry.binding);
13931401
if (uniformBuffer) {
13941402
return {
13951403
binding: entry.binding,
1396-
resource: { buffer: uniformBuffer.buffer },
1404+
resource: { buffer: uniformBuffer },
13971405
};
13981406
}
13991407

14001408
// This must be a texture/sampler entry
14011409
if (!entry.uniform) {
1402-
console.error('Entry missing uniform field:', entry, 'uniformBuffersForBinding:', uniformBuffersForBinding);
1410+
console.error('Entry missing uniform field:', entry, 'uniformBuffersForBinding:', this._uniformBuffersForBinding);
14031411
throw new Error(
14041412
`Bind group entry at binding ${entry.binding} has no uniform field and is not a uniform buffer!`
14051413
);
@@ -1513,6 +1521,7 @@ function rendererWebGPU(p5, fn) {
15131521
_hasGroupDataChanged(shader, bufferGroup) {
15141522
// First time
15151523
if (!bufferGroup.currentBuffer) return true;
1524+
return shader.buffersDirty?.[bufferGroup.group + ',' + bufferGroup.binding];
15161525
const cachedData = bufferGroup.currentBuffer.data;
15171526
const cachedDataView = bufferGroup.currentBuffer.dataView;
15181527

@@ -1732,15 +1741,16 @@ function rendererWebGPU(p5, fn) {
17321741
// Parse all uniform struct bindings in group 0
17331742
// Each binding represents a logical group of uniforms
17341743
const uniformGroups = [];
1735-
const uniformVarRegex = /@group\(0\)\s+@binding\((\d+)\)\s+var<uniform>\s+(\w+)\s*:\s*(\w+);/g;
1744+
const uniformVarRegex = /@group\((\d+)\)\s+@binding\((\d+)\)\s+var<uniform>\s+(\w+)\s*:\s*(\w+);/g;
17361745

17371746
let match;
17381747
while ((match = uniformVarRegex.exec(shader.vertSrc())) !== null) {
1739-
const [_, binding, varName, structType] = match;
1748+
const [_, groupNum, binding, varName, structType] = match;
17401749
const bindingIndex = parseInt(binding);
17411750
const uniforms = this._parseStruct(shader.vertSrc(), structType);
17421751

17431752
uniformGroups.push({
1753+
group: parseInt(groupNum),
17441754
binding: bindingIndex,
17451755
varName,
17461756
structType,
@@ -1840,12 +1850,13 @@ function rendererWebGPU(p5, fn) {
18401850
return maxBindingIndex + 1;
18411851
}
18421852

1843-
updateUniformValue(_shader, uniform, data) {
1853+
updateUniformValue(shader, uniform, data) {
18441854
if (uniform.isSampler) {
18451855
uniform.texture =
18461856
data instanceof Texture ? data : this.getTexture(data);
18471857
} else {
1848-
uniform.dirty = true;
1858+
shader.buffersDirty = shader.buffersDirty || {};
1859+
shader.buffersDirty[uniform.group + ',' + uniform.binding] = true;
18491860
}
18501861
}
18511862

0 commit comments

Comments
 (0)