@motion-core/motion-gpu
Version:
Framework-agnostic WebGPU runtime for fullscreen WGSL shaders with explicit Svelte, React, and Vue adapter entrypoints.
133 lines (132 loc) • 3.46 kB
JavaScript
import { assertComputeContract, extractWorkgroupSize } from "../core/compute-shader.js";
//#region src/lib/passes/PingPongComputePass.ts
/**
* Ping-pong compute pass for iterative GPU simulations.
*
* Manages two texture buffers (A/B) and alternates between them each iteration,
* enabling read-from-previous-write patterns commonly used in fluid simulations,
* reaction-diffusion, and particle systems.
*/
var PingPongComputePass = class PingPongComputePass {
/**
* Enables/disables this pass without removing it from graph.
*/
enabled;
/**
* Discriminant flag for render graph to identify compute passes.
*/
isCompute = true;
/**
* Discriminant flag to identify ping-pong compute passes.
*/
isPingPong = true;
compute;
target;
iterations;
dispatch;
workgroupSize;
totalIterations = 0;
constructor(options) {
assertComputeContract(options.compute);
const workgroupSize = extractWorkgroupSize(options.compute);
this.compute = options.compute;
this.target = options.target;
this.iterations = PingPongComputePass.assertIterations(options.iterations ?? 1);
this.dispatch = options.dispatch ?? "auto";
this.enabled = options.enabled ?? true;
this.workgroupSize = workgroupSize;
}
static assertIterations(count) {
if (!Number.isFinite(count) || count < 1 || !Number.isInteger(count)) throw new Error(`PingPongComputePass iterations must be a positive integer >= 1, got ${count}`);
return count;
}
/**
* Returns the texture key holding the latest result.
* Alternates between `{target}A` and `{target}B` based on accumulated iteration parity.
*/
getCurrentOutput() {
return this.totalIterations % 2 === 0 ? `${this.target}A` : `${this.target}B`;
}
/**
* Advances the iteration accumulator by the current iteration count
* (called by renderer after each frame's iterations).
*/
advanceFrame() {
this.totalIterations += this.iterations;
}
/**
* Replaces compute shader and updates workgroup size.
*/
setCompute(compute) {
assertComputeContract(compute);
const workgroupSize = extractWorkgroupSize(compute);
this.compute = compute;
this.workgroupSize = workgroupSize;
}
/**
* Updates iteration count.
*
* @param count - Must be >= 1.
*/
setIterations(count) {
this.iterations = PingPongComputePass.assertIterations(count);
}
/**
* Updates dispatch strategy.
*/
setDispatch(dispatch) {
this.dispatch = dispatch ?? "auto";
}
/**
* Returns the target texture key.
*/
getTarget() {
return this.target;
}
/**
* Returns the current iteration count.
*/
getIterations() {
return this.iterations;
}
/**
* Returns current compute shader source.
*/
getCompute() {
return this.compute;
}
/**
* Returns parsed workgroup size.
*/
getWorkgroupSize() {
return [...this.workgroupSize];
}
/**
* Resolves dispatch workgroup counts for current frame.
*/
resolveDispatch(ctx) {
if (this.dispatch === "auto") return [
Math.ceil(ctx.width / this.workgroupSize[0]),
Math.ceil(ctx.height / this.workgroupSize[1]),
Math.ceil(1 / this.workgroupSize[2])
];
if (typeof this.dispatch === "function") return this.dispatch(ctx);
if (Array.isArray(this.dispatch)) return [
this.dispatch[0],
this.dispatch[1] ?? 1,
this.dispatch[2] ?? 1
];
return [
1,
1,
1
];
}
/**
* Releases resources (no-op, GPU lifecycle is renderer-managed).
*/
dispose() {}
};
//#endregion
export { PingPongComputePass };
//# sourceMappingURL=PingPongComputePass.js.map