Skip to content

Commit 7b07d5b

Browse files
refactor(engine): share computation dispatch setup (#2833)
1 parent 2dc1f2e commit 7b07d5b

2 files changed

Lines changed: 49 additions & 21 deletions

File tree

modules/engine/src/compute/computation.ts

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -225,18 +225,7 @@ export class Computation {
225225
dispatch(computePass: ComputePass, x: number, y?: number, z?: number): void {
226226
try {
227227
this._logDrawCallStart();
228-
229-
// Check if the pipeline is invalidated
230-
// TODO - this is likely the worst place to do this from performance perspective. Perhaps add a predraw()?
231-
this.pipeline = this._updatePipeline();
232-
233-
// Set pipeline state, we may be sharing a pipeline so we need to set all state on every draw
234-
// Any caching needs to be done inside the pipeline functions
235-
this.pipeline.setBindings(this.bindings);
236-
computePass.setPipeline(this.pipeline);
237-
// @ts-expect-error
238-
computePass.setBindings({});
239-
228+
this._setPipeline(computePass);
240229
computePass.dispatch(x, y, z);
241230
} finally {
242231
this._logDrawCallEnd();
@@ -247,19 +236,26 @@ export class Computation {
247236
dispatchIndirect(computePass: ComputePass, indirectBuffer: Buffer, indirectOffset = 0): void {
248237
try {
249238
this._logDrawCallStart();
250-
251-
this.pipeline = this._updatePipeline();
252-
this.pipeline.setBindings(this.bindings);
253-
computePass.setPipeline(this.pipeline);
254-
// @ts-expect-error ComputePass implementations expose binding application internally.
255-
computePass.setBindings({});
256-
239+
this._setPipeline(computePass);
257240
computePass.dispatchIndirect(indirectBuffer, indirectOffset);
258241
} finally {
259242
this._logDrawCallEnd();
260243
}
261244
}
262245

246+
private _setPipeline(computePass: ComputePass): void {
247+
// Check if the pipeline is invalidated
248+
// TODO - this is likely the worst place to do this from performance perspective. Perhaps add a predraw()?
249+
this.pipeline = this._updatePipeline();
250+
251+
// Set pipeline state, we may be sharing a pipeline so we need to set all state on every draw
252+
// Any caching needs to be done inside the pipeline functions
253+
this.pipeline.setBindings(this.bindings);
254+
computePass.setPipeline(this.pipeline);
255+
// @ts-expect-error ComputePass implementations expose binding application internally.
256+
computePass.setBindings({});
257+
}
258+
263259
// Update fixed fields (can trigger pipeline rebuild)
264260

265261
// Update dynamic fields

modules/engine/test/compute/computation.spec.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ test('Computation#dispatchIndirect', async t => {
9393
usage: Buffer.STORAGE | Buffer.COPY_SRC
9494
});
9595
const dispatchBuffer = webgpuDevice.createBuffer({
96-
data: new Uint32Array([4, 1, 1]),
96+
data: new Uint32Array([4, 1, 1, 1, 1, 1]),
9797
usage: Buffer.INDIRECT
9898
});
9999
computation.setBindings({data: workBuffer});
@@ -103,11 +103,43 @@ test('Computation#dispatchIndirect', async t => {
103103
computePass.end();
104104
webgpuDevice.submit();
105105

106-
const computedData = new Int32Array(await workBuffer.readAsync());
106+
const computedBytes = await workBuffer.readAsync();
107+
const computedData = new Int32Array(
108+
computedBytes.buffer,
109+
computedBytes.byteOffset,
110+
computedBytes.byteLength / Int32Array.BYTES_PER_ELEMENT
111+
);
107112
t.deepEqual(Array.from(computedData), [2, 4, 6, 8], 'GPU-written dimensions drive dispatch');
108113

114+
const offsetWorkBuffer = webgpuDevice.createBuffer({
115+
data: new Int32Array([1, 2, 3, 4]),
116+
usage: Buffer.STORAGE | Buffer.COPY_SRC
117+
});
118+
computation.setBindings({data: offsetWorkBuffer});
119+
const offsetComputePass = webgpuDevice.beginComputePass({});
120+
computation.dispatchIndirect(
121+
offsetComputePass,
122+
dispatchBuffer,
123+
3 * Uint32Array.BYTES_PER_ELEMENT
124+
);
125+
offsetComputePass.end();
126+
webgpuDevice.submit();
127+
128+
const offsetComputedBytes = await offsetWorkBuffer.readAsync();
129+
const offsetComputedData = new Int32Array(
130+
offsetComputedBytes.buffer,
131+
offsetComputedBytes.byteOffset,
132+
offsetComputedBytes.byteLength / Int32Array.BYTES_PER_ELEMENT
133+
);
134+
t.deepEqual(
135+
Array.from(offsetComputedData),
136+
[2, 2, 3, 4],
137+
'nonzero byte offset selects the requested dispatch record'
138+
);
139+
109140
computation.destroy();
110141
workBuffer.destroy();
142+
offsetWorkBuffer.destroy();
111143
dispatchBuffer.destroy();
112144
}
113145
t.end();

0 commit comments

Comments
 (0)