UNPKG

@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
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