diff --git a/README.md b/README.md index 7acdf289..bb53f435 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,7 @@ Notice documentation is off? We do try our hardest, but if you find something, * [Destructured Assignments](#destructured-assignments-new-in-v2) * [Dealing With Transpilation](#dealing-with-transpilation) * [WebGPU](#webgpu) +* [WebAssembly](#webassembly) * [Asynchronous Kernels](#asynchronous-kernels) * [Full API reference](#full-api-reference) * [How possible in node](#how-possible-in-node) @@ -203,6 +204,7 @@ Representative performance factor: 1024×1024 matrix multiplication including re | `webgl2` | Browser | GLSL ES 3.00 fragment shaders | ~127× | The default browser backend. 2.20.0 renders scalar single-precision kernels to `R32F` and reads back one float per value where the driver allows | | `webgl` | Browser | GLSL ES 1.00 fragment shaders | ~87× | Fallback for older browsers | | `headlessgl` | Node | GLSL ES 1.00 via ANGLE | ~123× | The default Node backend | +| `webasm` **New!** | Anywhere | WebAssembly + f32x4 SIMD + threads | | Auto-selected only where no GL backend works; explicit via `mode: 'webasm'`. Threads engage under the async contract | | `cpu` | Anywhere | Plain JavaScript | 1× | Guaranteed fallback; also the reference for correctness | ## Demos @@ -295,7 +297,8 @@ Settings are an object used to create an instance of `GPU`. Example: `new GPU(s * 'headlessgl' **New in V2!**: Use the `HeadlessGLKernel` for transpiling a kernel * 'cpu': Use the `CPUKernel` for transpiling a kernel * 'webgpu' **New!**: Use the `WebGPUKernel` — kernels compile to WGSL compute shaders over storage buffers. Explicit opt-in only, never auto-selected, because every kernel call returns a `Promise` of its result (WebGPU readback is inherently asynchronous). Check `GPU.isWebGPUSupported` (synchronous, `navigator.gpu` presence) or `await GPU.isWebGPUAvailable()` (requests an actual adapter). - * 'async' **New!**: Auto-selection under the Promise contract. Picks the best available backend (webgl2 → webgl → cpu), turns `asyncMode` on for every kernel, and upgrades a kernel to webgpu on its first call if an adapter answers — falling back to the proven backend if the upgraded kernel cannot handle it. Write `await kernel(...)` once and the same code runs everywhere: + * 'webasm' **New!**: Use the `WebAssemblyKernel` — kernels compile to WebAssembly bytecode with f32x4 SIMD, and split across a worker pool under the async contract. Last in the automatic fallback chain, one step above `cpu`. See [WebAssembly](#webassembly). + * 'async' **New!**: Auto-selection under the Promise contract. Picks the best available backend (headlessgl → webgl2 → webgl → webasm → cpu), turns `asyncMode` on for every kernel, and upgrades a kernel to webgpu on its first call if an adapter answers — falling back to the proven backend if the upgraded kernel cannot handle it. Write `await kernel(...)` once and the same code runs everywhere: ```js const gpu = new GPU({ mode: 'async' }); const kernel = gpu.createKernel(function(a) { @@ -1319,6 +1322,37 @@ await GPU.isWebGPUAvailable(); // async: an adapter actually answered The mode is explicit opt-in and is never auto-selected — a synchronous caller handed a Promise would fail in silent, confusing ways. If you want automatic selection, that is exactly what [`mode: 'async'`](#asynchronous-kernels) is for. Graphical mode works: the kernel writes `this.color(...)` into a storage buffer and a fixed render pass presents it to the kernel's canvas — with one API difference, `getPixels()` returns a **Promise** (WebGPU readback is asynchronous). Since presentation needs no readback, an un-awaited `kernel()` per animation frame works. `Math.random()` works, and differently than on the GL backends: it is a PCG generator in integer WGSL, so with `randomSeed` the stream is **bit-exact across runs and drivers** — the GL backends' float-hash generator cannot promise that. Not yet supported (each throws a clear error): kernel maps, `toString()`, `precision: 'unsigned'`. +## WebAssembly + +**New!** + +The `webasm` backend compiles your kernel to a WebAssembly module and runs it on the CPU — but not the way the `cpu` backend does. Three things separate it from transpiled JavaScript: + +* **f32x4 SIMD.** Every kernel also compiles to a vectorized body that computes four cells per step, divergent control flow handled with lane masks the way real SIMD hardware does it. The scalar and vector paths are bit-identical — same operations, same order, per cell. +* **Threads, under the async contract.** With `asyncMode: true` (or `mode: 'async'`), a kernel with at least 4096 output cells splits across a lazy worker pool over one shared `WebAssembly.Memory` — `worker_threads` in Node, `Worker` in the browser (which needs the usual [cross-origin isolation headers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer#security_requirements) for `SharedArrayBuffer`). Results are identical whatever the split, `Math.random()` included. The main thread never blocks. Synchronous calls stay synchronous, single-threaded, and still SIMD. +* **f32 semantics for free.** Wasm arithmetic *is* IEEE-754 `f32`, so results match the GPU backends' float model without the rounding shims the `cpu` backend needs. + +`Math.random()` is the same PCG generator as the webgpu backend, in native i32 arithmetic: with `randomSeed` the stream is bit-exact across runs, platforms, and thread counts. + +Honesty about where it sits: any working GL backend outranks it. In auto-selection (`mode: 'gpu'`, default, or `'async'`) it is chosen only where no GL context exists — a Node build without headless-gl, a browser with WebGL disabled — one step above the `cpu` fallback. Opt in explicitly to benchmark it: + +```js +const gpu = new GPU({ mode: 'webasm' }); +const kernel = gpu.createKernel(function(a, b) { + let sum = 0; + for (let i = 0; i < 512; i++) { + sum += a[this.thread.y][i] * b[i][this.thread.x]; + } + return sum; +}).setOutput([512, 512]); + +const c = kernel(a, b); // synchronous, SIMD +``` + +A kernel is priced by the work it describes. A scatter algorithm rewritten gather-style so every thread computes its own cell — compaction as a binary search per output slot, a histogram as a per-bin scan — does log-factor or bin-count times the reads of the plain loop it replaces; a GL backend hides that multiplier under thousands of parallel threads, while cpu and webasm execute it serially and pay it in full. Measured against hand-written JavaScript of the *same* transposed algorithm, the cpu backend is within 2% and webasm within ±1.5× (its SIMD gather is often faster) — the cost is the transposition, not the transpilation. When cpu or webasm is a likely destination, prefer the direct algorithm over the GPU-shaped rewrite. + +`GPU.isWebAssemblySupported` reports the platform answer. `pipeline: true` is accepted the way the cpu backend accepts it: there is no device memory to pipeline into, so the result is a plain typed array (a fresh copy per call) that passes straight into downstream kernels. Not yet supported: graphical mode, kernel maps, and texture/image arguments all **degrade to the cpu backend** — in auto modes and under explicit `mode: 'webasm'` alike — the console warning names the reason and `kernel.kernel.fallbackReason` carries it queryably; a graphical fallback renders into the kernel's own canvas; `toString()` throws. Threaded runs accept a `poolSize` setting to cap the worker pool (defaults to `hardwareConcurrency`, or 4 when it cannot be read). `precision: 'unsigned'` is accepted and computed as single precision — wasm has no packed storage to be lossy in. + ## Asynchronous Kernels **New in 2.20.0!** @@ -1336,7 +1370,7 @@ What that buys depends on the backend, but the contract never changes: * **webgpu** — kernels are natively asynchronous; `asyncMode` is always on. * **cpu, webgl, headlessgl** — the synchronous result is resolved, so the calling contract stays uniform and your code stays portable. -`mode: 'async'` puts the whole `GPU` instance under this contract and picks the backend for you — the best synchronously-provable one immediately (webgl2 → webgl → cpu), upgraded to WebGPU on a kernel's first call if an adapter actually answers. **Graphical kernels bind at creation instead**: a canvas is permanently committed to its first context type, so the backend is decided before `kernel.canvas` is ever exposed — `await GPU.isWebGPUAvailable()` before `createKernel` to guarantee the probe has settled; a kernel created before it settles stays on the proven backend, and either way the canvas never changes identity. The Promise contract is exactly what buys the room for that probe. A kernel the WebGPU backend cannot take yet (a kernel map, say) simply stays on the proven backend: +`mode: 'async'` puts the whole `GPU` instance under this contract and picks the backend for you — the best synchronously-provable one immediately (headlessgl → webgl2 → webgl → webasm → cpu), upgraded to WebGPU on a kernel's first call if an adapter actually answers. On a GL-less platform that means webasm, where the async contract also unlocks its worker-pool threading — see the WebAssembly section for the SharedArrayBuffer caveat. **Graphical kernels bind at creation instead**: a canvas is permanently committed to its first context type, so the backend is decided before `kernel.canvas` is ever exposed — `await GPU.isWebGPUAvailable()` before `createKernel` to guarantee the probe has settled; a kernel created before it settles stays on the proven backend, and either way the canvas never changes identity. The Promise contract is exactly what buys the room for that probe. A kernel the WebGPU backend cannot take yet (a kernel map, say) simply stays on the proven backend: ```js const gpu = new GPU({ mode: 'async' }); diff --git a/dist/gpu-browser-core.js b/dist/gpu-browser-core.js index 93fbf559..ba7f5b89 100644 --- a/dist/gpu-browser-core.js +++ b/dist/gpu-browser-core.js @@ -5,7 +5,7 @@ * GPU Accelerated JavaScript * * @version 2.21.0 - * @date Mon Aug 03 2026 01:03:16 GMT+0800 (Singapore Standard Time) + * @date Mon Aug 03 2026 09:01:53 GMT+0800 (Singapore Standard Time) * * @license MIT * The MIT License @@ -473,6 +473,7 @@ return result; }, getAstString(source, ast) { + if (!ast.loc) return "[synthetic node]"; const lines = Array.isArray(source) ? source : source.split(/\r?\n/g); const start = ast.loc.start; const end = ast.loc.end; @@ -1035,7 +1036,7 @@ utils: utils }; }); - var require_kernel$6 = __commonJSMin((exports, module) => { + var require_kernel$7 = __commonJSMin((exports, module) => { const {utils: utils} = require_utils(); const {Input: Input} = require_input(); var Kernel = class { @@ -1067,6 +1068,7 @@ } this.useLegacyEncoder = false; this.fallbackRequested = false; + this.fallbackReason = null; this.onRequestFallback = null; this.onRequestSwitchKernel = null; this.argumentNames = typeof source === "string" ? utils.getArgumentNamesFromString(source) : null; @@ -1363,9 +1365,10 @@ this.tactic = tactic; return this; } - requestFallback(args) { + requestFallback(args, reason) { if (!this.onRequestFallback) throw new Error(`"onRequestFallback" not defined on ${this.constructor.name}`); this.fallbackRequested = true; + this.fallbackReason = reason || null; return this.onRequestFallback(args); } validateSettings() { @@ -2140,7 +2143,7 @@ FunctionTracer: FunctionTracer }; }); - var require_function_node$4 = __commonJSMin((exports, module) => { + var require_function_node$5 = __commonJSMin((exports, module) => { const acorn = require_empty_module(); const {utils: utils} = require_utils(); const {FunctionTracer: FunctionTracer} = require_function_tracer(); @@ -2264,6 +2267,30 @@ if (!ast) throw new Error("Failed to parse JS code"); return this.ast = functionAST; } + getAssignedArguments() { + if (this._assignedArguments) return this._assignedArguments; + const assigned = new Set; + const redeclared = new Set; + const names = this.argumentNames || []; + const walk = node => { + if (!node || typeof node !== "object") return; + if (Array.isArray(node)) { + for (const child of node) walk(child); + return; + } + if (node.type === "AssignmentExpression" && node.left.type === "Identifier" && names.indexOf(node.left.name) !== -1) assigned.add(node.left.name); + if (node.type === "UpdateExpression" && node.argument.type === "Identifier" && names.indexOf(node.argument.name) !== -1) assigned.add(node.argument.name); + if (node.type === "VariableDeclarator" && node.id.type === "Identifier" && names.indexOf(node.id.name) !== -1) redeclared.add(node.id.name); + for (const key in node) { + if (key === "loc" || key === "range" || key === "parent") continue; + const child = node[key]; + if (child && typeof child === "object") walk(child); + } + }; + walk(this.getJsAST()); + for (const name of redeclared) assigned.delete(name); + return this._assignedArguments = assigned; + } traceFunctionAST(ast) { const {contexts: contexts, declarations: declarations, functions: functions, identifiers: identifiers, functionCalls: functionCalls} = new FunctionTracer(ast); this.contexts = contexts; @@ -3429,9 +3456,13 @@ FunctionNode: FunctionNode }; }); - var require_function_node$3 = __commonJSMin((exports, module) => { - const {FunctionNode: FunctionNode} = require_function_node$4(); + var require_function_node$4 = __commonJSMin((exports, module) => { + const {FunctionNode: FunctionNode} = require_function_node$5(); var CPUFunctionNode = class extends FunctionNode { + markupUserName(name) { + if (this.isRootKernel && this.getAssignedArguments().has(name)) return `cellShadow_user_${name}`; + return `user_${name}`; + } astFunction(ast, retArr) { if (!this.isRootKernel) { retArr.push("function"); @@ -3446,10 +3477,15 @@ } retArr.push(") {\n"); } + if (this.isRootKernel) { + for (const name of this.getAssignedArguments()) retArr.push(`let cellShadow_user_${name} = user_${name};\n`); + retArr.push("kernelBody: {\n"); + } for (let i = 0; i < ast.body.body.length; ++i) { this.astGeneric(ast.body.body[i], retArr); retArr.push("\n"); } + if (this.isRootKernel) retArr.push("}\n"); if (!this.isRootKernel) retArr.push("}\n"); return retArr; } @@ -3461,7 +3497,7 @@ this.astGeneric(ast.argument, retArr); retArr.push(";\n"); retArr.push(this.followingReturnStatement); - retArr.push("continue;\n"); + retArr.push("break kernelBody;\n"); } else if (this.isSubKernel) { retArr.push(`subKernelResult_${this.name} = `); this.astGeneric(ast.argument, retArr); @@ -3495,7 +3531,7 @@ break; default: - if (!this.getDeclaration(idtNode) && this.constants && this.constants.hasOwnProperty(idtNode.name)) retArr.push("constants_" + idtNode.name); else retArr.push("user_" + idtNode.name); + if (!this.getDeclaration(idtNode) && this.constants && this.constants.hasOwnProperty(idtNode.name)) retArr.push("constants_" + idtNode.name); else if (!this.getDeclaration(idtNode) && this.isRootKernel && this.getAssignedArguments().has(idtNode.name)) retArr.push(this.markupUserName(idtNode.name)); else retArr.push("user_" + idtNode.name); } return retArr; } @@ -3553,14 +3589,13 @@ } astDoWhileStatement(doWhileNode, retArr) { if (doWhileNode.type !== "DoWhileStatement") throw this.astErrorOutput("Invalid while statement", doWhileNode); - retArr.push("for (let i = 0; i < LOOP_MAX; i++) {"); + const safeName = `safeI${this.astKey(doWhileNode, "_")}`; + retArr.push(`let ${safeName} = 0;\n`); + retArr.push("do {"); this.astGeneric(doWhileNode.body, retArr); - retArr.push("if (!"); + retArr.push("} while (("); this.astGeneric(doWhileNode.test, retArr); - retArr.push(") {\n"); - retArr.push("break;\n"); - retArr.push("}\n"); - retArr.push("}\n"); + retArr.push(`) && ++${safeName} < LOOP_MAX);\n`); return retArr; } astAssignmentExpression(assNode, retArr) { @@ -3731,10 +3766,10 @@ case "Integer": case "Float": case "Boolean": - retArr.push(`${origin}_${name}`); + retArr.push(origin === "user" ? this.markupUserName(name) : `${origin}_${name}`); return retArr; } - const markupName = `${origin}_${name}`; + const markupName = origin === "user" ? this.markupUserName(name) : `${origin}_${name}`; switch (type) { default: let size; @@ -3961,10 +3996,10 @@ cpuKernelString: cpuKernelString }; }); - var require_kernel$5 = __commonJSMin((exports, module) => { - const {Kernel: Kernel} = require_kernel$6(); + var require_kernel$6 = __commonJSMin((exports, module) => { + const {Kernel: Kernel} = require_kernel$7(); const {FunctionBuilder: FunctionBuilder} = require_function_builder(); - const {CPUFunctionNode: CPUFunctionNode} = require_function_node$3(); + const {CPUFunctionNode: CPUFunctionNode} = require_function_node$4(); const {utils: utils} = require_utils(); const {cpuKernelString: cpuKernelString} = require_kernel_string$1(); var CPUKernel = class extends Kernel { @@ -4775,8 +4810,8 @@ GLTextureGraphical: GLTextureGraphical }; }); - var require_kernel$4 = __commonJSMin((exports, module) => { - const {Kernel: Kernel} = require_kernel$6(); + var require_kernel$5 = __commonJSMin((exports, module) => { + const {Kernel: Kernel} = require_kernel$7(); const {utils: utils} = require_utils(); const {GLTextureArray2Float: GLTextureArray2Float} = require_array_2_float(); const {GLTextureArray2Float2D: GLTextureArray2Float2D} = require_array_2_float_2d(); @@ -5070,7 +5105,7 @@ case "Array(2)": case "Array(3)": case "Array(4)": - return this.requestFallback(args); + return this.requestFallback(args, `${this.returnType} output requires single precision, which this context does not support`); } } else { if (this.subKernels !== null) this.renderKernels = this.renderKernelsToArrays; @@ -5097,7 +5132,7 @@ case "Array(2)": case "Array(3)": case "Array(4)": - return this.requestFallback(args); + return this.requestFallback(args, `${this.returnType} output requires single precision, which this context does not support`); } } } else if (this.precision === "single") { @@ -5556,9 +5591,9 @@ GLKernel: GLKernel }; }); - var require_function_node$2 = __commonJSMin((exports, module) => { + var require_function_node$3 = __commonJSMin((exports, module) => { const {utils: utils} = require_utils(); - const {FunctionNode: FunctionNode} = require_function_node$4(); + const {FunctionNode: FunctionNode} = require_function_node$5(); const INTEGER_COMPARISON_ROUNDING = { "<": "ceil", ">=": "ceil", @@ -5625,6 +5660,17 @@ if (type === "sampler2D" || type === "sampler2DArray") retArr.push(`${type} user_${name},ivec2 user_${name}Size,ivec3 user_${name}Dim`); else retArr.push(`${type} user_${name}`); } retArr.push(") {\n"); + if (this.isRootKernel) { + const assignedArguments = this.getAssignedArguments(); + for (let i = 0; i < this.argumentNames.length; ++i) { + const argumentName = this.argumentNames[i]; + if (!assignedArguments.has(argumentName)) continue; + const type = typeMap[this.argumentTypes[i]]; + if (type !== "float" && type !== "int" && type !== "bool") continue; + const name = utils.sanitizeName(argumentName); + retArr.push(`${type} cellShadow_user_${name}=user_${name};\n`); + } + } for (let i = 0; i < ast.body.body.length; ++i) { this.astStatementWithHoisting(ast.body.body[i], retArr); retArr.push("\n"); @@ -6033,9 +6079,21 @@ if (idtNode.type !== "Identifier") throw this.astErrorOutput("IdentifierExpression - not an Identifier", idtNode); const type = this.getType(idtNode); const name = utils.sanitizeName(idtNode.name); - if (idtNode.name === "Infinity") retArr.push("3.402823466e+38"); else if (type === "Boolean") if (this.argumentNames.indexOf(name) > -1) retArr.push(`bool(user_${name})`); else retArr.push(`user_${name}`); else retArr.push(`user_${name}`); + if (idtNode.name === "Infinity") retArr.push("3.402823466e+38"); else if (type === "Boolean") if (this.argumentNames.indexOf(name) > -1) { + const marked = this.markupUserName(idtNode.name); + retArr.push(marked.startsWith("cellShadow_") ? marked : `bool(${marked})`); + } else retArr.push(`user_${name}`); else retArr.push(this.markupUserName(idtNode.name)); return retArr; } + markupUserName(name) { + const sanitized = utils.sanitizeName(name); + if (this.isRootKernel && this.getAssignedArguments().has(name)) { + const index = this.argumentNames.indexOf(name); + const type = index === -1 ? null : typeMap[this.argumentTypes[index]]; + if (type === "float" || type === "int" || type === "bool") return `cellShadow_user_${sanitized}`; + } + return `user_${sanitized}`; + } astForStatement(forNode, retArr) { if (forNode.type !== "ForStatement") throw this.astErrorOutput("Invalid for statement", forNode); const initArr = []; @@ -6092,10 +6150,10 @@ if (doWhileNode.type !== "DoWhileStatement") throw this.astErrorOutput("Invalid while statement", doWhileNode); const iVariableName = this.getInternalVariableName("safeI"); retArr.push(`for (int ${iVariableName}=0;${iVariableName}0){if (!`); this.astGeneric(doWhileNode.test, retArr); - retArr.push(") break;\n"); + retArr.push(") break;}\n"); + this.astGeneric(doWhileNode.body, retArr); retArr.push("}\n"); return retArr; } @@ -6127,7 +6185,7 @@ retArr.push("float("); this.astGeneric(assNode.right, retArr); retArr.push(")"); - } else this.astGeneric(assNode.right, retArr); + } else if (leftType === "Integer" && rightType === "LiteralInteger") this.castLiteralToInteger(assNode.right, retArr); else this.astGeneric(assNode.right, retArr); } if (!isStatement) retArr.push(")"); return retArr; @@ -6367,6 +6425,10 @@ } } ] }; + this.stampSyntheticNodes(replacement); + return replacement; + } + stampSyntheticNodes(root) { let syntheticId = this.syntheticNodeId || 1073741824; const stamp = node => { if (!node || typeof node !== "object") return; @@ -6384,9 +6446,8 @@ stamp(node[key]); } }; - stamp(replacement); + stamp(root); this.syntheticNodeId = syntheticId; - return replacement; } linearizeStatement(statement) { const statements = []; @@ -9173,10 +9234,10 @@ kernelValueMaps: kernelValueMaps }; }); - var require_kernel$3 = __commonJSMin((exports, module) => { - const {GLKernel: GLKernel} = require_kernel$4(); + var require_kernel$4 = __commonJSMin((exports, module) => { + const {GLKernel: GLKernel} = require_kernel$5(); const {FunctionBuilder: FunctionBuilder} = require_function_builder(); - const {WebGLFunctionNode: WebGLFunctionNode} = require_function_node$2(); + const {WebGLFunctionNode: WebGLFunctionNode} = require_function_node$3(); const {utils: utils} = require_utils(); const mrud = require_math_random_uniformly_distributed(); const {fragmentShader: fragmentShader} = require_fragment_shader$1(); @@ -9407,7 +9468,7 @@ this.argumentTypes.push(type); } else type = this.argumentTypes[index]; const KernelValue = this.constructor.lookupKernelValueType(type, this.dynamicArguments ? "dynamic" : "static", this.precision, args[index]); - if (KernelValue === null) return this.requestFallback(args); + if (KernelValue === null) return this.requestFallback(args, `argument "${this.argumentNames[index]}" of type ${type} is not supported by ${this.constructor.name}`); const kernelArgument = new KernelValue(value, { name: name, type: type, @@ -9455,7 +9516,7 @@ this.constantTypes[name] = type; } else type = this.constantTypes[name]; const KernelValue = this.constructor.lookupKernelValueType(type, "static", this.precision, value); - if (KernelValue === null) return this.requestFallback(args); + if (KernelValue === null) return this.requestFallback(args, `constant "${name}" of type ${type} is not supported by ${this.constructor.name}`); const kernelValue = new KernelValue(value, { name: name, type: type, @@ -10124,9 +10185,9 @@ WebGLKernel: WebGLKernel }; }); - var require_kernel$2 = __commonJSMin((exports, module) => { + var require_kernel$3 = __commonJSMin((exports, module) => { const getContext = require_empty_module(); - const {WebGLKernel: WebGLKernel} = require_kernel$3(); + const {WebGLKernel: WebGLKernel} = require_kernel$4(); const {glKernelString: glKernelString} = require_kernel_string(); let isSupported = null; let testCanvas = null; @@ -10238,15 +10299,18 @@ HeadlessGLKernel: HeadlessGLKernel }; }); - var require_function_node$1 = __commonJSMin((exports, module) => { + var require_function_node$2 = __commonJSMin((exports, module) => { const {utils: utils} = require_utils(); - const {WebGLFunctionNode: WebGLFunctionNode} = require_function_node$2(); + const {WebGLFunctionNode: WebGLFunctionNode} = require_function_node$3(); var WebGL2FunctionNode = class extends WebGLFunctionNode { astIdentifierExpression(idtNode, retArr) { if (idtNode.type !== "Identifier") throw this.astErrorOutput("IdentifierExpression - not an Identifier", idtNode); const type = this.getType(idtNode); const name = utils.sanitizeName(idtNode.name); - if (idtNode.name === "Infinity") retArr.push("intBitsToFloat(2139095039)"); else if (type === "Boolean") if (this.argumentNames.indexOf(name) > -1) retArr.push(`bool(user_${name})`); else retArr.push(`user_${name}`); else retArr.push(`user_${name}`); + if (idtNode.name === "Infinity") retArr.push("intBitsToFloat(2139095039)"); else if (type === "Boolean") if (this.argumentNames.indexOf(name) > -1) { + const marked = this.markupUserName(idtNode.name); + retArr.push(marked.startsWith("cellShadow_") ? marked : `bool(${marked})`); + } else retArr.push(`user_${name}`); else retArr.push(this.markupUserName(idtNode.name)); return retArr; } }; @@ -10922,9 +10986,9 @@ lookupKernelValueType: lookupKernelValueType }; }); - var require_kernel$1 = __commonJSMin((exports, module) => { - const {WebGLKernel: WebGLKernel} = require_kernel$3(); - const {WebGL2FunctionNode: WebGL2FunctionNode} = require_function_node$1(); + var require_kernel$2 = __commonJSMin((exports, module) => { + const {WebGLKernel: WebGLKernel} = require_kernel$4(); + const {WebGL2FunctionNode: WebGL2FunctionNode} = require_function_node$2(); const {FunctionBuilder: FunctionBuilder} = require_function_builder(); const {utils: utils} = require_utils(); const {fragmentShader: fragmentShader} = require_fragment_shader(); @@ -11408,9 +11472,9 @@ WebGL2Kernel: WebGL2Kernel }; }); - var require_function_node = __commonJSMin((exports, module) => { + var require_function_node$1 = __commonJSMin((exports, module) => { const {utils: utils} = require_utils(); - const {FunctionNode: FunctionNode} = require_function_node$4(); + const {FunctionNode: FunctionNode} = require_function_node$5(); var WGSLFunctionNode = class extends FunctionNode { get requiresSequenceFreeForInit() { return true; @@ -12687,10 +12751,10 @@ } }; }); - var require_kernel = __commonJSMin((exports, module) => { - const {Kernel: Kernel} = require_kernel$6(); + var require_kernel$1 = __commonJSMin((exports, module) => { + const {Kernel: Kernel} = require_kernel$7(); const {FunctionBuilder: FunctionBuilder} = require_function_builder(); - const {WGSLFunctionNode: WGSLFunctionNode} = require_function_node(); + const {WGSLFunctionNode: WGSLFunctionNode} = require_function_node$1(); const {WebGPUContext: WebGPUContext} = require_context(); const {WebGPUBufferResult: WebGPUBufferResult} = require_buffer_result(); const {utils: utils} = require_utils(); @@ -13015,10 +13079,10 @@ const context = await WebGPUContext.acquire(); this.context = context; const device = this._device = context.device; - const module$1 = device.createShaderModule({ + const module$5 = device.createShaderModule({ code: this.compiledSource }); - const errors = (await module$1.getCompilationInfo()).messages.filter(message => message.type === "error"); + const errors = (await module$5.getCompilationInfo()).messages.filter(message => message.type === "error"); if (errors.length > 0) throw new Error("Error compiling WGSL compute shader:\n" + errors.map(message => ` ${message.lineNum}:${message.linePos} ${message.message}`).join("\n") + `\n--- generated WGSL ---\n${this.compiledSource}`); const {arrayArgs: arrayArgs, bufferConstants: bufferConstants, byteLength: byteLength} = this.paramsLayout; const layoutEntries = [ { @@ -13059,7 +13123,7 @@ bindGroupLayouts: [ this.bindGroupLayout ] }), compute: { - module: module$1, + module: module$5, entryPoint: "main" } }); @@ -13613,207 +13677,5516 @@ WebGPUKernel: WebGPUKernel }; }); - var require_kernel_run_shortcut = __commonJSMin((exports, module) => { - const {utils: utils} = require_utils(); - const {Input: Input} = require_input(); - function kernelRunShortcut(kernel) { - const MAX_SWITCHES = 4; - function syncBody(args) { - kernel.build.apply(kernel, args); - kernel.checkArgumentTypes(args); - let result = kernel.switchingKernels ? void 0 : kernel.run.apply(kernel, args); - for (let i = 0; kernel.switchingKernels; i++) { - if (i >= MAX_SWITCHES) { - const reasons = kernel.resetSwitchingKernels(); - throw new Error(`this kernel cannot run the arguments it was given (${describeReasons(reasons)}); it did not settle on a kernel for them after ${MAX_SWITCHES} attempts. Create a separate kernel for this call's argument types.`); - } - const reasons = kernel.resetSwitchingKernels(); - const newKernel = kernel.onRequestSwitchKernel(reasons, args, kernel); - shortcut.kernel = kernel = newKernel; - newKernel.checkArgumentTypes(args); - result = newKernel.switchingKernels ? void 0 : newKernel.run.apply(newKernel, args); + var require_wasm_builder = __commonJSMin((exports, module) => { + const VAL_TYPES = { + i32: 127, + i64: 126, + f32: 125, + f64: 124, + v128: 123 + }; + const SECTION_TYPE = 1; + const SECTION_IMPORT = 2; + const SECTION_FUNCTION = 3; + const SECTION_GLOBAL = 6; + const SECTION_EXPORT = 7; + const SECTION_CODE = 10; + const f32Scratch = new DataView(new ArrayBuffer(16)); + function uleb(value, out) { + let v = value >>> 0; + do { + let byte = v & 127; + v >>>= 7; + if (v !== 0) byte |= 128; + out.push(byte); + } while (v !== 0); + } + function sleb(value, out) { + let v = value | 0; + for (;;) { + const byte = v & 127; + v >>= 7; + if (v === 0 && (byte & 64) === 0 || v === -1 && (byte & 64) !== 0) { + out.push(byte); + return; } - return result; + out.push(byte | 128); } - function describeReasons(reasons) { - if (!reasons || !reasons.length) return "unknown reason"; - return reasons.map(reason => { - if (reason.type === "argumentTypeMismatch") return `argument ${reason.index} is now ${reason.needed}`; - return reason.type; - }).join(", "); + } + function uleb5At(value, bytes, at) { + let v = value >>> 0; + for (let i = 0; i < 4; i++) { + bytes[at + i] = v & 127 | 128; + v >>>= 7; } - function syncRun(args) { - const result = syncBody(args); - if (kernel.renderKernels) return kernel.renderKernels(); else if (kernel.renderOutput) return kernel.renderOutput(); else return result; + bytes[at + 4] = v & 127; + } + function utf8(str, out) { + const bytes = []; + for (let i = 0; i < str.length; i++) { + let code = str.codePointAt(i); + if (code > 65535) i++; + if (code < 128) bytes.push(code); else if (code < 2048) bytes.push(192 | code >> 6, 128 | code & 63); else if (code < 65536) bytes.push(224 | code >> 12, 128 | code >> 6 & 63, 128 | code & 63); else bytes.push(240 | code >> 18, 128 | code >> 12 & 63, 128 | code >> 6 & 63, 128 | code & 63); + } + uleb(bytes.length, out); + for (let i = 0; i < bytes.length; i++) out.push(bytes[i]); + } + function valType(type) { + const byte = VAL_TYPES[type]; + if (byte === void 0) throw new Error(`WasmModuleBuilder: unknown value type "${type}"`); + return byte; + } + function blockType(type) { + if (type === void 0 || type === null || type === "void") return 64; + return valType(type); + } + var WasmFunctionEmitter = class { + constructor(builder, name, params, results, locals) { + this.builder = builder; + this.name = name; + this.params = params; + this.results = results; + this.locals = locals.slice(); + this.bytes = []; + this.callFixups = []; + } + addLocal(type) { + valType(type); + this.locals.push(type); + return this.params.length + this.locals.length - 1; + } + block(type) { + this.bytes.push(2, blockType(type)); + return this; } - function asyncRun(args) { - if (kernel.onAsyncModeUpgrade) { - const upgrade = kernel.onAsyncModeUpgrade; - kernel.onAsyncModeUpgrade = null; - const snapped = snapshotArguments(args); - return upgrade(snapped, kernel).then(upgradedKernel => { - if (upgradedKernel) shortcut.replaceKernel(upgradedKernel); - return asyncRun(snapped); - }); - } - try { - if (kernel.constructor.isAsync === true) { - kernel.build.apply(kernel, args); - return Promise.resolve(kernel.run.apply(kernel, args)); - } - for (let i = 0; i < args.length; i++) if (isWebGPUHandle(args[i])) return resolveHandles(args).then(resolved => asyncRun(resolved)); - const result = syncBody(args); - if (kernel.renderKernels) return Promise.resolve(kernel.renderKernels()); else if (kernel.renderOutput) { - if (kernel.renderOutputAsync) return kernel.renderOutputAsync(); - return Promise.resolve(kernel.renderOutput()); - } else return Promise.resolve(result); - } catch (e) { - return Promise.reject(e); - } + loop(type) { + this.bytes.push(3, blockType(type)); + return this; } - function isWebGPUHandle(value) { - return Boolean(value) && value.type === "WebGPUBuffer"; + if_(type) { + this.bytes.push(4, blockType(type)); + return this; } - function resolveHandles(args) { - const snapped = snapshotArguments(args); - const pending = []; - for (let i = 0; i < snapped.length; i++) if (isWebGPUHandle(snapped[i])) { - const index = i; - pending.push(Promise.resolve(snapped[index].toArray()).then(value => { - snapped[index] = value; - })); - } - return Promise.all(pending).then(() => snapped); + br(depth) { + this.bytes.push(12); + uleb(depth, this.bytes); + return this; } - function snapshotArguments(args) { - const copy = new Array(args.length); - for (let i = 0; i < args.length; i++) copy[i] = snapshotValue(args[i]); - return copy; + brIf(depth) { + this.bytes.push(13); + uleb(depth, this.bytes); + return this; } - function snapshotValue(value) { - if (!value || typeof value !== "object") return value; - if (isWebGPUHandle(value) || typeof value.delete === "function") return value; - if (ArrayBuffer.isView(value)) return value.slice(0); - if (Array.isArray(value)) return value.map(snapshotValue); - if (value instanceof Input) return new Input(snapshotValue(value.value), value.size); - return value; + call(name) { + this.bytes.push(16); + this.callFixups.push({ + at: this.bytes.length, + name: name + }); + this.bytes.push(0, 0, 0, 0, 0); + return this; } - function run() { - if (kernel.constructor.isAsync === true || kernel.asyncMode === true) return asyncRun(arguments); - return syncRun(arguments); + localGet(index) { + this.bytes.push(32); + uleb(index, this.bytes); + return this; } - const shortcut = function() { - return run.apply(kernel, arguments); - }; - shortcut.exec = function() { - return new Promise((accept, reject) => { - try { - accept(run.apply(this, arguments)); - } catch (e) { - reject(e); - } - }); - }; - shortcut.replaceKernel = function(replacementKernel) { - kernel = replacementKernel; - bindKernelToShortcut(kernel, shortcut); - }; - bindKernelToShortcut(kernel, shortcut); - return shortcut; - } - function bindKernelToShortcut(kernel, shortcut) { - if (shortcut.kernel) { - shortcut.kernel = kernel; - return; + localSet(index) { + this.bytes.push(33); + uleb(index, this.bytes); + return this; } - const properties = utils.allPropertiesOf(kernel); - for (let i = 0; i < properties.length; i++) { - const property = properties[i]; - if (property[0] === "_" && property[1] === "_") continue; - if (typeof kernel[property] === "function") if (property.substring(0, 3) === "add" || property.substring(0, 3) === "set") shortcut[property] = function() { - shortcut.kernel[property].apply(shortcut.kernel, arguments); - return shortcut; - }; else shortcut[property] = function() { - return shortcut.kernel[property].apply(shortcut.kernel, arguments); - }; else { - shortcut.__defineGetter__(property, () => shortcut.kernel[property]); - shortcut.__defineSetter__(property, value => { - shortcut.kernel[property] = value; - }); - } + localTee(index) { + this.bytes.push(34); + uleb(index, this.bytes); + return this; } - shortcut.kernel = kernel; - } - module.exports = { - kernelRunShortcut: kernelRunShortcut - }; - }); - var require_gpu = __commonJSMin((exports, module) => { - const {gpuMock: gpuMock} = require_gpu_mock_js(); - const {utils: utils} = require_utils(); - const {Kernel: Kernel} = require_kernel$6(); - const {CPUKernel: CPUKernel} = require_kernel$5(); - const {HeadlessGLKernel: HeadlessGLKernel} = require_kernel$2(); - const {WebGL2Kernel: WebGL2Kernel} = require_kernel$1(); - const {WebGLKernel: WebGLKernel} = require_kernel$3(); - const {WebGPUKernel: WebGPUKernel} = require_kernel(); - const {kernelRunShortcut: kernelRunShortcut} = require_kernel_run_shortcut(); - const kernelOrder = [ HeadlessGLKernel, WebGL2Kernel, WebGLKernel ]; - const kernelTypes = [ "gpu", "cpu" ]; - const internalKernels = { - headlessgl: HeadlessGLKernel, - webgl2: WebGL2Kernel, - webgl: WebGLKernel, - webgpu: WebGPUKernel - }; - let validate = true; - var GPU = class GPU { - static disableValidation() { - validate = false; + globalGet(index) { + this.bytes.push(35); + uleb(index, this.bytes); + return this; } - static enableValidation() { - validate = true; + globalSet(index) { + this.bytes.push(36); + uleb(index, this.bytes); + return this; } - static get isGPUSupported() { - return kernelOrder.some(Kernel => Kernel.isSupported); + i32Const(value) { + this.bytes.push(65); + sleb(value, this.bytes); + return this; } - static get isKernelMapSupported() { - return kernelOrder.some(Kernel => Kernel.isSupported && Kernel.features.kernelMap); + f32Const(value) { + this.bytes.push(67); + f32Scratch.setFloat32(0, value, true); + for (let i = 0; i < 4; i++) this.bytes.push(f32Scratch.getUint8(i)); + return this; } - static get isOffscreenCanvasSupported() { - return typeof Worker !== "undefined" && typeof OffscreenCanvas !== "undefined" || typeof importScripts !== "undefined"; + v128Const(lanes) { + if (lanes.length !== 16) throw new Error("WasmModuleBuilder: v128.const requires exactly 16 bytes"); + this.bytes.push(253, 12); + for (let i = 0; i < 16; i++) this.bytes.push(lanes[i] & 255); + return this; } - static get isWebGLSupported() { - return WebGLKernel.isSupported; + v128ConstI32x4(a, b, c, d) { + f32Scratch.setInt32(0, a, true); + f32Scratch.setInt32(4, b, true); + f32Scratch.setInt32(8, c, true); + f32Scratch.setInt32(12, d, true); + this.bytes.push(253, 12); + for (let i = 0; i < 16; i++) this.bytes.push(f32Scratch.getUint8(i)); + return this; } - static get isWebGL2Supported() { - return WebGL2Kernel.isSupported; + v128ConstF32x4(a, b, c, d) { + f32Scratch.setFloat32(0, a, true); + f32Scratch.setFloat32(4, b, true); + f32Scratch.setFloat32(8, c, true); + f32Scratch.setFloat32(12, d, true); + this.bytes.push(253, 12); + for (let i = 0; i < 16; i++) this.bytes.push(f32Scratch.getUint8(i)); + return this; } - static get isHeadlessGLSupported() { - return HeadlessGLKernel.isSupported; + i32Load(offset = 0, align = 2) { + this.bytes.push(40); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; } - static get isWebGPUSupported() { - return WebGPUKernel.isSupported; + f32Load(offset = 0, align = 2) { + this.bytes.push(42); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; } - static isWebGPUAvailable() { - if (!WebGPUKernel.isSupported) return Promise.resolve(false); - return navigator.gpu.requestAdapter().then(adapter => adapter !== null, () => false); + i32Store(offset = 0, align = 2) { + this.bytes.push(54); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; } - static get isCanvasSupported() { - return typeof HTMLCanvasElement !== "undefined"; + f32Store(offset = 0, align = 2) { + this.bytes.push(56); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; } - static get isGPUHTMLImageArraySupported() { - return WebGL2Kernel.isSupported; + v128Load(offset = 0, align = 4) { + this.bytes.push(253, 0); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; } - static get isSinglePrecisionSupported() { - return kernelOrder.some(Kernel => Kernel.isSupported && Kernel.features.isFloatRead && Kernel.features.isTextureFloat); + v128Store(offset = 0, align = 4) { + this.bytes.push(253, 11); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; } - constructor(settings) { - settings = settings || {}; - this.canvas = settings.canvas || null; - this.context = settings.context || null; - this.mode = settings.mode; - this.Kernel = null; + i32x4ExtractLane(lane) { + return this._lane(27, lane); + } + i32x4ReplaceLane(lane) { + return this._lane(28, lane); + } + f32x4ExtractLane(lane) { + return this._lane(31, lane); + } + f32x4ReplaceLane(lane) { + return this._lane(32, lane); + } + _lane(op, lane) { + if (!Number.isInteger(lane) || lane < 0 || lane > 3) throw new Error(`WasmModuleBuilder: lane index ${lane} out of range for 4-lane shape`); + this.bytes.push(253, op, lane); + return this; + } + _push(bytes) { + for (let i = 0; i < bytes.length; i++) this.bytes.push(bytes[i]); + return this; + } + }; + const PLAIN_OPS = { + unreachable: [ 0 ], + nop: [ 1 ], + else_: [ 5 ], + end: [ 11 ], + return_: [ 15 ], + drop: [ 26 ], + select: [ 27 ], + i32Eqz: [ 69 ], + i32Eq: [ 70 ], + i32Ne: [ 71 ], + i32LtS: [ 72 ], + i32LtU: [ 73 ], + i32GtS: [ 74 ], + i32GtU: [ 75 ], + i32LeS: [ 76 ], + i32LeU: [ 77 ], + i32GeS: [ 78 ], + i32GeU: [ 79 ], + f32Eq: [ 91 ], + f32Ne: [ 92 ], + f32Lt: [ 93 ], + f32Gt: [ 94 ], + f32Le: [ 95 ], + f32Ge: [ 96 ], + i32Clz: [ 103 ], + i32Ctz: [ 104 ], + i32Popcnt: [ 105 ], + i32Add: [ 106 ], + i32Sub: [ 107 ], + i32Mul: [ 108 ], + i32DivS: [ 109 ], + i32DivU: [ 110 ], + i32RemS: [ 111 ], + i32RemU: [ 112 ], + i32And: [ 113 ], + i32Or: [ 114 ], + i32Xor: [ 115 ], + i32Shl: [ 116 ], + i32ShrS: [ 117 ], + i32ShrU: [ 118 ], + i32Rotl: [ 119 ], + i32Rotr: [ 120 ], + f32Abs: [ 139 ], + f32Neg: [ 140 ], + f32Ceil: [ 141 ], + f32Floor: [ 142 ], + f32Trunc: [ 143 ], + f32Nearest: [ 144 ], + f32Sqrt: [ 145 ], + f32Add: [ 146 ], + f32Sub: [ 147 ], + f32Mul: [ 148 ], + f32Div: [ 149 ], + f32Min: [ 150 ], + f32Max: [ 151 ], + f32Copysign: [ 152 ], + i32TruncF32S: [ 168 ], + i32TruncF32U: [ 169 ], + f32ConvertI32S: [ 178 ], + f32ConvertI32U: [ 179 ], + i32ReinterpretF32: [ 188 ], + f32ReinterpretI32: [ 190 ], + i32TruncSatF32S: [ 252, 0 ], + i32TruncSatF32U: [ 252, 1 ] + }; + const SIMD_OPS = { + i32x4Splat: 17, + f32x4Splat: 19, + i32x4Eq: 55, + i32x4Ne: 56, + i32x4LtS: 57, + i32x4GtS: 59, + i32x4LeS: 61, + i32x4GeS: 63, + f32x4Eq: 65, + f32x4Ne: 66, + f32x4Lt: 67, + f32x4Gt: 68, + f32x4Le: 69, + f32x4Ge: 70, + v128Not: 77, + v128And: 78, + v128Andnot: 79, + v128Or: 80, + v128Xor: 81, + v128Bitselect: 82, + v128AnyTrue: 83, + f32x4Ceil: 103, + f32x4Floor: 104, + f32x4Trunc: 105, + f32x4Nearest: 106, + i32x4Abs: 160, + i32x4Neg: 161, + i32x4AllTrue: 163, + i32x4Bitmask: 164, + i32x4Shl: 171, + i32x4ShrS: 172, + i32x4ShrU: 173, + i32x4Add: 174, + i32x4Sub: 177, + i32x4Mul: 181, + i32x4MinS: 182, + i32x4MinU: 183, + i32x4MaxS: 184, + i32x4MaxU: 185, + f32x4Abs: 224, + f32x4Neg: 225, + f32x4Sqrt: 227, + f32x4Add: 228, + f32x4Sub: 229, + f32x4Mul: 230, + f32x4Div: 231, + f32x4Min: 232, + f32x4Max: 233, + f32x4Pmin: 234, + f32x4Pmax: 235, + i32x4TruncSatF32x4S: 248, + i32x4TruncSatF32x4U: 249, + f32x4ConvertI32x4S: 250, + f32x4ConvertI32x4U: 251 + }; + for (const name of Object.keys(PLAIN_OPS)) { + const bytes = PLAIN_OPS[name]; + WasmFunctionEmitter.prototype[name] = function() { + return this._push(bytes); + }; + } + for (const name of Object.keys(SIMD_OPS)) { + const bytes = [ 253 ]; + uleb(SIMD_OPS[name], bytes); + WasmFunctionEmitter.prototype[name] = function() { + return this._push(bytes); + }; + } + var WasmModuleBuilder = class { + constructor() { + this.types = []; + this.typeIndexByKey = {}; + this.memoryImport = null; + this.funcImports = []; + this.funcImportIndexByName = {}; + this.functions = []; + this.functionIndexByName = {}; + this.globals = []; + this.exports = []; + } + _typeIndex(params, results) { + const key = `${params.join(",")}=>${results.join(",")}`; + if (key in this.typeIndexByKey) return this.typeIndexByKey[key]; + const index = this.types.length; + this.types.push({ + params: params, + results: results + }); + this.typeIndexByKey[key] = index; + return index; + } + addMemoryImport(initial, maximum, shared = false) { + if (shared && (maximum === void 0 || maximum === null)) throw new Error("WasmModuleBuilder: shared memory import requires a maximum"); + this.memoryImport = { + initial: initial, + maximum: maximum, + shared: shared + }; + return this; + } + addFuncImport(name, params, results, module$3 = "env") { + if (name in this.funcImportIndexByName || name in this.functionIndexByName) throw new Error(`WasmModuleBuilder: duplicate function name "${name}"`); + const index = this.funcImports.length; + this.funcImports.push({ + name: name, + module: module$3, + typeIndex: this._typeIndex(params, results) + }); + this.funcImportIndexByName[name] = index; + return index; + } + addGlobal(type, mutable, initialValue) { + valType(type); + this.globals.push({ + type: type, + mutable: mutable, + initialValue: initialValue + }); + return this.globals.length - 1; + } + addFunction(name, {params: params = [], results: results = [], locals: locals = []} = {}) { + if (name in this.funcImportIndexByName || name in this.functionIndexByName) throw new Error(`WasmModuleBuilder: duplicate function name "${name}"`); + params.forEach(valType); + results.forEach(valType); + locals.forEach(valType); + const emitter = new WasmFunctionEmitter(this, name, params, results, locals); + this.functionIndexByName[name] = this.functions.length; + this.functions.push({ + name: name, + emitter: emitter, + typeIndex: this._typeIndex(params, results) + }); + return emitter; + } + exportFunction(name, exportName = name) { + this.exports.push({ + name: name, + exportName: exportName + }); + return this; + } + _resolveFuncIndex(name) { + if (name in this.funcImportIndexByName) return this.funcImportIndexByName[name]; + if (name in this.functionIndexByName) return this.funcImports.length + this.functionIndexByName[name]; + throw new Error(`WasmModuleBuilder: call target "${name}" is not an import or a defined function`); + } + _section(id, payload, out) { + out.push(id); + uleb(payload.length, out); + for (let i = 0; i < payload.length; i++) out.push(payload[i]); + } + toBytes() { + const out = [ 0, 97, 115, 109, 1, 0, 0, 0 ]; + if (this.types.length > 0) { + const payload = []; + uleb(this.types.length, payload); + for (const {params: params, results: results} of this.types) { + payload.push(96); + uleb(params.length, payload); + for (const p of params) payload.push(valType(p)); + uleb(results.length, payload); + for (const r of results) payload.push(valType(r)); + } + this._section(SECTION_TYPE, payload, out); + } + if (this.memoryImport !== null || this.funcImports.length > 0) { + const payload = []; + uleb((this.memoryImport !== null ? 1 : 0) + this.funcImports.length, payload); + if (this.memoryImport !== null) { + const {initial: initial, maximum: maximum, shared: shared} = this.memoryImport; + utf8("env", payload); + utf8("memory", payload); + payload.push(2); + const hasMax = maximum !== void 0 && maximum !== null; + payload.push(shared ? 3 : hasMax ? 1 : 0); + uleb(initial, payload); + if (hasMax) uleb(maximum, payload); + } + for (const {name: name, module: module$4, typeIndex: typeIndex} of this.funcImports) { + utf8(module$4, payload); + utf8(name, payload); + payload.push(0); + uleb(typeIndex, payload); + } + this._section(SECTION_IMPORT, payload, out); + } + if (this.functions.length > 0) { + const payload = []; + uleb(this.functions.length, payload); + for (const {typeIndex: typeIndex} of this.functions) uleb(typeIndex, payload); + this._section(SECTION_FUNCTION, payload, out); + } + if (this.globals.length > 0) { + const payload = []; + uleb(this.globals.length, payload); + for (const {type: type, mutable: mutable, initialValue: initialValue} of this.globals) { + payload.push(valType(type), mutable ? 1 : 0); + if (type === "i32") { + payload.push(65); + sleb(initialValue, payload); + } else if (type === "f32") { + payload.push(67); + f32Scratch.setFloat32(0, initialValue, true); + for (let i = 0; i < 4; i++) payload.push(f32Scratch.getUint8(i)); + } else if (type === "v128") { + payload.push(253, 12); + for (let i = 0; i < 16; i++) payload.push(0); + } else throw new Error(`WasmModuleBuilder: no initializer encoding for global type "${type}"`); + payload.push(11); + } + this._section(SECTION_GLOBAL, payload, out); + } + if (this.exports.length > 0) { + const payload = []; + uleb(this.exports.length, payload); + for (const {name: name, exportName: exportName} of this.exports) { + utf8(exportName, payload); + payload.push(0); + uleb(this._resolveFuncIndex(name), payload); + } + this._section(SECTION_EXPORT, payload, out); + } + if (this.functions.length > 0) { + const payload = []; + uleb(this.functions.length, payload); + for (const {emitter: emitter} of this.functions) { + const body = emitter.bytes.slice(); + for (const {at: at, name: name} of emitter.callFixups) uleb5At(this._resolveFuncIndex(name), body, at); + const entry = []; + const runs = []; + for (const local of emitter.locals) { + const type = valType(local); + if (runs.length > 0 && runs[runs.length - 1].type === type) runs[runs.length - 1].count++; else runs.push({ + type: type, + count: 1 + }); + } + uleb(runs.length, entry); + for (const {type: type, count: count} of runs) { + uleb(count, entry); + entry.push(type); + } + for (let i = 0; i < body.length; i++) entry.push(body[i]); + entry.push(11); + uleb(entry.length, payload); + for (let i = 0; i < entry.length; i++) payload.push(entry[i]); + } + this._section(SECTION_CODE, payload, out); + } + return Uint8Array.from(out); + } + }; + module.exports = { + WasmModuleBuilder: WasmModuleBuilder, + WasmFunctionEmitter: WasmFunctionEmitter + }; + }); + var require_function_node = __commonJSMin((exports, module) => { + const {utils: utils} = require_utils(); + const {FunctionNode: FunctionNode} = require_function_node$5(); + const {WasmFunctionEmitter: WasmFunctionEmitter} = require_wasm_builder(); + var NoopEmitter = class { + constructor() { + this.localCount = 0; + } + addLocal() { + return this.localCount++; + } + }; + for (const name of Object.getOwnPropertyNames(WasmFunctionEmitter.prototype)) { + if (name === "constructor" || name === "addLocal") continue; + if (typeof WasmFunctionEmitter.prototype[name] !== "function") continue; + NoopEmitter.prototype[name] = function() { + return this; + }; + } + const MATH_IMPORT_ARITY = { + sin: 1, + cos: 1, + tan: 1, + asin: 1, + acos: 1, + atan: 1, + atan2: 2, + sinh: 1, + cosh: 1, + tanh: 1, + asinh: 1, + acosh: 1, + atanh: 1, + exp: 1, + expm1: 1, + log: 1, + log2: 1, + log10: 1, + log1p: 1, + cbrt: 1, + pow: 2, + sign: 1 + }; + const MATH_NATIVE_OPS = { + abs: "f32Abs", + floor: "f32Floor", + ceil: "f32Ceil", + sqrt: "f32Sqrt", + trunc: "f32Trunc" + }; + const F32_ARITH = { + "+": "f32Add", + "-": "f32Sub", + "*": "f32Mul" + }; + const I32_ARITH = { + "+": "i32Add", + "-": "i32Sub", + "*": "i32Mul" + }; + const F32_COMPARE = { + "==": "f32Eq", + "===": "f32Eq", + "!=": "f32Ne", + "!==": "f32Ne", + "<": "f32Lt", + ">": "f32Gt", + "<=": "f32Le", + ">=": "f32Ge" + }; + const I32_COMPARE = { + "==": "i32Eq", + "===": "i32Eq", + "!=": "i32Ne", + "!==": "i32Ne", + "<": "i32LtS", + ">": "i32GtS", + "<=": "i32LeS", + ">=": "i32GeS" + }; + const BITWISE_OPS = { + "&": "i32And", + "|": "i32Or", + "^": "i32Xor", + "<<": "i32Shl", + ">>": "i32ShrS", + ">>>": "i32ShrU" + }; + const VF32_ARITH = { + "+": "f32x4Add", + "-": "f32x4Sub", + "*": "f32x4Mul" + }; + const VI32_ARITH = { + "+": "i32x4Add", + "-": "i32x4Sub", + "*": "i32x4Mul" + }; + const VF32_COMPARE = { + "==": "f32x4Eq", + "===": "f32x4Eq", + "!=": "f32x4Ne", + "!==": "f32x4Ne", + "<": "f32x4Lt", + ">": "f32x4Gt", + "<=": "f32x4Le", + ">=": "f32x4Ge" + }; + const VI32_COMPARE = { + "==": "i32x4Eq", + "===": "i32x4Eq", + "!=": "i32x4Ne", + "!==": "i32x4Ne", + "<": "i32x4LtS", + ">": "i32x4GtS", + "<=": "i32x4LeS", + ">=": "i32x4GeS" + }; + const VECTOR_SHIFT_OPS = { + "<<": "i32x4Shl", + ">>": "i32x4ShrS", + ">>>": "i32x4ShrU" + }; + const VECTOR_MATH_NATIVE_OPS = { + abs: "f32x4Abs", + floor: "f32x4Floor", + ceil: "f32x4Ceil", + sqrt: "f32x4Sqrt", + trunc: "f32x4Trunc" + }; + function scalarWasmType(type) { + switch (type) { + case "Number": + case "Float": + case "LiteralInteger": + return "f32"; + + case "Integer": + case "Boolean": + return "i32"; + + default: + throw new Error(`WebAssembly backend does not yet support ${type} arguments to helper functions`); + } + } + var WebAssemblyFunctionNode = class extends FunctionNode { + constructor(source, settings) { + super(source, settings); + this.assembler = null; + this.em = null; + this.locals = null; + this.depth = 0; + this.loopStack = null; + this.usedMathImports = new Set; + this.usesRandom = false; + this.readsThread = false; + this.taintedLocals = null; + this.uniformity = []; + this._analysisDone = false; + this._analysisPass = false; + this.vec = false; + this.vMaskDepth = 0; + this.vCur = -1; + this.vRetMask = -1; + this.vTerminated = false; + this.vInfo = null; + this._vBaseX = -1; + } + mangleFunctionName(name) { + return `fn_${utils.sanitizeName(name)}`; + } + getType(ast) { + if (ast && ast.type === "ConditionalExpression") { + const consequentType = this.getType(ast.consequent); + if (consequentType === "Integer" || consequentType === "LiteralInteger") { + const alternateType = this.getType(ast.alternate); + if (alternateType === "Number" || alternateType === "Float") return "Number"; + } + } + return super.getType(ast); + } + toString() { + if (!this._analysisDone) { + this._analysisDone = true; + this._analysisPass = true; + this.walkFunction(new NoopEmitter); + this._analysisPass = false; + } + return ""; + } + emitFunction(assembler) { + this.assembler = assembler; + const {module: module$2} = assembler; + let em; + if (this.isRootKernel) em = module$2.addFunction("kernel", { + params: [], + results: [] + }); else { + const params = this.argumentTypes.map(type => scalarWasmType(type === "LiteralInteger" ? "Number" : type)); + const results = []; + if (this.returnType) switch (this.returnType) { + case "Integer": + case "Boolean": + results.push("i32"); + break; + + case "Number": + case "Float": + case "LiteralInteger": + results.push("f32"); + break; + + default: + throw new Error(`WebAssembly backend does not yet support helper functions returning ${this.returnType}`); + } + em = module$2.addFunction(this.mangleFunctionName(this.name), { + params: params, + results: results + }); + } + this.walkFunction(em); + if (!this.isRootKernel && this.returnType) em.unreachable(); + return em; + } + walkFunction(em) { + this.em = em; + this.locals = new Map; + this.depth = 0; + this.loopStack = []; + this.taintedLocals = new Set; + const ast = this.getJsAST(); + if (this.isRootKernel) for (const name of this.collectAssignedArgumentNames(ast)) { + const argumentIndex = this.argumentNames.indexOf(name); + const gtype = this.argumentTypes[argumentIndex]; + if (gtype !== "Number" && gtype !== "Float" && gtype !== "Integer" && gtype !== "Boolean") continue; + const slot = this.assembler ? this.assembler.layout.scalars[name] : null; + const offset = slot ? slot.offset : 0; + const wtype = gtype === "Integer" || gtype === "Boolean" ? "i32" : "f32"; + const index = em.addLocal(wtype); + em.i32Const(0); + if (wtype === "i32") em.i32Load(offset); else em.f32Load(offset); + em.localSet(index); + this.locals.set(name, { + kind: "scalar", + index: index, + wtype: wtype, + gtype: gtype + }); + } + if (!this.isRootKernel) { + for (let i = 0; i < this.argumentNames.length; i++) { + const name = this.argumentNames[i]; + let argumentType = this.argumentTypes[i]; + if (!argumentType) throw this.astErrorOutput(`Unknown argument ${name} type`, ast); + if (argumentType === "LiteralInteger") this.argumentTypes[i] = argumentType = "Number"; + this.locals.set(name, { + kind: "scalar", + index: i, + wtype: scalarWasmType(argumentType), + gtype: argumentType + }); + } + if (!this.returnType) { + if (this.findLastReturn()) { + this.returnType = this.getType(ast.body); + if (this.returnType === "LiteralInteger") this.returnType = "Number"; + } + } + } + const body = ast.body.body; + for (let i = 0; i < body.length; i++) this.statement(body[i]); + } + collectAssignedArgumentNames(ast) { + const names = new Set; + const walk = node => { + if (!node || typeof node !== "object") return; + if (Array.isArray(node)) return node.forEach(walk); + if (node.type === "FunctionDeclaration" && node !== ast) return; + if (node.type === "AssignmentExpression" && node.left.type === "Identifier" && this.argumentNames.indexOf(node.left.name) !== -1) names.add(node.left.name); + if (node.type === "UpdateExpression" && node.argument.type === "Identifier" && this.argumentNames.indexOf(node.argument.name) !== -1) names.add(node.argument.name); + for (const key in node) { + if (key === "loc" || key === "start" || key === "end" || key === "parent") continue; + const child = node[key]; + if (child && typeof child === "object") walk(child); + } + }; + walk(ast.body); + return names; + } + enterBlock(type) { + this.em.block(type); + this.depth++; + } + enterLoop(type) { + this.em.loop(type); + this.depth++; + } + enterIf(type) { + this.em.if_(type); + this.depth++; + } + exit() { + this.em.end(); + this.depth--; + } + brTo(level) { + this.em.br(this.depth - level); + } + brIfTo(level) { + this.em.brIf(this.depth - level); + } + get loopMax() { + return parseInt(this.loopMaxIterations, 10) || 1e3; + } + coerce(from, to) { + if (from === to) return to; + if (from === "void") throw new Error("cannot use a void expression as a value"); + switch (to) { + case "f32": + this.em.f32ConvertI32S(); + return "f32"; + + case "i32": + if (from === "f32") this.em.i32TruncSatF32S(); + return "i32"; + + case "bool": + if (from === "f32") this.em.f32Const(0).f32Ne(); else this.em.i32Eqz().i32Eqz(); + return "bool"; + + default: + throw new Error(`unknown wasm value category ${to}`); + } + } + castLiteralToInteger(ast) { + this.pushState("casting-to-integer"); + const type = this.expression(ast); + this.popState("casting-to-integer"); + this.coerce(type, "i32"); + return "i32"; + } + castLiteralToFloat(ast) { + this.pushState("casting-to-float"); + const type = this.expression(ast); + this.popState("casting-to-float"); + this.coerce(type, "f32"); + return "f32"; + } + castValueToInteger(ast) { + this.pushState("casting-to-integer"); + const type = this.expression(ast); + this.popState("casting-to-integer"); + this.coerce(type, "i32"); + return "i32"; + } + castValueToFloat(ast) { + this.pushState("casting-to-float"); + const type = this.expression(ast); + this.popState("casting-to-float"); + this.coerce(type, "f32"); + return "f32"; + } + emitByType(ast, want) { + const type = this.getType(ast); + if (want === "f32") { + if (type === "Integer") return this.castValueToFloat(ast); + if (type === "LiteralInteger") return this.castLiteralToFloat(ast); + this.coerce(this.expression(ast), "f32"); + return "f32"; + } + if (type === "Number" || type === "Float") return this.castValueToInteger(ast); + if (type === "LiteralInteger") return this.castLiteralToInteger(ast); + this.coerce(this.expression(ast), "i32"); + return "i32"; + } + emitCondition(ast) { + const type = this.expression(ast); + if (type === "bool") return; + if (type === "i32") { + this.em.i32Eqz().i32Eqz(); + return; + } + if (type === "f32") { + this.em.f32Const(0).f32Ne(); + return; + } + throw this.astErrorOutput("cannot use a void expression as a condition", ast); + } + statement(ast) { + switch (ast.type) { + case "VariableDeclaration": + return this.stmtVariableDeclaration(ast); + + case "ExpressionStatement": + return this.statementExpression(ast.expression); + + case "ReturnStatement": + return this.stmtReturn(ast); + + case "IfStatement": + return this.stmtIf(ast); + + case "ForStatement": + return this.stmtFor(ast); + + case "WhileStatement": + return this.stmtWhile(ast); + + case "DoWhileStatement": + return this.stmtDoWhile(ast); + + case "BlockStatement": + for (let i = 0; i < ast.body.length; i++) this.statement(ast.body[i]); + return; + + case "BreakStatement": + return this.stmtBreak(ast); + + case "ContinueStatement": + return this.stmtContinue(ast); + + case "SwitchStatement": + return this.stmtSwitch(ast); + + case "FunctionDeclaration": + if (this.isChildFunction(ast)) return; + throw this.astErrorOutput("unexpected function declaration", ast); + + case "EmptyStatement": + case "DebuggerStatement": + return; + + default: + throw this.astErrorOutput(`Unknown statement type ${ast.type}`, ast); + } + } + statementExpression(expression) { + switch (expression.type) { + case "AssignmentExpression": + return this.emitAssignment(expression); + + case "UpdateExpression": + this.emitUpdate(expression, true); + return; + + case "SequenceExpression": + for (let i = 0; i < expression.expressions.length; i++) this.statementExpression(expression.expressions[i]); + return; + + case "Identifier": + case "Literal": + return; + + default: + if (this.expression(expression) !== "void") this.em.drop(); + } + } + stmtVariableDeclaration(varDecNode) { + const declarations = varDecNode.declarations; + if (!declarations || !declarations[0] || !declarations[0].init) throw this.astErrorOutput("Unexpected expression", varDecNode); + for (let i = 0; i < declarations.length; i++) { + const declaration = declarations[i]; + const init = declaration.init; + const info = this.getDeclaration(declaration.id); + const actualType = this.getType(init); + const name = declaration.id.name; + if (actualType === "Array(2)" || actualType === "Array(3)" || actualType === "Array(4)") { + this.declareVecLocal(name, actualType, init, info, varDecNode); + if (this.isThreadDependent(init)) this.taintedLocals.add(name); + continue; + } + let type = actualType; + if (type === "LiteralInteger") type = info.suggestedType === "Integer" ? "Integer" : "Number"; + if (actualType === "Integer" && type === "Integer") { + info.valueType = "Number"; + this.setScalarLocal(name, "f32", "Number", () => this.castValueToFloat(init)); + } else { + info.valueType = type; + switch (type) { + case "Number": + case "Float": + this.setScalarLocal(name, "f32", type, () => { + if (actualType === "LiteralInteger") this.castLiteralToFloat(init); else if (actualType === "Integer") this.castValueToFloat(init); else this.coerce(this.expression(init), "f32"); + }); + break; + + case "Integer": + this.setScalarLocal(name, "i32", "Integer", () => { + if (actualType === "LiteralInteger") this.castLiteralToInteger(init); else if (actualType === "Number" || actualType === "Float") this.castValueToInteger(init); else this.coerce(this.expression(init), "i32"); + }); + break; + + case "Boolean": + this.setScalarLocal(name, "i32", "Boolean", () => this.emitCondition(init)); + break; + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support declaring type ${type}`, varDecNode); + } + } + if (this.isThreadDependent(init)) this.taintedLocals.add(name); + } + } + setScalarLocal(name, wtype, gtype, emitInit) { + let local = this.locals.get(name); + if (!local || local.kind !== "scalar" || local.wtype !== wtype) { + local = { + kind: "scalar", + index: this.em.addLocal(wtype), + wtype: wtype, + gtype: gtype + }; + this.locals.set(name, local); + } else local.gtype = gtype; + emitInit(); + this.em.localSet(local.index); + } + declareVecLocal(name, type, init, info, varDecNode) { + const n = parseInt(type.substring(6), 10); + info.valueType = type; + let local = this.locals.get(name); + if (!local || local.kind !== "vec" || local.n !== n) { + const indices = []; + for (let c = 0; c < n; c++) indices.push(this.em.addLocal("f32")); + local = { + kind: "vec", + indices: indices, + n: n, + gtype: type + }; + this.locals.set(name, local); + } + if (init.type === "ArrayExpression") { + for (let c = 0; c < n; c++) { + this.emitArrayElement(init.elements[c]); + this.em.localSet(local.indices[c]); + } + return; + } + if (init.type === "Identifier") { + const source = this.locals.get(init.name); + if (source && source.kind === "vec" && source.n === n) { + for (let c = 0; c < n; c++) this.em.localGet(source.indices[c]).localSet(local.indices[c]); + return; + } + } + throw this.astErrorOutput(`WebAssembly backend does not yet support ${type} initializer of type ${init.type}`, varDecNode); + } + emitArrayElement(element) { + switch (this.getType(element)) { + case "Integer": + this.castValueToFloat(element); + break; + + case "LiteralInteger": + this.castLiteralToFloat(element); + break; + + default: + this.coerce(this.expression(element), "f32"); + } + } + emitAssignment(assNode) { + if (assNode.left.type !== "Identifier") throw this.astErrorOutput(`WebAssembly backend does not yet support assignment to ${assNode.left.type}`, assNode); + const name = assNode.left.name; + const local = this.locals.get(name); + let wtype = null; + let store = null; + if (local && local.kind === "scalar") { + wtype = local.wtype; + store = () => this.em.localSet(local.index); + } else if (!local && this.isRootKernel && this.argumentNames.indexOf(name) !== -1) { + const gtype = this.argumentTypes[this.argumentNames.indexOf(name)]; + const slot = this.assembler ? this.assembler.layout.scalars[name] : null; + if (this.assembler && !slot) throw this.astErrorOutput(`WebAssembly backend does not yet support assigning to the array argument "${name}"`, assNode); + const offset = slot ? slot.offset : 0; + wtype = gtype === "Integer" || gtype === "Boolean" ? "i32" : "f32"; + this.em.i32Const(0); + store = () => wtype === "i32" ? this.em.i32Store(offset) : this.em.f32Store(offset); + } else throw this.astErrorOutput(`cannot assign to "${name}"`, assNode); + if (assNode.operator === "=") { + const leftType = this.getType(assNode.left); + const rightType = this.getType(assNode.right); + if (leftType !== "Integer" && rightType === "Integer") { + this.castValueToFloat(assNode.right); + this.coerce("f32", wtype); + } else if (leftType !== "Integer" && rightType === "LiteralInteger") { + this.castLiteralToFloat(assNode.right); + this.coerce("f32", wtype); + } else if (leftType === "Integer" && rightType === "LiteralInteger") { + this.castLiteralToInteger(assNode.right); + this.coerce("i32", wtype); + } else if (leftType === "Integer" && (rightType === "Number" || rightType === "Float")) { + this.castValueToInteger(assNode.right); + this.coerce("i32", wtype); + } else this.coerce(this.expression(assNode.right), wtype); + } else { + const synthetic = { + type: "BinaryExpression", + operator: assNode.operator.slice(0, -1), + left: assNode.left, + right: assNode.right + }; + this.coerce(this.exprBinary(synthetic), wtype); + } + store(); + if (this.isThreadDependent(assNode.right) || assNode.operator !== "=" && this.taintedLocals.has(name)) this.taintedLocals.add(name); + } + emitUpdate(uNode, isStatement) { + if (uNode.argument.type !== "Identifier") throw this.astErrorOutput("update expression needs a variable", uNode); + const local = this.locals.get(uNode.argument.name); + if (!local || local.kind !== "scalar") throw this.astErrorOutput(`cannot update "${uNode.argument.name}"`, uNode); + const isInt = local.wtype === "i32"; + const one = () => isInt ? this.em.i32Const(1) : this.em.f32Const(1); + const op = uNode.operator === "++" ? isInt ? "i32Add" : "f32Add" : isInt ? "i32Sub" : "f32Sub"; + if (isStatement) { + this.em.localGet(local.index); + one(); + this.em[op]().localSet(local.index); + return "void"; + } + if (uNode.prefix) { + this.em.localGet(local.index); + one(); + this.em[op]().localTee(local.index); + } else { + this.em.localGet(local.index).localGet(local.index); + one(); + this.em[op]().localSet(local.index); + } + return local.wtype; + } + stmtReturn(ast) { + if (!ast.argument) { + if (this.isRootKernel) { + this.em.return_(); + return; + } + throw this.astErrorOutput("Unexpected return statement", ast); + } + this.pushState("skip-literal-correction"); + const type = this.getType(ast.argument); + this.popState("skip-literal-correction"); + if (!this.returnType) this.returnType = type === "LiteralInteger" || type === "Integer" ? "Number" : type; + if (this.isRootKernel) return this.stmtRootReturn(ast, type); + if (this.isSubKernel) throw this.astErrorOutput("WebAssembly backend does not yet support createKernelMap", ast); + switch (this.returnType) { + case "LiteralInteger": + case "Number": + case "Float": + if (type === "Integer") this.castValueToFloat(ast.argument); else if (type === "LiteralInteger") this.castLiteralToFloat(ast.argument); else this.coerce(this.expression(ast.argument), "f32"); + break; + + case "Integer": + if (type === "Float" || type === "Number") this.castValueToInteger(ast.argument); else if (type === "LiteralInteger") this.castLiteralToInteger(ast.argument); else this.coerce(this.expression(ast.argument), "i32"); + break; + + case "Boolean": + this.emitCondition(ast.argument); + break; + + default: + throw this.astErrorOutput(`unhandled return type ${this.returnType}`, ast); + } + this.em.return_(); + } + stmtRootReturn(ast, type) { + const globals = this.assembler ? this.assembler.globals : { + dataIndex: 0 + }; + const outputOffset = this.assembler ? this.assembler.layout.outputOffset : 0; + switch (this.returnType) { + case "Array(2)": + case "Array(3)": + case "Array(4)": + { + const n = parseInt(this.returnType.substring(6), 10); + const argument = ast.argument; + if (argument.type === "ArrayExpression") { + if (argument.elements.length !== n) throw this.astErrorOutput(`expected ${n} array elements to match return type ${this.returnType}`, ast); + for (let c = 0; c < n; c++) { + this.emitComponentAddress(globals.dataIndex, n, c); + this.emitArrayElement(argument.elements[c]); + this.em.f32Store(outputOffset); + } + } else if (argument.type === "Identifier") { + const local = this.locals.get(argument.name); + if (!local || local.kind !== "vec" || local.n !== n) throw this.astErrorOutput(`"${argument.name}" is not an Array(${n}) variable`, ast); + for (let c = 0; c < n; c++) { + this.emitComponentAddress(globals.dataIndex, n, c); + this.em.localGet(local.indices[c]); + this.em.f32Store(outputOffset); + } + } else throw this.astErrorOutput(`WebAssembly backend does not yet support returning ${this.returnType} from a ${argument.type}`, ast); + this.em.return_(); + return; + } + + default: + this.emitComponentAddress(globals.dataIndex, 1, 0); + switch (this.returnType) { + case "Integer": + if (type === "Float" || type === "Number") this.castValueToInteger(ast.argument); else if (type === "LiteralInteger") this.castLiteralToInteger(ast.argument); else this.coerce(this.expression(ast.argument), "i32"); + this.em.f32ConvertI32S(); + break; + + case "LiteralInteger": + case "Number": + case "Float": + if (type === "Integer") this.castValueToFloat(ast.argument); else if (type === "LiteralInteger") this.castLiteralToFloat(ast.argument); else this.coerce(this.expression(ast.argument), "f32"); + break; + + case "Boolean": + this.emitCondition(ast.argument); + this.em.f32ConvertI32S(); + break; + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support returning ${this.returnType}`, ast); + } + this.em.f32Store(outputOffset); + this.em.return_(); + } + } + emitComponentAddress(dataIndexGlobal, componentCount, component) { + this.em.globalGet(dataIndexGlobal); + if (componentCount !== 1) { + this.em.i32Const(componentCount).i32Mul(); + if (component !== 0) this.em.i32Const(component).i32Add(); + } + this.em.i32Const(2).i32Shl(); + } + stmtIf(ifNode) { + this.recordUniformity("if", ifNode.test); + this.emitCondition(ifNode.test); + this.enterIf(); + this.statement(ifNode.consequent); + if (ifNode.alternate) { + this.em.else_(); + this.statement(ifNode.alternate); + } + this.exit(); + } + forLoopIsSafe(forNode) { + let isSafe = null; + if (forNode.init) { + const declarations = forNode.init.declarations; + if (declarations) { + if (declarations.length > 1) isSafe = false; + for (let i = 0; i < declarations.length; i++) if (declarations[i].init && declarations[i].init.type !== "Literal") isSafe = false; + } else isSafe = false; + } else isSafe = false; + if (!forNode.test || !forNode.update) isSafe = false; + if (isSafe === null) isSafe = this.isSafe(forNode.init) && this.isSafe(forNode.test); + return isSafe; + } + stmtFor(forNode) { + if (forNode.type !== "ForStatement") throw this.astErrorOutput("Invalid for statement", forNode); + const isSafe = this.forLoopIsSafe(forNode); + this.recordUniformity("for", forNode.test || null); + if (forNode.init) if (forNode.init.type === "VariableDeclaration") this.stmtVariableDeclaration(forNode.init); else this.statementExpression(forNode.init); + let safeI = -1; + if (!isSafe) { + safeI = this.em.addLocal("i32"); + this.em.i32Const(0).localSet(safeI); + } + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + if (!isSafe) { + this.em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + } + if (forNode.test) { + this.emitCondition(forNode.test); + this.em.i32Eqz(); + this.brIfTo(breakLevel); + } + this.enterBlock(); + const continueLevel = this.depth; + this.loopStack.push({ + breakLevel: breakLevel, + continueLevel: continueLevel + }); + if (forNode.body) this.statement(forNode.body); + this.loopStack.pop(); + this.exit(); + if (forNode.update) this.statementExpression(forNode.update); + if (!isSafe) this.em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + } + stmtWhile(whileNode) { + if (whileNode.type !== "WhileStatement") throw this.astErrorOutput("Invalid while statement", whileNode); + this.recordUniformity("while", whileNode.test); + const safeI = this.em.addLocal("i32"); + this.em.i32Const(0).localSet(safeI); + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + this.em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + this.emitCondition(whileNode.test); + this.em.i32Eqz(); + this.brIfTo(breakLevel); + this.enterBlock(); + const continueLevel = this.depth; + this.loopStack.push({ + breakLevel: breakLevel, + continueLevel: continueLevel + }); + this.statement(whileNode.body); + this.loopStack.pop(); + this.exit(); + this.em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + } + stmtDoWhile(doWhileNode) { + if (doWhileNode.type !== "DoWhileStatement") throw this.astErrorOutput("Invalid while statement", doWhileNode); + this.recordUniformity("do-while", doWhileNode.test); + const safeI = this.em.addLocal("i32"); + this.em.i32Const(0).localSet(safeI); + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + this.em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + this.enterBlock(); + const continueLevel = this.depth; + this.loopStack.push({ + breakLevel: breakLevel, + continueLevel: continueLevel + }); + this.statement(doWhileNode.body); + this.loopStack.pop(); + this.exit(); + this.em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.emitCondition(doWhileNode.test); + this.brIfTo(loopLevel); + this.exit(); + this.exit(); + } + stmtBreak(brNode) { + const target = this.loopStack[this.loopStack.length - 1]; + if (!target) throw this.astErrorOutput("break used outside of a loop", brNode); + this.brTo(target.breakLevel); + } + stmtContinue(crNode) { + const target = this.loopStack[this.loopStack.length - 1]; + if (!target) throw this.astErrorOutput("continue used outside of a loop", crNode); + this.brTo(target.continueLevel); + } + stmtSwitch(ast) { + if (ast.type !== "SwitchStatement") throw this.astErrorOutput("Invalid switch statement", ast); + const {discriminant: discriminant, cases: cases} = ast; + const type = this.getType(discriminant); + this.recordUniformity("switch", discriminant); + let dLocal; + let dIsInt; + switch (type) { + case "Float": + case "Number": + dIsInt = false; + dLocal = this.em.addLocal("f32"); + this.coerce(this.expression(discriminant), "f32"); + this.em.localSet(dLocal); + break; + + case "Integer": + dIsInt = true; + dLocal = this.em.addLocal("i32"); + this.coerce(this.expression(discriminant), "i32"); + this.em.localSet(dLocal); + break; + + default: + throw this.astErrorOutput(`Unhandled switch discriminant type "${type}"`, ast); + } + if (cases.length === 1 && !cases[0].test) { + this.emitSwitchConsequent(cases[0].consequent); + return; + } + const {groups: groups, defaultConsequent: defaultConsequent} = this.collectSwitchGroups(cases); + const emitChain = index => { + if (index === groups.length) { + if (defaultConsequent) this.emitSwitchConsequent(defaultConsequent); + return false; + } + const {tests: tests, consequent: consequent} = groups[index]; + for (let i = 0; i < tests.length; i++) { + this.em.localGet(dLocal); + this.emitSwitchTest(tests[i], dIsInt); + if (dIsInt) this.em.i32Eq(); else this.em.f32Eq(); + if (i > 0) this.em.i32Or(); + } + this.enterIf(); + this.emitSwitchConsequent(consequent); + if (index + 1 < groups.length || defaultConsequent) { + this.em.else_(); + emitChain(index + 1); + } + this.exit(); + return true; + }; + emitChain(0); + } + emitSwitchTest(test, dIsInt) { + const testType = this.getType(test); + if (dIsInt) if (testType === "Number" || testType === "Float") this.castValueToInteger(test); else if (testType === "LiteralInteger") this.castLiteralToInteger(test); else this.coerce(this.expression(test), "i32"); else if (testType === "LiteralInteger") this.castLiteralToFloat(test); else if (testType === "Integer") this.castValueToFloat(test); else this.coerce(this.expression(test), "f32"); + } + collectSwitchGroups(cases) { + let defaultConsequent = null; + const groups = []; + let pendingTests = []; + for (let i = 0; i < cases.length; i++) { + if (!cases[i].test) { + defaultConsequent = cases[i].consequent; + continue; + } + pendingTests.push(cases[i].test); + if (cases[i].consequent && cases[i].consequent.length > 0) { + groups.push({ + tests: pendingTests, + consequent: cases[i].consequent + }); + pendingTests = []; + } + } + return { + groups: groups, + defaultConsequent: defaultConsequent + }; + } + collectSwitchCaseStatements(consequent) { + const statements = []; + for (let i = 0; i < consequent.length; i++) { + if (consequent[i].type === "BreakStatement") break; + statements.push(consequent[i]); + } + const containsBreak = node => { + if (!node || typeof node !== "object") return false; + if (Array.isArray(node)) return node.some(containsBreak); + if (node.type === "BreakStatement") return true; + if (node.type === "ForStatement" || node.type === "WhileStatement" || node.type === "DoWhileStatement" || node.type === "SwitchStatement") return false; + for (const key in node) { + if (key === "loc" || key === "range" || key === "parent") continue; + if (containsBreak(node[key])) return true; + } + return false; + }; + for (let i = 0; i < statements.length; i++) if (containsBreak(statements[i])) throw this.astErrorOutput("break inside a switch case is only supported as the case terminator", statements[i]); + return statements; + } + emitSwitchConsequent(consequent) { + const statements = this.collectSwitchCaseStatements(consequent); + for (let i = 0; i < statements.length; i++) this.statement(statements[i]); + } + expression(ast) { + switch (ast.type) { + case "Literal": + return this.exprLiteral(ast); + + case "Identifier": + return this.exprIdentifier(ast); + + case "BinaryExpression": + return this.exprBinary(ast); + + case "LogicalExpression": + return this.exprLogical(ast); + + case "UnaryExpression": + return this.exprUnary(ast); + + case "UpdateExpression": + return this.emitUpdate(ast, false); + + case "ConditionalExpression": + return this.exprConditional(ast); + + case "CallExpression": + return this.exprCall(ast); + + case "MemberExpression": + return this.exprMember(ast); + + case "ThisExpression": + throw this.astErrorOutput("unexpected bare `this`", ast); + + case "SequenceExpression": + if (ast.expressions.length === 1) return this.expression(ast.expressions[0]); + throw this.astErrorOutput("WebAssembly backend does not yet support the comma operator", ast); + + case "AssignmentExpression": + throw this.astErrorOutput("WebAssembly backend does not yet support assignment used as an expression", ast); + + case "ArrayExpression": + throw this.astErrorOutput("array literals are only supported as variable initializers and kernel returns", ast); + + default: + throw this.astErrorOutput(`Unknown expression type ${ast.type}`, ast); + } + } + exprLiteral(ast) { + if (ast.value === true || ast.value === false) { + this.em.i32Const(ast.value ? 1 : 0); + return "bool"; + } + if (isNaN(ast.value)) throw this.astErrorOutput("Non-numeric literal not supported : " + ast.value, ast); + const key = this.astKey(ast); + if (this.isState("casting-to-integer") || this.isState("building-integer")) { + if (!this.vec) this.literalTypes[key] = "Integer"; + this.em.i32Const(Math.round(ast.value)); + return "i32"; + } + if (!this.vec) this.literalTypes[key] = "Number"; + this.em.f32Const(ast.value); + return "f32"; + } + exprIdentifier(idtNode) { + if (idtNode.type !== "Identifier") throw this.astErrorOutput("IdentifierExpression - not an Identifier", idtNode); + if (idtNode.name === "Infinity") { + this.em.f32Const(Infinity); + return "f32"; + } + const local = this.locals.get(idtNode.name); + if (local) { + if (local.kind === "vec") throw this.astErrorOutput(`array-valued variable "${idtNode.name}" can only be indexed or returned`, idtNode); + this.em.localGet(local.index); + return local.gtype === "Boolean" ? "bool" : local.wtype; + } + const argumentIndex = this.argumentNames.indexOf(idtNode.name); + if (argumentIndex !== -1 && this.isRootKernel) { + const type = this.argumentTypes[argumentIndex]; + const slot = this.assembler ? this.assembler.layout.scalars[idtNode.name] : null; + const offset = slot ? slot.offset : 0; + this.em.i32Const(0); + switch (type) { + case "Integer": + this.em.i32Load(offset); + return "i32"; + + case "Boolean": + this.em.i32Load(offset); + return "bool"; + + case "Number": + case "Float": + this.em.f32Load(offset); + return "f32"; + + default: + throw this.astErrorOutput(`argument "${idtNode.name}" of type ${type} cannot be read as a scalar`, idtNode); + } + } + throw this.astErrorOutput(`Unhandled identifier "${idtNode.name}"`, idtNode); + } + exprBinary(ast) { + const operator = ast.operator; + if (operator === "**") { + this.emitByType(ast.left, "f32"); + this.emitByType(ast.right, "f32"); + this.usedMathImports.add("pow"); + this.em.call("math_pow"); + return "f32"; + } + if (BITWISE_OPS[operator]) { + this.emitAsIntegerOperand(ast.left); + this.emitAsIntegerOperand(ast.right); + this.em[BITWISE_OPS[operator]](); + return "i32"; + } + if (operator === "/" || operator === "%") { + if (operator === "/") { + this.emitByType(ast.left, "f32"); + this.emitByType(ast.right, "f32"); + this.em.f32Div(); + return "f32"; + } + const a = this.em.addLocal("f32"); + const b = this.em.addLocal("f32"); + this.emitByType(ast.left, "f32"); + this.em.localSet(a); + this.emitByType(ast.right, "f32"); + this.em.localSet(b); + this.em.localGet(a).localGet(a).localGet(b).f32Div().f32Trunc().localGet(b).f32Mul().f32Sub(); + return "f32"; + } + const leftType = this.getType(ast.left) || "Number"; + const rightType = this.getType(ast.right) || "Number"; + const key = leftType + " & " + rightType; + let category; + switch (key) { + case "Integer & Integer": + this.pushState("building-integer"); + this.coerce(this.expression(ast.left), "i32"); + this.coerce(this.expression(ast.right), "i32"); + this.popState("building-integer"); + category = "i32"; + break; + + case "Number & Float": + case "Float & Number": + case "Float & Float": + case "Number & Number": + this.pushState("building-float"); + this.coerce(this.expression(ast.left), "f32"); + this.coerce(this.expression(ast.right), "f32"); + this.popState("building-float"); + category = "f32"; + break; + + case "LiteralInteger & LiteralInteger": + if (this.isState("casting-to-integer") || this.isState("building-integer")) { + this.pushState("building-integer"); + this.coerce(this.expression(ast.left), "i32"); + this.coerce(this.expression(ast.right), "i32"); + this.popState("building-integer"); + category = "i32"; + } else { + this.pushState("building-float"); + this.castLiteralToFloat(ast.left); + this.castLiteralToFloat(ast.right); + this.popState("building-float"); + category = "f32"; + } + break; + + case "Integer & Float": + case "Integer & Number": + this.pushState("building-float"); + this.castValueToFloat(ast.left); + this.coerce(this.expression(ast.right), "f32"); + this.popState("building-float"); + category = "f32"; + break; + + case "Integer & LiteralInteger": + this.pushState("building-integer"); + this.coerce(this.expression(ast.left), "i32"); + this.castLiteralToInteger(ast.right); + this.popState("building-integer"); + category = "i32"; + break; + + case "Number & Integer": + case "Float & Integer": + this.pushState("building-float"); + this.coerce(this.expression(ast.left), "f32"); + this.castValueToFloat(ast.right); + this.popState("building-float"); + category = "f32"; + break; + + case "Float & LiteralInteger": + case "Number & LiteralInteger": + this.pushState("building-float"); + this.coerce(this.expression(ast.left), "f32"); + this.castLiteralToFloat(ast.right); + this.popState("building-float"); + category = "f32"; + break; + + case "LiteralInteger & Float": + case "LiteralInteger & Number": + if (this.isState("casting-to-integer")) { + this.pushState("building-integer"); + this.castLiteralToInteger(ast.left); + this.castValueToInteger(ast.right); + this.popState("building-integer"); + category = "i32"; + } else { + this.pushState("building-float"); + this.castLiteralToFloat(ast.left); + this.pushState("casting-to-float"); + this.coerce(this.expression(ast.right), "f32"); + this.popState("casting-to-float"); + this.popState("building-float"); + category = "f32"; + } + break; + + case "LiteralInteger & Integer": + this.pushState("building-integer"); + this.castLiteralToInteger(ast.left); + this.coerce(this.expression(ast.right), "i32"); + this.popState("building-integer"); + category = "i32"; + break; + + case "Boolean & Boolean": + this.coerce(this.expression(ast.left), "i32"); + this.coerce(this.expression(ast.right), "i32"); + category = "i32"; + break; + + default: + throw this.astErrorOutput(`Unhandled binary expression between ${key}`, ast); + } + const compareOp = category === "i32" ? I32_COMPARE[operator] : F32_COMPARE[operator]; + if (compareOp) { + this.em[compareOp](); + return "bool"; + } + const arithOp = category === "i32" ? I32_ARITH[operator] : F32_ARITH[operator]; + if (!arithOp) throw this.astErrorOutput(`Unhandled operator ${operator}`, ast); + this.em[arithOp](); + return category; + } + emitAsIntegerOperand(side) { + switch (this.getType(side)) { + case "Number": + case "Float": + this.castValueToInteger(side); + break; + + case "LiteralInteger": + this.castLiteralToInteger(side); + break; + + default: + { + this.pushState("building-integer"); + const type = this.expression(side); + this.popState("building-integer"); + this.coerce(type, "i32"); + } + } + } + exprLogical(logNode) { + this.emitCondition(logNode.left); + this.enterIf("i32"); + if (logNode.operator === "&&") { + this.emitCondition(logNode.right); + this.em.else_(); + this.em.i32Const(0); + } else if (logNode.operator === "||") { + this.em.i32Const(1); + this.em.else_(); + this.emitCondition(logNode.right); + } else throw this.astErrorOutput(`Unhandled logical operator ${logNode.operator}`, logNode); + this.exit(); + return "bool"; + } + exprUnary(uNode) { + switch (uNode.operator) { + case "~": + this.emitAsIntegerOperand(uNode.argument); + this.em.i32Const(-1).i32Xor(); + return "i32"; + + case "!": + this.emitCondition(uNode.argument); + this.em.i32Eqz(); + return "bool"; + + case "+": + return this.expression(uNode.argument); + + case "-": + { + const type = this.getType(uNode.argument); + if (type === "Integer" || type === "LiteralInteger" && (this.isState("casting-to-integer") || this.isState("building-integer"))) { + this.em.i32Const(0); + this.emitByType(uNode.argument, "i32"); + this.em.i32Sub(); + return "i32"; + } + this.emitByType(uNode.argument, "f32"); + this.em.f32Neg(); + return "f32"; + } + + default: + throw this.astErrorOutput(`Unhandled unary operator ${uNode.operator}`, uNode); + } + } + exprConditional(ast) { + if (ast.type !== "ConditionalExpression") throw this.astErrorOutput("Not a conditional expression", ast); + const consequentType = this.getType(ast.consequent); + const alternateType = this.getType(ast.alternate); + this.recordUniformity("ternary", ast.test); + if (consequentType === null && alternateType === null) { + this.emitCondition(ast.test); + this.enterIf(); + this.statementExpression(ast.consequent); + this.em.else_(); + this.statementExpression(ast.alternate); + this.exit(); + return "void"; + } + let targetType = consequentType === "LiteralInteger" ? "Number" : consequentType; + if (targetType === "Integer" && (alternateType === "Number" || alternateType === "Float")) targetType = "Number"; + const wtype = targetType === "Integer" || targetType === "Boolean" ? "i32" : "f32"; + const emitBranch = branch => { + const branchType = this.getType(branch); + switch (targetType) { + case "Number": + case "Float": + if (branchType === "Integer") this.castValueToFloat(branch); else if (branchType === "LiteralInteger") this.castLiteralToFloat(branch); else this.coerce(this.expression(branch), "f32"); + break; + + case "Integer": + if (branchType === "Number" || branchType === "Float") this.castValueToInteger(branch); else if (branchType === "LiteralInteger") this.castLiteralToInteger(branch); else this.coerce(this.expression(branch), "i32"); + break; + + case "Boolean": + this.emitCondition(branch); + break; + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support a ternary of type ${targetType}`, ast); + } + }; + this.emitCondition(ast.test); + this.enterIf(wtype); + emitBranch(ast.consequent); + this.em.else_(); + emitBranch(ast.alternate); + this.exit(); + return targetType === "Boolean" ? "bool" : wtype; + } + exprCall(ast) { + if (!ast.callee) throw this.astErrorOutput("Unknown CallExpression", ast); + if (ast.callee.type === "MemberExpression" && this.getVariableSignature(ast.callee, true) === "this.color") throw this.astErrorOutput("WebAssembly backend does not yet support graphical mode (this.color)", ast); + let functionName = null; + const isMathFunction = this.isAstMathFunction(ast); + if (isMathFunction || ast.callee.object && ast.callee.object.type === "ThisExpression") functionName = ast.callee.property.name; else if (ast.callee.type === "SequenceExpression" && ast.callee.expressions[0].type === "Literal" && !isNaN(ast.callee.expressions[0].raw)) functionName = ast.callee.expressions[1].property.name; else functionName = ast.callee.name; + if (!functionName) throw this.astErrorOutput(`Unhandled function, couldn't find name`, ast); + if (this.calledFunctions.indexOf(functionName) < 0) this.calledFunctions.push(functionName); + if (this.onFunctionCall) this.onFunctionCall(this.name, functionName, ast.arguments); + if (isMathFunction) return this.emitMathCall(functionName, ast); + const returnType = this.getType(ast); + const targetTypes = this.lookupFunctionArgumentTypes(functionName) || []; + for (let i = 0; i < ast.arguments.length; ++i) { + const argument = ast.arguments[i]; + let targetType = targetTypes[i]; + const argumentType = this.getType(argument); + if (!targetType) { + this.triggerImplyArgumentType(functionName, i, argumentType, this); + targetType = argumentType; + } + switch (argumentType) { + case "Boolean": + this.coerce(this.expression(argument), "i32"); + continue; + + case "Number": + case "Float": + if (targetType === "Integer") { + this.castValueToInteger(argument); + continue; + } else if (targetType === "Number" || targetType === "Float" || targetType === "LiteralInteger") { + this.coerce(this.expression(argument), "f32"); + continue; + } + break; + + case "Integer": + if (targetType === "Number" || targetType === "Float") { + this.castValueToFloat(argument); + continue; + } else if (targetType === "Integer") { + this.coerce(this.expression(argument), "i32"); + continue; + } + break; + + case "LiteralInteger": + if (targetType === "Integer") { + this.castLiteralToInteger(argument); + continue; + } else if (targetType === "Number" || targetType === "Float" || targetType === "LiteralInteger") { + this.castLiteralToFloat(argument); + continue; + } + break; + + case "Array(2)": + case "Array(3)": + case "Array(4)": + case "Array": + case "Array2D": + case "Array3D": + case "Input": + throw this.astErrorOutput("WebAssembly backend does not yet support array arguments to helper functions", ast); + } + throw this.astErrorOutput(`Unhandled argument combination of ${argumentType} and ${targetType} for argument named "${argument.name}"`, ast); + } + this.em.call(this.mangleFunctionName(functionName)); + switch (returnType) { + case null: + case void 0: + return "void"; + + case "Integer": + return "i32"; + + case "Boolean": + return "bool"; + + default: + return "f32"; + } + } + emitMathCall(functionName, ast) { + if (functionName === "random") { + this.usesRandom = true; + this.em.call("pcg_random"); + return "f32"; + } + const emitMathArg = argument => { + switch (this.getType(argument)) { + case "Integer": + this.castValueToFloat(argument); + break; + + case "LiteralInteger": + this.castLiteralToFloat(argument); + break; + + default: + this.coerce(this.expression(argument), "f32"); + } + }; + const nativeOp = MATH_NATIVE_OPS[functionName]; + if (nativeOp) { + emitMathArg(ast.arguments[0]); + this.em[nativeOp](); + return "f32"; + } + switch (functionName) { + case "round": + emitMathArg(ast.arguments[0]); + this.em.f32Const(.5).f32Add().f32Floor(); + return "f32"; + + case "fround": + emitMathArg(ast.arguments[0]); + return "f32"; + + case "min": + case "max": + { + const op = functionName === "min" ? "f32Min" : "f32Max"; + emitMathArg(ast.arguments[0]); + for (let i = 1; i < ast.arguments.length; i++) { + emitMathArg(ast.arguments[i]); + this.em[op](); + } + return "f32"; + } + + case "imul": + emitMathArg(ast.arguments[0]); + this.em.i32TruncSatF32S(); + emitMathArg(ast.arguments[1]); + this.em.i32TruncSatF32S(); + this.em.i32Mul().f32ConvertI32S(); + return "f32"; + + case "clz32": + emitMathArg(ast.arguments[0]); + this.em.i32TruncSatF32U().i32Clz().f32ConvertI32S(); + return "f32"; + + default: + { + const arity = MATH_IMPORT_ARITY[functionName]; + if (!arity) throw this.astErrorOutput(`WebAssembly backend does not yet support Math.${functionName}`, ast); + for (let i = 0; i < arity; i++) emitMathArg(ast.arguments[i]); + this.usedMathImports.add(functionName); + this.em.call("math_" + functionName); + return "f32"; + } + } + } + exprMember(mNode) { + const details = this.getMemberExpressionDetails(mNode); + if (!details) throw this.astErrorOutput("Unexpected expression", mNode); + const {signature: signature, name: name, origin: origin, type: type, property: property, xProperty: xProperty, yProperty: yProperty, zProperty: zProperty} = details; + switch (signature) { + case "value.thread.value": + case "this.thread.value": + { + if (name !== "x" && name !== "y" && name !== "z") throw this.astErrorOutput("Unexpected expression, expected `this.thread.x`, `this.thread.y`, or `this.thread.z`", mNode); + this.readsThread = true; + const globals = this.assembler ? this.assembler.globals : null; + this.em.globalGet(globals ? globals["thread" + name.toUpperCase()] : 0); + return "i32"; + } + + case "this.output.value": + { + const axisIndex = { + x: 0, + y: 1, + z: 2 + }[name]; + if (axisIndex === void 0) throw this.astErrorOutput("Unexpected expression", mNode); + const value = this.output[axisIndex]; + if (this.isState("casting-to-float")) { + this.em.f32Const(value); + return "f32"; + } + this.em.i32Const(value); + return "i32"; + } + + case "value.value": + { + if (origin === "Math") { + this.em.f32Const(Math[name]); + return "f32"; + } + const component = { + r: 0, + g: 1, + b: 2, + a: 3 + }[property]; + if (component !== void 0) { + const local = this.locals.get(name); + if (local && local.kind === "vec" && component < local.n) { + this.em.localGet(local.indices[component]); + return "f32"; + } + } + throw this.astErrorOutput("Unexpected expression", mNode); + } + + case "this.constants.value": + { + const value = this.constants[name]; + switch (type) { + case "Integer": + if (this.isState("casting-to-float")) { + this.em.f32Const(value); + return "f32"; + } + this.em.i32Const(Math.round(value)); + return "i32"; + + case "Number": + case "Float": + if (this.isState("casting-to-integer")) { + this.em.i32Const(Math.round(value)); + return "i32"; + } + this.em.f32Const(value); + return "f32"; + + case "Boolean": + this.em.i32Const(value ? 1 : 0); + return "bool"; + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support constant type ${type}`, mNode); + } + } + + case "value[]": + case "value[][]": + case "value[][][]": + case "value[][][][]": + { + const local = this.locals.get(name); + if (local && local.kind === "vec") { + if (signature !== "value[]") throw this.astErrorOutput("Unexpected expression", mNode); + return this.emitVecIndex(local, xProperty); + } + return this.emitFlatLoad("arrays", name, xProperty, yProperty, zProperty, mNode); + } + + case "this.constants.value[]": + case "this.constants.value[][]": + case "this.constants.value[][][]": + case "this.constants.value[][][][]": + return this.emitFlatLoad("constantArrays", name, xProperty, yProperty, zProperty, mNode); + + case "fn()[]": + throw this.astErrorOutput("WebAssembly backend does not yet support indexing a function call result", mNode); + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support expression signature "${signature}"`, mNode); + } + } + emitFlatLoad(table, name, xProperty, yProperty, zProperty, mNode) { + let layout; + if (this.assembler) { + layout = this.assembler.layout[table][name]; + if (!layout) throw this.astErrorOutput(`no memory layout for "${name}" \u2014 arrays are only readable as kernel arguments or constants`, mNode); + } else layout = { + offset: 0, + dims: [ 1, 1, 1 ] + }; + this.emitIndex(xProperty); + if (yProperty) { + this.emitIndex(yProperty); + this.em.i32Const(layout.dims[0]).i32Mul().i32Add(); + } + if (zProperty) { + this.emitIndex(zProperty); + this.em.i32Const(layout.dims[0] * layout.dims[1]).i32Mul().i32Add(); + } + if (this.vec && this.vMaskDepth > 0) this.emitClampScalarIndex(layout.dims[0] * layout.dims[1] * layout.dims[2] - 1); + this.em.i32Const(2).i32Shl(); + this.em.f32Load(layout.offset); + return "f32"; + } + emitClampScalarIndex(max) { + const t = this.em.addLocal("i32"); + this.em.localSet(t); + this.em.localGet(t).i32Const(0).localGet(t).i32Const(0).i32GeS().select(); + this.em.localSet(t); + this.em.localGet(t).i32Const(max).localGet(t).i32Const(max).i32LeS().select(); + } + emitVecIndex(local, xProperty) { + if (xProperty.type === "Literal" && Number.isInteger(xProperty.value)) { + if (xProperty.value < 0 || xProperty.value >= local.n) throw this.astErrorOutput(`index ${xProperty.value} out of range for Array(${local.n})`, xProperty); + this.em.localGet(local.indices[xProperty.value]); + return "f32"; + } + const idx = this.em.addLocal("i32"); + this.emitIndex(xProperty); + this.em.localSet(idx); + this.em.localGet(local.indices[0]); + for (let k = 1; k < local.n; k++) { + this.em.localGet(local.indices[k]); + this.em.localGet(idx).i32Const(k).i32Ne(); + this.em.select(); + } + return "f32"; + } + emitIndex(property) { + if (!property) throw new Error("Property not set"); + switch (this.getType(property)) { + case "Number": + case "Float": + this.castValueToInteger(property); + return; + + case "LiteralInteger": + this.castLiteralToInteger(property); + return; + + case "Integer": + { + this.pushState("building-integer"); + const emitted = this.expression(property); + this.popState("building-integer"); + this.coerce(emitted, "i32"); + return; + } + + default: + this.coerce(this.expression(property), "i32"); + } + } + emitVectorFunction(assembler) { + if (!this.isRootKernel) throw new Error("only the root kernel is vectorized; helpers are lane-scalarized at call sites"); + this.assembler = assembler; + const em = assembler.module.addFunction("kernel_simd", { + params: [], + results: [] + }); + this.em = em; + this.vec = true; + try { + this.locals = new Map; + this.depth = 0; + this.loopStack = []; + this.vLoopStack = []; + this.taintedLocals = new Set; + const ast = this.getJsAST(); + if (!this.vInfo) this.vInfo = this.vAnalyze(ast); + this.vMaskDepth = 0; + this.vTerminated = false; + this.vCur = em.addLocal("v128"); + em.v128ConstI32x4(-1, -1, -1, -1).localSet(this.vCur); + this.vRetMask = this.vInfo.varyingReturn ? em.addLocal("v128") : -1; + this._vBaseX = -1; + if (assembler.helperInfo) { + this._vBaseX = em.addLocal("i32"); + em.globalGet(assembler.globals.threadX).localSet(this._vBaseX); + } + for (const name of this.vInfo.assignedArgs) { + const argumentIndex = this.argumentNames.indexOf(name); + const gtype = this.argumentTypes[argumentIndex]; + const slot = assembler.layout.scalars[name]; + if (!slot) throw this.astErrorOutput(`WebAssembly backend does not yet support assigning to the array argument "${name}"`, this.getJsAST()); + const isInt = gtype === "Integer" || gtype === "Boolean"; + const index = em.addLocal("v128"); + em.i32Const(0); + if (isInt) em.i32Load(slot.offset).i32x4Splat(); else em.f32Load(slot.offset).f32x4Splat(); + em.localSet(index); + this.locals.set(name, { + kind: "vscalar", + index: index, + wtype: isInt ? "vi32" : "vf32", + gtype: gtype + }); + } + const body = ast.body.body; + for (let i = 0; i < body.length; i++) { + this.vstatement(body[i]); + if (this.vTerminated) break; + } + } finally { + this.vec = false; + this.vMaskDepth = 0; + } + return em; + } + vAnalyze(ast) { + const varying = new Set; + const assignedArgs = new Set; + let varyingReturn = false; + let changed = true; + const self = this; + const exprVarying = node => { + if (!node || typeof node !== "object") return false; + switch (node.type) { + case "Literal": + case "ThisExpression": + return false; + + case "Identifier": + return varying.has(node.name); + + case "MemberExpression": + if (!node.computed && node.object.type === "MemberExpression" && !node.object.computed && node.object.property && node.object.property.name === "thread") return node.property.name === "x"; + if (node.computed) return exprVarying(node.object) || exprVarying(node.property); + return exprVarying(node.object); + + case "BinaryExpression": + case "LogicalExpression": + return exprVarying(node.left) || exprVarying(node.right); + + case "UnaryExpression": + case "UpdateExpression": + return exprVarying(node.argument); + + case "ConditionalExpression": + return exprVarying(node.test) || exprVarying(node.consequent) || exprVarying(node.alternate); + + case "CallExpression": + if (self.isAstMathFunction(node)) { + if (node.callee.property.name === "random") return true; + return node.arguments.some(exprVarying); + } + return true; + + case "SequenceExpression": + return node.expressions.some(exprVarying); + + case "ArrayExpression": + return node.elements.some(exprVarying); + + case "AssignmentExpression": + return exprVarying(node.right) || node.left.type === "Identifier" && varying.has(node.left.name); + + default: + return true; + } + }; + const taint = name => { + if (name && !varying.has(name)) { + varying.add(name); + changed = true; + } + }; + const scanExprTaints = (node, cv) => { + if (!node || typeof node !== "object") return; + if (Array.isArray(node)) return node.forEach(sub => scanExprTaints(sub, cv)); + switch (node.type) { + case "UpdateExpression": + if (node.argument.type === "Identifier") { + if (self.argumentNames.indexOf(node.argument.name) !== -1) { + if (!assignedArgs.has(node.argument.name)) { + assignedArgs.add(node.argument.name); + changed = true; + } + taint(node.argument.name); + } + if (cv) taint(node.argument.name); + } + return scanExprTaints(node.argument, cv); + + case "AssignmentExpression": + if (node.left.type === "Identifier") { + if (self.argumentNames.indexOf(node.left.name) !== -1) { + if (!assignedArgs.has(node.left.name)) { + assignedArgs.add(node.left.name); + changed = true; + } + taint(node.left.name); + } + if (cv) taint(node.left.name); + } + scanExprTaints(node.left, cv); + return scanExprTaints(node.right, cv); + + case "ConditionalExpression": + { + scanExprTaints(node.test, cv); + const branchCv = cv || exprVarying(node.test); + scanExprTaints(node.consequent, branchCv); + return scanExprTaints(node.alternate, branchCv); + } + + case "LogicalExpression": + scanExprTaints(node.left, cv); + return scanExprTaints(node.right, true); + + default: + for (const key in node) { + if (key === "loc" || key === "start" || key === "end" || key === "parent") continue; + const child = node[key]; + if (child && typeof child === "object") scanExprTaints(child, cv); + } + } + }; + const collectAssigned = (node, out) => { + if (!node || typeof node !== "object") return; + if (Array.isArray(node)) return node.forEach(sub => collectAssigned(sub, out)); + switch (node.type) { + case "VariableDeclarator": + if (node.id && node.id.type === "Identifier") out.push(node.id.name); + break; + + case "AssignmentExpression": + if (node.left.type === "Identifier") out.push(node.left.name); + break; + + case "UpdateExpression": + if (node.argument.type === "Identifier") out.push(node.argument.name); + break; + + case "FunctionDeclaration": + return; + } + for (const key in node) { + if (key === "loc" || key === "start" || key === "end" || key === "parent") continue; + const child = node[key]; + if (child && typeof child === "object") collectAssigned(child, out); + } + }; + const hasVaryingExit = (node, cv) => { + if (!node || typeof node !== "object") return false; + if (Array.isArray(node)) return node.some(sub => hasVaryingExit(sub, cv)); + switch (node.type) { + case "BreakStatement": + case "ContinueStatement": + return cv; + + case "ForStatement": + case "WhileStatement": + case "DoWhileStatement": + case "FunctionDeclaration": + return false; + + case "IfStatement": + { + const branchCv = cv || exprVarying(node.test); + if (hasVaryingExit(node.consequent, branchCv)) return true; + return node.alternate ? hasVaryingExit(node.alternate, branchCv) : false; + } + + case "ConditionalExpression": + { + const branchCv = cv || exprVarying(node.test); + return hasVaryingExit(node.consequent, branchCv) || hasVaryingExit(node.alternate, branchCv); + } + + case "SwitchStatement": + { + const switchCv = cv || exprVarying(node.discriminant) || node.cases.some(c => c.test && exprVarying(c.test)); + return node.cases.some(c => c.consequent.some(stmt => stmt.type === "BreakStatement" ? false : hasVaryingExit(stmt, switchCv))); + } + + default: + for (const key in node) { + if (key === "loc" || key === "start" || key === "end" || key === "parent") continue; + const child = node[key]; + if (child && typeof child === "object" && hasVaryingExit(child, cv)) return true; + } + return false; + } + }; + const walkExprStatement = (node, cv) => { + switch (node.type) { + case "AssignmentExpression": + if (node.left.type === "Identifier") { + const name = node.left.name; + if (self.argumentNames.indexOf(name) !== -1) { + if (!assignedArgs.has(name)) { + assignedArgs.add(name); + changed = true; + } + taint(name); + } + if (cv || exprVarying(node.right) || node.operator !== "=" && varying.has(name)) taint(name); + } + return scanExprTaints(node.right, cv); + + case "UpdateExpression": + if (node.argument.type === "Identifier") { + const name = node.argument.name; + if (self.argumentNames.indexOf(name) !== -1) { + if (!assignedArgs.has(name)) { + assignedArgs.add(name); + changed = true; + } + taint(name); + } + if (cv) taint(name); + } + return; + + case "SequenceExpression": + return node.expressions.forEach(e => walkExprStatement(e, cv)); + + default: + return scanExprTaints(node, cv); + } + }; + const walkStatement = (node, cv) => { + if (!node) return; + switch (node.type) { + case "VariableDeclaration": + for (const declaration of node.declarations) { + if (!declaration.init) continue; + if (cv || exprVarying(declaration.init)) taint(declaration.id.name); + scanExprTaints(declaration.init, cv); + } + return; + + case "ExpressionStatement": + return walkExprStatement(node.expression, cv); + + case "ReturnStatement": + if (cv) varyingReturn = true; + if (node.argument) scanExprTaints(node.argument, cv); + return; + + case "IfStatement": + { + scanExprTaints(node.test, cv); + const branchCv = cv || exprVarying(node.test); + walkStatement(node.consequent, branchCv); + if (node.alternate) walkStatement(node.alternate, branchCv); + return; + } + + case "ForStatement": + case "WhileStatement": + case "DoWhileStatement": + { + const loopVarying = cv || (node.test ? exprVarying(node.test) : false) || hasVaryingExit(node.body, false); + if (loopVarying) { + const assigned = []; + if (node.init) collectAssigned(node.init, assigned); + collectAssigned(node.body, assigned); + if (node.update) collectAssigned(node.update, assigned); + assigned.forEach(taint); + } + if (node.init) if (node.init.type === "VariableDeclaration") walkStatement(node.init, cv); else walkExprStatement(node.init, cv); + walkStatement(node.body, loopVarying); + if (node.update) walkExprStatement(node.update, loopVarying); + if (node.test) scanExprTaints(node.test, loopVarying); + return; + } + + case "SwitchStatement": + { + const switchCv = cv || exprVarying(node.discriminant) || node.cases.some(c => c.test && exprVarying(c.test)); + for (const switchCase of node.cases) for (const stmt of switchCase.consequent) walkStatement(stmt, switchCv); + return; + } + + case "BlockStatement": + return node.body.forEach(stmt => walkStatement(stmt, cv)); + + default: + return; + } + }; + while (changed) { + changed = false; + walkStatement(ast.body, false); + } + return { + varying: varying, + varyingReturn: varyingReturn, + assignedArgs: assignedArgs, + exprVarying: exprVarying, + hasVaryingExit: hasVaryingExit + }; + } + vZero() { + this.em.v128ConstI32x4(0, 0, 0, 0); + return this; + } + vInnermostVaryingLoop() { + const top = this.vLoopStack[this.vLoopStack.length - 1]; + return top && top.varying ? top : null; + } + vRecomputeCur(savedIndex) { + const em = this.em; + em.localGet(savedIndex); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + const loop = this.vInnermostVaryingLoop(); + if (loop) { + if (loop.vBrk !== -1) em.localGet(loop.vBrk).v128Andnot(); + if (loop.vCnt !== -1) em.localGet(loop.vCnt).v128Andnot(); + } + em.localSet(this.vCur); + } + vLoopBodyExits(body) { + let hasBreak = false; + let hasContinue = false; + const walk = node => { + if (!node || typeof node !== "object" || hasBreak && hasContinue) return; + if (Array.isArray(node)) return node.forEach(walk); + switch (node.type) { + case "BreakStatement": + hasBreak = true; + return; + + case "ContinueStatement": + hasContinue = true; + return; + + case "ForStatement": + case "WhileStatement": + case "DoWhileStatement": + case "FunctionDeclaration": + return; + + case "SwitchStatement": + for (const switchCase of node.cases) for (const stmt of switchCase.consequent) if (stmt.type !== "BreakStatement") walk(stmt); + return; + } + for (const key in node) { + if (key === "loc" || key === "start" || key === "end" || key === "parent") continue; + const child = node[key]; + if (child && typeof child === "object") walk(child); + } + }; + walk(body); + return { + hasBreak: hasBreak, + hasContinue: hasContinue + }; + } + vSetLocal(index) { + const em = this.em; + if (this.vMaskDepth > 0) em.localGet(index).localGet(this.vCur).v128Bitselect(); + em.localSet(index); + } + vCoerce(from, to) { + if (from === to) return to; + const em = this.em; + switch (from) { + case "f32": + case "i32": + case "bool": + if (to === "vf32") { + this.coerce(from, "f32"); + em.f32x4Splat(); + return to; + } + if (to === "vi32") { + this.coerce(from, "i32"); + em.i32x4Splat(); + return to; + } + if (to === "vbool") { + this.coerce(from, "i32"); + em.i32x4Splat(); + this.vZero(); + em.i32x4Ne(); + return to; + } + break; + + case "vf32": + if (to === "vi32") { + em.i32x4TruncSatF32x4S(); + return to; + } + if (to === "vbool") { + em.v128ConstF32x4(0, 0, 0, 0).f32x4Ne(); + return to; + } + break; + + case "vi32": + if (to === "vf32") { + em.f32x4ConvertI32x4S(); + return to; + } + if (to === "vbool") { + this.vZero(); + em.i32x4Ne(); + return to; + } + break; + + case "vbool": + if (to === "vi32") { + em.v128ConstI32x4(1, 1, 1, 1).v128And(); + return to; + } + if (to === "vf32") { + em.v128ConstI32x4(1, 1, 1, 1).v128And().f32x4ConvertI32x4S(); + return to; + } + break; + } + throw new Error(`cannot convert ${from} to ${to}`); + } + vCastLiteralToInteger(ast) { + this.pushState("casting-to-integer"); + const type = this.vexpr(ast); + this.popState("casting-to-integer"); + this.vCoerce(type, "vi32"); + return "vi32"; + } + vCastLiteralToFloat(ast) { + this.pushState("casting-to-float"); + const type = this.vexpr(ast); + this.popState("casting-to-float"); + this.vCoerce(type, "vf32"); + return "vf32"; + } + vCastValueToInteger(ast) { + this.pushState("casting-to-integer"); + const type = this.vexpr(ast); + this.popState("casting-to-integer"); + this.vCoerce(type, "vi32"); + return "vi32"; + } + vCastValueToFloat(ast) { + this.pushState("casting-to-float"); + const type = this.vexpr(ast); + this.popState("casting-to-float"); + this.vCoerce(type, "vf32"); + return "vf32"; + } + vEmitByType(ast, want) { + const type = this.getType(ast); + if (want === "vf32") { + if (type === "Integer") return this.vCastValueToFloat(ast); + if (type === "LiteralInteger") return this.vCastLiteralToFloat(ast); + this.vCoerce(this.vexpr(ast), "vf32"); + return "vf32"; + } + if (type === "Number" || type === "Float") return this.vCastValueToInteger(ast); + if (type === "LiteralInteger") return this.vCastLiteralToInteger(ast); + this.vCoerce(this.vexpr(ast), "vi32"); + return "vi32"; + } + vexprMask(ast) { + const type = this.vexpr(ast); + if (type === "vbool") return; + if (type === "vi32") { + this.vZero(); + this.em.i32x4Ne(); + return; + } + if (type === "vf32") { + this.em.v128ConstF32x4(0, 0, 0, 0).f32x4Ne(); + return; + } + this.coerce(type, "bool"); + this.em.i32x4Splat(); + this.vZero(); + this.em.i32x4Ne(); + } + vstatement(ast) { + switch (ast.type) { + case "VariableDeclaration": + return this.vstmtVariableDeclaration(ast); + + case "ExpressionStatement": + return this.vstatementExpression(ast.expression); + + case "ReturnStatement": + return this.vstmtReturn(ast); + + case "IfStatement": + return this.vstmtIf(ast); + + case "ForStatement": + return this.vstmtFor(ast); + + case "WhileStatement": + return this.vstmtWhile(ast); + + case "DoWhileStatement": + return this.vstmtDoWhile(ast); + + case "BlockStatement": + for (let i = 0; i < ast.body.length; i++) { + this.vstatement(ast.body[i]); + if (this.vTerminated) break; + } + return; + + case "BreakStatement": + return this.vstmtBreak(ast); + + case "ContinueStatement": + return this.vstmtContinue(ast); + + case "SwitchStatement": + return this.vstmtSwitch(ast); + + case "FunctionDeclaration": + if (this.isChildFunction(ast)) return; + throw this.astErrorOutput("unexpected function declaration", ast); + + case "EmptyStatement": + case "DebuggerStatement": + return; + + default: + throw this.astErrorOutput(`Unknown statement type ${ast.type}`, ast); + } + } + vstatementBody(node) { + if (!node) return; + const previous = this.vTerminated; + this.vTerminated = false; + this.vstatement(node); + this.vTerminated = previous; + } + vstatementExpression(expression) { + switch (expression.type) { + case "AssignmentExpression": + return this.vAssign(expression); + + case "UpdateExpression": + this.vUpdate(expression, true); + return; + + case "SequenceExpression": + for (let i = 0; i < expression.expressions.length; i++) this.vstatementExpression(expression.expressions[i]); + return; + + case "Identifier": + case "Literal": + return; + + default: + if (this.vexpr(expression) !== "void") this.em.drop(); + } + } + vstmtVariableDeclaration(varDecNode) { + const declarations = varDecNode.declarations; + if (!declarations || !declarations[0] || !declarations[0].init) throw this.astErrorOutput("Unexpected expression", varDecNode); + for (let i = 0; i < declarations.length; i++) { + const declaration = declarations[i]; + if (!this.vInfo.varying.has(declaration.id.name)) { + this.stmtVariableDeclaration(Object.assign({}, varDecNode, { + declarations: [ declaration ] + })); + continue; + } + this.vDeclareVarying(declaration, varDecNode); + } + } + vDeclareVarying(declaration, varDecNode) { + const em = this.em; + const init = declaration.init; + const name = declaration.id.name; + const info = this.getDeclaration(declaration.id); + const actualType = this.getType(init); + if (actualType === "Array(2)" || actualType === "Array(3)" || actualType === "Array(4)") { + const n = parseInt(actualType.substring(6), 10); + info.valueType = actualType; + let local = this.locals.get(name); + if (!local || local.kind !== "vvec" || local.n !== n) { + const indices = []; + for (let c = 0; c < n; c++) indices.push(em.addLocal("v128")); + local = { + kind: "vvec", + indices: indices, + n: n, + gtype: actualType + }; + this.locals.set(name, local); + } + if (init.type === "ArrayExpression") { + for (let c = 0; c < n; c++) { + this.vEmitArrayElement(init.elements[c]); + this.vSetLocal(local.indices[c]); + } + return; + } + if (init.type === "Identifier") { + const source = this.locals.get(init.name); + if (source && source.kind === "vvec" && source.n === n) { + for (let c = 0; c < n; c++) { + em.localGet(source.indices[c]); + this.vSetLocal(local.indices[c]); + } + return; + } + if (source && source.kind === "vec" && source.n === n) { + for (let c = 0; c < n; c++) { + em.localGet(source.indices[c]).f32x4Splat(); + this.vSetLocal(local.indices[c]); + } + return; + } + } + throw this.astErrorOutput(`WebAssembly backend does not yet support ${actualType} initializer of type ${init.type}`, varDecNode); + } + let type = actualType; + if (type === "LiteralInteger") type = info.suggestedType === "Integer" ? "Integer" : "Number"; + if (actualType === "Integer" && type === "Integer") { + info.valueType = "Number"; + this.vSetVaryingScalar(name, "vf32", "Number", () => this.vCastValueToFloat(init)); + return; + } + info.valueType = type; + switch (type) { + case "Number": + case "Float": + this.vSetVaryingScalar(name, "vf32", type, () => { + if (actualType === "LiteralInteger") this.vCastLiteralToFloat(init); else if (actualType === "Integer") this.vCastValueToFloat(init); else this.vCoerce(this.vexpr(init), "vf32"); + }); + break; + + case "Integer": + this.vSetVaryingScalar(name, "vi32", "Integer", () => { + if (actualType === "LiteralInteger") this.vCastLiteralToInteger(init); else if (actualType === "Number" || actualType === "Float") this.vCastValueToInteger(init); else this.vCoerce(this.vexpr(init), "vi32"); + }); + break; + + case "Boolean": + this.vSetVaryingScalar(name, "vi32", "Boolean", () => { + this.vexprMask(init); + this.em.v128ConstI32x4(1, 1, 1, 1).v128And(); + }); + break; + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support declaring type ${type}`, varDecNode); + } + } + vSetVaryingScalar(name, wtype, gtype, emitInit) { + let local = this.locals.get(name); + if (!local || local.kind !== "vscalar" || local.wtype !== wtype) { + local = { + kind: "vscalar", + index: this.em.addLocal("v128"), + wtype: wtype, + gtype: gtype + }; + this.locals.set(name, local); + } else local.gtype = gtype; + emitInit(); + this.vSetLocal(local.index); + } + vEmitArrayElement(element) { + switch (this.getType(element)) { + case "Integer": + this.vCastValueToFloat(element); + break; + + case "LiteralInteger": + this.vCastLiteralToFloat(element); + break; + + default: + this.vCoerce(this.vexpr(element), "vf32"); + } + } + vAssign(assNode) { + if (assNode.left.type !== "Identifier") throw this.astErrorOutput(`WebAssembly backend does not yet support assignment to ${assNode.left.type}`, assNode); + const name = assNode.left.name; + const local = this.locals.get(name); + if (local && local.kind === "scalar") return this.emitAssignment(assNode); + if (!local || local.kind !== "vscalar") throw this.astErrorOutput(`cannot assign to "${name}"`, assNode); + const wtype = local.wtype; + if (assNode.operator === "=") { + const leftType = this.getType(assNode.left); + const rightType = this.getType(assNode.right); + if (leftType !== "Integer" && rightType === "Integer") { + this.vCastValueToFloat(assNode.right); + this.vCoerce("vf32", wtype); + } else if (leftType !== "Integer" && rightType === "LiteralInteger") { + this.vCastLiteralToFloat(assNode.right); + this.vCoerce("vf32", wtype); + } else if (leftType === "Integer" && rightType === "LiteralInteger") { + this.vCastLiteralToInteger(assNode.right); + this.vCoerce("vi32", wtype); + } else if (leftType === "Integer" && (rightType === "Number" || rightType === "Float")) { + this.vCastValueToInteger(assNode.right); + this.vCoerce("vi32", wtype); + } else this.vCoerce(this.vexpr(assNode.right), wtype); + } else { + const synthetic = { + type: "BinaryExpression", + operator: assNode.operator.slice(0, -1), + left: assNode.left, + right: assNode.right + }; + this.vCoerce(this.vexprBinary(synthetic), wtype); + } + this.vSetLocal(local.index); + } + vUpdate(uNode, isStatement) { + if (uNode.argument.type !== "Identifier") throw this.astErrorOutput("update expression needs a variable", uNode); + const local = this.locals.get(uNode.argument.name); + if (local && local.kind === "scalar") return this.emitUpdate(uNode, isStatement); + if (!local || local.kind !== "vscalar") throw this.astErrorOutput(`cannot update "${uNode.argument.name}"`, uNode); + const em = this.em; + const isInt = local.wtype === "vi32"; + const one = () => isInt ? em.v128ConstI32x4(1, 1, 1, 1) : em.v128ConstF32x4(1, 1, 1, 1); + const op = uNode.operator === "++" ? isInt ? "i32x4Add" : "f32x4Add" : isInt ? "i32x4Sub" : "f32x4Sub"; + if (isStatement) { + em.localGet(local.index); + one(); + em[op](); + this.vSetLocal(local.index); + return "void"; + } + if (uNode.prefix) { + em.localGet(local.index); + one(); + em[op](); + this.vSetLocal(local.index); + em.localGet(local.index); + } else { + const old = em.addLocal("v128"); + em.localGet(local.index).localSet(old); + em.localGet(local.index); + one(); + em[op](); + this.vSetLocal(local.index); + em.localGet(old); + } + return local.wtype; + } + vstmtIf(ifNode) { + const em = this.em; + if (!this.vInfo.exprVarying(ifNode.test)) { + this.emitCondition(ifNode.test); + this.enterIf(); + this.vstatementBody(ifNode.consequent); + if (ifNode.alternate) { + em.else_(); + this.vstatementBody(ifNode.alternate); + } + this.exit(); + return; + } + const m = em.addLocal("v128"); + this.vexprMask(ifNode.test); + em.localSet(m); + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + em.localGet(saved).localGet(m).v128And().localSet(this.vCur); + em.localGet(this.vCur).v128AnyTrue(); + this.enterIf(); + this.vMaskDepth++; + this.vstatementBody(ifNode.consequent); + this.vMaskDepth--; + this.exit(); + if (ifNode.alternate) { + em.localGet(saved).localGet(m).v128Andnot().localSet(this.vCur); + em.localGet(this.vCur).v128AnyTrue(); + this.enterIf(); + this.vMaskDepth++; + this.vstatementBody(ifNode.alternate); + this.vMaskDepth--; + this.exit(); + } + this.vRecomputeCur(saved); + } + vstmtReturn(ast) { + const em = this.em; + if (!ast.argument) { + this.vRetireOrReturn(); + return; + } + this.pushState("skip-literal-correction"); + const type = this.getType(ast.argument); + this.popState("skip-literal-correction"); + switch (this.returnType) { + case "Array(2)": + case "Array(3)": + case "Array(4)": + { + const n = parseInt(this.returnType.substring(6), 10); + const argument = ast.argument; + const comps = []; + if (argument.type === "ArrayExpression") { + if (argument.elements.length !== n) throw this.astErrorOutput(`expected ${n} array elements to match return type ${this.returnType}`, ast); + for (let c = 0; c < n; c++) { + const t = em.addLocal("v128"); + this.vEmitArrayElement(argument.elements[c]); + em.localSet(t); + comps.push(t); + } + } else if (argument.type === "Identifier") { + const local = this.locals.get(argument.name); + if (local && local.kind === "vvec" && local.n === n) for (let c = 0; c < n; c++) comps.push(local.indices[c]); else if (local && local.kind === "vec" && local.n === n) for (let c = 0; c < n; c++) { + const t = em.addLocal("v128"); + em.localGet(local.indices[c]).f32x4Splat().localSet(t); + comps.push(t); + } else throw this.astErrorOutput(`"${argument.name}" is not an Array(${n}) variable`, ast); + } else throw this.astErrorOutput(`WebAssembly backend does not yet support returning ${this.returnType} from a ${argument.type}`, ast); + this.vStoreOutput(comps); + this.vRetireOrReturn(); + return; + } + + default: + { + const t = em.addLocal("v128"); + switch (this.returnType) { + case "Integer": + if (type === "Float" || type === "Number") this.vCastValueToInteger(ast.argument); else if (type === "LiteralInteger") this.vCastLiteralToInteger(ast.argument); else this.vCoerce(this.vexpr(ast.argument), "vi32"); + em.f32x4ConvertI32x4S(); + break; + + case "LiteralInteger": + case "Number": + case "Float": + if (type === "Integer") this.vCastValueToFloat(ast.argument); else if (type === "LiteralInteger") this.vCastLiteralToFloat(ast.argument); else this.vCoerce(this.vexpr(ast.argument), "vf32"); + break; + + case "Boolean": + this.vexprMask(ast.argument); + em.v128ConstI32x4(1, 1, 1, 1).v128And().f32x4ConvertI32x4S(); + break; + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support returning ${this.returnType}`, ast); + } + em.localSet(t); + this.vStoreOutput([ t ]); + this.vRetireOrReturn(); + } + } + } + vStoreOutput(comps) { + const em = this.em; + const globals = this.assembler.globals; + const outputOffset = this.assembler.layout.outputOffset; + const n = comps.length; + let maskLocal = -1; + if (this.vMaskDepth > 0) maskLocal = this.vCur; else if (this.vRetMask !== -1) { + maskLocal = em.addLocal("v128"); + em.localGet(this.vRetMask).v128Not().localSet(maskLocal); + } + const addr = em.addLocal("i32"); + if (n === 1) { + em.globalGet(globals.dataIndex).i32Const(2).i32Shl().localSet(addr); + if (maskLocal === -1) em.localGet(addr).localGet(comps[0]).v128Store(outputOffset, 2); else { + em.localGet(addr); + em.localGet(comps[0]); + em.localGet(addr).v128Load(outputOffset, 2); + em.localGet(maskLocal).v128Bitselect(); + em.v128Store(outputOffset, 2); + } + return; + } + em.globalGet(globals.dataIndex).i32Const(n).i32Mul().i32Const(2).i32Shl().localSet(addr); + for (let lane = 0; lane < 4; lane++) for (let c = 0; c < n; c++) { + const offset = outputOffset + (lane * n + c) * 4; + em.localGet(addr); + em.localGet(comps[c]).f32x4ExtractLane(lane); + if (maskLocal !== -1) { + em.localGet(addr).f32Load(offset); + em.localGet(maskLocal).i32x4ExtractLane(lane); + em.select(); + } + em.f32Store(offset); + } + } + vRetireOrReturn() { + const em = this.em; + if (this.vMaskDepth === 0) { + em.return_(); + this.vTerminated = true; + return; + } + em.localGet(this.vRetMask).localGet(this.vCur).v128Or().localSet(this.vRetMask); + this.vZero(); + em.localSet(this.vCur); + this.vTerminated = true; + } + vstmtBreak(brNode) { + const target = this.vLoopStack[this.vLoopStack.length - 1]; + if (!target) throw this.astErrorOutput("break used outside of a loop", brNode); + if (!target.varying) { + this.brTo(target.breakLevel); + this.vTerminated = true; + return; + } + if (target.vBrk === -1) throw this.astErrorOutput("internal: loop exit scan missed a break", brNode); + const em = this.em; + em.localGet(target.vBrk).localGet(this.vCur).v128Or().localSet(target.vBrk); + this.vZero(); + em.localSet(this.vCur); + this.vTerminated = true; + } + vstmtContinue(crNode) { + const target = this.vLoopStack[this.vLoopStack.length - 1]; + if (!target) throw this.astErrorOutput("continue used outside of a loop", crNode); + if (!target.varying) { + this.brTo(target.continueLevel); + this.vTerminated = true; + return; + } + if (target.vCnt === -1) throw this.astErrorOutput("internal: loop exit scan missed a continue", crNode); + const em = this.em; + em.localGet(target.vCnt).localGet(this.vCur).v128Or().localSet(target.vCnt); + this.vZero(); + em.localSet(this.vCur); + this.vTerminated = true; + } + vstmtFor(forNode) { + if (forNode.type !== "ForStatement") throw this.astErrorOutput("Invalid for statement", forNode); + const em = this.em; + const varying = (forNode.test ? this.vInfo.exprVarying(forNode.test) : false) || this.vInfo.hasVaryingExit(forNode.body, false); + const isSafe = this.forLoopIsSafe(forNode); + if (forNode.init) if (forNode.init.type === "VariableDeclaration") this.vstmtVariableDeclaration(forNode.init); else this.vstatementExpression(forNode.init); + if (!varying) { + let safeI = -1; + if (!isSafe) { + safeI = em.addLocal("i32"); + em.i32Const(0).localSet(safeI); + } + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + if (!isSafe) { + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + } + if (forNode.test) { + this.emitCondition(forNode.test); + em.i32Eqz(); + this.brIfTo(breakLevel); + } + this.enterBlock(); + const continueLevel = this.depth; + this.vLoopStack.push({ + varying: false, + breakLevel: breakLevel, + continueLevel: continueLevel + }); + if (forNode.body) this.vstatementBody(forNode.body); + this.vLoopStack.pop(); + this.exit(); + if (forNode.update) this.vstatementExpression(forNode.update); + if (!isSafe) em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + return; + } + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + const vLive = em.addLocal("v128"); + em.localGet(this.vCur).localSet(vLive); + const exits = this.vLoopBodyExits(forNode.body); + let vBrk = -1; + if (exits.hasBreak) { + vBrk = em.addLocal("v128"); + this.vZero(); + em.localSet(vBrk); + } + const vCnt = exits.hasContinue ? em.addLocal("v128") : -1; + let safeI = -1; + if (!isSafe) { + safeI = em.addLocal("i32"); + em.i32Const(0).localSet(safeI); + } + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + if (!isSafe) { + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + } + if (vBrk !== -1 || this.vRetMask !== -1) { + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(vLive); + } + if (vCnt !== -1) { + this.vZero(); + em.localSet(vCnt); + } + this.vMaskDepth++; + em.localGet(vLive).localSet(this.vCur); + if (forNode.test) { + em.localGet(vLive); + this.vexprMask(forNode.test); + em.v128And().localSet(vLive); + } + em.localGet(vLive).v128AnyTrue().i32Eqz(); + this.brIfTo(breakLevel); + em.localGet(vLive).localSet(this.vCur); + this.vLoopStack.push({ + varying: true, + vLive: vLive, + vBrk: vBrk, + vCnt: vCnt, + breakLevel: breakLevel, + loopLevel: loopLevel + }); + if (forNode.body) this.vstatementBody(forNode.body); + this.vLoopStack.pop(); + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(this.vCur); + if (forNode.update) this.vstatementExpression(forNode.update); + this.vMaskDepth--; + if (!isSafe) em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + this.vRecomputeCur(saved); + } + vstmtWhile(whileNode) { + if (whileNode.type !== "WhileStatement") throw this.astErrorOutput("Invalid while statement", whileNode); + const em = this.em; + const varying = this.vInfo.exprVarying(whileNode.test) || this.vInfo.hasVaryingExit(whileNode.body, false); + const safeI = em.addLocal("i32"); + em.i32Const(0).localSet(safeI); + if (!varying) { + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + this.emitCondition(whileNode.test); + em.i32Eqz(); + this.brIfTo(breakLevel); + this.enterBlock(); + const continueLevel = this.depth; + this.vLoopStack.push({ + varying: false, + breakLevel: breakLevel, + continueLevel: continueLevel + }); + this.vstatementBody(whileNode.body); + this.vLoopStack.pop(); + this.exit(); + em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + return; + } + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + const vLive = em.addLocal("v128"); + em.localGet(this.vCur).localSet(vLive); + const exits = this.vLoopBodyExits(whileNode.body); + let vBrk = -1; + if (exits.hasBreak) { + vBrk = em.addLocal("v128"); + this.vZero(); + em.localSet(vBrk); + } + const vCnt = exits.hasContinue ? em.addLocal("v128") : -1; + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + if (vBrk !== -1 || this.vRetMask !== -1) { + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(vLive); + } + if (vCnt !== -1) { + this.vZero(); + em.localSet(vCnt); + } + this.vMaskDepth++; + em.localGet(vLive).localSet(this.vCur); + em.localGet(vLive); + this.vexprMask(whileNode.test); + em.v128And().localSet(vLive); + em.localGet(vLive).v128AnyTrue().i32Eqz(); + this.brIfTo(breakLevel); + em.localGet(vLive).localSet(this.vCur); + this.vLoopStack.push({ + varying: true, + vLive: vLive, + vBrk: vBrk, + vCnt: vCnt, + breakLevel: breakLevel, + loopLevel: loopLevel + }); + this.vstatementBody(whileNode.body); + this.vLoopStack.pop(); + this.vMaskDepth--; + em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + this.vRecomputeCur(saved); + } + vstmtDoWhile(doWhileNode) { + if (doWhileNode.type !== "DoWhileStatement") throw this.astErrorOutput("Invalid while statement", doWhileNode); + const em = this.em; + const varying = this.vInfo.exprVarying(doWhileNode.test) || this.vInfo.hasVaryingExit(doWhileNode.body, false); + const safeI = em.addLocal("i32"); + em.i32Const(0).localSet(safeI); + if (!varying) { + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + this.enterBlock(); + const continueLevel = this.depth; + this.vLoopStack.push({ + varying: false, + breakLevel: breakLevel, + continueLevel: continueLevel + }); + this.vstatementBody(doWhileNode.body); + this.vLoopStack.pop(); + this.exit(); + em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.emitCondition(doWhileNode.test); + this.brIfTo(loopLevel); + this.exit(); + this.exit(); + return; + } + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + const vLive = em.addLocal("v128"); + em.localGet(this.vCur).localSet(vLive); + const exits = this.vLoopBodyExits(doWhileNode.body); + let vBrk = -1; + if (exits.hasBreak) { + vBrk = em.addLocal("v128"); + this.vZero(); + em.localSet(vBrk); + } + const vCnt = exits.hasContinue ? em.addLocal("v128") : -1; + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + if (vBrk !== -1 || this.vRetMask !== -1) { + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(vLive); + } + if (vCnt !== -1) { + this.vZero(); + em.localSet(vCnt); + } + this.vMaskDepth++; + em.localGet(vLive).localSet(this.vCur); + this.vLoopStack.push({ + varying: true, + vLive: vLive, + vBrk: vBrk, + vCnt: vCnt, + breakLevel: breakLevel, + loopLevel: loopLevel + }); + this.vstatementBody(doWhileNode.body); + this.vLoopStack.pop(); + if (vBrk !== -1 || this.vRetMask !== -1) { + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(vLive); + } + em.localGet(vLive).localSet(this.vCur); + em.localGet(vLive); + this.vexprMask(doWhileNode.test); + em.v128And().localSet(vLive); + this.vMaskDepth--; + em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + em.localGet(vLive).v128AnyTrue(); + this.brIfTo(loopLevel); + this.exit(); + this.exit(); + this.vRecomputeCur(saved); + } + vstmtSwitch(ast) { + if (ast.type !== "SwitchStatement") throw this.astErrorOutput("Invalid switch statement", ast); + const {discriminant: discriminant, cases: cases} = ast; + const em = this.em; + const varying = this.vInfo.exprVarying(discriminant) || cases.some(c => c.test && this.vInfo.exprVarying(c.test)); + const type = this.getType(discriminant); + if (!varying) { + let dLocal; + let dIsInt; + switch (type) { + case "Float": + case "Number": + dIsInt = false; + dLocal = em.addLocal("f32"); + this.coerce(this.expression(discriminant), "f32"); + em.localSet(dLocal); + break; + + case "Integer": + dIsInt = true; + dLocal = em.addLocal("i32"); + this.coerce(this.expression(discriminant), "i32"); + em.localSet(dLocal); + break; + + default: + throw this.astErrorOutput(`Unhandled switch discriminant type "${type}"`, ast); + } + if (cases.length === 1 && !cases[0].test) { + this.vEmitSwitchConsequent(cases[0].consequent); + return; + } + const {groups: groups, defaultConsequent: defaultConsequent} = this.collectSwitchGroups(cases); + const emitChain = index => { + if (index === groups.length) { + if (defaultConsequent) this.vEmitSwitchConsequent(defaultConsequent); + return; + } + const {tests: tests, consequent: consequent} = groups[index]; + for (let i = 0; i < tests.length; i++) { + em.localGet(dLocal); + this.emitSwitchTest(tests[i], dIsInt); + if (dIsInt) em.i32Eq(); else em.f32Eq(); + if (i > 0) em.i32Or(); + } + this.enterIf(); + this.vEmitSwitchConsequent(consequent); + if (index + 1 < groups.length || defaultConsequent) { + em.else_(); + emitChain(index + 1); + } + this.exit(); + }; + emitChain(0); + return; + } + let dLocal; + let dIsInt; + switch (type) { + case "Float": + case "Number": + dIsInt = false; + dLocal = em.addLocal("v128"); + this.vCoerce(this.vexpr(discriminant), "vf32"); + em.localSet(dLocal); + break; + + case "Integer": + dIsInt = true; + dLocal = em.addLocal("v128"); + this.vCoerce(this.vexpr(discriminant), "vi32"); + em.localSet(dLocal); + break; + + default: + throw this.astErrorOutput(`Unhandled switch discriminant type "${type}"`, ast); + } + if (cases.length === 1 && !cases[0].test) { + this.vEmitSwitchConsequent(cases[0].consequent); + return; + } + const {groups: groups, defaultConsequent: defaultConsequent} = this.collectSwitchGroups(cases); + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + const prior = em.addLocal("v128"); + this.vZero(); + em.localSet(prior); + const gm = em.addLocal("v128"); + this.vMaskDepth++; + for (let g = 0; g < groups.length; g++) { + const {tests: tests, consequent: consequent} = groups[g]; + for (let i = 0; i < tests.length; i++) { + em.localGet(dLocal); + this.vEmitSwitchTest(tests[i], dIsInt); + if (dIsInt) em.i32x4Eq(); else em.f32x4Eq(); + if (i > 0) em.v128Or(); + } + em.localSet(gm); + this.vRecomputeCur(saved); + em.localGet(this.vCur).localGet(gm).v128And().localGet(prior).v128Andnot().localSet(this.vCur); + em.localGet(prior).localGet(gm).v128Or().localSet(prior); + em.localGet(this.vCur).v128AnyTrue(); + this.enterIf(); + this.vEmitSwitchConsequent(consequent); + this.exit(); + } + if (defaultConsequent) { + this.vRecomputeCur(saved); + em.localGet(this.vCur).localGet(prior).v128Andnot().localSet(this.vCur); + em.localGet(this.vCur).v128AnyTrue(); + this.enterIf(); + this.vEmitSwitchConsequent(defaultConsequent); + this.exit(); + } + this.vMaskDepth--; + this.vRecomputeCur(saved); + } + vEmitSwitchTest(test, dIsInt) { + const testType = this.getType(test); + if (dIsInt) if (testType === "Number" || testType === "Float") this.vCastValueToInteger(test); else if (testType === "LiteralInteger") this.vCastLiteralToInteger(test); else this.vCoerce(this.vexpr(test), "vi32"); else if (testType === "LiteralInteger") this.vCastLiteralToFloat(test); else if (testType === "Integer") this.vCastValueToFloat(test); else this.vCoerce(this.vexpr(test), "vf32"); + } + vEmitSwitchConsequent(consequent) { + const statements = this.collectSwitchCaseStatements(consequent); + const previous = this.vTerminated; + this.vTerminated = false; + for (let i = 0; i < statements.length; i++) { + this.vstatement(statements[i]); + if (this.vTerminated) break; + } + this.vTerminated = previous; + } + vexpr(ast) { + if (!this.vInfo.exprVarying(ast)) return this.expression(ast); + switch (ast.type) { + case "Identifier": + return this.vexprIdentifier(ast); + + case "BinaryExpression": + return this.vexprBinary(ast); + + case "LogicalExpression": + return this.vexprLogical(ast); + + case "UnaryExpression": + return this.vexprUnary(ast); + + case "UpdateExpression": + return this.vUpdate(ast, false); + + case "ConditionalExpression": + return this.vexprConditional(ast); + + case "CallExpression": + return this.vexprCall(ast); + + case "MemberExpression": + return this.vexprMember(ast); + + case "SequenceExpression": + if (ast.expressions.length === 1) return this.vexpr(ast.expressions[0]); + throw this.astErrorOutput("WebAssembly backend does not yet support the comma operator", ast); + + case "AssignmentExpression": + throw this.astErrorOutput("WebAssembly backend does not yet support assignment used as an expression", ast); + + default: + throw this.astErrorOutput(`Unknown expression type ${ast.type}`, ast); + } + } + vexprIdentifier(ast) { + const local = this.locals.get(ast.name); + if (!local) throw this.astErrorOutput(`Unhandled varying identifier "${ast.name}"`, ast); + if (local.kind === "vvec") throw this.astErrorOutput(`array-valued variable "${ast.name}" can only be indexed or returned`, ast); + if (local.kind !== "vscalar") throw this.astErrorOutput(`internal: varying read of uniform local "${ast.name}"`, ast); + this.em.localGet(local.index); + return local.wtype; + } + vexprBinary(ast) { + const operator = ast.operator; + const em = this.em; + if (operator === "**") { + const a = em.addLocal("v128"); + const b = em.addLocal("v128"); + this.vEmitByType(ast.left, "vf32"); + em.localSet(a); + this.vEmitByType(ast.right, "vf32"); + em.localSet(b); + this.usedMathImports.add("pow"); + this.vLaneCall2("math_pow", a, b); + return "vf32"; + } + if (BITWISE_OPS[operator]) { + if (VECTOR_SHIFT_OPS[operator]) return this.vexprShift(ast); + this.vEmitAsIntegerOperand(ast.left); + this.vEmitAsIntegerOperand(ast.right); + em[{ + "&": "v128And", + "|": "v128Or", + "^": "v128Xor" + }[operator]](); + return "vi32"; + } + if (operator === "/" || operator === "%") { + if (operator === "/") { + this.vEmitByType(ast.left, "vf32"); + this.vEmitByType(ast.right, "vf32"); + em.f32x4Div(); + return "vf32"; + } + const a = em.addLocal("v128"); + const b = em.addLocal("v128"); + this.vEmitByType(ast.left, "vf32"); + em.localSet(a); + this.vEmitByType(ast.right, "vf32"); + em.localSet(b); + em.localGet(a).localGet(a).localGet(b).f32x4Div().f32x4Trunc().localGet(b).f32x4Mul().f32x4Sub(); + return "vf32"; + } + const leftType = this.getType(ast.left) || "Number"; + const rightType = this.getType(ast.right) || "Number"; + const key = leftType + " & " + rightType; + let category; + switch (key) { + case "Integer & Integer": + this.pushState("building-integer"); + this.vCoerce(this.vexpr(ast.left), "vi32"); + this.vCoerce(this.vexpr(ast.right), "vi32"); + this.popState("building-integer"); + category = "vi32"; + break; + + case "Number & Float": + case "Float & Number": + case "Float & Float": + case "Number & Number": + this.pushState("building-float"); + this.vCoerce(this.vexpr(ast.left), "vf32"); + this.vCoerce(this.vexpr(ast.right), "vf32"); + this.popState("building-float"); + category = "vf32"; + break; + + case "LiteralInteger & LiteralInteger": + if (this.isState("casting-to-integer") || this.isState("building-integer")) { + this.pushState("building-integer"); + this.vCoerce(this.vexpr(ast.left), "vi32"); + this.vCoerce(this.vexpr(ast.right), "vi32"); + this.popState("building-integer"); + category = "vi32"; + } else { + this.pushState("building-float"); + this.vCastLiteralToFloat(ast.left); + this.vCastLiteralToFloat(ast.right); + this.popState("building-float"); + category = "vf32"; + } + break; + + case "Integer & Float": + case "Integer & Number": + this.pushState("building-float"); + this.vCastValueToFloat(ast.left); + this.vCoerce(this.vexpr(ast.right), "vf32"); + this.popState("building-float"); + category = "vf32"; + break; + + case "Integer & LiteralInteger": + this.pushState("building-integer"); + this.vCoerce(this.vexpr(ast.left), "vi32"); + this.vCastLiteralToInteger(ast.right); + this.popState("building-integer"); + category = "vi32"; + break; + + case "Number & Integer": + case "Float & Integer": + this.pushState("building-float"); + this.vCoerce(this.vexpr(ast.left), "vf32"); + this.vCastValueToFloat(ast.right); + this.popState("building-float"); + category = "vf32"; + break; + + case "Float & LiteralInteger": + case "Number & LiteralInteger": + this.pushState("building-float"); + this.vCoerce(this.vexpr(ast.left), "vf32"); + this.vCastLiteralToFloat(ast.right); + this.popState("building-float"); + category = "vf32"; + break; + + case "LiteralInteger & Float": + case "LiteralInteger & Number": + if (this.isState("casting-to-integer")) { + this.pushState("building-integer"); + this.vCastLiteralToInteger(ast.left); + this.vCastValueToInteger(ast.right); + this.popState("building-integer"); + category = "vi32"; + } else { + this.pushState("building-float"); + this.vCastLiteralToFloat(ast.left); + this.pushState("casting-to-float"); + this.vCoerce(this.vexpr(ast.right), "vf32"); + this.popState("casting-to-float"); + this.popState("building-float"); + category = "vf32"; + } + break; + + case "LiteralInteger & Integer": + this.pushState("building-integer"); + this.vCastLiteralToInteger(ast.left); + this.vCoerce(this.vexpr(ast.right), "vi32"); + this.popState("building-integer"); + category = "vi32"; + break; + + case "Boolean & Boolean": + this.vCoerce(this.vexpr(ast.left), "vi32"); + this.vCoerce(this.vexpr(ast.right), "vi32"); + category = "vi32"; + break; + + default: + throw this.astErrorOutput(`Unhandled binary expression between ${key}`, ast); + } + const compareOp = category === "vi32" ? VI32_COMPARE[operator] : VF32_COMPARE[operator]; + if (compareOp) { + em[compareOp](); + return "vbool"; + } + const arithOp = category === "vi32" ? VI32_ARITH[operator] : VF32_ARITH[operator]; + if (!arithOp) throw this.astErrorOutput(`Unhandled operator ${operator}`, ast); + em[arithOp](); + return category; + } + vexprShift(ast) { + const em = this.em; + this.vEmitAsIntegerOperand(ast.left); + if (!this.vInfo.exprVarying(ast.right)) { + this.emitAsIntegerOperand(ast.right); + em[VECTOR_SHIFT_OPS[ast.operator]](); + return "vi32"; + } + const a = em.addLocal("v128"); + const b = em.addLocal("v128"); + em.localSet(a); + this.vEmitAsIntegerOperand(ast.right); + em.localSet(b); + const op = BITWISE_OPS[ast.operator]; + for (let lane = 0; lane < 4; lane++) { + em.localGet(a).i32x4ExtractLane(lane); + em.localGet(b).i32x4ExtractLane(lane); + em[op](); + if (lane === 0) em.i32x4Splat(); else em.i32x4ReplaceLane(lane); + } + return "vi32"; + } + vEmitAsIntegerOperand(side) { + switch (this.getType(side)) { + case "Number": + case "Float": + this.vCastValueToInteger(side); + break; + + case "LiteralInteger": + this.vCastLiteralToInteger(side); + break; + + default: + { + this.pushState("building-integer"); + const type = this.vexpr(side); + this.popState("building-integer"); + this.vCoerce(type, "vi32"); + } + } + } + vexprLogical(ast) { + const em = this.em; + const mLeft = em.addLocal("v128"); + this.vexprMask(ast.left); + em.localSet(mLeft); + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + em.localGet(this.vCur).localGet(mLeft); + if (ast.operator === "&&") em.v128And(); else if (ast.operator === "||") em.v128Andnot(); else throw this.astErrorOutput(`Unhandled logical operator ${ast.operator}`, ast); + em.localSet(this.vCur); + this.vMaskDepth++; + this.vexprMask(ast.right); + this.vMaskDepth--; + em.localGet(saved).localSet(this.vCur); + em.localGet(mLeft); + if (ast.operator === "&&") em.v128And(); else em.v128Or(); + return "vbool"; + } + vexprUnary(ast) { + const em = this.em; + switch (ast.operator) { + case "~": + this.vEmitAsIntegerOperand(ast.argument); + em.v128ConstI32x4(-1, -1, -1, -1).v128Xor(); + return "vi32"; + + case "!": + this.vexprMask(ast.argument); + em.v128Not(); + return "vbool"; + + case "+": + return this.vexpr(ast.argument); + + case "-": + { + const type = this.getType(ast.argument); + if (type === "Integer" || type === "LiteralInteger" && (this.isState("casting-to-integer") || this.isState("building-integer"))) { + this.vZero(); + this.vEmitByType(ast.argument, "vi32"); + em.i32x4Sub(); + return "vi32"; + } + this.vEmitByType(ast.argument, "vf32"); + em.f32x4Neg(); + return "vf32"; + } + + default: + throw this.astErrorOutput(`Unhandled unary operator ${ast.operator}`, ast); + } + } + vexprConditional(ast) { + const em = this.em; + const consequentType = this.getType(ast.consequent); + const alternateType = this.getType(ast.alternate); + if (consequentType === null && alternateType === null) { + this.vTernaryStatement(ast); + return "void"; + } + let targetType = consequentType === "LiteralInteger" ? "Number" : consequentType; + if (targetType === "Integer" && (alternateType === "Number" || alternateType === "Float")) targetType = "Number"; + const emitBranch = branch => { + const branchType = this.getType(branch); + switch (targetType) { + case "Number": + case "Float": + if (branchType === "Integer") this.vCastValueToFloat(branch); else if (branchType === "LiteralInteger") this.vCastLiteralToFloat(branch); else this.vCoerce(this.vexpr(branch), "vf32"); + break; + + case "Integer": + if (branchType === "Number" || branchType === "Float") this.vCastValueToInteger(branch); else if (branchType === "LiteralInteger") this.vCastLiteralToInteger(branch); else this.vCoerce(this.vexpr(branch), "vi32"); + break; + + case "Boolean": + this.vexprMask(branch); + break; + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support a ternary of type ${targetType}`, ast); + } + }; + const resultCategory = targetType === "Integer" ? "vi32" : targetType === "Boolean" ? "vbool" : "vf32"; + if (!this.vInfo.exprVarying(ast.test)) { + this.emitCondition(ast.test); + this.enterIf("v128"); + emitBranch(ast.consequent); + em.else_(); + emitBranch(ast.alternate); + this.exit(); + return resultCategory; + } + const m = em.addLocal("v128"); + this.vexprMask(ast.test); + em.localSet(m); + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + const v1 = em.addLocal("v128"); + const v2 = em.addLocal("v128"); + em.localGet(saved).localGet(m).v128And().localSet(this.vCur); + this.vMaskDepth++; + emitBranch(ast.consequent); + em.localSet(v1); + em.localGet(saved).localGet(m).v128Andnot().localSet(this.vCur); + emitBranch(ast.alternate); + em.localSet(v2); + this.vMaskDepth--; + em.localGet(saved).localSet(this.vCur); + em.localGet(v1).localGet(v2).localGet(m).v128Bitselect(); + return resultCategory; + } + vTernaryStatement(ast) { + const em = this.em; + if (!this.vInfo.exprVarying(ast.test)) { + this.emitCondition(ast.test); + this.enterIf(); + this.vstatementExpression(ast.consequent); + em.else_(); + this.vstatementExpression(ast.alternate); + this.exit(); + return; + } + const m = em.addLocal("v128"); + this.vexprMask(ast.test); + em.localSet(m); + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + em.localGet(saved).localGet(m).v128And().localSet(this.vCur); + this.vMaskDepth++; + this.vstatementExpression(ast.consequent); + em.localGet(saved).localGet(m).v128Andnot().localSet(this.vCur); + this.vstatementExpression(ast.alternate); + this.vMaskDepth--; + em.localGet(saved).localSet(this.vCur); + } + vexprCall(ast) { + if (!ast.callee) throw this.astErrorOutput("Unknown CallExpression", ast); + if (ast.callee.type === "MemberExpression" && this.getVariableSignature(ast.callee, true) === "this.color") throw this.astErrorOutput("WebAssembly backend does not yet support graphical mode (this.color)", ast); + let functionName = null; + const isMathFunction = this.isAstMathFunction(ast); + if (isMathFunction || ast.callee.object && ast.callee.object.type === "ThisExpression") functionName = ast.callee.property.name; else if (ast.callee.type === "SequenceExpression" && ast.callee.expressions[0].type === "Literal" && !isNaN(ast.callee.expressions[0].raw)) functionName = ast.callee.expressions[1].property.name; else functionName = ast.callee.name; + if (!functionName) throw this.astErrorOutput(`Unhandled function, couldn't find name`, ast); + if (isMathFunction) return this.vMathCall(functionName, ast); + return this.vUserCall(functionName, ast); + } + vUserCall(functionName, ast) { + const em = this.em; + const info = this.assembler.helperInfo || { + readsThread: false, + usesRandom: false + }; + const globals = this.assembler.globals; + const returnType = this.getType(ast); + const targetTypes = this.lookupFunctionArgumentTypes(functionName) || []; + const argLocals = []; + for (let i = 0; i < ast.arguments.length; ++i) { + const argument = ast.arguments[i]; + let targetType = targetTypes[i]; + const argumentType = this.getType(argument); + if (!targetType) { + this.triggerImplyArgumentType(functionName, i, argumentType, this); + targetType = argumentType; + } + let wtype; + switch (argumentType) { + case "Boolean": + this.vCoerce(this.vexpr(argument), "vi32"); + wtype = "vi32"; + break; + + case "Number": + case "Float": + if (targetType === "Integer") { + this.vCastValueToInteger(argument); + wtype = "vi32"; + } else { + this.vCoerce(this.vexpr(argument), "vf32"); + wtype = "vf32"; + } + break; + + case "Integer": + if (targetType === "Number" || targetType === "Float") { + this.vCastValueToFloat(argument); + wtype = "vf32"; + } else { + this.vCoerce(this.vexpr(argument), "vi32"); + wtype = "vi32"; + } + break; + + case "LiteralInteger": + if (targetType === "Integer") { + this.vCastLiteralToInteger(argument); + wtype = "vi32"; + } else { + this.vCastLiteralToFloat(argument); + wtype = "vf32"; + } + break; + + default: + throw this.astErrorOutput("WebAssembly backend does not yet support array arguments to helper functions", ast); + } + const index = em.addLocal("v128"); + em.localSet(index); + argLocals.push({ + index: index, + wtype: wtype + }); + } + const resultKind = returnType === null || returnType === void 0 ? "void" : returnType === "Integer" || returnType === "Boolean" ? "i32" : "f32"; + const resultTmp = resultKind === "void" ? -1 : em.addLocal(resultKind); + const resultVec = resultKind === "void" ? -1 : em.addLocal("v128"); + let stateTmp = -1; + if (info.usesRandom) { + stateTmp = em.addLocal("v128"); + em.globalGet(globals.pcgStateV).localSet(stateTmp); + } + for (let lane = 0; lane < 4; lane++) { + if (info.readsThread) { + em.localGet(this._vBaseX); + if (lane > 0) em.i32Const(lane).i32Add(); + em.globalSet(globals.threadX); + } + if (info.usesRandom) em.localGet(stateTmp).i32x4ExtractLane(lane).globalSet(globals.pcgState); + for (const arg of argLocals) { + em.localGet(arg.index); + if (arg.wtype === "vi32") em.i32x4ExtractLane(lane); else em.f32x4ExtractLane(lane); + } + em.call(this.mangleFunctionName(functionName)); + if (resultKind !== "void") em.localSet(resultTmp); + if (info.usesRandom) em.localGet(stateTmp).globalGet(globals.pcgState).i32x4ReplaceLane(lane).localSet(stateTmp); + if (resultKind !== "void") if (lane === 0) { + em.localGet(resultTmp); + if (resultKind === "i32") em.i32x4Splat(); else em.f32x4Splat(); + em.localSet(resultVec); + } else { + em.localGet(resultVec).localGet(resultTmp); + if (resultKind === "i32") em.i32x4ReplaceLane(lane); else em.f32x4ReplaceLane(lane); + em.localSet(resultVec); + } + } + if (info.readsThread) em.localGet(this._vBaseX).globalSet(globals.threadX); + if (info.usesRandom) { + em.localGet(stateTmp).globalGet(globals.pcgStateV); + if (this.vMaskDepth > 0) em.localGet(this.vCur); else em.v128ConstI32x4(-1, -1, -1, -1); + em.v128Bitselect().globalSet(globals.pcgStateV); + } + if (resultKind === "void") return "void"; + em.localGet(resultVec); + return resultKind === "i32" ? "vi32" : "vf32"; + } + vMathCall(functionName, ast) { + const em = this.em; + if (functionName === "random") { + this.usesRandom = true; + if (this.vMaskDepth > 0) em.localGet(this.vCur); else em.v128ConstI32x4(-1, -1, -1, -1); + em.call("pcg_random_v"); + return "vf32"; + } + const emitArg = argument => { + switch (this.getType(argument)) { + case "Integer": + this.vCastValueToFloat(argument); + break; + + case "LiteralInteger": + this.vCastLiteralToFloat(argument); + break; + + default: + this.vCoerce(this.vexpr(argument), "vf32"); + } + }; + const nativeOp = VECTOR_MATH_NATIVE_OPS[functionName]; + if (nativeOp) { + emitArg(ast.arguments[0]); + em[nativeOp](); + return "vf32"; + } + switch (functionName) { + case "round": + emitArg(ast.arguments[0]); + em.v128ConstF32x4(.5, .5, .5, .5).f32x4Add().f32x4Floor(); + return "vf32"; + + case "fround": + emitArg(ast.arguments[0]); + return "vf32"; + + case "min": + case "max": + { + const op = functionName === "min" ? "f32x4Min" : "f32x4Max"; + emitArg(ast.arguments[0]); + for (let i = 1; i < ast.arguments.length; i++) { + emitArg(ast.arguments[i]); + em[op](); + } + return "vf32"; + } + + case "imul": + emitArg(ast.arguments[0]); + em.i32x4TruncSatF32x4S(); + emitArg(ast.arguments[1]); + em.i32x4TruncSatF32x4S(); + em.i32x4Mul().f32x4ConvertI32x4S(); + return "vf32"; + + case "clz32": + { + emitArg(ast.arguments[0]); + em.i32x4TruncSatF32x4U(); + const t = em.addLocal("v128"); + em.localSet(t); + em.localGet(t).i32x4ExtractLane(0).i32Clz().i32x4Splat(); + for (let lane = 1; lane < 4; lane++) em.localGet(t).i32x4ExtractLane(lane).i32Clz().i32x4ReplaceLane(lane); + em.f32x4ConvertI32x4S(); + return "vf32"; + } + + default: + { + const arity = MATH_IMPORT_ARITY[functionName]; + if (!arity) throw this.astErrorOutput(`WebAssembly backend does not yet support Math.${functionName}`, ast); + this.usedMathImports.add(functionName); + if (arity === 1) { + emitArg(ast.arguments[0]); + const t = em.addLocal("v128"); + em.localSet(t); + this.vLaneCall1("math_" + functionName, t); + } else { + const a = em.addLocal("v128"); + const b = em.addLocal("v128"); + emitArg(ast.arguments[0]); + em.localSet(a); + emitArg(ast.arguments[1]); + em.localSet(b); + this.vLaneCall2("math_" + functionName, a, b); + } + return "vf32"; + } + } + } + vLaneCall1(name, argLocal) { + const em = this.em; + em.localGet(argLocal).f32x4ExtractLane(0).call(name).f32x4Splat(); + for (let lane = 1; lane < 4; lane++) em.localGet(argLocal).f32x4ExtractLane(lane).call(name).f32x4ReplaceLane(lane); + } + vLaneCall2(name, aLocal, bLocal) { + const em = this.em; + em.localGet(aLocal).f32x4ExtractLane(0).localGet(bLocal).f32x4ExtractLane(0).call(name).f32x4Splat(); + for (let lane = 1; lane < 4; lane++) em.localGet(aLocal).f32x4ExtractLane(lane).localGet(bLocal).f32x4ExtractLane(lane).call(name).f32x4ReplaceLane(lane); + } + vexprMember(mNode) { + const details = this.getMemberExpressionDetails(mNode); + if (!details) throw this.astErrorOutput("Unexpected expression", mNode); + const {signature: signature, name: name, property: property, xProperty: xProperty, yProperty: yProperty, zProperty: zProperty} = details; + const em = this.em; + switch (signature) { + case "value.thread.value": + case "this.thread.value": + if (name !== "x") throw this.astErrorOutput(`internal: thread.${name} is uniform along the lane axis`, mNode); + this.readsThread = true; + em.globalGet(this.assembler.globals.threadX).i32x4Splat(); + em.v128ConstI32x4(0, 1, 2, 3).i32x4Add(); + return "vi32"; + + case "value.value": + { + const component = { + r: 0, + g: 1, + b: 2, + a: 3 + }[property]; + if (component !== void 0) { + const local = this.locals.get(name); + if (local && local.kind === "vvec" && component < local.n) { + em.localGet(local.indices[component]); + return "vf32"; + } + } + throw this.astErrorOutput("Unexpected expression", mNode); + } + + case "value[]": + case "value[][]": + case "value[][][]": + case "value[][][][]": + { + const local = this.locals.get(name); + if (local && (local.kind === "vec" || local.kind === "vvec")) { + if (signature !== "value[]") throw this.astErrorOutput("Unexpected expression", mNode); + return this.vVecIndex(local, xProperty); + } + return this.vGather("arrays", name, xProperty, yProperty, zProperty, mNode); + } + + case "this.constants.value[]": + case "this.constants.value[][]": + case "this.constants.value[][][]": + case "this.constants.value[][][][]": + return this.vGather("constantArrays", name, xProperty, yProperty, zProperty, mNode); + + case "fn()[]": + throw this.astErrorOutput("WebAssembly backend does not yet support indexing a function call result", mNode); + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support expression signature "${signature}"`, mNode); + } + } + vVecIndex(local, xProperty) { + const em = this.em; + const getComponent = k => { + em.localGet(local.indices[k]); + if (local.kind === "vec") em.f32x4Splat(); + }; + if (xProperty.type === "Literal" && Number.isInteger(xProperty.value)) { + if (xProperty.value < 0 || xProperty.value >= local.n) throw this.astErrorOutput(`index ${xProperty.value} out of range for Array(${local.n})`, xProperty); + getComponent(xProperty.value); + return "vf32"; + } + const idx = em.addLocal("v128"); + this.vEmitIndex(xProperty); + em.localSet(idx); + const acc = em.addLocal("v128"); + getComponent(0); + em.localSet(acc); + for (let k = 1; k < local.n; k++) { + getComponent(k); + em.localGet(acc); + em.localGet(idx).v128ConstI32x4(k, k, k, k).i32x4Eq(); + em.v128Bitselect(); + em.localSet(acc); + } + em.localGet(acc); + return "vf32"; + } + vEmitIndex(property) { + if (!property) throw new Error("Property not set"); + switch (this.getType(property)) { + case "Number": + case "Float": + this.vCastValueToInteger(property); + return; + + case "LiteralInteger": + this.vCastLiteralToInteger(property); + return; + + case "Integer": + { + this.pushState("building-integer"); + const emitted = this.vexpr(property); + this.popState("building-integer"); + this.vCoerce(emitted, "vi32"); + return; + } + + default: + this.vCoerce(this.vexpr(property), "vi32"); + } + } + vGather(table, name, xProperty, yProperty, zProperty, mNode) { + const em = this.em; + const layout = this.assembler.layout[table][name]; + if (!layout) throw this.astErrorOutput(`no memory layout for "${name}" \u2014 arrays are only readable as kernel arguments or constants`, mNode); + this.vEmitIndex(xProperty); + if (yProperty) { + this.vEmitIndex(yProperty); + const d = layout.dims[0]; + em.v128ConstI32x4(d, d, d, d).i32x4Mul().i32x4Add(); + } + if (zProperty) { + this.vEmitIndex(zProperty); + const d = layout.dims[0] * layout.dims[1]; + em.v128ConstI32x4(d, d, d, d).i32x4Mul().i32x4Add(); + } + this.vZero(); + em.i32x4MaxS(); + const max = layout.flatLength - 1; + em.v128ConstI32x4(max, max, max, max).i32x4MinS(); + const idx = em.addLocal("v128"); + em.localSet(idx); + em.localGet(idx).i32x4ExtractLane(0).i32Const(2).i32Shl().f32Load(layout.offset).f32x4Splat(); + for (let lane = 1; lane < 4; lane++) em.localGet(idx).i32x4ExtractLane(lane).i32Const(2).i32Shl().f32Load(layout.offset).f32x4ReplaceLane(lane); + return "vf32"; + } + isThreadDependent(ast) { + if (!ast || typeof ast !== "object") return false; + if (Array.isArray(ast)) return ast.some(node => this.isThreadDependent(node)); + switch (ast.type) { + case "MemberExpression": + { + const signature = this.getVariableSignature(ast); + if (signature === "this.thread.value" || signature === "value.thread.value") return ast.property.name === "x"; + break; + } + + case "CallExpression": + if (this.isAstMathFunction(ast)) { + if (ast.callee.property.name === "random") return true; + break; + } + return true; + + case "Identifier": + return this.taintedLocals ? this.taintedLocals.has(ast.name) : false; + + case "ThisExpression": + return false; + } + for (const key in ast) { + if (key === "loc" || key === "start" || key === "end" || key === "parent") continue; + const child = ast[key]; + if (child && typeof child === "object" && this.isThreadDependent(child)) return true; + } + return false; + } + recordUniformity(kind, testAst) { + if (!this._analysisPass) return; + this.uniformity.push({ + kind: kind, + threadDependent: testAst ? this.isThreadDependent(testAst) : true + }); + } + }; + module.exports = { + WebAssemblyFunctionNode: WebAssemblyFunctionNode + }; + }); + var require_worker_pool = __commonJSMin((exports, module) => { + let os = null; + try { + os = require_empty_module(); + } catch (e) {} + const IS_BROWSER_WORKER = typeof Worker === "function"; + function defaultConcurrency() { + if (typeof navigator !== "undefined" && navigator.hardwareConcurrency) return navigator.hardwareConcurrency; + if (os && typeof os.cpus === "function") { + const count = os.cpus().length; + if (count) return count; + } + return 4; + } + const WORKER_SOURCE = `\nvar entries = {};\nfunction handleMessage(message, post) {\n if (message.type === 'setup') {\n var imports = { env: { memory: message.memory } };\n for (var i = 0; i < message.mathImports.length; i++) {\n imports.env['math_' + message.mathImports[i]] = Math[message.mathImports[i]];\n }\n var instance = new WebAssembly.Instance(message.module, imports);\n entries[message.id] = {\n run: instance.exports.run,\n runSimd: instance.exports.run_simd || null,\n sizeX: message.sizeX\n };\n post({ type: 'ready', id: message.id });\n } else if (message.type === 'release') {\n delete entries[message.id];\n } else if (message.type === 'run') {\n var entry = entries[message.id];\n var start = message.start;\n var end = message.end;\n var seed = message.seed;\n if (entry.runSimd && (entry.sizeX & 3) === 0 && (start & 3) === 0) {\n var quadEnd = end - ((end - start) & 3);\n if (quadEnd > start) entry.runSimd(start, quadEnd, seed);\n if (quadEnd < end) entry.run(quadEnd, end, seed);\n } else {\n entry.run(start, end, seed);\n }\n post({ type: 'done', taskId: message.taskId });\n }\n}\nif (typeof self !== 'undefined' && typeof postMessage === 'function') {\n self.onmessage = function(event) {\n handleMessage(event.data, function(message) { postMessage(message); });\n };\n} else {\n var parentPort = require('worker_threads').parentPort;\n parentPort.on('message', function(message) {\n handleMessage(message, function(reply) { parentPort.postMessage(reply); });\n });\n}\n`; + var WebAssemblyWorkerPool = class { + constructor(size) { + this.size = size || defaultConcurrency(); + this.workers = []; + this.destroyed = false; + this.dispatchCount = 0; + this.lastDispatch = null; + this._taskId = 0; + } + get liveWorkerCount() { + let count = 0; + for (const worker of this.workers) if (!worker.dead) count++; + return count; + } + _spawn() { + const worker = { + handle: null, + dead: false, + state: { + setup: new Set, + settingUp: new Map, + pending: new Map + }, + fail: null, + die: null + }; + const state = worker.state; + worker.fail = error => { + for (const wait of state.settingUp.values()) wait.reject(error); + state.settingUp.clear(); + for (const task of state.pending.values()) task.reject(error); + state.pending.clear(); + }; + worker.die = error => { + if (worker.dead) return; + worker.dead = true; + worker.fail(error); + if (worker.handle && typeof worker.handle.terminate === "function") try { + worker.handle.terminate(); + } catch (e) {} + }; + const onMessage = message => { + if (message.type === "ready") { + const wait = state.settingUp.get(message.id); + if (wait) { + state.settingUp.delete(message.id); + state.setup.add(message.id); + this._updateRef(worker); + wait.resolve(); + } + } else if (message.type === "done") { + const task = state.pending.get(message.taskId); + if (task) { + state.pending.delete(message.taskId); + this._updateRef(worker); + task.resolve(); + } + } + }; + let handle; + if (IS_BROWSER_WORKER) { + const url = URL.createObjectURL(new Blob([ WORKER_SOURCE ], { + type: "text/javascript" + })); + handle = new Worker(url); + URL.revokeObjectURL(url); + handle.onmessage = event => onMessage(event.data); + handle.onerror = event => worker.die(new Error(event.message || "WebAssembly worker error")); + } else { + const {Worker: NodeWorker} = require_empty_module(); + handle = new NodeWorker(WORKER_SOURCE, { + eval: true + }); + handle.on("message", onMessage); + handle.on("error", error => worker.die(error)); + handle.on("exit", code => { + worker.die(new Error(`WebAssembly worker exited with code ${code}`)); + }); + handle.unref(); + } + worker.handle = handle; + return worker; + } + _worker(index) { + while (this.workers.length <= index) this.workers.push(this._spawn()); + if (this.workers[index].dead) this.workers[index] = this._spawn(); + return this.workers[index]; + } + _updateRef(worker) { + if (worker.dead || !worker.handle || typeof worker.handle.ref !== "function") return; + if (worker.state.settingUp.size + worker.state.pending.size > 0) worker.handle.ref(); else worker.handle.unref(); + } + _ensureSetup(worker, entry) { + if (worker.state.setup.has(entry.id)) return Promise.resolve(); + let wait = worker.state.settingUp.get(entry.id); + if (!wait) { + wait = {}; + wait.promise = new Promise((resolve, reject) => { + wait.resolve = resolve; + wait.reject = reject; + }); + worker.state.settingUp.set(entry.id, wait); + this._updateRef(worker); + worker.handle.postMessage({ + type: "setup", + id: entry.id, + module: entry.module, + memory: entry.memory, + mathImports: entry.mathImports, + sizeX: entry.sizeX + }); + } + return wait.promise; + } + dispatch(entry, tasks) { + if (this.destroyed) return Promise.reject(new Error("WebAssembly worker pool has been destroyed")); + this.dispatchCount++; + this.lastDispatch = { + workerCount: tasks.length, + ranges: tasks.map(task => [ task.start, task.end ]) + }; + const runs = tasks.map((task, index) => { + const worker = this._worker(index); + return this._ensureSetup(worker, entry).then(() => new Promise((resolve, reject) => { + if (worker.dead) { + reject(new Error("WebAssembly worker died before the task could run")); + return; + } + const taskId = ++this._taskId; + worker.state.pending.set(taskId, { + resolve: resolve, + reject: reject + }); + this._updateRef(worker); + worker.handle.postMessage({ + type: "run", + id: entry.id, + taskId: taskId, + start: task.start, + end: task.end, + seed: task.seed + }); + })); + }); + return Promise.all(runs).then(() => void 0); + } + release(entryId) { + if (this.destroyed) return; + for (const worker of this.workers) { + if (worker.dead) continue; + worker.state.setup.delete(entryId); + const wait = worker.state.settingUp.get(entryId); + if (wait) { + worker.state.settingUp.delete(entryId); + wait.reject(new Error("WebAssembly kernel entry released during setup")); + this._updateRef(worker); + } + worker.handle.postMessage({ + type: "release", + id: entryId + }); + } + } + destroy() { + if (this.destroyed) return; + this.destroyed = true; + const error = new Error("WebAssembly worker pool has been destroyed"); + for (const worker of this.workers) { + worker.dead = true; + worker.fail(error); + worker.handle.terminate(); + } + this.workers = []; + } + }; + module.exports = { + WebAssemblyWorkerPool: WebAssemblyWorkerPool + }; + }); + var require_kernel = __commonJSMin((exports, module) => { + const {Kernel: Kernel} = require_kernel$7(); + const {FunctionBuilder: FunctionBuilder} = require_function_builder(); + const {WebAssemblyFunctionNode: WebAssemblyFunctionNode} = require_function_node(); + const {WasmModuleBuilder: WasmModuleBuilder} = require_wasm_builder(); + const {WebAssemblyWorkerPool: WebAssemblyWorkerPool} = require_worker_pool(); + const {utils: utils} = require_utils(); + const {Input: Input} = require_input(); + const features = Object.freeze({ + kernelMap: false, + isIntegerDivisionAccurate: true, + isSpeedTacticSupported: false, + isTextureFloat: true, + isDrawBuffers: false, + kernelMapSize: 0, + channelCount: 1, + maxTextureSize: Infinity, + isFloatRead: true + }); + const PAGE_BYTES = 65536; + let simdSupported = null; + let threadsSupported = null; + let nextEntryId = 1; + module.exports = { + WebAssemblyKernel: class WebAssemblyKernel extends Kernel { + static get isSupported() { + if (typeof WebAssembly !== "object" || WebAssembly === null) return false; + return WebAssembly.validate(new Uint8Array([ 0, 97, 115, 109, 1, 0, 0, 0 ])); + } + static get isSIMDSupported() { + if (simdSupported === null) try { + const builder = new WasmModuleBuilder; + builder.addFunction("t", { + params: [], + results: [] + }).v128ConstI32x4(0, 0, 0, 0).drop(); + simdSupported = WebAssembly.validate(builder.toBytes()); + } catch (e) { + simdSupported = false; + } + return simdSupported; + } + static get isThreadsSupported() { + if (threadsSupported === null) try { + if (typeof SharedArrayBuffer === "undefined") threadsSupported = false; else { + const builder = new WasmModuleBuilder; + builder.addMemoryImport(1, 1, true); + const memory = new WebAssembly.Memory({ + initial: 1, + maximum: 1, + shared: true + }); + new WebAssembly.Instance(new WebAssembly.Module(builder.toBytes()), { + env: { + memory: memory + } + }); + threadsSupported = true; + } + } catch (e) { + threadsSupported = false; + } + return threadsSupported; + } + static isContextMatch(context) { + return false; + } + static getFeatures() { + return features; + } + static get features() { + return features; + } + static get mode() { + return "webasm"; + } + static getSignature(kernel, argumentTypes) { + return "webasm" + (argumentTypes.length > 0 ? ":" + argumentTypes.join(",") : ""); + } + static destroyContext(context) {} + static nativeFunctionArguments() { + throw new Error("WebAssembly backend does not yet support native functions"); + } + static nativeFunctionReturnType() { + throw new Error("WebAssembly backend does not yet support native functions"); + } + static combineKernels() { + throw new Error("WebAssembly backend does not yet support combineKernels"); + } + constructor(source, settings) { + super(source, settings); + this.poolSize = null; + this.mergeSettings(source.settings || settings); + if (this.precision === null) this.precision = "single"; + this.threadDim = null; + this.componentCount = 1; + this.moduleCacheLimit = 8; + this.functionBuilder = null; + this.tracedFunctions = null; + this.usesRandom = false; + this.usedMathImports = null; + this._moduleCache = new Map; + this._active = null; + this._lastRunPath = null; + this._pool = null; + this._threadedTail = Promise.resolve(); + } + initCanvas() { + if (this.graphical && typeof document !== "undefined") return document.createElement("canvas"); + return null; + } + initContext() { + return null; + } + initPlugins(settings) { + return []; + } + setOutput(output) { + const newOutput = this.toKernelOutput(output); + if (this.built && !this.dynamicOutput) throw new Error("Resizing a kernel with dynamicOutput: false is not possible"); + this.output = newOutput; + return this; + } + toString() { + throw new Error("WebAssembly backend does not yet support toString"); + } + build() { + if (this.built) return; + if (this.gpu && this.gpu.kernels && this.gpu.kernels.indexOf(this) === -1) this.gpu.kernels.push(this); + if (this.graphical) return this.requestFallback(arguments, "graphical mode is not supported on the webasm backend"); + if (this.subKernels && this.subKernels.length > 0) return this.requestFallback(arguments, "kernel maps are not supported on the webasm backend"); + this.setupConstants(); + this.setupArguments(arguments); + for (let i = 0; i < this.argumentTypes.length; i++) switch (this.argumentTypes[i]) { + case "Array": + case "Input": + case "Number": + case "Float": + case "Integer": + case "Boolean": + continue; + + default: + return this.requestFallback(arguments, `argument "${this.argumentNames[i]}" of type ${this.argumentTypes[i]} is not supported on the webasm backend`); + } + for (const name in this.constantTypes) switch (this.constantTypes[name]) { + case "Array": + case "Input": + case "Number": + case "Float": + case "Integer": + case "Boolean": + continue; + + default: + return this.requestFallback(arguments, `constant "${name}" of type ${this.constantTypes[name]} is not supported on the webasm backend`); + } + this.validateSettings(arguments); + const threadDim = this.threadDim = Array.from(this.output); + while (threadDim.length < 3) threadDim.push(1); + if (!this.translateSource()) return this.requestFallback(arguments, `return type ${this.returnType} is not supported on the webasm backend`); + this.buildSignature(arguments); + this._instantiate(this._entryKey(arguments), arguments); + this.built = true; + } + validateSettings(args) { + if (!this.output || this.output.length === 0) { + if (args.length !== 1) throw new Error("Auto output only supported for kernels with only one input"); + const argType = utils.getVariableType(args[0], this.strictIntegers); + if (argType === "Array") this.output = Array.from(utils.getDimensions(args[0])); else throw new Error("Auto output not supported for input type: " + argType); + } + this.checkOutput(); + } + translateSource() { + const functionBuilder = this.functionBuilder = FunctionBuilder.fromKernel(this, WebAssemblyFunctionNode); + this.tracedFunctions = functionBuilder.traceFunctionCalls("kernel", []); + if (!this.returnType) this.returnType = functionBuilder.getKernelResultType(); + switch (this.returnType) { + case "Number": + case "Float": + case "Integer": + case "LiteralInteger": + this.componentCount = 1; + break; + + case "Array(2)": + this.componentCount = 2; + break; + + case "Array(3)": + this.componentCount = 3; + break; + + case "Array(4)": + this.componentCount = 4; + break; + + default: + return false; + } + this.usesRandom = false; + this.usedMathImports = new Set; + for (const name of this.tracedFunctions) { + const node = functionBuilder.functionMap[name]; + if (!node) continue; + if (node.usesRandom) this.usesRandom = true; + for (const importName of node.usedMathImports) this.usedMathImports.add(importName); + } + return true; + } + computeLayout(args) { + const align16 = value => Math.ceil(value / 16) * 16; + let offset = 0; + const arrays = {}; + const scalars = {}; + for (let i = 0; i < this.argumentTypes.length; i++) { + const name = this.argumentNames[i]; + const type = this.argumentTypes[i]; + if (type === "Array" || type === "Input") { + const dims = this.valueDimensions(args[i]); + const flatLength = dims[0] * dims[1] * dims[2]; + arrays[name] = { + index: i, + offset: offset, + dims: dims, + flatLength: flatLength + }; + offset = align16(offset + flatLength * 4); + } else { + scalars[name] = { + index: i, + offset: offset, + type: type + }; + offset = align16(offset + 4); + } + } + const constantArrays = {}; + if (this.constants) for (const name in this.constants) { + if (!this.constants.hasOwnProperty(name)) continue; + const type = this.constantTypes[name]; + if (type === "Array" || type === "Input") { + const dims = this.valueDimensions(this.constants[name]); + const flatLength = dims[0] * dims[1] * dims[2]; + constantArrays[name] = { + offset: offset, + dims: dims, + flatLength: flatLength + }; + offset = align16(offset + flatLength * 4); + } + } + return { + arrays: arrays, + scalars: scalars, + constantArrays: constantArrays, + outputOffset: offset + }; + } + valueDimensions(value) { + const dims = value instanceof Input ? Array.from(value.size) : Array.from(utils.getDimensions(value)); + while (dims.length < 3) dims.push(1); + return dims; + } + _computeSizeSignature(args) { + const parts = [ this.output.join("x") ]; + for (let i = 0; i < this.argumentTypes.length; i++) { + const type = this.argumentTypes[i]; + if (type === "Array" || type === "Input") parts.push(this.valueDimensions(args[i]).join("x")); + } + return parts.join("|"); + } + _threadable() { + if (this.asyncMode !== true || !WebAssemblyKernel.isThreadsSupported) return false; + const [tx, ty, tz] = this.threadDim; + return tx * ty * tz >= 4096; + } + _entryKey(args) { + return this._computeSizeSignature(args) + (this._threadable() ? "|shared" : ""); + } + _assembleModule(layout, cells, shared) { + const builder = new WasmModuleBuilder; + const totalBytes = layout.outputOffset + cells * this.componentCount * 4; + const initial = Math.ceil(totalBytes / PAGE_BYTES) + 16; + const maximum = Math.max(initial, 4096); + builder.addMemoryImport(initial, maximum, shared); + const mathImports = Array.from(this.usedMathImports).sort(); + for (const name of mathImports) { + const params = name === "pow" || name === "atan2" ? [ "f32", "f32" ] : [ "f32" ]; + builder.addFuncImport("math_" + name, params, [ "f32" ]); + } + const globals = { + threadX: builder.addGlobal("i32", true, 0), + threadY: builder.addGlobal("i32", true, 0), + threadZ: builder.addGlobal("i32", true, 0), + dataIndex: builder.addGlobal("i32", true, 0) + }; + if (this.usesRandom) { + globals.pcgState = builder.addGlobal("i32", true, 0); + this._emitPcgRandom(builder, globals.pcgState); + } + const assembler = { + module: builder, + layout: layout, + globals: globals + }; + for (let i = this.tracedFunctions.length - 1; i >= 0; i--) { + const name = this.tracedFunctions[i]; + if (name === "kernel") continue; + const node = this.functionBuilder.functionMap[name]; + if (!node) continue; + node.output = this.output; + node.emitFunction(assembler); + } + this.functionBuilder.functionMap["kernel"].output = this.output; + this.functionBuilder.functionMap["kernel"].emitFunction(assembler); + const [sizeX, sizeY] = this.threadDim; + const run = builder.addFunction("run", { + params: [ "i32", "i32", "i32" ], + locals: [ "i32" ] + }); + const cell = 3; + run.localGet(0).localSet(cell); + if (this.output.length === 1) { + run.i32Const(0).globalSet(globals.threadY); + run.i32Const(0).globalSet(globals.threadZ); + } else if (this.output.length === 2) run.i32Const(0).globalSet(globals.threadZ); + run.block(); + run.localGet(cell).localGet(1).i32GeS().brIf(0); + run.loop(); + run.localGet(cell).globalSet(globals.dataIndex); + if (this.output.length === 1) run.localGet(cell).globalSet(globals.threadX); else if (this.output.length === 2) { + run.localGet(cell).i32Const(sizeX).i32RemU().globalSet(globals.threadX); + run.localGet(cell).i32Const(sizeX).i32DivU().globalSet(globals.threadY); + } else { + run.localGet(cell).i32Const(sizeX).i32RemU().globalSet(globals.threadX); + run.localGet(cell).i32Const(sizeX).i32DivU().i32Const(sizeY).i32RemU().globalSet(globals.threadY); + run.localGet(cell).i32Const(sizeX * sizeY).i32DivU().globalSet(globals.threadZ); + } + if (this.usesRandom) run.localGet(2).localGet(cell).i32Const(-1640531527).i32Mul().i32Add().i32Const(747796405).i32Mul().i32Const(-1403630843).i32Add().globalSet(globals.pcgState); + run.call("kernel"); + run.localGet(cell).i32Const(1).i32Add().localSet(cell); + run.localGet(cell).localGet(1).i32LtS().brIf(0); + run.end(); + run.end(); + builder.exportFunction("run"); + if (WebAssemblyKernel.isSIMDSupported) { + if (this.usesRandom) { + globals.pcgStateV = builder.addGlobal("v128", true, 0); + this._emitPcgRandomVector(builder, globals.pcgStateV); + } + let helperInfo = null; + for (const name of this.tracedFunctions) { + if (name === "kernel") continue; + const node = this.functionBuilder.functionMap[name]; + if (!node) continue; + if (!helperInfo) helperInfo = { + readsThread: false, + usesRandom: false + }; + if (node.readsThread) helperInfo.readsThread = true; + if (node.usesRandom) helperInfo.usesRandom = true; + } + assembler.helperInfo = helperInfo; + this.functionBuilder.functionMap["kernel"].emitVectorFunction(assembler); + this._emitRunSimd(builder, globals); + builder.exportFunction("run_simd"); + } + return { + bytes: builder.toBytes(), + initial: initial, + maximum: maximum + }; + } + _emitRunSimd(builder, globals) { + const [sizeX, sizeY] = this.threadDim; + const run = builder.addFunction("run_simd", { + params: [ "i32", "i32", "i32" ], + locals: [ "i32" ] + }); + const cell = 3; + run.localGet(0).localSet(cell); + if (this.output.length === 1) { + run.i32Const(0).globalSet(globals.threadY); + run.i32Const(0).globalSet(globals.threadZ); + } else if (this.output.length === 2) run.i32Const(0).globalSet(globals.threadZ); + run.block(); + run.localGet(cell).localGet(1).i32GeS().brIf(0); + run.loop(); + run.localGet(cell).globalSet(globals.dataIndex); + if (this.output.length === 1) run.localGet(cell).globalSet(globals.threadX); else if (this.output.length === 2) { + run.localGet(cell).i32Const(sizeX).i32RemU().globalSet(globals.threadX); + run.localGet(cell).i32Const(sizeX).i32DivU().globalSet(globals.threadY); + } else { + run.localGet(cell).i32Const(sizeX).i32RemU().globalSet(globals.threadX); + run.localGet(cell).i32Const(sizeX).i32DivU().i32Const(sizeY).i32RemU().globalSet(globals.threadY); + run.localGet(cell).i32Const(sizeX * sizeY).i32DivU().globalSet(globals.threadZ); + } + if (this.usesRandom) { + run.localGet(cell).i32x4Splat().v128ConstI32x4(0, 1, 2, 3).i32x4Add(); + run.v128ConstI32x4(-1640531527, -1640531527, -1640531527, -1640531527).i32x4Mul(); + run.localGet(2).i32x4Splat().i32x4Add(); + run.v128ConstI32x4(747796405, 747796405, 747796405, 747796405).i32x4Mul(); + run.v128ConstI32x4(-1403630843, -1403630843, -1403630843, -1403630843).i32x4Add(); + run.globalSet(globals.pcgStateV); + } + run.call("kernel_simd"); + run.localGet(cell).i32Const(4).i32Add().localSet(cell); + run.localGet(cell).localGet(1).i32LtS().brIf(0); + run.end(); + run.end(); + } + _emitPcgRandomVector(builder, stateGlobal) { + const em = builder.addFunction("pcg_random_v", { + params: [ "v128" ], + results: [ "v128" ] + }); + const s = em.addLocal("v128"); + const w = em.addLocal("i32"); + em.globalGet(stateGlobal).v128ConstI32x4(747796405, 747796405, 747796405, 747796405).i32x4Mul().v128ConstI32x4(-1403630843, -1403630843, -1403630843, -1403630843).i32x4Add().globalGet(stateGlobal).localGet(0).v128Bitselect().globalSet(stateGlobal); + em.globalGet(stateGlobal).localSet(s); + em.localGet(s).i32x4ExtractLane(0).localSet(w); + em.localGet(w).localGet(w).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU().i32x4Splat(); + for (let lane = 1; lane < 4; lane++) { + em.localGet(s).i32x4ExtractLane(lane).localSet(w); + em.localGet(w).localGet(w).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU().i32x4ReplaceLane(lane); + } + em.localGet(s).v128Xor(); + em.v128ConstI32x4(277803737, 277803737, 277803737, 277803737).i32x4Mul(); + const wv = em.addLocal("v128"); + em.localTee(wv); + em.i32Const(22).i32x4ShrU().localGet(wv).v128Xor(); + em.i32Const(8).i32x4ShrU(); + em.f32x4ConvertI32x4U(); + em.v128ConstF32x4(16777216, 16777216, 16777216, 16777216).f32x4Div(); + } + _emitPcgRandom(builder, stateGlobal) { + const em = builder.addFunction("pcg_random", { + params: [], + results: [ "f32" ] + }); + const word = em.addLocal("i32"); + em.globalGet(stateGlobal).i32Const(747796405).i32Mul().i32Const(-1403630843).i32Add().globalSet(stateGlobal); + em.globalGet(stateGlobal).globalGet(stateGlobal).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU().globalGet(stateGlobal).i32Xor().i32Const(277803737).i32Mul().localTee(word); + em.i32Const(22).i32ShrU().localGet(word).i32Xor().i32Const(8).i32ShrU().f32ConvertI32U().f32Const(16777216).f32Div(); + } + _releaseEntry(entry) { + const scrub = () => { + entry.instance = null; + entry.module = null; + entry.memory = null; + entry.run = null; + entry.runSimd = null; + entry.f32 = null; + entry.i32 = null; + entry.bytes = null; + }; + if (entry.shared && this._pool) { + const pool = this._pool; + this._threadedTail.then(() => { + pool.release(entry.id); + scrub(); + }, scrub); + } else scrub(); + } + _instantiate(entryKey, args) { + let entry = this._moduleCache.get(entryKey); + if (entry) { + this._moduleCache.delete(entryKey); + this._moduleCache.set(entryKey, entry); + } + if (!entry) { + const shared = this._threadable(); + const layout = this.computeLayout(args); + const [tx, ty, tz] = this.threadDim; + const cells = tx * ty * tz; + const {bytes: bytes, initial: initial, maximum: maximum} = this._assembleModule(layout, cells, shared); + if (!WebAssembly.validate(bytes)) throw new Error("WebAssembly backend: generated module failed validation (internal error)"); + const memory = shared ? new WebAssembly.Memory({ + initial: initial, + maximum: maximum, + shared: true + }) : new WebAssembly.Memory({ + initial: initial, + maximum: maximum + }); + const imports = { + env: { + memory: memory + } + }; + for (const name of this.usedMathImports) imports.env["math_" + name] = Math[name]; + const module$1 = new WebAssembly.Module(bytes); + const instance = new WebAssembly.Instance(module$1, imports); + entry = { + id: nextEntryId++, + sizeSignature: entryKey, + shared: shared, + layout: layout, + cells: cells, + bytes: bytes, + module: module$1, + memory: memory, + mathImports: Array.from(this.usedMathImports).sort(), + sizeX: tx, + instance: instance, + run: instance.exports.run, + runSimd: instance.exports.run_simd || null, + f32: new Float32Array(memory.buffer), + i32: new Int32Array(memory.buffer) + }; + for (const name in layout.constantArrays) { + const record = layout.constantArrays[name]; + const value = this.constants[name]; + utils.flattenTo(value instanceof Input ? value.value : value, entry.f32.subarray(record.offset / 4, record.offset / 4 + record.flatLength)); + } + this._moduleCache.set(entryKey, entry); + while (this._moduleCache.size > Math.max(this.moduleCacheLimit, 1)) { + const oldestKey = this._moduleCache.keys().next().value; + const oldest = this._moduleCache.get(oldestKey); + this._moduleCache.delete(oldestKey); + this._releaseEntry(oldest); + } + } + this._active = entry; + } + checkArgumentTypes(args) { + super.checkArgumentTypes(args); + if (!this.argumentTypes) return; + const length = Math.min(args.length, this.argumentTypes.length); + for (let i = 0; i < length; i++) { + const value = args[i]; + if (!value || !value.type) continue; + switch (this.argumentTypes[i]) { + case "Array": + case "Input": + case "Number": + case "Float": + case "Integer": + case "Boolean": + this.switchKernels({ + type: "argumentTypeMismatch", + index: i, + needed: utils.getVariableType(value, this.strictIntegers) + }); + break; + } + } + } + run() { + if (!this.built) { + this.build.apply(this, arguments); + if (this.fallbackRequested) return null; + } + const threadDim = this.threadDim = Array.from(this.output); + while (threadDim.length < 3) threadDim.push(1); + const entryKey = this._entryKey(arguments); + if (!this._active || this._active.sizeSignature !== entryKey) { + const previous = this._active ? this._active.layout.arrays : {}; + for (const name in previous) { + const record = previous[name]; + const dims = this.valueDimensions(arguments[record.index]); + if (!this.dynamicArguments && (dims[0] !== record.dims[0] || dims[1] !== record.dims[1] || dims[2] !== record.dims[2])) throw new Error(`argument "${name}" changed size from [${record.dims.join(", ")}] to [${dims.join(", ")}]; use dynamicArguments: true for varying input sizes`); + } + this._instantiate(entryKey, arguments); + } + if (this._active.shared && this._threadable()) return this._runThreaded(arguments); + const {layout: layout, cells: cells, f32: f32, i32: i32, run: run, runSimd: runSimd} = this._active; + for (const name in layout.arrays) { + const record = layout.arrays[name]; + const value = arguments[record.index]; + utils.flattenTo(value instanceof Input ? value.value : value, f32.subarray(record.offset / 4, record.offset / 4 + record.flatLength)); + } + for (const name in layout.scalars) { + const record = layout.scalars[name]; + const value = arguments[record.index]; + if (record.type === "Integer") i32[record.offset / 4] = value | 0; else if (record.type === "Boolean") i32[record.offset / 4] = value ? 1 : 0; else f32[record.offset / 4] = value; + } + let seed = 0; + if (this.usesRandom) seed = this.randomSeed !== null ? this.randomSeed >>> 0 : Math.random() * 4294967296 >>> 0; + seed = seed | 0; + if (runSimd && cells > 0) { + const sizeX = threadDim[0]; + if ((sizeX & 3) === 0) { + runSimd(0, cells, seed); + this._lastRunPath = "simd"; + } else { + const quadSpan = sizeX & -4; + const rows = cells / sizeX; + for (let row = 0; row < rows; row++) { + const base = row * sizeX; + if (quadSpan > 0) runSimd(base, base + quadSpan, seed); + run(base + quadSpan, base + sizeX, seed); + } + this._lastRunPath = quadSpan > 0 ? "simd+scalar-tail" : "scalar"; + } + } else { + run(0, cells, seed); + this._lastRunPath = "scalar"; + } + const base = layout.outputOffset / 4; + const data = f32.slice(base, base + cells * this.componentCount); + return this._shapeOutput(data, Array.from(this.output), this.componentCount); + } + _runThreaded(args) { + const entry = this._active; + const {layout: layout, cells: cells} = entry; + const staged = []; + for (const name in layout.arrays) { + const record = layout.arrays[name]; + const value = args[record.index]; + const flat = new Float32Array(record.flatLength); + utils.flattenTo(value instanceof Input ? value.value : value, flat); + staged.push({ + record: record, + flat: flat + }); + } + const scalarValues = []; + for (const name in layout.scalars) { + const record = layout.scalars[name]; + scalarValues.push({ + record: record, + value: args[record.index] + }); + } + let seed = 0; + if (this.usesRandom) seed = this.randomSeed !== null ? this.randomSeed >>> 0 : Math.random() * 4294967296 >>> 0; + seed = seed | 0; + if (!this._pool) this._pool = new WebAssemblyWorkerPool(this.poolSize || void 0); + const pool = this._pool; + const componentCount = this.componentCount; + const output = Array.from(this.output); + const result = this._threadedTail.then(() => { + if (!entry.f32) throw new Error("WebAssembly kernel was destroyed"); + for (let i = 0; i < staged.length; i++) entry.f32.set(staged[i].flat, staged[i].record.offset / 4); + for (let i = 0; i < scalarValues.length; i++) { + const {record: record, value: value} = scalarValues[i]; + if (record.type === "Integer") entry.i32[record.offset / 4] = value | 0; else if (record.type === "Boolean") entry.i32[record.offset / 4] = value ? 1 : 0; else entry.f32[record.offset / 4] = value; + } + const workerCount = Math.min(pool.size, Math.ceil(cells / 4096)); + let chunk = Math.ceil(cells / workerCount) & -4; + if (chunk < 4) chunk = 4; + const tasks = []; + for (let i = 0; i < workerCount; i++) { + const start = i * chunk; + if (start >= cells) break; + tasks.push({ + start: start, + end: i === workerCount - 1 ? cells : Math.min(start + chunk, cells), + seed: seed + }); + } + this._lastRunPath = "threaded"; + return pool.dispatch(entry, tasks).then(() => { + if (!entry.f32) throw new Error("WebAssembly kernel was destroyed"); + const base = layout.outputOffset / 4; + const data = entry.f32.slice(base, base + cells * componentCount); + return this._shapeOutput(data, output, componentCount); + }); + }); + this._threadedTail = result.then(() => void 0, () => void 0); + return result; + } + _shapeOutput(data, output, componentCount) { + const [width, height, depth] = [ output[0], output[1] || 1, output[2] || 1 ]; + if (componentCount === 1) switch (output.length) { + case 1: + return utils.erectMemoryOptimizedFloat(data, width); + + case 2: + return utils.erectMemoryOptimized2DFloat(data, width, height); + + default: + return utils.erectMemoryOptimized3DFloat(data, width, height, depth); + } + const n = componentCount; + const erectRow = offset => { + const row = new Array(width); + for (let x = 0; x < width; x++) row[x] = data.subarray(offset + x * n, offset + x * n + n); + return row; + }; + switch (output.length) { + case 1: + return erectRow(0); + + case 2: + { + const rows = new Array(height); + for (let y = 0; y < height; y++) rows[y] = erectRow(y * width * n); + return rows; + } + + default: + { + const layers = new Array(depth); + for (let z = 0; z < depth; z++) { + const rows = new Array(height); + for (let y = 0; y < height; y++) rows[y] = erectRow((z * height + y) * width * n); + layers[z] = rows; + } + return layers; + } + } + } + destroy(removeCanvasReferences) { + if (this._pool) { + this._pool.destroy(); + this._pool = null; + } + this._threadedTail = Promise.resolve(); + for (const entry of this._moduleCache.values()) { + entry.shared = false; + this._releaseEntry(entry); + } + this._moduleCache = new Map; + this._active = null; + this.built = false; + if (this.gpu && this.gpu.kernels) { + const index = this.gpu.kernels.indexOf(this); + if (index !== -1) this.gpu.kernels.splice(index, 1); + } + } + } + }; + }); + var require_kernel_run_shortcut = __commonJSMin((exports, module) => { + const {utils: utils} = require_utils(); + const {Input: Input} = require_input(); + function kernelRunShortcut(kernel) { + const MAX_SWITCHES = 4; + function syncBody(args) { + kernel.build.apply(kernel, args); + kernel.checkArgumentTypes(args); + let result = kernel.switchingKernels ? void 0 : kernel.run.apply(kernel, args); + for (let i = 0; kernel.switchingKernels; i++) { + if (i >= MAX_SWITCHES) { + const reasons = kernel.resetSwitchingKernels(); + throw new Error(`this kernel cannot run the arguments it was given (${describeReasons(reasons)}); it did not settle on a kernel for them after ${MAX_SWITCHES} attempts. Create a separate kernel for this call's argument types.`); + } + const reasons = kernel.resetSwitchingKernels(); + const newKernel = kernel.onRequestSwitchKernel(reasons, args, kernel); + shortcut.kernel = kernel = newKernel; + newKernel.checkArgumentTypes(args); + result = newKernel.switchingKernels ? void 0 : newKernel.run.apply(newKernel, args); + if (newKernel.fallbackRequested) result = kernel.run.apply(kernel, args); + } + return result; + } + function describeReasons(reasons) { + if (!reasons || !reasons.length) return "unknown reason"; + return reasons.map(reason => { + if (reason.type === "argumentTypeMismatch") return `argument ${reason.index} is now ${reason.needed}`; + return reason.type; + }).join(", "); + } + function syncRun(args) { + const result = syncBody(args); + if (kernel.renderKernels) return kernel.renderKernels(); else if (kernel.renderOutput) return kernel.renderOutput(); else return result; + } + function asyncRun(args) { + if (kernel.onAsyncModeUpgrade) { + const upgrade = kernel.onAsyncModeUpgrade; + kernel.onAsyncModeUpgrade = null; + const snapped = snapshotArguments(args); + return upgrade(snapped, kernel).then(upgradedKernel => { + if (upgradedKernel) shortcut.replaceKernel(upgradedKernel); + return asyncRun(snapped); + }); + } + try { + if (kernel.constructor.isAsync === true) { + kernel.build.apply(kernel, args); + return Promise.resolve(kernel.run.apply(kernel, args)); + } + for (let i = 0; i < args.length; i++) if (isWebGPUHandle(args[i])) return resolveHandles(args).then(resolved => asyncRun(resolved)); + const result = syncBody(args); + if (kernel.renderKernels) return Promise.resolve(kernel.renderKernels()); else if (kernel.renderOutput) { + if (kernel.renderOutputAsync) return kernel.renderOutputAsync(); + return Promise.resolve(kernel.renderOutput()); + } else return Promise.resolve(result); + } catch (e) { + return Promise.reject(e); + } + } + function isWebGPUHandle(value) { + return Boolean(value) && value.type === "WebGPUBuffer"; + } + function resolveHandles(args) { + const snapped = snapshotArguments(args); + const pending = []; + for (let i = 0; i < snapped.length; i++) if (isWebGPUHandle(snapped[i])) { + const index = i; + pending.push(Promise.resolve(snapped[index].toArray()).then(value => { + snapped[index] = value; + })); + } + return Promise.all(pending).then(() => snapped); + } + function snapshotArguments(args) { + const copy = new Array(args.length); + for (let i = 0; i < args.length; i++) copy[i] = snapshotValue(args[i]); + return copy; + } + function snapshotValue(value) { + if (!value || typeof value !== "object") return value; + if (isWebGPUHandle(value) || typeof value.delete === "function") return value; + if (ArrayBuffer.isView(value)) return value.slice(0); + if (Array.isArray(value)) return value.map(snapshotValue); + if (value instanceof Input) return new Input(snapshotValue(value.value), value.size); + return value; + } + function run() { + if (kernel.constructor.isAsync === true || kernel.asyncMode === true) return asyncRun(arguments); + return syncRun(arguments); + } + const shortcut = function() { + return run.apply(kernel, arguments); + }; + shortcut.exec = function() { + return new Promise((accept, reject) => { + try { + accept(run.apply(this, arguments)); + } catch (e) { + reject(e); + } + }); + }; + shortcut.replaceKernel = function(replacementKernel) { + kernel = replacementKernel; + bindKernelToShortcut(kernel, shortcut); + }; + bindKernelToShortcut(kernel, shortcut); + return shortcut; + } + function bindKernelToShortcut(kernel, shortcut) { + if (shortcut.kernel) { + shortcut.kernel = kernel; + return; + } + const properties = utils.allPropertiesOf(kernel); + for (let i = 0; i < properties.length; i++) { + const property = properties[i]; + if (property[0] === "_" && property[1] === "_") continue; + if (typeof kernel[property] === "function") if (property.substring(0, 3) === "add" || property.substring(0, 3) === "set") shortcut[property] = function() { + shortcut.kernel[property].apply(shortcut.kernel, arguments); + return shortcut; + }; else shortcut[property] = function() { + return shortcut.kernel[property].apply(shortcut.kernel, arguments); + }; else { + shortcut.__defineGetter__(property, () => shortcut.kernel[property]); + shortcut.__defineSetter__(property, value => { + shortcut.kernel[property] = value; + }); + } + } + shortcut.kernel = kernel; + } + module.exports = { + kernelRunShortcut: kernelRunShortcut + }; + }); + var require_gpu = __commonJSMin((exports, module) => { + const {gpuMock: gpuMock} = require_gpu_mock_js(); + const {utils: utils} = require_utils(); + const {Kernel: Kernel} = require_kernel$7(); + const {CPUKernel: CPUKernel} = require_kernel$6(); + const {HeadlessGLKernel: HeadlessGLKernel} = require_kernel$3(); + const {WebGL2Kernel: WebGL2Kernel} = require_kernel$2(); + const {WebGLKernel: WebGLKernel} = require_kernel$4(); + const {WebGPUKernel: WebGPUKernel} = require_kernel$1(); + const {WebAssemblyKernel: WebAssemblyKernel} = require_kernel(); + const {kernelRunShortcut: kernelRunShortcut} = require_kernel_run_shortcut(); + const kernelOrder = [ HeadlessGLKernel, WebGL2Kernel, WebGLKernel, WebAssemblyKernel ]; + const kernelTypes = [ "gpu", "cpu" ]; + const internalKernels = { + headlessgl: HeadlessGLKernel, + webgl2: WebGL2Kernel, + webgl: WebGLKernel, + webgpu: WebGPUKernel, + webasm: WebAssemblyKernel + }; + let validate = true; + var GPU = class GPU { + static disableValidation() { + validate = false; + } + static enableValidation() { + validate = true; + } + static get isGPUSupported() { + return kernelOrder.some(Kernel => Kernel.isSupported); + } + static get isKernelMapSupported() { + return kernelOrder.some(Kernel => Kernel.isSupported && Kernel.features.kernelMap); + } + static get isOffscreenCanvasSupported() { + return typeof Worker !== "undefined" && typeof OffscreenCanvas !== "undefined" || typeof importScripts !== "undefined"; + } + static get isWebGLSupported() { + return WebGLKernel.isSupported; + } + static get isWebGL2Supported() { + return WebGL2Kernel.isSupported; + } + static get isHeadlessGLSupported() { + return HeadlessGLKernel.isSupported; + } + static get isWebGPUSupported() { + return WebGPUKernel.isSupported; + } + static isWebGPUAvailable() { + if (!WebGPUKernel.isSupported) return Promise.resolve(false); + return navigator.gpu.requestAdapter().then(adapter => adapter !== null, () => false); + } + static get isWebAssemblySupported() { + return WebAssemblyKernel.isSupported; + } + static get isCanvasSupported() { + return typeof HTMLCanvasElement !== "undefined"; + } + static get isGPUHTMLImageArraySupported() { + return WebGL2Kernel.isSupported; + } + static get isSinglePrecisionSupported() { + return kernelOrder.some(Kernel => Kernel.isSupported && Kernel.features.isFloatRead && Kernel.features.isTextureFloat); + } + constructor(settings) { + settings = settings || {}; + this.canvas = settings.canvas || null; + this.context = settings.context || null; + this.mode = settings.mode; + this.Kernel = null; this._webGPUDecision = null; if (settings.mode === "async") if (WebGPUKernel.isSupported) GPU.isWebGPUAvailable().then(available => { this._webGPUDecision = available; @@ -13886,8 +19259,9 @@ const switchableKernels = {}; const settingsCopy = upgradeDeprecatedCreateKernelSettings(settings) || {}; if (settings && typeof settings.argumentTypes === "object") settingsCopy.argumentTypes = Object.keys(settings.argumentTypes).map(argumentName => settings.argumentTypes[argumentName]); + const gpuInstance = this; function onRequestFallback(args) { - console.warn("Falling back to CPU"); + console.warn(`Falling back to CPU${kernelRun.fallbackReason ? `: ${kernelRun.fallbackReason}` : ""}`); const fallbackKernel = new CPUKernel(source, { argumentTypes: kernelRun.argumentTypes, constantTypes: kernelRun.constantTypes, @@ -13909,11 +19283,17 @@ strictIntegers: kernelRun.strictIntegers, randomSeed: kernelRun.randomSeed, debug: kernelRun.debug, - asyncMode: kernelRun.asyncMode + asyncMode: kernelRun.asyncMode, + onRequestFallback: onRequestFallback, + onRequestSwitchKernel: onRequestSwitchKernel, + canvas: kernelRun.graphical && !kernelRun.context ? kernelRun.canvas : null }); + fallbackKernel.fallbackReason = kernelRun.fallbackReason; fallbackKernel.build.apply(fallbackKernel, args); const result = fallbackKernel.run.apply(fallbackKernel, args); kernelRun.replaceKernel(fallbackKernel); + if (!gpuInstance.canvas && fallbackKernel.canvas) gpuInstance.canvas = fallbackKernel.canvas; + if (!gpuInstance.context && fallbackKernel.context) gpuInstance.context = fallbackKernel.context; return result; } function onRequestSwitchKernel(reasons, args, _kernel) { @@ -14067,7 +19447,7 @@ if (this.mode !== "dev") { if (!this.Kernel.isSupported || !this.Kernel.features.kernelMap) { if (this.Kernel.mode === "webgpu") throw new Error("WebGPU backend does not yet support createKernelMap"); - if (this.mode && kernelTypes.indexOf(this.mode) < 0) throw new Error(`kernelMap not supported on ${this.Kernel.name}`); + if (this.mode && kernelTypes.indexOf(this.mode) < 0 && this.Kernel.mode !== "webasm") throw new Error(`kernelMap not supported on ${this.Kernel.name}`); } } const settingsCopy = upgradeDeprecatedCreateKernelSettings(settings); @@ -14207,22 +19587,24 @@ const {Input: Input, input: input} = require_input(); const {Texture: Texture} = require_texture$1(); const {FunctionBuilder: FunctionBuilder} = require_function_builder(); - const {FunctionNode: FunctionNode} = require_function_node$4(); - const {CPUFunctionNode: CPUFunctionNode} = require_function_node$3(); - const {CPUKernel: CPUKernel} = require_kernel$5(); - const {HeadlessGLKernel: HeadlessGLKernel} = require_kernel$2(); - const {WebGLFunctionNode: WebGLFunctionNode} = require_function_node$2(); - const {WebGLKernel: WebGLKernel} = require_kernel$3(); + const {FunctionNode: FunctionNode} = require_function_node$5(); + const {CPUFunctionNode: CPUFunctionNode} = require_function_node$4(); + const {CPUKernel: CPUKernel} = require_kernel$6(); + const {HeadlessGLKernel: HeadlessGLKernel} = require_kernel$3(); + const {WebGLFunctionNode: WebGLFunctionNode} = require_function_node$3(); + const {WebGLKernel: WebGLKernel} = require_kernel$4(); const {kernelValueMaps: webGLKernelValueMaps} = require_kernel_value_maps$1(); - const {WebGL2FunctionNode: WebGL2FunctionNode} = require_function_node$1(); - const {WebGL2Kernel: WebGL2Kernel} = require_kernel$1(); + const {WebGL2FunctionNode: WebGL2FunctionNode} = require_function_node$2(); + const {WebGL2Kernel: WebGL2Kernel} = require_kernel$2(); const {kernelValueMaps: webGL2KernelValueMaps} = require_kernel_value_maps(); - const {WGSLFunctionNode: WGSLFunctionNode} = require_function_node(); - const {WebGPUKernel: WebGPUKernel} = require_kernel(); + const {WGSLFunctionNode: WGSLFunctionNode} = require_function_node$1(); + const {WebGPUKernel: WebGPUKernel} = require_kernel$1(); const {WebGPUContext: WebGPUContext} = require_context(); const {WebGPUBufferResult: WebGPUBufferResult} = require_buffer_result(); - const {GLKernel: GLKernel} = require_kernel$4(); - const {Kernel: Kernel} = require_kernel$6(); + const {WebAssemblyFunctionNode: WebAssemblyFunctionNode} = require_function_node(); + const {WebAssemblyKernel: WebAssemblyKernel} = require_kernel(); + const {GLKernel: GLKernel} = require_kernel$5(); + const {Kernel: Kernel} = require_kernel$7(); const {FunctionTracer: FunctionTracer} = require_function_tracer(); module.exports = { alias: alias, @@ -14246,6 +19628,8 @@ WebGPUKernel: WebGPUKernel, WebGPUContext: WebGPUContext, WebGPUBufferResult: WebGPUBufferResult, + WebAssemblyFunctionNode: WebAssemblyFunctionNode, + WebAssemblyKernel: WebAssemblyKernel, GLKernel: GLKernel, Kernel: Kernel, FunctionTracer: FunctionTracer, diff --git a/dist/gpu-browser-core.min.js b/dist/gpu-browser-core.min.js index 33107460..6b266c83 100644 --- a/dist/gpu-browser-core.min.js +++ b/dist/gpu-browser-core.min.js @@ -5,11 +5,11 @@ * GPU Accelerated JavaScript * * @version 2.21.0 - * @date Mon Aug 03 2026 01:03:16 GMT+0800 (Singapore Standard Time) + * @date Mon Aug 03 2026 09:01:53 GMT+0800 (Singapore Standard Time) * * @license MIT * The MIT License * * Copyright (c) 2026 gpu.js Team */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):(e="undefined"!=typeof globalThis?globalThis:e||self).GPU=t()}(this,function(){var e=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),t=e((e,t)=>{function r(e){const t=new Array(e.length);for(let r=0;r{e.output=l(t),e.graphical&&u(e)},e.toJSON=()=>{throw new Error("Not usable with gpuMock")},e.setConstants=t=>(e.constants=t,e),e.setGraphical=t=>(e.graphical=t,e),e.setCanvas=t=>(e.canvas=t,e),e.setContext=t=>(e.context=t,e),e.destroy=()=>{},e.validateSettings=()=>{},e.graphical&&e.output&&u(e),e.exec=function(){return new Promise((t,r)=>{try{t(e.apply(e,arguments))}catch(e){r(e)}})},e.getPixels=t=>{const{x:r,y:n}=e.output;return t?function(e,t,r){const n=r/2|0,s=4*t,i=new Uint8ClampedArray(4*t),a=e.slice(0);for(let e=0;ee,r=["setWarnVarUsage","setArgumentTypes","setTactic","setOptimizeFloatMemory","setDebug","setLoopMaxIterations","setConstantTypes","setFunctions","setNativeFunctions","setInjectedNative","setPipeline","setPrecision","setOutputToTexture","setImmutable","setStrictIntegers","setDynamicOutput","setHardcodeConstants","setDynamicArguments","setUseLegacyEncoder","setWarnVarUsage","addSubKernel"];for(let n=0;n{t.exports={}}),n=e((e,t)=>{var r=class{constructor(e,t){this.value=e,Array.isArray(t)?this.size=t:(this.size=new Int32Array(3),t.z?this.size=new Int32Array([t.x,t.y,t.z]):t.y?this.size=new Int32Array([t.x,t.y]):this.size=new Int32Array([t.x]));const[r,n,s]=this.size;if(s){if(this.value.length!==r*n*s)throw new Error(`Input size ${this.value.length} does not match ${r} * ${n} * ${s} = ${n*r*s}`)}else if(n){if(this.value.length!==r*n)throw new Error(`Input size ${this.value.length} does not match ${r} * ${n} = ${n*r}`)}else if(this.value.length!==r)throw new Error(`Input size ${this.value.length} does not match ${r}`)}toArray(){const{utils:e}=i(),[t,r,n]=this.size;return n?e.erectMemoryOptimized3DFloat(this.value.subarray?this.value:new Float32Array(this.value),t,r,n):r?e.erectMemoryOptimized2DFloat(this.value.subarray?this.value:new Float32Array(this.value),t,r):this.value}};t.exports={Input:r,input:function(e,t){return new r(e,t)}}}),s=e((e,t)=>{t.exports={Texture:class{constructor(e){const{texture:t,size:r,dimensions:n,output:s,context:i,type:a="NumberTexture",kernel:o,internalFormat:u,textureFormat:l}=e;if(!s)throw new Error('settings property "output" required.');if(!i)throw new Error('settings property "context" required.');if(!t)throw new Error('settings property "texture" required.');if(!o)throw new Error('settings property "kernel" required.');this.texture=t,t._refs?t._refs++:t._refs=1,this.size=r,this.dimensions=n,this.output=s,this.context=i,this.kernel=o,this.type=a,this._deleted=!1,this.internalFormat=u,this.textureFormat=l}toArray(){throw new Error(`Not implemented on ${this.constructor.name}`)}clone(){throw new Error(`Not implemented on ${this.constructor.name}`)}delete(){throw new Error(`Not implemented on ${this.constructor.name}`)}clear(){throw new Error(`Not implemented on ${this.constructor.name}`)}}}}),i=e((e,t)=>{const i=r(),{Input:a}=n(),{Texture:o}=s(),u=/function ([^(]*)/,l=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,h=/([^\s,]+)/g,c={systemEndianness:()=>f,getSystemEndianness(){const e=new ArrayBuffer(4),t=new Uint32Array(e),r=new Uint8Array(e);if(t[0]=3735928559,239===r[0])return"LE";if(222===r[0])return"BE";throw new Error("unknown endianness")},isFunction:e=>"function"==typeof e,isFunctionString:e=>"string"==typeof e&&"function"===e.slice(0,8).toLowerCase(),getFunctionNameFromString(e){const t=u.exec(e);return t&&0!==t.length?t[1].trim():null},getFunctionBodyFromString:e=>e.substring(e.indexOf("{")+1,e.lastIndexOf("}")),getArgumentNamesFromString(e){const t=e.replace(l,"");let r=t.slice(t.indexOf("(")+1,t.indexOf(")")).match(h);return null===r&&(r=[]),r},clone(e){if(null===e||"object"!=typeof e||e.hasOwnProperty("isActiveClone"))return e;const t=e.constructor();for(let r in e)Object.prototype.hasOwnProperty.call(e,r)&&(e.isActiveClone=null,t[r]=c.clone(e[r]),delete e.isActiveClone);return t},isArray:e=>!isNaN(e.length),typeFitsValue(e,t){if("string"!=typeof e||null==t)return!0;if(t.type)return!0;switch(e){case"Input":return t instanceof a;case"Boolean":return"boolean"==typeof t;case"Number":case"Integer":case"Float":return"number"==typeof t}return-1!==e.indexOf("Texture")?Boolean(t.type):0!==e.indexOf("Array")||c.isArray(t)},getVariableType(e,t){if(c.isArray(e))return e.length>0&&"IMG"===e[0].nodeName?"HTMLImageArray":"Array";switch(e.constructor){case Boolean:return"Boolean";case Number:return t&&Number.isInteger(e)?"Integer":"Float";case o:return e.type;case a:return"Input"}if("nodeName"in e)switch(e.nodeName){case"IMG":case"CANVAS":return"HTMLImage";case"VIDEO":return"HTMLVideo"}else{if(e.hasOwnProperty("type"))return e.type;if("undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)return"OffscreenCanvas";if("undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap)return"ImageBitmap";if("undefined"!=typeof ImageData&&e instanceof ImageData)return"ImageData"}return"Unknown"},getKernelTextureSize(e,t){let[r,n,s]=t,i=(r||1)*(n||1)*(s||1);return e.optimizeFloatMemory&&"single"===e.precision&&(r=i=Math.ceil(i/4)),n>1&&r*n===i?new Int32Array([r,n]):c.closestSquareDimensions(i)},closestSquareDimensions(e){const t=Math.sqrt(e);let r=Math.ceil(t),n=Math.floor(t);for(;r*nMath.floor((e+t-1)/t)*t,getDimensions(e,t){let r;if(c.isArray(e)){const t=[];let n=e;for(;c.isArray(n);)t.push(n.length),n=n[0];r=t.reverse()}else if(e instanceof o)r=e.output;else{if(!(e instanceof a))throw new Error(`Unknown dimensions of ${e}`);r=e.size}if(t)for(r=Array.from(r);r.length<3;)r.push(1);return new Int32Array(r)},flatten2dArrayTo(e,t){let r=0;for(let n=0;ne.length>0?e.join(";\n")+";\n":"\n",warnDeprecated(e,t,r){r?console.warn(`You are using a deprecated ${e} "${t}". It has been replaced with "${r}". Fixing, but please upgrade as it will soon be removed.`):console.warn(`You are using a deprecated ${e} "${t}". It has been removed. Fixing, but please upgrade as it will soon be removed.`)},flipPixels:(e,t,r)=>{const n=r/2|0,s=4*t,i=new Uint8ClampedArray(4*t),a=e.slice(0);for(let e=0;ee.subarray(0,t),erect2DPackedFloat:(e,t,r)=>{const n=new Array(r);for(let s=0;s{const s=new Array(n);for(let i=0;ie.subarray(0,t),erectMemoryOptimized2DFloat:(e,t,r)=>{const n=new Array(r);for(let s=0;s{const s=new Array(n);for(let i=0;i{const r=new Float32Array(t);let n=0;for(let s=0;s{const n=new Array(r);let s=0;for(let i=0;i{const s=new Array(n);let i=0;for(let a=0;a{const r=new Array(t),n=4*t;let s=0;for(let t=0;t{const n=new Array(r),s=4*t;for(let i=0;i{const s=4*t,i=new Array(n);for(let a=0;a{const r=new Array(t),n=4*t;let s=0;for(let t=0;t{const n=4*t,s=new Array(r);for(let i=0;i{const s=4*t,i=new Array(n);for(let a=0;a{const r=new Array(e),n=4*t;let s=0;for(let t=0;t{const n=4*t,s=new Array(r);for(let i=0;i{const s=4*t,i=new Array(n);for(let a=0;a{const{findDependency:r,thisLookup:n,doNotDefine:s}=t;let a=t.flattened;a||(a=t.flattened={});const o=i.parse(e,{ecmaVersion:2020}),u=[];let l=0;const h=function e(t){if(Array.isArray(t)){const r=[];for(let n=0;nnull!==e);return s.length<1?"":`${t.kind} ${s.join(",")}`;case"VariableDeclarator":return t.init?t.init.object&&"ThisExpression"===t.init.object.type?n(t.init.property.name,!0)?`${t.id.name} = ${e(t.init)}`:null:`${t.id.name} = ${e(t.init)}`:t.id.name;case"CallExpression":if("subarray"===t.callee.property.name)return`${e(t.callee.object)}.${e(t.callee.property)}(${t.arguments.map(t=>e(t)).join(", ")})`;if("gl"===t.callee.object.name||"context"===t.callee.object.name)return`${e(t.callee.object)}.${e(t.callee.property)}(${t.arguments.map(t=>e(t)).join(", ")})`;if("ThisExpression"===t.callee.object.type)return u.push(r("this",t.callee.property.name)),`${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`;if(t.callee.object.name){const n=r(t.callee.object.name,t.callee.property.name);return null===n?`${t.callee.object.name}.${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`:(u.push(n),`${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`)}if("MemberExpression"===t.callee.object.type)return`${e(t.callee.object)}.${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`;throw new Error("unknown ast.callee");case"ReturnStatement":return`return ${e(t.argument)}`;case"BinaryExpression":return`(${e(t.left)}${t.operator}${e(t.right)})`;case"UnaryExpression":return t.prefix?`${t.operator} ${e(t.argument)}`:`${e(t.argument)} ${t.operator}`;case"ExpressionStatement":return`${e(t.expression)}`;case"SequenceExpression":return`(${e(t.expressions)})`;case"ArrowFunctionExpression":return`(${t.params.map(e).join(", ")}) => ${e(t.body)}`;case"Literal":return t.raw;case"Identifier":return t.name;case"MemberExpression":return"ThisExpression"===t.object.type?n(t.property.name):t.computed?`${e(t.object)}[${e(t.property)}]`:e(t.object)+"."+e(t.property);case"ThisExpression":return"this";case"NewExpression":return`new ${e(t.callee)}(${t.arguments.map(t=>e(t)).join(", ")})`;case"ForStatement":return`for (${e(t.init)};${e(t.test)};${e(t.update)}) ${e(t.body)}`;case"AssignmentExpression":return`${e(t.left)}${t.operator}${e(t.right)}`;case"UpdateExpression":return`${e(t.argument)}${t.operator}`;case"IfStatement":{const r=e(t.consequent);if(!t.alternate)return`if (${e(t.test)}) ${r}`;const n="BlockStatement"===t.consequent.type?"":";";return`if (${e(t.test)}) ${r}${n} else ${e(t.alternate)}`}case"ThrowStatement":return`throw ${e(t.argument)}`;case"ObjectPattern":return t.properties.map(e).join(", ");case"ArrayPattern":return t.elements.map(e).join(", ");case"DebuggerStatement":return"debugger;";case"ConditionalExpression":return`${e(t.test)}?${e(t.consequent)}:${e(t.alternate)}`;case"Property":if("init"===t.kind)return e(t.key)}throw new Error(`unhandled ast.type of ${t.type}`)}(o);if(u.length>0){const e=[];for(let r=0;r{if("VariableDeclaration"!==e.type)throw new Error('Ast is not of type "VariableDeclaration"');const t=[];for(let r=0;r{const r=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].r},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),n=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].g},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),s=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].b},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),i=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].a},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),a=[r(t),n(t),s(t),i(t)];return a.rKernel=r,a.gKernel=n,a.bKernel=s,a.aKernel=i,a.gpu=e,a},splitRGBAToCanvases:(e,t,r,n)=>{const s=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(t.r/255,0,0,255)},{output:[r,n],graphical:!0,argumentTypes:{v:"Array2D(4)"}});s(t);const i=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(0,t.g/255,0,255)},{output:[r,n],graphical:!0,argumentTypes:{v:"Array2D(4)"}});i(t);const a=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(0,0,t.b/255,255)},{output:[r,n],graphical:!0,argumentTypes:{v:"Array2D(4)"}});a(t);const o=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(255,255,255,t.a/255)},{output:[r,n],graphical:!0,argumentTypes:{v:"Array2D(4)"}});return o(t),[s.canvas,i.canvas,a.canvas,o.canvas]},getMinifySafeName:e=>{try{const{init:t}=i.parse(`const value = ${e.toString()}`,{ecmaVersion:2020}).body[0].declarations[0];return t.body.name||t.body.body[0].argument.name}catch(e){throw new Error("Unrecognized function type. Please use `() => yourFunctionVariableHere` or function() { return yourFunctionVariableHere; }")}},sanitizeName:function(e){return p.test(e)&&(e=e.replace(p,"S_S")),d.test(e)?e=e.replace(d,"U_U"):m.test(e)&&(e=e.replace(m,"u_u")),e}},p=/\$/,d=/__/,m=/_/,f=c.getSystemEndianness();t.exports={utils:c}}),a=e((e,t)=>{const{utils:r}=i(),{Input:s}=n();t.exports={Kernel:class{static get isSupported(){throw new Error(`"isSupported" not implemented on ${this.name}`)}static isContextMatch(e){throw new Error(`"isContextMatch" not implemented on ${this.name}`)}static getFeatures(){throw new Error(`"getFeatures" not implemented on ${this.name}`)}static destroyContext(e){throw new Error(`"destroyContext" called on ${this.name}`)}static nativeFunctionArguments(){throw new Error(`"nativeFunctionArguments" called on ${this.name}`)}static nativeFunctionReturnType(){throw new Error(`"nativeFunctionReturnType" called on ${this.name}`)}static combineKernels(){throw new Error(`"combineKernels" called on ${this.name}`)}constructor(e,t){if("object"!=typeof e){if("string"!=typeof e)throw new Error("source not a string");if(!r.isFunctionString(e))throw new Error("source not a function string")}this.useLegacyEncoder=!1,this.fallbackRequested=!1,this.onRequestFallback=null,this.onRequestSwitchKernel=null,this.argumentNames="string"==typeof e?r.getArgumentNamesFromString(e):null,this.argumentTypes=null,this.argumentSizes=null,this.argumentBitRatios=null,this.kernelArguments=null,this.kernelConstants=null,this.forceUploadKernelConstants=null,this.source=e,this.output=null,this.debug=!1,this.graphical=!1,this.loopMaxIterations=0,this.constants=null,this.constantTypes=null,this.constantBitRatios=null,this.dynamicArguments=!1,this.dynamicOutput=!1,this.canvas=null,this.context=null,this.checkContext=null,this.gpu=null,this.functions=null,this.nativeFunctions=null,this.injectedNative=null,this.subKernels=null,this.validate=!0,this.immutable=!1,this.pipeline=!1,this.asyncMode=!1,this.precision=null,this.tactic=null,this.plugins=null,this.returnType=null,this.leadingReturnStatement=null,this.followingReturnStatement=null,this.optimizeFloatMemory=null,this.strictIntegers=!1,this.fixIntegerDivisionAccuracy=null,this.randomSeed=null,this.built=!1,this.signature=null,this.switchingKernels=null}mergeSettings(e){for(let t in e)if(e.hasOwnProperty(t)&&this.hasOwnProperty(t)){switch(t){case"output":if(!Array.isArray(e.output)){this.setOutput(e.output);continue}break;case"functions":this.functions=[];for(let t=0;te.name):null,returnType:this.returnType}}}buildSignature(e){const t=this.constructor;this.signature=t.getSignature(this,t.getArgumentTypes(this,e))}static getArgumentTypes(e,t){const n=new Array(t.length);for(let s=0;st.argumentTypes[e])||[];const i=Object.keys(t.argumentTypes);if(i.length>0&&e.length>0&&s.every(e=>void 0===e))throw new Error(`argumentTypes keys [${i.join(", ")}] match none of the function's parameters [${e.join(", ")}] \u2014 a bundler may have renamed them. Use the array form: argumentTypes: ['${i.map(e=>t.argumentTypes[e]).join("', '")}']`)}else s=t.argumentTypes||[];return{name:t.name||r.getFunctionNameFromString(n)||("function"==typeof e&&e.name?e.name:null),source:n,argumentTypes:s,returnType:t.returnType||null}}onActivate(e){}switchKernels(e){this.switchingKernels?this.switchingKernels.push(e):this.switchingKernels=[e]}resetSwitchingKernels(){const e=this.switchingKernels;return this.switchingKernels=null,e}checkArgumentTypes(e){if(!this.argumentTypes)return;const t=Math.min(e.length,this.argumentTypes.length);for(let n=0;n{t.exports={FunctionBuilder:class e{static fromKernel(t,r,n){const{kernelArguments:s,kernelConstants:i,argumentNames:a,argumentSizes:o,argumentBitRatios:u,constants:l,constantBitRatios:h,debug:c,loopMaxIterations:p,nativeFunctions:d,output:m,optimizeFloatMemory:f,precision:g,plugins:y,source:x,subKernels:b,functions:T,leadingReturnStatement:S,followingReturnStatement:A,dynamicArguments:w,dynamicOutput:_}=t,E=new Array(s.length),v={};for(let e=0;eU.needsArgumentType(e,t),$=(e,t,r)=>{U.assignArgumentType(e,t,r)},D=(e,t,r)=>U.lookupReturnType(e,t,r),F=e=>U.lookupFunctionArgumentTypes(e),L=(e,t)=>U.lookupFunctionArgumentName(e,t),R=(e,t)=>U.lookupFunctionArgumentBitRatio(e,t),k=(e,t,r,n)=>{U.assignArgumentType(e,t,r,n)},C=(e,t,r,n)=>{U.assignArgumentBitRatio(e,t,r,n)},M=(e,t,r)=>{U.trackFunctionCall(e,t,r)},G=(e,t)=>{const n=[];for(let t=0;tnew r(e.source,{name:e.name||void 0,returnType:e.returnType,argumentTypes:e.argumentTypes,output:m,plugins:y,constants:l,constantTypes:v,constantBitRatios:h,optimizeFloatMemory:f,precision:g,lookupReturnType:D,lookupFunctionArgumentTypes:F,lookupFunctionArgumentName:L,lookupFunctionArgumentBitRatio:R,needsArgumentType:I,assignArgumentType:$,triggerImplyArgumentType:k,triggerImplyArgumentBitRatio:C,onFunctionCall:M,onNestedFunction:G})));let K=null;b&&(K=b.map(e=>{const{name:t,source:n}=e;return new r(n,Object.assign({},z,{name:t,isSubKernel:!0,isRootKernel:!1}))}));const U=new e({kernel:t,rootNode:O,functionNodes:V,nativeFunctions:d,subKernelNodes:K});return U}constructor(e){if(e=e||{},this.kernel=e.kernel,this.rootNode=e.rootNode,this.functionNodes=e.functionNodes||[],this.subKernelNodes=e.subKernelNodes||[],this.nativeFunctions=e.nativeFunctions||[],this.functionMap={},this.nativeFunctionNames=[],this.lookupChain=[],this.functionNodeDependencies={},this.functionCalls={},this.rootNode&&(this.functionMap.kernel=this.rootNode),this.functionNodes)for(let e=0;e-1){const r=t.indexOf(e);if(-1===r)t.push(e);else{const e=t.splice(r,1)[0];t.push(e)}return t}const r=this.functionMap[e];if(r){const n=t.indexOf(e);if(-1===n){t.push(e),r.toString();for(let e=0;e-1){t.push(this.nativeFunctions[s].source);continue}const i=this.functionMap[n];i&&t.push(i.toString())}return t}toJSON(){return this.traceFunctionCalls(this.rootNode.name).reverse().map(e=>{const t=this.nativeFunctions.indexOf(e);if(t>-1)return{name:e,source:this.nativeFunctions[t].source};if(this.functionMap[e])return this.functionMap[e].toJSON();throw new Error(`function ${e} not found`)})}fromJSON(e,t){this.functionMap={};for(let r=0;r0){const s=t.arguments;for(let t=0;t{const{utils:r}=i();function n(e){return e.length>0?e[e.length-1]:null}const s="trackIdentifiers",a="memberExpression",o="inForLoopInit";t.exports={FunctionTracer:class{constructor(e){this.runningContexts=[],this.functionContexts=[],this.contexts=[],this.functionCalls=[],this.declarations=[],this.identifiers=[],this.functions=[],this.returnStatements=[],this.trackedIdentifiers=null,this.states=[],this.newFunctionContext(),this.scan(e)}isState(e){return this.states[this.states.length-1]===e}hasState(e){return this.states.indexOf(e)>-1}pushState(e){this.states.push(e)}popState(e){if(!this.isState(e))throw new Error(`Cannot pop the non-active state "${e}"`);this.states.pop()}get currentFunctionContext(){return n(this.functionContexts)}get currentContext(){return n(this.runningContexts)}newFunctionContext(){const e={"@contextType":"function"};this.contexts.push(e),this.functionContexts.push(e)}newContext(e){const t=Object.assign({"@contextType":"const/let"},this.currentContext);this.contexts.push(t),this.runningContexts.push(t),e();const{currentFunctionContext:r}=this;for(const e in r)r.hasOwnProperty(e)&&!t.hasOwnProperty(e)&&(t[e]=r[e]);return this.runningContexts.pop(),t}useFunctionContext(e){const t=n(this.functionContexts);this.runningContexts.push(t),e(),this.runningContexts.pop()}getIdentifiers(e){const t=this.trackedIdentifiers=[];return this.pushState(s),e(),this.trackedIdentifiers=null,this.popState(s),t}getDeclaration(e){const{currentContext:t,currentFunctionContext:r,runningContexts:n}=this,s=t[e]||r[e]||null;if(!s&&t===r&&n.length>0){const t=n[n.length-2];if(t[e])return t[e]}return s}scan(e){if(e)if(Array.isArray(e))for(let t=0;t{this.scan(e.body)});break;case"BlockStatement":this.newContext(()=>{this.scan(e.body)});break;case"AssignmentExpression":case"LogicalExpression":case"BinaryExpression":this.scan(e.left),this.scan(e.right);break;case"UpdateExpression":if("++"===e.operator){const t=this.getDeclaration(e.argument.name);t&&(t.suggestedType="Integer")}this.scan(e.argument);break;case"UnaryExpression":this.scan(e.argument);break;case"VariableDeclaration":"var"===e.kind?this.useFunctionContext(()=>{e.declarations=r.normalizeDeclarations(e),this.scan(e.declarations)}):(e.declarations=r.normalizeDeclarations(e),this.scan(e.declarations));break;case"VariableDeclarator":{const{currentContext:t}=this,r=this.hasState(o),n={ast:e,context:t,name:e.id.name,origin:"declaration",inForLoopInit:r,inForLoopTest:null,assignable:t===this.currentFunctionContext||!r&&!t.hasOwnProperty(e.id.name),suggestedType:null,valueType:null,dependencies:null,isSafe:null};t[e.id.name]||(t[e.id.name]=n),this.declarations.push(n),this.scan(e.id),this.scan(e.init);break}case"FunctionExpression":case"FunctionDeclaration":0===this.runningContexts.length?this.scan(e.body):this.functions.push(e);break;case"IfStatement":this.scan(e.test),this.scan(e.consequent),e.alternate&&this.scan(e.alternate);break;case"ForStatement":{let t;const r=this.newContext(()=>{this.pushState(o),this.scan(e.init),this.popState(o),t=this.getIdentifiers(()=>{this.scan(e.test)}),this.scan(e.update),this.newContext(()=>{this.scan(e.body)})});if(t)for(const e in r)"@contextType"!==e&&t.indexOf(e)>-1&&(r[e].inForLoopTest=!0);break}case"DoWhileStatement":case"WhileStatement":this.newContext(()=>{this.scan(e.body),this.scan(e.test)});break;case"Identifier":this.isState(s)&&this.trackedIdentifiers.push(e.name),this.identifiers.push({context:this.currentContext,declaration:this.getDeclaration(e.name),ast:e});break;case"ReturnStatement":this.returnStatements.push(e),this.scan(e.argument);break;case"MemberExpression":this.pushState(a),this.scan(e.object),this.scan(e.property),this.popState(a);break;case"ExpressionStatement":this.scan(e.expression);break;case"SequenceExpression":this.scan(e.expressions);break;case"CallExpression":this.functionCalls.push({context:this.currentContext,ast:e}),this.scan(e.arguments);break;case"ArrayExpression":this.scan(e.elements);break;case"ConditionalExpression":this.scan(e.test),this.scan(e.alternate),this.scan(e.consequent);break;case"SwitchStatement":this.scan(e.discriminant),this.scan(e.cases);break;case"SwitchCase":this.scan(e.test),this.scan(e.consequent);break;case"ThisExpression":case"Literal":case"DebuggerStatement":case"EmptyStatement":case"BreakStatement":case"ContinueStatement":break;default:throw new Error(`unhandled type "${e.type}"`)}}}}}),l=e((e,t)=>{const n=r(),{utils:s}=i(),{FunctionTracer:a}=u(),o=["E","PI","SQRT2","SQRT1_2","LN2","LN10","LOG2E","LOG10E"],l=["abs","acos","acosh","asin","asinh","atan","atan2","atanh","cbrt","ceil","clz32","cos","cosh","expm1","exp","floor","fround","imul","log","log2","log10","log1p","max","min","pow","random","round","sign","sin","sinh","sqrt","tan","tanh","trunc"],h=["value","value[]","value[][]","value[][][]","value[][][][]","value.value","value.thread.value","this.thread.value","this.output.value","this.constants.value","this.constants.value[]","this.constants.value[][]","this.constants.value[][][]","this.constants.value[][][][]","fn()[]","fn()[][]","fn()[][][]","[][]"];const c={Number:"Number",Float:"Float",Integer:"Integer",Array:"Number","Array(2)":"Number","Array(3)":"Number","Array(4)":"Number","Matrix(2)":"Number","Matrix(3)":"Number","Matrix(4)":"Number",Array2D:"Number",Array3D:"Number",Input:"Number",HTMLCanvas:"Array(4)",OffscreenCanvas:"Array(4)",HTMLImage:"Array(4)",ImageBitmap:"Array(4)",ImageData:"Array(4)",HTMLVideo:"Array(4)",HTMLImageArray:"Array(4)",NumberTexture:"Number",MemoryOptimizedNumberTexture:"Number","Array1D(2)":"Array(2)","Array1D(3)":"Array(3)","Array1D(4)":"Array(4)","Array2D(2)":"Array(2)","Array2D(3)":"Array(3)","Array2D(4)":"Array(4)","Array3D(2)":"Array(2)","Array3D(3)":"Array(3)","Array3D(4)":"Array(4)","ArrayTexture(1)":"Number","ArrayTexture(2)":"Array(2)","ArrayTexture(3)":"Array(3)","ArrayTexture(4)":"Array(4)"};let p=536870912;function d(e,t){return e.start=p++,e.end=p++,t&&t.loc&&(e.loc=t.loc),e}function m(e,t){return e&&e.body&&"BlockStatement"===e.body.type?(f(e.body,t),e):e}function f(e,t){e.body=g(e.body,t)}function g(e,t){const r=[];for(let n=0;n{if(!e||"object"!=typeof e||r)return e;if(Array.isArray(e))return e.map(n);switch(e.type){case"ContinueStatement":return e.label?(r=!0,e):d({type:"BlockStatement",body:[...A(t),e]},e);case"ForStatement":case"WhileStatement":case"DoWhileStatement":case"FunctionExpression":case"FunctionDeclaration":case"ArrowFunctionExpression":default:return e;case"IfStatement":return e.consequent=n(e.consequent),e.alternate&&(e.alternate=n(e.alternate)),e;case"BlockStatement":return e.body=e.body.map(n),e;case"SwitchStatement":for(let t=0;t0?(r.push(e),r):[e]}case"WhileStatement":case"DoWhileStatement":return e.body&&(e.body=x(e.body,t)),[e];case"SwitchStatement":for(let r=0;r0&&this.argumentTypes.length!==this.argumentNames.length)throw new Error(`argumentTypes count of ${this.argumentTypes.length} exceeds ${this.argumentNames.length}`);if(this.output.length<1)throw new Error("this.output is not big enough")}isIdentifierConstant(e){return!!this.constants&&this.constants.hasOwnProperty(e)}isInput(e){return"Input"===this.argumentTypes[this.argumentNames.indexOf(e)]}pushState(e){this.states.push(e)}popState(e){if(this.state!==e)throw new Error(`Cannot popState ${e} when in ${this.state}`);this.states.pop()}isState(e){return this.state===e}get state(){return this.states[this.states.length-1]}astMemberExpressionUnroll(e){if("Identifier"===e.type)return e.name;if("ThisExpression"===e.type)return"this";if("MemberExpression"===e.type&&e.object&&e.property)return e.object.hasOwnProperty("name")&&"Math"!==e.object.name?this.astMemberExpressionUnroll(e.property):this.astMemberExpressionUnroll(e.object)+"."+this.astMemberExpressionUnroll(e.property);if(e.hasOwnProperty("expressions")){const t=e.expressions[0];if("Literal"===t.type&&0===t.value&&2===e.expressions.length)return this.astMemberExpressionUnroll(e.expressions[1])}throw this.astErrorOutput("Unknown astMemberExpressionUnroll",e)}get requiresSequenceFreeForInit(){return!1}getJsAST(e){if(this.ast)return this.ast;if("object"==typeof this.source)return m(this.source,this.requiresSequenceFreeForInit),this.traceFunctionAST(this.source),this.ast=this.source;if(null===(e=e||n))throw new Error("Missing JS to AST parser");const t=Object.freeze(e.parse(`const parser_${this.name} = ${this.source};`,{locations:!0,ecmaVersion:2020})),r=t.body[0].declarations[0].init;if(m(r,this.requiresSequenceFreeForInit),this.traceFunctionAST(r),!t)throw new Error("Failed to parse JS code");return this.ast=r}traceFunctionAST(e){const{contexts:t,declarations:r,functions:n,identifiers:s,functionCalls:i}=new a(e);this.contexts=t,this.identifiers=s,this.functionCalls=i,this.functions=n;for(let e=0;e":case"<":return"Boolean";case"&":case"|":case"^":case"<<":case">>":case">>>":return"Integer"}const r=this.getType(e.left);if(this.isState("skip-literal-correction"))return r;if("LiteralInteger"===r){const t=this.getType(e.right);return"LiteralInteger"===t?e.left.value%1==0?"Integer":"Float":t}if("Integer"===r){const t=this.getType(e.right);if("Number"===t||"Float"===t)return t}return c[r]||r;case"UpdateExpression":case"ReturnStatement":return this.getType(e.argument);case"UnaryExpression":return"~"===e.operator?"Integer":this.getType(e.argument);case"VariableDeclaration":{const t=e.declarations;let r;for(let e=0;ee.isSafe)}getDependencies(e,t,r){if(t||(t=[]),!e)return null;if(Array.isArray(e)){for(let n=0;n-1/0&&e.value<1/0&&!isNaN(e.value))});break;case"VariableDeclarator":return this.getDependencies(e.init,t,r);case"Identifier":const n=this.getDeclaration(e);if(n)t.push({name:e.name,origin:"declaration",isSafe:!r&&this.isSafeDependencies(n.dependencies)});else if(this.argumentNames.indexOf(e.name)>-1)t.push({name:e.name,origin:"argument",isSafe:!1});else if(this.strictTypingChecking)throw new Error(`Cannot find identifier origin "${e.name}"`);break;case"FunctionDeclaration":return this.getDependencies(e.body.body[e.body.body.length-1],t,r);case"ReturnStatement":return this.getDependencies(e.argument,t);case"BinaryExpression":case"LogicalExpression":return r="/"===e.operator||"*"===e.operator,this.getDependencies(e.left,t,r),this.getDependencies(e.right,t,r),t;case"UnaryExpression":case"UpdateExpression":return this.getDependencies(e.argument,t,r);case"VariableDeclaration":return this.getDependencies(e.declarations,t,r);case"ArrayExpression":return t.push({origin:"declaration",isSafe:!0}),t;case"CallExpression":return t.push({origin:"function",isSafe:!0}),t;case"MemberExpression":const s=this.getMemberExpressionDetails(e);switch(s.signature){case"value[]":this.getDependencies(e.object,t,r);break;case"value[][]":this.getDependencies(e.object.object,t,r);break;case"value[][][]":this.getDependencies(e.object.object.object,t,r);break;case"this.output.value":this.dynamicOutput&&t.push({name:s.name,origin:"output",isSafe:!1})}if(s)return s.property&&this.getDependencies(s.property,t,r),s.xProperty&&this.getDependencies(s.xProperty,t,r),s.yProperty&&this.getDependencies(s.yProperty,t,r),s.zProperty&&this.getDependencies(s.zProperty,t,r),t;case"SequenceExpression":return this.getDependencies(e.expressions,t,r);default:throw this.astErrorOutput(`Unhandled type ${e.type} in getDependencies`,e)}return t}getVariableSignature(e,t){if(!this.isAstVariable(e))throw new Error(`ast of type "${e.type}" is not a variable signature`);if("Identifier"===e.type)return"value";const r=[];for(;e;)e.computed?r.push("[]"):"ThisExpression"===e.type?r.unshift("this"):e.property&&e.property.name?"x"===e.property.name||"y"===e.property.name||"z"===e.property.name?r.unshift(t?"."+e.property.name:".value"):"constants"===e.property.name||"thread"===e.property.name||"output"===e.property.name?r.unshift("."+e.property.name):r.unshift(t?"."+e.property.name:".value"):e.name?r.unshift(t?e.name:"value"):e.callee&&e.callee.name?r.unshift(t?e.callee.name+"()":"fn()"):e.elements?r.unshift("[]"):r.unshift("unknown"),e=e.object;const n=r.join("");return t||h.includes(n)?n:null}build(){return this.toString().length>0}astGeneric(e,t){if(null===e)throw this.astErrorOutput("NULL ast",e);if(Array.isArray(e)){for(let r=0;r0?n[n.length-1]:0;return new Error(`${e} on line ${n.length}, position ${i.length}:\n ${r}`)}astDebuggerStatement(e,t){return t}astConditionalExpression(e,t){if("ConditionalExpression"!==e.type)throw this.astErrorOutput("Not a conditional expression",e);return t.push("("),this.astGeneric(e.test,t),t.push("?"),this.astGeneric(e.consequent,t),t.push(":"),this.astGeneric(e.alternate,t),t.push(")"),t}astFunction(e,t){throw new Error(`"astFunction" not defined on ${this.constructor.name}`)}astFunctionDeclaration(e,t){return this.isChildFunction(e)?t:this.astFunction(e,t)}astFunctionExpression(e,t){return this.isChildFunction(e)?t:this.astFunction(e,t)}isChildFunction(e){for(let t=0;t1?t.push("(",n.join(","),")"):t.push(n[0]),t}astUnaryExpression(e,t){return this.checkAndUpconvertBitwiseUnary(e,t)||(e.prefix?(t.push(e.operator),this.astGeneric(e.argument,t)):(this.astGeneric(e.argument,t),t.push(e.operator))),t}checkAndUpconvertBitwiseUnary(e,t){}astUpdateExpression(e,t){return e.prefix?(t.push(e.operator),this.astGeneric(e.argument,t)):(this.astGeneric(e.argument,t),t.push(e.operator)),t}astLogicalExpression(e,t){return t.push("("),this.astGeneric(e.left,t),t.push(e.operator),this.astGeneric(e.right,t),t.push(")"),t}astMemberExpression(e,t){return t}astCallExpression(e,t){return t}astArrayExpression(e,t){return t}getMemberExpressionDetails(e){if("MemberExpression"!==e.type)throw this.astErrorOutput(`Expression ${e.type} not a MemberExpression`,e);let t=null,r=null;const n=this.getVariableSignature(e);switch(n){case"value":return null;case"value.thread.value":case"this.thread.value":case"this.output.value":return{signature:n,type:"Integer",name:e.property.name};case"value[]":if("string"!=typeof e.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.name,{name:t,origin:"user",signature:n,type:this.getVariableType(e.object),xProperty:e.property};case"value[][]":if("string"!=typeof e.object.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.object.name,{name:t,origin:"user",signature:n,type:this.getVariableType(e.object.object),yProperty:e.object.property,xProperty:e.property};case"value[][][]":if("string"!=typeof e.object.object.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.object.object.name,{name:t,origin:"user",signature:n,type:this.getVariableType(e.object.object.object),zProperty:e.object.object.property,yProperty:e.object.property,xProperty:e.property};case"value[][][][]":if("string"!=typeof e.object.object.object.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.object.object.object.name,{name:t,origin:"user",signature:n,type:this.getVariableType(e.object.object.object.object),zProperty:e.object.object.property,yProperty:e.object.property,xProperty:e.property};case"value.value":if("string"!=typeof e.property.name)throw this.astErrorOutput("Unexpected expression",e);if(this.isAstMathVariable(e))return t=e.property.name,{name:t,origin:"Math",type:"Number",signature:n};switch(e.property.name){case"r":case"g":case"b":case"a":return t=e.object.name,{name:t,property:e.property.name,origin:"user",signature:n,type:"Number"};default:throw this.astErrorOutput("Unexpected expression",e)}case"this.constants.value":if("string"!=typeof e.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.property.name,r=this.getConstantType(t),!r)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:r,origin:"constants",signature:n};case"this.constants.value[]":if("string"!=typeof e.object.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.object.property.name,r=this.getConstantType(t),!r)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:r,origin:"constants",signature:n,xProperty:e.property};case"this.constants.value[][]":if("string"!=typeof e.object.object.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.object.object.property.name,r=this.getConstantType(t),!r)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:r,origin:"constants",signature:n,yProperty:e.object.property,xProperty:e.property};case"this.constants.value[][][]":if("string"!=typeof e.object.object.object.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.object.object.object.property.name,r=this.getConstantType(t),!r)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:r,origin:"constants",signature:n,zProperty:e.object.object.property,yProperty:e.object.property,xProperty:e.property};case"fn()[]":case"fn()[][]":case"[][]":return{signature:n,property:e.property};default:throw this.astErrorOutput("Unexpected expression",e)}}findIdentifierOrigin(e){const t=[this.ast];for(;t.length>0;){const r=t[0];if("VariableDeclarator"===r.type&&r.id&&r.id.name&&r.id.name===e.name)return r;if(t.shift(),r.argument)t.push(r.argument);else if(r.body)t.push(r.body);else if(r.declarations)t.push(r.declarations);else if(Array.isArray(r))for(let e=0;e0;){const e=t.pop();if("ReturnStatement"===e.type)return e;if("FunctionDeclaration"!==e.type)if(e.argument)t.push(e.argument);else if(e.body)t.push(e.body);else if(e.declarations)t.push(e.declarations);else if(Array.isArray(e))for(let r=0;r{const{FunctionNode:r}=l();t.exports={CPUFunctionNode:class extends r{astFunction(e,t){if(!this.isRootKernel){t.push("function"),t.push(" "),t.push(this.name),t.push("(");for(let e=0;e0&&t.push(", "),t.push("user_"),t.push(r)}t.push(") {\n")}for(let r=0;r0&&t.push(r.join(""),";\n"),t.push(`for (let ${e}=0;${e}0&&t.push(`if (!${n.join("")}) break;\n`),t.push(i.join("")),t.push(`\n${s.join("")};`),t.push("}\n")}return t}astWhileStatement(e,t){if("WhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);return t.push("for (let i = 0; i < LOOP_MAX; i++) {"),t.push("if ("),this.astGeneric(e.test,t),t.push(") {\n"),this.astGeneric(e.body,t),t.push("} else {\n"),t.push("break;\n"),t.push("}\n"),t.push("}\n"),t}astDoWhileStatement(e,t){if("DoWhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);return t.push("for (let i = 0; i < LOOP_MAX; i++) {"),this.astGeneric(e.body,t),t.push("if (!"),this.astGeneric(e.test,t),t.push(") {\n"),t.push("break;\n"),t.push("}\n"),t.push("}\n"),t}astAssignmentExpression(e,t){const r=this.getDeclaration(e.left);if(r&&!r.assignable)throw this.astErrorOutput(`Variable ${e.left.name} is not assignable here`,e);const n=this.isState("assignment-as-statement");return n?this.popState("assignment-as-statement"):t.push("("),this.astGeneric(e.left,t),t.push(e.operator),this.astGeneric(e.right,t),n||t.push(")"),t}astBlockStatement(e,t){if(this.isState("loop-body")){this.pushState("block-body");for(let r=0;r0&&t.push(",");const n=r[e],s=this.getDeclaration(n.id);s.valueType||(s.valueType=this.getType(n.init)),this.astGeneric(n,t)}return this.isState("in-for-loop-init")||t.push(";"),t}astIfStatement(e,t){return t.push("if ("),this.astGeneric(e.test,t),t.push(")"),"BlockStatement"===e.consequent.type?this.astGeneric(e.consequent,t):(t.push(" {\n"),this.astGeneric(e.consequent,t),t.push("\n}\n")),e.alternate&&(t.push("else "),"BlockStatement"===e.alternate.type||"IfStatement"===e.alternate.type?this.astGeneric(e.alternate,t):(t.push(" {\n"),this.astGeneric(e.alternate,t),t.push("\n}\n"))),t}astSwitchStatement(e,t){const{discriminant:r,cases:n}=e;t.push("switch ("),this.astGeneric(r,t),t.push(") {\n");for(let e=0;e0&&(this.astGeneric(n[e].consequent,t),t.push("break;\n"))):(t.push("default:\n"),this.astGeneric(n[e].consequent,t),n[e].consequent&&n[e].consequent.length>0&&t.push("break;\n"));t.push("\n}")}astThisExpression(e,t){return t.push("_this"),t}astMemberExpression(e,t){const{signature:r,type:n,property:s,xProperty:i,yProperty:a,zProperty:o,name:u,origin:l}=this.getMemberExpressionDetails(e);switch(r){case"this.thread.value":return t.push(`_this.thread.${u}`),t;case"this.output.value":switch(u){case"x":t.push("outputX");break;case"y":t.push("outputY");break;case"z":t.push("outputZ");break;default:throw this.astErrorOutput("Unexpected expression",e)}return t;case"value":default:throw this.astErrorOutput("Unexpected expression",e);case"value[]":case"value[][]":case"value[][][]":case"value.value":if("Math"===l)return t.push(Math[u]),t;switch(s){case"r":return t.push(`user_${u}[0]`),t;case"g":return t.push(`user_${u}[1]`),t;case"b":return t.push(`user_${u}[2]`),t;case"a":return t.push(`user_${u}[3]`),t}break;case"this.constants.value":case"this.constants.value[]":case"this.constants.value[][]":case"this.constants.value[][][]":break;case"fn()[]":return this.astGeneric(e.object,t),t.push("["),this.astGeneric(e.property,t),t.push("]"),t;case"fn()[][]":return this.astGeneric(e.object.object,t),t.push("["),this.astGeneric(e.object.property,t),t.push("]"),t.push("["),this.astGeneric(e.property,t),t.push("]"),t}if(!e.computed)switch(n){case"Number":case"Integer":case"Float":case"Boolean":return t.push(`${l}_${u}`),t}const h=`${l}_${u}`;{let e,r;if("constants"===l){const t=this.constants[u];r="Input"===this.constantTypes[u],e=r?t.size:null}else r=this.isInput(u),e=r?this.argumentSizes[this.argumentNames.indexOf(u)]:null;t.push(`${h}`),o&&a?r?(t.push("[("),this.astGeneric(o,t),t.push(`*${this.dynamicArguments?"(outputY * outputX)":e[1]*e[0]})+(`),this.astGeneric(a,t),t.push(`*${this.dynamicArguments?"outputX":e[0]})+`),this.astGeneric(i,t),t.push("]")):(t.push("["),this.astGeneric(o,t),t.push("]"),t.push("["),this.astGeneric(a,t),t.push("]"),t.push("["),this.astGeneric(i,t),t.push("]")):a?r?(t.push("[("),this.astGeneric(a,t),t.push(`*${this.dynamicArguments?"outputX":e[0]})+`),this.astGeneric(i,t),t.push("]")):(t.push("["),this.astGeneric(a,t),t.push("]"),t.push("["),this.astGeneric(i,t),t.push("]")):void 0!==i&&(t.push("["),this.astGeneric(i,t),t.push("]"))}return t}astCallExpression(e,t){if("CallExpression"!==e.type)throw this.astErrorOutput("Unknown CallExpression",e);let r=this.astMemberExpressionUnroll(e.callee);this.calledFunctions.indexOf(r)<0&&this.calledFunctions.push(r),this.isAstMathFunction(e),this.onFunctionCall&&this.onFunctionCall(this.name,r,e.arguments),t.push(r),t.push("(");const n=this.lookupFunctionArgumentTypes(r)||[];for(let s=0;s0&&t.push(", "),this.astGeneric(i,t)}return t.push(")"),t}astArrayExpression(e,t){const r=this.getType(e),n=e.elements.length,s=[];for(let t=0;t{const{utils:r}=i();t.exports={cpuKernelString:function(e,t){const n=[],s=[],i=[],a=!/^function/.test(e.color.toString());if(n.push(" const { context, canvas, constants: incomingConstants } = settings;",` const output = new Int32Array(${JSON.stringify(Array.from(e.output))});`,` const _constantTypes = ${JSON.stringify(e.constantTypes)};`,` const _constants = ${function(e,t){const r=[];for(const n in t){if(!t.hasOwnProperty(n))continue;const s=t[n],i=e[n];switch(s){case"Number":case"Integer":case"Float":case"Boolean":r.push(`${n}:${i}`);break;case"Array(2)":case"Array(3)":case"Array(4)":case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":r.push(`${n}:new ${i.constructor.name}(${JSON.stringify(Array.from(i))})`)}}return`{ ${r.join()} }`}(e.constants,e.constantTypes)};`),s.push(" constants: _constants,"," context,"," output,"," thread: {x: 0, y: 0, z: 0},"),e.graphical){n.push(` const _imageData = context.createImageData(${e.output[0]}, ${e.output[1]});`),n.push(` const _colorData = new Uint8ClampedArray(${e.output[0]} * ${e.output[1]} * 4);`);const t=r.flattenFunctionToString((a?"function ":"")+e.color.toString(),{thisLookup:t=>{switch(t){case"_colorData":return"_colorData";case"_imageData":return"_imageData";case"output":return"output";case"thread":return"this.thread"}return JSON.stringify(e[t])},findDependency:(e,t)=>null}),o=r.flattenFunctionToString((a?"function ":"")+e.getPixels.toString(),{thisLookup:t=>{switch(t){case"_colorData":return"_colorData";case"_imageData":return"_imageData";case"output":return"output";case"thread":return"this.thread"}return JSON.stringify(e[t])},findDependency:()=>null});s.push(" _imageData,"," _colorData,",` color: ${t},`),i.push(` kernel.getPixels = ${o};`)}const o=[],u=Object.keys(e.constantTypes);for(let t=0;t"this"===t?(a?"function ":"")+e[r].toString():null,thisLookup:e=>{switch(e){case"canvas":return;case"context":return"context"}}});i.push(t),s.push(" _mediaTo2DArray,"),s.push(" _imageTo3DArray,")}else if(-1!==e.argumentTypes.indexOf("HTMLImage")||-1!==o.indexOf("HTMLImage")){const t=r.flattenFunctionToString((a?"function ":"")+e._mediaTo2DArray.toString(),{findDependency:(e,t)=>null,thisLookup:e=>{switch(e){case"canvas":return"settings.canvas";case"context":return"settings.context"}throw new Error("unhandled thisLookup")}});i.push(t),s.push(" _mediaTo2DArray,")}return`function(settings) {\n${n.join("\n")}\n for (const p in _constantTypes) {\n if (!_constantTypes.hasOwnProperty(p)) continue;\n const type = _constantTypes[p];\n switch (type) {\n case 'Number':\n case 'Integer':\n case 'Float':\n case 'Boolean':\n case 'Array(2)':\n case 'Array(3)':\n case 'Array(4)':\n case 'Matrix(2)':\n case 'Matrix(3)':\n case 'Matrix(4)':\n if (incomingConstants.hasOwnProperty(p)) {\n console.warn('constant ' + p + ' of type ' + type + ' cannot be resigned');\n }\n continue;\n }\n if (!incomingConstants.hasOwnProperty(p)) {\n throw new Error('constant ' + p + ' not found');\n }\n _constants[p] = incomingConstants[p];\n }\n const kernel = (function() {\n${e._kernelString}\n })\n .apply({ ${s.join("\n")} });\n ${i.join("\n")}\n return kernel;\n}`}}}),p=e((e,t)=>{const{Kernel:r}=a(),{FunctionBuilder:n}=o(),{CPUFunctionNode:s}=h(),{utils:u}=i(),{cpuKernelString:l}=c();t.exports={CPUKernel:class extends r{static getFeatures(){return this.features}static get features(){return Object.freeze({kernelMap:!0,isIntegerDivisionAccurate:!0})}static get isSupported(){return!0}static isContextMatch(e){return!1}static get mode(){return"cpu"}static nativeFunctionArguments(){return null}static nativeFunctionReturnType(){throw new Error(`Looking up native function return type not supported on ${this.name}`)}static combineKernels(e){return e}static getSignature(e,t){return"cpu"+(t.length>0?":"+t.join(","):"")}constructor(e,t){super(e,t),this.mergeSettings(e.settings||t),this._imageData=null,this._colorData=null,this._kernelString=null,this._prependedString=[],this.thread={x:0,y:0,z:0},this.translatedSources=null}initCanvas(){return"undefined"!=typeof document?document.createElement("canvas"):"undefined"!=typeof OffscreenCanvas?new OffscreenCanvas(0,0):void 0}initContext(){return this.canvas?this.canvas.getContext("2d",{willReadFrequently:!0}):null}initPlugins(e){return[]}validateSettings(e){if(!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=u.getVariableType(e[0],this.strictIntegers);if("Array"===t)this.output=u.getDimensions(t);else{if("NumberTexture"!==t&&"ArrayTexture(4)"!==t)throw new Error("Auto output not supported for input type: "+t);this.output=e[0].output}}if(this.graphical&&2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");this.checkOutput()}translateSource(){if(this.leadingReturnStatement=this.output.length>1?"resultX[x] = ":"result[x] = ",this.subKernels){const e=[];for(let t=0;t1?`resultX_${r}[x] = subKernelResult_${r};\n`:`result_${r}[x] = subKernelResult_${r};\n`)}this.followingReturnStatement=e.join("")}const e=n.fromKernel(this,s);this.translatedSources=e.getPrototypes("kernel"),this.graphical||this.returnType||(this.returnType=e.getKernelResultType())}build(){if(this.built)return;if(null!==this.randomSeed&&console.warn("randomSeed is not supported in cpu mode; Math.random() will be unseeded"),this.setupConstants(),this.setupArguments(arguments),this.validateSettings(arguments),this.translateSource(),this.graphical){const{canvas:e,output:t}=this;if(!e)throw new Error("no canvas available for using graphical output");const r=t[0],n=t[1]||1;e.width=r,e.height=n,this._imageData=this.context.createImageData(r,n),this._colorData=new Uint8ClampedArray(r*n*4)}const e=this.getKernelString();this.kernelString=e,this.debug&&(console.log("Function output:"),console.log(e));try{this.run=new Function([],e).bind(this)()}catch(e){console.error("An error occurred compiling the javascript: ",e)}this.buildSignature(arguments),this.built=!0}color(e,t,r,n){void 0===n&&(n=1),e=Math.floor(255*e),t=Math.floor(255*t),r=Math.floor(255*r),n=Math.floor(255*n);const s=this.output[0],i=this.output[1],a=this.thread.x+(i-this.thread.y-1)*s;this._colorData[4*a+0]=e,this._colorData[4*a+1]=t,this._colorData[4*a+2]=r,this._colorData[4*a+3]=n}getKernelString(){if(null!==this._kernelString)return this._kernelString;let e=null,{translatedSources:t}=this;return t.length>1?t=t.filter(t=>/^function/.test(t)?t:(e=t,!1)):e=t.shift(),this._kernelString=` const LOOP_MAX = ${this._getLoopMaxString()};\n ${this.injectedNative||""}\n const _this = this;\n ${this._resultKernelHeader()}\n ${this._processConstants()}\n return (${this.argumentNames.map(e=>"user_"+e).join(", ")}) => {\n ${this._prependedString.join("")}\n ${this._earlyThrows()}\n ${this._processArguments()}\n ${this.graphical?this._graphicalKernelBody(e):this._resultKernelBody(e)}\n ${t.length>0?t.join("\n"):""}\n };`}toString(){return l(this)}_getLoopMaxString(){return this.loopMaxIterations?` ${parseInt(this.loopMaxIterations)};`:" 1000;"}_processConstants(){if(!this.constants)return"";const e=[];for(let t in this.constants)switch(this.constantTypes[t]){case"HTMLCanvas":case"OffscreenCanvas":case"HTMLImage":case"ImageBitmap":case"ImageData":case"HTMLVideo":e.push(` const constants_${t} = this._mediaTo2DArray(this.constants.${t});\n`);break;case"HTMLImageArray":e.push(` const constants_${t} = this._imageTo3DArray(this.constants.${t});\n`);break;case"Input":e.push(` const constants_${t} = this.constants.${t}.value;\n`);break;default:e.push(` const constants_${t} = this.constants.${t};\n`)}return e.join("")}_earlyThrows(){if(this.graphical)return"";if(this.immutable)return"";if(!this.pipeline)return"";const e=[];for(let t=0;t`user_${n} === result_${e.name}`).join(" || ");t.push(`user_${n} === result${s?` || ${s}`:""}`)}return`if (${t.join(" || ")}) throw new Error('Source and destination arrays are the same. Use immutable = true');`}_processArguments(){const e=[];for(let t=0;t0?e.width:e.videoWidth,n=e.height>0?e.height:e.videoHeight;t.width=0;e--){const t=a[e]=new Array(r);for(let e=0;e`const result_${e.name} = new ${t}(outputX);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n this.thread.y = 0;\n this.thread.z = 0;\n ${e}\n }`}_mutableKernel1DResults(){const e=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const result = new ${e}(outputX);\n ${this._mapSubKernels(t=>`const result_${t.name} = new ${e}(outputX);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}`}_resultMutableKernel1DLoop(e){return` const outputX = _this.output[0];\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n this.thread.y = 0;\n this.thread.z = 0;\n ${e}\n }`}_resultImmutableKernel2DLoop(e){const t=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const result = new Array(outputY);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputY);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n this.thread.z = 0;\n this.thread.y = y;\n const resultX = result[y] = new ${t}(outputX);\n ${this._mapSubKernels(e=>`const resultX_${e.name} = result_${e.name}[y] = new ${t}(outputX);\n`).join("")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }`}_mutableKernel2DResults(){const e=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const result = new Array(outputY);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputY);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n const resultX = result[y] = new ${e}(outputX);\n ${this._mapSubKernels(t=>`const resultX_${t.name} = result_${t.name}[y] = new ${e}(outputX);\n`).join("")}\n }`}_resultMutableKernel2DLoop(e){const t=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n for (let y = 0; y < outputY; y++) {\n this.thread.z = 0;\n this.thread.y = y;\n const resultX = result[y];\n ${this._mapSubKernels(e=>`const resultX_${e.name} = result_${e.name}[y] = new ${t}(outputX);\n`).join("")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }`}_graphicalKernel2DLoop(e){return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n for (let y = 0; y < outputY; y++) {\n this.thread.z = 0;\n this.thread.y = y;\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }`}_resultImmutableKernel3DLoop(e){const t=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const outputZ = _this.output[2];\n const result = new Array(outputZ);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputZ);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let z = 0; z < outputZ; z++) {\n this.thread.z = z;\n const resultY = result[z] = new Array(outputY);\n ${this._mapSubKernels(e=>`const resultY_${e.name} = result_${e.name}[z] = new Array(outputY);\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n this.thread.y = y;\n const resultX = resultY[y] = new ${t}(outputX);\n ${this._mapSubKernels(e=>`const resultX_${e.name} = resultY_${e.name}[y] = new ${t}(outputX);\n`).join(" ")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }\n }`}_mutableKernel3DResults(){const e=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const outputZ = _this.output[2];\n const result = new Array(outputZ);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputZ);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let z = 0; z < outputZ; z++) {\n const resultY = result[z] = new Array(outputY);\n ${this._mapSubKernels(e=>`const resultY_${e.name} = result_${e.name}[z] = new Array(outputY);\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n const resultX = resultY[y] = new ${e}(outputX);\n ${this._mapSubKernels(t=>`const resultX_${t.name} = resultY_${t.name}[y] = new ${e}(outputX);\n`).join(" ")}\n }\n }`}_resultMutableKernel3DLoop(e){return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const outputZ = _this.output[2];\n for (let z = 0; z < outputZ; z++) {\n this.thread.z = z;\n const resultY = result[z];\n for (let y = 0; y < outputY; y++) {\n this.thread.y = y;\n const resultX = resultY[y];\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }\n }`}_kernelOutput(){return this.subKernels?`\n return {\n result: result,\n ${this.subKernels.map(e=>`${e.property}: result_${e.name}`).join(",\n ")}\n };`:"\n return result;"}_mapSubKernels(e){return null===this.subKernels?[""]:this.subKernels.map(e)}destroy(e){e&&delete this.canvas}static destroyContext(e){}toJSON(){const e=super.toJSON();return e.functionNodes=n.fromKernel(this,s).toJSON(),e}setOutput(e){super.setOutput(e);const[t,r]=this.output;this.graphical&&(this._imageData=this.context.createImageData(t,r),this._colorData=new Uint8ClampedArray(t*r*4))}prependString(e){if(this._kernelString)throw new Error("Kernel already built");this._prependedString.push(e)}hasPrependString(e){return this._prependedString.indexOf(e)>-1}}}}),d=e((e,t)=>{const{Texture:r}=s();function n(e,t){e.activeTexture(e.TEXTURE15),e.bindTexture(e.TEXTURE_2D,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST)}t.exports={GLTexture:class extends r{get textureType(){throw new Error(`"textureType" not implemented on ${this.name}`)}clone(){return new this.constructor(this)}beforeMutate(){return this.texture._refs>1&&(this.newTexture(),!0)}cloneTexture(){this.texture._refs--;const{context:e,size:t,texture:r,kernel:s}=this;s.debug&&console.warn("cloning internal texture"),e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),n(e,r),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,r,0);const i=e.createTexture();n(e,i),e.texImage2D(e.TEXTURE_2D,0,this.internalFormat,t[0],t[1],0,this.textureFormat,this.textureType,null),e.copyTexSubImage2D(e.TEXTURE_2D,0,0,0,0,0,t[0],t[1]),i._refs=1,this.texture=i}newTexture(){this.texture._refs--;const e=this.context,t=this.size;this.kernel.debug&&console.warn("new internal texture");const r=e.createTexture();n(e,r),e.texImage2D(e.TEXTURE_2D,0,this.internalFormat,t[0],t[1],0,this.textureFormat,this.textureType,null),r._refs=1,this.texture=r}clear(){if(this.texture._refs){this.texture._refs--;const e=this.context,t=this.texture=e.createTexture();n(e,t);const r=this.size;t._refs=1,e.texImage2D(e.TEXTURE_2D,0,this.internalFormat,r[0],r[1],0,this.textureFormat,this.textureType,null)}const{context:e,texture:t}=this;e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),e.bindTexture(e.TEXTURE_2D,t),n(e,t),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t,0),e.clearColor(0,0,0,0),e.clear(e.COLOR_BUFFER_BIT|e.DEPTH_BUFFER_BIT)}delete(){this._deleted||(this._deleted=!0,this.texture._refs&&(this.texture._refs--,this.texture._refs)||(this.kernel&&this.kernel.deleteTexture?this.kernel.deleteTexture(this.texture):this.context.deleteTexture(this.texture)))}framebuffer(){return this._framebuffer||(this._framebuffer=this.kernel.getRawValueFramebuffer(this.size[0],this.size[1])),this._framebuffer}}}}),m=e((e,t)=>{const{utils:r}=i(),{GLTexture:n}=d();t.exports={GLTextureFloat:class extends n{get textureType(){return this.context.FLOAT}constructor(e){super(e),this.type="ArrayTexture(1)"}renderRawOutput(){const e=this.context,t=this.size;e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.texture,0);const r=new Float32Array(t[0]*t[1]*4);return e.readPixels(0,0,t[0],t[1],e.RGBA,e.FLOAT,r),r}renderValues(){return this._deleted?null:this.renderRawOutput()}toArray(){return r.erectFloat(this.renderValues(),this.output[0])}}}}),f=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray2Float:class extends n{constructor(e){super(e),this.type="ArrayTexture(2)"}toArray(){return r.erectArray2(this.renderValues(),this.output[0],this.output[1])}}}}),g=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray2Float2D:class extends n{constructor(e){super(e),this.type="ArrayTexture(2)"}toArray(){return r.erect2DArray2(this.renderValues(),this.output[0],this.output[1])}}}}),y=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray2Float3D:class extends n{constructor(e){super(e),this.type="ArrayTexture(2)"}toArray(){return r.erect3DArray2(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),x=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray3Float:class extends n{constructor(e){super(e),this.type="ArrayTexture(3)"}toArray(){return r.erectArray3(this.renderValues(),this.output[0])}}}}),b=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray3Float2D:class extends n{constructor(e){super(e),this.type="ArrayTexture(3)"}toArray(){return r.erect2DArray3(this.renderValues(),this.output[0],this.output[1])}}}}),T=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray3Float3D:class extends n{constructor(e){super(e),this.type="ArrayTexture(3)"}toArray(){return r.erect3DArray3(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),S=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray4Float:class extends n{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return r.erectArray4(this.renderValues(),this.output[0])}}}}),A=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray4Float2D:class extends n{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return r.erect2DArray4(this.renderValues(),this.output[0],this.output[1])}}}}),w=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray4Float3D:class extends n{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return r.erect3DArray4(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),_=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureFloat2D:class extends n{constructor(e){super(e),this.type="ArrayTexture(1)"}toArray(){return r.erect2DFloat(this.renderValues(),this.output[0],this.output[1])}}}}),E=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureFloat3D:class extends n{constructor(e){super(e),this.type="ArrayTexture(1)"}toArray(){return r.erect3DFloat(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),v=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureMemoryOptimized:class extends n{constructor(e){super(e),this.type="MemoryOptimizedNumberTexture"}toArray(){return r.erectMemoryOptimizedFloat(this.renderValues(),this.output[0])}}}}),I=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureMemoryOptimized2D:class extends n{constructor(e){super(e),this.type="MemoryOptimizedNumberTexture"}toArray(){return r.erectMemoryOptimized2DFloat(this.renderValues(),this.output[0],this.output[1])}}}}),$=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureMemoryOptimized3D:class extends n{constructor(e){super(e),this.type="MemoryOptimizedNumberTexture"}toArray(){return r.erectMemoryOptimized3DFloat(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),D=e((e,t)=>{const{utils:r}=i(),{GLTexture:n}=d();t.exports={GLTextureUnsigned:class extends n{get textureType(){return this.context.UNSIGNED_BYTE}constructor(e){super(e),this.type="NumberTexture"}renderRawOutput(){const{context:e}=this;e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.texture,0);const t=new Uint8Array(this.size[0]*this.size[1]*4);return e.readPixels(0,0,this.size[0],this.size[1],e.RGBA,e.UNSIGNED_BYTE,t),t}renderValues(){return this._deleted?null:new Float32Array(this.renderRawOutput().buffer)}toArray(){return r.erectPackedFloat(this.renderValues(),this.output[0])}}}}),F=e((e,t)=>{const{utils:r}=i(),{GLTextureUnsigned:n}=D();t.exports={GLTextureUnsigned2D:class extends n{constructor(e){super(e),this.type="NumberTexture"}toArray(){return r.erect2DPackedFloat(this.renderValues(),this.output[0],this.output[1])}}}}),L=e((e,t)=>{const{utils:r}=i(),{GLTextureUnsigned:n}=D();t.exports={GLTextureUnsigned3D:class extends n{constructor(e){super(e),this.type="NumberTexture"}toArray(){return r.erect3DPackedFloat(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),R=e((e,t)=>{const{GLTextureUnsigned:r}=D();t.exports={GLTextureGraphical:class extends r{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return this.renderValues()}}}}),k=e((e,t)=>{const{Kernel:r}=a(),{utils:n}=i(),{GLTextureArray2Float:s}=f(),{GLTextureArray2Float2D:o}=g(),{GLTextureArray2Float3D:u}=y(),{GLTextureArray3Float:l}=x(),{GLTextureArray3Float2D:h}=b(),{GLTextureArray3Float3D:c}=T(),{GLTextureArray4Float:p}=S(),{GLTextureArray4Float2D:d}=A(),{GLTextureArray4Float3D:k}=w(),{GLTextureFloat:C}=m(),{GLTextureFloat2D:M}=_(),{GLTextureFloat3D:G}=E(),{GLTextureMemoryOptimized:z}=v(),{GLTextureMemoryOptimized2D:N}=I(),{GLTextureMemoryOptimized3D:O}=$(),{GLTextureUnsigned:V}=D(),{GLTextureUnsigned2D:K}=F(),{GLTextureUnsigned3D:U}=L(),{GLTextureGraphical:P}=R();const B={int:"Integer",float:"Number",vec2:"Array(2)",vec3:"Array(3)",vec4:"Array(4)"};t.exports={GLKernel:class extends r{static get mode(){return"gpu"}static getIsFloatRead(){const e=new this("function kernelFunction() {\n return 1;\n }",{context:this.testContext,canvas:this.testCanvas,validate:!1,output:[1],precision:"single",returnType:"Number",tactic:"speed"});e.build(),e.run();const t=e.renderOutput();return e.destroy(!0),1===t[0]}static getIsIntegerDivisionAccurate(){const e=new this(function(e,t){return e[this.thread.x]/t[this.thread.x]}.toString(),{context:this.testContext,canvas:this.testCanvas,validate:!1,output:[2],returnType:"Number",precision:"unsigned",tactic:"speed"}),t=[[6,6030401],[3,3991]];e.build.apply(e,t),e.run.apply(e,t);const r=e.renderOutput();return e.destroy(!0),2===r[0]&&1511===r[1]}static getIsSpeedTacticSupported(){const e=new this(function(e){return e[this.thread.x]}.toString(),{context:this.testContext,canvas:this.testCanvas,validate:!1,output:[4],returnType:"Number",precision:"unsigned",tactic:"speed"}),t=[[0,1,2,3]];e.build.apply(e,t),e.run.apply(e,t);const r=e.renderOutput();return e.destroy(!0),0===Math.round(r[0])&&1===Math.round(r[1])&&2===Math.round(r[2])&&3===Math.round(r[3])}static get testCanvas(){throw new Error(`"testCanvas" not defined on ${this.name}`)}static get testContext(){throw new Error(`"testContext" not defined on ${this.name}`)}static getFeatures(){const e=this.testContext,t=this.getIsDrawBuffers();return Object.freeze({isFloatRead:this.getIsFloatRead(),isIntegerDivisionAccurate:this.getIsIntegerDivisionAccurate(),isSpeedTacticSupported:this.getIsSpeedTacticSupported(),isTextureFloat:this.getIsTextureFloat(),isDrawBuffers:t,kernelMap:t,channelCount:this.getChannelCount(),maxTextureSize:this.getMaxTextureSize(),lowIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_INT),lowFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_FLOAT),mediumIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_INT),mediumFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_FLOAT),highIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_INT),highFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT)})}static setupFeatureChecks(){throw new Error(`"setupFeatureChecks" not defined on ${this.name}`)}static getSignature(e,t){return e.getVariablePrecisionString()+(t.length>0?":"+t.join(","):"")}setFixIntegerDivisionAccuracy(e){return this.fixIntegerDivisionAccuracy=e,this}setPrecision(e){return this.precision=e,this}setFloatTextures(e){return n.warnDeprecated("method","setFloatTextures","setOptimizeFloatMemory"),this.floatTextures=e,this}static nativeFunctionArguments(e){const t=[],r=[],n=[],s=/^[a-zA-Z_]/,i=/[a-zA-Z_0-9]/;let a=0,o=null,u=null;for(;a0?n[n.length-1]:null;if("FUNCTION_ARGUMENTS"!==c||"/"!==l||"*"!==h)if("MULTI_LINE_COMMENT"!==c||"*"!==l||"/"!==h)if("FUNCTION_ARGUMENTS"!==c||"/"!==l||"/"!==h)if("COMMENT"!==c||"\n"!==l)if(null!==c||"("!==l){if("FUNCTION_ARGUMENTS"===c){if(")"===l){n.pop();break}if("f"===l&&"l"===h&&"o"===e[a+2]&&"a"===e[a+3]&&"t"===e[a+4]&&" "===e[a+5]){n.push("DECLARE_VARIABLE"),u="float",o="",a+=6;continue}if("i"===l&&"n"===h&&"t"===e[a+2]&&" "===e[a+3]){n.push("DECLARE_VARIABLE"),u="int",o="",a+=4;continue}if("v"===l&&"e"===h&&"c"===e[a+2]&&"2"===e[a+3]&&" "===e[a+4]){n.push("DECLARE_VARIABLE"),u="vec2",o="",a+=5;continue}if("v"===l&&"e"===h&&"c"===e[a+2]&&"3"===e[a+3]&&" "===e[a+4]){n.push("DECLARE_VARIABLE"),u="vec3",o="",a+=5;continue}if("v"===l&&"e"===h&&"c"===e[a+2]&&"4"===e[a+3]&&" "===e[a+4]){n.push("DECLARE_VARIABLE"),u="vec4",o="",a+=5;continue}}else if("DECLARE_VARIABLE"===c){if(""===o){if(" "===l){a++;continue}if(!s.test(l))throw new Error("variable name is not expected string")}o+=l,i.test(h)||(n.pop(),r.push(o),t.push(B[u]))}a++}else n.push("FUNCTION_ARGUMENTS"),a++;else n.pop(),a++;else n.push("COMMENT"),a+=2;else n.pop(),a+=2;else n.push("MULTI_LINE_COMMENT"),a+=2}if(n.length>0)throw new Error("GLSL function was not parsable");return{argumentNames:r,argumentTypes:t}}static nativeFunctionReturnType(e){return B[e.match(/int|float|vec[2-4]/)[0]]}static combineKernels(e,t){e.apply(null,arguments);const{texSize:r,context:s,threadDim:i}=t.texSize;let a;if("single"===t.precision){const e=r[0],t=Math.ceil(r[1]/4);a=new Float32Array(e*t*4*4),s.readPixels(0,0,e,4*t,s.RGBA,s.FLOAT,a)}else{const e=new Uint8Array(r[0]*r[1]*4);s.readPixels(0,0,r[0],r[1],s.RGBA,s.UNSIGNED_BYTE,e),a=new Float32Array(e.buffer)}return a=a.subarray(0,i[0]*i[1]*i[2]),1===t.output.length?a:2===t.output.length?n.splitArray(a,t.output[0]):3===t.output.length?n.splitArray(a,t.output[0]*t.output[1]).map(function(e){return n.splitArray(e,t.output[0])}):void 0}constructor(e,t){super(e,t),this.transferValues=null,this.formatValues=null,this.TextureConstructor=null,this.renderOutput=null,this.renderRawOutput=null,this.texSize=null,this.translatedSource=null,this.compiledFragmentShader=null,this.compiledVertexShader=null,this.switchingKernels=null,this._textureSwitched=null,this._mappedTextureSwitched=null}checkTextureSize(){const{features:e}=this.constructor;if(this.texSize[0]>e.maxTextureSize||this.texSize[1]>e.maxTextureSize)throw new Error(`Texture size [${this.texSize[0]},${this.texSize[1]}] generated by kernel is larger than supported size [${e.maxTextureSize},${e.maxTextureSize}]`)}translateSource(){throw new Error(`"translateSource" not defined on ${this.constructor.name}`)}pickRenderStrategy(e){if(this.graphical)return this.renderRawOutput=this.readPackedPixelsToUint8Array,this.transferValues=e=>e,this.TextureConstructor=P,null;if("unsigned"===this.precision)if(this.renderRawOutput=this.readPackedPixelsToUint8Array,this.transferValues=this.readPackedPixelsToFloat32Array,this.pipeline)switch(this.renderOutput=this.renderTexture,null!==this.subKernels&&(this.renderKernels=this.renderKernelsToTextures),this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.output[2]>0?(this.TextureConstructor=U,null):this.output[1]>0?(this.TextureConstructor=K,null):(this.TextureConstructor=V,null);case"Array(2)":case"Array(3)":case"Array(4)":return this.requestFallback(e)}else switch(null!==this.subKernels&&(this.renderKernels=this.renderKernelsToArrays),this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.renderOutput=this.renderValues,this.output[2]>0?(this.TextureConstructor=U,this.formatValues=n.erect3DPackedFloat,null):this.output[1]>0?(this.TextureConstructor=K,this.formatValues=n.erect2DPackedFloat,null):(this.TextureConstructor=V,this.formatValues=n.erectPackedFloat,null);case"Array(2)":case"Array(3)":case"Array(4)":return this.requestFallback(e)}else{if("single"!==this.precision)throw new Error(`unhandled precision of "${this.precision}"`);if(this.renderRawOutput=this.readFloatPixelsToFloat32Array,this.transferValues=this.readFloatPixelsToFloat32Array,this.pipeline)switch(this.renderOutput=this.renderTexture,null!==this.subKernels&&(this.renderKernels=this.renderKernelsToTextures),this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.optimizeFloatMemory?this.output[2]>0?(this.TextureConstructor=O,null):this.output[1]>0?(this.TextureConstructor=N,null):(this.TextureConstructor=z,null):this.output[2]>0?(this.TextureConstructor=G,null):this.output[1]>0?(this.TextureConstructor=M,null):(this.TextureConstructor=C,null);case"Array(2)":return this.output[2]>0?(this.TextureConstructor=u,null):this.output[1]>0?(this.TextureConstructor=o,null):(this.TextureConstructor=s,null);case"Array(3)":return this.output[2]>0?(this.TextureConstructor=c,null):this.output[1]>0?(this.TextureConstructor=h,null):(this.TextureConstructor=l,null);case"Array(4)":return this.output[2]>0?(this.TextureConstructor=k,null):this.output[1]>0?(this.TextureConstructor=d,null):(this.TextureConstructor=p,null)}if(this.renderOutput=this.renderValues,null!==this.subKernels&&(this.renderKernels=this.renderKernelsToArrays),this.optimizeFloatMemory)switch(this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.output[2]>0?(this.TextureConstructor=O,this.formatValues=n.erectMemoryOptimized3DFloat,null):this.output[1]>0?(this.TextureConstructor=N,this.formatValues=n.erectMemoryOptimized2DFloat,null):(this.TextureConstructor=z,this.formatValues=n.erectMemoryOptimizedFloat,null);case"Array(2)":return this.output[2]>0?(this.TextureConstructor=u,this.formatValues=n.erect3DArray2,null):this.output[1]>0?(this.TextureConstructor=o,this.formatValues=n.erect2DArray2,null):(this.TextureConstructor=s,this.formatValues=n.erectArray2,null);case"Array(3)":return this.output[2]>0?(this.TextureConstructor=c,this.formatValues=n.erect3DArray3,null):this.output[1]>0?(this.TextureConstructor=h,this.formatValues=n.erect2DArray3,null):(this.TextureConstructor=l,this.formatValues=n.erectArray3,null);case"Array(4)":return this.output[2]>0?(this.TextureConstructor=k,this.formatValues=n.erect3DArray4,null):this.output[1]>0?(this.TextureConstructor=d,this.formatValues=n.erect2DArray4,null):(this.TextureConstructor=p,this.formatValues=n.erectArray4,null)}else switch(this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.output[2]>0?(this.TextureConstructor=G,this.formatValues=n.erect3DFloat,null):this.output[1]>0?(this.TextureConstructor=M,this.formatValues=n.erect2DFloat,null):(this.TextureConstructor=C,this.formatValues=n.erectFloat,null);case"Array(2)":return this.output[2]>0?(this.TextureConstructor=u,this.formatValues=n.erect3DArray2,null):this.output[1]>0?(this.TextureConstructor=o,this.formatValues=n.erect2DArray2,null):(this.TextureConstructor=s,this.formatValues=n.erectArray2,null);case"Array(3)":return this.output[2]>0?(this.TextureConstructor=c,this.formatValues=n.erect3DArray3,null):this.output[1]>0?(this.TextureConstructor=h,this.formatValues=n.erect2DArray3,null):(this.TextureConstructor=l,this.formatValues=n.erectArray3,null);case"Array(4)":return this.output[2]>0?(this.TextureConstructor=k,this.formatValues=n.erect3DArray4,null):this.output[1]>0?(this.TextureConstructor=d,this.formatValues=n.erect2DArray4,null):(this.TextureConstructor=p,this.formatValues=n.erectArray4,null)}}throw new Error(`unhandled return type "${this.returnType}"`)}getKernelString(){throw new Error("abstract method call")}getMainResultTexture(){switch(this.returnType){case"LiteralInteger":case"Float":case"Integer":case"Number":return this.getMainResultNumberTexture();case"Array(2)":return this.getMainResultArray2Texture();case"Array(3)":return this.getMainResultArray3Texture();case"Array(4)":return this.getMainResultArray4Texture();default:throw new Error(`unhandled returnType type ${this.returnType}`)}}getMainResultKernelNumberTexture(){throw new Error("abstract method call")}getMainResultSubKernelNumberTexture(){throw new Error("abstract method call")}getMainResultKernelArray2Texture(){throw new Error("abstract method call")}getMainResultSubKernelArray2Texture(){throw new Error("abstract method call")}getMainResultKernelArray3Texture(){throw new Error("abstract method call")}getMainResultSubKernelArray3Texture(){throw new Error("abstract method call")}getMainResultKernelArray4Texture(){throw new Error("abstract method call")}getMainResultSubKernelArray4Texture(){throw new Error("abstract method call")}getMainResultGraphical(){throw new Error("abstract method call")}getMainResultMemoryOptimizedFloats(){throw new Error("abstract method call")}getMainResultPackedPixels(){throw new Error("abstract method call")}getMainResultString(){return this.graphical?this.getMainResultGraphical():"single"===this.precision?this.optimizeFloatMemory?this.getMainResultMemoryOptimizedFloats():this.getMainResultTexture():this.getMainResultPackedPixels()}getMainResultNumberTexture(){return n.linesToString(this.getMainResultKernelNumberTexture())+n.linesToString(this.getMainResultSubKernelNumberTexture())}getMainResultArray2Texture(){return n.linesToString(this.getMainResultKernelArray2Texture())+n.linesToString(this.getMainResultSubKernelArray2Texture())}getMainResultArray3Texture(){return n.linesToString(this.getMainResultKernelArray3Texture())+n.linesToString(this.getMainResultSubKernelArray3Texture())}getMainResultArray4Texture(){return n.linesToString(this.getMainResultKernelArray4Texture())+n.linesToString(this.getMainResultSubKernelArray4Texture())}getFloatTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic)} float;\n`}getIntTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic,!0)} int;\n`}getSampler2DTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic)} sampler2D;\n`}getSampler2DArrayTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic)} sampler2DArray;\n`}renderTexture(){return this.immutable?this.texture.clone():this.texture}readPackedPixelsToUint8Array(){if("unsigned"!==this.precision)throw new Error('Requires this.precision to be "unsigned"');const{texSize:e,context:t}=this,r=new Uint8Array(e[0]*e[1]*4);return t.readPixels(0,0,e[0],e[1],t.RGBA,t.UNSIGNED_BYTE,r),r}readPackedPixelsToFloat32Array(){return new Float32Array(this.readPackedPixelsToUint8Array().buffer)}readFloatPixelsToFloat32Array(){if("single"!==this.precision)throw new Error('Requires this.precision to be "single"');const{texSize:e,context:t}=this,r=e[0],n=e[1],s=new Float32Array(r*n*4);return t.readPixels(0,0,r,n,t.RGBA,t.FLOAT,s),s}getPixels(e){const{context:t,output:r}=this,[s,i]=r,a=new Uint8Array(s*i*4);t.readPixels(0,0,s,i,t.RGBA,t.UNSIGNED_BYTE,a);const o=new Uint8ClampedArray((e?a:n.flipPixels(a,s,i)).buffer);return this.asyncMode?Promise.resolve(o):o}renderKernelsToArrays(){const e={result:this.renderOutput()};for(let t=0;t0){for(let e=0;e0){const{mappedTextures:r}=this;for(let n=0;n{const{utils:r}=i(),{FunctionNode:n}=l(),s={"<":"ceil",">=":"ceil",">":"floor","<=":"floor"};function a(e){if(!e||"object"!=typeof e)return!0;if(Array.isArray(e))return e.every(a);if("UpdateExpression"===e.type||"AssignmentExpression"===e.type||"SequenceExpression"===e.type)return!1;for(const t in e)if("loc"!==t&&"range"!==t&&"parent"!==t&&!a(e[t]))return!1;return!0}function o(e){let t=!1;function r(e){if(!e||"object"!=typeof e||t)return!1;if(Array.isArray(e))return e.some(r);if("MemberExpression"===e.type&&e.computed)return!0;for(const t in e)if("loc"!==t&&"range"!==t&&"parent"!==t&&r(e[t]))return!0;return!1}return function e(n){if(n&&"object"==typeof n&&!t)if(Array.isArray(n))n.forEach(e);else if("MemberExpression"===n.type&&n.computed&&r(n.property))t=!0;else for(const t in n)"loc"!==t&&"range"!==t&&"parent"!==t&&e(n[t])}(e),t}function u(e,t){if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(e=>u(e,t));if("CallExpression"===e.type&&"Identifier"===e.callee.type&&e.callee.name===t)return!0;for(const r in e)if("loc"!==r&&"range"!==r&&"parent"!==r&&u(e[r],t))return!0;return!1}function h(e){let t=!1;return function e(r){if(r&&"object"==typeof r&&!t)if(Array.isArray(r))r.forEach(e);else if("CallExpression"===r.type&&"Identifier"===r.callee.type&&r.arguments.some(e=>u(e,r.callee.name)))t=!0;else for(const t in r)"loc"!==t&&"range"!==t&&"parent"!==t&&e(r[t])}(e),t}function c(e){const t="ExpressionStatement"===e.type&&"AssignmentExpression"===e.expression.type?e.expression:null;return function e(r){if(!r||"object"!=typeof r)return!0;if(Array.isArray(r))return r.every(e);if("string"==typeof r.type){if("UpdateExpression"===r.type||"SequenceExpression"===r.type)return!1;if("AssignmentExpression"===r.type&&r!==t)return!1}for(const t in r)if("loc"!==t&&"range"!==t&&"parent"!==t&&!e(r[t]))return!1;return!0}(e)}const p={"Matrix(2)":2,"Matrix(3)":3,"Matrix(4)":4},d={Array:"sampler2D","Array(2)":"vec2","Array(3)":"vec3","Array(4)":"vec4","Matrix(2)":"mat2","Matrix(3)":"mat3","Matrix(4)":"mat4",Array2D:"sampler2D",Array3D:"sampler2D",Boolean:"bool",Float:"float",Input:"sampler2D",Integer:"int",Number:"float",LiteralInteger:"float",NumberTexture:"sampler2D",MemoryOptimizedNumberTexture:"sampler2D","ArrayTexture(1)":"sampler2D","ArrayTexture(2)":"sampler2D","ArrayTexture(3)":"sampler2D","ArrayTexture(4)":"sampler2D",HTMLVideo:"sampler2D",HTMLCanvas:"sampler2D",OffscreenCanvas:"sampler2D",HTMLImage:"sampler2D",ImageBitmap:"sampler2D",ImageData:"sampler2D",HTMLImageArray:"sampler2DArray"},m={"===":"==","!==":"!="};t.exports={WebGLFunctionNode:class extends n{constructor(e,t){super(e,t),t&&t.hasOwnProperty("fixIntegerDivisionAccuracy")&&(this.fixIntegerDivisionAccuracy=t.fixIntegerDivisionAccuracy)}astConditionalExpression(e,t){if("ConditionalExpression"!==e.type)throw this.astErrorOutput("Not a conditional expression",e);const r=this.getType(e.consequent),n=this.getType(e.alternate);return null===r&&null===n?(t.push("if ("),this.astGeneric(e.test,t),t.push(") {"),this.astGeneric(e.consequent,t),t.push(";"),t.push("} else {"),this.astGeneric(e.alternate,t),t.push(";"),t.push("}"),t):(t.push("("),this.astGeneric(e.test,t),t.push("?"),this.astGeneric(e.consequent,t),t.push(":"),this.astGeneric(e.alternate,t),t.push(")"),t)}astFunction(e,t){if(this.isRootKernel)t.push("void");else{this.returnType||this.findLastReturn()&&(this.returnType=this.getType(e.body),"LiteralInteger"===this.returnType&&(this.returnType="Number"));const{returnType:r}=this;if(r){const e=d[r];if(!e)throw new Error(`unknown type ${r}`);t.push(e)}else t.push("void")}if(t.push(" "),t.push(this.name),t.push("("),!this.isRootKernel)for(let n=0;n0&&t.push(", ");let i=this.argumentTypes[this.argumentNames.indexOf(s)];if(!i)throw this.astErrorOutput(`Unknown argument ${s} type`,e);"LiteralInteger"===i&&(this.argumentTypes[n]=i="Number");const a=d[i];if(!a)throw this.astErrorOutput("Unexpected expression",e);const o=r.sanitizeName(s);"sampler2D"===a||"sampler2DArray"===a?t.push(`${a} user_${o},ivec2 user_${o}Size,ivec3 user_${o}Dim`):t.push(`${a} user_${o}`)}t.push(") {\n");for(let r=0;r>":"bitwiseSignedRightShift",">>>":"bitwiseZeroFillRightShift"}[e.operator];if(!r)return null;switch(t.push(r),t.push("("),this.getType(e.left)){case"Number":case"Float":this.castValueToInteger(e.left,t);break;case"LiteralInteger":this.castLiteralToInteger(e.left,t);break;default:this.astGeneric(e.left,t)}switch(t.push(","),this.getType(e.right)){case"Number":case"Float":this.castValueToInteger(e.right,t);break;case"LiteralInteger":this.castLiteralToInteger(e.right,t);break;default:this.astGeneric(e.right,t)}return t.push(")"),t}checkAndUpconvertBitwiseUnary(e,t){const r={"~":"bitwiseNot"}[e.operator];if(!r)return null;switch(t.push(r),t.push("("),this.getType(e.argument)){case"Number":case"Float":this.castValueToInteger(e.argument,t);break;case"LiteralInteger":this.castLiteralToInteger(e.argument,t);break;default:this.astGeneric(e.argument,t)}return t.push(")"),t}castLiteralToInteger(e,t){return this.pushState("casting-to-integer"),this.astGeneric(e,t),this.popState("casting-to-integer"),t}castLiteralToFloat(e,t){return this.pushState("casting-to-float"),this.astGeneric(e,t),this.popState("casting-to-float"),t}castValueToInteger(e,t){return this.pushState("casting-to-integer"),t.push("int("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-integer"),t}castValueToFloat(e,t){return this.pushState("casting-to-float"),t.push("float("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-float"),t}astIdentifierExpression(e,t){if("Identifier"!==e.type)throw this.astErrorOutput("IdentifierExpression - not an Identifier",e);const n=this.getType(e),s=r.sanitizeName(e.name);return"Infinity"===e.name?t.push("3.402823466e+38"):"Boolean"===n&&this.argumentNames.indexOf(s)>-1?t.push(`bool(user_${s})`):t.push(`user_${s}`),t}astForStatement(e,t){if("ForStatement"!==e.type)throw this.astErrorOutput("Invalid for statement",e);const r=[],n=[],s=[],i=[];let a=null;if(e.init){const{declarations:t}=e.init;t.length>1&&(a=!1),this.astGeneric(e.init,r);for(let e=0;e0&&t.push(r.join(""),"\n"),t.push(`for (int ${e}=0;${e}0&&t.push(`if (!${n.join("")}) break;\n`),t.push(i.join("")),t.push(`\n${s.join("")};`),t.push("}\n")}return t}astWhileStatement(e,t){if("WhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);const r=this.getInternalVariableName("safeI");return t.push(`for (int ${r}=0;${r}null!==e&&(o(e)||h(e))))return null;const i=e=>JSON.parse(JSON.stringify(e)),a=e=>({type:"IfStatement",test:{type:"UnaryExpression",operator:"!",prefix:!0,argument:e},consequent:{type:"BlockStatement",body:[{type:"BreakStatement",label:null}]},alternate:null}),u=e=>"VariableDeclaration"===e.type?e:{type:"ExpressionStatement",expression:e},l="BlockStatement"===e.body.type?e.body.body.slice():[e.body],c=(e,t)=>{const r=e=>{if(!e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map(r);switch(e.type){case"ContinueStatement":return{type:"BlockStatement",body:[...t(),e]};case"ForStatement":case"WhileStatement":case"DoWhileStatement":default:return e;case"IfStatement":return{...e,consequent:r(e.consequent),alternate:r(e.alternate)};case"BlockStatement":return{...e,body:e.body.map(r)};case"SwitchStatement":return{...e,cases:e.cases.map(e=>({...e,consequent:e.consequent.map(r)}))}}};return e.map(r)},p=[];"DoWhileStatement"===t?(p.push(...n?c(l,()=>[a(i(n))]):l),n&&p.push(a(n))):(n&&p.push(a(n)),p.push(...s?c(l,()=>[u(i(s))]):l),s&&p.push(u(s)));const d={type:"BlockStatement",body:[...r?[u(r)]:[],{type:"WhileStatement",test:{type:"Literal",value:!0,raw:"true"},body:{type:"BlockStatement",body:p}}]};let m=this.syntheticNodeId||1073741824;const f=e=>{if(e&&"object"==typeof e)if(Array.isArray(e))e.forEach(f);else{"string"==typeof e.type&&void 0===e.start&&(e.start=m,e.end=m+1,m+=2);for(const t in e)"loc"!==t&&"range"!==t&&"parent"!==t&&f(e[t])}};return f(d),this.syntheticNodeId=m,d}linearizeStatement(e){const t=[];let r=!1,n=this.linearTempId||0;const s=e=>({type:"Identifier",name:e}),i=(e,t,r)=>({type:"VariableDeclaration",kind:e,declarations:[{type:"VariableDeclarator",id:s(t),init:r}]}),o=(e,t)=>{const r="hoistSeq"+n++;return e.push(i("const",r,t)),s(r)},l=e=>!a(e),h=(e,t)=>{if(r||!e||"object"!=typeof e)return e;switch(e.type){case"Identifier":case"Literal":case"ThisExpression":return e;case"MemberExpression":{const r=h(e.object,t),n=e.computed?h(e.property,t):e.property;return{...e,object:r,property:n}}case"CallExpression":{const r=e.arguments.map(e=>h(e,t));if("Identifier"===e.callee.type)for(let n=0;nh(e,t))};case"UpdateExpression":{if("Identifier"!==e.argument.type)return r=!0,e;if(e.prefix)return t.push({type:"ExpressionStatement",expression:e}),o(t,e.argument);const n=o(t,e.argument);return t.push({type:"ExpressionStatement",expression:e}),n}case"AssignmentExpression":{if("Identifier"!==e.left.type)return r=!0,e;const n=h(e.right,t);return t.push({type:"ExpressionStatement",expression:{...e,right:n}}),o(t,e.left)}case"SequenceExpression":for(let r=0;r({type:"ExpressionStatement",expression:{type:"AssignmentExpression",operator:"=",left:s(e),right:t}});return o.push(d(a,c)),u.push(d(a,p)),t.push({type:"IfStatement",test:r,consequent:{type:"BlockStatement",body:o},alternate:{type:"BlockStatement",body:u}}),s(a)}case"LogicalExpression":{if(!l(e.right))return{...e,left:h(e.left,t)};const r=h(e.left,t),a="hoistSeq"+n++;t.push(i("let",a,r));const o=[],u=h(e.right,o);return o.push({type:"ExpressionStatement",expression:{type:"AssignmentExpression",operator:"=",left:s(a),right:u}}),t.push({type:"IfStatement",test:"&&"===e.operator?s(a):{type:"UnaryExpression",operator:"!",prefix:!0,argument:s(a)},consequent:{type:"BlockStatement",body:o},alternate:null}),s(a)}default:return r=!0,e}};switch(e.type){case"ExpressionStatement":{const r=e.expression;if("AssignmentExpression"===r.type&&"Identifier"===r.left.type){const e=h(r.right,t);t.push({type:"ExpressionStatement",expression:{...r,right:e}})}else{const e=h(r,t);"UpdateExpression"!==e.type&&"AssignmentExpression"!==e.type||t.push({type:"ExpressionStatement",expression:e})}break}case"VariableDeclaration":for(let r=0;r{if(e&&"object"==typeof e)if(Array.isArray(e))e.forEach(p);else{"string"==typeof e.type&&void 0===e.start&&(e.start=c,e.end=c+1,c+=2);for(const t in e)"loc"!==t&&"range"!==t&&"parent"!==t&&p(e[t])}};return p(t),this.syntheticNodeId=c,t}astStatementWithHoisting(e,t){switch(e.type){case"ExpressionStatement":case"VariableDeclaration":case"ReturnStatement":{if(!c(e))return this.astGeneric(e,t);const r=this.hoistedIndexReads,n=this.hoistedIndexReads=[],s=[];return this.astGeneric(e,s),this.hoistedIndexReads=r,t.push(...n,...s),t}default:return this.astGeneric(e,t)}}astVariableDeclaration(e,t){const n=e.declarations;if(!n||!n[0]||!n[0].init)throw this.astErrorOutput("Unexpected expression",e);const s=[];let i=null;const a=[];let o=[];for(let t=0;t0&&a.push(o.join(",")),s.push(a.join(";")),t.push(s.join("")),t.push(";"),t}astIfStatement(e,t){return t.push("if ("),this.astGeneric(e.test,t),t.push(")"),"BlockStatement"===e.consequent.type?this.astGeneric(e.consequent,t):(t.push(" {\n"),this.astGeneric(e.consequent,t),t.push("\n}\n")),e.alternate&&(t.push("else "),"BlockStatement"===e.alternate.type||"IfStatement"===e.alternate.type?this.astGeneric(e.alternate,t):(t.push(" {\n"),this.astGeneric(e.alternate,t),t.push("\n}\n"))),t}astSwitchCaseConsequent(e,t){const r=[];for(let t=0;t{if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(t);if("BreakStatement"===e.type)return!0;if("ForStatement"===e.type||"WhileStatement"===e.type||"DoWhileStatement"===e.type||"SwitchStatement"===e.type)return!1;for(const r in e)if("loc"!==r&&"range"!==r&&"parent"!==r&&t(e[r]))return!0;return!1};if(t(r[e]))throw this.astErrorOutput("break inside a switch case is only supported as the case terminator",r[e])}for(let e=0;er+1){u=!0,this.astSwitchCaseConsequent(n[r].consequent,o);continue}t.push(" else {\n")}this.astSwitchCaseConsequent(n[r].consequent,t),t.push("\n}")}return u&&(t.push(" else {"),t.push(o.join("")),t.push("}")),t}astThisExpression(e,t){return t.push("this"),t}astMemberExpression(e,t){const{property:n,name:s,signature:i,origin:a,type:o,xProperty:u,yProperty:l,zProperty:h}=this.getMemberExpressionDetails(e);switch(i){case"value.thread.value":case"this.thread.value":if("x"!==s&&"y"!==s&&"z"!==s)throw this.astErrorOutput("Unexpected expression, expected `this.thread.x`, `this.thread.y`, or `this.thread.z`",e);return t.push(`threadId.${s}`),t;case"this.output.value":if(this.dynamicOutput)switch(s){case"x":this.isState("casting-to-float")?t.push("float(uOutputDim.x)"):t.push("uOutputDim.x");break;case"y":this.isState("casting-to-float")?t.push("float(uOutputDim.y)"):t.push("uOutputDim.y");break;case"z":this.isState("casting-to-float")?t.push("float(uOutputDim.z)"):t.push("uOutputDim.z");break;default:throw this.astErrorOutput("Unexpected expression",e)}else switch(s){case"x":this.isState("casting-to-integer")?t.push(this.output[0]):t.push(this.output[0],".0");break;case"y":this.isState("casting-to-integer")?t.push(this.output[1]):t.push(this.output[1],".0");break;case"z":this.isState("casting-to-integer")?t.push(this.output[2]):t.push(this.output[2],".0");break;default:throw this.astErrorOutput("Unexpected expression",e)}return t;case"value":throw this.astErrorOutput("Unexpected expression",e);case"value[]":case"value[][]":case"value[][][]":case"value[][][][]":case"value.value":if("Math"===a)return t.push(Math[s]),t;const i=r.sanitizeName(s);switch(n){case"r":return t.push(`user_${i}.r`),t;case"g":return t.push(`user_${i}.g`),t;case"b":return t.push(`user_${i}.b`),t;case"a":return t.push(`user_${i}.a`),t}break;case"this.constants.value":if(void 0===u)switch(o){case"Array(2)":case"Array(3)":case"Array(4)":return t.push(`constants_${r.sanitizeName(s)}`),t}case"this.constants.value[]":case"this.constants.value[][]":case"this.constants.value[][][]":case"this.constants.value[][][][]":break;case"fn()[]":return this.astCallExpression(e.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(n)),t.push("]"),t;case"fn()[][]":{const r=e.object.property,n=e.property,s=p[this.getType(e.object.object)],i=e=>"LiteralInteger"===this.getType(e);return!s||i(r)&&i(n)?(this.astCallExpression(e.object.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(r)),t.push("]"),t.push("["),t.push(this.memberExpressionPropertyMarkup(n)),t.push("]"),t):(t.push(`getMatrix${s}(`),this.astCallExpression(e.object.object,t),t.push(", "),t.push(this.memberExpressionPropertyMarkup(r)),t.push(", "),t.push(this.memberExpressionPropertyMarkup(n)),t.push(")"),t)}case"[][]":return this.astArrayExpression(e.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(n)),t.push("]"),t;default:throw this.astErrorOutput("Unexpected expression",e)}if(!1===e.computed)switch(o){case"Number":case"Integer":case"Float":case"Boolean":return t.push(`${a}_${r.sanitizeName(s)}`),t}const c=`${a}_${r.sanitizeName(s)}`;switch(o){case"Array(2)":case"Array(3)":case"Array(4)":this.astGeneric(e.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(u)),t.push("]");break;case"HTMLImageArray":t.push(`getImage3D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"ArrayTexture(1)":t.push(`getFloatFromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"Array1D(2)":case"Array2D(2)":case"Array3D(2)":t.push(`getMemoryOptimizedVec2(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"ArrayTexture(2)":t.push(`getVec2FromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"Array1D(3)":case"Array2D(3)":case"Array3D(3)":t.push(`getMemoryOptimizedVec3(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"ArrayTexture(3)":t.push(`getVec3FromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"Array1D(4)":case"Array2D(4)":case"Array3D(4)":t.push(`getMemoryOptimizedVec4(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"ArrayTexture(4)":case"HTMLCanvas":case"OffscreenCanvas":case"HTMLImage":case"ImageBitmap":case"ImageData":case"HTMLVideo":t.push(`getVec4FromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"NumberTexture":case"Array":case"Array2D":case"Array3D":case"Array4D":case"Input":case"Number":case"Float":case"Integer":if("single"===this.precision)t.push(`getMemoryOptimized32(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");else{const e="user"===a?this.lookupFunctionArgumentBitRatio(this.name,s):this.constantBitRatios[s];switch(e){case 1:t.push(`get8(${c}, ${c}Size, ${c}Dim, `);break;case 2:t.push(`get16(${c}, ${c}Size, ${c}Dim, `);break;case 4:case 0:t.push(`get32(${c}, ${c}Size, ${c}Dim, `);break;default:throw new Error(`unhandled bit ratio of ${e}`)}this.memberExpressionXYZ(u,l,h,t),t.push(")")}break;case"MemoryOptimizedNumberTexture":t.push(`getMemoryOptimized32(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":t.push(`${c}[${this.memberExpressionPropertyMarkup(l)}]`),l&&t.push(`[${this.memberExpressionPropertyMarkup(u)}]`);break;default:throw new Error(`unhandled member expression "${o}"`)}return t}astCallExpression(e,t){if(!e.callee)throw this.astErrorOutput("Unknown CallExpression",e);let n=null;const s=this.isAstMathFunction(e);if(n=s||e.callee.object&&"ThisExpression"===e.callee.object.type?e.callee.property.name:"SequenceExpression"!==e.callee.type||"Literal"!==e.callee.expressions[0].type||isNaN(e.callee.expressions[0].raw)?e.callee.name:e.callee.expressions[1].property.name,!n)throw this.astErrorOutput("Unhandled function, couldn't find name",e);switch(n){case"pow":n="_pow";break;case"round":n="_round"}if(this.calledFunctions.indexOf(n)<0&&this.calledFunctions.push(n),"random"===n&&this.plugins&&this.plugins.length>0)for(let e=0;e0&&t.push(", "),"Integer"===s)this.castValueToFloat(n,t);else this.astGeneric(n,t)}else{const s=this.lookupFunctionArgumentTypes(n)||[];for(let i=0;i0&&t.push(", ");const u=this.getType(a);switch(o||(this.triggerImplyArgumentType(n,i,u,this),o=u),u){case"Boolean":this.astGeneric(a,t);continue;case"Number":case"Float":if("Integer"===o){t.push("int("),this.astGeneric(a,t),t.push(")");continue}if("Number"===o||"Float"===o){this.astGeneric(a,t);continue}if("LiteralInteger"===o){this.castLiteralToFloat(a,t);continue}break;case"Integer":if("Number"===o||"Float"===o){t.push("float("),this.astGeneric(a,t),t.push(")");continue}if("Integer"===o){this.astGeneric(a,t);continue}break;case"LiteralInteger":if("Integer"===o){this.castLiteralToInteger(a,t);continue}if("Number"===o||"Float"===o){this.castLiteralToFloat(a,t);continue}if("LiteralInteger"===o){this.astGeneric(a,t);continue}break;case"Array(2)":case"Array(3)":case"Array(4)":if(o===u){if("Identifier"===a.type)t.push(`user_${r.sanitizeName(a.name)}`);else{if("ArrayExpression"!==a.type&&"MemberExpression"!==a.type&&"CallExpression"!==a.type)throw this.astErrorOutput(`Unhandled argument type ${a.type}`,e);this.astGeneric(a,t)}continue}break;case"HTMLCanvas":case"OffscreenCanvas":case"HTMLImage":case"ImageBitmap":case"ImageData":case"HTMLImageArray":case"HTMLVideo":case"ArrayTexture(1)":case"ArrayTexture(2)":case"ArrayTexture(3)":case"ArrayTexture(4)":case"Array":case"Input":if(o===u){if("Identifier"!==a.type)throw this.astErrorOutput(`Unhandled argument type ${a.type}`,e);this.triggerImplyArgumentBitRatio(this.name,a.name,n,i);const s=r.sanitizeName(a.name);t.push(`user_${s},user_${s}Size,user_${s}Dim`);continue}}throw this.astErrorOutput(`Unhandled argument combination of ${u} and ${o} for argument named "${a.name}"`,e)}}return t.push(")"),t}astArrayExpression(e,t){const r=this.getType(e),n=e.elements.length;switch(r){case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":t.push(`mat${n}(`);break;default:t.push(`vec${n}(`)}for(let r=0;r0&&t.push(", ");const n=e.elements[r];this.astGeneric(n,t)}return t.push(")"),t}memberExpressionXYZ(e,t,r,n){return r?n.push(this.memberExpressionPropertyMarkup(r),", "):n.push("0, "),t?n.push(this.memberExpressionPropertyMarkup(t),", "):n.push("0, "),n.push(this.memberExpressionPropertyMarkup(e)),n}memberExpressionPropertyMarkup(e){if(!e)throw new Error("Property not set");const t=[];switch(this.getType(e)){case"Number":case"Float":this.castValueToInteger(e,t);break;case"LiteralInteger":this.castLiteralToInteger(e,t);break;default:this.astGeneric(e,t)}const n=t.join("");if(this.hoistedIndexReads&&/\b\w+\((user_|constants_)\w+, \1\w+Size/.test(n)){const e=`hoisted_${this.hoistedIndexReads.length}_${r.sanitizeName(this.name)}`,t=n.startsWith("int(");return this.hoistedIndexReads.push(`${t?"int":"float"} ${e}=${n};\n`),e}return n}}}}),M=e((e,t)=>{t.exports={name:"math-random-uniformly-distributed",onBeforeRun:e=>{if(null===e.randomSeed||void 0===e.randomSeed)return e.setUniform1f("randomSeed1",Math.random()),void e.setUniform1f("randomSeed2",Math.random());e._mathRandomGenerator&&e._mathRandomGeneratorSeed===e.randomSeed||(e._mathRandomGenerator=function(e){let t=e>>>0;return function(){t=t+1831565813>>>0;let e=t;return e=Math.imul(e^e>>>15,1|e),e^=e+Math.imul(e^e>>>7,61|e),((e^e>>>14)>>>0)/4294967296}}(e.randomSeed),e._mathRandomGeneratorSeed=e.randomSeed),e.setUniform1f("randomSeed1",e._mathRandomGenerator()),e.setUniform1f("randomSeed2",e._mathRandomGenerator())},functionMatch:"Math.random()",functionReplace:"nrand(vTexCoord)",functionReturnType:"Number",source:"// https://www.shadertoy.com/view/4t2SDh\n//note: uniformly distributed, normalized rand, [0,1]\nhighp float randomSeedShift = 1.0;\nhighp float slide = 1.0;\nuniform highp float randomSeed1;\nuniform highp float randomSeed2;\n\nhighp float nrand(highp vec2 n) {\n highp float result = fract(sin(dot((n.xy + 1.0) * vec2(randomSeed1 * slide, randomSeed2 * randomSeedShift), vec2(12.9898, 78.233))) * 43758.5453);\n randomSeedShift = result;\n if (randomSeedShift > 0.5) {\n slide += 0.00009; \n } else {\n slide += 0.0009;\n }\n return result;\n}"}}),G=e((e,t)=>{t.exports={fragmentShader:`__HEADER__;\n__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n\nconst int LOOP_MAX = __LOOP_MAX__;\n\n__PLUGINS__;\n__CONSTANTS__;\n\nvarying vec2 vTexCoord;\n\nfloat acosh(float x) {\n return log(x + sqrt(x * x - 1.0));\n}\n\nfloat sinh(float x) {\n return (pow(${Math.E}, x) - pow(${Math.E}, -x)) / 2.0;\n}\n\nfloat asinh(float x) {\n return log(x + sqrt(x * x + 1.0));\n}\n\nfloat atan2(float v1, float v2) {\n if (v2 == 0.0) {\n if (v1 == 0.0) return 0.0;\n if (v1 > 0.0) return 1.5707963267948966;\n if (v1 < 0.0) return -1.5707963267948966;\n }\n return atan(v1, v2);\n}\n\nfloat atanh(float x) {\n x = (x + 1.0) / (x - 1.0);\n if (x < 0.0) {\n return 0.5 * log(-x);\n }\n return 0.5 * log(x);\n}\n\nfloat cbrt(float x) {\n if (x >= 0.0) {\n return pow(x, 1.0 / 3.0);\n } else {\n return -pow(x, 1.0 / 3.0);\n }\n}\n\nfloat cosh(float x) {\n return (pow(${Math.E}, x) + pow(${Math.E}, -x)) / 2.0; \n}\n\nfloat expm1(float x) {\n return pow(${Math.E}, x) - 1.0; \n}\n\nfloat fround(highp float x) {\n return x;\n}\n\nfloat imul(float v1, float v2) {\n return float(int(v1) * int(v2));\n}\n\nfloat log10(float x) {\n return log2(x) * (1.0 / log2(10.0));\n}\n\nfloat log1p(float x) {\n return log(1.0 + x);\n}\n\nfloat _pow(float v1, float v2) {\n if (v2 == 0.0) return 1.0;\n return pow(v1, v2);\n}\n\nfloat tanh(float x) {\n float e = exp(2.0 * x);\n return (e - 1.0) / (e + 1.0);\n}\n\nfloat trunc(float x) {\n if (x >= 0.0) {\n return floor(x); \n } else {\n return ceil(x);\n }\n}\n\nvec4 _round(vec4 x) {\n return floor(x + 0.5);\n}\n\nfloat _round(float x) {\n return floor(x + 0.5);\n}\n\nconst int BIT_COUNT = 32;\nint modi(int x, int y) {\n return x - y * (x / y);\n}\n\nint bitwiseOr(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) || (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseXOR(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) != (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseAnd(int a, int b) {\n int result = 0;\n int n = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) && (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 && b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseNot(int a) {\n // ~a is identically -a - 1 in two's complement, for every value including\n // negatives. The previous bit-by-bit loop only worked for a >= 0, where it\n // leaned on 32-bit overflow wrapping to reach the negative answer; given a\n // negative input it computed ~abs(a), so ~(-1) gave -2 and ~~x never\n // returned x.\n return -a - 1;\n}\nint bitwiseZeroFillLeftShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n *= 2;\n }\n\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\n// _pow2 is defined further down, alongside encode32/decode32\nfloat _pow2(float e);\nint bitwiseSignedRightShift(int num, int shifts) {\n // pow(2.0, n) is approximate on many GPUs, and landing 1 ulp high makes the\n // division fall just under a whole number, which floor() then rounds away:\n // 2 >> 1 came out 0, 8 >> 1 came out 3. Only exact left operands were\n // affected, odd ones having enough slack to survive. _pow2 is exact.\n return int(floor(float(num) / _pow2(float(shifts))));\n}\n\nint bitwiseZeroFillRightShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n /= 2;\n }\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\nvec2 integerMod(vec2 x, float y) {\n vec2 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec3 integerMod(vec3 x, float y) {\n vec3 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec4 integerMod(vec4 x, vec4 y) {\n vec4 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nfloat integerMod(float x, float y) {\n float res = floor(mod(x, y));\n return res * (res > floor(y) - 1.0 ? 0.0 : 1.0);\n}\n\nint integerMod(int x, int y) {\n return x - (y * int(x / y));\n}\n\n// GLSL ES 1.00 accepts only a constant or a loop symbol inside an index\n// expression, so m[y][x] does not compile when y and x come from kernel\n// arguments -- the error is "Index expression can only contain const or loop\n// symbols". Loop counters are legal indices, so walk the matrix with them\n// instead. These are 2x2 to 4x4, so it costs at most sixteen comparisons.\nfloat getMatrix2(mat2 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 2; i++) {\n for (int j = 0; j < 2; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix3(mat3 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 3; i++) {\n for (int j = 0; j < 3; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix4(mat4 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 4; i++) {\n for (int j = 0; j < 4; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\n__DIVIDE_WITH_INTEGER_CHECK__;\n\n// Here be dragons!\n// DO NOT OPTIMIZE THIS CODE\n// YOU WILL BREAK SOMETHING ON SOMEBODY'S MACHINE\n// LEAVE IT AS IT IS, LEST YOU WASTE YOUR OWN TIME\n// Exact powers of two built from exact constant multiplies: exp2/log2/pow\n// are approximate on some GPUs (notably Apple silicon), and 1-2 ulp there\n// corrupts the packed bytes (#659)\nfloat _pow2(float e) {\n float r = 1.0;\n float a = abs(e);\n bool n = e < 0.0;\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 32.0) { r *= n ? 2.3283064365386963e-10 : 4294967296.0; a -= 32.0; }\n if (a >= 16.0) { r *= n ? 0.0000152587890625 : 65536.0; a -= 16.0; }\n if (a >= 8.0) { r *= n ? 0.00390625 : 256.0; a -= 8.0; }\n if (a >= 4.0) { r *= n ? 0.0625 : 16.0; a -= 4.0; }\n if (a >= 2.0) { r *= n ? 0.25 : 4.0; a -= 2.0; }\n if (a >= 1.0) { r *= n ? 0.5 : 2.0; }\n return r;\n}\nconst vec2 MAGIC_VEC = vec2(1.0, -256.0);\nconst vec4 SCALE_FACTOR = vec4(1.0, 256.0, 65536.0, 0.0);\nconst vec4 SCALE_FACTOR_INV = vec4(1.0, 0.00390625, 0.0000152587890625, 0.0); // 1, 1/256, 1/65536\nfloat decode32(vec4 texel) {\n __DECODE32_ENDIANNESS__;\n texel *= 255.0;\n vec2 gte128;\n gte128.x = texel.b >= 128.0 ? 1.0 : 0.0;\n gte128.y = texel.a >= 128.0 ? 1.0 : 0.0;\n float exponent = 2.0 * texel.a - 127.0 + dot(gte128, MAGIC_VEC);\n float res = _pow2(_round(exponent));\n texel.b = texel.b - 128.0 * gte128.x;\n res = dot(texel, SCALE_FACTOR) * _pow2(_round(exponent-23.0)) + res;\n res *= gte128.y * -2.0 + 1.0;\n return res;\n}\n\nfloat decode16(vec4 texel, int index) {\n int channel = integerMod(index, 2);\n if (channel == 0) return texel.r * 255.0 + texel.g * 65280.0;\n if (channel == 1) return texel.b * 255.0 + texel.a * 65280.0;\n return 0.0;\n}\n\nfloat decode8(vec4 texel, int index) {\n int channel = integerMod(index, 4);\n if (channel == 0) return texel.r * 255.0;\n if (channel == 1) return texel.g * 255.0;\n if (channel == 2) return texel.b * 255.0;\n if (channel == 3) return texel.a * 255.0;\n return 0.0;\n}\n\nvec4 legacyEncode32(float f) {\n float F = abs(f);\n float sign = f < 0.0 ? 1.0 : 0.0;\n float exponent = floor(log2(F));\n float mantissa = (exp2(-exponent) * F);\n // exponent += floor(log2(mantissa));\n vec4 texel = vec4(F * exp2(23.0-exponent)) * SCALE_FACTOR_INV;\n texel.rg = integerMod(texel.rg, 256.0);\n texel.b = integerMod(texel.b, 128.0);\n texel.a = exponent*0.5 + 63.5;\n texel.ba += vec2(integerMod(exponent+127.0, 2.0), sign) * 128.0;\n texel = floor(texel);\n texel *= 0.003921569; // 1/255\n __ENCODE32_ENDIANNESS__;\n return texel;\n}\n\n// https://github.com/gpujs/gpu.js/wiki/Encoder-details\nvec4 encode32(float value) {\n if (value == 0.0) return vec4(0, 0, 0, 0);\n\n float exponent;\n float mantissa;\n vec4 result;\n float sgn;\n\n sgn = step(0.0, -value);\n value = abs(value);\n\n exponent = floor(log2(value));\n float p2 = _pow2(exponent);\n // approximate log2 can land one off; correct by direct comparison\n if (p2 > value) { exponent -= 1.0; p2 *= 0.5; }\n else if (p2 * 2.0 <= value) { exponent += 1.0; p2 *= 2.0; }\n\n mantissa = value / p2 - 1.0;\n exponent = exponent+127.0;\n result = vec4(0,0,0,0);\n\n result.a = floor(exponent/2.0);\n exponent = exponent - result.a*2.0;\n result.a = result.a + 128.0*sgn;\n\n result.b = floor(mantissa * 128.0);\n mantissa = mantissa - result.b / 128.0;\n result.b = result.b + exponent*128.0;\n\n result.g = floor(mantissa*32768.0);\n mantissa = mantissa - result.g/32768.0;\n\n result.r = floor(mantissa*8388608.0);\n return result/255.0;\n}\n// Dragons end here\n\nint index;\nivec3 threadId;\n\nivec3 indexTo3D(int idx, ivec3 texDim) {\n int z = int(idx / (texDim.x * texDim.y));\n idx -= z * int(texDim.x * texDim.y);\n int y = int(idx / texDim.x);\n int x = int(integerMod(idx, texDim.x));\n return ivec3(x, y, z);\n}\n\nfloat get32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n return decode32(texel);\n}\n\nfloat get16(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x * 2;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize.x * 2, texSize.y));\n return decode16(texel, index);\n}\n\nfloat get8(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x * 4;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize.x * 4, texSize.y));\n return decode8(texel, index);\n}\n\nfloat getMemoryOptimized32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 4);\n index = index / 4;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n if (channel == 0) return texel.r;\n if (channel == 1) return texel.g;\n if (channel == 2) return texel.b;\n if (channel == 3) return texel.a;\n return 0.0;\n}\n\nvec4 getImage2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n return texture2D(tex, st / vec2(texSize));\n}\n\nfloat getFloatFromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return result[0];\n}\n\nvec2 getVec2FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec2(result[0], result[1]);\n}\n\nvec2 getMemoryOptimizedVec2(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int channel = integerMod(index, 2);\n index = index / 2;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n if (channel == 0) return vec2(texel.r, texel.g);\n if (channel == 1) return vec2(texel.b, texel.a);\n return vec2(0.0, 0.0);\n}\n\nvec3 getVec3FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec3(result[0], result[1], result[2]);\n}\n\nvec3 getMemoryOptimizedVec3(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int fieldIndex = 3 * (x + texDim.x * (y + texDim.y * z));\n int vectorIndex = fieldIndex / 4;\n int vectorOffset = fieldIndex - vectorIndex * 4;\n int readY = vectorIndex / texSize.x;\n int readX = vectorIndex - readY * texSize.x;\n vec4 tex1 = texture2D(tex, (vec2(readX, readY) + 0.5) / vec2(texSize));\n \n if (vectorOffset == 0) {\n return tex1.xyz;\n } else if (vectorOffset == 1) {\n return tex1.yzw;\n } else {\n readX++;\n if (readX >= texSize.x) {\n readX = 0;\n readY++;\n }\n vec4 tex2 = texture2D(tex, vec2(readX, readY) / vec2(texSize));\n if (vectorOffset == 2) {\n return vec3(tex1.z, tex1.w, tex2.x);\n } else {\n return vec3(tex1.w, tex2.x, tex2.y);\n }\n }\n}\n\nvec4 getVec4FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n return getImage2D(tex, texSize, texDim, z, y, x);\n}\n\nvec4 getMemoryOptimizedVec4(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 2);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n return vec4(texel.r, texel.g, texel.b, texel.a);\n}\n\nvec4 actualColor;\nvoid color(float r, float g, float b, float a) {\n actualColor = vec4(r,g,b,a);\n}\n\nvoid color(float r, float g, float b) {\n color(r,g,b,1.0);\n}\n\nvoid color(sampler2D image) {\n actualColor = texture2D(image, vTexCoord);\n}\n\nfloat modulo(float number, float divisor) {\n if (number < 0.0) {\n number = abs(number);\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return -mod(number, divisor);\n }\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return mod(number, divisor);\n}\n\n__INJECTED_NATIVE__;\n__MAIN_CONSTANTS__;\n__MAIN_ARGUMENTS__;\n__KERNEL__;\n\nvoid main(void) {\n index = int(vTexCoord.s * float(uTexSize.x)) + int(vTexCoord.t * float(uTexSize.y)) * uTexSize.x;\n __MAIN_RESULT__;\n}`}}),z=e((e,t)=>{t.exports={vertexShader:"__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n\nattribute vec2 aPos;\nattribute vec2 aTexCoord;\n\nvarying vec2 vTexCoord;\nuniform vec2 ratio;\n\nvoid main(void) {\n gl_Position = vec4((aPos + vec2(1)) * ratio + vec2(-1), 0, 1);\n vTexCoord = aTexCoord;\n}"}}),N=e((e,t)=>{function r(e,t={}){const{contextName:r="gl",throwGetError:a,useTrackablePrimitives:o,recording:u=[],variables:l={},onReadPixels:h,onUnrecognizedArgumentLookup:c}=t,p=new Proxy(e,{get:function(t,p){switch(p){case"addComment":return w;case"checkThrowError":return _;case"getReadPixelsVariableName":return f;case"insertVariable":return b;case"reset":return x;case"setIndent":return S;case"toString":return y;case"getContextVariableName":return v}return"function"==typeof e[p]?function(){switch(p){case"getError":return a?u.push(`${g}if (${r}.getError() !== ${r}.NONE) throw new Error('error');`):u.push(`${g}${r}.getError();`),e.getError();case"getExtension":{const t=`${r}Variables${d.length}`;u.push(`${g}const ${t} = ${r}.getExtension('${arguments[0]}');`);const s=e.getExtension(arguments[0]);if(s&&"object"==typeof s){const e=n(s,{getEntity:T,useTrackablePrimitives:o,recording:u,contextName:t,contextVariables:d,variables:l,indent:g,onUnrecognizedArgumentLookup:c});return d.push(e),e}return d.push(null),s}case"readPixels":const t=d.indexOf(arguments[6]);let i;if(-1===t){const e=function(e){if(l)for(const t in l)if(l[t]===e)return t;return null}(arguments[6]);e?(i=e,u.push(`${g}${e}`)):(i=`${r}Variable${d.length}`,d.push(arguments[6]),u.push(`${g}const ${i} = new ${arguments[6].constructor.name}(${arguments[6].length});`))}else i=`${r}Variable${t}`;f=i;const p=[arguments[0],arguments[1],arguments[2],arguments[3],T(arguments[4]),T(arguments[5]),i];return u.push(`${g}${r}.readPixels(${p.join(", ")});`),h&&h(i,p),e.readPixels.apply(e,arguments);case"drawBuffers":return u.push(`${g}${r}.drawBuffers([${s(arguments[0],{contextName:r,contextVariables:d,getEntity:T,addVariable:A,variables:l,onUnrecognizedArgumentLookup:c})}]);`),e.drawBuffers(arguments[0])}let t=e[p].apply(e,arguments);switch(typeof t){case"undefined":return void u.push(`${g}${E(p,arguments)};`);case"number":case"boolean":if(o&&-1===d.indexOf(i(t))){u.push(`${g}const ${r}Variable${d.length} = ${E(p,arguments)};`),d.push(t=i(t));break}default:null===t?u.push(`${E(p,arguments)};`):u.push(`${g}const ${r}Variable${d.length} = ${E(p,arguments)};`),d.push(t)}return t}:(m[e[p]]=p,e[p])}}),d=[],m={};let f,g="";return p;function y(){return u.join("\n")}function x(){for(;u.length>0;)u.pop()}function b(e,t){l[e]=t}function T(e){const t=m[e];return t?r+"."+t:e}function S(e){g=" ".repeat(e)}function A(e,t){const n=`${r}Variable${d.length}`;return u.push(`${g}const ${n} = ${t};`),d.push(e),n}function w(e){u.push(`${g}// ${e}`)}function _(){u.push(`${g}(() => {\n${g}const error = ${r}.getError();\n${g}if (error !== ${r}.NONE) {\n${g} const names = Object.getOwnPropertyNames(gl);\n${g} for (let i = 0; i < names.length; i++) {\n${g} const name = names[i];\n${g} if (${r}[name] === error) {\n${g} throw new Error('${r} threw ' + name);\n${g} }\n${g} }\n${g}}\n${g}})();`)}function E(e,t){return`${r}.${e}(${s(t,{contextName:r,contextVariables:d,getEntity:T,addVariable:A,variables:l,onUnrecognizedArgumentLookup:c})})`}function v(e){const t=d.indexOf(e);return-1!==t?`${r}Variable${t}`:null}}function n(e,t){const r=new Proxy(e,{get:function(t,r){return"function"==typeof t[r]?function(){if("drawBuffersWEBGL"===r)return h.push(`${p}${a}.drawBuffersWEBGL([${s(arguments[0],{contextName:a,contextVariables:o,getEntity:m,addVariable:g,variables:c,onUnrecognizedArgumentLookup:d})}]);`),e.drawBuffersWEBGL(arguments[0]);let t=e[r].apply(e,arguments);switch(typeof t){case"undefined":return void h.push(`${p}${f(r,arguments)};`);case"number":case"boolean":l&&-1===o.indexOf(i(t))?(h.push(`${p}const ${a}Variable${o.length} = ${f(r,arguments)};`),o.push(t=i(t))):(h.push(`${p}const ${a}Variable${o.length} = ${f(r,arguments)};`),o.push(t));break;default:null===t?h.push(`${f(r,arguments)};`):h.push(`${p}const ${a}Variable${o.length} = ${f(r,arguments)};`),o.push(t)}return t}:(n[e[r]]=r,e[r])}}),n={},{contextName:a,contextVariables:o,getEntity:u,useTrackablePrimitives:l,recording:h,variables:c,indent:p,onUnrecognizedArgumentLookup:d}=t;return r;function m(e){return n.hasOwnProperty(e)?`${a}.${n[e]}`:u(e)}function f(e,t){return`${a}.${e}(${s(t,{contextName:a,contextVariables:o,getEntity:m,addVariable:g,variables:c,onUnrecognizedArgumentLookup:d})})`}function g(e,t){const r=`${a}Variable${o.length}`;return o.push(e),h.push(`${p}const ${r} = ${t};`),r}}function s(e,t){const{variables:r,onUnrecognizedArgumentLookup:n}=t;return Array.from(e).map(e=>{const s=function(e){if(r)for(const t in r)if(r.hasOwnProperty(t)&&r[t]===e)return t;return n?n(e):null}(e);return s||function(e,t){const{contextName:r,contextVariables:n,getEntity:s,addVariable:i,onUnrecognizedArgumentLookup:a}=t;if(void 0===e)return"undefined";if(null===e)return"null";const o=n.indexOf(e);if(o>-1)return`${r}Variable${o}`;switch(e.constructor.name){case"String":const t=/\n/.test(e),r=/'/.test(e),n=/"/.test(e);return t?"`"+e+"`":r&&!n?'"'+e+'"':"'"+e+"'";case"Number":case"Boolean":return s(e);case"Array":return i(e,`new ${e.constructor.name}([${Array.from(e).join(",")}])`);case"Float32Array":case"Uint8Array":case"Uint16Array":case"Int32Array":return i(e,`new ${e.constructor.name}(${JSON.stringify(Array.from(e))})`);default:if(a){const t=a(e);if(t)return t}throw new Error(`unrecognized argument type ${e.constructor.name}`)}}(e,t)}).join(", ")}function i(e){return new e.constructor(e)}void 0!==t&&(t.exports={glWiretap:r,glExtensionWiretap:n}),"undefined"!=typeof window&&(r.glExtensionWiretap=n,window.glWiretap=r)}),O=e((e,t)=>{const{glWiretap:r}=N(),{utils:n}=i();function s(e){let t=e.toString().replace(/^function /,"");const r=t.indexOf("=>");if(-1!==r&&!/[{]|\bfunction\b/.test(t.slice(0,r))){const e=t.slice(0,r).trim(),n=t.slice(r+2).trim();t=n.startsWith("{")?`${e} ${n}`:`${e} { return ${n}; }`}return t.replace(/utils[.]/g,"/*utils.*/")}function a(e,t){const r="single"===t.precision?e:`new Float32Array(${e}.buffer)`;return t.output[2]?`renderOutput(${r}, ${t.output[0]}, ${t.output[1]}, ${t.output[2]})`:t.output[1]?`renderOutput(${r}, ${t.output[0]}, ${t.output[1]})`:`renderOutput(${r}, ${t.output[0]})`}function o(e,t){const r=e.toArray.toString(),s=!/^function/.test(r);return`() => {\n function framebuffer() { return getReadFramebuffer(); };\n ${n.flattenFunctionToString(`${s?"function ":""}${r}`,{findDependency:(t,r)=>{if("utils"===t)return`const ${r} = ${n[r].toString()};`;if("this"===t)return"framebuffer"===r?"":`${s?"function ":""}${e[r].toString()}`;throw new Error("unhandled fromObject")},thisLookup:(r,n)=>{if("texture"===r)return t;if("context"===r)return n?null:"gl";if(e.hasOwnProperty(r))return JSON.stringify(e[r]);throw new Error(`unhandled thisLookup ${r}`)}})}\n return toArray();\n }`}function u(e,t,r,n,s){if(null===e)return null;if(null===t)return null;switch(typeof e){case"boolean":case"number":return null}if("undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement)for(let s=0;s{switch(typeof e){case"boolean":return new Boolean(e);case"number":return new Number(e);default:return e}}):null;const c=[],p=[],d=r(i.context,{useTrackablePrimitives:!0,onReadPixels:e=>{if(M.subKernels){if(m){const t=M.subKernels[f++].property;p.push(` result${isNaN(t)?"."+t:`[${t}]`} = ${a(e,M)};`)}else p.push(` const result = { result: ${a(e,M)} };`),m=!0;f===M.subKernels.length&&p.push(" return result;")}else e?p.push(` return ${a(e,M)};`):p.push(" return null;")},onUnrecognizedArgumentLookup:e=>{const t=u(e,M.kernelArguments,[],d,c);if(t)return t;const r=u(e,M.kernelConstants,A?Object.keys(A).map(e=>A[e]):[],d,c);return r||null}});let m=!1,f=0;const{source:g,canvas:y,output:x,pipeline:b,graphical:T,loopMaxIterations:S,constants:A,optimizeFloatMemory:w,precision:_,fixIntegerDivisionAccuracy:E,functions:v,nativeFunctions:I,subKernels:$,immutable:D,argumentTypes:F,constantTypes:L,kernelArguments:R,kernelConstants:k,tactic:C}=i,M=new e(g,{canvas:y,context:d,checkContext:!1,output:x,pipeline:b,graphical:T,loopMaxIterations:S,constants:A,optimizeFloatMemory:w,precision:_,fixIntegerDivisionAccuracy:E,functions:v,nativeFunctions:I,subKernels:$,immutable:D,argumentTypes:F,constantTypes:L,tactic:C});let G=[];if(d.setIndent(2),M.build.apply(M,t),G.push(d.toString()),d.reset(),M.kernelArguments.forEach((e,r)=>{switch(e.type){case"Integer":case"Boolean":case"Number":case"Float":case"Array":case"Array(2)":case"Array(3)":case"Array(4)":case"HTMLCanvas":case"HTMLImage":case"HTMLVideo":case"Input":d.insertVariable(`uploadValue_${e.name}`,e.uploadValue);break;case"HTMLImageArray":for(let n=0;ne.varName).join(", ")}) {`),d.setIndent(4),M.run.apply(M,t),M.renderKernels?M.renderKernels():M.renderOutput&&M.renderOutput(),G.push(" /** start setup uploads for kernel values **/"),M.kernelArguments.forEach(e=>{G.push(" "+e.getStringValueHandler().split("\n").join("\n "))}),G.push(" /** end setup uploads for kernel values **/"),G.push(d.toString()),M.renderOutput===M.renderTexture)if(d.reset(),M.renderKernels){const e=M.renderKernels(),t=d.getContextVariableName(M.texture.texture);G.push(` return {\n result: {\n texture: ${t},\n type: '${e.result.type}',\n toArray: ${o(e.result,t)}\n },`);const{subKernels:r,mappedTextures:n}=M;for(let t=0;t"utils"===e?`const ${t} = ${n[t].toString()};`:null,thisLookup:t=>{if("context"===t)return null;if(e.hasOwnProperty(t))return JSON.stringify(e[t]);throw new Error(`unhandled thisLookup ${t}`)}})}(M)),G.push(" innerKernel.getPixels = getPixels;")),G.push(" return innerKernel;");let z=[];return k.forEach(e=>{z.push(`${e.getStringValueHandler()}`)}),`function kernel(settings) {\n const { context, constants } = settings;\n ${z.join("")}\n ${l||""}\n${G.join("\n")}\n}`}}}),V=e((e,t)=>{t.exports={KernelValue:class{constructor(e,t){const{name:r,kernel:n,context:s,checkContext:i,onRequestContextHandle:a,onUpdateValueMismatch:o,origin:u,strictIntegers:l,type:h,tactic:c}=t;if(!r)throw new Error("name not set");if(!h)throw new Error("type not set");if(!u)throw new Error("origin not set");if("user"!==u&&"constants"!==u)throw new Error(`origin must be "user" or "constants" value is "${u}"`);if(!a)throw new Error("onRequestContextHandle is not set");this.name=r,this.origin=u,this.tactic=c,this.varName="constants"===u?`constants.${r}`:r,this.kernel=n,this.strictIntegers=l,this.type=e.type||h,this.size=e.size||null,this.index=null,this.context=s,this.checkContext=null==i||i,this.contextHandle=null,this.onRequestContextHandle=a,this.onUpdateValueMismatch=o,this.forceUploadEachRun=null}get id(){return`${this.origin}_${name}`}getSource(){throw new Error(`"getSource" not defined on ${this.constructor.name}`)}updateValue(e){throw new Error(`"updateValue" not defined on ${this.constructor.name}`)}}}}),K=e((e,t)=>{const{utils:r}=i(),{KernelValue:n}=V();t.exports={WebGLKernelValue:class extends n{constructor(e,t){super(e,t),this.dimensionsId=null,this.sizeId=null,this.initialValueConstructor=e.constructor,this.onRequestTexture=t.onRequestTexture,this.onRequestIndex=t.onRequestIndex,this.uploadValue=null,this.textureSize=null,this.bitRatio=null,this.prevArg=null}get id(){return`${this.origin}_${r.sanitizeName(this.name)}`}setup(){}rebind(){}getTransferArrayType(e){if(Array.isArray(e[0]))return this.getTransferArrayType(e[0]);switch(e.constructor){case Array:case Int32Array:case Int16Array:case Int8Array:return Float32Array;case Uint8ClampedArray:case Uint8Array:case Uint16Array:case Uint32Array:case Float32Array:case Float64Array:return e.constructor}return console.warn("Unfamiliar constructor type. Will go ahead and use, but likley this may result in a transfer of zeros"),e.constructor}getStringValueHandler(){throw new Error(`"getStringValueHandler" not implemented on ${this.constructor.name}`)}getVariablePrecisionString(){return this.kernel.getVariablePrecisionString(this.textureSize||void 0,this.tactic||void 0)}destroy(){}}}}),U=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValue:n}=K();t.exports={WebGLKernelValueBoolean:class extends n{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const bool ${this.id} = ${e};\n`:`uniform bool ${this.id};\n`}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1i(this.id,this.uploadValue=e)}}}}),P=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValue:n}=K();t.exports={WebGLKernelValueFloat:class extends n{constructor(e,t){super(e,t),this.uploadValue=e}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(e){return"constants"===this.origin?Number.isInteger(e)?`const float ${this.id} = ${e}.0;\n`:`const float ${this.id} = ${e};\n`:`uniform float ${this.id};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1f(this.id,this.uploadValue=e)}}}}),B=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValue:n}=K();t.exports={WebGLKernelValueInteger:class extends n{constructor(e,t){super(e,t),this.uploadValue=e}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(e){return"constants"===this.origin?`const int ${this.id} = ${parseInt(e)};\n`:`uniform int ${this.id};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1i(this.id,this.uploadValue=e)}}}}),W=e((e,t)=>{const{WebGLKernelValue:r}=K(),{Input:s}=n();t.exports={WebGLKernelArray:class extends r{rebind(){if(!this.texture||void 0===this.contextHandle||null===this.contextHandle)return;const{context:e}=this;e.activeTexture(this.contextHandle),e.bindTexture(e.TEXTURE_2D,this.texture)}checkSize(e,t){if(!this.kernel.validate)return;const{maxTextureSize:r}=this.kernel.constructor.features;if(e>r||t>r)throw e>t?new Error(`Argument texture width of ${e} larger than maximum size of ${r} for your GPU`):e{const{utils:r}=i(),{WebGLKernelArray:n}=W();function s(e){return{width:e.width>0?e.width:e.videoWidth,height:e.height>0?e.height:e.videoHeight}}t.exports={WebGLKernelValueHTMLImage:class extends n{constructor(e,t){super(e,t);const{width:r,height:n}=s(e);this.checkSize(r,n),this.dimensions=[r,n,1],this.textureSize=[r,n],this.uploadValue=e}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!0),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,this.uploadValue=e),this.kernel.setUniform1i(this.id,this.index)}},mediaSize:s}}),X=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueHTMLImage:n,mediaSize:s}=j();t.exports={WebGLKernelValueDynamicHTMLImage:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){const{width:t,height:r}=s(e);this.checkSize(t,r),this.dimensions=[t,r,1],this.textureSize=[t,r],this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),H=e((e,t)=>{const{WebGLKernelValueHTMLImage:r}=j();t.exports={WebGLKernelValueHTMLVideo:class extends r{}}}),q=e((e,t)=>{const{WebGLKernelValueDynamicHTMLImage:r}=X();t.exports={WebGLKernelValueDynamicHTMLVideo:class extends r{}}}),Y=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGLKernelValueSingleInput:class extends n{constructor(e,t){super(e,t),this.bitRatio=4;let[n,s,i]=e.size;this.dimensions=new Int32Array([n||1,s||1,i||1]),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}.value, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e.value,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Z=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleInput:n}=Y();t.exports={WebGLKernelValueDynamicSingleInput:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){let[t,n,s]=e.size;this.dimensions=new Int32Array([t||1,n||1,s||1]),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),J=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGLKernelValueUnsignedInput:class extends n{constructor(e,t){super(e,t),this.bitRatio=this.getBitRatio(e);const[n,s,i]=e.size;this.dimensions=new Int32Array([n||1,s||1,i||1]),this.textureSize=r.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]),this.TranserArrayType=this.getTransferArrayType(e.value),this.preUploadValue=new this.TranserArrayType(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer)}getStringValueHandler(){return r.linesToString([`const preUploadValue_${this.name} = new ${this.TranserArrayType.name}(${this.uploadArrayLength})`,`const uploadValue_${this.name} = new Uint8Array(preUploadValue_${this.name}.buffer)`,`flattenTo(${this.varName}.value, preUploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(value.constructor);const{context:t}=this;r.flattenTo(e.value,this.preUploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.UNSIGNED_BYTE,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Q=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueUnsignedInput:n}=J();t.exports={WebGLKernelValueDynamicUnsignedInput:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){let[t,n,s]=e.size;this.dimensions=new Int32Array([t||1,n||1,s||1]),this.textureSize=r.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]);const i=this.getTransferArrayType(e.value);this.preUploadValue=new i(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ee=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W(),s="Source and destination textures are the same. Use immutable = true and manually cleanup kernel output texture memory with texture.delete()";t.exports={WebGLKernelValueMemoryOptimizedNumberTexture:class extends n{constructor(e,t){super(e,t);const[r,n]=e.size;this.checkSize(r,n),this.dimensions=e.dimensions,this.textureSize=e.size,this.uploadValue=e.texture,this.forceUploadEachRun=!0}setup(){this.setupTexture()}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName}.texture;\n`}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);if(this.checkContext&&e.context!==this.context)throw new Error(`Value ${this.name} (${this.type}) must be from same context`);const{kernel:t,context:r}=this;if(t.pipeline)if(t.immutable)t.updateTextureArgumentRefs(this,e);else{if(t.texture&&t.texture.texture===e.texture)throw new Error(s);if(t.mappedTextures){const{mappedTextures:r}=t;for(let t=0;t{const{utils:r}=i(),{WebGLKernelValueMemoryOptimizedNumberTexture:n}=ee();t.exports={WebGLKernelValueDynamicMemoryOptimizedNumberTexture:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=e.dimensions,this.checkSize(e.size[0],e.size[1]),this.textureSize=e.size,this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),re=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W(),{sameError:s}=ee();t.exports={WebGLKernelValueNumberTexture:class extends n{constructor(e,t){super(e,t);const[r,n]=e.size;this.checkSize(r,n);const{size:s,dimensions:i}=e;this.bitRatio=this.getBitRatio(e),this.dimensions=i,this.textureSize=s,this.uploadValue=e.texture,this.forceUploadEachRun=!0}setup(){this.setupTexture()}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName}.texture;\n`}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);if(this.checkContext&&e.context!==this.context)throw new Error(`Value ${this.name} (${this.type}) must be from same context`);const{kernel:t,context:r}=this;if(t.pipeline)if(t.immutable)t.updateTextureArgumentRefs(this,e);else{if(t.texture&&t.texture.texture===e.texture)throw new Error(s);if(t.mappedTextures){const{mappedTextures:r}=t;for(let t=0;t{const{utils:r}=i(),{WebGLKernelValueNumberTexture:n}=re();t.exports={WebGLKernelValueDynamicNumberTexture:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=e.dimensions,this.checkSize(e.size[0],e.size[1]),this.textureSize=e.size,this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),se=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGLKernelValueSingleArray:class extends n{constructor(e,t){super(e,t),this.bitRatio=4,this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(!r.isArray(e))return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),ie=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray:n}=se();t.exports={WebGLKernelValueDynamicSingleArray:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ae=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGLKernelValueSingleArray1DI:class extends n{constructor(e,t){super(e,t),this.bitRatio=4,this.setShape(e)}setShape(e){const t=r.getDimensions(e,!0);this.textureSize=r.getMemoryOptimizedFloatTextureSize(t,this.bitRatio),this.dimensions=new Int32Array([t[1],1,1]),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flatten2dArrayTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),oe=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray1DI:n}=ae();t.exports={WebGLKernelValueDynamicSingleArray1DI:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ue=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGLKernelValueSingleArray2DI:class extends n{constructor(e,t){super(e,t),this.bitRatio=4,this.setShape(e)}setShape(e){const t=r.getDimensions(e,!0);this.textureSize=r.getMemoryOptimizedFloatTextureSize(t,this.bitRatio),this.dimensions=new Int32Array([t[1],t[2],1]),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flatten3dArrayTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),le=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray2DI:n}=ue();t.exports={WebGLKernelValueDynamicSingleArray2DI:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),he=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGLKernelValueSingleArray3DI:class extends n{constructor(e,t){super(e,t),this.bitRatio=4,this.setShape(e)}setShape(e){const t=r.getDimensions(e,!0);this.textureSize=r.getMemoryOptimizedFloatTextureSize(t,this.bitRatio),this.dimensions=new Int32Array([t[1],t[2],t[3]]),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flatten4dArrayTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),ce=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray3DI:n}=he();t.exports={WebGLKernelValueDynamicSingleArray3DI:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),pe=e((e,t)=>{const{WebGLKernelValue:r}=K();t.exports={WebGLKernelValueArray2:class extends r{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const vec2 ${this.id} = vec2(${e[0]},${e[1]});\n`:`uniform vec2 ${this.id};\n`}getStringValueHandler(){return"constants"===this.origin?"":`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform2fv(this.id,this.uploadValue=e)}}}}),de=e((e,t)=>{const{WebGLKernelValue:r}=K();t.exports={WebGLKernelValueArray3:class extends r{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const vec3 ${this.id} = vec3(${e[0]},${e[1]},${e[2]});\n`:`uniform vec3 ${this.id};\n`}getStringValueHandler(){return"constants"===this.origin?"":`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform3fv(this.id,this.uploadValue=e)}}}}),me=e((e,t)=>{const{WebGLKernelValue:r}=K();t.exports={WebGLKernelValueArray4:class extends r{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const vec4 ${this.id} = vec4(${e[0]},${e[1]},${e[2]},${e[3]});\n`:`uniform vec4 ${this.id};\n`}getStringValueHandler(){return"constants"===this.origin?"":`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform4fv(this.id,this.uploadValue=e)}}}}),fe=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGLKernelValueUnsignedArray:class extends n{constructor(e,t){super(e,t),this.bitRatio=this.getBitRatio(e),this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]),this.TranserArrayType=this.getTransferArrayType(e),this.preUploadValue=new this.TranserArrayType(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer)}getStringValueHandler(){return r.linesToString([`const preUploadValue_${this.name} = new ${this.TranserArrayType.name}(${this.uploadArrayLength})`,`const uploadValue_${this.name} = new Uint8Array(preUploadValue_${this.name}.buffer)`,`flattenTo(${this.varName}, preUploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(!r.isArray(e))return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.preUploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.UNSIGNED_BYTE,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),ge=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueUnsignedArray:n}=fe();t.exports={WebGLKernelValueDynamicUnsignedArray:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]);const t=this.getTransferArrayType(e);this.preUploadValue=new t(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ye=e((e,t)=>{const{WebGLKernelValueBoolean:r}=U(),{WebGLKernelValueFloat:n}=P(),{WebGLKernelValueInteger:s}=B(),{WebGLKernelValueHTMLImage:i}=j(),{WebGLKernelValueDynamicHTMLImage:a}=X(),{WebGLKernelValueHTMLVideo:o}=H(),{WebGLKernelValueDynamicHTMLVideo:u}=q(),{WebGLKernelValueSingleInput:l}=Y(),{WebGLKernelValueDynamicSingleInput:h}=Z(),{WebGLKernelValueUnsignedInput:c}=J(),{WebGLKernelValueDynamicUnsignedInput:p}=Q(),{WebGLKernelValueMemoryOptimizedNumberTexture:d}=ee(),{WebGLKernelValueDynamicMemoryOptimizedNumberTexture:m}=te(),{WebGLKernelValueNumberTexture:f}=re(),{WebGLKernelValueDynamicNumberTexture:g}=ne(),{WebGLKernelValueSingleArray:y}=se(),{WebGLKernelValueDynamicSingleArray:x}=ie(),{WebGLKernelValueSingleArray1DI:b}=ae(),{WebGLKernelValueDynamicSingleArray1DI:T}=oe(),{WebGLKernelValueSingleArray2DI:S}=ue(),{WebGLKernelValueDynamicSingleArray2DI:A}=le(),{WebGLKernelValueSingleArray3DI:w}=he(),{WebGLKernelValueDynamicSingleArray3DI:_}=ce(),{WebGLKernelValueArray2:E}=pe(),{WebGLKernelValueArray3:v}=de(),{WebGLKernelValueArray4:I}=me(),{WebGLKernelValueUnsignedArray:$}=fe(),{WebGLKernelValueDynamicUnsignedArray:D}=ge(),F={unsigned:{dynamic:{Boolean:r,Integer:s,Float:n,Array:D,"Array(2)":E,"Array(3)":v,"Array(4)":I,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:p,NumberTexture:g,"ArrayTexture(1)":g,"ArrayTexture(2)":g,"ArrayTexture(3)":g,"ArrayTexture(4)":g,MemoryOptimizedNumberTexture:m,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:!1,HTMLVideo:u},static:{Boolean:r,Float:n,Integer:s,Array:$,"Array(2)":E,"Array(3)":v,"Array(4)":I,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:c,NumberTexture:f,"ArrayTexture(1)":f,"ArrayTexture(2)":f,"ArrayTexture(3)":f,"ArrayTexture(4)":f,MemoryOptimizedNumberTexture:d,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:!1,HTMLVideo:o}},single:{dynamic:{Boolean:r,Integer:s,Float:n,Array:x,"Array(2)":E,"Array(3)":v,"Array(4)":I,"Array1D(2)":T,"Array1D(3)":T,"Array1D(4)":T,"Array2D(2)":A,"Array2D(3)":A,"Array2D(4)":A,"Array3D(2)":_,"Array3D(3)":_,"Array3D(4)":_,Input:h,NumberTexture:g,"ArrayTexture(1)":g,"ArrayTexture(2)":g,"ArrayTexture(3)":g,"ArrayTexture(4)":g,MemoryOptimizedNumberTexture:m,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:!1,HTMLVideo:u},static:{Boolean:r,Float:n,Integer:s,Array:y,"Array(2)":E,"Array(3)":v,"Array(4)":I,"Array1D(2)":b,"Array1D(3)":b,"Array1D(4)":b,"Array2D(2)":S,"Array2D(3)":S,"Array2D(4)":S,"Array3D(2)":w,"Array3D(3)":w,"Array3D(4)":w,Input:l,NumberTexture:f,"ArrayTexture(1)":f,"ArrayTexture(2)":f,"ArrayTexture(3)":f,"ArrayTexture(4)":f,MemoryOptimizedNumberTexture:d,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:!1,HTMLVideo:o}}};t.exports={lookupKernelValueType:function(e,t,r,n){if(!e)throw new Error("type missing");if(!t)throw new Error("dynamic missing");if(!r)throw new Error("precision missing");n.type&&(e=n.type);const s=F[r][t];if("WebGPUBuffer"===e)throw new Error("this kernel runs on WebGL but received a WebGPU pipeline buffer; await handle.toArray() first, or give this kernel the async contract (asyncMode: true / mode: 'async') so the readback happens for you");if(!1===s[e])return null;if(void 0===s[e])throw new Error(`Could not find a KernelValue for ${e}`);return s[e]},kernelValueMaps:F}}),xe=e((e,t)=>{const{GLKernel:r}=k(),{FunctionBuilder:n}=o(),{WebGLFunctionNode:s}=C(),{utils:a}=i(),u=M(),{fragmentShader:l}=G(),{vertexShader:h}=z(),{glKernelString:c}=O(),{lookupKernelValueType:p}=ye();let d=null,m=null,f=null,g=null,y=null;const x=[u],b=[],T={};t.exports={WebGLKernel:class extends r{static get isSupported(){return null!==d||(this.setupFeatureChecks(),d=this.isContextMatch(f)),d}static setupFeatureChecks(){"undefined"!=typeof document?m=document.createElement("canvas"):"undefined"!=typeof OffscreenCanvas&&(m=new OffscreenCanvas(0,0)),m&&(f=m.getContext("webgl"),f||m instanceof OffscreenCanvas||(f=m.getContext("experimental-webgl")),f&&f.getExtension&&(g={OES_texture_float:f.getExtension("OES_texture_float"),OES_texture_float_linear:f.getExtension("OES_texture_float_linear"),OES_element_index_uint:f.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:f.getExtension("WEBGL_draw_buffers")},y=this.getFeatures()))}static isContextMatch(e){return"undefined"!=typeof WebGLRenderingContext&&e instanceof WebGLRenderingContext}static getIsTextureFloat(){return Boolean(g.OES_texture_float)}static getIsDrawBuffers(){return Boolean(g.WEBGL_draw_buffers)}static getChannelCount(){return g.WEBGL_draw_buffers?f.getParameter(g.WEBGL_draw_buffers.MAX_DRAW_BUFFERS_WEBGL):1}static getMaxTextureSize(){return f.getParameter(f.MAX_TEXTURE_SIZE)}static lookupKernelValueType(e,t,r,n){return p(e,t,r,n)}static get testCanvas(){return m}static get testContext(){return f}static get features(){return y}static get fragmentShader(){return l}static get vertexShader(){return h}constructor(e,t){super(e,t),this.program=null,this.pipeline=t.pipeline,this.endianness=a.systemEndianness(),this.extensions={},this.argumentTextureCount=0,this.constantTextureCount=0,this.fragShader=null,this.vertShader=null,this.drawBuffersMap=null,this.maxTexSize=null,this.onRequestSwitchKernel=null,this.texture=null,this.mappedTextures=null,this.mergeSettings(e.settings||t),this.threadDim=null,this.framebuffer=null,this.buffer=null,this.textureCache=[],this.programUniformLocationCache={},this.uniform1fCache={},this.uniform1iCache={},this.uniform2fCache={},this.uniform2fvCache={},this.uniform2ivCache={},this.uniform3fvCache={},this.uniform3ivCache={},this.uniform4fvCache={},this.uniform4ivCache={}}initCanvas(){if("undefined"!=typeof document){const e=document.createElement("canvas");return e.width=2,e.height=2,e}if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(0,0)}initContext(){const e={alpha:!1,depth:!1,antialias:!1};return this.canvas.getContext("webgl",e)||this.canvas.getContext("experimental-webgl",e)}initPlugins(e){const t=[],{source:r}=this;if("string"==typeof r)for(let e=0;ee===n.name)&&t.push(n)}return t}initExtensions(){this.extensions={OES_texture_float:this.context.getExtension("OES_texture_float"),OES_texture_float_linear:this.context.getExtension("OES_texture_float_linear"),OES_element_index_uint:this.context.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:this.context.getExtension("WEBGL_draw_buffers"),WEBGL_color_buffer_float:this.context.getExtension("WEBGL_color_buffer_float")}}validateSettings(e){if(!this.validate)return void(this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output));const{features:t}=this.constructor;if(!0===this.optimizeFloatMemory&&!t.isTextureFloat)throw new Error("Float textures are not supported");if("single"===this.precision&&!t.isFloatRead)throw new Error("Single precision not supported");if(this.graphical||null!==this.precision||(this.precision=t.isTextureFloat&&t.isFloatRead?"single":"unsigned"),this.subKernels&&this.subKernels.length>0&&!this.extensions.WEBGL_draw_buffers)throw new Error("could not instantiate draw buffers extension");if(null===this.fixIntegerDivisionAccuracy?this.fixIntegerDivisionAccuracy=!t.isIntegerDivisionAccurate:this.fixIntegerDivisionAccuracy&&t.isIntegerDivisionAccurate&&(this.fixIntegerDivisionAccuracy=!1),this.checkOutput(),!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=a.getVariableType(e[0],this.strictIntegers);switch(t){case"Array":this.output=a.getDimensions(t);break;case"NumberTexture":case"MemoryOptimizedNumberTexture":case"ArrayTexture(1)":case"ArrayTexture(2)":case"ArrayTexture(3)":case"ArrayTexture(4)":this.output=e[0].output;break;default:throw new Error("Auto output not supported for input type: "+t)}}if(this.graphical){if(2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");return"precision"===this.precision&&(this.precision="unsigned",console.warn("Cannot use graphical mode and single precision at the same time")),void(this.texSize=a.clone(this.output))}null===this.precision&&t.isTextureFloat&&(this.precision="single"),this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output),this.checkTextureSize()}updateMaxTexSize(){const{texSize:e,canvas:t}=this;if(null===this.maxTexSize){let r=b.indexOf(t);-1===r&&(r=b.length,b.push(t),T[r]=[e[0],e[1]]),this.maxTexSize=T[r]}this.maxTexSize[0]this.argumentNames.length)throw new Error("too many arguments for kernel");const{context:r}=this;let n=0;const s=()=>this.createTexture(),i=()=>this.constantTextureCount+n++,o=e=>{this.switchKernels({type:"argumentMismatch",needed:e})},u=()=>r.TEXTURE0+this.constantTextureCount+this.argumentTextureCount++;for(let n=0;nthis.createTexture(),onRequestIndex:()=>n++,onRequestContextHandle:()=>t.TEXTURE0+this.constantTextureCount++});this.constantBitRatios[s]=l.bitRatio,this.kernelConstants.push(l),l.setup(),l.forceUploadEachRun&&this.forceUploadKernelConstants.push(l)}}build(){if(this.built)return;if(this.initExtensions(),this.validateSettings(arguments),this.setupConstants(arguments),this.fallbackRequested)return;if(this.setupArguments(arguments),this.fallbackRequested)return;this.updateMaxTexSize(),this.translateSource();const e=this.pickRenderStrategy(arguments);if(e)return e;const{texSize:t,context:r,canvas:n}=this;r.enable(r.SCISSOR_TEST),this.pipeline&&this.precision,r.viewport(0,0,this.maxTexSize[0],this.maxTexSize[1]),n.width=this.maxTexSize[0],n.height=this.maxTexSize[1];const s=this.threadDim=Array.from(this.output);for(;s.length<3;)s.push(1);const i=this.getVertexShader(arguments),a=r.createShader(r.VERTEX_SHADER);r.shaderSource(a,i),r.compileShader(a),this.vertShader=a;const o=this.getFragmentShader(arguments),u=r.createShader(r.FRAGMENT_SHADER);if(r.shaderSource(u,o),r.compileShader(u),this.fragShader=u,this.debug&&(console.log("GLSL Shader Output:"),console.log(o)),!r.getShaderParameter(a,r.COMPILE_STATUS))throw new Error("Error compiling vertex shader: "+r.getShaderInfoLog(a));if(!r.getShaderParameter(u,r.COMPILE_STATUS))throw new Error("Error compiling fragment shader: "+r.getShaderInfoLog(u));const l=this.program=r.createProgram();r.attachShader(l,a),r.attachShader(l,u),r.linkProgram(l),this.framebuffer=r.createFramebuffer(),this.framebuffer.width=t[0],this.framebuffer.height=t[1],this.rawValueFramebuffers={};const h=new Float32Array([-1,-1,1,-1,-1,1,1,1]),c=new Float32Array([0,0,1,0,0,1,1,1]),p=h.byteLength;let d=this.buffer;d?r.bindBuffer(r.ARRAY_BUFFER,d):(d=this.buffer=r.createBuffer(),r.bindBuffer(r.ARRAY_BUFFER,d),r.bufferData(r.ARRAY_BUFFER,h.byteLength+c.byteLength,r.STATIC_DRAW)),r.bufferSubData(r.ARRAY_BUFFER,0,h),r.bufferSubData(r.ARRAY_BUFFER,p,c);const m=r.getAttribLocation(this.program,"aPos");-1!==m&&(r.enableVertexAttribArray(m),r.vertexAttribPointer(m,2,r.FLOAT,!1,0,0));const f=r.getAttribLocation(this.program,"aTexCoord");-1!==f&&(r.enableVertexAttribArray(f),r.vertexAttribPointer(f,2,r.FLOAT,!1,0,p)),r.bindFramebuffer(r.FRAMEBUFFER,this.framebuffer);let g=0;r.useProgram(this.program);for(let e in this.constants)this.kernelConstants[g++].updateValue(this.constants[e]);this._setupOutputTexture(),null!==this.subKernels&&this.subKernels.length>0&&(this._mappedTextureSwitched={},this._setupSubOutputTextures()),this.buildSignature(arguments),this.built=!0}translateSource(){const e=n.fromKernel(this,s,{fixIntegerDivisionAccuracy:this.fixIntegerDivisionAccuracy});this.translatedSource=e.getPrototypeString("kernel"),this.setupReturnTypes(e)}setupReturnTypes(e){if(this.graphical||this.returnType||(this.returnType=e.getKernelResultType()),this.subKernels&&this.subKernels.length>0)for(let t=0;te.source&&this.source.match(e.functionMatch)?e.source:"").join("\n"):"\n"}_getConstantsString(){const e=[],{threadDim:t,texSize:r}=this;return this.dynamicOutput?e.push("uniform ivec3 uOutputDim","uniform ivec2 uTexSize"):e.push(`ivec3 uOutputDim = ivec3(${t[0]}, ${t[1]}, ${t[2]})`,`ivec2 uTexSize = ivec2(${r[0]}, ${r[1]})`),a.linesToString(e)}_getTextureCoordinate(){const e=this.subKernels;return null===e||e.length<1?"varying vec2 vTexCoord;\n":"out vec2 vTexCoord;\n"}_getDecode32EndiannessString(){return"LE"===this.endianness?"":" texel.rgba = texel.abgr;\n"}_getEncode32EndiannessString(){return"LE"===this.endianness?"":" texel.rgba = texel.abgr;\n"}_getDivideWithIntegerCheckString(){return this.fixIntegerDivisionAccuracy?"float divWithIntCheck(float x, float y) {\n if (floor(x) == x && floor(y) == y) {\n float q = floor(x / y + 0.5);\n if (y * q == x) {\n return q;\n }\n }\n return x / y;\n}\n\nfloat integerCorrectionModulo(float number, float divisor) {\n if (number < 0.0) {\n number = abs(number);\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return -(number - (divisor * floor(divWithIntCheck(number, divisor))));\n }\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return number - (divisor * floor(divWithIntCheck(number, divisor)));\n}":""}_getMainArgumentsString(e){const t=[],{argumentNames:r}=this;for(let n=0;n{if(t.hasOwnProperty(r))return t[r];throw`unhandled artifact ${r}`})}getFragmentShader(e){return null!==this.compiledFragmentShader?this.compiledFragmentShader:this.compiledFragmentShader=this.replaceArtifacts(this.constructor.fragmentShader,this._getFragShaderArtifactMap(e))}getVertexShader(e){return null!==this.compiledVertexShader?this.compiledVertexShader:this.compiledVertexShader=this.replaceArtifacts(this.constructor.vertexShader,this._getVertShaderArtifactMap(e))}toString(){const e=a.linesToString(["const gl = context"]);return c(this.constructor,arguments,this,e)}destroy(e){if(!this.context)return;this.buffer&&this.context.deleteBuffer(this.buffer),this.framebuffer&&this.context.deleteFramebuffer(this.framebuffer);for(const e in this.rawValueFramebuffers){for(const t in this.rawValueFramebuffers[e])this.context.deleteFramebuffer(this.rawValueFramebuffers[e][t]),delete this.rawValueFramebuffers[e][t];delete this.rawValueFramebuffers[e]}if(this.vertShader&&this.context.deleteShader(this.vertShader),this.fragShader&&this.context.deleteShader(this.fragShader),this.program&&this.context.deleteProgram(this.program),this.texture){this.texture.delete();const e=this.textureCache.indexOf(this.texture.texture);e>-1&&this.textureCache.splice(e,1),this.texture=null}if(this.mappedTextures&&this.mappedTextures.length){for(let e=0;e-1&&this.textureCache.splice(r,1)}this.mappedTextures=null}if(this.kernelArguments)for(let e=0;e0;){const e=this.textureCache.pop();this.context.deleteTexture(e)}if(e){const e=b.indexOf(this.canvas);e>=0&&(b[e]=null,T[e]=null)}if(this.destroyExtensions(),delete this.context,delete this.canvas,!this.gpu)return;const t=this.gpu.kernels.indexOf(this);-1!==t&&this.gpu.kernels.splice(t,1)}destroyExtensions(){this.extensions.OES_texture_float=null,this.extensions.OES_texture_float_linear=null,this.extensions.OES_element_index_uint=null,this.extensions.WEBGL_draw_buffers=null}static destroyContext(e){const t=e.getExtension("WEBGL_lose_context");t&&t.loseContext()}toJSON(){const e=super.toJSON();return e.functionNodes=n.fromKernel(this,s).toJSON(),e.settings.threadDim=this.threadDim,e}}}}),be=e((e,t)=>{const n=r(),{WebGLKernel:s}=xe(),{glKernelString:i}=O();let a=null,o=null,u=null,l=null,h=null;t.exports={HeadlessGLKernel:class extends s{static get isSupported(){return null!==a||(this.setupFeatureChecks(),a=null!==u),a}static setupFeatureChecks(){if(o=null,l=null,"function"==typeof n)try{if(u=n(2,2,{preserveDrawingBuffer:!0}),!u||!u.getExtension)return;l={STACKGL_resize_drawingbuffer:u.getExtension("STACKGL_resize_drawingbuffer"),STACKGL_destroy_context:u.getExtension("STACKGL_destroy_context"),OES_texture_float:u.getExtension("OES_texture_float"),OES_texture_float_linear:u.getExtension("OES_texture_float_linear"),OES_element_index_uint:u.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:u.getExtension("WEBGL_draw_buffers"),WEBGL_color_buffer_float:u.getExtension("WEBGL_color_buffer_float")},h=this.getFeatures()}catch(e){console.warn(e)}}static isContextMatch(e){try{return"ANGLE"===e.getParameter(e.RENDERER)}catch(e){return!1}}static getIsTextureFloat(){return Boolean(l.OES_texture_float)}static getIsDrawBuffers(){return Boolean(l.WEBGL_draw_buffers)}static getChannelCount(){return l.WEBGL_draw_buffers?u.getParameter(l.WEBGL_draw_buffers.MAX_DRAW_BUFFERS_WEBGL):1}static getMaxTextureSize(){return u.getParameter(u.MAX_TEXTURE_SIZE)}static get testCanvas(){return o}static get testContext(){return u}static get features(){return h}initCanvas(){return{}}initContext(){return n(2,2,{preserveDrawingBuffer:!0})}initExtensions(){this.extensions={STACKGL_resize_drawingbuffer:this.context.getExtension("STACKGL_resize_drawingbuffer"),STACKGL_destroy_context:this.context.getExtension("STACKGL_destroy_context"),OES_texture_float:this.context.getExtension("OES_texture_float"),OES_texture_float_linear:this.context.getExtension("OES_texture_float_linear"),OES_element_index_uint:this.context.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:this.context.getExtension("WEBGL_draw_buffers")}}build(){super.build.apply(this,arguments),this.fallbackRequested||this.extensions.STACKGL_resize_drawingbuffer.resize(this.maxTexSize[0],this.maxTexSize[1])}destroyExtensions(){this.extensions.STACKGL_resize_drawingbuffer=null,this.extensions.STACKGL_destroy_context=null,this.extensions.OES_texture_float=null,this.extensions.OES_texture_float_linear=null,this.extensions.OES_element_index_uint=null,this.extensions.WEBGL_draw_buffers=null}static destroyContext(e){const t=e.getExtension("STACKGL_destroy_context");t&&t.destroy&&t.destroy()}toString(){return i(this.constructor,arguments,this,"const gl = context || require('gl')(1, 1);\n"," if (!context) { gl.getExtension('STACKGL_destroy_context').destroy(); }\n")}setOutput(e){return super.setOutput(e),this.graphical&&this.extensions.STACKGL_resize_drawingbuffer&&this.extensions.STACKGL_resize_drawingbuffer.resize(this.maxTexSize[0],this.maxTexSize[1]),this}}}}),Te=e((e,t)=>{const{utils:r}=i(),{WebGLFunctionNode:n}=C();t.exports={WebGL2FunctionNode:class extends n{astIdentifierExpression(e,t){if("Identifier"!==e.type)throw this.astErrorOutput("IdentifierExpression - not an Identifier",e);const n=this.getType(e),s=r.sanitizeName(e.name);return"Infinity"===e.name?t.push("intBitsToFloat(2139095039)"):"Boolean"===n&&this.argumentNames.indexOf(s)>-1?t.push(`bool(user_${s})`):t.push(`user_${s}`),t}}}}),Se=e((e,t)=>{t.exports={fragmentShader:`#version 300 es\n__HEADER__;\n__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n__SAMPLER_2D_ARRAY_TACTIC_DECLARATION__;\n\nconst int LOOP_MAX = __LOOP_MAX__;\n\n__PLUGINS__;\n__CONSTANTS__;\n\nin vec2 vTexCoord;\n\nfloat atan2(float v1, float v2) {\n if (v2 == 0.0) {\n if (v1 == 0.0) return 0.0;\n if (v1 > 0.0) return 1.5707963267948966;\n if (v1 < 0.0) return -1.5707963267948966;\n }\n return atan(v1, v2);\n}\n\nfloat cbrt(float x) {\n if (x >= 0.0) {\n return pow(x, 1.0 / 3.0);\n } else {\n return -pow(x, 1.0 / 3.0);\n }\n}\n\nfloat expm1(float x) {\n return pow(${Math.E}, x) - 1.0; \n}\n\nfloat fround(highp float x) {\n return x;\n}\n\nfloat imul(float v1, float v2) {\n return float(int(v1) * int(v2));\n}\n\nfloat log10(float x) {\n return log2(x) * (1.0 / log2(10.0));\n}\n\nfloat log1p(float x) {\n return log(1.0 + x);\n}\n\nfloat _pow(float v1, float v2) {\n if (v2 == 0.0) return 1.0;\n return pow(v1, v2);\n}\n\nfloat _round(float x) {\n return floor(x + 0.5);\n}\n\n\nconst int BIT_COUNT = 32;\nint modi(int x, int y) {\n return x - y * (x / y);\n}\n\nint bitwiseOr(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) || (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseXOR(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) != (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseAnd(int a, int b) {\n int result = 0;\n int n = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) && (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 && b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseNot(int a) {\n // ~a is identically -a - 1 in two's complement, for every value including\n // negatives. The previous bit-by-bit loop only worked for a >= 0, where it\n // leaned on 32-bit overflow wrapping to reach the negative answer; given a\n // negative input it computed ~abs(a), so ~(-1) gave -2 and ~~x never\n // returned x.\n return -a - 1;\n}\nint bitwiseZeroFillLeftShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n *= 2;\n }\n\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\n// _pow2 is defined further down, alongside encode32/decode32\nfloat _pow2(float e);\nint bitwiseSignedRightShift(int num, int shifts) {\n // pow(2.0, n) is approximate on many GPUs, and landing 1 ulp high makes the\n // division fall just under a whole number, which floor() then rounds away:\n // 2 >> 1 came out 0, 8 >> 1 came out 3. Only exact left operands were\n // affected, odd ones having enough slack to survive. _pow2 is exact.\n return int(floor(float(num) / _pow2(float(shifts))));\n}\n\nint bitwiseZeroFillRightShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n /= 2;\n }\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\nvec2 integerMod(vec2 x, float y) {\n vec2 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec3 integerMod(vec3 x, float y) {\n vec3 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec4 integerMod(vec4 x, vec4 y) {\n vec4 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nfloat integerMod(float x, float y) {\n float res = floor(mod(x, y));\n return res * (res > floor(y) - 1.0 ? 0.0 : 1.0);\n}\n\nint integerMod(int x, int y) {\n return x - (y * int(x/y));\n}\n\n// GLSL ES 1.00 accepts only a constant or a loop symbol inside an index\n// expression, so m[y][x] does not compile when y and x come from kernel\n// arguments -- the error is "Index expression can only contain const or loop\n// symbols". Loop counters are legal indices, so walk the matrix with them\n// instead. These are 2x2 to 4x4, so it costs at most sixteen comparisons.\nfloat getMatrix2(mat2 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 2; i++) {\n for (int j = 0; j < 2; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix3(mat3 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 3; i++) {\n for (int j = 0; j < 3; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix4(mat4 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 4; i++) {\n for (int j = 0; j < 4; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\n__DIVIDE_WITH_INTEGER_CHECK__;\n\n// Here be dragons!\n// DO NOT OPTIMIZE THIS CODE\n// YOU WILL BREAK SOMETHING ON SOMEBODY'S MACHINE\n// LEAVE IT AS IT IS, LEST YOU WASTE YOUR OWN TIME\n// Exact powers of two built from exact constant multiplies: exp2/log2/pow\n// are approximate on some GPUs (notably Apple silicon), and 1-2 ulp there\n// corrupts the packed bytes (#659)\nfloat _pow2(float e) {\n float r = 1.0;\n float a = abs(e);\n bool n = e < 0.0;\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 32.0) { r *= n ? 2.3283064365386963e-10 : 4294967296.0; a -= 32.0; }\n if (a >= 16.0) { r *= n ? 0.0000152587890625 : 65536.0; a -= 16.0; }\n if (a >= 8.0) { r *= n ? 0.00390625 : 256.0; a -= 8.0; }\n if (a >= 4.0) { r *= n ? 0.0625 : 16.0; a -= 4.0; }\n if (a >= 2.0) { r *= n ? 0.25 : 4.0; a -= 2.0; }\n if (a >= 1.0) { r *= n ? 0.5 : 2.0; }\n return r;\n}\nconst vec2 MAGIC_VEC = vec2(1.0, -256.0);\nconst vec4 SCALE_FACTOR = vec4(1.0, 256.0, 65536.0, 0.0);\nconst vec4 SCALE_FACTOR_INV = vec4(1.0, 0.00390625, 0.0000152587890625, 0.0); // 1, 1/256, 1/65536\nfloat decode32(vec4 texel) {\n __DECODE32_ENDIANNESS__;\n texel *= 255.0;\n vec2 gte128;\n gte128.x = texel.b >= 128.0 ? 1.0 : 0.0;\n gte128.y = texel.a >= 128.0 ? 1.0 : 0.0;\n float exponent = 2.0 * texel.a - 127.0 + dot(gte128, MAGIC_VEC);\n float res = _pow2(round(exponent));\n texel.b = texel.b - 128.0 * gte128.x;\n res = dot(texel, SCALE_FACTOR) * _pow2(round(exponent-23.0)) + res;\n res *= gte128.y * -2.0 + 1.0;\n return res;\n}\n\nfloat decode16(vec4 texel, int index) {\n int channel = integerMod(index, 2);\n return texel[channel*2] * 255.0 + texel[channel*2 + 1] * 65280.0;\n}\n\nfloat decode8(vec4 texel, int index) {\n int channel = integerMod(index, 4);\n return texel[channel] * 255.0;\n}\n\nvec4 legacyEncode32(float f) {\n float F = abs(f);\n float sign = f < 0.0 ? 1.0 : 0.0;\n float exponent = floor(log2(F));\n float mantissa = (exp2(-exponent) * F);\n // exponent += floor(log2(mantissa));\n vec4 texel = vec4(F * exp2(23.0-exponent)) * SCALE_FACTOR_INV;\n texel.rg = integerMod(texel.rg, 256.0);\n texel.b = integerMod(texel.b, 128.0);\n texel.a = exponent*0.5 + 63.5;\n texel.ba += vec2(integerMod(exponent+127.0, 2.0), sign) * 128.0;\n texel = floor(texel);\n texel *= 0.003921569; // 1/255\n __ENCODE32_ENDIANNESS__;\n return texel;\n}\n\n// https://github.com/gpujs/gpu.js/wiki/Encoder-details\nvec4 encode32(float value) {\n if (value == 0.0) return vec4(0, 0, 0, 0);\n\n float exponent;\n float mantissa;\n vec4 result;\n float sgn;\n\n sgn = step(0.0, -value);\n value = abs(value);\n\n exponent = floor(log2(value));\n float p2 = _pow2(exponent);\n // approximate log2 can land one off; correct by direct comparison\n if (p2 > value) { exponent -= 1.0; p2 *= 0.5; }\n else if (p2 * 2.0 <= value) { exponent += 1.0; p2 *= 2.0; }\n\n mantissa = value / p2 - 1.0;\n exponent = exponent+127.0;\n result = vec4(0,0,0,0);\n\n result.a = floor(exponent/2.0);\n exponent = exponent - result.a*2.0;\n result.a = result.a + 128.0*sgn;\n\n result.b = floor(mantissa * 128.0);\n mantissa = mantissa - result.b / 128.0;\n result.b = result.b + exponent*128.0;\n\n result.g = floor(mantissa*32768.0);\n mantissa = mantissa - result.g/32768.0;\n\n result.r = floor(mantissa*8388608.0);\n return result/255.0;\n}\n// Dragons end here\n\nint index;\nivec3 threadId;\n\nivec3 indexTo3D(int idx, ivec3 texDim) {\n int z = int(idx / (texDim.x * texDim.y));\n idx -= z * int(texDim.x * texDim.y);\n int y = int(idx / texDim.x);\n int x = int(integerMod(idx, texDim.x));\n return ivec3(x, y, z);\n}\n\nfloat get32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize));\n return decode32(texel);\n}\n\nfloat get16(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int w = texSize.x * 2;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize.x * 2, texSize.y));\n return decode16(texel, index);\n}\n\nfloat get8(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int w = texSize.x * 4;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize.x * 4, texSize.y));\n return decode8(texel, index);\n}\n\nfloat getMemoryOptimized32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int channel = integerMod(index, 4);\n index = index / 4;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n index = index / 4;\n vec4 texel = texture(tex, st / vec2(texSize));\n return texel[channel];\n}\n\nvec4 getImage2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n return texture(tex, st / vec2(texSize));\n}\n\nvec4 getImage3D(sampler2DArray tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n return texture(tex, vec3(st / vec2(texSize), z));\n}\n\nfloat getFloatFromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return result[0];\n}\n\nvec2 getVec2FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec2(result[0], result[1]);\n}\n\nvec2 getMemoryOptimizedVec2(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 2);\n index = index / 2;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize));\n if (channel == 0) return vec2(texel.r, texel.g);\n if (channel == 1) return vec2(texel.b, texel.a);\n return vec2(0.0, 0.0);\n}\n\nvec3 getVec3FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec3(result[0], result[1], result[2]);\n}\n\nvec3 getMemoryOptimizedVec3(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int fieldIndex = 3 * (x + texDim.x * (y + texDim.y * z));\n int vectorIndex = fieldIndex / 4;\n int vectorOffset = fieldIndex - vectorIndex * 4;\n int readY = vectorIndex / texSize.x;\n int readX = vectorIndex - readY * texSize.x;\n vec4 tex1 = texture(tex, (vec2(readX, readY) + 0.5) / vec2(texSize));\n\n if (vectorOffset == 0) {\n return tex1.xyz;\n } else if (vectorOffset == 1) {\n return tex1.yzw;\n } else {\n readX++;\n if (readX >= texSize.x) {\n readX = 0;\n readY++;\n }\n vec4 tex2 = texture(tex, vec2(readX, readY) / vec2(texSize));\n if (vectorOffset == 2) {\n return vec3(tex1.z, tex1.w, tex2.x);\n } else {\n return vec3(tex1.w, tex2.x, tex2.y);\n }\n }\n}\n\nvec4 getVec4FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n return getImage2D(tex, texSize, texDim, z, y, x);\n}\n\nvec4 getMemoryOptimizedVec4(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 2);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize));\n return vec4(texel.r, texel.g, texel.b, texel.a);\n}\n\nvec4 actualColor;\nvoid color(float r, float g, float b, float a) {\n actualColor = vec4(r,g,b,a);\n}\n\nvoid color(float r, float g, float b) {\n color(r,g,b,1.0);\n}\n\nfloat modulo(float number, float divisor) {\n if (number < 0.0) {\n number = abs(number);\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return -mod(number, divisor);\n }\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return mod(number, divisor);\n}\n\n__INJECTED_NATIVE__;\n__MAIN_CONSTANTS__;\n__MAIN_ARGUMENTS__;\n__KERNEL__;\n\nvoid main(void) {\n index = int(vTexCoord.s * float(uTexSize.x)) + int(vTexCoord.t * float(uTexSize.y)) * uTexSize.x;\n __MAIN_RESULT__;\n}`}}),Ae=e((e,t)=>{t.exports={vertexShader:"#version 300 es\n__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n\nin vec2 aPos;\nin vec2 aTexCoord;\n\nout vec2 vTexCoord;\nuniform vec2 ratio;\n\nvoid main(void) {\n gl_Position = vec4((aPos + vec2(1)) * ratio + vec2(-1), 0, 1);\n vTexCoord = aTexCoord;\n}"}}),we=e((e,t)=>{const{WebGLKernelValueBoolean:r}=U();t.exports={WebGL2KernelValueBoolean:class extends r{}}}),_e=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueFloat:n}=P();t.exports={WebGL2KernelValueFloat:class extends n{}}}),Ee=e((e,t)=>{const{WebGLKernelValueInteger:r}=B();t.exports={WebGL2KernelValueInteger:class extends r{getSource(e){const t=this.getVariablePrecisionString();return"constants"===this.origin?`const ${t} int ${this.id} = ${parseInt(e)};\n`:`uniform ${t} int ${this.id};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1i(this.id,this.uploadValue=e)}}}}),ve=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueHTMLImage:n}=j();t.exports={WebGL2KernelValueHTMLImage:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}}}}),Ie=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicHTMLImage:n}=X();t.exports={WebGL2KernelValueDynamicHTMLImage:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),$e=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGL2KernelValueHTMLImageArray:class extends n{constructor(e,t){super(e,t),this.checkSize(e[0].width,e[0].height),this.dimensions=[e[0].width,e[0].height,e.length],this.textureSize=[e[0].width,e[0].height]}defineTexture(){const{context:e}=this;e.activeTexture(this.contextHandle),e.bindTexture(e.TEXTURE_2D_ARRAY,this.texture),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_MIN_FILTER,e.NEAREST)}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2DArray ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){const{context:t}=this;t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D_ARRAY,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!0),t.texImage3D(t.TEXTURE_2D_ARRAY,0,t.RGBA,e[0].width,e[0].height,e.length,0,t.RGBA,t.UNSIGNED_BYTE,null);for(let r=0;r{const{utils:r}=i(),{WebGL2KernelValueHTMLImageArray:n}=$e();t.exports={WebGL2KernelValueDynamicHTMLImageArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2DArray ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){const{width:t,height:r}=e[0];this.checkSize(t,r),this.dimensions=[t,r,e.length],this.textureSize=[t,r],this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Fe=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueHTMLImage:n}=ve();t.exports={WebGL2KernelValueHTMLVideo:class extends n{}}}),Le=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueDynamicHTMLImage:n}=Ie();t.exports={WebGL2KernelValueDynamicHTMLVideo:class extends n{}}}),Re=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleInput:n}=Y();t.exports={WebGL2KernelValueSingleInput:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){const{context:t}=this;r.flattenTo(e.value,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),ke=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleInput:n}=Re();t.exports={WebGL2KernelValueDynamicSingleInput:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){let[t,n,s]=e.size;this.dimensions=new Int32Array([t||1,n||1,s||1]),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Ce=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueUnsignedInput:n}=J();t.exports={WebGL2KernelValueUnsignedInput:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}}}}),Me=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicUnsignedInput:n}=Q();t.exports={WebGL2KernelValueDynamicUnsignedInput:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),Ge=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueMemoryOptimizedNumberTexture:n}=ee();t.exports={WebGL2KernelValueMemoryOptimizedNumberTexture:class extends n{getSource(){const{id:e,sizeId:t,textureSize:n,dimensionsId:s,dimensions:i}=this,a=this.getVariablePrecisionString();return r.linesToString([`uniform sampler2D ${e}`,`${a} ivec2 ${t} = ivec2(${n[0]}, ${n[1]})`,`${a} ivec3 ${s} = ivec3(${i[0]}, ${i[1]}, ${i[2]})`])}}}}),ze=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicMemoryOptimizedNumberTexture:n}=te();t.exports={WebGL2KernelValueDynamicMemoryOptimizedNumberTexture:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}}}}),Ne=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueNumberTexture:n}=re();t.exports={WebGL2KernelValueNumberTexture:class extends n{getSource(){const{id:e,sizeId:t,textureSize:n,dimensionsId:s,dimensions:i}=this,a=this.getVariablePrecisionString();return r.linesToString([`uniform ${a} sampler2D ${e}`,`${a} ivec2 ${t} = ivec2(${n[0]}, ${n[1]})`,`${a} ivec3 ${s} = ivec3(${i[0]}, ${i[1]}, ${i[2]})`])}}}}),Oe=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicNumberTexture:n}=ne();t.exports={WebGL2KernelValueDynamicNumberTexture:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),Ve=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray:n}=se();t.exports={WebGL2KernelValueSingleArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(!r.isArray(e))return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Ke=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleArray:n}=Ve();t.exports={WebGL2KernelValueDynamicSingleArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Ue=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray1DI:n}=ae();t.exports={WebGL2KernelValueSingleArray1DI:class extends n{updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Pe=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleArray1DI:n}=Ue();t.exports={WebGL2KernelValueDynamicSingleArray1DI:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Be=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray2DI:n}=ue();t.exports={WebGL2KernelValueSingleArray2DI:class extends n{updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),We=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleArray2DI:n}=Be();t.exports={WebGL2KernelValueDynamicSingleArray2DI:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),je=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray3DI:n}=he();t.exports={WebGL2KernelValueSingleArray3DI:class extends n{updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Xe=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleArray3DI:n}=je();t.exports={WebGL2KernelValueDynamicSingleArray3DI:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),He=e((e,t)=>{const{WebGLKernelValueArray2:r}=pe();t.exports={WebGL2KernelValueArray2:class extends r{}}}),qe=e((e,t)=>{const{WebGLKernelValueArray3:r}=de();t.exports={WebGL2KernelValueArray3:class extends r{}}}),Ye=e((e,t)=>{const{WebGLKernelValueArray4:r}=me();t.exports={WebGL2KernelValueArray4:class extends r{}}}),Ze=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueUnsignedArray:n}=fe();t.exports={WebGL2KernelValueUnsignedArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}}}}),Je=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicUnsignedArray:n}=ge();t.exports={WebGL2KernelValueDynamicUnsignedArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),Qe=e((e,t)=>{const{WebGL2KernelValueBoolean:r}=we(),{WebGL2KernelValueFloat:n}=_e(),{WebGL2KernelValueInteger:s}=Ee(),{WebGL2KernelValueHTMLImage:i}=ve(),{WebGL2KernelValueDynamicHTMLImage:a}=Ie(),{WebGL2KernelValueHTMLImageArray:o}=$e(),{WebGL2KernelValueDynamicHTMLImageArray:u}=De(),{WebGL2KernelValueHTMLVideo:l}=Fe(),{WebGL2KernelValueDynamicHTMLVideo:h}=Le(),{WebGL2KernelValueSingleInput:c}=Re(),{WebGL2KernelValueDynamicSingleInput:p}=ke(),{WebGL2KernelValueUnsignedInput:d}=Ce(),{WebGL2KernelValueDynamicUnsignedInput:m}=Me(),{WebGL2KernelValueMemoryOptimizedNumberTexture:f}=Ge(),{WebGL2KernelValueDynamicMemoryOptimizedNumberTexture:g}=ze(),{WebGL2KernelValueNumberTexture:y}=Ne(),{WebGL2KernelValueDynamicNumberTexture:x}=Oe(),{WebGL2KernelValueSingleArray:b}=Ve(),{WebGL2KernelValueDynamicSingleArray:T}=Ke(),{WebGL2KernelValueSingleArray1DI:S}=Ue(),{WebGL2KernelValueDynamicSingleArray1DI:A}=Pe(),{WebGL2KernelValueSingleArray2DI:w}=Be(),{WebGL2KernelValueDynamicSingleArray2DI:_}=We(),{WebGL2KernelValueSingleArray3DI:E}=je(),{WebGL2KernelValueDynamicSingleArray3DI:v}=Xe(),{WebGL2KernelValueArray2:I}=He(),{WebGL2KernelValueArray3:$}=qe(),{WebGL2KernelValueArray4:D}=Ye(),{WebGL2KernelValueUnsignedArray:F}=Ze(),{WebGL2KernelValueDynamicUnsignedArray:L}=Je(),R={unsigned:{dynamic:{Boolean:r,Integer:s,Float:n,Array:L,"Array(2)":I,"Array(3)":$,"Array(4)":D,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:m,NumberTexture:x,"ArrayTexture(1)":x,"ArrayTexture(2)":x,"ArrayTexture(3)":x,"ArrayTexture(4)":x,MemoryOptimizedNumberTexture:g,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:u,HTMLVideo:h},static:{Boolean:r,Float:n,Integer:s,Array:F,"Array(2)":I,"Array(3)":$,"Array(4)":D,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:d,NumberTexture:y,"ArrayTexture(1)":y,"ArrayTexture(2)":y,"ArrayTexture(3)":y,"ArrayTexture(4)":y,MemoryOptimizedNumberTexture:g,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:o,HTMLVideo:l}},single:{dynamic:{Boolean:r,Integer:s,Float:n,Array:T,"Array(2)":I,"Array(3)":$,"Array(4)":D,"Array1D(2)":A,"Array1D(3)":A,"Array1D(4)":A,"Array2D(2)":_,"Array2D(3)":_,"Array2D(4)":_,"Array3D(2)":v,"Array3D(3)":v,"Array3D(4)":v,Input:p,NumberTexture:x,"ArrayTexture(1)":x,"ArrayTexture(2)":x,"ArrayTexture(3)":x,"ArrayTexture(4)":x,MemoryOptimizedNumberTexture:g,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:u,HTMLVideo:h},static:{Boolean:r,Float:n,Integer:s,Array:b,"Array(2)":I,"Array(3)":$,"Array(4)":D,"Array1D(2)":S,"Array1D(3)":S,"Array1D(4)":S,"Array2D(2)":w,"Array2D(3)":w,"Array2D(4)":w,"Array3D(2)":E,"Array3D(3)":E,"Array3D(4)":E,Input:c,NumberTexture:y,"ArrayTexture(1)":y,"ArrayTexture(2)":y,"ArrayTexture(3)":y,"ArrayTexture(4)":y,MemoryOptimizedNumberTexture:f,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:o,HTMLVideo:l}}};t.exports={kernelValueMaps:R,lookupKernelValueType:function(e,t,r,n){if(!e)throw new Error("type missing");if(!t)throw new Error("dynamic missing");if(!r)throw new Error("precision missing");n.type&&(e=n.type);const s=R[r][t];if("WebGPUBuffer"===e)throw new Error("this kernel runs on WebGL but received a WebGPU pipeline buffer; await handle.toArray() first, or give this kernel the async contract (asyncMode: true / mode: 'async') so the readback happens for you");if(!1===s[e])return null;if(void 0===s[e])throw new Error(`Could not find a KernelValue for ${e}`);return s[e]}}}),et=e((e,t)=>{const{WebGLKernel:r}=xe(),{WebGL2FunctionNode:n}=Te(),{FunctionBuilder:s}=o(),{utils:a}=i(),{fragmentShader:u}=Se(),{vertexShader:l}=Ae(),{lookupKernelValueType:h}=Qe();let c=null,p=null,d=null,m=null;t.exports={WebGL2Kernel:class extends r{static get isSupported(){return null!==c||(this.setupFeatureChecks(),c=this.isContextMatch(d)),c}static setupFeatureChecks(){"undefined"!=typeof document?p=document.createElement("canvas"):"undefined"!=typeof OffscreenCanvas&&(p=new OffscreenCanvas(0,0)),p&&(d=p.getContext("webgl2"),d&&d.getExtension&&(d.getExtension("EXT_color_buffer_float"),d.getExtension("OES_texture_float_linear"),m=this.getFeatures()))}static isContextMatch(e){return"undefined"!=typeof WebGL2RenderingContext&&e instanceof WebGL2RenderingContext}static getFeatures(){const e=this.testContext;return Object.freeze({isFloatRead:this.getIsFloatRead(),isIntegerDivisionAccurate:this.getIsIntegerDivisionAccurate(),isSpeedTacticSupported:this.getIsSpeedTacticSupported(),kernelMap:!0,isTextureFloat:!0,isDrawBuffers:!0,channelCount:this.getChannelCount(),maxTextureSize:this.getMaxTextureSize(),lowIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_INT),lowFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_FLOAT),mediumIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_INT),mediumFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_FLOAT),highIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_INT),highFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT)})}static getIsTextureFloat(){return!0}static getChannelCount(){return d.getParameter(d.MAX_DRAW_BUFFERS)}static getMaxTextureSize(){return d.getParameter(d.MAX_TEXTURE_SIZE)}static lookupKernelValueType(e,t,r,n){return h(e,t,r,n)}static get testCanvas(){return p}static get testContext(){return d}static get features(){return m}static get fragmentShader(){return u}static get vertexShader(){return l}initContext(){return this.canvas.getContext("webgl2",{alpha:!1,depth:!1,antialias:!1})}initExtensions(){this.extensions={EXT_color_buffer_float:this.context.getExtension("EXT_color_buffer_float"),OES_texture_float_linear:this.context.getExtension("OES_texture_float_linear")}}validateSettings(e){if(!this.validate)return void(this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output));const{features:t}=this.constructor;if("single"===this.precision&&!t.isFloatRead)throw new Error("Float texture outputs are not supported");if(this.graphical||null!==this.precision||(this.precision=t.isFloatRead?"single":"unsigned"),null===this.fixIntegerDivisionAccuracy?this.fixIntegerDivisionAccuracy=!t.isIntegerDivisionAccurate:this.fixIntegerDivisionAccuracy&&t.isIntegerDivisionAccurate&&(this.fixIntegerDivisionAccuracy=!1),this.checkOutput(),!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=a.getVariableType(e[0],this.strictIntegers);switch(t){case"Array":this.output=a.getDimensions(t);break;case"NumberTexture":case"MemoryOptimizedNumberTexture":case"ArrayTexture(1)":case"ArrayTexture(2)":case"ArrayTexture(3)":case"ArrayTexture(4)":this.output=e[0].output;break;default:throw new Error("Auto output not supported for input type: "+t)}}if(this.graphical){if(2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");return"single"===this.precision&&(console.warn("Cannot use graphical mode and single precision at the same time"),this.precision="unsigned"),void(this.texSize=a.clone(this.output))}!this.graphical&&null===this.precision&&t.isTextureFloat&&(this.precision="single"),this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output),this.checkTextureSize()}translateSource(){const e=s.fromKernel(this,n,{fixIntegerDivisionAccuracy:this.fixIntegerDivisionAccuracy});this.translatedSource=e.getPrototypeString("kernel"),this.setupReturnTypes(e)}drawBuffers(){this.context.drawBuffers(this.drawBuffersMap)}getTextureFormat(){const{context:e}=this;switch(this.getInternalFormat()){case e.R32F:return e.RED;case e.RG32F:return e.RG;case e.RGBA32F:case e.RGBA:return e.RGBA;default:throw new Error("Unknown internal format")}}renderValues(){return void 0===this._tightRead&&this._detectTightRead(),super.renderValues()}renderKernelsToArrays(){return void 0===this._tightRead&&this._detectTightRead(),super.renderKernelsToArrays()}readFloatPixelsToFloat32Array(){if(!this._tightRead)return super.readFloatPixelsToFloat32Array();const{texSize:e,context:t}=this,r=e[0],n=e[1],s=new Float32Array(r*n);return t.readPixels(0,0,r,n,t.RED,t.FLOAT,s),s}renderOutputAsync(){return this.renderOutput!==this.renderValues?Promise.resolve(this.renderOutput()):this.renderValuesAsync()}renderValuesAsync(){void 0===this._tightRead&&this._detectTightRead();const e=this.formatValues,[t,r,n]=this.output;return this.transferValuesAsync().then(s=>e(s,t,r,n))}transferValuesAsync(){const{texSize:e,context:t}=this,r=e[0],n=e[1];let s,i,a;"single"===this.precision?(s=this._tightRead?t.RED:t.RGBA,i=t.FLOAT,a=new Float32Array(r*n*(this._tightRead?1:4))):(s=t.RGBA,i=t.UNSIGNED_BYTE,a=new Uint8Array(r*n*4));const o=t.createBuffer();t.bindBuffer(t.PIXEL_PACK_BUFFER,o),t.bufferData(t.PIXEL_PACK_BUFFER,a.byteLength,t.STREAM_READ),t.readPixels(0,0,r,n,s,i,0),t.bindBuffer(t.PIXEL_PACK_BUFFER,null);const u=t.fenceSync(t.SYNC_GPU_COMMANDS_COMPLETE,0);return t.flush(),this._pollFence(u).then(()=>(t.bindBuffer(t.PIXEL_PACK_BUFFER,o),t.getBufferSubData(t.PIXEL_PACK_BUFFER,0,a),t.bindBuffer(t.PIXEL_PACK_BUFFER,null),t.deleteBuffer(o),"single"===this.precision?a:new Float32Array(a.buffer)),e=>{throw t.deleteBuffer(o),e})}_pollFence(e){const t=this.context;return new Promise((r,n)=>{let s,i=null;"undefined"!=typeof MessageChannel?(i=new MessageChannel,i.port1.onmessage=()=>o(),s=()=>i.port2.postMessage(0)):s=()=>setTimeout(o,0);const a=(r,n)=>{t.deleteSync(e),i&&(i.port1.close(),i.port2.close()),r(n)},o=()=>{if(t.isContextLost())return a(n,new Error("WebGL context lost while awaiting kernel result"));const i=t.clientWaitSync(e,0,0);return i===t.ALREADY_SIGNALED||i===t.CONDITION_SATISFIED?a(r):i===t.WAIT_FAILED?a(n,new Error("clientWaitSync failed while awaiting kernel result")):void s()};o()})}_detectTightRead(){const e=this.context;this._tightRead=!1,e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer);const t="Number"===this.returnType||"Float"===this.returnType||"Integer"===this.returnType||"LiteralInteger"===this.returnType;if("single"===this.precision&&!this.optimizeFloatMemory&&!this.graphical&&t&&e.getParameter(e.IMPLEMENTATION_COLOR_READ_FORMAT)===e.RED&&e.getParameter(e.IMPLEMENTATION_COLOR_READ_TYPE)===e.FLOAT){if(this.formatValues===a.erectFloat)this.formatValues=a.erectMemoryOptimizedFloat;else if(this.formatValues===a.erect2DFloat)this.formatValues=a.erectMemoryOptimized2DFloat;else if(this.formatValues===a.erect3DFloat)this.formatValues=a.erectMemoryOptimized3DFloat;else if(this.formatValues!==a.erectMemoryOptimizedFloat&&this.formatValues!==a.erectMemoryOptimized2DFloat&&this.formatValues!==a.erectMemoryOptimized3DFloat)return;this._tightRead=!0}}getInternalFormat(){const{context:e}=this;if("single"===this.precision)switch(this.returnType){case"Number":case"Float":case"Integer":return this.optimizeFloatMemory?e.RGBA32F:e.R32F;case"Array(2)":return e.RG32F;case"Array(3)":case"Array(4)":return e.RGBA32F;default:throw new Error("Unhandled return type")}return e.RGBA}_setupOutputTexture(){const e=this.context;if(this.texture)return e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.texture.texture,0),void(this._tightRead=void 0);e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer);const t=e.createTexture(),r=this.texSize;e.activeTexture(e.TEXTURE0+this.constantTextureCount+this.argumentTextureCount),e.bindTexture(e.TEXTURE_2D,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.REPEAT),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.REPEAT),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);const n=this.getInternalFormat();"single"===this.precision?e.texStorage2D(e.TEXTURE_2D,1,n,r[0],r[1]):e.texImage2D(e.TEXTURE_2D,0,n,r[0],r[1],0,n,e.UNSIGNED_BYTE,null),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t,0),this.texture=new this.TextureConstructor({texture:t,size:r,dimensions:this.threadDim,output:this.output,context:this.context,internalFormat:this.getInternalFormat(),textureFormat:this.getTextureFormat(),kernel:this}),this._tightRead=void 0}_setupSubOutputTextures(){const e=this.context;if(this.mappedTextures){for(let t=0;t{const{utils:r}=i(),{FunctionNode:n}=l();const s={Number:"f32",Float:"f32",Integer:"i32",LiteralInteger:"f32",Boolean:"bool","Array(2)":"vec2","Array(3)":"vec3","Array(4)":"vec4"},a={"===":"==","!==":"!="},o=["x","y","z","w"],u={pow:"_pow",round:"_round"},h={ceil:!0,floor:!0,_round:!0};t.exports={WGSLFunctionNode:class extends n{get requiresSequenceFreeForInit(){return!0}wgslFloat(e){if(e===1/0)return"0x1.fffffep+127";if(e===-1/0)return"-0x1.fffffep+127";if(e>34028234663852886e22)return"0x1.fffffep+127";if(e<-34028234663852886e22)return"-0x1.fffffep+127";const t=`${e}`;return-1!==t.indexOf(".")||-1!==t.indexOf("e")||-1!==t.indexOf("E")?t:`${t}.0`}wgslInt(e){return`${Math.round(e)}`}mangleFunctionName(e){return`fn_${r.sanitizeName(e)}`}getLookupType(e){return"WebGPUBuffer"===e?"Number":super.getLookupType(e)}astUpdateExpression(e,t){return this.astGeneric(e.argument,t),t.push(e.operator),t}getType(e){if(e&&"ConditionalExpression"===e.type){const t=this.getType(e.consequent);if("Integer"===t||"LiteralInteger"===t){const t=this.getType(e.alternate);if("Number"===t||"Float"===t)return"Number"}}return super.getType(e)}astConditionalExpression(e,t){if("ConditionalExpression"!==e.type)throw this.astErrorOutput("Not a conditional expression",e);const r=this.getType(e.consequent),n=this.getType(e.alternate);if(null===r&&null===n)return t.push("if ("),this.astGeneric(e.test,t),t.push(") {"),this.astGeneric(e.consequent,t),t.push(";"),t.push("} else {"),this.astGeneric(e.alternate,t),t.push(";"),t.push("}"),t;let s="LiteralInteger"===r?"Number":r;"Integer"!==s||"Number"!==n&&"Float"!==n||(s="Number");const i=e=>{const r=this.getType(e);switch(s){case"Number":case"Float":"Integer"===r?this.castValueToFloat(e,t):"LiteralInteger"===r?this.castLiteralToFloat(e,t):this.astGeneric(e,t);break;case"Integer":"Number"===r||"Float"===r?this.castValueToInteger(e,t):"LiteralInteger"===r?this.castLiteralToInteger(e,t):this.astGeneric(e,t);break;default:this.astGeneric(e,t)}};return t.push("select("),i(e.alternate),t.push(", "),i(e.consequent),t.push(", "),this.astGeneric(e.test,t),t.push(")"),t}astFunction(e,t){if(this.isRootKernel){for(let r=0;r0&&t.push(", ");let a=this.argumentTypes[this.argumentNames.indexOf(i)];if(!a)throw this.astErrorOutput(`Unknown argument ${i} type`,e);"LiteralInteger"===a&&(this.argumentTypes[n]=a="Number");const o=s[a];if(!o)throw this.astErrorOutput(`WebGPU backend does not yet support ${a} arguments to helper functions`,e);t.push(`user_${r.sanitizeName(i)} : ${o}`)}t.push(")"),i&&t.push(` -> ${i}`),t.push(" {\n");for(let r=0;r>":!0,">>>":!0}[e.operator])return null;const r=e=>{switch(this.getType(e)){case"Number":case"Float":this.castValueToInteger(e,t);break;case"LiteralInteger":this.castLiteralToInteger(e,t);break;default:this.pushState("building-integer"),this.astGeneric(e,t),this.popState("building-integer")}};return t.push("("),">>>"===e.operator?(t.push("bitcast(bitcast("),r(e.left),t.push(") >> u32("),r(e.right),t.push("))")):"<<"===e.operator||">>"===e.operator?(r(e.left),t.push(` ${e.operator} u32(`),r(e.right),t.push(")")):(r(e.left),t.push(` ${e.operator} `),r(e.right)),t.push(")"),t}checkAndUpconvertBitwiseUnary(e,t){if("~"!==e.operator)return null;switch(t.push("~("),this.getType(e.argument)){case"Number":case"Float":this.castValueToInteger(e.argument,t);break;case"LiteralInteger":this.castLiteralToInteger(e.argument,t);break;default:this.astGeneric(e.argument,t)}return t.push(")"),t}astUnaryExpression(e,t){return this.checkAndUpconvertBitwiseUnary(e,t)?t:"+"===e.operator?(this.astGeneric(e.argument,t),t):(e.prefix?(t.push(e.operator),this.astGeneric(e.argument,t)):(this.astGeneric(e.argument,t),t.push(e.operator)),t)}castLiteralToInteger(e,t){return this.pushState("casting-to-integer"),this.astGeneric(e,t),this.popState("casting-to-integer"),t}castLiteralToFloat(e,t){return this.pushState("casting-to-float"),this.astGeneric(e,t),this.popState("casting-to-float"),t}castValueToInteger(e,t){return this.pushState("casting-to-integer"),t.push("i32("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-integer"),t}castValueToFloat(e,t){return this.pushState("casting-to-float"),t.push("f32("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-float"),t}astIdentifierExpression(e,t){if("Identifier"!==e.type)throw this.astErrorOutput("IdentifierExpression - not an Identifier",e);const n=this.getType(e),s=r.sanitizeName(e.name);return"Infinity"===e.name?(t.push("0x1.fffffep+127"),t):!this.isRootKernel||-1===this.argumentNames.indexOf(e.name)||"Number"!==n&&"Float"!==n&&"Integer"!==n&&"Boolean"!==n?(t.push(`user_${s}`),t):("Boolean"===n?t.push(`bool(params.user_${s})`):t.push(`params.user_${s}`),t)}astForStatement(e,t){if("ForStatement"!==e.type)throw this.astErrorOutput("Invalid for statement",e);const r=[],n=[],s=[],i=[];let a=null;if(e.init){const{declarations:t}=e.init;t.length>1&&(a=!1),this.astGeneric(e.init,r);for(let e=0;e0&&t.push(r.join(""),"\n"),t.push(`for (var ${e} : i32 = 0;${e}0&&t.push(`if (!(${n.join("")})) { break; }\n`),t.push(i.join("")),t.push(`\n${s.join("")};`),t.push("}\n")}return t}astWhileStatement(e,t){if("WhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);const r=this.getInternalVariableName("safeI");return t.push(`for (var ${r} : i32 = 0;${r}{if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(t);if("BreakStatement"===e.type)return!0;if("ForStatement"===e.type||"WhileStatement"===e.type||"DoWhileStatement"===e.type||"SwitchStatement"===e.type)return!1;for(const r in e)if("loc"!==r&&"range"!==r&&"parent"!==r&&t(e[r]))return!0;return!1};if(t(r[e]))throw this.astErrorOutput("break inside a switch case is only supported as the case terminator",r[e])}for(let e=0;ee+1){u=!0,this.astSwitchCaseConsequent(n[e].consequent,o);continue}t.push(" else {\n")}this.astSwitchCaseConsequent(n[e].consequent,t),t.push("\n}")}return u&&(t.push(" else {"),t.push(o.join("")),t.push("}")),t.push("\n"),t}astThisExpression(e,t){return t.push("this"),t}astSequenceExpression(e,t){const{expressions:r}=e;if(1===r.length)return this.astGeneric(r[0],t),t;throw this.astErrorOutput("WebGPU backend does not yet support the comma operator",e)}astMemberExpression(e,t){const{property:n,name:i,signature:a,origin:o,type:u,xProperty:l,yProperty:h,zProperty:c}=this.getMemberExpressionDetails(e);switch(a){case"value.thread.value":case"this.thread.value":if("x"!==i&&"y"!==i&&"z"!==i)throw this.astErrorOutput("Unexpected expression, expected `this.thread.x`, `this.thread.y`, or `this.thread.z`",e);return t.push(`i32(threadGid.${i})`),t;case"this.output.value":{const r={x:0,y:1,z:2}[i];if(void 0===r)throw this.astErrorOutput("Unexpected expression",e);if(this.dynamicOutput){const e=`params.output${i.toUpperCase()}`;this.isState("casting-to-float")?t.push(`f32(${e})`):t.push(`i32(${e})`)}else this.isState("casting-to-integer")?t.push(`${this.output[r]}`):t.push(`${this.output[r]}.0`);return t}case"value":throw this.astErrorOutput("Unexpected expression",e);case"value[]":case"value[][]":case"value[][][]":case"value[][][][]":case"value.value":if("Math"===o)return t.push(this.wgslFloat(Math[i])),t;switch(n){case"r":return t.push(`user_${r.sanitizeName(i)}.x`),t;case"g":return t.push(`user_${r.sanitizeName(i)}.y`),t;case"b":return t.push(`user_${r.sanitizeName(i)}.z`),t;case"a":return t.push(`user_${r.sanitizeName(i)}.w`),t}break;case"this.constants.value":{const r=this.constants[i];switch(u){case"Integer":return this.isState("casting-to-float")?t.push(this.wgslFloat(r)):t.push(this.wgslInt(r)),t;case"Number":case"Float":return this.isState("casting-to-integer")?t.push(this.wgslInt(r)):t.push(this.wgslFloat(r)),t;case"Boolean":return t.push(r?"true":"false"),t;case"Array(2)":case"Array(3)":case"Array(4)":{const e=parseInt(u.substring(6),10),n=[];for(let t=0;t4)throw this.astErrorOutput("this.color takes (r, g, b) or (r, g, b, a)",e);t.push("kernelColor(data_index");for(let r=0;r0&&t.push(", "),s){case"Integer":this.castValueToFloat(n,t);break;case"LiteralInteger":this.castLiteralToFloat(n,t);break;default:this.astGeneric(n,t)}}else{const s=this.lookupFunctionArgumentTypes(n)||[];for(let i=0;i0&&t.push(", ");const u=this.getType(a);switch(o||(this.triggerImplyArgumentType(n,i,u,this),o=u),u){case"Boolean":this.astGeneric(a,t);continue;case"Number":case"Float":if("Integer"===o){t.push("i32("),this.astGeneric(a,t),t.push(")");continue}if("Number"===o||"Float"===o){this.astGeneric(a,t);continue}if("LiteralInteger"===o){this.castLiteralToFloat(a,t);continue}break;case"Integer":if("Number"===o||"Float"===o){t.push("f32("),this.astGeneric(a,t),t.push(")");continue}if("Integer"===o){this.astGeneric(a,t);continue}break;case"LiteralInteger":if("Integer"===o){this.castLiteralToInteger(a,t);continue}if("Number"===o||"Float"===o){this.castLiteralToFloat(a,t);continue}if("LiteralInteger"===o){this.astGeneric(a,t);continue}break;case"Array(2)":case"Array(3)":case"Array(4)":if(o===u){"Identifier"===a.type?t.push(`user_${r.sanitizeName(a.name)}`):this.astGeneric(a,t);continue}break;case"Array":case"Array2D":case"Array3D":case"Input":case"WebGPUBuffer":throw this.astErrorOutput("WebGPU backend does not yet support array arguments to helper functions",e)}throw this.astErrorOutput(`Unhandled argument combination of ${u} and ${o} for argument named "${a.name}"`,e)}}return t.push(")"),a&&t.push(")"),t}astArrayExpression(e,t){switch(this.getType(e)){case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":throw this.astErrorOutput("WebGPU backend does not yet support Matrix types",e)}const r=e.elements.length;t.push(`vec${r}(`);for(let n=0;n0&&t.push(", ");const r=e.elements[n];switch(this.getType(r)){case"Integer":this.castValueToFloat(r,t);break;case"LiteralInteger":this.castLiteralToFloat(r,t);break;default:this.astGeneric(r,t)}}return t.push(")"),t}memberExpressionXYZ(e,t,r,n){return r?n.push(this.memberExpressionPropertyMarkup(r),", "):n.push("0, "),t?n.push(this.memberExpressionPropertyMarkup(t),", "):n.push("0, "),n.push(this.memberExpressionPropertyMarkup(e)),n}memberExpressionPropertyMarkup(e){if(!e)throw new Error("Property not set");const t=[];switch(this.getType(e)){case"Number":case"Float":this.castValueToInteger(e,t);break;case"LiteralInteger":this.castLiteralToInteger(e,t);break;case"Integer":this.pushState("building-integer"),t.push("i32("),this.astGeneric(e,t),t.push(")"),this.popState("building-integer");break;default:this.astGeneric(e,t)}return t.join("")}}}}),rt=e((e,t)=>{let r=null;t.exports={WebGPUContext:class e{static get isSupported(){return"undefined"!=typeof navigator&&!!navigator.gpu}static acquire(){if(r)return r;const t=(async()=>{if(!e.isSupported)throw new Error("WebGPU is not supported on this platform (navigator.gpu is missing)");const n=await navigator.gpu.requestAdapter();if(!n)throw new Error("WebGPU is present (navigator.gpu) but no adapter is available. On headless Chromium there is no adapter; run headed. Use `await GPU.isWebGPUAvailable()` to feature-detect.");const s=await n.requestDevice({requiredLimits:{maxStorageBufferBindingSize:n.limits.maxStorageBufferBindingSize,maxBufferSize:n.limits.maxBufferSize}}),i={adapter:n,device:s,isLost:!1};return s.lost.then(e=>{i.isLost=!0,"destroyed"!==e.reason&&console.error(`gpu.js [webgpu]: device lost: ${e.message}`),r===t&&(r=null)}),s.onuncapturederror=e=>{console.error(`gpu.js [webgpu]: ${e.error.message}`)},i})();return t.catch(()=>{r===t&&(r=null)}),r=t}static destroy(){if(!r)return Promise.resolve();const e=r;return r=null,e.then(({device:e})=>{e.destroy()},()=>{})}}}}),nt=e((e,t)=>{t.exports={WebGPUBufferResult:class e{constructor(e){this.buffer=e.buffer,this.output=e.output,this.componentCount=e.componentCount||1,this.context=e.context,this.kernel=e.kernel,this.type="WebGPUBuffer",this._deleted=!1,this.buffer._refs?this.buffer._refs++:this.buffer._refs=1}toArray(){return this._deleted?Promise.reject(new Error("WebGPUBufferResult has been deleted")):this.kernel.readBufferResult(this)}delete(){this._deleted||(this._deleted=!0,0===--this.buffer._refs&&this.buffer.destroy())}clone(){return new e(this)}}}}),st=e((e,t)=>{const{Kernel:r}=a(),{FunctionBuilder:s}=o(),{WGSLFunctionNode:u}=tt(),{WebGPUContext:l}=rt(),{WebGPUBufferResult:h}=nt(),{utils:c}=i(),{Input:p}=n(),d=Object.freeze({kernelMap:!1,isIntegerDivisionAccurate:!0,isSpeedTacticSupported:!1,isTextureFloat:!0,isDrawBuffers:!1,kernelMapSize:0,channelCount:1,maxTextureSize:1/0,isFloatRead:!0}),m={_pow:"fn _pow(v1 : f32, v2 : f32) -> f32 {\n if (v2 == 0.0) { return 1.0; }\n return pow(v1, v2);\n}",_round:"fn _round(x : f32) -> f32 {\n return floor(x + 0.5);\n}",cbrt:"fn cbrt(x : f32) -> f32 {\n return sign(x) * pow(abs(x), 1.0 / 3.0);\n}",expm1:"fn expm1(x : f32) -> f32 {\n return exp(x) - 1.0;\n}",fround:"fn fround(x : f32) -> f32 {\n return x;\n}",imul:"fn imul(a : f32, b : f32) -> f32 {\n return f32(i32(a) * i32(b));\n}",log10:`fn log10(x : f32) -> f32 {\n return log2(x) * ${1/Math.log2(10)};\n}`,log1p:"fn log1p(x : f32) -> f32 {\n return log(1.0 + x);\n}",clz32:"fn clz32(x : f32) -> f32 {\n return f32(countLeadingZeros(u32(x)));\n}"};t.exports={WebGPUKernel:class extends r{static get isSupported(){return l.isSupported}static get isAsync(){return!0}static isContextMatch(e){return Boolean(e&&"function"==typeof e.createShaderModule&&"function"==typeof e.createComputePipeline)}static getFeatures(){return d}static get features(){return d}static get mode(){return"webgpu"}static getSignature(e,t){return"webgpu"+(t.length>0?":"+t.join(","):"")}static destroyContext(e){}static nativeFunctionArguments(){throw new Error("WebGPU backend does not yet support native functions")}static nativeFunctionReturnType(){throw new Error("WebGPU backend does not yet support native functions")}static combineKernels(){throw new Error("WebGPU backend does not yet support combineKernels; chain kernels with `await` and pipeline mode instead")}constructor(e,t){if(super(e,t),t){if("unsigned"===t.precision&&!t.graphical)throw new Error("WebGPU backend does not yet support precision: 'unsigned'; it is single precision only");if(t.subKernels)throw new Error("WebGPU backend does not yet support createKernelMap")}this.mergeSettings(e.settings||t),(null===this.precision||this.graphical)&&(this.precision="single"),this.asyncMode=!0,this.threadDim=null,this.componentCount=1,this.compiledSource=null,this.translatedBody=null,this.translatedFunctions=null,this.paramsLayout=null,this._buildPromise=null,this._device=null,this.computePipeline=null,this.bindGroupLayout=null,this.bindGroup=null,this.bindGroupDirty=!0,this.paramsBuffer=null,this.paramsMirror=null,this.outputBuffer=null,this.argumentBuffers=null,this.constantBuffers=null,this.stagingPool=[],this._canvasContext=null,this._blitPipeline=null,this._blitParamsBuffer=null,this._blitBindGroup=null,this._blitBoundOutputBuffer=null}initCanvas(){return this.graphical&&"undefined"!=typeof document?document.createElement("canvas"):null}initContext(){return null}initPlugins(e){return[]}setOutput(e){const t=this.toKernelOutput(e);if(this.built){if(!this.dynamicOutput)throw new Error("Resizing a kernel with dynamicOutput: false is not possible");if(t.length!==this.output.length)throw new Error("WebGPU backend does not yet support changing the output rank of a built kernel; the workgroup shape is fixed at build")}return this.output=t,this}toString(){throw new Error("WebGPU backend does not yet support toString")}validateSettings(e){if(this.graphical){if(!this.output||2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");if(this.pipeline)throw new Error("graphical mode and pipeline mode are mutually exclusive");if(!this.canvas)throw new Error("graphical mode requires a canvas (none could be created; pass one in settings)")}if("unsigned"===this.precision)throw new Error("WebGPU backend does not yet support precision: 'unsigned'; it is single precision only");if(this.precision="single",this.subKernels&&this.subKernels.length>0)throw new Error("WebGPU backend does not yet support createKernelMap");if(!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=c.getVariableType(e[0],this.strictIntegers);if("Array"===t)this.output=Array.from(c.getDimensions(e[0]));else{if("WebGPUBuffer"!==t)throw new Error("Auto output not supported for input type: "+t);this.output=Array.from(e[0].output)}}this.checkOutput()}setupArguments(e){super.setupArguments(e);for(let e=0;e,`);for(let e=0;e params : Params;");for(let t=0;t user_${e[t].name} : array;`);const i=1+e.length;n.push(`@group(0) @binding(${i}) var result : array;`),this.graphical&&n.push("fn kernelColor(index : i32, r : f32, g : f32, b : f32, a : f32) {\n result[index * 4] = r;\n result[index * 4 + 1] = g;\n result[index * 4 + 2] = b;\n result[index * 4 + 3] = a;\n}");for(let e=0;e constants_${r[e].name} : array;`);n.push("var threadGid : vec3;"),null!==this.paramsLayout.randomSeedOffset&&n.push("var pcgState : u32;\nfn pcg_random() -> f32 {\n pcgState = pcgState * 747796405u + 2891336453u;\n let word = ((pcgState >> ((pcgState >> 28u) + 4u)) ^ pcgState) * 277803737u;\n let mixed = (word >> 22u) ^ word;\n return f32(mixed >> 8u) / 16777216.0;\n}");const a=`${this.translatedFunctions}\n${this.translatedBody}`;/\bLOOP_MAX\b/.test(a)&&n.push(`const LOOP_MAX : i32 = ${parseInt(this.loopMaxIterations,10)||1e3};`);for(const e in m)new RegExp(`\\b${e}\\(`).test(a)&&n.push(m[e]);for(let t=0;t f32 {\n return user_${r}[u32(x + i32(params.user_${r}_dims.x) * (y + i32(params.user_${r}_dims.y) * z))];\n}`)}for(let e=0;e f32 {\n return constants_${t.name}[u32(x + ${i[0]} * (y + ${i[1]} * z))];\n}`)}this.translatedFunctions&&n.push(this.translatedFunctions);const o=1===this.output.length?[64,1,1]:[8,8,1];return this.workgroupSize=o,1===this.output.length?n.push(`@compute @workgroup_size(${o[0]}, ${o[1]}, ${o[2]})\nfn main(@builtin(global_invocation_id) gid : vec3) {\n let flat_index : u32 = gid.x + gid.y * params.dispatchWidth;\n threadGid = vec3(flat_index, 0u, 0u);\n if (flat_index >= params.outputX) { return; }\n let data_index : i32 = i32(flat_index);\n${null!==this.paramsLayout.randomSeedOffset?" pcgState = (params.randomSeed + u32(data_index) * 2654435769u) * 747796405u + 2891336453u;\n":""}${this.translatedBody}\n}`):n.push(`@compute @workgroup_size(${o[0]}, ${o[1]}, ${o[2]})\nfn main(@builtin(global_invocation_id) gid : vec3) {\n threadGid = gid;\n if (gid.x >= params.outputX || gid.y >= params.outputY || gid.z >= params.outputZ) { return; }\n let data_index : i32 = i32(gid.x + params.outputX * (gid.y + params.outputY * gid.z));\n${null!==this.paramsLayout.randomSeedOffset?" pcgState = (params.randomSeed + u32(data_index) * 2654435769u) * 747796405u + 2891336453u;\n":""}${this.translatedBody}\n}`),n.join("\n")}constantDimensions(e){const t=e instanceof p?Array.from(e.size):Array.from(c.getDimensions(e));for(;t.length<3;)t.push(1);return t}async _buildAsync(){const e=await l.acquire();this.context=e;const t=this._device=e.device,r=t.createShaderModule({code:this.compiledSource}),n=(await r.getCompilationInfo()).messages.filter(e=>"error"===e.type);if(n.length>0)throw new Error("Error compiling WGSL compute shader:\n"+n.map(e=>` ${e.lineNum}:${e.linePos} ${e.message}`).join("\n")+`\n--- generated WGSL ---\n${this.compiledSource}`);const{arrayArgs:s,bufferConstants:i,byteLength:a}=this.paramsLayout,o=[{binding:0,visibility:4,buffer:{type:"uniform"}}];for(let e=0;ei&&(s[1]=Math.ceil(s[0]/i),s[0]=Math.ceil(s[0]/s[1])),a=s[0]*t);for(let e=0;e<3;e++)if(s[e]>i)throw new Error(`output dimension ${e} needs ${s[e]} workgroups, over this device's limit of ${i}`);return{groups:s,dispatchWidth:a}}async _buildBlitPipeline(e){if(this.canvas.width=this.output[0],this.canvas.height=this.output[1],this._canvasContext=this.canvas.getContext("webgpu"),!this._canvasContext)throw new Error("could not get a webgpu context from the canvas");const t=navigator.gpu.getPreferredCanvasFormat();this._canvasContext.configure({device:e,format:t,alphaMode:"premultiplied"});const r=e.createShaderModule({code:"struct BlitParams { width : u32, height : u32, pad0 : u32, pad1 : u32 }\n@group(0) @binding(0) var blit : BlitParams;\n@group(0) @binding(1) var pixels : array;\n@vertex fn vs(@builtin(vertex_index) vi : u32) -> @builtin(position) vec4 {\n var pos = array, 3>(vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));\n return vec4(pos[vi], 0.0, 1.0);\n}\n@fragment fn fs(@builtin(position) pos : vec4) -> @location(0) vec4 {\n let x = u32(pos.x);\n let y = u32(pos.y);\n let row = blit.height - 1u - y;\n let i = (row * blit.width + x) * 4u;\n let a = pixels[i + 3u];\n return vec4(pixels[i] * a, pixels[i + 1u] * a, pixels[i + 2u] * a, a);\n}"}),n=(await r.getCompilationInfo()).messages.filter(e=>"error"===e.type);if(n.length>0)throw new Error("Error compiling the graphical blit shader:\n"+n.map(e=>` ${e.lineNum}:${e.linePos} ${e.message}`).join("\n"));this._blitBindGroupLayout=e.createBindGroupLayout({entries:[{binding:0,visibility:2,buffer:{type:"uniform"}},{binding:1,visibility:2,buffer:{type:"read-only-storage"}}]}),this._blitPipeline=e.createRenderPipeline({layout:e.createPipelineLayout({bindGroupLayouts:[this._blitBindGroupLayout]}),vertex:{module:r,entryPoint:"vs"},fragment:{module:r,entryPoint:"fs",targets:[{format:t}]},primitive:{topology:"triangle-list"}}),this._blitParamsBuffer=e.createBuffer({size:16,usage:72})}_ensureOutputBuffer(){const[e,t,r]=this.threadDim,n=e*t*r*4*this.componentCount;this.immutable&&this.pipeline&&this.outputBuffer&&(0===--this.outputBuffer._refs&&this.outputBuffer.destroy(),this.outputBuffer=null,this.bindGroupDirty=!0),this.outputBuffer&&this.outputBuffer.size>=n||(this.outputBuffer&&0===--this.outputBuffer._refs&&this.outputBuffer.destroy(),this._checkBufferSize(n,`output [${this.output.join(", ")}]`),this.outputBuffer=this._device.createBuffer({size:n,usage:132}),this.outputBuffer._refs=1,this.bindGroupDirty=!0)}_checkBufferSize(e,t){const r=this._device.limits,n=Math.min(r.maxStorageBufferBindingSize,r.maxBufferSize);if(e>n)throw new Error(`WebGPU backend: ${t} needs ${e} bytes but this device allows ${n} per storage buffer (maxStorageBufferBindingSize/maxBufferSize); reduce the output or split the work across kernels`)}_snapshotArguments(e){const t=new Array(e.length);for(let r=0;rthis._runInternal(e))}_runInternal(e){if(this.context&&this.context.isLost)throw new Error("WebGPU device was lost; call kernel.destroy() (or gpu.destroy()) and run again to rebuild on a fresh device");const t=this._device,r=t.queue,{arrayArgs:n,scalarArgs:s,bufferConstants:i}=this.paramsLayout,a=this.threadDim=Array.from(this.output);for(;a.length<3;)a.push(1);if(this._ensureOutputBuffer(),null!==this.paramsLayout.randomSeedOffset){const e=null!==this.randomSeed?this.randomSeed>>>0:4294967296*Math.random()>>>0;this.paramsU32[this.paramsLayout.randomSeedOffset/4]=e}this.paramsU32[0]=a[0],this.paramsU32[1]=a[1],this.paramsU32[2]=a[2],this.paramsU32[3]=this._computeDispatch(a).dispatchWidth;for(let s=0;s{const e=new Float32Array(p.buffer.getMappedRange(0,u).slice(0));return p.buffer.unmap(),this._releaseStaging(p),this._shapeOutput(e,d,this.componentCount)},e=>{throw this._releaseStaging(p),e})}_acquireStaging(e){for(let t=0;t=e)return r.busy=!0,r}const t={buffer:this._device.createBuffer({size:e,usage:9}),size:e,busy:!0,pooled:this.stagingPool.length<3};return t.pooled&&this.stagingPool.push(t),t}_releaseStaging(e){e.pooled?e.busy=!1:e.buffer.destroy()}_shapeOutput(e,t,r){const[n,s,i]=[t[0],t[1]||1,t[2]||1];if(1===r)switch(t.length){case 1:return c.erectMemoryOptimizedFloat(e,n);case 2:return c.erectMemoryOptimized2DFloat(e,n,s);default:return c.erectMemoryOptimized3DFloat(e,n,s,i)}const a=r,o=t=>{const r=new Array(n);for(let s=0;s{const t=new Float32Array(i.buffer.getMappedRange(0,s).slice(0));return i.buffer.unmap(),this._releaseStaging(i),this._shapeOutput(t,r,e.componentCount)},e=>{throw this._releaseStaging(i),e})}getPixels(e){if(!this.graphical)return Promise.reject(new Error("getPixels only works on a graphical kernel"));if(!this.outputBuffer)return Promise.reject(new Error("run the kernel before reading its pixels"));const[t,r]=this.output,n=t*r*4*4,s=this._acquireStaging(n),i=this._device.createCommandEncoder();return i.copyBufferToBuffer(this.outputBuffer,0,s.buffer,0,n),this._device.queue.submit([i.finish()]),s.buffer.mapAsync(1,0,n).then(()=>{const i=new Float32Array(s.buffer.getMappedRange(0,n).slice(0));s.buffer.unmap(),this._releaseStaging(s);const a=new Uint8ClampedArray(t*r*4);for(let n=0;n{throw this._releaseStaging(s),e})}destroy(e){if(this._blitParamsBuffer&&(this._blitParamsBuffer.destroy(),this._blitParamsBuffer=null),this._canvasContext&&(this._canvasContext.unconfigure(),this._canvasContext=null),this._blitPipeline=null,this._blitBindGroup=null,this._blitBoundOutputBuffer=null,this.paramsBuffer&&(this.paramsBuffer.destroy(),this.paramsBuffer=null),this.paramsLayout)for(let e=0;e{const{utils:r}=i(),{Input:s}=n();function a(e,t){if(t.kernel)return void(t.kernel=e);const n=r.allPropertiesOf(e);for(let r=0;rt.kernel[s]),t.__defineSetter__(s,e=>{t.kernel[s]=e})))}t.kernel=e}t.exports={kernelRunShortcut:function(e){function t(t){e.build.apply(e,t),e.checkArgumentTypes(t);let n=e.switchingKernels?void 0:e.run.apply(e,t);for(let s=0;e.switchingKernels;s++){if(s>=4){const t=e.resetSwitchingKernels();throw new Error(`this kernel cannot run the arguments it was given (${r(t)}); it did not settle on a kernel for them after 4 attempts. Create a separate kernel for this call's argument types.`)}const i=e.resetSwitchingKernels(),a=e.onRequestSwitchKernel(i,t,e);c.kernel=e=a,a.checkArgumentTypes(t),n=a.switchingKernels?void 0:a.run.apply(a,t)}return n}function r(e){return e&&e.length?e.map(e=>"argumentTypeMismatch"===e.type?`argument ${e.index} is now ${e.needed}`:e.type).join(", "):"unknown reason"}function n(r){if(e.onAsyncModeUpgrade){const t=e.onAsyncModeUpgrade;e.onAsyncModeUpgrade=null;const s=u(r);return t(s,e).then(e=>(e&&c.replaceKernel(e),n(s)))}try{if(!0===e.constructor.isAsync)return e.build.apply(e,r),Promise.resolve(e.run.apply(e,r));for(let e=0;en(e));const s=t(r);return e.renderKernels?Promise.resolve(e.renderKernels()):e.renderOutput?e.renderOutputAsync?e.renderOutputAsync():Promise.resolve(e.renderOutput()):Promise.resolve(s)}catch(e){return Promise.reject(e)}}function i(e){return Boolean(e)&&"WebGPUBuffer"===e.type}function o(e){const t=u(e),r=[];for(let e=0;e{t[n]=e}))}return Promise.all(r).then(()=>t)}function u(e){const t=new Array(e.length);for(let r=0;r{try{e(h.apply(this,arguments))}catch(e){t(e)}})},c.replaceKernel=function(t){a(e=t,c)},a(e,c),c}}}),at=e((e,r)=>{const{gpuMock:n}=t(),{utils:s}=i(),{Kernel:o}=a(),{CPUKernel:u}=p(),{HeadlessGLKernel:l}=be(),{WebGL2Kernel:h}=et(),{WebGLKernel:c}=xe(),{WebGPUKernel:d}=st(),{kernelRunShortcut:m}=it(),f=[l,h,c],g=["gpu","cpu"],y={headlessgl:l,webgl2:h,webgl:c,webgpu:d};let x=!0;function b(e){if(!e)return{};const t=Object.assign({},e);return e.hasOwnProperty("floatOutput")&&(s.warnDeprecated("setting","floatOutput","precision"),t.precision=e.floatOutput?"single":"unsigned"),e.hasOwnProperty("outputToTexture")&&(s.warnDeprecated("setting","outputToTexture","pipeline"),t.pipeline=Boolean(e.outputToTexture)),e.hasOwnProperty("outputImmutable")&&(s.warnDeprecated("setting","outputImmutable","immutable"),t.immutable=Boolean(e.outputImmutable)),e.hasOwnProperty("floatTextures")&&(s.warnDeprecated("setting","floatTextures","optimizeFloatMemory"),t.optimizeFloatMemory=Boolean(e.floatTextures)),t}r.exports={GPU:class e{static disableValidation(){x=!1}static enableValidation(){x=!0}static get isGPUSupported(){return f.some(e=>e.isSupported)}static get isKernelMapSupported(){return f.some(e=>e.isSupported&&e.features.kernelMap)}static get isOffscreenCanvasSupported(){return"undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas||"undefined"!=typeof importScripts}static get isWebGLSupported(){return c.isSupported}static get isWebGL2Supported(){return h.isSupported}static get isHeadlessGLSupported(){return l.isSupported}static get isWebGPUSupported(){return d.isSupported}static isWebGPUAvailable(){return d.isSupported?navigator.gpu.requestAdapter().then(e=>null!==e,()=>!1):Promise.resolve(!1)}static get isCanvasSupported(){return"undefined"!=typeof HTMLCanvasElement}static get isGPUHTMLImageArraySupported(){return h.isSupported}static get isSinglePrecisionSupported(){return f.some(e=>e.isSupported&&e.features.isFloatRead&&e.features.isTextureFloat)}constructor(t){if(t=t||{},this.canvas=t.canvas||null,this.context=t.context||null,this.mode=t.mode,this.Kernel=null,this._webGPUDecision=null,"async"===t.mode&&(d.isSupported?e.isWebGPUAvailable().then(e=>{this._webGPUDecision=e},()=>{this._webGPUDecision=!1}):this._webGPUDecision=!1),this.kernels=[],this.functions=[],this.nativeFunctions=[],this.injectedNative=null,"dev"!==this.mode){if(this.chooseKernel(),t.functions)for(let e=0;er.argumentTypes[e]));const h=Object.assign({context:this.context,canvas:this.canvas,functions:this.functions,nativeFunctions:this.nativeFunctions,injectedNative:this.injectedNative,gpu:this,validate:x,onRequestFallback:l,onRequestSwitchKernel:function e(r,n,s){s.debug&&console.warn("Switching kernels");let o=null;if(s.signature&&!a[s.signature]&&(a[s.signature]=s),s.dynamicOutput)for(let e=r.length-1;e>=0;e--){const t=r[e];"outputPrecisionMismatch"===t.type&&(o=t.needed)}const u=s.constructor,h=u.getArgumentTypes(s,n),c=u.getSignature(s,h),p=a[c];if(p)return p.onActivate(s),p;const d=a[c]=new u(t,{argumentTypes:h,constantTypes:s.constantTypes,graphical:s.graphical,loopMaxIterations:s.loopMaxIterations,constants:s.constants,dynamicOutput:s.dynamicOutput,dynamicArgument:s.dynamicArguments,context:s.context,canvas:s.canvas,output:o||s.output,precision:s.precision,pipeline:s.pipeline,immutable:s.immutable,optimizeFloatMemory:s.optimizeFloatMemory,fixIntegerDivisionAccuracy:s.fixIntegerDivisionAccuracy,functions:s.functions,nativeFunctions:s.nativeFunctions,injectedNative:s.injectedNative,subKernels:s.subKernels,strictIntegers:s.strictIntegers,randomSeed:s.randomSeed,debug:s.debug,asyncMode:s.asyncMode,gpu:s.gpu,validate:x,returnType:s.returnType,tactic:s.tactic,onRequestFallback:l,onRequestSwitchKernel:e,texture:s.texture,mappedTextures:s.mappedTextures,drawBuffersMap:s.drawBuffersMap});return d.build.apply(d,n),f.replaceKernel(d),i.push(d),d}},o);"async"===this.mode&&(h.asyncMode=!0);let c,p=this.Kernel;"async"===this.mode&&o.graphical&&!0===this._webGPUDecision&&(p=d,h.canvas===this.canvas&&(h.canvas=o.canvas||null),h.context===this.context&&(h.context=o.context||null),h.asyncMode=!0);try{c=new p(t,h)}catch(e){if(p===this.Kernel)throw e;c=new this.Kernel(t,Object.assign({},h,{canvas:this.canvas,context:this.context}))}const f=m(c);if("async"===this.mode&&d.isSupported&&!(c instanceof d)){const r=this;c.onAsyncModeUpgrade=function(n,s){return e.isWebGPUAvailable().then(e=>{if(!e)return null;if(s.graphical)return s.debug&&console.warn("webgpu upgrade declined: graphical kernels keep their canvas"),null;let a;try{a=new d(t,{functions:s.functions,nativeFunctions:s.nativeFunctions,injectedNative:s.injectedNative,gpu:r,validate:x,asyncMode:!0,output:s.output,pipeline:s.pipeline,immutable:s.immutable,dynamicOutput:s.dynamicOutput,dynamicArguments:!0,loopMaxIterations:s.loopMaxIterations,constants:s.constants,constantTypes:s.constantTypes,argumentTypes:s.argumentTypes,precision:s.precision,tactic:s.tactic,strictIntegers:s.strictIntegers,fixIntegerDivisionAccuracy:s.fixIntegerDivisionAccuracy,subKernels:s.subKernels,graphical:s.graphical,debug:s.debug}),a.build.apply(a,n)}catch(e){return s.debug&&console.warn("webgpu upgrade declined: "+e.message),null}return a._buildPromise.then(()=>(i.push(a),a),e=>(s.debug&&console.warn("webgpu upgrade declined: "+e.message),a.destroy(),null))},()=>null)}}return this.canvas||(this.canvas=c.canvas),this.context||(this.context=c.context),i.push(c),f}createKernelMap(){let e,t;const r=typeof arguments[arguments.length-2];if("function"===r||"string"===r?(e=arguments[arguments.length-2],t=arguments[arguments.length-1]):e=arguments[arguments.length-1],!("dev"===this.mode||this.Kernel.isSupported&&this.Kernel.features.kernelMap)){if("webgpu"===this.Kernel.mode)throw new Error("WebGPU backend does not yet support createKernelMap");if(this.mode&&g.indexOf(this.mode)<0)throw new Error(`kernelMap not supported on ${this.Kernel.name}`)}const n=b(t);if(t&&"object"==typeof t.argumentTypes&&(n.argumentTypes=Object.keys(t.argumentTypes).map(e=>t.argumentTypes[e])),Array.isArray(arguments[0])){n.subKernels=[];const e=arguments[0];for(let t=0;t0)throw new Error('Cannot call "addNativeFunction" after "createKernels" has been called.');return this.nativeFunctions.push(Object.assign({name:e,source:t},r)),this}injectNative(e){return this.injectedNative=e,this}destroy(){return new Promise((e,t)=>{this.kernels||e(),setTimeout(()=>{try{const e=this.kernels.slice();for(let t=0;t{const{utils:r}=i();t.exports={alias:function(e,t){const n=t.toString();return new Function(`return function ${e} (${r.getArgumentNamesFromString(n).join(", ")}) {\n ${r.getFunctionBodyFromString(n)}\n}`)()}}}),ut=e((e,t)=>{const{GPU:r}=at(),{alias:c}=ot(),{utils:d}=i(),{Input:m,input:f}=n(),{Texture:g}=s(),{FunctionBuilder:y}=o(),{FunctionNode:x}=l(),{CPUFunctionNode:b}=h(),{CPUKernel:T}=p(),{HeadlessGLKernel:S}=be(),{WebGLFunctionNode:A}=C(),{WebGLKernel:w}=xe(),{kernelValueMaps:_}=ye(),{WebGL2FunctionNode:E}=Te(),{WebGL2Kernel:v}=et(),{kernelValueMaps:I}=Qe(),{WGSLFunctionNode:$}=tt(),{WebGPUKernel:D}=st(),{WebGPUContext:F}=rt(),{WebGPUBufferResult:L}=nt(),{GLKernel:R}=k(),{Kernel:G}=a(),{FunctionTracer:z}=u();t.exports={alias:c,CPUFunctionNode:b,CPUKernel:T,GPU:r,FunctionBuilder:y,FunctionNode:x,HeadlessGLKernel:S,Input:m,input:f,Texture:g,utils:d,WebGL2FunctionNode:E,WebGL2Kernel:v,webGL2KernelValueMaps:I,WebGLFunctionNode:A,WebGLKernel:w,webGLKernelValueMaps:_,WGSLFunctionNode:$,WebGPUKernel:D,WebGPUContext:F,WebGPUBufferResult:L,GLKernel:R,Kernel:G,FunctionTracer:z,plugins:{mathRandom:M()}}});return e((e,t)=>{const r=ut(),n=r.GPU;for(const e in r)r.hasOwnProperty(e)&&"GPU"!==e&&(n[e]=r[e]);function s(e){e.GPU&&e.GPU.prototype&&e.GPU.prototype.createKernel||Object.defineProperty(e,"GPU",{configurable:!0,get:()=>n,set(){}})}n.GPU=n,"undefined"!=typeof window&&s(window),"undefined"!=typeof self&&s(self),t.exports=n})()}); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):(e="undefined"!=typeof globalThis?globalThis:e||self).GPU=t()}(this,function(){var e=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),t=e((e,t)=>{function r(e){const t=new Array(e.length);for(let r=0;r{e.output=l(t),e.graphical&&u(e)},e.toJSON=()=>{throw new Error("Not usable with gpuMock")},e.setConstants=t=>(e.constants=t,e),e.setGraphical=t=>(e.graphical=t,e),e.setCanvas=t=>(e.canvas=t,e),e.setContext=t=>(e.context=t,e),e.destroy=()=>{},e.validateSettings=()=>{},e.graphical&&e.output&&u(e),e.exec=function(){return new Promise((t,r)=>{try{t(e.apply(e,arguments))}catch(e){r(e)}})},e.getPixels=t=>{const{x:r,y:n}=e.output;return t?function(e,t,r){const n=r/2|0,s=4*t,i=new Uint8ClampedArray(4*t),a=e.slice(0);for(let e=0;ee,r=["setWarnVarUsage","setArgumentTypes","setTactic","setOptimizeFloatMemory","setDebug","setLoopMaxIterations","setConstantTypes","setFunctions","setNativeFunctions","setInjectedNative","setPipeline","setPrecision","setOutputToTexture","setImmutable","setStrictIntegers","setDynamicOutput","setHardcodeConstants","setDynamicArguments","setUseLegacyEncoder","setWarnVarUsage","addSubKernel"];for(let n=0;n{t.exports={}}),n=e((e,t)=>{var r=class{constructor(e,t){this.value=e,Array.isArray(t)?this.size=t:(this.size=new Int32Array(3),t.z?this.size=new Int32Array([t.x,t.y,t.z]):t.y?this.size=new Int32Array([t.x,t.y]):this.size=new Int32Array([t.x]));const[r,n,s]=this.size;if(s){if(this.value.length!==r*n*s)throw new Error(`Input size ${this.value.length} does not match ${r} * ${n} * ${s} = ${n*r*s}`)}else if(n){if(this.value.length!==r*n)throw new Error(`Input size ${this.value.length} does not match ${r} * ${n} = ${n*r}`)}else if(this.value.length!==r)throw new Error(`Input size ${this.value.length} does not match ${r}`)}toArray(){const{utils:e}=i(),[t,r,n]=this.size;return n?e.erectMemoryOptimized3DFloat(this.value.subarray?this.value:new Float32Array(this.value),t,r,n):r?e.erectMemoryOptimized2DFloat(this.value.subarray?this.value:new Float32Array(this.value),t,r):this.value}};t.exports={Input:r,input:function(e,t){return new r(e,t)}}}),s=e((e,t)=>{t.exports={Texture:class{constructor(e){const{texture:t,size:r,dimensions:n,output:s,context:i,type:a="NumberTexture",kernel:o,internalFormat:u,textureFormat:l}=e;if(!s)throw new Error('settings property "output" required.');if(!i)throw new Error('settings property "context" required.');if(!t)throw new Error('settings property "texture" required.');if(!o)throw new Error('settings property "kernel" required.');this.texture=t,t._refs?t._refs++:t._refs=1,this.size=r,this.dimensions=n,this.output=s,this.context=i,this.kernel=o,this.type=a,this._deleted=!1,this.internalFormat=u,this.textureFormat=l}toArray(){throw new Error(`Not implemented on ${this.constructor.name}`)}clone(){throw new Error(`Not implemented on ${this.constructor.name}`)}delete(){throw new Error(`Not implemented on ${this.constructor.name}`)}clear(){throw new Error(`Not implemented on ${this.constructor.name}`)}}}}),i=e((e,t)=>{const i=r(),{Input:a}=n(),{Texture:o}=s(),u=/function ([^(]*)/,l=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,h=/([^\s,]+)/g,c={systemEndianness:()=>f,getSystemEndianness(){const e=new ArrayBuffer(4),t=new Uint32Array(e),r=new Uint8Array(e);if(t[0]=3735928559,239===r[0])return"LE";if(222===r[0])return"BE";throw new Error("unknown endianness")},isFunction:e=>"function"==typeof e,isFunctionString:e=>"string"==typeof e&&"function"===e.slice(0,8).toLowerCase(),getFunctionNameFromString(e){const t=u.exec(e);return t&&0!==t.length?t[1].trim():null},getFunctionBodyFromString:e=>e.substring(e.indexOf("{")+1,e.lastIndexOf("}")),getArgumentNamesFromString(e){const t=e.replace(l,"");let r=t.slice(t.indexOf("(")+1,t.indexOf(")")).match(h);return null===r&&(r=[]),r},clone(e){if(null===e||"object"!=typeof e||e.hasOwnProperty("isActiveClone"))return e;const t=e.constructor();for(let r in e)Object.prototype.hasOwnProperty.call(e,r)&&(e.isActiveClone=null,t[r]=c.clone(e[r]),delete e.isActiveClone);return t},isArray:e=>!isNaN(e.length),typeFitsValue(e,t){if("string"!=typeof e||null==t)return!0;if(t.type)return!0;switch(e){case"Input":return t instanceof a;case"Boolean":return"boolean"==typeof t;case"Number":case"Integer":case"Float":return"number"==typeof t}return-1!==e.indexOf("Texture")?Boolean(t.type):0!==e.indexOf("Array")||c.isArray(t)},getVariableType(e,t){if(c.isArray(e))return e.length>0&&"IMG"===e[0].nodeName?"HTMLImageArray":"Array";switch(e.constructor){case Boolean:return"Boolean";case Number:return t&&Number.isInteger(e)?"Integer":"Float";case o:return e.type;case a:return"Input"}if("nodeName"in e)switch(e.nodeName){case"IMG":case"CANVAS":return"HTMLImage";case"VIDEO":return"HTMLVideo"}else{if(e.hasOwnProperty("type"))return e.type;if("undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)return"OffscreenCanvas";if("undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap)return"ImageBitmap";if("undefined"!=typeof ImageData&&e instanceof ImageData)return"ImageData"}return"Unknown"},getKernelTextureSize(e,t){let[r,n,s]=t,i=(r||1)*(n||1)*(s||1);return e.optimizeFloatMemory&&"single"===e.precision&&(r=i=Math.ceil(i/4)),n>1&&r*n===i?new Int32Array([r,n]):c.closestSquareDimensions(i)},closestSquareDimensions(e){const t=Math.sqrt(e);let r=Math.ceil(t),n=Math.floor(t);for(;r*nMath.floor((e+t-1)/t)*t,getDimensions(e,t){let r;if(c.isArray(e)){const t=[];let n=e;for(;c.isArray(n);)t.push(n.length),n=n[0];r=t.reverse()}else if(e instanceof o)r=e.output;else{if(!(e instanceof a))throw new Error(`Unknown dimensions of ${e}`);r=e.size}if(t)for(r=Array.from(r);r.length<3;)r.push(1);return new Int32Array(r)},flatten2dArrayTo(e,t){let r=0;for(let n=0;ne.length>0?e.join(";\n")+";\n":"\n",warnDeprecated(e,t,r){r?console.warn(`You are using a deprecated ${e} "${t}". It has been replaced with "${r}". Fixing, but please upgrade as it will soon be removed.`):console.warn(`You are using a deprecated ${e} "${t}". It has been removed. Fixing, but please upgrade as it will soon be removed.`)},flipPixels:(e,t,r)=>{const n=r/2|0,s=4*t,i=new Uint8ClampedArray(4*t),a=e.slice(0);for(let e=0;ee.subarray(0,t),erect2DPackedFloat:(e,t,r)=>{const n=new Array(r);for(let s=0;s{const s=new Array(n);for(let i=0;ie.subarray(0,t),erectMemoryOptimized2DFloat:(e,t,r)=>{const n=new Array(r);for(let s=0;s{const s=new Array(n);for(let i=0;i{const r=new Float32Array(t);let n=0;for(let s=0;s{const n=new Array(r);let s=0;for(let i=0;i{const s=new Array(n);let i=0;for(let a=0;a{const r=new Array(t),n=4*t;let s=0;for(let t=0;t{const n=new Array(r),s=4*t;for(let i=0;i{const s=4*t,i=new Array(n);for(let a=0;a{const r=new Array(t),n=4*t;let s=0;for(let t=0;t{const n=4*t,s=new Array(r);for(let i=0;i{const s=4*t,i=new Array(n);for(let a=0;a{const r=new Array(e),n=4*t;let s=0;for(let t=0;t{const n=4*t,s=new Array(r);for(let i=0;i{const s=4*t,i=new Array(n);for(let a=0;a{const{findDependency:r,thisLookup:n,doNotDefine:s}=t;let a=t.flattened;a||(a=t.flattened={});const o=i.parse(e,{ecmaVersion:2020}),u=[];let l=0;const h=function e(t){if(Array.isArray(t)){const r=[];for(let n=0;nnull!==e);return s.length<1?"":`${t.kind} ${s.join(",")}`;case"VariableDeclarator":return t.init?t.init.object&&"ThisExpression"===t.init.object.type?n(t.init.property.name,!0)?`${t.id.name} = ${e(t.init)}`:null:`${t.id.name} = ${e(t.init)}`:t.id.name;case"CallExpression":if("subarray"===t.callee.property.name)return`${e(t.callee.object)}.${e(t.callee.property)}(${t.arguments.map(t=>e(t)).join(", ")})`;if("gl"===t.callee.object.name||"context"===t.callee.object.name)return`${e(t.callee.object)}.${e(t.callee.property)}(${t.arguments.map(t=>e(t)).join(", ")})`;if("ThisExpression"===t.callee.object.type)return u.push(r("this",t.callee.property.name)),`${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`;if(t.callee.object.name){const n=r(t.callee.object.name,t.callee.property.name);return null===n?`${t.callee.object.name}.${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`:(u.push(n),`${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`)}if("MemberExpression"===t.callee.object.type)return`${e(t.callee.object)}.${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`;throw new Error("unknown ast.callee");case"ReturnStatement":return`return ${e(t.argument)}`;case"BinaryExpression":return`(${e(t.left)}${t.operator}${e(t.right)})`;case"UnaryExpression":return t.prefix?`${t.operator} ${e(t.argument)}`:`${e(t.argument)} ${t.operator}`;case"ExpressionStatement":return`${e(t.expression)}`;case"SequenceExpression":return`(${e(t.expressions)})`;case"ArrowFunctionExpression":return`(${t.params.map(e).join(", ")}) => ${e(t.body)}`;case"Literal":return t.raw;case"Identifier":return t.name;case"MemberExpression":return"ThisExpression"===t.object.type?n(t.property.name):t.computed?`${e(t.object)}[${e(t.property)}]`:e(t.object)+"."+e(t.property);case"ThisExpression":return"this";case"NewExpression":return`new ${e(t.callee)}(${t.arguments.map(t=>e(t)).join(", ")})`;case"ForStatement":return`for (${e(t.init)};${e(t.test)};${e(t.update)}) ${e(t.body)}`;case"AssignmentExpression":return`${e(t.left)}${t.operator}${e(t.right)}`;case"UpdateExpression":return`${e(t.argument)}${t.operator}`;case"IfStatement":{const r=e(t.consequent);if(!t.alternate)return`if (${e(t.test)}) ${r}`;const n="BlockStatement"===t.consequent.type?"":";";return`if (${e(t.test)}) ${r}${n} else ${e(t.alternate)}`}case"ThrowStatement":return`throw ${e(t.argument)}`;case"ObjectPattern":return t.properties.map(e).join(", ");case"ArrayPattern":return t.elements.map(e).join(", ");case"DebuggerStatement":return"debugger;";case"ConditionalExpression":return`${e(t.test)}?${e(t.consequent)}:${e(t.alternate)}`;case"Property":if("init"===t.kind)return e(t.key)}throw new Error(`unhandled ast.type of ${t.type}`)}(o);if(u.length>0){const e=[];for(let r=0;r{if("VariableDeclaration"!==e.type)throw new Error('Ast is not of type "VariableDeclaration"');const t=[];for(let r=0;r{const r=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].r},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),n=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].g},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),s=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].b},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),i=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].a},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),a=[r(t),n(t),s(t),i(t)];return a.rKernel=r,a.gKernel=n,a.bKernel=s,a.aKernel=i,a.gpu=e,a},splitRGBAToCanvases:(e,t,r,n)=>{const s=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(t.r/255,0,0,255)},{output:[r,n],graphical:!0,argumentTypes:{v:"Array2D(4)"}});s(t);const i=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(0,t.g/255,0,255)},{output:[r,n],graphical:!0,argumentTypes:{v:"Array2D(4)"}});i(t);const a=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(0,0,t.b/255,255)},{output:[r,n],graphical:!0,argumentTypes:{v:"Array2D(4)"}});a(t);const o=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(255,255,255,t.a/255)},{output:[r,n],graphical:!0,argumentTypes:{v:"Array2D(4)"}});return o(t),[s.canvas,i.canvas,a.canvas,o.canvas]},getMinifySafeName:e=>{try{const{init:t}=i.parse(`const value = ${e.toString()}`,{ecmaVersion:2020}).body[0].declarations[0];return t.body.name||t.body.body[0].argument.name}catch(e){throw new Error("Unrecognized function type. Please use `() => yourFunctionVariableHere` or function() { return yourFunctionVariableHere; }")}},sanitizeName:function(e){return p.test(e)&&(e=e.replace(p,"S_S")),d.test(e)?e=e.replace(d,"U_U"):m.test(e)&&(e=e.replace(m,"u_u")),e}},p=/\$/,d=/__/,m=/_/,f=c.getSystemEndianness();t.exports={utils:c}}),a=e((e,t)=>{const{utils:r}=i(),{Input:s}=n();t.exports={Kernel:class{static get isSupported(){throw new Error(`"isSupported" not implemented on ${this.name}`)}static isContextMatch(e){throw new Error(`"isContextMatch" not implemented on ${this.name}`)}static getFeatures(){throw new Error(`"getFeatures" not implemented on ${this.name}`)}static destroyContext(e){throw new Error(`"destroyContext" called on ${this.name}`)}static nativeFunctionArguments(){throw new Error(`"nativeFunctionArguments" called on ${this.name}`)}static nativeFunctionReturnType(){throw new Error(`"nativeFunctionReturnType" called on ${this.name}`)}static combineKernels(){throw new Error(`"combineKernels" called on ${this.name}`)}constructor(e,t){if("object"!=typeof e){if("string"!=typeof e)throw new Error("source not a string");if(!r.isFunctionString(e))throw new Error("source not a function string")}this.useLegacyEncoder=!1,this.fallbackRequested=!1,this.fallbackReason=null,this.onRequestFallback=null,this.onRequestSwitchKernel=null,this.argumentNames="string"==typeof e?r.getArgumentNamesFromString(e):null,this.argumentTypes=null,this.argumentSizes=null,this.argumentBitRatios=null,this.kernelArguments=null,this.kernelConstants=null,this.forceUploadKernelConstants=null,this.source=e,this.output=null,this.debug=!1,this.graphical=!1,this.loopMaxIterations=0,this.constants=null,this.constantTypes=null,this.constantBitRatios=null,this.dynamicArguments=!1,this.dynamicOutput=!1,this.canvas=null,this.context=null,this.checkContext=null,this.gpu=null,this.functions=null,this.nativeFunctions=null,this.injectedNative=null,this.subKernels=null,this.validate=!0,this.immutable=!1,this.pipeline=!1,this.asyncMode=!1,this.precision=null,this.tactic=null,this.plugins=null,this.returnType=null,this.leadingReturnStatement=null,this.followingReturnStatement=null,this.optimizeFloatMemory=null,this.strictIntegers=!1,this.fixIntegerDivisionAccuracy=null,this.randomSeed=null,this.built=!1,this.signature=null,this.switchingKernels=null}mergeSettings(e){for(let t in e)if(e.hasOwnProperty(t)&&this.hasOwnProperty(t)){switch(t){case"output":if(!Array.isArray(e.output)){this.setOutput(e.output);continue}break;case"functions":this.functions=[];for(let t=0;te.name):null,returnType:this.returnType}}}buildSignature(e){const t=this.constructor;this.signature=t.getSignature(this,t.getArgumentTypes(this,e))}static getArgumentTypes(e,t){const n=new Array(t.length);for(let s=0;st.argumentTypes[e])||[];const i=Object.keys(t.argumentTypes);if(i.length>0&&e.length>0&&s.every(e=>void 0===e))throw new Error(`argumentTypes keys [${i.join(", ")}] match none of the function's parameters [${e.join(", ")}] \u2014 a bundler may have renamed them. Use the array form: argumentTypes: ['${i.map(e=>t.argumentTypes[e]).join("', '")}']`)}else s=t.argumentTypes||[];return{name:t.name||r.getFunctionNameFromString(n)||("function"==typeof e&&e.name?e.name:null),source:n,argumentTypes:s,returnType:t.returnType||null}}onActivate(e){}switchKernels(e){this.switchingKernels?this.switchingKernels.push(e):this.switchingKernels=[e]}resetSwitchingKernels(){const e=this.switchingKernels;return this.switchingKernels=null,e}checkArgumentTypes(e){if(!this.argumentTypes)return;const t=Math.min(e.length,this.argumentTypes.length);for(let n=0;n{t.exports={FunctionBuilder:class e{static fromKernel(t,r,n){const{kernelArguments:s,kernelConstants:i,argumentNames:a,argumentSizes:o,argumentBitRatios:u,constants:l,constantBitRatios:h,debug:c,loopMaxIterations:p,nativeFunctions:d,output:m,optimizeFloatMemory:f,precision:g,plugins:y,source:x,subKernels:b,functions:T,leadingReturnStatement:v,followingReturnStatement:S,dynamicArguments:A,dynamicOutput:w}=t,E=new Array(s.length),I={};for(let e=0;eB.needsArgumentType(e,t),L=(e,t,r)=>{B.assignArgumentType(e,t,r)},F=(e,t,r)=>B.lookupReturnType(e,t,r),k=e=>B.lookupFunctionArgumentTypes(e),$=(e,t)=>B.lookupFunctionArgumentName(e,t),D=(e,t)=>B.lookupFunctionArgumentBitRatio(e,t),C=(e,t,r,n)=>{B.assignArgumentType(e,t,r,n)},G=(e,t,r,n)=>{B.assignArgumentBitRatio(e,t,r,n)},R=(e,t,r)=>{B.trackFunctionCall(e,t,r)},M=(e,t)=>{const n=[];for(let t=0;tnew r(e.source,{name:e.name||void 0,returnType:e.returnType,argumentTypes:e.argumentTypes,output:m,plugins:y,constants:l,constantTypes:I,constantBitRatios:h,optimizeFloatMemory:f,precision:g,lookupReturnType:F,lookupFunctionArgumentTypes:k,lookupFunctionArgumentName:$,lookupFunctionArgumentBitRatio:D,needsArgumentType:_,assignArgumentType:L,triggerImplyArgumentType:C,triggerImplyArgumentBitRatio:G,onFunctionCall:R,onNestedFunction:M})));let U=null;b&&(U=b.map(e=>{const{name:t,source:n}=e;return new r(n,Object.assign({},N,{name:t,isSubKernel:!0,isRootKernel:!1}))}));const B=new e({kernel:t,rootNode:z,functionNodes:V,nativeFunctions:d,subKernelNodes:U});return B}constructor(e){if(e=e||{},this.kernel=e.kernel,this.rootNode=e.rootNode,this.functionNodes=e.functionNodes||[],this.subKernelNodes=e.subKernelNodes||[],this.nativeFunctions=e.nativeFunctions||[],this.functionMap={},this.nativeFunctionNames=[],this.lookupChain=[],this.functionNodeDependencies={},this.functionCalls={},this.rootNode&&(this.functionMap.kernel=this.rootNode),this.functionNodes)for(let e=0;e-1){const r=t.indexOf(e);if(-1===r)t.push(e);else{const e=t.splice(r,1)[0];t.push(e)}return t}const r=this.functionMap[e];if(r){const n=t.indexOf(e);if(-1===n){t.push(e),r.toString();for(let e=0;e-1){t.push(this.nativeFunctions[s].source);continue}const i=this.functionMap[n];i&&t.push(i.toString())}return t}toJSON(){return this.traceFunctionCalls(this.rootNode.name).reverse().map(e=>{const t=this.nativeFunctions.indexOf(e);if(t>-1)return{name:e,source:this.nativeFunctions[t].source};if(this.functionMap[e])return this.functionMap[e].toJSON();throw new Error(`function ${e} not found`)})}fromJSON(e,t){this.functionMap={};for(let r=0;r0){const s=t.arguments;for(let t=0;t{const{utils:r}=i();function n(e){return e.length>0?e[e.length-1]:null}const s="trackIdentifiers",a="memberExpression",o="inForLoopInit";t.exports={FunctionTracer:class{constructor(e){this.runningContexts=[],this.functionContexts=[],this.contexts=[],this.functionCalls=[],this.declarations=[],this.identifiers=[],this.functions=[],this.returnStatements=[],this.trackedIdentifiers=null,this.states=[],this.newFunctionContext(),this.scan(e)}isState(e){return this.states[this.states.length-1]===e}hasState(e){return this.states.indexOf(e)>-1}pushState(e){this.states.push(e)}popState(e){if(!this.isState(e))throw new Error(`Cannot pop the non-active state "${e}"`);this.states.pop()}get currentFunctionContext(){return n(this.functionContexts)}get currentContext(){return n(this.runningContexts)}newFunctionContext(){const e={"@contextType":"function"};this.contexts.push(e),this.functionContexts.push(e)}newContext(e){const t=Object.assign({"@contextType":"const/let"},this.currentContext);this.contexts.push(t),this.runningContexts.push(t),e();const{currentFunctionContext:r}=this;for(const e in r)r.hasOwnProperty(e)&&!t.hasOwnProperty(e)&&(t[e]=r[e]);return this.runningContexts.pop(),t}useFunctionContext(e){const t=n(this.functionContexts);this.runningContexts.push(t),e(),this.runningContexts.pop()}getIdentifiers(e){const t=this.trackedIdentifiers=[];return this.pushState(s),e(),this.trackedIdentifiers=null,this.popState(s),t}getDeclaration(e){const{currentContext:t,currentFunctionContext:r,runningContexts:n}=this,s=t[e]||r[e]||null;if(!s&&t===r&&n.length>0){const t=n[n.length-2];if(t[e])return t[e]}return s}scan(e){if(e)if(Array.isArray(e))for(let t=0;t{this.scan(e.body)});break;case"BlockStatement":this.newContext(()=>{this.scan(e.body)});break;case"AssignmentExpression":case"LogicalExpression":case"BinaryExpression":this.scan(e.left),this.scan(e.right);break;case"UpdateExpression":if("++"===e.operator){const t=this.getDeclaration(e.argument.name);t&&(t.suggestedType="Integer")}this.scan(e.argument);break;case"UnaryExpression":this.scan(e.argument);break;case"VariableDeclaration":"var"===e.kind?this.useFunctionContext(()=>{e.declarations=r.normalizeDeclarations(e),this.scan(e.declarations)}):(e.declarations=r.normalizeDeclarations(e),this.scan(e.declarations));break;case"VariableDeclarator":{const{currentContext:t}=this,r=this.hasState(o),n={ast:e,context:t,name:e.id.name,origin:"declaration",inForLoopInit:r,inForLoopTest:null,assignable:t===this.currentFunctionContext||!r&&!t.hasOwnProperty(e.id.name),suggestedType:null,valueType:null,dependencies:null,isSafe:null};t[e.id.name]||(t[e.id.name]=n),this.declarations.push(n),this.scan(e.id),this.scan(e.init);break}case"FunctionExpression":case"FunctionDeclaration":0===this.runningContexts.length?this.scan(e.body):this.functions.push(e);break;case"IfStatement":this.scan(e.test),this.scan(e.consequent),e.alternate&&this.scan(e.alternate);break;case"ForStatement":{let t;const r=this.newContext(()=>{this.pushState(o),this.scan(e.init),this.popState(o),t=this.getIdentifiers(()=>{this.scan(e.test)}),this.scan(e.update),this.newContext(()=>{this.scan(e.body)})});if(t)for(const e in r)"@contextType"!==e&&t.indexOf(e)>-1&&(r[e].inForLoopTest=!0);break}case"DoWhileStatement":case"WhileStatement":this.newContext(()=>{this.scan(e.body),this.scan(e.test)});break;case"Identifier":this.isState(s)&&this.trackedIdentifiers.push(e.name),this.identifiers.push({context:this.currentContext,declaration:this.getDeclaration(e.name),ast:e});break;case"ReturnStatement":this.returnStatements.push(e),this.scan(e.argument);break;case"MemberExpression":this.pushState(a),this.scan(e.object),this.scan(e.property),this.popState(a);break;case"ExpressionStatement":this.scan(e.expression);break;case"SequenceExpression":this.scan(e.expressions);break;case"CallExpression":this.functionCalls.push({context:this.currentContext,ast:e}),this.scan(e.arguments);break;case"ArrayExpression":this.scan(e.elements);break;case"ConditionalExpression":this.scan(e.test),this.scan(e.alternate),this.scan(e.consequent);break;case"SwitchStatement":this.scan(e.discriminant),this.scan(e.cases);break;case"SwitchCase":this.scan(e.test),this.scan(e.consequent);break;case"ThisExpression":case"Literal":case"DebuggerStatement":case"EmptyStatement":case"BreakStatement":case"ContinueStatement":break;default:throw new Error(`unhandled type "${e.type}"`)}}}}}),l=e((e,t)=>{const n=r(),{utils:s}=i(),{FunctionTracer:a}=u(),o=["E","PI","SQRT2","SQRT1_2","LN2","LN10","LOG2E","LOG10E"],l=["abs","acos","acosh","asin","asinh","atan","atan2","atanh","cbrt","ceil","clz32","cos","cosh","expm1","exp","floor","fround","imul","log","log2","log10","log1p","max","min","pow","random","round","sign","sin","sinh","sqrt","tan","tanh","trunc"],h=["value","value[]","value[][]","value[][][]","value[][][][]","value.value","value.thread.value","this.thread.value","this.output.value","this.constants.value","this.constants.value[]","this.constants.value[][]","this.constants.value[][][]","this.constants.value[][][][]","fn()[]","fn()[][]","fn()[][][]","[][]"];const c={Number:"Number",Float:"Float",Integer:"Integer",Array:"Number","Array(2)":"Number","Array(3)":"Number","Array(4)":"Number","Matrix(2)":"Number","Matrix(3)":"Number","Matrix(4)":"Number",Array2D:"Number",Array3D:"Number",Input:"Number",HTMLCanvas:"Array(4)",OffscreenCanvas:"Array(4)",HTMLImage:"Array(4)",ImageBitmap:"Array(4)",ImageData:"Array(4)",HTMLVideo:"Array(4)",HTMLImageArray:"Array(4)",NumberTexture:"Number",MemoryOptimizedNumberTexture:"Number","Array1D(2)":"Array(2)","Array1D(3)":"Array(3)","Array1D(4)":"Array(4)","Array2D(2)":"Array(2)","Array2D(3)":"Array(3)","Array2D(4)":"Array(4)","Array3D(2)":"Array(2)","Array3D(3)":"Array(3)","Array3D(4)":"Array(4)","ArrayTexture(1)":"Number","ArrayTexture(2)":"Array(2)","ArrayTexture(3)":"Array(3)","ArrayTexture(4)":"Array(4)"};let p=536870912;function d(e,t){return e.start=p++,e.end=p++,t&&t.loc&&(e.loc=t.loc),e}function m(e,t){return e&&e.body&&"BlockStatement"===e.body.type?(f(e.body,t),e):e}function f(e,t){e.body=g(e.body,t)}function g(e,t){const r=[];for(let n=0;n{if(!e||"object"!=typeof e||r)return e;if(Array.isArray(e))return e.map(n);switch(e.type){case"ContinueStatement":return e.label?(r=!0,e):d({type:"BlockStatement",body:[...S(t),e]},e);case"ForStatement":case"WhileStatement":case"DoWhileStatement":case"FunctionExpression":case"FunctionDeclaration":case"ArrowFunctionExpression":default:return e;case"IfStatement":return e.consequent=n(e.consequent),e.alternate&&(e.alternate=n(e.alternate)),e;case"BlockStatement":return e.body=e.body.map(n),e;case"SwitchStatement":for(let t=0;t0?(r.push(e),r):[e]}case"WhileStatement":case"DoWhileStatement":return e.body&&(e.body=x(e.body,t)),[e];case"SwitchStatement":for(let r=0;r0&&this.argumentTypes.length!==this.argumentNames.length)throw new Error(`argumentTypes count of ${this.argumentTypes.length} exceeds ${this.argumentNames.length}`);if(this.output.length<1)throw new Error("this.output is not big enough")}isIdentifierConstant(e){return!!this.constants&&this.constants.hasOwnProperty(e)}isInput(e){return"Input"===this.argumentTypes[this.argumentNames.indexOf(e)]}pushState(e){this.states.push(e)}popState(e){if(this.state!==e)throw new Error(`Cannot popState ${e} when in ${this.state}`);this.states.pop()}isState(e){return this.state===e}get state(){return this.states[this.states.length-1]}astMemberExpressionUnroll(e){if("Identifier"===e.type)return e.name;if("ThisExpression"===e.type)return"this";if("MemberExpression"===e.type&&e.object&&e.property)return e.object.hasOwnProperty("name")&&"Math"!==e.object.name?this.astMemberExpressionUnroll(e.property):this.astMemberExpressionUnroll(e.object)+"."+this.astMemberExpressionUnroll(e.property);if(e.hasOwnProperty("expressions")){const t=e.expressions[0];if("Literal"===t.type&&0===t.value&&2===e.expressions.length)return this.astMemberExpressionUnroll(e.expressions[1])}throw this.astErrorOutput("Unknown astMemberExpressionUnroll",e)}get requiresSequenceFreeForInit(){return!1}getJsAST(e){if(this.ast)return this.ast;if("object"==typeof this.source)return m(this.source,this.requiresSequenceFreeForInit),this.traceFunctionAST(this.source),this.ast=this.source;if(null===(e=e||n))throw new Error("Missing JS to AST parser");const t=Object.freeze(e.parse(`const parser_${this.name} = ${this.source};`,{locations:!0,ecmaVersion:2020})),r=t.body[0].declarations[0].init;if(m(r,this.requiresSequenceFreeForInit),this.traceFunctionAST(r),!t)throw new Error("Failed to parse JS code");return this.ast=r}getAssignedArguments(){if(this._assignedArguments)return this._assignedArguments;const e=new Set,t=new Set,r=this.argumentNames||[],n=s=>{if(s&&"object"==typeof s)if(Array.isArray(s))for(const e of s)n(e);else{"AssignmentExpression"===s.type&&"Identifier"===s.left.type&&-1!==r.indexOf(s.left.name)&&e.add(s.left.name),"UpdateExpression"===s.type&&"Identifier"===s.argument.type&&-1!==r.indexOf(s.argument.name)&&e.add(s.argument.name),"VariableDeclarator"===s.type&&"Identifier"===s.id.type&&-1!==r.indexOf(s.id.name)&&t.add(s.id.name);for(const e in s){if("loc"===e||"range"===e||"parent"===e)continue;const t=s[e];t&&"object"==typeof t&&n(t)}}};n(this.getJsAST());for(const r of t)e.delete(r);return this._assignedArguments=e}traceFunctionAST(e){const{contexts:t,declarations:r,functions:n,identifiers:s,functionCalls:i}=new a(e);this.contexts=t,this.identifiers=s,this.functionCalls=i,this.functions=n;for(let e=0;e":case"<":return"Boolean";case"&":case"|":case"^":case"<<":case">>":case">>>":return"Integer"}const r=this.getType(e.left);if(this.isState("skip-literal-correction"))return r;if("LiteralInteger"===r){const t=this.getType(e.right);return"LiteralInteger"===t?e.left.value%1==0?"Integer":"Float":t}if("Integer"===r){const t=this.getType(e.right);if("Number"===t||"Float"===t)return t}return c[r]||r;case"UpdateExpression":case"ReturnStatement":return this.getType(e.argument);case"UnaryExpression":return"~"===e.operator?"Integer":this.getType(e.argument);case"VariableDeclaration":{const t=e.declarations;let r;for(let e=0;ee.isSafe)}getDependencies(e,t,r){if(t||(t=[]),!e)return null;if(Array.isArray(e)){for(let n=0;n-1/0&&e.value<1/0&&!isNaN(e.value))});break;case"VariableDeclarator":return this.getDependencies(e.init,t,r);case"Identifier":const n=this.getDeclaration(e);if(n)t.push({name:e.name,origin:"declaration",isSafe:!r&&this.isSafeDependencies(n.dependencies)});else if(this.argumentNames.indexOf(e.name)>-1)t.push({name:e.name,origin:"argument",isSafe:!1});else if(this.strictTypingChecking)throw new Error(`Cannot find identifier origin "${e.name}"`);break;case"FunctionDeclaration":return this.getDependencies(e.body.body[e.body.body.length-1],t,r);case"ReturnStatement":return this.getDependencies(e.argument,t);case"BinaryExpression":case"LogicalExpression":return r="/"===e.operator||"*"===e.operator,this.getDependencies(e.left,t,r),this.getDependencies(e.right,t,r),t;case"UnaryExpression":case"UpdateExpression":return this.getDependencies(e.argument,t,r);case"VariableDeclaration":return this.getDependencies(e.declarations,t,r);case"ArrayExpression":return t.push({origin:"declaration",isSafe:!0}),t;case"CallExpression":return t.push({origin:"function",isSafe:!0}),t;case"MemberExpression":const s=this.getMemberExpressionDetails(e);switch(s.signature){case"value[]":this.getDependencies(e.object,t,r);break;case"value[][]":this.getDependencies(e.object.object,t,r);break;case"value[][][]":this.getDependencies(e.object.object.object,t,r);break;case"this.output.value":this.dynamicOutput&&t.push({name:s.name,origin:"output",isSafe:!1})}if(s)return s.property&&this.getDependencies(s.property,t,r),s.xProperty&&this.getDependencies(s.xProperty,t,r),s.yProperty&&this.getDependencies(s.yProperty,t,r),s.zProperty&&this.getDependencies(s.zProperty,t,r),t;case"SequenceExpression":return this.getDependencies(e.expressions,t,r);default:throw this.astErrorOutput(`Unhandled type ${e.type} in getDependencies`,e)}return t}getVariableSignature(e,t){if(!this.isAstVariable(e))throw new Error(`ast of type "${e.type}" is not a variable signature`);if("Identifier"===e.type)return"value";const r=[];for(;e;)e.computed?r.push("[]"):"ThisExpression"===e.type?r.unshift("this"):e.property&&e.property.name?"x"===e.property.name||"y"===e.property.name||"z"===e.property.name?r.unshift(t?"."+e.property.name:".value"):"constants"===e.property.name||"thread"===e.property.name||"output"===e.property.name?r.unshift("."+e.property.name):r.unshift(t?"."+e.property.name:".value"):e.name?r.unshift(t?e.name:"value"):e.callee&&e.callee.name?r.unshift(t?e.callee.name+"()":"fn()"):e.elements?r.unshift("[]"):r.unshift("unknown"),e=e.object;const n=r.join("");return t||h.includes(n)?n:null}build(){return this.toString().length>0}astGeneric(e,t){if(null===e)throw this.astErrorOutput("NULL ast",e);if(Array.isArray(e)){for(let r=0;r0?n[n.length-1]:0;return new Error(`${e} on line ${n.length}, position ${i.length}:\n ${r}`)}astDebuggerStatement(e,t){return t}astConditionalExpression(e,t){if("ConditionalExpression"!==e.type)throw this.astErrorOutput("Not a conditional expression",e);return t.push("("),this.astGeneric(e.test,t),t.push("?"),this.astGeneric(e.consequent,t),t.push(":"),this.astGeneric(e.alternate,t),t.push(")"),t}astFunction(e,t){throw new Error(`"astFunction" not defined on ${this.constructor.name}`)}astFunctionDeclaration(e,t){return this.isChildFunction(e)?t:this.astFunction(e,t)}astFunctionExpression(e,t){return this.isChildFunction(e)?t:this.astFunction(e,t)}isChildFunction(e){for(let t=0;t1?t.push("(",n.join(","),")"):t.push(n[0]),t}astUnaryExpression(e,t){return this.checkAndUpconvertBitwiseUnary(e,t)||(e.prefix?(t.push(e.operator),this.astGeneric(e.argument,t)):(this.astGeneric(e.argument,t),t.push(e.operator))),t}checkAndUpconvertBitwiseUnary(e,t){}astUpdateExpression(e,t){return e.prefix?(t.push(e.operator),this.astGeneric(e.argument,t)):(this.astGeneric(e.argument,t),t.push(e.operator)),t}astLogicalExpression(e,t){return t.push("("),this.astGeneric(e.left,t),t.push(e.operator),this.astGeneric(e.right,t),t.push(")"),t}astMemberExpression(e,t){return t}astCallExpression(e,t){return t}astArrayExpression(e,t){return t}getMemberExpressionDetails(e){if("MemberExpression"!==e.type)throw this.astErrorOutput(`Expression ${e.type} not a MemberExpression`,e);let t=null,r=null;const n=this.getVariableSignature(e);switch(n){case"value":return null;case"value.thread.value":case"this.thread.value":case"this.output.value":return{signature:n,type:"Integer",name:e.property.name};case"value[]":if("string"!=typeof e.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.name,{name:t,origin:"user",signature:n,type:this.getVariableType(e.object),xProperty:e.property};case"value[][]":if("string"!=typeof e.object.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.object.name,{name:t,origin:"user",signature:n,type:this.getVariableType(e.object.object),yProperty:e.object.property,xProperty:e.property};case"value[][][]":if("string"!=typeof e.object.object.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.object.object.name,{name:t,origin:"user",signature:n,type:this.getVariableType(e.object.object.object),zProperty:e.object.object.property,yProperty:e.object.property,xProperty:e.property};case"value[][][][]":if("string"!=typeof e.object.object.object.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.object.object.object.name,{name:t,origin:"user",signature:n,type:this.getVariableType(e.object.object.object.object),zProperty:e.object.object.property,yProperty:e.object.property,xProperty:e.property};case"value.value":if("string"!=typeof e.property.name)throw this.astErrorOutput("Unexpected expression",e);if(this.isAstMathVariable(e))return t=e.property.name,{name:t,origin:"Math",type:"Number",signature:n};switch(e.property.name){case"r":case"g":case"b":case"a":return t=e.object.name,{name:t,property:e.property.name,origin:"user",signature:n,type:"Number"};default:throw this.astErrorOutput("Unexpected expression",e)}case"this.constants.value":if("string"!=typeof e.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.property.name,r=this.getConstantType(t),!r)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:r,origin:"constants",signature:n};case"this.constants.value[]":if("string"!=typeof e.object.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.object.property.name,r=this.getConstantType(t),!r)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:r,origin:"constants",signature:n,xProperty:e.property};case"this.constants.value[][]":if("string"!=typeof e.object.object.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.object.object.property.name,r=this.getConstantType(t),!r)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:r,origin:"constants",signature:n,yProperty:e.object.property,xProperty:e.property};case"this.constants.value[][][]":if("string"!=typeof e.object.object.object.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.object.object.object.property.name,r=this.getConstantType(t),!r)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:r,origin:"constants",signature:n,zProperty:e.object.object.property,yProperty:e.object.property,xProperty:e.property};case"fn()[]":case"fn()[][]":case"[][]":return{signature:n,property:e.property};default:throw this.astErrorOutput("Unexpected expression",e)}}findIdentifierOrigin(e){const t=[this.ast];for(;t.length>0;){const r=t[0];if("VariableDeclarator"===r.type&&r.id&&r.id.name&&r.id.name===e.name)return r;if(t.shift(),r.argument)t.push(r.argument);else if(r.body)t.push(r.body);else if(r.declarations)t.push(r.declarations);else if(Array.isArray(r))for(let e=0;e0;){const e=t.pop();if("ReturnStatement"===e.type)return e;if("FunctionDeclaration"!==e.type)if(e.argument)t.push(e.argument);else if(e.body)t.push(e.body);else if(e.declarations)t.push(e.declarations);else if(Array.isArray(e))for(let r=0;r{const{FunctionNode:r}=l();t.exports={CPUFunctionNode:class extends r{markupUserName(e){return this.isRootKernel&&this.getAssignedArguments().has(e)?`cellShadow_user_${e}`:`user_${e}`}astFunction(e,t){if(!this.isRootKernel){t.push("function"),t.push(" "),t.push(this.name),t.push("(");for(let e=0;e0&&t.push(", "),t.push("user_"),t.push(r)}t.push(") {\n")}if(this.isRootKernel){for(const e of this.getAssignedArguments())t.push(`let cellShadow_user_${e} = user_${e};\n`);t.push("kernelBody: {\n")}for(let r=0;r0&&t.push(r.join(""),";\n"),t.push(`for (let ${e}=0;${e}0&&t.push(`if (!${n.join("")}) break;\n`),t.push(i.join("")),t.push(`\n${s.join("")};`),t.push("}\n")}return t}astWhileStatement(e,t){if("WhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);return t.push("for (let i = 0; i < LOOP_MAX; i++) {"),t.push("if ("),this.astGeneric(e.test,t),t.push(") {\n"),this.astGeneric(e.body,t),t.push("} else {\n"),t.push("break;\n"),t.push("}\n"),t.push("}\n"),t}astDoWhileStatement(e,t){if("DoWhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);const r=`safeI${this.astKey(e,"_")}`;return t.push(`let ${r} = 0;\n`),t.push("do {"),this.astGeneric(e.body,t),t.push("} while (("),this.astGeneric(e.test,t),t.push(`) && ++${r} < LOOP_MAX);\n`),t}astAssignmentExpression(e,t){const r=this.getDeclaration(e.left);if(r&&!r.assignable)throw this.astErrorOutput(`Variable ${e.left.name} is not assignable here`,e);const n=this.isState("assignment-as-statement");return n?this.popState("assignment-as-statement"):t.push("("),this.astGeneric(e.left,t),t.push(e.operator),this.astGeneric(e.right,t),n||t.push(")"),t}astBlockStatement(e,t){if(this.isState("loop-body")){this.pushState("block-body");for(let r=0;r0&&t.push(",");const n=r[e],s=this.getDeclaration(n.id);s.valueType||(s.valueType=this.getType(n.init)),this.astGeneric(n,t)}return this.isState("in-for-loop-init")||t.push(";"),t}astIfStatement(e,t){return t.push("if ("),this.astGeneric(e.test,t),t.push(")"),"BlockStatement"===e.consequent.type?this.astGeneric(e.consequent,t):(t.push(" {\n"),this.astGeneric(e.consequent,t),t.push("\n}\n")),e.alternate&&(t.push("else "),"BlockStatement"===e.alternate.type||"IfStatement"===e.alternate.type?this.astGeneric(e.alternate,t):(t.push(" {\n"),this.astGeneric(e.alternate,t),t.push("\n}\n"))),t}astSwitchStatement(e,t){const{discriminant:r,cases:n}=e;t.push("switch ("),this.astGeneric(r,t),t.push(") {\n");for(let e=0;e0&&(this.astGeneric(n[e].consequent,t),t.push("break;\n"))):(t.push("default:\n"),this.astGeneric(n[e].consequent,t),n[e].consequent&&n[e].consequent.length>0&&t.push("break;\n"));t.push("\n}")}astThisExpression(e,t){return t.push("_this"),t}astMemberExpression(e,t){const{signature:r,type:n,property:s,xProperty:i,yProperty:a,zProperty:o,name:u,origin:l}=this.getMemberExpressionDetails(e);switch(r){case"this.thread.value":return t.push(`_this.thread.${u}`),t;case"this.output.value":switch(u){case"x":t.push("outputX");break;case"y":t.push("outputY");break;case"z":t.push("outputZ");break;default:throw this.astErrorOutput("Unexpected expression",e)}return t;case"value":default:throw this.astErrorOutput("Unexpected expression",e);case"value[]":case"value[][]":case"value[][][]":case"value.value":if("Math"===l)return t.push(Math[u]),t;switch(s){case"r":return t.push(`user_${u}[0]`),t;case"g":return t.push(`user_${u}[1]`),t;case"b":return t.push(`user_${u}[2]`),t;case"a":return t.push(`user_${u}[3]`),t}break;case"this.constants.value":case"this.constants.value[]":case"this.constants.value[][]":case"this.constants.value[][][]":break;case"fn()[]":return this.astGeneric(e.object,t),t.push("["),this.astGeneric(e.property,t),t.push("]"),t;case"fn()[][]":return this.astGeneric(e.object.object,t),t.push("["),this.astGeneric(e.object.property,t),t.push("]"),t.push("["),this.astGeneric(e.property,t),t.push("]"),t}if(!e.computed)switch(n){case"Number":case"Integer":case"Float":case"Boolean":return t.push("user"===l?this.markupUserName(u):`${l}_${u}`),t}const h="user"===l?this.markupUserName(u):`${l}_${u}`;{let e,r;if("constants"===l){const t=this.constants[u];r="Input"===this.constantTypes[u],e=r?t.size:null}else r=this.isInput(u),e=r?this.argumentSizes[this.argumentNames.indexOf(u)]:null;t.push(`${h}`),o&&a?r?(t.push("[("),this.astGeneric(o,t),t.push(`*${this.dynamicArguments?"(outputY * outputX)":e[1]*e[0]})+(`),this.astGeneric(a,t),t.push(`*${this.dynamicArguments?"outputX":e[0]})+`),this.astGeneric(i,t),t.push("]")):(t.push("["),this.astGeneric(o,t),t.push("]"),t.push("["),this.astGeneric(a,t),t.push("]"),t.push("["),this.astGeneric(i,t),t.push("]")):a?r?(t.push("[("),this.astGeneric(a,t),t.push(`*${this.dynamicArguments?"outputX":e[0]})+`),this.astGeneric(i,t),t.push("]")):(t.push("["),this.astGeneric(a,t),t.push("]"),t.push("["),this.astGeneric(i,t),t.push("]")):void 0!==i&&(t.push("["),this.astGeneric(i,t),t.push("]"))}return t}astCallExpression(e,t){if("CallExpression"!==e.type)throw this.astErrorOutput("Unknown CallExpression",e);let r=this.astMemberExpressionUnroll(e.callee);this.calledFunctions.indexOf(r)<0&&this.calledFunctions.push(r),this.isAstMathFunction(e),this.onFunctionCall&&this.onFunctionCall(this.name,r,e.arguments),t.push(r),t.push("(");const n=this.lookupFunctionArgumentTypes(r)||[];for(let s=0;s0&&t.push(", "),this.astGeneric(i,t)}return t.push(")"),t}astArrayExpression(e,t){const r=this.getType(e),n=e.elements.length,s=[];for(let t=0;t{const{utils:r}=i();t.exports={cpuKernelString:function(e,t){const n=[],s=[],i=[],a=!/^function/.test(e.color.toString());if(n.push(" const { context, canvas, constants: incomingConstants } = settings;",` const output = new Int32Array(${JSON.stringify(Array.from(e.output))});`,` const _constantTypes = ${JSON.stringify(e.constantTypes)};`,` const _constants = ${function(e,t){const r=[];for(const n in t){if(!t.hasOwnProperty(n))continue;const s=t[n],i=e[n];switch(s){case"Number":case"Integer":case"Float":case"Boolean":r.push(`${n}:${i}`);break;case"Array(2)":case"Array(3)":case"Array(4)":case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":r.push(`${n}:new ${i.constructor.name}(${JSON.stringify(Array.from(i))})`)}}return`{ ${r.join()} }`}(e.constants,e.constantTypes)};`),s.push(" constants: _constants,"," context,"," output,"," thread: {x: 0, y: 0, z: 0},"),e.graphical){n.push(` const _imageData = context.createImageData(${e.output[0]}, ${e.output[1]});`),n.push(` const _colorData = new Uint8ClampedArray(${e.output[0]} * ${e.output[1]} * 4);`);const t=r.flattenFunctionToString((a?"function ":"")+e.color.toString(),{thisLookup:t=>{switch(t){case"_colorData":return"_colorData";case"_imageData":return"_imageData";case"output":return"output";case"thread":return"this.thread"}return JSON.stringify(e[t])},findDependency:(e,t)=>null}),o=r.flattenFunctionToString((a?"function ":"")+e.getPixels.toString(),{thisLookup:t=>{switch(t){case"_colorData":return"_colorData";case"_imageData":return"_imageData";case"output":return"output";case"thread":return"this.thread"}return JSON.stringify(e[t])},findDependency:()=>null});s.push(" _imageData,"," _colorData,",` color: ${t},`),i.push(` kernel.getPixels = ${o};`)}const o=[],u=Object.keys(e.constantTypes);for(let t=0;t"this"===t?(a?"function ":"")+e[r].toString():null,thisLookup:e=>{switch(e){case"canvas":return;case"context":return"context"}}});i.push(t),s.push(" _mediaTo2DArray,"),s.push(" _imageTo3DArray,")}else if(-1!==e.argumentTypes.indexOf("HTMLImage")||-1!==o.indexOf("HTMLImage")){const t=r.flattenFunctionToString((a?"function ":"")+e._mediaTo2DArray.toString(),{findDependency:(e,t)=>null,thisLookup:e=>{switch(e){case"canvas":return"settings.canvas";case"context":return"settings.context"}throw new Error("unhandled thisLookup")}});i.push(t),s.push(" _mediaTo2DArray,")}return`function(settings) {\n${n.join("\n")}\n for (const p in _constantTypes) {\n if (!_constantTypes.hasOwnProperty(p)) continue;\n const type = _constantTypes[p];\n switch (type) {\n case 'Number':\n case 'Integer':\n case 'Float':\n case 'Boolean':\n case 'Array(2)':\n case 'Array(3)':\n case 'Array(4)':\n case 'Matrix(2)':\n case 'Matrix(3)':\n case 'Matrix(4)':\n if (incomingConstants.hasOwnProperty(p)) {\n console.warn('constant ' + p + ' of type ' + type + ' cannot be resigned');\n }\n continue;\n }\n if (!incomingConstants.hasOwnProperty(p)) {\n throw new Error('constant ' + p + ' not found');\n }\n _constants[p] = incomingConstants[p];\n }\n const kernel = (function() {\n${e._kernelString}\n })\n .apply({ ${s.join("\n")} });\n ${i.join("\n")}\n return kernel;\n}`}}}),p=e((e,t)=>{const{Kernel:r}=a(),{FunctionBuilder:n}=o(),{CPUFunctionNode:s}=h(),{utils:u}=i(),{cpuKernelString:l}=c();t.exports={CPUKernel:class extends r{static getFeatures(){return this.features}static get features(){return Object.freeze({kernelMap:!0,isIntegerDivisionAccurate:!0})}static get isSupported(){return!0}static isContextMatch(e){return!1}static get mode(){return"cpu"}static nativeFunctionArguments(){return null}static nativeFunctionReturnType(){throw new Error(`Looking up native function return type not supported on ${this.name}`)}static combineKernels(e){return e}static getSignature(e,t){return"cpu"+(t.length>0?":"+t.join(","):"")}constructor(e,t){super(e,t),this.mergeSettings(e.settings||t),this._imageData=null,this._colorData=null,this._kernelString=null,this._prependedString=[],this.thread={x:0,y:0,z:0},this.translatedSources=null}initCanvas(){return"undefined"!=typeof document?document.createElement("canvas"):"undefined"!=typeof OffscreenCanvas?new OffscreenCanvas(0,0):void 0}initContext(){return this.canvas?this.canvas.getContext("2d",{willReadFrequently:!0}):null}initPlugins(e){return[]}validateSettings(e){if(!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=u.getVariableType(e[0],this.strictIntegers);if("Array"===t)this.output=u.getDimensions(t);else{if("NumberTexture"!==t&&"ArrayTexture(4)"!==t)throw new Error("Auto output not supported for input type: "+t);this.output=e[0].output}}if(this.graphical&&2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");this.checkOutput()}translateSource(){if(this.leadingReturnStatement=this.output.length>1?"resultX[x] = ":"result[x] = ",this.subKernels){const e=[];for(let t=0;t1?`resultX_${r}[x] = subKernelResult_${r};\n`:`result_${r}[x] = subKernelResult_${r};\n`)}this.followingReturnStatement=e.join("")}const e=n.fromKernel(this,s);this.translatedSources=e.getPrototypes("kernel"),this.graphical||this.returnType||(this.returnType=e.getKernelResultType())}build(){if(this.built)return;if(null!==this.randomSeed&&console.warn("randomSeed is not supported in cpu mode; Math.random() will be unseeded"),this.setupConstants(),this.setupArguments(arguments),this.validateSettings(arguments),this.translateSource(),this.graphical){const{canvas:e,output:t}=this;if(!e)throw new Error("no canvas available for using graphical output");const r=t[0],n=t[1]||1;e.width=r,e.height=n,this._imageData=this.context.createImageData(r,n),this._colorData=new Uint8ClampedArray(r*n*4)}const e=this.getKernelString();this.kernelString=e,this.debug&&(console.log("Function output:"),console.log(e));try{this.run=new Function([],e).bind(this)()}catch(e){console.error("An error occurred compiling the javascript: ",e)}this.buildSignature(arguments),this.built=!0}color(e,t,r,n){void 0===n&&(n=1),e=Math.floor(255*e),t=Math.floor(255*t),r=Math.floor(255*r),n=Math.floor(255*n);const s=this.output[0],i=this.output[1],a=this.thread.x+(i-this.thread.y-1)*s;this._colorData[4*a+0]=e,this._colorData[4*a+1]=t,this._colorData[4*a+2]=r,this._colorData[4*a+3]=n}getKernelString(){if(null!==this._kernelString)return this._kernelString;let e=null,{translatedSources:t}=this;return t.length>1?t=t.filter(t=>/^function/.test(t)?t:(e=t,!1)):e=t.shift(),this._kernelString=` const LOOP_MAX = ${this._getLoopMaxString()};\n ${this.injectedNative||""}\n const _this = this;\n ${this._resultKernelHeader()}\n ${this._processConstants()}\n return (${this.argumentNames.map(e=>"user_"+e).join(", ")}) => {\n ${this._prependedString.join("")}\n ${this._earlyThrows()}\n ${this._processArguments()}\n ${this.graphical?this._graphicalKernelBody(e):this._resultKernelBody(e)}\n ${t.length>0?t.join("\n"):""}\n };`}toString(){return l(this)}_getLoopMaxString(){return this.loopMaxIterations?` ${parseInt(this.loopMaxIterations)};`:" 1000;"}_processConstants(){if(!this.constants)return"";const e=[];for(let t in this.constants)switch(this.constantTypes[t]){case"HTMLCanvas":case"OffscreenCanvas":case"HTMLImage":case"ImageBitmap":case"ImageData":case"HTMLVideo":e.push(` const constants_${t} = this._mediaTo2DArray(this.constants.${t});\n`);break;case"HTMLImageArray":e.push(` const constants_${t} = this._imageTo3DArray(this.constants.${t});\n`);break;case"Input":e.push(` const constants_${t} = this.constants.${t}.value;\n`);break;default:e.push(` const constants_${t} = this.constants.${t};\n`)}return e.join("")}_earlyThrows(){if(this.graphical)return"";if(this.immutable)return"";if(!this.pipeline)return"";const e=[];for(let t=0;t`user_${n} === result_${e.name}`).join(" || ");t.push(`user_${n} === result${s?` || ${s}`:""}`)}return`if (${t.join(" || ")}) throw new Error('Source and destination arrays are the same. Use immutable = true');`}_processArguments(){const e=[];for(let t=0;t0?e.width:e.videoWidth,n=e.height>0?e.height:e.videoHeight;t.width=0;e--){const t=a[e]=new Array(r);for(let e=0;e`const result_${e.name} = new ${t}(outputX);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n this.thread.y = 0;\n this.thread.z = 0;\n ${e}\n }`}_mutableKernel1DResults(){const e=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const result = new ${e}(outputX);\n ${this._mapSubKernels(t=>`const result_${t.name} = new ${e}(outputX);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}`}_resultMutableKernel1DLoop(e){return` const outputX = _this.output[0];\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n this.thread.y = 0;\n this.thread.z = 0;\n ${e}\n }`}_resultImmutableKernel2DLoop(e){const t=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const result = new Array(outputY);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputY);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n this.thread.z = 0;\n this.thread.y = y;\n const resultX = result[y] = new ${t}(outputX);\n ${this._mapSubKernels(e=>`const resultX_${e.name} = result_${e.name}[y] = new ${t}(outputX);\n`).join("")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }`}_mutableKernel2DResults(){const e=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const result = new Array(outputY);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputY);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n const resultX = result[y] = new ${e}(outputX);\n ${this._mapSubKernels(t=>`const resultX_${t.name} = result_${t.name}[y] = new ${e}(outputX);\n`).join("")}\n }`}_resultMutableKernel2DLoop(e){const t=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n for (let y = 0; y < outputY; y++) {\n this.thread.z = 0;\n this.thread.y = y;\n const resultX = result[y];\n ${this._mapSubKernels(e=>`const resultX_${e.name} = result_${e.name}[y] = new ${t}(outputX);\n`).join("")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }`}_graphicalKernel2DLoop(e){return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n for (let y = 0; y < outputY; y++) {\n this.thread.z = 0;\n this.thread.y = y;\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }`}_resultImmutableKernel3DLoop(e){const t=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const outputZ = _this.output[2];\n const result = new Array(outputZ);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputZ);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let z = 0; z < outputZ; z++) {\n this.thread.z = z;\n const resultY = result[z] = new Array(outputY);\n ${this._mapSubKernels(e=>`const resultY_${e.name} = result_${e.name}[z] = new Array(outputY);\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n this.thread.y = y;\n const resultX = resultY[y] = new ${t}(outputX);\n ${this._mapSubKernels(e=>`const resultX_${e.name} = resultY_${e.name}[y] = new ${t}(outputX);\n`).join(" ")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }\n }`}_mutableKernel3DResults(){const e=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const outputZ = _this.output[2];\n const result = new Array(outputZ);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputZ);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let z = 0; z < outputZ; z++) {\n const resultY = result[z] = new Array(outputY);\n ${this._mapSubKernels(e=>`const resultY_${e.name} = result_${e.name}[z] = new Array(outputY);\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n const resultX = resultY[y] = new ${e}(outputX);\n ${this._mapSubKernels(t=>`const resultX_${t.name} = resultY_${t.name}[y] = new ${e}(outputX);\n`).join(" ")}\n }\n }`}_resultMutableKernel3DLoop(e){return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const outputZ = _this.output[2];\n for (let z = 0; z < outputZ; z++) {\n this.thread.z = z;\n const resultY = result[z];\n for (let y = 0; y < outputY; y++) {\n this.thread.y = y;\n const resultX = resultY[y];\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }\n }`}_kernelOutput(){return this.subKernels?`\n return {\n result: result,\n ${this.subKernels.map(e=>`${e.property}: result_${e.name}`).join(",\n ")}\n };`:"\n return result;"}_mapSubKernels(e){return null===this.subKernels?[""]:this.subKernels.map(e)}destroy(e){e&&delete this.canvas}static destroyContext(e){}toJSON(){const e=super.toJSON();return e.functionNodes=n.fromKernel(this,s).toJSON(),e}setOutput(e){super.setOutput(e);const[t,r]=this.output;this.graphical&&(this._imageData=this.context.createImageData(t,r),this._colorData=new Uint8ClampedArray(t*r*4))}prependString(e){if(this._kernelString)throw new Error("Kernel already built");this._prependedString.push(e)}hasPrependString(e){return this._prependedString.indexOf(e)>-1}}}}),d=e((e,t)=>{const{Texture:r}=s();function n(e,t){e.activeTexture(e.TEXTURE15),e.bindTexture(e.TEXTURE_2D,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST)}t.exports={GLTexture:class extends r{get textureType(){throw new Error(`"textureType" not implemented on ${this.name}`)}clone(){return new this.constructor(this)}beforeMutate(){return this.texture._refs>1&&(this.newTexture(),!0)}cloneTexture(){this.texture._refs--;const{context:e,size:t,texture:r,kernel:s}=this;s.debug&&console.warn("cloning internal texture"),e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),n(e,r),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,r,0);const i=e.createTexture();n(e,i),e.texImage2D(e.TEXTURE_2D,0,this.internalFormat,t[0],t[1],0,this.textureFormat,this.textureType,null),e.copyTexSubImage2D(e.TEXTURE_2D,0,0,0,0,0,t[0],t[1]),i._refs=1,this.texture=i}newTexture(){this.texture._refs--;const e=this.context,t=this.size;this.kernel.debug&&console.warn("new internal texture");const r=e.createTexture();n(e,r),e.texImage2D(e.TEXTURE_2D,0,this.internalFormat,t[0],t[1],0,this.textureFormat,this.textureType,null),r._refs=1,this.texture=r}clear(){if(this.texture._refs){this.texture._refs--;const e=this.context,t=this.texture=e.createTexture();n(e,t);const r=this.size;t._refs=1,e.texImage2D(e.TEXTURE_2D,0,this.internalFormat,r[0],r[1],0,this.textureFormat,this.textureType,null)}const{context:e,texture:t}=this;e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),e.bindTexture(e.TEXTURE_2D,t),n(e,t),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t,0),e.clearColor(0,0,0,0),e.clear(e.COLOR_BUFFER_BIT|e.DEPTH_BUFFER_BIT)}delete(){this._deleted||(this._deleted=!0,this.texture._refs&&(this.texture._refs--,this.texture._refs)||(this.kernel&&this.kernel.deleteTexture?this.kernel.deleteTexture(this.texture):this.context.deleteTexture(this.texture)))}framebuffer(){return this._framebuffer||(this._framebuffer=this.kernel.getRawValueFramebuffer(this.size[0],this.size[1])),this._framebuffer}}}}),m=e((e,t)=>{const{utils:r}=i(),{GLTexture:n}=d();t.exports={GLTextureFloat:class extends n{get textureType(){return this.context.FLOAT}constructor(e){super(e),this.type="ArrayTexture(1)"}renderRawOutput(){const e=this.context,t=this.size;e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.texture,0);const r=new Float32Array(t[0]*t[1]*4);return e.readPixels(0,0,t[0],t[1],e.RGBA,e.FLOAT,r),r}renderValues(){return this._deleted?null:this.renderRawOutput()}toArray(){return r.erectFloat(this.renderValues(),this.output[0])}}}}),f=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray2Float:class extends n{constructor(e){super(e),this.type="ArrayTexture(2)"}toArray(){return r.erectArray2(this.renderValues(),this.output[0],this.output[1])}}}}),g=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray2Float2D:class extends n{constructor(e){super(e),this.type="ArrayTexture(2)"}toArray(){return r.erect2DArray2(this.renderValues(),this.output[0],this.output[1])}}}}),y=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray2Float3D:class extends n{constructor(e){super(e),this.type="ArrayTexture(2)"}toArray(){return r.erect3DArray2(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),x=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray3Float:class extends n{constructor(e){super(e),this.type="ArrayTexture(3)"}toArray(){return r.erectArray3(this.renderValues(),this.output[0])}}}}),b=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray3Float2D:class extends n{constructor(e){super(e),this.type="ArrayTexture(3)"}toArray(){return r.erect2DArray3(this.renderValues(),this.output[0],this.output[1])}}}}),T=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray3Float3D:class extends n{constructor(e){super(e),this.type="ArrayTexture(3)"}toArray(){return r.erect3DArray3(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),v=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray4Float:class extends n{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return r.erectArray4(this.renderValues(),this.output[0])}}}}),S=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray4Float2D:class extends n{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return r.erect2DArray4(this.renderValues(),this.output[0],this.output[1])}}}}),A=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray4Float3D:class extends n{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return r.erect3DArray4(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),w=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureFloat2D:class extends n{constructor(e){super(e),this.type="ArrayTexture(1)"}toArray(){return r.erect2DFloat(this.renderValues(),this.output[0],this.output[1])}}}}),E=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureFloat3D:class extends n{constructor(e){super(e),this.type="ArrayTexture(1)"}toArray(){return r.erect3DFloat(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),I=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureMemoryOptimized:class extends n{constructor(e){super(e),this.type="MemoryOptimizedNumberTexture"}toArray(){return r.erectMemoryOptimizedFloat(this.renderValues(),this.output[0])}}}}),_=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureMemoryOptimized2D:class extends n{constructor(e){super(e),this.type="MemoryOptimizedNumberTexture"}toArray(){return r.erectMemoryOptimized2DFloat(this.renderValues(),this.output[0],this.output[1])}}}}),L=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureMemoryOptimized3D:class extends n{constructor(e){super(e),this.type="MemoryOptimizedNumberTexture"}toArray(){return r.erectMemoryOptimized3DFloat(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),F=e((e,t)=>{const{utils:r}=i(),{GLTexture:n}=d();t.exports={GLTextureUnsigned:class extends n{get textureType(){return this.context.UNSIGNED_BYTE}constructor(e){super(e),this.type="NumberTexture"}renderRawOutput(){const{context:e}=this;e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.texture,0);const t=new Uint8Array(this.size[0]*this.size[1]*4);return e.readPixels(0,0,this.size[0],this.size[1],e.RGBA,e.UNSIGNED_BYTE,t),t}renderValues(){return this._deleted?null:new Float32Array(this.renderRawOutput().buffer)}toArray(){return r.erectPackedFloat(this.renderValues(),this.output[0])}}}}),k=e((e,t)=>{const{utils:r}=i(),{GLTextureUnsigned:n}=F();t.exports={GLTextureUnsigned2D:class extends n{constructor(e){super(e),this.type="NumberTexture"}toArray(){return r.erect2DPackedFloat(this.renderValues(),this.output[0],this.output[1])}}}}),$=e((e,t)=>{const{utils:r}=i(),{GLTextureUnsigned:n}=F();t.exports={GLTextureUnsigned3D:class extends n{constructor(e){super(e),this.type="NumberTexture"}toArray(){return r.erect3DPackedFloat(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),D=e((e,t)=>{const{GLTextureUnsigned:r}=F();t.exports={GLTextureGraphical:class extends r{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return this.renderValues()}}}}),C=e((e,t)=>{const{Kernel:r}=a(),{utils:n}=i(),{GLTextureArray2Float:s}=f(),{GLTextureArray2Float2D:o}=g(),{GLTextureArray2Float3D:u}=y(),{GLTextureArray3Float:l}=x(),{GLTextureArray3Float2D:h}=b(),{GLTextureArray3Float3D:c}=T(),{GLTextureArray4Float:p}=v(),{GLTextureArray4Float2D:d}=S(),{GLTextureArray4Float3D:C}=A(),{GLTextureFloat:G}=m(),{GLTextureFloat2D:R}=w(),{GLTextureFloat3D:M}=E(),{GLTextureMemoryOptimized:N}=I(),{GLTextureMemoryOptimized2D:O}=_(),{GLTextureMemoryOptimized3D:z}=L(),{GLTextureUnsigned:V}=F(),{GLTextureUnsigned2D:U}=k(),{GLTextureUnsigned3D:B}=$(),{GLTextureGraphical:K}=D();const P={int:"Integer",float:"Number",vec2:"Array(2)",vec3:"Array(3)",vec4:"Array(4)"};t.exports={GLKernel:class extends r{static get mode(){return"gpu"}static getIsFloatRead(){const e=new this("function kernelFunction() {\n return 1;\n }",{context:this.testContext,canvas:this.testCanvas,validate:!1,output:[1],precision:"single",returnType:"Number",tactic:"speed"});e.build(),e.run();const t=e.renderOutput();return e.destroy(!0),1===t[0]}static getIsIntegerDivisionAccurate(){const e=new this(function(e,t){return e[this.thread.x]/t[this.thread.x]}.toString(),{context:this.testContext,canvas:this.testCanvas,validate:!1,output:[2],returnType:"Number",precision:"unsigned",tactic:"speed"}),t=[[6,6030401],[3,3991]];e.build.apply(e,t),e.run.apply(e,t);const r=e.renderOutput();return e.destroy(!0),2===r[0]&&1511===r[1]}static getIsSpeedTacticSupported(){const e=new this(function(e){return e[this.thread.x]}.toString(),{context:this.testContext,canvas:this.testCanvas,validate:!1,output:[4],returnType:"Number",precision:"unsigned",tactic:"speed"}),t=[[0,1,2,3]];e.build.apply(e,t),e.run.apply(e,t);const r=e.renderOutput();return e.destroy(!0),0===Math.round(r[0])&&1===Math.round(r[1])&&2===Math.round(r[2])&&3===Math.round(r[3])}static get testCanvas(){throw new Error(`"testCanvas" not defined on ${this.name}`)}static get testContext(){throw new Error(`"testContext" not defined on ${this.name}`)}static getFeatures(){const e=this.testContext,t=this.getIsDrawBuffers();return Object.freeze({isFloatRead:this.getIsFloatRead(),isIntegerDivisionAccurate:this.getIsIntegerDivisionAccurate(),isSpeedTacticSupported:this.getIsSpeedTacticSupported(),isTextureFloat:this.getIsTextureFloat(),isDrawBuffers:t,kernelMap:t,channelCount:this.getChannelCount(),maxTextureSize:this.getMaxTextureSize(),lowIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_INT),lowFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_FLOAT),mediumIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_INT),mediumFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_FLOAT),highIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_INT),highFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT)})}static setupFeatureChecks(){throw new Error(`"setupFeatureChecks" not defined on ${this.name}`)}static getSignature(e,t){return e.getVariablePrecisionString()+(t.length>0?":"+t.join(","):"")}setFixIntegerDivisionAccuracy(e){return this.fixIntegerDivisionAccuracy=e,this}setPrecision(e){return this.precision=e,this}setFloatTextures(e){return n.warnDeprecated("method","setFloatTextures","setOptimizeFloatMemory"),this.floatTextures=e,this}static nativeFunctionArguments(e){const t=[],r=[],n=[],s=/^[a-zA-Z_]/,i=/[a-zA-Z_0-9]/;let a=0,o=null,u=null;for(;a0?n[n.length-1]:null;if("FUNCTION_ARGUMENTS"!==c||"/"!==l||"*"!==h)if("MULTI_LINE_COMMENT"!==c||"*"!==l||"/"!==h)if("FUNCTION_ARGUMENTS"!==c||"/"!==l||"/"!==h)if("COMMENT"!==c||"\n"!==l)if(null!==c||"("!==l){if("FUNCTION_ARGUMENTS"===c){if(")"===l){n.pop();break}if("f"===l&&"l"===h&&"o"===e[a+2]&&"a"===e[a+3]&&"t"===e[a+4]&&" "===e[a+5]){n.push("DECLARE_VARIABLE"),u="float",o="",a+=6;continue}if("i"===l&&"n"===h&&"t"===e[a+2]&&" "===e[a+3]){n.push("DECLARE_VARIABLE"),u="int",o="",a+=4;continue}if("v"===l&&"e"===h&&"c"===e[a+2]&&"2"===e[a+3]&&" "===e[a+4]){n.push("DECLARE_VARIABLE"),u="vec2",o="",a+=5;continue}if("v"===l&&"e"===h&&"c"===e[a+2]&&"3"===e[a+3]&&" "===e[a+4]){n.push("DECLARE_VARIABLE"),u="vec3",o="",a+=5;continue}if("v"===l&&"e"===h&&"c"===e[a+2]&&"4"===e[a+3]&&" "===e[a+4]){n.push("DECLARE_VARIABLE"),u="vec4",o="",a+=5;continue}}else if("DECLARE_VARIABLE"===c){if(""===o){if(" "===l){a++;continue}if(!s.test(l))throw new Error("variable name is not expected string")}o+=l,i.test(h)||(n.pop(),r.push(o),t.push(P[u]))}a++}else n.push("FUNCTION_ARGUMENTS"),a++;else n.pop(),a++;else n.push("COMMENT"),a+=2;else n.pop(),a+=2;else n.push("MULTI_LINE_COMMENT"),a+=2}if(n.length>0)throw new Error("GLSL function was not parsable");return{argumentNames:r,argumentTypes:t}}static nativeFunctionReturnType(e){return P[e.match(/int|float|vec[2-4]/)[0]]}static combineKernels(e,t){e.apply(null,arguments);const{texSize:r,context:s,threadDim:i}=t.texSize;let a;if("single"===t.precision){const e=r[0],t=Math.ceil(r[1]/4);a=new Float32Array(e*t*4*4),s.readPixels(0,0,e,4*t,s.RGBA,s.FLOAT,a)}else{const e=new Uint8Array(r[0]*r[1]*4);s.readPixels(0,0,r[0],r[1],s.RGBA,s.UNSIGNED_BYTE,e),a=new Float32Array(e.buffer)}return a=a.subarray(0,i[0]*i[1]*i[2]),1===t.output.length?a:2===t.output.length?n.splitArray(a,t.output[0]):3===t.output.length?n.splitArray(a,t.output[0]*t.output[1]).map(function(e){return n.splitArray(e,t.output[0])}):void 0}constructor(e,t){super(e,t),this.transferValues=null,this.formatValues=null,this.TextureConstructor=null,this.renderOutput=null,this.renderRawOutput=null,this.texSize=null,this.translatedSource=null,this.compiledFragmentShader=null,this.compiledVertexShader=null,this.switchingKernels=null,this._textureSwitched=null,this._mappedTextureSwitched=null}checkTextureSize(){const{features:e}=this.constructor;if(this.texSize[0]>e.maxTextureSize||this.texSize[1]>e.maxTextureSize)throw new Error(`Texture size [${this.texSize[0]},${this.texSize[1]}] generated by kernel is larger than supported size [${e.maxTextureSize},${e.maxTextureSize}]`)}translateSource(){throw new Error(`"translateSource" not defined on ${this.constructor.name}`)}pickRenderStrategy(e){if(this.graphical)return this.renderRawOutput=this.readPackedPixelsToUint8Array,this.transferValues=e=>e,this.TextureConstructor=K,null;if("unsigned"===this.precision)if(this.renderRawOutput=this.readPackedPixelsToUint8Array,this.transferValues=this.readPackedPixelsToFloat32Array,this.pipeline)switch(this.renderOutput=this.renderTexture,null!==this.subKernels&&(this.renderKernels=this.renderKernelsToTextures),this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.output[2]>0?(this.TextureConstructor=B,null):this.output[1]>0?(this.TextureConstructor=U,null):(this.TextureConstructor=V,null);case"Array(2)":case"Array(3)":case"Array(4)":return this.requestFallback(e,`${this.returnType} output requires single precision, which this context does not support`)}else switch(null!==this.subKernels&&(this.renderKernels=this.renderKernelsToArrays),this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.renderOutput=this.renderValues,this.output[2]>0?(this.TextureConstructor=B,this.formatValues=n.erect3DPackedFloat,null):this.output[1]>0?(this.TextureConstructor=U,this.formatValues=n.erect2DPackedFloat,null):(this.TextureConstructor=V,this.formatValues=n.erectPackedFloat,null);case"Array(2)":case"Array(3)":case"Array(4)":return this.requestFallback(e,`${this.returnType} output requires single precision, which this context does not support`)}else{if("single"!==this.precision)throw new Error(`unhandled precision of "${this.precision}"`);if(this.renderRawOutput=this.readFloatPixelsToFloat32Array,this.transferValues=this.readFloatPixelsToFloat32Array,this.pipeline)switch(this.renderOutput=this.renderTexture,null!==this.subKernels&&(this.renderKernels=this.renderKernelsToTextures),this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.optimizeFloatMemory?this.output[2]>0?(this.TextureConstructor=z,null):this.output[1]>0?(this.TextureConstructor=O,null):(this.TextureConstructor=N,null):this.output[2]>0?(this.TextureConstructor=M,null):this.output[1]>0?(this.TextureConstructor=R,null):(this.TextureConstructor=G,null);case"Array(2)":return this.output[2]>0?(this.TextureConstructor=u,null):this.output[1]>0?(this.TextureConstructor=o,null):(this.TextureConstructor=s,null);case"Array(3)":return this.output[2]>0?(this.TextureConstructor=c,null):this.output[1]>0?(this.TextureConstructor=h,null):(this.TextureConstructor=l,null);case"Array(4)":return this.output[2]>0?(this.TextureConstructor=C,null):this.output[1]>0?(this.TextureConstructor=d,null):(this.TextureConstructor=p,null)}if(this.renderOutput=this.renderValues,null!==this.subKernels&&(this.renderKernels=this.renderKernelsToArrays),this.optimizeFloatMemory)switch(this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.output[2]>0?(this.TextureConstructor=z,this.formatValues=n.erectMemoryOptimized3DFloat,null):this.output[1]>0?(this.TextureConstructor=O,this.formatValues=n.erectMemoryOptimized2DFloat,null):(this.TextureConstructor=N,this.formatValues=n.erectMemoryOptimizedFloat,null);case"Array(2)":return this.output[2]>0?(this.TextureConstructor=u,this.formatValues=n.erect3DArray2,null):this.output[1]>0?(this.TextureConstructor=o,this.formatValues=n.erect2DArray2,null):(this.TextureConstructor=s,this.formatValues=n.erectArray2,null);case"Array(3)":return this.output[2]>0?(this.TextureConstructor=c,this.formatValues=n.erect3DArray3,null):this.output[1]>0?(this.TextureConstructor=h,this.formatValues=n.erect2DArray3,null):(this.TextureConstructor=l,this.formatValues=n.erectArray3,null);case"Array(4)":return this.output[2]>0?(this.TextureConstructor=C,this.formatValues=n.erect3DArray4,null):this.output[1]>0?(this.TextureConstructor=d,this.formatValues=n.erect2DArray4,null):(this.TextureConstructor=p,this.formatValues=n.erectArray4,null)}else switch(this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.output[2]>0?(this.TextureConstructor=M,this.formatValues=n.erect3DFloat,null):this.output[1]>0?(this.TextureConstructor=R,this.formatValues=n.erect2DFloat,null):(this.TextureConstructor=G,this.formatValues=n.erectFloat,null);case"Array(2)":return this.output[2]>0?(this.TextureConstructor=u,this.formatValues=n.erect3DArray2,null):this.output[1]>0?(this.TextureConstructor=o,this.formatValues=n.erect2DArray2,null):(this.TextureConstructor=s,this.formatValues=n.erectArray2,null);case"Array(3)":return this.output[2]>0?(this.TextureConstructor=c,this.formatValues=n.erect3DArray3,null):this.output[1]>0?(this.TextureConstructor=h,this.formatValues=n.erect2DArray3,null):(this.TextureConstructor=l,this.formatValues=n.erectArray3,null);case"Array(4)":return this.output[2]>0?(this.TextureConstructor=C,this.formatValues=n.erect3DArray4,null):this.output[1]>0?(this.TextureConstructor=d,this.formatValues=n.erect2DArray4,null):(this.TextureConstructor=p,this.formatValues=n.erectArray4,null)}}throw new Error(`unhandled return type "${this.returnType}"`)}getKernelString(){throw new Error("abstract method call")}getMainResultTexture(){switch(this.returnType){case"LiteralInteger":case"Float":case"Integer":case"Number":return this.getMainResultNumberTexture();case"Array(2)":return this.getMainResultArray2Texture();case"Array(3)":return this.getMainResultArray3Texture();case"Array(4)":return this.getMainResultArray4Texture();default:throw new Error(`unhandled returnType type ${this.returnType}`)}}getMainResultKernelNumberTexture(){throw new Error("abstract method call")}getMainResultSubKernelNumberTexture(){throw new Error("abstract method call")}getMainResultKernelArray2Texture(){throw new Error("abstract method call")}getMainResultSubKernelArray2Texture(){throw new Error("abstract method call")}getMainResultKernelArray3Texture(){throw new Error("abstract method call")}getMainResultSubKernelArray3Texture(){throw new Error("abstract method call")}getMainResultKernelArray4Texture(){throw new Error("abstract method call")}getMainResultSubKernelArray4Texture(){throw new Error("abstract method call")}getMainResultGraphical(){throw new Error("abstract method call")}getMainResultMemoryOptimizedFloats(){throw new Error("abstract method call")}getMainResultPackedPixels(){throw new Error("abstract method call")}getMainResultString(){return this.graphical?this.getMainResultGraphical():"single"===this.precision?this.optimizeFloatMemory?this.getMainResultMemoryOptimizedFloats():this.getMainResultTexture():this.getMainResultPackedPixels()}getMainResultNumberTexture(){return n.linesToString(this.getMainResultKernelNumberTexture())+n.linesToString(this.getMainResultSubKernelNumberTexture())}getMainResultArray2Texture(){return n.linesToString(this.getMainResultKernelArray2Texture())+n.linesToString(this.getMainResultSubKernelArray2Texture())}getMainResultArray3Texture(){return n.linesToString(this.getMainResultKernelArray3Texture())+n.linesToString(this.getMainResultSubKernelArray3Texture())}getMainResultArray4Texture(){return n.linesToString(this.getMainResultKernelArray4Texture())+n.linesToString(this.getMainResultSubKernelArray4Texture())}getFloatTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic)} float;\n`}getIntTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic,!0)} int;\n`}getSampler2DTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic)} sampler2D;\n`}getSampler2DArrayTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic)} sampler2DArray;\n`}renderTexture(){return this.immutable?this.texture.clone():this.texture}readPackedPixelsToUint8Array(){if("unsigned"!==this.precision)throw new Error('Requires this.precision to be "unsigned"');const{texSize:e,context:t}=this,r=new Uint8Array(e[0]*e[1]*4);return t.readPixels(0,0,e[0],e[1],t.RGBA,t.UNSIGNED_BYTE,r),r}readPackedPixelsToFloat32Array(){return new Float32Array(this.readPackedPixelsToUint8Array().buffer)}readFloatPixelsToFloat32Array(){if("single"!==this.precision)throw new Error('Requires this.precision to be "single"');const{texSize:e,context:t}=this,r=e[0],n=e[1],s=new Float32Array(r*n*4);return t.readPixels(0,0,r,n,t.RGBA,t.FLOAT,s),s}getPixels(e){const{context:t,output:r}=this,[s,i]=r,a=new Uint8Array(s*i*4);t.readPixels(0,0,s,i,t.RGBA,t.UNSIGNED_BYTE,a);const o=new Uint8ClampedArray((e?a:n.flipPixels(a,s,i)).buffer);return this.asyncMode?Promise.resolve(o):o}renderKernelsToArrays(){const e={result:this.renderOutput()};for(let t=0;t0){for(let e=0;e0){const{mappedTextures:r}=this;for(let n=0;n{const{utils:r}=i(),{FunctionNode:n}=l(),s={"<":"ceil",">=":"ceil",">":"floor","<=":"floor"};function a(e){if(!e||"object"!=typeof e)return!0;if(Array.isArray(e))return e.every(a);if("UpdateExpression"===e.type||"AssignmentExpression"===e.type||"SequenceExpression"===e.type)return!1;for(const t in e)if("loc"!==t&&"range"!==t&&"parent"!==t&&!a(e[t]))return!1;return!0}function o(e){let t=!1;function r(e){if(!e||"object"!=typeof e||t)return!1;if(Array.isArray(e))return e.some(r);if("MemberExpression"===e.type&&e.computed)return!0;for(const t in e)if("loc"!==t&&"range"!==t&&"parent"!==t&&r(e[t]))return!0;return!1}return function e(n){if(n&&"object"==typeof n&&!t)if(Array.isArray(n))n.forEach(e);else if("MemberExpression"===n.type&&n.computed&&r(n.property))t=!0;else for(const t in n)"loc"!==t&&"range"!==t&&"parent"!==t&&e(n[t])}(e),t}function u(e,t){if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(e=>u(e,t));if("CallExpression"===e.type&&"Identifier"===e.callee.type&&e.callee.name===t)return!0;for(const r in e)if("loc"!==r&&"range"!==r&&"parent"!==r&&u(e[r],t))return!0;return!1}function h(e){let t=!1;return function e(r){if(r&&"object"==typeof r&&!t)if(Array.isArray(r))r.forEach(e);else if("CallExpression"===r.type&&"Identifier"===r.callee.type&&r.arguments.some(e=>u(e,r.callee.name)))t=!0;else for(const t in r)"loc"!==t&&"range"!==t&&"parent"!==t&&e(r[t])}(e),t}function c(e){const t="ExpressionStatement"===e.type&&"AssignmentExpression"===e.expression.type?e.expression:null;return function e(r){if(!r||"object"!=typeof r)return!0;if(Array.isArray(r))return r.every(e);if("string"==typeof r.type){if("UpdateExpression"===r.type||"SequenceExpression"===r.type)return!1;if("AssignmentExpression"===r.type&&r!==t)return!1}for(const t in r)if("loc"!==t&&"range"!==t&&"parent"!==t&&!e(r[t]))return!1;return!0}(e)}const p={"Matrix(2)":2,"Matrix(3)":3,"Matrix(4)":4},d={Array:"sampler2D","Array(2)":"vec2","Array(3)":"vec3","Array(4)":"vec4","Matrix(2)":"mat2","Matrix(3)":"mat3","Matrix(4)":"mat4",Array2D:"sampler2D",Array3D:"sampler2D",Boolean:"bool",Float:"float",Input:"sampler2D",Integer:"int",Number:"float",LiteralInteger:"float",NumberTexture:"sampler2D",MemoryOptimizedNumberTexture:"sampler2D","ArrayTexture(1)":"sampler2D","ArrayTexture(2)":"sampler2D","ArrayTexture(3)":"sampler2D","ArrayTexture(4)":"sampler2D",HTMLVideo:"sampler2D",HTMLCanvas:"sampler2D",OffscreenCanvas:"sampler2D",HTMLImage:"sampler2D",ImageBitmap:"sampler2D",ImageData:"sampler2D",HTMLImageArray:"sampler2DArray"},m={"===":"==","!==":"!="};t.exports={WebGLFunctionNode:class extends n{constructor(e,t){super(e,t),t&&t.hasOwnProperty("fixIntegerDivisionAccuracy")&&(this.fixIntegerDivisionAccuracy=t.fixIntegerDivisionAccuracy)}astConditionalExpression(e,t){if("ConditionalExpression"!==e.type)throw this.astErrorOutput("Not a conditional expression",e);const r=this.getType(e.consequent),n=this.getType(e.alternate);return null===r&&null===n?(t.push("if ("),this.astGeneric(e.test,t),t.push(") {"),this.astGeneric(e.consequent,t),t.push(";"),t.push("} else {"),this.astGeneric(e.alternate,t),t.push(";"),t.push("}"),t):(t.push("("),this.astGeneric(e.test,t),t.push("?"),this.astGeneric(e.consequent,t),t.push(":"),this.astGeneric(e.alternate,t),t.push(")"),t)}astFunction(e,t){if(this.isRootKernel)t.push("void");else{this.returnType||this.findLastReturn()&&(this.returnType=this.getType(e.body),"LiteralInteger"===this.returnType&&(this.returnType="Number"));const{returnType:r}=this;if(r){const e=d[r];if(!e)throw new Error(`unknown type ${r}`);t.push(e)}else t.push("void")}if(t.push(" "),t.push(this.name),t.push("("),!this.isRootKernel)for(let n=0;n0&&t.push(", ");let i=this.argumentTypes[this.argumentNames.indexOf(s)];if(!i)throw this.astErrorOutput(`Unknown argument ${s} type`,e);"LiteralInteger"===i&&(this.argumentTypes[n]=i="Number");const a=d[i];if(!a)throw this.astErrorOutput("Unexpected expression",e);const o=r.sanitizeName(s);"sampler2D"===a||"sampler2DArray"===a?t.push(`${a} user_${o},ivec2 user_${o}Size,ivec3 user_${o}Dim`):t.push(`${a} user_${o}`)}if(t.push(") {\n"),this.isRootKernel){const e=this.getAssignedArguments();for(let n=0;n>":"bitwiseSignedRightShift",">>>":"bitwiseZeroFillRightShift"}[e.operator];if(!r)return null;switch(t.push(r),t.push("("),this.getType(e.left)){case"Number":case"Float":this.castValueToInteger(e.left,t);break;case"LiteralInteger":this.castLiteralToInteger(e.left,t);break;default:this.astGeneric(e.left,t)}switch(t.push(","),this.getType(e.right)){case"Number":case"Float":this.castValueToInteger(e.right,t);break;case"LiteralInteger":this.castLiteralToInteger(e.right,t);break;default:this.astGeneric(e.right,t)}return t.push(")"),t}checkAndUpconvertBitwiseUnary(e,t){const r={"~":"bitwiseNot"}[e.operator];if(!r)return null;switch(t.push(r),t.push("("),this.getType(e.argument)){case"Number":case"Float":this.castValueToInteger(e.argument,t);break;case"LiteralInteger":this.castLiteralToInteger(e.argument,t);break;default:this.astGeneric(e.argument,t)}return t.push(")"),t}castLiteralToInteger(e,t){return this.pushState("casting-to-integer"),this.astGeneric(e,t),this.popState("casting-to-integer"),t}castLiteralToFloat(e,t){return this.pushState("casting-to-float"),this.astGeneric(e,t),this.popState("casting-to-float"),t}castValueToInteger(e,t){return this.pushState("casting-to-integer"),t.push("int("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-integer"),t}castValueToFloat(e,t){return this.pushState("casting-to-float"),t.push("float("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-float"),t}astIdentifierExpression(e,t){if("Identifier"!==e.type)throw this.astErrorOutput("IdentifierExpression - not an Identifier",e);const n=this.getType(e),s=r.sanitizeName(e.name);if("Infinity"===e.name)t.push("3.402823466e+38");else if("Boolean"===n)if(this.argumentNames.indexOf(s)>-1){const r=this.markupUserName(e.name);t.push(r.startsWith("cellShadow_")?r:`bool(${r})`)}else t.push(`user_${s}`);else t.push(this.markupUserName(e.name));return t}markupUserName(e){const t=r.sanitizeName(e);if(this.isRootKernel&&this.getAssignedArguments().has(e)){const r=this.argumentNames.indexOf(e),n=-1===r?null:d[this.argumentTypes[r]];if("float"===n||"int"===n||"bool"===n)return`cellShadow_user_${t}`}return`user_${t}`}astForStatement(e,t){if("ForStatement"!==e.type)throw this.astErrorOutput("Invalid for statement",e);const r=[],n=[],s=[],i=[];let a=null;if(e.init){const{declarations:t}=e.init;t.length>1&&(a=!1),this.astGeneric(e.init,r);for(let e=0;e0&&t.push(r.join(""),"\n"),t.push(`for (int ${e}=0;${e}0&&t.push(`if (!${n.join("")}) break;\n`),t.push(i.join("")),t.push(`\n${s.join("")};`),t.push("}\n")}return t}astWhileStatement(e,t){if("WhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);const r=this.getInternalVariableName("safeI");return t.push(`for (int ${r}=0;${r}0){if (!`),this.astGeneric(e.test,t),t.push(") break;}\n"),this.astGeneric(e.body,t),t.push("}\n"),t}astAssignmentExpression(e,t){const r=this.isState("assignment-as-statement");if(r?this.popState("assignment-as-statement"):t.push("("),"%="===e.operator)this.astGeneric(e.left,t),t.push("="),t.push("mod("),this.astGeneric(e.left,t),t.push(","),this.astGeneric(e.right,t),t.push(")");else if("**="===e.operator)this.astGeneric(e.left,t),t.push("="),t.push("pow("),this.astGeneric(e.left,t),t.push(","),this.astGeneric(e.right,t),t.push(")");else{const r=this.getType(e.left),n=this.getType(e.right);this.astGeneric(e.left,t),t.push(e.operator),"Integer"!==r&&"Integer"===n?(t.push("float("),this.astGeneric(e.right,t),t.push(")")):"Integer"===r&&"LiteralInteger"===n?this.castLiteralToInteger(e.right,t):this.astGeneric(e.right,t)}return r||t.push(")"),t}astBlockStatement(e,t){if(this.isState("loop-body")){this.pushState("block-body");for(let r=0;rnull!==e&&(o(e)||h(e))))return null;const i=e=>JSON.parse(JSON.stringify(e)),a=e=>({type:"IfStatement",test:{type:"UnaryExpression",operator:"!",prefix:!0,argument:e},consequent:{type:"BlockStatement",body:[{type:"BreakStatement",label:null}]},alternate:null}),u=e=>"VariableDeclaration"===e.type?e:{type:"ExpressionStatement",expression:e},l="BlockStatement"===e.body.type?e.body.body.slice():[e.body],c=(e,t)=>{const r=e=>{if(!e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map(r);switch(e.type){case"ContinueStatement":return{type:"BlockStatement",body:[...t(),e]};case"ForStatement":case"WhileStatement":case"DoWhileStatement":default:return e;case"IfStatement":return{...e,consequent:r(e.consequent),alternate:r(e.alternate)};case"BlockStatement":return{...e,body:e.body.map(r)};case"SwitchStatement":return{...e,cases:e.cases.map(e=>({...e,consequent:e.consequent.map(r)}))}}};return e.map(r)},p=[];"DoWhileStatement"===t?(p.push(...n?c(l,()=>[a(i(n))]):l),n&&p.push(a(n))):(n&&p.push(a(n)),p.push(...s?c(l,()=>[u(i(s))]):l),s&&p.push(u(s)));const d={type:"BlockStatement",body:[...r?[u(r)]:[],{type:"WhileStatement",test:{type:"Literal",value:!0,raw:"true"},body:{type:"BlockStatement",body:p}}]};return this.stampSyntheticNodes(d),d}stampSyntheticNodes(e){let t=this.syntheticNodeId||1073741824;const r=e=>{if(e&&"object"==typeof e)if(Array.isArray(e))e.forEach(r);else{"string"==typeof e.type&&void 0===e.start&&(e.start=t,e.end=t+1,t+=2);for(const t in e)"loc"!==t&&"range"!==t&&"parent"!==t&&r(e[t])}};r(e),this.syntheticNodeId=t}linearizeStatement(e){const t=[];let r=!1,n=this.linearTempId||0;const s=e=>({type:"Identifier",name:e}),i=(e,t,r)=>({type:"VariableDeclaration",kind:e,declarations:[{type:"VariableDeclarator",id:s(t),init:r}]}),o=(e,t)=>{const r="hoistSeq"+n++;return e.push(i("const",r,t)),s(r)},l=e=>!a(e),h=(e,t)=>{if(r||!e||"object"!=typeof e)return e;switch(e.type){case"Identifier":case"Literal":case"ThisExpression":return e;case"MemberExpression":{const r=h(e.object,t),n=e.computed?h(e.property,t):e.property;return{...e,object:r,property:n}}case"CallExpression":{const r=e.arguments.map(e=>h(e,t));if("Identifier"===e.callee.type)for(let n=0;nh(e,t))};case"UpdateExpression":{if("Identifier"!==e.argument.type)return r=!0,e;if(e.prefix)return t.push({type:"ExpressionStatement",expression:e}),o(t,e.argument);const n=o(t,e.argument);return t.push({type:"ExpressionStatement",expression:e}),n}case"AssignmentExpression":{if("Identifier"!==e.left.type)return r=!0,e;const n=h(e.right,t);return t.push({type:"ExpressionStatement",expression:{...e,right:n}}),o(t,e.left)}case"SequenceExpression":for(let r=0;r({type:"ExpressionStatement",expression:{type:"AssignmentExpression",operator:"=",left:s(e),right:t}});return o.push(d(a,c)),u.push(d(a,p)),t.push({type:"IfStatement",test:r,consequent:{type:"BlockStatement",body:o},alternate:{type:"BlockStatement",body:u}}),s(a)}case"LogicalExpression":{if(!l(e.right))return{...e,left:h(e.left,t)};const r=h(e.left,t),a="hoistSeq"+n++;t.push(i("let",a,r));const o=[],u=h(e.right,o);return o.push({type:"ExpressionStatement",expression:{type:"AssignmentExpression",operator:"=",left:s(a),right:u}}),t.push({type:"IfStatement",test:"&&"===e.operator?s(a):{type:"UnaryExpression",operator:"!",prefix:!0,argument:s(a)},consequent:{type:"BlockStatement",body:o},alternate:null}),s(a)}default:return r=!0,e}};switch(e.type){case"ExpressionStatement":{const r=e.expression;if("AssignmentExpression"===r.type&&"Identifier"===r.left.type){const e=h(r.right,t);t.push({type:"ExpressionStatement",expression:{...r,right:e}})}else{const e=h(r,t);"UpdateExpression"!==e.type&&"AssignmentExpression"!==e.type||t.push({type:"ExpressionStatement",expression:e})}break}case"VariableDeclaration":for(let r=0;r{if(e&&"object"==typeof e)if(Array.isArray(e))e.forEach(p);else{"string"==typeof e.type&&void 0===e.start&&(e.start=c,e.end=c+1,c+=2);for(const t in e)"loc"!==t&&"range"!==t&&"parent"!==t&&p(e[t])}};return p(t),this.syntheticNodeId=c,t}astStatementWithHoisting(e,t){switch(e.type){case"ExpressionStatement":case"VariableDeclaration":case"ReturnStatement":{if(!c(e))return this.astGeneric(e,t);const r=this.hoistedIndexReads,n=this.hoistedIndexReads=[],s=[];return this.astGeneric(e,s),this.hoistedIndexReads=r,t.push(...n,...s),t}default:return this.astGeneric(e,t)}}astVariableDeclaration(e,t){const n=e.declarations;if(!n||!n[0]||!n[0].init)throw this.astErrorOutput("Unexpected expression",e);const s=[];let i=null;const a=[];let o=[];for(let t=0;t0&&a.push(o.join(",")),s.push(a.join(";")),t.push(s.join("")),t.push(";"),t}astIfStatement(e,t){return t.push("if ("),this.astGeneric(e.test,t),t.push(")"),"BlockStatement"===e.consequent.type?this.astGeneric(e.consequent,t):(t.push(" {\n"),this.astGeneric(e.consequent,t),t.push("\n}\n")),e.alternate&&(t.push("else "),"BlockStatement"===e.alternate.type||"IfStatement"===e.alternate.type?this.astGeneric(e.alternate,t):(t.push(" {\n"),this.astGeneric(e.alternate,t),t.push("\n}\n"))),t}astSwitchCaseConsequent(e,t){const r=[];for(let t=0;t{if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(t);if("BreakStatement"===e.type)return!0;if("ForStatement"===e.type||"WhileStatement"===e.type||"DoWhileStatement"===e.type||"SwitchStatement"===e.type)return!1;for(const r in e)if("loc"!==r&&"range"!==r&&"parent"!==r&&t(e[r]))return!0;return!1};if(t(r[e]))throw this.astErrorOutput("break inside a switch case is only supported as the case terminator",r[e])}for(let e=0;er+1){u=!0,this.astSwitchCaseConsequent(n[r].consequent,o);continue}t.push(" else {\n")}this.astSwitchCaseConsequent(n[r].consequent,t),t.push("\n}")}return u&&(t.push(" else {"),t.push(o.join("")),t.push("}")),t}astThisExpression(e,t){return t.push("this"),t}astMemberExpression(e,t){const{property:n,name:s,signature:i,origin:a,type:o,xProperty:u,yProperty:l,zProperty:h}=this.getMemberExpressionDetails(e);switch(i){case"value.thread.value":case"this.thread.value":if("x"!==s&&"y"!==s&&"z"!==s)throw this.astErrorOutput("Unexpected expression, expected `this.thread.x`, `this.thread.y`, or `this.thread.z`",e);return t.push(`threadId.${s}`),t;case"this.output.value":if(this.dynamicOutput)switch(s){case"x":this.isState("casting-to-float")?t.push("float(uOutputDim.x)"):t.push("uOutputDim.x");break;case"y":this.isState("casting-to-float")?t.push("float(uOutputDim.y)"):t.push("uOutputDim.y");break;case"z":this.isState("casting-to-float")?t.push("float(uOutputDim.z)"):t.push("uOutputDim.z");break;default:throw this.astErrorOutput("Unexpected expression",e)}else switch(s){case"x":this.isState("casting-to-integer")?t.push(this.output[0]):t.push(this.output[0],".0");break;case"y":this.isState("casting-to-integer")?t.push(this.output[1]):t.push(this.output[1],".0");break;case"z":this.isState("casting-to-integer")?t.push(this.output[2]):t.push(this.output[2],".0");break;default:throw this.astErrorOutput("Unexpected expression",e)}return t;case"value":throw this.astErrorOutput("Unexpected expression",e);case"value[]":case"value[][]":case"value[][][]":case"value[][][][]":case"value.value":if("Math"===a)return t.push(Math[s]),t;const i=r.sanitizeName(s);switch(n){case"r":return t.push(`user_${i}.r`),t;case"g":return t.push(`user_${i}.g`),t;case"b":return t.push(`user_${i}.b`),t;case"a":return t.push(`user_${i}.a`),t}break;case"this.constants.value":if(void 0===u)switch(o){case"Array(2)":case"Array(3)":case"Array(4)":return t.push(`constants_${r.sanitizeName(s)}`),t}case"this.constants.value[]":case"this.constants.value[][]":case"this.constants.value[][][]":case"this.constants.value[][][][]":break;case"fn()[]":return this.astCallExpression(e.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(n)),t.push("]"),t;case"fn()[][]":{const r=e.object.property,n=e.property,s=p[this.getType(e.object.object)],i=e=>"LiteralInteger"===this.getType(e);return!s||i(r)&&i(n)?(this.astCallExpression(e.object.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(r)),t.push("]"),t.push("["),t.push(this.memberExpressionPropertyMarkup(n)),t.push("]"),t):(t.push(`getMatrix${s}(`),this.astCallExpression(e.object.object,t),t.push(", "),t.push(this.memberExpressionPropertyMarkup(r)),t.push(", "),t.push(this.memberExpressionPropertyMarkup(n)),t.push(")"),t)}case"[][]":return this.astArrayExpression(e.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(n)),t.push("]"),t;default:throw this.astErrorOutput("Unexpected expression",e)}if(!1===e.computed)switch(o){case"Number":case"Integer":case"Float":case"Boolean":return t.push(`${a}_${r.sanitizeName(s)}`),t}const c=`${a}_${r.sanitizeName(s)}`;switch(o){case"Array(2)":case"Array(3)":case"Array(4)":this.astGeneric(e.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(u)),t.push("]");break;case"HTMLImageArray":t.push(`getImage3D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"ArrayTexture(1)":t.push(`getFloatFromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"Array1D(2)":case"Array2D(2)":case"Array3D(2)":t.push(`getMemoryOptimizedVec2(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"ArrayTexture(2)":t.push(`getVec2FromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"Array1D(3)":case"Array2D(3)":case"Array3D(3)":t.push(`getMemoryOptimizedVec3(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"ArrayTexture(3)":t.push(`getVec3FromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"Array1D(4)":case"Array2D(4)":case"Array3D(4)":t.push(`getMemoryOptimizedVec4(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"ArrayTexture(4)":case"HTMLCanvas":case"OffscreenCanvas":case"HTMLImage":case"ImageBitmap":case"ImageData":case"HTMLVideo":t.push(`getVec4FromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"NumberTexture":case"Array":case"Array2D":case"Array3D":case"Array4D":case"Input":case"Number":case"Float":case"Integer":if("single"===this.precision)t.push(`getMemoryOptimized32(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");else{const e="user"===a?this.lookupFunctionArgumentBitRatio(this.name,s):this.constantBitRatios[s];switch(e){case 1:t.push(`get8(${c}, ${c}Size, ${c}Dim, `);break;case 2:t.push(`get16(${c}, ${c}Size, ${c}Dim, `);break;case 4:case 0:t.push(`get32(${c}, ${c}Size, ${c}Dim, `);break;default:throw new Error(`unhandled bit ratio of ${e}`)}this.memberExpressionXYZ(u,l,h,t),t.push(")")}break;case"MemoryOptimizedNumberTexture":t.push(`getMemoryOptimized32(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":t.push(`${c}[${this.memberExpressionPropertyMarkup(l)}]`),l&&t.push(`[${this.memberExpressionPropertyMarkup(u)}]`);break;default:throw new Error(`unhandled member expression "${o}"`)}return t}astCallExpression(e,t){if(!e.callee)throw this.astErrorOutput("Unknown CallExpression",e);let n=null;const s=this.isAstMathFunction(e);if(n=s||e.callee.object&&"ThisExpression"===e.callee.object.type?e.callee.property.name:"SequenceExpression"!==e.callee.type||"Literal"!==e.callee.expressions[0].type||isNaN(e.callee.expressions[0].raw)?e.callee.name:e.callee.expressions[1].property.name,!n)throw this.astErrorOutput("Unhandled function, couldn't find name",e);switch(n){case"pow":n="_pow";break;case"round":n="_round"}if(this.calledFunctions.indexOf(n)<0&&this.calledFunctions.push(n),"random"===n&&this.plugins&&this.plugins.length>0)for(let e=0;e0&&t.push(", "),"Integer"===s)this.castValueToFloat(n,t);else this.astGeneric(n,t)}else{const s=this.lookupFunctionArgumentTypes(n)||[];for(let i=0;i0&&t.push(", ");const u=this.getType(a);switch(o||(this.triggerImplyArgumentType(n,i,u,this),o=u),u){case"Boolean":this.astGeneric(a,t);continue;case"Number":case"Float":if("Integer"===o){t.push("int("),this.astGeneric(a,t),t.push(")");continue}if("Number"===o||"Float"===o){this.astGeneric(a,t);continue}if("LiteralInteger"===o){this.castLiteralToFloat(a,t);continue}break;case"Integer":if("Number"===o||"Float"===o){t.push("float("),this.astGeneric(a,t),t.push(")");continue}if("Integer"===o){this.astGeneric(a,t);continue}break;case"LiteralInteger":if("Integer"===o){this.castLiteralToInteger(a,t);continue}if("Number"===o||"Float"===o){this.castLiteralToFloat(a,t);continue}if("LiteralInteger"===o){this.astGeneric(a,t);continue}break;case"Array(2)":case"Array(3)":case"Array(4)":if(o===u){if("Identifier"===a.type)t.push(`user_${r.sanitizeName(a.name)}`);else{if("ArrayExpression"!==a.type&&"MemberExpression"!==a.type&&"CallExpression"!==a.type)throw this.astErrorOutput(`Unhandled argument type ${a.type}`,e);this.astGeneric(a,t)}continue}break;case"HTMLCanvas":case"OffscreenCanvas":case"HTMLImage":case"ImageBitmap":case"ImageData":case"HTMLImageArray":case"HTMLVideo":case"ArrayTexture(1)":case"ArrayTexture(2)":case"ArrayTexture(3)":case"ArrayTexture(4)":case"Array":case"Input":if(o===u){if("Identifier"!==a.type)throw this.astErrorOutput(`Unhandled argument type ${a.type}`,e);this.triggerImplyArgumentBitRatio(this.name,a.name,n,i);const s=r.sanitizeName(a.name);t.push(`user_${s},user_${s}Size,user_${s}Dim`);continue}}throw this.astErrorOutput(`Unhandled argument combination of ${u} and ${o} for argument named "${a.name}"`,e)}}return t.push(")"),t}astArrayExpression(e,t){const r=this.getType(e),n=e.elements.length;switch(r){case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":t.push(`mat${n}(`);break;default:t.push(`vec${n}(`)}for(let r=0;r0&&t.push(", ");const n=e.elements[r];this.astGeneric(n,t)}return t.push(")"),t}memberExpressionXYZ(e,t,r,n){return r?n.push(this.memberExpressionPropertyMarkup(r),", "):n.push("0, "),t?n.push(this.memberExpressionPropertyMarkup(t),", "):n.push("0, "),n.push(this.memberExpressionPropertyMarkup(e)),n}memberExpressionPropertyMarkup(e){if(!e)throw new Error("Property not set");const t=[];switch(this.getType(e)){case"Number":case"Float":this.castValueToInteger(e,t);break;case"LiteralInteger":this.castLiteralToInteger(e,t);break;default:this.astGeneric(e,t)}const n=t.join("");if(this.hoistedIndexReads&&/\b\w+\((user_|constants_)\w+, \1\w+Size/.test(n)){const e=`hoisted_${this.hoistedIndexReads.length}_${r.sanitizeName(this.name)}`,t=n.startsWith("int(");return this.hoistedIndexReads.push(`${t?"int":"float"} ${e}=${n};\n`),e}return n}}}}),R=e((e,t)=>{t.exports={name:"math-random-uniformly-distributed",onBeforeRun:e=>{if(null===e.randomSeed||void 0===e.randomSeed)return e.setUniform1f("randomSeed1",Math.random()),void e.setUniform1f("randomSeed2",Math.random());e._mathRandomGenerator&&e._mathRandomGeneratorSeed===e.randomSeed||(e._mathRandomGenerator=function(e){let t=e>>>0;return function(){t=t+1831565813>>>0;let e=t;return e=Math.imul(e^e>>>15,1|e),e^=e+Math.imul(e^e>>>7,61|e),((e^e>>>14)>>>0)/4294967296}}(e.randomSeed),e._mathRandomGeneratorSeed=e.randomSeed),e.setUniform1f("randomSeed1",e._mathRandomGenerator()),e.setUniform1f("randomSeed2",e._mathRandomGenerator())},functionMatch:"Math.random()",functionReplace:"nrand(vTexCoord)",functionReturnType:"Number",source:"// https://www.shadertoy.com/view/4t2SDh\n//note: uniformly distributed, normalized rand, [0,1]\nhighp float randomSeedShift = 1.0;\nhighp float slide = 1.0;\nuniform highp float randomSeed1;\nuniform highp float randomSeed2;\n\nhighp float nrand(highp vec2 n) {\n highp float result = fract(sin(dot((n.xy + 1.0) * vec2(randomSeed1 * slide, randomSeed2 * randomSeedShift), vec2(12.9898, 78.233))) * 43758.5453);\n randomSeedShift = result;\n if (randomSeedShift > 0.5) {\n slide += 0.00009; \n } else {\n slide += 0.0009;\n }\n return result;\n}"}}),M=e((e,t)=>{t.exports={fragmentShader:`__HEADER__;\n__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n\nconst int LOOP_MAX = __LOOP_MAX__;\n\n__PLUGINS__;\n__CONSTANTS__;\n\nvarying vec2 vTexCoord;\n\nfloat acosh(float x) {\n return log(x + sqrt(x * x - 1.0));\n}\n\nfloat sinh(float x) {\n return (pow(${Math.E}, x) - pow(${Math.E}, -x)) / 2.0;\n}\n\nfloat asinh(float x) {\n return log(x + sqrt(x * x + 1.0));\n}\n\nfloat atan2(float v1, float v2) {\n if (v2 == 0.0) {\n if (v1 == 0.0) return 0.0;\n if (v1 > 0.0) return 1.5707963267948966;\n if (v1 < 0.0) return -1.5707963267948966;\n }\n return atan(v1, v2);\n}\n\nfloat atanh(float x) {\n x = (x + 1.0) / (x - 1.0);\n if (x < 0.0) {\n return 0.5 * log(-x);\n }\n return 0.5 * log(x);\n}\n\nfloat cbrt(float x) {\n if (x >= 0.0) {\n return pow(x, 1.0 / 3.0);\n } else {\n return -pow(x, 1.0 / 3.0);\n }\n}\n\nfloat cosh(float x) {\n return (pow(${Math.E}, x) + pow(${Math.E}, -x)) / 2.0; \n}\n\nfloat expm1(float x) {\n return pow(${Math.E}, x) - 1.0; \n}\n\nfloat fround(highp float x) {\n return x;\n}\n\nfloat imul(float v1, float v2) {\n return float(int(v1) * int(v2));\n}\n\nfloat log10(float x) {\n return log2(x) * (1.0 / log2(10.0));\n}\n\nfloat log1p(float x) {\n return log(1.0 + x);\n}\n\nfloat _pow(float v1, float v2) {\n if (v2 == 0.0) return 1.0;\n return pow(v1, v2);\n}\n\nfloat tanh(float x) {\n float e = exp(2.0 * x);\n return (e - 1.0) / (e + 1.0);\n}\n\nfloat trunc(float x) {\n if (x >= 0.0) {\n return floor(x); \n } else {\n return ceil(x);\n }\n}\n\nvec4 _round(vec4 x) {\n return floor(x + 0.5);\n}\n\nfloat _round(float x) {\n return floor(x + 0.5);\n}\n\nconst int BIT_COUNT = 32;\nint modi(int x, int y) {\n return x - y * (x / y);\n}\n\nint bitwiseOr(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) || (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseXOR(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) != (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseAnd(int a, int b) {\n int result = 0;\n int n = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) && (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 && b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseNot(int a) {\n // ~a is identically -a - 1 in two's complement, for every value including\n // negatives. The previous bit-by-bit loop only worked for a >= 0, where it\n // leaned on 32-bit overflow wrapping to reach the negative answer; given a\n // negative input it computed ~abs(a), so ~(-1) gave -2 and ~~x never\n // returned x.\n return -a - 1;\n}\nint bitwiseZeroFillLeftShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n *= 2;\n }\n\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\n// _pow2 is defined further down, alongside encode32/decode32\nfloat _pow2(float e);\nint bitwiseSignedRightShift(int num, int shifts) {\n // pow(2.0, n) is approximate on many GPUs, and landing 1 ulp high makes the\n // division fall just under a whole number, which floor() then rounds away:\n // 2 >> 1 came out 0, 8 >> 1 came out 3. Only exact left operands were\n // affected, odd ones having enough slack to survive. _pow2 is exact.\n return int(floor(float(num) / _pow2(float(shifts))));\n}\n\nint bitwiseZeroFillRightShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n /= 2;\n }\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\nvec2 integerMod(vec2 x, float y) {\n vec2 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec3 integerMod(vec3 x, float y) {\n vec3 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec4 integerMod(vec4 x, vec4 y) {\n vec4 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nfloat integerMod(float x, float y) {\n float res = floor(mod(x, y));\n return res * (res > floor(y) - 1.0 ? 0.0 : 1.0);\n}\n\nint integerMod(int x, int y) {\n return x - (y * int(x / y));\n}\n\n// GLSL ES 1.00 accepts only a constant or a loop symbol inside an index\n// expression, so m[y][x] does not compile when y and x come from kernel\n// arguments -- the error is "Index expression can only contain const or loop\n// symbols". Loop counters are legal indices, so walk the matrix with them\n// instead. These are 2x2 to 4x4, so it costs at most sixteen comparisons.\nfloat getMatrix2(mat2 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 2; i++) {\n for (int j = 0; j < 2; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix3(mat3 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 3; i++) {\n for (int j = 0; j < 3; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix4(mat4 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 4; i++) {\n for (int j = 0; j < 4; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\n__DIVIDE_WITH_INTEGER_CHECK__;\n\n// Here be dragons!\n// DO NOT OPTIMIZE THIS CODE\n// YOU WILL BREAK SOMETHING ON SOMEBODY'S MACHINE\n// LEAVE IT AS IT IS, LEST YOU WASTE YOUR OWN TIME\n// Exact powers of two built from exact constant multiplies: exp2/log2/pow\n// are approximate on some GPUs (notably Apple silicon), and 1-2 ulp there\n// corrupts the packed bytes (#659)\nfloat _pow2(float e) {\n float r = 1.0;\n float a = abs(e);\n bool n = e < 0.0;\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 32.0) { r *= n ? 2.3283064365386963e-10 : 4294967296.0; a -= 32.0; }\n if (a >= 16.0) { r *= n ? 0.0000152587890625 : 65536.0; a -= 16.0; }\n if (a >= 8.0) { r *= n ? 0.00390625 : 256.0; a -= 8.0; }\n if (a >= 4.0) { r *= n ? 0.0625 : 16.0; a -= 4.0; }\n if (a >= 2.0) { r *= n ? 0.25 : 4.0; a -= 2.0; }\n if (a >= 1.0) { r *= n ? 0.5 : 2.0; }\n return r;\n}\nconst vec2 MAGIC_VEC = vec2(1.0, -256.0);\nconst vec4 SCALE_FACTOR = vec4(1.0, 256.0, 65536.0, 0.0);\nconst vec4 SCALE_FACTOR_INV = vec4(1.0, 0.00390625, 0.0000152587890625, 0.0); // 1, 1/256, 1/65536\nfloat decode32(vec4 texel) {\n __DECODE32_ENDIANNESS__;\n texel *= 255.0;\n vec2 gte128;\n gte128.x = texel.b >= 128.0 ? 1.0 : 0.0;\n gte128.y = texel.a >= 128.0 ? 1.0 : 0.0;\n float exponent = 2.0 * texel.a - 127.0 + dot(gte128, MAGIC_VEC);\n float res = _pow2(_round(exponent));\n texel.b = texel.b - 128.0 * gte128.x;\n res = dot(texel, SCALE_FACTOR) * _pow2(_round(exponent-23.0)) + res;\n res *= gte128.y * -2.0 + 1.0;\n return res;\n}\n\nfloat decode16(vec4 texel, int index) {\n int channel = integerMod(index, 2);\n if (channel == 0) return texel.r * 255.0 + texel.g * 65280.0;\n if (channel == 1) return texel.b * 255.0 + texel.a * 65280.0;\n return 0.0;\n}\n\nfloat decode8(vec4 texel, int index) {\n int channel = integerMod(index, 4);\n if (channel == 0) return texel.r * 255.0;\n if (channel == 1) return texel.g * 255.0;\n if (channel == 2) return texel.b * 255.0;\n if (channel == 3) return texel.a * 255.0;\n return 0.0;\n}\n\nvec4 legacyEncode32(float f) {\n float F = abs(f);\n float sign = f < 0.0 ? 1.0 : 0.0;\n float exponent = floor(log2(F));\n float mantissa = (exp2(-exponent) * F);\n // exponent += floor(log2(mantissa));\n vec4 texel = vec4(F * exp2(23.0-exponent)) * SCALE_FACTOR_INV;\n texel.rg = integerMod(texel.rg, 256.0);\n texel.b = integerMod(texel.b, 128.0);\n texel.a = exponent*0.5 + 63.5;\n texel.ba += vec2(integerMod(exponent+127.0, 2.0), sign) * 128.0;\n texel = floor(texel);\n texel *= 0.003921569; // 1/255\n __ENCODE32_ENDIANNESS__;\n return texel;\n}\n\n// https://github.com/gpujs/gpu.js/wiki/Encoder-details\nvec4 encode32(float value) {\n if (value == 0.0) return vec4(0, 0, 0, 0);\n\n float exponent;\n float mantissa;\n vec4 result;\n float sgn;\n\n sgn = step(0.0, -value);\n value = abs(value);\n\n exponent = floor(log2(value));\n float p2 = _pow2(exponent);\n // approximate log2 can land one off; correct by direct comparison\n if (p2 > value) { exponent -= 1.0; p2 *= 0.5; }\n else if (p2 * 2.0 <= value) { exponent += 1.0; p2 *= 2.0; }\n\n mantissa = value / p2 - 1.0;\n exponent = exponent+127.0;\n result = vec4(0,0,0,0);\n\n result.a = floor(exponent/2.0);\n exponent = exponent - result.a*2.0;\n result.a = result.a + 128.0*sgn;\n\n result.b = floor(mantissa * 128.0);\n mantissa = mantissa - result.b / 128.0;\n result.b = result.b + exponent*128.0;\n\n result.g = floor(mantissa*32768.0);\n mantissa = mantissa - result.g/32768.0;\n\n result.r = floor(mantissa*8388608.0);\n return result/255.0;\n}\n// Dragons end here\n\nint index;\nivec3 threadId;\n\nivec3 indexTo3D(int idx, ivec3 texDim) {\n int z = int(idx / (texDim.x * texDim.y));\n idx -= z * int(texDim.x * texDim.y);\n int y = int(idx / texDim.x);\n int x = int(integerMod(idx, texDim.x));\n return ivec3(x, y, z);\n}\n\nfloat get32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n return decode32(texel);\n}\n\nfloat get16(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x * 2;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize.x * 2, texSize.y));\n return decode16(texel, index);\n}\n\nfloat get8(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x * 4;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize.x * 4, texSize.y));\n return decode8(texel, index);\n}\n\nfloat getMemoryOptimized32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 4);\n index = index / 4;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n if (channel == 0) return texel.r;\n if (channel == 1) return texel.g;\n if (channel == 2) return texel.b;\n if (channel == 3) return texel.a;\n return 0.0;\n}\n\nvec4 getImage2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n return texture2D(tex, st / vec2(texSize));\n}\n\nfloat getFloatFromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return result[0];\n}\n\nvec2 getVec2FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec2(result[0], result[1]);\n}\n\nvec2 getMemoryOptimizedVec2(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int channel = integerMod(index, 2);\n index = index / 2;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n if (channel == 0) return vec2(texel.r, texel.g);\n if (channel == 1) return vec2(texel.b, texel.a);\n return vec2(0.0, 0.0);\n}\n\nvec3 getVec3FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec3(result[0], result[1], result[2]);\n}\n\nvec3 getMemoryOptimizedVec3(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int fieldIndex = 3 * (x + texDim.x * (y + texDim.y * z));\n int vectorIndex = fieldIndex / 4;\n int vectorOffset = fieldIndex - vectorIndex * 4;\n int readY = vectorIndex / texSize.x;\n int readX = vectorIndex - readY * texSize.x;\n vec4 tex1 = texture2D(tex, (vec2(readX, readY) + 0.5) / vec2(texSize));\n \n if (vectorOffset == 0) {\n return tex1.xyz;\n } else if (vectorOffset == 1) {\n return tex1.yzw;\n } else {\n readX++;\n if (readX >= texSize.x) {\n readX = 0;\n readY++;\n }\n vec4 tex2 = texture2D(tex, vec2(readX, readY) / vec2(texSize));\n if (vectorOffset == 2) {\n return vec3(tex1.z, tex1.w, tex2.x);\n } else {\n return vec3(tex1.w, tex2.x, tex2.y);\n }\n }\n}\n\nvec4 getVec4FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n return getImage2D(tex, texSize, texDim, z, y, x);\n}\n\nvec4 getMemoryOptimizedVec4(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 2);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n return vec4(texel.r, texel.g, texel.b, texel.a);\n}\n\nvec4 actualColor;\nvoid color(float r, float g, float b, float a) {\n actualColor = vec4(r,g,b,a);\n}\n\nvoid color(float r, float g, float b) {\n color(r,g,b,1.0);\n}\n\nvoid color(sampler2D image) {\n actualColor = texture2D(image, vTexCoord);\n}\n\nfloat modulo(float number, float divisor) {\n if (number < 0.0) {\n number = abs(number);\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return -mod(number, divisor);\n }\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return mod(number, divisor);\n}\n\n__INJECTED_NATIVE__;\n__MAIN_CONSTANTS__;\n__MAIN_ARGUMENTS__;\n__KERNEL__;\n\nvoid main(void) {\n index = int(vTexCoord.s * float(uTexSize.x)) + int(vTexCoord.t * float(uTexSize.y)) * uTexSize.x;\n __MAIN_RESULT__;\n}`}}),N=e((e,t)=>{t.exports={vertexShader:"__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n\nattribute vec2 aPos;\nattribute vec2 aTexCoord;\n\nvarying vec2 vTexCoord;\nuniform vec2 ratio;\n\nvoid main(void) {\n gl_Position = vec4((aPos + vec2(1)) * ratio + vec2(-1), 0, 1);\n vTexCoord = aTexCoord;\n}"}}),O=e((e,t)=>{function r(e,t={}){const{contextName:r="gl",throwGetError:a,useTrackablePrimitives:o,recording:u=[],variables:l={},onReadPixels:h,onUnrecognizedArgumentLookup:c}=t,p=new Proxy(e,{get:function(t,p){switch(p){case"addComment":return A;case"checkThrowError":return w;case"getReadPixelsVariableName":return f;case"insertVariable":return b;case"reset":return x;case"setIndent":return v;case"toString":return y;case"getContextVariableName":return I}return"function"==typeof e[p]?function(){switch(p){case"getError":return a?u.push(`${g}if (${r}.getError() !== ${r}.NONE) throw new Error('error');`):u.push(`${g}${r}.getError();`),e.getError();case"getExtension":{const t=`${r}Variables${d.length}`;u.push(`${g}const ${t} = ${r}.getExtension('${arguments[0]}');`);const s=e.getExtension(arguments[0]);if(s&&"object"==typeof s){const e=n(s,{getEntity:T,useTrackablePrimitives:o,recording:u,contextName:t,contextVariables:d,variables:l,indent:g,onUnrecognizedArgumentLookup:c});return d.push(e),e}return d.push(null),s}case"readPixels":const t=d.indexOf(arguments[6]);let i;if(-1===t){const e=function(e){if(l)for(const t in l)if(l[t]===e)return t;return null}(arguments[6]);e?(i=e,u.push(`${g}${e}`)):(i=`${r}Variable${d.length}`,d.push(arguments[6]),u.push(`${g}const ${i} = new ${arguments[6].constructor.name}(${arguments[6].length});`))}else i=`${r}Variable${t}`;f=i;const p=[arguments[0],arguments[1],arguments[2],arguments[3],T(arguments[4]),T(arguments[5]),i];return u.push(`${g}${r}.readPixels(${p.join(", ")});`),h&&h(i,p),e.readPixels.apply(e,arguments);case"drawBuffers":return u.push(`${g}${r}.drawBuffers([${s(arguments[0],{contextName:r,contextVariables:d,getEntity:T,addVariable:S,variables:l,onUnrecognizedArgumentLookup:c})}]);`),e.drawBuffers(arguments[0])}let t=e[p].apply(e,arguments);switch(typeof t){case"undefined":return void u.push(`${g}${E(p,arguments)};`);case"number":case"boolean":if(o&&-1===d.indexOf(i(t))){u.push(`${g}const ${r}Variable${d.length} = ${E(p,arguments)};`),d.push(t=i(t));break}default:null===t?u.push(`${E(p,arguments)};`):u.push(`${g}const ${r}Variable${d.length} = ${E(p,arguments)};`),d.push(t)}return t}:(m[e[p]]=p,e[p])}}),d=[],m={};let f,g="";return p;function y(){return u.join("\n")}function x(){for(;u.length>0;)u.pop()}function b(e,t){l[e]=t}function T(e){const t=m[e];return t?r+"."+t:e}function v(e){g=" ".repeat(e)}function S(e,t){const n=`${r}Variable${d.length}`;return u.push(`${g}const ${n} = ${t};`),d.push(e),n}function A(e){u.push(`${g}// ${e}`)}function w(){u.push(`${g}(() => {\n${g}const error = ${r}.getError();\n${g}if (error !== ${r}.NONE) {\n${g} const names = Object.getOwnPropertyNames(gl);\n${g} for (let i = 0; i < names.length; i++) {\n${g} const name = names[i];\n${g} if (${r}[name] === error) {\n${g} throw new Error('${r} threw ' + name);\n${g} }\n${g} }\n${g}}\n${g}})();`)}function E(e,t){return`${r}.${e}(${s(t,{contextName:r,contextVariables:d,getEntity:T,addVariable:S,variables:l,onUnrecognizedArgumentLookup:c})})`}function I(e){const t=d.indexOf(e);return-1!==t?`${r}Variable${t}`:null}}function n(e,t){const r=new Proxy(e,{get:function(t,r){return"function"==typeof t[r]?function(){if("drawBuffersWEBGL"===r)return h.push(`${p}${a}.drawBuffersWEBGL([${s(arguments[0],{contextName:a,contextVariables:o,getEntity:m,addVariable:g,variables:c,onUnrecognizedArgumentLookup:d})}]);`),e.drawBuffersWEBGL(arguments[0]);let t=e[r].apply(e,arguments);switch(typeof t){case"undefined":return void h.push(`${p}${f(r,arguments)};`);case"number":case"boolean":l&&-1===o.indexOf(i(t))?(h.push(`${p}const ${a}Variable${o.length} = ${f(r,arguments)};`),o.push(t=i(t))):(h.push(`${p}const ${a}Variable${o.length} = ${f(r,arguments)};`),o.push(t));break;default:null===t?h.push(`${f(r,arguments)};`):h.push(`${p}const ${a}Variable${o.length} = ${f(r,arguments)};`),o.push(t)}return t}:(n[e[r]]=r,e[r])}}),n={},{contextName:a,contextVariables:o,getEntity:u,useTrackablePrimitives:l,recording:h,variables:c,indent:p,onUnrecognizedArgumentLookup:d}=t;return r;function m(e){return n.hasOwnProperty(e)?`${a}.${n[e]}`:u(e)}function f(e,t){return`${a}.${e}(${s(t,{contextName:a,contextVariables:o,getEntity:m,addVariable:g,variables:c,onUnrecognizedArgumentLookup:d})})`}function g(e,t){const r=`${a}Variable${o.length}`;return o.push(e),h.push(`${p}const ${r} = ${t};`),r}}function s(e,t){const{variables:r,onUnrecognizedArgumentLookup:n}=t;return Array.from(e).map(e=>{const s=function(e){if(r)for(const t in r)if(r.hasOwnProperty(t)&&r[t]===e)return t;return n?n(e):null}(e);return s||function(e,t){const{contextName:r,contextVariables:n,getEntity:s,addVariable:i,onUnrecognizedArgumentLookup:a}=t;if(void 0===e)return"undefined";if(null===e)return"null";const o=n.indexOf(e);if(o>-1)return`${r}Variable${o}`;switch(e.constructor.name){case"String":const t=/\n/.test(e),r=/'/.test(e),n=/"/.test(e);return t?"`"+e+"`":r&&!n?'"'+e+'"':"'"+e+"'";case"Number":case"Boolean":return s(e);case"Array":return i(e,`new ${e.constructor.name}([${Array.from(e).join(",")}])`);case"Float32Array":case"Uint8Array":case"Uint16Array":case"Int32Array":return i(e,`new ${e.constructor.name}(${JSON.stringify(Array.from(e))})`);default:if(a){const t=a(e);if(t)return t}throw new Error(`unrecognized argument type ${e.constructor.name}`)}}(e,t)}).join(", ")}function i(e){return new e.constructor(e)}void 0!==t&&(t.exports={glWiretap:r,glExtensionWiretap:n}),"undefined"!=typeof window&&(r.glExtensionWiretap=n,window.glWiretap=r)}),z=e((e,t)=>{const{glWiretap:r}=O(),{utils:n}=i();function s(e){let t=e.toString().replace(/^function /,"");const r=t.indexOf("=>");if(-1!==r&&!/[{]|\bfunction\b/.test(t.slice(0,r))){const e=t.slice(0,r).trim(),n=t.slice(r+2).trim();t=n.startsWith("{")?`${e} ${n}`:`${e} { return ${n}; }`}return t.replace(/utils[.]/g,"/*utils.*/")}function a(e,t){const r="single"===t.precision?e:`new Float32Array(${e}.buffer)`;return t.output[2]?`renderOutput(${r}, ${t.output[0]}, ${t.output[1]}, ${t.output[2]})`:t.output[1]?`renderOutput(${r}, ${t.output[0]}, ${t.output[1]})`:`renderOutput(${r}, ${t.output[0]})`}function o(e,t){const r=e.toArray.toString(),s=!/^function/.test(r);return`() => {\n function framebuffer() { return getReadFramebuffer(); };\n ${n.flattenFunctionToString(`${s?"function ":""}${r}`,{findDependency:(t,r)=>{if("utils"===t)return`const ${r} = ${n[r].toString()};`;if("this"===t)return"framebuffer"===r?"":`${s?"function ":""}${e[r].toString()}`;throw new Error("unhandled fromObject")},thisLookup:(r,n)=>{if("texture"===r)return t;if("context"===r)return n?null:"gl";if(e.hasOwnProperty(r))return JSON.stringify(e[r]);throw new Error(`unhandled thisLookup ${r}`)}})}\n return toArray();\n }`}function u(e,t,r,n,s){if(null===e)return null;if(null===t)return null;switch(typeof e){case"boolean":case"number":return null}if("undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement)for(let s=0;s{switch(typeof e){case"boolean":return new Boolean(e);case"number":return new Number(e);default:return e}}):null;const c=[],p=[],d=r(i.context,{useTrackablePrimitives:!0,onReadPixels:e=>{if(R.subKernels){if(m){const t=R.subKernels[f++].property;p.push(` result${isNaN(t)?"."+t:`[${t}]`} = ${a(e,R)};`)}else p.push(` const result = { result: ${a(e,R)} };`),m=!0;f===R.subKernels.length&&p.push(" return result;")}else e?p.push(` return ${a(e,R)};`):p.push(" return null;")},onUnrecognizedArgumentLookup:e=>{const t=u(e,R.kernelArguments,[],d,c);if(t)return t;const r=u(e,R.kernelConstants,S?Object.keys(S).map(e=>S[e]):[],d,c);return r||null}});let m=!1,f=0;const{source:g,canvas:y,output:x,pipeline:b,graphical:T,loopMaxIterations:v,constants:S,optimizeFloatMemory:A,precision:w,fixIntegerDivisionAccuracy:E,functions:I,nativeFunctions:_,subKernels:L,immutable:F,argumentTypes:k,constantTypes:$,kernelArguments:D,kernelConstants:C,tactic:G}=i,R=new e(g,{canvas:y,context:d,checkContext:!1,output:x,pipeline:b,graphical:T,loopMaxIterations:v,constants:S,optimizeFloatMemory:A,precision:w,fixIntegerDivisionAccuracy:E,functions:I,nativeFunctions:_,subKernels:L,immutable:F,argumentTypes:k,constantTypes:$,tactic:G});let M=[];if(d.setIndent(2),R.build.apply(R,t),M.push(d.toString()),d.reset(),R.kernelArguments.forEach((e,r)=>{switch(e.type){case"Integer":case"Boolean":case"Number":case"Float":case"Array":case"Array(2)":case"Array(3)":case"Array(4)":case"HTMLCanvas":case"HTMLImage":case"HTMLVideo":case"Input":d.insertVariable(`uploadValue_${e.name}`,e.uploadValue);break;case"HTMLImageArray":for(let n=0;ne.varName).join(", ")}) {`),d.setIndent(4),R.run.apply(R,t),R.renderKernels?R.renderKernels():R.renderOutput&&R.renderOutput(),M.push(" /** start setup uploads for kernel values **/"),R.kernelArguments.forEach(e=>{M.push(" "+e.getStringValueHandler().split("\n").join("\n "))}),M.push(" /** end setup uploads for kernel values **/"),M.push(d.toString()),R.renderOutput===R.renderTexture)if(d.reset(),R.renderKernels){const e=R.renderKernels(),t=d.getContextVariableName(R.texture.texture);M.push(` return {\n result: {\n texture: ${t},\n type: '${e.result.type}',\n toArray: ${o(e.result,t)}\n },`);const{subKernels:r,mappedTextures:n}=R;for(let t=0;t"utils"===e?`const ${t} = ${n[t].toString()};`:null,thisLookup:t=>{if("context"===t)return null;if(e.hasOwnProperty(t))return JSON.stringify(e[t]);throw new Error(`unhandled thisLookup ${t}`)}})}(R)),M.push(" innerKernel.getPixels = getPixels;")),M.push(" return innerKernel;");let N=[];return C.forEach(e=>{N.push(`${e.getStringValueHandler()}`)}),`function kernel(settings) {\n const { context, constants } = settings;\n ${N.join("")}\n ${l||""}\n${M.join("\n")}\n}`}}}),V=e((e,t)=>{t.exports={KernelValue:class{constructor(e,t){const{name:r,kernel:n,context:s,checkContext:i,onRequestContextHandle:a,onUpdateValueMismatch:o,origin:u,strictIntegers:l,type:h,tactic:c}=t;if(!r)throw new Error("name not set");if(!h)throw new Error("type not set");if(!u)throw new Error("origin not set");if("user"!==u&&"constants"!==u)throw new Error(`origin must be "user" or "constants" value is "${u}"`);if(!a)throw new Error("onRequestContextHandle is not set");this.name=r,this.origin=u,this.tactic=c,this.varName="constants"===u?`constants.${r}`:r,this.kernel=n,this.strictIntegers=l,this.type=e.type||h,this.size=e.size||null,this.index=null,this.context=s,this.checkContext=null==i||i,this.contextHandle=null,this.onRequestContextHandle=a,this.onUpdateValueMismatch=o,this.forceUploadEachRun=null}get id(){return`${this.origin}_${name}`}getSource(){throw new Error(`"getSource" not defined on ${this.constructor.name}`)}updateValue(e){throw new Error(`"updateValue" not defined on ${this.constructor.name}`)}}}}),U=e((e,t)=>{const{utils:r}=i(),{KernelValue:n}=V();t.exports={WebGLKernelValue:class extends n{constructor(e,t){super(e,t),this.dimensionsId=null,this.sizeId=null,this.initialValueConstructor=e.constructor,this.onRequestTexture=t.onRequestTexture,this.onRequestIndex=t.onRequestIndex,this.uploadValue=null,this.textureSize=null,this.bitRatio=null,this.prevArg=null}get id(){return`${this.origin}_${r.sanitizeName(this.name)}`}setup(){}rebind(){}getTransferArrayType(e){if(Array.isArray(e[0]))return this.getTransferArrayType(e[0]);switch(e.constructor){case Array:case Int32Array:case Int16Array:case Int8Array:return Float32Array;case Uint8ClampedArray:case Uint8Array:case Uint16Array:case Uint32Array:case Float32Array:case Float64Array:return e.constructor}return console.warn("Unfamiliar constructor type. Will go ahead and use, but likley this may result in a transfer of zeros"),e.constructor}getStringValueHandler(){throw new Error(`"getStringValueHandler" not implemented on ${this.constructor.name}`)}getVariablePrecisionString(){return this.kernel.getVariablePrecisionString(this.textureSize||void 0,this.tactic||void 0)}destroy(){}}}}),B=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValue:n}=U();t.exports={WebGLKernelValueBoolean:class extends n{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const bool ${this.id} = ${e};\n`:`uniform bool ${this.id};\n`}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1i(this.id,this.uploadValue=e)}}}}),K=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValue:n}=U();t.exports={WebGLKernelValueFloat:class extends n{constructor(e,t){super(e,t),this.uploadValue=e}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(e){return"constants"===this.origin?Number.isInteger(e)?`const float ${this.id} = ${e}.0;\n`:`const float ${this.id} = ${e};\n`:`uniform float ${this.id};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1f(this.id,this.uploadValue=e)}}}}),P=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValue:n}=U();t.exports={WebGLKernelValueInteger:class extends n{constructor(e,t){super(e,t),this.uploadValue=e}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(e){return"constants"===this.origin?`const int ${this.id} = ${parseInt(e)};\n`:`uniform int ${this.id};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1i(this.id,this.uploadValue=e)}}}}),W=e((e,t)=>{const{WebGLKernelValue:r}=U(),{Input:s}=n();t.exports={WebGLKernelArray:class extends r{rebind(){if(!this.texture||void 0===this.contextHandle||null===this.contextHandle)return;const{context:e}=this;e.activeTexture(this.contextHandle),e.bindTexture(e.TEXTURE_2D,this.texture)}checkSize(e,t){if(!this.kernel.validate)return;const{maxTextureSize:r}=this.kernel.constructor.features;if(e>r||t>r)throw e>t?new Error(`Argument texture width of ${e} larger than maximum size of ${r} for your GPU`):e{const{utils:r}=i(),{WebGLKernelArray:n}=W();function s(e){return{width:e.width>0?e.width:e.videoWidth,height:e.height>0?e.height:e.videoHeight}}t.exports={WebGLKernelValueHTMLImage:class extends n{constructor(e,t){super(e,t);const{width:r,height:n}=s(e);this.checkSize(r,n),this.dimensions=[r,n,1],this.textureSize=[r,n],this.uploadValue=e}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!0),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,this.uploadValue=e),this.kernel.setUniform1i(this.id,this.index)}},mediaSize:s}}),q=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueHTMLImage:n,mediaSize:s}=j();t.exports={WebGLKernelValueDynamicHTMLImage:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){const{width:t,height:r}=s(e);this.checkSize(t,r),this.dimensions=[t,r,1],this.textureSize=[t,r],this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),X=e((e,t)=>{const{WebGLKernelValueHTMLImage:r}=j();t.exports={WebGLKernelValueHTMLVideo:class extends r{}}}),H=e((e,t)=>{const{WebGLKernelValueDynamicHTMLImage:r}=q();t.exports={WebGLKernelValueDynamicHTMLVideo:class extends r{}}}),Y=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGLKernelValueSingleInput:class extends n{constructor(e,t){super(e,t),this.bitRatio=4;let[n,s,i]=e.size;this.dimensions=new Int32Array([n||1,s||1,i||1]),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}.value, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e.value,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Z=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleInput:n}=Y();t.exports={WebGLKernelValueDynamicSingleInput:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){let[t,n,s]=e.size;this.dimensions=new Int32Array([t||1,n||1,s||1]),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),J=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGLKernelValueUnsignedInput:class extends n{constructor(e,t){super(e,t),this.bitRatio=this.getBitRatio(e);const[n,s,i]=e.size;this.dimensions=new Int32Array([n||1,s||1,i||1]),this.textureSize=r.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]),this.TranserArrayType=this.getTransferArrayType(e.value),this.preUploadValue=new this.TranserArrayType(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer)}getStringValueHandler(){return r.linesToString([`const preUploadValue_${this.name} = new ${this.TranserArrayType.name}(${this.uploadArrayLength})`,`const uploadValue_${this.name} = new Uint8Array(preUploadValue_${this.name}.buffer)`,`flattenTo(${this.varName}.value, preUploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(value.constructor);const{context:t}=this;r.flattenTo(e.value,this.preUploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.UNSIGNED_BYTE,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Q=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueUnsignedInput:n}=J();t.exports={WebGLKernelValueDynamicUnsignedInput:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){let[t,n,s]=e.size;this.dimensions=new Int32Array([t||1,n||1,s||1]),this.textureSize=r.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]);const i=this.getTransferArrayType(e.value);this.preUploadValue=new i(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ee=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W(),s="Source and destination textures are the same. Use immutable = true and manually cleanup kernel output texture memory with texture.delete()";t.exports={WebGLKernelValueMemoryOptimizedNumberTexture:class extends n{constructor(e,t){super(e,t);const[r,n]=e.size;this.checkSize(r,n),this.dimensions=e.dimensions,this.textureSize=e.size,this.uploadValue=e.texture,this.forceUploadEachRun=!0}setup(){this.setupTexture()}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName}.texture;\n`}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);if(this.checkContext&&e.context!==this.context)throw new Error(`Value ${this.name} (${this.type}) must be from same context`);const{kernel:t,context:r}=this;if(t.pipeline)if(t.immutable)t.updateTextureArgumentRefs(this,e);else{if(t.texture&&t.texture.texture===e.texture)throw new Error(s);if(t.mappedTextures){const{mappedTextures:r}=t;for(let t=0;t{const{utils:r}=i(),{WebGLKernelValueMemoryOptimizedNumberTexture:n}=ee();t.exports={WebGLKernelValueDynamicMemoryOptimizedNumberTexture:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=e.dimensions,this.checkSize(e.size[0],e.size[1]),this.textureSize=e.size,this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),re=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W(),{sameError:s}=ee();t.exports={WebGLKernelValueNumberTexture:class extends n{constructor(e,t){super(e,t);const[r,n]=e.size;this.checkSize(r,n);const{size:s,dimensions:i}=e;this.bitRatio=this.getBitRatio(e),this.dimensions=i,this.textureSize=s,this.uploadValue=e.texture,this.forceUploadEachRun=!0}setup(){this.setupTexture()}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName}.texture;\n`}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);if(this.checkContext&&e.context!==this.context)throw new Error(`Value ${this.name} (${this.type}) must be from same context`);const{kernel:t,context:r}=this;if(t.pipeline)if(t.immutable)t.updateTextureArgumentRefs(this,e);else{if(t.texture&&t.texture.texture===e.texture)throw new Error(s);if(t.mappedTextures){const{mappedTextures:r}=t;for(let t=0;t{const{utils:r}=i(),{WebGLKernelValueNumberTexture:n}=re();t.exports={WebGLKernelValueDynamicNumberTexture:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=e.dimensions,this.checkSize(e.size[0],e.size[1]),this.textureSize=e.size,this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),se=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGLKernelValueSingleArray:class extends n{constructor(e,t){super(e,t),this.bitRatio=4,this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(!r.isArray(e))return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),ie=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray:n}=se();t.exports={WebGLKernelValueDynamicSingleArray:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ae=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGLKernelValueSingleArray1DI:class extends n{constructor(e,t){super(e,t),this.bitRatio=4,this.setShape(e)}setShape(e){const t=r.getDimensions(e,!0);this.textureSize=r.getMemoryOptimizedFloatTextureSize(t,this.bitRatio),this.dimensions=new Int32Array([t[1],1,1]),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flatten2dArrayTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),oe=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray1DI:n}=ae();t.exports={WebGLKernelValueDynamicSingleArray1DI:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ue=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGLKernelValueSingleArray2DI:class extends n{constructor(e,t){super(e,t),this.bitRatio=4,this.setShape(e)}setShape(e){const t=r.getDimensions(e,!0);this.textureSize=r.getMemoryOptimizedFloatTextureSize(t,this.bitRatio),this.dimensions=new Int32Array([t[1],t[2],1]),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flatten3dArrayTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),le=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray2DI:n}=ue();t.exports={WebGLKernelValueDynamicSingleArray2DI:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),he=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGLKernelValueSingleArray3DI:class extends n{constructor(e,t){super(e,t),this.bitRatio=4,this.setShape(e)}setShape(e){const t=r.getDimensions(e,!0);this.textureSize=r.getMemoryOptimizedFloatTextureSize(t,this.bitRatio),this.dimensions=new Int32Array([t[1],t[2],t[3]]),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flatten4dArrayTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),ce=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray3DI:n}=he();t.exports={WebGLKernelValueDynamicSingleArray3DI:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),pe=e((e,t)=>{const{WebGLKernelValue:r}=U();t.exports={WebGLKernelValueArray2:class extends r{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const vec2 ${this.id} = vec2(${e[0]},${e[1]});\n`:`uniform vec2 ${this.id};\n`}getStringValueHandler(){return"constants"===this.origin?"":`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform2fv(this.id,this.uploadValue=e)}}}}),de=e((e,t)=>{const{WebGLKernelValue:r}=U();t.exports={WebGLKernelValueArray3:class extends r{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const vec3 ${this.id} = vec3(${e[0]},${e[1]},${e[2]});\n`:`uniform vec3 ${this.id};\n`}getStringValueHandler(){return"constants"===this.origin?"":`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform3fv(this.id,this.uploadValue=e)}}}}),me=e((e,t)=>{const{WebGLKernelValue:r}=U();t.exports={WebGLKernelValueArray4:class extends r{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const vec4 ${this.id} = vec4(${e[0]},${e[1]},${e[2]},${e[3]});\n`:`uniform vec4 ${this.id};\n`}getStringValueHandler(){return"constants"===this.origin?"":`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform4fv(this.id,this.uploadValue=e)}}}}),fe=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGLKernelValueUnsignedArray:class extends n{constructor(e,t){super(e,t),this.bitRatio=this.getBitRatio(e),this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]),this.TranserArrayType=this.getTransferArrayType(e),this.preUploadValue=new this.TranserArrayType(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer)}getStringValueHandler(){return r.linesToString([`const preUploadValue_${this.name} = new ${this.TranserArrayType.name}(${this.uploadArrayLength})`,`const uploadValue_${this.name} = new Uint8Array(preUploadValue_${this.name}.buffer)`,`flattenTo(${this.varName}, preUploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(!r.isArray(e))return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.preUploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.UNSIGNED_BYTE,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),ge=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueUnsignedArray:n}=fe();t.exports={WebGLKernelValueDynamicUnsignedArray:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]);const t=this.getTransferArrayType(e);this.preUploadValue=new t(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ye=e((e,t)=>{const{WebGLKernelValueBoolean:r}=B(),{WebGLKernelValueFloat:n}=K(),{WebGLKernelValueInteger:s}=P(),{WebGLKernelValueHTMLImage:i}=j(),{WebGLKernelValueDynamicHTMLImage:a}=q(),{WebGLKernelValueHTMLVideo:o}=X(),{WebGLKernelValueDynamicHTMLVideo:u}=H(),{WebGLKernelValueSingleInput:l}=Y(),{WebGLKernelValueDynamicSingleInput:h}=Z(),{WebGLKernelValueUnsignedInput:c}=J(),{WebGLKernelValueDynamicUnsignedInput:p}=Q(),{WebGLKernelValueMemoryOptimizedNumberTexture:d}=ee(),{WebGLKernelValueDynamicMemoryOptimizedNumberTexture:m}=te(),{WebGLKernelValueNumberTexture:f}=re(),{WebGLKernelValueDynamicNumberTexture:g}=ne(),{WebGLKernelValueSingleArray:y}=se(),{WebGLKernelValueDynamicSingleArray:x}=ie(),{WebGLKernelValueSingleArray1DI:b}=ae(),{WebGLKernelValueDynamicSingleArray1DI:T}=oe(),{WebGLKernelValueSingleArray2DI:v}=ue(),{WebGLKernelValueDynamicSingleArray2DI:S}=le(),{WebGLKernelValueSingleArray3DI:A}=he(),{WebGLKernelValueDynamicSingleArray3DI:w}=ce(),{WebGLKernelValueArray2:E}=pe(),{WebGLKernelValueArray3:I}=de(),{WebGLKernelValueArray4:_}=me(),{WebGLKernelValueUnsignedArray:L}=fe(),{WebGLKernelValueDynamicUnsignedArray:F}=ge(),k={unsigned:{dynamic:{Boolean:r,Integer:s,Float:n,Array:F,"Array(2)":E,"Array(3)":I,"Array(4)":_,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:p,NumberTexture:g,"ArrayTexture(1)":g,"ArrayTexture(2)":g,"ArrayTexture(3)":g,"ArrayTexture(4)":g,MemoryOptimizedNumberTexture:m,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:!1,HTMLVideo:u},static:{Boolean:r,Float:n,Integer:s,Array:L,"Array(2)":E,"Array(3)":I,"Array(4)":_,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:c,NumberTexture:f,"ArrayTexture(1)":f,"ArrayTexture(2)":f,"ArrayTexture(3)":f,"ArrayTexture(4)":f,MemoryOptimizedNumberTexture:d,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:!1,HTMLVideo:o}},single:{dynamic:{Boolean:r,Integer:s,Float:n,Array:x,"Array(2)":E,"Array(3)":I,"Array(4)":_,"Array1D(2)":T,"Array1D(3)":T,"Array1D(4)":T,"Array2D(2)":S,"Array2D(3)":S,"Array2D(4)":S,"Array3D(2)":w,"Array3D(3)":w,"Array3D(4)":w,Input:h,NumberTexture:g,"ArrayTexture(1)":g,"ArrayTexture(2)":g,"ArrayTexture(3)":g,"ArrayTexture(4)":g,MemoryOptimizedNumberTexture:m,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:!1,HTMLVideo:u},static:{Boolean:r,Float:n,Integer:s,Array:y,"Array(2)":E,"Array(3)":I,"Array(4)":_,"Array1D(2)":b,"Array1D(3)":b,"Array1D(4)":b,"Array2D(2)":v,"Array2D(3)":v,"Array2D(4)":v,"Array3D(2)":A,"Array3D(3)":A,"Array3D(4)":A,Input:l,NumberTexture:f,"ArrayTexture(1)":f,"ArrayTexture(2)":f,"ArrayTexture(3)":f,"ArrayTexture(4)":f,MemoryOptimizedNumberTexture:d,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:!1,HTMLVideo:o}}};t.exports={lookupKernelValueType:function(e,t,r,n){if(!e)throw new Error("type missing");if(!t)throw new Error("dynamic missing");if(!r)throw new Error("precision missing");n.type&&(e=n.type);const s=k[r][t];if("WebGPUBuffer"===e)throw new Error("this kernel runs on WebGL but received a WebGPU pipeline buffer; await handle.toArray() first, or give this kernel the async contract (asyncMode: true / mode: 'async') so the readback happens for you");if(!1===s[e])return null;if(void 0===s[e])throw new Error(`Could not find a KernelValue for ${e}`);return s[e]},kernelValueMaps:k}}),xe=e((e,t)=>{const{GLKernel:r}=C(),{FunctionBuilder:n}=o(),{WebGLFunctionNode:s}=G(),{utils:a}=i(),u=R(),{fragmentShader:l}=M(),{vertexShader:h}=N(),{glKernelString:c}=z(),{lookupKernelValueType:p}=ye();let d=null,m=null,f=null,g=null,y=null;const x=[u],b=[],T={};t.exports={WebGLKernel:class extends r{static get isSupported(){return null!==d||(this.setupFeatureChecks(),d=this.isContextMatch(f)),d}static setupFeatureChecks(){"undefined"!=typeof document?m=document.createElement("canvas"):"undefined"!=typeof OffscreenCanvas&&(m=new OffscreenCanvas(0,0)),m&&(f=m.getContext("webgl"),f||m instanceof OffscreenCanvas||(f=m.getContext("experimental-webgl")),f&&f.getExtension&&(g={OES_texture_float:f.getExtension("OES_texture_float"),OES_texture_float_linear:f.getExtension("OES_texture_float_linear"),OES_element_index_uint:f.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:f.getExtension("WEBGL_draw_buffers")},y=this.getFeatures()))}static isContextMatch(e){return"undefined"!=typeof WebGLRenderingContext&&e instanceof WebGLRenderingContext}static getIsTextureFloat(){return Boolean(g.OES_texture_float)}static getIsDrawBuffers(){return Boolean(g.WEBGL_draw_buffers)}static getChannelCount(){return g.WEBGL_draw_buffers?f.getParameter(g.WEBGL_draw_buffers.MAX_DRAW_BUFFERS_WEBGL):1}static getMaxTextureSize(){return f.getParameter(f.MAX_TEXTURE_SIZE)}static lookupKernelValueType(e,t,r,n){return p(e,t,r,n)}static get testCanvas(){return m}static get testContext(){return f}static get features(){return y}static get fragmentShader(){return l}static get vertexShader(){return h}constructor(e,t){super(e,t),this.program=null,this.pipeline=t.pipeline,this.endianness=a.systemEndianness(),this.extensions={},this.argumentTextureCount=0,this.constantTextureCount=0,this.fragShader=null,this.vertShader=null,this.drawBuffersMap=null,this.maxTexSize=null,this.onRequestSwitchKernel=null,this.texture=null,this.mappedTextures=null,this.mergeSettings(e.settings||t),this.threadDim=null,this.framebuffer=null,this.buffer=null,this.textureCache=[],this.programUniformLocationCache={},this.uniform1fCache={},this.uniform1iCache={},this.uniform2fCache={},this.uniform2fvCache={},this.uniform2ivCache={},this.uniform3fvCache={},this.uniform3ivCache={},this.uniform4fvCache={},this.uniform4ivCache={}}initCanvas(){if("undefined"!=typeof document){const e=document.createElement("canvas");return e.width=2,e.height=2,e}if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(0,0)}initContext(){const e={alpha:!1,depth:!1,antialias:!1};return this.canvas.getContext("webgl",e)||this.canvas.getContext("experimental-webgl",e)}initPlugins(e){const t=[],{source:r}=this;if("string"==typeof r)for(let e=0;ee===n.name)&&t.push(n)}return t}initExtensions(){this.extensions={OES_texture_float:this.context.getExtension("OES_texture_float"),OES_texture_float_linear:this.context.getExtension("OES_texture_float_linear"),OES_element_index_uint:this.context.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:this.context.getExtension("WEBGL_draw_buffers"),WEBGL_color_buffer_float:this.context.getExtension("WEBGL_color_buffer_float")}}validateSettings(e){if(!this.validate)return void(this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output));const{features:t}=this.constructor;if(!0===this.optimizeFloatMemory&&!t.isTextureFloat)throw new Error("Float textures are not supported");if("single"===this.precision&&!t.isFloatRead)throw new Error("Single precision not supported");if(this.graphical||null!==this.precision||(this.precision=t.isTextureFloat&&t.isFloatRead?"single":"unsigned"),this.subKernels&&this.subKernels.length>0&&!this.extensions.WEBGL_draw_buffers)throw new Error("could not instantiate draw buffers extension");if(null===this.fixIntegerDivisionAccuracy?this.fixIntegerDivisionAccuracy=!t.isIntegerDivisionAccurate:this.fixIntegerDivisionAccuracy&&t.isIntegerDivisionAccurate&&(this.fixIntegerDivisionAccuracy=!1),this.checkOutput(),!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=a.getVariableType(e[0],this.strictIntegers);switch(t){case"Array":this.output=a.getDimensions(t);break;case"NumberTexture":case"MemoryOptimizedNumberTexture":case"ArrayTexture(1)":case"ArrayTexture(2)":case"ArrayTexture(3)":case"ArrayTexture(4)":this.output=e[0].output;break;default:throw new Error("Auto output not supported for input type: "+t)}}if(this.graphical){if(2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");return"precision"===this.precision&&(this.precision="unsigned",console.warn("Cannot use graphical mode and single precision at the same time")),void(this.texSize=a.clone(this.output))}null===this.precision&&t.isTextureFloat&&(this.precision="single"),this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output),this.checkTextureSize()}updateMaxTexSize(){const{texSize:e,canvas:t}=this;if(null===this.maxTexSize){let r=b.indexOf(t);-1===r&&(r=b.length,b.push(t),T[r]=[e[0],e[1]]),this.maxTexSize=T[r]}this.maxTexSize[0]this.argumentNames.length)throw new Error("too many arguments for kernel");const{context:r}=this;let n=0;const s=()=>this.createTexture(),i=()=>this.constantTextureCount+n++,o=e=>{this.switchKernels({type:"argumentMismatch",needed:e})},u=()=>r.TEXTURE0+this.constantTextureCount+this.argumentTextureCount++;for(let n=0;nthis.createTexture(),onRequestIndex:()=>n++,onRequestContextHandle:()=>t.TEXTURE0+this.constantTextureCount++});this.constantBitRatios[s]=l.bitRatio,this.kernelConstants.push(l),l.setup(),l.forceUploadEachRun&&this.forceUploadKernelConstants.push(l)}}build(){if(this.built)return;if(this.initExtensions(),this.validateSettings(arguments),this.setupConstants(arguments),this.fallbackRequested)return;if(this.setupArguments(arguments),this.fallbackRequested)return;this.updateMaxTexSize(),this.translateSource();const e=this.pickRenderStrategy(arguments);if(e)return e;const{texSize:t,context:r,canvas:n}=this;r.enable(r.SCISSOR_TEST),this.pipeline&&this.precision,r.viewport(0,0,this.maxTexSize[0],this.maxTexSize[1]),n.width=this.maxTexSize[0],n.height=this.maxTexSize[1];const s=this.threadDim=Array.from(this.output);for(;s.length<3;)s.push(1);const i=this.getVertexShader(arguments),a=r.createShader(r.VERTEX_SHADER);r.shaderSource(a,i),r.compileShader(a),this.vertShader=a;const o=this.getFragmentShader(arguments),u=r.createShader(r.FRAGMENT_SHADER);if(r.shaderSource(u,o),r.compileShader(u),this.fragShader=u,this.debug&&(console.log("GLSL Shader Output:"),console.log(o)),!r.getShaderParameter(a,r.COMPILE_STATUS))throw new Error("Error compiling vertex shader: "+r.getShaderInfoLog(a));if(!r.getShaderParameter(u,r.COMPILE_STATUS))throw new Error("Error compiling fragment shader: "+r.getShaderInfoLog(u));const l=this.program=r.createProgram();r.attachShader(l,a),r.attachShader(l,u),r.linkProgram(l),this.framebuffer=r.createFramebuffer(),this.framebuffer.width=t[0],this.framebuffer.height=t[1],this.rawValueFramebuffers={};const h=new Float32Array([-1,-1,1,-1,-1,1,1,1]),c=new Float32Array([0,0,1,0,0,1,1,1]),p=h.byteLength;let d=this.buffer;d?r.bindBuffer(r.ARRAY_BUFFER,d):(d=this.buffer=r.createBuffer(),r.bindBuffer(r.ARRAY_BUFFER,d),r.bufferData(r.ARRAY_BUFFER,h.byteLength+c.byteLength,r.STATIC_DRAW)),r.bufferSubData(r.ARRAY_BUFFER,0,h),r.bufferSubData(r.ARRAY_BUFFER,p,c);const m=r.getAttribLocation(this.program,"aPos");-1!==m&&(r.enableVertexAttribArray(m),r.vertexAttribPointer(m,2,r.FLOAT,!1,0,0));const f=r.getAttribLocation(this.program,"aTexCoord");-1!==f&&(r.enableVertexAttribArray(f),r.vertexAttribPointer(f,2,r.FLOAT,!1,0,p)),r.bindFramebuffer(r.FRAMEBUFFER,this.framebuffer);let g=0;r.useProgram(this.program);for(let e in this.constants)this.kernelConstants[g++].updateValue(this.constants[e]);this._setupOutputTexture(),null!==this.subKernels&&this.subKernels.length>0&&(this._mappedTextureSwitched={},this._setupSubOutputTextures()),this.buildSignature(arguments),this.built=!0}translateSource(){const e=n.fromKernel(this,s,{fixIntegerDivisionAccuracy:this.fixIntegerDivisionAccuracy});this.translatedSource=e.getPrototypeString("kernel"),this.setupReturnTypes(e)}setupReturnTypes(e){if(this.graphical||this.returnType||(this.returnType=e.getKernelResultType()),this.subKernels&&this.subKernels.length>0)for(let t=0;te.source&&this.source.match(e.functionMatch)?e.source:"").join("\n"):"\n"}_getConstantsString(){const e=[],{threadDim:t,texSize:r}=this;return this.dynamicOutput?e.push("uniform ivec3 uOutputDim","uniform ivec2 uTexSize"):e.push(`ivec3 uOutputDim = ivec3(${t[0]}, ${t[1]}, ${t[2]})`,`ivec2 uTexSize = ivec2(${r[0]}, ${r[1]})`),a.linesToString(e)}_getTextureCoordinate(){const e=this.subKernels;return null===e||e.length<1?"varying vec2 vTexCoord;\n":"out vec2 vTexCoord;\n"}_getDecode32EndiannessString(){return"LE"===this.endianness?"":" texel.rgba = texel.abgr;\n"}_getEncode32EndiannessString(){return"LE"===this.endianness?"":" texel.rgba = texel.abgr;\n"}_getDivideWithIntegerCheckString(){return this.fixIntegerDivisionAccuracy?"float divWithIntCheck(float x, float y) {\n if (floor(x) == x && floor(y) == y) {\n float q = floor(x / y + 0.5);\n if (y * q == x) {\n return q;\n }\n }\n return x / y;\n}\n\nfloat integerCorrectionModulo(float number, float divisor) {\n if (number < 0.0) {\n number = abs(number);\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return -(number - (divisor * floor(divWithIntCheck(number, divisor))));\n }\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return number - (divisor * floor(divWithIntCheck(number, divisor)));\n}":""}_getMainArgumentsString(e){const t=[],{argumentNames:r}=this;for(let n=0;n{if(t.hasOwnProperty(r))return t[r];throw`unhandled artifact ${r}`})}getFragmentShader(e){return null!==this.compiledFragmentShader?this.compiledFragmentShader:this.compiledFragmentShader=this.replaceArtifacts(this.constructor.fragmentShader,this._getFragShaderArtifactMap(e))}getVertexShader(e){return null!==this.compiledVertexShader?this.compiledVertexShader:this.compiledVertexShader=this.replaceArtifacts(this.constructor.vertexShader,this._getVertShaderArtifactMap(e))}toString(){const e=a.linesToString(["const gl = context"]);return c(this.constructor,arguments,this,e)}destroy(e){if(!this.context)return;this.buffer&&this.context.deleteBuffer(this.buffer),this.framebuffer&&this.context.deleteFramebuffer(this.framebuffer);for(const e in this.rawValueFramebuffers){for(const t in this.rawValueFramebuffers[e])this.context.deleteFramebuffer(this.rawValueFramebuffers[e][t]),delete this.rawValueFramebuffers[e][t];delete this.rawValueFramebuffers[e]}if(this.vertShader&&this.context.deleteShader(this.vertShader),this.fragShader&&this.context.deleteShader(this.fragShader),this.program&&this.context.deleteProgram(this.program),this.texture){this.texture.delete();const e=this.textureCache.indexOf(this.texture.texture);e>-1&&this.textureCache.splice(e,1),this.texture=null}if(this.mappedTextures&&this.mappedTextures.length){for(let e=0;e-1&&this.textureCache.splice(r,1)}this.mappedTextures=null}if(this.kernelArguments)for(let e=0;e0;){const e=this.textureCache.pop();this.context.deleteTexture(e)}if(e){const e=b.indexOf(this.canvas);e>=0&&(b[e]=null,T[e]=null)}if(this.destroyExtensions(),delete this.context,delete this.canvas,!this.gpu)return;const t=this.gpu.kernels.indexOf(this);-1!==t&&this.gpu.kernels.splice(t,1)}destroyExtensions(){this.extensions.OES_texture_float=null,this.extensions.OES_texture_float_linear=null,this.extensions.OES_element_index_uint=null,this.extensions.WEBGL_draw_buffers=null}static destroyContext(e){const t=e.getExtension("WEBGL_lose_context");t&&t.loseContext()}toJSON(){const e=super.toJSON();return e.functionNodes=n.fromKernel(this,s).toJSON(),e.settings.threadDim=this.threadDim,e}}}}),be=e((e,t)=>{const n=r(),{WebGLKernel:s}=xe(),{glKernelString:i}=z();let a=null,o=null,u=null,l=null,h=null;t.exports={HeadlessGLKernel:class extends s{static get isSupported(){return null!==a||(this.setupFeatureChecks(),a=null!==u),a}static setupFeatureChecks(){if(o=null,l=null,"function"==typeof n)try{if(u=n(2,2,{preserveDrawingBuffer:!0}),!u||!u.getExtension)return;l={STACKGL_resize_drawingbuffer:u.getExtension("STACKGL_resize_drawingbuffer"),STACKGL_destroy_context:u.getExtension("STACKGL_destroy_context"),OES_texture_float:u.getExtension("OES_texture_float"),OES_texture_float_linear:u.getExtension("OES_texture_float_linear"),OES_element_index_uint:u.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:u.getExtension("WEBGL_draw_buffers"),WEBGL_color_buffer_float:u.getExtension("WEBGL_color_buffer_float")},h=this.getFeatures()}catch(e){console.warn(e)}}static isContextMatch(e){try{return"ANGLE"===e.getParameter(e.RENDERER)}catch(e){return!1}}static getIsTextureFloat(){return Boolean(l.OES_texture_float)}static getIsDrawBuffers(){return Boolean(l.WEBGL_draw_buffers)}static getChannelCount(){return l.WEBGL_draw_buffers?u.getParameter(l.WEBGL_draw_buffers.MAX_DRAW_BUFFERS_WEBGL):1}static getMaxTextureSize(){return u.getParameter(u.MAX_TEXTURE_SIZE)}static get testCanvas(){return o}static get testContext(){return u}static get features(){return h}initCanvas(){return{}}initContext(){return n(2,2,{preserveDrawingBuffer:!0})}initExtensions(){this.extensions={STACKGL_resize_drawingbuffer:this.context.getExtension("STACKGL_resize_drawingbuffer"),STACKGL_destroy_context:this.context.getExtension("STACKGL_destroy_context"),OES_texture_float:this.context.getExtension("OES_texture_float"),OES_texture_float_linear:this.context.getExtension("OES_texture_float_linear"),OES_element_index_uint:this.context.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:this.context.getExtension("WEBGL_draw_buffers")}}build(){super.build.apply(this,arguments),this.fallbackRequested||this.extensions.STACKGL_resize_drawingbuffer.resize(this.maxTexSize[0],this.maxTexSize[1])}destroyExtensions(){this.extensions.STACKGL_resize_drawingbuffer=null,this.extensions.STACKGL_destroy_context=null,this.extensions.OES_texture_float=null,this.extensions.OES_texture_float_linear=null,this.extensions.OES_element_index_uint=null,this.extensions.WEBGL_draw_buffers=null}static destroyContext(e){const t=e.getExtension("STACKGL_destroy_context");t&&t.destroy&&t.destroy()}toString(){return i(this.constructor,arguments,this,"const gl = context || require('gl')(1, 1);\n"," if (!context) { gl.getExtension('STACKGL_destroy_context').destroy(); }\n")}setOutput(e){return super.setOutput(e),this.graphical&&this.extensions.STACKGL_resize_drawingbuffer&&this.extensions.STACKGL_resize_drawingbuffer.resize(this.maxTexSize[0],this.maxTexSize[1]),this}}}}),Te=e((e,t)=>{const{utils:r}=i(),{WebGLFunctionNode:n}=G();t.exports={WebGL2FunctionNode:class extends n{astIdentifierExpression(e,t){if("Identifier"!==e.type)throw this.astErrorOutput("IdentifierExpression - not an Identifier",e);const n=this.getType(e),s=r.sanitizeName(e.name);if("Infinity"===e.name)t.push("intBitsToFloat(2139095039)");else if("Boolean"===n)if(this.argumentNames.indexOf(s)>-1){const r=this.markupUserName(e.name);t.push(r.startsWith("cellShadow_")?r:`bool(${r})`)}else t.push(`user_${s}`);else t.push(this.markupUserName(e.name));return t}}}}),ve=e((e,t)=>{t.exports={fragmentShader:`#version 300 es\n__HEADER__;\n__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n__SAMPLER_2D_ARRAY_TACTIC_DECLARATION__;\n\nconst int LOOP_MAX = __LOOP_MAX__;\n\n__PLUGINS__;\n__CONSTANTS__;\n\nin vec2 vTexCoord;\n\nfloat atan2(float v1, float v2) {\n if (v2 == 0.0) {\n if (v1 == 0.0) return 0.0;\n if (v1 > 0.0) return 1.5707963267948966;\n if (v1 < 0.0) return -1.5707963267948966;\n }\n return atan(v1, v2);\n}\n\nfloat cbrt(float x) {\n if (x >= 0.0) {\n return pow(x, 1.0 / 3.0);\n } else {\n return -pow(x, 1.0 / 3.0);\n }\n}\n\nfloat expm1(float x) {\n return pow(${Math.E}, x) - 1.0; \n}\n\nfloat fround(highp float x) {\n return x;\n}\n\nfloat imul(float v1, float v2) {\n return float(int(v1) * int(v2));\n}\n\nfloat log10(float x) {\n return log2(x) * (1.0 / log2(10.0));\n}\n\nfloat log1p(float x) {\n return log(1.0 + x);\n}\n\nfloat _pow(float v1, float v2) {\n if (v2 == 0.0) return 1.0;\n return pow(v1, v2);\n}\n\nfloat _round(float x) {\n return floor(x + 0.5);\n}\n\n\nconst int BIT_COUNT = 32;\nint modi(int x, int y) {\n return x - y * (x / y);\n}\n\nint bitwiseOr(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) || (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseXOR(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) != (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseAnd(int a, int b) {\n int result = 0;\n int n = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) && (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 && b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseNot(int a) {\n // ~a is identically -a - 1 in two's complement, for every value including\n // negatives. The previous bit-by-bit loop only worked for a >= 0, where it\n // leaned on 32-bit overflow wrapping to reach the negative answer; given a\n // negative input it computed ~abs(a), so ~(-1) gave -2 and ~~x never\n // returned x.\n return -a - 1;\n}\nint bitwiseZeroFillLeftShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n *= 2;\n }\n\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\n// _pow2 is defined further down, alongside encode32/decode32\nfloat _pow2(float e);\nint bitwiseSignedRightShift(int num, int shifts) {\n // pow(2.0, n) is approximate on many GPUs, and landing 1 ulp high makes the\n // division fall just under a whole number, which floor() then rounds away:\n // 2 >> 1 came out 0, 8 >> 1 came out 3. Only exact left operands were\n // affected, odd ones having enough slack to survive. _pow2 is exact.\n return int(floor(float(num) / _pow2(float(shifts))));\n}\n\nint bitwiseZeroFillRightShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n /= 2;\n }\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\nvec2 integerMod(vec2 x, float y) {\n vec2 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec3 integerMod(vec3 x, float y) {\n vec3 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec4 integerMod(vec4 x, vec4 y) {\n vec4 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nfloat integerMod(float x, float y) {\n float res = floor(mod(x, y));\n return res * (res > floor(y) - 1.0 ? 0.0 : 1.0);\n}\n\nint integerMod(int x, int y) {\n return x - (y * int(x/y));\n}\n\n// GLSL ES 1.00 accepts only a constant or a loop symbol inside an index\n// expression, so m[y][x] does not compile when y and x come from kernel\n// arguments -- the error is "Index expression can only contain const or loop\n// symbols". Loop counters are legal indices, so walk the matrix with them\n// instead. These are 2x2 to 4x4, so it costs at most sixteen comparisons.\nfloat getMatrix2(mat2 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 2; i++) {\n for (int j = 0; j < 2; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix3(mat3 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 3; i++) {\n for (int j = 0; j < 3; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix4(mat4 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 4; i++) {\n for (int j = 0; j < 4; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\n__DIVIDE_WITH_INTEGER_CHECK__;\n\n// Here be dragons!\n// DO NOT OPTIMIZE THIS CODE\n// YOU WILL BREAK SOMETHING ON SOMEBODY'S MACHINE\n// LEAVE IT AS IT IS, LEST YOU WASTE YOUR OWN TIME\n// Exact powers of two built from exact constant multiplies: exp2/log2/pow\n// are approximate on some GPUs (notably Apple silicon), and 1-2 ulp there\n// corrupts the packed bytes (#659)\nfloat _pow2(float e) {\n float r = 1.0;\n float a = abs(e);\n bool n = e < 0.0;\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 32.0) { r *= n ? 2.3283064365386963e-10 : 4294967296.0; a -= 32.0; }\n if (a >= 16.0) { r *= n ? 0.0000152587890625 : 65536.0; a -= 16.0; }\n if (a >= 8.0) { r *= n ? 0.00390625 : 256.0; a -= 8.0; }\n if (a >= 4.0) { r *= n ? 0.0625 : 16.0; a -= 4.0; }\n if (a >= 2.0) { r *= n ? 0.25 : 4.0; a -= 2.0; }\n if (a >= 1.0) { r *= n ? 0.5 : 2.0; }\n return r;\n}\nconst vec2 MAGIC_VEC = vec2(1.0, -256.0);\nconst vec4 SCALE_FACTOR = vec4(1.0, 256.0, 65536.0, 0.0);\nconst vec4 SCALE_FACTOR_INV = vec4(1.0, 0.00390625, 0.0000152587890625, 0.0); // 1, 1/256, 1/65536\nfloat decode32(vec4 texel) {\n __DECODE32_ENDIANNESS__;\n texel *= 255.0;\n vec2 gte128;\n gte128.x = texel.b >= 128.0 ? 1.0 : 0.0;\n gte128.y = texel.a >= 128.0 ? 1.0 : 0.0;\n float exponent = 2.0 * texel.a - 127.0 + dot(gte128, MAGIC_VEC);\n float res = _pow2(round(exponent));\n texel.b = texel.b - 128.0 * gte128.x;\n res = dot(texel, SCALE_FACTOR) * _pow2(round(exponent-23.0)) + res;\n res *= gte128.y * -2.0 + 1.0;\n return res;\n}\n\nfloat decode16(vec4 texel, int index) {\n int channel = integerMod(index, 2);\n return texel[channel*2] * 255.0 + texel[channel*2 + 1] * 65280.0;\n}\n\nfloat decode8(vec4 texel, int index) {\n int channel = integerMod(index, 4);\n return texel[channel] * 255.0;\n}\n\nvec4 legacyEncode32(float f) {\n float F = abs(f);\n float sign = f < 0.0 ? 1.0 : 0.0;\n float exponent = floor(log2(F));\n float mantissa = (exp2(-exponent) * F);\n // exponent += floor(log2(mantissa));\n vec4 texel = vec4(F * exp2(23.0-exponent)) * SCALE_FACTOR_INV;\n texel.rg = integerMod(texel.rg, 256.0);\n texel.b = integerMod(texel.b, 128.0);\n texel.a = exponent*0.5 + 63.5;\n texel.ba += vec2(integerMod(exponent+127.0, 2.0), sign) * 128.0;\n texel = floor(texel);\n texel *= 0.003921569; // 1/255\n __ENCODE32_ENDIANNESS__;\n return texel;\n}\n\n// https://github.com/gpujs/gpu.js/wiki/Encoder-details\nvec4 encode32(float value) {\n if (value == 0.0) return vec4(0, 0, 0, 0);\n\n float exponent;\n float mantissa;\n vec4 result;\n float sgn;\n\n sgn = step(0.0, -value);\n value = abs(value);\n\n exponent = floor(log2(value));\n float p2 = _pow2(exponent);\n // approximate log2 can land one off; correct by direct comparison\n if (p2 > value) { exponent -= 1.0; p2 *= 0.5; }\n else if (p2 * 2.0 <= value) { exponent += 1.0; p2 *= 2.0; }\n\n mantissa = value / p2 - 1.0;\n exponent = exponent+127.0;\n result = vec4(0,0,0,0);\n\n result.a = floor(exponent/2.0);\n exponent = exponent - result.a*2.0;\n result.a = result.a + 128.0*sgn;\n\n result.b = floor(mantissa * 128.0);\n mantissa = mantissa - result.b / 128.0;\n result.b = result.b + exponent*128.0;\n\n result.g = floor(mantissa*32768.0);\n mantissa = mantissa - result.g/32768.0;\n\n result.r = floor(mantissa*8388608.0);\n return result/255.0;\n}\n// Dragons end here\n\nint index;\nivec3 threadId;\n\nivec3 indexTo3D(int idx, ivec3 texDim) {\n int z = int(idx / (texDim.x * texDim.y));\n idx -= z * int(texDim.x * texDim.y);\n int y = int(idx / texDim.x);\n int x = int(integerMod(idx, texDim.x));\n return ivec3(x, y, z);\n}\n\nfloat get32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize));\n return decode32(texel);\n}\n\nfloat get16(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int w = texSize.x * 2;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize.x * 2, texSize.y));\n return decode16(texel, index);\n}\n\nfloat get8(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int w = texSize.x * 4;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize.x * 4, texSize.y));\n return decode8(texel, index);\n}\n\nfloat getMemoryOptimized32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int channel = integerMod(index, 4);\n index = index / 4;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n index = index / 4;\n vec4 texel = texture(tex, st / vec2(texSize));\n return texel[channel];\n}\n\nvec4 getImage2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n return texture(tex, st / vec2(texSize));\n}\n\nvec4 getImage3D(sampler2DArray tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n return texture(tex, vec3(st / vec2(texSize), z));\n}\n\nfloat getFloatFromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return result[0];\n}\n\nvec2 getVec2FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec2(result[0], result[1]);\n}\n\nvec2 getMemoryOptimizedVec2(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 2);\n index = index / 2;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize));\n if (channel == 0) return vec2(texel.r, texel.g);\n if (channel == 1) return vec2(texel.b, texel.a);\n return vec2(0.0, 0.0);\n}\n\nvec3 getVec3FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec3(result[0], result[1], result[2]);\n}\n\nvec3 getMemoryOptimizedVec3(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int fieldIndex = 3 * (x + texDim.x * (y + texDim.y * z));\n int vectorIndex = fieldIndex / 4;\n int vectorOffset = fieldIndex - vectorIndex * 4;\n int readY = vectorIndex / texSize.x;\n int readX = vectorIndex - readY * texSize.x;\n vec4 tex1 = texture(tex, (vec2(readX, readY) + 0.5) / vec2(texSize));\n\n if (vectorOffset == 0) {\n return tex1.xyz;\n } else if (vectorOffset == 1) {\n return tex1.yzw;\n } else {\n readX++;\n if (readX >= texSize.x) {\n readX = 0;\n readY++;\n }\n vec4 tex2 = texture(tex, vec2(readX, readY) / vec2(texSize));\n if (vectorOffset == 2) {\n return vec3(tex1.z, tex1.w, tex2.x);\n } else {\n return vec3(tex1.w, tex2.x, tex2.y);\n }\n }\n}\n\nvec4 getVec4FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n return getImage2D(tex, texSize, texDim, z, y, x);\n}\n\nvec4 getMemoryOptimizedVec4(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 2);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize));\n return vec4(texel.r, texel.g, texel.b, texel.a);\n}\n\nvec4 actualColor;\nvoid color(float r, float g, float b, float a) {\n actualColor = vec4(r,g,b,a);\n}\n\nvoid color(float r, float g, float b) {\n color(r,g,b,1.0);\n}\n\nfloat modulo(float number, float divisor) {\n if (number < 0.0) {\n number = abs(number);\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return -mod(number, divisor);\n }\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return mod(number, divisor);\n}\n\n__INJECTED_NATIVE__;\n__MAIN_CONSTANTS__;\n__MAIN_ARGUMENTS__;\n__KERNEL__;\n\nvoid main(void) {\n index = int(vTexCoord.s * float(uTexSize.x)) + int(vTexCoord.t * float(uTexSize.y)) * uTexSize.x;\n __MAIN_RESULT__;\n}`}}),Se=e((e,t)=>{t.exports={vertexShader:"#version 300 es\n__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n\nin vec2 aPos;\nin vec2 aTexCoord;\n\nout vec2 vTexCoord;\nuniform vec2 ratio;\n\nvoid main(void) {\n gl_Position = vec4((aPos + vec2(1)) * ratio + vec2(-1), 0, 1);\n vTexCoord = aTexCoord;\n}"}}),Ae=e((e,t)=>{const{WebGLKernelValueBoolean:r}=B();t.exports={WebGL2KernelValueBoolean:class extends r{}}}),we=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueFloat:n}=K();t.exports={WebGL2KernelValueFloat:class extends n{}}}),Ee=e((e,t)=>{const{WebGLKernelValueInteger:r}=P();t.exports={WebGL2KernelValueInteger:class extends r{getSource(e){const t=this.getVariablePrecisionString();return"constants"===this.origin?`const ${t} int ${this.id} = ${parseInt(e)};\n`:`uniform ${t} int ${this.id};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1i(this.id,this.uploadValue=e)}}}}),Ie=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueHTMLImage:n}=j();t.exports={WebGL2KernelValueHTMLImage:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}}}}),_e=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicHTMLImage:n}=q();t.exports={WebGL2KernelValueDynamicHTMLImage:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),Le=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=W();t.exports={WebGL2KernelValueHTMLImageArray:class extends n{constructor(e,t){super(e,t),this.checkSize(e[0].width,e[0].height),this.dimensions=[e[0].width,e[0].height,e.length],this.textureSize=[e[0].width,e[0].height]}defineTexture(){const{context:e}=this;e.activeTexture(this.contextHandle),e.bindTexture(e.TEXTURE_2D_ARRAY,this.texture),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_MIN_FILTER,e.NEAREST)}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2DArray ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){const{context:t}=this;t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D_ARRAY,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!0),t.texImage3D(t.TEXTURE_2D_ARRAY,0,t.RGBA,e[0].width,e[0].height,e.length,0,t.RGBA,t.UNSIGNED_BYTE,null);for(let r=0;r{const{utils:r}=i(),{WebGL2KernelValueHTMLImageArray:n}=Le();t.exports={WebGL2KernelValueDynamicHTMLImageArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2DArray ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){const{width:t,height:r}=e[0];this.checkSize(t,r),this.dimensions=[t,r,e.length],this.textureSize=[t,r],this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ke=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueHTMLImage:n}=Ie();t.exports={WebGL2KernelValueHTMLVideo:class extends n{}}}),$e=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueDynamicHTMLImage:n}=_e();t.exports={WebGL2KernelValueDynamicHTMLVideo:class extends n{}}}),De=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleInput:n}=Y();t.exports={WebGL2KernelValueSingleInput:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){const{context:t}=this;r.flattenTo(e.value,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Ce=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleInput:n}=De();t.exports={WebGL2KernelValueDynamicSingleInput:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){let[t,n,s]=e.size;this.dimensions=new Int32Array([t||1,n||1,s||1]),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Ge=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueUnsignedInput:n}=J();t.exports={WebGL2KernelValueUnsignedInput:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}}}}),Re=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicUnsignedInput:n}=Q();t.exports={WebGL2KernelValueDynamicUnsignedInput:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),Me=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueMemoryOptimizedNumberTexture:n}=ee();t.exports={WebGL2KernelValueMemoryOptimizedNumberTexture:class extends n{getSource(){const{id:e,sizeId:t,textureSize:n,dimensionsId:s,dimensions:i}=this,a=this.getVariablePrecisionString();return r.linesToString([`uniform sampler2D ${e}`,`${a} ivec2 ${t} = ivec2(${n[0]}, ${n[1]})`,`${a} ivec3 ${s} = ivec3(${i[0]}, ${i[1]}, ${i[2]})`])}}}}),Ne=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicMemoryOptimizedNumberTexture:n}=te();t.exports={WebGL2KernelValueDynamicMemoryOptimizedNumberTexture:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}}}}),Oe=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueNumberTexture:n}=re();t.exports={WebGL2KernelValueNumberTexture:class extends n{getSource(){const{id:e,sizeId:t,textureSize:n,dimensionsId:s,dimensions:i}=this,a=this.getVariablePrecisionString();return r.linesToString([`uniform ${a} sampler2D ${e}`,`${a} ivec2 ${t} = ivec2(${n[0]}, ${n[1]})`,`${a} ivec3 ${s} = ivec3(${i[0]}, ${i[1]}, ${i[2]})`])}}}}),ze=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicNumberTexture:n}=ne();t.exports={WebGL2KernelValueDynamicNumberTexture:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),Ve=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray:n}=se();t.exports={WebGL2KernelValueSingleArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(!r.isArray(e))return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Ue=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleArray:n}=Ve();t.exports={WebGL2KernelValueDynamicSingleArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Be=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray1DI:n}=ae();t.exports={WebGL2KernelValueSingleArray1DI:class extends n{updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Ke=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleArray1DI:n}=Be();t.exports={WebGL2KernelValueDynamicSingleArray1DI:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Pe=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray2DI:n}=ue();t.exports={WebGL2KernelValueSingleArray2DI:class extends n{updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),We=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleArray2DI:n}=Pe();t.exports={WebGL2KernelValueDynamicSingleArray2DI:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),je=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray3DI:n}=he();t.exports={WebGL2KernelValueSingleArray3DI:class extends n{updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),qe=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleArray3DI:n}=je();t.exports={WebGL2KernelValueDynamicSingleArray3DI:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Xe=e((e,t)=>{const{WebGLKernelValueArray2:r}=pe();t.exports={WebGL2KernelValueArray2:class extends r{}}}),He=e((e,t)=>{const{WebGLKernelValueArray3:r}=de();t.exports={WebGL2KernelValueArray3:class extends r{}}}),Ye=e((e,t)=>{const{WebGLKernelValueArray4:r}=me();t.exports={WebGL2KernelValueArray4:class extends r{}}}),Ze=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueUnsignedArray:n}=fe();t.exports={WebGL2KernelValueUnsignedArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}}}}),Je=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicUnsignedArray:n}=ge();t.exports={WebGL2KernelValueDynamicUnsignedArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),Qe=e((e,t)=>{const{WebGL2KernelValueBoolean:r}=Ae(),{WebGL2KernelValueFloat:n}=we(),{WebGL2KernelValueInteger:s}=Ee(),{WebGL2KernelValueHTMLImage:i}=Ie(),{WebGL2KernelValueDynamicHTMLImage:a}=_e(),{WebGL2KernelValueHTMLImageArray:o}=Le(),{WebGL2KernelValueDynamicHTMLImageArray:u}=Fe(),{WebGL2KernelValueHTMLVideo:l}=ke(),{WebGL2KernelValueDynamicHTMLVideo:h}=$e(),{WebGL2KernelValueSingleInput:c}=De(),{WebGL2KernelValueDynamicSingleInput:p}=Ce(),{WebGL2KernelValueUnsignedInput:d}=Ge(),{WebGL2KernelValueDynamicUnsignedInput:m}=Re(),{WebGL2KernelValueMemoryOptimizedNumberTexture:f}=Me(),{WebGL2KernelValueDynamicMemoryOptimizedNumberTexture:g}=Ne(),{WebGL2KernelValueNumberTexture:y}=Oe(),{WebGL2KernelValueDynamicNumberTexture:x}=ze(),{WebGL2KernelValueSingleArray:b}=Ve(),{WebGL2KernelValueDynamicSingleArray:T}=Ue(),{WebGL2KernelValueSingleArray1DI:v}=Be(),{WebGL2KernelValueDynamicSingleArray1DI:S}=Ke(),{WebGL2KernelValueSingleArray2DI:A}=Pe(),{WebGL2KernelValueDynamicSingleArray2DI:w}=We(),{WebGL2KernelValueSingleArray3DI:E}=je(),{WebGL2KernelValueDynamicSingleArray3DI:I}=qe(),{WebGL2KernelValueArray2:_}=Xe(),{WebGL2KernelValueArray3:L}=He(),{WebGL2KernelValueArray4:F}=Ye(),{WebGL2KernelValueUnsignedArray:k}=Ze(),{WebGL2KernelValueDynamicUnsignedArray:$}=Je(),D={unsigned:{dynamic:{Boolean:r,Integer:s,Float:n,Array:$,"Array(2)":_,"Array(3)":L,"Array(4)":F,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:m,NumberTexture:x,"ArrayTexture(1)":x,"ArrayTexture(2)":x,"ArrayTexture(3)":x,"ArrayTexture(4)":x,MemoryOptimizedNumberTexture:g,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:u,HTMLVideo:h},static:{Boolean:r,Float:n,Integer:s,Array:k,"Array(2)":_,"Array(3)":L,"Array(4)":F,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:d,NumberTexture:y,"ArrayTexture(1)":y,"ArrayTexture(2)":y,"ArrayTexture(3)":y,"ArrayTexture(4)":y,MemoryOptimizedNumberTexture:g,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:o,HTMLVideo:l}},single:{dynamic:{Boolean:r,Integer:s,Float:n,Array:T,"Array(2)":_,"Array(3)":L,"Array(4)":F,"Array1D(2)":S,"Array1D(3)":S,"Array1D(4)":S,"Array2D(2)":w,"Array2D(3)":w,"Array2D(4)":w,"Array3D(2)":I,"Array3D(3)":I,"Array3D(4)":I,Input:p,NumberTexture:x,"ArrayTexture(1)":x,"ArrayTexture(2)":x,"ArrayTexture(3)":x,"ArrayTexture(4)":x,MemoryOptimizedNumberTexture:g,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:u,HTMLVideo:h},static:{Boolean:r,Float:n,Integer:s,Array:b,"Array(2)":_,"Array(3)":L,"Array(4)":F,"Array1D(2)":v,"Array1D(3)":v,"Array1D(4)":v,"Array2D(2)":A,"Array2D(3)":A,"Array2D(4)":A,"Array3D(2)":E,"Array3D(3)":E,"Array3D(4)":E,Input:c,NumberTexture:y,"ArrayTexture(1)":y,"ArrayTexture(2)":y,"ArrayTexture(3)":y,"ArrayTexture(4)":y,MemoryOptimizedNumberTexture:f,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:o,HTMLVideo:l}}};t.exports={kernelValueMaps:D,lookupKernelValueType:function(e,t,r,n){if(!e)throw new Error("type missing");if(!t)throw new Error("dynamic missing");if(!r)throw new Error("precision missing");n.type&&(e=n.type);const s=D[r][t];if("WebGPUBuffer"===e)throw new Error("this kernel runs on WebGL but received a WebGPU pipeline buffer; await handle.toArray() first, or give this kernel the async contract (asyncMode: true / mode: 'async') so the readback happens for you");if(!1===s[e])return null;if(void 0===s[e])throw new Error(`Could not find a KernelValue for ${e}`);return s[e]}}}),et=e((e,t)=>{const{WebGLKernel:r}=xe(),{WebGL2FunctionNode:n}=Te(),{FunctionBuilder:s}=o(),{utils:a}=i(),{fragmentShader:u}=ve(),{vertexShader:l}=Se(),{lookupKernelValueType:h}=Qe();let c=null,p=null,d=null,m=null;t.exports={WebGL2Kernel:class extends r{static get isSupported(){return null!==c||(this.setupFeatureChecks(),c=this.isContextMatch(d)),c}static setupFeatureChecks(){"undefined"!=typeof document?p=document.createElement("canvas"):"undefined"!=typeof OffscreenCanvas&&(p=new OffscreenCanvas(0,0)),p&&(d=p.getContext("webgl2"),d&&d.getExtension&&(d.getExtension("EXT_color_buffer_float"),d.getExtension("OES_texture_float_linear"),m=this.getFeatures()))}static isContextMatch(e){return"undefined"!=typeof WebGL2RenderingContext&&e instanceof WebGL2RenderingContext}static getFeatures(){const e=this.testContext;return Object.freeze({isFloatRead:this.getIsFloatRead(),isIntegerDivisionAccurate:this.getIsIntegerDivisionAccurate(),isSpeedTacticSupported:this.getIsSpeedTacticSupported(),kernelMap:!0,isTextureFloat:!0,isDrawBuffers:!0,channelCount:this.getChannelCount(),maxTextureSize:this.getMaxTextureSize(),lowIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_INT),lowFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_FLOAT),mediumIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_INT),mediumFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_FLOAT),highIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_INT),highFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT)})}static getIsTextureFloat(){return!0}static getChannelCount(){return d.getParameter(d.MAX_DRAW_BUFFERS)}static getMaxTextureSize(){return d.getParameter(d.MAX_TEXTURE_SIZE)}static lookupKernelValueType(e,t,r,n){return h(e,t,r,n)}static get testCanvas(){return p}static get testContext(){return d}static get features(){return m}static get fragmentShader(){return u}static get vertexShader(){return l}initContext(){return this.canvas.getContext("webgl2",{alpha:!1,depth:!1,antialias:!1})}initExtensions(){this.extensions={EXT_color_buffer_float:this.context.getExtension("EXT_color_buffer_float"),OES_texture_float_linear:this.context.getExtension("OES_texture_float_linear")}}validateSettings(e){if(!this.validate)return void(this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output));const{features:t}=this.constructor;if("single"===this.precision&&!t.isFloatRead)throw new Error("Float texture outputs are not supported");if(this.graphical||null!==this.precision||(this.precision=t.isFloatRead?"single":"unsigned"),null===this.fixIntegerDivisionAccuracy?this.fixIntegerDivisionAccuracy=!t.isIntegerDivisionAccurate:this.fixIntegerDivisionAccuracy&&t.isIntegerDivisionAccurate&&(this.fixIntegerDivisionAccuracy=!1),this.checkOutput(),!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=a.getVariableType(e[0],this.strictIntegers);switch(t){case"Array":this.output=a.getDimensions(t);break;case"NumberTexture":case"MemoryOptimizedNumberTexture":case"ArrayTexture(1)":case"ArrayTexture(2)":case"ArrayTexture(3)":case"ArrayTexture(4)":this.output=e[0].output;break;default:throw new Error("Auto output not supported for input type: "+t)}}if(this.graphical){if(2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");return"single"===this.precision&&(console.warn("Cannot use graphical mode and single precision at the same time"),this.precision="unsigned"),void(this.texSize=a.clone(this.output))}!this.graphical&&null===this.precision&&t.isTextureFloat&&(this.precision="single"),this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output),this.checkTextureSize()}translateSource(){const e=s.fromKernel(this,n,{fixIntegerDivisionAccuracy:this.fixIntegerDivisionAccuracy});this.translatedSource=e.getPrototypeString("kernel"),this.setupReturnTypes(e)}drawBuffers(){this.context.drawBuffers(this.drawBuffersMap)}getTextureFormat(){const{context:e}=this;switch(this.getInternalFormat()){case e.R32F:return e.RED;case e.RG32F:return e.RG;case e.RGBA32F:case e.RGBA:return e.RGBA;default:throw new Error("Unknown internal format")}}renderValues(){return void 0===this._tightRead&&this._detectTightRead(),super.renderValues()}renderKernelsToArrays(){return void 0===this._tightRead&&this._detectTightRead(),super.renderKernelsToArrays()}readFloatPixelsToFloat32Array(){if(!this._tightRead)return super.readFloatPixelsToFloat32Array();const{texSize:e,context:t}=this,r=e[0],n=e[1],s=new Float32Array(r*n);return t.readPixels(0,0,r,n,t.RED,t.FLOAT,s),s}renderOutputAsync(){return this.renderOutput!==this.renderValues?Promise.resolve(this.renderOutput()):this.renderValuesAsync()}renderValuesAsync(){void 0===this._tightRead&&this._detectTightRead();const e=this.formatValues,[t,r,n]=this.output;return this.transferValuesAsync().then(s=>e(s,t,r,n))}transferValuesAsync(){const{texSize:e,context:t}=this,r=e[0],n=e[1];let s,i,a;"single"===this.precision?(s=this._tightRead?t.RED:t.RGBA,i=t.FLOAT,a=new Float32Array(r*n*(this._tightRead?1:4))):(s=t.RGBA,i=t.UNSIGNED_BYTE,a=new Uint8Array(r*n*4));const o=t.createBuffer();t.bindBuffer(t.PIXEL_PACK_BUFFER,o),t.bufferData(t.PIXEL_PACK_BUFFER,a.byteLength,t.STREAM_READ),t.readPixels(0,0,r,n,s,i,0),t.bindBuffer(t.PIXEL_PACK_BUFFER,null);const u=t.fenceSync(t.SYNC_GPU_COMMANDS_COMPLETE,0);return t.flush(),this._pollFence(u).then(()=>(t.bindBuffer(t.PIXEL_PACK_BUFFER,o),t.getBufferSubData(t.PIXEL_PACK_BUFFER,0,a),t.bindBuffer(t.PIXEL_PACK_BUFFER,null),t.deleteBuffer(o),"single"===this.precision?a:new Float32Array(a.buffer)),e=>{throw t.deleteBuffer(o),e})}_pollFence(e){const t=this.context;return new Promise((r,n)=>{let s,i=null;"undefined"!=typeof MessageChannel?(i=new MessageChannel,i.port1.onmessage=()=>o(),s=()=>i.port2.postMessage(0)):s=()=>setTimeout(o,0);const a=(r,n)=>{t.deleteSync(e),i&&(i.port1.close(),i.port2.close()),r(n)},o=()=>{if(t.isContextLost())return a(n,new Error("WebGL context lost while awaiting kernel result"));const i=t.clientWaitSync(e,0,0);return i===t.ALREADY_SIGNALED||i===t.CONDITION_SATISFIED?a(r):i===t.WAIT_FAILED?a(n,new Error("clientWaitSync failed while awaiting kernel result")):void s()};o()})}_detectTightRead(){const e=this.context;this._tightRead=!1,e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer);const t="Number"===this.returnType||"Float"===this.returnType||"Integer"===this.returnType||"LiteralInteger"===this.returnType;if("single"===this.precision&&!this.optimizeFloatMemory&&!this.graphical&&t&&e.getParameter(e.IMPLEMENTATION_COLOR_READ_FORMAT)===e.RED&&e.getParameter(e.IMPLEMENTATION_COLOR_READ_TYPE)===e.FLOAT){if(this.formatValues===a.erectFloat)this.formatValues=a.erectMemoryOptimizedFloat;else if(this.formatValues===a.erect2DFloat)this.formatValues=a.erectMemoryOptimized2DFloat;else if(this.formatValues===a.erect3DFloat)this.formatValues=a.erectMemoryOptimized3DFloat;else if(this.formatValues!==a.erectMemoryOptimizedFloat&&this.formatValues!==a.erectMemoryOptimized2DFloat&&this.formatValues!==a.erectMemoryOptimized3DFloat)return;this._tightRead=!0}}getInternalFormat(){const{context:e}=this;if("single"===this.precision)switch(this.returnType){case"Number":case"Float":case"Integer":return this.optimizeFloatMemory?e.RGBA32F:e.R32F;case"Array(2)":return e.RG32F;case"Array(3)":case"Array(4)":return e.RGBA32F;default:throw new Error("Unhandled return type")}return e.RGBA}_setupOutputTexture(){const e=this.context;if(this.texture)return e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.texture.texture,0),void(this._tightRead=void 0);e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer);const t=e.createTexture(),r=this.texSize;e.activeTexture(e.TEXTURE0+this.constantTextureCount+this.argumentTextureCount),e.bindTexture(e.TEXTURE_2D,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.REPEAT),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.REPEAT),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);const n=this.getInternalFormat();"single"===this.precision?e.texStorage2D(e.TEXTURE_2D,1,n,r[0],r[1]):e.texImage2D(e.TEXTURE_2D,0,n,r[0],r[1],0,n,e.UNSIGNED_BYTE,null),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t,0),this.texture=new this.TextureConstructor({texture:t,size:r,dimensions:this.threadDim,output:this.output,context:this.context,internalFormat:this.getInternalFormat(),textureFormat:this.getTextureFormat(),kernel:this}),this._tightRead=void 0}_setupSubOutputTextures(){const e=this.context;if(this.mappedTextures){for(let t=0;t{const{utils:r}=i(),{FunctionNode:n}=l();const s={Number:"f32",Float:"f32",Integer:"i32",LiteralInteger:"f32",Boolean:"bool","Array(2)":"vec2","Array(3)":"vec3","Array(4)":"vec4"},a={"===":"==","!==":"!="},o=["x","y","z","w"],u={pow:"_pow",round:"_round"},h={ceil:!0,floor:!0,_round:!0};t.exports={WGSLFunctionNode:class extends n{get requiresSequenceFreeForInit(){return!0}wgslFloat(e){if(e===1/0)return"0x1.fffffep+127";if(e===-1/0)return"-0x1.fffffep+127";if(e>34028234663852886e22)return"0x1.fffffep+127";if(e<-34028234663852886e22)return"-0x1.fffffep+127";const t=`${e}`;return-1!==t.indexOf(".")||-1!==t.indexOf("e")||-1!==t.indexOf("E")?t:`${t}.0`}wgslInt(e){return`${Math.round(e)}`}mangleFunctionName(e){return`fn_${r.sanitizeName(e)}`}getLookupType(e){return"WebGPUBuffer"===e?"Number":super.getLookupType(e)}astUpdateExpression(e,t){return this.astGeneric(e.argument,t),t.push(e.operator),t}getType(e){if(e&&"ConditionalExpression"===e.type){const t=this.getType(e.consequent);if("Integer"===t||"LiteralInteger"===t){const t=this.getType(e.alternate);if("Number"===t||"Float"===t)return"Number"}}return super.getType(e)}astConditionalExpression(e,t){if("ConditionalExpression"!==e.type)throw this.astErrorOutput("Not a conditional expression",e);const r=this.getType(e.consequent),n=this.getType(e.alternate);if(null===r&&null===n)return t.push("if ("),this.astGeneric(e.test,t),t.push(") {"),this.astGeneric(e.consequent,t),t.push(";"),t.push("} else {"),this.astGeneric(e.alternate,t),t.push(";"),t.push("}"),t;let s="LiteralInteger"===r?"Number":r;"Integer"!==s||"Number"!==n&&"Float"!==n||(s="Number");const i=e=>{const r=this.getType(e);switch(s){case"Number":case"Float":"Integer"===r?this.castValueToFloat(e,t):"LiteralInteger"===r?this.castLiteralToFloat(e,t):this.astGeneric(e,t);break;case"Integer":"Number"===r||"Float"===r?this.castValueToInteger(e,t):"LiteralInteger"===r?this.castLiteralToInteger(e,t):this.astGeneric(e,t);break;default:this.astGeneric(e,t)}};return t.push("select("),i(e.alternate),t.push(", "),i(e.consequent),t.push(", "),this.astGeneric(e.test,t),t.push(")"),t}astFunction(e,t){if(this.isRootKernel){for(let r=0;r0&&t.push(", ");let a=this.argumentTypes[this.argumentNames.indexOf(i)];if(!a)throw this.astErrorOutput(`Unknown argument ${i} type`,e);"LiteralInteger"===a&&(this.argumentTypes[n]=a="Number");const o=s[a];if(!o)throw this.astErrorOutput(`WebGPU backend does not yet support ${a} arguments to helper functions`,e);t.push(`user_${r.sanitizeName(i)} : ${o}`)}t.push(")"),i&&t.push(` -> ${i}`),t.push(" {\n");for(let r=0;r>":!0,">>>":!0}[e.operator])return null;const r=e=>{switch(this.getType(e)){case"Number":case"Float":this.castValueToInteger(e,t);break;case"LiteralInteger":this.castLiteralToInteger(e,t);break;default:this.pushState("building-integer"),this.astGeneric(e,t),this.popState("building-integer")}};return t.push("("),">>>"===e.operator?(t.push("bitcast(bitcast("),r(e.left),t.push(") >> u32("),r(e.right),t.push("))")):"<<"===e.operator||">>"===e.operator?(r(e.left),t.push(` ${e.operator} u32(`),r(e.right),t.push(")")):(r(e.left),t.push(` ${e.operator} `),r(e.right)),t.push(")"),t}checkAndUpconvertBitwiseUnary(e,t){if("~"!==e.operator)return null;switch(t.push("~("),this.getType(e.argument)){case"Number":case"Float":this.castValueToInteger(e.argument,t);break;case"LiteralInteger":this.castLiteralToInteger(e.argument,t);break;default:this.astGeneric(e.argument,t)}return t.push(")"),t}astUnaryExpression(e,t){return this.checkAndUpconvertBitwiseUnary(e,t)?t:"+"===e.operator?(this.astGeneric(e.argument,t),t):(e.prefix?(t.push(e.operator),this.astGeneric(e.argument,t)):(this.astGeneric(e.argument,t),t.push(e.operator)),t)}castLiteralToInteger(e,t){return this.pushState("casting-to-integer"),this.astGeneric(e,t),this.popState("casting-to-integer"),t}castLiteralToFloat(e,t){return this.pushState("casting-to-float"),this.astGeneric(e,t),this.popState("casting-to-float"),t}castValueToInteger(e,t){return this.pushState("casting-to-integer"),t.push("i32("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-integer"),t}castValueToFloat(e,t){return this.pushState("casting-to-float"),t.push("f32("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-float"),t}astIdentifierExpression(e,t){if("Identifier"!==e.type)throw this.astErrorOutput("IdentifierExpression - not an Identifier",e);const n=this.getType(e),s=r.sanitizeName(e.name);return"Infinity"===e.name?(t.push("0x1.fffffep+127"),t):!this.isRootKernel||-1===this.argumentNames.indexOf(e.name)||"Number"!==n&&"Float"!==n&&"Integer"!==n&&"Boolean"!==n?(t.push(`user_${s}`),t):("Boolean"===n?t.push(`bool(params.user_${s})`):t.push(`params.user_${s}`),t)}astForStatement(e,t){if("ForStatement"!==e.type)throw this.astErrorOutput("Invalid for statement",e);const r=[],n=[],s=[],i=[];let a=null;if(e.init){const{declarations:t}=e.init;t.length>1&&(a=!1),this.astGeneric(e.init,r);for(let e=0;e0&&t.push(r.join(""),"\n"),t.push(`for (var ${e} : i32 = 0;${e}0&&t.push(`if (!(${n.join("")})) { break; }\n`),t.push(i.join("")),t.push(`\n${s.join("")};`),t.push("}\n")}return t}astWhileStatement(e,t){if("WhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);const r=this.getInternalVariableName("safeI");return t.push(`for (var ${r} : i32 = 0;${r}{if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(t);if("BreakStatement"===e.type)return!0;if("ForStatement"===e.type||"WhileStatement"===e.type||"DoWhileStatement"===e.type||"SwitchStatement"===e.type)return!1;for(const r in e)if("loc"!==r&&"range"!==r&&"parent"!==r&&t(e[r]))return!0;return!1};if(t(r[e]))throw this.astErrorOutput("break inside a switch case is only supported as the case terminator",r[e])}for(let e=0;ee+1){u=!0,this.astSwitchCaseConsequent(n[e].consequent,o);continue}t.push(" else {\n")}this.astSwitchCaseConsequent(n[e].consequent,t),t.push("\n}")}return u&&(t.push(" else {"),t.push(o.join("")),t.push("}")),t.push("\n"),t}astThisExpression(e,t){return t.push("this"),t}astSequenceExpression(e,t){const{expressions:r}=e;if(1===r.length)return this.astGeneric(r[0],t),t;throw this.astErrorOutput("WebGPU backend does not yet support the comma operator",e)}astMemberExpression(e,t){const{property:n,name:i,signature:a,origin:o,type:u,xProperty:l,yProperty:h,zProperty:c}=this.getMemberExpressionDetails(e);switch(a){case"value.thread.value":case"this.thread.value":if("x"!==i&&"y"!==i&&"z"!==i)throw this.astErrorOutput("Unexpected expression, expected `this.thread.x`, `this.thread.y`, or `this.thread.z`",e);return t.push(`i32(threadGid.${i})`),t;case"this.output.value":{const r={x:0,y:1,z:2}[i];if(void 0===r)throw this.astErrorOutput("Unexpected expression",e);if(this.dynamicOutput){const e=`params.output${i.toUpperCase()}`;this.isState("casting-to-float")?t.push(`f32(${e})`):t.push(`i32(${e})`)}else this.isState("casting-to-integer")?t.push(`${this.output[r]}`):t.push(`${this.output[r]}.0`);return t}case"value":throw this.astErrorOutput("Unexpected expression",e);case"value[]":case"value[][]":case"value[][][]":case"value[][][][]":case"value.value":if("Math"===o)return t.push(this.wgslFloat(Math[i])),t;switch(n){case"r":return t.push(`user_${r.sanitizeName(i)}.x`),t;case"g":return t.push(`user_${r.sanitizeName(i)}.y`),t;case"b":return t.push(`user_${r.sanitizeName(i)}.z`),t;case"a":return t.push(`user_${r.sanitizeName(i)}.w`),t}break;case"this.constants.value":{const r=this.constants[i];switch(u){case"Integer":return this.isState("casting-to-float")?t.push(this.wgslFloat(r)):t.push(this.wgslInt(r)),t;case"Number":case"Float":return this.isState("casting-to-integer")?t.push(this.wgslInt(r)):t.push(this.wgslFloat(r)),t;case"Boolean":return t.push(r?"true":"false"),t;case"Array(2)":case"Array(3)":case"Array(4)":{const e=parseInt(u.substring(6),10),n=[];for(let t=0;t4)throw this.astErrorOutput("this.color takes (r, g, b) or (r, g, b, a)",e);t.push("kernelColor(data_index");for(let r=0;r0&&t.push(", "),s){case"Integer":this.castValueToFloat(n,t);break;case"LiteralInteger":this.castLiteralToFloat(n,t);break;default:this.astGeneric(n,t)}}else{const s=this.lookupFunctionArgumentTypes(n)||[];for(let i=0;i0&&t.push(", ");const u=this.getType(a);switch(o||(this.triggerImplyArgumentType(n,i,u,this),o=u),u){case"Boolean":this.astGeneric(a,t);continue;case"Number":case"Float":if("Integer"===o){t.push("i32("),this.astGeneric(a,t),t.push(")");continue}if("Number"===o||"Float"===o){this.astGeneric(a,t);continue}if("LiteralInteger"===o){this.castLiteralToFloat(a,t);continue}break;case"Integer":if("Number"===o||"Float"===o){t.push("f32("),this.astGeneric(a,t),t.push(")");continue}if("Integer"===o){this.astGeneric(a,t);continue}break;case"LiteralInteger":if("Integer"===o){this.castLiteralToInteger(a,t);continue}if("Number"===o||"Float"===o){this.castLiteralToFloat(a,t);continue}if("LiteralInteger"===o){this.astGeneric(a,t);continue}break;case"Array(2)":case"Array(3)":case"Array(4)":if(o===u){"Identifier"===a.type?t.push(`user_${r.sanitizeName(a.name)}`):this.astGeneric(a,t);continue}break;case"Array":case"Array2D":case"Array3D":case"Input":case"WebGPUBuffer":throw this.astErrorOutput("WebGPU backend does not yet support array arguments to helper functions",e)}throw this.astErrorOutput(`Unhandled argument combination of ${u} and ${o} for argument named "${a.name}"`,e)}}return t.push(")"),a&&t.push(")"),t}astArrayExpression(e,t){switch(this.getType(e)){case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":throw this.astErrorOutput("WebGPU backend does not yet support Matrix types",e)}const r=e.elements.length;t.push(`vec${r}(`);for(let n=0;n0&&t.push(", ");const r=e.elements[n];switch(this.getType(r)){case"Integer":this.castValueToFloat(r,t);break;case"LiteralInteger":this.castLiteralToFloat(r,t);break;default:this.astGeneric(r,t)}}return t.push(")"),t}memberExpressionXYZ(e,t,r,n){return r?n.push(this.memberExpressionPropertyMarkup(r),", "):n.push("0, "),t?n.push(this.memberExpressionPropertyMarkup(t),", "):n.push("0, "),n.push(this.memberExpressionPropertyMarkup(e)),n}memberExpressionPropertyMarkup(e){if(!e)throw new Error("Property not set");const t=[];switch(this.getType(e)){case"Number":case"Float":this.castValueToInteger(e,t);break;case"LiteralInteger":this.castLiteralToInteger(e,t);break;case"Integer":this.pushState("building-integer"),t.push("i32("),this.astGeneric(e,t),t.push(")"),this.popState("building-integer");break;default:this.astGeneric(e,t)}return t.join("")}}}}),rt=e((e,t)=>{let r=null;t.exports={WebGPUContext:class e{static get isSupported(){return"undefined"!=typeof navigator&&!!navigator.gpu}static acquire(){if(r)return r;const t=(async()=>{if(!e.isSupported)throw new Error("WebGPU is not supported on this platform (navigator.gpu is missing)");const n=await navigator.gpu.requestAdapter();if(!n)throw new Error("WebGPU is present (navigator.gpu) but no adapter is available. On headless Chromium there is no adapter; run headed. Use `await GPU.isWebGPUAvailable()` to feature-detect.");const s=await n.requestDevice({requiredLimits:{maxStorageBufferBindingSize:n.limits.maxStorageBufferBindingSize,maxBufferSize:n.limits.maxBufferSize}}),i={adapter:n,device:s,isLost:!1};return s.lost.then(e=>{i.isLost=!0,"destroyed"!==e.reason&&console.error(`gpu.js [webgpu]: device lost: ${e.message}`),r===t&&(r=null)}),s.onuncapturederror=e=>{console.error(`gpu.js [webgpu]: ${e.error.message}`)},i})();return t.catch(()=>{r===t&&(r=null)}),r=t}static destroy(){if(!r)return Promise.resolve();const e=r;return r=null,e.then(({device:e})=>{e.destroy()},()=>{})}}}}),nt=e((e,t)=>{t.exports={WebGPUBufferResult:class e{constructor(e){this.buffer=e.buffer,this.output=e.output,this.componentCount=e.componentCount||1,this.context=e.context,this.kernel=e.kernel,this.type="WebGPUBuffer",this._deleted=!1,this.buffer._refs?this.buffer._refs++:this.buffer._refs=1}toArray(){return this._deleted?Promise.reject(new Error("WebGPUBufferResult has been deleted")):this.kernel.readBufferResult(this)}delete(){this._deleted||(this._deleted=!0,0===--this.buffer._refs&&this.buffer.destroy())}clone(){return new e(this)}}}}),st=e((e,t)=>{const{Kernel:r}=a(),{FunctionBuilder:s}=o(),{WGSLFunctionNode:u}=tt(),{WebGPUContext:l}=rt(),{WebGPUBufferResult:h}=nt(),{utils:c}=i(),{Input:p}=n(),d=Object.freeze({kernelMap:!1,isIntegerDivisionAccurate:!0,isSpeedTacticSupported:!1,isTextureFloat:!0,isDrawBuffers:!1,kernelMapSize:0,channelCount:1,maxTextureSize:1/0,isFloatRead:!0}),m={_pow:"fn _pow(v1 : f32, v2 : f32) -> f32 {\n if (v2 == 0.0) { return 1.0; }\n return pow(v1, v2);\n}",_round:"fn _round(x : f32) -> f32 {\n return floor(x + 0.5);\n}",cbrt:"fn cbrt(x : f32) -> f32 {\n return sign(x) * pow(abs(x), 1.0 / 3.0);\n}",expm1:"fn expm1(x : f32) -> f32 {\n return exp(x) - 1.0;\n}",fround:"fn fround(x : f32) -> f32 {\n return x;\n}",imul:"fn imul(a : f32, b : f32) -> f32 {\n return f32(i32(a) * i32(b));\n}",log10:`fn log10(x : f32) -> f32 {\n return log2(x) * ${1/Math.log2(10)};\n}`,log1p:"fn log1p(x : f32) -> f32 {\n return log(1.0 + x);\n}",clz32:"fn clz32(x : f32) -> f32 {\n return f32(countLeadingZeros(u32(x)));\n}"};t.exports={WebGPUKernel:class extends r{static get isSupported(){return l.isSupported}static get isAsync(){return!0}static isContextMatch(e){return Boolean(e&&"function"==typeof e.createShaderModule&&"function"==typeof e.createComputePipeline)}static getFeatures(){return d}static get features(){return d}static get mode(){return"webgpu"}static getSignature(e,t){return"webgpu"+(t.length>0?":"+t.join(","):"")}static destroyContext(e){}static nativeFunctionArguments(){throw new Error("WebGPU backend does not yet support native functions")}static nativeFunctionReturnType(){throw new Error("WebGPU backend does not yet support native functions")}static combineKernels(){throw new Error("WebGPU backend does not yet support combineKernels; chain kernels with `await` and pipeline mode instead")}constructor(e,t){if(super(e,t),t){if("unsigned"===t.precision&&!t.graphical)throw new Error("WebGPU backend does not yet support precision: 'unsigned'; it is single precision only");if(t.subKernels)throw new Error("WebGPU backend does not yet support createKernelMap")}this.mergeSettings(e.settings||t),(null===this.precision||this.graphical)&&(this.precision="single"),this.asyncMode=!0,this.threadDim=null,this.componentCount=1,this.compiledSource=null,this.translatedBody=null,this.translatedFunctions=null,this.paramsLayout=null,this._buildPromise=null,this._device=null,this.computePipeline=null,this.bindGroupLayout=null,this.bindGroup=null,this.bindGroupDirty=!0,this.paramsBuffer=null,this.paramsMirror=null,this.outputBuffer=null,this.argumentBuffers=null,this.constantBuffers=null,this.stagingPool=[],this._canvasContext=null,this._blitPipeline=null,this._blitParamsBuffer=null,this._blitBindGroup=null,this._blitBoundOutputBuffer=null}initCanvas(){return this.graphical&&"undefined"!=typeof document?document.createElement("canvas"):null}initContext(){return null}initPlugins(e){return[]}setOutput(e){const t=this.toKernelOutput(e);if(this.built){if(!this.dynamicOutput)throw new Error("Resizing a kernel with dynamicOutput: false is not possible");if(t.length!==this.output.length)throw new Error("WebGPU backend does not yet support changing the output rank of a built kernel; the workgroup shape is fixed at build")}return this.output=t,this}toString(){throw new Error("WebGPU backend does not yet support toString")}validateSettings(e){if(this.graphical){if(!this.output||2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");if(this.pipeline)throw new Error("graphical mode and pipeline mode are mutually exclusive");if(!this.canvas)throw new Error("graphical mode requires a canvas (none could be created; pass one in settings)")}if("unsigned"===this.precision)throw new Error("WebGPU backend does not yet support precision: 'unsigned'; it is single precision only");if(this.precision="single",this.subKernels&&this.subKernels.length>0)throw new Error("WebGPU backend does not yet support createKernelMap");if(!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=c.getVariableType(e[0],this.strictIntegers);if("Array"===t)this.output=Array.from(c.getDimensions(e[0]));else{if("WebGPUBuffer"!==t)throw new Error("Auto output not supported for input type: "+t);this.output=Array.from(e[0].output)}}this.checkOutput()}setupArguments(e){super.setupArguments(e);for(let e=0;e,`);for(let e=0;e params : Params;");for(let t=0;t user_${e[t].name} : array;`);const i=1+e.length;n.push(`@group(0) @binding(${i}) var result : array;`),this.graphical&&n.push("fn kernelColor(index : i32, r : f32, g : f32, b : f32, a : f32) {\n result[index * 4] = r;\n result[index * 4 + 1] = g;\n result[index * 4 + 2] = b;\n result[index * 4 + 3] = a;\n}");for(let e=0;e constants_${r[e].name} : array;`);n.push("var threadGid : vec3;"),null!==this.paramsLayout.randomSeedOffset&&n.push("var pcgState : u32;\nfn pcg_random() -> f32 {\n pcgState = pcgState * 747796405u + 2891336453u;\n let word = ((pcgState >> ((pcgState >> 28u) + 4u)) ^ pcgState) * 277803737u;\n let mixed = (word >> 22u) ^ word;\n return f32(mixed >> 8u) / 16777216.0;\n}");const a=`${this.translatedFunctions}\n${this.translatedBody}`;/\bLOOP_MAX\b/.test(a)&&n.push(`const LOOP_MAX : i32 = ${parseInt(this.loopMaxIterations,10)||1e3};`);for(const e in m)new RegExp(`\\b${e}\\(`).test(a)&&n.push(m[e]);for(let t=0;t f32 {\n return user_${r}[u32(x + i32(params.user_${r}_dims.x) * (y + i32(params.user_${r}_dims.y) * z))];\n}`)}for(let e=0;e f32 {\n return constants_${t.name}[u32(x + ${i[0]} * (y + ${i[1]} * z))];\n}`)}this.translatedFunctions&&n.push(this.translatedFunctions);const o=1===this.output.length?[64,1,1]:[8,8,1];return this.workgroupSize=o,1===this.output.length?n.push(`@compute @workgroup_size(${o[0]}, ${o[1]}, ${o[2]})\nfn main(@builtin(global_invocation_id) gid : vec3) {\n let flat_index : u32 = gid.x + gid.y * params.dispatchWidth;\n threadGid = vec3(flat_index, 0u, 0u);\n if (flat_index >= params.outputX) { return; }\n let data_index : i32 = i32(flat_index);\n${null!==this.paramsLayout.randomSeedOffset?" pcgState = (params.randomSeed + u32(data_index) * 2654435769u) * 747796405u + 2891336453u;\n":""}${this.translatedBody}\n}`):n.push(`@compute @workgroup_size(${o[0]}, ${o[1]}, ${o[2]})\nfn main(@builtin(global_invocation_id) gid : vec3) {\n threadGid = gid;\n if (gid.x >= params.outputX || gid.y >= params.outputY || gid.z >= params.outputZ) { return; }\n let data_index : i32 = i32(gid.x + params.outputX * (gid.y + params.outputY * gid.z));\n${null!==this.paramsLayout.randomSeedOffset?" pcgState = (params.randomSeed + u32(data_index) * 2654435769u) * 747796405u + 2891336453u;\n":""}${this.translatedBody}\n}`),n.join("\n")}constantDimensions(e){const t=e instanceof p?Array.from(e.size):Array.from(c.getDimensions(e));for(;t.length<3;)t.push(1);return t}async _buildAsync(){const e=await l.acquire();this.context=e;const t=this._device=e.device,r=t.createShaderModule({code:this.compiledSource}),n=(await r.getCompilationInfo()).messages.filter(e=>"error"===e.type);if(n.length>0)throw new Error("Error compiling WGSL compute shader:\n"+n.map(e=>` ${e.lineNum}:${e.linePos} ${e.message}`).join("\n")+`\n--- generated WGSL ---\n${this.compiledSource}`);const{arrayArgs:s,bufferConstants:i,byteLength:a}=this.paramsLayout,o=[{binding:0,visibility:4,buffer:{type:"uniform"}}];for(let e=0;ei&&(s[1]=Math.ceil(s[0]/i),s[0]=Math.ceil(s[0]/s[1])),a=s[0]*t);for(let e=0;e<3;e++)if(s[e]>i)throw new Error(`output dimension ${e} needs ${s[e]} workgroups, over this device's limit of ${i}`);return{groups:s,dispatchWidth:a}}async _buildBlitPipeline(e){if(this.canvas.width=this.output[0],this.canvas.height=this.output[1],this._canvasContext=this.canvas.getContext("webgpu"),!this._canvasContext)throw new Error("could not get a webgpu context from the canvas");const t=navigator.gpu.getPreferredCanvasFormat();this._canvasContext.configure({device:e,format:t,alphaMode:"premultiplied"});const r=e.createShaderModule({code:"struct BlitParams { width : u32, height : u32, pad0 : u32, pad1 : u32 }\n@group(0) @binding(0) var blit : BlitParams;\n@group(0) @binding(1) var pixels : array;\n@vertex fn vs(@builtin(vertex_index) vi : u32) -> @builtin(position) vec4 {\n var pos = array, 3>(vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));\n return vec4(pos[vi], 0.0, 1.0);\n}\n@fragment fn fs(@builtin(position) pos : vec4) -> @location(0) vec4 {\n let x = u32(pos.x);\n let y = u32(pos.y);\n let row = blit.height - 1u - y;\n let i = (row * blit.width + x) * 4u;\n let a = pixels[i + 3u];\n return vec4(pixels[i] * a, pixels[i + 1u] * a, pixels[i + 2u] * a, a);\n}"}),n=(await r.getCompilationInfo()).messages.filter(e=>"error"===e.type);if(n.length>0)throw new Error("Error compiling the graphical blit shader:\n"+n.map(e=>` ${e.lineNum}:${e.linePos} ${e.message}`).join("\n"));this._blitBindGroupLayout=e.createBindGroupLayout({entries:[{binding:0,visibility:2,buffer:{type:"uniform"}},{binding:1,visibility:2,buffer:{type:"read-only-storage"}}]}),this._blitPipeline=e.createRenderPipeline({layout:e.createPipelineLayout({bindGroupLayouts:[this._blitBindGroupLayout]}),vertex:{module:r,entryPoint:"vs"},fragment:{module:r,entryPoint:"fs",targets:[{format:t}]},primitive:{topology:"triangle-list"}}),this._blitParamsBuffer=e.createBuffer({size:16,usage:72})}_ensureOutputBuffer(){const[e,t,r]=this.threadDim,n=e*t*r*4*this.componentCount;this.immutable&&this.pipeline&&this.outputBuffer&&(0===--this.outputBuffer._refs&&this.outputBuffer.destroy(),this.outputBuffer=null,this.bindGroupDirty=!0),this.outputBuffer&&this.outputBuffer.size>=n||(this.outputBuffer&&0===--this.outputBuffer._refs&&this.outputBuffer.destroy(),this._checkBufferSize(n,`output [${this.output.join(", ")}]`),this.outputBuffer=this._device.createBuffer({size:n,usage:132}),this.outputBuffer._refs=1,this.bindGroupDirty=!0)}_checkBufferSize(e,t){const r=this._device.limits,n=Math.min(r.maxStorageBufferBindingSize,r.maxBufferSize);if(e>n)throw new Error(`WebGPU backend: ${t} needs ${e} bytes but this device allows ${n} per storage buffer (maxStorageBufferBindingSize/maxBufferSize); reduce the output or split the work across kernels`)}_snapshotArguments(e){const t=new Array(e.length);for(let r=0;rthis._runInternal(e))}_runInternal(e){if(this.context&&this.context.isLost)throw new Error("WebGPU device was lost; call kernel.destroy() (or gpu.destroy()) and run again to rebuild on a fresh device");const t=this._device,r=t.queue,{arrayArgs:n,scalarArgs:s,bufferConstants:i}=this.paramsLayout,a=this.threadDim=Array.from(this.output);for(;a.length<3;)a.push(1);if(this._ensureOutputBuffer(),null!==this.paramsLayout.randomSeedOffset){const e=null!==this.randomSeed?this.randomSeed>>>0:4294967296*Math.random()>>>0;this.paramsU32[this.paramsLayout.randomSeedOffset/4]=e}this.paramsU32[0]=a[0],this.paramsU32[1]=a[1],this.paramsU32[2]=a[2],this.paramsU32[3]=this._computeDispatch(a).dispatchWidth;for(let s=0;s{const e=new Float32Array(p.buffer.getMappedRange(0,u).slice(0));return p.buffer.unmap(),this._releaseStaging(p),this._shapeOutput(e,d,this.componentCount)},e=>{throw this._releaseStaging(p),e})}_acquireStaging(e){for(let t=0;t=e)return r.busy=!0,r}const t={buffer:this._device.createBuffer({size:e,usage:9}),size:e,busy:!0,pooled:this.stagingPool.length<3};return t.pooled&&this.stagingPool.push(t),t}_releaseStaging(e){e.pooled?e.busy=!1:e.buffer.destroy()}_shapeOutput(e,t,r){const[n,s,i]=[t[0],t[1]||1,t[2]||1];if(1===r)switch(t.length){case 1:return c.erectMemoryOptimizedFloat(e,n);case 2:return c.erectMemoryOptimized2DFloat(e,n,s);default:return c.erectMemoryOptimized3DFloat(e,n,s,i)}const a=r,o=t=>{const r=new Array(n);for(let s=0;s{const t=new Float32Array(i.buffer.getMappedRange(0,s).slice(0));return i.buffer.unmap(),this._releaseStaging(i),this._shapeOutput(t,r,e.componentCount)},e=>{throw this._releaseStaging(i),e})}getPixels(e){if(!this.graphical)return Promise.reject(new Error("getPixels only works on a graphical kernel"));if(!this.outputBuffer)return Promise.reject(new Error("run the kernel before reading its pixels"));const[t,r]=this.output,n=t*r*4*4,s=this._acquireStaging(n),i=this._device.createCommandEncoder();return i.copyBufferToBuffer(this.outputBuffer,0,s.buffer,0,n),this._device.queue.submit([i.finish()]),s.buffer.mapAsync(1,0,n).then(()=>{const i=new Float32Array(s.buffer.getMappedRange(0,n).slice(0));s.buffer.unmap(),this._releaseStaging(s);const a=new Uint8ClampedArray(t*r*4);for(let n=0;n{throw this._releaseStaging(s),e})}destroy(e){if(this._blitParamsBuffer&&(this._blitParamsBuffer.destroy(),this._blitParamsBuffer=null),this._canvasContext&&(this._canvasContext.unconfigure(),this._canvasContext=null),this._blitPipeline=null,this._blitBindGroup=null,this._blitBoundOutputBuffer=null,this.paramsBuffer&&(this.paramsBuffer.destroy(),this.paramsBuffer=null),this.paramsLayout)for(let e=0;e{const r={i32:127,i64:126,f32:125,f64:124,v128:123},n=new DataView(new ArrayBuffer(16));function s(e,t){let r=e>>>0;do{let e=127&r;r>>>=7,0!==r&&(e|=128),t.push(e)}while(0!==r)}function i(e,t){let r=0|e;for(;;){const e=127&r;if(r>>=7,0===r&&!(64&e)||-1===r&&64&e)return void t.push(e);t.push(128|e)}}function a(e,t,r){let n=e>>>0;for(let e=0;e<4;e++)t[r+e]=127&n|128,n>>>=7;t[r+4]=127&n}function o(e,t){const r=[];for(let t=0;t65535&&t++,n<128?r.push(n):n<2048?r.push(192|n>>6,128|63&n):n<65536?r.push(224|n>>12,128|n>>6&63,128|63&n):r.push(240|n>>18,128|n>>12&63,128|n>>6&63,128|63&n)}s(r.length,t);for(let e=0;e3)throw new Error(`WasmModuleBuilder: lane index ${t} out of range for 4-lane shape`);return this.bytes.push(253,e,t),this}_push(e){for(let t=0;t${t.join(",")}`;if(r in this.typeIndexByKey)return this.typeIndexByKey[r];const n=this.types.length;return this.types.push({params:e,results:t}),this.typeIndexByKey[r]=n,n}addMemoryImport(e,t,r=!1){if(r&&null==t)throw new Error("WasmModuleBuilder: shared memory import requires a maximum");return this.memoryImport={initial:e,maximum:t,shared:r},this}addFuncImport(e,t,r,n="env"){if(e in this.funcImportIndexByName||e in this.functionIndexByName)throw new Error(`WasmModuleBuilder: duplicate function name "${e}"`);const s=this.funcImports.length;return this.funcImports.push({name:e,module:n,typeIndex:this._typeIndex(t,r)}),this.funcImportIndexByName[e]=s,s}addGlobal(e,t,r){return u(e),this.globals.push({type:e,mutable:t,initialValue:r}),this.globals.length-1}addFunction(e,{params:t=[],results:r=[],locals:n=[]}={}){if(e in this.funcImportIndexByName||e in this.functionIndexByName)throw new Error(`WasmModuleBuilder: duplicate function name "${e}"`);t.forEach(u),r.forEach(u),n.forEach(u);const s=new h(this,e,t,r,n);return this.functionIndexByName[e]=this.functions.length,this.functions.push({name:e,emitter:s,typeIndex:this._typeIndex(t,r)}),s}exportFunction(e,t=e){return this.exports.push({name:e,exportName:t}),this}_resolveFuncIndex(e){if(e in this.funcImportIndexByName)return this.funcImportIndexByName[e];if(e in this.functionIndexByName)return this.funcImports.length+this.functionIndexByName[e];throw new Error(`WasmModuleBuilder: call target "${e}" is not an import or a defined function`)}_section(e,t,r){r.push(e),s(t.length,r);for(let e=0;e0){const t=[];s(this.types.length,t);for(const{params:e,results:r}of this.types){t.push(96),s(e.length,t);for(const r of e)t.push(u(r));s(r.length,t);for(const e of r)t.push(u(e))}this._section(1,t,e)}if(null!==this.memoryImport||this.funcImports.length>0){const t=[];if(s((null!==this.memoryImport?1:0)+this.funcImports.length,t),null!==this.memoryImport){const{initial:e,maximum:r,shared:n}=this.memoryImport;o("env",t),o("memory",t),t.push(2);const i=null!=r;t.push(n?3:i?1:0),s(e,t),i&&s(r,t)}for(const{name:e,module:r,typeIndex:n}of this.funcImports)o(r,t),o(e,t),t.push(0),s(n,t);this._section(2,t,e)}if(this.functions.length>0){const t=[];s(this.functions.length,t);for(const{typeIndex:e}of this.functions)s(e,t);this._section(3,t,e)}if(this.globals.length>0){const t=[];s(this.globals.length,t);for(const{type:e,mutable:r,initialValue:s}of this.globals){if(t.push(u(e),r?1:0),"i32"===e)t.push(65),i(s,t);else if("f32"===e){t.push(67),n.setFloat32(0,s,!0);for(let e=0;e<4;e++)t.push(n.getUint8(e))}else{if("v128"!==e)throw new Error(`WasmModuleBuilder: no initializer encoding for global type "${e}"`);t.push(253,12);for(let e=0;e<16;e++)t.push(0)}t.push(11)}this._section(6,t,e)}if(this.exports.length>0){const t=[];s(this.exports.length,t);for(const{name:e,exportName:r}of this.exports)o(r,t),t.push(0),s(this._resolveFuncIndex(e),t);this._section(7,t,e)}if(this.functions.length>0){const t=[];s(this.functions.length,t);for(const{emitter:e}of this.functions){const r=e.bytes.slice();for(const{at:t,name:n}of e.callFixups)a(this._resolveFuncIndex(n),r,t);const n=[],i=[];for(const t of e.locals){const e=u(t);i.length>0&&i[i.length-1].type===e?i[i.length-1].count++:i.push({type:e,count:1})}s(i.length,n);for(const{type:e,count:t}of i)s(t,n),n.push(e);for(let e=0;e{const{utils:r}=i(),{FunctionNode:n}=l(),{WasmFunctionEmitter:s}=it();var a=class{constructor(){this.localCount=0}addLocal(){return this.localCount++}};for(const e of Object.getOwnPropertyNames(s.prototype))"constructor"!==e&&"addLocal"!==e&&"function"==typeof s.prototype[e]&&(a.prototype[e]=function(){return this});const o={sin:1,cos:1,tan:1,asin:1,acos:1,atan:1,atan2:2,sinh:1,cosh:1,tanh:1,asinh:1,acosh:1,atanh:1,exp:1,expm1:1,log:1,log2:1,log10:1,log1p:1,cbrt:1,pow:2,sign:1},u={abs:"f32Abs",floor:"f32Floor",ceil:"f32Ceil",sqrt:"f32Sqrt",trunc:"f32Trunc"},h={"+":"f32Add","-":"f32Sub","*":"f32Mul"},c={"+":"i32Add","-":"i32Sub","*":"i32Mul"},p={"==":"f32Eq","===":"f32Eq","!=":"f32Ne","!==":"f32Ne","<":"f32Lt",">":"f32Gt","<=":"f32Le",">=":"f32Ge"},d={"==":"i32Eq","===":"i32Eq","!=":"i32Ne","!==":"i32Ne","<":"i32LtS",">":"i32GtS","<=":"i32LeS",">=":"i32GeS"},m={"&":"i32And","|":"i32Or","^":"i32Xor","<<":"i32Shl",">>":"i32ShrS",">>>":"i32ShrU"},f={"+":"f32x4Add","-":"f32x4Sub","*":"f32x4Mul"},g={"+":"i32x4Add","-":"i32x4Sub","*":"i32x4Mul"},y={"==":"f32x4Eq","===":"f32x4Eq","!=":"f32x4Ne","!==":"f32x4Ne","<":"f32x4Lt",">":"f32x4Gt","<=":"f32x4Le",">=":"f32x4Ge"},x={"==":"i32x4Eq","===":"i32x4Eq","!=":"i32x4Ne","!==":"i32x4Ne","<":"i32x4LtS",">":"i32x4GtS","<=":"i32x4LeS",">=":"i32x4GeS"},b={"<<":"i32x4Shl",">>":"i32x4ShrS",">>>":"i32x4ShrU"},T={abs:"f32x4Abs",floor:"f32x4Floor",ceil:"f32x4Ceil",sqrt:"f32x4Sqrt",trunc:"f32x4Trunc"};function v(e){switch(e){case"Number":case"Float":case"LiteralInteger":return"f32";case"Integer":case"Boolean":return"i32";default:throw new Error(`WebAssembly backend does not yet support ${e} arguments to helper functions`)}}t.exports={WebAssemblyFunctionNode:class extends n{constructor(e,t){super(e,t),this.assembler=null,this.em=null,this.locals=null,this.depth=0,this.loopStack=null,this.usedMathImports=new Set,this.usesRandom=!1,this.readsThread=!1,this.taintedLocals=null,this.uniformity=[],this._analysisDone=!1,this._analysisPass=!1,this.vec=!1,this.vMaskDepth=0,this.vCur=-1,this.vRetMask=-1,this.vTerminated=!1,this.vInfo=null,this._vBaseX=-1}mangleFunctionName(e){return`fn_${r.sanitizeName(e)}`}getType(e){if(e&&"ConditionalExpression"===e.type){const t=this.getType(e.consequent);if("Integer"===t||"LiteralInteger"===t){const t=this.getType(e.alternate);if("Number"===t||"Float"===t)return"Number"}}return super.getType(e)}toString(){return this._analysisDone||(this._analysisDone=!0,this._analysisPass=!0,this.walkFunction(new a),this._analysisPass=!1),""}emitFunction(e){this.assembler=e;const{module:t}=e;let r;if(this.isRootKernel)r=t.addFunction("kernel",{params:[],results:[]});else{const e=this.argumentTypes.map(e=>v("LiteralInteger"===e?"Number":e)),n=[];if(this.returnType)switch(this.returnType){case"Integer":case"Boolean":n.push("i32");break;case"Number":case"Float":case"LiteralInteger":n.push("f32");break;default:throw new Error(`WebAssembly backend does not yet support helper functions returning ${this.returnType}`)}r=t.addFunction(this.mangleFunctionName(this.name),{params:e,results:n})}return this.walkFunction(r),!this.isRootKernel&&this.returnType&&r.unreachable(),r}walkFunction(e){this.em=e,this.locals=new Map,this.depth=0,this.loopStack=[],this.taintedLocals=new Set;const t=this.getJsAST();if(this.isRootKernel)for(const r of this.collectAssignedArgumentNames(t)){const t=this.argumentNames.indexOf(r),n=this.argumentTypes[t];if("Number"!==n&&"Float"!==n&&"Integer"!==n&&"Boolean"!==n)continue;const s=this.assembler?this.assembler.layout.scalars[r]:null,i=s?s.offset:0,a="Integer"===n||"Boolean"===n?"i32":"f32",o=e.addLocal(a);e.i32Const(0),"i32"===a?e.i32Load(i):e.f32Load(i),e.localSet(o),this.locals.set(r,{kind:"scalar",index:o,wtype:a,gtype:n})}if(!this.isRootKernel){for(let e=0;e{if(n&&"object"==typeof n){if(Array.isArray(n))return n.forEach(r);if("FunctionDeclaration"!==n.type||n===e){"AssignmentExpression"===n.type&&"Identifier"===n.left.type&&-1!==this.argumentNames.indexOf(n.left.name)&&t.add(n.left.name),"UpdateExpression"===n.type&&"Identifier"===n.argument.type&&-1!==this.argumentNames.indexOf(n.argument.name)&&t.add(n.argument.name);for(const e in n){if("loc"===e||"start"===e||"end"===e||"parent"===e)continue;const t=n[e];t&&"object"==typeof t&&r(t)}}}};return r(e.body),t}enterBlock(e){this.em.block(e),this.depth++}enterLoop(e){this.em.loop(e),this.depth++}enterIf(e){this.em.if_(e),this.depth++}exit(){this.em.end(),this.depth--}brTo(e){this.em.br(this.depth-e)}brIfTo(e){this.em.brIf(this.depth-e)}get loopMax(){return parseInt(this.loopMaxIterations,10)||1e3}coerce(e,t){if(e===t)return t;if("void"===e)throw new Error("cannot use a void expression as a value");switch(t){case"f32":return this.em.f32ConvertI32S(),"f32";case"i32":return"f32"===e&&this.em.i32TruncSatF32S(),"i32";case"bool":return"f32"===e?this.em.f32Const(0).f32Ne():this.em.i32Eqz().i32Eqz(),"bool";default:throw new Error(`unknown wasm value category ${t}`)}}castLiteralToInteger(e){this.pushState("casting-to-integer");const t=this.expression(e);return this.popState("casting-to-integer"),this.coerce(t,"i32"),"i32"}castLiteralToFloat(e){this.pushState("casting-to-float");const t=this.expression(e);return this.popState("casting-to-float"),this.coerce(t,"f32"),"f32"}castValueToInteger(e){this.pushState("casting-to-integer");const t=this.expression(e);return this.popState("casting-to-integer"),this.coerce(t,"i32"),"i32"}castValueToFloat(e){this.pushState("casting-to-float");const t=this.expression(e);return this.popState("casting-to-float"),this.coerce(t,"f32"),"f32"}emitByType(e,t){const r=this.getType(e);return"f32"===t?"Integer"===r?this.castValueToFloat(e):"LiteralInteger"===r?this.castLiteralToFloat(e):(this.coerce(this.expression(e),"f32"),"f32"):"Number"===r||"Float"===r?this.castValueToInteger(e):"LiteralInteger"===r?this.castLiteralToInteger(e):(this.coerce(this.expression(e),"i32"),"i32")}emitCondition(e){const t=this.expression(e);if("bool"!==t)if("i32"!==t){if("f32"!==t)throw this.astErrorOutput("cannot use a void expression as a condition",e);this.em.f32Const(0).f32Ne()}else this.em.i32Eqz().i32Eqz()}statement(e){switch(e.type){case"VariableDeclaration":return this.stmtVariableDeclaration(e);case"ExpressionStatement":return this.statementExpression(e.expression);case"ReturnStatement":return this.stmtReturn(e);case"IfStatement":return this.stmtIf(e);case"ForStatement":return this.stmtFor(e);case"WhileStatement":return this.stmtWhile(e);case"DoWhileStatement":return this.stmtDoWhile(e);case"BlockStatement":for(let t=0;tthis.castValueToFloat(s));else switch(i.valueType=u,u){case"Number":case"Float":this.setScalarLocal(o,"f32",u,()=>{"LiteralInteger"===a?this.castLiteralToFloat(s):"Integer"===a?this.castValueToFloat(s):this.coerce(this.expression(s),"f32")});break;case"Integer":this.setScalarLocal(o,"i32","Integer",()=>{"LiteralInteger"===a?this.castLiteralToInteger(s):"Number"===a||"Float"===a?this.castValueToInteger(s):this.coerce(this.expression(s),"i32")});break;case"Boolean":this.setScalarLocal(o,"i32","Boolean",()=>this.emitCondition(s));break;default:throw this.astErrorOutput(`WebAssembly backend does not yet support declaring type ${u}`,e)}this.isThreadDependent(s)&&this.taintedLocals.add(o)}}setScalarLocal(e,t,r,n){let s=this.locals.get(e);s&&"scalar"===s.kind&&s.wtype===t?s.gtype=r:(s={kind:"scalar",index:this.em.addLocal(t),wtype:t,gtype:r},this.locals.set(e,s)),n(),this.em.localSet(s.index)}declareVecLocal(e,t,r,n,s){const i=parseInt(t.substring(6),10);n.valueType=t;let a=this.locals.get(e);if(!a||"vec"!==a.kind||a.n!==i){const r=[];for(let e=0;ethis.em.localSet(r.index);else{if(r||!this.isRootKernel||-1===this.argumentNames.indexOf(t))throw this.astErrorOutput(`cannot assign to "${t}"`,e);{const r=this.argumentTypes[this.argumentNames.indexOf(t)],i=this.assembler?this.assembler.layout.scalars[t]:null;if(this.assembler&&!i)throw this.astErrorOutput(`WebAssembly backend does not yet support assigning to the array argument "${t}"`,e);const a=i?i.offset:0;n="Integer"===r||"Boolean"===r?"i32":"f32",this.em.i32Const(0),s=()=>"i32"===n?this.em.i32Store(a):this.em.f32Store(a)}}if("="===e.operator){const t=this.getType(e.left),r=this.getType(e.right);"Integer"!==t&&"Integer"===r?(this.castValueToFloat(e.right),this.coerce("f32",n)):"Integer"!==t&&"LiteralInteger"===r?(this.castLiteralToFloat(e.right),this.coerce("f32",n)):"Integer"===t&&"LiteralInteger"===r?(this.castLiteralToInteger(e.right),this.coerce("i32",n)):"Integer"!==t||"Number"!==r&&"Float"!==r?this.coerce(this.expression(e.right),n):(this.castValueToInteger(e.right),this.coerce("i32",n))}else{const t={type:"BinaryExpression",operator:e.operator.slice(0,-1),left:e.left,right:e.right};this.coerce(this.exprBinary(t),n)}s(),(this.isThreadDependent(e.right)||"="!==e.operator&&this.taintedLocals.has(t))&&this.taintedLocals.add(t)}emitUpdate(e,t){if("Identifier"!==e.argument.type)throw this.astErrorOutput("update expression needs a variable",e);const r=this.locals.get(e.argument.name);if(!r||"scalar"!==r.kind)throw this.astErrorOutput(`cannot update "${e.argument.name}"`,e);const n="i32"===r.wtype,s=()=>n?this.em.i32Const(1):this.em.f32Const(1),i="++"===e.operator?n?"i32Add":"f32Add":n?"i32Sub":"f32Sub";return t?(this.em.localGet(r.index),s(),this.em[i]().localSet(r.index),"void"):(e.prefix?(this.em.localGet(r.index),s(),this.em[i]().localTee(r.index)):(this.em.localGet(r.index).localGet(r.index),s(),this.em[i]().localSet(r.index)),r.wtype)}stmtReturn(e){if(!e.argument){if(this.isRootKernel)return void this.em.return_();throw this.astErrorOutput("Unexpected return statement",e)}this.pushState("skip-literal-correction");const t=this.getType(e.argument);if(this.popState("skip-literal-correction"),this.returnType||(this.returnType="LiteralInteger"===t||"Integer"===t?"Number":t),this.isRootKernel)return this.stmtRootReturn(e,t);if(this.isSubKernel)throw this.astErrorOutput("WebAssembly backend does not yet support createKernelMap",e);switch(this.returnType){case"LiteralInteger":case"Number":case"Float":"Integer"===t?this.castValueToFloat(e.argument):"LiteralInteger"===t?this.castLiteralToFloat(e.argument):this.coerce(this.expression(e.argument),"f32");break;case"Integer":"Float"===t||"Number"===t?this.castValueToInteger(e.argument):"LiteralInteger"===t?this.castLiteralToInteger(e.argument):this.coerce(this.expression(e.argument),"i32");break;case"Boolean":this.emitCondition(e.argument);break;default:throw this.astErrorOutput(`unhandled return type ${this.returnType}`,e)}this.em.return_()}stmtRootReturn(e,t){const r=this.assembler?this.assembler.globals:{dataIndex:0},n=this.assembler?this.assembler.layout.outputOffset:0;switch(this.returnType){case"Array(2)":case"Array(3)":case"Array(4)":{const t=parseInt(this.returnType.substring(6),10),s=e.argument;if("ArrayExpression"===s.type){if(s.elements.length!==t)throw this.astErrorOutput(`expected ${t} array elements to match return type ${this.returnType}`,e);for(let e=0;e1&&(t=!1);for(let e=0;e{if(e===a.length)return o&&this.emitSwitchConsequent(o),!1;const{tests:t,consequent:r}=a[e];for(let e=0;e0&&this.em.i32Or();return this.enterIf(),this.emitSwitchConsequent(r),(e+10&&(r.push({tests:n,consequent:e[s].consequent}),n=[])):t=e[s].consequent;return{groups:r,defaultConsequent:t}}collectSwitchCaseStatements(e){const t=[];for(let r=0;r{if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(r);if("BreakStatement"===e.type)return!0;if("ForStatement"===e.type||"WhileStatement"===e.type||"DoWhileStatement"===e.type||"SwitchStatement"===e.type)return!1;for(const t in e)if("loc"!==t&&"range"!==t&&"parent"!==t&&r(e[t]))return!0;return!1};for(let e=0;e{const r=this.getType(t);switch(n){case"Number":case"Float":"Integer"===r?this.castValueToFloat(t):"LiteralInteger"===r?this.castLiteralToFloat(t):this.coerce(this.expression(t),"f32");break;case"Integer":"Number"===r||"Float"===r?this.castValueToInteger(t):"LiteralInteger"===r?this.castLiteralToInteger(t):this.coerce(this.expression(t),"i32");break;case"Boolean":this.emitCondition(t);break;default:throw this.astErrorOutput(`WebAssembly backend does not yet support a ternary of type ${n}`,e)}};return this.emitCondition(e.test),this.enterIf(s),i(e.consequent),this.em.else_(),i(e.alternate),this.exit(),"Boolean"===n?"bool":s}exprCall(e){if(!e.callee)throw this.astErrorOutput("Unknown CallExpression",e);if("MemberExpression"===e.callee.type&&"this.color"===this.getVariableSignature(e.callee,!0))throw this.astErrorOutput("WebAssembly backend does not yet support graphical mode (this.color)",e);let t=null;const r=this.isAstMathFunction(e);if(t=r||e.callee.object&&"ThisExpression"===e.callee.object.type?e.callee.property.name:"SequenceExpression"!==e.callee.type||"Literal"!==e.callee.expressions[0].type||isNaN(e.callee.expressions[0].raw)?e.callee.name:e.callee.expressions[1].property.name,!t)throw this.astErrorOutput("Unhandled function, couldn't find name",e);if(this.calledFunctions.indexOf(t)<0&&this.calledFunctions.push(t),this.onFunctionCall&&this.onFunctionCall(this.name,t,e.arguments),r)return this.emitMathCall(t,e);const n=this.getType(e),s=this.lookupFunctionArgumentTypes(t)||[];for(let r=0;r{switch(this.getType(e)){case"Integer":this.castValueToFloat(e);break;case"LiteralInteger":this.castLiteralToFloat(e);break;default:this.coerce(this.expression(e),"f32")}},n=u[e];if(n)return r(t.arguments[0]),this.em[n](),"f32";switch(e){case"round":return r(t.arguments[0]),this.em.f32Const(.5).f32Add().f32Floor(),"f32";case"fround":return r(t.arguments[0]),"f32";case"min":case"max":{const n="min"===e?"f32Min":"f32Max";r(t.arguments[0]);for(let e=1;e0&&this.emitClampScalarIndex(a.dims[0]*a.dims[1]*a.dims[2]-1),this.em.i32Const(2).i32Shl(),this.em.f32Load(a.offset),"f32"}emitClampScalarIndex(e){const t=this.em.addLocal("i32");this.em.localSet(t),this.em.localGet(t).i32Const(0).localGet(t).i32Const(0).i32GeS().select(),this.em.localSet(t),this.em.localGet(t).i32Const(e).localGet(t).i32Const(e).i32LeS().select()}emitVecIndex(e,t){if("Literal"===t.type&&Number.isInteger(t.value)){if(t.value<0||t.value>=e.n)throw this.astErrorOutput(`index ${t.value} out of range for Array(${e.n})`,t);return this.em.localGet(e.indices[t.value]),"f32"}const r=this.em.addLocal("i32");this.emitIndex(t),this.em.localSet(r),this.em.localGet(e.indices[0]);for(let t=1;t{if(!e||"object"!=typeof e)return!1;switch(e.type){case"Literal":case"ThisExpression":return!1;case"Identifier":return t.has(e.name);case"MemberExpression":return e.computed||"MemberExpression"!==e.object.type||e.object.computed||!e.object.property||"thread"!==e.object.property.name?e.computed?a(e.object)||a(e.property):a(e.object):"x"===e.property.name;case"BinaryExpression":case"LogicalExpression":return a(e.left)||a(e.right);case"UnaryExpression":case"UpdateExpression":return a(e.argument);case"ConditionalExpression":return a(e.test)||a(e.consequent)||a(e.alternate);case"CallExpression":return!i.isAstMathFunction(e)||("random"===e.callee.property.name||e.arguments.some(a));case"SequenceExpression":return e.expressions.some(a);case"ArrayExpression":return e.elements.some(a);case"AssignmentExpression":return a(e.right)||"Identifier"===e.left.type&&t.has(e.left.name);default:return!0}},o=e=>{e&&!t.has(e)&&(t.add(e),s=!0)},u=(e,t)=>{if(e&&"object"==typeof e){if(Array.isArray(e))return e.forEach(e=>u(e,t));switch(e.type){case"UpdateExpression":return"Identifier"===e.argument.type&&(-1!==i.argumentNames.indexOf(e.argument.name)&&(r.has(e.argument.name)||(r.add(e.argument.name),s=!0),o(e.argument.name)),t&&o(e.argument.name)),u(e.argument,t);case"AssignmentExpression":return"Identifier"===e.left.type&&(-1!==i.argumentNames.indexOf(e.left.name)&&(r.has(e.left.name)||(r.add(e.left.name),s=!0),o(e.left.name)),t&&o(e.left.name)),u(e.left,t),u(e.right,t);case"ConditionalExpression":{u(e.test,t);const r=t||a(e.test);return u(e.consequent,r),u(e.alternate,r)}case"LogicalExpression":return u(e.left,t),u(e.right,!0);default:for(const r in e){if("loc"===r||"start"===r||"end"===r||"parent"===r)continue;const n=e[r];n&&"object"==typeof n&&u(n,t)}}}},l=(e,t)=>{if(e&&"object"==typeof e){if(Array.isArray(e))return e.forEach(e=>l(e,t));switch(e.type){case"VariableDeclarator":e.id&&"Identifier"===e.id.type&&t.push(e.id.name);break;case"AssignmentExpression":"Identifier"===e.left.type&&t.push(e.left.name);break;case"UpdateExpression":"Identifier"===e.argument.type&&t.push(e.argument.name);break;case"FunctionDeclaration":return}for(const r in e){if("loc"===r||"start"===r||"end"===r||"parent"===r)continue;const n=e[r];n&&"object"==typeof n&&l(n,t)}}},h=(e,t)=>{if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(e=>h(e,t));switch(e.type){case"BreakStatement":case"ContinueStatement":return t;case"ForStatement":case"WhileStatement":case"DoWhileStatement":case"FunctionDeclaration":return!1;case"IfStatement":{const r=t||a(e.test);return!!h(e.consequent,r)||!!e.alternate&&h(e.alternate,r)}case"ConditionalExpression":{const r=t||a(e.test);return h(e.consequent,r)||h(e.alternate,r)}case"SwitchStatement":{const r=t||a(e.discriminant)||e.cases.some(e=>e.test&&a(e.test));return e.cases.some(e=>e.consequent.some(e=>"BreakStatement"!==e.type&&h(e,r)))}default:for(const r in e){if("loc"===r||"start"===r||"end"===r||"parent"===r)continue;const n=e[r];if(n&&"object"==typeof n&&h(n,t))return!0}return!1}},c=(e,n)=>{switch(e.type){case"AssignmentExpression":if("Identifier"===e.left.type){const u=e.left.name;-1!==i.argumentNames.indexOf(u)&&(r.has(u)||(r.add(u),s=!0),o(u)),(n||a(e.right)||"="!==e.operator&&t.has(u))&&o(u)}return u(e.right,n);case"UpdateExpression":if("Identifier"===e.argument.type){const t=e.argument.name;-1!==i.argumentNames.indexOf(t)&&(r.has(t)||(r.add(t),s=!0),o(t)),n&&o(t)}return;case"SequenceExpression":return e.expressions.forEach(e=>c(e,n));default:return u(e,n)}},p=(e,t)=>{if(e)switch(e.type){case"VariableDeclaration":for(const r of e.declarations)r.init&&((t||a(r.init))&&o(r.id.name),u(r.init,t));return;case"ExpressionStatement":return c(e.expression,t);case"ReturnStatement":return t&&(n=!0),void(e.argument&&u(e.argument,t));case"IfStatement":{u(e.test,t);const r=t||a(e.test);return p(e.consequent,r),void(e.alternate&&p(e.alternate,r))}case"ForStatement":case"WhileStatement":case"DoWhileStatement":{const r=t||!!e.test&&a(e.test)||h(e.body,!1);if(r){const t=[];e.init&&l(e.init,t),l(e.body,t),e.update&&l(e.update,t),t.forEach(o)}return e.init&&("VariableDeclaration"===e.init.type?p(e.init,t):c(e.init,t)),p(e.body,r),e.update&&c(e.update,r),void(e.test&&u(e.test,r))}case"SwitchStatement":{const r=t||a(e.discriminant)||e.cases.some(e=>e.test&&a(e.test));for(const t of e.cases)for(const e of t.consequent)p(e,r);return}case"BlockStatement":return e.body.forEach(e=>p(e,t));default:return}};for(;s;)s=!1,p(e.body,!1);return{varying:t,varyingReturn:n,assignedArgs:r,exprVarying:a,hasVaryingExit:h}}vZero(){return this.em.v128ConstI32x4(0,0,0,0),this}vInnermostVaryingLoop(){const e=this.vLoopStack[this.vLoopStack.length-1];return e&&e.varying?e:null}vRecomputeCur(e){const t=this.em;t.localGet(e),-1!==this.vRetMask&&t.localGet(this.vRetMask).v128Andnot();const r=this.vInnermostVaryingLoop();r&&(-1!==r.vBrk&&t.localGet(r.vBrk).v128Andnot(),-1!==r.vCnt&&t.localGet(r.vCnt).v128Andnot()),t.localSet(this.vCur)}vLoopBodyExits(e){let t=!1,r=!1;const n=e=>{if(!(!e||"object"!=typeof e||t&&r)){if(Array.isArray(e))return e.forEach(n);switch(e.type){case"BreakStatement":return void(t=!0);case"ContinueStatement":return void(r=!0);case"ForStatement":case"WhileStatement":case"DoWhileStatement":case"FunctionDeclaration":return;case"SwitchStatement":for(const t of e.cases)for(const e of t.consequent)"BreakStatement"!==e.type&&n(e);return}for(const t in e){if("loc"===t||"start"===t||"end"===t||"parent"===t)continue;const r=e[t];r&&"object"==typeof r&&n(r)}}};return n(e),{hasBreak:t,hasContinue:r}}vSetLocal(e){const t=this.em;this.vMaskDepth>0&&t.localGet(e).localGet(this.vCur).v128Bitselect(),t.localSet(e)}vCoerce(e,t){if(e===t)return t;const r=this.em;switch(e){case"f32":case"i32":case"bool":if("vf32"===t)return this.coerce(e,"f32"),r.f32x4Splat(),t;if("vi32"===t)return this.coerce(e,"i32"),r.i32x4Splat(),t;if("vbool"===t)return this.coerce(e,"i32"),r.i32x4Splat(),this.vZero(),r.i32x4Ne(),t;break;case"vf32":if("vi32"===t)return r.i32x4TruncSatF32x4S(),t;if("vbool"===t)return r.v128ConstF32x4(0,0,0,0).f32x4Ne(),t;break;case"vi32":if("vf32"===t)return r.f32x4ConvertI32x4S(),t;if("vbool"===t)return this.vZero(),r.i32x4Ne(),t;break;case"vbool":if("vi32"===t)return r.v128ConstI32x4(1,1,1,1).v128And(),t;if("vf32"===t)return r.v128ConstI32x4(1,1,1,1).v128And().f32x4ConvertI32x4S(),t}throw new Error(`cannot convert ${e} to ${t}`)}vCastLiteralToInteger(e){this.pushState("casting-to-integer");const t=this.vexpr(e);return this.popState("casting-to-integer"),this.vCoerce(t,"vi32"),"vi32"}vCastLiteralToFloat(e){this.pushState("casting-to-float");const t=this.vexpr(e);return this.popState("casting-to-float"),this.vCoerce(t,"vf32"),"vf32"}vCastValueToInteger(e){this.pushState("casting-to-integer");const t=this.vexpr(e);return this.popState("casting-to-integer"),this.vCoerce(t,"vi32"),"vi32"}vCastValueToFloat(e){this.pushState("casting-to-float");const t=this.vexpr(e);return this.popState("casting-to-float"),this.vCoerce(t,"vf32"),"vf32"}vEmitByType(e,t){const r=this.getType(e);return"vf32"===t?"Integer"===r?this.vCastValueToFloat(e):"LiteralInteger"===r?this.vCastLiteralToFloat(e):(this.vCoerce(this.vexpr(e),"vf32"),"vf32"):"Number"===r||"Float"===r?this.vCastValueToInteger(e):"LiteralInteger"===r?this.vCastLiteralToInteger(e):(this.vCoerce(this.vexpr(e),"vi32"),"vi32")}vexprMask(e){const t=this.vexpr(e);if("vbool"!==t)return"vi32"===t?(this.vZero(),void this.em.i32x4Ne()):void("vf32"!==t?(this.coerce(t,"bool"),this.em.i32x4Splat(),this.vZero(),this.em.i32x4Ne()):this.em.v128ConstF32x4(0,0,0,0).f32x4Ne())}vstatement(e){switch(e.type){case"VariableDeclaration":return this.vstmtVariableDeclaration(e);case"ExpressionStatement":return this.vstatementExpression(e.expression);case"ReturnStatement":return this.vstmtReturn(e);case"IfStatement":return this.vstmtIf(e);case"ForStatement":return this.vstmtFor(e);case"WhileStatement":return this.vstmtWhile(e);case"DoWhileStatement":return this.vstmtDoWhile(e);case"BlockStatement":for(let t=0;tthis.vCastValueToFloat(n));switch(i.valueType=o,o){case"Number":case"Float":this.vSetVaryingScalar(s,"vf32",o,()=>{"LiteralInteger"===a?this.vCastLiteralToFloat(n):"Integer"===a?this.vCastValueToFloat(n):this.vCoerce(this.vexpr(n),"vf32")});break;case"Integer":this.vSetVaryingScalar(s,"vi32","Integer",()=>{"LiteralInteger"===a?this.vCastLiteralToInteger(n):"Number"===a||"Float"===a?this.vCastValueToInteger(n):this.vCoerce(this.vexpr(n),"vi32")});break;case"Boolean":this.vSetVaryingScalar(s,"vi32","Boolean",()=>{this.vexprMask(n),this.em.v128ConstI32x4(1,1,1,1).v128And()});break;default:throw this.astErrorOutput(`WebAssembly backend does not yet support declaring type ${o}`,t)}}vSetVaryingScalar(e,t,r,n){let s=this.locals.get(e);s&&"vscalar"===s.kind&&s.wtype===t?s.gtype=r:(s={kind:"vscalar",index:this.em.addLocal("v128"),wtype:t,gtype:r},this.locals.set(e,s)),n(),this.vSetLocal(s.index)}vEmitArrayElement(e){switch(this.getType(e)){case"Integer":this.vCastValueToFloat(e);break;case"LiteralInteger":this.vCastLiteralToFloat(e);break;default:this.vCoerce(this.vexpr(e),"vf32")}}vAssign(e){if("Identifier"!==e.left.type)throw this.astErrorOutput(`WebAssembly backend does not yet support assignment to ${e.left.type}`,e);const t=e.left.name,r=this.locals.get(t);if(r&&"scalar"===r.kind)return this.emitAssignment(e);if(!r||"vscalar"!==r.kind)throw this.astErrorOutput(`cannot assign to "${t}"`,e);const n=r.wtype;if("="===e.operator){const t=this.getType(e.left),r=this.getType(e.right);"Integer"!==t&&"Integer"===r?(this.vCastValueToFloat(e.right),this.vCoerce("vf32",n)):"Integer"!==t&&"LiteralInteger"===r?(this.vCastLiteralToFloat(e.right),this.vCoerce("vf32",n)):"Integer"===t&&"LiteralInteger"===r?(this.vCastLiteralToInteger(e.right),this.vCoerce("vi32",n)):"Integer"!==t||"Number"!==r&&"Float"!==r?this.vCoerce(this.vexpr(e.right),n):(this.vCastValueToInteger(e.right),this.vCoerce("vi32",n))}else{const t={type:"BinaryExpression",operator:e.operator.slice(0,-1),left:e.left,right:e.right};this.vCoerce(this.vexprBinary(t),n)}this.vSetLocal(r.index)}vUpdate(e,t){if("Identifier"!==e.argument.type)throw this.astErrorOutput("update expression needs a variable",e);const r=this.locals.get(e.argument.name);if(r&&"scalar"===r.kind)return this.emitUpdate(e,t);if(!r||"vscalar"!==r.kind)throw this.astErrorOutput(`cannot update "${e.argument.name}"`,e);const n=this.em,s="vi32"===r.wtype,i=()=>s?n.v128ConstI32x4(1,1,1,1):n.v128ConstF32x4(1,1,1,1),a="++"===e.operator?s?"i32x4Add":"f32x4Add":s?"i32x4Sub":"f32x4Sub";if(t)return n.localGet(r.index),i(),n[a](),this.vSetLocal(r.index),"void";if(e.prefix)n.localGet(r.index),i(),n[a](),this.vSetLocal(r.index),n.localGet(r.index);else{const e=n.addLocal("v128");n.localGet(r.index).localSet(e),n.localGet(r.index),i(),n[a](),this.vSetLocal(r.index),n.localGet(e)}return r.wtype}vstmtIf(e){const t=this.em;if(!this.vInfo.exprVarying(e.test))return this.emitCondition(e.test),this.enterIf(),this.vstatementBody(e.consequent),e.alternate&&(t.else_(),this.vstatementBody(e.alternate)),void this.exit();const r=t.addLocal("v128");this.vexprMask(e.test),t.localSet(r);const n=t.addLocal("v128");t.localGet(this.vCur).localSet(n),t.localGet(n).localGet(r).v128And().localSet(this.vCur),t.localGet(this.vCur).v128AnyTrue(),this.enterIf(),this.vMaskDepth++,this.vstatementBody(e.consequent),this.vMaskDepth--,this.exit(),e.alternate&&(t.localGet(n).localGet(r).v128Andnot().localSet(this.vCur),t.localGet(this.vCur).v128AnyTrue(),this.enterIf(),this.vMaskDepth++,this.vstatementBody(e.alternate),this.vMaskDepth--,this.exit()),this.vRecomputeCur(n)}vstmtReturn(e){const t=this.em;if(!e.argument)return void this.vRetireOrReturn();this.pushState("skip-literal-correction");const r=this.getType(e.argument);switch(this.popState("skip-literal-correction"),this.returnType){case"Array(2)":case"Array(3)":case"Array(4)":{const r=parseInt(this.returnType.substring(6),10),n=e.argument,s=[];if("ArrayExpression"===n.type){if(n.elements.length!==r)throw this.astErrorOutput(`expected ${r} array elements to match return type ${this.returnType}`,e);for(let e=0;e0?i=this.vCur:-1!==this.vRetMask&&(i=t.addLocal("v128"),t.localGet(this.vRetMask).v128Not().localSet(i));const a=t.addLocal("i32");if(1===s)return t.globalGet(r.dataIndex).i32Const(2).i32Shl().localSet(a),void(-1===i?t.localGet(a).localGet(e[0]).v128Store(n,2):(t.localGet(a),t.localGet(e[0]),t.localGet(a).v128Load(n,2),t.localGet(i).v128Bitselect(),t.v128Store(n,2)));t.globalGet(r.dataIndex).i32Const(s).i32Mul().i32Const(2).i32Shl().localSet(a);for(let r=0;r<4;r++)for(let o=0;oe.test&&this.vInfo.exprVarying(e.test)),i=this.getType(t);if(!s){let s,a;switch(i){case"Float":case"Number":a=!1,s=n.addLocal("f32"),this.coerce(this.expression(t),"f32"),n.localSet(s);break;case"Integer":a=!0,s=n.addLocal("i32"),this.coerce(this.expression(t),"i32"),n.localSet(s);break;default:throw this.astErrorOutput(`Unhandled switch discriminant type "${i}"`,e)}if(1===r.length&&!r[0].test)return void this.vEmitSwitchConsequent(r[0].consequent);const{groups:o,defaultConsequent:u}=this.collectSwitchGroups(r),l=e=>{if(e===o.length)return void(u&&this.vEmitSwitchConsequent(u));const{tests:t,consequent:r}=o[e];for(let e=0;e0&&n.i32Or();this.enterIf(),this.vEmitSwitchConsequent(r),(e+10&&n.v128Or();n.localSet(p),this.vRecomputeCur(h),n.localGet(this.vCur).localGet(p).v128And().localGet(c).v128Andnot().localSet(this.vCur),n.localGet(c).localGet(p).v128Or().localSet(c),n.localGet(this.vCur).v128AnyTrue(),this.enterIf(),this.vEmitSwitchConsequent(r),this.exit()}l&&(this.vRecomputeCur(h),n.localGet(this.vCur).localGet(c).v128Andnot().localSet(this.vCur),n.localGet(this.vCur).v128AnyTrue(),this.enterIf(),this.vEmitSwitchConsequent(l),this.exit()),this.vMaskDepth--,this.vRecomputeCur(h)}vEmitSwitchTest(e,t){const r=this.getType(e);t?"Number"===r||"Float"===r?this.vCastValueToInteger(e):"LiteralInteger"===r?this.vCastLiteralToInteger(e):this.vCoerce(this.vexpr(e),"vi32"):"LiteralInteger"===r?this.vCastLiteralToFloat(e):"Integer"===r?this.vCastValueToFloat(e):this.vCoerce(this.vexpr(e),"vf32")}vEmitSwitchConsequent(e){const t=this.collectSwitchCaseStatements(e),r=this.vTerminated;this.vTerminated=!1;for(let e=0;e{const r=this.getType(t);switch(s){case"Number":case"Float":"Integer"===r?this.vCastValueToFloat(t):"LiteralInteger"===r?this.vCastLiteralToFloat(t):this.vCoerce(this.vexpr(t),"vf32");break;case"Integer":"Number"===r||"Float"===r?this.vCastValueToInteger(t):"LiteralInteger"===r?this.vCastLiteralToInteger(t):this.vCoerce(this.vexpr(t),"vi32");break;case"Boolean":this.vexprMask(t);break;default:throw this.astErrorOutput(`WebAssembly backend does not yet support a ternary of type ${s}`,e)}},a="Integer"===s?"vi32":"Boolean"===s?"vbool":"vf32";if(!this.vInfo.exprVarying(e.test))return this.emitCondition(e.test),this.enterIf("v128"),i(e.consequent),t.else_(),i(e.alternate),this.exit(),a;const o=t.addLocal("v128");this.vexprMask(e.test),t.localSet(o);const u=t.addLocal("v128");t.localGet(this.vCur).localSet(u);const l=t.addLocal("v128"),h=t.addLocal("v128");return t.localGet(u).localGet(o).v128And().localSet(this.vCur),this.vMaskDepth++,i(e.consequent),t.localSet(l),t.localGet(u).localGet(o).v128Andnot().localSet(this.vCur),i(e.alternate),t.localSet(h),this.vMaskDepth--,t.localGet(u).localSet(this.vCur),t.localGet(l).localGet(h).localGet(o).v128Bitselect(),a}vTernaryStatement(e){const t=this.em;if(!this.vInfo.exprVarying(e.test))return this.emitCondition(e.test),this.enterIf(),this.vstatementExpression(e.consequent),t.else_(),this.vstatementExpression(e.alternate),void this.exit();const r=t.addLocal("v128");this.vexprMask(e.test),t.localSet(r);const n=t.addLocal("v128");t.localGet(this.vCur).localSet(n),t.localGet(n).localGet(r).v128And().localSet(this.vCur),this.vMaskDepth++,this.vstatementExpression(e.consequent),t.localGet(n).localGet(r).v128Andnot().localSet(this.vCur),this.vstatementExpression(e.alternate),this.vMaskDepth--,t.localGet(n).localSet(this.vCur)}vexprCall(e){if(!e.callee)throw this.astErrorOutput("Unknown CallExpression",e);if("MemberExpression"===e.callee.type&&"this.color"===this.getVariableSignature(e.callee,!0))throw this.astErrorOutput("WebAssembly backend does not yet support graphical mode (this.color)",e);let t=null;const r=this.isAstMathFunction(e);if(t=r||e.callee.object&&"ThisExpression"===e.callee.object.type?e.callee.property.name:"SequenceExpression"!==e.callee.type||"Literal"!==e.callee.expressions[0].type||isNaN(e.callee.expressions[0].raw)?e.callee.name:e.callee.expressions[1].property.name,!t)throw this.astErrorOutput("Unhandled function, couldn't find name",e);return r?this.vMathCall(t,e):this.vUserCall(t,e)}vUserCall(e,t){const r=this.em,n=this.assembler.helperInfo||{readsThread:!1,usesRandom:!1},s=this.assembler.globals,i=this.getType(t),a=this.lookupFunctionArgumentTypes(e)||[],o=[];for(let n=0;n0&&r.i32Const(t).i32Add(),r.globalSet(s.threadX)),n.usesRandom&&r.localGet(c).i32x4ExtractLane(t).globalSet(s.pcgState);for(const e of o)r.localGet(e.index),"vi32"===e.wtype?r.i32x4ExtractLane(t):r.f32x4ExtractLane(t);r.call(this.mangleFunctionName(e)),"void"!==u&&r.localSet(l),n.usesRandom&&r.localGet(c).globalGet(s.pcgState).i32x4ReplaceLane(t).localSet(c),"void"!==u&&(0===t?(r.localGet(l),"i32"===u?r.i32x4Splat():r.f32x4Splat(),r.localSet(h)):(r.localGet(h).localGet(l),"i32"===u?r.i32x4ReplaceLane(t):r.f32x4ReplaceLane(t),r.localSet(h)))}return n.readsThread&&r.localGet(this._vBaseX).globalSet(s.threadX),n.usesRandom&&(r.localGet(c).globalGet(s.pcgStateV),this.vMaskDepth>0?r.localGet(this.vCur):r.v128ConstI32x4(-1,-1,-1,-1),r.v128Bitselect().globalSet(s.pcgStateV)),"void"===u?"void":(r.localGet(h),"i32"===u?"vi32":"vf32")}vMathCall(e,t){const r=this.em;if("random"===e)return this.usesRandom=!0,this.vMaskDepth>0?r.localGet(this.vCur):r.v128ConstI32x4(-1,-1,-1,-1),r.call("pcg_random_v"),"vf32";const n=e=>{switch(this.getType(e)){case"Integer":this.vCastValueToFloat(e);break;case"LiteralInteger":this.vCastLiteralToFloat(e);break;default:this.vCoerce(this.vexpr(e),"vf32")}},s=T[e];if(s)return n(t.arguments[0]),r[s](),"vf32";switch(e){case"round":return n(t.arguments[0]),r.v128ConstF32x4(.5,.5,.5,.5).f32x4Add().f32x4Floor(),"vf32";case"fround":return n(t.arguments[0]),"vf32";case"min":case"max":{const s="min"===e?"f32x4Min":"f32x4Max";n(t.arguments[0]);for(let e=1;e{r.localGet(e.indices[t]),"vec"===e.kind&&r.f32x4Splat()};if("Literal"===t.type&&Number.isInteger(t.value)){if(t.value<0||t.value>=e.n)throw this.astErrorOutput(`index ${t.value} out of range for Array(${e.n})`,t);return n(t.value),"vf32"}const s=r.addLocal("v128");this.vEmitIndex(t),r.localSet(s);const i=r.addLocal("v128");n(0),r.localSet(i);for(let t=1;tthis.isThreadDependent(e));switch(e.type){case"MemberExpression":{const t=this.getVariableSignature(e);if("this.thread.value"===t||"value.thread.value"===t)return"x"===e.property.name;break}case"CallExpression":if(this.isAstMathFunction(e)){if("random"===e.callee.property.name)return!0;break}return!0;case"Identifier":return!!this.taintedLocals&&this.taintedLocals.has(e.name);case"ThisExpression":return!1}for(const t in e){if("loc"===t||"start"===t||"end"===t||"parent"===t)continue;const r=e[t];if(r&&"object"==typeof r&&this.isThreadDependent(r))return!0}return!1}recordUniformity(e,t){this._analysisPass&&this.uniformity.push({kind:e,threadDependent:!t||this.isThreadDependent(t)})}}}}),ot=e((e,t)=>{let n=null;try{n=r()}catch(e){}const s="function"==typeof Worker;const i="\nvar entries = {};\nfunction handleMessage(message, post) {\n if (message.type === 'setup') {\n var imports = { env: { memory: message.memory } };\n for (var i = 0; i < message.mathImports.length; i++) {\n imports.env['math_' + message.mathImports[i]] = Math[message.mathImports[i]];\n }\n var instance = new WebAssembly.Instance(message.module, imports);\n entries[message.id] = {\n run: instance.exports.run,\n runSimd: instance.exports.run_simd || null,\n sizeX: message.sizeX\n };\n post({ type: 'ready', id: message.id });\n } else if (message.type === 'release') {\n delete entries[message.id];\n } else if (message.type === 'run') {\n var entry = entries[message.id];\n var start = message.start;\n var end = message.end;\n var seed = message.seed;\n if (entry.runSimd && (entry.sizeX & 3) === 0 && (start & 3) === 0) {\n var quadEnd = end - ((end - start) & 3);\n if (quadEnd > start) entry.runSimd(start, quadEnd, seed);\n if (quadEnd < end) entry.run(quadEnd, end, seed);\n } else {\n entry.run(start, end, seed);\n }\n post({ type: 'done', taskId: message.taskId });\n }\n}\nif (typeof self !== 'undefined' && typeof postMessage === 'function') {\n self.onmessage = function(event) {\n handleMessage(event.data, function(message) { postMessage(message); });\n };\n} else {\n var parentPort = require('worker_threads').parentPort;\n parentPort.on('message', function(message) {\n handleMessage(message, function(reply) { parentPort.postMessage(reply); });\n });\n}\n";t.exports={WebAssemblyWorkerPool:class{constructor(e){this.size=e||function(){if("undefined"!=typeof navigator&&navigator.hardwareConcurrency)return navigator.hardwareConcurrency;if(n&&"function"==typeof n.cpus){const e=n.cpus().length;if(e)return e}return 4}(),this.workers=[],this.destroyed=!1,this.dispatchCount=0,this.lastDispatch=null,this._taskId=0}get liveWorkerCount(){let e=0;for(const t of this.workers)t.dead||e++;return e}_spawn(){const e={handle:null,dead:!1,state:{setup:new Set,settingUp:new Map,pending:new Map},fail:null,die:null},t=e.state;e.fail=e=>{for(const r of t.settingUp.values())r.reject(e);t.settingUp.clear();for(const r of t.pending.values())r.reject(e);t.pending.clear()},e.die=t=>{if(!e.dead&&(e.dead=!0,e.fail(t),e.handle&&"function"==typeof e.handle.terminate))try{e.handle.terminate()}catch(e){}};const n=r=>{if("ready"===r.type){const n=t.settingUp.get(r.id);n&&(t.settingUp.delete(r.id),t.setup.add(r.id),this._updateRef(e),n.resolve())}else if("done"===r.type){const n=t.pending.get(r.taskId);n&&(t.pending.delete(r.taskId),this._updateRef(e),n.resolve())}};let a;if(s){const t=URL.createObjectURL(new Blob([i],{type:"text/javascript"}));a=new Worker(t),URL.revokeObjectURL(t),a.onmessage=e=>n(e.data),a.onerror=t=>e.die(new Error(t.message||"WebAssembly worker error"))}else{const{Worker:t}=r();a=new t(i,{eval:!0}),a.on("message",n),a.on("error",t=>e.die(t)),a.on("exit",t=>{e.die(new Error(`WebAssembly worker exited with code ${t}`))}),a.unref()}return e.handle=a,e}_worker(e){for(;this.workers.length<=e;)this.workers.push(this._spawn());return this.workers[e].dead&&(this.workers[e]=this._spawn()),this.workers[e]}_updateRef(e){!e.dead&&e.handle&&"function"==typeof e.handle.ref&&(e.state.settingUp.size+e.state.pending.size>0?e.handle.ref():e.handle.unref())}_ensureSetup(e,t){if(e.state.setup.has(t.id))return Promise.resolve();let r=e.state.settingUp.get(t.id);return r||(r={},r.promise=new Promise((e,t)=>{r.resolve=e,r.reject=t}),e.state.settingUp.set(t.id,r),this._updateRef(e),e.handle.postMessage({type:"setup",id:t.id,module:t.module,memory:t.memory,mathImports:t.mathImports,sizeX:t.sizeX})),r.promise}dispatch(e,t){if(this.destroyed)return Promise.reject(new Error("WebAssembly worker pool has been destroyed"));this.dispatchCount++,this.lastDispatch={workerCount:t.length,ranges:t.map(e=>[e.start,e.end])};const r=t.map((t,r)=>{const n=this._worker(r);return this._ensureSetup(n,e).then(()=>new Promise((r,s)=>{if(n.dead)return void s(new Error("WebAssembly worker died before the task could run"));const i=++this._taskId;n.state.pending.set(i,{resolve:r,reject:s}),this._updateRef(n),n.handle.postMessage({type:"run",id:e.id,taskId:i,start:t.start,end:t.end,seed:t.seed})}))});return Promise.all(r).then(()=>{})}release(e){if(!this.destroyed)for(const t of this.workers){if(t.dead)continue;t.state.setup.delete(e);const r=t.state.settingUp.get(e);r&&(t.state.settingUp.delete(e),r.reject(new Error("WebAssembly kernel entry released during setup")),this._updateRef(t)),t.handle.postMessage({type:"release",id:e})}}destroy(){if(this.destroyed)return;this.destroyed=!0;const e=new Error("WebAssembly worker pool has been destroyed");for(const t of this.workers)t.dead=!0,t.fail(e),t.handle.terminate();this.workers=[]}}}}),ut=e((e,t)=>{const{Kernel:r}=a(),{FunctionBuilder:s}=o(),{WebAssemblyFunctionNode:u}=at(),{WasmModuleBuilder:l}=it(),{WebAssemblyWorkerPool:h}=ot(),{utils:c}=i(),{Input:p}=n(),d=Object.freeze({kernelMap:!1,isIntegerDivisionAccurate:!0,isSpeedTacticSupported:!1,isTextureFloat:!0,isDrawBuffers:!1,kernelMapSize:0,channelCount:1,maxTextureSize:1/0,isFloatRead:!0});let m=null,f=null,g=1;t.exports={WebAssemblyKernel:class e extends r{static get isSupported(){return"object"==typeof WebAssembly&&null!==WebAssembly&&WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0]))}static get isSIMDSupported(){if(null===m)try{const e=new l;e.addFunction("t",{params:[],results:[]}).v128ConstI32x4(0,0,0,0).drop(),m=WebAssembly.validate(e.toBytes())}catch(e){m=!1}return m}static get isThreadsSupported(){if(null===f)try{if("undefined"==typeof SharedArrayBuffer)f=!1;else{const e=new l;e.addMemoryImport(1,1,!0);const t=new WebAssembly.Memory({initial:1,maximum:1,shared:!0});new WebAssembly.Instance(new WebAssembly.Module(e.toBytes()),{env:{memory:t}}),f=!0}}catch(e){f=!1}return f}static isContextMatch(e){return!1}static getFeatures(){return d}static get features(){return d}static get mode(){return"webasm"}static getSignature(e,t){return"webasm"+(t.length>0?":"+t.join(","):"")}static destroyContext(e){}static nativeFunctionArguments(){throw new Error("WebAssembly backend does not yet support native functions")}static nativeFunctionReturnType(){throw new Error("WebAssembly backend does not yet support native functions")}static combineKernels(){throw new Error("WebAssembly backend does not yet support combineKernels")}constructor(e,t){super(e,t),this.poolSize=null,this.mergeSettings(e.settings||t),null===this.precision&&(this.precision="single"),this.threadDim=null,this.componentCount=1,this.moduleCacheLimit=8,this.functionBuilder=null,this.tracedFunctions=null,this.usesRandom=!1,this.usedMathImports=null,this._moduleCache=new Map,this._active=null,this._lastRunPath=null,this._pool=null,this._threadedTail=Promise.resolve()}initCanvas(){return this.graphical&&"undefined"!=typeof document?document.createElement("canvas"):null}initContext(){return null}initPlugins(e){return[]}setOutput(e){const t=this.toKernelOutput(e);if(this.built&&!this.dynamicOutput)throw new Error("Resizing a kernel with dynamicOutput: false is not possible");return this.output=t,this}toString(){throw new Error("WebAssembly backend does not yet support toString")}build(){if(this.built)return;if(this.gpu&&this.gpu.kernels&&-1===this.gpu.kernels.indexOf(this)&&this.gpu.kernels.push(this),this.graphical)return this.requestFallback(arguments,"graphical mode is not supported on the webasm backend");if(this.subKernels&&this.subKernels.length>0)return this.requestFallback(arguments,"kernel maps are not supported on the webasm backend");this.setupConstants(),this.setupArguments(arguments);for(let e=0;e16*Math.ceil(e/16);let r=0;const n={},s={};for(let i=0;i=4096}_entryKey(e){return this._computeSizeSignature(e)+(this._threadable()?"|shared":"")}_assembleModule(t,r,n){const s=new l,i=t.outputOffset+r*this.componentCount*4,a=Math.ceil(i/65536)+16,o=Math.max(a,4096);s.addMemoryImport(a,o,n);const u=Array.from(this.usedMathImports).sort();for(const e of u){const t="pow"===e||"atan2"===e?["f32","f32"]:["f32"];s.addFuncImport("math_"+e,t,["f32"])}const h={threadX:s.addGlobal("i32",!0,0),threadY:s.addGlobal("i32",!0,0),threadZ:s.addGlobal("i32",!0,0),dataIndex:s.addGlobal("i32",!0,0)};this.usesRandom&&(h.pcgState=s.addGlobal("i32",!0,0),this._emitPcgRandom(s,h.pcgState));const c={module:s,layout:t,globals:h};for(let e=this.tracedFunctions.length-1;e>=0;e--){const t=this.tracedFunctions[e];if("kernel"===t)continue;const r=this.functionBuilder.functionMap[t];r&&(r.output=this.output,r.emitFunction(c))}this.functionBuilder.functionMap.kernel.output=this.output,this.functionBuilder.functionMap.kernel.emitFunction(c);const[p,d]=this.threadDim,m=s.addFunction("run",{params:["i32","i32","i32"],locals:["i32"]});if(m.localGet(0).localSet(3),1===this.output.length?(m.i32Const(0).globalSet(h.threadY),m.i32Const(0).globalSet(h.threadZ)):2===this.output.length&&m.i32Const(0).globalSet(h.threadZ),m.block(),m.localGet(3).localGet(1).i32GeS().brIf(0),m.loop(),m.localGet(3).globalSet(h.dataIndex),1===this.output.length?m.localGet(3).globalSet(h.threadX):2===this.output.length?(m.localGet(3).i32Const(p).i32RemU().globalSet(h.threadX),m.localGet(3).i32Const(p).i32DivU().globalSet(h.threadY)):(m.localGet(3).i32Const(p).i32RemU().globalSet(h.threadX),m.localGet(3).i32Const(p).i32DivU().i32Const(d).i32RemU().globalSet(h.threadY),m.localGet(3).i32Const(p*d).i32DivU().globalSet(h.threadZ)),this.usesRandom&&m.localGet(2).localGet(3).i32Const(-1640531527).i32Mul().i32Add().i32Const(747796405).i32Mul().i32Const(-1403630843).i32Add().globalSet(h.pcgState),m.call("kernel"),m.localGet(3).i32Const(1).i32Add().localSet(3),m.localGet(3).localGet(1).i32LtS().brIf(0),m.end(),m.end(),s.exportFunction("run"),e.isSIMDSupported){this.usesRandom&&(h.pcgStateV=s.addGlobal("v128",!0,0),this._emitPcgRandomVector(s,h.pcgStateV));let e=null;for(const t of this.tracedFunctions){if("kernel"===t)continue;const r=this.functionBuilder.functionMap[t];r&&(e||(e={readsThread:!1,usesRandom:!1}),r.readsThread&&(e.readsThread=!0),r.usesRandom&&(e.usesRandom=!0))}c.helperInfo=e,this.functionBuilder.functionMap.kernel.emitVectorFunction(c),this._emitRunSimd(s,h),s.exportFunction("run_simd")}return{bytes:s.toBytes(),initial:a,maximum:o}}_emitRunSimd(e,t){const[r,n]=this.threadDim,s=e.addFunction("run_simd",{params:["i32","i32","i32"],locals:["i32"]});s.localGet(0).localSet(3),1===this.output.length?(s.i32Const(0).globalSet(t.threadY),s.i32Const(0).globalSet(t.threadZ)):2===this.output.length&&s.i32Const(0).globalSet(t.threadZ),s.block(),s.localGet(3).localGet(1).i32GeS().brIf(0),s.loop(),s.localGet(3).globalSet(t.dataIndex),1===this.output.length?s.localGet(3).globalSet(t.threadX):2===this.output.length?(s.localGet(3).i32Const(r).i32RemU().globalSet(t.threadX),s.localGet(3).i32Const(r).i32DivU().globalSet(t.threadY)):(s.localGet(3).i32Const(r).i32RemU().globalSet(t.threadX),s.localGet(3).i32Const(r).i32DivU().i32Const(n).i32RemU().globalSet(t.threadY),s.localGet(3).i32Const(r*n).i32DivU().globalSet(t.threadZ)),this.usesRandom&&(s.localGet(3).i32x4Splat().v128ConstI32x4(0,1,2,3).i32x4Add(),s.v128ConstI32x4(-1640531527,-1640531527,-1640531527,-1640531527).i32x4Mul(),s.localGet(2).i32x4Splat().i32x4Add(),s.v128ConstI32x4(747796405,747796405,747796405,747796405).i32x4Mul(),s.v128ConstI32x4(-1403630843,-1403630843,-1403630843,-1403630843).i32x4Add(),s.globalSet(t.pcgStateV)),s.call("kernel_simd"),s.localGet(3).i32Const(4).i32Add().localSet(3),s.localGet(3).localGet(1).i32LtS().brIf(0),s.end(),s.end()}_emitPcgRandomVector(e,t){const r=e.addFunction("pcg_random_v",{params:["v128"],results:["v128"]}),n=r.addLocal("v128"),s=r.addLocal("i32");r.globalGet(t).v128ConstI32x4(747796405,747796405,747796405,747796405).i32x4Mul().v128ConstI32x4(-1403630843,-1403630843,-1403630843,-1403630843).i32x4Add().globalGet(t).localGet(0).v128Bitselect().globalSet(t),r.globalGet(t).localSet(n),r.localGet(n).i32x4ExtractLane(0).localSet(s),r.localGet(s).localGet(s).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU().i32x4Splat();for(let e=1;e<4;e++)r.localGet(n).i32x4ExtractLane(e).localSet(s),r.localGet(s).localGet(s).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU().i32x4ReplaceLane(e);r.localGet(n).v128Xor(),r.v128ConstI32x4(277803737,277803737,277803737,277803737).i32x4Mul();const i=r.addLocal("v128");r.localTee(i),r.i32Const(22).i32x4ShrU().localGet(i).v128Xor(),r.i32Const(8).i32x4ShrU(),r.f32x4ConvertI32x4U(),r.v128ConstF32x4(16777216,16777216,16777216,16777216).f32x4Div()}_emitPcgRandom(e,t){const r=e.addFunction("pcg_random",{params:[],results:["f32"]}),n=r.addLocal("i32");r.globalGet(t).i32Const(747796405).i32Mul().i32Const(-1403630843).i32Add().globalSet(t),r.globalGet(t).globalGet(t).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU().globalGet(t).i32Xor().i32Const(277803737).i32Mul().localTee(n),r.i32Const(22).i32ShrU().localGet(n).i32Xor().i32Const(8).i32ShrU().f32ConvertI32U().f32Const(16777216).f32Div()}_releaseEntry(e){const t=()=>{e.instance=null,e.module=null,e.memory=null,e.run=null,e.runSimd=null,e.f32=null,e.i32=null,e.bytes=null};if(e.shared&&this._pool){const r=this._pool;this._threadedTail.then(()=>{r.release(e.id),t()},t)}else t()}_instantiate(e,t){let r=this._moduleCache.get(e);if(r&&(this._moduleCache.delete(e),this._moduleCache.set(e,r)),!r){const n=this._threadable(),s=this.computeLayout(t),[i,a,o]=this.threadDim,u=i*a*o,{bytes:l,initial:h,maximum:d}=this._assembleModule(s,u,n);if(!WebAssembly.validate(l))throw new Error("WebAssembly backend: generated module failed validation (internal error)");const m=n?new WebAssembly.Memory({initial:h,maximum:d,shared:!0}):new WebAssembly.Memory({initial:h,maximum:d}),f={env:{memory:m}};for(const e of this.usedMathImports)f.env["math_"+e]=Math[e];const y=new WebAssembly.Module(l),x=new WebAssembly.Instance(y,f);r={id:g++,sizeSignature:e,shared:n,layout:s,cells:u,bytes:l,module:y,memory:m,mathImports:Array.from(this.usedMathImports).sort(),sizeX:i,instance:x,run:x.exports.run,runSimd:x.exports.run_simd||null,f32:new Float32Array(m.buffer),i32:new Int32Array(m.buffer)};for(const e in s.constantArrays){const t=s.constantArrays[e],n=this.constants[e];c.flattenTo(n instanceof p?n.value:n,r.f32.subarray(t.offset/4,t.offset/4+t.flatLength))}for(this._moduleCache.set(e,r);this._moduleCache.size>Math.max(this.moduleCacheLimit,1);){const e=this._moduleCache.keys().next().value,t=this._moduleCache.get(e);this._moduleCache.delete(e),this._releaseEntry(t)}}this._active=r}checkArgumentTypes(e){if(super.checkArgumentTypes(e),!this.argumentTypes)return;const t=Math.min(e.length,this.argumentTypes.length);for(let r=0;r>>0:4294967296*Math.random()>>>0),u|=0,o&&n>0){const t=e[0];if(3&t){const e=-4&t,r=n/t;for(let n=0;n0&&o(r,r+e,u),a(r+e,r+t,u)}this._lastRunPath=e>0?"simd+scalar-tail":"scalar"}else o(0,n,u),this._lastRunPath="simd"}else a(0,n,u),this._lastRunPath="scalar";const l=r.outputOffset/4,h=s.slice(l,l+n*this.componentCount);return this._shapeOutput(h,Array.from(this.output),this.componentCount)}_runThreaded(e){const t=this._active,{layout:r,cells:n}=t,s=[];for(const t in r.arrays){const n=r.arrays[t],i=e[n.index],a=new Float32Array(n.flatLength);c.flattenTo(i instanceof p?i.value:i,a),s.push({record:n,flat:a})}const i=[];for(const t in r.scalars){const n=r.scalars[t];i.push({record:n,value:e[n.index]})}let a=0;this.usesRandom&&(a=null!==this.randomSeed?this.randomSeed>>>0:4294967296*Math.random()>>>0),a|=0,this._pool||(this._pool=new h(this.poolSize||void 0));const o=this._pool,u=this.componentCount,l=Array.from(this.output),d=this._threadedTail.then(()=>{if(!t.f32)throw new Error("WebAssembly kernel was destroyed");for(let e=0;e=n)break;c.push({start:r,end:t===e-1?n:Math.min(r+h,n),seed:a})}return this._lastRunPath="threaded",o.dispatch(t,c).then(()=>{if(!t.f32)throw new Error("WebAssembly kernel was destroyed");const e=r.outputOffset/4,s=t.f32.slice(e,e+n*u);return this._shapeOutput(s,l,u)})});return this._threadedTail=d.then(()=>{},()=>{}),d}_shapeOutput(e,t,r){const[n,s,i]=[t[0],t[1]||1,t[2]||1];if(1===r)switch(t.length){case 1:return c.erectMemoryOptimizedFloat(e,n);case 2:return c.erectMemoryOptimized2DFloat(e,n,s);default:return c.erectMemoryOptimized3DFloat(e,n,s,i)}const a=r,o=t=>{const r=new Array(n);for(let s=0;s{const{utils:r}=i(),{Input:s}=n();function a(e,t){if(t.kernel)return void(t.kernel=e);const n=r.allPropertiesOf(e);for(let r=0;rt.kernel[s]),t.__defineSetter__(s,e=>{t.kernel[s]=e})))}t.kernel=e}t.exports={kernelRunShortcut:function(e){function t(t){e.build.apply(e,t),e.checkArgumentTypes(t);let n=e.switchingKernels?void 0:e.run.apply(e,t);for(let s=0;e.switchingKernels;s++){if(s>=4){const t=e.resetSwitchingKernels();throw new Error(`this kernel cannot run the arguments it was given (${r(t)}); it did not settle on a kernel for them after 4 attempts. Create a separate kernel for this call's argument types.`)}const i=e.resetSwitchingKernels(),a=e.onRequestSwitchKernel(i,t,e);c.kernel=e=a,a.checkArgumentTypes(t),n=a.switchingKernels?void 0:a.run.apply(a,t),a.fallbackRequested&&(n=e.run.apply(e,t))}return n}function r(e){return e&&e.length?e.map(e=>"argumentTypeMismatch"===e.type?`argument ${e.index} is now ${e.needed}`:e.type).join(", "):"unknown reason"}function n(r){if(e.onAsyncModeUpgrade){const t=e.onAsyncModeUpgrade;e.onAsyncModeUpgrade=null;const s=u(r);return t(s,e).then(e=>(e&&c.replaceKernel(e),n(s)))}try{if(!0===e.constructor.isAsync)return e.build.apply(e,r),Promise.resolve(e.run.apply(e,r));for(let e=0;en(e));const s=t(r);return e.renderKernels?Promise.resolve(e.renderKernels()):e.renderOutput?e.renderOutputAsync?e.renderOutputAsync():Promise.resolve(e.renderOutput()):Promise.resolve(s)}catch(e){return Promise.reject(e)}}function i(e){return Boolean(e)&&"WebGPUBuffer"===e.type}function o(e){const t=u(e),r=[];for(let e=0;e{t[n]=e}))}return Promise.all(r).then(()=>t)}function u(e){const t=new Array(e.length);for(let r=0;r{try{e(h.apply(this,arguments))}catch(e){t(e)}})},c.replaceKernel=function(t){a(e=t,c)},a(e,c),c}}}),ht=e((e,r)=>{const{gpuMock:n}=t(),{utils:s}=i(),{Kernel:o}=a(),{CPUKernel:u}=p(),{HeadlessGLKernel:l}=be(),{WebGL2Kernel:h}=et(),{WebGLKernel:c}=xe(),{WebGPUKernel:d}=st(),{WebAssemblyKernel:m}=ut(),{kernelRunShortcut:f}=lt(),g=[l,h,c,m],y=["gpu","cpu"],x={headlessgl:l,webgl2:h,webgl:c,webgpu:d,webasm:m};let b=!0;function T(e){if(!e)return{};const t=Object.assign({},e);return e.hasOwnProperty("floatOutput")&&(s.warnDeprecated("setting","floatOutput","precision"),t.precision=e.floatOutput?"single":"unsigned"),e.hasOwnProperty("outputToTexture")&&(s.warnDeprecated("setting","outputToTexture","pipeline"),t.pipeline=Boolean(e.outputToTexture)),e.hasOwnProperty("outputImmutable")&&(s.warnDeprecated("setting","outputImmutable","immutable"),t.immutable=Boolean(e.outputImmutable)),e.hasOwnProperty("floatTextures")&&(s.warnDeprecated("setting","floatTextures","optimizeFloatMemory"),t.optimizeFloatMemory=Boolean(e.floatTextures)),t}r.exports={GPU:class e{static disableValidation(){b=!1}static enableValidation(){b=!0}static get isGPUSupported(){return g.some(e=>e.isSupported)}static get isKernelMapSupported(){return g.some(e=>e.isSupported&&e.features.kernelMap)}static get isOffscreenCanvasSupported(){return"undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas||"undefined"!=typeof importScripts}static get isWebGLSupported(){return c.isSupported}static get isWebGL2Supported(){return h.isSupported}static get isHeadlessGLSupported(){return l.isSupported}static get isWebGPUSupported(){return d.isSupported}static isWebGPUAvailable(){return d.isSupported?navigator.gpu.requestAdapter().then(e=>null!==e,()=>!1):Promise.resolve(!1)}static get isWebAssemblySupported(){return m.isSupported}static get isCanvasSupported(){return"undefined"!=typeof HTMLCanvasElement}static get isGPUHTMLImageArraySupported(){return h.isSupported}static get isSinglePrecisionSupported(){return g.some(e=>e.isSupported&&e.features.isFloatRead&&e.features.isTextureFloat)}constructor(t){if(t=t||{},this.canvas=t.canvas||null,this.context=t.context||null,this.mode=t.mode,this.Kernel=null,this._webGPUDecision=null,"async"===t.mode&&(d.isSupported?e.isWebGPUAvailable().then(e=>{this._webGPUDecision=e},()=>{this._webGPUDecision=!1}):this._webGPUDecision=!1),this.kernels=[],this.functions=[],this.nativeFunctions=[],this.injectedNative=null,"dev"!==this.mode){if(this.chooseKernel(),t.functions)for(let e=0;er.argumentTypes[e]));const l=this;function h(e){console.warn("Falling back to CPU"+(y.fallbackReason?`: ${y.fallbackReason}`:""));const r=new u(t,{argumentTypes:y.argumentTypes,constantTypes:y.constantTypes,graphical:y.graphical,loopMaxIterations:y.loopMaxIterations,constants:y.constants,dynamicOutput:y.dynamicOutput,dynamicArgument:y.dynamicArguments,output:y.output,precision:y.precision,pipeline:y.pipeline,immutable:y.immutable,optimizeFloatMemory:y.optimizeFloatMemory,fixIntegerDivisionAccuracy:y.fixIntegerDivisionAccuracy,functions:y.functions,nativeFunctions:y.nativeFunctions,injectedNative:y.injectedNative,subKernels:y.subKernels,strictIntegers:y.strictIntegers,randomSeed:y.randomSeed,debug:y.debug,asyncMode:y.asyncMode,onRequestFallback:h,onRequestSwitchKernel:c,canvas:y.graphical&&!y.context?y.canvas:null});r.fallbackReason=y.fallbackReason,r.build.apply(r,e);const n=r.run.apply(r,e);return y.replaceKernel(r),!l.canvas&&r.canvas&&(l.canvas=r.canvas),!l.context&&r.context&&(l.context=r.context),n}function c(e,r,n){n.debug&&console.warn("Switching kernels");let s=null;if(n.signature&&!a[n.signature]&&(a[n.signature]=n),n.dynamicOutput)for(let t=e.length-1;t>=0;t--){const r=e[t];"outputPrecisionMismatch"===r.type&&(s=r.needed)}const o=n.constructor,u=o.getArgumentTypes(n,r),l=o.getSignature(n,u),p=a[l];if(p)return p.onActivate(n),p;const d=a[l]=new o(t,{argumentTypes:u,constantTypes:n.constantTypes,graphical:n.graphical,loopMaxIterations:n.loopMaxIterations,constants:n.constants,dynamicOutput:n.dynamicOutput,dynamicArgument:n.dynamicArguments,context:n.context,canvas:n.canvas,output:s||n.output,precision:n.precision,pipeline:n.pipeline,immutable:n.immutable,optimizeFloatMemory:n.optimizeFloatMemory,fixIntegerDivisionAccuracy:n.fixIntegerDivisionAccuracy,functions:n.functions,nativeFunctions:n.nativeFunctions,injectedNative:n.injectedNative,subKernels:n.subKernels,strictIntegers:n.strictIntegers,randomSeed:n.randomSeed,debug:n.debug,asyncMode:n.asyncMode,gpu:n.gpu,validate:b,returnType:n.returnType,tactic:n.tactic,onRequestFallback:h,onRequestSwitchKernel:c,texture:n.texture,mappedTextures:n.mappedTextures,drawBuffersMap:n.drawBuffersMap});return d.build.apply(d,r),y.replaceKernel(d),i.push(d),d}const p=Object.assign({context:this.context,canvas:this.canvas,functions:this.functions,nativeFunctions:this.nativeFunctions,injectedNative:this.injectedNative,gpu:this,validate:b,onRequestFallback:h,onRequestSwitchKernel:c},o);"async"===this.mode&&(p.asyncMode=!0);let m,g=this.Kernel;"async"===this.mode&&o.graphical&&!0===this._webGPUDecision&&(g=d,p.canvas===this.canvas&&(p.canvas=o.canvas||null),p.context===this.context&&(p.context=o.context||null),p.asyncMode=!0);try{m=new g(t,p)}catch(e){if(g===this.Kernel)throw e;m=new this.Kernel(t,Object.assign({},p,{canvas:this.canvas,context:this.context}))}const y=f(m);if("async"===this.mode&&d.isSupported&&!(m instanceof d)){const r=this;m.onAsyncModeUpgrade=function(n,s){return e.isWebGPUAvailable().then(e=>{if(!e)return null;if(s.graphical)return s.debug&&console.warn("webgpu upgrade declined: graphical kernels keep their canvas"),null;let a;try{a=new d(t,{functions:s.functions,nativeFunctions:s.nativeFunctions,injectedNative:s.injectedNative,gpu:r,validate:b,asyncMode:!0,output:s.output,pipeline:s.pipeline,immutable:s.immutable,dynamicOutput:s.dynamicOutput,dynamicArguments:!0,loopMaxIterations:s.loopMaxIterations,constants:s.constants,constantTypes:s.constantTypes,argumentTypes:s.argumentTypes,precision:s.precision,tactic:s.tactic,strictIntegers:s.strictIntegers,fixIntegerDivisionAccuracy:s.fixIntegerDivisionAccuracy,subKernels:s.subKernels,graphical:s.graphical,debug:s.debug}),a.build.apply(a,n)}catch(e){return s.debug&&console.warn("webgpu upgrade declined: "+e.message),null}return a._buildPromise.then(()=>(i.push(a),a),e=>(s.debug&&console.warn("webgpu upgrade declined: "+e.message),a.destroy(),null))},()=>null)}}return this.canvas||(this.canvas=m.canvas),this.context||(this.context=m.context),i.push(m),y}createKernelMap(){let e,t;const r=typeof arguments[arguments.length-2];if("function"===r||"string"===r?(e=arguments[arguments.length-2],t=arguments[arguments.length-1]):e=arguments[arguments.length-1],!("dev"===this.mode||this.Kernel.isSupported&&this.Kernel.features.kernelMap)){if("webgpu"===this.Kernel.mode)throw new Error("WebGPU backend does not yet support createKernelMap");if(this.mode&&y.indexOf(this.mode)<0&&"webasm"!==this.Kernel.mode)throw new Error(`kernelMap not supported on ${this.Kernel.name}`)}const n=T(t);if(t&&"object"==typeof t.argumentTypes&&(n.argumentTypes=Object.keys(t.argumentTypes).map(e=>t.argumentTypes[e])),Array.isArray(arguments[0])){n.subKernels=[];const e=arguments[0];for(let t=0;t0)throw new Error('Cannot call "addNativeFunction" after "createKernels" has been called.');return this.nativeFunctions.push(Object.assign({name:e,source:t},r)),this}injectNative(e){return this.injectedNative=e,this}destroy(){return new Promise((e,t)=>{this.kernels||e(),setTimeout(()=>{try{const e=this.kernels.slice();for(let t=0;t{const{utils:r}=i();t.exports={alias:function(e,t){const n=t.toString();return new Function(`return function ${e} (${r.getArgumentNamesFromString(n).join(", ")}) {\n ${r.getFunctionBodyFromString(n)}\n}`)()}}}),pt=e((e,t)=>{const{GPU:r}=ht(),{alias:c}=ct(),{utils:d}=i(),{Input:m,input:f}=n(),{Texture:g}=s(),{FunctionBuilder:y}=o(),{FunctionNode:x}=l(),{CPUFunctionNode:b}=h(),{CPUKernel:T}=p(),{HeadlessGLKernel:v}=be(),{WebGLFunctionNode:S}=G(),{WebGLKernel:A}=xe(),{kernelValueMaps:w}=ye(),{WebGL2FunctionNode:E}=Te(),{WebGL2Kernel:I}=et(),{kernelValueMaps:_}=Qe(),{WGSLFunctionNode:L}=tt(),{WebGPUKernel:F}=st(),{WebGPUContext:k}=rt(),{WebGPUBufferResult:$}=nt(),{WebAssemblyFunctionNode:D}=at(),{WebAssemblyKernel:M}=ut(),{GLKernel:N}=C(),{Kernel:O}=a(),{FunctionTracer:z}=u();t.exports={alias:c,CPUFunctionNode:b,CPUKernel:T,GPU:r,FunctionBuilder:y,FunctionNode:x,HeadlessGLKernel:v,Input:m,input:f,Texture:g,utils:d,WebGL2FunctionNode:E,WebGL2Kernel:I,webGL2KernelValueMaps:_,WebGLFunctionNode:S,WebGLKernel:A,webGLKernelValueMaps:w,WGSLFunctionNode:L,WebGPUKernel:F,WebGPUContext:k,WebGPUBufferResult:$,WebAssemblyFunctionNode:D,WebAssemblyKernel:M,GLKernel:N,Kernel:O,FunctionTracer:z,plugins:{mathRandom:R()}}});return e((e,t)=>{const r=pt(),n=r.GPU;for(const e in r)r.hasOwnProperty(e)&&"GPU"!==e&&(n[e]=r[e]);function s(e){e.GPU&&e.GPU.prototype&&e.GPU.prototype.createKernel||Object.defineProperty(e,"GPU",{configurable:!0,get:()=>n,set(){}})}n.GPU=n,"undefined"!=typeof window&&s(window),"undefined"!=typeof self&&s(self),t.exports=n})()}); \ No newline at end of file diff --git a/dist/gpu-browser.js b/dist/gpu-browser.js index aa64438b..1a81f9d5 100644 --- a/dist/gpu-browser.js +++ b/dist/gpu-browser.js @@ -5,7 +5,7 @@ * GPU Accelerated JavaScript * * @version 2.21.0 - * @date Mon Aug 03 2026 01:03:16 GMT+0800 (Singapore Standard Time) + * @date Mon Aug 03 2026 09:01:53 GMT+0800 (Singapore Standard Time) * * @license MIT * The MIT License @@ -4667,6 +4667,7 @@ return result; }, getAstString(source, ast) { + if (!ast.loc) return "[synthetic node]"; const lines = Array.isArray(source) ? source : source.split(/\r?\n/g); const start = ast.loc.start; const end = ast.loc.end; @@ -5229,7 +5230,7 @@ utils: utils }; }); - var require_kernel$6 = __commonJSMin((exports, module) => { + var require_kernel$7 = __commonJSMin((exports, module) => { const {utils: utils} = require_utils(); const {Input: Input} = require_input(); var Kernel = class { @@ -5261,6 +5262,7 @@ } this.useLegacyEncoder = false; this.fallbackRequested = false; + this.fallbackReason = null; this.onRequestFallback = null; this.onRequestSwitchKernel = null; this.argumentNames = typeof source === "string" ? utils.getArgumentNamesFromString(source) : null; @@ -5557,9 +5559,10 @@ this.tactic = tactic; return this; } - requestFallback(args) { + requestFallback(args, reason) { if (!this.onRequestFallback) throw new Error(`"onRequestFallback" not defined on ${this.constructor.name}`); this.fallbackRequested = true; + this.fallbackReason = reason || null; return this.onRequestFallback(args); } validateSettings() { @@ -6334,7 +6337,7 @@ FunctionTracer: FunctionTracer }; }); - var require_function_node$4 = __commonJSMin((exports, module) => { + var require_function_node$5 = __commonJSMin((exports, module) => { const acorn = require_acorn(); const {utils: utils} = require_utils(); const {FunctionTracer: FunctionTracer} = require_function_tracer(); @@ -6458,6 +6461,30 @@ if (!ast) throw new Error("Failed to parse JS code"); return this.ast = functionAST; } + getAssignedArguments() { + if (this._assignedArguments) return this._assignedArguments; + const assigned = new Set; + const redeclared = new Set; + const names = this.argumentNames || []; + const walk = node => { + if (!node || typeof node !== "object") return; + if (Array.isArray(node)) { + for (const child of node) walk(child); + return; + } + if (node.type === "AssignmentExpression" && node.left.type === "Identifier" && names.indexOf(node.left.name) !== -1) assigned.add(node.left.name); + if (node.type === "UpdateExpression" && node.argument.type === "Identifier" && names.indexOf(node.argument.name) !== -1) assigned.add(node.argument.name); + if (node.type === "VariableDeclarator" && node.id.type === "Identifier" && names.indexOf(node.id.name) !== -1) redeclared.add(node.id.name); + for (const key in node) { + if (key === "loc" || key === "range" || key === "parent") continue; + const child = node[key]; + if (child && typeof child === "object") walk(child); + } + }; + walk(this.getJsAST()); + for (const name of redeclared) assigned.delete(name); + return this._assignedArguments = assigned; + } traceFunctionAST(ast) { const {contexts: contexts, declarations: declarations, functions: functions, identifiers: identifiers, functionCalls: functionCalls} = new FunctionTracer(ast); this.contexts = contexts; @@ -7623,9 +7650,13 @@ FunctionNode: FunctionNode }; }); - var require_function_node$3 = __commonJSMin((exports, module) => { - const {FunctionNode: FunctionNode} = require_function_node$4(); + var require_function_node$4 = __commonJSMin((exports, module) => { + const {FunctionNode: FunctionNode} = require_function_node$5(); var CPUFunctionNode = class extends FunctionNode { + markupUserName(name) { + if (this.isRootKernel && this.getAssignedArguments().has(name)) return `cellShadow_user_${name}`; + return `user_${name}`; + } astFunction(ast, retArr) { if (!this.isRootKernel) { retArr.push("function"); @@ -7640,10 +7671,15 @@ } retArr.push(") {\n"); } + if (this.isRootKernel) { + for (const name of this.getAssignedArguments()) retArr.push(`let cellShadow_user_${name} = user_${name};\n`); + retArr.push("kernelBody: {\n"); + } for (let i = 0; i < ast.body.body.length; ++i) { this.astGeneric(ast.body.body[i], retArr); retArr.push("\n"); } + if (this.isRootKernel) retArr.push("}\n"); if (!this.isRootKernel) retArr.push("}\n"); return retArr; } @@ -7655,7 +7691,7 @@ this.astGeneric(ast.argument, retArr); retArr.push(";\n"); retArr.push(this.followingReturnStatement); - retArr.push("continue;\n"); + retArr.push("break kernelBody;\n"); } else if (this.isSubKernel) { retArr.push(`subKernelResult_${this.name} = `); this.astGeneric(ast.argument, retArr); @@ -7689,7 +7725,7 @@ break; default: - if (!this.getDeclaration(idtNode) && this.constants && this.constants.hasOwnProperty(idtNode.name)) retArr.push("constants_" + idtNode.name); else retArr.push("user_" + idtNode.name); + if (!this.getDeclaration(idtNode) && this.constants && this.constants.hasOwnProperty(idtNode.name)) retArr.push("constants_" + idtNode.name); else if (!this.getDeclaration(idtNode) && this.isRootKernel && this.getAssignedArguments().has(idtNode.name)) retArr.push(this.markupUserName(idtNode.name)); else retArr.push("user_" + idtNode.name); } return retArr; } @@ -7747,14 +7783,13 @@ } astDoWhileStatement(doWhileNode, retArr) { if (doWhileNode.type !== "DoWhileStatement") throw this.astErrorOutput("Invalid while statement", doWhileNode); - retArr.push("for (let i = 0; i < LOOP_MAX; i++) {"); + const safeName = `safeI${this.astKey(doWhileNode, "_")}`; + retArr.push(`let ${safeName} = 0;\n`); + retArr.push("do {"); this.astGeneric(doWhileNode.body, retArr); - retArr.push("if (!"); + retArr.push("} while (("); this.astGeneric(doWhileNode.test, retArr); - retArr.push(") {\n"); - retArr.push("break;\n"); - retArr.push("}\n"); - retArr.push("}\n"); + retArr.push(`) && ++${safeName} < LOOP_MAX);\n`); return retArr; } astAssignmentExpression(assNode, retArr) { @@ -7925,10 +7960,10 @@ case "Integer": case "Float": case "Boolean": - retArr.push(`${origin}_${name}`); + retArr.push(origin === "user" ? this.markupUserName(name) : `${origin}_${name}`); return retArr; } - const markupName = `${origin}_${name}`; + const markupName = origin === "user" ? this.markupUserName(name) : `${origin}_${name}`; switch (type) { default: let size; @@ -8155,10 +8190,10 @@ cpuKernelString: cpuKernelString }; }); - var require_kernel$5 = __commonJSMin((exports, module) => { - const {Kernel: Kernel} = require_kernel$6(); + var require_kernel$6 = __commonJSMin((exports, module) => { + const {Kernel: Kernel} = require_kernel$7(); const {FunctionBuilder: FunctionBuilder} = require_function_builder(); - const {CPUFunctionNode: CPUFunctionNode} = require_function_node$3(); + const {CPUFunctionNode: CPUFunctionNode} = require_function_node$4(); const {utils: utils} = require_utils(); const {cpuKernelString: cpuKernelString} = require_kernel_string$1(); var CPUKernel = class extends Kernel { @@ -8972,8 +9007,8 @@ GLTextureGraphical: GLTextureGraphical }; }); - var require_kernel$4 = __commonJSMin((exports, module) => { - const {Kernel: Kernel} = require_kernel$6(); + var require_kernel$5 = __commonJSMin((exports, module) => { + const {Kernel: Kernel} = require_kernel$7(); const {utils: utils} = require_utils(); const {GLTextureArray2Float: GLTextureArray2Float} = require_array_2_float(); const {GLTextureArray2Float2D: GLTextureArray2Float2D} = require_array_2_float_2d(); @@ -9267,7 +9302,7 @@ case "Array(2)": case "Array(3)": case "Array(4)": - return this.requestFallback(args); + return this.requestFallback(args, `${this.returnType} output requires single precision, which this context does not support`); } } else { if (this.subKernels !== null) this.renderKernels = this.renderKernelsToArrays; @@ -9294,7 +9329,7 @@ case "Array(2)": case "Array(3)": case "Array(4)": - return this.requestFallback(args); + return this.requestFallback(args, `${this.returnType} output requires single precision, which this context does not support`); } } } else if (this.precision === "single") { @@ -9753,9 +9788,9 @@ GLKernel: GLKernel }; }); - var require_function_node$2 = __commonJSMin((exports, module) => { + var require_function_node$3 = __commonJSMin((exports, module) => { const {utils: utils} = require_utils(); - const {FunctionNode: FunctionNode} = require_function_node$4(); + const {FunctionNode: FunctionNode} = require_function_node$5(); const INTEGER_COMPARISON_ROUNDING = { "<": "ceil", ">=": "ceil", @@ -9822,6 +9857,17 @@ if (type === "sampler2D" || type === "sampler2DArray") retArr.push(`${type} user_${name},ivec2 user_${name}Size,ivec3 user_${name}Dim`); else retArr.push(`${type} user_${name}`); } retArr.push(") {\n"); + if (this.isRootKernel) { + const assignedArguments = this.getAssignedArguments(); + for (let i = 0; i < this.argumentNames.length; ++i) { + const argumentName = this.argumentNames[i]; + if (!assignedArguments.has(argumentName)) continue; + const type = typeMap[this.argumentTypes[i]]; + if (type !== "float" && type !== "int" && type !== "bool") continue; + const name = utils.sanitizeName(argumentName); + retArr.push(`${type} cellShadow_user_${name}=user_${name};\n`); + } + } for (let i = 0; i < ast.body.body.length; ++i) { this.astStatementWithHoisting(ast.body.body[i], retArr); retArr.push("\n"); @@ -10230,9 +10276,21 @@ if (idtNode.type !== "Identifier") throw this.astErrorOutput("IdentifierExpression - not an Identifier", idtNode); const type = this.getType(idtNode); const name = utils.sanitizeName(idtNode.name); - if (idtNode.name === "Infinity") retArr.push("3.402823466e+38"); else if (type === "Boolean") if (this.argumentNames.indexOf(name) > -1) retArr.push(`bool(user_${name})`); else retArr.push(`user_${name}`); else retArr.push(`user_${name}`); + if (idtNode.name === "Infinity") retArr.push("3.402823466e+38"); else if (type === "Boolean") if (this.argumentNames.indexOf(name) > -1) { + const marked = this.markupUserName(idtNode.name); + retArr.push(marked.startsWith("cellShadow_") ? marked : `bool(${marked})`); + } else retArr.push(`user_${name}`); else retArr.push(this.markupUserName(idtNode.name)); return retArr; } + markupUserName(name) { + const sanitized = utils.sanitizeName(name); + if (this.isRootKernel && this.getAssignedArguments().has(name)) { + const index = this.argumentNames.indexOf(name); + const type = index === -1 ? null : typeMap[this.argumentTypes[index]]; + if (type === "float" || type === "int" || type === "bool") return `cellShadow_user_${sanitized}`; + } + return `user_${sanitized}`; + } astForStatement(forNode, retArr) { if (forNode.type !== "ForStatement") throw this.astErrorOutput("Invalid for statement", forNode); const initArr = []; @@ -10289,10 +10347,10 @@ if (doWhileNode.type !== "DoWhileStatement") throw this.astErrorOutput("Invalid while statement", doWhileNode); const iVariableName = this.getInternalVariableName("safeI"); retArr.push(`for (int ${iVariableName}=0;${iVariableName}0){if (!`); this.astGeneric(doWhileNode.test, retArr); - retArr.push(") break;\n"); + retArr.push(") break;}\n"); + this.astGeneric(doWhileNode.body, retArr); retArr.push("}\n"); return retArr; } @@ -10324,7 +10382,7 @@ retArr.push("float("); this.astGeneric(assNode.right, retArr); retArr.push(")"); - } else this.astGeneric(assNode.right, retArr); + } else if (leftType === "Integer" && rightType === "LiteralInteger") this.castLiteralToInteger(assNode.right, retArr); else this.astGeneric(assNode.right, retArr); } if (!isStatement) retArr.push(")"); return retArr; @@ -10564,6 +10622,10 @@ } } ] }; + this.stampSyntheticNodes(replacement); + return replacement; + } + stampSyntheticNodes(root) { let syntheticId = this.syntheticNodeId || 1073741824; const stamp = node => { if (!node || typeof node !== "object") return; @@ -10581,9 +10643,8 @@ stamp(node[key]); } }; - stamp(replacement); + stamp(root); this.syntheticNodeId = syntheticId; - return replacement; } linearizeStatement(statement) { const statements = []; @@ -13370,10 +13431,10 @@ kernelValueMaps: kernelValueMaps }; }); - var require_kernel$3 = __commonJSMin((exports, module) => { - const {GLKernel: GLKernel} = require_kernel$4(); + var require_kernel$4 = __commonJSMin((exports, module) => { + const {GLKernel: GLKernel} = require_kernel$5(); const {FunctionBuilder: FunctionBuilder} = require_function_builder(); - const {WebGLFunctionNode: WebGLFunctionNode} = require_function_node$2(); + const {WebGLFunctionNode: WebGLFunctionNode} = require_function_node$3(); const {utils: utils} = require_utils(); const mrud = require_math_random_uniformly_distributed(); const {fragmentShader: fragmentShader} = require_fragment_shader$1(); @@ -13604,7 +13665,7 @@ this.argumentTypes.push(type); } else type = this.argumentTypes[index]; const KernelValue = this.constructor.lookupKernelValueType(type, this.dynamicArguments ? "dynamic" : "static", this.precision, args[index]); - if (KernelValue === null) return this.requestFallback(args); + if (KernelValue === null) return this.requestFallback(args, `argument "${this.argumentNames[index]}" of type ${type} is not supported by ${this.constructor.name}`); const kernelArgument = new KernelValue(value, { name: name, type: type, @@ -13652,7 +13713,7 @@ this.constantTypes[name] = type; } else type = this.constantTypes[name]; const KernelValue = this.constructor.lookupKernelValueType(type, "static", this.precision, value); - if (KernelValue === null) return this.requestFallback(args); + if (KernelValue === null) return this.requestFallback(args, `constant "${name}" of type ${type} is not supported by ${this.constructor.name}`); const kernelValue = new KernelValue(value, { name: name, type: type, @@ -14321,9 +14382,9 @@ WebGLKernel: WebGLKernel }; }); - var require_kernel$2 = __commonJSMin((exports, module) => { + var require_kernel$3 = __commonJSMin((exports, module) => { const getContext = require_empty_module(); - const {WebGLKernel: WebGLKernel} = require_kernel$3(); + const {WebGLKernel: WebGLKernel} = require_kernel$4(); const {glKernelString: glKernelString} = require_kernel_string(); let isSupported = null; let testCanvas = null; @@ -14435,15 +14496,18 @@ HeadlessGLKernel: HeadlessGLKernel }; }); - var require_function_node$1 = __commonJSMin((exports, module) => { + var require_function_node$2 = __commonJSMin((exports, module) => { const {utils: utils} = require_utils(); - const {WebGLFunctionNode: WebGLFunctionNode} = require_function_node$2(); + const {WebGLFunctionNode: WebGLFunctionNode} = require_function_node$3(); var WebGL2FunctionNode = class extends WebGLFunctionNode { astIdentifierExpression(idtNode, retArr) { if (idtNode.type !== "Identifier") throw this.astErrorOutput("IdentifierExpression - not an Identifier", idtNode); const type = this.getType(idtNode); const name = utils.sanitizeName(idtNode.name); - if (idtNode.name === "Infinity") retArr.push("intBitsToFloat(2139095039)"); else if (type === "Boolean") if (this.argumentNames.indexOf(name) > -1) retArr.push(`bool(user_${name})`); else retArr.push(`user_${name}`); else retArr.push(`user_${name}`); + if (idtNode.name === "Infinity") retArr.push("intBitsToFloat(2139095039)"); else if (type === "Boolean") if (this.argumentNames.indexOf(name) > -1) { + const marked = this.markupUserName(idtNode.name); + retArr.push(marked.startsWith("cellShadow_") ? marked : `bool(${marked})`); + } else retArr.push(`user_${name}`); else retArr.push(this.markupUserName(idtNode.name)); return retArr; } }; @@ -15119,9 +15183,9 @@ lookupKernelValueType: lookupKernelValueType }; }); - var require_kernel$1 = __commonJSMin((exports, module) => { - const {WebGLKernel: WebGLKernel} = require_kernel$3(); - const {WebGL2FunctionNode: WebGL2FunctionNode} = require_function_node$1(); + var require_kernel$2 = __commonJSMin((exports, module) => { + const {WebGLKernel: WebGLKernel} = require_kernel$4(); + const {WebGL2FunctionNode: WebGL2FunctionNode} = require_function_node$2(); const {FunctionBuilder: FunctionBuilder} = require_function_builder(); const {utils: utils} = require_utils(); const {fragmentShader: fragmentShader} = require_fragment_shader(); @@ -15605,9 +15669,9 @@ WebGL2Kernel: WebGL2Kernel }; }); - var require_function_node = __commonJSMin((exports, module) => { + var require_function_node$1 = __commonJSMin((exports, module) => { const {utils: utils} = require_utils(); - const {FunctionNode: FunctionNode} = require_function_node$4(); + const {FunctionNode: FunctionNode} = require_function_node$5(); var WGSLFunctionNode = class extends FunctionNode { get requiresSequenceFreeForInit() { return true; @@ -16884,10 +16948,10 @@ } }; }); - var require_kernel = __commonJSMin((exports, module) => { - const {Kernel: Kernel} = require_kernel$6(); + var require_kernel$1 = __commonJSMin((exports, module) => { + const {Kernel: Kernel} = require_kernel$7(); const {FunctionBuilder: FunctionBuilder} = require_function_builder(); - const {WGSLFunctionNode: WGSLFunctionNode} = require_function_node(); + const {WGSLFunctionNode: WGSLFunctionNode} = require_function_node$1(); const {WebGPUContext: WebGPUContext} = require_context(); const {WebGPUBufferResult: WebGPUBufferResult} = require_buffer_result(); const {utils: utils} = require_utils(); @@ -17212,10 +17276,10 @@ const context = await WebGPUContext.acquire(); this.context = context; const device = this._device = context.device; - const module$1 = device.createShaderModule({ + const module$5 = device.createShaderModule({ code: this.compiledSource }); - const errors = (await module$1.getCompilationInfo()).messages.filter(message => message.type === "error"); + const errors = (await module$5.getCompilationInfo()).messages.filter(message => message.type === "error"); if (errors.length > 0) throw new Error("Error compiling WGSL compute shader:\n" + errors.map(message => ` ${message.lineNum}:${message.linePos} ${message.message}`).join("\n") + `\n--- generated WGSL ---\n${this.compiledSource}`); const {arrayArgs: arrayArgs, bufferConstants: bufferConstants, byteLength: byteLength} = this.paramsLayout; const layoutEntries = [ { @@ -17256,7 +17320,7 @@ bindGroupLayouts: [ this.bindGroupLayout ] }), compute: { - module: module$1, + module: module$5, entryPoint: "main" } }); @@ -17810,207 +17874,5516 @@ WebGPUKernel: WebGPUKernel }; }); - var require_kernel_run_shortcut = __commonJSMin((exports, module) => { - const {utils: utils} = require_utils(); - const {Input: Input} = require_input(); - function kernelRunShortcut(kernel) { - const MAX_SWITCHES = 4; - function syncBody(args) { - kernel.build.apply(kernel, args); - kernel.checkArgumentTypes(args); - let result = kernel.switchingKernels ? void 0 : kernel.run.apply(kernel, args); - for (let i = 0; kernel.switchingKernels; i++) { - if (i >= MAX_SWITCHES) { - const reasons = kernel.resetSwitchingKernels(); - throw new Error(`this kernel cannot run the arguments it was given (${describeReasons(reasons)}); it did not settle on a kernel for them after ${MAX_SWITCHES} attempts. Create a separate kernel for this call's argument types.`); - } - const reasons = kernel.resetSwitchingKernels(); - const newKernel = kernel.onRequestSwitchKernel(reasons, args, kernel); - shortcut.kernel = kernel = newKernel; - newKernel.checkArgumentTypes(args); - result = newKernel.switchingKernels ? void 0 : newKernel.run.apply(newKernel, args); + var require_wasm_builder = __commonJSMin((exports, module) => { + const VAL_TYPES = { + i32: 127, + i64: 126, + f32: 125, + f64: 124, + v128: 123 + }; + const SECTION_TYPE = 1; + const SECTION_IMPORT = 2; + const SECTION_FUNCTION = 3; + const SECTION_GLOBAL = 6; + const SECTION_EXPORT = 7; + const SECTION_CODE = 10; + const f32Scratch = new DataView(new ArrayBuffer(16)); + function uleb(value, out) { + let v = value >>> 0; + do { + let byte = v & 127; + v >>>= 7; + if (v !== 0) byte |= 128; + out.push(byte); + } while (v !== 0); + } + function sleb(value, out) { + let v = value | 0; + for (;;) { + const byte = v & 127; + v >>= 7; + if (v === 0 && (byte & 64) === 0 || v === -1 && (byte & 64) !== 0) { + out.push(byte); + return; } - return result; + out.push(byte | 128); } - function describeReasons(reasons) { - if (!reasons || !reasons.length) return "unknown reason"; - return reasons.map(reason => { - if (reason.type === "argumentTypeMismatch") return `argument ${reason.index} is now ${reason.needed}`; - return reason.type; - }).join(", "); + } + function uleb5At(value, bytes, at) { + let v = value >>> 0; + for (let i = 0; i < 4; i++) { + bytes[at + i] = v & 127 | 128; + v >>>= 7; } - function syncRun(args) { - const result = syncBody(args); - if (kernel.renderKernels) return kernel.renderKernels(); else if (kernel.renderOutput) return kernel.renderOutput(); else return result; + bytes[at + 4] = v & 127; + } + function utf8(str, out) { + const bytes = []; + for (let i = 0; i < str.length; i++) { + let code = str.codePointAt(i); + if (code > 65535) i++; + if (code < 128) bytes.push(code); else if (code < 2048) bytes.push(192 | code >> 6, 128 | code & 63); else if (code < 65536) bytes.push(224 | code >> 12, 128 | code >> 6 & 63, 128 | code & 63); else bytes.push(240 | code >> 18, 128 | code >> 12 & 63, 128 | code >> 6 & 63, 128 | code & 63); + } + uleb(bytes.length, out); + for (let i = 0; i < bytes.length; i++) out.push(bytes[i]); + } + function valType(type) { + const byte = VAL_TYPES[type]; + if (byte === void 0) throw new Error(`WasmModuleBuilder: unknown value type "${type}"`); + return byte; + } + function blockType(type) { + if (type === void 0 || type === null || type === "void") return 64; + return valType(type); + } + var WasmFunctionEmitter = class { + constructor(builder, name, params, results, locals) { + this.builder = builder; + this.name = name; + this.params = params; + this.results = results; + this.locals = locals.slice(); + this.bytes = []; + this.callFixups = []; + } + addLocal(type) { + valType(type); + this.locals.push(type); + return this.params.length + this.locals.length - 1; + } + block(type) { + this.bytes.push(2, blockType(type)); + return this; } - function asyncRun(args) { - if (kernel.onAsyncModeUpgrade) { - const upgrade = kernel.onAsyncModeUpgrade; - kernel.onAsyncModeUpgrade = null; - const snapped = snapshotArguments(args); - return upgrade(snapped, kernel).then(upgradedKernel => { - if (upgradedKernel) shortcut.replaceKernel(upgradedKernel); - return asyncRun(snapped); - }); - } - try { - if (kernel.constructor.isAsync === true) { - kernel.build.apply(kernel, args); - return Promise.resolve(kernel.run.apply(kernel, args)); - } - for (let i = 0; i < args.length; i++) if (isWebGPUHandle(args[i])) return resolveHandles(args).then(resolved => asyncRun(resolved)); - const result = syncBody(args); - if (kernel.renderKernels) return Promise.resolve(kernel.renderKernels()); else if (kernel.renderOutput) { - if (kernel.renderOutputAsync) return kernel.renderOutputAsync(); - return Promise.resolve(kernel.renderOutput()); - } else return Promise.resolve(result); - } catch (e) { - return Promise.reject(e); - } + loop(type) { + this.bytes.push(3, blockType(type)); + return this; } - function isWebGPUHandle(value) { - return Boolean(value) && value.type === "WebGPUBuffer"; + if_(type) { + this.bytes.push(4, blockType(type)); + return this; } - function resolveHandles(args) { - const snapped = snapshotArguments(args); - const pending = []; - for (let i = 0; i < snapped.length; i++) if (isWebGPUHandle(snapped[i])) { - const index = i; - pending.push(Promise.resolve(snapped[index].toArray()).then(value => { - snapped[index] = value; - })); - } - return Promise.all(pending).then(() => snapped); + br(depth) { + this.bytes.push(12); + uleb(depth, this.bytes); + return this; } - function snapshotArguments(args) { - const copy = new Array(args.length); - for (let i = 0; i < args.length; i++) copy[i] = snapshotValue(args[i]); - return copy; + brIf(depth) { + this.bytes.push(13); + uleb(depth, this.bytes); + return this; } - function snapshotValue(value) { - if (!value || typeof value !== "object") return value; - if (isWebGPUHandle(value) || typeof value.delete === "function") return value; - if (ArrayBuffer.isView(value)) return value.slice(0); - if (Array.isArray(value)) return value.map(snapshotValue); - if (value instanceof Input) return new Input(snapshotValue(value.value), value.size); - return value; + call(name) { + this.bytes.push(16); + this.callFixups.push({ + at: this.bytes.length, + name: name + }); + this.bytes.push(0, 0, 0, 0, 0); + return this; } - function run() { - if (kernel.constructor.isAsync === true || kernel.asyncMode === true) return asyncRun(arguments); - return syncRun(arguments); + localGet(index) { + this.bytes.push(32); + uleb(index, this.bytes); + return this; } - const shortcut = function() { - return run.apply(kernel, arguments); - }; - shortcut.exec = function() { - return new Promise((accept, reject) => { - try { - accept(run.apply(this, arguments)); - } catch (e) { - reject(e); - } - }); - }; - shortcut.replaceKernel = function(replacementKernel) { - kernel = replacementKernel; - bindKernelToShortcut(kernel, shortcut); - }; - bindKernelToShortcut(kernel, shortcut); - return shortcut; - } - function bindKernelToShortcut(kernel, shortcut) { - if (shortcut.kernel) { - shortcut.kernel = kernel; - return; + localSet(index) { + this.bytes.push(33); + uleb(index, this.bytes); + return this; } - const properties = utils.allPropertiesOf(kernel); - for (let i = 0; i < properties.length; i++) { - const property = properties[i]; - if (property[0] === "_" && property[1] === "_") continue; - if (typeof kernel[property] === "function") if (property.substring(0, 3) === "add" || property.substring(0, 3) === "set") shortcut[property] = function() { - shortcut.kernel[property].apply(shortcut.kernel, arguments); - return shortcut; - }; else shortcut[property] = function() { - return shortcut.kernel[property].apply(shortcut.kernel, arguments); - }; else { - shortcut.__defineGetter__(property, () => shortcut.kernel[property]); - shortcut.__defineSetter__(property, value => { - shortcut.kernel[property] = value; - }); - } + localTee(index) { + this.bytes.push(34); + uleb(index, this.bytes); + return this; } - shortcut.kernel = kernel; - } - module.exports = { - kernelRunShortcut: kernelRunShortcut - }; - }); - var require_gpu = __commonJSMin((exports, module) => { - const {gpuMock: gpuMock} = require_gpu_mock_js(); - const {utils: utils} = require_utils(); - const {Kernel: Kernel} = require_kernel$6(); - const {CPUKernel: CPUKernel} = require_kernel$5(); - const {HeadlessGLKernel: HeadlessGLKernel} = require_kernel$2(); - const {WebGL2Kernel: WebGL2Kernel} = require_kernel$1(); - const {WebGLKernel: WebGLKernel} = require_kernel$3(); - const {WebGPUKernel: WebGPUKernel} = require_kernel(); - const {kernelRunShortcut: kernelRunShortcut} = require_kernel_run_shortcut(); - const kernelOrder = [ HeadlessGLKernel, WebGL2Kernel, WebGLKernel ]; - const kernelTypes = [ "gpu", "cpu" ]; - const internalKernels = { - headlessgl: HeadlessGLKernel, - webgl2: WebGL2Kernel, - webgl: WebGLKernel, - webgpu: WebGPUKernel - }; - let validate = true; - var GPU = class GPU { - static disableValidation() { - validate = false; + globalGet(index) { + this.bytes.push(35); + uleb(index, this.bytes); + return this; } - static enableValidation() { - validate = true; + globalSet(index) { + this.bytes.push(36); + uleb(index, this.bytes); + return this; } - static get isGPUSupported() { - return kernelOrder.some(Kernel => Kernel.isSupported); + i32Const(value) { + this.bytes.push(65); + sleb(value, this.bytes); + return this; } - static get isKernelMapSupported() { - return kernelOrder.some(Kernel => Kernel.isSupported && Kernel.features.kernelMap); + f32Const(value) { + this.bytes.push(67); + f32Scratch.setFloat32(0, value, true); + for (let i = 0; i < 4; i++) this.bytes.push(f32Scratch.getUint8(i)); + return this; } - static get isOffscreenCanvasSupported() { - return typeof Worker !== "undefined" && typeof OffscreenCanvas !== "undefined" || typeof importScripts !== "undefined"; + v128Const(lanes) { + if (lanes.length !== 16) throw new Error("WasmModuleBuilder: v128.const requires exactly 16 bytes"); + this.bytes.push(253, 12); + for (let i = 0; i < 16; i++) this.bytes.push(lanes[i] & 255); + return this; } - static get isWebGLSupported() { - return WebGLKernel.isSupported; + v128ConstI32x4(a, b, c, d) { + f32Scratch.setInt32(0, a, true); + f32Scratch.setInt32(4, b, true); + f32Scratch.setInt32(8, c, true); + f32Scratch.setInt32(12, d, true); + this.bytes.push(253, 12); + for (let i = 0; i < 16; i++) this.bytes.push(f32Scratch.getUint8(i)); + return this; } - static get isWebGL2Supported() { - return WebGL2Kernel.isSupported; + v128ConstF32x4(a, b, c, d) { + f32Scratch.setFloat32(0, a, true); + f32Scratch.setFloat32(4, b, true); + f32Scratch.setFloat32(8, c, true); + f32Scratch.setFloat32(12, d, true); + this.bytes.push(253, 12); + for (let i = 0; i < 16; i++) this.bytes.push(f32Scratch.getUint8(i)); + return this; } - static get isHeadlessGLSupported() { - return HeadlessGLKernel.isSupported; + i32Load(offset = 0, align = 2) { + this.bytes.push(40); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; } - static get isWebGPUSupported() { - return WebGPUKernel.isSupported; + f32Load(offset = 0, align = 2) { + this.bytes.push(42); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; } - static isWebGPUAvailable() { - if (!WebGPUKernel.isSupported) return Promise.resolve(false); - return navigator.gpu.requestAdapter().then(adapter => adapter !== null, () => false); + i32Store(offset = 0, align = 2) { + this.bytes.push(54); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; } - static get isCanvasSupported() { - return typeof HTMLCanvasElement !== "undefined"; + f32Store(offset = 0, align = 2) { + this.bytes.push(56); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; } - static get isGPUHTMLImageArraySupported() { - return WebGL2Kernel.isSupported; + v128Load(offset = 0, align = 4) { + this.bytes.push(253, 0); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; } - static get isSinglePrecisionSupported() { - return kernelOrder.some(Kernel => Kernel.isSupported && Kernel.features.isFloatRead && Kernel.features.isTextureFloat); + v128Store(offset = 0, align = 4) { + this.bytes.push(253, 11); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; } - constructor(settings) { - settings = settings || {}; - this.canvas = settings.canvas || null; - this.context = settings.context || null; - this.mode = settings.mode; - this.Kernel = null; + i32x4ExtractLane(lane) { + return this._lane(27, lane); + } + i32x4ReplaceLane(lane) { + return this._lane(28, lane); + } + f32x4ExtractLane(lane) { + return this._lane(31, lane); + } + f32x4ReplaceLane(lane) { + return this._lane(32, lane); + } + _lane(op, lane) { + if (!Number.isInteger(lane) || lane < 0 || lane > 3) throw new Error(`WasmModuleBuilder: lane index ${lane} out of range for 4-lane shape`); + this.bytes.push(253, op, lane); + return this; + } + _push(bytes) { + for (let i = 0; i < bytes.length; i++) this.bytes.push(bytes[i]); + return this; + } + }; + const PLAIN_OPS = { + unreachable: [ 0 ], + nop: [ 1 ], + else_: [ 5 ], + end: [ 11 ], + return_: [ 15 ], + drop: [ 26 ], + select: [ 27 ], + i32Eqz: [ 69 ], + i32Eq: [ 70 ], + i32Ne: [ 71 ], + i32LtS: [ 72 ], + i32LtU: [ 73 ], + i32GtS: [ 74 ], + i32GtU: [ 75 ], + i32LeS: [ 76 ], + i32LeU: [ 77 ], + i32GeS: [ 78 ], + i32GeU: [ 79 ], + f32Eq: [ 91 ], + f32Ne: [ 92 ], + f32Lt: [ 93 ], + f32Gt: [ 94 ], + f32Le: [ 95 ], + f32Ge: [ 96 ], + i32Clz: [ 103 ], + i32Ctz: [ 104 ], + i32Popcnt: [ 105 ], + i32Add: [ 106 ], + i32Sub: [ 107 ], + i32Mul: [ 108 ], + i32DivS: [ 109 ], + i32DivU: [ 110 ], + i32RemS: [ 111 ], + i32RemU: [ 112 ], + i32And: [ 113 ], + i32Or: [ 114 ], + i32Xor: [ 115 ], + i32Shl: [ 116 ], + i32ShrS: [ 117 ], + i32ShrU: [ 118 ], + i32Rotl: [ 119 ], + i32Rotr: [ 120 ], + f32Abs: [ 139 ], + f32Neg: [ 140 ], + f32Ceil: [ 141 ], + f32Floor: [ 142 ], + f32Trunc: [ 143 ], + f32Nearest: [ 144 ], + f32Sqrt: [ 145 ], + f32Add: [ 146 ], + f32Sub: [ 147 ], + f32Mul: [ 148 ], + f32Div: [ 149 ], + f32Min: [ 150 ], + f32Max: [ 151 ], + f32Copysign: [ 152 ], + i32TruncF32S: [ 168 ], + i32TruncF32U: [ 169 ], + f32ConvertI32S: [ 178 ], + f32ConvertI32U: [ 179 ], + i32ReinterpretF32: [ 188 ], + f32ReinterpretI32: [ 190 ], + i32TruncSatF32S: [ 252, 0 ], + i32TruncSatF32U: [ 252, 1 ] + }; + const SIMD_OPS = { + i32x4Splat: 17, + f32x4Splat: 19, + i32x4Eq: 55, + i32x4Ne: 56, + i32x4LtS: 57, + i32x4GtS: 59, + i32x4LeS: 61, + i32x4GeS: 63, + f32x4Eq: 65, + f32x4Ne: 66, + f32x4Lt: 67, + f32x4Gt: 68, + f32x4Le: 69, + f32x4Ge: 70, + v128Not: 77, + v128And: 78, + v128Andnot: 79, + v128Or: 80, + v128Xor: 81, + v128Bitselect: 82, + v128AnyTrue: 83, + f32x4Ceil: 103, + f32x4Floor: 104, + f32x4Trunc: 105, + f32x4Nearest: 106, + i32x4Abs: 160, + i32x4Neg: 161, + i32x4AllTrue: 163, + i32x4Bitmask: 164, + i32x4Shl: 171, + i32x4ShrS: 172, + i32x4ShrU: 173, + i32x4Add: 174, + i32x4Sub: 177, + i32x4Mul: 181, + i32x4MinS: 182, + i32x4MinU: 183, + i32x4MaxS: 184, + i32x4MaxU: 185, + f32x4Abs: 224, + f32x4Neg: 225, + f32x4Sqrt: 227, + f32x4Add: 228, + f32x4Sub: 229, + f32x4Mul: 230, + f32x4Div: 231, + f32x4Min: 232, + f32x4Max: 233, + f32x4Pmin: 234, + f32x4Pmax: 235, + i32x4TruncSatF32x4S: 248, + i32x4TruncSatF32x4U: 249, + f32x4ConvertI32x4S: 250, + f32x4ConvertI32x4U: 251 + }; + for (const name of Object.keys(PLAIN_OPS)) { + const bytes = PLAIN_OPS[name]; + WasmFunctionEmitter.prototype[name] = function() { + return this._push(bytes); + }; + } + for (const name of Object.keys(SIMD_OPS)) { + const bytes = [ 253 ]; + uleb(SIMD_OPS[name], bytes); + WasmFunctionEmitter.prototype[name] = function() { + return this._push(bytes); + }; + } + var WasmModuleBuilder = class { + constructor() { + this.types = []; + this.typeIndexByKey = {}; + this.memoryImport = null; + this.funcImports = []; + this.funcImportIndexByName = {}; + this.functions = []; + this.functionIndexByName = {}; + this.globals = []; + this.exports = []; + } + _typeIndex(params, results) { + const key = `${params.join(",")}=>${results.join(",")}`; + if (key in this.typeIndexByKey) return this.typeIndexByKey[key]; + const index = this.types.length; + this.types.push({ + params: params, + results: results + }); + this.typeIndexByKey[key] = index; + return index; + } + addMemoryImport(initial, maximum, shared = false) { + if (shared && (maximum === void 0 || maximum === null)) throw new Error("WasmModuleBuilder: shared memory import requires a maximum"); + this.memoryImport = { + initial: initial, + maximum: maximum, + shared: shared + }; + return this; + } + addFuncImport(name, params, results, module$3 = "env") { + if (name in this.funcImportIndexByName || name in this.functionIndexByName) throw new Error(`WasmModuleBuilder: duplicate function name "${name}"`); + const index = this.funcImports.length; + this.funcImports.push({ + name: name, + module: module$3, + typeIndex: this._typeIndex(params, results) + }); + this.funcImportIndexByName[name] = index; + return index; + } + addGlobal(type, mutable, initialValue) { + valType(type); + this.globals.push({ + type: type, + mutable: mutable, + initialValue: initialValue + }); + return this.globals.length - 1; + } + addFunction(name, {params: params = [], results: results = [], locals: locals = []} = {}) { + if (name in this.funcImportIndexByName || name in this.functionIndexByName) throw new Error(`WasmModuleBuilder: duplicate function name "${name}"`); + params.forEach(valType); + results.forEach(valType); + locals.forEach(valType); + const emitter = new WasmFunctionEmitter(this, name, params, results, locals); + this.functionIndexByName[name] = this.functions.length; + this.functions.push({ + name: name, + emitter: emitter, + typeIndex: this._typeIndex(params, results) + }); + return emitter; + } + exportFunction(name, exportName = name) { + this.exports.push({ + name: name, + exportName: exportName + }); + return this; + } + _resolveFuncIndex(name) { + if (name in this.funcImportIndexByName) return this.funcImportIndexByName[name]; + if (name in this.functionIndexByName) return this.funcImports.length + this.functionIndexByName[name]; + throw new Error(`WasmModuleBuilder: call target "${name}" is not an import or a defined function`); + } + _section(id, payload, out) { + out.push(id); + uleb(payload.length, out); + for (let i = 0; i < payload.length; i++) out.push(payload[i]); + } + toBytes() { + const out = [ 0, 97, 115, 109, 1, 0, 0, 0 ]; + if (this.types.length > 0) { + const payload = []; + uleb(this.types.length, payload); + for (const {params: params, results: results} of this.types) { + payload.push(96); + uleb(params.length, payload); + for (const p of params) payload.push(valType(p)); + uleb(results.length, payload); + for (const r of results) payload.push(valType(r)); + } + this._section(SECTION_TYPE, payload, out); + } + if (this.memoryImport !== null || this.funcImports.length > 0) { + const payload = []; + uleb((this.memoryImport !== null ? 1 : 0) + this.funcImports.length, payload); + if (this.memoryImport !== null) { + const {initial: initial, maximum: maximum, shared: shared} = this.memoryImport; + utf8("env", payload); + utf8("memory", payload); + payload.push(2); + const hasMax = maximum !== void 0 && maximum !== null; + payload.push(shared ? 3 : hasMax ? 1 : 0); + uleb(initial, payload); + if (hasMax) uleb(maximum, payload); + } + for (const {name: name, module: module$4, typeIndex: typeIndex} of this.funcImports) { + utf8(module$4, payload); + utf8(name, payload); + payload.push(0); + uleb(typeIndex, payload); + } + this._section(SECTION_IMPORT, payload, out); + } + if (this.functions.length > 0) { + const payload = []; + uleb(this.functions.length, payload); + for (const {typeIndex: typeIndex} of this.functions) uleb(typeIndex, payload); + this._section(SECTION_FUNCTION, payload, out); + } + if (this.globals.length > 0) { + const payload = []; + uleb(this.globals.length, payload); + for (const {type: type, mutable: mutable, initialValue: initialValue} of this.globals) { + payload.push(valType(type), mutable ? 1 : 0); + if (type === "i32") { + payload.push(65); + sleb(initialValue, payload); + } else if (type === "f32") { + payload.push(67); + f32Scratch.setFloat32(0, initialValue, true); + for (let i = 0; i < 4; i++) payload.push(f32Scratch.getUint8(i)); + } else if (type === "v128") { + payload.push(253, 12); + for (let i = 0; i < 16; i++) payload.push(0); + } else throw new Error(`WasmModuleBuilder: no initializer encoding for global type "${type}"`); + payload.push(11); + } + this._section(SECTION_GLOBAL, payload, out); + } + if (this.exports.length > 0) { + const payload = []; + uleb(this.exports.length, payload); + for (const {name: name, exportName: exportName} of this.exports) { + utf8(exportName, payload); + payload.push(0); + uleb(this._resolveFuncIndex(name), payload); + } + this._section(SECTION_EXPORT, payload, out); + } + if (this.functions.length > 0) { + const payload = []; + uleb(this.functions.length, payload); + for (const {emitter: emitter} of this.functions) { + const body = emitter.bytes.slice(); + for (const {at: at, name: name} of emitter.callFixups) uleb5At(this._resolveFuncIndex(name), body, at); + const entry = []; + const runs = []; + for (const local of emitter.locals) { + const type = valType(local); + if (runs.length > 0 && runs[runs.length - 1].type === type) runs[runs.length - 1].count++; else runs.push({ + type: type, + count: 1 + }); + } + uleb(runs.length, entry); + for (const {type: type, count: count} of runs) { + uleb(count, entry); + entry.push(type); + } + for (let i = 0; i < body.length; i++) entry.push(body[i]); + entry.push(11); + uleb(entry.length, payload); + for (let i = 0; i < entry.length; i++) payload.push(entry[i]); + } + this._section(SECTION_CODE, payload, out); + } + return Uint8Array.from(out); + } + }; + module.exports = { + WasmModuleBuilder: WasmModuleBuilder, + WasmFunctionEmitter: WasmFunctionEmitter + }; + }); + var require_function_node = __commonJSMin((exports, module) => { + const {utils: utils} = require_utils(); + const {FunctionNode: FunctionNode} = require_function_node$5(); + const {WasmFunctionEmitter: WasmFunctionEmitter} = require_wasm_builder(); + var NoopEmitter = class { + constructor() { + this.localCount = 0; + } + addLocal() { + return this.localCount++; + } + }; + for (const name of Object.getOwnPropertyNames(WasmFunctionEmitter.prototype)) { + if (name === "constructor" || name === "addLocal") continue; + if (typeof WasmFunctionEmitter.prototype[name] !== "function") continue; + NoopEmitter.prototype[name] = function() { + return this; + }; + } + const MATH_IMPORT_ARITY = { + sin: 1, + cos: 1, + tan: 1, + asin: 1, + acos: 1, + atan: 1, + atan2: 2, + sinh: 1, + cosh: 1, + tanh: 1, + asinh: 1, + acosh: 1, + atanh: 1, + exp: 1, + expm1: 1, + log: 1, + log2: 1, + log10: 1, + log1p: 1, + cbrt: 1, + pow: 2, + sign: 1 + }; + const MATH_NATIVE_OPS = { + abs: "f32Abs", + floor: "f32Floor", + ceil: "f32Ceil", + sqrt: "f32Sqrt", + trunc: "f32Trunc" + }; + const F32_ARITH = { + "+": "f32Add", + "-": "f32Sub", + "*": "f32Mul" + }; + const I32_ARITH = { + "+": "i32Add", + "-": "i32Sub", + "*": "i32Mul" + }; + const F32_COMPARE = { + "==": "f32Eq", + "===": "f32Eq", + "!=": "f32Ne", + "!==": "f32Ne", + "<": "f32Lt", + ">": "f32Gt", + "<=": "f32Le", + ">=": "f32Ge" + }; + const I32_COMPARE = { + "==": "i32Eq", + "===": "i32Eq", + "!=": "i32Ne", + "!==": "i32Ne", + "<": "i32LtS", + ">": "i32GtS", + "<=": "i32LeS", + ">=": "i32GeS" + }; + const BITWISE_OPS = { + "&": "i32And", + "|": "i32Or", + "^": "i32Xor", + "<<": "i32Shl", + ">>": "i32ShrS", + ">>>": "i32ShrU" + }; + const VF32_ARITH = { + "+": "f32x4Add", + "-": "f32x4Sub", + "*": "f32x4Mul" + }; + const VI32_ARITH = { + "+": "i32x4Add", + "-": "i32x4Sub", + "*": "i32x4Mul" + }; + const VF32_COMPARE = { + "==": "f32x4Eq", + "===": "f32x4Eq", + "!=": "f32x4Ne", + "!==": "f32x4Ne", + "<": "f32x4Lt", + ">": "f32x4Gt", + "<=": "f32x4Le", + ">=": "f32x4Ge" + }; + const VI32_COMPARE = { + "==": "i32x4Eq", + "===": "i32x4Eq", + "!=": "i32x4Ne", + "!==": "i32x4Ne", + "<": "i32x4LtS", + ">": "i32x4GtS", + "<=": "i32x4LeS", + ">=": "i32x4GeS" + }; + const VECTOR_SHIFT_OPS = { + "<<": "i32x4Shl", + ">>": "i32x4ShrS", + ">>>": "i32x4ShrU" + }; + const VECTOR_MATH_NATIVE_OPS = { + abs: "f32x4Abs", + floor: "f32x4Floor", + ceil: "f32x4Ceil", + sqrt: "f32x4Sqrt", + trunc: "f32x4Trunc" + }; + function scalarWasmType(type) { + switch (type) { + case "Number": + case "Float": + case "LiteralInteger": + return "f32"; + + case "Integer": + case "Boolean": + return "i32"; + + default: + throw new Error(`WebAssembly backend does not yet support ${type} arguments to helper functions`); + } + } + var WebAssemblyFunctionNode = class extends FunctionNode { + constructor(source, settings) { + super(source, settings); + this.assembler = null; + this.em = null; + this.locals = null; + this.depth = 0; + this.loopStack = null; + this.usedMathImports = new Set; + this.usesRandom = false; + this.readsThread = false; + this.taintedLocals = null; + this.uniformity = []; + this._analysisDone = false; + this._analysisPass = false; + this.vec = false; + this.vMaskDepth = 0; + this.vCur = -1; + this.vRetMask = -1; + this.vTerminated = false; + this.vInfo = null; + this._vBaseX = -1; + } + mangleFunctionName(name) { + return `fn_${utils.sanitizeName(name)}`; + } + getType(ast) { + if (ast && ast.type === "ConditionalExpression") { + const consequentType = this.getType(ast.consequent); + if (consequentType === "Integer" || consequentType === "LiteralInteger") { + const alternateType = this.getType(ast.alternate); + if (alternateType === "Number" || alternateType === "Float") return "Number"; + } + } + return super.getType(ast); + } + toString() { + if (!this._analysisDone) { + this._analysisDone = true; + this._analysisPass = true; + this.walkFunction(new NoopEmitter); + this._analysisPass = false; + } + return ""; + } + emitFunction(assembler) { + this.assembler = assembler; + const {module: module$2} = assembler; + let em; + if (this.isRootKernel) em = module$2.addFunction("kernel", { + params: [], + results: [] + }); else { + const params = this.argumentTypes.map(type => scalarWasmType(type === "LiteralInteger" ? "Number" : type)); + const results = []; + if (this.returnType) switch (this.returnType) { + case "Integer": + case "Boolean": + results.push("i32"); + break; + + case "Number": + case "Float": + case "LiteralInteger": + results.push("f32"); + break; + + default: + throw new Error(`WebAssembly backend does not yet support helper functions returning ${this.returnType}`); + } + em = module$2.addFunction(this.mangleFunctionName(this.name), { + params: params, + results: results + }); + } + this.walkFunction(em); + if (!this.isRootKernel && this.returnType) em.unreachable(); + return em; + } + walkFunction(em) { + this.em = em; + this.locals = new Map; + this.depth = 0; + this.loopStack = []; + this.taintedLocals = new Set; + const ast = this.getJsAST(); + if (this.isRootKernel) for (const name of this.collectAssignedArgumentNames(ast)) { + const argumentIndex = this.argumentNames.indexOf(name); + const gtype = this.argumentTypes[argumentIndex]; + if (gtype !== "Number" && gtype !== "Float" && gtype !== "Integer" && gtype !== "Boolean") continue; + const slot = this.assembler ? this.assembler.layout.scalars[name] : null; + const offset = slot ? slot.offset : 0; + const wtype = gtype === "Integer" || gtype === "Boolean" ? "i32" : "f32"; + const index = em.addLocal(wtype); + em.i32Const(0); + if (wtype === "i32") em.i32Load(offset); else em.f32Load(offset); + em.localSet(index); + this.locals.set(name, { + kind: "scalar", + index: index, + wtype: wtype, + gtype: gtype + }); + } + if (!this.isRootKernel) { + for (let i = 0; i < this.argumentNames.length; i++) { + const name = this.argumentNames[i]; + let argumentType = this.argumentTypes[i]; + if (!argumentType) throw this.astErrorOutput(`Unknown argument ${name} type`, ast); + if (argumentType === "LiteralInteger") this.argumentTypes[i] = argumentType = "Number"; + this.locals.set(name, { + kind: "scalar", + index: i, + wtype: scalarWasmType(argumentType), + gtype: argumentType + }); + } + if (!this.returnType) { + if (this.findLastReturn()) { + this.returnType = this.getType(ast.body); + if (this.returnType === "LiteralInteger") this.returnType = "Number"; + } + } + } + const body = ast.body.body; + for (let i = 0; i < body.length; i++) this.statement(body[i]); + } + collectAssignedArgumentNames(ast) { + const names = new Set; + const walk = node => { + if (!node || typeof node !== "object") return; + if (Array.isArray(node)) return node.forEach(walk); + if (node.type === "FunctionDeclaration" && node !== ast) return; + if (node.type === "AssignmentExpression" && node.left.type === "Identifier" && this.argumentNames.indexOf(node.left.name) !== -1) names.add(node.left.name); + if (node.type === "UpdateExpression" && node.argument.type === "Identifier" && this.argumentNames.indexOf(node.argument.name) !== -1) names.add(node.argument.name); + for (const key in node) { + if (key === "loc" || key === "start" || key === "end" || key === "parent") continue; + const child = node[key]; + if (child && typeof child === "object") walk(child); + } + }; + walk(ast.body); + return names; + } + enterBlock(type) { + this.em.block(type); + this.depth++; + } + enterLoop(type) { + this.em.loop(type); + this.depth++; + } + enterIf(type) { + this.em.if_(type); + this.depth++; + } + exit() { + this.em.end(); + this.depth--; + } + brTo(level) { + this.em.br(this.depth - level); + } + brIfTo(level) { + this.em.brIf(this.depth - level); + } + get loopMax() { + return parseInt(this.loopMaxIterations, 10) || 1e3; + } + coerce(from, to) { + if (from === to) return to; + if (from === "void") throw new Error("cannot use a void expression as a value"); + switch (to) { + case "f32": + this.em.f32ConvertI32S(); + return "f32"; + + case "i32": + if (from === "f32") this.em.i32TruncSatF32S(); + return "i32"; + + case "bool": + if (from === "f32") this.em.f32Const(0).f32Ne(); else this.em.i32Eqz().i32Eqz(); + return "bool"; + + default: + throw new Error(`unknown wasm value category ${to}`); + } + } + castLiteralToInteger(ast) { + this.pushState("casting-to-integer"); + const type = this.expression(ast); + this.popState("casting-to-integer"); + this.coerce(type, "i32"); + return "i32"; + } + castLiteralToFloat(ast) { + this.pushState("casting-to-float"); + const type = this.expression(ast); + this.popState("casting-to-float"); + this.coerce(type, "f32"); + return "f32"; + } + castValueToInteger(ast) { + this.pushState("casting-to-integer"); + const type = this.expression(ast); + this.popState("casting-to-integer"); + this.coerce(type, "i32"); + return "i32"; + } + castValueToFloat(ast) { + this.pushState("casting-to-float"); + const type = this.expression(ast); + this.popState("casting-to-float"); + this.coerce(type, "f32"); + return "f32"; + } + emitByType(ast, want) { + const type = this.getType(ast); + if (want === "f32") { + if (type === "Integer") return this.castValueToFloat(ast); + if (type === "LiteralInteger") return this.castLiteralToFloat(ast); + this.coerce(this.expression(ast), "f32"); + return "f32"; + } + if (type === "Number" || type === "Float") return this.castValueToInteger(ast); + if (type === "LiteralInteger") return this.castLiteralToInteger(ast); + this.coerce(this.expression(ast), "i32"); + return "i32"; + } + emitCondition(ast) { + const type = this.expression(ast); + if (type === "bool") return; + if (type === "i32") { + this.em.i32Eqz().i32Eqz(); + return; + } + if (type === "f32") { + this.em.f32Const(0).f32Ne(); + return; + } + throw this.astErrorOutput("cannot use a void expression as a condition", ast); + } + statement(ast) { + switch (ast.type) { + case "VariableDeclaration": + return this.stmtVariableDeclaration(ast); + + case "ExpressionStatement": + return this.statementExpression(ast.expression); + + case "ReturnStatement": + return this.stmtReturn(ast); + + case "IfStatement": + return this.stmtIf(ast); + + case "ForStatement": + return this.stmtFor(ast); + + case "WhileStatement": + return this.stmtWhile(ast); + + case "DoWhileStatement": + return this.stmtDoWhile(ast); + + case "BlockStatement": + for (let i = 0; i < ast.body.length; i++) this.statement(ast.body[i]); + return; + + case "BreakStatement": + return this.stmtBreak(ast); + + case "ContinueStatement": + return this.stmtContinue(ast); + + case "SwitchStatement": + return this.stmtSwitch(ast); + + case "FunctionDeclaration": + if (this.isChildFunction(ast)) return; + throw this.astErrorOutput("unexpected function declaration", ast); + + case "EmptyStatement": + case "DebuggerStatement": + return; + + default: + throw this.astErrorOutput(`Unknown statement type ${ast.type}`, ast); + } + } + statementExpression(expression) { + switch (expression.type) { + case "AssignmentExpression": + return this.emitAssignment(expression); + + case "UpdateExpression": + this.emitUpdate(expression, true); + return; + + case "SequenceExpression": + for (let i = 0; i < expression.expressions.length; i++) this.statementExpression(expression.expressions[i]); + return; + + case "Identifier": + case "Literal": + return; + + default: + if (this.expression(expression) !== "void") this.em.drop(); + } + } + stmtVariableDeclaration(varDecNode) { + const declarations = varDecNode.declarations; + if (!declarations || !declarations[0] || !declarations[0].init) throw this.astErrorOutput("Unexpected expression", varDecNode); + for (let i = 0; i < declarations.length; i++) { + const declaration = declarations[i]; + const init = declaration.init; + const info = this.getDeclaration(declaration.id); + const actualType = this.getType(init); + const name = declaration.id.name; + if (actualType === "Array(2)" || actualType === "Array(3)" || actualType === "Array(4)") { + this.declareVecLocal(name, actualType, init, info, varDecNode); + if (this.isThreadDependent(init)) this.taintedLocals.add(name); + continue; + } + let type = actualType; + if (type === "LiteralInteger") type = info.suggestedType === "Integer" ? "Integer" : "Number"; + if (actualType === "Integer" && type === "Integer") { + info.valueType = "Number"; + this.setScalarLocal(name, "f32", "Number", () => this.castValueToFloat(init)); + } else { + info.valueType = type; + switch (type) { + case "Number": + case "Float": + this.setScalarLocal(name, "f32", type, () => { + if (actualType === "LiteralInteger") this.castLiteralToFloat(init); else if (actualType === "Integer") this.castValueToFloat(init); else this.coerce(this.expression(init), "f32"); + }); + break; + + case "Integer": + this.setScalarLocal(name, "i32", "Integer", () => { + if (actualType === "LiteralInteger") this.castLiteralToInteger(init); else if (actualType === "Number" || actualType === "Float") this.castValueToInteger(init); else this.coerce(this.expression(init), "i32"); + }); + break; + + case "Boolean": + this.setScalarLocal(name, "i32", "Boolean", () => this.emitCondition(init)); + break; + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support declaring type ${type}`, varDecNode); + } + } + if (this.isThreadDependent(init)) this.taintedLocals.add(name); + } + } + setScalarLocal(name, wtype, gtype, emitInit) { + let local = this.locals.get(name); + if (!local || local.kind !== "scalar" || local.wtype !== wtype) { + local = { + kind: "scalar", + index: this.em.addLocal(wtype), + wtype: wtype, + gtype: gtype + }; + this.locals.set(name, local); + } else local.gtype = gtype; + emitInit(); + this.em.localSet(local.index); + } + declareVecLocal(name, type, init, info, varDecNode) { + const n = parseInt(type.substring(6), 10); + info.valueType = type; + let local = this.locals.get(name); + if (!local || local.kind !== "vec" || local.n !== n) { + const indices = []; + for (let c = 0; c < n; c++) indices.push(this.em.addLocal("f32")); + local = { + kind: "vec", + indices: indices, + n: n, + gtype: type + }; + this.locals.set(name, local); + } + if (init.type === "ArrayExpression") { + for (let c = 0; c < n; c++) { + this.emitArrayElement(init.elements[c]); + this.em.localSet(local.indices[c]); + } + return; + } + if (init.type === "Identifier") { + const source = this.locals.get(init.name); + if (source && source.kind === "vec" && source.n === n) { + for (let c = 0; c < n; c++) this.em.localGet(source.indices[c]).localSet(local.indices[c]); + return; + } + } + throw this.astErrorOutput(`WebAssembly backend does not yet support ${type} initializer of type ${init.type}`, varDecNode); + } + emitArrayElement(element) { + switch (this.getType(element)) { + case "Integer": + this.castValueToFloat(element); + break; + + case "LiteralInteger": + this.castLiteralToFloat(element); + break; + + default: + this.coerce(this.expression(element), "f32"); + } + } + emitAssignment(assNode) { + if (assNode.left.type !== "Identifier") throw this.astErrorOutput(`WebAssembly backend does not yet support assignment to ${assNode.left.type}`, assNode); + const name = assNode.left.name; + const local = this.locals.get(name); + let wtype = null; + let store = null; + if (local && local.kind === "scalar") { + wtype = local.wtype; + store = () => this.em.localSet(local.index); + } else if (!local && this.isRootKernel && this.argumentNames.indexOf(name) !== -1) { + const gtype = this.argumentTypes[this.argumentNames.indexOf(name)]; + const slot = this.assembler ? this.assembler.layout.scalars[name] : null; + if (this.assembler && !slot) throw this.astErrorOutput(`WebAssembly backend does not yet support assigning to the array argument "${name}"`, assNode); + const offset = slot ? slot.offset : 0; + wtype = gtype === "Integer" || gtype === "Boolean" ? "i32" : "f32"; + this.em.i32Const(0); + store = () => wtype === "i32" ? this.em.i32Store(offset) : this.em.f32Store(offset); + } else throw this.astErrorOutput(`cannot assign to "${name}"`, assNode); + if (assNode.operator === "=") { + const leftType = this.getType(assNode.left); + const rightType = this.getType(assNode.right); + if (leftType !== "Integer" && rightType === "Integer") { + this.castValueToFloat(assNode.right); + this.coerce("f32", wtype); + } else if (leftType !== "Integer" && rightType === "LiteralInteger") { + this.castLiteralToFloat(assNode.right); + this.coerce("f32", wtype); + } else if (leftType === "Integer" && rightType === "LiteralInteger") { + this.castLiteralToInteger(assNode.right); + this.coerce("i32", wtype); + } else if (leftType === "Integer" && (rightType === "Number" || rightType === "Float")) { + this.castValueToInteger(assNode.right); + this.coerce("i32", wtype); + } else this.coerce(this.expression(assNode.right), wtype); + } else { + const synthetic = { + type: "BinaryExpression", + operator: assNode.operator.slice(0, -1), + left: assNode.left, + right: assNode.right + }; + this.coerce(this.exprBinary(synthetic), wtype); + } + store(); + if (this.isThreadDependent(assNode.right) || assNode.operator !== "=" && this.taintedLocals.has(name)) this.taintedLocals.add(name); + } + emitUpdate(uNode, isStatement) { + if (uNode.argument.type !== "Identifier") throw this.astErrorOutput("update expression needs a variable", uNode); + const local = this.locals.get(uNode.argument.name); + if (!local || local.kind !== "scalar") throw this.astErrorOutput(`cannot update "${uNode.argument.name}"`, uNode); + const isInt = local.wtype === "i32"; + const one = () => isInt ? this.em.i32Const(1) : this.em.f32Const(1); + const op = uNode.operator === "++" ? isInt ? "i32Add" : "f32Add" : isInt ? "i32Sub" : "f32Sub"; + if (isStatement) { + this.em.localGet(local.index); + one(); + this.em[op]().localSet(local.index); + return "void"; + } + if (uNode.prefix) { + this.em.localGet(local.index); + one(); + this.em[op]().localTee(local.index); + } else { + this.em.localGet(local.index).localGet(local.index); + one(); + this.em[op]().localSet(local.index); + } + return local.wtype; + } + stmtReturn(ast) { + if (!ast.argument) { + if (this.isRootKernel) { + this.em.return_(); + return; + } + throw this.astErrorOutput("Unexpected return statement", ast); + } + this.pushState("skip-literal-correction"); + const type = this.getType(ast.argument); + this.popState("skip-literal-correction"); + if (!this.returnType) this.returnType = type === "LiteralInteger" || type === "Integer" ? "Number" : type; + if (this.isRootKernel) return this.stmtRootReturn(ast, type); + if (this.isSubKernel) throw this.astErrorOutput("WebAssembly backend does not yet support createKernelMap", ast); + switch (this.returnType) { + case "LiteralInteger": + case "Number": + case "Float": + if (type === "Integer") this.castValueToFloat(ast.argument); else if (type === "LiteralInteger") this.castLiteralToFloat(ast.argument); else this.coerce(this.expression(ast.argument), "f32"); + break; + + case "Integer": + if (type === "Float" || type === "Number") this.castValueToInteger(ast.argument); else if (type === "LiteralInteger") this.castLiteralToInteger(ast.argument); else this.coerce(this.expression(ast.argument), "i32"); + break; + + case "Boolean": + this.emitCondition(ast.argument); + break; + + default: + throw this.astErrorOutput(`unhandled return type ${this.returnType}`, ast); + } + this.em.return_(); + } + stmtRootReturn(ast, type) { + const globals = this.assembler ? this.assembler.globals : { + dataIndex: 0 + }; + const outputOffset = this.assembler ? this.assembler.layout.outputOffset : 0; + switch (this.returnType) { + case "Array(2)": + case "Array(3)": + case "Array(4)": + { + const n = parseInt(this.returnType.substring(6), 10); + const argument = ast.argument; + if (argument.type === "ArrayExpression") { + if (argument.elements.length !== n) throw this.astErrorOutput(`expected ${n} array elements to match return type ${this.returnType}`, ast); + for (let c = 0; c < n; c++) { + this.emitComponentAddress(globals.dataIndex, n, c); + this.emitArrayElement(argument.elements[c]); + this.em.f32Store(outputOffset); + } + } else if (argument.type === "Identifier") { + const local = this.locals.get(argument.name); + if (!local || local.kind !== "vec" || local.n !== n) throw this.astErrorOutput(`"${argument.name}" is not an Array(${n}) variable`, ast); + for (let c = 0; c < n; c++) { + this.emitComponentAddress(globals.dataIndex, n, c); + this.em.localGet(local.indices[c]); + this.em.f32Store(outputOffset); + } + } else throw this.astErrorOutput(`WebAssembly backend does not yet support returning ${this.returnType} from a ${argument.type}`, ast); + this.em.return_(); + return; + } + + default: + this.emitComponentAddress(globals.dataIndex, 1, 0); + switch (this.returnType) { + case "Integer": + if (type === "Float" || type === "Number") this.castValueToInteger(ast.argument); else if (type === "LiteralInteger") this.castLiteralToInteger(ast.argument); else this.coerce(this.expression(ast.argument), "i32"); + this.em.f32ConvertI32S(); + break; + + case "LiteralInteger": + case "Number": + case "Float": + if (type === "Integer") this.castValueToFloat(ast.argument); else if (type === "LiteralInteger") this.castLiteralToFloat(ast.argument); else this.coerce(this.expression(ast.argument), "f32"); + break; + + case "Boolean": + this.emitCondition(ast.argument); + this.em.f32ConvertI32S(); + break; + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support returning ${this.returnType}`, ast); + } + this.em.f32Store(outputOffset); + this.em.return_(); + } + } + emitComponentAddress(dataIndexGlobal, componentCount, component) { + this.em.globalGet(dataIndexGlobal); + if (componentCount !== 1) { + this.em.i32Const(componentCount).i32Mul(); + if (component !== 0) this.em.i32Const(component).i32Add(); + } + this.em.i32Const(2).i32Shl(); + } + stmtIf(ifNode) { + this.recordUniformity("if", ifNode.test); + this.emitCondition(ifNode.test); + this.enterIf(); + this.statement(ifNode.consequent); + if (ifNode.alternate) { + this.em.else_(); + this.statement(ifNode.alternate); + } + this.exit(); + } + forLoopIsSafe(forNode) { + let isSafe = null; + if (forNode.init) { + const declarations = forNode.init.declarations; + if (declarations) { + if (declarations.length > 1) isSafe = false; + for (let i = 0; i < declarations.length; i++) if (declarations[i].init && declarations[i].init.type !== "Literal") isSafe = false; + } else isSafe = false; + } else isSafe = false; + if (!forNode.test || !forNode.update) isSafe = false; + if (isSafe === null) isSafe = this.isSafe(forNode.init) && this.isSafe(forNode.test); + return isSafe; + } + stmtFor(forNode) { + if (forNode.type !== "ForStatement") throw this.astErrorOutput("Invalid for statement", forNode); + const isSafe = this.forLoopIsSafe(forNode); + this.recordUniformity("for", forNode.test || null); + if (forNode.init) if (forNode.init.type === "VariableDeclaration") this.stmtVariableDeclaration(forNode.init); else this.statementExpression(forNode.init); + let safeI = -1; + if (!isSafe) { + safeI = this.em.addLocal("i32"); + this.em.i32Const(0).localSet(safeI); + } + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + if (!isSafe) { + this.em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + } + if (forNode.test) { + this.emitCondition(forNode.test); + this.em.i32Eqz(); + this.brIfTo(breakLevel); + } + this.enterBlock(); + const continueLevel = this.depth; + this.loopStack.push({ + breakLevel: breakLevel, + continueLevel: continueLevel + }); + if (forNode.body) this.statement(forNode.body); + this.loopStack.pop(); + this.exit(); + if (forNode.update) this.statementExpression(forNode.update); + if (!isSafe) this.em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + } + stmtWhile(whileNode) { + if (whileNode.type !== "WhileStatement") throw this.astErrorOutput("Invalid while statement", whileNode); + this.recordUniformity("while", whileNode.test); + const safeI = this.em.addLocal("i32"); + this.em.i32Const(0).localSet(safeI); + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + this.em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + this.emitCondition(whileNode.test); + this.em.i32Eqz(); + this.brIfTo(breakLevel); + this.enterBlock(); + const continueLevel = this.depth; + this.loopStack.push({ + breakLevel: breakLevel, + continueLevel: continueLevel + }); + this.statement(whileNode.body); + this.loopStack.pop(); + this.exit(); + this.em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + } + stmtDoWhile(doWhileNode) { + if (doWhileNode.type !== "DoWhileStatement") throw this.astErrorOutput("Invalid while statement", doWhileNode); + this.recordUniformity("do-while", doWhileNode.test); + const safeI = this.em.addLocal("i32"); + this.em.i32Const(0).localSet(safeI); + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + this.em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + this.enterBlock(); + const continueLevel = this.depth; + this.loopStack.push({ + breakLevel: breakLevel, + continueLevel: continueLevel + }); + this.statement(doWhileNode.body); + this.loopStack.pop(); + this.exit(); + this.em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.emitCondition(doWhileNode.test); + this.brIfTo(loopLevel); + this.exit(); + this.exit(); + } + stmtBreak(brNode) { + const target = this.loopStack[this.loopStack.length - 1]; + if (!target) throw this.astErrorOutput("break used outside of a loop", brNode); + this.brTo(target.breakLevel); + } + stmtContinue(crNode) { + const target = this.loopStack[this.loopStack.length - 1]; + if (!target) throw this.astErrorOutput("continue used outside of a loop", crNode); + this.brTo(target.continueLevel); + } + stmtSwitch(ast) { + if (ast.type !== "SwitchStatement") throw this.astErrorOutput("Invalid switch statement", ast); + const {discriminant: discriminant, cases: cases} = ast; + const type = this.getType(discriminant); + this.recordUniformity("switch", discriminant); + let dLocal; + let dIsInt; + switch (type) { + case "Float": + case "Number": + dIsInt = false; + dLocal = this.em.addLocal("f32"); + this.coerce(this.expression(discriminant), "f32"); + this.em.localSet(dLocal); + break; + + case "Integer": + dIsInt = true; + dLocal = this.em.addLocal("i32"); + this.coerce(this.expression(discriminant), "i32"); + this.em.localSet(dLocal); + break; + + default: + throw this.astErrorOutput(`Unhandled switch discriminant type "${type}"`, ast); + } + if (cases.length === 1 && !cases[0].test) { + this.emitSwitchConsequent(cases[0].consequent); + return; + } + const {groups: groups, defaultConsequent: defaultConsequent} = this.collectSwitchGroups(cases); + const emitChain = index => { + if (index === groups.length) { + if (defaultConsequent) this.emitSwitchConsequent(defaultConsequent); + return false; + } + const {tests: tests, consequent: consequent} = groups[index]; + for (let i = 0; i < tests.length; i++) { + this.em.localGet(dLocal); + this.emitSwitchTest(tests[i], dIsInt); + if (dIsInt) this.em.i32Eq(); else this.em.f32Eq(); + if (i > 0) this.em.i32Or(); + } + this.enterIf(); + this.emitSwitchConsequent(consequent); + if (index + 1 < groups.length || defaultConsequent) { + this.em.else_(); + emitChain(index + 1); + } + this.exit(); + return true; + }; + emitChain(0); + } + emitSwitchTest(test, dIsInt) { + const testType = this.getType(test); + if (dIsInt) if (testType === "Number" || testType === "Float") this.castValueToInteger(test); else if (testType === "LiteralInteger") this.castLiteralToInteger(test); else this.coerce(this.expression(test), "i32"); else if (testType === "LiteralInteger") this.castLiteralToFloat(test); else if (testType === "Integer") this.castValueToFloat(test); else this.coerce(this.expression(test), "f32"); + } + collectSwitchGroups(cases) { + let defaultConsequent = null; + const groups = []; + let pendingTests = []; + for (let i = 0; i < cases.length; i++) { + if (!cases[i].test) { + defaultConsequent = cases[i].consequent; + continue; + } + pendingTests.push(cases[i].test); + if (cases[i].consequent && cases[i].consequent.length > 0) { + groups.push({ + tests: pendingTests, + consequent: cases[i].consequent + }); + pendingTests = []; + } + } + return { + groups: groups, + defaultConsequent: defaultConsequent + }; + } + collectSwitchCaseStatements(consequent) { + const statements = []; + for (let i = 0; i < consequent.length; i++) { + if (consequent[i].type === "BreakStatement") break; + statements.push(consequent[i]); + } + const containsBreak = node => { + if (!node || typeof node !== "object") return false; + if (Array.isArray(node)) return node.some(containsBreak); + if (node.type === "BreakStatement") return true; + if (node.type === "ForStatement" || node.type === "WhileStatement" || node.type === "DoWhileStatement" || node.type === "SwitchStatement") return false; + for (const key in node) { + if (key === "loc" || key === "range" || key === "parent") continue; + if (containsBreak(node[key])) return true; + } + return false; + }; + for (let i = 0; i < statements.length; i++) if (containsBreak(statements[i])) throw this.astErrorOutput("break inside a switch case is only supported as the case terminator", statements[i]); + return statements; + } + emitSwitchConsequent(consequent) { + const statements = this.collectSwitchCaseStatements(consequent); + for (let i = 0; i < statements.length; i++) this.statement(statements[i]); + } + expression(ast) { + switch (ast.type) { + case "Literal": + return this.exprLiteral(ast); + + case "Identifier": + return this.exprIdentifier(ast); + + case "BinaryExpression": + return this.exprBinary(ast); + + case "LogicalExpression": + return this.exprLogical(ast); + + case "UnaryExpression": + return this.exprUnary(ast); + + case "UpdateExpression": + return this.emitUpdate(ast, false); + + case "ConditionalExpression": + return this.exprConditional(ast); + + case "CallExpression": + return this.exprCall(ast); + + case "MemberExpression": + return this.exprMember(ast); + + case "ThisExpression": + throw this.astErrorOutput("unexpected bare `this`", ast); + + case "SequenceExpression": + if (ast.expressions.length === 1) return this.expression(ast.expressions[0]); + throw this.astErrorOutput("WebAssembly backend does not yet support the comma operator", ast); + + case "AssignmentExpression": + throw this.astErrorOutput("WebAssembly backend does not yet support assignment used as an expression", ast); + + case "ArrayExpression": + throw this.astErrorOutput("array literals are only supported as variable initializers and kernel returns", ast); + + default: + throw this.astErrorOutput(`Unknown expression type ${ast.type}`, ast); + } + } + exprLiteral(ast) { + if (ast.value === true || ast.value === false) { + this.em.i32Const(ast.value ? 1 : 0); + return "bool"; + } + if (isNaN(ast.value)) throw this.astErrorOutput("Non-numeric literal not supported : " + ast.value, ast); + const key = this.astKey(ast); + if (this.isState("casting-to-integer") || this.isState("building-integer")) { + if (!this.vec) this.literalTypes[key] = "Integer"; + this.em.i32Const(Math.round(ast.value)); + return "i32"; + } + if (!this.vec) this.literalTypes[key] = "Number"; + this.em.f32Const(ast.value); + return "f32"; + } + exprIdentifier(idtNode) { + if (idtNode.type !== "Identifier") throw this.astErrorOutput("IdentifierExpression - not an Identifier", idtNode); + if (idtNode.name === "Infinity") { + this.em.f32Const(Infinity); + return "f32"; + } + const local = this.locals.get(idtNode.name); + if (local) { + if (local.kind === "vec") throw this.astErrorOutput(`array-valued variable "${idtNode.name}" can only be indexed or returned`, idtNode); + this.em.localGet(local.index); + return local.gtype === "Boolean" ? "bool" : local.wtype; + } + const argumentIndex = this.argumentNames.indexOf(idtNode.name); + if (argumentIndex !== -1 && this.isRootKernel) { + const type = this.argumentTypes[argumentIndex]; + const slot = this.assembler ? this.assembler.layout.scalars[idtNode.name] : null; + const offset = slot ? slot.offset : 0; + this.em.i32Const(0); + switch (type) { + case "Integer": + this.em.i32Load(offset); + return "i32"; + + case "Boolean": + this.em.i32Load(offset); + return "bool"; + + case "Number": + case "Float": + this.em.f32Load(offset); + return "f32"; + + default: + throw this.astErrorOutput(`argument "${idtNode.name}" of type ${type} cannot be read as a scalar`, idtNode); + } + } + throw this.astErrorOutput(`Unhandled identifier "${idtNode.name}"`, idtNode); + } + exprBinary(ast) { + const operator = ast.operator; + if (operator === "**") { + this.emitByType(ast.left, "f32"); + this.emitByType(ast.right, "f32"); + this.usedMathImports.add("pow"); + this.em.call("math_pow"); + return "f32"; + } + if (BITWISE_OPS[operator]) { + this.emitAsIntegerOperand(ast.left); + this.emitAsIntegerOperand(ast.right); + this.em[BITWISE_OPS[operator]](); + return "i32"; + } + if (operator === "/" || operator === "%") { + if (operator === "/") { + this.emitByType(ast.left, "f32"); + this.emitByType(ast.right, "f32"); + this.em.f32Div(); + return "f32"; + } + const a = this.em.addLocal("f32"); + const b = this.em.addLocal("f32"); + this.emitByType(ast.left, "f32"); + this.em.localSet(a); + this.emitByType(ast.right, "f32"); + this.em.localSet(b); + this.em.localGet(a).localGet(a).localGet(b).f32Div().f32Trunc().localGet(b).f32Mul().f32Sub(); + return "f32"; + } + const leftType = this.getType(ast.left) || "Number"; + const rightType = this.getType(ast.right) || "Number"; + const key = leftType + " & " + rightType; + let category; + switch (key) { + case "Integer & Integer": + this.pushState("building-integer"); + this.coerce(this.expression(ast.left), "i32"); + this.coerce(this.expression(ast.right), "i32"); + this.popState("building-integer"); + category = "i32"; + break; + + case "Number & Float": + case "Float & Number": + case "Float & Float": + case "Number & Number": + this.pushState("building-float"); + this.coerce(this.expression(ast.left), "f32"); + this.coerce(this.expression(ast.right), "f32"); + this.popState("building-float"); + category = "f32"; + break; + + case "LiteralInteger & LiteralInteger": + if (this.isState("casting-to-integer") || this.isState("building-integer")) { + this.pushState("building-integer"); + this.coerce(this.expression(ast.left), "i32"); + this.coerce(this.expression(ast.right), "i32"); + this.popState("building-integer"); + category = "i32"; + } else { + this.pushState("building-float"); + this.castLiteralToFloat(ast.left); + this.castLiteralToFloat(ast.right); + this.popState("building-float"); + category = "f32"; + } + break; + + case "Integer & Float": + case "Integer & Number": + this.pushState("building-float"); + this.castValueToFloat(ast.left); + this.coerce(this.expression(ast.right), "f32"); + this.popState("building-float"); + category = "f32"; + break; + + case "Integer & LiteralInteger": + this.pushState("building-integer"); + this.coerce(this.expression(ast.left), "i32"); + this.castLiteralToInteger(ast.right); + this.popState("building-integer"); + category = "i32"; + break; + + case "Number & Integer": + case "Float & Integer": + this.pushState("building-float"); + this.coerce(this.expression(ast.left), "f32"); + this.castValueToFloat(ast.right); + this.popState("building-float"); + category = "f32"; + break; + + case "Float & LiteralInteger": + case "Number & LiteralInteger": + this.pushState("building-float"); + this.coerce(this.expression(ast.left), "f32"); + this.castLiteralToFloat(ast.right); + this.popState("building-float"); + category = "f32"; + break; + + case "LiteralInteger & Float": + case "LiteralInteger & Number": + if (this.isState("casting-to-integer")) { + this.pushState("building-integer"); + this.castLiteralToInteger(ast.left); + this.castValueToInteger(ast.right); + this.popState("building-integer"); + category = "i32"; + } else { + this.pushState("building-float"); + this.castLiteralToFloat(ast.left); + this.pushState("casting-to-float"); + this.coerce(this.expression(ast.right), "f32"); + this.popState("casting-to-float"); + this.popState("building-float"); + category = "f32"; + } + break; + + case "LiteralInteger & Integer": + this.pushState("building-integer"); + this.castLiteralToInteger(ast.left); + this.coerce(this.expression(ast.right), "i32"); + this.popState("building-integer"); + category = "i32"; + break; + + case "Boolean & Boolean": + this.coerce(this.expression(ast.left), "i32"); + this.coerce(this.expression(ast.right), "i32"); + category = "i32"; + break; + + default: + throw this.astErrorOutput(`Unhandled binary expression between ${key}`, ast); + } + const compareOp = category === "i32" ? I32_COMPARE[operator] : F32_COMPARE[operator]; + if (compareOp) { + this.em[compareOp](); + return "bool"; + } + const arithOp = category === "i32" ? I32_ARITH[operator] : F32_ARITH[operator]; + if (!arithOp) throw this.astErrorOutput(`Unhandled operator ${operator}`, ast); + this.em[arithOp](); + return category; + } + emitAsIntegerOperand(side) { + switch (this.getType(side)) { + case "Number": + case "Float": + this.castValueToInteger(side); + break; + + case "LiteralInteger": + this.castLiteralToInteger(side); + break; + + default: + { + this.pushState("building-integer"); + const type = this.expression(side); + this.popState("building-integer"); + this.coerce(type, "i32"); + } + } + } + exprLogical(logNode) { + this.emitCondition(logNode.left); + this.enterIf("i32"); + if (logNode.operator === "&&") { + this.emitCondition(logNode.right); + this.em.else_(); + this.em.i32Const(0); + } else if (logNode.operator === "||") { + this.em.i32Const(1); + this.em.else_(); + this.emitCondition(logNode.right); + } else throw this.astErrorOutput(`Unhandled logical operator ${logNode.operator}`, logNode); + this.exit(); + return "bool"; + } + exprUnary(uNode) { + switch (uNode.operator) { + case "~": + this.emitAsIntegerOperand(uNode.argument); + this.em.i32Const(-1).i32Xor(); + return "i32"; + + case "!": + this.emitCondition(uNode.argument); + this.em.i32Eqz(); + return "bool"; + + case "+": + return this.expression(uNode.argument); + + case "-": + { + const type = this.getType(uNode.argument); + if (type === "Integer" || type === "LiteralInteger" && (this.isState("casting-to-integer") || this.isState("building-integer"))) { + this.em.i32Const(0); + this.emitByType(uNode.argument, "i32"); + this.em.i32Sub(); + return "i32"; + } + this.emitByType(uNode.argument, "f32"); + this.em.f32Neg(); + return "f32"; + } + + default: + throw this.astErrorOutput(`Unhandled unary operator ${uNode.operator}`, uNode); + } + } + exprConditional(ast) { + if (ast.type !== "ConditionalExpression") throw this.astErrorOutput("Not a conditional expression", ast); + const consequentType = this.getType(ast.consequent); + const alternateType = this.getType(ast.alternate); + this.recordUniformity("ternary", ast.test); + if (consequentType === null && alternateType === null) { + this.emitCondition(ast.test); + this.enterIf(); + this.statementExpression(ast.consequent); + this.em.else_(); + this.statementExpression(ast.alternate); + this.exit(); + return "void"; + } + let targetType = consequentType === "LiteralInteger" ? "Number" : consequentType; + if (targetType === "Integer" && (alternateType === "Number" || alternateType === "Float")) targetType = "Number"; + const wtype = targetType === "Integer" || targetType === "Boolean" ? "i32" : "f32"; + const emitBranch = branch => { + const branchType = this.getType(branch); + switch (targetType) { + case "Number": + case "Float": + if (branchType === "Integer") this.castValueToFloat(branch); else if (branchType === "LiteralInteger") this.castLiteralToFloat(branch); else this.coerce(this.expression(branch), "f32"); + break; + + case "Integer": + if (branchType === "Number" || branchType === "Float") this.castValueToInteger(branch); else if (branchType === "LiteralInteger") this.castLiteralToInteger(branch); else this.coerce(this.expression(branch), "i32"); + break; + + case "Boolean": + this.emitCondition(branch); + break; + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support a ternary of type ${targetType}`, ast); + } + }; + this.emitCondition(ast.test); + this.enterIf(wtype); + emitBranch(ast.consequent); + this.em.else_(); + emitBranch(ast.alternate); + this.exit(); + return targetType === "Boolean" ? "bool" : wtype; + } + exprCall(ast) { + if (!ast.callee) throw this.astErrorOutput("Unknown CallExpression", ast); + if (ast.callee.type === "MemberExpression" && this.getVariableSignature(ast.callee, true) === "this.color") throw this.astErrorOutput("WebAssembly backend does not yet support graphical mode (this.color)", ast); + let functionName = null; + const isMathFunction = this.isAstMathFunction(ast); + if (isMathFunction || ast.callee.object && ast.callee.object.type === "ThisExpression") functionName = ast.callee.property.name; else if (ast.callee.type === "SequenceExpression" && ast.callee.expressions[0].type === "Literal" && !isNaN(ast.callee.expressions[0].raw)) functionName = ast.callee.expressions[1].property.name; else functionName = ast.callee.name; + if (!functionName) throw this.astErrorOutput(`Unhandled function, couldn't find name`, ast); + if (this.calledFunctions.indexOf(functionName) < 0) this.calledFunctions.push(functionName); + if (this.onFunctionCall) this.onFunctionCall(this.name, functionName, ast.arguments); + if (isMathFunction) return this.emitMathCall(functionName, ast); + const returnType = this.getType(ast); + const targetTypes = this.lookupFunctionArgumentTypes(functionName) || []; + for (let i = 0; i < ast.arguments.length; ++i) { + const argument = ast.arguments[i]; + let targetType = targetTypes[i]; + const argumentType = this.getType(argument); + if (!targetType) { + this.triggerImplyArgumentType(functionName, i, argumentType, this); + targetType = argumentType; + } + switch (argumentType) { + case "Boolean": + this.coerce(this.expression(argument), "i32"); + continue; + + case "Number": + case "Float": + if (targetType === "Integer") { + this.castValueToInteger(argument); + continue; + } else if (targetType === "Number" || targetType === "Float" || targetType === "LiteralInteger") { + this.coerce(this.expression(argument), "f32"); + continue; + } + break; + + case "Integer": + if (targetType === "Number" || targetType === "Float") { + this.castValueToFloat(argument); + continue; + } else if (targetType === "Integer") { + this.coerce(this.expression(argument), "i32"); + continue; + } + break; + + case "LiteralInteger": + if (targetType === "Integer") { + this.castLiteralToInteger(argument); + continue; + } else if (targetType === "Number" || targetType === "Float" || targetType === "LiteralInteger") { + this.castLiteralToFloat(argument); + continue; + } + break; + + case "Array(2)": + case "Array(3)": + case "Array(4)": + case "Array": + case "Array2D": + case "Array3D": + case "Input": + throw this.astErrorOutput("WebAssembly backend does not yet support array arguments to helper functions", ast); + } + throw this.astErrorOutput(`Unhandled argument combination of ${argumentType} and ${targetType} for argument named "${argument.name}"`, ast); + } + this.em.call(this.mangleFunctionName(functionName)); + switch (returnType) { + case null: + case void 0: + return "void"; + + case "Integer": + return "i32"; + + case "Boolean": + return "bool"; + + default: + return "f32"; + } + } + emitMathCall(functionName, ast) { + if (functionName === "random") { + this.usesRandom = true; + this.em.call("pcg_random"); + return "f32"; + } + const emitMathArg = argument => { + switch (this.getType(argument)) { + case "Integer": + this.castValueToFloat(argument); + break; + + case "LiteralInteger": + this.castLiteralToFloat(argument); + break; + + default: + this.coerce(this.expression(argument), "f32"); + } + }; + const nativeOp = MATH_NATIVE_OPS[functionName]; + if (nativeOp) { + emitMathArg(ast.arguments[0]); + this.em[nativeOp](); + return "f32"; + } + switch (functionName) { + case "round": + emitMathArg(ast.arguments[0]); + this.em.f32Const(.5).f32Add().f32Floor(); + return "f32"; + + case "fround": + emitMathArg(ast.arguments[0]); + return "f32"; + + case "min": + case "max": + { + const op = functionName === "min" ? "f32Min" : "f32Max"; + emitMathArg(ast.arguments[0]); + for (let i = 1; i < ast.arguments.length; i++) { + emitMathArg(ast.arguments[i]); + this.em[op](); + } + return "f32"; + } + + case "imul": + emitMathArg(ast.arguments[0]); + this.em.i32TruncSatF32S(); + emitMathArg(ast.arguments[1]); + this.em.i32TruncSatF32S(); + this.em.i32Mul().f32ConvertI32S(); + return "f32"; + + case "clz32": + emitMathArg(ast.arguments[0]); + this.em.i32TruncSatF32U().i32Clz().f32ConvertI32S(); + return "f32"; + + default: + { + const arity = MATH_IMPORT_ARITY[functionName]; + if (!arity) throw this.astErrorOutput(`WebAssembly backend does not yet support Math.${functionName}`, ast); + for (let i = 0; i < arity; i++) emitMathArg(ast.arguments[i]); + this.usedMathImports.add(functionName); + this.em.call("math_" + functionName); + return "f32"; + } + } + } + exprMember(mNode) { + const details = this.getMemberExpressionDetails(mNode); + if (!details) throw this.astErrorOutput("Unexpected expression", mNode); + const {signature: signature, name: name, origin: origin, type: type, property: property, xProperty: xProperty, yProperty: yProperty, zProperty: zProperty} = details; + switch (signature) { + case "value.thread.value": + case "this.thread.value": + { + if (name !== "x" && name !== "y" && name !== "z") throw this.astErrorOutput("Unexpected expression, expected `this.thread.x`, `this.thread.y`, or `this.thread.z`", mNode); + this.readsThread = true; + const globals = this.assembler ? this.assembler.globals : null; + this.em.globalGet(globals ? globals["thread" + name.toUpperCase()] : 0); + return "i32"; + } + + case "this.output.value": + { + const axisIndex = { + x: 0, + y: 1, + z: 2 + }[name]; + if (axisIndex === void 0) throw this.astErrorOutput("Unexpected expression", mNode); + const value = this.output[axisIndex]; + if (this.isState("casting-to-float")) { + this.em.f32Const(value); + return "f32"; + } + this.em.i32Const(value); + return "i32"; + } + + case "value.value": + { + if (origin === "Math") { + this.em.f32Const(Math[name]); + return "f32"; + } + const component = { + r: 0, + g: 1, + b: 2, + a: 3 + }[property]; + if (component !== void 0) { + const local = this.locals.get(name); + if (local && local.kind === "vec" && component < local.n) { + this.em.localGet(local.indices[component]); + return "f32"; + } + } + throw this.astErrorOutput("Unexpected expression", mNode); + } + + case "this.constants.value": + { + const value = this.constants[name]; + switch (type) { + case "Integer": + if (this.isState("casting-to-float")) { + this.em.f32Const(value); + return "f32"; + } + this.em.i32Const(Math.round(value)); + return "i32"; + + case "Number": + case "Float": + if (this.isState("casting-to-integer")) { + this.em.i32Const(Math.round(value)); + return "i32"; + } + this.em.f32Const(value); + return "f32"; + + case "Boolean": + this.em.i32Const(value ? 1 : 0); + return "bool"; + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support constant type ${type}`, mNode); + } + } + + case "value[]": + case "value[][]": + case "value[][][]": + case "value[][][][]": + { + const local = this.locals.get(name); + if (local && local.kind === "vec") { + if (signature !== "value[]") throw this.astErrorOutput("Unexpected expression", mNode); + return this.emitVecIndex(local, xProperty); + } + return this.emitFlatLoad("arrays", name, xProperty, yProperty, zProperty, mNode); + } + + case "this.constants.value[]": + case "this.constants.value[][]": + case "this.constants.value[][][]": + case "this.constants.value[][][][]": + return this.emitFlatLoad("constantArrays", name, xProperty, yProperty, zProperty, mNode); + + case "fn()[]": + throw this.astErrorOutput("WebAssembly backend does not yet support indexing a function call result", mNode); + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support expression signature "${signature}"`, mNode); + } + } + emitFlatLoad(table, name, xProperty, yProperty, zProperty, mNode) { + let layout; + if (this.assembler) { + layout = this.assembler.layout[table][name]; + if (!layout) throw this.astErrorOutput(`no memory layout for "${name}" \u2014 arrays are only readable as kernel arguments or constants`, mNode); + } else layout = { + offset: 0, + dims: [ 1, 1, 1 ] + }; + this.emitIndex(xProperty); + if (yProperty) { + this.emitIndex(yProperty); + this.em.i32Const(layout.dims[0]).i32Mul().i32Add(); + } + if (zProperty) { + this.emitIndex(zProperty); + this.em.i32Const(layout.dims[0] * layout.dims[1]).i32Mul().i32Add(); + } + if (this.vec && this.vMaskDepth > 0) this.emitClampScalarIndex(layout.dims[0] * layout.dims[1] * layout.dims[2] - 1); + this.em.i32Const(2).i32Shl(); + this.em.f32Load(layout.offset); + return "f32"; + } + emitClampScalarIndex(max) { + const t = this.em.addLocal("i32"); + this.em.localSet(t); + this.em.localGet(t).i32Const(0).localGet(t).i32Const(0).i32GeS().select(); + this.em.localSet(t); + this.em.localGet(t).i32Const(max).localGet(t).i32Const(max).i32LeS().select(); + } + emitVecIndex(local, xProperty) { + if (xProperty.type === "Literal" && Number.isInteger(xProperty.value)) { + if (xProperty.value < 0 || xProperty.value >= local.n) throw this.astErrorOutput(`index ${xProperty.value} out of range for Array(${local.n})`, xProperty); + this.em.localGet(local.indices[xProperty.value]); + return "f32"; + } + const idx = this.em.addLocal("i32"); + this.emitIndex(xProperty); + this.em.localSet(idx); + this.em.localGet(local.indices[0]); + for (let k = 1; k < local.n; k++) { + this.em.localGet(local.indices[k]); + this.em.localGet(idx).i32Const(k).i32Ne(); + this.em.select(); + } + return "f32"; + } + emitIndex(property) { + if (!property) throw new Error("Property not set"); + switch (this.getType(property)) { + case "Number": + case "Float": + this.castValueToInteger(property); + return; + + case "LiteralInteger": + this.castLiteralToInteger(property); + return; + + case "Integer": + { + this.pushState("building-integer"); + const emitted = this.expression(property); + this.popState("building-integer"); + this.coerce(emitted, "i32"); + return; + } + + default: + this.coerce(this.expression(property), "i32"); + } + } + emitVectorFunction(assembler) { + if (!this.isRootKernel) throw new Error("only the root kernel is vectorized; helpers are lane-scalarized at call sites"); + this.assembler = assembler; + const em = assembler.module.addFunction("kernel_simd", { + params: [], + results: [] + }); + this.em = em; + this.vec = true; + try { + this.locals = new Map; + this.depth = 0; + this.loopStack = []; + this.vLoopStack = []; + this.taintedLocals = new Set; + const ast = this.getJsAST(); + if (!this.vInfo) this.vInfo = this.vAnalyze(ast); + this.vMaskDepth = 0; + this.vTerminated = false; + this.vCur = em.addLocal("v128"); + em.v128ConstI32x4(-1, -1, -1, -1).localSet(this.vCur); + this.vRetMask = this.vInfo.varyingReturn ? em.addLocal("v128") : -1; + this._vBaseX = -1; + if (assembler.helperInfo) { + this._vBaseX = em.addLocal("i32"); + em.globalGet(assembler.globals.threadX).localSet(this._vBaseX); + } + for (const name of this.vInfo.assignedArgs) { + const argumentIndex = this.argumentNames.indexOf(name); + const gtype = this.argumentTypes[argumentIndex]; + const slot = assembler.layout.scalars[name]; + if (!slot) throw this.astErrorOutput(`WebAssembly backend does not yet support assigning to the array argument "${name}"`, this.getJsAST()); + const isInt = gtype === "Integer" || gtype === "Boolean"; + const index = em.addLocal("v128"); + em.i32Const(0); + if (isInt) em.i32Load(slot.offset).i32x4Splat(); else em.f32Load(slot.offset).f32x4Splat(); + em.localSet(index); + this.locals.set(name, { + kind: "vscalar", + index: index, + wtype: isInt ? "vi32" : "vf32", + gtype: gtype + }); + } + const body = ast.body.body; + for (let i = 0; i < body.length; i++) { + this.vstatement(body[i]); + if (this.vTerminated) break; + } + } finally { + this.vec = false; + this.vMaskDepth = 0; + } + return em; + } + vAnalyze(ast) { + const varying = new Set; + const assignedArgs = new Set; + let varyingReturn = false; + let changed = true; + const self = this; + const exprVarying = node => { + if (!node || typeof node !== "object") return false; + switch (node.type) { + case "Literal": + case "ThisExpression": + return false; + + case "Identifier": + return varying.has(node.name); + + case "MemberExpression": + if (!node.computed && node.object.type === "MemberExpression" && !node.object.computed && node.object.property && node.object.property.name === "thread") return node.property.name === "x"; + if (node.computed) return exprVarying(node.object) || exprVarying(node.property); + return exprVarying(node.object); + + case "BinaryExpression": + case "LogicalExpression": + return exprVarying(node.left) || exprVarying(node.right); + + case "UnaryExpression": + case "UpdateExpression": + return exprVarying(node.argument); + + case "ConditionalExpression": + return exprVarying(node.test) || exprVarying(node.consequent) || exprVarying(node.alternate); + + case "CallExpression": + if (self.isAstMathFunction(node)) { + if (node.callee.property.name === "random") return true; + return node.arguments.some(exprVarying); + } + return true; + + case "SequenceExpression": + return node.expressions.some(exprVarying); + + case "ArrayExpression": + return node.elements.some(exprVarying); + + case "AssignmentExpression": + return exprVarying(node.right) || node.left.type === "Identifier" && varying.has(node.left.name); + + default: + return true; + } + }; + const taint = name => { + if (name && !varying.has(name)) { + varying.add(name); + changed = true; + } + }; + const scanExprTaints = (node, cv) => { + if (!node || typeof node !== "object") return; + if (Array.isArray(node)) return node.forEach(sub => scanExprTaints(sub, cv)); + switch (node.type) { + case "UpdateExpression": + if (node.argument.type === "Identifier") { + if (self.argumentNames.indexOf(node.argument.name) !== -1) { + if (!assignedArgs.has(node.argument.name)) { + assignedArgs.add(node.argument.name); + changed = true; + } + taint(node.argument.name); + } + if (cv) taint(node.argument.name); + } + return scanExprTaints(node.argument, cv); + + case "AssignmentExpression": + if (node.left.type === "Identifier") { + if (self.argumentNames.indexOf(node.left.name) !== -1) { + if (!assignedArgs.has(node.left.name)) { + assignedArgs.add(node.left.name); + changed = true; + } + taint(node.left.name); + } + if (cv) taint(node.left.name); + } + scanExprTaints(node.left, cv); + return scanExprTaints(node.right, cv); + + case "ConditionalExpression": + { + scanExprTaints(node.test, cv); + const branchCv = cv || exprVarying(node.test); + scanExprTaints(node.consequent, branchCv); + return scanExprTaints(node.alternate, branchCv); + } + + case "LogicalExpression": + scanExprTaints(node.left, cv); + return scanExprTaints(node.right, true); + + default: + for (const key in node) { + if (key === "loc" || key === "start" || key === "end" || key === "parent") continue; + const child = node[key]; + if (child && typeof child === "object") scanExprTaints(child, cv); + } + } + }; + const collectAssigned = (node, out) => { + if (!node || typeof node !== "object") return; + if (Array.isArray(node)) return node.forEach(sub => collectAssigned(sub, out)); + switch (node.type) { + case "VariableDeclarator": + if (node.id && node.id.type === "Identifier") out.push(node.id.name); + break; + + case "AssignmentExpression": + if (node.left.type === "Identifier") out.push(node.left.name); + break; + + case "UpdateExpression": + if (node.argument.type === "Identifier") out.push(node.argument.name); + break; + + case "FunctionDeclaration": + return; + } + for (const key in node) { + if (key === "loc" || key === "start" || key === "end" || key === "parent") continue; + const child = node[key]; + if (child && typeof child === "object") collectAssigned(child, out); + } + }; + const hasVaryingExit = (node, cv) => { + if (!node || typeof node !== "object") return false; + if (Array.isArray(node)) return node.some(sub => hasVaryingExit(sub, cv)); + switch (node.type) { + case "BreakStatement": + case "ContinueStatement": + return cv; + + case "ForStatement": + case "WhileStatement": + case "DoWhileStatement": + case "FunctionDeclaration": + return false; + + case "IfStatement": + { + const branchCv = cv || exprVarying(node.test); + if (hasVaryingExit(node.consequent, branchCv)) return true; + return node.alternate ? hasVaryingExit(node.alternate, branchCv) : false; + } + + case "ConditionalExpression": + { + const branchCv = cv || exprVarying(node.test); + return hasVaryingExit(node.consequent, branchCv) || hasVaryingExit(node.alternate, branchCv); + } + + case "SwitchStatement": + { + const switchCv = cv || exprVarying(node.discriminant) || node.cases.some(c => c.test && exprVarying(c.test)); + return node.cases.some(c => c.consequent.some(stmt => stmt.type === "BreakStatement" ? false : hasVaryingExit(stmt, switchCv))); + } + + default: + for (const key in node) { + if (key === "loc" || key === "start" || key === "end" || key === "parent") continue; + const child = node[key]; + if (child && typeof child === "object" && hasVaryingExit(child, cv)) return true; + } + return false; + } + }; + const walkExprStatement = (node, cv) => { + switch (node.type) { + case "AssignmentExpression": + if (node.left.type === "Identifier") { + const name = node.left.name; + if (self.argumentNames.indexOf(name) !== -1) { + if (!assignedArgs.has(name)) { + assignedArgs.add(name); + changed = true; + } + taint(name); + } + if (cv || exprVarying(node.right) || node.operator !== "=" && varying.has(name)) taint(name); + } + return scanExprTaints(node.right, cv); + + case "UpdateExpression": + if (node.argument.type === "Identifier") { + const name = node.argument.name; + if (self.argumentNames.indexOf(name) !== -1) { + if (!assignedArgs.has(name)) { + assignedArgs.add(name); + changed = true; + } + taint(name); + } + if (cv) taint(name); + } + return; + + case "SequenceExpression": + return node.expressions.forEach(e => walkExprStatement(e, cv)); + + default: + return scanExprTaints(node, cv); + } + }; + const walkStatement = (node, cv) => { + if (!node) return; + switch (node.type) { + case "VariableDeclaration": + for (const declaration of node.declarations) { + if (!declaration.init) continue; + if (cv || exprVarying(declaration.init)) taint(declaration.id.name); + scanExprTaints(declaration.init, cv); + } + return; + + case "ExpressionStatement": + return walkExprStatement(node.expression, cv); + + case "ReturnStatement": + if (cv) varyingReturn = true; + if (node.argument) scanExprTaints(node.argument, cv); + return; + + case "IfStatement": + { + scanExprTaints(node.test, cv); + const branchCv = cv || exprVarying(node.test); + walkStatement(node.consequent, branchCv); + if (node.alternate) walkStatement(node.alternate, branchCv); + return; + } + + case "ForStatement": + case "WhileStatement": + case "DoWhileStatement": + { + const loopVarying = cv || (node.test ? exprVarying(node.test) : false) || hasVaryingExit(node.body, false); + if (loopVarying) { + const assigned = []; + if (node.init) collectAssigned(node.init, assigned); + collectAssigned(node.body, assigned); + if (node.update) collectAssigned(node.update, assigned); + assigned.forEach(taint); + } + if (node.init) if (node.init.type === "VariableDeclaration") walkStatement(node.init, cv); else walkExprStatement(node.init, cv); + walkStatement(node.body, loopVarying); + if (node.update) walkExprStatement(node.update, loopVarying); + if (node.test) scanExprTaints(node.test, loopVarying); + return; + } + + case "SwitchStatement": + { + const switchCv = cv || exprVarying(node.discriminant) || node.cases.some(c => c.test && exprVarying(c.test)); + for (const switchCase of node.cases) for (const stmt of switchCase.consequent) walkStatement(stmt, switchCv); + return; + } + + case "BlockStatement": + return node.body.forEach(stmt => walkStatement(stmt, cv)); + + default: + return; + } + }; + while (changed) { + changed = false; + walkStatement(ast.body, false); + } + return { + varying: varying, + varyingReturn: varyingReturn, + assignedArgs: assignedArgs, + exprVarying: exprVarying, + hasVaryingExit: hasVaryingExit + }; + } + vZero() { + this.em.v128ConstI32x4(0, 0, 0, 0); + return this; + } + vInnermostVaryingLoop() { + const top = this.vLoopStack[this.vLoopStack.length - 1]; + return top && top.varying ? top : null; + } + vRecomputeCur(savedIndex) { + const em = this.em; + em.localGet(savedIndex); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + const loop = this.vInnermostVaryingLoop(); + if (loop) { + if (loop.vBrk !== -1) em.localGet(loop.vBrk).v128Andnot(); + if (loop.vCnt !== -1) em.localGet(loop.vCnt).v128Andnot(); + } + em.localSet(this.vCur); + } + vLoopBodyExits(body) { + let hasBreak = false; + let hasContinue = false; + const walk = node => { + if (!node || typeof node !== "object" || hasBreak && hasContinue) return; + if (Array.isArray(node)) return node.forEach(walk); + switch (node.type) { + case "BreakStatement": + hasBreak = true; + return; + + case "ContinueStatement": + hasContinue = true; + return; + + case "ForStatement": + case "WhileStatement": + case "DoWhileStatement": + case "FunctionDeclaration": + return; + + case "SwitchStatement": + for (const switchCase of node.cases) for (const stmt of switchCase.consequent) if (stmt.type !== "BreakStatement") walk(stmt); + return; + } + for (const key in node) { + if (key === "loc" || key === "start" || key === "end" || key === "parent") continue; + const child = node[key]; + if (child && typeof child === "object") walk(child); + } + }; + walk(body); + return { + hasBreak: hasBreak, + hasContinue: hasContinue + }; + } + vSetLocal(index) { + const em = this.em; + if (this.vMaskDepth > 0) em.localGet(index).localGet(this.vCur).v128Bitselect(); + em.localSet(index); + } + vCoerce(from, to) { + if (from === to) return to; + const em = this.em; + switch (from) { + case "f32": + case "i32": + case "bool": + if (to === "vf32") { + this.coerce(from, "f32"); + em.f32x4Splat(); + return to; + } + if (to === "vi32") { + this.coerce(from, "i32"); + em.i32x4Splat(); + return to; + } + if (to === "vbool") { + this.coerce(from, "i32"); + em.i32x4Splat(); + this.vZero(); + em.i32x4Ne(); + return to; + } + break; + + case "vf32": + if (to === "vi32") { + em.i32x4TruncSatF32x4S(); + return to; + } + if (to === "vbool") { + em.v128ConstF32x4(0, 0, 0, 0).f32x4Ne(); + return to; + } + break; + + case "vi32": + if (to === "vf32") { + em.f32x4ConvertI32x4S(); + return to; + } + if (to === "vbool") { + this.vZero(); + em.i32x4Ne(); + return to; + } + break; + + case "vbool": + if (to === "vi32") { + em.v128ConstI32x4(1, 1, 1, 1).v128And(); + return to; + } + if (to === "vf32") { + em.v128ConstI32x4(1, 1, 1, 1).v128And().f32x4ConvertI32x4S(); + return to; + } + break; + } + throw new Error(`cannot convert ${from} to ${to}`); + } + vCastLiteralToInteger(ast) { + this.pushState("casting-to-integer"); + const type = this.vexpr(ast); + this.popState("casting-to-integer"); + this.vCoerce(type, "vi32"); + return "vi32"; + } + vCastLiteralToFloat(ast) { + this.pushState("casting-to-float"); + const type = this.vexpr(ast); + this.popState("casting-to-float"); + this.vCoerce(type, "vf32"); + return "vf32"; + } + vCastValueToInteger(ast) { + this.pushState("casting-to-integer"); + const type = this.vexpr(ast); + this.popState("casting-to-integer"); + this.vCoerce(type, "vi32"); + return "vi32"; + } + vCastValueToFloat(ast) { + this.pushState("casting-to-float"); + const type = this.vexpr(ast); + this.popState("casting-to-float"); + this.vCoerce(type, "vf32"); + return "vf32"; + } + vEmitByType(ast, want) { + const type = this.getType(ast); + if (want === "vf32") { + if (type === "Integer") return this.vCastValueToFloat(ast); + if (type === "LiteralInteger") return this.vCastLiteralToFloat(ast); + this.vCoerce(this.vexpr(ast), "vf32"); + return "vf32"; + } + if (type === "Number" || type === "Float") return this.vCastValueToInteger(ast); + if (type === "LiteralInteger") return this.vCastLiteralToInteger(ast); + this.vCoerce(this.vexpr(ast), "vi32"); + return "vi32"; + } + vexprMask(ast) { + const type = this.vexpr(ast); + if (type === "vbool") return; + if (type === "vi32") { + this.vZero(); + this.em.i32x4Ne(); + return; + } + if (type === "vf32") { + this.em.v128ConstF32x4(0, 0, 0, 0).f32x4Ne(); + return; + } + this.coerce(type, "bool"); + this.em.i32x4Splat(); + this.vZero(); + this.em.i32x4Ne(); + } + vstatement(ast) { + switch (ast.type) { + case "VariableDeclaration": + return this.vstmtVariableDeclaration(ast); + + case "ExpressionStatement": + return this.vstatementExpression(ast.expression); + + case "ReturnStatement": + return this.vstmtReturn(ast); + + case "IfStatement": + return this.vstmtIf(ast); + + case "ForStatement": + return this.vstmtFor(ast); + + case "WhileStatement": + return this.vstmtWhile(ast); + + case "DoWhileStatement": + return this.vstmtDoWhile(ast); + + case "BlockStatement": + for (let i = 0; i < ast.body.length; i++) { + this.vstatement(ast.body[i]); + if (this.vTerminated) break; + } + return; + + case "BreakStatement": + return this.vstmtBreak(ast); + + case "ContinueStatement": + return this.vstmtContinue(ast); + + case "SwitchStatement": + return this.vstmtSwitch(ast); + + case "FunctionDeclaration": + if (this.isChildFunction(ast)) return; + throw this.astErrorOutput("unexpected function declaration", ast); + + case "EmptyStatement": + case "DebuggerStatement": + return; + + default: + throw this.astErrorOutput(`Unknown statement type ${ast.type}`, ast); + } + } + vstatementBody(node) { + if (!node) return; + const previous = this.vTerminated; + this.vTerminated = false; + this.vstatement(node); + this.vTerminated = previous; + } + vstatementExpression(expression) { + switch (expression.type) { + case "AssignmentExpression": + return this.vAssign(expression); + + case "UpdateExpression": + this.vUpdate(expression, true); + return; + + case "SequenceExpression": + for (let i = 0; i < expression.expressions.length; i++) this.vstatementExpression(expression.expressions[i]); + return; + + case "Identifier": + case "Literal": + return; + + default: + if (this.vexpr(expression) !== "void") this.em.drop(); + } + } + vstmtVariableDeclaration(varDecNode) { + const declarations = varDecNode.declarations; + if (!declarations || !declarations[0] || !declarations[0].init) throw this.astErrorOutput("Unexpected expression", varDecNode); + for (let i = 0; i < declarations.length; i++) { + const declaration = declarations[i]; + if (!this.vInfo.varying.has(declaration.id.name)) { + this.stmtVariableDeclaration(Object.assign({}, varDecNode, { + declarations: [ declaration ] + })); + continue; + } + this.vDeclareVarying(declaration, varDecNode); + } + } + vDeclareVarying(declaration, varDecNode) { + const em = this.em; + const init = declaration.init; + const name = declaration.id.name; + const info = this.getDeclaration(declaration.id); + const actualType = this.getType(init); + if (actualType === "Array(2)" || actualType === "Array(3)" || actualType === "Array(4)") { + const n = parseInt(actualType.substring(6), 10); + info.valueType = actualType; + let local = this.locals.get(name); + if (!local || local.kind !== "vvec" || local.n !== n) { + const indices = []; + for (let c = 0; c < n; c++) indices.push(em.addLocal("v128")); + local = { + kind: "vvec", + indices: indices, + n: n, + gtype: actualType + }; + this.locals.set(name, local); + } + if (init.type === "ArrayExpression") { + for (let c = 0; c < n; c++) { + this.vEmitArrayElement(init.elements[c]); + this.vSetLocal(local.indices[c]); + } + return; + } + if (init.type === "Identifier") { + const source = this.locals.get(init.name); + if (source && source.kind === "vvec" && source.n === n) { + for (let c = 0; c < n; c++) { + em.localGet(source.indices[c]); + this.vSetLocal(local.indices[c]); + } + return; + } + if (source && source.kind === "vec" && source.n === n) { + for (let c = 0; c < n; c++) { + em.localGet(source.indices[c]).f32x4Splat(); + this.vSetLocal(local.indices[c]); + } + return; + } + } + throw this.astErrorOutput(`WebAssembly backend does not yet support ${actualType} initializer of type ${init.type}`, varDecNode); + } + let type = actualType; + if (type === "LiteralInteger") type = info.suggestedType === "Integer" ? "Integer" : "Number"; + if (actualType === "Integer" && type === "Integer") { + info.valueType = "Number"; + this.vSetVaryingScalar(name, "vf32", "Number", () => this.vCastValueToFloat(init)); + return; + } + info.valueType = type; + switch (type) { + case "Number": + case "Float": + this.vSetVaryingScalar(name, "vf32", type, () => { + if (actualType === "LiteralInteger") this.vCastLiteralToFloat(init); else if (actualType === "Integer") this.vCastValueToFloat(init); else this.vCoerce(this.vexpr(init), "vf32"); + }); + break; + + case "Integer": + this.vSetVaryingScalar(name, "vi32", "Integer", () => { + if (actualType === "LiteralInteger") this.vCastLiteralToInteger(init); else if (actualType === "Number" || actualType === "Float") this.vCastValueToInteger(init); else this.vCoerce(this.vexpr(init), "vi32"); + }); + break; + + case "Boolean": + this.vSetVaryingScalar(name, "vi32", "Boolean", () => { + this.vexprMask(init); + this.em.v128ConstI32x4(1, 1, 1, 1).v128And(); + }); + break; + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support declaring type ${type}`, varDecNode); + } + } + vSetVaryingScalar(name, wtype, gtype, emitInit) { + let local = this.locals.get(name); + if (!local || local.kind !== "vscalar" || local.wtype !== wtype) { + local = { + kind: "vscalar", + index: this.em.addLocal("v128"), + wtype: wtype, + gtype: gtype + }; + this.locals.set(name, local); + } else local.gtype = gtype; + emitInit(); + this.vSetLocal(local.index); + } + vEmitArrayElement(element) { + switch (this.getType(element)) { + case "Integer": + this.vCastValueToFloat(element); + break; + + case "LiteralInteger": + this.vCastLiteralToFloat(element); + break; + + default: + this.vCoerce(this.vexpr(element), "vf32"); + } + } + vAssign(assNode) { + if (assNode.left.type !== "Identifier") throw this.astErrorOutput(`WebAssembly backend does not yet support assignment to ${assNode.left.type}`, assNode); + const name = assNode.left.name; + const local = this.locals.get(name); + if (local && local.kind === "scalar") return this.emitAssignment(assNode); + if (!local || local.kind !== "vscalar") throw this.astErrorOutput(`cannot assign to "${name}"`, assNode); + const wtype = local.wtype; + if (assNode.operator === "=") { + const leftType = this.getType(assNode.left); + const rightType = this.getType(assNode.right); + if (leftType !== "Integer" && rightType === "Integer") { + this.vCastValueToFloat(assNode.right); + this.vCoerce("vf32", wtype); + } else if (leftType !== "Integer" && rightType === "LiteralInteger") { + this.vCastLiteralToFloat(assNode.right); + this.vCoerce("vf32", wtype); + } else if (leftType === "Integer" && rightType === "LiteralInteger") { + this.vCastLiteralToInteger(assNode.right); + this.vCoerce("vi32", wtype); + } else if (leftType === "Integer" && (rightType === "Number" || rightType === "Float")) { + this.vCastValueToInteger(assNode.right); + this.vCoerce("vi32", wtype); + } else this.vCoerce(this.vexpr(assNode.right), wtype); + } else { + const synthetic = { + type: "BinaryExpression", + operator: assNode.operator.slice(0, -1), + left: assNode.left, + right: assNode.right + }; + this.vCoerce(this.vexprBinary(synthetic), wtype); + } + this.vSetLocal(local.index); + } + vUpdate(uNode, isStatement) { + if (uNode.argument.type !== "Identifier") throw this.astErrorOutput("update expression needs a variable", uNode); + const local = this.locals.get(uNode.argument.name); + if (local && local.kind === "scalar") return this.emitUpdate(uNode, isStatement); + if (!local || local.kind !== "vscalar") throw this.astErrorOutput(`cannot update "${uNode.argument.name}"`, uNode); + const em = this.em; + const isInt = local.wtype === "vi32"; + const one = () => isInt ? em.v128ConstI32x4(1, 1, 1, 1) : em.v128ConstF32x4(1, 1, 1, 1); + const op = uNode.operator === "++" ? isInt ? "i32x4Add" : "f32x4Add" : isInt ? "i32x4Sub" : "f32x4Sub"; + if (isStatement) { + em.localGet(local.index); + one(); + em[op](); + this.vSetLocal(local.index); + return "void"; + } + if (uNode.prefix) { + em.localGet(local.index); + one(); + em[op](); + this.vSetLocal(local.index); + em.localGet(local.index); + } else { + const old = em.addLocal("v128"); + em.localGet(local.index).localSet(old); + em.localGet(local.index); + one(); + em[op](); + this.vSetLocal(local.index); + em.localGet(old); + } + return local.wtype; + } + vstmtIf(ifNode) { + const em = this.em; + if (!this.vInfo.exprVarying(ifNode.test)) { + this.emitCondition(ifNode.test); + this.enterIf(); + this.vstatementBody(ifNode.consequent); + if (ifNode.alternate) { + em.else_(); + this.vstatementBody(ifNode.alternate); + } + this.exit(); + return; + } + const m = em.addLocal("v128"); + this.vexprMask(ifNode.test); + em.localSet(m); + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + em.localGet(saved).localGet(m).v128And().localSet(this.vCur); + em.localGet(this.vCur).v128AnyTrue(); + this.enterIf(); + this.vMaskDepth++; + this.vstatementBody(ifNode.consequent); + this.vMaskDepth--; + this.exit(); + if (ifNode.alternate) { + em.localGet(saved).localGet(m).v128Andnot().localSet(this.vCur); + em.localGet(this.vCur).v128AnyTrue(); + this.enterIf(); + this.vMaskDepth++; + this.vstatementBody(ifNode.alternate); + this.vMaskDepth--; + this.exit(); + } + this.vRecomputeCur(saved); + } + vstmtReturn(ast) { + const em = this.em; + if (!ast.argument) { + this.vRetireOrReturn(); + return; + } + this.pushState("skip-literal-correction"); + const type = this.getType(ast.argument); + this.popState("skip-literal-correction"); + switch (this.returnType) { + case "Array(2)": + case "Array(3)": + case "Array(4)": + { + const n = parseInt(this.returnType.substring(6), 10); + const argument = ast.argument; + const comps = []; + if (argument.type === "ArrayExpression") { + if (argument.elements.length !== n) throw this.astErrorOutput(`expected ${n} array elements to match return type ${this.returnType}`, ast); + for (let c = 0; c < n; c++) { + const t = em.addLocal("v128"); + this.vEmitArrayElement(argument.elements[c]); + em.localSet(t); + comps.push(t); + } + } else if (argument.type === "Identifier") { + const local = this.locals.get(argument.name); + if (local && local.kind === "vvec" && local.n === n) for (let c = 0; c < n; c++) comps.push(local.indices[c]); else if (local && local.kind === "vec" && local.n === n) for (let c = 0; c < n; c++) { + const t = em.addLocal("v128"); + em.localGet(local.indices[c]).f32x4Splat().localSet(t); + comps.push(t); + } else throw this.astErrorOutput(`"${argument.name}" is not an Array(${n}) variable`, ast); + } else throw this.astErrorOutput(`WebAssembly backend does not yet support returning ${this.returnType} from a ${argument.type}`, ast); + this.vStoreOutput(comps); + this.vRetireOrReturn(); + return; + } + + default: + { + const t = em.addLocal("v128"); + switch (this.returnType) { + case "Integer": + if (type === "Float" || type === "Number") this.vCastValueToInteger(ast.argument); else if (type === "LiteralInteger") this.vCastLiteralToInteger(ast.argument); else this.vCoerce(this.vexpr(ast.argument), "vi32"); + em.f32x4ConvertI32x4S(); + break; + + case "LiteralInteger": + case "Number": + case "Float": + if (type === "Integer") this.vCastValueToFloat(ast.argument); else if (type === "LiteralInteger") this.vCastLiteralToFloat(ast.argument); else this.vCoerce(this.vexpr(ast.argument), "vf32"); + break; + + case "Boolean": + this.vexprMask(ast.argument); + em.v128ConstI32x4(1, 1, 1, 1).v128And().f32x4ConvertI32x4S(); + break; + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support returning ${this.returnType}`, ast); + } + em.localSet(t); + this.vStoreOutput([ t ]); + this.vRetireOrReturn(); + } + } + } + vStoreOutput(comps) { + const em = this.em; + const globals = this.assembler.globals; + const outputOffset = this.assembler.layout.outputOffset; + const n = comps.length; + let maskLocal = -1; + if (this.vMaskDepth > 0) maskLocal = this.vCur; else if (this.vRetMask !== -1) { + maskLocal = em.addLocal("v128"); + em.localGet(this.vRetMask).v128Not().localSet(maskLocal); + } + const addr = em.addLocal("i32"); + if (n === 1) { + em.globalGet(globals.dataIndex).i32Const(2).i32Shl().localSet(addr); + if (maskLocal === -1) em.localGet(addr).localGet(comps[0]).v128Store(outputOffset, 2); else { + em.localGet(addr); + em.localGet(comps[0]); + em.localGet(addr).v128Load(outputOffset, 2); + em.localGet(maskLocal).v128Bitselect(); + em.v128Store(outputOffset, 2); + } + return; + } + em.globalGet(globals.dataIndex).i32Const(n).i32Mul().i32Const(2).i32Shl().localSet(addr); + for (let lane = 0; lane < 4; lane++) for (let c = 0; c < n; c++) { + const offset = outputOffset + (lane * n + c) * 4; + em.localGet(addr); + em.localGet(comps[c]).f32x4ExtractLane(lane); + if (maskLocal !== -1) { + em.localGet(addr).f32Load(offset); + em.localGet(maskLocal).i32x4ExtractLane(lane); + em.select(); + } + em.f32Store(offset); + } + } + vRetireOrReturn() { + const em = this.em; + if (this.vMaskDepth === 0) { + em.return_(); + this.vTerminated = true; + return; + } + em.localGet(this.vRetMask).localGet(this.vCur).v128Or().localSet(this.vRetMask); + this.vZero(); + em.localSet(this.vCur); + this.vTerminated = true; + } + vstmtBreak(brNode) { + const target = this.vLoopStack[this.vLoopStack.length - 1]; + if (!target) throw this.astErrorOutput("break used outside of a loop", brNode); + if (!target.varying) { + this.brTo(target.breakLevel); + this.vTerminated = true; + return; + } + if (target.vBrk === -1) throw this.astErrorOutput("internal: loop exit scan missed a break", brNode); + const em = this.em; + em.localGet(target.vBrk).localGet(this.vCur).v128Or().localSet(target.vBrk); + this.vZero(); + em.localSet(this.vCur); + this.vTerminated = true; + } + vstmtContinue(crNode) { + const target = this.vLoopStack[this.vLoopStack.length - 1]; + if (!target) throw this.astErrorOutput("continue used outside of a loop", crNode); + if (!target.varying) { + this.brTo(target.continueLevel); + this.vTerminated = true; + return; + } + if (target.vCnt === -1) throw this.astErrorOutput("internal: loop exit scan missed a continue", crNode); + const em = this.em; + em.localGet(target.vCnt).localGet(this.vCur).v128Or().localSet(target.vCnt); + this.vZero(); + em.localSet(this.vCur); + this.vTerminated = true; + } + vstmtFor(forNode) { + if (forNode.type !== "ForStatement") throw this.astErrorOutput("Invalid for statement", forNode); + const em = this.em; + const varying = (forNode.test ? this.vInfo.exprVarying(forNode.test) : false) || this.vInfo.hasVaryingExit(forNode.body, false); + const isSafe = this.forLoopIsSafe(forNode); + if (forNode.init) if (forNode.init.type === "VariableDeclaration") this.vstmtVariableDeclaration(forNode.init); else this.vstatementExpression(forNode.init); + if (!varying) { + let safeI = -1; + if (!isSafe) { + safeI = em.addLocal("i32"); + em.i32Const(0).localSet(safeI); + } + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + if (!isSafe) { + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + } + if (forNode.test) { + this.emitCondition(forNode.test); + em.i32Eqz(); + this.brIfTo(breakLevel); + } + this.enterBlock(); + const continueLevel = this.depth; + this.vLoopStack.push({ + varying: false, + breakLevel: breakLevel, + continueLevel: continueLevel + }); + if (forNode.body) this.vstatementBody(forNode.body); + this.vLoopStack.pop(); + this.exit(); + if (forNode.update) this.vstatementExpression(forNode.update); + if (!isSafe) em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + return; + } + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + const vLive = em.addLocal("v128"); + em.localGet(this.vCur).localSet(vLive); + const exits = this.vLoopBodyExits(forNode.body); + let vBrk = -1; + if (exits.hasBreak) { + vBrk = em.addLocal("v128"); + this.vZero(); + em.localSet(vBrk); + } + const vCnt = exits.hasContinue ? em.addLocal("v128") : -1; + let safeI = -1; + if (!isSafe) { + safeI = em.addLocal("i32"); + em.i32Const(0).localSet(safeI); + } + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + if (!isSafe) { + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + } + if (vBrk !== -1 || this.vRetMask !== -1) { + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(vLive); + } + if (vCnt !== -1) { + this.vZero(); + em.localSet(vCnt); + } + this.vMaskDepth++; + em.localGet(vLive).localSet(this.vCur); + if (forNode.test) { + em.localGet(vLive); + this.vexprMask(forNode.test); + em.v128And().localSet(vLive); + } + em.localGet(vLive).v128AnyTrue().i32Eqz(); + this.brIfTo(breakLevel); + em.localGet(vLive).localSet(this.vCur); + this.vLoopStack.push({ + varying: true, + vLive: vLive, + vBrk: vBrk, + vCnt: vCnt, + breakLevel: breakLevel, + loopLevel: loopLevel + }); + if (forNode.body) this.vstatementBody(forNode.body); + this.vLoopStack.pop(); + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(this.vCur); + if (forNode.update) this.vstatementExpression(forNode.update); + this.vMaskDepth--; + if (!isSafe) em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + this.vRecomputeCur(saved); + } + vstmtWhile(whileNode) { + if (whileNode.type !== "WhileStatement") throw this.astErrorOutput("Invalid while statement", whileNode); + const em = this.em; + const varying = this.vInfo.exprVarying(whileNode.test) || this.vInfo.hasVaryingExit(whileNode.body, false); + const safeI = em.addLocal("i32"); + em.i32Const(0).localSet(safeI); + if (!varying) { + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + this.emitCondition(whileNode.test); + em.i32Eqz(); + this.brIfTo(breakLevel); + this.enterBlock(); + const continueLevel = this.depth; + this.vLoopStack.push({ + varying: false, + breakLevel: breakLevel, + continueLevel: continueLevel + }); + this.vstatementBody(whileNode.body); + this.vLoopStack.pop(); + this.exit(); + em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + return; + } + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + const vLive = em.addLocal("v128"); + em.localGet(this.vCur).localSet(vLive); + const exits = this.vLoopBodyExits(whileNode.body); + let vBrk = -1; + if (exits.hasBreak) { + vBrk = em.addLocal("v128"); + this.vZero(); + em.localSet(vBrk); + } + const vCnt = exits.hasContinue ? em.addLocal("v128") : -1; + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + if (vBrk !== -1 || this.vRetMask !== -1) { + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(vLive); + } + if (vCnt !== -1) { + this.vZero(); + em.localSet(vCnt); + } + this.vMaskDepth++; + em.localGet(vLive).localSet(this.vCur); + em.localGet(vLive); + this.vexprMask(whileNode.test); + em.v128And().localSet(vLive); + em.localGet(vLive).v128AnyTrue().i32Eqz(); + this.brIfTo(breakLevel); + em.localGet(vLive).localSet(this.vCur); + this.vLoopStack.push({ + varying: true, + vLive: vLive, + vBrk: vBrk, + vCnt: vCnt, + breakLevel: breakLevel, + loopLevel: loopLevel + }); + this.vstatementBody(whileNode.body); + this.vLoopStack.pop(); + this.vMaskDepth--; + em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + this.vRecomputeCur(saved); + } + vstmtDoWhile(doWhileNode) { + if (doWhileNode.type !== "DoWhileStatement") throw this.astErrorOutput("Invalid while statement", doWhileNode); + const em = this.em; + const varying = this.vInfo.exprVarying(doWhileNode.test) || this.vInfo.hasVaryingExit(doWhileNode.body, false); + const safeI = em.addLocal("i32"); + em.i32Const(0).localSet(safeI); + if (!varying) { + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + this.enterBlock(); + const continueLevel = this.depth; + this.vLoopStack.push({ + varying: false, + breakLevel: breakLevel, + continueLevel: continueLevel + }); + this.vstatementBody(doWhileNode.body); + this.vLoopStack.pop(); + this.exit(); + em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.emitCondition(doWhileNode.test); + this.brIfTo(loopLevel); + this.exit(); + this.exit(); + return; + } + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + const vLive = em.addLocal("v128"); + em.localGet(this.vCur).localSet(vLive); + const exits = this.vLoopBodyExits(doWhileNode.body); + let vBrk = -1; + if (exits.hasBreak) { + vBrk = em.addLocal("v128"); + this.vZero(); + em.localSet(vBrk); + } + const vCnt = exits.hasContinue ? em.addLocal("v128") : -1; + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + if (vBrk !== -1 || this.vRetMask !== -1) { + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(vLive); + } + if (vCnt !== -1) { + this.vZero(); + em.localSet(vCnt); + } + this.vMaskDepth++; + em.localGet(vLive).localSet(this.vCur); + this.vLoopStack.push({ + varying: true, + vLive: vLive, + vBrk: vBrk, + vCnt: vCnt, + breakLevel: breakLevel, + loopLevel: loopLevel + }); + this.vstatementBody(doWhileNode.body); + this.vLoopStack.pop(); + if (vBrk !== -1 || this.vRetMask !== -1) { + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(vLive); + } + em.localGet(vLive).localSet(this.vCur); + em.localGet(vLive); + this.vexprMask(doWhileNode.test); + em.v128And().localSet(vLive); + this.vMaskDepth--; + em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + em.localGet(vLive).v128AnyTrue(); + this.brIfTo(loopLevel); + this.exit(); + this.exit(); + this.vRecomputeCur(saved); + } + vstmtSwitch(ast) { + if (ast.type !== "SwitchStatement") throw this.astErrorOutput("Invalid switch statement", ast); + const {discriminant: discriminant, cases: cases} = ast; + const em = this.em; + const varying = this.vInfo.exprVarying(discriminant) || cases.some(c => c.test && this.vInfo.exprVarying(c.test)); + const type = this.getType(discriminant); + if (!varying) { + let dLocal; + let dIsInt; + switch (type) { + case "Float": + case "Number": + dIsInt = false; + dLocal = em.addLocal("f32"); + this.coerce(this.expression(discriminant), "f32"); + em.localSet(dLocal); + break; + + case "Integer": + dIsInt = true; + dLocal = em.addLocal("i32"); + this.coerce(this.expression(discriminant), "i32"); + em.localSet(dLocal); + break; + + default: + throw this.astErrorOutput(`Unhandled switch discriminant type "${type}"`, ast); + } + if (cases.length === 1 && !cases[0].test) { + this.vEmitSwitchConsequent(cases[0].consequent); + return; + } + const {groups: groups, defaultConsequent: defaultConsequent} = this.collectSwitchGroups(cases); + const emitChain = index => { + if (index === groups.length) { + if (defaultConsequent) this.vEmitSwitchConsequent(defaultConsequent); + return; + } + const {tests: tests, consequent: consequent} = groups[index]; + for (let i = 0; i < tests.length; i++) { + em.localGet(dLocal); + this.emitSwitchTest(tests[i], dIsInt); + if (dIsInt) em.i32Eq(); else em.f32Eq(); + if (i > 0) em.i32Or(); + } + this.enterIf(); + this.vEmitSwitchConsequent(consequent); + if (index + 1 < groups.length || defaultConsequent) { + em.else_(); + emitChain(index + 1); + } + this.exit(); + }; + emitChain(0); + return; + } + let dLocal; + let dIsInt; + switch (type) { + case "Float": + case "Number": + dIsInt = false; + dLocal = em.addLocal("v128"); + this.vCoerce(this.vexpr(discriminant), "vf32"); + em.localSet(dLocal); + break; + + case "Integer": + dIsInt = true; + dLocal = em.addLocal("v128"); + this.vCoerce(this.vexpr(discriminant), "vi32"); + em.localSet(dLocal); + break; + + default: + throw this.astErrorOutput(`Unhandled switch discriminant type "${type}"`, ast); + } + if (cases.length === 1 && !cases[0].test) { + this.vEmitSwitchConsequent(cases[0].consequent); + return; + } + const {groups: groups, defaultConsequent: defaultConsequent} = this.collectSwitchGroups(cases); + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + const prior = em.addLocal("v128"); + this.vZero(); + em.localSet(prior); + const gm = em.addLocal("v128"); + this.vMaskDepth++; + for (let g = 0; g < groups.length; g++) { + const {tests: tests, consequent: consequent} = groups[g]; + for (let i = 0; i < tests.length; i++) { + em.localGet(dLocal); + this.vEmitSwitchTest(tests[i], dIsInt); + if (dIsInt) em.i32x4Eq(); else em.f32x4Eq(); + if (i > 0) em.v128Or(); + } + em.localSet(gm); + this.vRecomputeCur(saved); + em.localGet(this.vCur).localGet(gm).v128And().localGet(prior).v128Andnot().localSet(this.vCur); + em.localGet(prior).localGet(gm).v128Or().localSet(prior); + em.localGet(this.vCur).v128AnyTrue(); + this.enterIf(); + this.vEmitSwitchConsequent(consequent); + this.exit(); + } + if (defaultConsequent) { + this.vRecomputeCur(saved); + em.localGet(this.vCur).localGet(prior).v128Andnot().localSet(this.vCur); + em.localGet(this.vCur).v128AnyTrue(); + this.enterIf(); + this.vEmitSwitchConsequent(defaultConsequent); + this.exit(); + } + this.vMaskDepth--; + this.vRecomputeCur(saved); + } + vEmitSwitchTest(test, dIsInt) { + const testType = this.getType(test); + if (dIsInt) if (testType === "Number" || testType === "Float") this.vCastValueToInteger(test); else if (testType === "LiteralInteger") this.vCastLiteralToInteger(test); else this.vCoerce(this.vexpr(test), "vi32"); else if (testType === "LiteralInteger") this.vCastLiteralToFloat(test); else if (testType === "Integer") this.vCastValueToFloat(test); else this.vCoerce(this.vexpr(test), "vf32"); + } + vEmitSwitchConsequent(consequent) { + const statements = this.collectSwitchCaseStatements(consequent); + const previous = this.vTerminated; + this.vTerminated = false; + for (let i = 0; i < statements.length; i++) { + this.vstatement(statements[i]); + if (this.vTerminated) break; + } + this.vTerminated = previous; + } + vexpr(ast) { + if (!this.vInfo.exprVarying(ast)) return this.expression(ast); + switch (ast.type) { + case "Identifier": + return this.vexprIdentifier(ast); + + case "BinaryExpression": + return this.vexprBinary(ast); + + case "LogicalExpression": + return this.vexprLogical(ast); + + case "UnaryExpression": + return this.vexprUnary(ast); + + case "UpdateExpression": + return this.vUpdate(ast, false); + + case "ConditionalExpression": + return this.vexprConditional(ast); + + case "CallExpression": + return this.vexprCall(ast); + + case "MemberExpression": + return this.vexprMember(ast); + + case "SequenceExpression": + if (ast.expressions.length === 1) return this.vexpr(ast.expressions[0]); + throw this.astErrorOutput("WebAssembly backend does not yet support the comma operator", ast); + + case "AssignmentExpression": + throw this.astErrorOutput("WebAssembly backend does not yet support assignment used as an expression", ast); + + default: + throw this.astErrorOutput(`Unknown expression type ${ast.type}`, ast); + } + } + vexprIdentifier(ast) { + const local = this.locals.get(ast.name); + if (!local) throw this.astErrorOutput(`Unhandled varying identifier "${ast.name}"`, ast); + if (local.kind === "vvec") throw this.astErrorOutput(`array-valued variable "${ast.name}" can only be indexed or returned`, ast); + if (local.kind !== "vscalar") throw this.astErrorOutput(`internal: varying read of uniform local "${ast.name}"`, ast); + this.em.localGet(local.index); + return local.wtype; + } + vexprBinary(ast) { + const operator = ast.operator; + const em = this.em; + if (operator === "**") { + const a = em.addLocal("v128"); + const b = em.addLocal("v128"); + this.vEmitByType(ast.left, "vf32"); + em.localSet(a); + this.vEmitByType(ast.right, "vf32"); + em.localSet(b); + this.usedMathImports.add("pow"); + this.vLaneCall2("math_pow", a, b); + return "vf32"; + } + if (BITWISE_OPS[operator]) { + if (VECTOR_SHIFT_OPS[operator]) return this.vexprShift(ast); + this.vEmitAsIntegerOperand(ast.left); + this.vEmitAsIntegerOperand(ast.right); + em[{ + "&": "v128And", + "|": "v128Or", + "^": "v128Xor" + }[operator]](); + return "vi32"; + } + if (operator === "/" || operator === "%") { + if (operator === "/") { + this.vEmitByType(ast.left, "vf32"); + this.vEmitByType(ast.right, "vf32"); + em.f32x4Div(); + return "vf32"; + } + const a = em.addLocal("v128"); + const b = em.addLocal("v128"); + this.vEmitByType(ast.left, "vf32"); + em.localSet(a); + this.vEmitByType(ast.right, "vf32"); + em.localSet(b); + em.localGet(a).localGet(a).localGet(b).f32x4Div().f32x4Trunc().localGet(b).f32x4Mul().f32x4Sub(); + return "vf32"; + } + const leftType = this.getType(ast.left) || "Number"; + const rightType = this.getType(ast.right) || "Number"; + const key = leftType + " & " + rightType; + let category; + switch (key) { + case "Integer & Integer": + this.pushState("building-integer"); + this.vCoerce(this.vexpr(ast.left), "vi32"); + this.vCoerce(this.vexpr(ast.right), "vi32"); + this.popState("building-integer"); + category = "vi32"; + break; + + case "Number & Float": + case "Float & Number": + case "Float & Float": + case "Number & Number": + this.pushState("building-float"); + this.vCoerce(this.vexpr(ast.left), "vf32"); + this.vCoerce(this.vexpr(ast.right), "vf32"); + this.popState("building-float"); + category = "vf32"; + break; + + case "LiteralInteger & LiteralInteger": + if (this.isState("casting-to-integer") || this.isState("building-integer")) { + this.pushState("building-integer"); + this.vCoerce(this.vexpr(ast.left), "vi32"); + this.vCoerce(this.vexpr(ast.right), "vi32"); + this.popState("building-integer"); + category = "vi32"; + } else { + this.pushState("building-float"); + this.vCastLiteralToFloat(ast.left); + this.vCastLiteralToFloat(ast.right); + this.popState("building-float"); + category = "vf32"; + } + break; + + case "Integer & Float": + case "Integer & Number": + this.pushState("building-float"); + this.vCastValueToFloat(ast.left); + this.vCoerce(this.vexpr(ast.right), "vf32"); + this.popState("building-float"); + category = "vf32"; + break; + + case "Integer & LiteralInteger": + this.pushState("building-integer"); + this.vCoerce(this.vexpr(ast.left), "vi32"); + this.vCastLiteralToInteger(ast.right); + this.popState("building-integer"); + category = "vi32"; + break; + + case "Number & Integer": + case "Float & Integer": + this.pushState("building-float"); + this.vCoerce(this.vexpr(ast.left), "vf32"); + this.vCastValueToFloat(ast.right); + this.popState("building-float"); + category = "vf32"; + break; + + case "Float & LiteralInteger": + case "Number & LiteralInteger": + this.pushState("building-float"); + this.vCoerce(this.vexpr(ast.left), "vf32"); + this.vCastLiteralToFloat(ast.right); + this.popState("building-float"); + category = "vf32"; + break; + + case "LiteralInteger & Float": + case "LiteralInteger & Number": + if (this.isState("casting-to-integer")) { + this.pushState("building-integer"); + this.vCastLiteralToInteger(ast.left); + this.vCastValueToInteger(ast.right); + this.popState("building-integer"); + category = "vi32"; + } else { + this.pushState("building-float"); + this.vCastLiteralToFloat(ast.left); + this.pushState("casting-to-float"); + this.vCoerce(this.vexpr(ast.right), "vf32"); + this.popState("casting-to-float"); + this.popState("building-float"); + category = "vf32"; + } + break; + + case "LiteralInteger & Integer": + this.pushState("building-integer"); + this.vCastLiteralToInteger(ast.left); + this.vCoerce(this.vexpr(ast.right), "vi32"); + this.popState("building-integer"); + category = "vi32"; + break; + + case "Boolean & Boolean": + this.vCoerce(this.vexpr(ast.left), "vi32"); + this.vCoerce(this.vexpr(ast.right), "vi32"); + category = "vi32"; + break; + + default: + throw this.astErrorOutput(`Unhandled binary expression between ${key}`, ast); + } + const compareOp = category === "vi32" ? VI32_COMPARE[operator] : VF32_COMPARE[operator]; + if (compareOp) { + em[compareOp](); + return "vbool"; + } + const arithOp = category === "vi32" ? VI32_ARITH[operator] : VF32_ARITH[operator]; + if (!arithOp) throw this.astErrorOutput(`Unhandled operator ${operator}`, ast); + em[arithOp](); + return category; + } + vexprShift(ast) { + const em = this.em; + this.vEmitAsIntegerOperand(ast.left); + if (!this.vInfo.exprVarying(ast.right)) { + this.emitAsIntegerOperand(ast.right); + em[VECTOR_SHIFT_OPS[ast.operator]](); + return "vi32"; + } + const a = em.addLocal("v128"); + const b = em.addLocal("v128"); + em.localSet(a); + this.vEmitAsIntegerOperand(ast.right); + em.localSet(b); + const op = BITWISE_OPS[ast.operator]; + for (let lane = 0; lane < 4; lane++) { + em.localGet(a).i32x4ExtractLane(lane); + em.localGet(b).i32x4ExtractLane(lane); + em[op](); + if (lane === 0) em.i32x4Splat(); else em.i32x4ReplaceLane(lane); + } + return "vi32"; + } + vEmitAsIntegerOperand(side) { + switch (this.getType(side)) { + case "Number": + case "Float": + this.vCastValueToInteger(side); + break; + + case "LiteralInteger": + this.vCastLiteralToInteger(side); + break; + + default: + { + this.pushState("building-integer"); + const type = this.vexpr(side); + this.popState("building-integer"); + this.vCoerce(type, "vi32"); + } + } + } + vexprLogical(ast) { + const em = this.em; + const mLeft = em.addLocal("v128"); + this.vexprMask(ast.left); + em.localSet(mLeft); + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + em.localGet(this.vCur).localGet(mLeft); + if (ast.operator === "&&") em.v128And(); else if (ast.operator === "||") em.v128Andnot(); else throw this.astErrorOutput(`Unhandled logical operator ${ast.operator}`, ast); + em.localSet(this.vCur); + this.vMaskDepth++; + this.vexprMask(ast.right); + this.vMaskDepth--; + em.localGet(saved).localSet(this.vCur); + em.localGet(mLeft); + if (ast.operator === "&&") em.v128And(); else em.v128Or(); + return "vbool"; + } + vexprUnary(ast) { + const em = this.em; + switch (ast.operator) { + case "~": + this.vEmitAsIntegerOperand(ast.argument); + em.v128ConstI32x4(-1, -1, -1, -1).v128Xor(); + return "vi32"; + + case "!": + this.vexprMask(ast.argument); + em.v128Not(); + return "vbool"; + + case "+": + return this.vexpr(ast.argument); + + case "-": + { + const type = this.getType(ast.argument); + if (type === "Integer" || type === "LiteralInteger" && (this.isState("casting-to-integer") || this.isState("building-integer"))) { + this.vZero(); + this.vEmitByType(ast.argument, "vi32"); + em.i32x4Sub(); + return "vi32"; + } + this.vEmitByType(ast.argument, "vf32"); + em.f32x4Neg(); + return "vf32"; + } + + default: + throw this.astErrorOutput(`Unhandled unary operator ${ast.operator}`, ast); + } + } + vexprConditional(ast) { + const em = this.em; + const consequentType = this.getType(ast.consequent); + const alternateType = this.getType(ast.alternate); + if (consequentType === null && alternateType === null) { + this.vTernaryStatement(ast); + return "void"; + } + let targetType = consequentType === "LiteralInteger" ? "Number" : consequentType; + if (targetType === "Integer" && (alternateType === "Number" || alternateType === "Float")) targetType = "Number"; + const emitBranch = branch => { + const branchType = this.getType(branch); + switch (targetType) { + case "Number": + case "Float": + if (branchType === "Integer") this.vCastValueToFloat(branch); else if (branchType === "LiteralInteger") this.vCastLiteralToFloat(branch); else this.vCoerce(this.vexpr(branch), "vf32"); + break; + + case "Integer": + if (branchType === "Number" || branchType === "Float") this.vCastValueToInteger(branch); else if (branchType === "LiteralInteger") this.vCastLiteralToInteger(branch); else this.vCoerce(this.vexpr(branch), "vi32"); + break; + + case "Boolean": + this.vexprMask(branch); + break; + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support a ternary of type ${targetType}`, ast); + } + }; + const resultCategory = targetType === "Integer" ? "vi32" : targetType === "Boolean" ? "vbool" : "vf32"; + if (!this.vInfo.exprVarying(ast.test)) { + this.emitCondition(ast.test); + this.enterIf("v128"); + emitBranch(ast.consequent); + em.else_(); + emitBranch(ast.alternate); + this.exit(); + return resultCategory; + } + const m = em.addLocal("v128"); + this.vexprMask(ast.test); + em.localSet(m); + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + const v1 = em.addLocal("v128"); + const v2 = em.addLocal("v128"); + em.localGet(saved).localGet(m).v128And().localSet(this.vCur); + this.vMaskDepth++; + emitBranch(ast.consequent); + em.localSet(v1); + em.localGet(saved).localGet(m).v128Andnot().localSet(this.vCur); + emitBranch(ast.alternate); + em.localSet(v2); + this.vMaskDepth--; + em.localGet(saved).localSet(this.vCur); + em.localGet(v1).localGet(v2).localGet(m).v128Bitselect(); + return resultCategory; + } + vTernaryStatement(ast) { + const em = this.em; + if (!this.vInfo.exprVarying(ast.test)) { + this.emitCondition(ast.test); + this.enterIf(); + this.vstatementExpression(ast.consequent); + em.else_(); + this.vstatementExpression(ast.alternate); + this.exit(); + return; + } + const m = em.addLocal("v128"); + this.vexprMask(ast.test); + em.localSet(m); + const saved = em.addLocal("v128"); + em.localGet(this.vCur).localSet(saved); + em.localGet(saved).localGet(m).v128And().localSet(this.vCur); + this.vMaskDepth++; + this.vstatementExpression(ast.consequent); + em.localGet(saved).localGet(m).v128Andnot().localSet(this.vCur); + this.vstatementExpression(ast.alternate); + this.vMaskDepth--; + em.localGet(saved).localSet(this.vCur); + } + vexprCall(ast) { + if (!ast.callee) throw this.astErrorOutput("Unknown CallExpression", ast); + if (ast.callee.type === "MemberExpression" && this.getVariableSignature(ast.callee, true) === "this.color") throw this.astErrorOutput("WebAssembly backend does not yet support graphical mode (this.color)", ast); + let functionName = null; + const isMathFunction = this.isAstMathFunction(ast); + if (isMathFunction || ast.callee.object && ast.callee.object.type === "ThisExpression") functionName = ast.callee.property.name; else if (ast.callee.type === "SequenceExpression" && ast.callee.expressions[0].type === "Literal" && !isNaN(ast.callee.expressions[0].raw)) functionName = ast.callee.expressions[1].property.name; else functionName = ast.callee.name; + if (!functionName) throw this.astErrorOutput(`Unhandled function, couldn't find name`, ast); + if (isMathFunction) return this.vMathCall(functionName, ast); + return this.vUserCall(functionName, ast); + } + vUserCall(functionName, ast) { + const em = this.em; + const info = this.assembler.helperInfo || { + readsThread: false, + usesRandom: false + }; + const globals = this.assembler.globals; + const returnType = this.getType(ast); + const targetTypes = this.lookupFunctionArgumentTypes(functionName) || []; + const argLocals = []; + for (let i = 0; i < ast.arguments.length; ++i) { + const argument = ast.arguments[i]; + let targetType = targetTypes[i]; + const argumentType = this.getType(argument); + if (!targetType) { + this.triggerImplyArgumentType(functionName, i, argumentType, this); + targetType = argumentType; + } + let wtype; + switch (argumentType) { + case "Boolean": + this.vCoerce(this.vexpr(argument), "vi32"); + wtype = "vi32"; + break; + + case "Number": + case "Float": + if (targetType === "Integer") { + this.vCastValueToInteger(argument); + wtype = "vi32"; + } else { + this.vCoerce(this.vexpr(argument), "vf32"); + wtype = "vf32"; + } + break; + + case "Integer": + if (targetType === "Number" || targetType === "Float") { + this.vCastValueToFloat(argument); + wtype = "vf32"; + } else { + this.vCoerce(this.vexpr(argument), "vi32"); + wtype = "vi32"; + } + break; + + case "LiteralInteger": + if (targetType === "Integer") { + this.vCastLiteralToInteger(argument); + wtype = "vi32"; + } else { + this.vCastLiteralToFloat(argument); + wtype = "vf32"; + } + break; + + default: + throw this.astErrorOutput("WebAssembly backend does not yet support array arguments to helper functions", ast); + } + const index = em.addLocal("v128"); + em.localSet(index); + argLocals.push({ + index: index, + wtype: wtype + }); + } + const resultKind = returnType === null || returnType === void 0 ? "void" : returnType === "Integer" || returnType === "Boolean" ? "i32" : "f32"; + const resultTmp = resultKind === "void" ? -1 : em.addLocal(resultKind); + const resultVec = resultKind === "void" ? -1 : em.addLocal("v128"); + let stateTmp = -1; + if (info.usesRandom) { + stateTmp = em.addLocal("v128"); + em.globalGet(globals.pcgStateV).localSet(stateTmp); + } + for (let lane = 0; lane < 4; lane++) { + if (info.readsThread) { + em.localGet(this._vBaseX); + if (lane > 0) em.i32Const(lane).i32Add(); + em.globalSet(globals.threadX); + } + if (info.usesRandom) em.localGet(stateTmp).i32x4ExtractLane(lane).globalSet(globals.pcgState); + for (const arg of argLocals) { + em.localGet(arg.index); + if (arg.wtype === "vi32") em.i32x4ExtractLane(lane); else em.f32x4ExtractLane(lane); + } + em.call(this.mangleFunctionName(functionName)); + if (resultKind !== "void") em.localSet(resultTmp); + if (info.usesRandom) em.localGet(stateTmp).globalGet(globals.pcgState).i32x4ReplaceLane(lane).localSet(stateTmp); + if (resultKind !== "void") if (lane === 0) { + em.localGet(resultTmp); + if (resultKind === "i32") em.i32x4Splat(); else em.f32x4Splat(); + em.localSet(resultVec); + } else { + em.localGet(resultVec).localGet(resultTmp); + if (resultKind === "i32") em.i32x4ReplaceLane(lane); else em.f32x4ReplaceLane(lane); + em.localSet(resultVec); + } + } + if (info.readsThread) em.localGet(this._vBaseX).globalSet(globals.threadX); + if (info.usesRandom) { + em.localGet(stateTmp).globalGet(globals.pcgStateV); + if (this.vMaskDepth > 0) em.localGet(this.vCur); else em.v128ConstI32x4(-1, -1, -1, -1); + em.v128Bitselect().globalSet(globals.pcgStateV); + } + if (resultKind === "void") return "void"; + em.localGet(resultVec); + return resultKind === "i32" ? "vi32" : "vf32"; + } + vMathCall(functionName, ast) { + const em = this.em; + if (functionName === "random") { + this.usesRandom = true; + if (this.vMaskDepth > 0) em.localGet(this.vCur); else em.v128ConstI32x4(-1, -1, -1, -1); + em.call("pcg_random_v"); + return "vf32"; + } + const emitArg = argument => { + switch (this.getType(argument)) { + case "Integer": + this.vCastValueToFloat(argument); + break; + + case "LiteralInteger": + this.vCastLiteralToFloat(argument); + break; + + default: + this.vCoerce(this.vexpr(argument), "vf32"); + } + }; + const nativeOp = VECTOR_MATH_NATIVE_OPS[functionName]; + if (nativeOp) { + emitArg(ast.arguments[0]); + em[nativeOp](); + return "vf32"; + } + switch (functionName) { + case "round": + emitArg(ast.arguments[0]); + em.v128ConstF32x4(.5, .5, .5, .5).f32x4Add().f32x4Floor(); + return "vf32"; + + case "fround": + emitArg(ast.arguments[0]); + return "vf32"; + + case "min": + case "max": + { + const op = functionName === "min" ? "f32x4Min" : "f32x4Max"; + emitArg(ast.arguments[0]); + for (let i = 1; i < ast.arguments.length; i++) { + emitArg(ast.arguments[i]); + em[op](); + } + return "vf32"; + } + + case "imul": + emitArg(ast.arguments[0]); + em.i32x4TruncSatF32x4S(); + emitArg(ast.arguments[1]); + em.i32x4TruncSatF32x4S(); + em.i32x4Mul().f32x4ConvertI32x4S(); + return "vf32"; + + case "clz32": + { + emitArg(ast.arguments[0]); + em.i32x4TruncSatF32x4U(); + const t = em.addLocal("v128"); + em.localSet(t); + em.localGet(t).i32x4ExtractLane(0).i32Clz().i32x4Splat(); + for (let lane = 1; lane < 4; lane++) em.localGet(t).i32x4ExtractLane(lane).i32Clz().i32x4ReplaceLane(lane); + em.f32x4ConvertI32x4S(); + return "vf32"; + } + + default: + { + const arity = MATH_IMPORT_ARITY[functionName]; + if (!arity) throw this.astErrorOutput(`WebAssembly backend does not yet support Math.${functionName}`, ast); + this.usedMathImports.add(functionName); + if (arity === 1) { + emitArg(ast.arguments[0]); + const t = em.addLocal("v128"); + em.localSet(t); + this.vLaneCall1("math_" + functionName, t); + } else { + const a = em.addLocal("v128"); + const b = em.addLocal("v128"); + emitArg(ast.arguments[0]); + em.localSet(a); + emitArg(ast.arguments[1]); + em.localSet(b); + this.vLaneCall2("math_" + functionName, a, b); + } + return "vf32"; + } + } + } + vLaneCall1(name, argLocal) { + const em = this.em; + em.localGet(argLocal).f32x4ExtractLane(0).call(name).f32x4Splat(); + for (let lane = 1; lane < 4; lane++) em.localGet(argLocal).f32x4ExtractLane(lane).call(name).f32x4ReplaceLane(lane); + } + vLaneCall2(name, aLocal, bLocal) { + const em = this.em; + em.localGet(aLocal).f32x4ExtractLane(0).localGet(bLocal).f32x4ExtractLane(0).call(name).f32x4Splat(); + for (let lane = 1; lane < 4; lane++) em.localGet(aLocal).f32x4ExtractLane(lane).localGet(bLocal).f32x4ExtractLane(lane).call(name).f32x4ReplaceLane(lane); + } + vexprMember(mNode) { + const details = this.getMemberExpressionDetails(mNode); + if (!details) throw this.astErrorOutput("Unexpected expression", mNode); + const {signature: signature, name: name, property: property, xProperty: xProperty, yProperty: yProperty, zProperty: zProperty} = details; + const em = this.em; + switch (signature) { + case "value.thread.value": + case "this.thread.value": + if (name !== "x") throw this.astErrorOutput(`internal: thread.${name} is uniform along the lane axis`, mNode); + this.readsThread = true; + em.globalGet(this.assembler.globals.threadX).i32x4Splat(); + em.v128ConstI32x4(0, 1, 2, 3).i32x4Add(); + return "vi32"; + + case "value.value": + { + const component = { + r: 0, + g: 1, + b: 2, + a: 3 + }[property]; + if (component !== void 0) { + const local = this.locals.get(name); + if (local && local.kind === "vvec" && component < local.n) { + em.localGet(local.indices[component]); + return "vf32"; + } + } + throw this.astErrorOutput("Unexpected expression", mNode); + } + + case "value[]": + case "value[][]": + case "value[][][]": + case "value[][][][]": + { + const local = this.locals.get(name); + if (local && (local.kind === "vec" || local.kind === "vvec")) { + if (signature !== "value[]") throw this.astErrorOutput("Unexpected expression", mNode); + return this.vVecIndex(local, xProperty); + } + return this.vGather("arrays", name, xProperty, yProperty, zProperty, mNode); + } + + case "this.constants.value[]": + case "this.constants.value[][]": + case "this.constants.value[][][]": + case "this.constants.value[][][][]": + return this.vGather("constantArrays", name, xProperty, yProperty, zProperty, mNode); + + case "fn()[]": + throw this.astErrorOutput("WebAssembly backend does not yet support indexing a function call result", mNode); + + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support expression signature "${signature}"`, mNode); + } + } + vVecIndex(local, xProperty) { + const em = this.em; + const getComponent = k => { + em.localGet(local.indices[k]); + if (local.kind === "vec") em.f32x4Splat(); + }; + if (xProperty.type === "Literal" && Number.isInteger(xProperty.value)) { + if (xProperty.value < 0 || xProperty.value >= local.n) throw this.astErrorOutput(`index ${xProperty.value} out of range for Array(${local.n})`, xProperty); + getComponent(xProperty.value); + return "vf32"; + } + const idx = em.addLocal("v128"); + this.vEmitIndex(xProperty); + em.localSet(idx); + const acc = em.addLocal("v128"); + getComponent(0); + em.localSet(acc); + for (let k = 1; k < local.n; k++) { + getComponent(k); + em.localGet(acc); + em.localGet(idx).v128ConstI32x4(k, k, k, k).i32x4Eq(); + em.v128Bitselect(); + em.localSet(acc); + } + em.localGet(acc); + return "vf32"; + } + vEmitIndex(property) { + if (!property) throw new Error("Property not set"); + switch (this.getType(property)) { + case "Number": + case "Float": + this.vCastValueToInteger(property); + return; + + case "LiteralInteger": + this.vCastLiteralToInteger(property); + return; + + case "Integer": + { + this.pushState("building-integer"); + const emitted = this.vexpr(property); + this.popState("building-integer"); + this.vCoerce(emitted, "vi32"); + return; + } + + default: + this.vCoerce(this.vexpr(property), "vi32"); + } + } + vGather(table, name, xProperty, yProperty, zProperty, mNode) { + const em = this.em; + const layout = this.assembler.layout[table][name]; + if (!layout) throw this.astErrorOutput(`no memory layout for "${name}" \u2014 arrays are only readable as kernel arguments or constants`, mNode); + this.vEmitIndex(xProperty); + if (yProperty) { + this.vEmitIndex(yProperty); + const d = layout.dims[0]; + em.v128ConstI32x4(d, d, d, d).i32x4Mul().i32x4Add(); + } + if (zProperty) { + this.vEmitIndex(zProperty); + const d = layout.dims[0] * layout.dims[1]; + em.v128ConstI32x4(d, d, d, d).i32x4Mul().i32x4Add(); + } + this.vZero(); + em.i32x4MaxS(); + const max = layout.flatLength - 1; + em.v128ConstI32x4(max, max, max, max).i32x4MinS(); + const idx = em.addLocal("v128"); + em.localSet(idx); + em.localGet(idx).i32x4ExtractLane(0).i32Const(2).i32Shl().f32Load(layout.offset).f32x4Splat(); + for (let lane = 1; lane < 4; lane++) em.localGet(idx).i32x4ExtractLane(lane).i32Const(2).i32Shl().f32Load(layout.offset).f32x4ReplaceLane(lane); + return "vf32"; + } + isThreadDependent(ast) { + if (!ast || typeof ast !== "object") return false; + if (Array.isArray(ast)) return ast.some(node => this.isThreadDependent(node)); + switch (ast.type) { + case "MemberExpression": + { + const signature = this.getVariableSignature(ast); + if (signature === "this.thread.value" || signature === "value.thread.value") return ast.property.name === "x"; + break; + } + + case "CallExpression": + if (this.isAstMathFunction(ast)) { + if (ast.callee.property.name === "random") return true; + break; + } + return true; + + case "Identifier": + return this.taintedLocals ? this.taintedLocals.has(ast.name) : false; + + case "ThisExpression": + return false; + } + for (const key in ast) { + if (key === "loc" || key === "start" || key === "end" || key === "parent") continue; + const child = ast[key]; + if (child && typeof child === "object" && this.isThreadDependent(child)) return true; + } + return false; + } + recordUniformity(kind, testAst) { + if (!this._analysisPass) return; + this.uniformity.push({ + kind: kind, + threadDependent: testAst ? this.isThreadDependent(testAst) : true + }); + } + }; + module.exports = { + WebAssemblyFunctionNode: WebAssemblyFunctionNode + }; + }); + var require_worker_pool = __commonJSMin((exports, module) => { + let os = null; + try { + os = require_empty_module(); + } catch (e) {} + const IS_BROWSER_WORKER = typeof Worker === "function"; + function defaultConcurrency() { + if (typeof navigator !== "undefined" && navigator.hardwareConcurrency) return navigator.hardwareConcurrency; + if (os && typeof os.cpus === "function") { + const count = os.cpus().length; + if (count) return count; + } + return 4; + } + const WORKER_SOURCE = `\nvar entries = {};\nfunction handleMessage(message, post) {\n if (message.type === 'setup') {\n var imports = { env: { memory: message.memory } };\n for (var i = 0; i < message.mathImports.length; i++) {\n imports.env['math_' + message.mathImports[i]] = Math[message.mathImports[i]];\n }\n var instance = new WebAssembly.Instance(message.module, imports);\n entries[message.id] = {\n run: instance.exports.run,\n runSimd: instance.exports.run_simd || null,\n sizeX: message.sizeX\n };\n post({ type: 'ready', id: message.id });\n } else if (message.type === 'release') {\n delete entries[message.id];\n } else if (message.type === 'run') {\n var entry = entries[message.id];\n var start = message.start;\n var end = message.end;\n var seed = message.seed;\n if (entry.runSimd && (entry.sizeX & 3) === 0 && (start & 3) === 0) {\n var quadEnd = end - ((end - start) & 3);\n if (quadEnd > start) entry.runSimd(start, quadEnd, seed);\n if (quadEnd < end) entry.run(quadEnd, end, seed);\n } else {\n entry.run(start, end, seed);\n }\n post({ type: 'done', taskId: message.taskId });\n }\n}\nif (typeof self !== 'undefined' && typeof postMessage === 'function') {\n self.onmessage = function(event) {\n handleMessage(event.data, function(message) { postMessage(message); });\n };\n} else {\n var parentPort = require('worker_threads').parentPort;\n parentPort.on('message', function(message) {\n handleMessage(message, function(reply) { parentPort.postMessage(reply); });\n });\n}\n`; + var WebAssemblyWorkerPool = class { + constructor(size) { + this.size = size || defaultConcurrency(); + this.workers = []; + this.destroyed = false; + this.dispatchCount = 0; + this.lastDispatch = null; + this._taskId = 0; + } + get liveWorkerCount() { + let count = 0; + for (const worker of this.workers) if (!worker.dead) count++; + return count; + } + _spawn() { + const worker = { + handle: null, + dead: false, + state: { + setup: new Set, + settingUp: new Map, + pending: new Map + }, + fail: null, + die: null + }; + const state = worker.state; + worker.fail = error => { + for (const wait of state.settingUp.values()) wait.reject(error); + state.settingUp.clear(); + for (const task of state.pending.values()) task.reject(error); + state.pending.clear(); + }; + worker.die = error => { + if (worker.dead) return; + worker.dead = true; + worker.fail(error); + if (worker.handle && typeof worker.handle.terminate === "function") try { + worker.handle.terminate(); + } catch (e) {} + }; + const onMessage = message => { + if (message.type === "ready") { + const wait = state.settingUp.get(message.id); + if (wait) { + state.settingUp.delete(message.id); + state.setup.add(message.id); + this._updateRef(worker); + wait.resolve(); + } + } else if (message.type === "done") { + const task = state.pending.get(message.taskId); + if (task) { + state.pending.delete(message.taskId); + this._updateRef(worker); + task.resolve(); + } + } + }; + let handle; + if (IS_BROWSER_WORKER) { + const url = URL.createObjectURL(new Blob([ WORKER_SOURCE ], { + type: "text/javascript" + })); + handle = new Worker(url); + URL.revokeObjectURL(url); + handle.onmessage = event => onMessage(event.data); + handle.onerror = event => worker.die(new Error(event.message || "WebAssembly worker error")); + } else { + const {Worker: NodeWorker} = require_empty_module(); + handle = new NodeWorker(WORKER_SOURCE, { + eval: true + }); + handle.on("message", onMessage); + handle.on("error", error => worker.die(error)); + handle.on("exit", code => { + worker.die(new Error(`WebAssembly worker exited with code ${code}`)); + }); + handle.unref(); + } + worker.handle = handle; + return worker; + } + _worker(index) { + while (this.workers.length <= index) this.workers.push(this._spawn()); + if (this.workers[index].dead) this.workers[index] = this._spawn(); + return this.workers[index]; + } + _updateRef(worker) { + if (worker.dead || !worker.handle || typeof worker.handle.ref !== "function") return; + if (worker.state.settingUp.size + worker.state.pending.size > 0) worker.handle.ref(); else worker.handle.unref(); + } + _ensureSetup(worker, entry) { + if (worker.state.setup.has(entry.id)) return Promise.resolve(); + let wait = worker.state.settingUp.get(entry.id); + if (!wait) { + wait = {}; + wait.promise = new Promise((resolve, reject) => { + wait.resolve = resolve; + wait.reject = reject; + }); + worker.state.settingUp.set(entry.id, wait); + this._updateRef(worker); + worker.handle.postMessage({ + type: "setup", + id: entry.id, + module: entry.module, + memory: entry.memory, + mathImports: entry.mathImports, + sizeX: entry.sizeX + }); + } + return wait.promise; + } + dispatch(entry, tasks) { + if (this.destroyed) return Promise.reject(new Error("WebAssembly worker pool has been destroyed")); + this.dispatchCount++; + this.lastDispatch = { + workerCount: tasks.length, + ranges: tasks.map(task => [ task.start, task.end ]) + }; + const runs = tasks.map((task, index) => { + const worker = this._worker(index); + return this._ensureSetup(worker, entry).then(() => new Promise((resolve, reject) => { + if (worker.dead) { + reject(new Error("WebAssembly worker died before the task could run")); + return; + } + const taskId = ++this._taskId; + worker.state.pending.set(taskId, { + resolve: resolve, + reject: reject + }); + this._updateRef(worker); + worker.handle.postMessage({ + type: "run", + id: entry.id, + taskId: taskId, + start: task.start, + end: task.end, + seed: task.seed + }); + })); + }); + return Promise.all(runs).then(() => void 0); + } + release(entryId) { + if (this.destroyed) return; + for (const worker of this.workers) { + if (worker.dead) continue; + worker.state.setup.delete(entryId); + const wait = worker.state.settingUp.get(entryId); + if (wait) { + worker.state.settingUp.delete(entryId); + wait.reject(new Error("WebAssembly kernel entry released during setup")); + this._updateRef(worker); + } + worker.handle.postMessage({ + type: "release", + id: entryId + }); + } + } + destroy() { + if (this.destroyed) return; + this.destroyed = true; + const error = new Error("WebAssembly worker pool has been destroyed"); + for (const worker of this.workers) { + worker.dead = true; + worker.fail(error); + worker.handle.terminate(); + } + this.workers = []; + } + }; + module.exports = { + WebAssemblyWorkerPool: WebAssemblyWorkerPool + }; + }); + var require_kernel = __commonJSMin((exports, module) => { + const {Kernel: Kernel} = require_kernel$7(); + const {FunctionBuilder: FunctionBuilder} = require_function_builder(); + const {WebAssemblyFunctionNode: WebAssemblyFunctionNode} = require_function_node(); + const {WasmModuleBuilder: WasmModuleBuilder} = require_wasm_builder(); + const {WebAssemblyWorkerPool: WebAssemblyWorkerPool} = require_worker_pool(); + const {utils: utils} = require_utils(); + const {Input: Input} = require_input(); + const features = Object.freeze({ + kernelMap: false, + isIntegerDivisionAccurate: true, + isSpeedTacticSupported: false, + isTextureFloat: true, + isDrawBuffers: false, + kernelMapSize: 0, + channelCount: 1, + maxTextureSize: Infinity, + isFloatRead: true + }); + const PAGE_BYTES = 65536; + let simdSupported = null; + let threadsSupported = null; + let nextEntryId = 1; + module.exports = { + WebAssemblyKernel: class WebAssemblyKernel extends Kernel { + static get isSupported() { + if (typeof WebAssembly !== "object" || WebAssembly === null) return false; + return WebAssembly.validate(new Uint8Array([ 0, 97, 115, 109, 1, 0, 0, 0 ])); + } + static get isSIMDSupported() { + if (simdSupported === null) try { + const builder = new WasmModuleBuilder; + builder.addFunction("t", { + params: [], + results: [] + }).v128ConstI32x4(0, 0, 0, 0).drop(); + simdSupported = WebAssembly.validate(builder.toBytes()); + } catch (e) { + simdSupported = false; + } + return simdSupported; + } + static get isThreadsSupported() { + if (threadsSupported === null) try { + if (typeof SharedArrayBuffer === "undefined") threadsSupported = false; else { + const builder = new WasmModuleBuilder; + builder.addMemoryImport(1, 1, true); + const memory = new WebAssembly.Memory({ + initial: 1, + maximum: 1, + shared: true + }); + new WebAssembly.Instance(new WebAssembly.Module(builder.toBytes()), { + env: { + memory: memory + } + }); + threadsSupported = true; + } + } catch (e) { + threadsSupported = false; + } + return threadsSupported; + } + static isContextMatch(context) { + return false; + } + static getFeatures() { + return features; + } + static get features() { + return features; + } + static get mode() { + return "webasm"; + } + static getSignature(kernel, argumentTypes) { + return "webasm" + (argumentTypes.length > 0 ? ":" + argumentTypes.join(",") : ""); + } + static destroyContext(context) {} + static nativeFunctionArguments() { + throw new Error("WebAssembly backend does not yet support native functions"); + } + static nativeFunctionReturnType() { + throw new Error("WebAssembly backend does not yet support native functions"); + } + static combineKernels() { + throw new Error("WebAssembly backend does not yet support combineKernels"); + } + constructor(source, settings) { + super(source, settings); + this.poolSize = null; + this.mergeSettings(source.settings || settings); + if (this.precision === null) this.precision = "single"; + this.threadDim = null; + this.componentCount = 1; + this.moduleCacheLimit = 8; + this.functionBuilder = null; + this.tracedFunctions = null; + this.usesRandom = false; + this.usedMathImports = null; + this._moduleCache = new Map; + this._active = null; + this._lastRunPath = null; + this._pool = null; + this._threadedTail = Promise.resolve(); + } + initCanvas() { + if (this.graphical && typeof document !== "undefined") return document.createElement("canvas"); + return null; + } + initContext() { + return null; + } + initPlugins(settings) { + return []; + } + setOutput(output) { + const newOutput = this.toKernelOutput(output); + if (this.built && !this.dynamicOutput) throw new Error("Resizing a kernel with dynamicOutput: false is not possible"); + this.output = newOutput; + return this; + } + toString() { + throw new Error("WebAssembly backend does not yet support toString"); + } + build() { + if (this.built) return; + if (this.gpu && this.gpu.kernels && this.gpu.kernels.indexOf(this) === -1) this.gpu.kernels.push(this); + if (this.graphical) return this.requestFallback(arguments, "graphical mode is not supported on the webasm backend"); + if (this.subKernels && this.subKernels.length > 0) return this.requestFallback(arguments, "kernel maps are not supported on the webasm backend"); + this.setupConstants(); + this.setupArguments(arguments); + for (let i = 0; i < this.argumentTypes.length; i++) switch (this.argumentTypes[i]) { + case "Array": + case "Input": + case "Number": + case "Float": + case "Integer": + case "Boolean": + continue; + + default: + return this.requestFallback(arguments, `argument "${this.argumentNames[i]}" of type ${this.argumentTypes[i]} is not supported on the webasm backend`); + } + for (const name in this.constantTypes) switch (this.constantTypes[name]) { + case "Array": + case "Input": + case "Number": + case "Float": + case "Integer": + case "Boolean": + continue; + + default: + return this.requestFallback(arguments, `constant "${name}" of type ${this.constantTypes[name]} is not supported on the webasm backend`); + } + this.validateSettings(arguments); + const threadDim = this.threadDim = Array.from(this.output); + while (threadDim.length < 3) threadDim.push(1); + if (!this.translateSource()) return this.requestFallback(arguments, `return type ${this.returnType} is not supported on the webasm backend`); + this.buildSignature(arguments); + this._instantiate(this._entryKey(arguments), arguments); + this.built = true; + } + validateSettings(args) { + if (!this.output || this.output.length === 0) { + if (args.length !== 1) throw new Error("Auto output only supported for kernels with only one input"); + const argType = utils.getVariableType(args[0], this.strictIntegers); + if (argType === "Array") this.output = Array.from(utils.getDimensions(args[0])); else throw new Error("Auto output not supported for input type: " + argType); + } + this.checkOutput(); + } + translateSource() { + const functionBuilder = this.functionBuilder = FunctionBuilder.fromKernel(this, WebAssemblyFunctionNode); + this.tracedFunctions = functionBuilder.traceFunctionCalls("kernel", []); + if (!this.returnType) this.returnType = functionBuilder.getKernelResultType(); + switch (this.returnType) { + case "Number": + case "Float": + case "Integer": + case "LiteralInteger": + this.componentCount = 1; + break; + + case "Array(2)": + this.componentCount = 2; + break; + + case "Array(3)": + this.componentCount = 3; + break; + + case "Array(4)": + this.componentCount = 4; + break; + + default: + return false; + } + this.usesRandom = false; + this.usedMathImports = new Set; + for (const name of this.tracedFunctions) { + const node = functionBuilder.functionMap[name]; + if (!node) continue; + if (node.usesRandom) this.usesRandom = true; + for (const importName of node.usedMathImports) this.usedMathImports.add(importName); + } + return true; + } + computeLayout(args) { + const align16 = value => Math.ceil(value / 16) * 16; + let offset = 0; + const arrays = {}; + const scalars = {}; + for (let i = 0; i < this.argumentTypes.length; i++) { + const name = this.argumentNames[i]; + const type = this.argumentTypes[i]; + if (type === "Array" || type === "Input") { + const dims = this.valueDimensions(args[i]); + const flatLength = dims[0] * dims[1] * dims[2]; + arrays[name] = { + index: i, + offset: offset, + dims: dims, + flatLength: flatLength + }; + offset = align16(offset + flatLength * 4); + } else { + scalars[name] = { + index: i, + offset: offset, + type: type + }; + offset = align16(offset + 4); + } + } + const constantArrays = {}; + if (this.constants) for (const name in this.constants) { + if (!this.constants.hasOwnProperty(name)) continue; + const type = this.constantTypes[name]; + if (type === "Array" || type === "Input") { + const dims = this.valueDimensions(this.constants[name]); + const flatLength = dims[0] * dims[1] * dims[2]; + constantArrays[name] = { + offset: offset, + dims: dims, + flatLength: flatLength + }; + offset = align16(offset + flatLength * 4); + } + } + return { + arrays: arrays, + scalars: scalars, + constantArrays: constantArrays, + outputOffset: offset + }; + } + valueDimensions(value) { + const dims = value instanceof Input ? Array.from(value.size) : Array.from(utils.getDimensions(value)); + while (dims.length < 3) dims.push(1); + return dims; + } + _computeSizeSignature(args) { + const parts = [ this.output.join("x") ]; + for (let i = 0; i < this.argumentTypes.length; i++) { + const type = this.argumentTypes[i]; + if (type === "Array" || type === "Input") parts.push(this.valueDimensions(args[i]).join("x")); + } + return parts.join("|"); + } + _threadable() { + if (this.asyncMode !== true || !WebAssemblyKernel.isThreadsSupported) return false; + const [tx, ty, tz] = this.threadDim; + return tx * ty * tz >= 4096; + } + _entryKey(args) { + return this._computeSizeSignature(args) + (this._threadable() ? "|shared" : ""); + } + _assembleModule(layout, cells, shared) { + const builder = new WasmModuleBuilder; + const totalBytes = layout.outputOffset + cells * this.componentCount * 4; + const initial = Math.ceil(totalBytes / PAGE_BYTES) + 16; + const maximum = Math.max(initial, 4096); + builder.addMemoryImport(initial, maximum, shared); + const mathImports = Array.from(this.usedMathImports).sort(); + for (const name of mathImports) { + const params = name === "pow" || name === "atan2" ? [ "f32", "f32" ] : [ "f32" ]; + builder.addFuncImport("math_" + name, params, [ "f32" ]); + } + const globals = { + threadX: builder.addGlobal("i32", true, 0), + threadY: builder.addGlobal("i32", true, 0), + threadZ: builder.addGlobal("i32", true, 0), + dataIndex: builder.addGlobal("i32", true, 0) + }; + if (this.usesRandom) { + globals.pcgState = builder.addGlobal("i32", true, 0); + this._emitPcgRandom(builder, globals.pcgState); + } + const assembler = { + module: builder, + layout: layout, + globals: globals + }; + for (let i = this.tracedFunctions.length - 1; i >= 0; i--) { + const name = this.tracedFunctions[i]; + if (name === "kernel") continue; + const node = this.functionBuilder.functionMap[name]; + if (!node) continue; + node.output = this.output; + node.emitFunction(assembler); + } + this.functionBuilder.functionMap["kernel"].output = this.output; + this.functionBuilder.functionMap["kernel"].emitFunction(assembler); + const [sizeX, sizeY] = this.threadDim; + const run = builder.addFunction("run", { + params: [ "i32", "i32", "i32" ], + locals: [ "i32" ] + }); + const cell = 3; + run.localGet(0).localSet(cell); + if (this.output.length === 1) { + run.i32Const(0).globalSet(globals.threadY); + run.i32Const(0).globalSet(globals.threadZ); + } else if (this.output.length === 2) run.i32Const(0).globalSet(globals.threadZ); + run.block(); + run.localGet(cell).localGet(1).i32GeS().brIf(0); + run.loop(); + run.localGet(cell).globalSet(globals.dataIndex); + if (this.output.length === 1) run.localGet(cell).globalSet(globals.threadX); else if (this.output.length === 2) { + run.localGet(cell).i32Const(sizeX).i32RemU().globalSet(globals.threadX); + run.localGet(cell).i32Const(sizeX).i32DivU().globalSet(globals.threadY); + } else { + run.localGet(cell).i32Const(sizeX).i32RemU().globalSet(globals.threadX); + run.localGet(cell).i32Const(sizeX).i32DivU().i32Const(sizeY).i32RemU().globalSet(globals.threadY); + run.localGet(cell).i32Const(sizeX * sizeY).i32DivU().globalSet(globals.threadZ); + } + if (this.usesRandom) run.localGet(2).localGet(cell).i32Const(-1640531527).i32Mul().i32Add().i32Const(747796405).i32Mul().i32Const(-1403630843).i32Add().globalSet(globals.pcgState); + run.call("kernel"); + run.localGet(cell).i32Const(1).i32Add().localSet(cell); + run.localGet(cell).localGet(1).i32LtS().brIf(0); + run.end(); + run.end(); + builder.exportFunction("run"); + if (WebAssemblyKernel.isSIMDSupported) { + if (this.usesRandom) { + globals.pcgStateV = builder.addGlobal("v128", true, 0); + this._emitPcgRandomVector(builder, globals.pcgStateV); + } + let helperInfo = null; + for (const name of this.tracedFunctions) { + if (name === "kernel") continue; + const node = this.functionBuilder.functionMap[name]; + if (!node) continue; + if (!helperInfo) helperInfo = { + readsThread: false, + usesRandom: false + }; + if (node.readsThread) helperInfo.readsThread = true; + if (node.usesRandom) helperInfo.usesRandom = true; + } + assembler.helperInfo = helperInfo; + this.functionBuilder.functionMap["kernel"].emitVectorFunction(assembler); + this._emitRunSimd(builder, globals); + builder.exportFunction("run_simd"); + } + return { + bytes: builder.toBytes(), + initial: initial, + maximum: maximum + }; + } + _emitRunSimd(builder, globals) { + const [sizeX, sizeY] = this.threadDim; + const run = builder.addFunction("run_simd", { + params: [ "i32", "i32", "i32" ], + locals: [ "i32" ] + }); + const cell = 3; + run.localGet(0).localSet(cell); + if (this.output.length === 1) { + run.i32Const(0).globalSet(globals.threadY); + run.i32Const(0).globalSet(globals.threadZ); + } else if (this.output.length === 2) run.i32Const(0).globalSet(globals.threadZ); + run.block(); + run.localGet(cell).localGet(1).i32GeS().brIf(0); + run.loop(); + run.localGet(cell).globalSet(globals.dataIndex); + if (this.output.length === 1) run.localGet(cell).globalSet(globals.threadX); else if (this.output.length === 2) { + run.localGet(cell).i32Const(sizeX).i32RemU().globalSet(globals.threadX); + run.localGet(cell).i32Const(sizeX).i32DivU().globalSet(globals.threadY); + } else { + run.localGet(cell).i32Const(sizeX).i32RemU().globalSet(globals.threadX); + run.localGet(cell).i32Const(sizeX).i32DivU().i32Const(sizeY).i32RemU().globalSet(globals.threadY); + run.localGet(cell).i32Const(sizeX * sizeY).i32DivU().globalSet(globals.threadZ); + } + if (this.usesRandom) { + run.localGet(cell).i32x4Splat().v128ConstI32x4(0, 1, 2, 3).i32x4Add(); + run.v128ConstI32x4(-1640531527, -1640531527, -1640531527, -1640531527).i32x4Mul(); + run.localGet(2).i32x4Splat().i32x4Add(); + run.v128ConstI32x4(747796405, 747796405, 747796405, 747796405).i32x4Mul(); + run.v128ConstI32x4(-1403630843, -1403630843, -1403630843, -1403630843).i32x4Add(); + run.globalSet(globals.pcgStateV); + } + run.call("kernel_simd"); + run.localGet(cell).i32Const(4).i32Add().localSet(cell); + run.localGet(cell).localGet(1).i32LtS().brIf(0); + run.end(); + run.end(); + } + _emitPcgRandomVector(builder, stateGlobal) { + const em = builder.addFunction("pcg_random_v", { + params: [ "v128" ], + results: [ "v128" ] + }); + const s = em.addLocal("v128"); + const w = em.addLocal("i32"); + em.globalGet(stateGlobal).v128ConstI32x4(747796405, 747796405, 747796405, 747796405).i32x4Mul().v128ConstI32x4(-1403630843, -1403630843, -1403630843, -1403630843).i32x4Add().globalGet(stateGlobal).localGet(0).v128Bitselect().globalSet(stateGlobal); + em.globalGet(stateGlobal).localSet(s); + em.localGet(s).i32x4ExtractLane(0).localSet(w); + em.localGet(w).localGet(w).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU().i32x4Splat(); + for (let lane = 1; lane < 4; lane++) { + em.localGet(s).i32x4ExtractLane(lane).localSet(w); + em.localGet(w).localGet(w).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU().i32x4ReplaceLane(lane); + } + em.localGet(s).v128Xor(); + em.v128ConstI32x4(277803737, 277803737, 277803737, 277803737).i32x4Mul(); + const wv = em.addLocal("v128"); + em.localTee(wv); + em.i32Const(22).i32x4ShrU().localGet(wv).v128Xor(); + em.i32Const(8).i32x4ShrU(); + em.f32x4ConvertI32x4U(); + em.v128ConstF32x4(16777216, 16777216, 16777216, 16777216).f32x4Div(); + } + _emitPcgRandom(builder, stateGlobal) { + const em = builder.addFunction("pcg_random", { + params: [], + results: [ "f32" ] + }); + const word = em.addLocal("i32"); + em.globalGet(stateGlobal).i32Const(747796405).i32Mul().i32Const(-1403630843).i32Add().globalSet(stateGlobal); + em.globalGet(stateGlobal).globalGet(stateGlobal).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU().globalGet(stateGlobal).i32Xor().i32Const(277803737).i32Mul().localTee(word); + em.i32Const(22).i32ShrU().localGet(word).i32Xor().i32Const(8).i32ShrU().f32ConvertI32U().f32Const(16777216).f32Div(); + } + _releaseEntry(entry) { + const scrub = () => { + entry.instance = null; + entry.module = null; + entry.memory = null; + entry.run = null; + entry.runSimd = null; + entry.f32 = null; + entry.i32 = null; + entry.bytes = null; + }; + if (entry.shared && this._pool) { + const pool = this._pool; + this._threadedTail.then(() => { + pool.release(entry.id); + scrub(); + }, scrub); + } else scrub(); + } + _instantiate(entryKey, args) { + let entry = this._moduleCache.get(entryKey); + if (entry) { + this._moduleCache.delete(entryKey); + this._moduleCache.set(entryKey, entry); + } + if (!entry) { + const shared = this._threadable(); + const layout = this.computeLayout(args); + const [tx, ty, tz] = this.threadDim; + const cells = tx * ty * tz; + const {bytes: bytes, initial: initial, maximum: maximum} = this._assembleModule(layout, cells, shared); + if (!WebAssembly.validate(bytes)) throw new Error("WebAssembly backend: generated module failed validation (internal error)"); + const memory = shared ? new WebAssembly.Memory({ + initial: initial, + maximum: maximum, + shared: true + }) : new WebAssembly.Memory({ + initial: initial, + maximum: maximum + }); + const imports = { + env: { + memory: memory + } + }; + for (const name of this.usedMathImports) imports.env["math_" + name] = Math[name]; + const module$1 = new WebAssembly.Module(bytes); + const instance = new WebAssembly.Instance(module$1, imports); + entry = { + id: nextEntryId++, + sizeSignature: entryKey, + shared: shared, + layout: layout, + cells: cells, + bytes: bytes, + module: module$1, + memory: memory, + mathImports: Array.from(this.usedMathImports).sort(), + sizeX: tx, + instance: instance, + run: instance.exports.run, + runSimd: instance.exports.run_simd || null, + f32: new Float32Array(memory.buffer), + i32: new Int32Array(memory.buffer) + }; + for (const name in layout.constantArrays) { + const record = layout.constantArrays[name]; + const value = this.constants[name]; + utils.flattenTo(value instanceof Input ? value.value : value, entry.f32.subarray(record.offset / 4, record.offset / 4 + record.flatLength)); + } + this._moduleCache.set(entryKey, entry); + while (this._moduleCache.size > Math.max(this.moduleCacheLimit, 1)) { + const oldestKey = this._moduleCache.keys().next().value; + const oldest = this._moduleCache.get(oldestKey); + this._moduleCache.delete(oldestKey); + this._releaseEntry(oldest); + } + } + this._active = entry; + } + checkArgumentTypes(args) { + super.checkArgumentTypes(args); + if (!this.argumentTypes) return; + const length = Math.min(args.length, this.argumentTypes.length); + for (let i = 0; i < length; i++) { + const value = args[i]; + if (!value || !value.type) continue; + switch (this.argumentTypes[i]) { + case "Array": + case "Input": + case "Number": + case "Float": + case "Integer": + case "Boolean": + this.switchKernels({ + type: "argumentTypeMismatch", + index: i, + needed: utils.getVariableType(value, this.strictIntegers) + }); + break; + } + } + } + run() { + if (!this.built) { + this.build.apply(this, arguments); + if (this.fallbackRequested) return null; + } + const threadDim = this.threadDim = Array.from(this.output); + while (threadDim.length < 3) threadDim.push(1); + const entryKey = this._entryKey(arguments); + if (!this._active || this._active.sizeSignature !== entryKey) { + const previous = this._active ? this._active.layout.arrays : {}; + for (const name in previous) { + const record = previous[name]; + const dims = this.valueDimensions(arguments[record.index]); + if (!this.dynamicArguments && (dims[0] !== record.dims[0] || dims[1] !== record.dims[1] || dims[2] !== record.dims[2])) throw new Error(`argument "${name}" changed size from [${record.dims.join(", ")}] to [${dims.join(", ")}]; use dynamicArguments: true for varying input sizes`); + } + this._instantiate(entryKey, arguments); + } + if (this._active.shared && this._threadable()) return this._runThreaded(arguments); + const {layout: layout, cells: cells, f32: f32, i32: i32, run: run, runSimd: runSimd} = this._active; + for (const name in layout.arrays) { + const record = layout.arrays[name]; + const value = arguments[record.index]; + utils.flattenTo(value instanceof Input ? value.value : value, f32.subarray(record.offset / 4, record.offset / 4 + record.flatLength)); + } + for (const name in layout.scalars) { + const record = layout.scalars[name]; + const value = arguments[record.index]; + if (record.type === "Integer") i32[record.offset / 4] = value | 0; else if (record.type === "Boolean") i32[record.offset / 4] = value ? 1 : 0; else f32[record.offset / 4] = value; + } + let seed = 0; + if (this.usesRandom) seed = this.randomSeed !== null ? this.randomSeed >>> 0 : Math.random() * 4294967296 >>> 0; + seed = seed | 0; + if (runSimd && cells > 0) { + const sizeX = threadDim[0]; + if ((sizeX & 3) === 0) { + runSimd(0, cells, seed); + this._lastRunPath = "simd"; + } else { + const quadSpan = sizeX & -4; + const rows = cells / sizeX; + for (let row = 0; row < rows; row++) { + const base = row * sizeX; + if (quadSpan > 0) runSimd(base, base + quadSpan, seed); + run(base + quadSpan, base + sizeX, seed); + } + this._lastRunPath = quadSpan > 0 ? "simd+scalar-tail" : "scalar"; + } + } else { + run(0, cells, seed); + this._lastRunPath = "scalar"; + } + const base = layout.outputOffset / 4; + const data = f32.slice(base, base + cells * this.componentCount); + return this._shapeOutput(data, Array.from(this.output), this.componentCount); + } + _runThreaded(args) { + const entry = this._active; + const {layout: layout, cells: cells} = entry; + const staged = []; + for (const name in layout.arrays) { + const record = layout.arrays[name]; + const value = args[record.index]; + const flat = new Float32Array(record.flatLength); + utils.flattenTo(value instanceof Input ? value.value : value, flat); + staged.push({ + record: record, + flat: flat + }); + } + const scalarValues = []; + for (const name in layout.scalars) { + const record = layout.scalars[name]; + scalarValues.push({ + record: record, + value: args[record.index] + }); + } + let seed = 0; + if (this.usesRandom) seed = this.randomSeed !== null ? this.randomSeed >>> 0 : Math.random() * 4294967296 >>> 0; + seed = seed | 0; + if (!this._pool) this._pool = new WebAssemblyWorkerPool(this.poolSize || void 0); + const pool = this._pool; + const componentCount = this.componentCount; + const output = Array.from(this.output); + const result = this._threadedTail.then(() => { + if (!entry.f32) throw new Error("WebAssembly kernel was destroyed"); + for (let i = 0; i < staged.length; i++) entry.f32.set(staged[i].flat, staged[i].record.offset / 4); + for (let i = 0; i < scalarValues.length; i++) { + const {record: record, value: value} = scalarValues[i]; + if (record.type === "Integer") entry.i32[record.offset / 4] = value | 0; else if (record.type === "Boolean") entry.i32[record.offset / 4] = value ? 1 : 0; else entry.f32[record.offset / 4] = value; + } + const workerCount = Math.min(pool.size, Math.ceil(cells / 4096)); + let chunk = Math.ceil(cells / workerCount) & -4; + if (chunk < 4) chunk = 4; + const tasks = []; + for (let i = 0; i < workerCount; i++) { + const start = i * chunk; + if (start >= cells) break; + tasks.push({ + start: start, + end: i === workerCount - 1 ? cells : Math.min(start + chunk, cells), + seed: seed + }); + } + this._lastRunPath = "threaded"; + return pool.dispatch(entry, tasks).then(() => { + if (!entry.f32) throw new Error("WebAssembly kernel was destroyed"); + const base = layout.outputOffset / 4; + const data = entry.f32.slice(base, base + cells * componentCount); + return this._shapeOutput(data, output, componentCount); + }); + }); + this._threadedTail = result.then(() => void 0, () => void 0); + return result; + } + _shapeOutput(data, output, componentCount) { + const [width, height, depth] = [ output[0], output[1] || 1, output[2] || 1 ]; + if (componentCount === 1) switch (output.length) { + case 1: + return utils.erectMemoryOptimizedFloat(data, width); + + case 2: + return utils.erectMemoryOptimized2DFloat(data, width, height); + + default: + return utils.erectMemoryOptimized3DFloat(data, width, height, depth); + } + const n = componentCount; + const erectRow = offset => { + const row = new Array(width); + for (let x = 0; x < width; x++) row[x] = data.subarray(offset + x * n, offset + x * n + n); + return row; + }; + switch (output.length) { + case 1: + return erectRow(0); + + case 2: + { + const rows = new Array(height); + for (let y = 0; y < height; y++) rows[y] = erectRow(y * width * n); + return rows; + } + + default: + { + const layers = new Array(depth); + for (let z = 0; z < depth; z++) { + const rows = new Array(height); + for (let y = 0; y < height; y++) rows[y] = erectRow((z * height + y) * width * n); + layers[z] = rows; + } + return layers; + } + } + } + destroy(removeCanvasReferences) { + if (this._pool) { + this._pool.destroy(); + this._pool = null; + } + this._threadedTail = Promise.resolve(); + for (const entry of this._moduleCache.values()) { + entry.shared = false; + this._releaseEntry(entry); + } + this._moduleCache = new Map; + this._active = null; + this.built = false; + if (this.gpu && this.gpu.kernels) { + const index = this.gpu.kernels.indexOf(this); + if (index !== -1) this.gpu.kernels.splice(index, 1); + } + } + } + }; + }); + var require_kernel_run_shortcut = __commonJSMin((exports, module) => { + const {utils: utils} = require_utils(); + const {Input: Input} = require_input(); + function kernelRunShortcut(kernel) { + const MAX_SWITCHES = 4; + function syncBody(args) { + kernel.build.apply(kernel, args); + kernel.checkArgumentTypes(args); + let result = kernel.switchingKernels ? void 0 : kernel.run.apply(kernel, args); + for (let i = 0; kernel.switchingKernels; i++) { + if (i >= MAX_SWITCHES) { + const reasons = kernel.resetSwitchingKernels(); + throw new Error(`this kernel cannot run the arguments it was given (${describeReasons(reasons)}); it did not settle on a kernel for them after ${MAX_SWITCHES} attempts. Create a separate kernel for this call's argument types.`); + } + const reasons = kernel.resetSwitchingKernels(); + const newKernel = kernel.onRequestSwitchKernel(reasons, args, kernel); + shortcut.kernel = kernel = newKernel; + newKernel.checkArgumentTypes(args); + result = newKernel.switchingKernels ? void 0 : newKernel.run.apply(newKernel, args); + if (newKernel.fallbackRequested) result = kernel.run.apply(kernel, args); + } + return result; + } + function describeReasons(reasons) { + if (!reasons || !reasons.length) return "unknown reason"; + return reasons.map(reason => { + if (reason.type === "argumentTypeMismatch") return `argument ${reason.index} is now ${reason.needed}`; + return reason.type; + }).join(", "); + } + function syncRun(args) { + const result = syncBody(args); + if (kernel.renderKernels) return kernel.renderKernels(); else if (kernel.renderOutput) return kernel.renderOutput(); else return result; + } + function asyncRun(args) { + if (kernel.onAsyncModeUpgrade) { + const upgrade = kernel.onAsyncModeUpgrade; + kernel.onAsyncModeUpgrade = null; + const snapped = snapshotArguments(args); + return upgrade(snapped, kernel).then(upgradedKernel => { + if (upgradedKernel) shortcut.replaceKernel(upgradedKernel); + return asyncRun(snapped); + }); + } + try { + if (kernel.constructor.isAsync === true) { + kernel.build.apply(kernel, args); + return Promise.resolve(kernel.run.apply(kernel, args)); + } + for (let i = 0; i < args.length; i++) if (isWebGPUHandle(args[i])) return resolveHandles(args).then(resolved => asyncRun(resolved)); + const result = syncBody(args); + if (kernel.renderKernels) return Promise.resolve(kernel.renderKernels()); else if (kernel.renderOutput) { + if (kernel.renderOutputAsync) return kernel.renderOutputAsync(); + return Promise.resolve(kernel.renderOutput()); + } else return Promise.resolve(result); + } catch (e) { + return Promise.reject(e); + } + } + function isWebGPUHandle(value) { + return Boolean(value) && value.type === "WebGPUBuffer"; + } + function resolveHandles(args) { + const snapped = snapshotArguments(args); + const pending = []; + for (let i = 0; i < snapped.length; i++) if (isWebGPUHandle(snapped[i])) { + const index = i; + pending.push(Promise.resolve(snapped[index].toArray()).then(value => { + snapped[index] = value; + })); + } + return Promise.all(pending).then(() => snapped); + } + function snapshotArguments(args) { + const copy = new Array(args.length); + for (let i = 0; i < args.length; i++) copy[i] = snapshotValue(args[i]); + return copy; + } + function snapshotValue(value) { + if (!value || typeof value !== "object") return value; + if (isWebGPUHandle(value) || typeof value.delete === "function") return value; + if (ArrayBuffer.isView(value)) return value.slice(0); + if (Array.isArray(value)) return value.map(snapshotValue); + if (value instanceof Input) return new Input(snapshotValue(value.value), value.size); + return value; + } + function run() { + if (kernel.constructor.isAsync === true || kernel.asyncMode === true) return asyncRun(arguments); + return syncRun(arguments); + } + const shortcut = function() { + return run.apply(kernel, arguments); + }; + shortcut.exec = function() { + return new Promise((accept, reject) => { + try { + accept(run.apply(this, arguments)); + } catch (e) { + reject(e); + } + }); + }; + shortcut.replaceKernel = function(replacementKernel) { + kernel = replacementKernel; + bindKernelToShortcut(kernel, shortcut); + }; + bindKernelToShortcut(kernel, shortcut); + return shortcut; + } + function bindKernelToShortcut(kernel, shortcut) { + if (shortcut.kernel) { + shortcut.kernel = kernel; + return; + } + const properties = utils.allPropertiesOf(kernel); + for (let i = 0; i < properties.length; i++) { + const property = properties[i]; + if (property[0] === "_" && property[1] === "_") continue; + if (typeof kernel[property] === "function") if (property.substring(0, 3) === "add" || property.substring(0, 3) === "set") shortcut[property] = function() { + shortcut.kernel[property].apply(shortcut.kernel, arguments); + return shortcut; + }; else shortcut[property] = function() { + return shortcut.kernel[property].apply(shortcut.kernel, arguments); + }; else { + shortcut.__defineGetter__(property, () => shortcut.kernel[property]); + shortcut.__defineSetter__(property, value => { + shortcut.kernel[property] = value; + }); + } + } + shortcut.kernel = kernel; + } + module.exports = { + kernelRunShortcut: kernelRunShortcut + }; + }); + var require_gpu = __commonJSMin((exports, module) => { + const {gpuMock: gpuMock} = require_gpu_mock_js(); + const {utils: utils} = require_utils(); + const {Kernel: Kernel} = require_kernel$7(); + const {CPUKernel: CPUKernel} = require_kernel$6(); + const {HeadlessGLKernel: HeadlessGLKernel} = require_kernel$3(); + const {WebGL2Kernel: WebGL2Kernel} = require_kernel$2(); + const {WebGLKernel: WebGLKernel} = require_kernel$4(); + const {WebGPUKernel: WebGPUKernel} = require_kernel$1(); + const {WebAssemblyKernel: WebAssemblyKernel} = require_kernel(); + const {kernelRunShortcut: kernelRunShortcut} = require_kernel_run_shortcut(); + const kernelOrder = [ HeadlessGLKernel, WebGL2Kernel, WebGLKernel, WebAssemblyKernel ]; + const kernelTypes = [ "gpu", "cpu" ]; + const internalKernels = { + headlessgl: HeadlessGLKernel, + webgl2: WebGL2Kernel, + webgl: WebGLKernel, + webgpu: WebGPUKernel, + webasm: WebAssemblyKernel + }; + let validate = true; + var GPU = class GPU { + static disableValidation() { + validate = false; + } + static enableValidation() { + validate = true; + } + static get isGPUSupported() { + return kernelOrder.some(Kernel => Kernel.isSupported); + } + static get isKernelMapSupported() { + return kernelOrder.some(Kernel => Kernel.isSupported && Kernel.features.kernelMap); + } + static get isOffscreenCanvasSupported() { + return typeof Worker !== "undefined" && typeof OffscreenCanvas !== "undefined" || typeof importScripts !== "undefined"; + } + static get isWebGLSupported() { + return WebGLKernel.isSupported; + } + static get isWebGL2Supported() { + return WebGL2Kernel.isSupported; + } + static get isHeadlessGLSupported() { + return HeadlessGLKernel.isSupported; + } + static get isWebGPUSupported() { + return WebGPUKernel.isSupported; + } + static isWebGPUAvailable() { + if (!WebGPUKernel.isSupported) return Promise.resolve(false); + return navigator.gpu.requestAdapter().then(adapter => adapter !== null, () => false); + } + static get isWebAssemblySupported() { + return WebAssemblyKernel.isSupported; + } + static get isCanvasSupported() { + return typeof HTMLCanvasElement !== "undefined"; + } + static get isGPUHTMLImageArraySupported() { + return WebGL2Kernel.isSupported; + } + static get isSinglePrecisionSupported() { + return kernelOrder.some(Kernel => Kernel.isSupported && Kernel.features.isFloatRead && Kernel.features.isTextureFloat); + } + constructor(settings) { + settings = settings || {}; + this.canvas = settings.canvas || null; + this.context = settings.context || null; + this.mode = settings.mode; + this.Kernel = null; this._webGPUDecision = null; if (settings.mode === "async") if (WebGPUKernel.isSupported) GPU.isWebGPUAvailable().then(available => { this._webGPUDecision = available; @@ -18083,8 +23456,9 @@ const switchableKernels = {}; const settingsCopy = upgradeDeprecatedCreateKernelSettings(settings) || {}; if (settings && typeof settings.argumentTypes === "object") settingsCopy.argumentTypes = Object.keys(settings.argumentTypes).map(argumentName => settings.argumentTypes[argumentName]); + const gpuInstance = this; function onRequestFallback(args) { - console.warn("Falling back to CPU"); + console.warn(`Falling back to CPU${kernelRun.fallbackReason ? `: ${kernelRun.fallbackReason}` : ""}`); const fallbackKernel = new CPUKernel(source, { argumentTypes: kernelRun.argumentTypes, constantTypes: kernelRun.constantTypes, @@ -18106,11 +23480,17 @@ strictIntegers: kernelRun.strictIntegers, randomSeed: kernelRun.randomSeed, debug: kernelRun.debug, - asyncMode: kernelRun.asyncMode + asyncMode: kernelRun.asyncMode, + onRequestFallback: onRequestFallback, + onRequestSwitchKernel: onRequestSwitchKernel, + canvas: kernelRun.graphical && !kernelRun.context ? kernelRun.canvas : null }); + fallbackKernel.fallbackReason = kernelRun.fallbackReason; fallbackKernel.build.apply(fallbackKernel, args); const result = fallbackKernel.run.apply(fallbackKernel, args); kernelRun.replaceKernel(fallbackKernel); + if (!gpuInstance.canvas && fallbackKernel.canvas) gpuInstance.canvas = fallbackKernel.canvas; + if (!gpuInstance.context && fallbackKernel.context) gpuInstance.context = fallbackKernel.context; return result; } function onRequestSwitchKernel(reasons, args, _kernel) { @@ -18264,7 +23644,7 @@ if (this.mode !== "dev") { if (!this.Kernel.isSupported || !this.Kernel.features.kernelMap) { if (this.Kernel.mode === "webgpu") throw new Error("WebGPU backend does not yet support createKernelMap"); - if (this.mode && kernelTypes.indexOf(this.mode) < 0) throw new Error(`kernelMap not supported on ${this.Kernel.name}`); + if (this.mode && kernelTypes.indexOf(this.mode) < 0 && this.Kernel.mode !== "webasm") throw new Error(`kernelMap not supported on ${this.Kernel.name}`); } } const settingsCopy = upgradeDeprecatedCreateKernelSettings(settings); @@ -18404,22 +23784,24 @@ const {Input: Input, input: input} = require_input(); const {Texture: Texture} = require_texture$1(); const {FunctionBuilder: FunctionBuilder} = require_function_builder(); - const {FunctionNode: FunctionNode} = require_function_node$4(); - const {CPUFunctionNode: CPUFunctionNode} = require_function_node$3(); - const {CPUKernel: CPUKernel} = require_kernel$5(); - const {HeadlessGLKernel: HeadlessGLKernel} = require_kernel$2(); - const {WebGLFunctionNode: WebGLFunctionNode} = require_function_node$2(); - const {WebGLKernel: WebGLKernel} = require_kernel$3(); + const {FunctionNode: FunctionNode} = require_function_node$5(); + const {CPUFunctionNode: CPUFunctionNode} = require_function_node$4(); + const {CPUKernel: CPUKernel} = require_kernel$6(); + const {HeadlessGLKernel: HeadlessGLKernel} = require_kernel$3(); + const {WebGLFunctionNode: WebGLFunctionNode} = require_function_node$3(); + const {WebGLKernel: WebGLKernel} = require_kernel$4(); const {kernelValueMaps: webGLKernelValueMaps} = require_kernel_value_maps$1(); - const {WebGL2FunctionNode: WebGL2FunctionNode} = require_function_node$1(); - const {WebGL2Kernel: WebGL2Kernel} = require_kernel$1(); + const {WebGL2FunctionNode: WebGL2FunctionNode} = require_function_node$2(); + const {WebGL2Kernel: WebGL2Kernel} = require_kernel$2(); const {kernelValueMaps: webGL2KernelValueMaps} = require_kernel_value_maps(); - const {WGSLFunctionNode: WGSLFunctionNode} = require_function_node(); - const {WebGPUKernel: WebGPUKernel} = require_kernel(); + const {WGSLFunctionNode: WGSLFunctionNode} = require_function_node$1(); + const {WebGPUKernel: WebGPUKernel} = require_kernel$1(); const {WebGPUContext: WebGPUContext} = require_context(); const {WebGPUBufferResult: WebGPUBufferResult} = require_buffer_result(); - const {GLKernel: GLKernel} = require_kernel$4(); - const {Kernel: Kernel} = require_kernel$6(); + const {WebAssemblyFunctionNode: WebAssemblyFunctionNode} = require_function_node(); + const {WebAssemblyKernel: WebAssemblyKernel} = require_kernel(); + const {GLKernel: GLKernel} = require_kernel$5(); + const {Kernel: Kernel} = require_kernel$7(); const {FunctionTracer: FunctionTracer} = require_function_tracer(); module.exports = { alias: alias, @@ -18443,6 +23825,8 @@ WebGPUKernel: WebGPUKernel, WebGPUContext: WebGPUContext, WebGPUBufferResult: WebGPUBufferResult, + WebAssemblyFunctionNode: WebAssemblyFunctionNode, + WebAssemblyKernel: WebAssemblyKernel, GLKernel: GLKernel, Kernel: Kernel, FunctionTracer: FunctionTracer, diff --git a/dist/gpu-browser.min.js b/dist/gpu-browser.min.js index f5fec9f8..de6bf05b 100644 --- a/dist/gpu-browser.min.js +++ b/dist/gpu-browser.min.js @@ -5,11 +5,11 @@ * GPU Accelerated JavaScript * * @version 2.21.0 - * @date Mon Aug 03 2026 01:03:16 GMT+0800 (Singapore Standard Time) + * @date Mon Aug 03 2026 09:01:53 GMT+0800 (Singapore Standard Time) * * @license MIT * The MIT License * * Copyright (c) 2026 gpu.js Team */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):(e="undefined"!=typeof globalThis?globalThis:e||self).GPU=t()}(this,function(){var e=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),t=e((e,t)=>{function r(e){const t=new Array(e.length);for(let r=0;r{e.output=h(t),e.graphical&&u(e)},e.toJSON=()=>{throw new Error("Not usable with gpuMock")},e.setConstants=t=>(e.constants=t,e),e.setGraphical=t=>(e.graphical=t,e),e.setCanvas=t=>(e.canvas=t,e),e.setContext=t=>(e.context=t,e),e.destroy=()=>{},e.validateSettings=()=>{},e.graphical&&e.output&&u(e),e.exec=function(){return new Promise((t,r)=>{try{t(e.apply(e,arguments))}catch(e){r(e)}})},e.getPixels=t=>{const{x:r,y:n}=e.output;return t?function(e,t,r){const n=r/2|0,s=4*t,i=new Uint8ClampedArray(4*t),a=e.slice(0);for(let e=0;ee,r=["setWarnVarUsage","setArgumentTypes","setTactic","setOptimizeFloatMemory","setDebug","setLoopMaxIterations","setConstantTypes","setFunctions","setNativeFunctions","setInjectedNative","setPipeline","setPrecision","setOutputToTexture","setImmutable","setStrictIntegers","setDynamicOutput","setHardcodeConstants","setDynamicArguments","setUseLegacyEncoder","setWarnVarUsage","addSubKernel"];for(let n=0;n{var r,n;r=e,n=function(e){"use strict";var t=[509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,574,3,9,9,7,9,32,4,318,1,80,3,71,10,50,3,123,2,54,14,32,10,3,1,11,3,46,10,8,0,46,9,7,2,37,13,2,9,6,1,45,0,13,2,49,13,9,3,2,11,83,11,7,0,3,0,158,11,6,9,7,3,56,1,2,6,3,1,3,2,10,0,11,1,3,6,4,4,68,8,2,0,3,0,2,3,2,4,2,0,15,1,83,17,10,9,5,0,82,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,7,19,58,14,5,9,243,14,166,9,71,5,2,1,3,3,2,0,2,1,13,9,120,6,3,6,4,0,29,9,41,6,2,3,9,0,10,10,47,15,343,9,54,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,49,4,2,1,2,4,9,9,330,3,10,1,2,0,49,6,4,4,14,10,5350,0,7,14,11465,27,2343,9,87,9,39,4,60,6,26,9,535,9,470,0,2,54,8,3,82,0,12,1,19628,1,4178,9,519,45,3,22,543,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,101,0,161,6,10,9,357,0,62,13,499,13,245,1,2,9,726,6,110,6,6,9,4759,9,787719,239],r=[0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,13,10,2,14,2,6,2,1,2,10,2,14,2,6,2,1,4,51,13,310,10,21,11,7,25,5,2,41,2,8,70,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,28,43,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,14,35,39,27,10,22,251,41,7,1,17,2,60,28,11,0,9,21,43,17,47,20,28,22,13,52,58,1,3,0,14,44,33,24,27,35,30,0,3,0,9,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,20,1,64,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,31,9,2,0,3,0,2,37,2,0,26,0,2,0,45,52,19,3,21,2,31,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,14,0,72,26,38,6,186,43,117,63,32,7,3,0,3,7,2,1,2,23,16,0,2,0,95,7,3,38,17,0,2,0,29,0,11,39,8,0,22,0,12,45,20,0,19,72,200,32,32,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,26,5,2,1,2,31,15,0,328,18,16,0,2,12,2,33,125,0,80,921,103,110,18,195,2637,96,16,1071,18,5,26,3994,6,582,6842,29,1763,568,8,30,18,78,18,29,19,47,17,3,32,20,6,18,433,44,212,63,129,74,6,0,67,12,65,1,2,0,29,6135,9,1237,42,9,8936,3,2,6,2,1,2,290,16,0,30,2,3,0,15,3,9,395,2309,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,1845,30,7,5,262,61,147,44,11,6,17,0,322,29,19,43,485,27,229,29,3,0,496,6,2,3,2,1,2,14,2,196,60,67,8,0,1205,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42719,33,4153,7,221,3,5761,15,7472,16,621,2467,541,1507,4938,6,4191],n="\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u0870-\u0887\u0889-\u088e\u08a0-\u08c9\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c5d\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cdd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d04-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e86-\u0e8a\u0e8c-\u0ea3\u0ea5\u0ea7-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u1711\u171f-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4c\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c8a\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1cfa\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31bf\u31f0-\u31ff\u3400-\u4dbf\u4e00-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7cd\ua7d0\ua7d1\ua7d3\ua7d5-\ua7dc\ua7f2-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab69\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc",s={3:"abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile",5:"class enum extends super const export import",6:"enum",strict:"implements interface let package private protected public static yield",strictBind:"eval arguments"},i="break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this",a={5:i,"5module":i+" export import",6:i+" const class extends export import super"},o=/^in(stanceof)?$/,u=new RegExp("["+n+"]"),h=new RegExp("["+n+"\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u0897-\u089f\u08ca-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b55-\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3c\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0cf3\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d81-\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0ebc\u0ec8-\u0ece\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1715\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u180f-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1abf-\u1ace\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf4\u1cf7-\u1cf9\u1dc0-\u1dff\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\u30fb\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua82c\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f\uff65]");function l(e,t){for(var r=65536,n=0;ne)return!1;if((r+=t[n+1])>=e)return!0}return!1}function c(e,t){return e<65?36===e:e<91||(e<97?95===e:e<123||(e<=65535?e>=170&&u.test(String.fromCharCode(e)):!1!==t&&l(e,r)))}function p(e,n){return e<48?36===e:e<58||!(e<65)&&(e<91||(e<97?95===e:e<123||(e<=65535?e>=170&&h.test(String.fromCharCode(e)):!1!==n&&(l(e,r)||l(e,t)))))}var d=function(e,t){void 0===t&&(t={}),this.label=e,this.keyword=t.keyword,this.beforeExpr=!!t.beforeExpr,this.startsExpr=!!t.startsExpr,this.isLoop=!!t.isLoop,this.isAssign=!!t.isAssign,this.prefix=!!t.prefix,this.postfix=!!t.postfix,this.binop=t.binop||null,this.updateContext=null};function f(e,t){return new d(e,{beforeExpr:!0,binop:t})}var m={beforeExpr:!0},g={startsExpr:!0},x={};function y(e,t){return void 0===t&&(t={}),t.keyword=e,x[e]=new d(e,t)}var b={num:new d("num",g),regexp:new d("regexp",g),string:new d("string",g),name:new d("name",g),privateId:new d("privateId",g),eof:new d("eof"),bracketL:new d("[",{beforeExpr:!0,startsExpr:!0}),bracketR:new d("]"),braceL:new d("{",{beforeExpr:!0,startsExpr:!0}),braceR:new d("}"),parenL:new d("(",{beforeExpr:!0,startsExpr:!0}),parenR:new d(")"),comma:new d(",",m),semi:new d(";",m),colon:new d(":",m),dot:new d("."),question:new d("?",m),questionDot:new d("?."),arrow:new d("=>",m),template:new d("template"),invalidTemplate:new d("invalidTemplate"),ellipsis:new d("...",m),backQuote:new d("`",g),dollarBraceL:new d("${",{beforeExpr:!0,startsExpr:!0}),eq:new d("=",{beforeExpr:!0,isAssign:!0}),assign:new d("_=",{beforeExpr:!0,isAssign:!0}),incDec:new d("++/--",{prefix:!0,postfix:!0,startsExpr:!0}),prefix:new d("!/~",{beforeExpr:!0,prefix:!0,startsExpr:!0}),logicalOR:f("||",1),logicalAND:f("&&",2),bitwiseOR:f("|",3),bitwiseXOR:f("^",4),bitwiseAND:f("&",5),equality:f("==/!=/===/!==",6),relational:f("/<=/>=",7),bitShift:f("<>/>>>",8),plusMin:new d("+/-",{beforeExpr:!0,binop:9,prefix:!0,startsExpr:!0}),modulo:f("%",10),star:f("*",10),slash:f("/",10),starstar:new d("**",{beforeExpr:!0}),coalesce:f("??",1),_break:y("break"),_case:y("case",m),_catch:y("catch"),_continue:y("continue"),_debugger:y("debugger"),_default:y("default",m),_do:y("do",{isLoop:!0,beforeExpr:!0}),_else:y("else",m),_finally:y("finally"),_for:y("for",{isLoop:!0}),_function:y("function",g),_if:y("if"),_return:y("return",m),_switch:y("switch"),_throw:y("throw",m),_try:y("try"),_var:y("var"),_const:y("const"),_while:y("while",{isLoop:!0}),_with:y("with"),_new:y("new",{beforeExpr:!0,startsExpr:!0}),_this:y("this",g),_super:y("super",g),_class:y("class",g),_extends:y("extends",m),_export:y("export"),_import:y("import",g),_null:y("null",g),_true:y("true",g),_false:y("false",g),_in:y("in",{beforeExpr:!0,binop:7}),_instanceof:y("instanceof",{beforeExpr:!0,binop:7}),_typeof:y("typeof",{beforeExpr:!0,prefix:!0,startsExpr:!0}),_void:y("void",{beforeExpr:!0,prefix:!0,startsExpr:!0}),_delete:y("delete",{beforeExpr:!0,prefix:!0,startsExpr:!0})},T=/\r\n?|\n|\u2028|\u2029/,S=new RegExp(T.source,"g");function v(e){return 10===e||13===e||8232===e||8233===e}function A(e,t,r){void 0===r&&(r=e.length);for(var n=t;n>10),56320+(1023&e)))}var R=/(?:[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/,N=function(e,t){this.line=e,this.column=t};N.prototype.offset=function(e){return new N(this.line,this.column+e)};var V=function(e,t,r){this.start=t,this.end=r,null!==e.sourceFile&&(this.source=e.sourceFile)};function M(e,t){for(var r=1,n=0;;){var s=A(e,n,t);if(s<0)return new N(r,t-n);++r,n=s}}var O={ecmaVersion:null,sourceType:"script",onInsertedSemicolon:null,onTrailingComma:null,allowReserved:null,allowReturnOutsideFunction:!1,allowImportExportEverywhere:!1,allowAwaitOutsideFunction:null,allowSuperOutsideMethod:null,allowHashBang:!1,checkPrivateFields:!0,locations:!1,onToken:null,onComment:null,ranges:!1,program:null,sourceFile:null,directSourceFile:null,preserveParens:!1},P=!1;function G(e){var t={};for(var r in O)t[r]=e&&D(e,r)?e[r]:O[r];if("latest"===t.ecmaVersion?t.ecmaVersion=1e8:null==t.ecmaVersion?(!P&&"object"==typeof console&&console.warn&&(P=!0,console.warn("Since Acorn 8.0.0, options.ecmaVersion is required.\nDefaulting to 2020, but this will stop working in the future.")),t.ecmaVersion=11):t.ecmaVersion>=2015&&(t.ecmaVersion-=2009),null==t.allowReserved&&(t.allowReserved=t.ecmaVersion<5),e&&null!=e.allowHashBang||(t.allowHashBang=t.ecmaVersion>=14),C(t.onToken)){var n=t.onToken;t.onToken=function(e){return n.push(e)}}return C(t.onComment)&&(t.onComment=function(e,t){return function(r,n,s,i,a,o){var u={type:r?"Block":"Line",value:n,start:s,end:i};e.locations&&(u.loc=new V(this,a,o)),e.ranges&&(u.range=[s,i]),t.push(u)}}(t,t.onComment)),t}var z=256;function U(e,t){return 2|(e?4:0)|(t?8:0)}var K=function(e,t,r){this.options=e=G(e),this.sourceFile=e.sourceFile,this.keywords=$(a[e.ecmaVersion>=6?6:"module"===e.sourceType?"5module":5]);var n="";!0!==e.allowReserved&&(n=s[e.ecmaVersion>=6?6:5===e.ecmaVersion?5:3],"module"===e.sourceType&&(n+=" await")),this.reservedWords=$(n);var i=(n?n+" ":"")+s.strict;this.reservedWordsStrict=$(i),this.reservedWordsStrictBind=$(i+" "+s.strictBind),this.input=String(t),this.containsEsc=!1,r?(this.pos=r,this.lineStart=this.input.lastIndexOf("\n",r-1)+1,this.curLine=this.input.slice(0,this.lineStart).split(T).length):(this.pos=this.lineStart=0,this.curLine=1),this.type=b.eof,this.value=null,this.start=this.end=this.pos,this.startLoc=this.endLoc=this.curPosition(),this.lastTokEndLoc=this.lastTokStartLoc=null,this.lastTokStart=this.lastTokEnd=this.pos,this.context=this.initialContext(),this.exprAllowed=!0,this.inModule="module"===e.sourceType,this.strict=this.inModule||this.strictDirective(this.pos),this.potentialArrowAt=-1,this.potentialArrowInForAwait=!1,this.yieldPos=this.awaitPos=this.awaitIdentPos=0,this.labels=[],this.undefinedExports=Object.create(null),0===this.pos&&e.allowHashBang&&"#!"===this.input.slice(0,2)&&this.skipLineComment(2),this.scopeStack=[],this.enterScope(1),this.regexpState=null,this.privateNameStack=[]},B={inFunction:{configurable:!0},inGenerator:{configurable:!0},inAsync:{configurable:!0},canAwait:{configurable:!0},allowSuper:{configurable:!0},allowDirectSuper:{configurable:!0},treatFunctionsAsVar:{configurable:!0},allowNewDotTarget:{configurable:!0},inClassStaticBlock:{configurable:!0}};K.prototype.parse=function(){var e=this.options.program||this.startNode();return this.nextToken(),this.parseTopLevel(e)},B.inFunction.get=function(){return(2&this.currentVarScope().flags)>0},B.inGenerator.get=function(){return(8&this.currentVarScope().flags)>0&&!this.currentVarScope().inClassFieldInit},B.inAsync.get=function(){return(4&this.currentVarScope().flags)>0&&!this.currentVarScope().inClassFieldInit},B.canAwait.get=function(){for(var e=this.scopeStack.length-1;e>=0;e--){var t=this.scopeStack[e];if(t.inClassFieldInit||t.flags&z)return!1;if(2&t.flags)return(4&t.flags)>0}return this.inModule&&this.options.ecmaVersion>=13||this.options.allowAwaitOutsideFunction},B.allowSuper.get=function(){var e=this.currentThisScope(),t=e.flags,r=e.inClassFieldInit;return(64&t)>0||r||this.options.allowSuperOutsideMethod},B.allowDirectSuper.get=function(){return(128&this.currentThisScope().flags)>0},B.treatFunctionsAsVar.get=function(){return this.treatFunctionsAsVarInScope(this.currentScope())},B.allowNewDotTarget.get=function(){var e=this.currentThisScope(),t=e.flags,r=e.inClassFieldInit;return(258&t)>0||r},B.inClassStaticBlock.get=function(){return(this.currentVarScope().flags&z)>0},K.extend=function(){for(var e=[],t=arguments.length;t--;)e[t]=arguments[t];for(var r=this,n=0;n=,?^&]/.test(s)||"!"===s&&"="===this.input.charAt(n+1))}e+=t[0].length,w.lastIndex=e,e+=w.exec(this.input)[0].length,";"===this.input[e]&&e++}},W.eat=function(e){return this.type===e&&(this.next(),!0)},W.isContextual=function(e){return this.type===b.name&&this.value===e&&!this.containsEsc},W.eatContextual=function(e){return!!this.isContextual(e)&&(this.next(),!0)},W.expectContextual=function(e){this.eatContextual(e)||this.unexpected()},W.canInsertSemicolon=function(){return this.type===b.eof||this.type===b.braceR||T.test(this.input.slice(this.lastTokEnd,this.start))},W.insertSemicolon=function(){if(this.canInsertSemicolon())return this.options.onInsertedSemicolon&&this.options.onInsertedSemicolon(this.lastTokEnd,this.lastTokEndLoc),!0},W.semicolon=function(){this.eat(b.semi)||this.insertSemicolon()||this.unexpected()},W.afterTrailingComma=function(e,t){if(this.type===e)return this.options.onTrailingComma&&this.options.onTrailingComma(this.lastTokStart,this.lastTokStartLoc),t||this.next(),!0},W.expect=function(e){this.eat(e)||this.unexpected()},W.unexpected=function(e){this.raise(null!=e?e:this.start,"Unexpected token")};var H=function(){this.shorthandAssign=this.trailingComma=this.parenthesizedAssign=this.parenthesizedBind=this.doubleProto=-1};W.checkPatternErrors=function(e,t){if(e){e.trailingComma>-1&&this.raiseRecoverable(e.trailingComma,"Comma is not permitted after the rest element");var r=t?e.parenthesizedAssign:e.parenthesizedBind;r>-1&&this.raiseRecoverable(r,t?"Assigning to rvalue":"Parenthesized pattern")}},W.checkExpressionErrors=function(e,t){if(!e)return!1;var r=e.shorthandAssign,n=e.doubleProto;if(!t)return r>=0||n>=0;r>=0&&this.raise(r,"Shorthand property assignments are valid only in destructuring patterns"),n>=0&&this.raiseRecoverable(n,"Redefinition of __proto__ property")},W.checkYieldAwaitInDefaultParams=function(){this.yieldPos&&(!this.awaitPos||this.yieldPos55295&&n<56320)return!0;if(c(n,!0)){for(var s=r+1;p(n=this.input.charCodeAt(s),!0);)++s;if(92===n||n>55295&&n<56320)return!0;var i=this.input.slice(r,s);if(!o.test(i))return!0}return!1},X.isAsyncFunction=function(){if(this.options.ecmaVersion<8||!this.isContextual("async"))return!1;w.lastIndex=this.pos;var e,t=w.exec(this.input),r=this.pos+t[0].length;return!(T.test(this.input.slice(this.pos,r))||"function"!==this.input.slice(r,r+8)||r+8!==this.input.length&&(p(e=this.input.charCodeAt(r+8))||e>55295&&e<56320))},X.parseStatement=function(e,t,r){var n,s=this.type,i=this.startNode();switch(this.isLet(e)&&(s=b._var,n="let"),s){case b._break:case b._continue:return this.parseBreakContinueStatement(i,s.keyword);case b._debugger:return this.parseDebuggerStatement(i);case b._do:return this.parseDoStatement(i);case b._for:return this.parseForStatement(i);case b._function:return e&&(this.strict||"if"!==e&&"label"!==e)&&this.options.ecmaVersion>=6&&this.unexpected(),this.parseFunctionStatement(i,!1,!e);case b._class:return e&&this.unexpected(),this.parseClass(i,!0);case b._if:return this.parseIfStatement(i);case b._return:return this.parseReturnStatement(i);case b._switch:return this.parseSwitchStatement(i);case b._throw:return this.parseThrowStatement(i);case b._try:return this.parseTryStatement(i);case b._const:case b._var:return n=n||this.value,e&&"var"!==n&&this.unexpected(),this.parseVarStatement(i,n);case b._while:return this.parseWhileStatement(i);case b._with:return this.parseWithStatement(i);case b.braceL:return this.parseBlock(!0,i);case b.semi:return this.parseEmptyStatement(i);case b._export:case b._import:if(this.options.ecmaVersion>10&&s===b._import){w.lastIndex=this.pos;var a=w.exec(this.input),o=this.pos+a[0].length,u=this.input.charCodeAt(o);if(40===u||46===u)return this.parseExpressionStatement(i,this.parseExpression())}return this.options.allowImportExportEverywhere||(t||this.raise(this.start,"'import' and 'export' may only appear at the top level"),this.inModule||this.raise(this.start,"'import' and 'export' may appear only with 'sourceType: module'")),s===b._import?this.parseImport(i):this.parseExport(i,r);default:if(this.isAsyncFunction())return e&&this.unexpected(),this.next(),this.parseFunctionStatement(i,!0,!e);var h=this.value,l=this.parseExpression();return s===b.name&&"Identifier"===l.type&&this.eat(b.colon)?this.parseLabeledStatement(i,h,l,e):this.parseExpressionStatement(i,l)}},X.parseBreakContinueStatement=function(e,t){var r="break"===t;this.next(),this.eat(b.semi)||this.insertSemicolon()?e.label=null:this.type!==b.name?this.unexpected():(e.label=this.parseIdent(),this.semicolon());for(var n=0;n=6?this.eat(b.semi):this.semicolon(),this.finishNode(e,"DoWhileStatement")},X.parseForStatement=function(e){this.next();var t=this.options.ecmaVersion>=9&&this.canAwait&&this.eatContextual("await")?this.lastTokStart:-1;if(this.labels.push(q),this.enterScope(0),this.expect(b.parenL),this.type===b.semi)return t>-1&&this.unexpected(t),this.parseFor(e,null);var r=this.isLet();if(this.type===b._var||this.type===b._const||r){var n=this.startNode(),s=r?"let":this.value;return this.next(),this.parseVar(n,!0,s),this.finishNode(n,"VariableDeclaration"),(this.type===b._in||this.options.ecmaVersion>=6&&this.isContextual("of"))&&1===n.declarations.length?(this.options.ecmaVersion>=9&&(this.type===b._in?t>-1&&this.unexpected(t):e.await=t>-1),this.parseForIn(e,n)):(t>-1&&this.unexpected(t),this.parseFor(e,n))}var i=this.isContextual("let"),a=!1,o=this.containsEsc,u=new H,h=this.start,l=t>-1?this.parseExprSubscripts(u,"await"):this.parseExpression(!0,u);return this.type===b._in||(a=this.options.ecmaVersion>=6&&this.isContextual("of"))?(t>-1?(this.type===b._in&&this.unexpected(t),e.await=!0):a&&this.options.ecmaVersion>=8&&(l.start!==h||o||"Identifier"!==l.type||"async"!==l.name?this.options.ecmaVersion>=9&&(e.await=!1):this.unexpected()),i&&a&&this.raise(l.start,"The left-hand side of a for-of loop may not start with 'let'."),this.toAssignable(l,!1,u),this.checkLValPattern(l),this.parseForIn(e,l)):(this.checkExpressionErrors(u,!0),t>-1&&this.unexpected(t),this.parseFor(e,l))},X.parseFunctionStatement=function(e,t,r){return this.next(),this.parseFunction(e,J|(r?0:Q),!1,t)},X.parseIfStatement=function(e){return this.next(),e.test=this.parseParenExpression(),e.consequent=this.parseStatement("if"),e.alternate=this.eat(b._else)?this.parseStatement("if"):null,this.finishNode(e,"IfStatement")},X.parseReturnStatement=function(e){return this.inFunction||this.options.allowReturnOutsideFunction||this.raise(this.start,"'return' outside of function"),this.next(),this.eat(b.semi)||this.insertSemicolon()?e.argument=null:(e.argument=this.parseExpression(),this.semicolon()),this.finishNode(e,"ReturnStatement")},X.parseSwitchStatement=function(e){var t;this.next(),e.discriminant=this.parseParenExpression(),e.cases=[],this.expect(b.braceL),this.labels.push(Y),this.enterScope(0);for(var r=!1;this.type!==b.braceR;)if(this.type===b._case||this.type===b._default){var n=this.type===b._case;t&&this.finishNode(t,"SwitchCase"),e.cases.push(t=this.startNode()),t.consequent=[],this.next(),n?t.test=this.parseExpression():(r&&this.raiseRecoverable(this.lastTokStart,"Multiple default clauses"),r=!0,t.test=null),this.expect(b.colon)}else t||this.unexpected(),t.consequent.push(this.parseStatement(null));return this.exitScope(),t&&this.finishNode(t,"SwitchCase"),this.next(),this.labels.pop(),this.finishNode(e,"SwitchStatement")},X.parseThrowStatement=function(e){return this.next(),T.test(this.input.slice(this.lastTokEnd,this.start))&&this.raise(this.lastTokEnd,"Illegal newline after throw"),e.argument=this.parseExpression(),this.semicolon(),this.finishNode(e,"ThrowStatement")};var Z=[];X.parseCatchClauseParam=function(){var e=this.parseBindingAtom(),t="Identifier"===e.type;return this.enterScope(t?32:0),this.checkLValPattern(e,t?4:2),this.expect(b.parenR),e},X.parseTryStatement=function(e){if(this.next(),e.block=this.parseBlock(),e.handler=null,this.type===b._catch){var t=this.startNode();this.next(),this.eat(b.parenL)?t.param=this.parseCatchClauseParam():(this.options.ecmaVersion<10&&this.unexpected(),t.param=null,this.enterScope(0)),t.body=this.parseBlock(!1),this.exitScope(),e.handler=this.finishNode(t,"CatchClause")}return e.finalizer=this.eat(b._finally)?this.parseBlock():null,e.handler||e.finalizer||this.raise(e.start,"Missing catch or finally clause"),this.finishNode(e,"TryStatement")},X.parseVarStatement=function(e,t,r){return this.next(),this.parseVar(e,!1,t,r),this.semicolon(),this.finishNode(e,"VariableDeclaration")},X.parseWhileStatement=function(e){return this.next(),e.test=this.parseParenExpression(),this.labels.push(q),e.body=this.parseStatement("while"),this.labels.pop(),this.finishNode(e,"WhileStatement")},X.parseWithStatement=function(e){return this.strict&&this.raise(this.start,"'with' in strict mode"),this.next(),e.object=this.parseParenExpression(),e.body=this.parseStatement("with"),this.finishNode(e,"WithStatement")},X.parseEmptyStatement=function(e){return this.next(),this.finishNode(e,"EmptyStatement")},X.parseLabeledStatement=function(e,t,r,n){for(var s=0,i=this.labels;s=0;o--){var u=this.labels[o];if(u.statementStart!==e.start)break;u.statementStart=this.start,u.kind=a}return this.labels.push({name:t,kind:a,statementStart:this.start}),e.body=this.parseStatement(n?-1===n.indexOf("label")?n+"label":n:"label"),this.labels.pop(),e.label=r,this.finishNode(e,"LabeledStatement")},X.parseExpressionStatement=function(e,t){return e.expression=t,this.semicolon(),this.finishNode(e,"ExpressionStatement")},X.parseBlock=function(e,t,r){for(void 0===e&&(e=!0),void 0===t&&(t=this.startNode()),t.body=[],this.expect(b.braceL),e&&this.enterScope(0);this.type!==b.braceR;){var n=this.parseStatement(null);t.body.push(n)}return r&&(this.strict=!1),this.next(),e&&this.exitScope(),this.finishNode(t,"BlockStatement")},X.parseFor=function(e,t){return e.init=t,this.expect(b.semi),e.test=this.type===b.semi?null:this.parseExpression(),this.expect(b.semi),e.update=this.type===b.parenR?null:this.parseExpression(),this.expect(b.parenR),e.body=this.parseStatement("for"),this.exitScope(),this.labels.pop(),this.finishNode(e,"ForStatement")},X.parseForIn=function(e,t){var r=this.type===b._in;return this.next(),"VariableDeclaration"===t.type&&null!=t.declarations[0].init&&(!r||this.options.ecmaVersion<8||this.strict||"var"!==t.kind||"Identifier"!==t.declarations[0].id.type)&&this.raise(t.start,(r?"for-in":"for-of")+" loop variable declaration may not have an initializer"),e.left=t,e.right=r?this.parseExpression():this.parseMaybeAssign(),this.expect(b.parenR),e.body=this.parseStatement("for"),this.exitScope(),this.labels.pop(),this.finishNode(e,r?"ForInStatement":"ForOfStatement")},X.parseVar=function(e,t,r,n){for(e.declarations=[],e.kind=r;;){var s=this.startNode();if(this.parseVarId(s,r),this.eat(b.eq)?s.init=this.parseMaybeAssign(t):n||"const"!==r||this.type===b._in||this.options.ecmaVersion>=6&&this.isContextual("of")?n||"Identifier"===s.id.type||t&&(this.type===b._in||this.isContextual("of"))?s.init=null:this.raise(this.lastTokEnd,"Complex binding patterns require an initialization value"):this.unexpected(),e.declarations.push(this.finishNode(s,"VariableDeclarator")),!this.eat(b.comma))break}return e},X.parseVarId=function(e,t){e.id=this.parseBindingAtom(),this.checkLValPattern(e.id,"var"===t?1:2,!1)};var J=1,Q=2;function ee(e,t){var r=t.key.name,n=e[r],s="true";return"MethodDefinition"!==t.type||"get"!==t.kind&&"set"!==t.kind||(s=(t.static?"s":"i")+t.kind),"iget"===n&&"iset"===s||"iset"===n&&"iget"===s||"sget"===n&&"sset"===s||"sset"===n&&"sget"===s?(e[r]="true",!1):!!n||(e[r]=s,!1)}function te(e,t){var r=e.computed,n=e.key;return!r&&("Identifier"===n.type&&n.name===t||"Literal"===n.type&&n.value===t)}X.parseFunction=function(e,t,r,n,s){this.initFunction(e),(this.options.ecmaVersion>=9||this.options.ecmaVersion>=6&&!n)&&(this.type===b.star&&t&Q&&this.unexpected(),e.generator=this.eat(b.star)),this.options.ecmaVersion>=8&&(e.async=!!n),t&J&&(e.id=4&t&&this.type!==b.name?null:this.parseIdent(),!e.id||t&Q||this.checkLValSimple(e.id,this.strict||e.generator||e.async?this.treatFunctionsAsVar?1:2:3));var i=this.yieldPos,a=this.awaitPos,o=this.awaitIdentPos;return this.yieldPos=0,this.awaitPos=0,this.awaitIdentPos=0,this.enterScope(U(e.async,e.generator)),t&J||(e.id=this.type===b.name?this.parseIdent():null),this.parseFunctionParams(e),this.parseFunctionBody(e,r,!1,s),this.yieldPos=i,this.awaitPos=a,this.awaitIdentPos=o,this.finishNode(e,t&J?"FunctionDeclaration":"FunctionExpression")},X.parseFunctionParams=function(e){this.expect(b.parenL),e.params=this.parseBindingList(b.parenR,!1,this.options.ecmaVersion>=8),this.checkYieldAwaitInDefaultParams()},X.parseClass=function(e,t){this.next();var r=this.strict;this.strict=!0,this.parseClassId(e,t),this.parseClassSuper(e);var n=this.enterClassBody(),s=this.startNode(),i=!1;for(s.body=[],this.expect(b.braceL);this.type!==b.braceR;){var a=this.parseClassElement(null!==e.superClass);a&&(s.body.push(a),"MethodDefinition"===a.type&&"constructor"===a.kind?(i&&this.raiseRecoverable(a.start,"Duplicate constructor in the same class"),i=!0):a.key&&"PrivateIdentifier"===a.key.type&&ee(n,a)&&this.raiseRecoverable(a.key.start,"Identifier '#"+a.key.name+"' has already been declared"))}return this.strict=r,this.next(),e.body=this.finishNode(s,"ClassBody"),this.exitClassBody(),this.finishNode(e,t?"ClassDeclaration":"ClassExpression")},X.parseClassElement=function(e){if(this.eat(b.semi))return null;var t=this.options.ecmaVersion,r=this.startNode(),n="",s=!1,i=!1,a="method",o=!1;if(this.eatContextual("static")){if(t>=13&&this.eat(b.braceL))return this.parseClassStaticBlock(r),r;this.isClassElementNameStart()||this.type===b.star?o=!0:n="static"}if(r.static=o,!n&&t>=8&&this.eatContextual("async")&&(!this.isClassElementNameStart()&&this.type!==b.star||this.canInsertSemicolon()?n="async":i=!0),!n&&(t>=9||!i)&&this.eat(b.star)&&(s=!0),!n&&!i&&!s){var u=this.value;(this.eatContextual("get")||this.eatContextual("set"))&&(this.isClassElementNameStart()?a=u:n=u)}if(n?(r.computed=!1,r.key=this.startNodeAt(this.lastTokStart,this.lastTokStartLoc),r.key.name=n,this.finishNode(r.key,"Identifier")):this.parseClassElementName(r),t<13||this.type===b.parenL||"method"!==a||s||i){var h=!r.static&&te(r,"constructor"),l=h&&e;h&&"method"!==a&&this.raise(r.key.start,"Constructor can't have get/set modifier"),r.kind=h?"constructor":a,this.parseClassMethod(r,s,i,l)}else this.parseClassField(r);return r},X.isClassElementNameStart=function(){return this.type===b.name||this.type===b.privateId||this.type===b.num||this.type===b.string||this.type===b.bracketL||this.type.keyword},X.parseClassElementName=function(e){this.type===b.privateId?("constructor"===this.value&&this.raise(this.start,"Classes can't have an element named '#constructor'"),e.computed=!1,e.key=this.parsePrivateIdent()):this.parsePropertyName(e)},X.parseClassMethod=function(e,t,r,n){var s=e.key;"constructor"===e.kind?(t&&this.raise(s.start,"Constructor can't be a generator"),r&&this.raise(s.start,"Constructor can't be an async method")):e.static&&te(e,"prototype")&&this.raise(s.start,"Classes may not have a static property named prototype");var i=e.value=this.parseMethod(t,r,n);return"get"===e.kind&&0!==i.params.length&&this.raiseRecoverable(i.start,"getter should have no params"),"set"===e.kind&&1!==i.params.length&&this.raiseRecoverable(i.start,"setter should have exactly one param"),"set"===e.kind&&"RestElement"===i.params[0].type&&this.raiseRecoverable(i.params[0].start,"Setter cannot use rest params"),this.finishNode(e,"MethodDefinition")},X.parseClassField=function(e){if(te(e,"constructor")?this.raise(e.key.start,"Classes can't have a field named 'constructor'"):e.static&&te(e,"prototype")&&this.raise(e.key.start,"Classes can't have a static field named 'prototype'"),this.eat(b.eq)){var t=this.currentThisScope(),r=t.inClassFieldInit;t.inClassFieldInit=!0,e.value=this.parseMaybeAssign(),t.inClassFieldInit=r}else e.value=null;return this.semicolon(),this.finishNode(e,"PropertyDefinition")},X.parseClassStaticBlock=function(e){e.body=[];var t=this.labels;for(this.labels=[],this.enterScope(320);this.type!==b.braceR;){var r=this.parseStatement(null);e.body.push(r)}return this.next(),this.exitScope(),this.labels=t,this.finishNode(e,"StaticBlock")},X.parseClassId=function(e,t){this.type===b.name?(e.id=this.parseIdent(),t&&this.checkLValSimple(e.id,2,!1)):(!0===t&&this.unexpected(),e.id=null)},X.parseClassSuper=function(e){e.superClass=this.eat(b._extends)?this.parseExprSubscripts(null,!1):null},X.enterClassBody=function(){var e={declared:Object.create(null),used:[]};return this.privateNameStack.push(e),e.declared},X.exitClassBody=function(){var e=this.privateNameStack.pop(),t=e.declared,r=e.used;if(this.options.checkPrivateFields)for(var n=this.privateNameStack.length,s=0===n?null:this.privateNameStack[n-1],i=0;i=11&&(this.eatContextual("as")?(e.exported=this.parseModuleExportName(),this.checkExport(t,e.exported,this.lastTokStart)):e.exported=null),this.expectContextual("from"),this.type!==b.string&&this.unexpected(),e.source=this.parseExprAtom(),this.options.ecmaVersion>=16&&(e.attributes=this.parseWithClause()),this.semicolon(),this.finishNode(e,"ExportAllDeclaration")},X.parseExport=function(e,t){if(this.next(),this.eat(b.star))return this.parseExportAllDeclaration(e,t);if(this.eat(b._default))return this.checkExport(t,"default",this.lastTokStart),e.declaration=this.parseExportDefaultDeclaration(),this.finishNode(e,"ExportDefaultDeclaration");if(this.shouldParseExportStatement())e.declaration=this.parseExportDeclaration(e),"VariableDeclaration"===e.declaration.type?this.checkVariableExport(t,e.declaration.declarations):this.checkExport(t,e.declaration.id,e.declaration.id.start),e.specifiers=[],e.source=null;else{if(e.declaration=null,e.specifiers=this.parseExportSpecifiers(t),this.eatContextual("from"))this.type!==b.string&&this.unexpected(),e.source=this.parseExprAtom(),this.options.ecmaVersion>=16&&(e.attributes=this.parseWithClause());else{for(var r=0,n=e.specifiers;r=16&&(e.attributes=this.parseWithClause()),this.semicolon(),this.finishNode(e,"ImportDeclaration")},X.parseImportSpecifier=function(){var e=this.startNode();return e.imported=this.parseModuleExportName(),this.eatContextual("as")?e.local=this.parseIdent():(this.checkUnreserved(e.imported),e.local=e.imported),this.checkLValSimple(e.local,2),this.finishNode(e,"ImportSpecifier")},X.parseImportDefaultSpecifier=function(){var e=this.startNode();return e.local=this.parseIdent(),this.checkLValSimple(e.local,2),this.finishNode(e,"ImportDefaultSpecifier")},X.parseImportNamespaceSpecifier=function(){var e=this.startNode();return this.next(),this.expectContextual("as"),e.local=this.parseIdent(),this.checkLValSimple(e.local,2),this.finishNode(e,"ImportNamespaceSpecifier")},X.parseImportSpecifiers=function(){var e=[],t=!0;if(this.type===b.name&&(e.push(this.parseImportDefaultSpecifier()),!this.eat(b.comma)))return e;if(this.type===b.star)return e.push(this.parseImportNamespaceSpecifier()),e;for(this.expect(b.braceL);!this.eat(b.braceR);){if(t)t=!1;else if(this.expect(b.comma),this.afterTrailingComma(b.braceR))break;e.push(this.parseImportSpecifier())}return e},X.parseWithClause=function(){var e=[];if(!this.eat(b._with))return e;this.expect(b.braceL);for(var t={},r=!0;!this.eat(b.braceR);){if(r)r=!1;else if(this.expect(b.comma),this.afterTrailingComma(b.braceR))break;var n=this.parseImportAttribute(),s="Identifier"===n.key.type?n.key.name:n.key.value;D(t,s)&&this.raiseRecoverable(n.key.start,"Duplicate attribute key '"+s+"'"),t[s]=!0,e.push(n)}return e},X.parseImportAttribute=function(){var e=this.startNode();return e.key=this.type===b.string?this.parseExprAtom():this.parseIdent("never"!==this.options.allowReserved),this.expect(b.colon),this.type!==b.string&&this.unexpected(),e.value=this.parseExprAtom(),this.finishNode(e,"ImportAttribute")},X.parseModuleExportName=function(){if(this.options.ecmaVersion>=13&&this.type===b.string){var e=this.parseLiteral(this.value);return R.test(e.value)&&this.raise(e.start,"An export name cannot include a lone surrogate."),e}return this.parseIdent(!0)},X.adaptDirectivePrologue=function(e){for(var t=0;t=5&&"ExpressionStatement"===e.type&&"Literal"===e.expression.type&&"string"==typeof e.expression.value&&('"'===this.input[e.start]||"'"===this.input[e.start])};var re=K.prototype;re.toAssignable=function(e,t,r){if(this.options.ecmaVersion>=6&&e)switch(e.type){case"Identifier":this.inAsync&&"await"===e.name&&this.raise(e.start,"Cannot use 'await' as identifier inside an async function");break;case"ObjectPattern":case"ArrayPattern":case"AssignmentPattern":case"RestElement":break;case"ObjectExpression":e.type="ObjectPattern",r&&this.checkPatternErrors(r,!0);for(var n=0,s=e.properties;n=8&&!o&&"async"===u.name&&!this.canInsertSemicolon()&&this.eat(b._function))return this.overrideContext(se.f_expr),this.parseFunction(this.startNodeAt(i,a),0,!1,!0,t);if(s&&!this.canInsertSemicolon()){if(this.eat(b.arrow))return this.parseArrowExpression(this.startNodeAt(i,a),[u],!1,t);if(this.options.ecmaVersion>=8&&"async"===u.name&&this.type===b.name&&!o&&(!this.potentialArrowInForAwait||"of"!==this.value||this.containsEsc))return u=this.parseIdent(!1),!this.canInsertSemicolon()&&this.eat(b.arrow)||this.unexpected(),this.parseArrowExpression(this.startNodeAt(i,a),[u],!0,t)}return u;case b.regexp:var h=this.value;return(n=this.parseLiteral(h.value)).regex={pattern:h.pattern,flags:h.flags},n;case b.num:case b.string:return this.parseLiteral(this.value);case b._null:case b._true:case b._false:return(n=this.startNode()).value=this.type===b._null?null:this.type===b._true,n.raw=this.type.keyword,this.next(),this.finishNode(n,"Literal");case b.parenL:var l=this.start,c=this.parseParenAndDistinguishExpression(s,t);return e&&(e.parenthesizedAssign<0&&!this.isSimpleAssignTarget(c)&&(e.parenthesizedAssign=l),e.parenthesizedBind<0&&(e.parenthesizedBind=l)),c;case b.bracketL:return n=this.startNode(),this.next(),n.elements=this.parseExprList(b.bracketR,!0,!0,e),this.finishNode(n,"ArrayExpression");case b.braceL:return this.overrideContext(se.b_expr),this.parseObj(!1,e);case b._function:return n=this.startNode(),this.next(),this.parseFunction(n,0);case b._class:return this.parseClass(this.startNode(),!1);case b._new:return this.parseNew();case b.backQuote:return this.parseTemplate();case b._import:return this.options.ecmaVersion>=11?this.parseExprImport(r):this.unexpected();default:return this.parseExprAtomDefault()}},ae.parseExprAtomDefault=function(){this.unexpected()},ae.parseExprImport=function(e){var t=this.startNode();if(this.containsEsc&&this.raiseRecoverable(this.start,"Escape sequence in keyword import"),this.next(),this.type===b.parenL&&!e)return this.parseDynamicImport(t);if(this.type===b.dot){var r=this.startNodeAt(t.start,t.loc&&t.loc.start);return r.name="import",t.meta=this.finishNode(r,"Identifier"),this.parseImportMeta(t)}this.unexpected()},ae.parseDynamicImport=function(e){if(this.next(),e.source=this.parseMaybeAssign(),this.options.ecmaVersion>=16)this.eat(b.parenR)?e.options=null:(this.expect(b.comma),this.afterTrailingComma(b.parenR)?e.options=null:(e.options=this.parseMaybeAssign(),this.eat(b.parenR)||(this.expect(b.comma),this.afterTrailingComma(b.parenR)||this.unexpected())));else if(!this.eat(b.parenR)){var t=this.start;this.eat(b.comma)&&this.eat(b.parenR)?this.raiseRecoverable(t,"Trailing comma is not allowed in import()"):this.unexpected(t)}return this.finishNode(e,"ImportExpression")},ae.parseImportMeta=function(e){this.next();var t=this.containsEsc;return e.property=this.parseIdent(!0),"meta"!==e.property.name&&this.raiseRecoverable(e.property.start,"The only valid meta property for import is 'import.meta'"),t&&this.raiseRecoverable(e.start,"'import.meta' must not contain escaped characters"),"module"===this.options.sourceType||this.options.allowImportExportEverywhere||this.raiseRecoverable(e.start,"Cannot use 'import.meta' outside a module"),this.finishNode(e,"MetaProperty")},ae.parseLiteral=function(e){var t=this.startNode();return t.value=e,t.raw=this.input.slice(this.start,this.end),110===t.raw.charCodeAt(t.raw.length-1)&&(t.bigint=t.raw.slice(0,-1).replace(/_/g,"")),this.next(),this.finishNode(t,"Literal")},ae.parseParenExpression=function(){this.expect(b.parenL);var e=this.parseExpression();return this.expect(b.parenR),e},ae.shouldParseArrow=function(e){return!this.canInsertSemicolon()},ae.parseParenAndDistinguishExpression=function(e,t){var r,n=this.start,s=this.startLoc,i=this.options.ecmaVersion>=8;if(this.options.ecmaVersion>=6){this.next();var a,o=this.start,u=this.startLoc,h=[],l=!0,c=!1,p=new H,d=this.yieldPos,f=this.awaitPos;for(this.yieldPos=0,this.awaitPos=0;this.type!==b.parenR;){if(l?l=!1:this.expect(b.comma),i&&this.afterTrailingComma(b.parenR,!0)){c=!0;break}if(this.type===b.ellipsis){a=this.start,h.push(this.parseParenItem(this.parseRestBinding())),this.type===b.comma&&this.raiseRecoverable(this.start,"Comma is not permitted after the rest element");break}h.push(this.parseMaybeAssign(!1,p,this.parseParenItem))}var m=this.lastTokEnd,g=this.lastTokEndLoc;if(this.expect(b.parenR),e&&this.shouldParseArrow(h)&&this.eat(b.arrow))return this.checkPatternErrors(p,!1),this.checkYieldAwaitInDefaultParams(),this.yieldPos=d,this.awaitPos=f,this.parseParenArrowList(n,s,h,t);h.length&&!c||this.unexpected(this.lastTokStart),a&&this.unexpected(a),this.checkExpressionErrors(p,!0),this.yieldPos=d||this.yieldPos,this.awaitPos=f||this.awaitPos,h.length>1?((r=this.startNodeAt(o,u)).expressions=h,this.finishNodeAt(r,"SequenceExpression",m,g)):r=h[0]}else r=this.parseParenExpression();if(this.options.preserveParens){var x=this.startNodeAt(n,s);return x.expression=r,this.finishNode(x,"ParenthesizedExpression")}return r},ae.parseParenItem=function(e){return e},ae.parseParenArrowList=function(e,t,r,n){return this.parseArrowExpression(this.startNodeAt(e,t),r,!1,n)};var he=[];ae.parseNew=function(){this.containsEsc&&this.raiseRecoverable(this.start,"Escape sequence in keyword new");var e=this.startNode();if(this.next(),this.options.ecmaVersion>=6&&this.type===b.dot){var t=this.startNodeAt(e.start,e.loc&&e.loc.start);t.name="new",e.meta=this.finishNode(t,"Identifier"),this.next();var r=this.containsEsc;return e.property=this.parseIdent(!0),"target"!==e.property.name&&this.raiseRecoverable(e.property.start,"The only valid meta property for new is 'new.target'"),r&&this.raiseRecoverable(e.start,"'new.target' must not contain escaped characters"),this.allowNewDotTarget||this.raiseRecoverable(e.start,"'new.target' can only be used in functions and class static block"),this.finishNode(e,"MetaProperty")}var n=this.start,s=this.startLoc;return e.callee=this.parseSubscripts(this.parseExprAtom(null,!1,!0),n,s,!0,!1),this.eat(b.parenL)?e.arguments=this.parseExprList(b.parenR,this.options.ecmaVersion>=8,!1):e.arguments=he,this.finishNode(e,"NewExpression")},ae.parseTemplateElement=function(e){var t=e.isTagged,r=this.startNode();return this.type===b.invalidTemplate?(t||this.raiseRecoverable(this.start,"Bad escape sequence in untagged template literal"),r.value={raw:this.value.replace(/\r\n?/g,"\n"),cooked:null}):r.value={raw:this.input.slice(this.start,this.end).replace(/\r\n?/g,"\n"),cooked:this.value},this.next(),r.tail=this.type===b.backQuote,this.finishNode(r,"TemplateElement")},ae.parseTemplate=function(e){void 0===e&&(e={});var t=e.isTagged;void 0===t&&(t=!1);var r=this.startNode();this.next(),r.expressions=[];var n=this.parseTemplateElement({isTagged:t});for(r.quasis=[n];!n.tail;)this.type===b.eof&&this.raise(this.pos,"Unterminated template literal"),this.expect(b.dollarBraceL),r.expressions.push(this.parseExpression()),this.expect(b.braceR),r.quasis.push(n=this.parseTemplateElement({isTagged:t}));return this.next(),this.finishNode(r,"TemplateLiteral")},ae.isAsyncProp=function(e){return!e.computed&&"Identifier"===e.key.type&&"async"===e.key.name&&(this.type===b.name||this.type===b.num||this.type===b.string||this.type===b.bracketL||this.type.keyword||this.options.ecmaVersion>=9&&this.type===b.star)&&!T.test(this.input.slice(this.lastTokEnd,this.start))},ae.parseObj=function(e,t){var r=this.startNode(),n=!0,s={};for(r.properties=[],this.next();!this.eat(b.braceR);){if(n)n=!1;else if(this.expect(b.comma),this.options.ecmaVersion>=5&&this.afterTrailingComma(b.braceR))break;var i=this.parseProperty(e,t);e||this.checkPropClash(i,s,t),r.properties.push(i)}return this.finishNode(r,e?"ObjectPattern":"ObjectExpression")},ae.parseProperty=function(e,t){var r,n,s,i,a=this.startNode();if(this.options.ecmaVersion>=9&&this.eat(b.ellipsis))return e?(a.argument=this.parseIdent(!1),this.type===b.comma&&this.raiseRecoverable(this.start,"Comma is not permitted after the rest element"),this.finishNode(a,"RestElement")):(a.argument=this.parseMaybeAssign(!1,t),this.type===b.comma&&t&&t.trailingComma<0&&(t.trailingComma=this.start),this.finishNode(a,"SpreadElement"));this.options.ecmaVersion>=6&&(a.method=!1,a.shorthand=!1,(e||t)&&(s=this.start,i=this.startLoc),e||(r=this.eat(b.star)));var o=this.containsEsc;return this.parsePropertyName(a),!e&&!o&&this.options.ecmaVersion>=8&&!r&&this.isAsyncProp(a)?(n=!0,r=this.options.ecmaVersion>=9&&this.eat(b.star),this.parsePropertyName(a)):n=!1,this.parsePropertyValue(a,e,r,n,s,i,t,o),this.finishNode(a,"Property")},ae.parseGetterSetter=function(e){e.kind=e.key.name,this.parsePropertyName(e),e.value=this.parseMethod(!1);var t="get"===e.kind?0:1;if(e.value.params.length!==t){var r=e.value.start;"get"===e.kind?this.raiseRecoverable(r,"getter should have no params"):this.raiseRecoverable(r,"setter should have exactly one param")}else"set"===e.kind&&"RestElement"===e.value.params[0].type&&this.raiseRecoverable(e.value.params[0].start,"Setter cannot use rest params")},ae.parsePropertyValue=function(e,t,r,n,s,i,a,o){(r||n)&&this.type===b.colon&&this.unexpected(),this.eat(b.colon)?(e.value=t?this.parseMaybeDefault(this.start,this.startLoc):this.parseMaybeAssign(!1,a),e.kind="init"):this.options.ecmaVersion>=6&&this.type===b.parenL?(t&&this.unexpected(),e.kind="init",e.method=!0,e.value=this.parseMethod(r,n)):t||o||!(this.options.ecmaVersion>=5)||e.computed||"Identifier"!==e.key.type||"get"!==e.key.name&&"set"!==e.key.name||this.type===b.comma||this.type===b.braceR||this.type===b.eq?this.options.ecmaVersion>=6&&!e.computed&&"Identifier"===e.key.type?((r||n)&&this.unexpected(),this.checkUnreserved(e.key),"await"!==e.key.name||this.awaitIdentPos||(this.awaitIdentPos=s),e.kind="init",t?e.value=this.parseMaybeDefault(s,i,this.copyNode(e.key)):this.type===b.eq&&a?(a.shorthandAssign<0&&(a.shorthandAssign=this.start),e.value=this.parseMaybeDefault(s,i,this.copyNode(e.key))):e.value=this.copyNode(e.key),e.shorthand=!0):this.unexpected():((r||n)&&this.unexpected(),this.parseGetterSetter(e))},ae.parsePropertyName=function(e){if(this.options.ecmaVersion>=6){if(this.eat(b.bracketL))return e.computed=!0,e.key=this.parseMaybeAssign(),this.expect(b.bracketR),e.key;e.computed=!1}return e.key=this.type===b.num||this.type===b.string?this.parseExprAtom():this.parseIdent("never"!==this.options.allowReserved)},ae.initFunction=function(e){e.id=null,this.options.ecmaVersion>=6&&(e.generator=e.expression=!1),this.options.ecmaVersion>=8&&(e.async=!1)},ae.parseMethod=function(e,t,r){var n=this.startNode(),s=this.yieldPos,i=this.awaitPos,a=this.awaitIdentPos;return this.initFunction(n),this.options.ecmaVersion>=6&&(n.generator=e),this.options.ecmaVersion>=8&&(n.async=!!t),this.yieldPos=0,this.awaitPos=0,this.awaitIdentPos=0,this.enterScope(64|U(t,n.generator)|(r?128:0)),this.expect(b.parenL),n.params=this.parseBindingList(b.parenR,!1,this.options.ecmaVersion>=8),this.checkYieldAwaitInDefaultParams(),this.parseFunctionBody(n,!1,!0,!1),this.yieldPos=s,this.awaitPos=i,this.awaitIdentPos=a,this.finishNode(n,"FunctionExpression")},ae.parseArrowExpression=function(e,t,r,n){var s=this.yieldPos,i=this.awaitPos,a=this.awaitIdentPos;return this.enterScope(16|U(r,!1)),this.initFunction(e),this.options.ecmaVersion>=8&&(e.async=!!r),this.yieldPos=0,this.awaitPos=0,this.awaitIdentPos=0,e.params=this.toAssignableList(t,!0),this.parseFunctionBody(e,!0,!1,n),this.yieldPos=s,this.awaitPos=i,this.awaitIdentPos=a,this.finishNode(e,"ArrowFunctionExpression")},ae.parseFunctionBody=function(e,t,r,n){var s=t&&this.type!==b.braceL,i=this.strict,a=!1;if(s)e.body=this.parseMaybeAssign(n),e.expression=!0,this.checkParams(e,!1);else{var o=this.options.ecmaVersion>=7&&!this.isSimpleParamList(e.params);i&&!o||(a=this.strictDirective(this.end))&&o&&this.raiseRecoverable(e.start,"Illegal 'use strict' directive in function with non-simple parameter list");var u=this.labels;this.labels=[],a&&(this.strict=!0),this.checkParams(e,!i&&!a&&!t&&!r&&this.isSimpleParamList(e.params)),this.strict&&e.id&&this.checkLValSimple(e.id,5),e.body=this.parseBlock(!1,void 0,a&&!i),e.expression=!1,this.adaptDirectivePrologue(e.body.body),this.labels=u}this.exitScope()},ae.isSimpleParamList=function(e){for(var t=0,r=e;t-1||s.functions.indexOf(e)>-1||s.var.indexOf(e)>-1,s.lexical.push(e),this.inModule&&1&s.flags&&delete this.undefinedExports[e]}else if(4===t)this.currentScope().lexical.push(e);else if(3===t){var i=this.currentScope();n=this.treatFunctionsAsVar?i.lexical.indexOf(e)>-1:i.lexical.indexOf(e)>-1||i.var.indexOf(e)>-1,i.functions.push(e)}else for(var a=this.scopeStack.length-1;a>=0;--a){var o=this.scopeStack[a];if(o.lexical.indexOf(e)>-1&&!(32&o.flags&&o.lexical[0]===e)||!this.treatFunctionsAsVarInScope(o)&&o.functions.indexOf(e)>-1){n=!0;break}if(o.var.push(e),this.inModule&&1&o.flags&&delete this.undefinedExports[e],259&o.flags)break}n&&this.raiseRecoverable(r,"Identifier '"+e+"' has already been declared")},ce.checkLocalExport=function(e){-1===this.scopeStack[0].lexical.indexOf(e.name)&&-1===this.scopeStack[0].var.indexOf(e.name)&&(this.undefinedExports[e.name]=e)},ce.currentScope=function(){return this.scopeStack[this.scopeStack.length-1]},ce.currentVarScope=function(){for(var e=this.scopeStack.length-1;;e--){var t=this.scopeStack[e];if(259&t.flags)return t}},ce.currentThisScope=function(){for(var e=this.scopeStack.length-1;;e--){var t=this.scopeStack[e];if(259&t.flags&&!(16&t.flags))return t}};var de=function(e,t,r){this.type="",this.start=t,this.end=0,e.options.locations&&(this.loc=new V(e,r)),e.options.directSourceFile&&(this.sourceFile=e.options.directSourceFile),e.options.ranges&&(this.range=[t,0])},fe=K.prototype;function me(e,t,r,n){return e.type=t,e.end=r,this.options.locations&&(e.loc.end=n),this.options.ranges&&(e.range[1]=r),e}fe.startNode=function(){return new de(this,this.start,this.startLoc)},fe.startNodeAt=function(e,t){return new de(this,e,t)},fe.finishNode=function(e,t){return me.call(this,e,t,this.lastTokEnd,this.lastTokEndLoc)},fe.finishNodeAt=function(e,t,r,n){return me.call(this,e,t,r,n)},fe.copyNode=function(e){var t=new de(this,e.start,this.startLoc);for(var r in e)t[r]=e[r];return t};var ge="ASCII ASCII_Hex_Digit AHex Alphabetic Alpha Any Assigned Bidi_Control Bidi_C Bidi_Mirrored Bidi_M Case_Ignorable CI Cased Changes_When_Casefolded CWCF Changes_When_Casemapped CWCM Changes_When_Lowercased CWL Changes_When_NFKC_Casefolded CWKCF Changes_When_Titlecased CWT Changes_When_Uppercased CWU Dash Default_Ignorable_Code_Point DI Deprecated Dep Diacritic Dia Emoji Emoji_Component Emoji_Modifier Emoji_Modifier_Base Emoji_Presentation Extender Ext Grapheme_Base Gr_Base Grapheme_Extend Gr_Ext Hex_Digit Hex IDS_Binary_Operator IDSB IDS_Trinary_Operator IDST ID_Continue IDC ID_Start IDS Ideographic Ideo Join_Control Join_C Logical_Order_Exception LOE Lowercase Lower Math Noncharacter_Code_Point NChar Pattern_Syntax Pat_Syn Pattern_White_Space Pat_WS Quotation_Mark QMark Radical Regional_Indicator RI Sentence_Terminal STerm Soft_Dotted SD Terminal_Punctuation Term Unified_Ideograph UIdeo Uppercase Upper Variation_Selector VS White_Space space XID_Continue XIDC XID_Start XIDS",xe=ge+" Extended_Pictographic",ye=xe+" EBase EComp EMod EPres ExtPict",be={9:ge,10:xe,11:xe,12:ye,13:ye,14:ye},Te={9:"",10:"",11:"",12:"",13:"",14:"Basic_Emoji Emoji_Keycap_Sequence RGI_Emoji_Modifier_Sequence RGI_Emoji_Flag_Sequence RGI_Emoji_Tag_Sequence RGI_Emoji_ZWJ_Sequence RGI_Emoji"},Se="Cased_Letter LC Close_Punctuation Pe Connector_Punctuation Pc Control Cc cntrl Currency_Symbol Sc Dash_Punctuation Pd Decimal_Number Nd digit Enclosing_Mark Me Final_Punctuation Pf Format Cf Initial_Punctuation Pi Letter L Letter_Number Nl Line_Separator Zl Lowercase_Letter Ll Mark M Combining_Mark Math_Symbol Sm Modifier_Letter Lm Modifier_Symbol Sk Nonspacing_Mark Mn Number N Open_Punctuation Ps Other C Other_Letter Lo Other_Number No Other_Punctuation Po Other_Symbol So Paragraph_Separator Zp Private_Use Co Punctuation P punct Separator Z Space_Separator Zs Spacing_Mark Mc Surrogate Cs Symbol S Titlecase_Letter Lt Unassigned Cn Uppercase_Letter Lu",ve="Adlam Adlm Ahom Anatolian_Hieroglyphs Hluw Arabic Arab Armenian Armn Avestan Avst Balinese Bali Bamum Bamu Bassa_Vah Bass Batak Batk Bengali Beng Bhaiksuki Bhks Bopomofo Bopo Brahmi Brah Braille Brai Buginese Bugi Buhid Buhd Canadian_Aboriginal Cans Carian Cari Caucasian_Albanian Aghb Chakma Cakm Cham Cham Cherokee Cher Common Zyyy Coptic Copt Qaac Cuneiform Xsux Cypriot Cprt Cyrillic Cyrl Deseret Dsrt Devanagari Deva Duployan Dupl Egyptian_Hieroglyphs Egyp Elbasan Elba Ethiopic Ethi Georgian Geor Glagolitic Glag Gothic Goth Grantha Gran Greek Grek Gujarati Gujr Gurmukhi Guru Han Hani Hangul Hang Hanunoo Hano Hatran Hatr Hebrew Hebr Hiragana Hira Imperial_Aramaic Armi Inherited Zinh Qaai Inscriptional_Pahlavi Phli Inscriptional_Parthian Prti Javanese Java Kaithi Kthi Kannada Knda Katakana Kana Kayah_Li Kali Kharoshthi Khar Khmer Khmr Khojki Khoj Khudawadi Sind Lao Laoo Latin Latn Lepcha Lepc Limbu Limb Linear_A Lina Linear_B Linb Lisu Lisu Lycian Lyci Lydian Lydi Mahajani Mahj Malayalam Mlym Mandaic Mand Manichaean Mani Marchen Marc Masaram_Gondi Gonm Meetei_Mayek Mtei Mende_Kikakui Mend Meroitic_Cursive Merc Meroitic_Hieroglyphs Mero Miao Plrd Modi Mongolian Mong Mro Mroo Multani Mult Myanmar Mymr Nabataean Nbat New_Tai_Lue Talu Newa Newa Nko Nkoo Nushu Nshu Ogham Ogam Ol_Chiki Olck Old_Hungarian Hung Old_Italic Ital Old_North_Arabian Narb Old_Permic Perm Old_Persian Xpeo Old_South_Arabian Sarb Old_Turkic Orkh Oriya Orya Osage Osge Osmanya Osma Pahawh_Hmong Hmng Palmyrene Palm Pau_Cin_Hau Pauc Phags_Pa Phag Phoenician Phnx Psalter_Pahlavi Phlp Rejang Rjng Runic Runr Samaritan Samr Saurashtra Saur Sharada Shrd Shavian Shaw Siddham Sidd SignWriting Sgnw Sinhala Sinh Sora_Sompeng Sora Soyombo Soyo Sundanese Sund Syloti_Nagri Sylo Syriac Syrc Tagalog Tglg Tagbanwa Tagb Tai_Le Tale Tai_Tham Lana Tai_Viet Tavt Takri Takr Tamil Taml Tangut Tang Telugu Telu Thaana Thaa Thai Thai Tibetan Tibt Tifinagh Tfng Tirhuta Tirh Ugaritic Ugar Vai Vaii Warang_Citi Wara Yi Yiii Zanabazar_Square Zanb",Ae=ve+" Dogra Dogr Gunjala_Gondi Gong Hanifi_Rohingya Rohg Makasar Maka Medefaidrin Medf Old_Sogdian Sogo Sogdian Sogd",_e=Ae+" Elymaic Elym Nandinagari Nand Nyiakeng_Puachue_Hmong Hmnp Wancho Wcho",we=_e+" Chorasmian Chrs Diak Dives_Akuru Khitan_Small_Script Kits Yezi Yezidi",Ee=we+" Cypro_Minoan Cpmn Old_Uyghur Ougr Tangsa Tnsa Toto Vithkuqi Vith",Ie={9:ve,10:Ae,11:_e,12:we,13:Ee,14:Ee+" Gara Garay Gukh Gurung_Khema Hrkt Katakana_Or_Hiragana Kawi Kirat_Rai Krai Nag_Mundari Nagm Ol_Onal Onao Sunu Sunuwar Todhri Todr Tulu_Tigalari Tutg Unknown Zzzz"},ke={};function De(e){var t=ke[e]={binary:$(be[e]+" "+Se),binaryOfStrings:$(Te[e]),nonBinary:{General_Category:$(Se),Script:$(Ie[e])}};t.nonBinary.Script_Extensions=t.nonBinary.Script,t.nonBinary.gc=t.nonBinary.General_Category,t.nonBinary.sc=t.nonBinary.Script,t.nonBinary.scx=t.nonBinary.Script_Extensions}for(var Ce=0,Le=[9,10,11,12,13,14];Ce=6?"uy":"")+(e.options.ecmaVersion>=9?"s":"")+(e.options.ecmaVersion>=13?"d":"")+(e.options.ecmaVersion>=15?"v":""),this.unicodeProperties=ke[e.options.ecmaVersion>=14?14:e.options.ecmaVersion],this.source="",this.flags="",this.start=0,this.switchU=!1,this.switchV=!1,this.switchN=!1,this.pos=0,this.lastIntValue=0,this.lastStringValue="",this.lastAssertionIsQuantifiable=!1,this.numCapturingParens=0,this.maxBackReference=0,this.groupNames=Object.create(null),this.backReferenceNames=[],this.branchID=null};function Ne(e){return 105===e||109===e||115===e}function Ve(e){return 36===e||e>=40&&e<=43||46===e||63===e||e>=91&&e<=94||e>=123&&e<=125}function Me(e){return e>=65&&e<=90||e>=97&&e<=122}function Oe(e){return Me(e)||95===e}function Pe(e){return Oe(e)||Ge(e)}function Ge(e){return e>=48&&e<=57}function ze(e){return e>=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102}function Ue(e){return e>=65&&e<=70?e-65+10:e>=97&&e<=102?e-97+10:e-48}function Ke(e){return e>=48&&e<=55}Re.prototype.reset=function(e,t,r){var n=-1!==r.indexOf("v"),s=-1!==r.indexOf("u");this.start=0|e,this.source=t+"",this.flags=r,n&&this.parser.options.ecmaVersion>=15?(this.switchU=!0,this.switchV=!0,this.switchN=!0):(this.switchU=s&&this.parser.options.ecmaVersion>=6,this.switchV=!1,this.switchN=s&&this.parser.options.ecmaVersion>=9)},Re.prototype.raise=function(e){this.parser.raiseRecoverable(this.start,"Invalid regular expression: /"+this.source+"/: "+e)},Re.prototype.at=function(e,t){void 0===t&&(t=!1);var r=this.source,n=r.length;if(e>=n)return-1;var s=r.charCodeAt(e);if(!t&&!this.switchU||s<=55295||s>=57344||e+1>=n)return s;var i=r.charCodeAt(e+1);return i>=56320&&i<=57343?(s<<10)+i-56613888:s},Re.prototype.nextIndex=function(e,t){void 0===t&&(t=!1);var r=this.source,n=r.length;if(e>=n)return n;var s,i=r.charCodeAt(e);return!t&&!this.switchU||i<=55295||i>=57344||e+1>=n||(s=r.charCodeAt(e+1))<56320||s>57343?e+1:e+2},Re.prototype.current=function(e){return void 0===e&&(e=!1),this.at(this.pos,e)},Re.prototype.lookahead=function(e){return void 0===e&&(e=!1),this.at(this.nextIndex(this.pos,e),e)},Re.prototype.advance=function(e){void 0===e&&(e=!1),this.pos=this.nextIndex(this.pos,e)},Re.prototype.eat=function(e,t){return void 0===t&&(t=!1),this.current(t)===e&&(this.advance(t),!0)},Re.prototype.eatChars=function(e,t){void 0===t&&(t=!1);for(var r=this.pos,n=0,s=e;n-1&&this.raise(e.start,"Duplicate regular expression flag"),"u"===a&&(n=!0),"v"===a&&(s=!0)}this.options.ecmaVersion>=15&&n&&s&&this.raise(e.start,"Invalid regular expression flag")},$e.validateRegExpPattern=function(e){this.regexp_pattern(e),!e.switchN&&this.options.ecmaVersion>=9&&function(e){for(var t in e)return!0;return!1}(e.groupNames)&&(e.switchN=!0,this.regexp_pattern(e))},$e.regexp_pattern=function(e){e.pos=0,e.lastIntValue=0,e.lastStringValue="",e.lastAssertionIsQuantifiable=!1,e.numCapturingParens=0,e.maxBackReference=0,e.groupNames=Object.create(null),e.backReferenceNames.length=0,e.branchID=null,this.regexp_disjunction(e),e.pos!==e.source.length&&(e.eat(41)&&e.raise("Unmatched ')'"),(e.eat(93)||e.eat(125))&&e.raise("Lone quantifier brackets")),e.maxBackReference>e.numCapturingParens&&e.raise("Invalid escape");for(var t=0,r=e.backReferenceNames;t=16;for(t&&(e.branchID=new Fe(e.branchID,null)),this.regexp_alternative(e);e.eat(124);)t&&(e.branchID=e.branchID.sibling()),this.regexp_alternative(e);t&&(e.branchID=e.branchID.parent),this.regexp_eatQuantifier(e,!0)&&e.raise("Nothing to repeat"),e.eat(123)&&e.raise("Lone quantifier brackets")},$e.regexp_alternative=function(e){for(;e.pos=9&&(r=e.eat(60)),e.eat(61)||e.eat(33))return this.regexp_disjunction(e),e.eat(41)||e.raise("Unterminated group"),e.lastAssertionIsQuantifiable=!r,!0}return e.pos=t,!1},$e.regexp_eatQuantifier=function(e,t){return void 0===t&&(t=!1),!!this.regexp_eatQuantifierPrefix(e,t)&&(e.eat(63),!0)},$e.regexp_eatQuantifierPrefix=function(e,t){return e.eat(42)||e.eat(43)||e.eat(63)||this.regexp_eatBracedQuantifier(e,t)},$e.regexp_eatBracedQuantifier=function(e,t){var r=e.pos;if(e.eat(123)){var n=0,s=-1;if(this.regexp_eatDecimalDigits(e)&&(n=e.lastIntValue,e.eat(44)&&this.regexp_eatDecimalDigits(e)&&(s=e.lastIntValue),e.eat(125)))return-1!==s&&s=16){var r=this.regexp_eatModifiers(e),n=e.eat(45);if(r||n){for(var s=0;s-1&&e.raise("Duplicate regular expression modifiers")}if(n){var a=this.regexp_eatModifiers(e);r||a||58!==e.current()||e.raise("Invalid regular expression modifiers");for(var o=0;o-1||r.indexOf(u)>-1)&&e.raise("Duplicate regular expression modifiers")}}}}if(e.eat(58)){if(this.regexp_disjunction(e),e.eat(41))return!0;e.raise("Unterminated group")}}e.pos=t}return!1},$e.regexp_eatCapturingGroup=function(e){if(e.eat(40)){if(this.options.ecmaVersion>=9?this.regexp_groupSpecifier(e):63===e.current()&&e.raise("Invalid group"),this.regexp_disjunction(e),e.eat(41))return e.numCapturingParens+=1,!0;e.raise("Unterminated group")}return!1},$e.regexp_eatModifiers=function(e){for(var t="",r=0;-1!==(r=e.current())&&Ne(r);)t+=F(r),e.advance();return t},$e.regexp_eatExtendedAtom=function(e){return e.eat(46)||this.regexp_eatReverseSolidusAtomEscape(e)||this.regexp_eatCharacterClass(e)||this.regexp_eatUncapturingGroup(e)||this.regexp_eatCapturingGroup(e)||this.regexp_eatInvalidBracedQuantifier(e)||this.regexp_eatExtendedPatternCharacter(e)},$e.regexp_eatInvalidBracedQuantifier=function(e){return this.regexp_eatBracedQuantifier(e,!0)&&e.raise("Nothing to repeat"),!1},$e.regexp_eatSyntaxCharacter=function(e){var t=e.current();return!!Ve(t)&&(e.lastIntValue=t,e.advance(),!0)},$e.regexp_eatPatternCharacters=function(e){for(var t=e.pos,r=0;-1!==(r=e.current())&&!Ve(r);)e.advance();return e.pos!==t},$e.regexp_eatExtendedPatternCharacter=function(e){var t=e.current();return!(-1===t||36===t||t>=40&&t<=43||46===t||63===t||91===t||94===t||124===t||(e.advance(),0))},$e.regexp_groupSpecifier=function(e){if(e.eat(63)){this.regexp_eatGroupName(e)||e.raise("Invalid group");var t=this.options.ecmaVersion>=16,r=e.groupNames[e.lastStringValue];if(r)if(t)for(var n=0,s=r;n=11,n=e.current(r);return e.advance(r),92===n&&this.regexp_eatRegExpUnicodeEscapeSequence(e,r)&&(n=e.lastIntValue),function(e){return c(e,!0)||36===e||95===e}(n)?(e.lastIntValue=n,!0):(e.pos=t,!1)},$e.regexp_eatRegExpIdentifierPart=function(e){var t=e.pos,r=this.options.ecmaVersion>=11,n=e.current(r);return e.advance(r),92===n&&this.regexp_eatRegExpUnicodeEscapeSequence(e,r)&&(n=e.lastIntValue),function(e){return p(e,!0)||36===e||95===e||8204===e||8205===e}(n)?(e.lastIntValue=n,!0):(e.pos=t,!1)},$e.regexp_eatAtomEscape=function(e){return!!(this.regexp_eatBackReference(e)||this.regexp_eatCharacterClassEscape(e)||this.regexp_eatCharacterEscape(e)||e.switchN&&this.regexp_eatKGroupName(e))||(e.switchU&&(99===e.current()&&e.raise("Invalid unicode escape"),e.raise("Invalid escape")),!1)},$e.regexp_eatBackReference=function(e){var t=e.pos;if(this.regexp_eatDecimalEscape(e)){var r=e.lastIntValue;if(e.switchU)return r>e.maxBackReference&&(e.maxBackReference=r),!0;if(r<=e.numCapturingParens)return!0;e.pos=t}return!1},$e.regexp_eatKGroupName=function(e){if(e.eat(107)){if(this.regexp_eatGroupName(e))return e.backReferenceNames.push(e.lastStringValue),!0;e.raise("Invalid named reference")}return!1},$e.regexp_eatCharacterEscape=function(e){return this.regexp_eatControlEscape(e)||this.regexp_eatCControlLetter(e)||this.regexp_eatZero(e)||this.regexp_eatHexEscapeSequence(e)||this.regexp_eatRegExpUnicodeEscapeSequence(e,!1)||!e.switchU&&this.regexp_eatLegacyOctalEscapeSequence(e)||this.regexp_eatIdentityEscape(e)},$e.regexp_eatCControlLetter=function(e){var t=e.pos;if(e.eat(99)){if(this.regexp_eatControlLetter(e))return!0;e.pos=t}return!1},$e.regexp_eatZero=function(e){return 48===e.current()&&!Ge(e.lookahead())&&(e.lastIntValue=0,e.advance(),!0)},$e.regexp_eatControlEscape=function(e){var t=e.current();return 116===t?(e.lastIntValue=9,e.advance(),!0):110===t?(e.lastIntValue=10,e.advance(),!0):118===t?(e.lastIntValue=11,e.advance(),!0):102===t?(e.lastIntValue=12,e.advance(),!0):114===t&&(e.lastIntValue=13,e.advance(),!0)},$e.regexp_eatControlLetter=function(e){var t=e.current();return!!Me(t)&&(e.lastIntValue=t%32,e.advance(),!0)},$e.regexp_eatRegExpUnicodeEscapeSequence=function(e,t){void 0===t&&(t=!1);var r,n=e.pos,s=t||e.switchU;if(e.eat(117)){if(this.regexp_eatFixedHexDigits(e,4)){var i=e.lastIntValue;if(s&&i>=55296&&i<=56319){var a=e.pos;if(e.eat(92)&&e.eat(117)&&this.regexp_eatFixedHexDigits(e,4)){var o=e.lastIntValue;if(o>=56320&&o<=57343)return e.lastIntValue=1024*(i-55296)+(o-56320)+65536,!0}e.pos=a,e.lastIntValue=i}return!0}if(s&&e.eat(123)&&this.regexp_eatHexDigits(e)&&e.eat(125)&&(r=e.lastIntValue)>=0&&r<=1114111)return!0;s&&e.raise("Invalid unicode escape"),e.pos=n}return!1},$e.regexp_eatIdentityEscape=function(e){if(e.switchU)return!!this.regexp_eatSyntaxCharacter(e)||!!e.eat(47)&&(e.lastIntValue=47,!0);var t=e.current();return!(99===t||e.switchN&&107===t||(e.lastIntValue=t,e.advance(),0))},$e.regexp_eatDecimalEscape=function(e){e.lastIntValue=0;var t=e.current();if(t>=49&&t<=57){do{e.lastIntValue=10*e.lastIntValue+(t-48),e.advance()}while((t=e.current())>=48&&t<=57);return!0}return!1},$e.regexp_eatCharacterClassEscape=function(e){var t=e.current();if(function(e){return 100===e||68===e||115===e||83===e||119===e||87===e}(t))return e.lastIntValue=-1,e.advance(),1;var r=!1;if(e.switchU&&this.options.ecmaVersion>=9&&((r=80===t)||112===t)){var n;if(e.lastIntValue=-1,e.advance(),e.eat(123)&&(n=this.regexp_eatUnicodePropertyValueExpression(e))&&e.eat(125))return r&&2===n&&e.raise("Invalid property name"),n;e.raise("Invalid property name")}return 0},$e.regexp_eatUnicodePropertyValueExpression=function(e){var t=e.pos;if(this.regexp_eatUnicodePropertyName(e)&&e.eat(61)){var r=e.lastStringValue;if(this.regexp_eatUnicodePropertyValue(e)){var n=e.lastStringValue;return this.regexp_validateUnicodePropertyNameAndValue(e,r,n),1}}if(e.pos=t,this.regexp_eatLoneUnicodePropertyNameOrValue(e)){var s=e.lastStringValue;return this.regexp_validateUnicodePropertyNameOrValue(e,s)}return 0},$e.regexp_validateUnicodePropertyNameAndValue=function(e,t,r){D(e.unicodeProperties.nonBinary,t)||e.raise("Invalid property name"),e.unicodeProperties.nonBinary[t].test(r)||e.raise("Invalid property value")},$e.regexp_validateUnicodePropertyNameOrValue=function(e,t){return e.unicodeProperties.binary.test(t)?1:e.switchV&&e.unicodeProperties.binaryOfStrings.test(t)?2:void e.raise("Invalid property name")},$e.regexp_eatUnicodePropertyName=function(e){var t=0;for(e.lastStringValue="";Oe(t=e.current());)e.lastStringValue+=F(t),e.advance();return""!==e.lastStringValue},$e.regexp_eatUnicodePropertyValue=function(e){var t=0;for(e.lastStringValue="";Pe(t=e.current());)e.lastStringValue+=F(t),e.advance();return""!==e.lastStringValue},$e.regexp_eatLoneUnicodePropertyNameOrValue=function(e){return this.regexp_eatUnicodePropertyValue(e)},$e.regexp_eatCharacterClass=function(e){if(e.eat(91)){var t=e.eat(94),r=this.regexp_classContents(e);return e.eat(93)||e.raise("Unterminated character class"),t&&2===r&&e.raise("Negated character class may contain strings"),!0}return!1},$e.regexp_classContents=function(e){return 93===e.current()?1:e.switchV?this.regexp_classSetExpression(e):(this.regexp_nonEmptyClassRanges(e),1)},$e.regexp_nonEmptyClassRanges=function(e){for(;this.regexp_eatClassAtom(e);){var t=e.lastIntValue;if(e.eat(45)&&this.regexp_eatClassAtom(e)){var r=e.lastIntValue;!e.switchU||-1!==t&&-1!==r||e.raise("Invalid character class"),-1!==t&&-1!==r&&t>r&&e.raise("Range out of order in character class")}}},$e.regexp_eatClassAtom=function(e){var t=e.pos;if(e.eat(92)){if(this.regexp_eatClassEscape(e))return!0;if(e.switchU){var r=e.current();(99===r||Ke(r))&&e.raise("Invalid class escape"),e.raise("Invalid escape")}e.pos=t}var n=e.current();return 93!==n&&(e.lastIntValue=n,e.advance(),!0)},$e.regexp_eatClassEscape=function(e){var t=e.pos;if(e.eat(98))return e.lastIntValue=8,!0;if(e.switchU&&e.eat(45))return e.lastIntValue=45,!0;if(!e.switchU&&e.eat(99)){if(this.regexp_eatClassControlLetter(e))return!0;e.pos=t}return this.regexp_eatCharacterClassEscape(e)||this.regexp_eatCharacterEscape(e)},$e.regexp_classSetExpression=function(e){var t,r=1;if(this.regexp_eatClassSetRange(e));else if(t=this.regexp_eatClassSetOperand(e)){2===t&&(r=2);for(var n=e.pos;e.eatChars([38,38]);)38!==e.current()&&(t=this.regexp_eatClassSetOperand(e))?2!==t&&(r=1):e.raise("Invalid character in character class");if(n!==e.pos)return r;for(;e.eatChars([45,45]);)this.regexp_eatClassSetOperand(e)||e.raise("Invalid character in character class");if(n!==e.pos)return r}else e.raise("Invalid character in character class");for(;;)if(!this.regexp_eatClassSetRange(e)){if(!(t=this.regexp_eatClassSetOperand(e)))return r;2===t&&(r=2)}},$e.regexp_eatClassSetRange=function(e){var t=e.pos;if(this.regexp_eatClassSetCharacter(e)){var r=e.lastIntValue;if(e.eat(45)&&this.regexp_eatClassSetCharacter(e)){var n=e.lastIntValue;return-1!==r&&-1!==n&&r>n&&e.raise("Range out of order in character class"),!0}e.pos=t}return!1},$e.regexp_eatClassSetOperand=function(e){return this.regexp_eatClassSetCharacter(e)?1:this.regexp_eatClassStringDisjunction(e)||this.regexp_eatNestedClass(e)},$e.regexp_eatNestedClass=function(e){var t=e.pos;if(e.eat(91)){var r=e.eat(94),n=this.regexp_classContents(e);if(e.eat(93))return r&&2===n&&e.raise("Negated character class may contain strings"),n;e.pos=t}if(e.eat(92)){var s=this.regexp_eatCharacterClassEscape(e);if(s)return s;e.pos=t}return null},$e.regexp_eatClassStringDisjunction=function(e){var t=e.pos;if(e.eatChars([92,113])){if(e.eat(123)){var r=this.regexp_classStringDisjunctionContents(e);if(e.eat(125))return r}else e.raise("Invalid escape");e.pos=t}return null},$e.regexp_classStringDisjunctionContents=function(e){for(var t=this.regexp_classString(e);e.eat(124);)2===this.regexp_classString(e)&&(t=2);return t},$e.regexp_classString=function(e){for(var t=0;this.regexp_eatClassSetCharacter(e);)t++;return 1===t?1:2},$e.regexp_eatClassSetCharacter=function(e){var t=e.pos;if(e.eat(92))return!(!this.regexp_eatCharacterEscape(e)&&!this.regexp_eatClassSetReservedPunctuator(e)&&(e.eat(98)?(e.lastIntValue=8,0):(e.pos=t,1)));var r=e.current();return!(r<0||r===e.lookahead()&&function(e){return 33===e||e>=35&&e<=38||e>=42&&e<=44||46===e||e>=58&&e<=64||94===e||96===e||126===e}(r)||function(e){return 40===e||41===e||45===e||47===e||e>=91&&e<=93||e>=123&&e<=125}(r)||(e.advance(),e.lastIntValue=r,0))},$e.regexp_eatClassSetReservedPunctuator=function(e){var t=e.current();return!!function(e){return 33===e||35===e||37===e||38===e||44===e||45===e||e>=58&&e<=62||64===e||96===e||126===e}(t)&&(e.lastIntValue=t,e.advance(),!0)},$e.regexp_eatClassControlLetter=function(e){var t=e.current();return!(!Ge(t)&&95!==t||(e.lastIntValue=t%32,e.advance(),0))},$e.regexp_eatHexEscapeSequence=function(e){var t=e.pos;if(e.eat(120)){if(this.regexp_eatFixedHexDigits(e,2))return!0;e.switchU&&e.raise("Invalid escape"),e.pos=t}return!1},$e.regexp_eatDecimalDigits=function(e){var t=e.pos,r=0;for(e.lastIntValue=0;Ge(r=e.current());)e.lastIntValue=10*e.lastIntValue+(r-48),e.advance();return e.pos!==t},$e.regexp_eatHexDigits=function(e){var t=e.pos,r=0;for(e.lastIntValue=0;ze(r=e.current());)e.lastIntValue=16*e.lastIntValue+Ue(r),e.advance();return e.pos!==t},$e.regexp_eatLegacyOctalEscapeSequence=function(e){if(this.regexp_eatOctalDigit(e)){var t=e.lastIntValue;if(this.regexp_eatOctalDigit(e)){var r=e.lastIntValue;t<=3&&this.regexp_eatOctalDigit(e)?e.lastIntValue=64*t+8*r+e.lastIntValue:e.lastIntValue=8*t+r}else e.lastIntValue=t;return!0}return!1},$e.regexp_eatOctalDigit=function(e){var t=e.current();return Ke(t)?(e.lastIntValue=t-48,e.advance(),!0):(e.lastIntValue=0,!1)},$e.regexp_eatFixedHexDigits=function(e,t){var r=e.pos;e.lastIntValue=0;for(var n=0;n=this.input.length?this.finishToken(b.eof):e.override?e.override(this):void this.readToken(this.fullCharCodeAtPos())},We.readToken=function(e){return c(e,this.options.ecmaVersion>=6)||92===e?this.readWord():this.getTokenFromCode(e)},We.fullCharCodeAtPos=function(){var e=this.input.charCodeAt(this.pos);if(e<=55295||e>=56320)return e;var t=this.input.charCodeAt(this.pos+1);return t<=56319||t>=57344?e:(e<<10)+t-56613888},We.skipBlockComment=function(){var e=this.options.onComment&&this.curPosition(),t=this.pos,r=this.input.indexOf("*/",this.pos+=2);if(-1===r&&this.raise(this.pos-2,"Unterminated comment"),this.pos=r+2,this.options.locations)for(var n=void 0,s=t;(n=A(this.input,s,this.pos))>-1;)++this.curLine,s=this.lineStart=n;this.options.onComment&&this.options.onComment(!0,this.input.slice(t+2,r),t,this.pos,e,this.curPosition())},We.skipLineComment=function(e){for(var t=this.pos,r=this.options.onComment&&this.curPosition(),n=this.input.charCodeAt(this.pos+=e);this.pos8&&e<14||e>=5760&&_.test(String.fromCharCode(e))))break e;++this.pos}}},We.finishToken=function(e,t){this.end=this.pos,this.options.locations&&(this.endLoc=this.curPosition());var r=this.type;this.type=e,this.value=t,this.updateContext(r)},We.readToken_dot=function(){var e=this.input.charCodeAt(this.pos+1);if(e>=48&&e<=57)return this.readNumber(!0);var t=this.input.charCodeAt(this.pos+2);return this.options.ecmaVersion>=6&&46===e&&46===t?(this.pos+=3,this.finishToken(b.ellipsis)):(++this.pos,this.finishToken(b.dot))},We.readToken_slash=function(){var e=this.input.charCodeAt(this.pos+1);return this.exprAllowed?(++this.pos,this.readRegexp()):61===e?this.finishOp(b.assign,2):this.finishOp(b.slash,1)},We.readToken_mult_modulo_exp=function(e){var t=this.input.charCodeAt(this.pos+1),r=1,n=42===e?b.star:b.modulo;return this.options.ecmaVersion>=7&&42===e&&42===t&&(++r,n=b.starstar,t=this.input.charCodeAt(this.pos+2)),61===t?this.finishOp(b.assign,r+1):this.finishOp(n,r)},We.readToken_pipe_amp=function(e){var t=this.input.charCodeAt(this.pos+1);return t===e?this.options.ecmaVersion>=12&&61===this.input.charCodeAt(this.pos+2)?this.finishOp(b.assign,3):this.finishOp(124===e?b.logicalOR:b.logicalAND,2):61===t?this.finishOp(b.assign,2):this.finishOp(124===e?b.bitwiseOR:b.bitwiseAND,1)},We.readToken_caret=function(){return 61===this.input.charCodeAt(this.pos+1)?this.finishOp(b.assign,2):this.finishOp(b.bitwiseXOR,1)},We.readToken_plus_min=function(e){var t=this.input.charCodeAt(this.pos+1);return t===e?45!==t||this.inModule||62!==this.input.charCodeAt(this.pos+2)||0!==this.lastTokEnd&&!T.test(this.input.slice(this.lastTokEnd,this.pos))?this.finishOp(b.incDec,2):(this.skipLineComment(3),this.skipSpace(),this.nextToken()):61===t?this.finishOp(b.assign,2):this.finishOp(b.plusMin,1)},We.readToken_lt_gt=function(e){var t=this.input.charCodeAt(this.pos+1),r=1;return t===e?(r=62===e&&62===this.input.charCodeAt(this.pos+2)?3:2,61===this.input.charCodeAt(this.pos+r)?this.finishOp(b.assign,r+1):this.finishOp(b.bitShift,r)):33!==t||60!==e||this.inModule||45!==this.input.charCodeAt(this.pos+2)||45!==this.input.charCodeAt(this.pos+3)?(61===t&&(r=2),this.finishOp(b.relational,r)):(this.skipLineComment(4),this.skipSpace(),this.nextToken())},We.readToken_eq_excl=function(e){var t=this.input.charCodeAt(this.pos+1);return 61===t?this.finishOp(b.equality,61===this.input.charCodeAt(this.pos+2)?3:2):61===e&&62===t&&this.options.ecmaVersion>=6?(this.pos+=2,this.finishToken(b.arrow)):this.finishOp(61===e?b.eq:b.prefix,1)},We.readToken_question=function(){var e=this.options.ecmaVersion;if(e>=11){var t=this.input.charCodeAt(this.pos+1);if(46===t){var r=this.input.charCodeAt(this.pos+2);if(r<48||r>57)return this.finishOp(b.questionDot,2)}if(63===t)return e>=12&&61===this.input.charCodeAt(this.pos+2)?this.finishOp(b.assign,3):this.finishOp(b.coalesce,2)}return this.finishOp(b.question,1)},We.readToken_numberSign=function(){var e=35;if(this.options.ecmaVersion>=13&&(++this.pos,c(e=this.fullCharCodeAtPos(),!0)||92===e))return this.finishToken(b.privateId,this.readWord1());this.raise(this.pos,"Unexpected character '"+F(e)+"'")},We.getTokenFromCode=function(e){switch(e){case 46:return this.readToken_dot();case 40:return++this.pos,this.finishToken(b.parenL);case 41:return++this.pos,this.finishToken(b.parenR);case 59:return++this.pos,this.finishToken(b.semi);case 44:return++this.pos,this.finishToken(b.comma);case 91:return++this.pos,this.finishToken(b.bracketL);case 93:return++this.pos,this.finishToken(b.bracketR);case 123:return++this.pos,this.finishToken(b.braceL);case 125:return++this.pos,this.finishToken(b.braceR);case 58:return++this.pos,this.finishToken(b.colon);case 96:if(this.options.ecmaVersion<6)break;return++this.pos,this.finishToken(b.backQuote);case 48:var t=this.input.charCodeAt(this.pos+1);if(120===t||88===t)return this.readRadixNumber(16);if(this.options.ecmaVersion>=6){if(111===t||79===t)return this.readRadixNumber(8);if(98===t||66===t)return this.readRadixNumber(2)}case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return this.readNumber(!1);case 34:case 39:return this.readString(e);case 47:return this.readToken_slash();case 37:case 42:return this.readToken_mult_modulo_exp(e);case 124:case 38:return this.readToken_pipe_amp(e);case 94:return this.readToken_caret();case 43:case 45:return this.readToken_plus_min(e);case 60:case 62:return this.readToken_lt_gt(e);case 61:case 33:return this.readToken_eq_excl(e);case 63:return this.readToken_question();case 126:return this.finishOp(b.prefix,1);case 35:return this.readToken_numberSign()}this.raise(this.pos,"Unexpected character '"+F(e)+"'")},We.finishOp=function(e,t){var r=this.input.slice(this.pos,this.pos+t);return this.pos+=t,this.finishToken(e,r)},We.readRegexp=function(){for(var e,t,r=this.pos;;){this.pos>=this.input.length&&this.raise(r,"Unterminated regular expression");var n=this.input.charAt(this.pos);if(T.test(n)&&this.raise(r,"Unterminated regular expression"),e)e=!1;else{if("["===n)t=!0;else if("]"===n&&t)t=!1;else if("/"===n&&!t)break;e="\\"===n}++this.pos}var s=this.input.slice(r,this.pos);++this.pos;var i=this.pos,a=this.readWord1();this.containsEsc&&this.unexpected(i);var o=this.regexpState||(this.regexpState=new Re(this));o.reset(r,s,a),this.validateRegExpFlags(o),this.validateRegExpPattern(o);var u=null;try{u=new RegExp(s,a)}catch(e){}return this.finishToken(b.regexp,{pattern:s,flags:a,value:u})},We.readInt=function(e,t,r){for(var n=this.options.ecmaVersion>=12&&void 0===t,s=r&&48===this.input.charCodeAt(this.pos),i=this.pos,a=0,o=0,u=0,h=null==t?1/0:t;u=97?l-97+10:l>=65?l-65+10:l>=48&&l<=57?l-48:1/0)>=e)break;o=l,a=a*e+c}}return n&&95===o&&this.raiseRecoverable(this.pos-1,"Numeric separator is not allowed at the last of digits"),this.pos===i||null!=t&&this.pos-i!==t?null:a},We.readRadixNumber=function(e){var t=this.pos;this.pos+=2;var r=this.readInt(e);return null==r&&this.raise(this.start+2,"Expected number in radix "+e),this.options.ecmaVersion>=11&&110===this.input.charCodeAt(this.pos)?(r=je(this.input.slice(t,this.pos)),++this.pos):c(this.fullCharCodeAtPos())&&this.raise(this.pos,"Identifier directly after number"),this.finishToken(b.num,r)},We.readNumber=function(e){var t=this.pos;e||null!==this.readInt(10,void 0,!0)||this.raise(t,"Invalid number");var r=this.pos-t>=2&&48===this.input.charCodeAt(t);r&&this.strict&&this.raise(t,"Invalid number");var n=this.input.charCodeAt(this.pos);if(!r&&!e&&this.options.ecmaVersion>=11&&110===n){var s=je(this.input.slice(t,this.pos));return++this.pos,c(this.fullCharCodeAtPos())&&this.raise(this.pos,"Identifier directly after number"),this.finishToken(b.num,s)}r&&/[89]/.test(this.input.slice(t,this.pos))&&(r=!1),46!==n||r||(++this.pos,this.readInt(10),n=this.input.charCodeAt(this.pos)),69!==n&&101!==n||r||(43!==(n=this.input.charCodeAt(++this.pos))&&45!==n||++this.pos,null===this.readInt(10)&&this.raise(t,"Invalid number")),c(this.fullCharCodeAtPos())&&this.raise(this.pos,"Identifier directly after number");var i,a=(i=this.input.slice(t,this.pos),r?parseInt(i,8):parseFloat(i.replace(/_/g,"")));return this.finishToken(b.num,a)},We.readCodePoint=function(){var e;if(123===this.input.charCodeAt(this.pos)){this.options.ecmaVersion<6&&this.unexpected();var t=++this.pos;e=this.readHexChar(this.input.indexOf("}",this.pos)-this.pos),++this.pos,e>1114111&&this.invalidStringToken(t,"Code point out of bounds")}else e=this.readHexChar(4);return e},We.readString=function(e){for(var t="",r=++this.pos;;){this.pos>=this.input.length&&this.raise(this.start,"Unterminated string constant");var n=this.input.charCodeAt(this.pos);if(n===e)break;92===n?(t+=this.input.slice(r,this.pos),t+=this.readEscapedChar(!1),r=this.pos):8232===n||8233===n?(this.options.ecmaVersion<10&&this.raise(this.start,"Unterminated string constant"),++this.pos,this.options.locations&&(this.curLine++,this.lineStart=this.pos)):(v(n)&&this.raise(this.start,"Unterminated string constant"),++this.pos)}return t+=this.input.slice(r,this.pos++),this.finishToken(b.string,t)};var He={};We.tryReadTemplateToken=function(){this.inTemplateElement=!0;try{this.readTmplToken()}catch(e){if(e!==He)throw e;this.readInvalidTemplateToken()}this.inTemplateElement=!1},We.invalidStringToken=function(e,t){if(this.inTemplateElement&&this.options.ecmaVersion>=9)throw He;this.raise(e,t)},We.readTmplToken=function(){for(var e="",t=this.pos;;){this.pos>=this.input.length&&this.raise(this.start,"Unterminated template");var r=this.input.charCodeAt(this.pos);if(96===r||36===r&&123===this.input.charCodeAt(this.pos+1))return this.pos!==this.start||this.type!==b.template&&this.type!==b.invalidTemplate?(e+=this.input.slice(t,this.pos),this.finishToken(b.template,e)):36===r?(this.pos+=2,this.finishToken(b.dollarBraceL)):(++this.pos,this.finishToken(b.backQuote));if(92===r)e+=this.input.slice(t,this.pos),e+=this.readEscapedChar(!0),t=this.pos;else if(v(r)){switch(e+=this.input.slice(t,this.pos),++this.pos,r){case 13:10===this.input.charCodeAt(this.pos)&&++this.pos;case 10:e+="\n";break;default:e+=String.fromCharCode(r)}this.options.locations&&(++this.curLine,this.lineStart=this.pos),t=this.pos}else++this.pos}},We.readInvalidTemplateToken=function(){for(;this.pos=48&&t<=55){var n=this.input.substr(this.pos-1,3).match(/^[0-7]+/)[0],s=parseInt(n,8);return s>255&&(n=n.slice(0,-1),s=parseInt(n,8)),this.pos+=n.length-1,t=this.input.charCodeAt(this.pos),"0"===n&&56!==t&&57!==t||!this.strict&&!e||this.invalidStringToken(this.pos-1-n.length,e?"Octal literal in template string":"Octal literal in strict mode"),String.fromCharCode(s)}return v(t)?(this.options.locations&&(this.lineStart=this.pos,++this.curLine),""):String.fromCharCode(t)}},We.readHexChar=function(e){var t=this.pos,r=this.readInt(16,e);return null===r&&this.invalidStringToken(t,"Bad character escape sequence"),r},We.readWord1=function(){this.containsEsc=!1;for(var e="",t=!0,r=this.pos,n=this.options.ecmaVersion>=6;this.pos{var r=class{constructor(e,t){this.value=e,Array.isArray(t)?this.size=t:(this.size=new Int32Array(3),t.z?this.size=new Int32Array([t.x,t.y,t.z]):t.y?this.size=new Int32Array([t.x,t.y]):this.size=new Int32Array([t.x]));const[r,n,s]=this.size;if(s){if(this.value.length!==r*n*s)throw new Error(`Input size ${this.value.length} does not match ${r} * ${n} * ${s} = ${n*r*s}`)}else if(n){if(this.value.length!==r*n)throw new Error(`Input size ${this.value.length} does not match ${r} * ${n} = ${n*r}`)}else if(this.value.length!==r)throw new Error(`Input size ${this.value.length} does not match ${r}`)}toArray(){const{utils:e}=i(),[t,r,n]=this.size;return n?e.erectMemoryOptimized3DFloat(this.value.subarray?this.value:new Float32Array(this.value),t,r,n):r?e.erectMemoryOptimized2DFloat(this.value.subarray?this.value:new Float32Array(this.value),t,r):this.value}};t.exports={Input:r,input:function(e,t){return new r(e,t)}}}),s=e((e,t)=>{t.exports={Texture:class{constructor(e){const{texture:t,size:r,dimensions:n,output:s,context:i,type:a="NumberTexture",kernel:o,internalFormat:u,textureFormat:h}=e;if(!s)throw new Error('settings property "output" required.');if(!i)throw new Error('settings property "context" required.');if(!t)throw new Error('settings property "texture" required.');if(!o)throw new Error('settings property "kernel" required.');this.texture=t,t._refs?t._refs++:t._refs=1,this.size=r,this.dimensions=n,this.output=s,this.context=i,this.kernel=o,this.type=a,this._deleted=!1,this.internalFormat=u,this.textureFormat=h}toArray(){throw new Error(`Not implemented on ${this.constructor.name}`)}clone(){throw new Error(`Not implemented on ${this.constructor.name}`)}delete(){throw new Error(`Not implemented on ${this.constructor.name}`)}clear(){throw new Error(`Not implemented on ${this.constructor.name}`)}}}}),i=e((e,t)=>{const i=r(),{Input:a}=n(),{Texture:o}=s(),u=/function ([^(]*)/,h=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,l=/([^\s,]+)/g,c={systemEndianness:()=>m,getSystemEndianness(){const e=new ArrayBuffer(4),t=new Uint32Array(e),r=new Uint8Array(e);if(t[0]=3735928559,239===r[0])return"LE";if(222===r[0])return"BE";throw new Error("unknown endianness")},isFunction:e=>"function"==typeof e,isFunctionString:e=>"string"==typeof e&&"function"===e.slice(0,8).toLowerCase(),getFunctionNameFromString(e){const t=u.exec(e);return t&&0!==t.length?t[1].trim():null},getFunctionBodyFromString:e=>e.substring(e.indexOf("{")+1,e.lastIndexOf("}")),getArgumentNamesFromString(e){const t=e.replace(h,"");let r=t.slice(t.indexOf("(")+1,t.indexOf(")")).match(l);return null===r&&(r=[]),r},clone(e){if(null===e||"object"!=typeof e||e.hasOwnProperty("isActiveClone"))return e;const t=e.constructor();for(let r in e)Object.prototype.hasOwnProperty.call(e,r)&&(e.isActiveClone=null,t[r]=c.clone(e[r]),delete e.isActiveClone);return t},isArray:e=>!isNaN(e.length),typeFitsValue(e,t){if("string"!=typeof e||null==t)return!0;if(t.type)return!0;switch(e){case"Input":return t instanceof a;case"Boolean":return"boolean"==typeof t;case"Number":case"Integer":case"Float":return"number"==typeof t}return-1!==e.indexOf("Texture")?Boolean(t.type):0!==e.indexOf("Array")||c.isArray(t)},getVariableType(e,t){if(c.isArray(e))return e.length>0&&"IMG"===e[0].nodeName?"HTMLImageArray":"Array";switch(e.constructor){case Boolean:return"Boolean";case Number:return t&&Number.isInteger(e)?"Integer":"Float";case o:return e.type;case a:return"Input"}if("nodeName"in e)switch(e.nodeName){case"IMG":case"CANVAS":return"HTMLImage";case"VIDEO":return"HTMLVideo"}else{if(e.hasOwnProperty("type"))return e.type;if("undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)return"OffscreenCanvas";if("undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap)return"ImageBitmap";if("undefined"!=typeof ImageData&&e instanceof ImageData)return"ImageData"}return"Unknown"},getKernelTextureSize(e,t){let[r,n,s]=t,i=(r||1)*(n||1)*(s||1);return e.optimizeFloatMemory&&"single"===e.precision&&(r=i=Math.ceil(i/4)),n>1&&r*n===i?new Int32Array([r,n]):c.closestSquareDimensions(i)},closestSquareDimensions(e){const t=Math.sqrt(e);let r=Math.ceil(t),n=Math.floor(t);for(;r*nMath.floor((e+t-1)/t)*t,getDimensions(e,t){let r;if(c.isArray(e)){const t=[];let n=e;for(;c.isArray(n);)t.push(n.length),n=n[0];r=t.reverse()}else if(e instanceof o)r=e.output;else{if(!(e instanceof a))throw new Error(`Unknown dimensions of ${e}`);r=e.size}if(t)for(r=Array.from(r);r.length<3;)r.push(1);return new Int32Array(r)},flatten2dArrayTo(e,t){let r=0;for(let n=0;ne.length>0?e.join(";\n")+";\n":"\n",warnDeprecated(e,t,r){r?console.warn(`You are using a deprecated ${e} "${t}". It has been replaced with "${r}". Fixing, but please upgrade as it will soon be removed.`):console.warn(`You are using a deprecated ${e} "${t}". It has been removed. Fixing, but please upgrade as it will soon be removed.`)},flipPixels:(e,t,r)=>{const n=r/2|0,s=4*t,i=new Uint8ClampedArray(4*t),a=e.slice(0);for(let e=0;ee.subarray(0,t),erect2DPackedFloat:(e,t,r)=>{const n=new Array(r);for(let s=0;s{const s=new Array(n);for(let i=0;ie.subarray(0,t),erectMemoryOptimized2DFloat:(e,t,r)=>{const n=new Array(r);for(let s=0;s{const s=new Array(n);for(let i=0;i{const r=new Float32Array(t);let n=0;for(let s=0;s{const n=new Array(r);let s=0;for(let i=0;i{const s=new Array(n);let i=0;for(let a=0;a{const r=new Array(t),n=4*t;let s=0;for(let t=0;t{const n=new Array(r),s=4*t;for(let i=0;i{const s=4*t,i=new Array(n);for(let a=0;a{const r=new Array(t),n=4*t;let s=0;for(let t=0;t{const n=4*t,s=new Array(r);for(let i=0;i{const s=4*t,i=new Array(n);for(let a=0;a{const r=new Array(e),n=4*t;let s=0;for(let t=0;t{const n=4*t,s=new Array(r);for(let i=0;i{const s=4*t,i=new Array(n);for(let a=0;a{const{findDependency:r,thisLookup:n,doNotDefine:s}=t;let a=t.flattened;a||(a=t.flattened={});const o=i.parse(e,{ecmaVersion:2020}),u=[];let h=0;const l=function e(t){if(Array.isArray(t)){const r=[];for(let n=0;nnull!==e);return s.length<1?"":`${t.kind} ${s.join(",")}`;case"VariableDeclarator":return t.init?t.init.object&&"ThisExpression"===t.init.object.type?n(t.init.property.name,!0)?`${t.id.name} = ${e(t.init)}`:null:`${t.id.name} = ${e(t.init)}`:t.id.name;case"CallExpression":if("subarray"===t.callee.property.name)return`${e(t.callee.object)}.${e(t.callee.property)}(${t.arguments.map(t=>e(t)).join(", ")})`;if("gl"===t.callee.object.name||"context"===t.callee.object.name)return`${e(t.callee.object)}.${e(t.callee.property)}(${t.arguments.map(t=>e(t)).join(", ")})`;if("ThisExpression"===t.callee.object.type)return u.push(r("this",t.callee.property.name)),`${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`;if(t.callee.object.name){const n=r(t.callee.object.name,t.callee.property.name);return null===n?`${t.callee.object.name}.${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`:(u.push(n),`${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`)}if("MemberExpression"===t.callee.object.type)return`${e(t.callee.object)}.${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`;throw new Error("unknown ast.callee");case"ReturnStatement":return`return ${e(t.argument)}`;case"BinaryExpression":return`(${e(t.left)}${t.operator}${e(t.right)})`;case"UnaryExpression":return t.prefix?`${t.operator} ${e(t.argument)}`:`${e(t.argument)} ${t.operator}`;case"ExpressionStatement":return`${e(t.expression)}`;case"SequenceExpression":return`(${e(t.expressions)})`;case"ArrowFunctionExpression":return`(${t.params.map(e).join(", ")}) => ${e(t.body)}`;case"Literal":return t.raw;case"Identifier":return t.name;case"MemberExpression":return"ThisExpression"===t.object.type?n(t.property.name):t.computed?`${e(t.object)}[${e(t.property)}]`:e(t.object)+"."+e(t.property);case"ThisExpression":return"this";case"NewExpression":return`new ${e(t.callee)}(${t.arguments.map(t=>e(t)).join(", ")})`;case"ForStatement":return`for (${e(t.init)};${e(t.test)};${e(t.update)}) ${e(t.body)}`;case"AssignmentExpression":return`${e(t.left)}${t.operator}${e(t.right)}`;case"UpdateExpression":return`${e(t.argument)}${t.operator}`;case"IfStatement":{const r=e(t.consequent);if(!t.alternate)return`if (${e(t.test)}) ${r}`;const n="BlockStatement"===t.consequent.type?"":";";return`if (${e(t.test)}) ${r}${n} else ${e(t.alternate)}`}case"ThrowStatement":return`throw ${e(t.argument)}`;case"ObjectPattern":return t.properties.map(e).join(", ");case"ArrayPattern":return t.elements.map(e).join(", ");case"DebuggerStatement":return"debugger;";case"ConditionalExpression":return`${e(t.test)}?${e(t.consequent)}:${e(t.alternate)}`;case"Property":if("init"===t.kind)return e(t.key)}throw new Error(`unhandled ast.type of ${t.type}`)}(o);if(u.length>0){const e=[];for(let r=0;r{if("VariableDeclaration"!==e.type)throw new Error('Ast is not of type "VariableDeclaration"');const t=[];for(let r=0;r{const r=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].r},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),n=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].g},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),s=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].b},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),i=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].a},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),a=[r(t),n(t),s(t),i(t)];return a.rKernel=r,a.gKernel=n,a.bKernel=s,a.aKernel=i,a.gpu=e,a},splitRGBAToCanvases:(e,t,r,n)=>{const s=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(t.r/255,0,0,255)},{output:[r,n],graphical:!0,argumentTypes:{v:"Array2D(4)"}});s(t);const i=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(0,t.g/255,0,255)},{output:[r,n],graphical:!0,argumentTypes:{v:"Array2D(4)"}});i(t);const a=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(0,0,t.b/255,255)},{output:[r,n],graphical:!0,argumentTypes:{v:"Array2D(4)"}});a(t);const o=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(255,255,255,t.a/255)},{output:[r,n],graphical:!0,argumentTypes:{v:"Array2D(4)"}});return o(t),[s.canvas,i.canvas,a.canvas,o.canvas]},getMinifySafeName:e=>{try{const{init:t}=i.parse(`const value = ${e.toString()}`,{ecmaVersion:2020}).body[0].declarations[0];return t.body.name||t.body.body[0].argument.name}catch(e){throw new Error("Unrecognized function type. Please use `() => yourFunctionVariableHere` or function() { return yourFunctionVariableHere; }")}},sanitizeName:function(e){return p.test(e)&&(e=e.replace(p,"S_S")),d.test(e)?e=e.replace(d,"U_U"):f.test(e)&&(e=e.replace(f,"u_u")),e}},p=/\$/,d=/__/,f=/_/,m=c.getSystemEndianness();t.exports={utils:c}}),a=e((e,t)=>{const{utils:r}=i(),{Input:s}=n();t.exports={Kernel:class{static get isSupported(){throw new Error(`"isSupported" not implemented on ${this.name}`)}static isContextMatch(e){throw new Error(`"isContextMatch" not implemented on ${this.name}`)}static getFeatures(){throw new Error(`"getFeatures" not implemented on ${this.name}`)}static destroyContext(e){throw new Error(`"destroyContext" called on ${this.name}`)}static nativeFunctionArguments(){throw new Error(`"nativeFunctionArguments" called on ${this.name}`)}static nativeFunctionReturnType(){throw new Error(`"nativeFunctionReturnType" called on ${this.name}`)}static combineKernels(){throw new Error(`"combineKernels" called on ${this.name}`)}constructor(e,t){if("object"!=typeof e){if("string"!=typeof e)throw new Error("source not a string");if(!r.isFunctionString(e))throw new Error("source not a function string")}this.useLegacyEncoder=!1,this.fallbackRequested=!1,this.onRequestFallback=null,this.onRequestSwitchKernel=null,this.argumentNames="string"==typeof e?r.getArgumentNamesFromString(e):null,this.argumentTypes=null,this.argumentSizes=null,this.argumentBitRatios=null,this.kernelArguments=null,this.kernelConstants=null,this.forceUploadKernelConstants=null,this.source=e,this.output=null,this.debug=!1,this.graphical=!1,this.loopMaxIterations=0,this.constants=null,this.constantTypes=null,this.constantBitRatios=null,this.dynamicArguments=!1,this.dynamicOutput=!1,this.canvas=null,this.context=null,this.checkContext=null,this.gpu=null,this.functions=null,this.nativeFunctions=null,this.injectedNative=null,this.subKernels=null,this.validate=!0,this.immutable=!1,this.pipeline=!1,this.asyncMode=!1,this.precision=null,this.tactic=null,this.plugins=null,this.returnType=null,this.leadingReturnStatement=null,this.followingReturnStatement=null,this.optimizeFloatMemory=null,this.strictIntegers=!1,this.fixIntegerDivisionAccuracy=null,this.randomSeed=null,this.built=!1,this.signature=null,this.switchingKernels=null}mergeSettings(e){for(let t in e)if(e.hasOwnProperty(t)&&this.hasOwnProperty(t)){switch(t){case"output":if(!Array.isArray(e.output)){this.setOutput(e.output);continue}break;case"functions":this.functions=[];for(let t=0;te.name):null,returnType:this.returnType}}}buildSignature(e){const t=this.constructor;this.signature=t.getSignature(this,t.getArgumentTypes(this,e))}static getArgumentTypes(e,t){const n=new Array(t.length);for(let s=0;st.argumentTypes[e])||[];const i=Object.keys(t.argumentTypes);if(i.length>0&&e.length>0&&s.every(e=>void 0===e))throw new Error(`argumentTypes keys [${i.join(", ")}] match none of the function's parameters [${e.join(", ")}] \u2014 a bundler may have renamed them. Use the array form: argumentTypes: ['${i.map(e=>t.argumentTypes[e]).join("', '")}']`)}else s=t.argumentTypes||[];return{name:t.name||r.getFunctionNameFromString(n)||("function"==typeof e&&e.name?e.name:null),source:n,argumentTypes:s,returnType:t.returnType||null}}onActivate(e){}switchKernels(e){this.switchingKernels?this.switchingKernels.push(e):this.switchingKernels=[e]}resetSwitchingKernels(){const e=this.switchingKernels;return this.switchingKernels=null,e}checkArgumentTypes(e){if(!this.argumentTypes)return;const t=Math.min(e.length,this.argumentTypes.length);for(let n=0;n{t.exports={FunctionBuilder:class e{static fromKernel(t,r,n){const{kernelArguments:s,kernelConstants:i,argumentNames:a,argumentSizes:o,argumentBitRatios:u,constants:h,constantBitRatios:l,debug:c,loopMaxIterations:p,nativeFunctions:d,output:f,optimizeFloatMemory:m,precision:g,plugins:x,source:y,subKernels:b,functions:T,leadingReturnStatement:S,followingReturnStatement:v,dynamicArguments:A,dynamicOutput:_}=t,w=new Array(s.length),E={};for(let e=0;eU.needsArgumentType(e,t),k=(e,t,r)=>{U.assignArgumentType(e,t,r)},D=(e,t,r)=>U.lookupReturnType(e,t,r),C=e=>U.lookupFunctionArgumentTypes(e),L=(e,t)=>U.lookupFunctionArgumentName(e,t),$=(e,t)=>U.lookupFunctionArgumentBitRatio(e,t),F=(e,t,r,n)=>{U.assignArgumentType(e,t,r,n)},R=(e,t,r,n)=>{U.assignArgumentBitRatio(e,t,r,n)},N=(e,t,r)=>{U.trackFunctionCall(e,t,r)},V=(e,t)=>{const n=[];for(let t=0;tnew r(e.source,{name:e.name||void 0,returnType:e.returnType,argumentTypes:e.argumentTypes,output:f,plugins:x,constants:h,constantTypes:E,constantBitRatios:l,optimizeFloatMemory:m,precision:g,lookupReturnType:D,lookupFunctionArgumentTypes:C,lookupFunctionArgumentName:L,lookupFunctionArgumentBitRatio:$,needsArgumentType:I,assignArgumentType:k,triggerImplyArgumentType:F,triggerImplyArgumentBitRatio:R,onFunctionCall:N,onNestedFunction:V})));let z=null;b&&(z=b.map(e=>{const{name:t,source:n}=e;return new r(n,Object.assign({},M,{name:t,isSubKernel:!0,isRootKernel:!1}))}));const U=new e({kernel:t,rootNode:P,functionNodes:G,nativeFunctions:d,subKernelNodes:z});return U}constructor(e){if(e=e||{},this.kernel=e.kernel,this.rootNode=e.rootNode,this.functionNodes=e.functionNodes||[],this.subKernelNodes=e.subKernelNodes||[],this.nativeFunctions=e.nativeFunctions||[],this.functionMap={},this.nativeFunctionNames=[],this.lookupChain=[],this.functionNodeDependencies={},this.functionCalls={},this.rootNode&&(this.functionMap.kernel=this.rootNode),this.functionNodes)for(let e=0;e-1){const r=t.indexOf(e);if(-1===r)t.push(e);else{const e=t.splice(r,1)[0];t.push(e)}return t}const r=this.functionMap[e];if(r){const n=t.indexOf(e);if(-1===n){t.push(e),r.toString();for(let e=0;e-1){t.push(this.nativeFunctions[s].source);continue}const i=this.functionMap[n];i&&t.push(i.toString())}return t}toJSON(){return this.traceFunctionCalls(this.rootNode.name).reverse().map(e=>{const t=this.nativeFunctions.indexOf(e);if(t>-1)return{name:e,source:this.nativeFunctions[t].source};if(this.functionMap[e])return this.functionMap[e].toJSON();throw new Error(`function ${e} not found`)})}fromJSON(e,t){this.functionMap={};for(let r=0;r0){const s=t.arguments;for(let t=0;t{const{utils:r}=i();function n(e){return e.length>0?e[e.length-1]:null}const s="trackIdentifiers",a="memberExpression",o="inForLoopInit";t.exports={FunctionTracer:class{constructor(e){this.runningContexts=[],this.functionContexts=[],this.contexts=[],this.functionCalls=[],this.declarations=[],this.identifiers=[],this.functions=[],this.returnStatements=[],this.trackedIdentifiers=null,this.states=[],this.newFunctionContext(),this.scan(e)}isState(e){return this.states[this.states.length-1]===e}hasState(e){return this.states.indexOf(e)>-1}pushState(e){this.states.push(e)}popState(e){if(!this.isState(e))throw new Error(`Cannot pop the non-active state "${e}"`);this.states.pop()}get currentFunctionContext(){return n(this.functionContexts)}get currentContext(){return n(this.runningContexts)}newFunctionContext(){const e={"@contextType":"function"};this.contexts.push(e),this.functionContexts.push(e)}newContext(e){const t=Object.assign({"@contextType":"const/let"},this.currentContext);this.contexts.push(t),this.runningContexts.push(t),e();const{currentFunctionContext:r}=this;for(const e in r)r.hasOwnProperty(e)&&!t.hasOwnProperty(e)&&(t[e]=r[e]);return this.runningContexts.pop(),t}useFunctionContext(e){const t=n(this.functionContexts);this.runningContexts.push(t),e(),this.runningContexts.pop()}getIdentifiers(e){const t=this.trackedIdentifiers=[];return this.pushState(s),e(),this.trackedIdentifiers=null,this.popState(s),t}getDeclaration(e){const{currentContext:t,currentFunctionContext:r,runningContexts:n}=this,s=t[e]||r[e]||null;if(!s&&t===r&&n.length>0){const t=n[n.length-2];if(t[e])return t[e]}return s}scan(e){if(e)if(Array.isArray(e))for(let t=0;t{this.scan(e.body)});break;case"BlockStatement":this.newContext(()=>{this.scan(e.body)});break;case"AssignmentExpression":case"LogicalExpression":case"BinaryExpression":this.scan(e.left),this.scan(e.right);break;case"UpdateExpression":if("++"===e.operator){const t=this.getDeclaration(e.argument.name);t&&(t.suggestedType="Integer")}this.scan(e.argument);break;case"UnaryExpression":this.scan(e.argument);break;case"VariableDeclaration":"var"===e.kind?this.useFunctionContext(()=>{e.declarations=r.normalizeDeclarations(e),this.scan(e.declarations)}):(e.declarations=r.normalizeDeclarations(e),this.scan(e.declarations));break;case"VariableDeclarator":{const{currentContext:t}=this,r=this.hasState(o),n={ast:e,context:t,name:e.id.name,origin:"declaration",inForLoopInit:r,inForLoopTest:null,assignable:t===this.currentFunctionContext||!r&&!t.hasOwnProperty(e.id.name),suggestedType:null,valueType:null,dependencies:null,isSafe:null};t[e.id.name]||(t[e.id.name]=n),this.declarations.push(n),this.scan(e.id),this.scan(e.init);break}case"FunctionExpression":case"FunctionDeclaration":0===this.runningContexts.length?this.scan(e.body):this.functions.push(e);break;case"IfStatement":this.scan(e.test),this.scan(e.consequent),e.alternate&&this.scan(e.alternate);break;case"ForStatement":{let t;const r=this.newContext(()=>{this.pushState(o),this.scan(e.init),this.popState(o),t=this.getIdentifiers(()=>{this.scan(e.test)}),this.scan(e.update),this.newContext(()=>{this.scan(e.body)})});if(t)for(const e in r)"@contextType"!==e&&t.indexOf(e)>-1&&(r[e].inForLoopTest=!0);break}case"DoWhileStatement":case"WhileStatement":this.newContext(()=>{this.scan(e.body),this.scan(e.test)});break;case"Identifier":this.isState(s)&&this.trackedIdentifiers.push(e.name),this.identifiers.push({context:this.currentContext,declaration:this.getDeclaration(e.name),ast:e});break;case"ReturnStatement":this.returnStatements.push(e),this.scan(e.argument);break;case"MemberExpression":this.pushState(a),this.scan(e.object),this.scan(e.property),this.popState(a);break;case"ExpressionStatement":this.scan(e.expression);break;case"SequenceExpression":this.scan(e.expressions);break;case"CallExpression":this.functionCalls.push({context:this.currentContext,ast:e}),this.scan(e.arguments);break;case"ArrayExpression":this.scan(e.elements);break;case"ConditionalExpression":this.scan(e.test),this.scan(e.alternate),this.scan(e.consequent);break;case"SwitchStatement":this.scan(e.discriminant),this.scan(e.cases);break;case"SwitchCase":this.scan(e.test),this.scan(e.consequent);break;case"ThisExpression":case"Literal":case"DebuggerStatement":case"EmptyStatement":case"BreakStatement":case"ContinueStatement":break;default:throw new Error(`unhandled type "${e.type}"`)}}}}}),h=e((e,t)=>{const n=r(),{utils:s}=i(),{FunctionTracer:a}=u(),o=["E","PI","SQRT2","SQRT1_2","LN2","LN10","LOG2E","LOG10E"],h=["abs","acos","acosh","asin","asinh","atan","atan2","atanh","cbrt","ceil","clz32","cos","cosh","expm1","exp","floor","fround","imul","log","log2","log10","log1p","max","min","pow","random","round","sign","sin","sinh","sqrt","tan","tanh","trunc"],l=["value","value[]","value[][]","value[][][]","value[][][][]","value.value","value.thread.value","this.thread.value","this.output.value","this.constants.value","this.constants.value[]","this.constants.value[][]","this.constants.value[][][]","this.constants.value[][][][]","fn()[]","fn()[][]","fn()[][][]","[][]"];const c={Number:"Number",Float:"Float",Integer:"Integer",Array:"Number","Array(2)":"Number","Array(3)":"Number","Array(4)":"Number","Matrix(2)":"Number","Matrix(3)":"Number","Matrix(4)":"Number",Array2D:"Number",Array3D:"Number",Input:"Number",HTMLCanvas:"Array(4)",OffscreenCanvas:"Array(4)",HTMLImage:"Array(4)",ImageBitmap:"Array(4)",ImageData:"Array(4)",HTMLVideo:"Array(4)",HTMLImageArray:"Array(4)",NumberTexture:"Number",MemoryOptimizedNumberTexture:"Number","Array1D(2)":"Array(2)","Array1D(3)":"Array(3)","Array1D(4)":"Array(4)","Array2D(2)":"Array(2)","Array2D(3)":"Array(3)","Array2D(4)":"Array(4)","Array3D(2)":"Array(2)","Array3D(3)":"Array(3)","Array3D(4)":"Array(4)","ArrayTexture(1)":"Number","ArrayTexture(2)":"Array(2)","ArrayTexture(3)":"Array(3)","ArrayTexture(4)":"Array(4)"};let p=536870912;function d(e,t){return e.start=p++,e.end=p++,t&&t.loc&&(e.loc=t.loc),e}function f(e,t){return e&&e.body&&"BlockStatement"===e.body.type?(m(e.body,t),e):e}function m(e,t){e.body=g(e.body,t)}function g(e,t){const r=[];for(let n=0;n{if(!e||"object"!=typeof e||r)return e;if(Array.isArray(e))return e.map(n);switch(e.type){case"ContinueStatement":return e.label?(r=!0,e):d({type:"BlockStatement",body:[...v(t),e]},e);case"ForStatement":case"WhileStatement":case"DoWhileStatement":case"FunctionExpression":case"FunctionDeclaration":case"ArrowFunctionExpression":default:return e;case"IfStatement":return e.consequent=n(e.consequent),e.alternate&&(e.alternate=n(e.alternate)),e;case"BlockStatement":return e.body=e.body.map(n),e;case"SwitchStatement":for(let t=0;t0?(r.push(e),r):[e]}case"WhileStatement":case"DoWhileStatement":return e.body&&(e.body=y(e.body,t)),[e];case"SwitchStatement":for(let r=0;r0&&this.argumentTypes.length!==this.argumentNames.length)throw new Error(`argumentTypes count of ${this.argumentTypes.length} exceeds ${this.argumentNames.length}`);if(this.output.length<1)throw new Error("this.output is not big enough")}isIdentifierConstant(e){return!!this.constants&&this.constants.hasOwnProperty(e)}isInput(e){return"Input"===this.argumentTypes[this.argumentNames.indexOf(e)]}pushState(e){this.states.push(e)}popState(e){if(this.state!==e)throw new Error(`Cannot popState ${e} when in ${this.state}`);this.states.pop()}isState(e){return this.state===e}get state(){return this.states[this.states.length-1]}astMemberExpressionUnroll(e){if("Identifier"===e.type)return e.name;if("ThisExpression"===e.type)return"this";if("MemberExpression"===e.type&&e.object&&e.property)return e.object.hasOwnProperty("name")&&"Math"!==e.object.name?this.astMemberExpressionUnroll(e.property):this.astMemberExpressionUnroll(e.object)+"."+this.astMemberExpressionUnroll(e.property);if(e.hasOwnProperty("expressions")){const t=e.expressions[0];if("Literal"===t.type&&0===t.value&&2===e.expressions.length)return this.astMemberExpressionUnroll(e.expressions[1])}throw this.astErrorOutput("Unknown astMemberExpressionUnroll",e)}get requiresSequenceFreeForInit(){return!1}getJsAST(e){if(this.ast)return this.ast;if("object"==typeof this.source)return f(this.source,this.requiresSequenceFreeForInit),this.traceFunctionAST(this.source),this.ast=this.source;if(null===(e=e||n))throw new Error("Missing JS to AST parser");const t=Object.freeze(e.parse(`const parser_${this.name} = ${this.source};`,{locations:!0,ecmaVersion:2020})),r=t.body[0].declarations[0].init;if(f(r,this.requiresSequenceFreeForInit),this.traceFunctionAST(r),!t)throw new Error("Failed to parse JS code");return this.ast=r}traceFunctionAST(e){const{contexts:t,declarations:r,functions:n,identifiers:s,functionCalls:i}=new a(e);this.contexts=t,this.identifiers=s,this.functionCalls=i,this.functions=n;for(let e=0;e":case"<":return"Boolean";case"&":case"|":case"^":case"<<":case">>":case">>>":return"Integer"}const r=this.getType(e.left);if(this.isState("skip-literal-correction"))return r;if("LiteralInteger"===r){const t=this.getType(e.right);return"LiteralInteger"===t?e.left.value%1==0?"Integer":"Float":t}if("Integer"===r){const t=this.getType(e.right);if("Number"===t||"Float"===t)return t}return c[r]||r;case"UpdateExpression":case"ReturnStatement":return this.getType(e.argument);case"UnaryExpression":return"~"===e.operator?"Integer":this.getType(e.argument);case"VariableDeclaration":{const t=e.declarations;let r;for(let e=0;ee.isSafe)}getDependencies(e,t,r){if(t||(t=[]),!e)return null;if(Array.isArray(e)){for(let n=0;n-1/0&&e.value<1/0&&!isNaN(e.value))});break;case"VariableDeclarator":return this.getDependencies(e.init,t,r);case"Identifier":const n=this.getDeclaration(e);if(n)t.push({name:e.name,origin:"declaration",isSafe:!r&&this.isSafeDependencies(n.dependencies)});else if(this.argumentNames.indexOf(e.name)>-1)t.push({name:e.name,origin:"argument",isSafe:!1});else if(this.strictTypingChecking)throw new Error(`Cannot find identifier origin "${e.name}"`);break;case"FunctionDeclaration":return this.getDependencies(e.body.body[e.body.body.length-1],t,r);case"ReturnStatement":return this.getDependencies(e.argument,t);case"BinaryExpression":case"LogicalExpression":return r="/"===e.operator||"*"===e.operator,this.getDependencies(e.left,t,r),this.getDependencies(e.right,t,r),t;case"UnaryExpression":case"UpdateExpression":return this.getDependencies(e.argument,t,r);case"VariableDeclaration":return this.getDependencies(e.declarations,t,r);case"ArrayExpression":return t.push({origin:"declaration",isSafe:!0}),t;case"CallExpression":return t.push({origin:"function",isSafe:!0}),t;case"MemberExpression":const s=this.getMemberExpressionDetails(e);switch(s.signature){case"value[]":this.getDependencies(e.object,t,r);break;case"value[][]":this.getDependencies(e.object.object,t,r);break;case"value[][][]":this.getDependencies(e.object.object.object,t,r);break;case"this.output.value":this.dynamicOutput&&t.push({name:s.name,origin:"output",isSafe:!1})}if(s)return s.property&&this.getDependencies(s.property,t,r),s.xProperty&&this.getDependencies(s.xProperty,t,r),s.yProperty&&this.getDependencies(s.yProperty,t,r),s.zProperty&&this.getDependencies(s.zProperty,t,r),t;case"SequenceExpression":return this.getDependencies(e.expressions,t,r);default:throw this.astErrorOutput(`Unhandled type ${e.type} in getDependencies`,e)}return t}getVariableSignature(e,t){if(!this.isAstVariable(e))throw new Error(`ast of type "${e.type}" is not a variable signature`);if("Identifier"===e.type)return"value";const r=[];for(;e;)e.computed?r.push("[]"):"ThisExpression"===e.type?r.unshift("this"):e.property&&e.property.name?"x"===e.property.name||"y"===e.property.name||"z"===e.property.name?r.unshift(t?"."+e.property.name:".value"):"constants"===e.property.name||"thread"===e.property.name||"output"===e.property.name?r.unshift("."+e.property.name):r.unshift(t?"."+e.property.name:".value"):e.name?r.unshift(t?e.name:"value"):e.callee&&e.callee.name?r.unshift(t?e.callee.name+"()":"fn()"):e.elements?r.unshift("[]"):r.unshift("unknown"),e=e.object;const n=r.join("");return t||l.includes(n)?n:null}build(){return this.toString().length>0}astGeneric(e,t){if(null===e)throw this.astErrorOutput("NULL ast",e);if(Array.isArray(e)){for(let r=0;r0?n[n.length-1]:0;return new Error(`${e} on line ${n.length}, position ${i.length}:\n ${r}`)}astDebuggerStatement(e,t){return t}astConditionalExpression(e,t){if("ConditionalExpression"!==e.type)throw this.astErrorOutput("Not a conditional expression",e);return t.push("("),this.astGeneric(e.test,t),t.push("?"),this.astGeneric(e.consequent,t),t.push(":"),this.astGeneric(e.alternate,t),t.push(")"),t}astFunction(e,t){throw new Error(`"astFunction" not defined on ${this.constructor.name}`)}astFunctionDeclaration(e,t){return this.isChildFunction(e)?t:this.astFunction(e,t)}astFunctionExpression(e,t){return this.isChildFunction(e)?t:this.astFunction(e,t)}isChildFunction(e){for(let t=0;t1?t.push("(",n.join(","),")"):t.push(n[0]),t}astUnaryExpression(e,t){return this.checkAndUpconvertBitwiseUnary(e,t)||(e.prefix?(t.push(e.operator),this.astGeneric(e.argument,t)):(this.astGeneric(e.argument,t),t.push(e.operator))),t}checkAndUpconvertBitwiseUnary(e,t){}astUpdateExpression(e,t){return e.prefix?(t.push(e.operator),this.astGeneric(e.argument,t)):(this.astGeneric(e.argument,t),t.push(e.operator)),t}astLogicalExpression(e,t){return t.push("("),this.astGeneric(e.left,t),t.push(e.operator),this.astGeneric(e.right,t),t.push(")"),t}astMemberExpression(e,t){return t}astCallExpression(e,t){return t}astArrayExpression(e,t){return t}getMemberExpressionDetails(e){if("MemberExpression"!==e.type)throw this.astErrorOutput(`Expression ${e.type} not a MemberExpression`,e);let t=null,r=null;const n=this.getVariableSignature(e);switch(n){case"value":return null;case"value.thread.value":case"this.thread.value":case"this.output.value":return{signature:n,type:"Integer",name:e.property.name};case"value[]":if("string"!=typeof e.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.name,{name:t,origin:"user",signature:n,type:this.getVariableType(e.object),xProperty:e.property};case"value[][]":if("string"!=typeof e.object.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.object.name,{name:t,origin:"user",signature:n,type:this.getVariableType(e.object.object),yProperty:e.object.property,xProperty:e.property};case"value[][][]":if("string"!=typeof e.object.object.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.object.object.name,{name:t,origin:"user",signature:n,type:this.getVariableType(e.object.object.object),zProperty:e.object.object.property,yProperty:e.object.property,xProperty:e.property};case"value[][][][]":if("string"!=typeof e.object.object.object.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.object.object.object.name,{name:t,origin:"user",signature:n,type:this.getVariableType(e.object.object.object.object),zProperty:e.object.object.property,yProperty:e.object.property,xProperty:e.property};case"value.value":if("string"!=typeof e.property.name)throw this.astErrorOutput("Unexpected expression",e);if(this.isAstMathVariable(e))return t=e.property.name,{name:t,origin:"Math",type:"Number",signature:n};switch(e.property.name){case"r":case"g":case"b":case"a":return t=e.object.name,{name:t,property:e.property.name,origin:"user",signature:n,type:"Number"};default:throw this.astErrorOutput("Unexpected expression",e)}case"this.constants.value":if("string"!=typeof e.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.property.name,r=this.getConstantType(t),!r)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:r,origin:"constants",signature:n};case"this.constants.value[]":if("string"!=typeof e.object.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.object.property.name,r=this.getConstantType(t),!r)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:r,origin:"constants",signature:n,xProperty:e.property};case"this.constants.value[][]":if("string"!=typeof e.object.object.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.object.object.property.name,r=this.getConstantType(t),!r)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:r,origin:"constants",signature:n,yProperty:e.object.property,xProperty:e.property};case"this.constants.value[][][]":if("string"!=typeof e.object.object.object.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.object.object.object.property.name,r=this.getConstantType(t),!r)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:r,origin:"constants",signature:n,zProperty:e.object.object.property,yProperty:e.object.property,xProperty:e.property};case"fn()[]":case"fn()[][]":case"[][]":return{signature:n,property:e.property};default:throw this.astErrorOutput("Unexpected expression",e)}}findIdentifierOrigin(e){const t=[this.ast];for(;t.length>0;){const r=t[0];if("VariableDeclarator"===r.type&&r.id&&r.id.name&&r.id.name===e.name)return r;if(t.shift(),r.argument)t.push(r.argument);else if(r.body)t.push(r.body);else if(r.declarations)t.push(r.declarations);else if(Array.isArray(r))for(let e=0;e0;){const e=t.pop();if("ReturnStatement"===e.type)return e;if("FunctionDeclaration"!==e.type)if(e.argument)t.push(e.argument);else if(e.body)t.push(e.body);else if(e.declarations)t.push(e.declarations);else if(Array.isArray(e))for(let r=0;r{const{FunctionNode:r}=h();t.exports={CPUFunctionNode:class extends r{astFunction(e,t){if(!this.isRootKernel){t.push("function"),t.push(" "),t.push(this.name),t.push("(");for(let e=0;e0&&t.push(", "),t.push("user_"),t.push(r)}t.push(") {\n")}for(let r=0;r0&&t.push(r.join(""),";\n"),t.push(`for (let ${e}=0;${e}0&&t.push(`if (!${n.join("")}) break;\n`),t.push(i.join("")),t.push(`\n${s.join("")};`),t.push("}\n")}return t}astWhileStatement(e,t){if("WhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);return t.push("for (let i = 0; i < LOOP_MAX; i++) {"),t.push("if ("),this.astGeneric(e.test,t),t.push(") {\n"),this.astGeneric(e.body,t),t.push("} else {\n"),t.push("break;\n"),t.push("}\n"),t.push("}\n"),t}astDoWhileStatement(e,t){if("DoWhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);return t.push("for (let i = 0; i < LOOP_MAX; i++) {"),this.astGeneric(e.body,t),t.push("if (!"),this.astGeneric(e.test,t),t.push(") {\n"),t.push("break;\n"),t.push("}\n"),t.push("}\n"),t}astAssignmentExpression(e,t){const r=this.getDeclaration(e.left);if(r&&!r.assignable)throw this.astErrorOutput(`Variable ${e.left.name} is not assignable here`,e);const n=this.isState("assignment-as-statement");return n?this.popState("assignment-as-statement"):t.push("("),this.astGeneric(e.left,t),t.push(e.operator),this.astGeneric(e.right,t),n||t.push(")"),t}astBlockStatement(e,t){if(this.isState("loop-body")){this.pushState("block-body");for(let r=0;r0&&t.push(",");const n=r[e],s=this.getDeclaration(n.id);s.valueType||(s.valueType=this.getType(n.init)),this.astGeneric(n,t)}return this.isState("in-for-loop-init")||t.push(";"),t}astIfStatement(e,t){return t.push("if ("),this.astGeneric(e.test,t),t.push(")"),"BlockStatement"===e.consequent.type?this.astGeneric(e.consequent,t):(t.push(" {\n"),this.astGeneric(e.consequent,t),t.push("\n}\n")),e.alternate&&(t.push("else "),"BlockStatement"===e.alternate.type||"IfStatement"===e.alternate.type?this.astGeneric(e.alternate,t):(t.push(" {\n"),this.astGeneric(e.alternate,t),t.push("\n}\n"))),t}astSwitchStatement(e,t){const{discriminant:r,cases:n}=e;t.push("switch ("),this.astGeneric(r,t),t.push(") {\n");for(let e=0;e0&&(this.astGeneric(n[e].consequent,t),t.push("break;\n"))):(t.push("default:\n"),this.astGeneric(n[e].consequent,t),n[e].consequent&&n[e].consequent.length>0&&t.push("break;\n"));t.push("\n}")}astThisExpression(e,t){return t.push("_this"),t}astMemberExpression(e,t){const{signature:r,type:n,property:s,xProperty:i,yProperty:a,zProperty:o,name:u,origin:h}=this.getMemberExpressionDetails(e);switch(r){case"this.thread.value":return t.push(`_this.thread.${u}`),t;case"this.output.value":switch(u){case"x":t.push("outputX");break;case"y":t.push("outputY");break;case"z":t.push("outputZ");break;default:throw this.astErrorOutput("Unexpected expression",e)}return t;case"value":default:throw this.astErrorOutput("Unexpected expression",e);case"value[]":case"value[][]":case"value[][][]":case"value.value":if("Math"===h)return t.push(Math[u]),t;switch(s){case"r":return t.push(`user_${u}[0]`),t;case"g":return t.push(`user_${u}[1]`),t;case"b":return t.push(`user_${u}[2]`),t;case"a":return t.push(`user_${u}[3]`),t}break;case"this.constants.value":case"this.constants.value[]":case"this.constants.value[][]":case"this.constants.value[][][]":break;case"fn()[]":return this.astGeneric(e.object,t),t.push("["),this.astGeneric(e.property,t),t.push("]"),t;case"fn()[][]":return this.astGeneric(e.object.object,t),t.push("["),this.astGeneric(e.object.property,t),t.push("]"),t.push("["),this.astGeneric(e.property,t),t.push("]"),t}if(!e.computed)switch(n){case"Number":case"Integer":case"Float":case"Boolean":return t.push(`${h}_${u}`),t}const l=`${h}_${u}`;{let e,r;if("constants"===h){const t=this.constants[u];r="Input"===this.constantTypes[u],e=r?t.size:null}else r=this.isInput(u),e=r?this.argumentSizes[this.argumentNames.indexOf(u)]:null;t.push(`${l}`),o&&a?r?(t.push("[("),this.astGeneric(o,t),t.push(`*${this.dynamicArguments?"(outputY * outputX)":e[1]*e[0]})+(`),this.astGeneric(a,t),t.push(`*${this.dynamicArguments?"outputX":e[0]})+`),this.astGeneric(i,t),t.push("]")):(t.push("["),this.astGeneric(o,t),t.push("]"),t.push("["),this.astGeneric(a,t),t.push("]"),t.push("["),this.astGeneric(i,t),t.push("]")):a?r?(t.push("[("),this.astGeneric(a,t),t.push(`*${this.dynamicArguments?"outputX":e[0]})+`),this.astGeneric(i,t),t.push("]")):(t.push("["),this.astGeneric(a,t),t.push("]"),t.push("["),this.astGeneric(i,t),t.push("]")):void 0!==i&&(t.push("["),this.astGeneric(i,t),t.push("]"))}return t}astCallExpression(e,t){if("CallExpression"!==e.type)throw this.astErrorOutput("Unknown CallExpression",e);let r=this.astMemberExpressionUnroll(e.callee);this.calledFunctions.indexOf(r)<0&&this.calledFunctions.push(r),this.isAstMathFunction(e),this.onFunctionCall&&this.onFunctionCall(this.name,r,e.arguments),t.push(r),t.push("(");const n=this.lookupFunctionArgumentTypes(r)||[];for(let s=0;s0&&t.push(", "),this.astGeneric(i,t)}return t.push(")"),t}astArrayExpression(e,t){const r=this.getType(e),n=e.elements.length,s=[];for(let t=0;t{const{utils:r}=i();t.exports={cpuKernelString:function(e,t){const n=[],s=[],i=[],a=!/^function/.test(e.color.toString());if(n.push(" const { context, canvas, constants: incomingConstants } = settings;",` const output = new Int32Array(${JSON.stringify(Array.from(e.output))});`,` const _constantTypes = ${JSON.stringify(e.constantTypes)};`,` const _constants = ${function(e,t){const r=[];for(const n in t){if(!t.hasOwnProperty(n))continue;const s=t[n],i=e[n];switch(s){case"Number":case"Integer":case"Float":case"Boolean":r.push(`${n}:${i}`);break;case"Array(2)":case"Array(3)":case"Array(4)":case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":r.push(`${n}:new ${i.constructor.name}(${JSON.stringify(Array.from(i))})`)}}return`{ ${r.join()} }`}(e.constants,e.constantTypes)};`),s.push(" constants: _constants,"," context,"," output,"," thread: {x: 0, y: 0, z: 0},"),e.graphical){n.push(` const _imageData = context.createImageData(${e.output[0]}, ${e.output[1]});`),n.push(` const _colorData = new Uint8ClampedArray(${e.output[0]} * ${e.output[1]} * 4);`);const t=r.flattenFunctionToString((a?"function ":"")+e.color.toString(),{thisLookup:t=>{switch(t){case"_colorData":return"_colorData";case"_imageData":return"_imageData";case"output":return"output";case"thread":return"this.thread"}return JSON.stringify(e[t])},findDependency:(e,t)=>null}),o=r.flattenFunctionToString((a?"function ":"")+e.getPixels.toString(),{thisLookup:t=>{switch(t){case"_colorData":return"_colorData";case"_imageData":return"_imageData";case"output":return"output";case"thread":return"this.thread"}return JSON.stringify(e[t])},findDependency:()=>null});s.push(" _imageData,"," _colorData,",` color: ${t},`),i.push(` kernel.getPixels = ${o};`)}const o=[],u=Object.keys(e.constantTypes);for(let t=0;t"this"===t?(a?"function ":"")+e[r].toString():null,thisLookup:e=>{switch(e){case"canvas":return;case"context":return"context"}}});i.push(t),s.push(" _mediaTo2DArray,"),s.push(" _imageTo3DArray,")}else if(-1!==e.argumentTypes.indexOf("HTMLImage")||-1!==o.indexOf("HTMLImage")){const t=r.flattenFunctionToString((a?"function ":"")+e._mediaTo2DArray.toString(),{findDependency:(e,t)=>null,thisLookup:e=>{switch(e){case"canvas":return"settings.canvas";case"context":return"settings.context"}throw new Error("unhandled thisLookup")}});i.push(t),s.push(" _mediaTo2DArray,")}return`function(settings) {\n${n.join("\n")}\n for (const p in _constantTypes) {\n if (!_constantTypes.hasOwnProperty(p)) continue;\n const type = _constantTypes[p];\n switch (type) {\n case 'Number':\n case 'Integer':\n case 'Float':\n case 'Boolean':\n case 'Array(2)':\n case 'Array(3)':\n case 'Array(4)':\n case 'Matrix(2)':\n case 'Matrix(3)':\n case 'Matrix(4)':\n if (incomingConstants.hasOwnProperty(p)) {\n console.warn('constant ' + p + ' of type ' + type + ' cannot be resigned');\n }\n continue;\n }\n if (!incomingConstants.hasOwnProperty(p)) {\n throw new Error('constant ' + p + ' not found');\n }\n _constants[p] = incomingConstants[p];\n }\n const kernel = (function() {\n${e._kernelString}\n })\n .apply({ ${s.join("\n")} });\n ${i.join("\n")}\n return kernel;\n}`}}}),p=e((e,t)=>{const{Kernel:r}=a(),{FunctionBuilder:n}=o(),{CPUFunctionNode:s}=l(),{utils:u}=i(),{cpuKernelString:h}=c();t.exports={CPUKernel:class extends r{static getFeatures(){return this.features}static get features(){return Object.freeze({kernelMap:!0,isIntegerDivisionAccurate:!0})}static get isSupported(){return!0}static isContextMatch(e){return!1}static get mode(){return"cpu"}static nativeFunctionArguments(){return null}static nativeFunctionReturnType(){throw new Error(`Looking up native function return type not supported on ${this.name}`)}static combineKernels(e){return e}static getSignature(e,t){return"cpu"+(t.length>0?":"+t.join(","):"")}constructor(e,t){super(e,t),this.mergeSettings(e.settings||t),this._imageData=null,this._colorData=null,this._kernelString=null,this._prependedString=[],this.thread={x:0,y:0,z:0},this.translatedSources=null}initCanvas(){return"undefined"!=typeof document?document.createElement("canvas"):"undefined"!=typeof OffscreenCanvas?new OffscreenCanvas(0,0):void 0}initContext(){return this.canvas?this.canvas.getContext("2d",{willReadFrequently:!0}):null}initPlugins(e){return[]}validateSettings(e){if(!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=u.getVariableType(e[0],this.strictIntegers);if("Array"===t)this.output=u.getDimensions(t);else{if("NumberTexture"!==t&&"ArrayTexture(4)"!==t)throw new Error("Auto output not supported for input type: "+t);this.output=e[0].output}}if(this.graphical&&2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");this.checkOutput()}translateSource(){if(this.leadingReturnStatement=this.output.length>1?"resultX[x] = ":"result[x] = ",this.subKernels){const e=[];for(let t=0;t1?`resultX_${r}[x] = subKernelResult_${r};\n`:`result_${r}[x] = subKernelResult_${r};\n`)}this.followingReturnStatement=e.join("")}const e=n.fromKernel(this,s);this.translatedSources=e.getPrototypes("kernel"),this.graphical||this.returnType||(this.returnType=e.getKernelResultType())}build(){if(this.built)return;if(null!==this.randomSeed&&console.warn("randomSeed is not supported in cpu mode; Math.random() will be unseeded"),this.setupConstants(),this.setupArguments(arguments),this.validateSettings(arguments),this.translateSource(),this.graphical){const{canvas:e,output:t}=this;if(!e)throw new Error("no canvas available for using graphical output");const r=t[0],n=t[1]||1;e.width=r,e.height=n,this._imageData=this.context.createImageData(r,n),this._colorData=new Uint8ClampedArray(r*n*4)}const e=this.getKernelString();this.kernelString=e,this.debug&&(console.log("Function output:"),console.log(e));try{this.run=new Function([],e).bind(this)()}catch(e){console.error("An error occurred compiling the javascript: ",e)}this.buildSignature(arguments),this.built=!0}color(e,t,r,n){void 0===n&&(n=1),e=Math.floor(255*e),t=Math.floor(255*t),r=Math.floor(255*r),n=Math.floor(255*n);const s=this.output[0],i=this.output[1],a=this.thread.x+(i-this.thread.y-1)*s;this._colorData[4*a+0]=e,this._colorData[4*a+1]=t,this._colorData[4*a+2]=r,this._colorData[4*a+3]=n}getKernelString(){if(null!==this._kernelString)return this._kernelString;let e=null,{translatedSources:t}=this;return t.length>1?t=t.filter(t=>/^function/.test(t)?t:(e=t,!1)):e=t.shift(),this._kernelString=` const LOOP_MAX = ${this._getLoopMaxString()};\n ${this.injectedNative||""}\n const _this = this;\n ${this._resultKernelHeader()}\n ${this._processConstants()}\n return (${this.argumentNames.map(e=>"user_"+e).join(", ")}) => {\n ${this._prependedString.join("")}\n ${this._earlyThrows()}\n ${this._processArguments()}\n ${this.graphical?this._graphicalKernelBody(e):this._resultKernelBody(e)}\n ${t.length>0?t.join("\n"):""}\n };`}toString(){return h(this)}_getLoopMaxString(){return this.loopMaxIterations?` ${parseInt(this.loopMaxIterations)};`:" 1000;"}_processConstants(){if(!this.constants)return"";const e=[];for(let t in this.constants)switch(this.constantTypes[t]){case"HTMLCanvas":case"OffscreenCanvas":case"HTMLImage":case"ImageBitmap":case"ImageData":case"HTMLVideo":e.push(` const constants_${t} = this._mediaTo2DArray(this.constants.${t});\n`);break;case"HTMLImageArray":e.push(` const constants_${t} = this._imageTo3DArray(this.constants.${t});\n`);break;case"Input":e.push(` const constants_${t} = this.constants.${t}.value;\n`);break;default:e.push(` const constants_${t} = this.constants.${t};\n`)}return e.join("")}_earlyThrows(){if(this.graphical)return"";if(this.immutable)return"";if(!this.pipeline)return"";const e=[];for(let t=0;t`user_${n} === result_${e.name}`).join(" || ");t.push(`user_${n} === result${s?` || ${s}`:""}`)}return`if (${t.join(" || ")}) throw new Error('Source and destination arrays are the same. Use immutable = true');`}_processArguments(){const e=[];for(let t=0;t0?e.width:e.videoWidth,n=e.height>0?e.height:e.videoHeight;t.width=0;e--){const t=a[e]=new Array(r);for(let e=0;e`const result_${e.name} = new ${t}(outputX);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n this.thread.y = 0;\n this.thread.z = 0;\n ${e}\n }`}_mutableKernel1DResults(){const e=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const result = new ${e}(outputX);\n ${this._mapSubKernels(t=>`const result_${t.name} = new ${e}(outputX);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}`}_resultMutableKernel1DLoop(e){return` const outputX = _this.output[0];\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n this.thread.y = 0;\n this.thread.z = 0;\n ${e}\n }`}_resultImmutableKernel2DLoop(e){const t=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const result = new Array(outputY);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputY);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n this.thread.z = 0;\n this.thread.y = y;\n const resultX = result[y] = new ${t}(outputX);\n ${this._mapSubKernels(e=>`const resultX_${e.name} = result_${e.name}[y] = new ${t}(outputX);\n`).join("")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }`}_mutableKernel2DResults(){const e=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const result = new Array(outputY);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputY);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n const resultX = result[y] = new ${e}(outputX);\n ${this._mapSubKernels(t=>`const resultX_${t.name} = result_${t.name}[y] = new ${e}(outputX);\n`).join("")}\n }`}_resultMutableKernel2DLoop(e){const t=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n for (let y = 0; y < outputY; y++) {\n this.thread.z = 0;\n this.thread.y = y;\n const resultX = result[y];\n ${this._mapSubKernels(e=>`const resultX_${e.name} = result_${e.name}[y] = new ${t}(outputX);\n`).join("")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }`}_graphicalKernel2DLoop(e){return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n for (let y = 0; y < outputY; y++) {\n this.thread.z = 0;\n this.thread.y = y;\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }`}_resultImmutableKernel3DLoop(e){const t=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const outputZ = _this.output[2];\n const result = new Array(outputZ);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputZ);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let z = 0; z < outputZ; z++) {\n this.thread.z = z;\n const resultY = result[z] = new Array(outputY);\n ${this._mapSubKernels(e=>`const resultY_${e.name} = result_${e.name}[z] = new Array(outputY);\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n this.thread.y = y;\n const resultX = resultY[y] = new ${t}(outputX);\n ${this._mapSubKernels(e=>`const resultX_${e.name} = resultY_${e.name}[y] = new ${t}(outputX);\n`).join(" ")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }\n }`}_mutableKernel3DResults(){const e=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const outputZ = _this.output[2];\n const result = new Array(outputZ);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputZ);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let z = 0; z < outputZ; z++) {\n const resultY = result[z] = new Array(outputY);\n ${this._mapSubKernels(e=>`const resultY_${e.name} = result_${e.name}[z] = new Array(outputY);\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n const resultX = resultY[y] = new ${e}(outputX);\n ${this._mapSubKernels(t=>`const resultX_${t.name} = resultY_${t.name}[y] = new ${e}(outputX);\n`).join(" ")}\n }\n }`}_resultMutableKernel3DLoop(e){return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const outputZ = _this.output[2];\n for (let z = 0; z < outputZ; z++) {\n this.thread.z = z;\n const resultY = result[z];\n for (let y = 0; y < outputY; y++) {\n this.thread.y = y;\n const resultX = resultY[y];\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }\n }`}_kernelOutput(){return this.subKernels?`\n return {\n result: result,\n ${this.subKernels.map(e=>`${e.property}: result_${e.name}`).join(",\n ")}\n };`:"\n return result;"}_mapSubKernels(e){return null===this.subKernels?[""]:this.subKernels.map(e)}destroy(e){e&&delete this.canvas}static destroyContext(e){}toJSON(){const e=super.toJSON();return e.functionNodes=n.fromKernel(this,s).toJSON(),e}setOutput(e){super.setOutput(e);const[t,r]=this.output;this.graphical&&(this._imageData=this.context.createImageData(t,r),this._colorData=new Uint8ClampedArray(t*r*4))}prependString(e){if(this._kernelString)throw new Error("Kernel already built");this._prependedString.push(e)}hasPrependString(e){return this._prependedString.indexOf(e)>-1}}}}),d=e((e,t)=>{t.exports={}}),f=e((e,t)=>{const{Texture:r}=s();function n(e,t){e.activeTexture(e.TEXTURE15),e.bindTexture(e.TEXTURE_2D,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST)}t.exports={GLTexture:class extends r{get textureType(){throw new Error(`"textureType" not implemented on ${this.name}`)}clone(){return new this.constructor(this)}beforeMutate(){return this.texture._refs>1&&(this.newTexture(),!0)}cloneTexture(){this.texture._refs--;const{context:e,size:t,texture:r,kernel:s}=this;s.debug&&console.warn("cloning internal texture"),e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),n(e,r),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,r,0);const i=e.createTexture();n(e,i),e.texImage2D(e.TEXTURE_2D,0,this.internalFormat,t[0],t[1],0,this.textureFormat,this.textureType,null),e.copyTexSubImage2D(e.TEXTURE_2D,0,0,0,0,0,t[0],t[1]),i._refs=1,this.texture=i}newTexture(){this.texture._refs--;const e=this.context,t=this.size;this.kernel.debug&&console.warn("new internal texture");const r=e.createTexture();n(e,r),e.texImage2D(e.TEXTURE_2D,0,this.internalFormat,t[0],t[1],0,this.textureFormat,this.textureType,null),r._refs=1,this.texture=r}clear(){if(this.texture._refs){this.texture._refs--;const e=this.context,t=this.texture=e.createTexture();n(e,t);const r=this.size;t._refs=1,e.texImage2D(e.TEXTURE_2D,0,this.internalFormat,r[0],r[1],0,this.textureFormat,this.textureType,null)}const{context:e,texture:t}=this;e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),e.bindTexture(e.TEXTURE_2D,t),n(e,t),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t,0),e.clearColor(0,0,0,0),e.clear(e.COLOR_BUFFER_BIT|e.DEPTH_BUFFER_BIT)}delete(){this._deleted||(this._deleted=!0,this.texture._refs&&(this.texture._refs--,this.texture._refs)||(this.kernel&&this.kernel.deleteTexture?this.kernel.deleteTexture(this.texture):this.context.deleteTexture(this.texture)))}framebuffer(){return this._framebuffer||(this._framebuffer=this.kernel.getRawValueFramebuffer(this.size[0],this.size[1])),this._framebuffer}}}}),m=e((e,t)=>{const{utils:r}=i(),{GLTexture:n}=f();t.exports={GLTextureFloat:class extends n{get textureType(){return this.context.FLOAT}constructor(e){super(e),this.type="ArrayTexture(1)"}renderRawOutput(){const e=this.context,t=this.size;e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.texture,0);const r=new Float32Array(t[0]*t[1]*4);return e.readPixels(0,0,t[0],t[1],e.RGBA,e.FLOAT,r),r}renderValues(){return this._deleted?null:this.renderRawOutput()}toArray(){return r.erectFloat(this.renderValues(),this.output[0])}}}}),g=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray2Float:class extends n{constructor(e){super(e),this.type="ArrayTexture(2)"}toArray(){return r.erectArray2(this.renderValues(),this.output[0],this.output[1])}}}}),x=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray2Float2D:class extends n{constructor(e){super(e),this.type="ArrayTexture(2)"}toArray(){return r.erect2DArray2(this.renderValues(),this.output[0],this.output[1])}}}}),y=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray2Float3D:class extends n{constructor(e){super(e),this.type="ArrayTexture(2)"}toArray(){return r.erect3DArray2(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),b=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray3Float:class extends n{constructor(e){super(e),this.type="ArrayTexture(3)"}toArray(){return r.erectArray3(this.renderValues(),this.output[0])}}}}),T=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray3Float2D:class extends n{constructor(e){super(e),this.type="ArrayTexture(3)"}toArray(){return r.erect2DArray3(this.renderValues(),this.output[0],this.output[1])}}}}),S=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray3Float3D:class extends n{constructor(e){super(e),this.type="ArrayTexture(3)"}toArray(){return r.erect3DArray3(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),v=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray4Float:class extends n{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return r.erectArray4(this.renderValues(),this.output[0])}}}}),A=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray4Float2D:class extends n{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return r.erect2DArray4(this.renderValues(),this.output[0],this.output[1])}}}}),_=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureArray4Float3D:class extends n{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return r.erect3DArray4(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),w=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureFloat2D:class extends n{constructor(e){super(e),this.type="ArrayTexture(1)"}toArray(){return r.erect2DFloat(this.renderValues(),this.output[0],this.output[1])}}}}),E=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureFloat3D:class extends n{constructor(e){super(e),this.type="ArrayTexture(1)"}toArray(){return r.erect3DFloat(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),I=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureMemoryOptimized:class extends n{constructor(e){super(e),this.type="MemoryOptimizedNumberTexture"}toArray(){return r.erectMemoryOptimizedFloat(this.renderValues(),this.output[0])}}}}),k=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureMemoryOptimized2D:class extends n{constructor(e){super(e),this.type="MemoryOptimizedNumberTexture"}toArray(){return r.erectMemoryOptimized2DFloat(this.renderValues(),this.output[0],this.output[1])}}}}),D=e((e,t)=>{const{utils:r}=i(),{GLTextureFloat:n}=m();t.exports={GLTextureMemoryOptimized3D:class extends n{constructor(e){super(e),this.type="MemoryOptimizedNumberTexture"}toArray(){return r.erectMemoryOptimized3DFloat(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),C=e((e,t)=>{const{utils:r}=i(),{GLTexture:n}=f();t.exports={GLTextureUnsigned:class extends n{get textureType(){return this.context.UNSIGNED_BYTE}constructor(e){super(e),this.type="NumberTexture"}renderRawOutput(){const{context:e}=this;e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.texture,0);const t=new Uint8Array(this.size[0]*this.size[1]*4);return e.readPixels(0,0,this.size[0],this.size[1],e.RGBA,e.UNSIGNED_BYTE,t),t}renderValues(){return this._deleted?null:new Float32Array(this.renderRawOutput().buffer)}toArray(){return r.erectPackedFloat(this.renderValues(),this.output[0])}}}}),L=e((e,t)=>{const{utils:r}=i(),{GLTextureUnsigned:n}=C();t.exports={GLTextureUnsigned2D:class extends n{constructor(e){super(e),this.type="NumberTexture"}toArray(){return r.erect2DPackedFloat(this.renderValues(),this.output[0],this.output[1])}}}}),$=e((e,t)=>{const{utils:r}=i(),{GLTextureUnsigned:n}=C();t.exports={GLTextureUnsigned3D:class extends n{constructor(e){super(e),this.type="NumberTexture"}toArray(){return r.erect3DPackedFloat(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),F=e((e,t)=>{const{GLTextureUnsigned:r}=C();t.exports={GLTextureGraphical:class extends r{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return this.renderValues()}}}}),R=e((e,t)=>{const{Kernel:r}=a(),{utils:n}=i(),{GLTextureArray2Float:s}=g(),{GLTextureArray2Float2D:o}=x(),{GLTextureArray2Float3D:u}=y(),{GLTextureArray3Float:h}=b(),{GLTextureArray3Float2D:l}=T(),{GLTextureArray3Float3D:c}=S(),{GLTextureArray4Float:p}=v(),{GLTextureArray4Float2D:d}=A(),{GLTextureArray4Float3D:f}=_(),{GLTextureFloat:R}=m(),{GLTextureFloat2D:N}=w(),{GLTextureFloat3D:V}=E(),{GLTextureMemoryOptimized:M}=I(),{GLTextureMemoryOptimized2D:O}=k(),{GLTextureMemoryOptimized3D:P}=D(),{GLTextureUnsigned:G}=C(),{GLTextureUnsigned2D:z}=L(),{GLTextureUnsigned3D:U}=$(),{GLTextureGraphical:K}=F();const B={int:"Integer",float:"Number",vec2:"Array(2)",vec3:"Array(3)",vec4:"Array(4)"};t.exports={GLKernel:class extends r{static get mode(){return"gpu"}static getIsFloatRead(){const e=new this("function kernelFunction() {\n return 1;\n }",{context:this.testContext,canvas:this.testCanvas,validate:!1,output:[1],precision:"single",returnType:"Number",tactic:"speed"});e.build(),e.run();const t=e.renderOutput();return e.destroy(!0),1===t[0]}static getIsIntegerDivisionAccurate(){const e=new this(function(e,t){return e[this.thread.x]/t[this.thread.x]}.toString(),{context:this.testContext,canvas:this.testCanvas,validate:!1,output:[2],returnType:"Number",precision:"unsigned",tactic:"speed"}),t=[[6,6030401],[3,3991]];e.build.apply(e,t),e.run.apply(e,t);const r=e.renderOutput();return e.destroy(!0),2===r[0]&&1511===r[1]}static getIsSpeedTacticSupported(){const e=new this(function(e){return e[this.thread.x]}.toString(),{context:this.testContext,canvas:this.testCanvas,validate:!1,output:[4],returnType:"Number",precision:"unsigned",tactic:"speed"}),t=[[0,1,2,3]];e.build.apply(e,t),e.run.apply(e,t);const r=e.renderOutput();return e.destroy(!0),0===Math.round(r[0])&&1===Math.round(r[1])&&2===Math.round(r[2])&&3===Math.round(r[3])}static get testCanvas(){throw new Error(`"testCanvas" not defined on ${this.name}`)}static get testContext(){throw new Error(`"testContext" not defined on ${this.name}`)}static getFeatures(){const e=this.testContext,t=this.getIsDrawBuffers();return Object.freeze({isFloatRead:this.getIsFloatRead(),isIntegerDivisionAccurate:this.getIsIntegerDivisionAccurate(),isSpeedTacticSupported:this.getIsSpeedTacticSupported(),isTextureFloat:this.getIsTextureFloat(),isDrawBuffers:t,kernelMap:t,channelCount:this.getChannelCount(),maxTextureSize:this.getMaxTextureSize(),lowIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_INT),lowFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_FLOAT),mediumIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_INT),mediumFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_FLOAT),highIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_INT),highFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT)})}static setupFeatureChecks(){throw new Error(`"setupFeatureChecks" not defined on ${this.name}`)}static getSignature(e,t){return e.getVariablePrecisionString()+(t.length>0?":"+t.join(","):"")}setFixIntegerDivisionAccuracy(e){return this.fixIntegerDivisionAccuracy=e,this}setPrecision(e){return this.precision=e,this}setFloatTextures(e){return n.warnDeprecated("method","setFloatTextures","setOptimizeFloatMemory"),this.floatTextures=e,this}static nativeFunctionArguments(e){const t=[],r=[],n=[],s=/^[a-zA-Z_]/,i=/[a-zA-Z_0-9]/;let a=0,o=null,u=null;for(;a0?n[n.length-1]:null;if("FUNCTION_ARGUMENTS"!==c||"/"!==h||"*"!==l)if("MULTI_LINE_COMMENT"!==c||"*"!==h||"/"!==l)if("FUNCTION_ARGUMENTS"!==c||"/"!==h||"/"!==l)if("COMMENT"!==c||"\n"!==h)if(null!==c||"("!==h){if("FUNCTION_ARGUMENTS"===c){if(")"===h){n.pop();break}if("f"===h&&"l"===l&&"o"===e[a+2]&&"a"===e[a+3]&&"t"===e[a+4]&&" "===e[a+5]){n.push("DECLARE_VARIABLE"),u="float",o="",a+=6;continue}if("i"===h&&"n"===l&&"t"===e[a+2]&&" "===e[a+3]){n.push("DECLARE_VARIABLE"),u="int",o="",a+=4;continue}if("v"===h&&"e"===l&&"c"===e[a+2]&&"2"===e[a+3]&&" "===e[a+4]){n.push("DECLARE_VARIABLE"),u="vec2",o="",a+=5;continue}if("v"===h&&"e"===l&&"c"===e[a+2]&&"3"===e[a+3]&&" "===e[a+4]){n.push("DECLARE_VARIABLE"),u="vec3",o="",a+=5;continue}if("v"===h&&"e"===l&&"c"===e[a+2]&&"4"===e[a+3]&&" "===e[a+4]){n.push("DECLARE_VARIABLE"),u="vec4",o="",a+=5;continue}}else if("DECLARE_VARIABLE"===c){if(""===o){if(" "===h){a++;continue}if(!s.test(h))throw new Error("variable name is not expected string")}o+=h,i.test(l)||(n.pop(),r.push(o),t.push(B[u]))}a++}else n.push("FUNCTION_ARGUMENTS"),a++;else n.pop(),a++;else n.push("COMMENT"),a+=2;else n.pop(),a+=2;else n.push("MULTI_LINE_COMMENT"),a+=2}if(n.length>0)throw new Error("GLSL function was not parsable");return{argumentNames:r,argumentTypes:t}}static nativeFunctionReturnType(e){return B[e.match(/int|float|vec[2-4]/)[0]]}static combineKernels(e,t){e.apply(null,arguments);const{texSize:r,context:s,threadDim:i}=t.texSize;let a;if("single"===t.precision){const e=r[0],t=Math.ceil(r[1]/4);a=new Float32Array(e*t*4*4),s.readPixels(0,0,e,4*t,s.RGBA,s.FLOAT,a)}else{const e=new Uint8Array(r[0]*r[1]*4);s.readPixels(0,0,r[0],r[1],s.RGBA,s.UNSIGNED_BYTE,e),a=new Float32Array(e.buffer)}return a=a.subarray(0,i[0]*i[1]*i[2]),1===t.output.length?a:2===t.output.length?n.splitArray(a,t.output[0]):3===t.output.length?n.splitArray(a,t.output[0]*t.output[1]).map(function(e){return n.splitArray(e,t.output[0])}):void 0}constructor(e,t){super(e,t),this.transferValues=null,this.formatValues=null,this.TextureConstructor=null,this.renderOutput=null,this.renderRawOutput=null,this.texSize=null,this.translatedSource=null,this.compiledFragmentShader=null,this.compiledVertexShader=null,this.switchingKernels=null,this._textureSwitched=null,this._mappedTextureSwitched=null}checkTextureSize(){const{features:e}=this.constructor;if(this.texSize[0]>e.maxTextureSize||this.texSize[1]>e.maxTextureSize)throw new Error(`Texture size [${this.texSize[0]},${this.texSize[1]}] generated by kernel is larger than supported size [${e.maxTextureSize},${e.maxTextureSize}]`)}translateSource(){throw new Error(`"translateSource" not defined on ${this.constructor.name}`)}pickRenderStrategy(e){if(this.graphical)return this.renderRawOutput=this.readPackedPixelsToUint8Array,this.transferValues=e=>e,this.TextureConstructor=K,null;if("unsigned"===this.precision)if(this.renderRawOutput=this.readPackedPixelsToUint8Array,this.transferValues=this.readPackedPixelsToFloat32Array,this.pipeline)switch(this.renderOutput=this.renderTexture,null!==this.subKernels&&(this.renderKernels=this.renderKernelsToTextures),this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.output[2]>0?(this.TextureConstructor=U,null):this.output[1]>0?(this.TextureConstructor=z,null):(this.TextureConstructor=G,null);case"Array(2)":case"Array(3)":case"Array(4)":return this.requestFallback(e)}else switch(null!==this.subKernels&&(this.renderKernels=this.renderKernelsToArrays),this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.renderOutput=this.renderValues,this.output[2]>0?(this.TextureConstructor=U,this.formatValues=n.erect3DPackedFloat,null):this.output[1]>0?(this.TextureConstructor=z,this.formatValues=n.erect2DPackedFloat,null):(this.TextureConstructor=G,this.formatValues=n.erectPackedFloat,null);case"Array(2)":case"Array(3)":case"Array(4)":return this.requestFallback(e)}else{if("single"!==this.precision)throw new Error(`unhandled precision of "${this.precision}"`);if(this.renderRawOutput=this.readFloatPixelsToFloat32Array,this.transferValues=this.readFloatPixelsToFloat32Array,this.pipeline)switch(this.renderOutput=this.renderTexture,null!==this.subKernels&&(this.renderKernels=this.renderKernelsToTextures),this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.optimizeFloatMemory?this.output[2]>0?(this.TextureConstructor=P,null):this.output[1]>0?(this.TextureConstructor=O,null):(this.TextureConstructor=M,null):this.output[2]>0?(this.TextureConstructor=V,null):this.output[1]>0?(this.TextureConstructor=N,null):(this.TextureConstructor=R,null);case"Array(2)":return this.output[2]>0?(this.TextureConstructor=u,null):this.output[1]>0?(this.TextureConstructor=o,null):(this.TextureConstructor=s,null);case"Array(3)":return this.output[2]>0?(this.TextureConstructor=c,null):this.output[1]>0?(this.TextureConstructor=l,null):(this.TextureConstructor=h,null);case"Array(4)":return this.output[2]>0?(this.TextureConstructor=f,null):this.output[1]>0?(this.TextureConstructor=d,null):(this.TextureConstructor=p,null)}if(this.renderOutput=this.renderValues,null!==this.subKernels&&(this.renderKernels=this.renderKernelsToArrays),this.optimizeFloatMemory)switch(this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.output[2]>0?(this.TextureConstructor=P,this.formatValues=n.erectMemoryOptimized3DFloat,null):this.output[1]>0?(this.TextureConstructor=O,this.formatValues=n.erectMemoryOptimized2DFloat,null):(this.TextureConstructor=M,this.formatValues=n.erectMemoryOptimizedFloat,null);case"Array(2)":return this.output[2]>0?(this.TextureConstructor=u,this.formatValues=n.erect3DArray2,null):this.output[1]>0?(this.TextureConstructor=o,this.formatValues=n.erect2DArray2,null):(this.TextureConstructor=s,this.formatValues=n.erectArray2,null);case"Array(3)":return this.output[2]>0?(this.TextureConstructor=c,this.formatValues=n.erect3DArray3,null):this.output[1]>0?(this.TextureConstructor=l,this.formatValues=n.erect2DArray3,null):(this.TextureConstructor=h,this.formatValues=n.erectArray3,null);case"Array(4)":return this.output[2]>0?(this.TextureConstructor=f,this.formatValues=n.erect3DArray4,null):this.output[1]>0?(this.TextureConstructor=d,this.formatValues=n.erect2DArray4,null):(this.TextureConstructor=p,this.formatValues=n.erectArray4,null)}else switch(this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.output[2]>0?(this.TextureConstructor=V,this.formatValues=n.erect3DFloat,null):this.output[1]>0?(this.TextureConstructor=N,this.formatValues=n.erect2DFloat,null):(this.TextureConstructor=R,this.formatValues=n.erectFloat,null);case"Array(2)":return this.output[2]>0?(this.TextureConstructor=u,this.formatValues=n.erect3DArray2,null):this.output[1]>0?(this.TextureConstructor=o,this.formatValues=n.erect2DArray2,null):(this.TextureConstructor=s,this.formatValues=n.erectArray2,null);case"Array(3)":return this.output[2]>0?(this.TextureConstructor=c,this.formatValues=n.erect3DArray3,null):this.output[1]>0?(this.TextureConstructor=l,this.formatValues=n.erect2DArray3,null):(this.TextureConstructor=h,this.formatValues=n.erectArray3,null);case"Array(4)":return this.output[2]>0?(this.TextureConstructor=f,this.formatValues=n.erect3DArray4,null):this.output[1]>0?(this.TextureConstructor=d,this.formatValues=n.erect2DArray4,null):(this.TextureConstructor=p,this.formatValues=n.erectArray4,null)}}throw new Error(`unhandled return type "${this.returnType}"`)}getKernelString(){throw new Error("abstract method call")}getMainResultTexture(){switch(this.returnType){case"LiteralInteger":case"Float":case"Integer":case"Number":return this.getMainResultNumberTexture();case"Array(2)":return this.getMainResultArray2Texture();case"Array(3)":return this.getMainResultArray3Texture();case"Array(4)":return this.getMainResultArray4Texture();default:throw new Error(`unhandled returnType type ${this.returnType}`)}}getMainResultKernelNumberTexture(){throw new Error("abstract method call")}getMainResultSubKernelNumberTexture(){throw new Error("abstract method call")}getMainResultKernelArray2Texture(){throw new Error("abstract method call")}getMainResultSubKernelArray2Texture(){throw new Error("abstract method call")}getMainResultKernelArray3Texture(){throw new Error("abstract method call")}getMainResultSubKernelArray3Texture(){throw new Error("abstract method call")}getMainResultKernelArray4Texture(){throw new Error("abstract method call")}getMainResultSubKernelArray4Texture(){throw new Error("abstract method call")}getMainResultGraphical(){throw new Error("abstract method call")}getMainResultMemoryOptimizedFloats(){throw new Error("abstract method call")}getMainResultPackedPixels(){throw new Error("abstract method call")}getMainResultString(){return this.graphical?this.getMainResultGraphical():"single"===this.precision?this.optimizeFloatMemory?this.getMainResultMemoryOptimizedFloats():this.getMainResultTexture():this.getMainResultPackedPixels()}getMainResultNumberTexture(){return n.linesToString(this.getMainResultKernelNumberTexture())+n.linesToString(this.getMainResultSubKernelNumberTexture())}getMainResultArray2Texture(){return n.linesToString(this.getMainResultKernelArray2Texture())+n.linesToString(this.getMainResultSubKernelArray2Texture())}getMainResultArray3Texture(){return n.linesToString(this.getMainResultKernelArray3Texture())+n.linesToString(this.getMainResultSubKernelArray3Texture())}getMainResultArray4Texture(){return n.linesToString(this.getMainResultKernelArray4Texture())+n.linesToString(this.getMainResultSubKernelArray4Texture())}getFloatTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic)} float;\n`}getIntTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic,!0)} int;\n`}getSampler2DTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic)} sampler2D;\n`}getSampler2DArrayTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic)} sampler2DArray;\n`}renderTexture(){return this.immutable?this.texture.clone():this.texture}readPackedPixelsToUint8Array(){if("unsigned"!==this.precision)throw new Error('Requires this.precision to be "unsigned"');const{texSize:e,context:t}=this,r=new Uint8Array(e[0]*e[1]*4);return t.readPixels(0,0,e[0],e[1],t.RGBA,t.UNSIGNED_BYTE,r),r}readPackedPixelsToFloat32Array(){return new Float32Array(this.readPackedPixelsToUint8Array().buffer)}readFloatPixelsToFloat32Array(){if("single"!==this.precision)throw new Error('Requires this.precision to be "single"');const{texSize:e,context:t}=this,r=e[0],n=e[1],s=new Float32Array(r*n*4);return t.readPixels(0,0,r,n,t.RGBA,t.FLOAT,s),s}getPixels(e){const{context:t,output:r}=this,[s,i]=r,a=new Uint8Array(s*i*4);t.readPixels(0,0,s,i,t.RGBA,t.UNSIGNED_BYTE,a);const o=new Uint8ClampedArray((e?a:n.flipPixels(a,s,i)).buffer);return this.asyncMode?Promise.resolve(o):o}renderKernelsToArrays(){const e={result:this.renderOutput()};for(let t=0;t0){for(let e=0;e0){const{mappedTextures:r}=this;for(let n=0;n{const{utils:r}=i(),{FunctionNode:n}=h(),s={"<":"ceil",">=":"ceil",">":"floor","<=":"floor"};function a(e){if(!e||"object"!=typeof e)return!0;if(Array.isArray(e))return e.every(a);if("UpdateExpression"===e.type||"AssignmentExpression"===e.type||"SequenceExpression"===e.type)return!1;for(const t in e)if("loc"!==t&&"range"!==t&&"parent"!==t&&!a(e[t]))return!1;return!0}function o(e){let t=!1;function r(e){if(!e||"object"!=typeof e||t)return!1;if(Array.isArray(e))return e.some(r);if("MemberExpression"===e.type&&e.computed)return!0;for(const t in e)if("loc"!==t&&"range"!==t&&"parent"!==t&&r(e[t]))return!0;return!1}return function e(n){if(n&&"object"==typeof n&&!t)if(Array.isArray(n))n.forEach(e);else if("MemberExpression"===n.type&&n.computed&&r(n.property))t=!0;else for(const t in n)"loc"!==t&&"range"!==t&&"parent"!==t&&e(n[t])}(e),t}function u(e,t){if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(e=>u(e,t));if("CallExpression"===e.type&&"Identifier"===e.callee.type&&e.callee.name===t)return!0;for(const r in e)if("loc"!==r&&"range"!==r&&"parent"!==r&&u(e[r],t))return!0;return!1}function l(e){let t=!1;return function e(r){if(r&&"object"==typeof r&&!t)if(Array.isArray(r))r.forEach(e);else if("CallExpression"===r.type&&"Identifier"===r.callee.type&&r.arguments.some(e=>u(e,r.callee.name)))t=!0;else for(const t in r)"loc"!==t&&"range"!==t&&"parent"!==t&&e(r[t])}(e),t}function c(e){const t="ExpressionStatement"===e.type&&"AssignmentExpression"===e.expression.type?e.expression:null;return function e(r){if(!r||"object"!=typeof r)return!0;if(Array.isArray(r))return r.every(e);if("string"==typeof r.type){if("UpdateExpression"===r.type||"SequenceExpression"===r.type)return!1;if("AssignmentExpression"===r.type&&r!==t)return!1}for(const t in r)if("loc"!==t&&"range"!==t&&"parent"!==t&&!e(r[t]))return!1;return!0}(e)}const p={"Matrix(2)":2,"Matrix(3)":3,"Matrix(4)":4},d={Array:"sampler2D","Array(2)":"vec2","Array(3)":"vec3","Array(4)":"vec4","Matrix(2)":"mat2","Matrix(3)":"mat3","Matrix(4)":"mat4",Array2D:"sampler2D",Array3D:"sampler2D",Boolean:"bool",Float:"float",Input:"sampler2D",Integer:"int",Number:"float",LiteralInteger:"float",NumberTexture:"sampler2D",MemoryOptimizedNumberTexture:"sampler2D","ArrayTexture(1)":"sampler2D","ArrayTexture(2)":"sampler2D","ArrayTexture(3)":"sampler2D","ArrayTexture(4)":"sampler2D",HTMLVideo:"sampler2D",HTMLCanvas:"sampler2D",OffscreenCanvas:"sampler2D",HTMLImage:"sampler2D",ImageBitmap:"sampler2D",ImageData:"sampler2D",HTMLImageArray:"sampler2DArray"},f={"===":"==","!==":"!="};t.exports={WebGLFunctionNode:class extends n{constructor(e,t){super(e,t),t&&t.hasOwnProperty("fixIntegerDivisionAccuracy")&&(this.fixIntegerDivisionAccuracy=t.fixIntegerDivisionAccuracy)}astConditionalExpression(e,t){if("ConditionalExpression"!==e.type)throw this.astErrorOutput("Not a conditional expression",e);const r=this.getType(e.consequent),n=this.getType(e.alternate);return null===r&&null===n?(t.push("if ("),this.astGeneric(e.test,t),t.push(") {"),this.astGeneric(e.consequent,t),t.push(";"),t.push("} else {"),this.astGeneric(e.alternate,t),t.push(";"),t.push("}"),t):(t.push("("),this.astGeneric(e.test,t),t.push("?"),this.astGeneric(e.consequent,t),t.push(":"),this.astGeneric(e.alternate,t),t.push(")"),t)}astFunction(e,t){if(this.isRootKernel)t.push("void");else{this.returnType||this.findLastReturn()&&(this.returnType=this.getType(e.body),"LiteralInteger"===this.returnType&&(this.returnType="Number"));const{returnType:r}=this;if(r){const e=d[r];if(!e)throw new Error(`unknown type ${r}`);t.push(e)}else t.push("void")}if(t.push(" "),t.push(this.name),t.push("("),!this.isRootKernel)for(let n=0;n0&&t.push(", ");let i=this.argumentTypes[this.argumentNames.indexOf(s)];if(!i)throw this.astErrorOutput(`Unknown argument ${s} type`,e);"LiteralInteger"===i&&(this.argumentTypes[n]=i="Number");const a=d[i];if(!a)throw this.astErrorOutput("Unexpected expression",e);const o=r.sanitizeName(s);"sampler2D"===a||"sampler2DArray"===a?t.push(`${a} user_${o},ivec2 user_${o}Size,ivec3 user_${o}Dim`):t.push(`${a} user_${o}`)}t.push(") {\n");for(let r=0;r>":"bitwiseSignedRightShift",">>>":"bitwiseZeroFillRightShift"}[e.operator];if(!r)return null;switch(t.push(r),t.push("("),this.getType(e.left)){case"Number":case"Float":this.castValueToInteger(e.left,t);break;case"LiteralInteger":this.castLiteralToInteger(e.left,t);break;default:this.astGeneric(e.left,t)}switch(t.push(","),this.getType(e.right)){case"Number":case"Float":this.castValueToInteger(e.right,t);break;case"LiteralInteger":this.castLiteralToInteger(e.right,t);break;default:this.astGeneric(e.right,t)}return t.push(")"),t}checkAndUpconvertBitwiseUnary(e,t){const r={"~":"bitwiseNot"}[e.operator];if(!r)return null;switch(t.push(r),t.push("("),this.getType(e.argument)){case"Number":case"Float":this.castValueToInteger(e.argument,t);break;case"LiteralInteger":this.castLiteralToInteger(e.argument,t);break;default:this.astGeneric(e.argument,t)}return t.push(")"),t}castLiteralToInteger(e,t){return this.pushState("casting-to-integer"),this.astGeneric(e,t),this.popState("casting-to-integer"),t}castLiteralToFloat(e,t){return this.pushState("casting-to-float"),this.astGeneric(e,t),this.popState("casting-to-float"),t}castValueToInteger(e,t){return this.pushState("casting-to-integer"),t.push("int("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-integer"),t}castValueToFloat(e,t){return this.pushState("casting-to-float"),t.push("float("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-float"),t}astIdentifierExpression(e,t){if("Identifier"!==e.type)throw this.astErrorOutput("IdentifierExpression - not an Identifier",e);const n=this.getType(e),s=r.sanitizeName(e.name);return"Infinity"===e.name?t.push("3.402823466e+38"):"Boolean"===n&&this.argumentNames.indexOf(s)>-1?t.push(`bool(user_${s})`):t.push(`user_${s}`),t}astForStatement(e,t){if("ForStatement"!==e.type)throw this.astErrorOutput("Invalid for statement",e);const r=[],n=[],s=[],i=[];let a=null;if(e.init){const{declarations:t}=e.init;t.length>1&&(a=!1),this.astGeneric(e.init,r);for(let e=0;e0&&t.push(r.join(""),"\n"),t.push(`for (int ${e}=0;${e}0&&t.push(`if (!${n.join("")}) break;\n`),t.push(i.join("")),t.push(`\n${s.join("")};`),t.push("}\n")}return t}astWhileStatement(e,t){if("WhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);const r=this.getInternalVariableName("safeI");return t.push(`for (int ${r}=0;${r}null!==e&&(o(e)||l(e))))return null;const i=e=>JSON.parse(JSON.stringify(e)),a=e=>({type:"IfStatement",test:{type:"UnaryExpression",operator:"!",prefix:!0,argument:e},consequent:{type:"BlockStatement",body:[{type:"BreakStatement",label:null}]},alternate:null}),u=e=>"VariableDeclaration"===e.type?e:{type:"ExpressionStatement",expression:e},h="BlockStatement"===e.body.type?e.body.body.slice():[e.body],c=(e,t)=>{const r=e=>{if(!e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map(r);switch(e.type){case"ContinueStatement":return{type:"BlockStatement",body:[...t(),e]};case"ForStatement":case"WhileStatement":case"DoWhileStatement":default:return e;case"IfStatement":return{...e,consequent:r(e.consequent),alternate:r(e.alternate)};case"BlockStatement":return{...e,body:e.body.map(r)};case"SwitchStatement":return{...e,cases:e.cases.map(e=>({...e,consequent:e.consequent.map(r)}))}}};return e.map(r)},p=[];"DoWhileStatement"===t?(p.push(...n?c(h,()=>[a(i(n))]):h),n&&p.push(a(n))):(n&&p.push(a(n)),p.push(...s?c(h,()=>[u(i(s))]):h),s&&p.push(u(s)));const d={type:"BlockStatement",body:[...r?[u(r)]:[],{type:"WhileStatement",test:{type:"Literal",value:!0,raw:"true"},body:{type:"BlockStatement",body:p}}]};let f=this.syntheticNodeId||1073741824;const m=e=>{if(e&&"object"==typeof e)if(Array.isArray(e))e.forEach(m);else{"string"==typeof e.type&&void 0===e.start&&(e.start=f,e.end=f+1,f+=2);for(const t in e)"loc"!==t&&"range"!==t&&"parent"!==t&&m(e[t])}};return m(d),this.syntheticNodeId=f,d}linearizeStatement(e){const t=[];let r=!1,n=this.linearTempId||0;const s=e=>({type:"Identifier",name:e}),i=(e,t,r)=>({type:"VariableDeclaration",kind:e,declarations:[{type:"VariableDeclarator",id:s(t),init:r}]}),o=(e,t)=>{const r="hoistSeq"+n++;return e.push(i("const",r,t)),s(r)},h=e=>!a(e),l=(e,t)=>{if(r||!e||"object"!=typeof e)return e;switch(e.type){case"Identifier":case"Literal":case"ThisExpression":return e;case"MemberExpression":{const r=l(e.object,t),n=e.computed?l(e.property,t):e.property;return{...e,object:r,property:n}}case"CallExpression":{const r=e.arguments.map(e=>l(e,t));if("Identifier"===e.callee.type)for(let n=0;nl(e,t))};case"UpdateExpression":{if("Identifier"!==e.argument.type)return r=!0,e;if(e.prefix)return t.push({type:"ExpressionStatement",expression:e}),o(t,e.argument);const n=o(t,e.argument);return t.push({type:"ExpressionStatement",expression:e}),n}case"AssignmentExpression":{if("Identifier"!==e.left.type)return r=!0,e;const n=l(e.right,t);return t.push({type:"ExpressionStatement",expression:{...e,right:n}}),o(t,e.left)}case"SequenceExpression":for(let r=0;r({type:"ExpressionStatement",expression:{type:"AssignmentExpression",operator:"=",left:s(e),right:t}});return o.push(d(a,c)),u.push(d(a,p)),t.push({type:"IfStatement",test:r,consequent:{type:"BlockStatement",body:o},alternate:{type:"BlockStatement",body:u}}),s(a)}case"LogicalExpression":{if(!h(e.right))return{...e,left:l(e.left,t)};const r=l(e.left,t),a="hoistSeq"+n++;t.push(i("let",a,r));const o=[],u=l(e.right,o);return o.push({type:"ExpressionStatement",expression:{type:"AssignmentExpression",operator:"=",left:s(a),right:u}}),t.push({type:"IfStatement",test:"&&"===e.operator?s(a):{type:"UnaryExpression",operator:"!",prefix:!0,argument:s(a)},consequent:{type:"BlockStatement",body:o},alternate:null}),s(a)}default:return r=!0,e}};switch(e.type){case"ExpressionStatement":{const r=e.expression;if("AssignmentExpression"===r.type&&"Identifier"===r.left.type){const e=l(r.right,t);t.push({type:"ExpressionStatement",expression:{...r,right:e}})}else{const e=l(r,t);"UpdateExpression"!==e.type&&"AssignmentExpression"!==e.type||t.push({type:"ExpressionStatement",expression:e})}break}case"VariableDeclaration":for(let r=0;r{if(e&&"object"==typeof e)if(Array.isArray(e))e.forEach(p);else{"string"==typeof e.type&&void 0===e.start&&(e.start=c,e.end=c+1,c+=2);for(const t in e)"loc"!==t&&"range"!==t&&"parent"!==t&&p(e[t])}};return p(t),this.syntheticNodeId=c,t}astStatementWithHoisting(e,t){switch(e.type){case"ExpressionStatement":case"VariableDeclaration":case"ReturnStatement":{if(!c(e))return this.astGeneric(e,t);const r=this.hoistedIndexReads,n=this.hoistedIndexReads=[],s=[];return this.astGeneric(e,s),this.hoistedIndexReads=r,t.push(...n,...s),t}default:return this.astGeneric(e,t)}}astVariableDeclaration(e,t){const n=e.declarations;if(!n||!n[0]||!n[0].init)throw this.astErrorOutput("Unexpected expression",e);const s=[];let i=null;const a=[];let o=[];for(let t=0;t0&&a.push(o.join(",")),s.push(a.join(";")),t.push(s.join("")),t.push(";"),t}astIfStatement(e,t){return t.push("if ("),this.astGeneric(e.test,t),t.push(")"),"BlockStatement"===e.consequent.type?this.astGeneric(e.consequent,t):(t.push(" {\n"),this.astGeneric(e.consequent,t),t.push("\n}\n")),e.alternate&&(t.push("else "),"BlockStatement"===e.alternate.type||"IfStatement"===e.alternate.type?this.astGeneric(e.alternate,t):(t.push(" {\n"),this.astGeneric(e.alternate,t),t.push("\n}\n"))),t}astSwitchCaseConsequent(e,t){const r=[];for(let t=0;t{if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(t);if("BreakStatement"===e.type)return!0;if("ForStatement"===e.type||"WhileStatement"===e.type||"DoWhileStatement"===e.type||"SwitchStatement"===e.type)return!1;for(const r in e)if("loc"!==r&&"range"!==r&&"parent"!==r&&t(e[r]))return!0;return!1};if(t(r[e]))throw this.astErrorOutput("break inside a switch case is only supported as the case terminator",r[e])}for(let e=0;er+1){u=!0,this.astSwitchCaseConsequent(n[r].consequent,o);continue}t.push(" else {\n")}this.astSwitchCaseConsequent(n[r].consequent,t),t.push("\n}")}return u&&(t.push(" else {"),t.push(o.join("")),t.push("}")),t}astThisExpression(e,t){return t.push("this"),t}astMemberExpression(e,t){const{property:n,name:s,signature:i,origin:a,type:o,xProperty:u,yProperty:h,zProperty:l}=this.getMemberExpressionDetails(e);switch(i){case"value.thread.value":case"this.thread.value":if("x"!==s&&"y"!==s&&"z"!==s)throw this.astErrorOutput("Unexpected expression, expected `this.thread.x`, `this.thread.y`, or `this.thread.z`",e);return t.push(`threadId.${s}`),t;case"this.output.value":if(this.dynamicOutput)switch(s){case"x":this.isState("casting-to-float")?t.push("float(uOutputDim.x)"):t.push("uOutputDim.x");break;case"y":this.isState("casting-to-float")?t.push("float(uOutputDim.y)"):t.push("uOutputDim.y");break;case"z":this.isState("casting-to-float")?t.push("float(uOutputDim.z)"):t.push("uOutputDim.z");break;default:throw this.astErrorOutput("Unexpected expression",e)}else switch(s){case"x":this.isState("casting-to-integer")?t.push(this.output[0]):t.push(this.output[0],".0");break;case"y":this.isState("casting-to-integer")?t.push(this.output[1]):t.push(this.output[1],".0");break;case"z":this.isState("casting-to-integer")?t.push(this.output[2]):t.push(this.output[2],".0");break;default:throw this.astErrorOutput("Unexpected expression",e)}return t;case"value":throw this.astErrorOutput("Unexpected expression",e);case"value[]":case"value[][]":case"value[][][]":case"value[][][][]":case"value.value":if("Math"===a)return t.push(Math[s]),t;const i=r.sanitizeName(s);switch(n){case"r":return t.push(`user_${i}.r`),t;case"g":return t.push(`user_${i}.g`),t;case"b":return t.push(`user_${i}.b`),t;case"a":return t.push(`user_${i}.a`),t}break;case"this.constants.value":if(void 0===u)switch(o){case"Array(2)":case"Array(3)":case"Array(4)":return t.push(`constants_${r.sanitizeName(s)}`),t}case"this.constants.value[]":case"this.constants.value[][]":case"this.constants.value[][][]":case"this.constants.value[][][][]":break;case"fn()[]":return this.astCallExpression(e.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(n)),t.push("]"),t;case"fn()[][]":{const r=e.object.property,n=e.property,s=p[this.getType(e.object.object)],i=e=>"LiteralInteger"===this.getType(e);return!s||i(r)&&i(n)?(this.astCallExpression(e.object.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(r)),t.push("]"),t.push("["),t.push(this.memberExpressionPropertyMarkup(n)),t.push("]"),t):(t.push(`getMatrix${s}(`),this.astCallExpression(e.object.object,t),t.push(", "),t.push(this.memberExpressionPropertyMarkup(r)),t.push(", "),t.push(this.memberExpressionPropertyMarkup(n)),t.push(")"),t)}case"[][]":return this.astArrayExpression(e.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(n)),t.push("]"),t;default:throw this.astErrorOutput("Unexpected expression",e)}if(!1===e.computed)switch(o){case"Number":case"Integer":case"Float":case"Boolean":return t.push(`${a}_${r.sanitizeName(s)}`),t}const c=`${a}_${r.sanitizeName(s)}`;switch(o){case"Array(2)":case"Array(3)":case"Array(4)":this.astGeneric(e.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(u)),t.push("]");break;case"HTMLImageArray":t.push(`getImage3D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,h,l,t),t.push(")");break;case"ArrayTexture(1)":t.push(`getFloatFromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,h,l,t),t.push(")");break;case"Array1D(2)":case"Array2D(2)":case"Array3D(2)":t.push(`getMemoryOptimizedVec2(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,h,l,t),t.push(")");break;case"ArrayTexture(2)":t.push(`getVec2FromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,h,l,t),t.push(")");break;case"Array1D(3)":case"Array2D(3)":case"Array3D(3)":t.push(`getMemoryOptimizedVec3(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,h,l,t),t.push(")");break;case"ArrayTexture(3)":t.push(`getVec3FromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,h,l,t),t.push(")");break;case"Array1D(4)":case"Array2D(4)":case"Array3D(4)":t.push(`getMemoryOptimizedVec4(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,h,l,t),t.push(")");break;case"ArrayTexture(4)":case"HTMLCanvas":case"OffscreenCanvas":case"HTMLImage":case"ImageBitmap":case"ImageData":case"HTMLVideo":t.push(`getVec4FromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,h,l,t),t.push(")");break;case"NumberTexture":case"Array":case"Array2D":case"Array3D":case"Array4D":case"Input":case"Number":case"Float":case"Integer":if("single"===this.precision)t.push(`getMemoryOptimized32(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,h,l,t),t.push(")");else{const e="user"===a?this.lookupFunctionArgumentBitRatio(this.name,s):this.constantBitRatios[s];switch(e){case 1:t.push(`get8(${c}, ${c}Size, ${c}Dim, `);break;case 2:t.push(`get16(${c}, ${c}Size, ${c}Dim, `);break;case 4:case 0:t.push(`get32(${c}, ${c}Size, ${c}Dim, `);break;default:throw new Error(`unhandled bit ratio of ${e}`)}this.memberExpressionXYZ(u,h,l,t),t.push(")")}break;case"MemoryOptimizedNumberTexture":t.push(`getMemoryOptimized32(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,h,l,t),t.push(")");break;case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":t.push(`${c}[${this.memberExpressionPropertyMarkup(h)}]`),h&&t.push(`[${this.memberExpressionPropertyMarkup(u)}]`);break;default:throw new Error(`unhandled member expression "${o}"`)}return t}astCallExpression(e,t){if(!e.callee)throw this.astErrorOutput("Unknown CallExpression",e);let n=null;const s=this.isAstMathFunction(e);if(n=s||e.callee.object&&"ThisExpression"===e.callee.object.type?e.callee.property.name:"SequenceExpression"!==e.callee.type||"Literal"!==e.callee.expressions[0].type||isNaN(e.callee.expressions[0].raw)?e.callee.name:e.callee.expressions[1].property.name,!n)throw this.astErrorOutput("Unhandled function, couldn't find name",e);switch(n){case"pow":n="_pow";break;case"round":n="_round"}if(this.calledFunctions.indexOf(n)<0&&this.calledFunctions.push(n),"random"===n&&this.plugins&&this.plugins.length>0)for(let e=0;e0&&t.push(", "),"Integer"===s)this.castValueToFloat(n,t);else this.astGeneric(n,t)}else{const s=this.lookupFunctionArgumentTypes(n)||[];for(let i=0;i0&&t.push(", ");const u=this.getType(a);switch(o||(this.triggerImplyArgumentType(n,i,u,this),o=u),u){case"Boolean":this.astGeneric(a,t);continue;case"Number":case"Float":if("Integer"===o){t.push("int("),this.astGeneric(a,t),t.push(")");continue}if("Number"===o||"Float"===o){this.astGeneric(a,t);continue}if("LiteralInteger"===o){this.castLiteralToFloat(a,t);continue}break;case"Integer":if("Number"===o||"Float"===o){t.push("float("),this.astGeneric(a,t),t.push(")");continue}if("Integer"===o){this.astGeneric(a,t);continue}break;case"LiteralInteger":if("Integer"===o){this.castLiteralToInteger(a,t);continue}if("Number"===o||"Float"===o){this.castLiteralToFloat(a,t);continue}if("LiteralInteger"===o){this.astGeneric(a,t);continue}break;case"Array(2)":case"Array(3)":case"Array(4)":if(o===u){if("Identifier"===a.type)t.push(`user_${r.sanitizeName(a.name)}`);else{if("ArrayExpression"!==a.type&&"MemberExpression"!==a.type&&"CallExpression"!==a.type)throw this.astErrorOutput(`Unhandled argument type ${a.type}`,e);this.astGeneric(a,t)}continue}break;case"HTMLCanvas":case"OffscreenCanvas":case"HTMLImage":case"ImageBitmap":case"ImageData":case"HTMLImageArray":case"HTMLVideo":case"ArrayTexture(1)":case"ArrayTexture(2)":case"ArrayTexture(3)":case"ArrayTexture(4)":case"Array":case"Input":if(o===u){if("Identifier"!==a.type)throw this.astErrorOutput(`Unhandled argument type ${a.type}`,e);this.triggerImplyArgumentBitRatio(this.name,a.name,n,i);const s=r.sanitizeName(a.name);t.push(`user_${s},user_${s}Size,user_${s}Dim`);continue}}throw this.astErrorOutput(`Unhandled argument combination of ${u} and ${o} for argument named "${a.name}"`,e)}}return t.push(")"),t}astArrayExpression(e,t){const r=this.getType(e),n=e.elements.length;switch(r){case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":t.push(`mat${n}(`);break;default:t.push(`vec${n}(`)}for(let r=0;r0&&t.push(", ");const n=e.elements[r];this.astGeneric(n,t)}return t.push(")"),t}memberExpressionXYZ(e,t,r,n){return r?n.push(this.memberExpressionPropertyMarkup(r),", "):n.push("0, "),t?n.push(this.memberExpressionPropertyMarkup(t),", "):n.push("0, "),n.push(this.memberExpressionPropertyMarkup(e)),n}memberExpressionPropertyMarkup(e){if(!e)throw new Error("Property not set");const t=[];switch(this.getType(e)){case"Number":case"Float":this.castValueToInteger(e,t);break;case"LiteralInteger":this.castLiteralToInteger(e,t);break;default:this.astGeneric(e,t)}const n=t.join("");if(this.hoistedIndexReads&&/\b\w+\((user_|constants_)\w+, \1\w+Size/.test(n)){const e=`hoisted_${this.hoistedIndexReads.length}_${r.sanitizeName(this.name)}`,t=n.startsWith("int(");return this.hoistedIndexReads.push(`${t?"int":"float"} ${e}=${n};\n`),e}return n}}}}),V=e((e,t)=>{t.exports={name:"math-random-uniformly-distributed",onBeforeRun:e=>{if(null===e.randomSeed||void 0===e.randomSeed)return e.setUniform1f("randomSeed1",Math.random()),void e.setUniform1f("randomSeed2",Math.random());e._mathRandomGenerator&&e._mathRandomGeneratorSeed===e.randomSeed||(e._mathRandomGenerator=function(e){let t=e>>>0;return function(){t=t+1831565813>>>0;let e=t;return e=Math.imul(e^e>>>15,1|e),e^=e+Math.imul(e^e>>>7,61|e),((e^e>>>14)>>>0)/4294967296}}(e.randomSeed),e._mathRandomGeneratorSeed=e.randomSeed),e.setUniform1f("randomSeed1",e._mathRandomGenerator()),e.setUniform1f("randomSeed2",e._mathRandomGenerator())},functionMatch:"Math.random()",functionReplace:"nrand(vTexCoord)",functionReturnType:"Number",source:"// https://www.shadertoy.com/view/4t2SDh\n//note: uniformly distributed, normalized rand, [0,1]\nhighp float randomSeedShift = 1.0;\nhighp float slide = 1.0;\nuniform highp float randomSeed1;\nuniform highp float randomSeed2;\n\nhighp float nrand(highp vec2 n) {\n highp float result = fract(sin(dot((n.xy + 1.0) * vec2(randomSeed1 * slide, randomSeed2 * randomSeedShift), vec2(12.9898, 78.233))) * 43758.5453);\n randomSeedShift = result;\n if (randomSeedShift > 0.5) {\n slide += 0.00009; \n } else {\n slide += 0.0009;\n }\n return result;\n}"}}),M=e((e,t)=>{t.exports={fragmentShader:`__HEADER__;\n__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n\nconst int LOOP_MAX = __LOOP_MAX__;\n\n__PLUGINS__;\n__CONSTANTS__;\n\nvarying vec2 vTexCoord;\n\nfloat acosh(float x) {\n return log(x + sqrt(x * x - 1.0));\n}\n\nfloat sinh(float x) {\n return (pow(${Math.E}, x) - pow(${Math.E}, -x)) / 2.0;\n}\n\nfloat asinh(float x) {\n return log(x + sqrt(x * x + 1.0));\n}\n\nfloat atan2(float v1, float v2) {\n if (v2 == 0.0) {\n if (v1 == 0.0) return 0.0;\n if (v1 > 0.0) return 1.5707963267948966;\n if (v1 < 0.0) return -1.5707963267948966;\n }\n return atan(v1, v2);\n}\n\nfloat atanh(float x) {\n x = (x + 1.0) / (x - 1.0);\n if (x < 0.0) {\n return 0.5 * log(-x);\n }\n return 0.5 * log(x);\n}\n\nfloat cbrt(float x) {\n if (x >= 0.0) {\n return pow(x, 1.0 / 3.0);\n } else {\n return -pow(x, 1.0 / 3.0);\n }\n}\n\nfloat cosh(float x) {\n return (pow(${Math.E}, x) + pow(${Math.E}, -x)) / 2.0; \n}\n\nfloat expm1(float x) {\n return pow(${Math.E}, x) - 1.0; \n}\n\nfloat fround(highp float x) {\n return x;\n}\n\nfloat imul(float v1, float v2) {\n return float(int(v1) * int(v2));\n}\n\nfloat log10(float x) {\n return log2(x) * (1.0 / log2(10.0));\n}\n\nfloat log1p(float x) {\n return log(1.0 + x);\n}\n\nfloat _pow(float v1, float v2) {\n if (v2 == 0.0) return 1.0;\n return pow(v1, v2);\n}\n\nfloat tanh(float x) {\n float e = exp(2.0 * x);\n return (e - 1.0) / (e + 1.0);\n}\n\nfloat trunc(float x) {\n if (x >= 0.0) {\n return floor(x); \n } else {\n return ceil(x);\n }\n}\n\nvec4 _round(vec4 x) {\n return floor(x + 0.5);\n}\n\nfloat _round(float x) {\n return floor(x + 0.5);\n}\n\nconst int BIT_COUNT = 32;\nint modi(int x, int y) {\n return x - y * (x / y);\n}\n\nint bitwiseOr(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) || (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseXOR(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) != (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseAnd(int a, int b) {\n int result = 0;\n int n = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) && (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 && b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseNot(int a) {\n // ~a is identically -a - 1 in two's complement, for every value including\n // negatives. The previous bit-by-bit loop only worked for a >= 0, where it\n // leaned on 32-bit overflow wrapping to reach the negative answer; given a\n // negative input it computed ~abs(a), so ~(-1) gave -2 and ~~x never\n // returned x.\n return -a - 1;\n}\nint bitwiseZeroFillLeftShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n *= 2;\n }\n\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\n// _pow2 is defined further down, alongside encode32/decode32\nfloat _pow2(float e);\nint bitwiseSignedRightShift(int num, int shifts) {\n // pow(2.0, n) is approximate on many GPUs, and landing 1 ulp high makes the\n // division fall just under a whole number, which floor() then rounds away:\n // 2 >> 1 came out 0, 8 >> 1 came out 3. Only exact left operands were\n // affected, odd ones having enough slack to survive. _pow2 is exact.\n return int(floor(float(num) / _pow2(float(shifts))));\n}\n\nint bitwiseZeroFillRightShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n /= 2;\n }\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\nvec2 integerMod(vec2 x, float y) {\n vec2 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec3 integerMod(vec3 x, float y) {\n vec3 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec4 integerMod(vec4 x, vec4 y) {\n vec4 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nfloat integerMod(float x, float y) {\n float res = floor(mod(x, y));\n return res * (res > floor(y) - 1.0 ? 0.0 : 1.0);\n}\n\nint integerMod(int x, int y) {\n return x - (y * int(x / y));\n}\n\n// GLSL ES 1.00 accepts only a constant or a loop symbol inside an index\n// expression, so m[y][x] does not compile when y and x come from kernel\n// arguments -- the error is "Index expression can only contain const or loop\n// symbols". Loop counters are legal indices, so walk the matrix with them\n// instead. These are 2x2 to 4x4, so it costs at most sixteen comparisons.\nfloat getMatrix2(mat2 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 2; i++) {\n for (int j = 0; j < 2; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix3(mat3 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 3; i++) {\n for (int j = 0; j < 3; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix4(mat4 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 4; i++) {\n for (int j = 0; j < 4; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\n__DIVIDE_WITH_INTEGER_CHECK__;\n\n// Here be dragons!\n// DO NOT OPTIMIZE THIS CODE\n// YOU WILL BREAK SOMETHING ON SOMEBODY'S MACHINE\n// LEAVE IT AS IT IS, LEST YOU WASTE YOUR OWN TIME\n// Exact powers of two built from exact constant multiplies: exp2/log2/pow\n// are approximate on some GPUs (notably Apple silicon), and 1-2 ulp there\n// corrupts the packed bytes (#659)\nfloat _pow2(float e) {\n float r = 1.0;\n float a = abs(e);\n bool n = e < 0.0;\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 32.0) { r *= n ? 2.3283064365386963e-10 : 4294967296.0; a -= 32.0; }\n if (a >= 16.0) { r *= n ? 0.0000152587890625 : 65536.0; a -= 16.0; }\n if (a >= 8.0) { r *= n ? 0.00390625 : 256.0; a -= 8.0; }\n if (a >= 4.0) { r *= n ? 0.0625 : 16.0; a -= 4.0; }\n if (a >= 2.0) { r *= n ? 0.25 : 4.0; a -= 2.0; }\n if (a >= 1.0) { r *= n ? 0.5 : 2.0; }\n return r;\n}\nconst vec2 MAGIC_VEC = vec2(1.0, -256.0);\nconst vec4 SCALE_FACTOR = vec4(1.0, 256.0, 65536.0, 0.0);\nconst vec4 SCALE_FACTOR_INV = vec4(1.0, 0.00390625, 0.0000152587890625, 0.0); // 1, 1/256, 1/65536\nfloat decode32(vec4 texel) {\n __DECODE32_ENDIANNESS__;\n texel *= 255.0;\n vec2 gte128;\n gte128.x = texel.b >= 128.0 ? 1.0 : 0.0;\n gte128.y = texel.a >= 128.0 ? 1.0 : 0.0;\n float exponent = 2.0 * texel.a - 127.0 + dot(gte128, MAGIC_VEC);\n float res = _pow2(_round(exponent));\n texel.b = texel.b - 128.0 * gte128.x;\n res = dot(texel, SCALE_FACTOR) * _pow2(_round(exponent-23.0)) + res;\n res *= gte128.y * -2.0 + 1.0;\n return res;\n}\n\nfloat decode16(vec4 texel, int index) {\n int channel = integerMod(index, 2);\n if (channel == 0) return texel.r * 255.0 + texel.g * 65280.0;\n if (channel == 1) return texel.b * 255.0 + texel.a * 65280.0;\n return 0.0;\n}\n\nfloat decode8(vec4 texel, int index) {\n int channel = integerMod(index, 4);\n if (channel == 0) return texel.r * 255.0;\n if (channel == 1) return texel.g * 255.0;\n if (channel == 2) return texel.b * 255.0;\n if (channel == 3) return texel.a * 255.0;\n return 0.0;\n}\n\nvec4 legacyEncode32(float f) {\n float F = abs(f);\n float sign = f < 0.0 ? 1.0 : 0.0;\n float exponent = floor(log2(F));\n float mantissa = (exp2(-exponent) * F);\n // exponent += floor(log2(mantissa));\n vec4 texel = vec4(F * exp2(23.0-exponent)) * SCALE_FACTOR_INV;\n texel.rg = integerMod(texel.rg, 256.0);\n texel.b = integerMod(texel.b, 128.0);\n texel.a = exponent*0.5 + 63.5;\n texel.ba += vec2(integerMod(exponent+127.0, 2.0), sign) * 128.0;\n texel = floor(texel);\n texel *= 0.003921569; // 1/255\n __ENCODE32_ENDIANNESS__;\n return texel;\n}\n\n// https://github.com/gpujs/gpu.js/wiki/Encoder-details\nvec4 encode32(float value) {\n if (value == 0.0) return vec4(0, 0, 0, 0);\n\n float exponent;\n float mantissa;\n vec4 result;\n float sgn;\n\n sgn = step(0.0, -value);\n value = abs(value);\n\n exponent = floor(log2(value));\n float p2 = _pow2(exponent);\n // approximate log2 can land one off; correct by direct comparison\n if (p2 > value) { exponent -= 1.0; p2 *= 0.5; }\n else if (p2 * 2.0 <= value) { exponent += 1.0; p2 *= 2.0; }\n\n mantissa = value / p2 - 1.0;\n exponent = exponent+127.0;\n result = vec4(0,0,0,0);\n\n result.a = floor(exponent/2.0);\n exponent = exponent - result.a*2.0;\n result.a = result.a + 128.0*sgn;\n\n result.b = floor(mantissa * 128.0);\n mantissa = mantissa - result.b / 128.0;\n result.b = result.b + exponent*128.0;\n\n result.g = floor(mantissa*32768.0);\n mantissa = mantissa - result.g/32768.0;\n\n result.r = floor(mantissa*8388608.0);\n return result/255.0;\n}\n// Dragons end here\n\nint index;\nivec3 threadId;\n\nivec3 indexTo3D(int idx, ivec3 texDim) {\n int z = int(idx / (texDim.x * texDim.y));\n idx -= z * int(texDim.x * texDim.y);\n int y = int(idx / texDim.x);\n int x = int(integerMod(idx, texDim.x));\n return ivec3(x, y, z);\n}\n\nfloat get32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n return decode32(texel);\n}\n\nfloat get16(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x * 2;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize.x * 2, texSize.y));\n return decode16(texel, index);\n}\n\nfloat get8(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x * 4;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize.x * 4, texSize.y));\n return decode8(texel, index);\n}\n\nfloat getMemoryOptimized32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 4);\n index = index / 4;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n if (channel == 0) return texel.r;\n if (channel == 1) return texel.g;\n if (channel == 2) return texel.b;\n if (channel == 3) return texel.a;\n return 0.0;\n}\n\nvec4 getImage2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n return texture2D(tex, st / vec2(texSize));\n}\n\nfloat getFloatFromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return result[0];\n}\n\nvec2 getVec2FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec2(result[0], result[1]);\n}\n\nvec2 getMemoryOptimizedVec2(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int channel = integerMod(index, 2);\n index = index / 2;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n if (channel == 0) return vec2(texel.r, texel.g);\n if (channel == 1) return vec2(texel.b, texel.a);\n return vec2(0.0, 0.0);\n}\n\nvec3 getVec3FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec3(result[0], result[1], result[2]);\n}\n\nvec3 getMemoryOptimizedVec3(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int fieldIndex = 3 * (x + texDim.x * (y + texDim.y * z));\n int vectorIndex = fieldIndex / 4;\n int vectorOffset = fieldIndex - vectorIndex * 4;\n int readY = vectorIndex / texSize.x;\n int readX = vectorIndex - readY * texSize.x;\n vec4 tex1 = texture2D(tex, (vec2(readX, readY) + 0.5) / vec2(texSize));\n \n if (vectorOffset == 0) {\n return tex1.xyz;\n } else if (vectorOffset == 1) {\n return tex1.yzw;\n } else {\n readX++;\n if (readX >= texSize.x) {\n readX = 0;\n readY++;\n }\n vec4 tex2 = texture2D(tex, vec2(readX, readY) / vec2(texSize));\n if (vectorOffset == 2) {\n return vec3(tex1.z, tex1.w, tex2.x);\n } else {\n return vec3(tex1.w, tex2.x, tex2.y);\n }\n }\n}\n\nvec4 getVec4FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n return getImage2D(tex, texSize, texDim, z, y, x);\n}\n\nvec4 getMemoryOptimizedVec4(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 2);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n return vec4(texel.r, texel.g, texel.b, texel.a);\n}\n\nvec4 actualColor;\nvoid color(float r, float g, float b, float a) {\n actualColor = vec4(r,g,b,a);\n}\n\nvoid color(float r, float g, float b) {\n color(r,g,b,1.0);\n}\n\nvoid color(sampler2D image) {\n actualColor = texture2D(image, vTexCoord);\n}\n\nfloat modulo(float number, float divisor) {\n if (number < 0.0) {\n number = abs(number);\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return -mod(number, divisor);\n }\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return mod(number, divisor);\n}\n\n__INJECTED_NATIVE__;\n__MAIN_CONSTANTS__;\n__MAIN_ARGUMENTS__;\n__KERNEL__;\n\nvoid main(void) {\n index = int(vTexCoord.s * float(uTexSize.x)) + int(vTexCoord.t * float(uTexSize.y)) * uTexSize.x;\n __MAIN_RESULT__;\n}`}}),O=e((e,t)=>{t.exports={vertexShader:"__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n\nattribute vec2 aPos;\nattribute vec2 aTexCoord;\n\nvarying vec2 vTexCoord;\nuniform vec2 ratio;\n\nvoid main(void) {\n gl_Position = vec4((aPos + vec2(1)) * ratio + vec2(-1), 0, 1);\n vTexCoord = aTexCoord;\n}"}}),P=e((e,t)=>{function r(e,t={}){const{contextName:r="gl",throwGetError:a,useTrackablePrimitives:o,recording:u=[],variables:h={},onReadPixels:l,onUnrecognizedArgumentLookup:c}=t,p=new Proxy(e,{get:function(t,p){switch(p){case"addComment":return A;case"checkThrowError":return _;case"getReadPixelsVariableName":return m;case"insertVariable":return b;case"reset":return y;case"setIndent":return S;case"toString":return x;case"getContextVariableName":return E}return"function"==typeof e[p]?function(){switch(p){case"getError":return a?u.push(`${g}if (${r}.getError() !== ${r}.NONE) throw new Error('error');`):u.push(`${g}${r}.getError();`),e.getError();case"getExtension":{const t=`${r}Variables${d.length}`;u.push(`${g}const ${t} = ${r}.getExtension('${arguments[0]}');`);const s=e.getExtension(arguments[0]);if(s&&"object"==typeof s){const e=n(s,{getEntity:T,useTrackablePrimitives:o,recording:u,contextName:t,contextVariables:d,variables:h,indent:g,onUnrecognizedArgumentLookup:c});return d.push(e),e}return d.push(null),s}case"readPixels":const t=d.indexOf(arguments[6]);let i;if(-1===t){const e=function(e){if(h)for(const t in h)if(h[t]===e)return t;return null}(arguments[6]);e?(i=e,u.push(`${g}${e}`)):(i=`${r}Variable${d.length}`,d.push(arguments[6]),u.push(`${g}const ${i} = new ${arguments[6].constructor.name}(${arguments[6].length});`))}else i=`${r}Variable${t}`;m=i;const p=[arguments[0],arguments[1],arguments[2],arguments[3],T(arguments[4]),T(arguments[5]),i];return u.push(`${g}${r}.readPixels(${p.join(", ")});`),l&&l(i,p),e.readPixels.apply(e,arguments);case"drawBuffers":return u.push(`${g}${r}.drawBuffers([${s(arguments[0],{contextName:r,contextVariables:d,getEntity:T,addVariable:v,variables:h,onUnrecognizedArgumentLookup:c})}]);`),e.drawBuffers(arguments[0])}let t=e[p].apply(e,arguments);switch(typeof t){case"undefined":return void u.push(`${g}${w(p,arguments)};`);case"number":case"boolean":if(o&&-1===d.indexOf(i(t))){u.push(`${g}const ${r}Variable${d.length} = ${w(p,arguments)};`),d.push(t=i(t));break}default:null===t?u.push(`${w(p,arguments)};`):u.push(`${g}const ${r}Variable${d.length} = ${w(p,arguments)};`),d.push(t)}return t}:(f[e[p]]=p,e[p])}}),d=[],f={};let m,g="";return p;function x(){return u.join("\n")}function y(){for(;u.length>0;)u.pop()}function b(e,t){h[e]=t}function T(e){const t=f[e];return t?r+"."+t:e}function S(e){g=" ".repeat(e)}function v(e,t){const n=`${r}Variable${d.length}`;return u.push(`${g}const ${n} = ${t};`),d.push(e),n}function A(e){u.push(`${g}// ${e}`)}function _(){u.push(`${g}(() => {\n${g}const error = ${r}.getError();\n${g}if (error !== ${r}.NONE) {\n${g} const names = Object.getOwnPropertyNames(gl);\n${g} for (let i = 0; i < names.length; i++) {\n${g} const name = names[i];\n${g} if (${r}[name] === error) {\n${g} throw new Error('${r} threw ' + name);\n${g} }\n${g} }\n${g}}\n${g}})();`)}function w(e,t){return`${r}.${e}(${s(t,{contextName:r,contextVariables:d,getEntity:T,addVariable:v,variables:h,onUnrecognizedArgumentLookup:c})})`}function E(e){const t=d.indexOf(e);return-1!==t?`${r}Variable${t}`:null}}function n(e,t){const r=new Proxy(e,{get:function(t,r){return"function"==typeof t[r]?function(){if("drawBuffersWEBGL"===r)return l.push(`${p}${a}.drawBuffersWEBGL([${s(arguments[0],{contextName:a,contextVariables:o,getEntity:f,addVariable:g,variables:c,onUnrecognizedArgumentLookup:d})}]);`),e.drawBuffersWEBGL(arguments[0]);let t=e[r].apply(e,arguments);switch(typeof t){case"undefined":return void l.push(`${p}${m(r,arguments)};`);case"number":case"boolean":h&&-1===o.indexOf(i(t))?(l.push(`${p}const ${a}Variable${o.length} = ${m(r,arguments)};`),o.push(t=i(t))):(l.push(`${p}const ${a}Variable${o.length} = ${m(r,arguments)};`),o.push(t));break;default:null===t?l.push(`${m(r,arguments)};`):l.push(`${p}const ${a}Variable${o.length} = ${m(r,arguments)};`),o.push(t)}return t}:(n[e[r]]=r,e[r])}}),n={},{contextName:a,contextVariables:o,getEntity:u,useTrackablePrimitives:h,recording:l,variables:c,indent:p,onUnrecognizedArgumentLookup:d}=t;return r;function f(e){return n.hasOwnProperty(e)?`${a}.${n[e]}`:u(e)}function m(e,t){return`${a}.${e}(${s(t,{contextName:a,contextVariables:o,getEntity:f,addVariable:g,variables:c,onUnrecognizedArgumentLookup:d})})`}function g(e,t){const r=`${a}Variable${o.length}`;return o.push(e),l.push(`${p}const ${r} = ${t};`),r}}function s(e,t){const{variables:r,onUnrecognizedArgumentLookup:n}=t;return Array.from(e).map(e=>{const s=function(e){if(r)for(const t in r)if(r.hasOwnProperty(t)&&r[t]===e)return t;return n?n(e):null}(e);return s||function(e,t){const{contextName:r,contextVariables:n,getEntity:s,addVariable:i,onUnrecognizedArgumentLookup:a}=t;if(void 0===e)return"undefined";if(null===e)return"null";const o=n.indexOf(e);if(o>-1)return`${r}Variable${o}`;switch(e.constructor.name){case"String":const t=/\n/.test(e),r=/'/.test(e),n=/"/.test(e);return t?"`"+e+"`":r&&!n?'"'+e+'"':"'"+e+"'";case"Number":case"Boolean":return s(e);case"Array":return i(e,`new ${e.constructor.name}([${Array.from(e).join(",")}])`);case"Float32Array":case"Uint8Array":case"Uint16Array":case"Int32Array":return i(e,`new ${e.constructor.name}(${JSON.stringify(Array.from(e))})`);default:if(a){const t=a(e);if(t)return t}throw new Error(`unrecognized argument type ${e.constructor.name}`)}}(e,t)}).join(", ")}function i(e){return new e.constructor(e)}void 0!==t&&(t.exports={glWiretap:r,glExtensionWiretap:n}),"undefined"!=typeof window&&(r.glExtensionWiretap=n,window.glWiretap=r)}),G=e((e,t)=>{const{glWiretap:r}=P(),{utils:n}=i();function s(e){let t=e.toString().replace(/^function /,"");const r=t.indexOf("=>");if(-1!==r&&!/[{]|\bfunction\b/.test(t.slice(0,r))){const e=t.slice(0,r).trim(),n=t.slice(r+2).trim();t=n.startsWith("{")?`${e} ${n}`:`${e} { return ${n}; }`}return t.replace(/utils[.]/g,"/*utils.*/")}function a(e,t){const r="single"===t.precision?e:`new Float32Array(${e}.buffer)`;return t.output[2]?`renderOutput(${r}, ${t.output[0]}, ${t.output[1]}, ${t.output[2]})`:t.output[1]?`renderOutput(${r}, ${t.output[0]}, ${t.output[1]})`:`renderOutput(${r}, ${t.output[0]})`}function o(e,t){const r=e.toArray.toString(),s=!/^function/.test(r);return`() => {\n function framebuffer() { return getReadFramebuffer(); };\n ${n.flattenFunctionToString(`${s?"function ":""}${r}`,{findDependency:(t,r)=>{if("utils"===t)return`const ${r} = ${n[r].toString()};`;if("this"===t)return"framebuffer"===r?"":`${s?"function ":""}${e[r].toString()}`;throw new Error("unhandled fromObject")},thisLookup:(r,n)=>{if("texture"===r)return t;if("context"===r)return n?null:"gl";if(e.hasOwnProperty(r))return JSON.stringify(e[r]);throw new Error(`unhandled thisLookup ${r}`)}})}\n return toArray();\n }`}function u(e,t,r,n,s){if(null===e)return null;if(null===t)return null;switch(typeof e){case"boolean":case"number":return null}if("undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement)for(let s=0;s{switch(typeof e){case"boolean":return new Boolean(e);case"number":return new Number(e);default:return e}}):null;const c=[],p=[],d=r(i.context,{useTrackablePrimitives:!0,onReadPixels:e=>{if(N.subKernels){if(f){const t=N.subKernels[m++].property;p.push(` result${isNaN(t)?"."+t:`[${t}]`} = ${a(e,N)};`)}else p.push(` const result = { result: ${a(e,N)} };`),f=!0;m===N.subKernels.length&&p.push(" return result;")}else e?p.push(` return ${a(e,N)};`):p.push(" return null;")},onUnrecognizedArgumentLookup:e=>{const t=u(e,N.kernelArguments,[],d,c);if(t)return t;const r=u(e,N.kernelConstants,v?Object.keys(v).map(e=>v[e]):[],d,c);return r||null}});let f=!1,m=0;const{source:g,canvas:x,output:y,pipeline:b,graphical:T,loopMaxIterations:S,constants:v,optimizeFloatMemory:A,precision:_,fixIntegerDivisionAccuracy:w,functions:E,nativeFunctions:I,subKernels:k,immutable:D,argumentTypes:C,constantTypes:L,kernelArguments:$,kernelConstants:F,tactic:R}=i,N=new e(g,{canvas:x,context:d,checkContext:!1,output:y,pipeline:b,graphical:T,loopMaxIterations:S,constants:v,optimizeFloatMemory:A,precision:_,fixIntegerDivisionAccuracy:w,functions:E,nativeFunctions:I,subKernels:k,immutable:D,argumentTypes:C,constantTypes:L,tactic:R});let V=[];if(d.setIndent(2),N.build.apply(N,t),V.push(d.toString()),d.reset(),N.kernelArguments.forEach((e,r)=>{switch(e.type){case"Integer":case"Boolean":case"Number":case"Float":case"Array":case"Array(2)":case"Array(3)":case"Array(4)":case"HTMLCanvas":case"HTMLImage":case"HTMLVideo":case"Input":d.insertVariable(`uploadValue_${e.name}`,e.uploadValue);break;case"HTMLImageArray":for(let n=0;ne.varName).join(", ")}) {`),d.setIndent(4),N.run.apply(N,t),N.renderKernels?N.renderKernels():N.renderOutput&&N.renderOutput(),V.push(" /** start setup uploads for kernel values **/"),N.kernelArguments.forEach(e=>{V.push(" "+e.getStringValueHandler().split("\n").join("\n "))}),V.push(" /** end setup uploads for kernel values **/"),V.push(d.toString()),N.renderOutput===N.renderTexture)if(d.reset(),N.renderKernels){const e=N.renderKernels(),t=d.getContextVariableName(N.texture.texture);V.push(` return {\n result: {\n texture: ${t},\n type: '${e.result.type}',\n toArray: ${o(e.result,t)}\n },`);const{subKernels:r,mappedTextures:n}=N;for(let t=0;t"utils"===e?`const ${t} = ${n[t].toString()};`:null,thisLookup:t=>{if("context"===t)return null;if(e.hasOwnProperty(t))return JSON.stringify(e[t]);throw new Error(`unhandled thisLookup ${t}`)}})}(N)),V.push(" innerKernel.getPixels = getPixels;")),V.push(" return innerKernel;");let M=[];return F.forEach(e=>{M.push(`${e.getStringValueHandler()}`)}),`function kernel(settings) {\n const { context, constants } = settings;\n ${M.join("")}\n ${h||""}\n${V.join("\n")}\n}`}}}),z=e((e,t)=>{t.exports={KernelValue:class{constructor(e,t){const{name:r,kernel:n,context:s,checkContext:i,onRequestContextHandle:a,onUpdateValueMismatch:o,origin:u,strictIntegers:h,type:l,tactic:c}=t;if(!r)throw new Error("name not set");if(!l)throw new Error("type not set");if(!u)throw new Error("origin not set");if("user"!==u&&"constants"!==u)throw new Error(`origin must be "user" or "constants" value is "${u}"`);if(!a)throw new Error("onRequestContextHandle is not set");this.name=r,this.origin=u,this.tactic=c,this.varName="constants"===u?`constants.${r}`:r,this.kernel=n,this.strictIntegers=h,this.type=e.type||l,this.size=e.size||null,this.index=null,this.context=s,this.checkContext=null==i||i,this.contextHandle=null,this.onRequestContextHandle=a,this.onUpdateValueMismatch=o,this.forceUploadEachRun=null}get id(){return`${this.origin}_${name}`}getSource(){throw new Error(`"getSource" not defined on ${this.constructor.name}`)}updateValue(e){throw new Error(`"updateValue" not defined on ${this.constructor.name}`)}}}}),U=e((e,t)=>{const{utils:r}=i(),{KernelValue:n}=z();t.exports={WebGLKernelValue:class extends n{constructor(e,t){super(e,t),this.dimensionsId=null,this.sizeId=null,this.initialValueConstructor=e.constructor,this.onRequestTexture=t.onRequestTexture,this.onRequestIndex=t.onRequestIndex,this.uploadValue=null,this.textureSize=null,this.bitRatio=null,this.prevArg=null}get id(){return`${this.origin}_${r.sanitizeName(this.name)}`}setup(){}rebind(){}getTransferArrayType(e){if(Array.isArray(e[0]))return this.getTransferArrayType(e[0]);switch(e.constructor){case Array:case Int32Array:case Int16Array:case Int8Array:return Float32Array;case Uint8ClampedArray:case Uint8Array:case Uint16Array:case Uint32Array:case Float32Array:case Float64Array:return e.constructor}return console.warn("Unfamiliar constructor type. Will go ahead and use, but likley this may result in a transfer of zeros"),e.constructor}getStringValueHandler(){throw new Error(`"getStringValueHandler" not implemented on ${this.constructor.name}`)}getVariablePrecisionString(){return this.kernel.getVariablePrecisionString(this.textureSize||void 0,this.tactic||void 0)}destroy(){}}}}),K=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValue:n}=U();t.exports={WebGLKernelValueBoolean:class extends n{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const bool ${this.id} = ${e};\n`:`uniform bool ${this.id};\n`}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1i(this.id,this.uploadValue=e)}}}}),B=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValue:n}=U();t.exports={WebGLKernelValueFloat:class extends n{constructor(e,t){super(e,t),this.uploadValue=e}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(e){return"constants"===this.origin?Number.isInteger(e)?`const float ${this.id} = ${e}.0;\n`:`const float ${this.id} = ${e};\n`:`uniform float ${this.id};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1f(this.id,this.uploadValue=e)}}}}),W=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValue:n}=U();t.exports={WebGLKernelValueInteger:class extends n{constructor(e,t){super(e,t),this.uploadValue=e}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(e){return"constants"===this.origin?`const int ${this.id} = ${parseInt(e)};\n`:`uniform int ${this.id};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1i(this.id,this.uploadValue=e)}}}}),j=e((e,t)=>{const{WebGLKernelValue:r}=U(),{Input:s}=n();t.exports={WebGLKernelArray:class extends r{rebind(){if(!this.texture||void 0===this.contextHandle||null===this.contextHandle)return;const{context:e}=this;e.activeTexture(this.contextHandle),e.bindTexture(e.TEXTURE_2D,this.texture)}checkSize(e,t){if(!this.kernel.validate)return;const{maxTextureSize:r}=this.kernel.constructor.features;if(e>r||t>r)throw e>t?new Error(`Argument texture width of ${e} larger than maximum size of ${r} for your GPU`):e{const{utils:r}=i(),{WebGLKernelArray:n}=j();function s(e){return{width:e.width>0?e.width:e.videoWidth,height:e.height>0?e.height:e.videoHeight}}t.exports={WebGLKernelValueHTMLImage:class extends n{constructor(e,t){super(e,t);const{width:r,height:n}=s(e);this.checkSize(r,n),this.dimensions=[r,n,1],this.textureSize=[r,n],this.uploadValue=e}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!0),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,this.uploadValue=e),this.kernel.setUniform1i(this.id,this.index)}},mediaSize:s}}),X=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueHTMLImage:n,mediaSize:s}=H();t.exports={WebGLKernelValueDynamicHTMLImage:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){const{width:t,height:r}=s(e);this.checkSize(t,r),this.dimensions=[t,r,1],this.textureSize=[t,r],this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),q=e((e,t)=>{const{WebGLKernelValueHTMLImage:r}=H();t.exports={WebGLKernelValueHTMLVideo:class extends r{}}}),Y=e((e,t)=>{const{WebGLKernelValueDynamicHTMLImage:r}=X();t.exports={WebGLKernelValueDynamicHTMLVideo:class extends r{}}}),Z=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=j();t.exports={WebGLKernelValueSingleInput:class extends n{constructor(e,t){super(e,t),this.bitRatio=4;let[n,s,i]=e.size;this.dimensions=new Int32Array([n||1,s||1,i||1]),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}.value, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e.value,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),J=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleInput:n}=Z();t.exports={WebGLKernelValueDynamicSingleInput:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){let[t,n,s]=e.size;this.dimensions=new Int32Array([t||1,n||1,s||1]),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Q=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=j();t.exports={WebGLKernelValueUnsignedInput:class extends n{constructor(e,t){super(e,t),this.bitRatio=this.getBitRatio(e);const[n,s,i]=e.size;this.dimensions=new Int32Array([n||1,s||1,i||1]),this.textureSize=r.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]),this.TranserArrayType=this.getTransferArrayType(e.value),this.preUploadValue=new this.TranserArrayType(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer)}getStringValueHandler(){return r.linesToString([`const preUploadValue_${this.name} = new ${this.TranserArrayType.name}(${this.uploadArrayLength})`,`const uploadValue_${this.name} = new Uint8Array(preUploadValue_${this.name}.buffer)`,`flattenTo(${this.varName}.value, preUploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(value.constructor);const{context:t}=this;r.flattenTo(e.value,this.preUploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.UNSIGNED_BYTE,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),ee=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueUnsignedInput:n}=Q();t.exports={WebGLKernelValueDynamicUnsignedInput:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){let[t,n,s]=e.size;this.dimensions=new Int32Array([t||1,n||1,s||1]),this.textureSize=r.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]);const i=this.getTransferArrayType(e.value);this.preUploadValue=new i(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),te=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=j(),s="Source and destination textures are the same. Use immutable = true and manually cleanup kernel output texture memory with texture.delete()";t.exports={WebGLKernelValueMemoryOptimizedNumberTexture:class extends n{constructor(e,t){super(e,t);const[r,n]=e.size;this.checkSize(r,n),this.dimensions=e.dimensions,this.textureSize=e.size,this.uploadValue=e.texture,this.forceUploadEachRun=!0}setup(){this.setupTexture()}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName}.texture;\n`}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);if(this.checkContext&&e.context!==this.context)throw new Error(`Value ${this.name} (${this.type}) must be from same context`);const{kernel:t,context:r}=this;if(t.pipeline)if(t.immutable)t.updateTextureArgumentRefs(this,e);else{if(t.texture&&t.texture.texture===e.texture)throw new Error(s);if(t.mappedTextures){const{mappedTextures:r}=t;for(let t=0;t{const{utils:r}=i(),{WebGLKernelValueMemoryOptimizedNumberTexture:n}=te();t.exports={WebGLKernelValueDynamicMemoryOptimizedNumberTexture:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=e.dimensions,this.checkSize(e.size[0],e.size[1]),this.textureSize=e.size,this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ne=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=j(),{sameError:s}=te();t.exports={WebGLKernelValueNumberTexture:class extends n{constructor(e,t){super(e,t);const[r,n]=e.size;this.checkSize(r,n);const{size:s,dimensions:i}=e;this.bitRatio=this.getBitRatio(e),this.dimensions=i,this.textureSize=s,this.uploadValue=e.texture,this.forceUploadEachRun=!0}setup(){this.setupTexture()}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName}.texture;\n`}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);if(this.checkContext&&e.context!==this.context)throw new Error(`Value ${this.name} (${this.type}) must be from same context`);const{kernel:t,context:r}=this;if(t.pipeline)if(t.immutable)t.updateTextureArgumentRefs(this,e);else{if(t.texture&&t.texture.texture===e.texture)throw new Error(s);if(t.mappedTextures){const{mappedTextures:r}=t;for(let t=0;t{const{utils:r}=i(),{WebGLKernelValueNumberTexture:n}=ne();t.exports={WebGLKernelValueDynamicNumberTexture:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=e.dimensions,this.checkSize(e.size[0],e.size[1]),this.textureSize=e.size,this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ie=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=j();t.exports={WebGLKernelValueSingleArray:class extends n{constructor(e,t){super(e,t),this.bitRatio=4,this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(!r.isArray(e))return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),ae=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray:n}=ie();t.exports={WebGLKernelValueDynamicSingleArray:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),oe=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=j();t.exports={WebGLKernelValueSingleArray1DI:class extends n{constructor(e,t){super(e,t),this.bitRatio=4,this.setShape(e)}setShape(e){const t=r.getDimensions(e,!0);this.textureSize=r.getMemoryOptimizedFloatTextureSize(t,this.bitRatio),this.dimensions=new Int32Array([t[1],1,1]),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flatten2dArrayTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),ue=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray1DI:n}=oe();t.exports={WebGLKernelValueDynamicSingleArray1DI:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),he=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=j();t.exports={WebGLKernelValueSingleArray2DI:class extends n{constructor(e,t){super(e,t),this.bitRatio=4,this.setShape(e)}setShape(e){const t=r.getDimensions(e,!0);this.textureSize=r.getMemoryOptimizedFloatTextureSize(t,this.bitRatio),this.dimensions=new Int32Array([t[1],t[2],1]),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flatten3dArrayTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),le=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray2DI:n}=he();t.exports={WebGLKernelValueDynamicSingleArray2DI:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ce=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=j();t.exports={WebGLKernelValueSingleArray3DI:class extends n{constructor(e,t){super(e,t),this.bitRatio=4,this.setShape(e)}setShape(e){const t=r.getDimensions(e,!0);this.textureSize=r.getMemoryOptimizedFloatTextureSize(t,this.bitRatio),this.dimensions=new Int32Array([t[1],t[2],t[3]]),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return r.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flatten4dArrayTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),pe=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray3DI:n}=ce();t.exports={WebGLKernelValueDynamicSingleArray3DI:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),de=e((e,t)=>{const{WebGLKernelValue:r}=U();t.exports={WebGLKernelValueArray2:class extends r{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const vec2 ${this.id} = vec2(${e[0]},${e[1]});\n`:`uniform vec2 ${this.id};\n`}getStringValueHandler(){return"constants"===this.origin?"":`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform2fv(this.id,this.uploadValue=e)}}}}),fe=e((e,t)=>{const{WebGLKernelValue:r}=U();t.exports={WebGLKernelValueArray3:class extends r{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const vec3 ${this.id} = vec3(${e[0]},${e[1]},${e[2]});\n`:`uniform vec3 ${this.id};\n`}getStringValueHandler(){return"constants"===this.origin?"":`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform3fv(this.id,this.uploadValue=e)}}}}),me=e((e,t)=>{const{WebGLKernelValue:r}=U();t.exports={WebGLKernelValueArray4:class extends r{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const vec4 ${this.id} = vec4(${e[0]},${e[1]},${e[2]},${e[3]});\n`:`uniform vec4 ${this.id};\n`}getStringValueHandler(){return"constants"===this.origin?"":`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform4fv(this.id,this.uploadValue=e)}}}}),ge=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=j();t.exports={WebGLKernelValueUnsignedArray:class extends n{constructor(e,t){super(e,t),this.bitRatio=this.getBitRatio(e),this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]),this.TranserArrayType=this.getTransferArrayType(e),this.preUploadValue=new this.TranserArrayType(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer)}getStringValueHandler(){return r.linesToString([`const preUploadValue_${this.name} = new ${this.TranserArrayType.name}(${this.uploadArrayLength})`,`const uploadValue_${this.name} = new Uint8Array(preUploadValue_${this.name}.buffer)`,`flattenTo(${this.varName}, preUploadValue_${this.name})`])}getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(!r.isArray(e))return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.preUploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.UNSIGNED_BYTE,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),xe=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueUnsignedArray:n}=ge();t.exports={WebGLKernelValueDynamicUnsignedArray:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]);const t=this.getTransferArrayType(e);this.preUploadValue=new t(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ye=e((e,t)=>{const{WebGLKernelValueBoolean:r}=K(),{WebGLKernelValueFloat:n}=B(),{WebGLKernelValueInteger:s}=W(),{WebGLKernelValueHTMLImage:i}=H(),{WebGLKernelValueDynamicHTMLImage:a}=X(),{WebGLKernelValueHTMLVideo:o}=q(),{WebGLKernelValueDynamicHTMLVideo:u}=Y(),{WebGLKernelValueSingleInput:h}=Z(),{WebGLKernelValueDynamicSingleInput:l}=J(),{WebGLKernelValueUnsignedInput:c}=Q(),{WebGLKernelValueDynamicUnsignedInput:p}=ee(),{WebGLKernelValueMemoryOptimizedNumberTexture:d}=te(),{WebGLKernelValueDynamicMemoryOptimizedNumberTexture:f}=re(),{WebGLKernelValueNumberTexture:m}=ne(),{WebGLKernelValueDynamicNumberTexture:g}=se(),{WebGLKernelValueSingleArray:x}=ie(),{WebGLKernelValueDynamicSingleArray:y}=ae(),{WebGLKernelValueSingleArray1DI:b}=oe(),{WebGLKernelValueDynamicSingleArray1DI:T}=ue(),{WebGLKernelValueSingleArray2DI:S}=he(),{WebGLKernelValueDynamicSingleArray2DI:v}=le(),{WebGLKernelValueSingleArray3DI:A}=ce(),{WebGLKernelValueDynamicSingleArray3DI:_}=pe(),{WebGLKernelValueArray2:w}=de(),{WebGLKernelValueArray3:E}=fe(),{WebGLKernelValueArray4:I}=me(),{WebGLKernelValueUnsignedArray:k}=ge(),{WebGLKernelValueDynamicUnsignedArray:D}=xe(),C={unsigned:{dynamic:{Boolean:r,Integer:s,Float:n,Array:D,"Array(2)":w,"Array(3)":E,"Array(4)":I,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:p,NumberTexture:g,"ArrayTexture(1)":g,"ArrayTexture(2)":g,"ArrayTexture(3)":g,"ArrayTexture(4)":g,MemoryOptimizedNumberTexture:f,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:!1,HTMLVideo:u},static:{Boolean:r,Float:n,Integer:s,Array:k,"Array(2)":w,"Array(3)":E,"Array(4)":I,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:c,NumberTexture:m,"ArrayTexture(1)":m,"ArrayTexture(2)":m,"ArrayTexture(3)":m,"ArrayTexture(4)":m,MemoryOptimizedNumberTexture:d,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:!1,HTMLVideo:o}},single:{dynamic:{Boolean:r,Integer:s,Float:n,Array:y,"Array(2)":w,"Array(3)":E,"Array(4)":I,"Array1D(2)":T,"Array1D(3)":T,"Array1D(4)":T,"Array2D(2)":v,"Array2D(3)":v,"Array2D(4)":v,"Array3D(2)":_,"Array3D(3)":_,"Array3D(4)":_,Input:l,NumberTexture:g,"ArrayTexture(1)":g,"ArrayTexture(2)":g,"ArrayTexture(3)":g,"ArrayTexture(4)":g,MemoryOptimizedNumberTexture:f,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:!1,HTMLVideo:u},static:{Boolean:r,Float:n,Integer:s,Array:x,"Array(2)":w,"Array(3)":E,"Array(4)":I,"Array1D(2)":b,"Array1D(3)":b,"Array1D(4)":b,"Array2D(2)":S,"Array2D(3)":S,"Array2D(4)":S,"Array3D(2)":A,"Array3D(3)":A,"Array3D(4)":A,Input:h,NumberTexture:m,"ArrayTexture(1)":m,"ArrayTexture(2)":m,"ArrayTexture(3)":m,"ArrayTexture(4)":m,MemoryOptimizedNumberTexture:d,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:!1,HTMLVideo:o}}};t.exports={lookupKernelValueType:function(e,t,r,n){if(!e)throw new Error("type missing");if(!t)throw new Error("dynamic missing");if(!r)throw new Error("precision missing");n.type&&(e=n.type);const s=C[r][t];if("WebGPUBuffer"===e)throw new Error("this kernel runs on WebGL but received a WebGPU pipeline buffer; await handle.toArray() first, or give this kernel the async contract (asyncMode: true / mode: 'async') so the readback happens for you");if(!1===s[e])return null;if(void 0===s[e])throw new Error(`Could not find a KernelValue for ${e}`);return s[e]},kernelValueMaps:C}}),be=e((e,t)=>{const{GLKernel:r}=R(),{FunctionBuilder:n}=o(),{WebGLFunctionNode:s}=N(),{utils:a}=i(),u=V(),{fragmentShader:h}=M(),{vertexShader:l}=O(),{glKernelString:c}=G(),{lookupKernelValueType:p}=ye();let d=null,f=null,m=null,g=null,x=null;const y=[u],b=[],T={};t.exports={WebGLKernel:class extends r{static get isSupported(){return null!==d||(this.setupFeatureChecks(),d=this.isContextMatch(m)),d}static setupFeatureChecks(){"undefined"!=typeof document?f=document.createElement("canvas"):"undefined"!=typeof OffscreenCanvas&&(f=new OffscreenCanvas(0,0)),f&&(m=f.getContext("webgl"),m||f instanceof OffscreenCanvas||(m=f.getContext("experimental-webgl")),m&&m.getExtension&&(g={OES_texture_float:m.getExtension("OES_texture_float"),OES_texture_float_linear:m.getExtension("OES_texture_float_linear"),OES_element_index_uint:m.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:m.getExtension("WEBGL_draw_buffers")},x=this.getFeatures()))}static isContextMatch(e){return"undefined"!=typeof WebGLRenderingContext&&e instanceof WebGLRenderingContext}static getIsTextureFloat(){return Boolean(g.OES_texture_float)}static getIsDrawBuffers(){return Boolean(g.WEBGL_draw_buffers)}static getChannelCount(){return g.WEBGL_draw_buffers?m.getParameter(g.WEBGL_draw_buffers.MAX_DRAW_BUFFERS_WEBGL):1}static getMaxTextureSize(){return m.getParameter(m.MAX_TEXTURE_SIZE)}static lookupKernelValueType(e,t,r,n){return p(e,t,r,n)}static get testCanvas(){return f}static get testContext(){return m}static get features(){return x}static get fragmentShader(){return h}static get vertexShader(){return l}constructor(e,t){super(e,t),this.program=null,this.pipeline=t.pipeline,this.endianness=a.systemEndianness(),this.extensions={},this.argumentTextureCount=0,this.constantTextureCount=0,this.fragShader=null,this.vertShader=null,this.drawBuffersMap=null,this.maxTexSize=null,this.onRequestSwitchKernel=null,this.texture=null,this.mappedTextures=null,this.mergeSettings(e.settings||t),this.threadDim=null,this.framebuffer=null,this.buffer=null,this.textureCache=[],this.programUniformLocationCache={},this.uniform1fCache={},this.uniform1iCache={},this.uniform2fCache={},this.uniform2fvCache={},this.uniform2ivCache={},this.uniform3fvCache={},this.uniform3ivCache={},this.uniform4fvCache={},this.uniform4ivCache={}}initCanvas(){if("undefined"!=typeof document){const e=document.createElement("canvas");return e.width=2,e.height=2,e}if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(0,0)}initContext(){const e={alpha:!1,depth:!1,antialias:!1};return this.canvas.getContext("webgl",e)||this.canvas.getContext("experimental-webgl",e)}initPlugins(e){const t=[],{source:r}=this;if("string"==typeof r)for(let e=0;ee===n.name)&&t.push(n)}return t}initExtensions(){this.extensions={OES_texture_float:this.context.getExtension("OES_texture_float"),OES_texture_float_linear:this.context.getExtension("OES_texture_float_linear"),OES_element_index_uint:this.context.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:this.context.getExtension("WEBGL_draw_buffers"),WEBGL_color_buffer_float:this.context.getExtension("WEBGL_color_buffer_float")}}validateSettings(e){if(!this.validate)return void(this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output));const{features:t}=this.constructor;if(!0===this.optimizeFloatMemory&&!t.isTextureFloat)throw new Error("Float textures are not supported");if("single"===this.precision&&!t.isFloatRead)throw new Error("Single precision not supported");if(this.graphical||null!==this.precision||(this.precision=t.isTextureFloat&&t.isFloatRead?"single":"unsigned"),this.subKernels&&this.subKernels.length>0&&!this.extensions.WEBGL_draw_buffers)throw new Error("could not instantiate draw buffers extension");if(null===this.fixIntegerDivisionAccuracy?this.fixIntegerDivisionAccuracy=!t.isIntegerDivisionAccurate:this.fixIntegerDivisionAccuracy&&t.isIntegerDivisionAccurate&&(this.fixIntegerDivisionAccuracy=!1),this.checkOutput(),!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=a.getVariableType(e[0],this.strictIntegers);switch(t){case"Array":this.output=a.getDimensions(t);break;case"NumberTexture":case"MemoryOptimizedNumberTexture":case"ArrayTexture(1)":case"ArrayTexture(2)":case"ArrayTexture(3)":case"ArrayTexture(4)":this.output=e[0].output;break;default:throw new Error("Auto output not supported for input type: "+t)}}if(this.graphical){if(2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");return"precision"===this.precision&&(this.precision="unsigned",console.warn("Cannot use graphical mode and single precision at the same time")),void(this.texSize=a.clone(this.output))}null===this.precision&&t.isTextureFloat&&(this.precision="single"),this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output),this.checkTextureSize()}updateMaxTexSize(){const{texSize:e,canvas:t}=this;if(null===this.maxTexSize){let r=b.indexOf(t);-1===r&&(r=b.length,b.push(t),T[r]=[e[0],e[1]]),this.maxTexSize=T[r]}this.maxTexSize[0]this.argumentNames.length)throw new Error("too many arguments for kernel");const{context:r}=this;let n=0;const s=()=>this.createTexture(),i=()=>this.constantTextureCount+n++,o=e=>{this.switchKernels({type:"argumentMismatch",needed:e})},u=()=>r.TEXTURE0+this.constantTextureCount+this.argumentTextureCount++;for(let n=0;nthis.createTexture(),onRequestIndex:()=>n++,onRequestContextHandle:()=>t.TEXTURE0+this.constantTextureCount++});this.constantBitRatios[s]=h.bitRatio,this.kernelConstants.push(h),h.setup(),h.forceUploadEachRun&&this.forceUploadKernelConstants.push(h)}}build(){if(this.built)return;if(this.initExtensions(),this.validateSettings(arguments),this.setupConstants(arguments),this.fallbackRequested)return;if(this.setupArguments(arguments),this.fallbackRequested)return;this.updateMaxTexSize(),this.translateSource();const e=this.pickRenderStrategy(arguments);if(e)return e;const{texSize:t,context:r,canvas:n}=this;r.enable(r.SCISSOR_TEST),this.pipeline&&this.precision,r.viewport(0,0,this.maxTexSize[0],this.maxTexSize[1]),n.width=this.maxTexSize[0],n.height=this.maxTexSize[1];const s=this.threadDim=Array.from(this.output);for(;s.length<3;)s.push(1);const i=this.getVertexShader(arguments),a=r.createShader(r.VERTEX_SHADER);r.shaderSource(a,i),r.compileShader(a),this.vertShader=a;const o=this.getFragmentShader(arguments),u=r.createShader(r.FRAGMENT_SHADER);if(r.shaderSource(u,o),r.compileShader(u),this.fragShader=u,this.debug&&(console.log("GLSL Shader Output:"),console.log(o)),!r.getShaderParameter(a,r.COMPILE_STATUS))throw new Error("Error compiling vertex shader: "+r.getShaderInfoLog(a));if(!r.getShaderParameter(u,r.COMPILE_STATUS))throw new Error("Error compiling fragment shader: "+r.getShaderInfoLog(u));const h=this.program=r.createProgram();r.attachShader(h,a),r.attachShader(h,u),r.linkProgram(h),this.framebuffer=r.createFramebuffer(),this.framebuffer.width=t[0],this.framebuffer.height=t[1],this.rawValueFramebuffers={};const l=new Float32Array([-1,-1,1,-1,-1,1,1,1]),c=new Float32Array([0,0,1,0,0,1,1,1]),p=l.byteLength;let d=this.buffer;d?r.bindBuffer(r.ARRAY_BUFFER,d):(d=this.buffer=r.createBuffer(),r.bindBuffer(r.ARRAY_BUFFER,d),r.bufferData(r.ARRAY_BUFFER,l.byteLength+c.byteLength,r.STATIC_DRAW)),r.bufferSubData(r.ARRAY_BUFFER,0,l),r.bufferSubData(r.ARRAY_BUFFER,p,c);const f=r.getAttribLocation(this.program,"aPos");-1!==f&&(r.enableVertexAttribArray(f),r.vertexAttribPointer(f,2,r.FLOAT,!1,0,0));const m=r.getAttribLocation(this.program,"aTexCoord");-1!==m&&(r.enableVertexAttribArray(m),r.vertexAttribPointer(m,2,r.FLOAT,!1,0,p)),r.bindFramebuffer(r.FRAMEBUFFER,this.framebuffer);let g=0;r.useProgram(this.program);for(let e in this.constants)this.kernelConstants[g++].updateValue(this.constants[e]);this._setupOutputTexture(),null!==this.subKernels&&this.subKernels.length>0&&(this._mappedTextureSwitched={},this._setupSubOutputTextures()),this.buildSignature(arguments),this.built=!0}translateSource(){const e=n.fromKernel(this,s,{fixIntegerDivisionAccuracy:this.fixIntegerDivisionAccuracy});this.translatedSource=e.getPrototypeString("kernel"),this.setupReturnTypes(e)}setupReturnTypes(e){if(this.graphical||this.returnType||(this.returnType=e.getKernelResultType()),this.subKernels&&this.subKernels.length>0)for(let t=0;te.source&&this.source.match(e.functionMatch)?e.source:"").join("\n"):"\n"}_getConstantsString(){const e=[],{threadDim:t,texSize:r}=this;return this.dynamicOutput?e.push("uniform ivec3 uOutputDim","uniform ivec2 uTexSize"):e.push(`ivec3 uOutputDim = ivec3(${t[0]}, ${t[1]}, ${t[2]})`,`ivec2 uTexSize = ivec2(${r[0]}, ${r[1]})`),a.linesToString(e)}_getTextureCoordinate(){const e=this.subKernels;return null===e||e.length<1?"varying vec2 vTexCoord;\n":"out vec2 vTexCoord;\n"}_getDecode32EndiannessString(){return"LE"===this.endianness?"":" texel.rgba = texel.abgr;\n"}_getEncode32EndiannessString(){return"LE"===this.endianness?"":" texel.rgba = texel.abgr;\n"}_getDivideWithIntegerCheckString(){return this.fixIntegerDivisionAccuracy?"float divWithIntCheck(float x, float y) {\n if (floor(x) == x && floor(y) == y) {\n float q = floor(x / y + 0.5);\n if (y * q == x) {\n return q;\n }\n }\n return x / y;\n}\n\nfloat integerCorrectionModulo(float number, float divisor) {\n if (number < 0.0) {\n number = abs(number);\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return -(number - (divisor * floor(divWithIntCheck(number, divisor))));\n }\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return number - (divisor * floor(divWithIntCheck(number, divisor)));\n}":""}_getMainArgumentsString(e){const t=[],{argumentNames:r}=this;for(let n=0;n{if(t.hasOwnProperty(r))return t[r];throw`unhandled artifact ${r}`})}getFragmentShader(e){return null!==this.compiledFragmentShader?this.compiledFragmentShader:this.compiledFragmentShader=this.replaceArtifacts(this.constructor.fragmentShader,this._getFragShaderArtifactMap(e))}getVertexShader(e){return null!==this.compiledVertexShader?this.compiledVertexShader:this.compiledVertexShader=this.replaceArtifacts(this.constructor.vertexShader,this._getVertShaderArtifactMap(e))}toString(){const e=a.linesToString(["const gl = context"]);return c(this.constructor,arguments,this,e)}destroy(e){if(!this.context)return;this.buffer&&this.context.deleteBuffer(this.buffer),this.framebuffer&&this.context.deleteFramebuffer(this.framebuffer);for(const e in this.rawValueFramebuffers){for(const t in this.rawValueFramebuffers[e])this.context.deleteFramebuffer(this.rawValueFramebuffers[e][t]),delete this.rawValueFramebuffers[e][t];delete this.rawValueFramebuffers[e]}if(this.vertShader&&this.context.deleteShader(this.vertShader),this.fragShader&&this.context.deleteShader(this.fragShader),this.program&&this.context.deleteProgram(this.program),this.texture){this.texture.delete();const e=this.textureCache.indexOf(this.texture.texture);e>-1&&this.textureCache.splice(e,1),this.texture=null}if(this.mappedTextures&&this.mappedTextures.length){for(let e=0;e-1&&this.textureCache.splice(r,1)}this.mappedTextures=null}if(this.kernelArguments)for(let e=0;e0;){const e=this.textureCache.pop();this.context.deleteTexture(e)}if(e){const e=b.indexOf(this.canvas);e>=0&&(b[e]=null,T[e]=null)}if(this.destroyExtensions(),delete this.context,delete this.canvas,!this.gpu)return;const t=this.gpu.kernels.indexOf(this);-1!==t&&this.gpu.kernels.splice(t,1)}destroyExtensions(){this.extensions.OES_texture_float=null,this.extensions.OES_texture_float_linear=null,this.extensions.OES_element_index_uint=null,this.extensions.WEBGL_draw_buffers=null}static destroyContext(e){const t=e.getExtension("WEBGL_lose_context");t&&t.loseContext()}toJSON(){const e=super.toJSON();return e.functionNodes=n.fromKernel(this,s).toJSON(),e.settings.threadDim=this.threadDim,e}}}}),Te=e((e,t)=>{const r=d(),{WebGLKernel:n}=be(),{glKernelString:s}=G();let i=null,a=null,o=null,u=null,h=null;t.exports={HeadlessGLKernel:class extends n{static get isSupported(){return null!==i||(this.setupFeatureChecks(),i=null!==o),i}static setupFeatureChecks(){if(a=null,u=null,"function"==typeof r)try{if(o=r(2,2,{preserveDrawingBuffer:!0}),!o||!o.getExtension)return;u={STACKGL_resize_drawingbuffer:o.getExtension("STACKGL_resize_drawingbuffer"),STACKGL_destroy_context:o.getExtension("STACKGL_destroy_context"),OES_texture_float:o.getExtension("OES_texture_float"),OES_texture_float_linear:o.getExtension("OES_texture_float_linear"),OES_element_index_uint:o.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:o.getExtension("WEBGL_draw_buffers"),WEBGL_color_buffer_float:o.getExtension("WEBGL_color_buffer_float")},h=this.getFeatures()}catch(e){console.warn(e)}}static isContextMatch(e){try{return"ANGLE"===e.getParameter(e.RENDERER)}catch(e){return!1}}static getIsTextureFloat(){return Boolean(u.OES_texture_float)}static getIsDrawBuffers(){return Boolean(u.WEBGL_draw_buffers)}static getChannelCount(){return u.WEBGL_draw_buffers?o.getParameter(u.WEBGL_draw_buffers.MAX_DRAW_BUFFERS_WEBGL):1}static getMaxTextureSize(){return o.getParameter(o.MAX_TEXTURE_SIZE)}static get testCanvas(){return a}static get testContext(){return o}static get features(){return h}initCanvas(){return{}}initContext(){return r(2,2,{preserveDrawingBuffer:!0})}initExtensions(){this.extensions={STACKGL_resize_drawingbuffer:this.context.getExtension("STACKGL_resize_drawingbuffer"),STACKGL_destroy_context:this.context.getExtension("STACKGL_destroy_context"),OES_texture_float:this.context.getExtension("OES_texture_float"),OES_texture_float_linear:this.context.getExtension("OES_texture_float_linear"),OES_element_index_uint:this.context.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:this.context.getExtension("WEBGL_draw_buffers")}}build(){super.build.apply(this,arguments),this.fallbackRequested||this.extensions.STACKGL_resize_drawingbuffer.resize(this.maxTexSize[0],this.maxTexSize[1])}destroyExtensions(){this.extensions.STACKGL_resize_drawingbuffer=null,this.extensions.STACKGL_destroy_context=null,this.extensions.OES_texture_float=null,this.extensions.OES_texture_float_linear=null,this.extensions.OES_element_index_uint=null,this.extensions.WEBGL_draw_buffers=null}static destroyContext(e){const t=e.getExtension("STACKGL_destroy_context");t&&t.destroy&&t.destroy()}toString(){return s(this.constructor,arguments,this,"const gl = context || require('gl')(1, 1);\n"," if (!context) { gl.getExtension('STACKGL_destroy_context').destroy(); }\n")}setOutput(e){return super.setOutput(e),this.graphical&&this.extensions.STACKGL_resize_drawingbuffer&&this.extensions.STACKGL_resize_drawingbuffer.resize(this.maxTexSize[0],this.maxTexSize[1]),this}}}}),Se=e((e,t)=>{const{utils:r}=i(),{WebGLFunctionNode:n}=N();t.exports={WebGL2FunctionNode:class extends n{astIdentifierExpression(e,t){if("Identifier"!==e.type)throw this.astErrorOutput("IdentifierExpression - not an Identifier",e);const n=this.getType(e),s=r.sanitizeName(e.name);return"Infinity"===e.name?t.push("intBitsToFloat(2139095039)"):"Boolean"===n&&this.argumentNames.indexOf(s)>-1?t.push(`bool(user_${s})`):t.push(`user_${s}`),t}}}}),ve=e((e,t)=>{t.exports={fragmentShader:`#version 300 es\n__HEADER__;\n__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n__SAMPLER_2D_ARRAY_TACTIC_DECLARATION__;\n\nconst int LOOP_MAX = __LOOP_MAX__;\n\n__PLUGINS__;\n__CONSTANTS__;\n\nin vec2 vTexCoord;\n\nfloat atan2(float v1, float v2) {\n if (v2 == 0.0) {\n if (v1 == 0.0) return 0.0;\n if (v1 > 0.0) return 1.5707963267948966;\n if (v1 < 0.0) return -1.5707963267948966;\n }\n return atan(v1, v2);\n}\n\nfloat cbrt(float x) {\n if (x >= 0.0) {\n return pow(x, 1.0 / 3.0);\n } else {\n return -pow(x, 1.0 / 3.0);\n }\n}\n\nfloat expm1(float x) {\n return pow(${Math.E}, x) - 1.0; \n}\n\nfloat fround(highp float x) {\n return x;\n}\n\nfloat imul(float v1, float v2) {\n return float(int(v1) * int(v2));\n}\n\nfloat log10(float x) {\n return log2(x) * (1.0 / log2(10.0));\n}\n\nfloat log1p(float x) {\n return log(1.0 + x);\n}\n\nfloat _pow(float v1, float v2) {\n if (v2 == 0.0) return 1.0;\n return pow(v1, v2);\n}\n\nfloat _round(float x) {\n return floor(x + 0.5);\n}\n\n\nconst int BIT_COUNT = 32;\nint modi(int x, int y) {\n return x - y * (x / y);\n}\n\nint bitwiseOr(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) || (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseXOR(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) != (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseAnd(int a, int b) {\n int result = 0;\n int n = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) && (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 && b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseNot(int a) {\n // ~a is identically -a - 1 in two's complement, for every value including\n // negatives. The previous bit-by-bit loop only worked for a >= 0, where it\n // leaned on 32-bit overflow wrapping to reach the negative answer; given a\n // negative input it computed ~abs(a), so ~(-1) gave -2 and ~~x never\n // returned x.\n return -a - 1;\n}\nint bitwiseZeroFillLeftShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n *= 2;\n }\n\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\n// _pow2 is defined further down, alongside encode32/decode32\nfloat _pow2(float e);\nint bitwiseSignedRightShift(int num, int shifts) {\n // pow(2.0, n) is approximate on many GPUs, and landing 1 ulp high makes the\n // division fall just under a whole number, which floor() then rounds away:\n // 2 >> 1 came out 0, 8 >> 1 came out 3. Only exact left operands were\n // affected, odd ones having enough slack to survive. _pow2 is exact.\n return int(floor(float(num) / _pow2(float(shifts))));\n}\n\nint bitwiseZeroFillRightShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n /= 2;\n }\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\nvec2 integerMod(vec2 x, float y) {\n vec2 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec3 integerMod(vec3 x, float y) {\n vec3 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec4 integerMod(vec4 x, vec4 y) {\n vec4 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nfloat integerMod(float x, float y) {\n float res = floor(mod(x, y));\n return res * (res > floor(y) - 1.0 ? 0.0 : 1.0);\n}\n\nint integerMod(int x, int y) {\n return x - (y * int(x/y));\n}\n\n// GLSL ES 1.00 accepts only a constant or a loop symbol inside an index\n// expression, so m[y][x] does not compile when y and x come from kernel\n// arguments -- the error is "Index expression can only contain const or loop\n// symbols". Loop counters are legal indices, so walk the matrix with them\n// instead. These are 2x2 to 4x4, so it costs at most sixteen comparisons.\nfloat getMatrix2(mat2 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 2; i++) {\n for (int j = 0; j < 2; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix3(mat3 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 3; i++) {\n for (int j = 0; j < 3; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix4(mat4 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 4; i++) {\n for (int j = 0; j < 4; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\n__DIVIDE_WITH_INTEGER_CHECK__;\n\n// Here be dragons!\n// DO NOT OPTIMIZE THIS CODE\n// YOU WILL BREAK SOMETHING ON SOMEBODY'S MACHINE\n// LEAVE IT AS IT IS, LEST YOU WASTE YOUR OWN TIME\n// Exact powers of two built from exact constant multiplies: exp2/log2/pow\n// are approximate on some GPUs (notably Apple silicon), and 1-2 ulp there\n// corrupts the packed bytes (#659)\nfloat _pow2(float e) {\n float r = 1.0;\n float a = abs(e);\n bool n = e < 0.0;\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 32.0) { r *= n ? 2.3283064365386963e-10 : 4294967296.0; a -= 32.0; }\n if (a >= 16.0) { r *= n ? 0.0000152587890625 : 65536.0; a -= 16.0; }\n if (a >= 8.0) { r *= n ? 0.00390625 : 256.0; a -= 8.0; }\n if (a >= 4.0) { r *= n ? 0.0625 : 16.0; a -= 4.0; }\n if (a >= 2.0) { r *= n ? 0.25 : 4.0; a -= 2.0; }\n if (a >= 1.0) { r *= n ? 0.5 : 2.0; }\n return r;\n}\nconst vec2 MAGIC_VEC = vec2(1.0, -256.0);\nconst vec4 SCALE_FACTOR = vec4(1.0, 256.0, 65536.0, 0.0);\nconst vec4 SCALE_FACTOR_INV = vec4(1.0, 0.00390625, 0.0000152587890625, 0.0); // 1, 1/256, 1/65536\nfloat decode32(vec4 texel) {\n __DECODE32_ENDIANNESS__;\n texel *= 255.0;\n vec2 gte128;\n gte128.x = texel.b >= 128.0 ? 1.0 : 0.0;\n gte128.y = texel.a >= 128.0 ? 1.0 : 0.0;\n float exponent = 2.0 * texel.a - 127.0 + dot(gte128, MAGIC_VEC);\n float res = _pow2(round(exponent));\n texel.b = texel.b - 128.0 * gte128.x;\n res = dot(texel, SCALE_FACTOR) * _pow2(round(exponent-23.0)) + res;\n res *= gte128.y * -2.0 + 1.0;\n return res;\n}\n\nfloat decode16(vec4 texel, int index) {\n int channel = integerMod(index, 2);\n return texel[channel*2] * 255.0 + texel[channel*2 + 1] * 65280.0;\n}\n\nfloat decode8(vec4 texel, int index) {\n int channel = integerMod(index, 4);\n return texel[channel] * 255.0;\n}\n\nvec4 legacyEncode32(float f) {\n float F = abs(f);\n float sign = f < 0.0 ? 1.0 : 0.0;\n float exponent = floor(log2(F));\n float mantissa = (exp2(-exponent) * F);\n // exponent += floor(log2(mantissa));\n vec4 texel = vec4(F * exp2(23.0-exponent)) * SCALE_FACTOR_INV;\n texel.rg = integerMod(texel.rg, 256.0);\n texel.b = integerMod(texel.b, 128.0);\n texel.a = exponent*0.5 + 63.5;\n texel.ba += vec2(integerMod(exponent+127.0, 2.0), sign) * 128.0;\n texel = floor(texel);\n texel *= 0.003921569; // 1/255\n __ENCODE32_ENDIANNESS__;\n return texel;\n}\n\n// https://github.com/gpujs/gpu.js/wiki/Encoder-details\nvec4 encode32(float value) {\n if (value == 0.0) return vec4(0, 0, 0, 0);\n\n float exponent;\n float mantissa;\n vec4 result;\n float sgn;\n\n sgn = step(0.0, -value);\n value = abs(value);\n\n exponent = floor(log2(value));\n float p2 = _pow2(exponent);\n // approximate log2 can land one off; correct by direct comparison\n if (p2 > value) { exponent -= 1.0; p2 *= 0.5; }\n else if (p2 * 2.0 <= value) { exponent += 1.0; p2 *= 2.0; }\n\n mantissa = value / p2 - 1.0;\n exponent = exponent+127.0;\n result = vec4(0,0,0,0);\n\n result.a = floor(exponent/2.0);\n exponent = exponent - result.a*2.0;\n result.a = result.a + 128.0*sgn;\n\n result.b = floor(mantissa * 128.0);\n mantissa = mantissa - result.b / 128.0;\n result.b = result.b + exponent*128.0;\n\n result.g = floor(mantissa*32768.0);\n mantissa = mantissa - result.g/32768.0;\n\n result.r = floor(mantissa*8388608.0);\n return result/255.0;\n}\n// Dragons end here\n\nint index;\nivec3 threadId;\n\nivec3 indexTo3D(int idx, ivec3 texDim) {\n int z = int(idx / (texDim.x * texDim.y));\n idx -= z * int(texDim.x * texDim.y);\n int y = int(idx / texDim.x);\n int x = int(integerMod(idx, texDim.x));\n return ivec3(x, y, z);\n}\n\nfloat get32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize));\n return decode32(texel);\n}\n\nfloat get16(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int w = texSize.x * 2;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize.x * 2, texSize.y));\n return decode16(texel, index);\n}\n\nfloat get8(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int w = texSize.x * 4;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize.x * 4, texSize.y));\n return decode8(texel, index);\n}\n\nfloat getMemoryOptimized32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int channel = integerMod(index, 4);\n index = index / 4;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n index = index / 4;\n vec4 texel = texture(tex, st / vec2(texSize));\n return texel[channel];\n}\n\nvec4 getImage2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n return texture(tex, st / vec2(texSize));\n}\n\nvec4 getImage3D(sampler2DArray tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n return texture(tex, vec3(st / vec2(texSize), z));\n}\n\nfloat getFloatFromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return result[0];\n}\n\nvec2 getVec2FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec2(result[0], result[1]);\n}\n\nvec2 getMemoryOptimizedVec2(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 2);\n index = index / 2;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize));\n if (channel == 0) return vec2(texel.r, texel.g);\n if (channel == 1) return vec2(texel.b, texel.a);\n return vec2(0.0, 0.0);\n}\n\nvec3 getVec3FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec3(result[0], result[1], result[2]);\n}\n\nvec3 getMemoryOptimizedVec3(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int fieldIndex = 3 * (x + texDim.x * (y + texDim.y * z));\n int vectorIndex = fieldIndex / 4;\n int vectorOffset = fieldIndex - vectorIndex * 4;\n int readY = vectorIndex / texSize.x;\n int readX = vectorIndex - readY * texSize.x;\n vec4 tex1 = texture(tex, (vec2(readX, readY) + 0.5) / vec2(texSize));\n\n if (vectorOffset == 0) {\n return tex1.xyz;\n } else if (vectorOffset == 1) {\n return tex1.yzw;\n } else {\n readX++;\n if (readX >= texSize.x) {\n readX = 0;\n readY++;\n }\n vec4 tex2 = texture(tex, vec2(readX, readY) / vec2(texSize));\n if (vectorOffset == 2) {\n return vec3(tex1.z, tex1.w, tex2.x);\n } else {\n return vec3(tex1.w, tex2.x, tex2.y);\n }\n }\n}\n\nvec4 getVec4FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n return getImage2D(tex, texSize, texDim, z, y, x);\n}\n\nvec4 getMemoryOptimizedVec4(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 2);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize));\n return vec4(texel.r, texel.g, texel.b, texel.a);\n}\n\nvec4 actualColor;\nvoid color(float r, float g, float b, float a) {\n actualColor = vec4(r,g,b,a);\n}\n\nvoid color(float r, float g, float b) {\n color(r,g,b,1.0);\n}\n\nfloat modulo(float number, float divisor) {\n if (number < 0.0) {\n number = abs(number);\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return -mod(number, divisor);\n }\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return mod(number, divisor);\n}\n\n__INJECTED_NATIVE__;\n__MAIN_CONSTANTS__;\n__MAIN_ARGUMENTS__;\n__KERNEL__;\n\nvoid main(void) {\n index = int(vTexCoord.s * float(uTexSize.x)) + int(vTexCoord.t * float(uTexSize.y)) * uTexSize.x;\n __MAIN_RESULT__;\n}`}}),Ae=e((e,t)=>{t.exports={vertexShader:"#version 300 es\n__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n\nin vec2 aPos;\nin vec2 aTexCoord;\n\nout vec2 vTexCoord;\nuniform vec2 ratio;\n\nvoid main(void) {\n gl_Position = vec4((aPos + vec2(1)) * ratio + vec2(-1), 0, 1);\n vTexCoord = aTexCoord;\n}"}}),_e=e((e,t)=>{const{WebGLKernelValueBoolean:r}=K();t.exports={WebGL2KernelValueBoolean:class extends r{}}}),we=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueFloat:n}=B();t.exports={WebGL2KernelValueFloat:class extends n{}}}),Ee=e((e,t)=>{const{WebGLKernelValueInteger:r}=W();t.exports={WebGL2KernelValueInteger:class extends r{getSource(e){const t=this.getVariablePrecisionString();return"constants"===this.origin?`const ${t} int ${this.id} = ${parseInt(e)};\n`:`uniform ${t} int ${this.id};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1i(this.id,this.uploadValue=e)}}}}),Ie=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueHTMLImage:n}=H();t.exports={WebGL2KernelValueHTMLImage:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}}}}),ke=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicHTMLImage:n}=X();t.exports={WebGL2KernelValueDynamicHTMLImage:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),De=e((e,t)=>{const{utils:r}=i(),{WebGLKernelArray:n}=j();t.exports={WebGL2KernelValueHTMLImageArray:class extends n{constructor(e,t){super(e,t),this.checkSize(e[0].width,e[0].height),this.dimensions=[e[0].width,e[0].height,e.length],this.textureSize=[e[0].width,e[0].height]}defineTexture(){const{context:e}=this;e.activeTexture(this.contextHandle),e.bindTexture(e.TEXTURE_2D_ARRAY,this.texture),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_MIN_FILTER,e.NEAREST)}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2DArray ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){const{context:t}=this;t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D_ARRAY,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!0),t.texImage3D(t.TEXTURE_2D_ARRAY,0,t.RGBA,e[0].width,e[0].height,e.length,0,t.RGBA,t.UNSIGNED_BYTE,null);for(let r=0;r{const{utils:r}=i(),{WebGL2KernelValueHTMLImageArray:n}=De();t.exports={WebGL2KernelValueDynamicHTMLImageArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2DArray ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){const{width:t,height:r}=e[0];this.checkSize(t,r),this.dimensions=[t,r,e.length],this.textureSize=[t,r],this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Le=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueHTMLImage:n}=Ie();t.exports={WebGL2KernelValueHTMLVideo:class extends n{}}}),$e=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueDynamicHTMLImage:n}=ke();t.exports={WebGL2KernelValueDynamicHTMLVideo:class extends n{}}}),Fe=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleInput:n}=Z();t.exports={WebGL2KernelValueSingleInput:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){const{context:t}=this;r.flattenTo(e.value,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Re=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleInput:n}=Fe();t.exports={WebGL2KernelValueDynamicSingleInput:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){let[t,n,s]=e.size;this.dimensions=new Int32Array([t||1,n||1,s||1]),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Ne=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueUnsignedInput:n}=Q();t.exports={WebGL2KernelValueUnsignedInput:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}}}}),Ve=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicUnsignedInput:n}=ee();t.exports={WebGL2KernelValueDynamicUnsignedInput:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),Me=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueMemoryOptimizedNumberTexture:n}=te();t.exports={WebGL2KernelValueMemoryOptimizedNumberTexture:class extends n{getSource(){const{id:e,sizeId:t,textureSize:n,dimensionsId:s,dimensions:i}=this,a=this.getVariablePrecisionString();return r.linesToString([`uniform sampler2D ${e}`,`${a} ivec2 ${t} = ivec2(${n[0]}, ${n[1]})`,`${a} ivec3 ${s} = ivec3(${i[0]}, ${i[1]}, ${i[2]})`])}}}}),Oe=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicMemoryOptimizedNumberTexture:n}=re();t.exports={WebGL2KernelValueDynamicMemoryOptimizedNumberTexture:class extends n{getSource(){return r.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}}}}),Pe=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueNumberTexture:n}=ne();t.exports={WebGL2KernelValueNumberTexture:class extends n{getSource(){const{id:e,sizeId:t,textureSize:n,dimensionsId:s,dimensions:i}=this,a=this.getVariablePrecisionString();return r.linesToString([`uniform ${a} sampler2D ${e}`,`${a} ivec2 ${t} = ivec2(${n[0]}, ${n[1]})`,`${a} ivec3 ${s} = ivec3(${i[0]}, ${i[1]}, ${i[2]})`])}}}}),Ge=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicNumberTexture:n}=se();t.exports={WebGL2KernelValueDynamicNumberTexture:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),ze=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray:n}=ie();t.exports={WebGL2KernelValueSingleArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(!r.isArray(e))return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Ue=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleArray:n}=ze();t.exports={WebGL2KernelValueDynamicSingleArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=r.getDimensions(e,!0),this.textureSize=r.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Ke=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray1DI:n}=oe();t.exports={WebGL2KernelValueSingleArray1DI:class extends n{updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Be=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleArray1DI:n}=Ke();t.exports={WebGL2KernelValueDynamicSingleArray1DI:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),We=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray2DI:n}=he();t.exports={WebGL2KernelValueSingleArray2DI:class extends n{updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),je=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleArray2DI:n}=We();t.exports={WebGL2KernelValueDynamicSingleArray2DI:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),He=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueSingleArray3DI:n}=ce();t.exports={WebGL2KernelValueSingleArray3DI:class extends n{updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;r.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Xe=e((e,t)=>{const{utils:r}=i(),{WebGL2KernelValueSingleArray3DI:n}=He();t.exports={WebGL2KernelValueDynamicSingleArray3DI:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),qe=e((e,t)=>{const{WebGLKernelValueArray2:r}=de();t.exports={WebGL2KernelValueArray2:class extends r{}}}),Ye=e((e,t)=>{const{WebGLKernelValueArray3:r}=fe();t.exports={WebGL2KernelValueArray3:class extends r{}}}),Ze=e((e,t)=>{const{WebGLKernelValueArray4:r}=me();t.exports={WebGL2KernelValueArray4:class extends r{}}}),Je=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueUnsignedArray:n}=ge();t.exports={WebGL2KernelValueUnsignedArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}}}}),Qe=e((e,t)=>{const{utils:r}=i(),{WebGLKernelValueDynamicUnsignedArray:n}=xe();t.exports={WebGL2KernelValueDynamicUnsignedArray:class extends n{getSource(){const e=this.getVariablePrecisionString();return r.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),et=e((e,t)=>{const{WebGL2KernelValueBoolean:r}=_e(),{WebGL2KernelValueFloat:n}=we(),{WebGL2KernelValueInteger:s}=Ee(),{WebGL2KernelValueHTMLImage:i}=Ie(),{WebGL2KernelValueDynamicHTMLImage:a}=ke(),{WebGL2KernelValueHTMLImageArray:o}=De(),{WebGL2KernelValueDynamicHTMLImageArray:u}=Ce(),{WebGL2KernelValueHTMLVideo:h}=Le(),{WebGL2KernelValueDynamicHTMLVideo:l}=$e(),{WebGL2KernelValueSingleInput:c}=Fe(),{WebGL2KernelValueDynamicSingleInput:p}=Re(),{WebGL2KernelValueUnsignedInput:d}=Ne(),{WebGL2KernelValueDynamicUnsignedInput:f}=Ve(),{WebGL2KernelValueMemoryOptimizedNumberTexture:m}=Me(),{WebGL2KernelValueDynamicMemoryOptimizedNumberTexture:g}=Oe(),{WebGL2KernelValueNumberTexture:x}=Pe(),{WebGL2KernelValueDynamicNumberTexture:y}=Ge(),{WebGL2KernelValueSingleArray:b}=ze(),{WebGL2KernelValueDynamicSingleArray:T}=Ue(),{WebGL2KernelValueSingleArray1DI:S}=Ke(),{WebGL2KernelValueDynamicSingleArray1DI:v}=Be(),{WebGL2KernelValueSingleArray2DI:A}=We(),{WebGL2KernelValueDynamicSingleArray2DI:_}=je(),{WebGL2KernelValueSingleArray3DI:w}=He(),{WebGL2KernelValueDynamicSingleArray3DI:E}=Xe(),{WebGL2KernelValueArray2:I}=qe(),{WebGL2KernelValueArray3:k}=Ye(),{WebGL2KernelValueArray4:D}=Ze(),{WebGL2KernelValueUnsignedArray:C}=Je(),{WebGL2KernelValueDynamicUnsignedArray:L}=Qe(),$={unsigned:{dynamic:{Boolean:r,Integer:s,Float:n,Array:L,"Array(2)":I,"Array(3)":k,"Array(4)":D,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:f,NumberTexture:y,"ArrayTexture(1)":y,"ArrayTexture(2)":y,"ArrayTexture(3)":y,"ArrayTexture(4)":y,MemoryOptimizedNumberTexture:g,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:u,HTMLVideo:l},static:{Boolean:r,Float:n,Integer:s,Array:C,"Array(2)":I,"Array(3)":k,"Array(4)":D,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:d,NumberTexture:x,"ArrayTexture(1)":x,"ArrayTexture(2)":x,"ArrayTexture(3)":x,"ArrayTexture(4)":x,MemoryOptimizedNumberTexture:g,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:o,HTMLVideo:h}},single:{dynamic:{Boolean:r,Integer:s,Float:n,Array:T,"Array(2)":I,"Array(3)":k,"Array(4)":D,"Array1D(2)":v,"Array1D(3)":v,"Array1D(4)":v,"Array2D(2)":_,"Array2D(3)":_,"Array2D(4)":_,"Array3D(2)":E,"Array3D(3)":E,"Array3D(4)":E,Input:p,NumberTexture:y,"ArrayTexture(1)":y,"ArrayTexture(2)":y,"ArrayTexture(3)":y,"ArrayTexture(4)":y,MemoryOptimizedNumberTexture:g,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:u,HTMLVideo:l},static:{Boolean:r,Float:n,Integer:s,Array:b,"Array(2)":I,"Array(3)":k,"Array(4)":D,"Array1D(2)":S,"Array1D(3)":S,"Array1D(4)":S,"Array2D(2)":A,"Array2D(3)":A,"Array2D(4)":A,"Array3D(2)":w,"Array3D(3)":w,"Array3D(4)":w,Input:c,NumberTexture:x,"ArrayTexture(1)":x,"ArrayTexture(2)":x,"ArrayTexture(3)":x,"ArrayTexture(4)":x,MemoryOptimizedNumberTexture:m,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:o,HTMLVideo:h}}};t.exports={kernelValueMaps:$,lookupKernelValueType:function(e,t,r,n){if(!e)throw new Error("type missing");if(!t)throw new Error("dynamic missing");if(!r)throw new Error("precision missing");n.type&&(e=n.type);const s=$[r][t];if("WebGPUBuffer"===e)throw new Error("this kernel runs on WebGL but received a WebGPU pipeline buffer; await handle.toArray() first, or give this kernel the async contract (asyncMode: true / mode: 'async') so the readback happens for you");if(!1===s[e])return null;if(void 0===s[e])throw new Error(`Could not find a KernelValue for ${e}`);return s[e]}}}),tt=e((e,t)=>{const{WebGLKernel:r}=be(),{WebGL2FunctionNode:n}=Se(),{FunctionBuilder:s}=o(),{utils:a}=i(),{fragmentShader:u}=ve(),{vertexShader:h}=Ae(),{lookupKernelValueType:l}=et();let c=null,p=null,d=null,f=null;t.exports={WebGL2Kernel:class extends r{static get isSupported(){return null!==c||(this.setupFeatureChecks(),c=this.isContextMatch(d)),c}static setupFeatureChecks(){"undefined"!=typeof document?p=document.createElement("canvas"):"undefined"!=typeof OffscreenCanvas&&(p=new OffscreenCanvas(0,0)),p&&(d=p.getContext("webgl2"),d&&d.getExtension&&(d.getExtension("EXT_color_buffer_float"),d.getExtension("OES_texture_float_linear"),f=this.getFeatures()))}static isContextMatch(e){return"undefined"!=typeof WebGL2RenderingContext&&e instanceof WebGL2RenderingContext}static getFeatures(){const e=this.testContext;return Object.freeze({isFloatRead:this.getIsFloatRead(),isIntegerDivisionAccurate:this.getIsIntegerDivisionAccurate(),isSpeedTacticSupported:this.getIsSpeedTacticSupported(),kernelMap:!0,isTextureFloat:!0,isDrawBuffers:!0,channelCount:this.getChannelCount(),maxTextureSize:this.getMaxTextureSize(),lowIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_INT),lowFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_FLOAT),mediumIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_INT),mediumFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_FLOAT),highIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_INT),highFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT)})}static getIsTextureFloat(){return!0}static getChannelCount(){return d.getParameter(d.MAX_DRAW_BUFFERS)}static getMaxTextureSize(){return d.getParameter(d.MAX_TEXTURE_SIZE)}static lookupKernelValueType(e,t,r,n){return l(e,t,r,n)}static get testCanvas(){return p}static get testContext(){return d}static get features(){return f}static get fragmentShader(){return u}static get vertexShader(){return h}initContext(){return this.canvas.getContext("webgl2",{alpha:!1,depth:!1,antialias:!1})}initExtensions(){this.extensions={EXT_color_buffer_float:this.context.getExtension("EXT_color_buffer_float"),OES_texture_float_linear:this.context.getExtension("OES_texture_float_linear")}}validateSettings(e){if(!this.validate)return void(this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output));const{features:t}=this.constructor;if("single"===this.precision&&!t.isFloatRead)throw new Error("Float texture outputs are not supported");if(this.graphical||null!==this.precision||(this.precision=t.isFloatRead?"single":"unsigned"),null===this.fixIntegerDivisionAccuracy?this.fixIntegerDivisionAccuracy=!t.isIntegerDivisionAccurate:this.fixIntegerDivisionAccuracy&&t.isIntegerDivisionAccurate&&(this.fixIntegerDivisionAccuracy=!1),this.checkOutput(),!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=a.getVariableType(e[0],this.strictIntegers);switch(t){case"Array":this.output=a.getDimensions(t);break;case"NumberTexture":case"MemoryOptimizedNumberTexture":case"ArrayTexture(1)":case"ArrayTexture(2)":case"ArrayTexture(3)":case"ArrayTexture(4)":this.output=e[0].output;break;default:throw new Error("Auto output not supported for input type: "+t)}}if(this.graphical){if(2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");return"single"===this.precision&&(console.warn("Cannot use graphical mode and single precision at the same time"),this.precision="unsigned"),void(this.texSize=a.clone(this.output))}!this.graphical&&null===this.precision&&t.isTextureFloat&&(this.precision="single"),this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output),this.checkTextureSize()}translateSource(){const e=s.fromKernel(this,n,{fixIntegerDivisionAccuracy:this.fixIntegerDivisionAccuracy});this.translatedSource=e.getPrototypeString("kernel"),this.setupReturnTypes(e)}drawBuffers(){this.context.drawBuffers(this.drawBuffersMap)}getTextureFormat(){const{context:e}=this;switch(this.getInternalFormat()){case e.R32F:return e.RED;case e.RG32F:return e.RG;case e.RGBA32F:case e.RGBA:return e.RGBA;default:throw new Error("Unknown internal format")}}renderValues(){return void 0===this._tightRead&&this._detectTightRead(),super.renderValues()}renderKernelsToArrays(){return void 0===this._tightRead&&this._detectTightRead(),super.renderKernelsToArrays()}readFloatPixelsToFloat32Array(){if(!this._tightRead)return super.readFloatPixelsToFloat32Array();const{texSize:e,context:t}=this,r=e[0],n=e[1],s=new Float32Array(r*n);return t.readPixels(0,0,r,n,t.RED,t.FLOAT,s),s}renderOutputAsync(){return this.renderOutput!==this.renderValues?Promise.resolve(this.renderOutput()):this.renderValuesAsync()}renderValuesAsync(){void 0===this._tightRead&&this._detectTightRead();const e=this.formatValues,[t,r,n]=this.output;return this.transferValuesAsync().then(s=>e(s,t,r,n))}transferValuesAsync(){const{texSize:e,context:t}=this,r=e[0],n=e[1];let s,i,a;"single"===this.precision?(s=this._tightRead?t.RED:t.RGBA,i=t.FLOAT,a=new Float32Array(r*n*(this._tightRead?1:4))):(s=t.RGBA,i=t.UNSIGNED_BYTE,a=new Uint8Array(r*n*4));const o=t.createBuffer();t.bindBuffer(t.PIXEL_PACK_BUFFER,o),t.bufferData(t.PIXEL_PACK_BUFFER,a.byteLength,t.STREAM_READ),t.readPixels(0,0,r,n,s,i,0),t.bindBuffer(t.PIXEL_PACK_BUFFER,null);const u=t.fenceSync(t.SYNC_GPU_COMMANDS_COMPLETE,0);return t.flush(),this._pollFence(u).then(()=>(t.bindBuffer(t.PIXEL_PACK_BUFFER,o),t.getBufferSubData(t.PIXEL_PACK_BUFFER,0,a),t.bindBuffer(t.PIXEL_PACK_BUFFER,null),t.deleteBuffer(o),"single"===this.precision?a:new Float32Array(a.buffer)),e=>{throw t.deleteBuffer(o),e})}_pollFence(e){const t=this.context;return new Promise((r,n)=>{let s,i=null;"undefined"!=typeof MessageChannel?(i=new MessageChannel,i.port1.onmessage=()=>o(),s=()=>i.port2.postMessage(0)):s=()=>setTimeout(o,0);const a=(r,n)=>{t.deleteSync(e),i&&(i.port1.close(),i.port2.close()),r(n)},o=()=>{if(t.isContextLost())return a(n,new Error("WebGL context lost while awaiting kernel result"));const i=t.clientWaitSync(e,0,0);return i===t.ALREADY_SIGNALED||i===t.CONDITION_SATISFIED?a(r):i===t.WAIT_FAILED?a(n,new Error("clientWaitSync failed while awaiting kernel result")):void s()};o()})}_detectTightRead(){const e=this.context;this._tightRead=!1,e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer);const t="Number"===this.returnType||"Float"===this.returnType||"Integer"===this.returnType||"LiteralInteger"===this.returnType;if("single"===this.precision&&!this.optimizeFloatMemory&&!this.graphical&&t&&e.getParameter(e.IMPLEMENTATION_COLOR_READ_FORMAT)===e.RED&&e.getParameter(e.IMPLEMENTATION_COLOR_READ_TYPE)===e.FLOAT){if(this.formatValues===a.erectFloat)this.formatValues=a.erectMemoryOptimizedFloat;else if(this.formatValues===a.erect2DFloat)this.formatValues=a.erectMemoryOptimized2DFloat;else if(this.formatValues===a.erect3DFloat)this.formatValues=a.erectMemoryOptimized3DFloat;else if(this.formatValues!==a.erectMemoryOptimizedFloat&&this.formatValues!==a.erectMemoryOptimized2DFloat&&this.formatValues!==a.erectMemoryOptimized3DFloat)return;this._tightRead=!0}}getInternalFormat(){const{context:e}=this;if("single"===this.precision)switch(this.returnType){case"Number":case"Float":case"Integer":return this.optimizeFloatMemory?e.RGBA32F:e.R32F;case"Array(2)":return e.RG32F;case"Array(3)":case"Array(4)":return e.RGBA32F;default:throw new Error("Unhandled return type")}return e.RGBA}_setupOutputTexture(){const e=this.context;if(this.texture)return e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.texture.texture,0),void(this._tightRead=void 0);e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer);const t=e.createTexture(),r=this.texSize;e.activeTexture(e.TEXTURE0+this.constantTextureCount+this.argumentTextureCount),e.bindTexture(e.TEXTURE_2D,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.REPEAT),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.REPEAT),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);const n=this.getInternalFormat();"single"===this.precision?e.texStorage2D(e.TEXTURE_2D,1,n,r[0],r[1]):e.texImage2D(e.TEXTURE_2D,0,n,r[0],r[1],0,n,e.UNSIGNED_BYTE,null),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t,0),this.texture=new this.TextureConstructor({texture:t,size:r,dimensions:this.threadDim,output:this.output,context:this.context,internalFormat:this.getInternalFormat(),textureFormat:this.getTextureFormat(),kernel:this}),this._tightRead=void 0}_setupSubOutputTextures(){const e=this.context;if(this.mappedTextures){for(let t=0;t{const{utils:r}=i(),{FunctionNode:n}=h();const s={Number:"f32",Float:"f32",Integer:"i32",LiteralInteger:"f32",Boolean:"bool","Array(2)":"vec2","Array(3)":"vec3","Array(4)":"vec4"},a={"===":"==","!==":"!="},o=["x","y","z","w"],u={pow:"_pow",round:"_round"},l={ceil:!0,floor:!0,_round:!0};t.exports={WGSLFunctionNode:class extends n{get requiresSequenceFreeForInit(){return!0}wgslFloat(e){if(e===1/0)return"0x1.fffffep+127";if(e===-1/0)return"-0x1.fffffep+127";if(e>34028234663852886e22)return"0x1.fffffep+127";if(e<-34028234663852886e22)return"-0x1.fffffep+127";const t=`${e}`;return-1!==t.indexOf(".")||-1!==t.indexOf("e")||-1!==t.indexOf("E")?t:`${t}.0`}wgslInt(e){return`${Math.round(e)}`}mangleFunctionName(e){return`fn_${r.sanitizeName(e)}`}getLookupType(e){return"WebGPUBuffer"===e?"Number":super.getLookupType(e)}astUpdateExpression(e,t){return this.astGeneric(e.argument,t),t.push(e.operator),t}getType(e){if(e&&"ConditionalExpression"===e.type){const t=this.getType(e.consequent);if("Integer"===t||"LiteralInteger"===t){const t=this.getType(e.alternate);if("Number"===t||"Float"===t)return"Number"}}return super.getType(e)}astConditionalExpression(e,t){if("ConditionalExpression"!==e.type)throw this.astErrorOutput("Not a conditional expression",e);const r=this.getType(e.consequent),n=this.getType(e.alternate);if(null===r&&null===n)return t.push("if ("),this.astGeneric(e.test,t),t.push(") {"),this.astGeneric(e.consequent,t),t.push(";"),t.push("} else {"),this.astGeneric(e.alternate,t),t.push(";"),t.push("}"),t;let s="LiteralInteger"===r?"Number":r;"Integer"!==s||"Number"!==n&&"Float"!==n||(s="Number");const i=e=>{const r=this.getType(e);switch(s){case"Number":case"Float":"Integer"===r?this.castValueToFloat(e,t):"LiteralInteger"===r?this.castLiteralToFloat(e,t):this.astGeneric(e,t);break;case"Integer":"Number"===r||"Float"===r?this.castValueToInteger(e,t):"LiteralInteger"===r?this.castLiteralToInteger(e,t):this.astGeneric(e,t);break;default:this.astGeneric(e,t)}};return t.push("select("),i(e.alternate),t.push(", "),i(e.consequent),t.push(", "),this.astGeneric(e.test,t),t.push(")"),t}astFunction(e,t){if(this.isRootKernel){for(let r=0;r0&&t.push(", ");let a=this.argumentTypes[this.argumentNames.indexOf(i)];if(!a)throw this.astErrorOutput(`Unknown argument ${i} type`,e);"LiteralInteger"===a&&(this.argumentTypes[n]=a="Number");const o=s[a];if(!o)throw this.astErrorOutput(`WebGPU backend does not yet support ${a} arguments to helper functions`,e);t.push(`user_${r.sanitizeName(i)} : ${o}`)}t.push(")"),i&&t.push(` -> ${i}`),t.push(" {\n");for(let r=0;r>":!0,">>>":!0}[e.operator])return null;const r=e=>{switch(this.getType(e)){case"Number":case"Float":this.castValueToInteger(e,t);break;case"LiteralInteger":this.castLiteralToInteger(e,t);break;default:this.pushState("building-integer"),this.astGeneric(e,t),this.popState("building-integer")}};return t.push("("),">>>"===e.operator?(t.push("bitcast(bitcast("),r(e.left),t.push(") >> u32("),r(e.right),t.push("))")):"<<"===e.operator||">>"===e.operator?(r(e.left),t.push(` ${e.operator} u32(`),r(e.right),t.push(")")):(r(e.left),t.push(` ${e.operator} `),r(e.right)),t.push(")"),t}checkAndUpconvertBitwiseUnary(e,t){if("~"!==e.operator)return null;switch(t.push("~("),this.getType(e.argument)){case"Number":case"Float":this.castValueToInteger(e.argument,t);break;case"LiteralInteger":this.castLiteralToInteger(e.argument,t);break;default:this.astGeneric(e.argument,t)}return t.push(")"),t}astUnaryExpression(e,t){return this.checkAndUpconvertBitwiseUnary(e,t)?t:"+"===e.operator?(this.astGeneric(e.argument,t),t):(e.prefix?(t.push(e.operator),this.astGeneric(e.argument,t)):(this.astGeneric(e.argument,t),t.push(e.operator)),t)}castLiteralToInteger(e,t){return this.pushState("casting-to-integer"),this.astGeneric(e,t),this.popState("casting-to-integer"),t}castLiteralToFloat(e,t){return this.pushState("casting-to-float"),this.astGeneric(e,t),this.popState("casting-to-float"),t}castValueToInteger(e,t){return this.pushState("casting-to-integer"),t.push("i32("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-integer"),t}castValueToFloat(e,t){return this.pushState("casting-to-float"),t.push("f32("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-float"),t}astIdentifierExpression(e,t){if("Identifier"!==e.type)throw this.astErrorOutput("IdentifierExpression - not an Identifier",e);const n=this.getType(e),s=r.sanitizeName(e.name);return"Infinity"===e.name?(t.push("0x1.fffffep+127"),t):!this.isRootKernel||-1===this.argumentNames.indexOf(e.name)||"Number"!==n&&"Float"!==n&&"Integer"!==n&&"Boolean"!==n?(t.push(`user_${s}`),t):("Boolean"===n?t.push(`bool(params.user_${s})`):t.push(`params.user_${s}`),t)}astForStatement(e,t){if("ForStatement"!==e.type)throw this.astErrorOutput("Invalid for statement",e);const r=[],n=[],s=[],i=[];let a=null;if(e.init){const{declarations:t}=e.init;t.length>1&&(a=!1),this.astGeneric(e.init,r);for(let e=0;e0&&t.push(r.join(""),"\n"),t.push(`for (var ${e} : i32 = 0;${e}0&&t.push(`if (!(${n.join("")})) { break; }\n`),t.push(i.join("")),t.push(`\n${s.join("")};`),t.push("}\n")}return t}astWhileStatement(e,t){if("WhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);const r=this.getInternalVariableName("safeI");return t.push(`for (var ${r} : i32 = 0;${r}{if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(t);if("BreakStatement"===e.type)return!0;if("ForStatement"===e.type||"WhileStatement"===e.type||"DoWhileStatement"===e.type||"SwitchStatement"===e.type)return!1;for(const r in e)if("loc"!==r&&"range"!==r&&"parent"!==r&&t(e[r]))return!0;return!1};if(t(r[e]))throw this.astErrorOutput("break inside a switch case is only supported as the case terminator",r[e])}for(let e=0;ee+1){u=!0,this.astSwitchCaseConsequent(n[e].consequent,o);continue}t.push(" else {\n")}this.astSwitchCaseConsequent(n[e].consequent,t),t.push("\n}")}return u&&(t.push(" else {"),t.push(o.join("")),t.push("}")),t.push("\n"),t}astThisExpression(e,t){return t.push("this"),t}astSequenceExpression(e,t){const{expressions:r}=e;if(1===r.length)return this.astGeneric(r[0],t),t;throw this.astErrorOutput("WebGPU backend does not yet support the comma operator",e)}astMemberExpression(e,t){const{property:n,name:i,signature:a,origin:o,type:u,xProperty:h,yProperty:l,zProperty:c}=this.getMemberExpressionDetails(e);switch(a){case"value.thread.value":case"this.thread.value":if("x"!==i&&"y"!==i&&"z"!==i)throw this.astErrorOutput("Unexpected expression, expected `this.thread.x`, `this.thread.y`, or `this.thread.z`",e);return t.push(`i32(threadGid.${i})`),t;case"this.output.value":{const r={x:0,y:1,z:2}[i];if(void 0===r)throw this.astErrorOutput("Unexpected expression",e);if(this.dynamicOutput){const e=`params.output${i.toUpperCase()}`;this.isState("casting-to-float")?t.push(`f32(${e})`):t.push(`i32(${e})`)}else this.isState("casting-to-integer")?t.push(`${this.output[r]}`):t.push(`${this.output[r]}.0`);return t}case"value":throw this.astErrorOutput("Unexpected expression",e);case"value[]":case"value[][]":case"value[][][]":case"value[][][][]":case"value.value":if("Math"===o)return t.push(this.wgslFloat(Math[i])),t;switch(n){case"r":return t.push(`user_${r.sanitizeName(i)}.x`),t;case"g":return t.push(`user_${r.sanitizeName(i)}.y`),t;case"b":return t.push(`user_${r.sanitizeName(i)}.z`),t;case"a":return t.push(`user_${r.sanitizeName(i)}.w`),t}break;case"this.constants.value":{const r=this.constants[i];switch(u){case"Integer":return this.isState("casting-to-float")?t.push(this.wgslFloat(r)):t.push(this.wgslInt(r)),t;case"Number":case"Float":return this.isState("casting-to-integer")?t.push(this.wgslInt(r)):t.push(this.wgslFloat(r)),t;case"Boolean":return t.push(r?"true":"false"),t;case"Array(2)":case"Array(3)":case"Array(4)":{const e=parseInt(u.substring(6),10),n=[];for(let t=0;t4)throw this.astErrorOutput("this.color takes (r, g, b) or (r, g, b, a)",e);t.push("kernelColor(data_index");for(let r=0;r0&&t.push(", "),s){case"Integer":this.castValueToFloat(n,t);break;case"LiteralInteger":this.castLiteralToFloat(n,t);break;default:this.astGeneric(n,t)}}else{const s=this.lookupFunctionArgumentTypes(n)||[];for(let i=0;i0&&t.push(", ");const u=this.getType(a);switch(o||(this.triggerImplyArgumentType(n,i,u,this),o=u),u){case"Boolean":this.astGeneric(a,t);continue;case"Number":case"Float":if("Integer"===o){t.push("i32("),this.astGeneric(a,t),t.push(")");continue}if("Number"===o||"Float"===o){this.astGeneric(a,t);continue}if("LiteralInteger"===o){this.castLiteralToFloat(a,t);continue}break;case"Integer":if("Number"===o||"Float"===o){t.push("f32("),this.astGeneric(a,t),t.push(")");continue}if("Integer"===o){this.astGeneric(a,t);continue}break;case"LiteralInteger":if("Integer"===o){this.castLiteralToInteger(a,t);continue}if("Number"===o||"Float"===o){this.castLiteralToFloat(a,t);continue}if("LiteralInteger"===o){this.astGeneric(a,t);continue}break;case"Array(2)":case"Array(3)":case"Array(4)":if(o===u){"Identifier"===a.type?t.push(`user_${r.sanitizeName(a.name)}`):this.astGeneric(a,t);continue}break;case"Array":case"Array2D":case"Array3D":case"Input":case"WebGPUBuffer":throw this.astErrorOutput("WebGPU backend does not yet support array arguments to helper functions",e)}throw this.astErrorOutput(`Unhandled argument combination of ${u} and ${o} for argument named "${a.name}"`,e)}}return t.push(")"),a&&t.push(")"),t}astArrayExpression(e,t){switch(this.getType(e)){case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":throw this.astErrorOutput("WebGPU backend does not yet support Matrix types",e)}const r=e.elements.length;t.push(`vec${r}(`);for(let n=0;n0&&t.push(", ");const r=e.elements[n];switch(this.getType(r)){case"Integer":this.castValueToFloat(r,t);break;case"LiteralInteger":this.castLiteralToFloat(r,t);break;default:this.astGeneric(r,t)}}return t.push(")"),t}memberExpressionXYZ(e,t,r,n){return r?n.push(this.memberExpressionPropertyMarkup(r),", "):n.push("0, "),t?n.push(this.memberExpressionPropertyMarkup(t),", "):n.push("0, "),n.push(this.memberExpressionPropertyMarkup(e)),n}memberExpressionPropertyMarkup(e){if(!e)throw new Error("Property not set");const t=[];switch(this.getType(e)){case"Number":case"Float":this.castValueToInteger(e,t);break;case"LiteralInteger":this.castLiteralToInteger(e,t);break;case"Integer":this.pushState("building-integer"),t.push("i32("),this.astGeneric(e,t),t.push(")"),this.popState("building-integer");break;default:this.astGeneric(e,t)}return t.join("")}}}}),nt=e((e,t)=>{let r=null;t.exports={WebGPUContext:class e{static get isSupported(){return"undefined"!=typeof navigator&&!!navigator.gpu}static acquire(){if(r)return r;const t=(async()=>{if(!e.isSupported)throw new Error("WebGPU is not supported on this platform (navigator.gpu is missing)");const n=await navigator.gpu.requestAdapter();if(!n)throw new Error("WebGPU is present (navigator.gpu) but no adapter is available. On headless Chromium there is no adapter; run headed. Use `await GPU.isWebGPUAvailable()` to feature-detect.");const s=await n.requestDevice({requiredLimits:{maxStorageBufferBindingSize:n.limits.maxStorageBufferBindingSize,maxBufferSize:n.limits.maxBufferSize}}),i={adapter:n,device:s,isLost:!1};return s.lost.then(e=>{i.isLost=!0,"destroyed"!==e.reason&&console.error(`gpu.js [webgpu]: device lost: ${e.message}`),r===t&&(r=null)}),s.onuncapturederror=e=>{console.error(`gpu.js [webgpu]: ${e.error.message}`)},i})();return t.catch(()=>{r===t&&(r=null)}),r=t}static destroy(){if(!r)return Promise.resolve();const e=r;return r=null,e.then(({device:e})=>{e.destroy()},()=>{})}}}}),st=e((e,t)=>{t.exports={WebGPUBufferResult:class e{constructor(e){this.buffer=e.buffer,this.output=e.output,this.componentCount=e.componentCount||1,this.context=e.context,this.kernel=e.kernel,this.type="WebGPUBuffer",this._deleted=!1,this.buffer._refs?this.buffer._refs++:this.buffer._refs=1}toArray(){return this._deleted?Promise.reject(new Error("WebGPUBufferResult has been deleted")):this.kernel.readBufferResult(this)}delete(){this._deleted||(this._deleted=!0,0===--this.buffer._refs&&this.buffer.destroy())}clone(){return new e(this)}}}}),it=e((e,t)=>{const{Kernel:r}=a(),{FunctionBuilder:s}=o(),{WGSLFunctionNode:u}=rt(),{WebGPUContext:h}=nt(),{WebGPUBufferResult:l}=st(),{utils:c}=i(),{Input:p}=n(),d=Object.freeze({kernelMap:!1,isIntegerDivisionAccurate:!0,isSpeedTacticSupported:!1,isTextureFloat:!0,isDrawBuffers:!1,kernelMapSize:0,channelCount:1,maxTextureSize:1/0,isFloatRead:!0}),f={_pow:"fn _pow(v1 : f32, v2 : f32) -> f32 {\n if (v2 == 0.0) { return 1.0; }\n return pow(v1, v2);\n}",_round:"fn _round(x : f32) -> f32 {\n return floor(x + 0.5);\n}",cbrt:"fn cbrt(x : f32) -> f32 {\n return sign(x) * pow(abs(x), 1.0 / 3.0);\n}",expm1:"fn expm1(x : f32) -> f32 {\n return exp(x) - 1.0;\n}",fround:"fn fround(x : f32) -> f32 {\n return x;\n}",imul:"fn imul(a : f32, b : f32) -> f32 {\n return f32(i32(a) * i32(b));\n}",log10:`fn log10(x : f32) -> f32 {\n return log2(x) * ${1/Math.log2(10)};\n}`,log1p:"fn log1p(x : f32) -> f32 {\n return log(1.0 + x);\n}",clz32:"fn clz32(x : f32) -> f32 {\n return f32(countLeadingZeros(u32(x)));\n}"};t.exports={WebGPUKernel:class extends r{static get isSupported(){return h.isSupported}static get isAsync(){return!0}static isContextMatch(e){return Boolean(e&&"function"==typeof e.createShaderModule&&"function"==typeof e.createComputePipeline)}static getFeatures(){return d}static get features(){return d}static get mode(){return"webgpu"}static getSignature(e,t){return"webgpu"+(t.length>0?":"+t.join(","):"")}static destroyContext(e){}static nativeFunctionArguments(){throw new Error("WebGPU backend does not yet support native functions")}static nativeFunctionReturnType(){throw new Error("WebGPU backend does not yet support native functions")}static combineKernels(){throw new Error("WebGPU backend does not yet support combineKernels; chain kernels with `await` and pipeline mode instead")}constructor(e,t){if(super(e,t),t){if("unsigned"===t.precision&&!t.graphical)throw new Error("WebGPU backend does not yet support precision: 'unsigned'; it is single precision only");if(t.subKernels)throw new Error("WebGPU backend does not yet support createKernelMap")}this.mergeSettings(e.settings||t),(null===this.precision||this.graphical)&&(this.precision="single"),this.asyncMode=!0,this.threadDim=null,this.componentCount=1,this.compiledSource=null,this.translatedBody=null,this.translatedFunctions=null,this.paramsLayout=null,this._buildPromise=null,this._device=null,this.computePipeline=null,this.bindGroupLayout=null,this.bindGroup=null,this.bindGroupDirty=!0,this.paramsBuffer=null,this.paramsMirror=null,this.outputBuffer=null,this.argumentBuffers=null,this.constantBuffers=null,this.stagingPool=[],this._canvasContext=null,this._blitPipeline=null,this._blitParamsBuffer=null,this._blitBindGroup=null,this._blitBoundOutputBuffer=null}initCanvas(){return this.graphical&&"undefined"!=typeof document?document.createElement("canvas"):null}initContext(){return null}initPlugins(e){return[]}setOutput(e){const t=this.toKernelOutput(e);if(this.built){if(!this.dynamicOutput)throw new Error("Resizing a kernel with dynamicOutput: false is not possible");if(t.length!==this.output.length)throw new Error("WebGPU backend does not yet support changing the output rank of a built kernel; the workgroup shape is fixed at build")}return this.output=t,this}toString(){throw new Error("WebGPU backend does not yet support toString")}validateSettings(e){if(this.graphical){if(!this.output||2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");if(this.pipeline)throw new Error("graphical mode and pipeline mode are mutually exclusive");if(!this.canvas)throw new Error("graphical mode requires a canvas (none could be created; pass one in settings)")}if("unsigned"===this.precision)throw new Error("WebGPU backend does not yet support precision: 'unsigned'; it is single precision only");if(this.precision="single",this.subKernels&&this.subKernels.length>0)throw new Error("WebGPU backend does not yet support createKernelMap");if(!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=c.getVariableType(e[0],this.strictIntegers);if("Array"===t)this.output=Array.from(c.getDimensions(e[0]));else{if("WebGPUBuffer"!==t)throw new Error("Auto output not supported for input type: "+t);this.output=Array.from(e[0].output)}}this.checkOutput()}setupArguments(e){super.setupArguments(e);for(let e=0;e,`);for(let e=0;e params : Params;");for(let t=0;t user_${e[t].name} : array;`);const i=1+e.length;n.push(`@group(0) @binding(${i}) var result : array;`),this.graphical&&n.push("fn kernelColor(index : i32, r : f32, g : f32, b : f32, a : f32) {\n result[index * 4] = r;\n result[index * 4 + 1] = g;\n result[index * 4 + 2] = b;\n result[index * 4 + 3] = a;\n}");for(let e=0;e constants_${r[e].name} : array;`);n.push("var threadGid : vec3;"),null!==this.paramsLayout.randomSeedOffset&&n.push("var pcgState : u32;\nfn pcg_random() -> f32 {\n pcgState = pcgState * 747796405u + 2891336453u;\n let word = ((pcgState >> ((pcgState >> 28u) + 4u)) ^ pcgState) * 277803737u;\n let mixed = (word >> 22u) ^ word;\n return f32(mixed >> 8u) / 16777216.0;\n}");const a=`${this.translatedFunctions}\n${this.translatedBody}`;/\bLOOP_MAX\b/.test(a)&&n.push(`const LOOP_MAX : i32 = ${parseInt(this.loopMaxIterations,10)||1e3};`);for(const e in f)new RegExp(`\\b${e}\\(`).test(a)&&n.push(f[e]);for(let t=0;t f32 {\n return user_${r}[u32(x + i32(params.user_${r}_dims.x) * (y + i32(params.user_${r}_dims.y) * z))];\n}`)}for(let e=0;e f32 {\n return constants_${t.name}[u32(x + ${i[0]} * (y + ${i[1]} * z))];\n}`)}this.translatedFunctions&&n.push(this.translatedFunctions);const o=1===this.output.length?[64,1,1]:[8,8,1];return this.workgroupSize=o,1===this.output.length?n.push(`@compute @workgroup_size(${o[0]}, ${o[1]}, ${o[2]})\nfn main(@builtin(global_invocation_id) gid : vec3) {\n let flat_index : u32 = gid.x + gid.y * params.dispatchWidth;\n threadGid = vec3(flat_index, 0u, 0u);\n if (flat_index >= params.outputX) { return; }\n let data_index : i32 = i32(flat_index);\n${null!==this.paramsLayout.randomSeedOffset?" pcgState = (params.randomSeed + u32(data_index) * 2654435769u) * 747796405u + 2891336453u;\n":""}${this.translatedBody}\n}`):n.push(`@compute @workgroup_size(${o[0]}, ${o[1]}, ${o[2]})\nfn main(@builtin(global_invocation_id) gid : vec3) {\n threadGid = gid;\n if (gid.x >= params.outputX || gid.y >= params.outputY || gid.z >= params.outputZ) { return; }\n let data_index : i32 = i32(gid.x + params.outputX * (gid.y + params.outputY * gid.z));\n${null!==this.paramsLayout.randomSeedOffset?" pcgState = (params.randomSeed + u32(data_index) * 2654435769u) * 747796405u + 2891336453u;\n":""}${this.translatedBody}\n}`),n.join("\n")}constantDimensions(e){const t=e instanceof p?Array.from(e.size):Array.from(c.getDimensions(e));for(;t.length<3;)t.push(1);return t}async _buildAsync(){const e=await h.acquire();this.context=e;const t=this._device=e.device,r=t.createShaderModule({code:this.compiledSource}),n=(await r.getCompilationInfo()).messages.filter(e=>"error"===e.type);if(n.length>0)throw new Error("Error compiling WGSL compute shader:\n"+n.map(e=>` ${e.lineNum}:${e.linePos} ${e.message}`).join("\n")+`\n--- generated WGSL ---\n${this.compiledSource}`);const{arrayArgs:s,bufferConstants:i,byteLength:a}=this.paramsLayout,o=[{binding:0,visibility:4,buffer:{type:"uniform"}}];for(let e=0;ei&&(s[1]=Math.ceil(s[0]/i),s[0]=Math.ceil(s[0]/s[1])),a=s[0]*t);for(let e=0;e<3;e++)if(s[e]>i)throw new Error(`output dimension ${e} needs ${s[e]} workgroups, over this device's limit of ${i}`);return{groups:s,dispatchWidth:a}}async _buildBlitPipeline(e){if(this.canvas.width=this.output[0],this.canvas.height=this.output[1],this._canvasContext=this.canvas.getContext("webgpu"),!this._canvasContext)throw new Error("could not get a webgpu context from the canvas");const t=navigator.gpu.getPreferredCanvasFormat();this._canvasContext.configure({device:e,format:t,alphaMode:"premultiplied"});const r=e.createShaderModule({code:"struct BlitParams { width : u32, height : u32, pad0 : u32, pad1 : u32 }\n@group(0) @binding(0) var blit : BlitParams;\n@group(0) @binding(1) var pixels : array;\n@vertex fn vs(@builtin(vertex_index) vi : u32) -> @builtin(position) vec4 {\n var pos = array, 3>(vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));\n return vec4(pos[vi], 0.0, 1.0);\n}\n@fragment fn fs(@builtin(position) pos : vec4) -> @location(0) vec4 {\n let x = u32(pos.x);\n let y = u32(pos.y);\n let row = blit.height - 1u - y;\n let i = (row * blit.width + x) * 4u;\n let a = pixels[i + 3u];\n return vec4(pixels[i] * a, pixels[i + 1u] * a, pixels[i + 2u] * a, a);\n}"}),n=(await r.getCompilationInfo()).messages.filter(e=>"error"===e.type);if(n.length>0)throw new Error("Error compiling the graphical blit shader:\n"+n.map(e=>` ${e.lineNum}:${e.linePos} ${e.message}`).join("\n"));this._blitBindGroupLayout=e.createBindGroupLayout({entries:[{binding:0,visibility:2,buffer:{type:"uniform"}},{binding:1,visibility:2,buffer:{type:"read-only-storage"}}]}),this._blitPipeline=e.createRenderPipeline({layout:e.createPipelineLayout({bindGroupLayouts:[this._blitBindGroupLayout]}),vertex:{module:r,entryPoint:"vs"},fragment:{module:r,entryPoint:"fs",targets:[{format:t}]},primitive:{topology:"triangle-list"}}),this._blitParamsBuffer=e.createBuffer({size:16,usage:72})}_ensureOutputBuffer(){const[e,t,r]=this.threadDim,n=e*t*r*4*this.componentCount;this.immutable&&this.pipeline&&this.outputBuffer&&(0===--this.outputBuffer._refs&&this.outputBuffer.destroy(),this.outputBuffer=null,this.bindGroupDirty=!0),this.outputBuffer&&this.outputBuffer.size>=n||(this.outputBuffer&&0===--this.outputBuffer._refs&&this.outputBuffer.destroy(),this._checkBufferSize(n,`output [${this.output.join(", ")}]`),this.outputBuffer=this._device.createBuffer({size:n,usage:132}),this.outputBuffer._refs=1,this.bindGroupDirty=!0)}_checkBufferSize(e,t){const r=this._device.limits,n=Math.min(r.maxStorageBufferBindingSize,r.maxBufferSize);if(e>n)throw new Error(`WebGPU backend: ${t} needs ${e} bytes but this device allows ${n} per storage buffer (maxStorageBufferBindingSize/maxBufferSize); reduce the output or split the work across kernels`)}_snapshotArguments(e){const t=new Array(e.length);for(let r=0;rthis._runInternal(e))}_runInternal(e){if(this.context&&this.context.isLost)throw new Error("WebGPU device was lost; call kernel.destroy() (or gpu.destroy()) and run again to rebuild on a fresh device");const t=this._device,r=t.queue,{arrayArgs:n,scalarArgs:s,bufferConstants:i}=this.paramsLayout,a=this.threadDim=Array.from(this.output);for(;a.length<3;)a.push(1);if(this._ensureOutputBuffer(),null!==this.paramsLayout.randomSeedOffset){const e=null!==this.randomSeed?this.randomSeed>>>0:4294967296*Math.random()>>>0;this.paramsU32[this.paramsLayout.randomSeedOffset/4]=e}this.paramsU32[0]=a[0],this.paramsU32[1]=a[1],this.paramsU32[2]=a[2],this.paramsU32[3]=this._computeDispatch(a).dispatchWidth;for(let s=0;s{const e=new Float32Array(p.buffer.getMappedRange(0,u).slice(0));return p.buffer.unmap(),this._releaseStaging(p),this._shapeOutput(e,d,this.componentCount)},e=>{throw this._releaseStaging(p),e})}_acquireStaging(e){for(let t=0;t=e)return r.busy=!0,r}const t={buffer:this._device.createBuffer({size:e,usage:9}),size:e,busy:!0,pooled:this.stagingPool.length<3};return t.pooled&&this.stagingPool.push(t),t}_releaseStaging(e){e.pooled?e.busy=!1:e.buffer.destroy()}_shapeOutput(e,t,r){const[n,s,i]=[t[0],t[1]||1,t[2]||1];if(1===r)switch(t.length){case 1:return c.erectMemoryOptimizedFloat(e,n);case 2:return c.erectMemoryOptimized2DFloat(e,n,s);default:return c.erectMemoryOptimized3DFloat(e,n,s,i)}const a=r,o=t=>{const r=new Array(n);for(let s=0;s{const t=new Float32Array(i.buffer.getMappedRange(0,s).slice(0));return i.buffer.unmap(),this._releaseStaging(i),this._shapeOutput(t,r,e.componentCount)},e=>{throw this._releaseStaging(i),e})}getPixels(e){if(!this.graphical)return Promise.reject(new Error("getPixels only works on a graphical kernel"));if(!this.outputBuffer)return Promise.reject(new Error("run the kernel before reading its pixels"));const[t,r]=this.output,n=t*r*4*4,s=this._acquireStaging(n),i=this._device.createCommandEncoder();return i.copyBufferToBuffer(this.outputBuffer,0,s.buffer,0,n),this._device.queue.submit([i.finish()]),s.buffer.mapAsync(1,0,n).then(()=>{const i=new Float32Array(s.buffer.getMappedRange(0,n).slice(0));s.buffer.unmap(),this._releaseStaging(s);const a=new Uint8ClampedArray(t*r*4);for(let n=0;n{throw this._releaseStaging(s),e})}destroy(e){if(this._blitParamsBuffer&&(this._blitParamsBuffer.destroy(),this._blitParamsBuffer=null),this._canvasContext&&(this._canvasContext.unconfigure(),this._canvasContext=null),this._blitPipeline=null,this._blitBindGroup=null,this._blitBoundOutputBuffer=null,this.paramsBuffer&&(this.paramsBuffer.destroy(),this.paramsBuffer=null),this.paramsLayout)for(let e=0;e{const{utils:r}=i(),{Input:s}=n();function a(e,t){if(t.kernel)return void(t.kernel=e);const n=r.allPropertiesOf(e);for(let r=0;rt.kernel[s]),t.__defineSetter__(s,e=>{t.kernel[s]=e})))}t.kernel=e}t.exports={kernelRunShortcut:function(e){function t(t){e.build.apply(e,t),e.checkArgumentTypes(t);let n=e.switchingKernels?void 0:e.run.apply(e,t);for(let s=0;e.switchingKernels;s++){if(s>=4){const t=e.resetSwitchingKernels();throw new Error(`this kernel cannot run the arguments it was given (${r(t)}); it did not settle on a kernel for them after 4 attempts. Create a separate kernel for this call's argument types.`)}const i=e.resetSwitchingKernels(),a=e.onRequestSwitchKernel(i,t,e);c.kernel=e=a,a.checkArgumentTypes(t),n=a.switchingKernels?void 0:a.run.apply(a,t)}return n}function r(e){return e&&e.length?e.map(e=>"argumentTypeMismatch"===e.type?`argument ${e.index} is now ${e.needed}`:e.type).join(", "):"unknown reason"}function n(r){if(e.onAsyncModeUpgrade){const t=e.onAsyncModeUpgrade;e.onAsyncModeUpgrade=null;const s=u(r);return t(s,e).then(e=>(e&&c.replaceKernel(e),n(s)))}try{if(!0===e.constructor.isAsync)return e.build.apply(e,r),Promise.resolve(e.run.apply(e,r));for(let e=0;en(e));const s=t(r);return e.renderKernels?Promise.resolve(e.renderKernels()):e.renderOutput?e.renderOutputAsync?e.renderOutputAsync():Promise.resolve(e.renderOutput()):Promise.resolve(s)}catch(e){return Promise.reject(e)}}function i(e){return Boolean(e)&&"WebGPUBuffer"===e.type}function o(e){const t=u(e),r=[];for(let e=0;e{t[n]=e}))}return Promise.all(r).then(()=>t)}function u(e){const t=new Array(e.length);for(let r=0;r{try{e(l.apply(this,arguments))}catch(e){t(e)}})},c.replaceKernel=function(t){a(e=t,c)},a(e,c),c}}}),ot=e((e,r)=>{const{gpuMock:n}=t(),{utils:s}=i(),{Kernel:o}=a(),{CPUKernel:u}=p(),{HeadlessGLKernel:h}=Te(),{WebGL2Kernel:l}=tt(),{WebGLKernel:c}=be(),{WebGPUKernel:d}=it(),{kernelRunShortcut:f}=at(),m=[h,l,c],g=["gpu","cpu"],x={headlessgl:h,webgl2:l,webgl:c,webgpu:d};let y=!0;function b(e){if(!e)return{};const t=Object.assign({},e);return e.hasOwnProperty("floatOutput")&&(s.warnDeprecated("setting","floatOutput","precision"),t.precision=e.floatOutput?"single":"unsigned"),e.hasOwnProperty("outputToTexture")&&(s.warnDeprecated("setting","outputToTexture","pipeline"),t.pipeline=Boolean(e.outputToTexture)),e.hasOwnProperty("outputImmutable")&&(s.warnDeprecated("setting","outputImmutable","immutable"),t.immutable=Boolean(e.outputImmutable)),e.hasOwnProperty("floatTextures")&&(s.warnDeprecated("setting","floatTextures","optimizeFloatMemory"),t.optimizeFloatMemory=Boolean(e.floatTextures)),t}r.exports={GPU:class e{static disableValidation(){y=!1}static enableValidation(){y=!0}static get isGPUSupported(){return m.some(e=>e.isSupported)}static get isKernelMapSupported(){return m.some(e=>e.isSupported&&e.features.kernelMap)}static get isOffscreenCanvasSupported(){return"undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas||"undefined"!=typeof importScripts}static get isWebGLSupported(){return c.isSupported}static get isWebGL2Supported(){return l.isSupported}static get isHeadlessGLSupported(){return h.isSupported}static get isWebGPUSupported(){return d.isSupported}static isWebGPUAvailable(){return d.isSupported?navigator.gpu.requestAdapter().then(e=>null!==e,()=>!1):Promise.resolve(!1)}static get isCanvasSupported(){return"undefined"!=typeof HTMLCanvasElement}static get isGPUHTMLImageArraySupported(){return l.isSupported}static get isSinglePrecisionSupported(){return m.some(e=>e.isSupported&&e.features.isFloatRead&&e.features.isTextureFloat)}constructor(t){if(t=t||{},this.canvas=t.canvas||null,this.context=t.context||null,this.mode=t.mode,this.Kernel=null,this._webGPUDecision=null,"async"===t.mode&&(d.isSupported?e.isWebGPUAvailable().then(e=>{this._webGPUDecision=e},()=>{this._webGPUDecision=!1}):this._webGPUDecision=!1),this.kernels=[],this.functions=[],this.nativeFunctions=[],this.injectedNative=null,"dev"!==this.mode){if(this.chooseKernel(),t.functions)for(let e=0;er.argumentTypes[e]));const l=Object.assign({context:this.context,canvas:this.canvas,functions:this.functions,nativeFunctions:this.nativeFunctions,injectedNative:this.injectedNative,gpu:this,validate:y,onRequestFallback:h,onRequestSwitchKernel:function e(r,n,s){s.debug&&console.warn("Switching kernels");let o=null;if(s.signature&&!a[s.signature]&&(a[s.signature]=s),s.dynamicOutput)for(let e=r.length-1;e>=0;e--){const t=r[e];"outputPrecisionMismatch"===t.type&&(o=t.needed)}const u=s.constructor,l=u.getArgumentTypes(s,n),c=u.getSignature(s,l),p=a[c];if(p)return p.onActivate(s),p;const d=a[c]=new u(t,{argumentTypes:l,constantTypes:s.constantTypes,graphical:s.graphical,loopMaxIterations:s.loopMaxIterations,constants:s.constants,dynamicOutput:s.dynamicOutput,dynamicArgument:s.dynamicArguments,context:s.context,canvas:s.canvas,output:o||s.output,precision:s.precision,pipeline:s.pipeline,immutable:s.immutable,optimizeFloatMemory:s.optimizeFloatMemory,fixIntegerDivisionAccuracy:s.fixIntegerDivisionAccuracy,functions:s.functions,nativeFunctions:s.nativeFunctions,injectedNative:s.injectedNative,subKernels:s.subKernels,strictIntegers:s.strictIntegers,randomSeed:s.randomSeed,debug:s.debug,asyncMode:s.asyncMode,gpu:s.gpu,validate:y,returnType:s.returnType,tactic:s.tactic,onRequestFallback:h,onRequestSwitchKernel:e,texture:s.texture,mappedTextures:s.mappedTextures,drawBuffersMap:s.drawBuffersMap});return d.build.apply(d,n),m.replaceKernel(d),i.push(d),d}},o);"async"===this.mode&&(l.asyncMode=!0);let c,p=this.Kernel;"async"===this.mode&&o.graphical&&!0===this._webGPUDecision&&(p=d,l.canvas===this.canvas&&(l.canvas=o.canvas||null),l.context===this.context&&(l.context=o.context||null),l.asyncMode=!0);try{c=new p(t,l)}catch(e){if(p===this.Kernel)throw e;c=new this.Kernel(t,Object.assign({},l,{canvas:this.canvas,context:this.context}))}const m=f(c);if("async"===this.mode&&d.isSupported&&!(c instanceof d)){const r=this;c.onAsyncModeUpgrade=function(n,s){return e.isWebGPUAvailable().then(e=>{if(!e)return null;if(s.graphical)return s.debug&&console.warn("webgpu upgrade declined: graphical kernels keep their canvas"),null;let a;try{a=new d(t,{functions:s.functions,nativeFunctions:s.nativeFunctions,injectedNative:s.injectedNative,gpu:r,validate:y,asyncMode:!0,output:s.output,pipeline:s.pipeline,immutable:s.immutable,dynamicOutput:s.dynamicOutput,dynamicArguments:!0,loopMaxIterations:s.loopMaxIterations,constants:s.constants,constantTypes:s.constantTypes,argumentTypes:s.argumentTypes,precision:s.precision,tactic:s.tactic,strictIntegers:s.strictIntegers,fixIntegerDivisionAccuracy:s.fixIntegerDivisionAccuracy,subKernels:s.subKernels,graphical:s.graphical,debug:s.debug}),a.build.apply(a,n)}catch(e){return s.debug&&console.warn("webgpu upgrade declined: "+e.message),null}return a._buildPromise.then(()=>(i.push(a),a),e=>(s.debug&&console.warn("webgpu upgrade declined: "+e.message),a.destroy(),null))},()=>null)}}return this.canvas||(this.canvas=c.canvas),this.context||(this.context=c.context),i.push(c),m}createKernelMap(){let e,t;const r=typeof arguments[arguments.length-2];if("function"===r||"string"===r?(e=arguments[arguments.length-2],t=arguments[arguments.length-1]):e=arguments[arguments.length-1],!("dev"===this.mode||this.Kernel.isSupported&&this.Kernel.features.kernelMap)){if("webgpu"===this.Kernel.mode)throw new Error("WebGPU backend does not yet support createKernelMap");if(this.mode&&g.indexOf(this.mode)<0)throw new Error(`kernelMap not supported on ${this.Kernel.name}`)}const n=b(t);if(t&&"object"==typeof t.argumentTypes&&(n.argumentTypes=Object.keys(t.argumentTypes).map(e=>t.argumentTypes[e])),Array.isArray(arguments[0])){n.subKernels=[];const e=arguments[0];for(let t=0;t0)throw new Error('Cannot call "addNativeFunction" after "createKernels" has been called.');return this.nativeFunctions.push(Object.assign({name:e,source:t},r)),this}injectNative(e){return this.injectedNative=e,this}destroy(){return new Promise((e,t)=>{this.kernels||e(),setTimeout(()=>{try{const e=this.kernels.slice();for(let t=0;t{const{utils:r}=i();t.exports={alias:function(e,t){const n=t.toString();return new Function(`return function ${e} (${r.getArgumentNamesFromString(n).join(", ")}) {\n ${r.getFunctionBodyFromString(n)}\n}`)()}}}),ht=e((e,t)=>{const{GPU:r}=ot(),{alias:c}=ut(),{utils:d}=i(),{Input:f,input:m}=n(),{Texture:g}=s(),{FunctionBuilder:x}=o(),{FunctionNode:y}=h(),{CPUFunctionNode:b}=l(),{CPUKernel:T}=p(),{HeadlessGLKernel:S}=Te(),{WebGLFunctionNode:v}=N(),{WebGLKernel:A}=be(),{kernelValueMaps:_}=ye(),{WebGL2FunctionNode:w}=Se(),{WebGL2Kernel:E}=tt(),{kernelValueMaps:I}=et(),{WGSLFunctionNode:k}=rt(),{WebGPUKernel:D}=it(),{WebGPUContext:C}=nt(),{WebGPUBufferResult:L}=st(),{GLKernel:$}=R(),{Kernel:F}=a(),{FunctionTracer:M}=u();t.exports={alias:c,CPUFunctionNode:b,CPUKernel:T,GPU:r,FunctionBuilder:x,FunctionNode:y,HeadlessGLKernel:S,Input:f,input:m,Texture:g,utils:d,WebGL2FunctionNode:w,WebGL2Kernel:E,webGL2KernelValueMaps:I,WebGLFunctionNode:v,WebGLKernel:A,webGLKernelValueMaps:_,WGSLFunctionNode:k,WebGPUKernel:D,WebGPUContext:C,WebGPUBufferResult:L,GLKernel:$,Kernel:F,FunctionTracer:M,plugins:{mathRandom:V()}}});return e((e,t)=>{const r=ht(),n=r.GPU;for(const e in r)r.hasOwnProperty(e)&&"GPU"!==e&&(n[e]=r[e]);function s(e){e.GPU&&e.GPU.prototype&&e.GPU.prototype.createKernel||Object.defineProperty(e,"GPU",{configurable:!0,get:()=>n,set(){}})}n.GPU=n,"undefined"!=typeof window&&s(window),"undefined"!=typeof self&&s(self),t.exports=n})()}); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):(e="undefined"!=typeof globalThis?globalThis:e||self).GPU=t()}(this,function(){var e=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),t=e((e,t)=>{function s(e){const t=new Array(e.length);for(let s=0;s{e.output=l(t),e.graphical&&u(e)},e.toJSON=()=>{throw new Error("Not usable with gpuMock")},e.setConstants=t=>(e.constants=t,e),e.setGraphical=t=>(e.graphical=t,e),e.setCanvas=t=>(e.canvas=t,e),e.setContext=t=>(e.context=t,e),e.destroy=()=>{},e.validateSettings=()=>{},e.graphical&&e.output&&u(e),e.exec=function(){return new Promise((t,s)=>{try{t(e.apply(e,arguments))}catch(e){s(e)}})},e.getPixels=t=>{const{x:s,y:r}=e.output;return t?function(e,t,s){const r=s/2|0,n=4*t,i=new Uint8ClampedArray(4*t),a=e.slice(0);for(let e=0;ee,s=["setWarnVarUsage","setArgumentTypes","setTactic","setOptimizeFloatMemory","setDebug","setLoopMaxIterations","setConstantTypes","setFunctions","setNativeFunctions","setInjectedNative","setPipeline","setPrecision","setOutputToTexture","setImmutable","setStrictIntegers","setDynamicOutput","setHardcodeConstants","setDynamicArguments","setUseLegacyEncoder","setWarnVarUsage","addSubKernel"];for(let r=0;r{var s,r;s=e,r=function(e){"use strict";var t=[509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,166,1,574,3,9,9,7,9,32,4,318,1,80,3,71,10,50,3,123,2,54,14,32,10,3,1,11,3,46,10,8,0,46,9,7,2,37,13,2,9,6,1,45,0,13,2,49,13,9,3,2,11,83,11,7,0,3,0,158,11,6,9,7,3,56,1,2,6,3,1,3,2,10,0,11,1,3,6,4,4,68,8,2,0,3,0,2,3,2,4,2,0,15,1,83,17,10,9,5,0,82,19,13,9,214,6,3,8,28,1,83,16,16,9,82,12,9,9,7,19,58,14,5,9,243,14,166,9,71,5,2,1,3,3,2,0,2,1,13,9,120,6,3,6,4,0,29,9,41,6,2,3,9,0,10,10,47,15,343,9,54,7,2,7,17,9,57,21,2,13,123,5,4,0,2,1,2,6,2,0,9,9,49,4,2,1,2,4,9,9,330,3,10,1,2,0,49,6,4,4,14,10,5350,0,7,14,11465,27,2343,9,87,9,39,4,60,6,26,9,535,9,470,0,2,54,8,3,82,0,12,1,19628,1,4178,9,519,45,3,22,543,4,4,5,9,7,3,6,31,3,149,2,1418,49,513,54,5,49,9,0,15,0,23,4,2,14,1361,6,2,16,3,6,2,1,2,4,101,0,161,6,10,9,357,0,62,13,499,13,245,1,2,9,726,6,110,6,6,9,4759,9,787719,239],s=[0,11,2,25,2,18,2,1,2,14,3,13,35,122,70,52,268,28,4,48,48,31,14,29,6,37,11,29,3,35,5,7,2,4,43,157,19,35,5,35,5,39,9,51,13,10,2,14,2,6,2,1,2,10,2,14,2,6,2,1,4,51,13,310,10,21,11,7,25,5,2,41,2,8,70,5,3,0,2,43,2,1,4,0,3,22,11,22,10,30,66,18,2,1,11,21,11,25,71,55,7,1,65,0,16,3,2,2,2,28,43,28,4,28,36,7,2,27,28,53,11,21,11,18,14,17,111,72,56,50,14,50,14,35,39,27,10,22,251,41,7,1,17,2,60,28,11,0,9,21,43,17,47,20,28,22,13,52,58,1,3,0,14,44,33,24,27,35,30,0,3,0,9,34,4,0,13,47,15,3,22,0,2,0,36,17,2,24,20,1,64,6,2,0,2,3,2,14,2,9,8,46,39,7,3,1,3,21,2,6,2,1,2,4,4,0,19,0,13,4,31,9,2,0,3,0,2,37,2,0,26,0,2,0,45,52,19,3,21,2,31,47,21,1,2,0,185,46,42,3,37,47,21,0,60,42,14,0,72,26,38,6,186,43,117,63,32,7,3,0,3,7,2,1,2,23,16,0,2,0,95,7,3,38,17,0,2,0,29,0,11,39,8,0,22,0,12,45,20,0,19,72,200,32,32,8,2,36,18,0,50,29,113,6,2,1,2,37,22,0,26,5,2,1,2,31,15,0,328,18,16,0,2,12,2,33,125,0,80,921,103,110,18,195,2637,96,16,1071,18,5,26,3994,6,582,6842,29,1763,568,8,30,18,78,18,29,19,47,17,3,32,20,6,18,433,44,212,63,129,74,6,0,67,12,65,1,2,0,29,6135,9,1237,42,9,8936,3,2,6,2,1,2,290,16,0,30,2,3,0,15,3,9,395,2309,106,6,12,4,8,8,9,5991,84,2,70,2,1,3,0,3,1,3,3,2,11,2,0,2,6,2,64,2,3,3,7,2,6,2,27,2,3,2,4,2,0,4,6,2,339,3,24,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,30,2,24,2,7,1845,30,7,5,262,61,147,44,11,6,17,0,322,29,19,43,485,27,229,29,3,0,496,6,2,3,2,1,2,14,2,196,60,67,8,0,1205,3,2,26,2,1,2,0,3,0,2,9,2,3,2,0,2,0,7,0,5,0,2,0,2,0,2,2,2,1,2,0,3,0,2,0,2,0,2,0,2,0,2,1,2,0,3,3,2,6,2,3,2,3,2,0,2,9,2,16,6,2,2,4,2,16,4421,42719,33,4153,7,221,3,5761,15,7472,16,621,2467,541,1507,4938,6,4191],r="\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u0870-\u0887\u0889-\u088e\u08a0-\u08c9\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c5d\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cdd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d04-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e86-\u0e8a\u0e8c-\u0ea3\u0ea5\u0ea7-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u1711\u171f-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4c\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c8a\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1cfa\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31bf\u31f0-\u31ff\u3400-\u4dbf\u4e00-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7cd\ua7d0\ua7d1\ua7d3\ua7d5-\ua7dc\ua7f2-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab69\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc",n={3:"abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile",5:"class enum extends super const export import",6:"enum",strict:"implements interface let package private protected public static yield",strictBind:"eval arguments"},i="break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this",a={5:i,"5module":i+" export import",6:i+" const class extends export import super"},o=/^in(stanceof)?$/,u=new RegExp("["+r+"]"),l=new RegExp("["+r+"\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u0897-\u089f\u08ca-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b55-\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3c\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0cf3\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d81-\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0ebc\u0ec8-\u0ece\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1715\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u180f-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1abf-\u1ace\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf4\u1cf7-\u1cf9\u1dc0-\u1dff\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\u30fb\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua82c\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f\uff65]");function h(e,t){for(var s=65536,r=0;re)return!1;if((s+=t[r+1])>=e)return!0}return!1}function c(e,t){return e<65?36===e:e<91||(e<97?95===e:e<123||(e<=65535?e>=170&&u.test(String.fromCharCode(e)):!1!==t&&h(e,s)))}function p(e,r){return e<48?36===e:e<58||!(e<65)&&(e<91||(e<97?95===e:e<123||(e<=65535?e>=170&&l.test(String.fromCharCode(e)):!1!==r&&(h(e,s)||h(e,t)))))}var d=function(e,t){void 0===t&&(t={}),this.label=e,this.keyword=t.keyword,this.beforeExpr=!!t.beforeExpr,this.startsExpr=!!t.startsExpr,this.isLoop=!!t.isLoop,this.isAssign=!!t.isAssign,this.prefix=!!t.prefix,this.postfix=!!t.postfix,this.binop=t.binop||null,this.updateContext=null};function f(e,t){return new d(e,{beforeExpr:!0,binop:t})}var m={beforeExpr:!0},g={startsExpr:!0},x={};function y(e,t){return void 0===t&&(t={}),t.keyword=e,x[e]=new d(e,t)}var b={num:new d("num",g),regexp:new d("regexp",g),string:new d("string",g),name:new d("name",g),privateId:new d("privateId",g),eof:new d("eof"),bracketL:new d("[",{beforeExpr:!0,startsExpr:!0}),bracketR:new d("]"),braceL:new d("{",{beforeExpr:!0,startsExpr:!0}),braceR:new d("}"),parenL:new d("(",{beforeExpr:!0,startsExpr:!0}),parenR:new d(")"),comma:new d(",",m),semi:new d(";",m),colon:new d(":",m),dot:new d("."),question:new d("?",m),questionDot:new d("?."),arrow:new d("=>",m),template:new d("template"),invalidTemplate:new d("invalidTemplate"),ellipsis:new d("...",m),backQuote:new d("`",g),dollarBraceL:new d("${",{beforeExpr:!0,startsExpr:!0}),eq:new d("=",{beforeExpr:!0,isAssign:!0}),assign:new d("_=",{beforeExpr:!0,isAssign:!0}),incDec:new d("++/--",{prefix:!0,postfix:!0,startsExpr:!0}),prefix:new d("!/~",{beforeExpr:!0,prefix:!0,startsExpr:!0}),logicalOR:f("||",1),logicalAND:f("&&",2),bitwiseOR:f("|",3),bitwiseXOR:f("^",4),bitwiseAND:f("&",5),equality:f("==/!=/===/!==",6),relational:f("/<=/>=",7),bitShift:f("<>/>>>",8),plusMin:new d("+/-",{beforeExpr:!0,binop:9,prefix:!0,startsExpr:!0}),modulo:f("%",10),star:f("*",10),slash:f("/",10),starstar:new d("**",{beforeExpr:!0}),coalesce:f("??",1),_break:y("break"),_case:y("case",m),_catch:y("catch"),_continue:y("continue"),_debugger:y("debugger"),_default:y("default",m),_do:y("do",{isLoop:!0,beforeExpr:!0}),_else:y("else",m),_finally:y("finally"),_for:y("for",{isLoop:!0}),_function:y("function",g),_if:y("if"),_return:y("return",m),_switch:y("switch"),_throw:y("throw",m),_try:y("try"),_var:y("var"),_const:y("const"),_while:y("while",{isLoop:!0}),_with:y("with"),_new:y("new",{beforeExpr:!0,startsExpr:!0}),_this:y("this",g),_super:y("super",g),_class:y("class",g),_extends:y("extends",m),_export:y("export"),_import:y("import",g),_null:y("null",g),_true:y("true",g),_false:y("false",g),_in:y("in",{beforeExpr:!0,binop:7}),_instanceof:y("instanceof",{beforeExpr:!0,binop:7}),_typeof:y("typeof",{beforeExpr:!0,prefix:!0,startsExpr:!0}),_void:y("void",{beforeExpr:!0,prefix:!0,startsExpr:!0}),_delete:y("delete",{beforeExpr:!0,prefix:!0,startsExpr:!0})},v=/\r\n?|\n|\u2028|\u2029/,S=new RegExp(v.source,"g");function T(e){return 10===e||13===e||8232===e||8233===e}function A(e,t,s){void 0===s&&(s=e.length);for(var r=t;r>10),56320+(1023&e)))}var N=/(?:[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/,R=function(e,t){this.line=e,this.column=t};R.prototype.offset=function(e){return new R(this.line,this.column+e)};var M=function(e,t,s){this.start=t,this.end=s,null!==e.sourceFile&&(this.source=e.sourceFile)};function G(e,t){for(var s=1,r=0;;){var n=A(e,r,t);if(n<0)return new R(s,t-r);++s,r=n}}var O={ecmaVersion:null,sourceType:"script",onInsertedSemicolon:null,onTrailingComma:null,allowReserved:null,allowReturnOutsideFunction:!1,allowImportExportEverywhere:!1,allowAwaitOutsideFunction:null,allowSuperOutsideMethod:null,allowHashBang:!1,checkPrivateFields:!0,locations:!1,onToken:null,onComment:null,ranges:!1,program:null,sourceFile:null,directSourceFile:null,preserveParens:!1},V=!1;function P(e){var t={};for(var s in O)t[s]=e&&C(e,s)?e[s]:O[s];if("latest"===t.ecmaVersion?t.ecmaVersion=1e8:null==t.ecmaVersion?(!V&&"object"==typeof console&&console.warn&&(V=!0,console.warn("Since Acorn 8.0.0, options.ecmaVersion is required.\nDefaulting to 2020, but this will stop working in the future.")),t.ecmaVersion=11):t.ecmaVersion>=2015&&(t.ecmaVersion-=2009),null==t.allowReserved&&(t.allowReserved=t.ecmaVersion<5),e&&null!=e.allowHashBang||(t.allowHashBang=t.ecmaVersion>=14),L(t.onToken)){var r=t.onToken;t.onToken=function(e){return r.push(e)}}return L(t.onComment)&&(t.onComment=function(e,t){return function(s,r,n,i,a,o){var u={type:s?"Block":"Line",value:r,start:n,end:i};e.locations&&(u.loc=new M(this,a,o)),e.ranges&&(u.range=[n,i]),t.push(u)}}(t,t.onComment)),t}var z=256;function U(e,t){return 2|(e?4:0)|(t?8:0)}var B=function(e,t,s){this.options=e=P(e),this.sourceFile=e.sourceFile,this.keywords=F(a[e.ecmaVersion>=6?6:"module"===e.sourceType?"5module":5]);var r="";!0!==e.allowReserved&&(r=n[e.ecmaVersion>=6?6:5===e.ecmaVersion?5:3],"module"===e.sourceType&&(r+=" await")),this.reservedWords=F(r);var i=(r?r+" ":"")+n.strict;this.reservedWordsStrict=F(i),this.reservedWordsStrictBind=F(i+" "+n.strictBind),this.input=String(t),this.containsEsc=!1,s?(this.pos=s,this.lineStart=this.input.lastIndexOf("\n",s-1)+1,this.curLine=this.input.slice(0,this.lineStart).split(v).length):(this.pos=this.lineStart=0,this.curLine=1),this.type=b.eof,this.value=null,this.start=this.end=this.pos,this.startLoc=this.endLoc=this.curPosition(),this.lastTokEndLoc=this.lastTokStartLoc=null,this.lastTokStart=this.lastTokEnd=this.pos,this.context=this.initialContext(),this.exprAllowed=!0,this.inModule="module"===e.sourceType,this.strict=this.inModule||this.strictDirective(this.pos),this.potentialArrowAt=-1,this.potentialArrowInForAwait=!1,this.yieldPos=this.awaitPos=this.awaitIdentPos=0,this.labels=[],this.undefinedExports=Object.create(null),0===this.pos&&e.allowHashBang&&"#!"===this.input.slice(0,2)&&this.skipLineComment(2),this.scopeStack=[],this.enterScope(1),this.regexpState=null,this.privateNameStack=[]},K={inFunction:{configurable:!0},inGenerator:{configurable:!0},inAsync:{configurable:!0},canAwait:{configurable:!0},allowSuper:{configurable:!0},allowDirectSuper:{configurable:!0},treatFunctionsAsVar:{configurable:!0},allowNewDotTarget:{configurable:!0},inClassStaticBlock:{configurable:!0}};B.prototype.parse=function(){var e=this.options.program||this.startNode();return this.nextToken(),this.parseTopLevel(e)},K.inFunction.get=function(){return(2&this.currentVarScope().flags)>0},K.inGenerator.get=function(){return(8&this.currentVarScope().flags)>0&&!this.currentVarScope().inClassFieldInit},K.inAsync.get=function(){return(4&this.currentVarScope().flags)>0&&!this.currentVarScope().inClassFieldInit},K.canAwait.get=function(){for(var e=this.scopeStack.length-1;e>=0;e--){var t=this.scopeStack[e];if(t.inClassFieldInit||t.flags&z)return!1;if(2&t.flags)return(4&t.flags)>0}return this.inModule&&this.options.ecmaVersion>=13||this.options.allowAwaitOutsideFunction},K.allowSuper.get=function(){var e=this.currentThisScope(),t=e.flags,s=e.inClassFieldInit;return(64&t)>0||s||this.options.allowSuperOutsideMethod},K.allowDirectSuper.get=function(){return(128&this.currentThisScope().flags)>0},K.treatFunctionsAsVar.get=function(){return this.treatFunctionsAsVarInScope(this.currentScope())},K.allowNewDotTarget.get=function(){var e=this.currentThisScope(),t=e.flags,s=e.inClassFieldInit;return(258&t)>0||s},K.inClassStaticBlock.get=function(){return(this.currentVarScope().flags&z)>0},B.extend=function(){for(var e=[],t=arguments.length;t--;)e[t]=arguments[t];for(var s=this,r=0;r=,?^&]/.test(n)||"!"===n&&"="===this.input.charAt(r+1))}e+=t[0].length,E.lastIndex=e,e+=E.exec(this.input)[0].length,";"===this.input[e]&&e++}},W.eat=function(e){return this.type===e&&(this.next(),!0)},W.isContextual=function(e){return this.type===b.name&&this.value===e&&!this.containsEsc},W.eatContextual=function(e){return!!this.isContextual(e)&&(this.next(),!0)},W.expectContextual=function(e){this.eatContextual(e)||this.unexpected()},W.canInsertSemicolon=function(){return this.type===b.eof||this.type===b.braceR||v.test(this.input.slice(this.lastTokEnd,this.start))},W.insertSemicolon=function(){if(this.canInsertSemicolon())return this.options.onInsertedSemicolon&&this.options.onInsertedSemicolon(this.lastTokEnd,this.lastTokEndLoc),!0},W.semicolon=function(){this.eat(b.semi)||this.insertSemicolon()||this.unexpected()},W.afterTrailingComma=function(e,t){if(this.type===e)return this.options.onTrailingComma&&this.options.onTrailingComma(this.lastTokStart,this.lastTokStartLoc),t||this.next(),!0},W.expect=function(e){this.eat(e)||this.unexpected()},W.unexpected=function(e){this.raise(null!=e?e:this.start,"Unexpected token")};var q=function(){this.shorthandAssign=this.trailingComma=this.parenthesizedAssign=this.parenthesizedBind=this.doubleProto=-1};W.checkPatternErrors=function(e,t){if(e){e.trailingComma>-1&&this.raiseRecoverable(e.trailingComma,"Comma is not permitted after the rest element");var s=t?e.parenthesizedAssign:e.parenthesizedBind;s>-1&&this.raiseRecoverable(s,t?"Assigning to rvalue":"Parenthesized pattern")}},W.checkExpressionErrors=function(e,t){if(!e)return!1;var s=e.shorthandAssign,r=e.doubleProto;if(!t)return s>=0||r>=0;s>=0&&this.raise(s,"Shorthand property assignments are valid only in destructuring patterns"),r>=0&&this.raiseRecoverable(r,"Redefinition of __proto__ property")},W.checkYieldAwaitInDefaultParams=function(){this.yieldPos&&(!this.awaitPos||this.yieldPos55295&&r<56320)return!0;if(c(r,!0)){for(var n=s+1;p(r=this.input.charCodeAt(n),!0);)++n;if(92===r||r>55295&&r<56320)return!0;var i=this.input.slice(s,n);if(!o.test(i))return!0}return!1},X.isAsyncFunction=function(){if(this.options.ecmaVersion<8||!this.isContextual("async"))return!1;E.lastIndex=this.pos;var e,t=E.exec(this.input),s=this.pos+t[0].length;return!(v.test(this.input.slice(this.pos,s))||"function"!==this.input.slice(s,s+8)||s+8!==this.input.length&&(p(e=this.input.charCodeAt(s+8))||e>55295&&e<56320))},X.parseStatement=function(e,t,s){var r,n=this.type,i=this.startNode();switch(this.isLet(e)&&(n=b._var,r="let"),n){case b._break:case b._continue:return this.parseBreakContinueStatement(i,n.keyword);case b._debugger:return this.parseDebuggerStatement(i);case b._do:return this.parseDoStatement(i);case b._for:return this.parseForStatement(i);case b._function:return e&&(this.strict||"if"!==e&&"label"!==e)&&this.options.ecmaVersion>=6&&this.unexpected(),this.parseFunctionStatement(i,!1,!e);case b._class:return e&&this.unexpected(),this.parseClass(i,!0);case b._if:return this.parseIfStatement(i);case b._return:return this.parseReturnStatement(i);case b._switch:return this.parseSwitchStatement(i);case b._throw:return this.parseThrowStatement(i);case b._try:return this.parseTryStatement(i);case b._const:case b._var:return r=r||this.value,e&&"var"!==r&&this.unexpected(),this.parseVarStatement(i,r);case b._while:return this.parseWhileStatement(i);case b._with:return this.parseWithStatement(i);case b.braceL:return this.parseBlock(!0,i);case b.semi:return this.parseEmptyStatement(i);case b._export:case b._import:if(this.options.ecmaVersion>10&&n===b._import){E.lastIndex=this.pos;var a=E.exec(this.input),o=this.pos+a[0].length,u=this.input.charCodeAt(o);if(40===u||46===u)return this.parseExpressionStatement(i,this.parseExpression())}return this.options.allowImportExportEverywhere||(t||this.raise(this.start,"'import' and 'export' may only appear at the top level"),this.inModule||this.raise(this.start,"'import' and 'export' may appear only with 'sourceType: module'")),n===b._import?this.parseImport(i):this.parseExport(i,s);default:if(this.isAsyncFunction())return e&&this.unexpected(),this.next(),this.parseFunctionStatement(i,!0,!e);var l=this.value,h=this.parseExpression();return n===b.name&&"Identifier"===h.type&&this.eat(b.colon)?this.parseLabeledStatement(i,l,h,e):this.parseExpressionStatement(i,h)}},X.parseBreakContinueStatement=function(e,t){var s="break"===t;this.next(),this.eat(b.semi)||this.insertSemicolon()?e.label=null:this.type!==b.name?this.unexpected():(e.label=this.parseIdent(),this.semicolon());for(var r=0;r=6?this.eat(b.semi):this.semicolon(),this.finishNode(e,"DoWhileStatement")},X.parseForStatement=function(e){this.next();var t=this.options.ecmaVersion>=9&&this.canAwait&&this.eatContextual("await")?this.lastTokStart:-1;if(this.labels.push(H),this.enterScope(0),this.expect(b.parenL),this.type===b.semi)return t>-1&&this.unexpected(t),this.parseFor(e,null);var s=this.isLet();if(this.type===b._var||this.type===b._const||s){var r=this.startNode(),n=s?"let":this.value;return this.next(),this.parseVar(r,!0,n),this.finishNode(r,"VariableDeclaration"),(this.type===b._in||this.options.ecmaVersion>=6&&this.isContextual("of"))&&1===r.declarations.length?(this.options.ecmaVersion>=9&&(this.type===b._in?t>-1&&this.unexpected(t):e.await=t>-1),this.parseForIn(e,r)):(t>-1&&this.unexpected(t),this.parseFor(e,r))}var i=this.isContextual("let"),a=!1,o=this.containsEsc,u=new q,l=this.start,h=t>-1?this.parseExprSubscripts(u,"await"):this.parseExpression(!0,u);return this.type===b._in||(a=this.options.ecmaVersion>=6&&this.isContextual("of"))?(t>-1?(this.type===b._in&&this.unexpected(t),e.await=!0):a&&this.options.ecmaVersion>=8&&(h.start!==l||o||"Identifier"!==h.type||"async"!==h.name?this.options.ecmaVersion>=9&&(e.await=!1):this.unexpected()),i&&a&&this.raise(h.start,"The left-hand side of a for-of loop may not start with 'let'."),this.toAssignable(h,!1,u),this.checkLValPattern(h),this.parseForIn(e,h)):(this.checkExpressionErrors(u,!0),t>-1&&this.unexpected(t),this.parseFor(e,h))},X.parseFunctionStatement=function(e,t,s){return this.next(),this.parseFunction(e,J|(s?0:Q),!1,t)},X.parseIfStatement=function(e){return this.next(),e.test=this.parseParenExpression(),e.consequent=this.parseStatement("if"),e.alternate=this.eat(b._else)?this.parseStatement("if"):null,this.finishNode(e,"IfStatement")},X.parseReturnStatement=function(e){return this.inFunction||this.options.allowReturnOutsideFunction||this.raise(this.start,"'return' outside of function"),this.next(),this.eat(b.semi)||this.insertSemicolon()?e.argument=null:(e.argument=this.parseExpression(),this.semicolon()),this.finishNode(e,"ReturnStatement")},X.parseSwitchStatement=function(e){var t;this.next(),e.discriminant=this.parseParenExpression(),e.cases=[],this.expect(b.braceL),this.labels.push(Y),this.enterScope(0);for(var s=!1;this.type!==b.braceR;)if(this.type===b._case||this.type===b._default){var r=this.type===b._case;t&&this.finishNode(t,"SwitchCase"),e.cases.push(t=this.startNode()),t.consequent=[],this.next(),r?t.test=this.parseExpression():(s&&this.raiseRecoverable(this.lastTokStart,"Multiple default clauses"),s=!0,t.test=null),this.expect(b.colon)}else t||this.unexpected(),t.consequent.push(this.parseStatement(null));return this.exitScope(),t&&this.finishNode(t,"SwitchCase"),this.next(),this.labels.pop(),this.finishNode(e,"SwitchStatement")},X.parseThrowStatement=function(e){return this.next(),v.test(this.input.slice(this.lastTokEnd,this.start))&&this.raise(this.lastTokEnd,"Illegal newline after throw"),e.argument=this.parseExpression(),this.semicolon(),this.finishNode(e,"ThrowStatement")};var Z=[];X.parseCatchClauseParam=function(){var e=this.parseBindingAtom(),t="Identifier"===e.type;return this.enterScope(t?32:0),this.checkLValPattern(e,t?4:2),this.expect(b.parenR),e},X.parseTryStatement=function(e){if(this.next(),e.block=this.parseBlock(),e.handler=null,this.type===b._catch){var t=this.startNode();this.next(),this.eat(b.parenL)?t.param=this.parseCatchClauseParam():(this.options.ecmaVersion<10&&this.unexpected(),t.param=null,this.enterScope(0)),t.body=this.parseBlock(!1),this.exitScope(),e.handler=this.finishNode(t,"CatchClause")}return e.finalizer=this.eat(b._finally)?this.parseBlock():null,e.handler||e.finalizer||this.raise(e.start,"Missing catch or finally clause"),this.finishNode(e,"TryStatement")},X.parseVarStatement=function(e,t,s){return this.next(),this.parseVar(e,!1,t,s),this.semicolon(),this.finishNode(e,"VariableDeclaration")},X.parseWhileStatement=function(e){return this.next(),e.test=this.parseParenExpression(),this.labels.push(H),e.body=this.parseStatement("while"),this.labels.pop(),this.finishNode(e,"WhileStatement")},X.parseWithStatement=function(e){return this.strict&&this.raise(this.start,"'with' in strict mode"),this.next(),e.object=this.parseParenExpression(),e.body=this.parseStatement("with"),this.finishNode(e,"WithStatement")},X.parseEmptyStatement=function(e){return this.next(),this.finishNode(e,"EmptyStatement")},X.parseLabeledStatement=function(e,t,s,r){for(var n=0,i=this.labels;n=0;o--){var u=this.labels[o];if(u.statementStart!==e.start)break;u.statementStart=this.start,u.kind=a}return this.labels.push({name:t,kind:a,statementStart:this.start}),e.body=this.parseStatement(r?-1===r.indexOf("label")?r+"label":r:"label"),this.labels.pop(),e.label=s,this.finishNode(e,"LabeledStatement")},X.parseExpressionStatement=function(e,t){return e.expression=t,this.semicolon(),this.finishNode(e,"ExpressionStatement")},X.parseBlock=function(e,t,s){for(void 0===e&&(e=!0),void 0===t&&(t=this.startNode()),t.body=[],this.expect(b.braceL),e&&this.enterScope(0);this.type!==b.braceR;){var r=this.parseStatement(null);t.body.push(r)}return s&&(this.strict=!1),this.next(),e&&this.exitScope(),this.finishNode(t,"BlockStatement")},X.parseFor=function(e,t){return e.init=t,this.expect(b.semi),e.test=this.type===b.semi?null:this.parseExpression(),this.expect(b.semi),e.update=this.type===b.parenR?null:this.parseExpression(),this.expect(b.parenR),e.body=this.parseStatement("for"),this.exitScope(),this.labels.pop(),this.finishNode(e,"ForStatement")},X.parseForIn=function(e,t){var s=this.type===b._in;return this.next(),"VariableDeclaration"===t.type&&null!=t.declarations[0].init&&(!s||this.options.ecmaVersion<8||this.strict||"var"!==t.kind||"Identifier"!==t.declarations[0].id.type)&&this.raise(t.start,(s?"for-in":"for-of")+" loop variable declaration may not have an initializer"),e.left=t,e.right=s?this.parseExpression():this.parseMaybeAssign(),this.expect(b.parenR),e.body=this.parseStatement("for"),this.exitScope(),this.labels.pop(),this.finishNode(e,s?"ForInStatement":"ForOfStatement")},X.parseVar=function(e,t,s,r){for(e.declarations=[],e.kind=s;;){var n=this.startNode();if(this.parseVarId(n,s),this.eat(b.eq)?n.init=this.parseMaybeAssign(t):r||"const"!==s||this.type===b._in||this.options.ecmaVersion>=6&&this.isContextual("of")?r||"Identifier"===n.id.type||t&&(this.type===b._in||this.isContextual("of"))?n.init=null:this.raise(this.lastTokEnd,"Complex binding patterns require an initialization value"):this.unexpected(),e.declarations.push(this.finishNode(n,"VariableDeclarator")),!this.eat(b.comma))break}return e},X.parseVarId=function(e,t){e.id=this.parseBindingAtom(),this.checkLValPattern(e.id,"var"===t?1:2,!1)};var J=1,Q=2;function ee(e,t){var s=t.key.name,r=e[s],n="true";return"MethodDefinition"!==t.type||"get"!==t.kind&&"set"!==t.kind||(n=(t.static?"s":"i")+t.kind),"iget"===r&&"iset"===n||"iset"===r&&"iget"===n||"sget"===r&&"sset"===n||"sset"===r&&"sget"===n?(e[s]="true",!1):!!r||(e[s]=n,!1)}function te(e,t){var s=e.computed,r=e.key;return!s&&("Identifier"===r.type&&r.name===t||"Literal"===r.type&&r.value===t)}X.parseFunction=function(e,t,s,r,n){this.initFunction(e),(this.options.ecmaVersion>=9||this.options.ecmaVersion>=6&&!r)&&(this.type===b.star&&t&Q&&this.unexpected(),e.generator=this.eat(b.star)),this.options.ecmaVersion>=8&&(e.async=!!r),t&J&&(e.id=4&t&&this.type!==b.name?null:this.parseIdent(),!e.id||t&Q||this.checkLValSimple(e.id,this.strict||e.generator||e.async?this.treatFunctionsAsVar?1:2:3));var i=this.yieldPos,a=this.awaitPos,o=this.awaitIdentPos;return this.yieldPos=0,this.awaitPos=0,this.awaitIdentPos=0,this.enterScope(U(e.async,e.generator)),t&J||(e.id=this.type===b.name?this.parseIdent():null),this.parseFunctionParams(e),this.parseFunctionBody(e,s,!1,n),this.yieldPos=i,this.awaitPos=a,this.awaitIdentPos=o,this.finishNode(e,t&J?"FunctionDeclaration":"FunctionExpression")},X.parseFunctionParams=function(e){this.expect(b.parenL),e.params=this.parseBindingList(b.parenR,!1,this.options.ecmaVersion>=8),this.checkYieldAwaitInDefaultParams()},X.parseClass=function(e,t){this.next();var s=this.strict;this.strict=!0,this.parseClassId(e,t),this.parseClassSuper(e);var r=this.enterClassBody(),n=this.startNode(),i=!1;for(n.body=[],this.expect(b.braceL);this.type!==b.braceR;){var a=this.parseClassElement(null!==e.superClass);a&&(n.body.push(a),"MethodDefinition"===a.type&&"constructor"===a.kind?(i&&this.raiseRecoverable(a.start,"Duplicate constructor in the same class"),i=!0):a.key&&"PrivateIdentifier"===a.key.type&&ee(r,a)&&this.raiseRecoverable(a.key.start,"Identifier '#"+a.key.name+"' has already been declared"))}return this.strict=s,this.next(),e.body=this.finishNode(n,"ClassBody"),this.exitClassBody(),this.finishNode(e,t?"ClassDeclaration":"ClassExpression")},X.parseClassElement=function(e){if(this.eat(b.semi))return null;var t=this.options.ecmaVersion,s=this.startNode(),r="",n=!1,i=!1,a="method",o=!1;if(this.eatContextual("static")){if(t>=13&&this.eat(b.braceL))return this.parseClassStaticBlock(s),s;this.isClassElementNameStart()||this.type===b.star?o=!0:r="static"}if(s.static=o,!r&&t>=8&&this.eatContextual("async")&&(!this.isClassElementNameStart()&&this.type!==b.star||this.canInsertSemicolon()?r="async":i=!0),!r&&(t>=9||!i)&&this.eat(b.star)&&(n=!0),!r&&!i&&!n){var u=this.value;(this.eatContextual("get")||this.eatContextual("set"))&&(this.isClassElementNameStart()?a=u:r=u)}if(r?(s.computed=!1,s.key=this.startNodeAt(this.lastTokStart,this.lastTokStartLoc),s.key.name=r,this.finishNode(s.key,"Identifier")):this.parseClassElementName(s),t<13||this.type===b.parenL||"method"!==a||n||i){var l=!s.static&&te(s,"constructor"),h=l&&e;l&&"method"!==a&&this.raise(s.key.start,"Constructor can't have get/set modifier"),s.kind=l?"constructor":a,this.parseClassMethod(s,n,i,h)}else this.parseClassField(s);return s},X.isClassElementNameStart=function(){return this.type===b.name||this.type===b.privateId||this.type===b.num||this.type===b.string||this.type===b.bracketL||this.type.keyword},X.parseClassElementName=function(e){this.type===b.privateId?("constructor"===this.value&&this.raise(this.start,"Classes can't have an element named '#constructor'"),e.computed=!1,e.key=this.parsePrivateIdent()):this.parsePropertyName(e)},X.parseClassMethod=function(e,t,s,r){var n=e.key;"constructor"===e.kind?(t&&this.raise(n.start,"Constructor can't be a generator"),s&&this.raise(n.start,"Constructor can't be an async method")):e.static&&te(e,"prototype")&&this.raise(n.start,"Classes may not have a static property named prototype");var i=e.value=this.parseMethod(t,s,r);return"get"===e.kind&&0!==i.params.length&&this.raiseRecoverable(i.start,"getter should have no params"),"set"===e.kind&&1!==i.params.length&&this.raiseRecoverable(i.start,"setter should have exactly one param"),"set"===e.kind&&"RestElement"===i.params[0].type&&this.raiseRecoverable(i.params[0].start,"Setter cannot use rest params"),this.finishNode(e,"MethodDefinition")},X.parseClassField=function(e){if(te(e,"constructor")?this.raise(e.key.start,"Classes can't have a field named 'constructor'"):e.static&&te(e,"prototype")&&this.raise(e.key.start,"Classes can't have a static field named 'prototype'"),this.eat(b.eq)){var t=this.currentThisScope(),s=t.inClassFieldInit;t.inClassFieldInit=!0,e.value=this.parseMaybeAssign(),t.inClassFieldInit=s}else e.value=null;return this.semicolon(),this.finishNode(e,"PropertyDefinition")},X.parseClassStaticBlock=function(e){e.body=[];var t=this.labels;for(this.labels=[],this.enterScope(320);this.type!==b.braceR;){var s=this.parseStatement(null);e.body.push(s)}return this.next(),this.exitScope(),this.labels=t,this.finishNode(e,"StaticBlock")},X.parseClassId=function(e,t){this.type===b.name?(e.id=this.parseIdent(),t&&this.checkLValSimple(e.id,2,!1)):(!0===t&&this.unexpected(),e.id=null)},X.parseClassSuper=function(e){e.superClass=this.eat(b._extends)?this.parseExprSubscripts(null,!1):null},X.enterClassBody=function(){var e={declared:Object.create(null),used:[]};return this.privateNameStack.push(e),e.declared},X.exitClassBody=function(){var e=this.privateNameStack.pop(),t=e.declared,s=e.used;if(this.options.checkPrivateFields)for(var r=this.privateNameStack.length,n=0===r?null:this.privateNameStack[r-1],i=0;i=11&&(this.eatContextual("as")?(e.exported=this.parseModuleExportName(),this.checkExport(t,e.exported,this.lastTokStart)):e.exported=null),this.expectContextual("from"),this.type!==b.string&&this.unexpected(),e.source=this.parseExprAtom(),this.options.ecmaVersion>=16&&(e.attributes=this.parseWithClause()),this.semicolon(),this.finishNode(e,"ExportAllDeclaration")},X.parseExport=function(e,t){if(this.next(),this.eat(b.star))return this.parseExportAllDeclaration(e,t);if(this.eat(b._default))return this.checkExport(t,"default",this.lastTokStart),e.declaration=this.parseExportDefaultDeclaration(),this.finishNode(e,"ExportDefaultDeclaration");if(this.shouldParseExportStatement())e.declaration=this.parseExportDeclaration(e),"VariableDeclaration"===e.declaration.type?this.checkVariableExport(t,e.declaration.declarations):this.checkExport(t,e.declaration.id,e.declaration.id.start),e.specifiers=[],e.source=null;else{if(e.declaration=null,e.specifiers=this.parseExportSpecifiers(t),this.eatContextual("from"))this.type!==b.string&&this.unexpected(),e.source=this.parseExprAtom(),this.options.ecmaVersion>=16&&(e.attributes=this.parseWithClause());else{for(var s=0,r=e.specifiers;s=16&&(e.attributes=this.parseWithClause()),this.semicolon(),this.finishNode(e,"ImportDeclaration")},X.parseImportSpecifier=function(){var e=this.startNode();return e.imported=this.parseModuleExportName(),this.eatContextual("as")?e.local=this.parseIdent():(this.checkUnreserved(e.imported),e.local=e.imported),this.checkLValSimple(e.local,2),this.finishNode(e,"ImportSpecifier")},X.parseImportDefaultSpecifier=function(){var e=this.startNode();return e.local=this.parseIdent(),this.checkLValSimple(e.local,2),this.finishNode(e,"ImportDefaultSpecifier")},X.parseImportNamespaceSpecifier=function(){var e=this.startNode();return this.next(),this.expectContextual("as"),e.local=this.parseIdent(),this.checkLValSimple(e.local,2),this.finishNode(e,"ImportNamespaceSpecifier")},X.parseImportSpecifiers=function(){var e=[],t=!0;if(this.type===b.name&&(e.push(this.parseImportDefaultSpecifier()),!this.eat(b.comma)))return e;if(this.type===b.star)return e.push(this.parseImportNamespaceSpecifier()),e;for(this.expect(b.braceL);!this.eat(b.braceR);){if(t)t=!1;else if(this.expect(b.comma),this.afterTrailingComma(b.braceR))break;e.push(this.parseImportSpecifier())}return e},X.parseWithClause=function(){var e=[];if(!this.eat(b._with))return e;this.expect(b.braceL);for(var t={},s=!0;!this.eat(b.braceR);){if(s)s=!1;else if(this.expect(b.comma),this.afterTrailingComma(b.braceR))break;var r=this.parseImportAttribute(),n="Identifier"===r.key.type?r.key.name:r.key.value;C(t,n)&&this.raiseRecoverable(r.key.start,"Duplicate attribute key '"+n+"'"),t[n]=!0,e.push(r)}return e},X.parseImportAttribute=function(){var e=this.startNode();return e.key=this.type===b.string?this.parseExprAtom():this.parseIdent("never"!==this.options.allowReserved),this.expect(b.colon),this.type!==b.string&&this.unexpected(),e.value=this.parseExprAtom(),this.finishNode(e,"ImportAttribute")},X.parseModuleExportName=function(){if(this.options.ecmaVersion>=13&&this.type===b.string){var e=this.parseLiteral(this.value);return N.test(e.value)&&this.raise(e.start,"An export name cannot include a lone surrogate."),e}return this.parseIdent(!0)},X.adaptDirectivePrologue=function(e){for(var t=0;t=5&&"ExpressionStatement"===e.type&&"Literal"===e.expression.type&&"string"==typeof e.expression.value&&('"'===this.input[e.start]||"'"===this.input[e.start])};var se=B.prototype;se.toAssignable=function(e,t,s){if(this.options.ecmaVersion>=6&&e)switch(e.type){case"Identifier":this.inAsync&&"await"===e.name&&this.raise(e.start,"Cannot use 'await' as identifier inside an async function");break;case"ObjectPattern":case"ArrayPattern":case"AssignmentPattern":case"RestElement":break;case"ObjectExpression":e.type="ObjectPattern",s&&this.checkPatternErrors(s,!0);for(var r=0,n=e.properties;r=8&&!o&&"async"===u.name&&!this.canInsertSemicolon()&&this.eat(b._function))return this.overrideContext(ne.f_expr),this.parseFunction(this.startNodeAt(i,a),0,!1,!0,t);if(n&&!this.canInsertSemicolon()){if(this.eat(b.arrow))return this.parseArrowExpression(this.startNodeAt(i,a),[u],!1,t);if(this.options.ecmaVersion>=8&&"async"===u.name&&this.type===b.name&&!o&&(!this.potentialArrowInForAwait||"of"!==this.value||this.containsEsc))return u=this.parseIdent(!1),!this.canInsertSemicolon()&&this.eat(b.arrow)||this.unexpected(),this.parseArrowExpression(this.startNodeAt(i,a),[u],!0,t)}return u;case b.regexp:var l=this.value;return(r=this.parseLiteral(l.value)).regex={pattern:l.pattern,flags:l.flags},r;case b.num:case b.string:return this.parseLiteral(this.value);case b._null:case b._true:case b._false:return(r=this.startNode()).value=this.type===b._null?null:this.type===b._true,r.raw=this.type.keyword,this.next(),this.finishNode(r,"Literal");case b.parenL:var h=this.start,c=this.parseParenAndDistinguishExpression(n,t);return e&&(e.parenthesizedAssign<0&&!this.isSimpleAssignTarget(c)&&(e.parenthesizedAssign=h),e.parenthesizedBind<0&&(e.parenthesizedBind=h)),c;case b.bracketL:return r=this.startNode(),this.next(),r.elements=this.parseExprList(b.bracketR,!0,!0,e),this.finishNode(r,"ArrayExpression");case b.braceL:return this.overrideContext(ne.b_expr),this.parseObj(!1,e);case b._function:return r=this.startNode(),this.next(),this.parseFunction(r,0);case b._class:return this.parseClass(this.startNode(),!1);case b._new:return this.parseNew();case b.backQuote:return this.parseTemplate();case b._import:return this.options.ecmaVersion>=11?this.parseExprImport(s):this.unexpected();default:return this.parseExprAtomDefault()}},ae.parseExprAtomDefault=function(){this.unexpected()},ae.parseExprImport=function(e){var t=this.startNode();if(this.containsEsc&&this.raiseRecoverable(this.start,"Escape sequence in keyword import"),this.next(),this.type===b.parenL&&!e)return this.parseDynamicImport(t);if(this.type===b.dot){var s=this.startNodeAt(t.start,t.loc&&t.loc.start);return s.name="import",t.meta=this.finishNode(s,"Identifier"),this.parseImportMeta(t)}this.unexpected()},ae.parseDynamicImport=function(e){if(this.next(),e.source=this.parseMaybeAssign(),this.options.ecmaVersion>=16)this.eat(b.parenR)?e.options=null:(this.expect(b.comma),this.afterTrailingComma(b.parenR)?e.options=null:(e.options=this.parseMaybeAssign(),this.eat(b.parenR)||(this.expect(b.comma),this.afterTrailingComma(b.parenR)||this.unexpected())));else if(!this.eat(b.parenR)){var t=this.start;this.eat(b.comma)&&this.eat(b.parenR)?this.raiseRecoverable(t,"Trailing comma is not allowed in import()"):this.unexpected(t)}return this.finishNode(e,"ImportExpression")},ae.parseImportMeta=function(e){this.next();var t=this.containsEsc;return e.property=this.parseIdent(!0),"meta"!==e.property.name&&this.raiseRecoverable(e.property.start,"The only valid meta property for import is 'import.meta'"),t&&this.raiseRecoverable(e.start,"'import.meta' must not contain escaped characters"),"module"===this.options.sourceType||this.options.allowImportExportEverywhere||this.raiseRecoverable(e.start,"Cannot use 'import.meta' outside a module"),this.finishNode(e,"MetaProperty")},ae.parseLiteral=function(e){var t=this.startNode();return t.value=e,t.raw=this.input.slice(this.start,this.end),110===t.raw.charCodeAt(t.raw.length-1)&&(t.bigint=t.raw.slice(0,-1).replace(/_/g,"")),this.next(),this.finishNode(t,"Literal")},ae.parseParenExpression=function(){this.expect(b.parenL);var e=this.parseExpression();return this.expect(b.parenR),e},ae.shouldParseArrow=function(e){return!this.canInsertSemicolon()},ae.parseParenAndDistinguishExpression=function(e,t){var s,r=this.start,n=this.startLoc,i=this.options.ecmaVersion>=8;if(this.options.ecmaVersion>=6){this.next();var a,o=this.start,u=this.startLoc,l=[],h=!0,c=!1,p=new q,d=this.yieldPos,f=this.awaitPos;for(this.yieldPos=0,this.awaitPos=0;this.type!==b.parenR;){if(h?h=!1:this.expect(b.comma),i&&this.afterTrailingComma(b.parenR,!0)){c=!0;break}if(this.type===b.ellipsis){a=this.start,l.push(this.parseParenItem(this.parseRestBinding())),this.type===b.comma&&this.raiseRecoverable(this.start,"Comma is not permitted after the rest element");break}l.push(this.parseMaybeAssign(!1,p,this.parseParenItem))}var m=this.lastTokEnd,g=this.lastTokEndLoc;if(this.expect(b.parenR),e&&this.shouldParseArrow(l)&&this.eat(b.arrow))return this.checkPatternErrors(p,!1),this.checkYieldAwaitInDefaultParams(),this.yieldPos=d,this.awaitPos=f,this.parseParenArrowList(r,n,l,t);l.length&&!c||this.unexpected(this.lastTokStart),a&&this.unexpected(a),this.checkExpressionErrors(p,!0),this.yieldPos=d||this.yieldPos,this.awaitPos=f||this.awaitPos,l.length>1?((s=this.startNodeAt(o,u)).expressions=l,this.finishNodeAt(s,"SequenceExpression",m,g)):s=l[0]}else s=this.parseParenExpression();if(this.options.preserveParens){var x=this.startNodeAt(r,n);return x.expression=s,this.finishNode(x,"ParenthesizedExpression")}return s},ae.parseParenItem=function(e){return e},ae.parseParenArrowList=function(e,t,s,r){return this.parseArrowExpression(this.startNodeAt(e,t),s,!1,r)};var le=[];ae.parseNew=function(){this.containsEsc&&this.raiseRecoverable(this.start,"Escape sequence in keyword new");var e=this.startNode();if(this.next(),this.options.ecmaVersion>=6&&this.type===b.dot){var t=this.startNodeAt(e.start,e.loc&&e.loc.start);t.name="new",e.meta=this.finishNode(t,"Identifier"),this.next();var s=this.containsEsc;return e.property=this.parseIdent(!0),"target"!==e.property.name&&this.raiseRecoverable(e.property.start,"The only valid meta property for new is 'new.target'"),s&&this.raiseRecoverable(e.start,"'new.target' must not contain escaped characters"),this.allowNewDotTarget||this.raiseRecoverable(e.start,"'new.target' can only be used in functions and class static block"),this.finishNode(e,"MetaProperty")}var r=this.start,n=this.startLoc;return e.callee=this.parseSubscripts(this.parseExprAtom(null,!1,!0),r,n,!0,!1),this.eat(b.parenL)?e.arguments=this.parseExprList(b.parenR,this.options.ecmaVersion>=8,!1):e.arguments=le,this.finishNode(e,"NewExpression")},ae.parseTemplateElement=function(e){var t=e.isTagged,s=this.startNode();return this.type===b.invalidTemplate?(t||this.raiseRecoverable(this.start,"Bad escape sequence in untagged template literal"),s.value={raw:this.value.replace(/\r\n?/g,"\n"),cooked:null}):s.value={raw:this.input.slice(this.start,this.end).replace(/\r\n?/g,"\n"),cooked:this.value},this.next(),s.tail=this.type===b.backQuote,this.finishNode(s,"TemplateElement")},ae.parseTemplate=function(e){void 0===e&&(e={});var t=e.isTagged;void 0===t&&(t=!1);var s=this.startNode();this.next(),s.expressions=[];var r=this.parseTemplateElement({isTagged:t});for(s.quasis=[r];!r.tail;)this.type===b.eof&&this.raise(this.pos,"Unterminated template literal"),this.expect(b.dollarBraceL),s.expressions.push(this.parseExpression()),this.expect(b.braceR),s.quasis.push(r=this.parseTemplateElement({isTagged:t}));return this.next(),this.finishNode(s,"TemplateLiteral")},ae.isAsyncProp=function(e){return!e.computed&&"Identifier"===e.key.type&&"async"===e.key.name&&(this.type===b.name||this.type===b.num||this.type===b.string||this.type===b.bracketL||this.type.keyword||this.options.ecmaVersion>=9&&this.type===b.star)&&!v.test(this.input.slice(this.lastTokEnd,this.start))},ae.parseObj=function(e,t){var s=this.startNode(),r=!0,n={};for(s.properties=[],this.next();!this.eat(b.braceR);){if(r)r=!1;else if(this.expect(b.comma),this.options.ecmaVersion>=5&&this.afterTrailingComma(b.braceR))break;var i=this.parseProperty(e,t);e||this.checkPropClash(i,n,t),s.properties.push(i)}return this.finishNode(s,e?"ObjectPattern":"ObjectExpression")},ae.parseProperty=function(e,t){var s,r,n,i,a=this.startNode();if(this.options.ecmaVersion>=9&&this.eat(b.ellipsis))return e?(a.argument=this.parseIdent(!1),this.type===b.comma&&this.raiseRecoverable(this.start,"Comma is not permitted after the rest element"),this.finishNode(a,"RestElement")):(a.argument=this.parseMaybeAssign(!1,t),this.type===b.comma&&t&&t.trailingComma<0&&(t.trailingComma=this.start),this.finishNode(a,"SpreadElement"));this.options.ecmaVersion>=6&&(a.method=!1,a.shorthand=!1,(e||t)&&(n=this.start,i=this.startLoc),e||(s=this.eat(b.star)));var o=this.containsEsc;return this.parsePropertyName(a),!e&&!o&&this.options.ecmaVersion>=8&&!s&&this.isAsyncProp(a)?(r=!0,s=this.options.ecmaVersion>=9&&this.eat(b.star),this.parsePropertyName(a)):r=!1,this.parsePropertyValue(a,e,s,r,n,i,t,o),this.finishNode(a,"Property")},ae.parseGetterSetter=function(e){e.kind=e.key.name,this.parsePropertyName(e),e.value=this.parseMethod(!1);var t="get"===e.kind?0:1;if(e.value.params.length!==t){var s=e.value.start;"get"===e.kind?this.raiseRecoverable(s,"getter should have no params"):this.raiseRecoverable(s,"setter should have exactly one param")}else"set"===e.kind&&"RestElement"===e.value.params[0].type&&this.raiseRecoverable(e.value.params[0].start,"Setter cannot use rest params")},ae.parsePropertyValue=function(e,t,s,r,n,i,a,o){(s||r)&&this.type===b.colon&&this.unexpected(),this.eat(b.colon)?(e.value=t?this.parseMaybeDefault(this.start,this.startLoc):this.parseMaybeAssign(!1,a),e.kind="init"):this.options.ecmaVersion>=6&&this.type===b.parenL?(t&&this.unexpected(),e.kind="init",e.method=!0,e.value=this.parseMethod(s,r)):t||o||!(this.options.ecmaVersion>=5)||e.computed||"Identifier"!==e.key.type||"get"!==e.key.name&&"set"!==e.key.name||this.type===b.comma||this.type===b.braceR||this.type===b.eq?this.options.ecmaVersion>=6&&!e.computed&&"Identifier"===e.key.type?((s||r)&&this.unexpected(),this.checkUnreserved(e.key),"await"!==e.key.name||this.awaitIdentPos||(this.awaitIdentPos=n),e.kind="init",t?e.value=this.parseMaybeDefault(n,i,this.copyNode(e.key)):this.type===b.eq&&a?(a.shorthandAssign<0&&(a.shorthandAssign=this.start),e.value=this.parseMaybeDefault(n,i,this.copyNode(e.key))):e.value=this.copyNode(e.key),e.shorthand=!0):this.unexpected():((s||r)&&this.unexpected(),this.parseGetterSetter(e))},ae.parsePropertyName=function(e){if(this.options.ecmaVersion>=6){if(this.eat(b.bracketL))return e.computed=!0,e.key=this.parseMaybeAssign(),this.expect(b.bracketR),e.key;e.computed=!1}return e.key=this.type===b.num||this.type===b.string?this.parseExprAtom():this.parseIdent("never"!==this.options.allowReserved)},ae.initFunction=function(e){e.id=null,this.options.ecmaVersion>=6&&(e.generator=e.expression=!1),this.options.ecmaVersion>=8&&(e.async=!1)},ae.parseMethod=function(e,t,s){var r=this.startNode(),n=this.yieldPos,i=this.awaitPos,a=this.awaitIdentPos;return this.initFunction(r),this.options.ecmaVersion>=6&&(r.generator=e),this.options.ecmaVersion>=8&&(r.async=!!t),this.yieldPos=0,this.awaitPos=0,this.awaitIdentPos=0,this.enterScope(64|U(t,r.generator)|(s?128:0)),this.expect(b.parenL),r.params=this.parseBindingList(b.parenR,!1,this.options.ecmaVersion>=8),this.checkYieldAwaitInDefaultParams(),this.parseFunctionBody(r,!1,!0,!1),this.yieldPos=n,this.awaitPos=i,this.awaitIdentPos=a,this.finishNode(r,"FunctionExpression")},ae.parseArrowExpression=function(e,t,s,r){var n=this.yieldPos,i=this.awaitPos,a=this.awaitIdentPos;return this.enterScope(16|U(s,!1)),this.initFunction(e),this.options.ecmaVersion>=8&&(e.async=!!s),this.yieldPos=0,this.awaitPos=0,this.awaitIdentPos=0,e.params=this.toAssignableList(t,!0),this.parseFunctionBody(e,!0,!1,r),this.yieldPos=n,this.awaitPos=i,this.awaitIdentPos=a,this.finishNode(e,"ArrowFunctionExpression")},ae.parseFunctionBody=function(e,t,s,r){var n=t&&this.type!==b.braceL,i=this.strict,a=!1;if(n)e.body=this.parseMaybeAssign(r),e.expression=!0,this.checkParams(e,!1);else{var o=this.options.ecmaVersion>=7&&!this.isSimpleParamList(e.params);i&&!o||(a=this.strictDirective(this.end))&&o&&this.raiseRecoverable(e.start,"Illegal 'use strict' directive in function with non-simple parameter list");var u=this.labels;this.labels=[],a&&(this.strict=!0),this.checkParams(e,!i&&!a&&!t&&!s&&this.isSimpleParamList(e.params)),this.strict&&e.id&&this.checkLValSimple(e.id,5),e.body=this.parseBlock(!1,void 0,a&&!i),e.expression=!1,this.adaptDirectivePrologue(e.body.body),this.labels=u}this.exitScope()},ae.isSimpleParamList=function(e){for(var t=0,s=e;t-1||n.functions.indexOf(e)>-1||n.var.indexOf(e)>-1,n.lexical.push(e),this.inModule&&1&n.flags&&delete this.undefinedExports[e]}else if(4===t)this.currentScope().lexical.push(e);else if(3===t){var i=this.currentScope();r=this.treatFunctionsAsVar?i.lexical.indexOf(e)>-1:i.lexical.indexOf(e)>-1||i.var.indexOf(e)>-1,i.functions.push(e)}else for(var a=this.scopeStack.length-1;a>=0;--a){var o=this.scopeStack[a];if(o.lexical.indexOf(e)>-1&&!(32&o.flags&&o.lexical[0]===e)||!this.treatFunctionsAsVarInScope(o)&&o.functions.indexOf(e)>-1){r=!0;break}if(o.var.push(e),this.inModule&&1&o.flags&&delete this.undefinedExports[e],259&o.flags)break}r&&this.raiseRecoverable(s,"Identifier '"+e+"' has already been declared")},ce.checkLocalExport=function(e){-1===this.scopeStack[0].lexical.indexOf(e.name)&&-1===this.scopeStack[0].var.indexOf(e.name)&&(this.undefinedExports[e.name]=e)},ce.currentScope=function(){return this.scopeStack[this.scopeStack.length-1]},ce.currentVarScope=function(){for(var e=this.scopeStack.length-1;;e--){var t=this.scopeStack[e];if(259&t.flags)return t}},ce.currentThisScope=function(){for(var e=this.scopeStack.length-1;;e--){var t=this.scopeStack[e];if(259&t.flags&&!(16&t.flags))return t}};var de=function(e,t,s){this.type="",this.start=t,this.end=0,e.options.locations&&(this.loc=new M(e,s)),e.options.directSourceFile&&(this.sourceFile=e.options.directSourceFile),e.options.ranges&&(this.range=[t,0])},fe=B.prototype;function me(e,t,s,r){return e.type=t,e.end=s,this.options.locations&&(e.loc.end=r),this.options.ranges&&(e.range[1]=s),e}fe.startNode=function(){return new de(this,this.start,this.startLoc)},fe.startNodeAt=function(e,t){return new de(this,e,t)},fe.finishNode=function(e,t){return me.call(this,e,t,this.lastTokEnd,this.lastTokEndLoc)},fe.finishNodeAt=function(e,t,s,r){return me.call(this,e,t,s,r)},fe.copyNode=function(e){var t=new de(this,e.start,this.startLoc);for(var s in e)t[s]=e[s];return t};var ge="ASCII ASCII_Hex_Digit AHex Alphabetic Alpha Any Assigned Bidi_Control Bidi_C Bidi_Mirrored Bidi_M Case_Ignorable CI Cased Changes_When_Casefolded CWCF Changes_When_Casemapped CWCM Changes_When_Lowercased CWL Changes_When_NFKC_Casefolded CWKCF Changes_When_Titlecased CWT Changes_When_Uppercased CWU Dash Default_Ignorable_Code_Point DI Deprecated Dep Diacritic Dia Emoji Emoji_Component Emoji_Modifier Emoji_Modifier_Base Emoji_Presentation Extender Ext Grapheme_Base Gr_Base Grapheme_Extend Gr_Ext Hex_Digit Hex IDS_Binary_Operator IDSB IDS_Trinary_Operator IDST ID_Continue IDC ID_Start IDS Ideographic Ideo Join_Control Join_C Logical_Order_Exception LOE Lowercase Lower Math Noncharacter_Code_Point NChar Pattern_Syntax Pat_Syn Pattern_White_Space Pat_WS Quotation_Mark QMark Radical Regional_Indicator RI Sentence_Terminal STerm Soft_Dotted SD Terminal_Punctuation Term Unified_Ideograph UIdeo Uppercase Upper Variation_Selector VS White_Space space XID_Continue XIDC XID_Start XIDS",xe=ge+" Extended_Pictographic",ye=xe+" EBase EComp EMod EPres ExtPict",be={9:ge,10:xe,11:xe,12:ye,13:ye,14:ye},ve={9:"",10:"",11:"",12:"",13:"",14:"Basic_Emoji Emoji_Keycap_Sequence RGI_Emoji_Modifier_Sequence RGI_Emoji_Flag_Sequence RGI_Emoji_Tag_Sequence RGI_Emoji_ZWJ_Sequence RGI_Emoji"},Se="Cased_Letter LC Close_Punctuation Pe Connector_Punctuation Pc Control Cc cntrl Currency_Symbol Sc Dash_Punctuation Pd Decimal_Number Nd digit Enclosing_Mark Me Final_Punctuation Pf Format Cf Initial_Punctuation Pi Letter L Letter_Number Nl Line_Separator Zl Lowercase_Letter Ll Mark M Combining_Mark Math_Symbol Sm Modifier_Letter Lm Modifier_Symbol Sk Nonspacing_Mark Mn Number N Open_Punctuation Ps Other C Other_Letter Lo Other_Number No Other_Punctuation Po Other_Symbol So Paragraph_Separator Zp Private_Use Co Punctuation P punct Separator Z Space_Separator Zs Spacing_Mark Mc Surrogate Cs Symbol S Titlecase_Letter Lt Unassigned Cn Uppercase_Letter Lu",Te="Adlam Adlm Ahom Anatolian_Hieroglyphs Hluw Arabic Arab Armenian Armn Avestan Avst Balinese Bali Bamum Bamu Bassa_Vah Bass Batak Batk Bengali Beng Bhaiksuki Bhks Bopomofo Bopo Brahmi Brah Braille Brai Buginese Bugi Buhid Buhd Canadian_Aboriginal Cans Carian Cari Caucasian_Albanian Aghb Chakma Cakm Cham Cham Cherokee Cher Common Zyyy Coptic Copt Qaac Cuneiform Xsux Cypriot Cprt Cyrillic Cyrl Deseret Dsrt Devanagari Deva Duployan Dupl Egyptian_Hieroglyphs Egyp Elbasan Elba Ethiopic Ethi Georgian Geor Glagolitic Glag Gothic Goth Grantha Gran Greek Grek Gujarati Gujr Gurmukhi Guru Han Hani Hangul Hang Hanunoo Hano Hatran Hatr Hebrew Hebr Hiragana Hira Imperial_Aramaic Armi Inherited Zinh Qaai Inscriptional_Pahlavi Phli Inscriptional_Parthian Prti Javanese Java Kaithi Kthi Kannada Knda Katakana Kana Kayah_Li Kali Kharoshthi Khar Khmer Khmr Khojki Khoj Khudawadi Sind Lao Laoo Latin Latn Lepcha Lepc Limbu Limb Linear_A Lina Linear_B Linb Lisu Lisu Lycian Lyci Lydian Lydi Mahajani Mahj Malayalam Mlym Mandaic Mand Manichaean Mani Marchen Marc Masaram_Gondi Gonm Meetei_Mayek Mtei Mende_Kikakui Mend Meroitic_Cursive Merc Meroitic_Hieroglyphs Mero Miao Plrd Modi Mongolian Mong Mro Mroo Multani Mult Myanmar Mymr Nabataean Nbat New_Tai_Lue Talu Newa Newa Nko Nkoo Nushu Nshu Ogham Ogam Ol_Chiki Olck Old_Hungarian Hung Old_Italic Ital Old_North_Arabian Narb Old_Permic Perm Old_Persian Xpeo Old_South_Arabian Sarb Old_Turkic Orkh Oriya Orya Osage Osge Osmanya Osma Pahawh_Hmong Hmng Palmyrene Palm Pau_Cin_Hau Pauc Phags_Pa Phag Phoenician Phnx Psalter_Pahlavi Phlp Rejang Rjng Runic Runr Samaritan Samr Saurashtra Saur Sharada Shrd Shavian Shaw Siddham Sidd SignWriting Sgnw Sinhala Sinh Sora_Sompeng Sora Soyombo Soyo Sundanese Sund Syloti_Nagri Sylo Syriac Syrc Tagalog Tglg Tagbanwa Tagb Tai_Le Tale Tai_Tham Lana Tai_Viet Tavt Takri Takr Tamil Taml Tangut Tang Telugu Telu Thaana Thaa Thai Thai Tibetan Tibt Tifinagh Tfng Tirhuta Tirh Ugaritic Ugar Vai Vaii Warang_Citi Wara Yi Yiii Zanabazar_Square Zanb",Ae=Te+" Dogra Dogr Gunjala_Gondi Gong Hanifi_Rohingya Rohg Makasar Maka Medefaidrin Medf Old_Sogdian Sogo Sogdian Sogd",we=Ae+" Elymaic Elym Nandinagari Nand Nyiakeng_Puachue_Hmong Hmnp Wancho Wcho",Ee=we+" Chorasmian Chrs Diak Dives_Akuru Khitan_Small_Script Kits Yezi Yezidi",_e=Ee+" Cypro_Minoan Cpmn Old_Uyghur Ougr Tangsa Tnsa Toto Vithkuqi Vith",Ie={9:Te,10:Ae,11:we,12:Ee,13:_e,14:_e+" Gara Garay Gukh Gurung_Khema Hrkt Katakana_Or_Hiragana Kawi Kirat_Rai Krai Nag_Mundari Nagm Ol_Onal Onao Sunu Sunuwar Todhri Todr Tulu_Tigalari Tutg Unknown Zzzz"},ke={};function Ce(e){var t=ke[e]={binary:F(be[e]+" "+Se),binaryOfStrings:F(ve[e]),nonBinary:{General_Category:F(Se),Script:F(Ie[e])}};t.nonBinary.Script_Extensions=t.nonBinary.Script,t.nonBinary.gc=t.nonBinary.General_Category,t.nonBinary.sc=t.nonBinary.Script,t.nonBinary.scx=t.nonBinary.Script_Extensions}for(var Le=0,De=[9,10,11,12,13,14];Le=6?"uy":"")+(e.options.ecmaVersion>=9?"s":"")+(e.options.ecmaVersion>=13?"d":"")+(e.options.ecmaVersion>=15?"v":""),this.unicodeProperties=ke[e.options.ecmaVersion>=14?14:e.options.ecmaVersion],this.source="",this.flags="",this.start=0,this.switchU=!1,this.switchV=!1,this.switchN=!1,this.pos=0,this.lastIntValue=0,this.lastStringValue="",this.lastAssertionIsQuantifiable=!1,this.numCapturingParens=0,this.maxBackReference=0,this.groupNames=Object.create(null),this.backReferenceNames=[],this.branchID=null};function Re(e){return 105===e||109===e||115===e}function Me(e){return 36===e||e>=40&&e<=43||46===e||63===e||e>=91&&e<=94||e>=123&&e<=125}function Ge(e){return e>=65&&e<=90||e>=97&&e<=122}function Oe(e){return Ge(e)||95===e}function Ve(e){return Oe(e)||Pe(e)}function Pe(e){return e>=48&&e<=57}function ze(e){return e>=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102}function Ue(e){return e>=65&&e<=70?e-65+10:e>=97&&e<=102?e-97+10:e-48}function Be(e){return e>=48&&e<=55}Ne.prototype.reset=function(e,t,s){var r=-1!==s.indexOf("v"),n=-1!==s.indexOf("u");this.start=0|e,this.source=t+"",this.flags=s,r&&this.parser.options.ecmaVersion>=15?(this.switchU=!0,this.switchV=!0,this.switchN=!0):(this.switchU=n&&this.parser.options.ecmaVersion>=6,this.switchV=!1,this.switchN=n&&this.parser.options.ecmaVersion>=9)},Ne.prototype.raise=function(e){this.parser.raiseRecoverable(this.start,"Invalid regular expression: /"+this.source+"/: "+e)},Ne.prototype.at=function(e,t){void 0===t&&(t=!1);var s=this.source,r=s.length;if(e>=r)return-1;var n=s.charCodeAt(e);if(!t&&!this.switchU||n<=55295||n>=57344||e+1>=r)return n;var i=s.charCodeAt(e+1);return i>=56320&&i<=57343?(n<<10)+i-56613888:n},Ne.prototype.nextIndex=function(e,t){void 0===t&&(t=!1);var s=this.source,r=s.length;if(e>=r)return r;var n,i=s.charCodeAt(e);return!t&&!this.switchU||i<=55295||i>=57344||e+1>=r||(n=s.charCodeAt(e+1))<56320||n>57343?e+1:e+2},Ne.prototype.current=function(e){return void 0===e&&(e=!1),this.at(this.pos,e)},Ne.prototype.lookahead=function(e){return void 0===e&&(e=!1),this.at(this.nextIndex(this.pos,e),e)},Ne.prototype.advance=function(e){void 0===e&&(e=!1),this.pos=this.nextIndex(this.pos,e)},Ne.prototype.eat=function(e,t){return void 0===t&&(t=!1),this.current(t)===e&&(this.advance(t),!0)},Ne.prototype.eatChars=function(e,t){void 0===t&&(t=!1);for(var s=this.pos,r=0,n=e;r-1&&this.raise(e.start,"Duplicate regular expression flag"),"u"===a&&(r=!0),"v"===a&&(n=!0)}this.options.ecmaVersion>=15&&r&&n&&this.raise(e.start,"Invalid regular expression flag")},Fe.validateRegExpPattern=function(e){this.regexp_pattern(e),!e.switchN&&this.options.ecmaVersion>=9&&function(e){for(var t in e)return!0;return!1}(e.groupNames)&&(e.switchN=!0,this.regexp_pattern(e))},Fe.regexp_pattern=function(e){e.pos=0,e.lastIntValue=0,e.lastStringValue="",e.lastAssertionIsQuantifiable=!1,e.numCapturingParens=0,e.maxBackReference=0,e.groupNames=Object.create(null),e.backReferenceNames.length=0,e.branchID=null,this.regexp_disjunction(e),e.pos!==e.source.length&&(e.eat(41)&&e.raise("Unmatched ')'"),(e.eat(93)||e.eat(125))&&e.raise("Lone quantifier brackets")),e.maxBackReference>e.numCapturingParens&&e.raise("Invalid escape");for(var t=0,s=e.backReferenceNames;t=16;for(t&&(e.branchID=new $e(e.branchID,null)),this.regexp_alternative(e);e.eat(124);)t&&(e.branchID=e.branchID.sibling()),this.regexp_alternative(e);t&&(e.branchID=e.branchID.parent),this.regexp_eatQuantifier(e,!0)&&e.raise("Nothing to repeat"),e.eat(123)&&e.raise("Lone quantifier brackets")},Fe.regexp_alternative=function(e){for(;e.pos=9&&(s=e.eat(60)),e.eat(61)||e.eat(33))return this.regexp_disjunction(e),e.eat(41)||e.raise("Unterminated group"),e.lastAssertionIsQuantifiable=!s,!0}return e.pos=t,!1},Fe.regexp_eatQuantifier=function(e,t){return void 0===t&&(t=!1),!!this.regexp_eatQuantifierPrefix(e,t)&&(e.eat(63),!0)},Fe.regexp_eatQuantifierPrefix=function(e,t){return e.eat(42)||e.eat(43)||e.eat(63)||this.regexp_eatBracedQuantifier(e,t)},Fe.regexp_eatBracedQuantifier=function(e,t){var s=e.pos;if(e.eat(123)){var r=0,n=-1;if(this.regexp_eatDecimalDigits(e)&&(r=e.lastIntValue,e.eat(44)&&this.regexp_eatDecimalDigits(e)&&(n=e.lastIntValue),e.eat(125)))return-1!==n&&n=16){var s=this.regexp_eatModifiers(e),r=e.eat(45);if(s||r){for(var n=0;n-1&&e.raise("Duplicate regular expression modifiers")}if(r){var a=this.regexp_eatModifiers(e);s||a||58!==e.current()||e.raise("Invalid regular expression modifiers");for(var o=0;o-1||s.indexOf(u)>-1)&&e.raise("Duplicate regular expression modifiers")}}}}if(e.eat(58)){if(this.regexp_disjunction(e),e.eat(41))return!0;e.raise("Unterminated group")}}e.pos=t}return!1},Fe.regexp_eatCapturingGroup=function(e){if(e.eat(40)){if(this.options.ecmaVersion>=9?this.regexp_groupSpecifier(e):63===e.current()&&e.raise("Invalid group"),this.regexp_disjunction(e),e.eat(41))return e.numCapturingParens+=1,!0;e.raise("Unterminated group")}return!1},Fe.regexp_eatModifiers=function(e){for(var t="",s=0;-1!==(s=e.current())&&Re(s);)t+=$(s),e.advance();return t},Fe.regexp_eatExtendedAtom=function(e){return e.eat(46)||this.regexp_eatReverseSolidusAtomEscape(e)||this.regexp_eatCharacterClass(e)||this.regexp_eatUncapturingGroup(e)||this.regexp_eatCapturingGroup(e)||this.regexp_eatInvalidBracedQuantifier(e)||this.regexp_eatExtendedPatternCharacter(e)},Fe.regexp_eatInvalidBracedQuantifier=function(e){return this.regexp_eatBracedQuantifier(e,!0)&&e.raise("Nothing to repeat"),!1},Fe.regexp_eatSyntaxCharacter=function(e){var t=e.current();return!!Me(t)&&(e.lastIntValue=t,e.advance(),!0)},Fe.regexp_eatPatternCharacters=function(e){for(var t=e.pos,s=0;-1!==(s=e.current())&&!Me(s);)e.advance();return e.pos!==t},Fe.regexp_eatExtendedPatternCharacter=function(e){var t=e.current();return!(-1===t||36===t||t>=40&&t<=43||46===t||63===t||91===t||94===t||124===t||(e.advance(),0))},Fe.regexp_groupSpecifier=function(e){if(e.eat(63)){this.regexp_eatGroupName(e)||e.raise("Invalid group");var t=this.options.ecmaVersion>=16,s=e.groupNames[e.lastStringValue];if(s)if(t)for(var r=0,n=s;r=11,r=e.current(s);return e.advance(s),92===r&&this.regexp_eatRegExpUnicodeEscapeSequence(e,s)&&(r=e.lastIntValue),function(e){return c(e,!0)||36===e||95===e}(r)?(e.lastIntValue=r,!0):(e.pos=t,!1)},Fe.regexp_eatRegExpIdentifierPart=function(e){var t=e.pos,s=this.options.ecmaVersion>=11,r=e.current(s);return e.advance(s),92===r&&this.regexp_eatRegExpUnicodeEscapeSequence(e,s)&&(r=e.lastIntValue),function(e){return p(e,!0)||36===e||95===e||8204===e||8205===e}(r)?(e.lastIntValue=r,!0):(e.pos=t,!1)},Fe.regexp_eatAtomEscape=function(e){return!!(this.regexp_eatBackReference(e)||this.regexp_eatCharacterClassEscape(e)||this.regexp_eatCharacterEscape(e)||e.switchN&&this.regexp_eatKGroupName(e))||(e.switchU&&(99===e.current()&&e.raise("Invalid unicode escape"),e.raise("Invalid escape")),!1)},Fe.regexp_eatBackReference=function(e){var t=e.pos;if(this.regexp_eatDecimalEscape(e)){var s=e.lastIntValue;if(e.switchU)return s>e.maxBackReference&&(e.maxBackReference=s),!0;if(s<=e.numCapturingParens)return!0;e.pos=t}return!1},Fe.regexp_eatKGroupName=function(e){if(e.eat(107)){if(this.regexp_eatGroupName(e))return e.backReferenceNames.push(e.lastStringValue),!0;e.raise("Invalid named reference")}return!1},Fe.regexp_eatCharacterEscape=function(e){return this.regexp_eatControlEscape(e)||this.regexp_eatCControlLetter(e)||this.regexp_eatZero(e)||this.regexp_eatHexEscapeSequence(e)||this.regexp_eatRegExpUnicodeEscapeSequence(e,!1)||!e.switchU&&this.regexp_eatLegacyOctalEscapeSequence(e)||this.regexp_eatIdentityEscape(e)},Fe.regexp_eatCControlLetter=function(e){var t=e.pos;if(e.eat(99)){if(this.regexp_eatControlLetter(e))return!0;e.pos=t}return!1},Fe.regexp_eatZero=function(e){return 48===e.current()&&!Pe(e.lookahead())&&(e.lastIntValue=0,e.advance(),!0)},Fe.regexp_eatControlEscape=function(e){var t=e.current();return 116===t?(e.lastIntValue=9,e.advance(),!0):110===t?(e.lastIntValue=10,e.advance(),!0):118===t?(e.lastIntValue=11,e.advance(),!0):102===t?(e.lastIntValue=12,e.advance(),!0):114===t&&(e.lastIntValue=13,e.advance(),!0)},Fe.regexp_eatControlLetter=function(e){var t=e.current();return!!Ge(t)&&(e.lastIntValue=t%32,e.advance(),!0)},Fe.regexp_eatRegExpUnicodeEscapeSequence=function(e,t){void 0===t&&(t=!1);var s,r=e.pos,n=t||e.switchU;if(e.eat(117)){if(this.regexp_eatFixedHexDigits(e,4)){var i=e.lastIntValue;if(n&&i>=55296&&i<=56319){var a=e.pos;if(e.eat(92)&&e.eat(117)&&this.regexp_eatFixedHexDigits(e,4)){var o=e.lastIntValue;if(o>=56320&&o<=57343)return e.lastIntValue=1024*(i-55296)+(o-56320)+65536,!0}e.pos=a,e.lastIntValue=i}return!0}if(n&&e.eat(123)&&this.regexp_eatHexDigits(e)&&e.eat(125)&&(s=e.lastIntValue)>=0&&s<=1114111)return!0;n&&e.raise("Invalid unicode escape"),e.pos=r}return!1},Fe.regexp_eatIdentityEscape=function(e){if(e.switchU)return!!this.regexp_eatSyntaxCharacter(e)||!!e.eat(47)&&(e.lastIntValue=47,!0);var t=e.current();return!(99===t||e.switchN&&107===t||(e.lastIntValue=t,e.advance(),0))},Fe.regexp_eatDecimalEscape=function(e){e.lastIntValue=0;var t=e.current();if(t>=49&&t<=57){do{e.lastIntValue=10*e.lastIntValue+(t-48),e.advance()}while((t=e.current())>=48&&t<=57);return!0}return!1},Fe.regexp_eatCharacterClassEscape=function(e){var t=e.current();if(function(e){return 100===e||68===e||115===e||83===e||119===e||87===e}(t))return e.lastIntValue=-1,e.advance(),1;var s=!1;if(e.switchU&&this.options.ecmaVersion>=9&&((s=80===t)||112===t)){var r;if(e.lastIntValue=-1,e.advance(),e.eat(123)&&(r=this.regexp_eatUnicodePropertyValueExpression(e))&&e.eat(125))return s&&2===r&&e.raise("Invalid property name"),r;e.raise("Invalid property name")}return 0},Fe.regexp_eatUnicodePropertyValueExpression=function(e){var t=e.pos;if(this.regexp_eatUnicodePropertyName(e)&&e.eat(61)){var s=e.lastStringValue;if(this.regexp_eatUnicodePropertyValue(e)){var r=e.lastStringValue;return this.regexp_validateUnicodePropertyNameAndValue(e,s,r),1}}if(e.pos=t,this.regexp_eatLoneUnicodePropertyNameOrValue(e)){var n=e.lastStringValue;return this.regexp_validateUnicodePropertyNameOrValue(e,n)}return 0},Fe.regexp_validateUnicodePropertyNameAndValue=function(e,t,s){C(e.unicodeProperties.nonBinary,t)||e.raise("Invalid property name"),e.unicodeProperties.nonBinary[t].test(s)||e.raise("Invalid property value")},Fe.regexp_validateUnicodePropertyNameOrValue=function(e,t){return e.unicodeProperties.binary.test(t)?1:e.switchV&&e.unicodeProperties.binaryOfStrings.test(t)?2:void e.raise("Invalid property name")},Fe.regexp_eatUnicodePropertyName=function(e){var t=0;for(e.lastStringValue="";Oe(t=e.current());)e.lastStringValue+=$(t),e.advance();return""!==e.lastStringValue},Fe.regexp_eatUnicodePropertyValue=function(e){var t=0;for(e.lastStringValue="";Ve(t=e.current());)e.lastStringValue+=$(t),e.advance();return""!==e.lastStringValue},Fe.regexp_eatLoneUnicodePropertyNameOrValue=function(e){return this.regexp_eatUnicodePropertyValue(e)},Fe.regexp_eatCharacterClass=function(e){if(e.eat(91)){var t=e.eat(94),s=this.regexp_classContents(e);return e.eat(93)||e.raise("Unterminated character class"),t&&2===s&&e.raise("Negated character class may contain strings"),!0}return!1},Fe.regexp_classContents=function(e){return 93===e.current()?1:e.switchV?this.regexp_classSetExpression(e):(this.regexp_nonEmptyClassRanges(e),1)},Fe.regexp_nonEmptyClassRanges=function(e){for(;this.regexp_eatClassAtom(e);){var t=e.lastIntValue;if(e.eat(45)&&this.regexp_eatClassAtom(e)){var s=e.lastIntValue;!e.switchU||-1!==t&&-1!==s||e.raise("Invalid character class"),-1!==t&&-1!==s&&t>s&&e.raise("Range out of order in character class")}}},Fe.regexp_eatClassAtom=function(e){var t=e.pos;if(e.eat(92)){if(this.regexp_eatClassEscape(e))return!0;if(e.switchU){var s=e.current();(99===s||Be(s))&&e.raise("Invalid class escape"),e.raise("Invalid escape")}e.pos=t}var r=e.current();return 93!==r&&(e.lastIntValue=r,e.advance(),!0)},Fe.regexp_eatClassEscape=function(e){var t=e.pos;if(e.eat(98))return e.lastIntValue=8,!0;if(e.switchU&&e.eat(45))return e.lastIntValue=45,!0;if(!e.switchU&&e.eat(99)){if(this.regexp_eatClassControlLetter(e))return!0;e.pos=t}return this.regexp_eatCharacterClassEscape(e)||this.regexp_eatCharacterEscape(e)},Fe.regexp_classSetExpression=function(e){var t,s=1;if(this.regexp_eatClassSetRange(e));else if(t=this.regexp_eatClassSetOperand(e)){2===t&&(s=2);for(var r=e.pos;e.eatChars([38,38]);)38!==e.current()&&(t=this.regexp_eatClassSetOperand(e))?2!==t&&(s=1):e.raise("Invalid character in character class");if(r!==e.pos)return s;for(;e.eatChars([45,45]);)this.regexp_eatClassSetOperand(e)||e.raise("Invalid character in character class");if(r!==e.pos)return s}else e.raise("Invalid character in character class");for(;;)if(!this.regexp_eatClassSetRange(e)){if(!(t=this.regexp_eatClassSetOperand(e)))return s;2===t&&(s=2)}},Fe.regexp_eatClassSetRange=function(e){var t=e.pos;if(this.regexp_eatClassSetCharacter(e)){var s=e.lastIntValue;if(e.eat(45)&&this.regexp_eatClassSetCharacter(e)){var r=e.lastIntValue;return-1!==s&&-1!==r&&s>r&&e.raise("Range out of order in character class"),!0}e.pos=t}return!1},Fe.regexp_eatClassSetOperand=function(e){return this.regexp_eatClassSetCharacter(e)?1:this.regexp_eatClassStringDisjunction(e)||this.regexp_eatNestedClass(e)},Fe.regexp_eatNestedClass=function(e){var t=e.pos;if(e.eat(91)){var s=e.eat(94),r=this.regexp_classContents(e);if(e.eat(93))return s&&2===r&&e.raise("Negated character class may contain strings"),r;e.pos=t}if(e.eat(92)){var n=this.regexp_eatCharacterClassEscape(e);if(n)return n;e.pos=t}return null},Fe.regexp_eatClassStringDisjunction=function(e){var t=e.pos;if(e.eatChars([92,113])){if(e.eat(123)){var s=this.regexp_classStringDisjunctionContents(e);if(e.eat(125))return s}else e.raise("Invalid escape");e.pos=t}return null},Fe.regexp_classStringDisjunctionContents=function(e){for(var t=this.regexp_classString(e);e.eat(124);)2===this.regexp_classString(e)&&(t=2);return t},Fe.regexp_classString=function(e){for(var t=0;this.regexp_eatClassSetCharacter(e);)t++;return 1===t?1:2},Fe.regexp_eatClassSetCharacter=function(e){var t=e.pos;if(e.eat(92))return!(!this.regexp_eatCharacterEscape(e)&&!this.regexp_eatClassSetReservedPunctuator(e)&&(e.eat(98)?(e.lastIntValue=8,0):(e.pos=t,1)));var s=e.current();return!(s<0||s===e.lookahead()&&function(e){return 33===e||e>=35&&e<=38||e>=42&&e<=44||46===e||e>=58&&e<=64||94===e||96===e||126===e}(s)||function(e){return 40===e||41===e||45===e||47===e||e>=91&&e<=93||e>=123&&e<=125}(s)||(e.advance(),e.lastIntValue=s,0))},Fe.regexp_eatClassSetReservedPunctuator=function(e){var t=e.current();return!!function(e){return 33===e||35===e||37===e||38===e||44===e||45===e||e>=58&&e<=62||64===e||96===e||126===e}(t)&&(e.lastIntValue=t,e.advance(),!0)},Fe.regexp_eatClassControlLetter=function(e){var t=e.current();return!(!Pe(t)&&95!==t||(e.lastIntValue=t%32,e.advance(),0))},Fe.regexp_eatHexEscapeSequence=function(e){var t=e.pos;if(e.eat(120)){if(this.regexp_eatFixedHexDigits(e,2))return!0;e.switchU&&e.raise("Invalid escape"),e.pos=t}return!1},Fe.regexp_eatDecimalDigits=function(e){var t=e.pos,s=0;for(e.lastIntValue=0;Pe(s=e.current());)e.lastIntValue=10*e.lastIntValue+(s-48),e.advance();return e.pos!==t},Fe.regexp_eatHexDigits=function(e){var t=e.pos,s=0;for(e.lastIntValue=0;ze(s=e.current());)e.lastIntValue=16*e.lastIntValue+Ue(s),e.advance();return e.pos!==t},Fe.regexp_eatLegacyOctalEscapeSequence=function(e){if(this.regexp_eatOctalDigit(e)){var t=e.lastIntValue;if(this.regexp_eatOctalDigit(e)){var s=e.lastIntValue;t<=3&&this.regexp_eatOctalDigit(e)?e.lastIntValue=64*t+8*s+e.lastIntValue:e.lastIntValue=8*t+s}else e.lastIntValue=t;return!0}return!1},Fe.regexp_eatOctalDigit=function(e){var t=e.current();return Be(t)?(e.lastIntValue=t-48,e.advance(),!0):(e.lastIntValue=0,!1)},Fe.regexp_eatFixedHexDigits=function(e,t){var s=e.pos;e.lastIntValue=0;for(var r=0;r=this.input.length?this.finishToken(b.eof):e.override?e.override(this):void this.readToken(this.fullCharCodeAtPos())},We.readToken=function(e){return c(e,this.options.ecmaVersion>=6)||92===e?this.readWord():this.getTokenFromCode(e)},We.fullCharCodeAtPos=function(){var e=this.input.charCodeAt(this.pos);if(e<=55295||e>=56320)return e;var t=this.input.charCodeAt(this.pos+1);return t<=56319||t>=57344?e:(e<<10)+t-56613888},We.skipBlockComment=function(){var e=this.options.onComment&&this.curPosition(),t=this.pos,s=this.input.indexOf("*/",this.pos+=2);if(-1===s&&this.raise(this.pos-2,"Unterminated comment"),this.pos=s+2,this.options.locations)for(var r=void 0,n=t;(r=A(this.input,n,this.pos))>-1;)++this.curLine,n=this.lineStart=r;this.options.onComment&&this.options.onComment(!0,this.input.slice(t+2,s),t,this.pos,e,this.curPosition())},We.skipLineComment=function(e){for(var t=this.pos,s=this.options.onComment&&this.curPosition(),r=this.input.charCodeAt(this.pos+=e);this.pos8&&e<14||e>=5760&&w.test(String.fromCharCode(e))))break e;++this.pos}}},We.finishToken=function(e,t){this.end=this.pos,this.options.locations&&(this.endLoc=this.curPosition());var s=this.type;this.type=e,this.value=t,this.updateContext(s)},We.readToken_dot=function(){var e=this.input.charCodeAt(this.pos+1);if(e>=48&&e<=57)return this.readNumber(!0);var t=this.input.charCodeAt(this.pos+2);return this.options.ecmaVersion>=6&&46===e&&46===t?(this.pos+=3,this.finishToken(b.ellipsis)):(++this.pos,this.finishToken(b.dot))},We.readToken_slash=function(){var e=this.input.charCodeAt(this.pos+1);return this.exprAllowed?(++this.pos,this.readRegexp()):61===e?this.finishOp(b.assign,2):this.finishOp(b.slash,1)},We.readToken_mult_modulo_exp=function(e){var t=this.input.charCodeAt(this.pos+1),s=1,r=42===e?b.star:b.modulo;return this.options.ecmaVersion>=7&&42===e&&42===t&&(++s,r=b.starstar,t=this.input.charCodeAt(this.pos+2)),61===t?this.finishOp(b.assign,s+1):this.finishOp(r,s)},We.readToken_pipe_amp=function(e){var t=this.input.charCodeAt(this.pos+1);return t===e?this.options.ecmaVersion>=12&&61===this.input.charCodeAt(this.pos+2)?this.finishOp(b.assign,3):this.finishOp(124===e?b.logicalOR:b.logicalAND,2):61===t?this.finishOp(b.assign,2):this.finishOp(124===e?b.bitwiseOR:b.bitwiseAND,1)},We.readToken_caret=function(){return 61===this.input.charCodeAt(this.pos+1)?this.finishOp(b.assign,2):this.finishOp(b.bitwiseXOR,1)},We.readToken_plus_min=function(e){var t=this.input.charCodeAt(this.pos+1);return t===e?45!==t||this.inModule||62!==this.input.charCodeAt(this.pos+2)||0!==this.lastTokEnd&&!v.test(this.input.slice(this.lastTokEnd,this.pos))?this.finishOp(b.incDec,2):(this.skipLineComment(3),this.skipSpace(),this.nextToken()):61===t?this.finishOp(b.assign,2):this.finishOp(b.plusMin,1)},We.readToken_lt_gt=function(e){var t=this.input.charCodeAt(this.pos+1),s=1;return t===e?(s=62===e&&62===this.input.charCodeAt(this.pos+2)?3:2,61===this.input.charCodeAt(this.pos+s)?this.finishOp(b.assign,s+1):this.finishOp(b.bitShift,s)):33!==t||60!==e||this.inModule||45!==this.input.charCodeAt(this.pos+2)||45!==this.input.charCodeAt(this.pos+3)?(61===t&&(s=2),this.finishOp(b.relational,s)):(this.skipLineComment(4),this.skipSpace(),this.nextToken())},We.readToken_eq_excl=function(e){var t=this.input.charCodeAt(this.pos+1);return 61===t?this.finishOp(b.equality,61===this.input.charCodeAt(this.pos+2)?3:2):61===e&&62===t&&this.options.ecmaVersion>=6?(this.pos+=2,this.finishToken(b.arrow)):this.finishOp(61===e?b.eq:b.prefix,1)},We.readToken_question=function(){var e=this.options.ecmaVersion;if(e>=11){var t=this.input.charCodeAt(this.pos+1);if(46===t){var s=this.input.charCodeAt(this.pos+2);if(s<48||s>57)return this.finishOp(b.questionDot,2)}if(63===t)return e>=12&&61===this.input.charCodeAt(this.pos+2)?this.finishOp(b.assign,3):this.finishOp(b.coalesce,2)}return this.finishOp(b.question,1)},We.readToken_numberSign=function(){var e=35;if(this.options.ecmaVersion>=13&&(++this.pos,c(e=this.fullCharCodeAtPos(),!0)||92===e))return this.finishToken(b.privateId,this.readWord1());this.raise(this.pos,"Unexpected character '"+$(e)+"'")},We.getTokenFromCode=function(e){switch(e){case 46:return this.readToken_dot();case 40:return++this.pos,this.finishToken(b.parenL);case 41:return++this.pos,this.finishToken(b.parenR);case 59:return++this.pos,this.finishToken(b.semi);case 44:return++this.pos,this.finishToken(b.comma);case 91:return++this.pos,this.finishToken(b.bracketL);case 93:return++this.pos,this.finishToken(b.bracketR);case 123:return++this.pos,this.finishToken(b.braceL);case 125:return++this.pos,this.finishToken(b.braceR);case 58:return++this.pos,this.finishToken(b.colon);case 96:if(this.options.ecmaVersion<6)break;return++this.pos,this.finishToken(b.backQuote);case 48:var t=this.input.charCodeAt(this.pos+1);if(120===t||88===t)return this.readRadixNumber(16);if(this.options.ecmaVersion>=6){if(111===t||79===t)return this.readRadixNumber(8);if(98===t||66===t)return this.readRadixNumber(2)}case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return this.readNumber(!1);case 34:case 39:return this.readString(e);case 47:return this.readToken_slash();case 37:case 42:return this.readToken_mult_modulo_exp(e);case 124:case 38:return this.readToken_pipe_amp(e);case 94:return this.readToken_caret();case 43:case 45:return this.readToken_plus_min(e);case 60:case 62:return this.readToken_lt_gt(e);case 61:case 33:return this.readToken_eq_excl(e);case 63:return this.readToken_question();case 126:return this.finishOp(b.prefix,1);case 35:return this.readToken_numberSign()}this.raise(this.pos,"Unexpected character '"+$(e)+"'")},We.finishOp=function(e,t){var s=this.input.slice(this.pos,this.pos+t);return this.pos+=t,this.finishToken(e,s)},We.readRegexp=function(){for(var e,t,s=this.pos;;){this.pos>=this.input.length&&this.raise(s,"Unterminated regular expression");var r=this.input.charAt(this.pos);if(v.test(r)&&this.raise(s,"Unterminated regular expression"),e)e=!1;else{if("["===r)t=!0;else if("]"===r&&t)t=!1;else if("/"===r&&!t)break;e="\\"===r}++this.pos}var n=this.input.slice(s,this.pos);++this.pos;var i=this.pos,a=this.readWord1();this.containsEsc&&this.unexpected(i);var o=this.regexpState||(this.regexpState=new Ne(this));o.reset(s,n,a),this.validateRegExpFlags(o),this.validateRegExpPattern(o);var u=null;try{u=new RegExp(n,a)}catch(e){}return this.finishToken(b.regexp,{pattern:n,flags:a,value:u})},We.readInt=function(e,t,s){for(var r=this.options.ecmaVersion>=12&&void 0===t,n=s&&48===this.input.charCodeAt(this.pos),i=this.pos,a=0,o=0,u=0,l=null==t?1/0:t;u=97?h-97+10:h>=65?h-65+10:h>=48&&h<=57?h-48:1/0)>=e)break;o=h,a=a*e+c}}return r&&95===o&&this.raiseRecoverable(this.pos-1,"Numeric separator is not allowed at the last of digits"),this.pos===i||null!=t&&this.pos-i!==t?null:a},We.readRadixNumber=function(e){var t=this.pos;this.pos+=2;var s=this.readInt(e);return null==s&&this.raise(this.start+2,"Expected number in radix "+e),this.options.ecmaVersion>=11&&110===this.input.charCodeAt(this.pos)?(s=je(this.input.slice(t,this.pos)),++this.pos):c(this.fullCharCodeAtPos())&&this.raise(this.pos,"Identifier directly after number"),this.finishToken(b.num,s)},We.readNumber=function(e){var t=this.pos;e||null!==this.readInt(10,void 0,!0)||this.raise(t,"Invalid number");var s=this.pos-t>=2&&48===this.input.charCodeAt(t);s&&this.strict&&this.raise(t,"Invalid number");var r=this.input.charCodeAt(this.pos);if(!s&&!e&&this.options.ecmaVersion>=11&&110===r){var n=je(this.input.slice(t,this.pos));return++this.pos,c(this.fullCharCodeAtPos())&&this.raise(this.pos,"Identifier directly after number"),this.finishToken(b.num,n)}s&&/[89]/.test(this.input.slice(t,this.pos))&&(s=!1),46!==r||s||(++this.pos,this.readInt(10),r=this.input.charCodeAt(this.pos)),69!==r&&101!==r||s||(43!==(r=this.input.charCodeAt(++this.pos))&&45!==r||++this.pos,null===this.readInt(10)&&this.raise(t,"Invalid number")),c(this.fullCharCodeAtPos())&&this.raise(this.pos,"Identifier directly after number");var i,a=(i=this.input.slice(t,this.pos),s?parseInt(i,8):parseFloat(i.replace(/_/g,"")));return this.finishToken(b.num,a)},We.readCodePoint=function(){var e;if(123===this.input.charCodeAt(this.pos)){this.options.ecmaVersion<6&&this.unexpected();var t=++this.pos;e=this.readHexChar(this.input.indexOf("}",this.pos)-this.pos),++this.pos,e>1114111&&this.invalidStringToken(t,"Code point out of bounds")}else e=this.readHexChar(4);return e},We.readString=function(e){for(var t="",s=++this.pos;;){this.pos>=this.input.length&&this.raise(this.start,"Unterminated string constant");var r=this.input.charCodeAt(this.pos);if(r===e)break;92===r?(t+=this.input.slice(s,this.pos),t+=this.readEscapedChar(!1),s=this.pos):8232===r||8233===r?(this.options.ecmaVersion<10&&this.raise(this.start,"Unterminated string constant"),++this.pos,this.options.locations&&(this.curLine++,this.lineStart=this.pos)):(T(r)&&this.raise(this.start,"Unterminated string constant"),++this.pos)}return t+=this.input.slice(s,this.pos++),this.finishToken(b.string,t)};var qe={};We.tryReadTemplateToken=function(){this.inTemplateElement=!0;try{this.readTmplToken()}catch(e){if(e!==qe)throw e;this.readInvalidTemplateToken()}this.inTemplateElement=!1},We.invalidStringToken=function(e,t){if(this.inTemplateElement&&this.options.ecmaVersion>=9)throw qe;this.raise(e,t)},We.readTmplToken=function(){for(var e="",t=this.pos;;){this.pos>=this.input.length&&this.raise(this.start,"Unterminated template");var s=this.input.charCodeAt(this.pos);if(96===s||36===s&&123===this.input.charCodeAt(this.pos+1))return this.pos!==this.start||this.type!==b.template&&this.type!==b.invalidTemplate?(e+=this.input.slice(t,this.pos),this.finishToken(b.template,e)):36===s?(this.pos+=2,this.finishToken(b.dollarBraceL)):(++this.pos,this.finishToken(b.backQuote));if(92===s)e+=this.input.slice(t,this.pos),e+=this.readEscapedChar(!0),t=this.pos;else if(T(s)){switch(e+=this.input.slice(t,this.pos),++this.pos,s){case 13:10===this.input.charCodeAt(this.pos)&&++this.pos;case 10:e+="\n";break;default:e+=String.fromCharCode(s)}this.options.locations&&(++this.curLine,this.lineStart=this.pos),t=this.pos}else++this.pos}},We.readInvalidTemplateToken=function(){for(;this.pos=48&&t<=55){var r=this.input.substr(this.pos-1,3).match(/^[0-7]+/)[0],n=parseInt(r,8);return n>255&&(r=r.slice(0,-1),n=parseInt(r,8)),this.pos+=r.length-1,t=this.input.charCodeAt(this.pos),"0"===r&&56!==t&&57!==t||!this.strict&&!e||this.invalidStringToken(this.pos-1-r.length,e?"Octal literal in template string":"Octal literal in strict mode"),String.fromCharCode(n)}return T(t)?(this.options.locations&&(this.lineStart=this.pos,++this.curLine),""):String.fromCharCode(t)}},We.readHexChar=function(e){var t=this.pos,s=this.readInt(16,e);return null===s&&this.invalidStringToken(t,"Bad character escape sequence"),s},We.readWord1=function(){this.containsEsc=!1;for(var e="",t=!0,s=this.pos,r=this.options.ecmaVersion>=6;this.pos{var s=class{constructor(e,t){this.value=e,Array.isArray(t)?this.size=t:(this.size=new Int32Array(3),t.z?this.size=new Int32Array([t.x,t.y,t.z]):t.y?this.size=new Int32Array([t.x,t.y]):this.size=new Int32Array([t.x]));const[s,r,n]=this.size;if(n){if(this.value.length!==s*r*n)throw new Error(`Input size ${this.value.length} does not match ${s} * ${r} * ${n} = ${r*s*n}`)}else if(r){if(this.value.length!==s*r)throw new Error(`Input size ${this.value.length} does not match ${s} * ${r} = ${r*s}`)}else if(this.value.length!==s)throw new Error(`Input size ${this.value.length} does not match ${s}`)}toArray(){const{utils:e}=i(),[t,s,r]=this.size;return r?e.erectMemoryOptimized3DFloat(this.value.subarray?this.value:new Float32Array(this.value),t,s,r):s?e.erectMemoryOptimized2DFloat(this.value.subarray?this.value:new Float32Array(this.value),t,s):this.value}};t.exports={Input:s,input:function(e,t){return new s(e,t)}}}),n=e((e,t)=>{t.exports={Texture:class{constructor(e){const{texture:t,size:s,dimensions:r,output:n,context:i,type:a="NumberTexture",kernel:o,internalFormat:u,textureFormat:l}=e;if(!n)throw new Error('settings property "output" required.');if(!i)throw new Error('settings property "context" required.');if(!t)throw new Error('settings property "texture" required.');if(!o)throw new Error('settings property "kernel" required.');this.texture=t,t._refs?t._refs++:t._refs=1,this.size=s,this.dimensions=r,this.output=n,this.context=i,this.kernel=o,this.type=a,this._deleted=!1,this.internalFormat=u,this.textureFormat=l}toArray(){throw new Error(`Not implemented on ${this.constructor.name}`)}clone(){throw new Error(`Not implemented on ${this.constructor.name}`)}delete(){throw new Error(`Not implemented on ${this.constructor.name}`)}clear(){throw new Error(`Not implemented on ${this.constructor.name}`)}}}}),i=e((e,t)=>{const i=s(),{Input:a}=r(),{Texture:o}=n(),u=/function ([^(]*)/,l=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm,h=/([^\s,]+)/g,c={systemEndianness:()=>m,getSystemEndianness(){const e=new ArrayBuffer(4),t=new Uint32Array(e),s=new Uint8Array(e);if(t[0]=3735928559,239===s[0])return"LE";if(222===s[0])return"BE";throw new Error("unknown endianness")},isFunction:e=>"function"==typeof e,isFunctionString:e=>"string"==typeof e&&"function"===e.slice(0,8).toLowerCase(),getFunctionNameFromString(e){const t=u.exec(e);return t&&0!==t.length?t[1].trim():null},getFunctionBodyFromString:e=>e.substring(e.indexOf("{")+1,e.lastIndexOf("}")),getArgumentNamesFromString(e){const t=e.replace(l,"");let s=t.slice(t.indexOf("(")+1,t.indexOf(")")).match(h);return null===s&&(s=[]),s},clone(e){if(null===e||"object"!=typeof e||e.hasOwnProperty("isActiveClone"))return e;const t=e.constructor();for(let s in e)Object.prototype.hasOwnProperty.call(e,s)&&(e.isActiveClone=null,t[s]=c.clone(e[s]),delete e.isActiveClone);return t},isArray:e=>!isNaN(e.length),typeFitsValue(e,t){if("string"!=typeof e||null==t)return!0;if(t.type)return!0;switch(e){case"Input":return t instanceof a;case"Boolean":return"boolean"==typeof t;case"Number":case"Integer":case"Float":return"number"==typeof t}return-1!==e.indexOf("Texture")?Boolean(t.type):0!==e.indexOf("Array")||c.isArray(t)},getVariableType(e,t){if(c.isArray(e))return e.length>0&&"IMG"===e[0].nodeName?"HTMLImageArray":"Array";switch(e.constructor){case Boolean:return"Boolean";case Number:return t&&Number.isInteger(e)?"Integer":"Float";case o:return e.type;case a:return"Input"}if("nodeName"in e)switch(e.nodeName){case"IMG":case"CANVAS":return"HTMLImage";case"VIDEO":return"HTMLVideo"}else{if(e.hasOwnProperty("type"))return e.type;if("undefined"!=typeof OffscreenCanvas&&e instanceof OffscreenCanvas)return"OffscreenCanvas";if("undefined"!=typeof ImageBitmap&&e instanceof ImageBitmap)return"ImageBitmap";if("undefined"!=typeof ImageData&&e instanceof ImageData)return"ImageData"}return"Unknown"},getKernelTextureSize(e,t){let[s,r,n]=t,i=(s||1)*(r||1)*(n||1);return e.optimizeFloatMemory&&"single"===e.precision&&(s=i=Math.ceil(i/4)),r>1&&s*r===i?new Int32Array([s,r]):c.closestSquareDimensions(i)},closestSquareDimensions(e){const t=Math.sqrt(e);let s=Math.ceil(t),r=Math.floor(t);for(;s*rMath.floor((e+t-1)/t)*t,getDimensions(e,t){let s;if(c.isArray(e)){const t=[];let r=e;for(;c.isArray(r);)t.push(r.length),r=r[0];s=t.reverse()}else if(e instanceof o)s=e.output;else{if(!(e instanceof a))throw new Error(`Unknown dimensions of ${e}`);s=e.size}if(t)for(s=Array.from(s);s.length<3;)s.push(1);return new Int32Array(s)},flatten2dArrayTo(e,t){let s=0;for(let r=0;re.length>0?e.join(";\n")+";\n":"\n",warnDeprecated(e,t,s){s?console.warn(`You are using a deprecated ${e} "${t}". It has been replaced with "${s}". Fixing, but please upgrade as it will soon be removed.`):console.warn(`You are using a deprecated ${e} "${t}". It has been removed. Fixing, but please upgrade as it will soon be removed.`)},flipPixels:(e,t,s)=>{const r=s/2|0,n=4*t,i=new Uint8ClampedArray(4*t),a=e.slice(0);for(let e=0;ee.subarray(0,t),erect2DPackedFloat:(e,t,s)=>{const r=new Array(s);for(let n=0;n{const n=new Array(r);for(let i=0;ie.subarray(0,t),erectMemoryOptimized2DFloat:(e,t,s)=>{const r=new Array(s);for(let n=0;n{const n=new Array(r);for(let i=0;i{const s=new Float32Array(t);let r=0;for(let n=0;n{const r=new Array(s);let n=0;for(let i=0;i{const n=new Array(r);let i=0;for(let a=0;a{const s=new Array(t),r=4*t;let n=0;for(let t=0;t{const r=new Array(s),n=4*t;for(let i=0;i{const n=4*t,i=new Array(r);for(let a=0;a{const s=new Array(t),r=4*t;let n=0;for(let t=0;t{const r=4*t,n=new Array(s);for(let i=0;i{const n=4*t,i=new Array(r);for(let a=0;a{const s=new Array(e),r=4*t;let n=0;for(let t=0;t{const r=4*t,n=new Array(s);for(let i=0;i{const n=4*t,i=new Array(r);for(let a=0;a{const{findDependency:s,thisLookup:r,doNotDefine:n}=t;let a=t.flattened;a||(a=t.flattened={});const o=i.parse(e,{ecmaVersion:2020}),u=[];let l=0;const h=function e(t){if(Array.isArray(t)){const s=[];for(let r=0;rnull!==e);return n.length<1?"":`${t.kind} ${n.join(",")}`;case"VariableDeclarator":return t.init?t.init.object&&"ThisExpression"===t.init.object.type?r(t.init.property.name,!0)?`${t.id.name} = ${e(t.init)}`:null:`${t.id.name} = ${e(t.init)}`:t.id.name;case"CallExpression":if("subarray"===t.callee.property.name)return`${e(t.callee.object)}.${e(t.callee.property)}(${t.arguments.map(t=>e(t)).join(", ")})`;if("gl"===t.callee.object.name||"context"===t.callee.object.name)return`${e(t.callee.object)}.${e(t.callee.property)}(${t.arguments.map(t=>e(t)).join(", ")})`;if("ThisExpression"===t.callee.object.type)return u.push(s("this",t.callee.property.name)),`${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`;if(t.callee.object.name){const r=s(t.callee.object.name,t.callee.property.name);return null===r?`${t.callee.object.name}.${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`:(u.push(r),`${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`)}if("MemberExpression"===t.callee.object.type)return`${e(t.callee.object)}.${t.callee.property.name}(${t.arguments.map(t=>e(t)).join(", ")})`;throw new Error("unknown ast.callee");case"ReturnStatement":return`return ${e(t.argument)}`;case"BinaryExpression":return`(${e(t.left)}${t.operator}${e(t.right)})`;case"UnaryExpression":return t.prefix?`${t.operator} ${e(t.argument)}`:`${e(t.argument)} ${t.operator}`;case"ExpressionStatement":return`${e(t.expression)}`;case"SequenceExpression":return`(${e(t.expressions)})`;case"ArrowFunctionExpression":return`(${t.params.map(e).join(", ")}) => ${e(t.body)}`;case"Literal":return t.raw;case"Identifier":return t.name;case"MemberExpression":return"ThisExpression"===t.object.type?r(t.property.name):t.computed?`${e(t.object)}[${e(t.property)}]`:e(t.object)+"."+e(t.property);case"ThisExpression":return"this";case"NewExpression":return`new ${e(t.callee)}(${t.arguments.map(t=>e(t)).join(", ")})`;case"ForStatement":return`for (${e(t.init)};${e(t.test)};${e(t.update)}) ${e(t.body)}`;case"AssignmentExpression":return`${e(t.left)}${t.operator}${e(t.right)}`;case"UpdateExpression":return`${e(t.argument)}${t.operator}`;case"IfStatement":{const s=e(t.consequent);if(!t.alternate)return`if (${e(t.test)}) ${s}`;const r="BlockStatement"===t.consequent.type?"":";";return`if (${e(t.test)}) ${s}${r} else ${e(t.alternate)}`}case"ThrowStatement":return`throw ${e(t.argument)}`;case"ObjectPattern":return t.properties.map(e).join(", ");case"ArrayPattern":return t.elements.map(e).join(", ");case"DebuggerStatement":return"debugger;";case"ConditionalExpression":return`${e(t.test)}?${e(t.consequent)}:${e(t.alternate)}`;case"Property":if("init"===t.kind)return e(t.key)}throw new Error(`unhandled ast.type of ${t.type}`)}(o);if(u.length>0){const e=[];for(let s=0;s{if("VariableDeclaration"!==e.type)throw new Error('Ast is not of type "VariableDeclaration"');const t=[];for(let s=0;s{const s=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].r},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),r=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].g},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),n=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].b},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),i=e.createKernel(function(e){return 255*e[this.thread.y][this.thread.x].a},{output:[t.width,t.height],precision:"unsigned",argumentTypes:{a:"HTMLImage"}}),a=[s(t),r(t),n(t),i(t)];return a.rKernel=s,a.gKernel=r,a.bKernel=n,a.aKernel=i,a.gpu=e,a},splitRGBAToCanvases:(e,t,s,r)=>{const n=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(t.r/255,0,0,255)},{output:[s,r],graphical:!0,argumentTypes:{v:"Array2D(4)"}});n(t);const i=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(0,t.g/255,0,255)},{output:[s,r],graphical:!0,argumentTypes:{v:"Array2D(4)"}});i(t);const a=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(0,0,t.b/255,255)},{output:[s,r],graphical:!0,argumentTypes:{v:"Array2D(4)"}});a(t);const o=e.createKernel(function(e){const t=e[this.thread.y][this.thread.x];this.color(255,255,255,t.a/255)},{output:[s,r],graphical:!0,argumentTypes:{v:"Array2D(4)"}});return o(t),[n.canvas,i.canvas,a.canvas,o.canvas]},getMinifySafeName:e=>{try{const{init:t}=i.parse(`const value = ${e.toString()}`,{ecmaVersion:2020}).body[0].declarations[0];return t.body.name||t.body.body[0].argument.name}catch(e){throw new Error("Unrecognized function type. Please use `() => yourFunctionVariableHere` or function() { return yourFunctionVariableHere; }")}},sanitizeName:function(e){return p.test(e)&&(e=e.replace(p,"S_S")),d.test(e)?e=e.replace(d,"U_U"):f.test(e)&&(e=e.replace(f,"u_u")),e}},p=/\$/,d=/__/,f=/_/,m=c.getSystemEndianness();t.exports={utils:c}}),a=e((e,t)=>{const{utils:s}=i(),{Input:n}=r();t.exports={Kernel:class{static get isSupported(){throw new Error(`"isSupported" not implemented on ${this.name}`)}static isContextMatch(e){throw new Error(`"isContextMatch" not implemented on ${this.name}`)}static getFeatures(){throw new Error(`"getFeatures" not implemented on ${this.name}`)}static destroyContext(e){throw new Error(`"destroyContext" called on ${this.name}`)}static nativeFunctionArguments(){throw new Error(`"nativeFunctionArguments" called on ${this.name}`)}static nativeFunctionReturnType(){throw new Error(`"nativeFunctionReturnType" called on ${this.name}`)}static combineKernels(){throw new Error(`"combineKernels" called on ${this.name}`)}constructor(e,t){if("object"!=typeof e){if("string"!=typeof e)throw new Error("source not a string");if(!s.isFunctionString(e))throw new Error("source not a function string")}this.useLegacyEncoder=!1,this.fallbackRequested=!1,this.fallbackReason=null,this.onRequestFallback=null,this.onRequestSwitchKernel=null,this.argumentNames="string"==typeof e?s.getArgumentNamesFromString(e):null,this.argumentTypes=null,this.argumentSizes=null,this.argumentBitRatios=null,this.kernelArguments=null,this.kernelConstants=null,this.forceUploadKernelConstants=null,this.source=e,this.output=null,this.debug=!1,this.graphical=!1,this.loopMaxIterations=0,this.constants=null,this.constantTypes=null,this.constantBitRatios=null,this.dynamicArguments=!1,this.dynamicOutput=!1,this.canvas=null,this.context=null,this.checkContext=null,this.gpu=null,this.functions=null,this.nativeFunctions=null,this.injectedNative=null,this.subKernels=null,this.validate=!0,this.immutable=!1,this.pipeline=!1,this.asyncMode=!1,this.precision=null,this.tactic=null,this.plugins=null,this.returnType=null,this.leadingReturnStatement=null,this.followingReturnStatement=null,this.optimizeFloatMemory=null,this.strictIntegers=!1,this.fixIntegerDivisionAccuracy=null,this.randomSeed=null,this.built=!1,this.signature=null,this.switchingKernels=null}mergeSettings(e){for(let t in e)if(e.hasOwnProperty(t)&&this.hasOwnProperty(t)){switch(t){case"output":if(!Array.isArray(e.output)){this.setOutput(e.output);continue}break;case"functions":this.functions=[];for(let t=0;te.name):null,returnType:this.returnType}}}buildSignature(e){const t=this.constructor;this.signature=t.getSignature(this,t.getArgumentTypes(this,e))}static getArgumentTypes(e,t){const r=new Array(t.length);for(let n=0;nt.argumentTypes[e])||[];const i=Object.keys(t.argumentTypes);if(i.length>0&&e.length>0&&n.every(e=>void 0===e))throw new Error(`argumentTypes keys [${i.join(", ")}] match none of the function's parameters [${e.join(", ")}] \u2014 a bundler may have renamed them. Use the array form: argumentTypes: ['${i.map(e=>t.argumentTypes[e]).join("', '")}']`)}else n=t.argumentTypes||[];return{name:t.name||s.getFunctionNameFromString(r)||("function"==typeof e&&e.name?e.name:null),source:r,argumentTypes:n,returnType:t.returnType||null}}onActivate(e){}switchKernels(e){this.switchingKernels?this.switchingKernels.push(e):this.switchingKernels=[e]}resetSwitchingKernels(){const e=this.switchingKernels;return this.switchingKernels=null,e}checkArgumentTypes(e){if(!this.argumentTypes)return;const t=Math.min(e.length,this.argumentTypes.length);for(let r=0;r{t.exports={FunctionBuilder:class e{static fromKernel(t,s,r){const{kernelArguments:n,kernelConstants:i,argumentNames:a,argumentSizes:o,argumentBitRatios:u,constants:l,constantBitRatios:h,debug:c,loopMaxIterations:p,nativeFunctions:d,output:f,optimizeFloatMemory:m,precision:g,plugins:x,source:y,subKernels:b,functions:v,leadingReturnStatement:S,followingReturnStatement:T,dynamicArguments:A,dynamicOutput:w}=t,E=new Array(n.length),_={};for(let e=0;eU.needsArgumentType(e,t),k=(e,t,s)=>{U.assignArgumentType(e,t,s)},C=(e,t,s)=>U.lookupReturnType(e,t,s),L=e=>U.lookupFunctionArgumentTypes(e),D=(e,t)=>U.lookupFunctionArgumentName(e,t),F=(e,t)=>U.lookupFunctionArgumentBitRatio(e,t),$=(e,t,s,r)=>{U.assignArgumentType(e,t,s,r)},N=(e,t,s,r)=>{U.assignArgumentBitRatio(e,t,s,r)},R=(e,t,s)=>{U.trackFunctionCall(e,t,s)},M=(e,t)=>{const r=[];for(let t=0;tnew s(e.source,{name:e.name||void 0,returnType:e.returnType,argumentTypes:e.argumentTypes,output:f,plugins:x,constants:l,constantTypes:_,constantBitRatios:h,optimizeFloatMemory:m,precision:g,lookupReturnType:C,lookupFunctionArgumentTypes:L,lookupFunctionArgumentName:D,lookupFunctionArgumentBitRatio:F,needsArgumentType:I,assignArgumentType:k,triggerImplyArgumentType:$,triggerImplyArgumentBitRatio:N,onFunctionCall:R,onNestedFunction:M})));let z=null;b&&(z=b.map(e=>{const{name:t,source:r}=e;return new s(r,Object.assign({},G,{name:t,isSubKernel:!0,isRootKernel:!1}))}));const U=new e({kernel:t,rootNode:V,functionNodes:P,nativeFunctions:d,subKernelNodes:z});return U}constructor(e){if(e=e||{},this.kernel=e.kernel,this.rootNode=e.rootNode,this.functionNodes=e.functionNodes||[],this.subKernelNodes=e.subKernelNodes||[],this.nativeFunctions=e.nativeFunctions||[],this.functionMap={},this.nativeFunctionNames=[],this.lookupChain=[],this.functionNodeDependencies={},this.functionCalls={},this.rootNode&&(this.functionMap.kernel=this.rootNode),this.functionNodes)for(let e=0;e-1){const s=t.indexOf(e);if(-1===s)t.push(e);else{const e=t.splice(s,1)[0];t.push(e)}return t}const s=this.functionMap[e];if(s){const r=t.indexOf(e);if(-1===r){t.push(e),s.toString();for(let e=0;e-1){t.push(this.nativeFunctions[n].source);continue}const i=this.functionMap[r];i&&t.push(i.toString())}return t}toJSON(){return this.traceFunctionCalls(this.rootNode.name).reverse().map(e=>{const t=this.nativeFunctions.indexOf(e);if(t>-1)return{name:e,source:this.nativeFunctions[t].source};if(this.functionMap[e])return this.functionMap[e].toJSON();throw new Error(`function ${e} not found`)})}fromJSON(e,t){this.functionMap={};for(let s=0;s0){const n=t.arguments;for(let t=0;t{const{utils:s}=i();function r(e){return e.length>0?e[e.length-1]:null}const n="trackIdentifiers",a="memberExpression",o="inForLoopInit";t.exports={FunctionTracer:class{constructor(e){this.runningContexts=[],this.functionContexts=[],this.contexts=[],this.functionCalls=[],this.declarations=[],this.identifiers=[],this.functions=[],this.returnStatements=[],this.trackedIdentifiers=null,this.states=[],this.newFunctionContext(),this.scan(e)}isState(e){return this.states[this.states.length-1]===e}hasState(e){return this.states.indexOf(e)>-1}pushState(e){this.states.push(e)}popState(e){if(!this.isState(e))throw new Error(`Cannot pop the non-active state "${e}"`);this.states.pop()}get currentFunctionContext(){return r(this.functionContexts)}get currentContext(){return r(this.runningContexts)}newFunctionContext(){const e={"@contextType":"function"};this.contexts.push(e),this.functionContexts.push(e)}newContext(e){const t=Object.assign({"@contextType":"const/let"},this.currentContext);this.contexts.push(t),this.runningContexts.push(t),e();const{currentFunctionContext:s}=this;for(const e in s)s.hasOwnProperty(e)&&!t.hasOwnProperty(e)&&(t[e]=s[e]);return this.runningContexts.pop(),t}useFunctionContext(e){const t=r(this.functionContexts);this.runningContexts.push(t),e(),this.runningContexts.pop()}getIdentifiers(e){const t=this.trackedIdentifiers=[];return this.pushState(n),e(),this.trackedIdentifiers=null,this.popState(n),t}getDeclaration(e){const{currentContext:t,currentFunctionContext:s,runningContexts:r}=this,n=t[e]||s[e]||null;if(!n&&t===s&&r.length>0){const t=r[r.length-2];if(t[e])return t[e]}return n}scan(e){if(e)if(Array.isArray(e))for(let t=0;t{this.scan(e.body)});break;case"BlockStatement":this.newContext(()=>{this.scan(e.body)});break;case"AssignmentExpression":case"LogicalExpression":case"BinaryExpression":this.scan(e.left),this.scan(e.right);break;case"UpdateExpression":if("++"===e.operator){const t=this.getDeclaration(e.argument.name);t&&(t.suggestedType="Integer")}this.scan(e.argument);break;case"UnaryExpression":this.scan(e.argument);break;case"VariableDeclaration":"var"===e.kind?this.useFunctionContext(()=>{e.declarations=s.normalizeDeclarations(e),this.scan(e.declarations)}):(e.declarations=s.normalizeDeclarations(e),this.scan(e.declarations));break;case"VariableDeclarator":{const{currentContext:t}=this,s=this.hasState(o),r={ast:e,context:t,name:e.id.name,origin:"declaration",inForLoopInit:s,inForLoopTest:null,assignable:t===this.currentFunctionContext||!s&&!t.hasOwnProperty(e.id.name),suggestedType:null,valueType:null,dependencies:null,isSafe:null};t[e.id.name]||(t[e.id.name]=r),this.declarations.push(r),this.scan(e.id),this.scan(e.init);break}case"FunctionExpression":case"FunctionDeclaration":0===this.runningContexts.length?this.scan(e.body):this.functions.push(e);break;case"IfStatement":this.scan(e.test),this.scan(e.consequent),e.alternate&&this.scan(e.alternate);break;case"ForStatement":{let t;const s=this.newContext(()=>{this.pushState(o),this.scan(e.init),this.popState(o),t=this.getIdentifiers(()=>{this.scan(e.test)}),this.scan(e.update),this.newContext(()=>{this.scan(e.body)})});if(t)for(const e in s)"@contextType"!==e&&t.indexOf(e)>-1&&(s[e].inForLoopTest=!0);break}case"DoWhileStatement":case"WhileStatement":this.newContext(()=>{this.scan(e.body),this.scan(e.test)});break;case"Identifier":this.isState(n)&&this.trackedIdentifiers.push(e.name),this.identifiers.push({context:this.currentContext,declaration:this.getDeclaration(e.name),ast:e});break;case"ReturnStatement":this.returnStatements.push(e),this.scan(e.argument);break;case"MemberExpression":this.pushState(a),this.scan(e.object),this.scan(e.property),this.popState(a);break;case"ExpressionStatement":this.scan(e.expression);break;case"SequenceExpression":this.scan(e.expressions);break;case"CallExpression":this.functionCalls.push({context:this.currentContext,ast:e}),this.scan(e.arguments);break;case"ArrayExpression":this.scan(e.elements);break;case"ConditionalExpression":this.scan(e.test),this.scan(e.alternate),this.scan(e.consequent);break;case"SwitchStatement":this.scan(e.discriminant),this.scan(e.cases);break;case"SwitchCase":this.scan(e.test),this.scan(e.consequent);break;case"ThisExpression":case"Literal":case"DebuggerStatement":case"EmptyStatement":case"BreakStatement":case"ContinueStatement":break;default:throw new Error(`unhandled type "${e.type}"`)}}}}}),l=e((e,t)=>{const r=s(),{utils:n}=i(),{FunctionTracer:a}=u(),o=["E","PI","SQRT2","SQRT1_2","LN2","LN10","LOG2E","LOG10E"],l=["abs","acos","acosh","asin","asinh","atan","atan2","atanh","cbrt","ceil","clz32","cos","cosh","expm1","exp","floor","fround","imul","log","log2","log10","log1p","max","min","pow","random","round","sign","sin","sinh","sqrt","tan","tanh","trunc"],h=["value","value[]","value[][]","value[][][]","value[][][][]","value.value","value.thread.value","this.thread.value","this.output.value","this.constants.value","this.constants.value[]","this.constants.value[][]","this.constants.value[][][]","this.constants.value[][][][]","fn()[]","fn()[][]","fn()[][][]","[][]"];const c={Number:"Number",Float:"Float",Integer:"Integer",Array:"Number","Array(2)":"Number","Array(3)":"Number","Array(4)":"Number","Matrix(2)":"Number","Matrix(3)":"Number","Matrix(4)":"Number",Array2D:"Number",Array3D:"Number",Input:"Number",HTMLCanvas:"Array(4)",OffscreenCanvas:"Array(4)",HTMLImage:"Array(4)",ImageBitmap:"Array(4)",ImageData:"Array(4)",HTMLVideo:"Array(4)",HTMLImageArray:"Array(4)",NumberTexture:"Number",MemoryOptimizedNumberTexture:"Number","Array1D(2)":"Array(2)","Array1D(3)":"Array(3)","Array1D(4)":"Array(4)","Array2D(2)":"Array(2)","Array2D(3)":"Array(3)","Array2D(4)":"Array(4)","Array3D(2)":"Array(2)","Array3D(3)":"Array(3)","Array3D(4)":"Array(4)","ArrayTexture(1)":"Number","ArrayTexture(2)":"Array(2)","ArrayTexture(3)":"Array(3)","ArrayTexture(4)":"Array(4)"};let p=536870912;function d(e,t){return e.start=p++,e.end=p++,t&&t.loc&&(e.loc=t.loc),e}function f(e,t){return e&&e.body&&"BlockStatement"===e.body.type?(m(e.body,t),e):e}function m(e,t){e.body=g(e.body,t)}function g(e,t){const s=[];for(let r=0;r{if(!e||"object"!=typeof e||s)return e;if(Array.isArray(e))return e.map(r);switch(e.type){case"ContinueStatement":return e.label?(s=!0,e):d({type:"BlockStatement",body:[...T(t),e]},e);case"ForStatement":case"WhileStatement":case"DoWhileStatement":case"FunctionExpression":case"FunctionDeclaration":case"ArrowFunctionExpression":default:return e;case"IfStatement":return e.consequent=r(e.consequent),e.alternate&&(e.alternate=r(e.alternate)),e;case"BlockStatement":return e.body=e.body.map(r),e;case"SwitchStatement":for(let t=0;t0?(s.push(e),s):[e]}case"WhileStatement":case"DoWhileStatement":return e.body&&(e.body=y(e.body,t)),[e];case"SwitchStatement":for(let s=0;s0&&this.argumentTypes.length!==this.argumentNames.length)throw new Error(`argumentTypes count of ${this.argumentTypes.length} exceeds ${this.argumentNames.length}`);if(this.output.length<1)throw new Error("this.output is not big enough")}isIdentifierConstant(e){return!!this.constants&&this.constants.hasOwnProperty(e)}isInput(e){return"Input"===this.argumentTypes[this.argumentNames.indexOf(e)]}pushState(e){this.states.push(e)}popState(e){if(this.state!==e)throw new Error(`Cannot popState ${e} when in ${this.state}`);this.states.pop()}isState(e){return this.state===e}get state(){return this.states[this.states.length-1]}astMemberExpressionUnroll(e){if("Identifier"===e.type)return e.name;if("ThisExpression"===e.type)return"this";if("MemberExpression"===e.type&&e.object&&e.property)return e.object.hasOwnProperty("name")&&"Math"!==e.object.name?this.astMemberExpressionUnroll(e.property):this.astMemberExpressionUnroll(e.object)+"."+this.astMemberExpressionUnroll(e.property);if(e.hasOwnProperty("expressions")){const t=e.expressions[0];if("Literal"===t.type&&0===t.value&&2===e.expressions.length)return this.astMemberExpressionUnroll(e.expressions[1])}throw this.astErrorOutput("Unknown astMemberExpressionUnroll",e)}get requiresSequenceFreeForInit(){return!1}getJsAST(e){if(this.ast)return this.ast;if("object"==typeof this.source)return f(this.source,this.requiresSequenceFreeForInit),this.traceFunctionAST(this.source),this.ast=this.source;if(null===(e=e||r))throw new Error("Missing JS to AST parser");const t=Object.freeze(e.parse(`const parser_${this.name} = ${this.source};`,{locations:!0,ecmaVersion:2020})),s=t.body[0].declarations[0].init;if(f(s,this.requiresSequenceFreeForInit),this.traceFunctionAST(s),!t)throw new Error("Failed to parse JS code");return this.ast=s}getAssignedArguments(){if(this._assignedArguments)return this._assignedArguments;const e=new Set,t=new Set,s=this.argumentNames||[],r=n=>{if(n&&"object"==typeof n)if(Array.isArray(n))for(const e of n)r(e);else{"AssignmentExpression"===n.type&&"Identifier"===n.left.type&&-1!==s.indexOf(n.left.name)&&e.add(n.left.name),"UpdateExpression"===n.type&&"Identifier"===n.argument.type&&-1!==s.indexOf(n.argument.name)&&e.add(n.argument.name),"VariableDeclarator"===n.type&&"Identifier"===n.id.type&&-1!==s.indexOf(n.id.name)&&t.add(n.id.name);for(const e in n){if("loc"===e||"range"===e||"parent"===e)continue;const t=n[e];t&&"object"==typeof t&&r(t)}}};r(this.getJsAST());for(const s of t)e.delete(s);return this._assignedArguments=e}traceFunctionAST(e){const{contexts:t,declarations:s,functions:r,identifiers:n,functionCalls:i}=new a(e);this.contexts=t,this.identifiers=n,this.functionCalls=i,this.functions=r;for(let e=0;e":case"<":return"Boolean";case"&":case"|":case"^":case"<<":case">>":case">>>":return"Integer"}const s=this.getType(e.left);if(this.isState("skip-literal-correction"))return s;if("LiteralInteger"===s){const t=this.getType(e.right);return"LiteralInteger"===t?e.left.value%1==0?"Integer":"Float":t}if("Integer"===s){const t=this.getType(e.right);if("Number"===t||"Float"===t)return t}return c[s]||s;case"UpdateExpression":case"ReturnStatement":return this.getType(e.argument);case"UnaryExpression":return"~"===e.operator?"Integer":this.getType(e.argument);case"VariableDeclaration":{const t=e.declarations;let s;for(let e=0;ee.isSafe)}getDependencies(e,t,s){if(t||(t=[]),!e)return null;if(Array.isArray(e)){for(let r=0;r-1/0&&e.value<1/0&&!isNaN(e.value))});break;case"VariableDeclarator":return this.getDependencies(e.init,t,s);case"Identifier":const r=this.getDeclaration(e);if(r)t.push({name:e.name,origin:"declaration",isSafe:!s&&this.isSafeDependencies(r.dependencies)});else if(this.argumentNames.indexOf(e.name)>-1)t.push({name:e.name,origin:"argument",isSafe:!1});else if(this.strictTypingChecking)throw new Error(`Cannot find identifier origin "${e.name}"`);break;case"FunctionDeclaration":return this.getDependencies(e.body.body[e.body.body.length-1],t,s);case"ReturnStatement":return this.getDependencies(e.argument,t);case"BinaryExpression":case"LogicalExpression":return s="/"===e.operator||"*"===e.operator,this.getDependencies(e.left,t,s),this.getDependencies(e.right,t,s),t;case"UnaryExpression":case"UpdateExpression":return this.getDependencies(e.argument,t,s);case"VariableDeclaration":return this.getDependencies(e.declarations,t,s);case"ArrayExpression":return t.push({origin:"declaration",isSafe:!0}),t;case"CallExpression":return t.push({origin:"function",isSafe:!0}),t;case"MemberExpression":const n=this.getMemberExpressionDetails(e);switch(n.signature){case"value[]":this.getDependencies(e.object,t,s);break;case"value[][]":this.getDependencies(e.object.object,t,s);break;case"value[][][]":this.getDependencies(e.object.object.object,t,s);break;case"this.output.value":this.dynamicOutput&&t.push({name:n.name,origin:"output",isSafe:!1})}if(n)return n.property&&this.getDependencies(n.property,t,s),n.xProperty&&this.getDependencies(n.xProperty,t,s),n.yProperty&&this.getDependencies(n.yProperty,t,s),n.zProperty&&this.getDependencies(n.zProperty,t,s),t;case"SequenceExpression":return this.getDependencies(e.expressions,t,s);default:throw this.astErrorOutput(`Unhandled type ${e.type} in getDependencies`,e)}return t}getVariableSignature(e,t){if(!this.isAstVariable(e))throw new Error(`ast of type "${e.type}" is not a variable signature`);if("Identifier"===e.type)return"value";const s=[];for(;e;)e.computed?s.push("[]"):"ThisExpression"===e.type?s.unshift("this"):e.property&&e.property.name?"x"===e.property.name||"y"===e.property.name||"z"===e.property.name?s.unshift(t?"."+e.property.name:".value"):"constants"===e.property.name||"thread"===e.property.name||"output"===e.property.name?s.unshift("."+e.property.name):s.unshift(t?"."+e.property.name:".value"):e.name?s.unshift(t?e.name:"value"):e.callee&&e.callee.name?s.unshift(t?e.callee.name+"()":"fn()"):e.elements?s.unshift("[]"):s.unshift("unknown"),e=e.object;const r=s.join("");return t||h.includes(r)?r:null}build(){return this.toString().length>0}astGeneric(e,t){if(null===e)throw this.astErrorOutput("NULL ast",e);if(Array.isArray(e)){for(let s=0;s0?r[r.length-1]:0;return new Error(`${e} on line ${r.length}, position ${i.length}:\n ${s}`)}astDebuggerStatement(e,t){return t}astConditionalExpression(e,t){if("ConditionalExpression"!==e.type)throw this.astErrorOutput("Not a conditional expression",e);return t.push("("),this.astGeneric(e.test,t),t.push("?"),this.astGeneric(e.consequent,t),t.push(":"),this.astGeneric(e.alternate,t),t.push(")"),t}astFunction(e,t){throw new Error(`"astFunction" not defined on ${this.constructor.name}`)}astFunctionDeclaration(e,t){return this.isChildFunction(e)?t:this.astFunction(e,t)}astFunctionExpression(e,t){return this.isChildFunction(e)?t:this.astFunction(e,t)}isChildFunction(e){for(let t=0;t1?t.push("(",r.join(","),")"):t.push(r[0]),t}astUnaryExpression(e,t){return this.checkAndUpconvertBitwiseUnary(e,t)||(e.prefix?(t.push(e.operator),this.astGeneric(e.argument,t)):(this.astGeneric(e.argument,t),t.push(e.operator))),t}checkAndUpconvertBitwiseUnary(e,t){}astUpdateExpression(e,t){return e.prefix?(t.push(e.operator),this.astGeneric(e.argument,t)):(this.astGeneric(e.argument,t),t.push(e.operator)),t}astLogicalExpression(e,t){return t.push("("),this.astGeneric(e.left,t),t.push(e.operator),this.astGeneric(e.right,t),t.push(")"),t}astMemberExpression(e,t){return t}astCallExpression(e,t){return t}astArrayExpression(e,t){return t}getMemberExpressionDetails(e){if("MemberExpression"!==e.type)throw this.astErrorOutput(`Expression ${e.type} not a MemberExpression`,e);let t=null,s=null;const r=this.getVariableSignature(e);switch(r){case"value":return null;case"value.thread.value":case"this.thread.value":case"this.output.value":return{signature:r,type:"Integer",name:e.property.name};case"value[]":if("string"!=typeof e.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.name,{name:t,origin:"user",signature:r,type:this.getVariableType(e.object),xProperty:e.property};case"value[][]":if("string"!=typeof e.object.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.object.name,{name:t,origin:"user",signature:r,type:this.getVariableType(e.object.object),yProperty:e.object.property,xProperty:e.property};case"value[][][]":if("string"!=typeof e.object.object.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.object.object.name,{name:t,origin:"user",signature:r,type:this.getVariableType(e.object.object.object),zProperty:e.object.object.property,yProperty:e.object.property,xProperty:e.property};case"value[][][][]":if("string"!=typeof e.object.object.object.object.name)throw this.astErrorOutput("Unexpected expression",e);return t=e.object.object.object.object.name,{name:t,origin:"user",signature:r,type:this.getVariableType(e.object.object.object.object),zProperty:e.object.object.property,yProperty:e.object.property,xProperty:e.property};case"value.value":if("string"!=typeof e.property.name)throw this.astErrorOutput("Unexpected expression",e);if(this.isAstMathVariable(e))return t=e.property.name,{name:t,origin:"Math",type:"Number",signature:r};switch(e.property.name){case"r":case"g":case"b":case"a":return t=e.object.name,{name:t,property:e.property.name,origin:"user",signature:r,type:"Number"};default:throw this.astErrorOutput("Unexpected expression",e)}case"this.constants.value":if("string"!=typeof e.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.property.name,s=this.getConstantType(t),!s)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:s,origin:"constants",signature:r};case"this.constants.value[]":if("string"!=typeof e.object.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.object.property.name,s=this.getConstantType(t),!s)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:s,origin:"constants",signature:r,xProperty:e.property};case"this.constants.value[][]":if("string"!=typeof e.object.object.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.object.object.property.name,s=this.getConstantType(t),!s)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:s,origin:"constants",signature:r,yProperty:e.object.property,xProperty:e.property};case"this.constants.value[][][]":if("string"!=typeof e.object.object.object.property.name)throw this.astErrorOutput("Unexpected expression",e);if(t=e.object.object.object.property.name,s=this.getConstantType(t),!s)throw this.astErrorOutput("Constant has no type",e);return{name:t,type:s,origin:"constants",signature:r,zProperty:e.object.object.property,yProperty:e.object.property,xProperty:e.property};case"fn()[]":case"fn()[][]":case"[][]":return{signature:r,property:e.property};default:throw this.astErrorOutput("Unexpected expression",e)}}findIdentifierOrigin(e){const t=[this.ast];for(;t.length>0;){const s=t[0];if("VariableDeclarator"===s.type&&s.id&&s.id.name&&s.id.name===e.name)return s;if(t.shift(),s.argument)t.push(s.argument);else if(s.body)t.push(s.body);else if(s.declarations)t.push(s.declarations);else if(Array.isArray(s))for(let e=0;e0;){const e=t.pop();if("ReturnStatement"===e.type)return e;if("FunctionDeclaration"!==e.type)if(e.argument)t.push(e.argument);else if(e.body)t.push(e.body);else if(e.declarations)t.push(e.declarations);else if(Array.isArray(e))for(let s=0;s{const{FunctionNode:s}=l();t.exports={CPUFunctionNode:class extends s{markupUserName(e){return this.isRootKernel&&this.getAssignedArguments().has(e)?`cellShadow_user_${e}`:`user_${e}`}astFunction(e,t){if(!this.isRootKernel){t.push("function"),t.push(" "),t.push(this.name),t.push("(");for(let e=0;e0&&t.push(", "),t.push("user_"),t.push(s)}t.push(") {\n")}if(this.isRootKernel){for(const e of this.getAssignedArguments())t.push(`let cellShadow_user_${e} = user_${e};\n`);t.push("kernelBody: {\n")}for(let s=0;s0&&t.push(s.join(""),";\n"),t.push(`for (let ${e}=0;${e}0&&t.push(`if (!${r.join("")}) break;\n`),t.push(i.join("")),t.push(`\n${n.join("")};`),t.push("}\n")}return t}astWhileStatement(e,t){if("WhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);return t.push("for (let i = 0; i < LOOP_MAX; i++) {"),t.push("if ("),this.astGeneric(e.test,t),t.push(") {\n"),this.astGeneric(e.body,t),t.push("} else {\n"),t.push("break;\n"),t.push("}\n"),t.push("}\n"),t}astDoWhileStatement(e,t){if("DoWhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);const s=`safeI${this.astKey(e,"_")}`;return t.push(`let ${s} = 0;\n`),t.push("do {"),this.astGeneric(e.body,t),t.push("} while (("),this.astGeneric(e.test,t),t.push(`) && ++${s} < LOOP_MAX);\n`),t}astAssignmentExpression(e,t){const s=this.getDeclaration(e.left);if(s&&!s.assignable)throw this.astErrorOutput(`Variable ${e.left.name} is not assignable here`,e);const r=this.isState("assignment-as-statement");return r?this.popState("assignment-as-statement"):t.push("("),this.astGeneric(e.left,t),t.push(e.operator),this.astGeneric(e.right,t),r||t.push(")"),t}astBlockStatement(e,t){if(this.isState("loop-body")){this.pushState("block-body");for(let s=0;s0&&t.push(",");const r=s[e],n=this.getDeclaration(r.id);n.valueType||(n.valueType=this.getType(r.init)),this.astGeneric(r,t)}return this.isState("in-for-loop-init")||t.push(";"),t}astIfStatement(e,t){return t.push("if ("),this.astGeneric(e.test,t),t.push(")"),"BlockStatement"===e.consequent.type?this.astGeneric(e.consequent,t):(t.push(" {\n"),this.astGeneric(e.consequent,t),t.push("\n}\n")),e.alternate&&(t.push("else "),"BlockStatement"===e.alternate.type||"IfStatement"===e.alternate.type?this.astGeneric(e.alternate,t):(t.push(" {\n"),this.astGeneric(e.alternate,t),t.push("\n}\n"))),t}astSwitchStatement(e,t){const{discriminant:s,cases:r}=e;t.push("switch ("),this.astGeneric(s,t),t.push(") {\n");for(let e=0;e0&&(this.astGeneric(r[e].consequent,t),t.push("break;\n"))):(t.push("default:\n"),this.astGeneric(r[e].consequent,t),r[e].consequent&&r[e].consequent.length>0&&t.push("break;\n"));t.push("\n}")}astThisExpression(e,t){return t.push("_this"),t}astMemberExpression(e,t){const{signature:s,type:r,property:n,xProperty:i,yProperty:a,zProperty:o,name:u,origin:l}=this.getMemberExpressionDetails(e);switch(s){case"this.thread.value":return t.push(`_this.thread.${u}`),t;case"this.output.value":switch(u){case"x":t.push("outputX");break;case"y":t.push("outputY");break;case"z":t.push("outputZ");break;default:throw this.astErrorOutput("Unexpected expression",e)}return t;case"value":default:throw this.astErrorOutput("Unexpected expression",e);case"value[]":case"value[][]":case"value[][][]":case"value.value":if("Math"===l)return t.push(Math[u]),t;switch(n){case"r":return t.push(`user_${u}[0]`),t;case"g":return t.push(`user_${u}[1]`),t;case"b":return t.push(`user_${u}[2]`),t;case"a":return t.push(`user_${u}[3]`),t}break;case"this.constants.value":case"this.constants.value[]":case"this.constants.value[][]":case"this.constants.value[][][]":break;case"fn()[]":return this.astGeneric(e.object,t),t.push("["),this.astGeneric(e.property,t),t.push("]"),t;case"fn()[][]":return this.astGeneric(e.object.object,t),t.push("["),this.astGeneric(e.object.property,t),t.push("]"),t.push("["),this.astGeneric(e.property,t),t.push("]"),t}if(!e.computed)switch(r){case"Number":case"Integer":case"Float":case"Boolean":return t.push("user"===l?this.markupUserName(u):`${l}_${u}`),t}const h="user"===l?this.markupUserName(u):`${l}_${u}`;{let e,s;if("constants"===l){const t=this.constants[u];s="Input"===this.constantTypes[u],e=s?t.size:null}else s=this.isInput(u),e=s?this.argumentSizes[this.argumentNames.indexOf(u)]:null;t.push(`${h}`),o&&a?s?(t.push("[("),this.astGeneric(o,t),t.push(`*${this.dynamicArguments?"(outputY * outputX)":e[1]*e[0]})+(`),this.astGeneric(a,t),t.push(`*${this.dynamicArguments?"outputX":e[0]})+`),this.astGeneric(i,t),t.push("]")):(t.push("["),this.astGeneric(o,t),t.push("]"),t.push("["),this.astGeneric(a,t),t.push("]"),t.push("["),this.astGeneric(i,t),t.push("]")):a?s?(t.push("[("),this.astGeneric(a,t),t.push(`*${this.dynamicArguments?"outputX":e[0]})+`),this.astGeneric(i,t),t.push("]")):(t.push("["),this.astGeneric(a,t),t.push("]"),t.push("["),this.astGeneric(i,t),t.push("]")):void 0!==i&&(t.push("["),this.astGeneric(i,t),t.push("]"))}return t}astCallExpression(e,t){if("CallExpression"!==e.type)throw this.astErrorOutput("Unknown CallExpression",e);let s=this.astMemberExpressionUnroll(e.callee);this.calledFunctions.indexOf(s)<0&&this.calledFunctions.push(s),this.isAstMathFunction(e),this.onFunctionCall&&this.onFunctionCall(this.name,s,e.arguments),t.push(s),t.push("(");const r=this.lookupFunctionArgumentTypes(s)||[];for(let n=0;n0&&t.push(", "),this.astGeneric(i,t)}return t.push(")"),t}astArrayExpression(e,t){const s=this.getType(e),r=e.elements.length,n=[];for(let t=0;t{const{utils:s}=i();t.exports={cpuKernelString:function(e,t){const r=[],n=[],i=[],a=!/^function/.test(e.color.toString());if(r.push(" const { context, canvas, constants: incomingConstants } = settings;",` const output = new Int32Array(${JSON.stringify(Array.from(e.output))});`,` const _constantTypes = ${JSON.stringify(e.constantTypes)};`,` const _constants = ${function(e,t){const s=[];for(const r in t){if(!t.hasOwnProperty(r))continue;const n=t[r],i=e[r];switch(n){case"Number":case"Integer":case"Float":case"Boolean":s.push(`${r}:${i}`);break;case"Array(2)":case"Array(3)":case"Array(4)":case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":s.push(`${r}:new ${i.constructor.name}(${JSON.stringify(Array.from(i))})`)}}return`{ ${s.join()} }`}(e.constants,e.constantTypes)};`),n.push(" constants: _constants,"," context,"," output,"," thread: {x: 0, y: 0, z: 0},"),e.graphical){r.push(` const _imageData = context.createImageData(${e.output[0]}, ${e.output[1]});`),r.push(` const _colorData = new Uint8ClampedArray(${e.output[0]} * ${e.output[1]} * 4);`);const t=s.flattenFunctionToString((a?"function ":"")+e.color.toString(),{thisLookup:t=>{switch(t){case"_colorData":return"_colorData";case"_imageData":return"_imageData";case"output":return"output";case"thread":return"this.thread"}return JSON.stringify(e[t])},findDependency:(e,t)=>null}),o=s.flattenFunctionToString((a?"function ":"")+e.getPixels.toString(),{thisLookup:t=>{switch(t){case"_colorData":return"_colorData";case"_imageData":return"_imageData";case"output":return"output";case"thread":return"this.thread"}return JSON.stringify(e[t])},findDependency:()=>null});n.push(" _imageData,"," _colorData,",` color: ${t},`),i.push(` kernel.getPixels = ${o};`)}const o=[],u=Object.keys(e.constantTypes);for(let t=0;t"this"===t?(a?"function ":"")+e[s].toString():null,thisLookup:e=>{switch(e){case"canvas":return;case"context":return"context"}}});i.push(t),n.push(" _mediaTo2DArray,"),n.push(" _imageTo3DArray,")}else if(-1!==e.argumentTypes.indexOf("HTMLImage")||-1!==o.indexOf("HTMLImage")){const t=s.flattenFunctionToString((a?"function ":"")+e._mediaTo2DArray.toString(),{findDependency:(e,t)=>null,thisLookup:e=>{switch(e){case"canvas":return"settings.canvas";case"context":return"settings.context"}throw new Error("unhandled thisLookup")}});i.push(t),n.push(" _mediaTo2DArray,")}return`function(settings) {\n${r.join("\n")}\n for (const p in _constantTypes) {\n if (!_constantTypes.hasOwnProperty(p)) continue;\n const type = _constantTypes[p];\n switch (type) {\n case 'Number':\n case 'Integer':\n case 'Float':\n case 'Boolean':\n case 'Array(2)':\n case 'Array(3)':\n case 'Array(4)':\n case 'Matrix(2)':\n case 'Matrix(3)':\n case 'Matrix(4)':\n if (incomingConstants.hasOwnProperty(p)) {\n console.warn('constant ' + p + ' of type ' + type + ' cannot be resigned');\n }\n continue;\n }\n if (!incomingConstants.hasOwnProperty(p)) {\n throw new Error('constant ' + p + ' not found');\n }\n _constants[p] = incomingConstants[p];\n }\n const kernel = (function() {\n${e._kernelString}\n })\n .apply({ ${n.join("\n")} });\n ${i.join("\n")}\n return kernel;\n}`}}}),p=e((e,t)=>{const{Kernel:s}=a(),{FunctionBuilder:r}=o(),{CPUFunctionNode:n}=h(),{utils:u}=i(),{cpuKernelString:l}=c();t.exports={CPUKernel:class extends s{static getFeatures(){return this.features}static get features(){return Object.freeze({kernelMap:!0,isIntegerDivisionAccurate:!0})}static get isSupported(){return!0}static isContextMatch(e){return!1}static get mode(){return"cpu"}static nativeFunctionArguments(){return null}static nativeFunctionReturnType(){throw new Error(`Looking up native function return type not supported on ${this.name}`)}static combineKernels(e){return e}static getSignature(e,t){return"cpu"+(t.length>0?":"+t.join(","):"")}constructor(e,t){super(e,t),this.mergeSettings(e.settings||t),this._imageData=null,this._colorData=null,this._kernelString=null,this._prependedString=[],this.thread={x:0,y:0,z:0},this.translatedSources=null}initCanvas(){return"undefined"!=typeof document?document.createElement("canvas"):"undefined"!=typeof OffscreenCanvas?new OffscreenCanvas(0,0):void 0}initContext(){return this.canvas?this.canvas.getContext("2d",{willReadFrequently:!0}):null}initPlugins(e){return[]}validateSettings(e){if(!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=u.getVariableType(e[0],this.strictIntegers);if("Array"===t)this.output=u.getDimensions(t);else{if("NumberTexture"!==t&&"ArrayTexture(4)"!==t)throw new Error("Auto output not supported for input type: "+t);this.output=e[0].output}}if(this.graphical&&2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");this.checkOutput()}translateSource(){if(this.leadingReturnStatement=this.output.length>1?"resultX[x] = ":"result[x] = ",this.subKernels){const e=[];for(let t=0;t1?`resultX_${s}[x] = subKernelResult_${s};\n`:`result_${s}[x] = subKernelResult_${s};\n`)}this.followingReturnStatement=e.join("")}const e=r.fromKernel(this,n);this.translatedSources=e.getPrototypes("kernel"),this.graphical||this.returnType||(this.returnType=e.getKernelResultType())}build(){if(this.built)return;if(null!==this.randomSeed&&console.warn("randomSeed is not supported in cpu mode; Math.random() will be unseeded"),this.setupConstants(),this.setupArguments(arguments),this.validateSettings(arguments),this.translateSource(),this.graphical){const{canvas:e,output:t}=this;if(!e)throw new Error("no canvas available for using graphical output");const s=t[0],r=t[1]||1;e.width=s,e.height=r,this._imageData=this.context.createImageData(s,r),this._colorData=new Uint8ClampedArray(s*r*4)}const e=this.getKernelString();this.kernelString=e,this.debug&&(console.log("Function output:"),console.log(e));try{this.run=new Function([],e).bind(this)()}catch(e){console.error("An error occurred compiling the javascript: ",e)}this.buildSignature(arguments),this.built=!0}color(e,t,s,r){void 0===r&&(r=1),e=Math.floor(255*e),t=Math.floor(255*t),s=Math.floor(255*s),r=Math.floor(255*r);const n=this.output[0],i=this.output[1],a=this.thread.x+(i-this.thread.y-1)*n;this._colorData[4*a+0]=e,this._colorData[4*a+1]=t,this._colorData[4*a+2]=s,this._colorData[4*a+3]=r}getKernelString(){if(null!==this._kernelString)return this._kernelString;let e=null,{translatedSources:t}=this;return t.length>1?t=t.filter(t=>/^function/.test(t)?t:(e=t,!1)):e=t.shift(),this._kernelString=` const LOOP_MAX = ${this._getLoopMaxString()};\n ${this.injectedNative||""}\n const _this = this;\n ${this._resultKernelHeader()}\n ${this._processConstants()}\n return (${this.argumentNames.map(e=>"user_"+e).join(", ")}) => {\n ${this._prependedString.join("")}\n ${this._earlyThrows()}\n ${this._processArguments()}\n ${this.graphical?this._graphicalKernelBody(e):this._resultKernelBody(e)}\n ${t.length>0?t.join("\n"):""}\n };`}toString(){return l(this)}_getLoopMaxString(){return this.loopMaxIterations?` ${parseInt(this.loopMaxIterations)};`:" 1000;"}_processConstants(){if(!this.constants)return"";const e=[];for(let t in this.constants)switch(this.constantTypes[t]){case"HTMLCanvas":case"OffscreenCanvas":case"HTMLImage":case"ImageBitmap":case"ImageData":case"HTMLVideo":e.push(` const constants_${t} = this._mediaTo2DArray(this.constants.${t});\n`);break;case"HTMLImageArray":e.push(` const constants_${t} = this._imageTo3DArray(this.constants.${t});\n`);break;case"Input":e.push(` const constants_${t} = this.constants.${t}.value;\n`);break;default:e.push(` const constants_${t} = this.constants.${t};\n`)}return e.join("")}_earlyThrows(){if(this.graphical)return"";if(this.immutable)return"";if(!this.pipeline)return"";const e=[];for(let t=0;t`user_${r} === result_${e.name}`).join(" || ");t.push(`user_${r} === result${n?` || ${n}`:""}`)}return`if (${t.join(" || ")}) throw new Error('Source and destination arrays are the same. Use immutable = true');`}_processArguments(){const e=[];for(let t=0;t0?e.width:e.videoWidth,r=e.height>0?e.height:e.videoHeight;t.width=0;e--){const t=a[e]=new Array(s);for(let e=0;e`const result_${e.name} = new ${t}(outputX);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n this.thread.y = 0;\n this.thread.z = 0;\n ${e}\n }`}_mutableKernel1DResults(){const e=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const result = new ${e}(outputX);\n ${this._mapSubKernels(t=>`const result_${t.name} = new ${e}(outputX);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}`}_resultMutableKernel1DLoop(e){return` const outputX = _this.output[0];\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n this.thread.y = 0;\n this.thread.z = 0;\n ${e}\n }`}_resultImmutableKernel2DLoop(e){const t=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const result = new Array(outputY);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputY);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n this.thread.z = 0;\n this.thread.y = y;\n const resultX = result[y] = new ${t}(outputX);\n ${this._mapSubKernels(e=>`const resultX_${e.name} = result_${e.name}[y] = new ${t}(outputX);\n`).join("")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }`}_mutableKernel2DResults(){const e=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const result = new Array(outputY);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputY);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n const resultX = result[y] = new ${e}(outputX);\n ${this._mapSubKernels(t=>`const resultX_${t.name} = result_${t.name}[y] = new ${e}(outputX);\n`).join("")}\n }`}_resultMutableKernel2DLoop(e){const t=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n for (let y = 0; y < outputY; y++) {\n this.thread.z = 0;\n this.thread.y = y;\n const resultX = result[y];\n ${this._mapSubKernels(e=>`const resultX_${e.name} = result_${e.name}[y] = new ${t}(outputX);\n`).join("")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }`}_graphicalKernel2DLoop(e){return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n for (let y = 0; y < outputY; y++) {\n this.thread.z = 0;\n this.thread.y = y;\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }`}_resultImmutableKernel3DLoop(e){const t=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const outputZ = _this.output[2];\n const result = new Array(outputZ);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputZ);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let z = 0; z < outputZ; z++) {\n this.thread.z = z;\n const resultY = result[z] = new Array(outputY);\n ${this._mapSubKernels(e=>`const resultY_${e.name} = result_${e.name}[z] = new Array(outputY);\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n this.thread.y = y;\n const resultX = resultY[y] = new ${t}(outputX);\n ${this._mapSubKernels(e=>`const resultX_${e.name} = resultY_${e.name}[y] = new ${t}(outputX);\n`).join(" ")}\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }\n }`}_mutableKernel3DResults(){const e=this._getKernelResultTypeConstructorString();return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const outputZ = _this.output[2];\n const result = new Array(outputZ);\n ${this._mapSubKernels(e=>`const result_${e.name} = new Array(outputZ);\n`).join(" ")}\n ${this._mapSubKernels(e=>`let subKernelResult_${e.name};\n`).join(" ")}\n for (let z = 0; z < outputZ; z++) {\n const resultY = result[z] = new Array(outputY);\n ${this._mapSubKernels(e=>`const resultY_${e.name} = result_${e.name}[z] = new Array(outputY);\n`).join(" ")}\n for (let y = 0; y < outputY; y++) {\n const resultX = resultY[y] = new ${e}(outputX);\n ${this._mapSubKernels(t=>`const resultX_${t.name} = resultY_${t.name}[y] = new ${e}(outputX);\n`).join(" ")}\n }\n }`}_resultMutableKernel3DLoop(e){return` const outputX = _this.output[0];\n const outputY = _this.output[1];\n const outputZ = _this.output[2];\n for (let z = 0; z < outputZ; z++) {\n this.thread.z = z;\n const resultY = result[z];\n for (let y = 0; y < outputY; y++) {\n this.thread.y = y;\n const resultX = resultY[y];\n for (let x = 0; x < outputX; x++) {\n this.thread.x = x;\n ${e}\n }\n }\n }`}_kernelOutput(){return this.subKernels?`\n return {\n result: result,\n ${this.subKernels.map(e=>`${e.property}: result_${e.name}`).join(",\n ")}\n };`:"\n return result;"}_mapSubKernels(e){return null===this.subKernels?[""]:this.subKernels.map(e)}destroy(e){e&&delete this.canvas}static destroyContext(e){}toJSON(){const e=super.toJSON();return e.functionNodes=r.fromKernel(this,n).toJSON(),e}setOutput(e){super.setOutput(e);const[t,s]=this.output;this.graphical&&(this._imageData=this.context.createImageData(t,s),this._colorData=new Uint8ClampedArray(t*s*4))}prependString(e){if(this._kernelString)throw new Error("Kernel already built");this._prependedString.push(e)}hasPrependString(e){return this._prependedString.indexOf(e)>-1}}}}),d=e((e,t)=>{t.exports={}}),f=e((e,t)=>{const{Texture:s}=n();function r(e,t){e.activeTexture(e.TEXTURE15),e.bindTexture(e.TEXTURE_2D,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST)}t.exports={GLTexture:class extends s{get textureType(){throw new Error(`"textureType" not implemented on ${this.name}`)}clone(){return new this.constructor(this)}beforeMutate(){return this.texture._refs>1&&(this.newTexture(),!0)}cloneTexture(){this.texture._refs--;const{context:e,size:t,texture:s,kernel:n}=this;n.debug&&console.warn("cloning internal texture"),e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),r(e,s),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,s,0);const i=e.createTexture();r(e,i),e.texImage2D(e.TEXTURE_2D,0,this.internalFormat,t[0],t[1],0,this.textureFormat,this.textureType,null),e.copyTexSubImage2D(e.TEXTURE_2D,0,0,0,0,0,t[0],t[1]),i._refs=1,this.texture=i}newTexture(){this.texture._refs--;const e=this.context,t=this.size;this.kernel.debug&&console.warn("new internal texture");const s=e.createTexture();r(e,s),e.texImage2D(e.TEXTURE_2D,0,this.internalFormat,t[0],t[1],0,this.textureFormat,this.textureType,null),s._refs=1,this.texture=s}clear(){if(this.texture._refs){this.texture._refs--;const e=this.context,t=this.texture=e.createTexture();r(e,t);const s=this.size;t._refs=1,e.texImage2D(e.TEXTURE_2D,0,this.internalFormat,s[0],s[1],0,this.textureFormat,this.textureType,null)}const{context:e,texture:t}=this;e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),e.bindTexture(e.TEXTURE_2D,t),r(e,t),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t,0),e.clearColor(0,0,0,0),e.clear(e.COLOR_BUFFER_BIT|e.DEPTH_BUFFER_BIT)}delete(){this._deleted||(this._deleted=!0,this.texture._refs&&(this.texture._refs--,this.texture._refs)||(this.kernel&&this.kernel.deleteTexture?this.kernel.deleteTexture(this.texture):this.context.deleteTexture(this.texture)))}framebuffer(){return this._framebuffer||(this._framebuffer=this.kernel.getRawValueFramebuffer(this.size[0],this.size[1])),this._framebuffer}}}}),m=e((e,t)=>{const{utils:s}=i(),{GLTexture:r}=f();t.exports={GLTextureFloat:class extends r{get textureType(){return this.context.FLOAT}constructor(e){super(e),this.type="ArrayTexture(1)"}renderRawOutput(){const e=this.context,t=this.size;e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.texture,0);const s=new Float32Array(t[0]*t[1]*4);return e.readPixels(0,0,t[0],t[1],e.RGBA,e.FLOAT,s),s}renderValues(){return this._deleted?null:this.renderRawOutput()}toArray(){return s.erectFloat(this.renderValues(),this.output[0])}}}}),g=e((e,t)=>{const{utils:s}=i(),{GLTextureFloat:r}=m();t.exports={GLTextureArray2Float:class extends r{constructor(e){super(e),this.type="ArrayTexture(2)"}toArray(){return s.erectArray2(this.renderValues(),this.output[0],this.output[1])}}}}),x=e((e,t)=>{const{utils:s}=i(),{GLTextureFloat:r}=m();t.exports={GLTextureArray2Float2D:class extends r{constructor(e){super(e),this.type="ArrayTexture(2)"}toArray(){return s.erect2DArray2(this.renderValues(),this.output[0],this.output[1])}}}}),y=e((e,t)=>{const{utils:s}=i(),{GLTextureFloat:r}=m();t.exports={GLTextureArray2Float3D:class extends r{constructor(e){super(e),this.type="ArrayTexture(2)"}toArray(){return s.erect3DArray2(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),b=e((e,t)=>{const{utils:s}=i(),{GLTextureFloat:r}=m();t.exports={GLTextureArray3Float:class extends r{constructor(e){super(e),this.type="ArrayTexture(3)"}toArray(){return s.erectArray3(this.renderValues(),this.output[0])}}}}),v=e((e,t)=>{const{utils:s}=i(),{GLTextureFloat:r}=m();t.exports={GLTextureArray3Float2D:class extends r{constructor(e){super(e),this.type="ArrayTexture(3)"}toArray(){return s.erect2DArray3(this.renderValues(),this.output[0],this.output[1])}}}}),S=e((e,t)=>{const{utils:s}=i(),{GLTextureFloat:r}=m();t.exports={GLTextureArray3Float3D:class extends r{constructor(e){super(e),this.type="ArrayTexture(3)"}toArray(){return s.erect3DArray3(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),T=e((e,t)=>{const{utils:s}=i(),{GLTextureFloat:r}=m();t.exports={GLTextureArray4Float:class extends r{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return s.erectArray4(this.renderValues(),this.output[0])}}}}),A=e((e,t)=>{const{utils:s}=i(),{GLTextureFloat:r}=m();t.exports={GLTextureArray4Float2D:class extends r{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return s.erect2DArray4(this.renderValues(),this.output[0],this.output[1])}}}}),w=e((e,t)=>{const{utils:s}=i(),{GLTextureFloat:r}=m();t.exports={GLTextureArray4Float3D:class extends r{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return s.erect3DArray4(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),E=e((e,t)=>{const{utils:s}=i(),{GLTextureFloat:r}=m();t.exports={GLTextureFloat2D:class extends r{constructor(e){super(e),this.type="ArrayTexture(1)"}toArray(){return s.erect2DFloat(this.renderValues(),this.output[0],this.output[1])}}}}),_=e((e,t)=>{const{utils:s}=i(),{GLTextureFloat:r}=m();t.exports={GLTextureFloat3D:class extends r{constructor(e){super(e),this.type="ArrayTexture(1)"}toArray(){return s.erect3DFloat(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),I=e((e,t)=>{const{utils:s}=i(),{GLTextureFloat:r}=m();t.exports={GLTextureMemoryOptimized:class extends r{constructor(e){super(e),this.type="MemoryOptimizedNumberTexture"}toArray(){return s.erectMemoryOptimizedFloat(this.renderValues(),this.output[0])}}}}),k=e((e,t)=>{const{utils:s}=i(),{GLTextureFloat:r}=m();t.exports={GLTextureMemoryOptimized2D:class extends r{constructor(e){super(e),this.type="MemoryOptimizedNumberTexture"}toArray(){return s.erectMemoryOptimized2DFloat(this.renderValues(),this.output[0],this.output[1])}}}}),C=e((e,t)=>{const{utils:s}=i(),{GLTextureFloat:r}=m();t.exports={GLTextureMemoryOptimized3D:class extends r{constructor(e){super(e),this.type="MemoryOptimizedNumberTexture"}toArray(){return s.erectMemoryOptimized3DFloat(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),L=e((e,t)=>{const{utils:s}=i(),{GLTexture:r}=f();t.exports={GLTextureUnsigned:class extends r{get textureType(){return this.context.UNSIGNED_BYTE}constructor(e){super(e),this.type="NumberTexture"}renderRawOutput(){const{context:e}=this;e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer()),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.texture,0);const t=new Uint8Array(this.size[0]*this.size[1]*4);return e.readPixels(0,0,this.size[0],this.size[1],e.RGBA,e.UNSIGNED_BYTE,t),t}renderValues(){return this._deleted?null:new Float32Array(this.renderRawOutput().buffer)}toArray(){return s.erectPackedFloat(this.renderValues(),this.output[0])}}}}),D=e((e,t)=>{const{utils:s}=i(),{GLTextureUnsigned:r}=L();t.exports={GLTextureUnsigned2D:class extends r{constructor(e){super(e),this.type="NumberTexture"}toArray(){return s.erect2DPackedFloat(this.renderValues(),this.output[0],this.output[1])}}}}),F=e((e,t)=>{const{utils:s}=i(),{GLTextureUnsigned:r}=L();t.exports={GLTextureUnsigned3D:class extends r{constructor(e){super(e),this.type="NumberTexture"}toArray(){return s.erect3DPackedFloat(this.renderValues(),this.output[0],this.output[1],this.output[2])}}}}),$=e((e,t)=>{const{GLTextureUnsigned:s}=L();t.exports={GLTextureGraphical:class extends s{constructor(e){super(e),this.type="ArrayTexture(4)"}toArray(){return this.renderValues()}}}}),N=e((e,t)=>{const{Kernel:s}=a(),{utils:r}=i(),{GLTextureArray2Float:n}=g(),{GLTextureArray2Float2D:o}=x(),{GLTextureArray2Float3D:u}=y(),{GLTextureArray3Float:l}=b(),{GLTextureArray3Float2D:h}=v(),{GLTextureArray3Float3D:c}=S(),{GLTextureArray4Float:p}=T(),{GLTextureArray4Float2D:d}=A(),{GLTextureArray4Float3D:f}=w(),{GLTextureFloat:N}=m(),{GLTextureFloat2D:R}=E(),{GLTextureFloat3D:M}=_(),{GLTextureMemoryOptimized:G}=I(),{GLTextureMemoryOptimized2D:O}=k(),{GLTextureMemoryOptimized3D:V}=C(),{GLTextureUnsigned:P}=L(),{GLTextureUnsigned2D:z}=D(),{GLTextureUnsigned3D:U}=F(),{GLTextureGraphical:B}=$();const K={int:"Integer",float:"Number",vec2:"Array(2)",vec3:"Array(3)",vec4:"Array(4)"};t.exports={GLKernel:class extends s{static get mode(){return"gpu"}static getIsFloatRead(){const e=new this("function kernelFunction() {\n return 1;\n }",{context:this.testContext,canvas:this.testCanvas,validate:!1,output:[1],precision:"single",returnType:"Number",tactic:"speed"});e.build(),e.run();const t=e.renderOutput();return e.destroy(!0),1===t[0]}static getIsIntegerDivisionAccurate(){const e=new this(function(e,t){return e[this.thread.x]/t[this.thread.x]}.toString(),{context:this.testContext,canvas:this.testCanvas,validate:!1,output:[2],returnType:"Number",precision:"unsigned",tactic:"speed"}),t=[[6,6030401],[3,3991]];e.build.apply(e,t),e.run.apply(e,t);const s=e.renderOutput();return e.destroy(!0),2===s[0]&&1511===s[1]}static getIsSpeedTacticSupported(){const e=new this(function(e){return e[this.thread.x]}.toString(),{context:this.testContext,canvas:this.testCanvas,validate:!1,output:[4],returnType:"Number",precision:"unsigned",tactic:"speed"}),t=[[0,1,2,3]];e.build.apply(e,t),e.run.apply(e,t);const s=e.renderOutput();return e.destroy(!0),0===Math.round(s[0])&&1===Math.round(s[1])&&2===Math.round(s[2])&&3===Math.round(s[3])}static get testCanvas(){throw new Error(`"testCanvas" not defined on ${this.name}`)}static get testContext(){throw new Error(`"testContext" not defined on ${this.name}`)}static getFeatures(){const e=this.testContext,t=this.getIsDrawBuffers();return Object.freeze({isFloatRead:this.getIsFloatRead(),isIntegerDivisionAccurate:this.getIsIntegerDivisionAccurate(),isSpeedTacticSupported:this.getIsSpeedTacticSupported(),isTextureFloat:this.getIsTextureFloat(),isDrawBuffers:t,kernelMap:t,channelCount:this.getChannelCount(),maxTextureSize:this.getMaxTextureSize(),lowIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_INT),lowFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_FLOAT),mediumIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_INT),mediumFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_FLOAT),highIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_INT),highFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT)})}static setupFeatureChecks(){throw new Error(`"setupFeatureChecks" not defined on ${this.name}`)}static getSignature(e,t){return e.getVariablePrecisionString()+(t.length>0?":"+t.join(","):"")}setFixIntegerDivisionAccuracy(e){return this.fixIntegerDivisionAccuracy=e,this}setPrecision(e){return this.precision=e,this}setFloatTextures(e){return r.warnDeprecated("method","setFloatTextures","setOptimizeFloatMemory"),this.floatTextures=e,this}static nativeFunctionArguments(e){const t=[],s=[],r=[],n=/^[a-zA-Z_]/,i=/[a-zA-Z_0-9]/;let a=0,o=null,u=null;for(;a0?r[r.length-1]:null;if("FUNCTION_ARGUMENTS"!==c||"/"!==l||"*"!==h)if("MULTI_LINE_COMMENT"!==c||"*"!==l||"/"!==h)if("FUNCTION_ARGUMENTS"!==c||"/"!==l||"/"!==h)if("COMMENT"!==c||"\n"!==l)if(null!==c||"("!==l){if("FUNCTION_ARGUMENTS"===c){if(")"===l){r.pop();break}if("f"===l&&"l"===h&&"o"===e[a+2]&&"a"===e[a+3]&&"t"===e[a+4]&&" "===e[a+5]){r.push("DECLARE_VARIABLE"),u="float",o="",a+=6;continue}if("i"===l&&"n"===h&&"t"===e[a+2]&&" "===e[a+3]){r.push("DECLARE_VARIABLE"),u="int",o="",a+=4;continue}if("v"===l&&"e"===h&&"c"===e[a+2]&&"2"===e[a+3]&&" "===e[a+4]){r.push("DECLARE_VARIABLE"),u="vec2",o="",a+=5;continue}if("v"===l&&"e"===h&&"c"===e[a+2]&&"3"===e[a+3]&&" "===e[a+4]){r.push("DECLARE_VARIABLE"),u="vec3",o="",a+=5;continue}if("v"===l&&"e"===h&&"c"===e[a+2]&&"4"===e[a+3]&&" "===e[a+4]){r.push("DECLARE_VARIABLE"),u="vec4",o="",a+=5;continue}}else if("DECLARE_VARIABLE"===c){if(""===o){if(" "===l){a++;continue}if(!n.test(l))throw new Error("variable name is not expected string")}o+=l,i.test(h)||(r.pop(),s.push(o),t.push(K[u]))}a++}else r.push("FUNCTION_ARGUMENTS"),a++;else r.pop(),a++;else r.push("COMMENT"),a+=2;else r.pop(),a+=2;else r.push("MULTI_LINE_COMMENT"),a+=2}if(r.length>0)throw new Error("GLSL function was not parsable");return{argumentNames:s,argumentTypes:t}}static nativeFunctionReturnType(e){return K[e.match(/int|float|vec[2-4]/)[0]]}static combineKernels(e,t){e.apply(null,arguments);const{texSize:s,context:n,threadDim:i}=t.texSize;let a;if("single"===t.precision){const e=s[0],t=Math.ceil(s[1]/4);a=new Float32Array(e*t*4*4),n.readPixels(0,0,e,4*t,n.RGBA,n.FLOAT,a)}else{const e=new Uint8Array(s[0]*s[1]*4);n.readPixels(0,0,s[0],s[1],n.RGBA,n.UNSIGNED_BYTE,e),a=new Float32Array(e.buffer)}return a=a.subarray(0,i[0]*i[1]*i[2]),1===t.output.length?a:2===t.output.length?r.splitArray(a,t.output[0]):3===t.output.length?r.splitArray(a,t.output[0]*t.output[1]).map(function(e){return r.splitArray(e,t.output[0])}):void 0}constructor(e,t){super(e,t),this.transferValues=null,this.formatValues=null,this.TextureConstructor=null,this.renderOutput=null,this.renderRawOutput=null,this.texSize=null,this.translatedSource=null,this.compiledFragmentShader=null,this.compiledVertexShader=null,this.switchingKernels=null,this._textureSwitched=null,this._mappedTextureSwitched=null}checkTextureSize(){const{features:e}=this.constructor;if(this.texSize[0]>e.maxTextureSize||this.texSize[1]>e.maxTextureSize)throw new Error(`Texture size [${this.texSize[0]},${this.texSize[1]}] generated by kernel is larger than supported size [${e.maxTextureSize},${e.maxTextureSize}]`)}translateSource(){throw new Error(`"translateSource" not defined on ${this.constructor.name}`)}pickRenderStrategy(e){if(this.graphical)return this.renderRawOutput=this.readPackedPixelsToUint8Array,this.transferValues=e=>e,this.TextureConstructor=B,null;if("unsigned"===this.precision)if(this.renderRawOutput=this.readPackedPixelsToUint8Array,this.transferValues=this.readPackedPixelsToFloat32Array,this.pipeline)switch(this.renderOutput=this.renderTexture,null!==this.subKernels&&(this.renderKernels=this.renderKernelsToTextures),this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.output[2]>0?(this.TextureConstructor=U,null):this.output[1]>0?(this.TextureConstructor=z,null):(this.TextureConstructor=P,null);case"Array(2)":case"Array(3)":case"Array(4)":return this.requestFallback(e,`${this.returnType} output requires single precision, which this context does not support`)}else switch(null!==this.subKernels&&(this.renderKernels=this.renderKernelsToArrays),this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.renderOutput=this.renderValues,this.output[2]>0?(this.TextureConstructor=U,this.formatValues=r.erect3DPackedFloat,null):this.output[1]>0?(this.TextureConstructor=z,this.formatValues=r.erect2DPackedFloat,null):(this.TextureConstructor=P,this.formatValues=r.erectPackedFloat,null);case"Array(2)":case"Array(3)":case"Array(4)":return this.requestFallback(e,`${this.returnType} output requires single precision, which this context does not support`)}else{if("single"!==this.precision)throw new Error(`unhandled precision of "${this.precision}"`);if(this.renderRawOutput=this.readFloatPixelsToFloat32Array,this.transferValues=this.readFloatPixelsToFloat32Array,this.pipeline)switch(this.renderOutput=this.renderTexture,null!==this.subKernels&&(this.renderKernels=this.renderKernelsToTextures),this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.optimizeFloatMemory?this.output[2]>0?(this.TextureConstructor=V,null):this.output[1]>0?(this.TextureConstructor=O,null):(this.TextureConstructor=G,null):this.output[2]>0?(this.TextureConstructor=M,null):this.output[1]>0?(this.TextureConstructor=R,null):(this.TextureConstructor=N,null);case"Array(2)":return this.output[2]>0?(this.TextureConstructor=u,null):this.output[1]>0?(this.TextureConstructor=o,null):(this.TextureConstructor=n,null);case"Array(3)":return this.output[2]>0?(this.TextureConstructor=c,null):this.output[1]>0?(this.TextureConstructor=h,null):(this.TextureConstructor=l,null);case"Array(4)":return this.output[2]>0?(this.TextureConstructor=f,null):this.output[1]>0?(this.TextureConstructor=d,null):(this.TextureConstructor=p,null)}if(this.renderOutput=this.renderValues,null!==this.subKernels&&(this.renderKernels=this.renderKernelsToArrays),this.optimizeFloatMemory)switch(this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.output[2]>0?(this.TextureConstructor=V,this.formatValues=r.erectMemoryOptimized3DFloat,null):this.output[1]>0?(this.TextureConstructor=O,this.formatValues=r.erectMemoryOptimized2DFloat,null):(this.TextureConstructor=G,this.formatValues=r.erectMemoryOptimizedFloat,null);case"Array(2)":return this.output[2]>0?(this.TextureConstructor=u,this.formatValues=r.erect3DArray2,null):this.output[1]>0?(this.TextureConstructor=o,this.formatValues=r.erect2DArray2,null):(this.TextureConstructor=n,this.formatValues=r.erectArray2,null);case"Array(3)":return this.output[2]>0?(this.TextureConstructor=c,this.formatValues=r.erect3DArray3,null):this.output[1]>0?(this.TextureConstructor=h,this.formatValues=r.erect2DArray3,null):(this.TextureConstructor=l,this.formatValues=r.erectArray3,null);case"Array(4)":return this.output[2]>0?(this.TextureConstructor=f,this.formatValues=r.erect3DArray4,null):this.output[1]>0?(this.TextureConstructor=d,this.formatValues=r.erect2DArray4,null):(this.TextureConstructor=p,this.formatValues=r.erectArray4,null)}else switch(this.returnType){case"LiteralInteger":case"Float":case"Number":case"Integer":return this.output[2]>0?(this.TextureConstructor=M,this.formatValues=r.erect3DFloat,null):this.output[1]>0?(this.TextureConstructor=R,this.formatValues=r.erect2DFloat,null):(this.TextureConstructor=N,this.formatValues=r.erectFloat,null);case"Array(2)":return this.output[2]>0?(this.TextureConstructor=u,this.formatValues=r.erect3DArray2,null):this.output[1]>0?(this.TextureConstructor=o,this.formatValues=r.erect2DArray2,null):(this.TextureConstructor=n,this.formatValues=r.erectArray2,null);case"Array(3)":return this.output[2]>0?(this.TextureConstructor=c,this.formatValues=r.erect3DArray3,null):this.output[1]>0?(this.TextureConstructor=h,this.formatValues=r.erect2DArray3,null):(this.TextureConstructor=l,this.formatValues=r.erectArray3,null);case"Array(4)":return this.output[2]>0?(this.TextureConstructor=f,this.formatValues=r.erect3DArray4,null):this.output[1]>0?(this.TextureConstructor=d,this.formatValues=r.erect2DArray4,null):(this.TextureConstructor=p,this.formatValues=r.erectArray4,null)}}throw new Error(`unhandled return type "${this.returnType}"`)}getKernelString(){throw new Error("abstract method call")}getMainResultTexture(){switch(this.returnType){case"LiteralInteger":case"Float":case"Integer":case"Number":return this.getMainResultNumberTexture();case"Array(2)":return this.getMainResultArray2Texture();case"Array(3)":return this.getMainResultArray3Texture();case"Array(4)":return this.getMainResultArray4Texture();default:throw new Error(`unhandled returnType type ${this.returnType}`)}}getMainResultKernelNumberTexture(){throw new Error("abstract method call")}getMainResultSubKernelNumberTexture(){throw new Error("abstract method call")}getMainResultKernelArray2Texture(){throw new Error("abstract method call")}getMainResultSubKernelArray2Texture(){throw new Error("abstract method call")}getMainResultKernelArray3Texture(){throw new Error("abstract method call")}getMainResultSubKernelArray3Texture(){throw new Error("abstract method call")}getMainResultKernelArray4Texture(){throw new Error("abstract method call")}getMainResultSubKernelArray4Texture(){throw new Error("abstract method call")}getMainResultGraphical(){throw new Error("abstract method call")}getMainResultMemoryOptimizedFloats(){throw new Error("abstract method call")}getMainResultPackedPixels(){throw new Error("abstract method call")}getMainResultString(){return this.graphical?this.getMainResultGraphical():"single"===this.precision?this.optimizeFloatMemory?this.getMainResultMemoryOptimizedFloats():this.getMainResultTexture():this.getMainResultPackedPixels()}getMainResultNumberTexture(){return r.linesToString(this.getMainResultKernelNumberTexture())+r.linesToString(this.getMainResultSubKernelNumberTexture())}getMainResultArray2Texture(){return r.linesToString(this.getMainResultKernelArray2Texture())+r.linesToString(this.getMainResultSubKernelArray2Texture())}getMainResultArray3Texture(){return r.linesToString(this.getMainResultKernelArray3Texture())+r.linesToString(this.getMainResultSubKernelArray3Texture())}getMainResultArray4Texture(){return r.linesToString(this.getMainResultKernelArray4Texture())+r.linesToString(this.getMainResultSubKernelArray4Texture())}getFloatTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic)} float;\n`}getIntTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic,!0)} int;\n`}getSampler2DTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic)} sampler2D;\n`}getSampler2DArrayTacticDeclaration(){return`precision ${this.getVariablePrecisionString(this.texSize,this.tactic)} sampler2DArray;\n`}renderTexture(){return this.immutable?this.texture.clone():this.texture}readPackedPixelsToUint8Array(){if("unsigned"!==this.precision)throw new Error('Requires this.precision to be "unsigned"');const{texSize:e,context:t}=this,s=new Uint8Array(e[0]*e[1]*4);return t.readPixels(0,0,e[0],e[1],t.RGBA,t.UNSIGNED_BYTE,s),s}readPackedPixelsToFloat32Array(){return new Float32Array(this.readPackedPixelsToUint8Array().buffer)}readFloatPixelsToFloat32Array(){if("single"!==this.precision)throw new Error('Requires this.precision to be "single"');const{texSize:e,context:t}=this,s=e[0],r=e[1],n=new Float32Array(s*r*4);return t.readPixels(0,0,s,r,t.RGBA,t.FLOAT,n),n}getPixels(e){const{context:t,output:s}=this,[n,i]=s,a=new Uint8Array(n*i*4);t.readPixels(0,0,n,i,t.RGBA,t.UNSIGNED_BYTE,a);const o=new Uint8ClampedArray((e?a:r.flipPixels(a,n,i)).buffer);return this.asyncMode?Promise.resolve(o):o}renderKernelsToArrays(){const e={result:this.renderOutput()};for(let t=0;t0){for(let e=0;e0){const{mappedTextures:s}=this;for(let r=0;r{const{utils:s}=i(),{FunctionNode:r}=l(),n={"<":"ceil",">=":"ceil",">":"floor","<=":"floor"};function a(e){if(!e||"object"!=typeof e)return!0;if(Array.isArray(e))return e.every(a);if("UpdateExpression"===e.type||"AssignmentExpression"===e.type||"SequenceExpression"===e.type)return!1;for(const t in e)if("loc"!==t&&"range"!==t&&"parent"!==t&&!a(e[t]))return!1;return!0}function o(e){let t=!1;function s(e){if(!e||"object"!=typeof e||t)return!1;if(Array.isArray(e))return e.some(s);if("MemberExpression"===e.type&&e.computed)return!0;for(const t in e)if("loc"!==t&&"range"!==t&&"parent"!==t&&s(e[t]))return!0;return!1}return function e(r){if(r&&"object"==typeof r&&!t)if(Array.isArray(r))r.forEach(e);else if("MemberExpression"===r.type&&r.computed&&s(r.property))t=!0;else for(const t in r)"loc"!==t&&"range"!==t&&"parent"!==t&&e(r[t])}(e),t}function u(e,t){if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(e=>u(e,t));if("CallExpression"===e.type&&"Identifier"===e.callee.type&&e.callee.name===t)return!0;for(const s in e)if("loc"!==s&&"range"!==s&&"parent"!==s&&u(e[s],t))return!0;return!1}function h(e){let t=!1;return function e(s){if(s&&"object"==typeof s&&!t)if(Array.isArray(s))s.forEach(e);else if("CallExpression"===s.type&&"Identifier"===s.callee.type&&s.arguments.some(e=>u(e,s.callee.name)))t=!0;else for(const t in s)"loc"!==t&&"range"!==t&&"parent"!==t&&e(s[t])}(e),t}function c(e){const t="ExpressionStatement"===e.type&&"AssignmentExpression"===e.expression.type?e.expression:null;return function e(s){if(!s||"object"!=typeof s)return!0;if(Array.isArray(s))return s.every(e);if("string"==typeof s.type){if("UpdateExpression"===s.type||"SequenceExpression"===s.type)return!1;if("AssignmentExpression"===s.type&&s!==t)return!1}for(const t in s)if("loc"!==t&&"range"!==t&&"parent"!==t&&!e(s[t]))return!1;return!0}(e)}const p={"Matrix(2)":2,"Matrix(3)":3,"Matrix(4)":4},d={Array:"sampler2D","Array(2)":"vec2","Array(3)":"vec3","Array(4)":"vec4","Matrix(2)":"mat2","Matrix(3)":"mat3","Matrix(4)":"mat4",Array2D:"sampler2D",Array3D:"sampler2D",Boolean:"bool",Float:"float",Input:"sampler2D",Integer:"int",Number:"float",LiteralInteger:"float",NumberTexture:"sampler2D",MemoryOptimizedNumberTexture:"sampler2D","ArrayTexture(1)":"sampler2D","ArrayTexture(2)":"sampler2D","ArrayTexture(3)":"sampler2D","ArrayTexture(4)":"sampler2D",HTMLVideo:"sampler2D",HTMLCanvas:"sampler2D",OffscreenCanvas:"sampler2D",HTMLImage:"sampler2D",ImageBitmap:"sampler2D",ImageData:"sampler2D",HTMLImageArray:"sampler2DArray"},f={"===":"==","!==":"!="};t.exports={WebGLFunctionNode:class extends r{constructor(e,t){super(e,t),t&&t.hasOwnProperty("fixIntegerDivisionAccuracy")&&(this.fixIntegerDivisionAccuracy=t.fixIntegerDivisionAccuracy)}astConditionalExpression(e,t){if("ConditionalExpression"!==e.type)throw this.astErrorOutput("Not a conditional expression",e);const s=this.getType(e.consequent),r=this.getType(e.alternate);return null===s&&null===r?(t.push("if ("),this.astGeneric(e.test,t),t.push(") {"),this.astGeneric(e.consequent,t),t.push(";"),t.push("} else {"),this.astGeneric(e.alternate,t),t.push(";"),t.push("}"),t):(t.push("("),this.astGeneric(e.test,t),t.push("?"),this.astGeneric(e.consequent,t),t.push(":"),this.astGeneric(e.alternate,t),t.push(")"),t)}astFunction(e,t){if(this.isRootKernel)t.push("void");else{this.returnType||this.findLastReturn()&&(this.returnType=this.getType(e.body),"LiteralInteger"===this.returnType&&(this.returnType="Number"));const{returnType:s}=this;if(s){const e=d[s];if(!e)throw new Error(`unknown type ${s}`);t.push(e)}else t.push("void")}if(t.push(" "),t.push(this.name),t.push("("),!this.isRootKernel)for(let r=0;r0&&t.push(", ");let i=this.argumentTypes[this.argumentNames.indexOf(n)];if(!i)throw this.astErrorOutput(`Unknown argument ${n} type`,e);"LiteralInteger"===i&&(this.argumentTypes[r]=i="Number");const a=d[i];if(!a)throw this.astErrorOutput("Unexpected expression",e);const o=s.sanitizeName(n);"sampler2D"===a||"sampler2DArray"===a?t.push(`${a} user_${o},ivec2 user_${o}Size,ivec3 user_${o}Dim`):t.push(`${a} user_${o}`)}if(t.push(") {\n"),this.isRootKernel){const e=this.getAssignedArguments();for(let r=0;r>":"bitwiseSignedRightShift",">>>":"bitwiseZeroFillRightShift"}[e.operator];if(!s)return null;switch(t.push(s),t.push("("),this.getType(e.left)){case"Number":case"Float":this.castValueToInteger(e.left,t);break;case"LiteralInteger":this.castLiteralToInteger(e.left,t);break;default:this.astGeneric(e.left,t)}switch(t.push(","),this.getType(e.right)){case"Number":case"Float":this.castValueToInteger(e.right,t);break;case"LiteralInteger":this.castLiteralToInteger(e.right,t);break;default:this.astGeneric(e.right,t)}return t.push(")"),t}checkAndUpconvertBitwiseUnary(e,t){const s={"~":"bitwiseNot"}[e.operator];if(!s)return null;switch(t.push(s),t.push("("),this.getType(e.argument)){case"Number":case"Float":this.castValueToInteger(e.argument,t);break;case"LiteralInteger":this.castLiteralToInteger(e.argument,t);break;default:this.astGeneric(e.argument,t)}return t.push(")"),t}castLiteralToInteger(e,t){return this.pushState("casting-to-integer"),this.astGeneric(e,t),this.popState("casting-to-integer"),t}castLiteralToFloat(e,t){return this.pushState("casting-to-float"),this.astGeneric(e,t),this.popState("casting-to-float"),t}castValueToInteger(e,t){return this.pushState("casting-to-integer"),t.push("int("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-integer"),t}castValueToFloat(e,t){return this.pushState("casting-to-float"),t.push("float("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-float"),t}astIdentifierExpression(e,t){if("Identifier"!==e.type)throw this.astErrorOutput("IdentifierExpression - not an Identifier",e);const r=this.getType(e),n=s.sanitizeName(e.name);if("Infinity"===e.name)t.push("3.402823466e+38");else if("Boolean"===r)if(this.argumentNames.indexOf(n)>-1){const s=this.markupUserName(e.name);t.push(s.startsWith("cellShadow_")?s:`bool(${s})`)}else t.push(`user_${n}`);else t.push(this.markupUserName(e.name));return t}markupUserName(e){const t=s.sanitizeName(e);if(this.isRootKernel&&this.getAssignedArguments().has(e)){const s=this.argumentNames.indexOf(e),r=-1===s?null:d[this.argumentTypes[s]];if("float"===r||"int"===r||"bool"===r)return`cellShadow_user_${t}`}return`user_${t}`}astForStatement(e,t){if("ForStatement"!==e.type)throw this.astErrorOutput("Invalid for statement",e);const s=[],r=[],n=[],i=[];let a=null;if(e.init){const{declarations:t}=e.init;t.length>1&&(a=!1),this.astGeneric(e.init,s);for(let e=0;e0&&t.push(s.join(""),"\n"),t.push(`for (int ${e}=0;${e}0&&t.push(`if (!${r.join("")}) break;\n`),t.push(i.join("")),t.push(`\n${n.join("")};`),t.push("}\n")}return t}astWhileStatement(e,t){if("WhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);const s=this.getInternalVariableName("safeI");return t.push(`for (int ${s}=0;${s}0){if (!`),this.astGeneric(e.test,t),t.push(") break;}\n"),this.astGeneric(e.body,t),t.push("}\n"),t}astAssignmentExpression(e,t){const s=this.isState("assignment-as-statement");if(s?this.popState("assignment-as-statement"):t.push("("),"%="===e.operator)this.astGeneric(e.left,t),t.push("="),t.push("mod("),this.astGeneric(e.left,t),t.push(","),this.astGeneric(e.right,t),t.push(")");else if("**="===e.operator)this.astGeneric(e.left,t),t.push("="),t.push("pow("),this.astGeneric(e.left,t),t.push(","),this.astGeneric(e.right,t),t.push(")");else{const s=this.getType(e.left),r=this.getType(e.right);this.astGeneric(e.left,t),t.push(e.operator),"Integer"!==s&&"Integer"===r?(t.push("float("),this.astGeneric(e.right,t),t.push(")")):"Integer"===s&&"LiteralInteger"===r?this.castLiteralToInteger(e.right,t):this.astGeneric(e.right,t)}return s||t.push(")"),t}astBlockStatement(e,t){if(this.isState("loop-body")){this.pushState("block-body");for(let s=0;snull!==e&&(o(e)||h(e))))return null;const i=e=>JSON.parse(JSON.stringify(e)),a=e=>({type:"IfStatement",test:{type:"UnaryExpression",operator:"!",prefix:!0,argument:e},consequent:{type:"BlockStatement",body:[{type:"BreakStatement",label:null}]},alternate:null}),u=e=>"VariableDeclaration"===e.type?e:{type:"ExpressionStatement",expression:e},l="BlockStatement"===e.body.type?e.body.body.slice():[e.body],c=(e,t)=>{const s=e=>{if(!e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map(s);switch(e.type){case"ContinueStatement":return{type:"BlockStatement",body:[...t(),e]};case"ForStatement":case"WhileStatement":case"DoWhileStatement":default:return e;case"IfStatement":return{...e,consequent:s(e.consequent),alternate:s(e.alternate)};case"BlockStatement":return{...e,body:e.body.map(s)};case"SwitchStatement":return{...e,cases:e.cases.map(e=>({...e,consequent:e.consequent.map(s)}))}}};return e.map(s)},p=[];"DoWhileStatement"===t?(p.push(...r?c(l,()=>[a(i(r))]):l),r&&p.push(a(r))):(r&&p.push(a(r)),p.push(...n?c(l,()=>[u(i(n))]):l),n&&p.push(u(n)));const d={type:"BlockStatement",body:[...s?[u(s)]:[],{type:"WhileStatement",test:{type:"Literal",value:!0,raw:"true"},body:{type:"BlockStatement",body:p}}]};return this.stampSyntheticNodes(d),d}stampSyntheticNodes(e){let t=this.syntheticNodeId||1073741824;const s=e=>{if(e&&"object"==typeof e)if(Array.isArray(e))e.forEach(s);else{"string"==typeof e.type&&void 0===e.start&&(e.start=t,e.end=t+1,t+=2);for(const t in e)"loc"!==t&&"range"!==t&&"parent"!==t&&s(e[t])}};s(e),this.syntheticNodeId=t}linearizeStatement(e){const t=[];let s=!1,r=this.linearTempId||0;const n=e=>({type:"Identifier",name:e}),i=(e,t,s)=>({type:"VariableDeclaration",kind:e,declarations:[{type:"VariableDeclarator",id:n(t),init:s}]}),o=(e,t)=>{const s="hoistSeq"+r++;return e.push(i("const",s,t)),n(s)},l=e=>!a(e),h=(e,t)=>{if(s||!e||"object"!=typeof e)return e;switch(e.type){case"Identifier":case"Literal":case"ThisExpression":return e;case"MemberExpression":{const s=h(e.object,t),r=e.computed?h(e.property,t):e.property;return{...e,object:s,property:r}}case"CallExpression":{const s=e.arguments.map(e=>h(e,t));if("Identifier"===e.callee.type)for(let r=0;rh(e,t))};case"UpdateExpression":{if("Identifier"!==e.argument.type)return s=!0,e;if(e.prefix)return t.push({type:"ExpressionStatement",expression:e}),o(t,e.argument);const r=o(t,e.argument);return t.push({type:"ExpressionStatement",expression:e}),r}case"AssignmentExpression":{if("Identifier"!==e.left.type)return s=!0,e;const r=h(e.right,t);return t.push({type:"ExpressionStatement",expression:{...e,right:r}}),o(t,e.left)}case"SequenceExpression":for(let s=0;s({type:"ExpressionStatement",expression:{type:"AssignmentExpression",operator:"=",left:n(e),right:t}});return o.push(d(a,c)),u.push(d(a,p)),t.push({type:"IfStatement",test:s,consequent:{type:"BlockStatement",body:o},alternate:{type:"BlockStatement",body:u}}),n(a)}case"LogicalExpression":{if(!l(e.right))return{...e,left:h(e.left,t)};const s=h(e.left,t),a="hoistSeq"+r++;t.push(i("let",a,s));const o=[],u=h(e.right,o);return o.push({type:"ExpressionStatement",expression:{type:"AssignmentExpression",operator:"=",left:n(a),right:u}}),t.push({type:"IfStatement",test:"&&"===e.operator?n(a):{type:"UnaryExpression",operator:"!",prefix:!0,argument:n(a)},consequent:{type:"BlockStatement",body:o},alternate:null}),n(a)}default:return s=!0,e}};switch(e.type){case"ExpressionStatement":{const s=e.expression;if("AssignmentExpression"===s.type&&"Identifier"===s.left.type){const e=h(s.right,t);t.push({type:"ExpressionStatement",expression:{...s,right:e}})}else{const e=h(s,t);"UpdateExpression"!==e.type&&"AssignmentExpression"!==e.type||t.push({type:"ExpressionStatement",expression:e})}break}case"VariableDeclaration":for(let s=0;s{if(e&&"object"==typeof e)if(Array.isArray(e))e.forEach(p);else{"string"==typeof e.type&&void 0===e.start&&(e.start=c,e.end=c+1,c+=2);for(const t in e)"loc"!==t&&"range"!==t&&"parent"!==t&&p(e[t])}};return p(t),this.syntheticNodeId=c,t}astStatementWithHoisting(e,t){switch(e.type){case"ExpressionStatement":case"VariableDeclaration":case"ReturnStatement":{if(!c(e))return this.astGeneric(e,t);const s=this.hoistedIndexReads,r=this.hoistedIndexReads=[],n=[];return this.astGeneric(e,n),this.hoistedIndexReads=s,t.push(...r,...n),t}default:return this.astGeneric(e,t)}}astVariableDeclaration(e,t){const r=e.declarations;if(!r||!r[0]||!r[0].init)throw this.astErrorOutput("Unexpected expression",e);const n=[];let i=null;const a=[];let o=[];for(let t=0;t0&&a.push(o.join(",")),n.push(a.join(";")),t.push(n.join("")),t.push(";"),t}astIfStatement(e,t){return t.push("if ("),this.astGeneric(e.test,t),t.push(")"),"BlockStatement"===e.consequent.type?this.astGeneric(e.consequent,t):(t.push(" {\n"),this.astGeneric(e.consequent,t),t.push("\n}\n")),e.alternate&&(t.push("else "),"BlockStatement"===e.alternate.type||"IfStatement"===e.alternate.type?this.astGeneric(e.alternate,t):(t.push(" {\n"),this.astGeneric(e.alternate,t),t.push("\n}\n"))),t}astSwitchCaseConsequent(e,t){const s=[];for(let t=0;t{if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(t);if("BreakStatement"===e.type)return!0;if("ForStatement"===e.type||"WhileStatement"===e.type||"DoWhileStatement"===e.type||"SwitchStatement"===e.type)return!1;for(const s in e)if("loc"!==s&&"range"!==s&&"parent"!==s&&t(e[s]))return!0;return!1};if(t(s[e]))throw this.astErrorOutput("break inside a switch case is only supported as the case terminator",s[e])}for(let e=0;es+1){u=!0,this.astSwitchCaseConsequent(r[s].consequent,o);continue}t.push(" else {\n")}this.astSwitchCaseConsequent(r[s].consequent,t),t.push("\n}")}return u&&(t.push(" else {"),t.push(o.join("")),t.push("}")),t}astThisExpression(e,t){return t.push("this"),t}astMemberExpression(e,t){const{property:r,name:n,signature:i,origin:a,type:o,xProperty:u,yProperty:l,zProperty:h}=this.getMemberExpressionDetails(e);switch(i){case"value.thread.value":case"this.thread.value":if("x"!==n&&"y"!==n&&"z"!==n)throw this.astErrorOutput("Unexpected expression, expected `this.thread.x`, `this.thread.y`, or `this.thread.z`",e);return t.push(`threadId.${n}`),t;case"this.output.value":if(this.dynamicOutput)switch(n){case"x":this.isState("casting-to-float")?t.push("float(uOutputDim.x)"):t.push("uOutputDim.x");break;case"y":this.isState("casting-to-float")?t.push("float(uOutputDim.y)"):t.push("uOutputDim.y");break;case"z":this.isState("casting-to-float")?t.push("float(uOutputDim.z)"):t.push("uOutputDim.z");break;default:throw this.astErrorOutput("Unexpected expression",e)}else switch(n){case"x":this.isState("casting-to-integer")?t.push(this.output[0]):t.push(this.output[0],".0");break;case"y":this.isState("casting-to-integer")?t.push(this.output[1]):t.push(this.output[1],".0");break;case"z":this.isState("casting-to-integer")?t.push(this.output[2]):t.push(this.output[2],".0");break;default:throw this.astErrorOutput("Unexpected expression",e)}return t;case"value":throw this.astErrorOutput("Unexpected expression",e);case"value[]":case"value[][]":case"value[][][]":case"value[][][][]":case"value.value":if("Math"===a)return t.push(Math[n]),t;const i=s.sanitizeName(n);switch(r){case"r":return t.push(`user_${i}.r`),t;case"g":return t.push(`user_${i}.g`),t;case"b":return t.push(`user_${i}.b`),t;case"a":return t.push(`user_${i}.a`),t}break;case"this.constants.value":if(void 0===u)switch(o){case"Array(2)":case"Array(3)":case"Array(4)":return t.push(`constants_${s.sanitizeName(n)}`),t}case"this.constants.value[]":case"this.constants.value[][]":case"this.constants.value[][][]":case"this.constants.value[][][][]":break;case"fn()[]":return this.astCallExpression(e.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(r)),t.push("]"),t;case"fn()[][]":{const s=e.object.property,r=e.property,n=p[this.getType(e.object.object)],i=e=>"LiteralInteger"===this.getType(e);return!n||i(s)&&i(r)?(this.astCallExpression(e.object.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(s)),t.push("]"),t.push("["),t.push(this.memberExpressionPropertyMarkup(r)),t.push("]"),t):(t.push(`getMatrix${n}(`),this.astCallExpression(e.object.object,t),t.push(", "),t.push(this.memberExpressionPropertyMarkup(s)),t.push(", "),t.push(this.memberExpressionPropertyMarkup(r)),t.push(")"),t)}case"[][]":return this.astArrayExpression(e.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(r)),t.push("]"),t;default:throw this.astErrorOutput("Unexpected expression",e)}if(!1===e.computed)switch(o){case"Number":case"Integer":case"Float":case"Boolean":return t.push(`${a}_${s.sanitizeName(n)}`),t}const c=`${a}_${s.sanitizeName(n)}`;switch(o){case"Array(2)":case"Array(3)":case"Array(4)":this.astGeneric(e.object,t),t.push("["),t.push(this.memberExpressionPropertyMarkup(u)),t.push("]");break;case"HTMLImageArray":t.push(`getImage3D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"ArrayTexture(1)":t.push(`getFloatFromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"Array1D(2)":case"Array2D(2)":case"Array3D(2)":t.push(`getMemoryOptimizedVec2(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"ArrayTexture(2)":t.push(`getVec2FromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"Array1D(3)":case"Array2D(3)":case"Array3D(3)":t.push(`getMemoryOptimizedVec3(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"ArrayTexture(3)":t.push(`getVec3FromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"Array1D(4)":case"Array2D(4)":case"Array3D(4)":t.push(`getMemoryOptimizedVec4(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"ArrayTexture(4)":case"HTMLCanvas":case"OffscreenCanvas":case"HTMLImage":case"ImageBitmap":case"ImageData":case"HTMLVideo":t.push(`getVec4FromSampler2D(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"NumberTexture":case"Array":case"Array2D":case"Array3D":case"Array4D":case"Input":case"Number":case"Float":case"Integer":if("single"===this.precision)t.push(`getMemoryOptimized32(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");else{const e="user"===a?this.lookupFunctionArgumentBitRatio(this.name,n):this.constantBitRatios[n];switch(e){case 1:t.push(`get8(${c}, ${c}Size, ${c}Dim, `);break;case 2:t.push(`get16(${c}, ${c}Size, ${c}Dim, `);break;case 4:case 0:t.push(`get32(${c}, ${c}Size, ${c}Dim, `);break;default:throw new Error(`unhandled bit ratio of ${e}`)}this.memberExpressionXYZ(u,l,h,t),t.push(")")}break;case"MemoryOptimizedNumberTexture":t.push(`getMemoryOptimized32(${c}, ${c}Size, ${c}Dim, `),this.memberExpressionXYZ(u,l,h,t),t.push(")");break;case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":t.push(`${c}[${this.memberExpressionPropertyMarkup(l)}]`),l&&t.push(`[${this.memberExpressionPropertyMarkup(u)}]`);break;default:throw new Error(`unhandled member expression "${o}"`)}return t}astCallExpression(e,t){if(!e.callee)throw this.astErrorOutput("Unknown CallExpression",e);let r=null;const n=this.isAstMathFunction(e);if(r=n||e.callee.object&&"ThisExpression"===e.callee.object.type?e.callee.property.name:"SequenceExpression"!==e.callee.type||"Literal"!==e.callee.expressions[0].type||isNaN(e.callee.expressions[0].raw)?e.callee.name:e.callee.expressions[1].property.name,!r)throw this.astErrorOutput("Unhandled function, couldn't find name",e);switch(r){case"pow":r="_pow";break;case"round":r="_round"}if(this.calledFunctions.indexOf(r)<0&&this.calledFunctions.push(r),"random"===r&&this.plugins&&this.plugins.length>0)for(let e=0;e0&&t.push(", "),"Integer"===n)this.castValueToFloat(r,t);else this.astGeneric(r,t)}else{const n=this.lookupFunctionArgumentTypes(r)||[];for(let i=0;i0&&t.push(", ");const u=this.getType(a);switch(o||(this.triggerImplyArgumentType(r,i,u,this),o=u),u){case"Boolean":this.astGeneric(a,t);continue;case"Number":case"Float":if("Integer"===o){t.push("int("),this.astGeneric(a,t),t.push(")");continue}if("Number"===o||"Float"===o){this.astGeneric(a,t);continue}if("LiteralInteger"===o){this.castLiteralToFloat(a,t);continue}break;case"Integer":if("Number"===o||"Float"===o){t.push("float("),this.astGeneric(a,t),t.push(")");continue}if("Integer"===o){this.astGeneric(a,t);continue}break;case"LiteralInteger":if("Integer"===o){this.castLiteralToInteger(a,t);continue}if("Number"===o||"Float"===o){this.castLiteralToFloat(a,t);continue}if("LiteralInteger"===o){this.astGeneric(a,t);continue}break;case"Array(2)":case"Array(3)":case"Array(4)":if(o===u){if("Identifier"===a.type)t.push(`user_${s.sanitizeName(a.name)}`);else{if("ArrayExpression"!==a.type&&"MemberExpression"!==a.type&&"CallExpression"!==a.type)throw this.astErrorOutput(`Unhandled argument type ${a.type}`,e);this.astGeneric(a,t)}continue}break;case"HTMLCanvas":case"OffscreenCanvas":case"HTMLImage":case"ImageBitmap":case"ImageData":case"HTMLImageArray":case"HTMLVideo":case"ArrayTexture(1)":case"ArrayTexture(2)":case"ArrayTexture(3)":case"ArrayTexture(4)":case"Array":case"Input":if(o===u){if("Identifier"!==a.type)throw this.astErrorOutput(`Unhandled argument type ${a.type}`,e);this.triggerImplyArgumentBitRatio(this.name,a.name,r,i);const n=s.sanitizeName(a.name);t.push(`user_${n},user_${n}Size,user_${n}Dim`);continue}}throw this.astErrorOutput(`Unhandled argument combination of ${u} and ${o} for argument named "${a.name}"`,e)}}return t.push(")"),t}astArrayExpression(e,t){const s=this.getType(e),r=e.elements.length;switch(s){case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":t.push(`mat${r}(`);break;default:t.push(`vec${r}(`)}for(let s=0;s0&&t.push(", ");const r=e.elements[s];this.astGeneric(r,t)}return t.push(")"),t}memberExpressionXYZ(e,t,s,r){return s?r.push(this.memberExpressionPropertyMarkup(s),", "):r.push("0, "),t?r.push(this.memberExpressionPropertyMarkup(t),", "):r.push("0, "),r.push(this.memberExpressionPropertyMarkup(e)),r}memberExpressionPropertyMarkup(e){if(!e)throw new Error("Property not set");const t=[];switch(this.getType(e)){case"Number":case"Float":this.castValueToInteger(e,t);break;case"LiteralInteger":this.castLiteralToInteger(e,t);break;default:this.astGeneric(e,t)}const r=t.join("");if(this.hoistedIndexReads&&/\b\w+\((user_|constants_)\w+, \1\w+Size/.test(r)){const e=`hoisted_${this.hoistedIndexReads.length}_${s.sanitizeName(this.name)}`,t=r.startsWith("int(");return this.hoistedIndexReads.push(`${t?"int":"float"} ${e}=${r};\n`),e}return r}}}}),M=e((e,t)=>{t.exports={name:"math-random-uniformly-distributed",onBeforeRun:e=>{if(null===e.randomSeed||void 0===e.randomSeed)return e.setUniform1f("randomSeed1",Math.random()),void e.setUniform1f("randomSeed2",Math.random());e._mathRandomGenerator&&e._mathRandomGeneratorSeed===e.randomSeed||(e._mathRandomGenerator=function(e){let t=e>>>0;return function(){t=t+1831565813>>>0;let e=t;return e=Math.imul(e^e>>>15,1|e),e^=e+Math.imul(e^e>>>7,61|e),((e^e>>>14)>>>0)/4294967296}}(e.randomSeed),e._mathRandomGeneratorSeed=e.randomSeed),e.setUniform1f("randomSeed1",e._mathRandomGenerator()),e.setUniform1f("randomSeed2",e._mathRandomGenerator())},functionMatch:"Math.random()",functionReplace:"nrand(vTexCoord)",functionReturnType:"Number",source:"// https://www.shadertoy.com/view/4t2SDh\n//note: uniformly distributed, normalized rand, [0,1]\nhighp float randomSeedShift = 1.0;\nhighp float slide = 1.0;\nuniform highp float randomSeed1;\nuniform highp float randomSeed2;\n\nhighp float nrand(highp vec2 n) {\n highp float result = fract(sin(dot((n.xy + 1.0) * vec2(randomSeed1 * slide, randomSeed2 * randomSeedShift), vec2(12.9898, 78.233))) * 43758.5453);\n randomSeedShift = result;\n if (randomSeedShift > 0.5) {\n slide += 0.00009; \n } else {\n slide += 0.0009;\n }\n return result;\n}"}}),G=e((e,t)=>{t.exports={fragmentShader:`__HEADER__;\n__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n\nconst int LOOP_MAX = __LOOP_MAX__;\n\n__PLUGINS__;\n__CONSTANTS__;\n\nvarying vec2 vTexCoord;\n\nfloat acosh(float x) {\n return log(x + sqrt(x * x - 1.0));\n}\n\nfloat sinh(float x) {\n return (pow(${Math.E}, x) - pow(${Math.E}, -x)) / 2.0;\n}\n\nfloat asinh(float x) {\n return log(x + sqrt(x * x + 1.0));\n}\n\nfloat atan2(float v1, float v2) {\n if (v2 == 0.0) {\n if (v1 == 0.0) return 0.0;\n if (v1 > 0.0) return 1.5707963267948966;\n if (v1 < 0.0) return -1.5707963267948966;\n }\n return atan(v1, v2);\n}\n\nfloat atanh(float x) {\n x = (x + 1.0) / (x - 1.0);\n if (x < 0.0) {\n return 0.5 * log(-x);\n }\n return 0.5 * log(x);\n}\n\nfloat cbrt(float x) {\n if (x >= 0.0) {\n return pow(x, 1.0 / 3.0);\n } else {\n return -pow(x, 1.0 / 3.0);\n }\n}\n\nfloat cosh(float x) {\n return (pow(${Math.E}, x) + pow(${Math.E}, -x)) / 2.0; \n}\n\nfloat expm1(float x) {\n return pow(${Math.E}, x) - 1.0; \n}\n\nfloat fround(highp float x) {\n return x;\n}\n\nfloat imul(float v1, float v2) {\n return float(int(v1) * int(v2));\n}\n\nfloat log10(float x) {\n return log2(x) * (1.0 / log2(10.0));\n}\n\nfloat log1p(float x) {\n return log(1.0 + x);\n}\n\nfloat _pow(float v1, float v2) {\n if (v2 == 0.0) return 1.0;\n return pow(v1, v2);\n}\n\nfloat tanh(float x) {\n float e = exp(2.0 * x);\n return (e - 1.0) / (e + 1.0);\n}\n\nfloat trunc(float x) {\n if (x >= 0.0) {\n return floor(x); \n } else {\n return ceil(x);\n }\n}\n\nvec4 _round(vec4 x) {\n return floor(x + 0.5);\n}\n\nfloat _round(float x) {\n return floor(x + 0.5);\n}\n\nconst int BIT_COUNT = 32;\nint modi(int x, int y) {\n return x - y * (x / y);\n}\n\nint bitwiseOr(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) || (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseXOR(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) != (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseAnd(int a, int b) {\n int result = 0;\n int n = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) && (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 && b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseNot(int a) {\n // ~a is identically -a - 1 in two's complement, for every value including\n // negatives. The previous bit-by-bit loop only worked for a >= 0, where it\n // leaned on 32-bit overflow wrapping to reach the negative answer; given a\n // negative input it computed ~abs(a), so ~(-1) gave -2 and ~~x never\n // returned x.\n return -a - 1;\n}\nint bitwiseZeroFillLeftShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n *= 2;\n }\n\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\n// _pow2 is defined further down, alongside encode32/decode32\nfloat _pow2(float e);\nint bitwiseSignedRightShift(int num, int shifts) {\n // pow(2.0, n) is approximate on many GPUs, and landing 1 ulp high makes the\n // division fall just under a whole number, which floor() then rounds away:\n // 2 >> 1 came out 0, 8 >> 1 came out 3. Only exact left operands were\n // affected, odd ones having enough slack to survive. _pow2 is exact.\n return int(floor(float(num) / _pow2(float(shifts))));\n}\n\nint bitwiseZeroFillRightShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n /= 2;\n }\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\nvec2 integerMod(vec2 x, float y) {\n vec2 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec3 integerMod(vec3 x, float y) {\n vec3 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec4 integerMod(vec4 x, vec4 y) {\n vec4 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nfloat integerMod(float x, float y) {\n float res = floor(mod(x, y));\n return res * (res > floor(y) - 1.0 ? 0.0 : 1.0);\n}\n\nint integerMod(int x, int y) {\n return x - (y * int(x / y));\n}\n\n// GLSL ES 1.00 accepts only a constant or a loop symbol inside an index\n// expression, so m[y][x] does not compile when y and x come from kernel\n// arguments -- the error is "Index expression can only contain const or loop\n// symbols". Loop counters are legal indices, so walk the matrix with them\n// instead. These are 2x2 to 4x4, so it costs at most sixteen comparisons.\nfloat getMatrix2(mat2 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 2; i++) {\n for (int j = 0; j < 2; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix3(mat3 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 3; i++) {\n for (int j = 0; j < 3; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix4(mat4 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 4; i++) {\n for (int j = 0; j < 4; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\n__DIVIDE_WITH_INTEGER_CHECK__;\n\n// Here be dragons!\n// DO NOT OPTIMIZE THIS CODE\n// YOU WILL BREAK SOMETHING ON SOMEBODY'S MACHINE\n// LEAVE IT AS IT IS, LEST YOU WASTE YOUR OWN TIME\n// Exact powers of two built from exact constant multiplies: exp2/log2/pow\n// are approximate on some GPUs (notably Apple silicon), and 1-2 ulp there\n// corrupts the packed bytes (#659)\nfloat _pow2(float e) {\n float r = 1.0;\n float a = abs(e);\n bool n = e < 0.0;\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 32.0) { r *= n ? 2.3283064365386963e-10 : 4294967296.0; a -= 32.0; }\n if (a >= 16.0) { r *= n ? 0.0000152587890625 : 65536.0; a -= 16.0; }\n if (a >= 8.0) { r *= n ? 0.00390625 : 256.0; a -= 8.0; }\n if (a >= 4.0) { r *= n ? 0.0625 : 16.0; a -= 4.0; }\n if (a >= 2.0) { r *= n ? 0.25 : 4.0; a -= 2.0; }\n if (a >= 1.0) { r *= n ? 0.5 : 2.0; }\n return r;\n}\nconst vec2 MAGIC_VEC = vec2(1.0, -256.0);\nconst vec4 SCALE_FACTOR = vec4(1.0, 256.0, 65536.0, 0.0);\nconst vec4 SCALE_FACTOR_INV = vec4(1.0, 0.00390625, 0.0000152587890625, 0.0); // 1, 1/256, 1/65536\nfloat decode32(vec4 texel) {\n __DECODE32_ENDIANNESS__;\n texel *= 255.0;\n vec2 gte128;\n gte128.x = texel.b >= 128.0 ? 1.0 : 0.0;\n gte128.y = texel.a >= 128.0 ? 1.0 : 0.0;\n float exponent = 2.0 * texel.a - 127.0 + dot(gte128, MAGIC_VEC);\n float res = _pow2(_round(exponent));\n texel.b = texel.b - 128.0 * gte128.x;\n res = dot(texel, SCALE_FACTOR) * _pow2(_round(exponent-23.0)) + res;\n res *= gte128.y * -2.0 + 1.0;\n return res;\n}\n\nfloat decode16(vec4 texel, int index) {\n int channel = integerMod(index, 2);\n if (channel == 0) return texel.r * 255.0 + texel.g * 65280.0;\n if (channel == 1) return texel.b * 255.0 + texel.a * 65280.0;\n return 0.0;\n}\n\nfloat decode8(vec4 texel, int index) {\n int channel = integerMod(index, 4);\n if (channel == 0) return texel.r * 255.0;\n if (channel == 1) return texel.g * 255.0;\n if (channel == 2) return texel.b * 255.0;\n if (channel == 3) return texel.a * 255.0;\n return 0.0;\n}\n\nvec4 legacyEncode32(float f) {\n float F = abs(f);\n float sign = f < 0.0 ? 1.0 : 0.0;\n float exponent = floor(log2(F));\n float mantissa = (exp2(-exponent) * F);\n // exponent += floor(log2(mantissa));\n vec4 texel = vec4(F * exp2(23.0-exponent)) * SCALE_FACTOR_INV;\n texel.rg = integerMod(texel.rg, 256.0);\n texel.b = integerMod(texel.b, 128.0);\n texel.a = exponent*0.5 + 63.5;\n texel.ba += vec2(integerMod(exponent+127.0, 2.0), sign) * 128.0;\n texel = floor(texel);\n texel *= 0.003921569; // 1/255\n __ENCODE32_ENDIANNESS__;\n return texel;\n}\n\n// https://github.com/gpujs/gpu.js/wiki/Encoder-details\nvec4 encode32(float value) {\n if (value == 0.0) return vec4(0, 0, 0, 0);\n\n float exponent;\n float mantissa;\n vec4 result;\n float sgn;\n\n sgn = step(0.0, -value);\n value = abs(value);\n\n exponent = floor(log2(value));\n float p2 = _pow2(exponent);\n // approximate log2 can land one off; correct by direct comparison\n if (p2 > value) { exponent -= 1.0; p2 *= 0.5; }\n else if (p2 * 2.0 <= value) { exponent += 1.0; p2 *= 2.0; }\n\n mantissa = value / p2 - 1.0;\n exponent = exponent+127.0;\n result = vec4(0,0,0,0);\n\n result.a = floor(exponent/2.0);\n exponent = exponent - result.a*2.0;\n result.a = result.a + 128.0*sgn;\n\n result.b = floor(mantissa * 128.0);\n mantissa = mantissa - result.b / 128.0;\n result.b = result.b + exponent*128.0;\n\n result.g = floor(mantissa*32768.0);\n mantissa = mantissa - result.g/32768.0;\n\n result.r = floor(mantissa*8388608.0);\n return result/255.0;\n}\n// Dragons end here\n\nint index;\nivec3 threadId;\n\nivec3 indexTo3D(int idx, ivec3 texDim) {\n int z = int(idx / (texDim.x * texDim.y));\n idx -= z * int(texDim.x * texDim.y);\n int y = int(idx / texDim.x);\n int x = int(integerMod(idx, texDim.x));\n return ivec3(x, y, z);\n}\n\nfloat get32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n return decode32(texel);\n}\n\nfloat get16(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x * 2;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize.x * 2, texSize.y));\n return decode16(texel, index);\n}\n\nfloat get8(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x * 4;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize.x * 4, texSize.y));\n return decode8(texel, index);\n}\n\nfloat getMemoryOptimized32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 4);\n index = index / 4;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n if (channel == 0) return texel.r;\n if (channel == 1) return texel.g;\n if (channel == 2) return texel.b;\n if (channel == 3) return texel.a;\n return 0.0;\n}\n\nvec4 getImage2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n return texture2D(tex, st / vec2(texSize));\n}\n\nfloat getFloatFromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return result[0];\n}\n\nvec2 getVec2FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec2(result[0], result[1]);\n}\n\nvec2 getMemoryOptimizedVec2(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int channel = integerMod(index, 2);\n index = index / 2;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n if (channel == 0) return vec2(texel.r, texel.g);\n if (channel == 1) return vec2(texel.b, texel.a);\n return vec2(0.0, 0.0);\n}\n\nvec3 getVec3FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec3(result[0], result[1], result[2]);\n}\n\nvec3 getMemoryOptimizedVec3(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int fieldIndex = 3 * (x + texDim.x * (y + texDim.y * z));\n int vectorIndex = fieldIndex / 4;\n int vectorOffset = fieldIndex - vectorIndex * 4;\n int readY = vectorIndex / texSize.x;\n int readX = vectorIndex - readY * texSize.x;\n vec4 tex1 = texture2D(tex, (vec2(readX, readY) + 0.5) / vec2(texSize));\n \n if (vectorOffset == 0) {\n return tex1.xyz;\n } else if (vectorOffset == 1) {\n return tex1.yzw;\n } else {\n readX++;\n if (readX >= texSize.x) {\n readX = 0;\n readY++;\n }\n vec4 tex2 = texture2D(tex, vec2(readX, readY) / vec2(texSize));\n if (vectorOffset == 2) {\n return vec3(tex1.z, tex1.w, tex2.x);\n } else {\n return vec3(tex1.w, tex2.x, tex2.y);\n }\n }\n}\n\nvec4 getVec4FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n return getImage2D(tex, texSize, texDim, z, y, x);\n}\n\nvec4 getMemoryOptimizedVec4(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 2);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture2D(tex, st / vec2(texSize));\n return vec4(texel.r, texel.g, texel.b, texel.a);\n}\n\nvec4 actualColor;\nvoid color(float r, float g, float b, float a) {\n actualColor = vec4(r,g,b,a);\n}\n\nvoid color(float r, float g, float b) {\n color(r,g,b,1.0);\n}\n\nvoid color(sampler2D image) {\n actualColor = texture2D(image, vTexCoord);\n}\n\nfloat modulo(float number, float divisor) {\n if (number < 0.0) {\n number = abs(number);\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return -mod(number, divisor);\n }\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return mod(number, divisor);\n}\n\n__INJECTED_NATIVE__;\n__MAIN_CONSTANTS__;\n__MAIN_ARGUMENTS__;\n__KERNEL__;\n\nvoid main(void) {\n index = int(vTexCoord.s * float(uTexSize.x)) + int(vTexCoord.t * float(uTexSize.y)) * uTexSize.x;\n __MAIN_RESULT__;\n}`}}),O=e((e,t)=>{t.exports={vertexShader:"__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n\nattribute vec2 aPos;\nattribute vec2 aTexCoord;\n\nvarying vec2 vTexCoord;\nuniform vec2 ratio;\n\nvoid main(void) {\n gl_Position = vec4((aPos + vec2(1)) * ratio + vec2(-1), 0, 1);\n vTexCoord = aTexCoord;\n}"}}),V=e((e,t)=>{function s(e,t={}){const{contextName:s="gl",throwGetError:a,useTrackablePrimitives:o,recording:u=[],variables:l={},onReadPixels:h,onUnrecognizedArgumentLookup:c}=t,p=new Proxy(e,{get:function(t,p){switch(p){case"addComment":return A;case"checkThrowError":return w;case"getReadPixelsVariableName":return m;case"insertVariable":return b;case"reset":return y;case"setIndent":return S;case"toString":return x;case"getContextVariableName":return _}return"function"==typeof e[p]?function(){switch(p){case"getError":return a?u.push(`${g}if (${s}.getError() !== ${s}.NONE) throw new Error('error');`):u.push(`${g}${s}.getError();`),e.getError();case"getExtension":{const t=`${s}Variables${d.length}`;u.push(`${g}const ${t} = ${s}.getExtension('${arguments[0]}');`);const n=e.getExtension(arguments[0]);if(n&&"object"==typeof n){const e=r(n,{getEntity:v,useTrackablePrimitives:o,recording:u,contextName:t,contextVariables:d,variables:l,indent:g,onUnrecognizedArgumentLookup:c});return d.push(e),e}return d.push(null),n}case"readPixels":const t=d.indexOf(arguments[6]);let i;if(-1===t){const e=function(e){if(l)for(const t in l)if(l[t]===e)return t;return null}(arguments[6]);e?(i=e,u.push(`${g}${e}`)):(i=`${s}Variable${d.length}`,d.push(arguments[6]),u.push(`${g}const ${i} = new ${arguments[6].constructor.name}(${arguments[6].length});`))}else i=`${s}Variable${t}`;m=i;const p=[arguments[0],arguments[1],arguments[2],arguments[3],v(arguments[4]),v(arguments[5]),i];return u.push(`${g}${s}.readPixels(${p.join(", ")});`),h&&h(i,p),e.readPixels.apply(e,arguments);case"drawBuffers":return u.push(`${g}${s}.drawBuffers([${n(arguments[0],{contextName:s,contextVariables:d,getEntity:v,addVariable:T,variables:l,onUnrecognizedArgumentLookup:c})}]);`),e.drawBuffers(arguments[0])}let t=e[p].apply(e,arguments);switch(typeof t){case"undefined":return void u.push(`${g}${E(p,arguments)};`);case"number":case"boolean":if(o&&-1===d.indexOf(i(t))){u.push(`${g}const ${s}Variable${d.length} = ${E(p,arguments)};`),d.push(t=i(t));break}default:null===t?u.push(`${E(p,arguments)};`):u.push(`${g}const ${s}Variable${d.length} = ${E(p,arguments)};`),d.push(t)}return t}:(f[e[p]]=p,e[p])}}),d=[],f={};let m,g="";return p;function x(){return u.join("\n")}function y(){for(;u.length>0;)u.pop()}function b(e,t){l[e]=t}function v(e){const t=f[e];return t?s+"."+t:e}function S(e){g=" ".repeat(e)}function T(e,t){const r=`${s}Variable${d.length}`;return u.push(`${g}const ${r} = ${t};`),d.push(e),r}function A(e){u.push(`${g}// ${e}`)}function w(){u.push(`${g}(() => {\n${g}const error = ${s}.getError();\n${g}if (error !== ${s}.NONE) {\n${g} const names = Object.getOwnPropertyNames(gl);\n${g} for (let i = 0; i < names.length; i++) {\n${g} const name = names[i];\n${g} if (${s}[name] === error) {\n${g} throw new Error('${s} threw ' + name);\n${g} }\n${g} }\n${g}}\n${g}})();`)}function E(e,t){return`${s}.${e}(${n(t,{contextName:s,contextVariables:d,getEntity:v,addVariable:T,variables:l,onUnrecognizedArgumentLookup:c})})`}function _(e){const t=d.indexOf(e);return-1!==t?`${s}Variable${t}`:null}}function r(e,t){const s=new Proxy(e,{get:function(t,s){return"function"==typeof t[s]?function(){if("drawBuffersWEBGL"===s)return h.push(`${p}${a}.drawBuffersWEBGL([${n(arguments[0],{contextName:a,contextVariables:o,getEntity:f,addVariable:g,variables:c,onUnrecognizedArgumentLookup:d})}]);`),e.drawBuffersWEBGL(arguments[0]);let t=e[s].apply(e,arguments);switch(typeof t){case"undefined":return void h.push(`${p}${m(s,arguments)};`);case"number":case"boolean":l&&-1===o.indexOf(i(t))?(h.push(`${p}const ${a}Variable${o.length} = ${m(s,arguments)};`),o.push(t=i(t))):(h.push(`${p}const ${a}Variable${o.length} = ${m(s,arguments)};`),o.push(t));break;default:null===t?h.push(`${m(s,arguments)};`):h.push(`${p}const ${a}Variable${o.length} = ${m(s,arguments)};`),o.push(t)}return t}:(r[e[s]]=s,e[s])}}),r={},{contextName:a,contextVariables:o,getEntity:u,useTrackablePrimitives:l,recording:h,variables:c,indent:p,onUnrecognizedArgumentLookup:d}=t;return s;function f(e){return r.hasOwnProperty(e)?`${a}.${r[e]}`:u(e)}function m(e,t){return`${a}.${e}(${n(t,{contextName:a,contextVariables:o,getEntity:f,addVariable:g,variables:c,onUnrecognizedArgumentLookup:d})})`}function g(e,t){const s=`${a}Variable${o.length}`;return o.push(e),h.push(`${p}const ${s} = ${t};`),s}}function n(e,t){const{variables:s,onUnrecognizedArgumentLookup:r}=t;return Array.from(e).map(e=>{const n=function(e){if(s)for(const t in s)if(s.hasOwnProperty(t)&&s[t]===e)return t;return r?r(e):null}(e);return n||function(e,t){const{contextName:s,contextVariables:r,getEntity:n,addVariable:i,onUnrecognizedArgumentLookup:a}=t;if(void 0===e)return"undefined";if(null===e)return"null";const o=r.indexOf(e);if(o>-1)return`${s}Variable${o}`;switch(e.constructor.name){case"String":const t=/\n/.test(e),s=/'/.test(e),r=/"/.test(e);return t?"`"+e+"`":s&&!r?'"'+e+'"':"'"+e+"'";case"Number":case"Boolean":return n(e);case"Array":return i(e,`new ${e.constructor.name}([${Array.from(e).join(",")}])`);case"Float32Array":case"Uint8Array":case"Uint16Array":case"Int32Array":return i(e,`new ${e.constructor.name}(${JSON.stringify(Array.from(e))})`);default:if(a){const t=a(e);if(t)return t}throw new Error(`unrecognized argument type ${e.constructor.name}`)}}(e,t)}).join(", ")}function i(e){return new e.constructor(e)}void 0!==t&&(t.exports={glWiretap:s,glExtensionWiretap:r}),"undefined"!=typeof window&&(s.glExtensionWiretap=r,window.glWiretap=s)}),P=e((e,t)=>{const{glWiretap:s}=V(),{utils:r}=i();function n(e){let t=e.toString().replace(/^function /,"");const s=t.indexOf("=>");if(-1!==s&&!/[{]|\bfunction\b/.test(t.slice(0,s))){const e=t.slice(0,s).trim(),r=t.slice(s+2).trim();t=r.startsWith("{")?`${e} ${r}`:`${e} { return ${r}; }`}return t.replace(/utils[.]/g,"/*utils.*/")}function a(e,t){const s="single"===t.precision?e:`new Float32Array(${e}.buffer)`;return t.output[2]?`renderOutput(${s}, ${t.output[0]}, ${t.output[1]}, ${t.output[2]})`:t.output[1]?`renderOutput(${s}, ${t.output[0]}, ${t.output[1]})`:`renderOutput(${s}, ${t.output[0]})`}function o(e,t){const s=e.toArray.toString(),n=!/^function/.test(s);return`() => {\n function framebuffer() { return getReadFramebuffer(); };\n ${r.flattenFunctionToString(`${n?"function ":""}${s}`,{findDependency:(t,s)=>{if("utils"===t)return`const ${s} = ${r[s].toString()};`;if("this"===t)return"framebuffer"===s?"":`${n?"function ":""}${e[s].toString()}`;throw new Error("unhandled fromObject")},thisLookup:(s,r)=>{if("texture"===s)return t;if("context"===s)return r?null:"gl";if(e.hasOwnProperty(s))return JSON.stringify(e[s]);throw new Error(`unhandled thisLookup ${s}`)}})}\n return toArray();\n }`}function u(e,t,s,r,n){if(null===e)return null;if(null===t)return null;switch(typeof e){case"boolean":case"number":return null}if("undefined"!=typeof HTMLImageElement&&e instanceof HTMLImageElement)for(let n=0;n{switch(typeof e){case"boolean":return new Boolean(e);case"number":return new Number(e);default:return e}}):null;const c=[],p=[],d=s(i.context,{useTrackablePrimitives:!0,onReadPixels:e=>{if(R.subKernels){if(f){const t=R.subKernels[m++].property;p.push(` result${isNaN(t)?"."+t:`[${t}]`} = ${a(e,R)};`)}else p.push(` const result = { result: ${a(e,R)} };`),f=!0;m===R.subKernels.length&&p.push(" return result;")}else e?p.push(` return ${a(e,R)};`):p.push(" return null;")},onUnrecognizedArgumentLookup:e=>{const t=u(e,R.kernelArguments,[],d,c);if(t)return t;const s=u(e,R.kernelConstants,T?Object.keys(T).map(e=>T[e]):[],d,c);return s||null}});let f=!1,m=0;const{source:g,canvas:x,output:y,pipeline:b,graphical:v,loopMaxIterations:S,constants:T,optimizeFloatMemory:A,precision:w,fixIntegerDivisionAccuracy:E,functions:_,nativeFunctions:I,subKernels:k,immutable:C,argumentTypes:L,constantTypes:D,kernelArguments:F,kernelConstants:$,tactic:N}=i,R=new e(g,{canvas:x,context:d,checkContext:!1,output:y,pipeline:b,graphical:v,loopMaxIterations:S,constants:T,optimizeFloatMemory:A,precision:w,fixIntegerDivisionAccuracy:E,functions:_,nativeFunctions:I,subKernels:k,immutable:C,argumentTypes:L,constantTypes:D,tactic:N});let M=[];if(d.setIndent(2),R.build.apply(R,t),M.push(d.toString()),d.reset(),R.kernelArguments.forEach((e,s)=>{switch(e.type){case"Integer":case"Boolean":case"Number":case"Float":case"Array":case"Array(2)":case"Array(3)":case"Array(4)":case"HTMLCanvas":case"HTMLImage":case"HTMLVideo":case"Input":d.insertVariable(`uploadValue_${e.name}`,e.uploadValue);break;case"HTMLImageArray":for(let r=0;re.varName).join(", ")}) {`),d.setIndent(4),R.run.apply(R,t),R.renderKernels?R.renderKernels():R.renderOutput&&R.renderOutput(),M.push(" /** start setup uploads for kernel values **/"),R.kernelArguments.forEach(e=>{M.push(" "+e.getStringValueHandler().split("\n").join("\n "))}),M.push(" /** end setup uploads for kernel values **/"),M.push(d.toString()),R.renderOutput===R.renderTexture)if(d.reset(),R.renderKernels){const e=R.renderKernels(),t=d.getContextVariableName(R.texture.texture);M.push(` return {\n result: {\n texture: ${t},\n type: '${e.result.type}',\n toArray: ${o(e.result,t)}\n },`);const{subKernels:s,mappedTextures:r}=R;for(let t=0;t"utils"===e?`const ${t} = ${r[t].toString()};`:null,thisLookup:t=>{if("context"===t)return null;if(e.hasOwnProperty(t))return JSON.stringify(e[t]);throw new Error(`unhandled thisLookup ${t}`)}})}(R)),M.push(" innerKernel.getPixels = getPixels;")),M.push(" return innerKernel;");let G=[];return $.forEach(e=>{G.push(`${e.getStringValueHandler()}`)}),`function kernel(settings) {\n const { context, constants } = settings;\n ${G.join("")}\n ${l||""}\n${M.join("\n")}\n}`}}}),z=e((e,t)=>{t.exports={KernelValue:class{constructor(e,t){const{name:s,kernel:r,context:n,checkContext:i,onRequestContextHandle:a,onUpdateValueMismatch:o,origin:u,strictIntegers:l,type:h,tactic:c}=t;if(!s)throw new Error("name not set");if(!h)throw new Error("type not set");if(!u)throw new Error("origin not set");if("user"!==u&&"constants"!==u)throw new Error(`origin must be "user" or "constants" value is "${u}"`);if(!a)throw new Error("onRequestContextHandle is not set");this.name=s,this.origin=u,this.tactic=c,this.varName="constants"===u?`constants.${s}`:s,this.kernel=r,this.strictIntegers=l,this.type=e.type||h,this.size=e.size||null,this.index=null,this.context=n,this.checkContext=null==i||i,this.contextHandle=null,this.onRequestContextHandle=a,this.onUpdateValueMismatch=o,this.forceUploadEachRun=null}get id(){return`${this.origin}_${name}`}getSource(){throw new Error(`"getSource" not defined on ${this.constructor.name}`)}updateValue(e){throw new Error(`"updateValue" not defined on ${this.constructor.name}`)}}}}),U=e((e,t)=>{const{utils:s}=i(),{KernelValue:r}=z();t.exports={WebGLKernelValue:class extends r{constructor(e,t){super(e,t),this.dimensionsId=null,this.sizeId=null,this.initialValueConstructor=e.constructor,this.onRequestTexture=t.onRequestTexture,this.onRequestIndex=t.onRequestIndex,this.uploadValue=null,this.textureSize=null,this.bitRatio=null,this.prevArg=null}get id(){return`${this.origin}_${s.sanitizeName(this.name)}`}setup(){}rebind(){}getTransferArrayType(e){if(Array.isArray(e[0]))return this.getTransferArrayType(e[0]);switch(e.constructor){case Array:case Int32Array:case Int16Array:case Int8Array:return Float32Array;case Uint8ClampedArray:case Uint8Array:case Uint16Array:case Uint32Array:case Float32Array:case Float64Array:return e.constructor}return console.warn("Unfamiliar constructor type. Will go ahead and use, but likley this may result in a transfer of zeros"),e.constructor}getStringValueHandler(){throw new Error(`"getStringValueHandler" not implemented on ${this.constructor.name}`)}getVariablePrecisionString(){return this.kernel.getVariablePrecisionString(this.textureSize||void 0,this.tactic||void 0)}destroy(){}}}}),B=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValue:r}=U();t.exports={WebGLKernelValueBoolean:class extends r{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const bool ${this.id} = ${e};\n`:`uniform bool ${this.id};\n`}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1i(this.id,this.uploadValue=e)}}}}),K=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValue:r}=U();t.exports={WebGLKernelValueFloat:class extends r{constructor(e,t){super(e,t),this.uploadValue=e}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(e){return"constants"===this.origin?Number.isInteger(e)?`const float ${this.id} = ${e}.0;\n`:`const float ${this.id} = ${e};\n`:`uniform float ${this.id};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1f(this.id,this.uploadValue=e)}}}}),W=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValue:r}=U();t.exports={WebGLKernelValueInteger:class extends r{constructor(e,t){super(e,t),this.uploadValue=e}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(e){return"constants"===this.origin?`const int ${this.id} = ${parseInt(e)};\n`:`uniform int ${this.id};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1i(this.id,this.uploadValue=e)}}}}),j=e((e,t)=>{const{WebGLKernelValue:s}=U(),{Input:n}=r();t.exports={WebGLKernelArray:class extends s{rebind(){if(!this.texture||void 0===this.contextHandle||null===this.contextHandle)return;const{context:e}=this;e.activeTexture(this.contextHandle),e.bindTexture(e.TEXTURE_2D,this.texture)}checkSize(e,t){if(!this.kernel.validate)return;const{maxTextureSize:s}=this.kernel.constructor.features;if(e>s||t>s)throw e>t?new Error(`Argument texture width of ${e} larger than maximum size of ${s} for your GPU`):e{const{utils:s}=i(),{WebGLKernelArray:r}=j();function n(e){return{width:e.width>0?e.width:e.videoWidth,height:e.height>0?e.height:e.videoHeight}}t.exports={WebGLKernelValueHTMLImage:class extends r{constructor(e,t){super(e,t);const{width:s,height:r}=n(e);this.checkSize(s,r),this.dimensions=[s,r,1],this.textureSize=[s,r],this.uploadValue=e}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!0),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,this.uploadValue=e),this.kernel.setUniform1i(this.id,this.index)}},mediaSize:n}}),X=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueHTMLImage:r,mediaSize:n}=q();t.exports={WebGLKernelValueDynamicHTMLImage:class extends r{getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){const{width:t,height:s}=n(e);this.checkSize(t,s),this.dimensions=[t,s,1],this.textureSize=[t,s],this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),H=e((e,t)=>{const{WebGLKernelValueHTMLImage:s}=q();t.exports={WebGLKernelValueHTMLVideo:class extends s{}}}),Y=e((e,t)=>{const{WebGLKernelValueDynamicHTMLImage:s}=X();t.exports={WebGLKernelValueDynamicHTMLVideo:class extends s{}}}),Z=e((e,t)=>{const{utils:s}=i(),{WebGLKernelArray:r}=j();t.exports={WebGLKernelValueSingleInput:class extends r{constructor(e,t){super(e,t),this.bitRatio=4;let[r,n,i]=e.size;this.dimensions=new Int32Array([r||1,n||1,i||1]),this.textureSize=s.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return s.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}.value, uploadValue_${this.name})`])}getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;s.flattenTo(e.value,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),J=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueSingleInput:r}=Z();t.exports={WebGLKernelValueDynamicSingleInput:class extends r{getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){let[t,r,n]=e.size;this.dimensions=new Int32Array([t||1,r||1,n||1]),this.textureSize=s.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Q=e((e,t)=>{const{utils:s}=i(),{WebGLKernelArray:r}=j();t.exports={WebGLKernelValueUnsignedInput:class extends r{constructor(e,t){super(e,t),this.bitRatio=this.getBitRatio(e);const[r,n,i]=e.size;this.dimensions=new Int32Array([r||1,n||1,i||1]),this.textureSize=s.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]),this.TranserArrayType=this.getTransferArrayType(e.value),this.preUploadValue=new this.TranserArrayType(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer)}getStringValueHandler(){return s.linesToString([`const preUploadValue_${this.name} = new ${this.TranserArrayType.name}(${this.uploadArrayLength})`,`const uploadValue_${this.name} = new Uint8Array(preUploadValue_${this.name}.buffer)`,`flattenTo(${this.varName}.value, preUploadValue_${this.name})`])}getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(value.constructor);const{context:t}=this;s.flattenTo(e.value,this.preUploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.UNSIGNED_BYTE,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),ee=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueUnsignedInput:r}=Q();t.exports={WebGLKernelValueDynamicUnsignedInput:class extends r{getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){let[t,r,n]=e.size;this.dimensions=new Int32Array([t||1,r||1,n||1]),this.textureSize=s.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]);const i=this.getTransferArrayType(e.value);this.preUploadValue=new i(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),te=e((e,t)=>{const{utils:s}=i(),{WebGLKernelArray:r}=j(),n="Source and destination textures are the same. Use immutable = true and manually cleanup kernel output texture memory with texture.delete()";t.exports={WebGLKernelValueMemoryOptimizedNumberTexture:class extends r{constructor(e,t){super(e,t);const[s,r]=e.size;this.checkSize(s,r),this.dimensions=e.dimensions,this.textureSize=e.size,this.uploadValue=e.texture,this.forceUploadEachRun=!0}setup(){this.setupTexture()}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName}.texture;\n`}getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);if(this.checkContext&&e.context!==this.context)throw new Error(`Value ${this.name} (${this.type}) must be from same context`);const{kernel:t,context:s}=this;if(t.pipeline)if(t.immutable)t.updateTextureArgumentRefs(this,e);else{if(t.texture&&t.texture.texture===e.texture)throw new Error(n);if(t.mappedTextures){const{mappedTextures:s}=t;for(let t=0;t{const{utils:s}=i(),{WebGLKernelValueMemoryOptimizedNumberTexture:r}=te();t.exports={WebGLKernelValueDynamicMemoryOptimizedNumberTexture:class extends r{getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=e.dimensions,this.checkSize(e.size[0],e.size[1]),this.textureSize=e.size,this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),re=e((e,t)=>{const{utils:s}=i(),{WebGLKernelArray:r}=j(),{sameError:n}=te();t.exports={WebGLKernelValueNumberTexture:class extends r{constructor(e,t){super(e,t);const[s,r]=e.size;this.checkSize(s,r);const{size:n,dimensions:i}=e;this.bitRatio=this.getBitRatio(e),this.dimensions=i,this.textureSize=n,this.uploadValue=e.texture,this.forceUploadEachRun=!0}setup(){this.setupTexture()}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName}.texture;\n`}getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);if(this.checkContext&&e.context!==this.context)throw new Error(`Value ${this.name} (${this.type}) must be from same context`);const{kernel:t,context:s}=this;if(t.pipeline)if(t.immutable)t.updateTextureArgumentRefs(this,e);else{if(t.texture&&t.texture.texture===e.texture)throw new Error(n);if(t.mappedTextures){const{mappedTextures:s}=t;for(let t=0;t{const{utils:s}=i(),{WebGLKernelValueNumberTexture:r}=re();t.exports={WebGLKernelValueDynamicNumberTexture:class extends r{getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=e.dimensions,this.checkSize(e.size[0],e.size[1]),this.textureSize=e.size,this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ie=e((e,t)=>{const{utils:s}=i(),{WebGLKernelArray:r}=j();t.exports={WebGLKernelValueSingleArray:class extends r{constructor(e,t){super(e,t),this.bitRatio=4,this.dimensions=s.getDimensions(e,!0),this.textureSize=s.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return s.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(!s.isArray(e))return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;s.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),ae=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueSingleArray:r}=ie();t.exports={WebGLKernelValueDynamicSingleArray:class extends r{getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=s.getDimensions(e,!0),this.textureSize=s.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),oe=e((e,t)=>{const{utils:s}=i(),{WebGLKernelArray:r}=j();t.exports={WebGLKernelValueSingleArray1DI:class extends r{constructor(e,t){super(e,t),this.bitRatio=4,this.setShape(e)}setShape(e){const t=s.getDimensions(e,!0);this.textureSize=s.getMemoryOptimizedFloatTextureSize(t,this.bitRatio),this.dimensions=new Int32Array([t[1],1,1]),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return s.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;s.flatten2dArrayTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),ue=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueSingleArray1DI:r}=oe();t.exports={WebGLKernelValueDynamicSingleArray1DI:class extends r{getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),le=e((e,t)=>{const{utils:s}=i(),{WebGLKernelArray:r}=j();t.exports={WebGLKernelValueSingleArray2DI:class extends r{constructor(e,t){super(e,t),this.bitRatio=4,this.setShape(e)}setShape(e){const t=s.getDimensions(e,!0);this.textureSize=s.getMemoryOptimizedFloatTextureSize(t,this.bitRatio),this.dimensions=new Int32Array([t[1],t[2],1]),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return s.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;s.flatten3dArrayTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),he=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueSingleArray2DI:r}=le();t.exports={WebGLKernelValueDynamicSingleArray2DI:class extends r{getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ce=e((e,t)=>{const{utils:s}=i(),{WebGLKernelArray:r}=j();t.exports={WebGLKernelValueSingleArray3DI:class extends r{constructor(e,t){super(e,t),this.bitRatio=4,this.setShape(e)}setShape(e){const t=s.getDimensions(e,!0);this.textureSize=s.getMemoryOptimizedFloatTextureSize(t,this.bitRatio),this.dimensions=new Int32Array([t[1],t[2],t[3]]),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength)}getStringValueHandler(){return s.linesToString([`const uploadValue_${this.name} = new Float32Array(${this.uploadArrayLength})`,`flattenTo(${this.varName}, uploadValue_${this.name})`])}getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;s.flatten4dArrayTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),pe=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueSingleArray3DI:r}=ce();t.exports={WebGLKernelValueDynamicSingleArray3DI:class extends r{getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),de=e((e,t)=>{const{WebGLKernelValue:s}=U();t.exports={WebGLKernelValueArray2:class extends s{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const vec2 ${this.id} = vec2(${e[0]},${e[1]});\n`:`uniform vec2 ${this.id};\n`}getStringValueHandler(){return"constants"===this.origin?"":`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform2fv(this.id,this.uploadValue=e)}}}}),fe=e((e,t)=>{const{WebGLKernelValue:s}=U();t.exports={WebGLKernelValueArray3:class extends s{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const vec3 ${this.id} = vec3(${e[0]},${e[1]},${e[2]});\n`:`uniform vec3 ${this.id};\n`}getStringValueHandler(){return"constants"===this.origin?"":`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform3fv(this.id,this.uploadValue=e)}}}}),me=e((e,t)=>{const{WebGLKernelValue:s}=U();t.exports={WebGLKernelValueArray4:class extends s{constructor(e,t){super(e,t),this.uploadValue=e}getSource(e){return"constants"===this.origin?`const vec4 ${this.id} = vec4(${e[0]},${e[1]},${e[2]},${e[3]});\n`:`uniform vec4 ${this.id};\n`}getStringValueHandler(){return"constants"===this.origin?"":`const uploadValue_${this.name} = ${this.varName};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform4fv(this.id,this.uploadValue=e)}}}}),ge=e((e,t)=>{const{utils:s}=i(),{WebGLKernelArray:r}=j();t.exports={WebGLKernelValueUnsignedArray:class extends r{constructor(e,t){super(e,t),this.bitRatio=this.getBitRatio(e),this.dimensions=s.getDimensions(e,!0),this.textureSize=s.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]),this.TranserArrayType=this.getTransferArrayType(e),this.preUploadValue=new this.TranserArrayType(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer)}getStringValueHandler(){return s.linesToString([`const preUploadValue_${this.name} = new ${this.TranserArrayType.name}(${this.uploadArrayLength})`,`const uploadValue_${this.name} = new Uint8Array(preUploadValue_${this.name}.buffer)`,`flattenTo(${this.varName}, preUploadValue_${this.name})`])}getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(!s.isArray(e))return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;s.flattenTo(e,this.preUploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.UNSIGNED_BYTE,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),xe=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueUnsignedArray:r}=ge();t.exports={WebGLKernelValueDynamicUnsignedArray:class extends r{getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=s.getDimensions(e,!0),this.textureSize=s.getMemoryOptimizedPackedTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*(4/this.bitRatio),this.checkSize(this.textureSize[0],this.textureSize[1]);const t=this.getTransferArrayType(e);this.preUploadValue=new t(this.uploadArrayLength),this.uploadValue=new Uint8Array(this.preUploadValue.buffer),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),ye=e((e,t)=>{const{WebGLKernelValueBoolean:s}=B(),{WebGLKernelValueFloat:r}=K(),{WebGLKernelValueInteger:n}=W(),{WebGLKernelValueHTMLImage:i}=q(),{WebGLKernelValueDynamicHTMLImage:a}=X(),{WebGLKernelValueHTMLVideo:o}=H(),{WebGLKernelValueDynamicHTMLVideo:u}=Y(),{WebGLKernelValueSingleInput:l}=Z(),{WebGLKernelValueDynamicSingleInput:h}=J(),{WebGLKernelValueUnsignedInput:c}=Q(),{WebGLKernelValueDynamicUnsignedInput:p}=ee(),{WebGLKernelValueMemoryOptimizedNumberTexture:d}=te(),{WebGLKernelValueDynamicMemoryOptimizedNumberTexture:f}=se(),{WebGLKernelValueNumberTexture:m}=re(),{WebGLKernelValueDynamicNumberTexture:g}=ne(),{WebGLKernelValueSingleArray:x}=ie(),{WebGLKernelValueDynamicSingleArray:y}=ae(),{WebGLKernelValueSingleArray1DI:b}=oe(),{WebGLKernelValueDynamicSingleArray1DI:v}=ue(),{WebGLKernelValueSingleArray2DI:S}=le(),{WebGLKernelValueDynamicSingleArray2DI:T}=he(),{WebGLKernelValueSingleArray3DI:A}=ce(),{WebGLKernelValueDynamicSingleArray3DI:w}=pe(),{WebGLKernelValueArray2:E}=de(),{WebGLKernelValueArray3:_}=fe(),{WebGLKernelValueArray4:I}=me(),{WebGLKernelValueUnsignedArray:k}=ge(),{WebGLKernelValueDynamicUnsignedArray:C}=xe(),L={unsigned:{dynamic:{Boolean:s,Integer:n,Float:r,Array:C,"Array(2)":E,"Array(3)":_,"Array(4)":I,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:p,NumberTexture:g,"ArrayTexture(1)":g,"ArrayTexture(2)":g,"ArrayTexture(3)":g,"ArrayTexture(4)":g,MemoryOptimizedNumberTexture:f,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:!1,HTMLVideo:u},static:{Boolean:s,Float:r,Integer:n,Array:k,"Array(2)":E,"Array(3)":_,"Array(4)":I,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:c,NumberTexture:m,"ArrayTexture(1)":m,"ArrayTexture(2)":m,"ArrayTexture(3)":m,"ArrayTexture(4)":m,MemoryOptimizedNumberTexture:d,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:!1,HTMLVideo:o}},single:{dynamic:{Boolean:s,Integer:n,Float:r,Array:y,"Array(2)":E,"Array(3)":_,"Array(4)":I,"Array1D(2)":v,"Array1D(3)":v,"Array1D(4)":v,"Array2D(2)":T,"Array2D(3)":T,"Array2D(4)":T,"Array3D(2)":w,"Array3D(3)":w,"Array3D(4)":w,Input:h,NumberTexture:g,"ArrayTexture(1)":g,"ArrayTexture(2)":g,"ArrayTexture(3)":g,"ArrayTexture(4)":g,MemoryOptimizedNumberTexture:f,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:!1,HTMLVideo:u},static:{Boolean:s,Float:r,Integer:n,Array:x,"Array(2)":E,"Array(3)":_,"Array(4)":I,"Array1D(2)":b,"Array1D(3)":b,"Array1D(4)":b,"Array2D(2)":S,"Array2D(3)":S,"Array2D(4)":S,"Array3D(2)":A,"Array3D(3)":A,"Array3D(4)":A,Input:l,NumberTexture:m,"ArrayTexture(1)":m,"ArrayTexture(2)":m,"ArrayTexture(3)":m,"ArrayTexture(4)":m,MemoryOptimizedNumberTexture:d,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:!1,HTMLVideo:o}}};t.exports={lookupKernelValueType:function(e,t,s,r){if(!e)throw new Error("type missing");if(!t)throw new Error("dynamic missing");if(!s)throw new Error("precision missing");r.type&&(e=r.type);const n=L[s][t];if("WebGPUBuffer"===e)throw new Error("this kernel runs on WebGL but received a WebGPU pipeline buffer; await handle.toArray() first, or give this kernel the async contract (asyncMode: true / mode: 'async') so the readback happens for you");if(!1===n[e])return null;if(void 0===n[e])throw new Error(`Could not find a KernelValue for ${e}`);return n[e]},kernelValueMaps:L}}),be=e((e,t)=>{const{GLKernel:s}=N(),{FunctionBuilder:r}=o(),{WebGLFunctionNode:n}=R(),{utils:a}=i(),u=M(),{fragmentShader:l}=G(),{vertexShader:h}=O(),{glKernelString:c}=P(),{lookupKernelValueType:p}=ye();let d=null,f=null,m=null,g=null,x=null;const y=[u],b=[],v={};t.exports={WebGLKernel:class extends s{static get isSupported(){return null!==d||(this.setupFeatureChecks(),d=this.isContextMatch(m)),d}static setupFeatureChecks(){"undefined"!=typeof document?f=document.createElement("canvas"):"undefined"!=typeof OffscreenCanvas&&(f=new OffscreenCanvas(0,0)),f&&(m=f.getContext("webgl"),m||f instanceof OffscreenCanvas||(m=f.getContext("experimental-webgl")),m&&m.getExtension&&(g={OES_texture_float:m.getExtension("OES_texture_float"),OES_texture_float_linear:m.getExtension("OES_texture_float_linear"),OES_element_index_uint:m.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:m.getExtension("WEBGL_draw_buffers")},x=this.getFeatures()))}static isContextMatch(e){return"undefined"!=typeof WebGLRenderingContext&&e instanceof WebGLRenderingContext}static getIsTextureFloat(){return Boolean(g.OES_texture_float)}static getIsDrawBuffers(){return Boolean(g.WEBGL_draw_buffers)}static getChannelCount(){return g.WEBGL_draw_buffers?m.getParameter(g.WEBGL_draw_buffers.MAX_DRAW_BUFFERS_WEBGL):1}static getMaxTextureSize(){return m.getParameter(m.MAX_TEXTURE_SIZE)}static lookupKernelValueType(e,t,s,r){return p(e,t,s,r)}static get testCanvas(){return f}static get testContext(){return m}static get features(){return x}static get fragmentShader(){return l}static get vertexShader(){return h}constructor(e,t){super(e,t),this.program=null,this.pipeline=t.pipeline,this.endianness=a.systemEndianness(),this.extensions={},this.argumentTextureCount=0,this.constantTextureCount=0,this.fragShader=null,this.vertShader=null,this.drawBuffersMap=null,this.maxTexSize=null,this.onRequestSwitchKernel=null,this.texture=null,this.mappedTextures=null,this.mergeSettings(e.settings||t),this.threadDim=null,this.framebuffer=null,this.buffer=null,this.textureCache=[],this.programUniformLocationCache={},this.uniform1fCache={},this.uniform1iCache={},this.uniform2fCache={},this.uniform2fvCache={},this.uniform2ivCache={},this.uniform3fvCache={},this.uniform3ivCache={},this.uniform4fvCache={},this.uniform4ivCache={}}initCanvas(){if("undefined"!=typeof document){const e=document.createElement("canvas");return e.width=2,e.height=2,e}if("undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(0,0)}initContext(){const e={alpha:!1,depth:!1,antialias:!1};return this.canvas.getContext("webgl",e)||this.canvas.getContext("experimental-webgl",e)}initPlugins(e){const t=[],{source:s}=this;if("string"==typeof s)for(let e=0;ee===r.name)&&t.push(r)}return t}initExtensions(){this.extensions={OES_texture_float:this.context.getExtension("OES_texture_float"),OES_texture_float_linear:this.context.getExtension("OES_texture_float_linear"),OES_element_index_uint:this.context.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:this.context.getExtension("WEBGL_draw_buffers"),WEBGL_color_buffer_float:this.context.getExtension("WEBGL_color_buffer_float")}}validateSettings(e){if(!this.validate)return void(this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output));const{features:t}=this.constructor;if(!0===this.optimizeFloatMemory&&!t.isTextureFloat)throw new Error("Float textures are not supported");if("single"===this.precision&&!t.isFloatRead)throw new Error("Single precision not supported");if(this.graphical||null!==this.precision||(this.precision=t.isTextureFloat&&t.isFloatRead?"single":"unsigned"),this.subKernels&&this.subKernels.length>0&&!this.extensions.WEBGL_draw_buffers)throw new Error("could not instantiate draw buffers extension");if(null===this.fixIntegerDivisionAccuracy?this.fixIntegerDivisionAccuracy=!t.isIntegerDivisionAccurate:this.fixIntegerDivisionAccuracy&&t.isIntegerDivisionAccurate&&(this.fixIntegerDivisionAccuracy=!1),this.checkOutput(),!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=a.getVariableType(e[0],this.strictIntegers);switch(t){case"Array":this.output=a.getDimensions(t);break;case"NumberTexture":case"MemoryOptimizedNumberTexture":case"ArrayTexture(1)":case"ArrayTexture(2)":case"ArrayTexture(3)":case"ArrayTexture(4)":this.output=e[0].output;break;default:throw new Error("Auto output not supported for input type: "+t)}}if(this.graphical){if(2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");return"precision"===this.precision&&(this.precision="unsigned",console.warn("Cannot use graphical mode and single precision at the same time")),void(this.texSize=a.clone(this.output))}null===this.precision&&t.isTextureFloat&&(this.precision="single"),this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output),this.checkTextureSize()}updateMaxTexSize(){const{texSize:e,canvas:t}=this;if(null===this.maxTexSize){let s=b.indexOf(t);-1===s&&(s=b.length,b.push(t),v[s]=[e[0],e[1]]),this.maxTexSize=v[s]}this.maxTexSize[0]this.argumentNames.length)throw new Error("too many arguments for kernel");const{context:s}=this;let r=0;const n=()=>this.createTexture(),i=()=>this.constantTextureCount+r++,o=e=>{this.switchKernels({type:"argumentMismatch",needed:e})},u=()=>s.TEXTURE0+this.constantTextureCount+this.argumentTextureCount++;for(let r=0;rthis.createTexture(),onRequestIndex:()=>r++,onRequestContextHandle:()=>t.TEXTURE0+this.constantTextureCount++});this.constantBitRatios[n]=l.bitRatio,this.kernelConstants.push(l),l.setup(),l.forceUploadEachRun&&this.forceUploadKernelConstants.push(l)}}build(){if(this.built)return;if(this.initExtensions(),this.validateSettings(arguments),this.setupConstants(arguments),this.fallbackRequested)return;if(this.setupArguments(arguments),this.fallbackRequested)return;this.updateMaxTexSize(),this.translateSource();const e=this.pickRenderStrategy(arguments);if(e)return e;const{texSize:t,context:s,canvas:r}=this;s.enable(s.SCISSOR_TEST),this.pipeline&&this.precision,s.viewport(0,0,this.maxTexSize[0],this.maxTexSize[1]),r.width=this.maxTexSize[0],r.height=this.maxTexSize[1];const n=this.threadDim=Array.from(this.output);for(;n.length<3;)n.push(1);const i=this.getVertexShader(arguments),a=s.createShader(s.VERTEX_SHADER);s.shaderSource(a,i),s.compileShader(a),this.vertShader=a;const o=this.getFragmentShader(arguments),u=s.createShader(s.FRAGMENT_SHADER);if(s.shaderSource(u,o),s.compileShader(u),this.fragShader=u,this.debug&&(console.log("GLSL Shader Output:"),console.log(o)),!s.getShaderParameter(a,s.COMPILE_STATUS))throw new Error("Error compiling vertex shader: "+s.getShaderInfoLog(a));if(!s.getShaderParameter(u,s.COMPILE_STATUS))throw new Error("Error compiling fragment shader: "+s.getShaderInfoLog(u));const l=this.program=s.createProgram();s.attachShader(l,a),s.attachShader(l,u),s.linkProgram(l),this.framebuffer=s.createFramebuffer(),this.framebuffer.width=t[0],this.framebuffer.height=t[1],this.rawValueFramebuffers={};const h=new Float32Array([-1,-1,1,-1,-1,1,1,1]),c=new Float32Array([0,0,1,0,0,1,1,1]),p=h.byteLength;let d=this.buffer;d?s.bindBuffer(s.ARRAY_BUFFER,d):(d=this.buffer=s.createBuffer(),s.bindBuffer(s.ARRAY_BUFFER,d),s.bufferData(s.ARRAY_BUFFER,h.byteLength+c.byteLength,s.STATIC_DRAW)),s.bufferSubData(s.ARRAY_BUFFER,0,h),s.bufferSubData(s.ARRAY_BUFFER,p,c);const f=s.getAttribLocation(this.program,"aPos");-1!==f&&(s.enableVertexAttribArray(f),s.vertexAttribPointer(f,2,s.FLOAT,!1,0,0));const m=s.getAttribLocation(this.program,"aTexCoord");-1!==m&&(s.enableVertexAttribArray(m),s.vertexAttribPointer(m,2,s.FLOAT,!1,0,p)),s.bindFramebuffer(s.FRAMEBUFFER,this.framebuffer);let g=0;s.useProgram(this.program);for(let e in this.constants)this.kernelConstants[g++].updateValue(this.constants[e]);this._setupOutputTexture(),null!==this.subKernels&&this.subKernels.length>0&&(this._mappedTextureSwitched={},this._setupSubOutputTextures()),this.buildSignature(arguments),this.built=!0}translateSource(){const e=r.fromKernel(this,n,{fixIntegerDivisionAccuracy:this.fixIntegerDivisionAccuracy});this.translatedSource=e.getPrototypeString("kernel"),this.setupReturnTypes(e)}setupReturnTypes(e){if(this.graphical||this.returnType||(this.returnType=e.getKernelResultType()),this.subKernels&&this.subKernels.length>0)for(let t=0;te.source&&this.source.match(e.functionMatch)?e.source:"").join("\n"):"\n"}_getConstantsString(){const e=[],{threadDim:t,texSize:s}=this;return this.dynamicOutput?e.push("uniform ivec3 uOutputDim","uniform ivec2 uTexSize"):e.push(`ivec3 uOutputDim = ivec3(${t[0]}, ${t[1]}, ${t[2]})`,`ivec2 uTexSize = ivec2(${s[0]}, ${s[1]})`),a.linesToString(e)}_getTextureCoordinate(){const e=this.subKernels;return null===e||e.length<1?"varying vec2 vTexCoord;\n":"out vec2 vTexCoord;\n"}_getDecode32EndiannessString(){return"LE"===this.endianness?"":" texel.rgba = texel.abgr;\n"}_getEncode32EndiannessString(){return"LE"===this.endianness?"":" texel.rgba = texel.abgr;\n"}_getDivideWithIntegerCheckString(){return this.fixIntegerDivisionAccuracy?"float divWithIntCheck(float x, float y) {\n if (floor(x) == x && floor(y) == y) {\n float q = floor(x / y + 0.5);\n if (y * q == x) {\n return q;\n }\n }\n return x / y;\n}\n\nfloat integerCorrectionModulo(float number, float divisor) {\n if (number < 0.0) {\n number = abs(number);\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return -(number - (divisor * floor(divWithIntCheck(number, divisor))));\n }\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return number - (divisor * floor(divWithIntCheck(number, divisor)));\n}":""}_getMainArgumentsString(e){const t=[],{argumentNames:s}=this;for(let r=0;r{if(t.hasOwnProperty(s))return t[s];throw`unhandled artifact ${s}`})}getFragmentShader(e){return null!==this.compiledFragmentShader?this.compiledFragmentShader:this.compiledFragmentShader=this.replaceArtifacts(this.constructor.fragmentShader,this._getFragShaderArtifactMap(e))}getVertexShader(e){return null!==this.compiledVertexShader?this.compiledVertexShader:this.compiledVertexShader=this.replaceArtifacts(this.constructor.vertexShader,this._getVertShaderArtifactMap(e))}toString(){const e=a.linesToString(["const gl = context"]);return c(this.constructor,arguments,this,e)}destroy(e){if(!this.context)return;this.buffer&&this.context.deleteBuffer(this.buffer),this.framebuffer&&this.context.deleteFramebuffer(this.framebuffer);for(const e in this.rawValueFramebuffers){for(const t in this.rawValueFramebuffers[e])this.context.deleteFramebuffer(this.rawValueFramebuffers[e][t]),delete this.rawValueFramebuffers[e][t];delete this.rawValueFramebuffers[e]}if(this.vertShader&&this.context.deleteShader(this.vertShader),this.fragShader&&this.context.deleteShader(this.fragShader),this.program&&this.context.deleteProgram(this.program),this.texture){this.texture.delete();const e=this.textureCache.indexOf(this.texture.texture);e>-1&&this.textureCache.splice(e,1),this.texture=null}if(this.mappedTextures&&this.mappedTextures.length){for(let e=0;e-1&&this.textureCache.splice(s,1)}this.mappedTextures=null}if(this.kernelArguments)for(let e=0;e0;){const e=this.textureCache.pop();this.context.deleteTexture(e)}if(e){const e=b.indexOf(this.canvas);e>=0&&(b[e]=null,v[e]=null)}if(this.destroyExtensions(),delete this.context,delete this.canvas,!this.gpu)return;const t=this.gpu.kernels.indexOf(this);-1!==t&&this.gpu.kernels.splice(t,1)}destroyExtensions(){this.extensions.OES_texture_float=null,this.extensions.OES_texture_float_linear=null,this.extensions.OES_element_index_uint=null,this.extensions.WEBGL_draw_buffers=null}static destroyContext(e){const t=e.getExtension("WEBGL_lose_context");t&&t.loseContext()}toJSON(){const e=super.toJSON();return e.functionNodes=r.fromKernel(this,n).toJSON(),e.settings.threadDim=this.threadDim,e}}}}),ve=e((e,t)=>{const s=d(),{WebGLKernel:r}=be(),{glKernelString:n}=P();let i=null,a=null,o=null,u=null,l=null;t.exports={HeadlessGLKernel:class extends r{static get isSupported(){return null!==i||(this.setupFeatureChecks(),i=null!==o),i}static setupFeatureChecks(){if(a=null,u=null,"function"==typeof s)try{if(o=s(2,2,{preserveDrawingBuffer:!0}),!o||!o.getExtension)return;u={STACKGL_resize_drawingbuffer:o.getExtension("STACKGL_resize_drawingbuffer"),STACKGL_destroy_context:o.getExtension("STACKGL_destroy_context"),OES_texture_float:o.getExtension("OES_texture_float"),OES_texture_float_linear:o.getExtension("OES_texture_float_linear"),OES_element_index_uint:o.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:o.getExtension("WEBGL_draw_buffers"),WEBGL_color_buffer_float:o.getExtension("WEBGL_color_buffer_float")},l=this.getFeatures()}catch(e){console.warn(e)}}static isContextMatch(e){try{return"ANGLE"===e.getParameter(e.RENDERER)}catch(e){return!1}}static getIsTextureFloat(){return Boolean(u.OES_texture_float)}static getIsDrawBuffers(){return Boolean(u.WEBGL_draw_buffers)}static getChannelCount(){return u.WEBGL_draw_buffers?o.getParameter(u.WEBGL_draw_buffers.MAX_DRAW_BUFFERS_WEBGL):1}static getMaxTextureSize(){return o.getParameter(o.MAX_TEXTURE_SIZE)}static get testCanvas(){return a}static get testContext(){return o}static get features(){return l}initCanvas(){return{}}initContext(){return s(2,2,{preserveDrawingBuffer:!0})}initExtensions(){this.extensions={STACKGL_resize_drawingbuffer:this.context.getExtension("STACKGL_resize_drawingbuffer"),STACKGL_destroy_context:this.context.getExtension("STACKGL_destroy_context"),OES_texture_float:this.context.getExtension("OES_texture_float"),OES_texture_float_linear:this.context.getExtension("OES_texture_float_linear"),OES_element_index_uint:this.context.getExtension("OES_element_index_uint"),WEBGL_draw_buffers:this.context.getExtension("WEBGL_draw_buffers")}}build(){super.build.apply(this,arguments),this.fallbackRequested||this.extensions.STACKGL_resize_drawingbuffer.resize(this.maxTexSize[0],this.maxTexSize[1])}destroyExtensions(){this.extensions.STACKGL_resize_drawingbuffer=null,this.extensions.STACKGL_destroy_context=null,this.extensions.OES_texture_float=null,this.extensions.OES_texture_float_linear=null,this.extensions.OES_element_index_uint=null,this.extensions.WEBGL_draw_buffers=null}static destroyContext(e){const t=e.getExtension("STACKGL_destroy_context");t&&t.destroy&&t.destroy()}toString(){return n(this.constructor,arguments,this,"const gl = context || require('gl')(1, 1);\n"," if (!context) { gl.getExtension('STACKGL_destroy_context').destroy(); }\n")}setOutput(e){return super.setOutput(e),this.graphical&&this.extensions.STACKGL_resize_drawingbuffer&&this.extensions.STACKGL_resize_drawingbuffer.resize(this.maxTexSize[0],this.maxTexSize[1]),this}}}}),Se=e((e,t)=>{const{utils:s}=i(),{WebGLFunctionNode:r}=R();t.exports={WebGL2FunctionNode:class extends r{astIdentifierExpression(e,t){if("Identifier"!==e.type)throw this.astErrorOutput("IdentifierExpression - not an Identifier",e);const r=this.getType(e),n=s.sanitizeName(e.name);if("Infinity"===e.name)t.push("intBitsToFloat(2139095039)");else if("Boolean"===r)if(this.argumentNames.indexOf(n)>-1){const s=this.markupUserName(e.name);t.push(s.startsWith("cellShadow_")?s:`bool(${s})`)}else t.push(`user_${n}`);else t.push(this.markupUserName(e.name));return t}}}}),Te=e((e,t)=>{t.exports={fragmentShader:`#version 300 es\n__HEADER__;\n__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n__SAMPLER_2D_ARRAY_TACTIC_DECLARATION__;\n\nconst int LOOP_MAX = __LOOP_MAX__;\n\n__PLUGINS__;\n__CONSTANTS__;\n\nin vec2 vTexCoord;\n\nfloat atan2(float v1, float v2) {\n if (v2 == 0.0) {\n if (v1 == 0.0) return 0.0;\n if (v1 > 0.0) return 1.5707963267948966;\n if (v1 < 0.0) return -1.5707963267948966;\n }\n return atan(v1, v2);\n}\n\nfloat cbrt(float x) {\n if (x >= 0.0) {\n return pow(x, 1.0 / 3.0);\n } else {\n return -pow(x, 1.0 / 3.0);\n }\n}\n\nfloat expm1(float x) {\n return pow(${Math.E}, x) - 1.0; \n}\n\nfloat fround(highp float x) {\n return x;\n}\n\nfloat imul(float v1, float v2) {\n return float(int(v1) * int(v2));\n}\n\nfloat log10(float x) {\n return log2(x) * (1.0 / log2(10.0));\n}\n\nfloat log1p(float x) {\n return log(1.0 + x);\n}\n\nfloat _pow(float v1, float v2) {\n if (v2 == 0.0) return 1.0;\n return pow(v1, v2);\n}\n\nfloat _round(float x) {\n return floor(x + 0.5);\n}\n\n\nconst int BIT_COUNT = 32;\nint modi(int x, int y) {\n return x - y * (x / y);\n}\n\nint bitwiseOr(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) || (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseXOR(int a, int b) {\n int result = 0;\n int n = 1;\n \n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) != (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 || b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseAnd(int a, int b) {\n int result = 0;\n int n = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if ((modi(a, 2) == 1) && (modi(b, 2) == 1)) {\n result += n;\n }\n a = a / 2;\n b = b / 2;\n n = n * 2;\n if(!(a > 0 && b > 0)) {\n break;\n }\n }\n return result;\n}\nint bitwiseNot(int a) {\n // ~a is identically -a - 1 in two's complement, for every value including\n // negatives. The previous bit-by-bit loop only worked for a >= 0, where it\n // leaned on 32-bit overflow wrapping to reach the negative answer; given a\n // negative input it computed ~abs(a), so ~(-1) gave -2 and ~~x never\n // returned x.\n return -a - 1;\n}\nint bitwiseZeroFillLeftShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n *= 2;\n }\n\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\n// _pow2 is defined further down, alongside encode32/decode32\nfloat _pow2(float e);\nint bitwiseSignedRightShift(int num, int shifts) {\n // pow(2.0, n) is approximate on many GPUs, and landing 1 ulp high makes the\n // division fall just under a whole number, which floor() then rounds away:\n // 2 >> 1 came out 0, 8 >> 1 came out 3. Only exact left operands were\n // affected, odd ones having enough slack to survive. _pow2 is exact.\n return int(floor(float(num) / _pow2(float(shifts))));\n}\n\nint bitwiseZeroFillRightShift(int n, int shift) {\n int maxBytes = BIT_COUNT;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (maxBytes >= n) {\n break;\n }\n maxBytes *= 2;\n }\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= shift) {\n break;\n }\n n /= 2;\n }\n int result = 0;\n int byteVal = 1;\n for (int i = 0; i < BIT_COUNT; i++) {\n if (i >= maxBytes) break;\n if (modi(n, 2) > 0) { result += byteVal; }\n n = int(n / 2);\n byteVal *= 2;\n }\n return result;\n}\n\nvec2 integerMod(vec2 x, float y) {\n vec2 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec3 integerMod(vec3 x, float y) {\n vec3 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nvec4 integerMod(vec4 x, vec4 y) {\n vec4 res = floor(mod(x, y));\n return res * step(1.0 - floor(y), -res);\n}\n\nfloat integerMod(float x, float y) {\n float res = floor(mod(x, y));\n return res * (res > floor(y) - 1.0 ? 0.0 : 1.0);\n}\n\nint integerMod(int x, int y) {\n return x - (y * int(x/y));\n}\n\n// GLSL ES 1.00 accepts only a constant or a loop symbol inside an index\n// expression, so m[y][x] does not compile when y and x come from kernel\n// arguments -- the error is "Index expression can only contain const or loop\n// symbols". Loop counters are legal indices, so walk the matrix with them\n// instead. These are 2x2 to 4x4, so it costs at most sixteen comparisons.\nfloat getMatrix2(mat2 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 2; i++) {\n for (int j = 0; j < 2; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix3(mat3 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 3; i++) {\n for (int j = 0; j < 3; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\nfloat getMatrix4(mat4 m, int y, int x) {\n float result = 0.0;\n for (int i = 0; i < 4; i++) {\n for (int j = 0; j < 4; j++) {\n if (i == y && j == x) result = m[i][j];\n }\n }\n return result;\n}\n\n__DIVIDE_WITH_INTEGER_CHECK__;\n\n// Here be dragons!\n// DO NOT OPTIMIZE THIS CODE\n// YOU WILL BREAK SOMETHING ON SOMEBODY'S MACHINE\n// LEAVE IT AS IT IS, LEST YOU WASTE YOUR OWN TIME\n// Exact powers of two built from exact constant multiplies: exp2/log2/pow\n// are approximate on some GPUs (notably Apple silicon), and 1-2 ulp there\n// corrupts the packed bytes (#659)\nfloat _pow2(float e) {\n float r = 1.0;\n float a = abs(e);\n bool n = e < 0.0;\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 64.0) { r *= n ? 5.421010862427522e-20 : 18446744073709551616.0; a -= 64.0; }\n if (a >= 32.0) { r *= n ? 2.3283064365386963e-10 : 4294967296.0; a -= 32.0; }\n if (a >= 16.0) { r *= n ? 0.0000152587890625 : 65536.0; a -= 16.0; }\n if (a >= 8.0) { r *= n ? 0.00390625 : 256.0; a -= 8.0; }\n if (a >= 4.0) { r *= n ? 0.0625 : 16.0; a -= 4.0; }\n if (a >= 2.0) { r *= n ? 0.25 : 4.0; a -= 2.0; }\n if (a >= 1.0) { r *= n ? 0.5 : 2.0; }\n return r;\n}\nconst vec2 MAGIC_VEC = vec2(1.0, -256.0);\nconst vec4 SCALE_FACTOR = vec4(1.0, 256.0, 65536.0, 0.0);\nconst vec4 SCALE_FACTOR_INV = vec4(1.0, 0.00390625, 0.0000152587890625, 0.0); // 1, 1/256, 1/65536\nfloat decode32(vec4 texel) {\n __DECODE32_ENDIANNESS__;\n texel *= 255.0;\n vec2 gte128;\n gte128.x = texel.b >= 128.0 ? 1.0 : 0.0;\n gte128.y = texel.a >= 128.0 ? 1.0 : 0.0;\n float exponent = 2.0 * texel.a - 127.0 + dot(gte128, MAGIC_VEC);\n float res = _pow2(round(exponent));\n texel.b = texel.b - 128.0 * gte128.x;\n res = dot(texel, SCALE_FACTOR) * _pow2(round(exponent-23.0)) + res;\n res *= gte128.y * -2.0 + 1.0;\n return res;\n}\n\nfloat decode16(vec4 texel, int index) {\n int channel = integerMod(index, 2);\n return texel[channel*2] * 255.0 + texel[channel*2 + 1] * 65280.0;\n}\n\nfloat decode8(vec4 texel, int index) {\n int channel = integerMod(index, 4);\n return texel[channel] * 255.0;\n}\n\nvec4 legacyEncode32(float f) {\n float F = abs(f);\n float sign = f < 0.0 ? 1.0 : 0.0;\n float exponent = floor(log2(F));\n float mantissa = (exp2(-exponent) * F);\n // exponent += floor(log2(mantissa));\n vec4 texel = vec4(F * exp2(23.0-exponent)) * SCALE_FACTOR_INV;\n texel.rg = integerMod(texel.rg, 256.0);\n texel.b = integerMod(texel.b, 128.0);\n texel.a = exponent*0.5 + 63.5;\n texel.ba += vec2(integerMod(exponent+127.0, 2.0), sign) * 128.0;\n texel = floor(texel);\n texel *= 0.003921569; // 1/255\n __ENCODE32_ENDIANNESS__;\n return texel;\n}\n\n// https://github.com/gpujs/gpu.js/wiki/Encoder-details\nvec4 encode32(float value) {\n if (value == 0.0) return vec4(0, 0, 0, 0);\n\n float exponent;\n float mantissa;\n vec4 result;\n float sgn;\n\n sgn = step(0.0, -value);\n value = abs(value);\n\n exponent = floor(log2(value));\n float p2 = _pow2(exponent);\n // approximate log2 can land one off; correct by direct comparison\n if (p2 > value) { exponent -= 1.0; p2 *= 0.5; }\n else if (p2 * 2.0 <= value) { exponent += 1.0; p2 *= 2.0; }\n\n mantissa = value / p2 - 1.0;\n exponent = exponent+127.0;\n result = vec4(0,0,0,0);\n\n result.a = floor(exponent/2.0);\n exponent = exponent - result.a*2.0;\n result.a = result.a + 128.0*sgn;\n\n result.b = floor(mantissa * 128.0);\n mantissa = mantissa - result.b / 128.0;\n result.b = result.b + exponent*128.0;\n\n result.g = floor(mantissa*32768.0);\n mantissa = mantissa - result.g/32768.0;\n\n result.r = floor(mantissa*8388608.0);\n return result/255.0;\n}\n// Dragons end here\n\nint index;\nivec3 threadId;\n\nivec3 indexTo3D(int idx, ivec3 texDim) {\n int z = int(idx / (texDim.x * texDim.y));\n idx -= z * int(texDim.x * texDim.y);\n int y = int(idx / texDim.x);\n int x = int(integerMod(idx, texDim.x));\n return ivec3(x, y, z);\n}\n\nfloat get32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize));\n return decode32(texel);\n}\n\nfloat get16(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int w = texSize.x * 2;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize.x * 2, texSize.y));\n return decode16(texel, index);\n}\n\nfloat get8(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int w = texSize.x * 4;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize.x * 4, texSize.y));\n return decode8(texel, index);\n}\n\nfloat getMemoryOptimized32(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + (texDim.x * (y + (texDim.y * z)));\n int channel = integerMod(index, 4);\n index = index / 4;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n index = index / 4;\n vec4 texel = texture(tex, st / vec2(texSize));\n return texel[channel];\n}\n\nvec4 getImage2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n return texture(tex, st / vec2(texSize));\n}\n\nvec4 getImage3D(sampler2DArray tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n return texture(tex, vec3(st / vec2(texSize), z));\n}\n\nfloat getFloatFromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return result[0];\n}\n\nvec2 getVec2FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec2(result[0], result[1]);\n}\n\nvec2 getMemoryOptimizedVec2(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 2);\n index = index / 2;\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize));\n if (channel == 0) return vec2(texel.r, texel.g);\n if (channel == 1) return vec2(texel.b, texel.a);\n return vec2(0.0, 0.0);\n}\n\nvec3 getVec3FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n vec4 result = getImage2D(tex, texSize, texDim, z, y, x);\n return vec3(result[0], result[1], result[2]);\n}\n\nvec3 getMemoryOptimizedVec3(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int fieldIndex = 3 * (x + texDim.x * (y + texDim.y * z));\n int vectorIndex = fieldIndex / 4;\n int vectorOffset = fieldIndex - vectorIndex * 4;\n int readY = vectorIndex / texSize.x;\n int readX = vectorIndex - readY * texSize.x;\n vec4 tex1 = texture(tex, (vec2(readX, readY) + 0.5) / vec2(texSize));\n\n if (vectorOffset == 0) {\n return tex1.xyz;\n } else if (vectorOffset == 1) {\n return tex1.yzw;\n } else {\n readX++;\n if (readX >= texSize.x) {\n readX = 0;\n readY++;\n }\n vec4 tex2 = texture(tex, vec2(readX, readY) / vec2(texSize));\n if (vectorOffset == 2) {\n return vec3(tex1.z, tex1.w, tex2.x);\n } else {\n return vec3(tex1.w, tex2.x, tex2.y);\n }\n }\n}\n\nvec4 getVec4FromSampler2D(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n return getImage2D(tex, texSize, texDim, z, y, x);\n}\n\nvec4 getMemoryOptimizedVec4(sampler2D tex, ivec2 texSize, ivec3 texDim, int z, int y, int x) {\n int index = x + texDim.x * (y + texDim.y * z);\n int channel = integerMod(index, 2);\n int w = texSize.x;\n vec2 st = vec2(float(integerMod(index, w)), float(index / w)) + 0.5;\n vec4 texel = texture(tex, st / vec2(texSize));\n return vec4(texel.r, texel.g, texel.b, texel.a);\n}\n\nvec4 actualColor;\nvoid color(float r, float g, float b, float a) {\n actualColor = vec4(r,g,b,a);\n}\n\nvoid color(float r, float g, float b) {\n color(r,g,b,1.0);\n}\n\nfloat modulo(float number, float divisor) {\n if (number < 0.0) {\n number = abs(number);\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return -mod(number, divisor);\n }\n if (divisor < 0.0) {\n divisor = abs(divisor);\n }\n return mod(number, divisor);\n}\n\n__INJECTED_NATIVE__;\n__MAIN_CONSTANTS__;\n__MAIN_ARGUMENTS__;\n__KERNEL__;\n\nvoid main(void) {\n index = int(vTexCoord.s * float(uTexSize.x)) + int(vTexCoord.t * float(uTexSize.y)) * uTexSize.x;\n __MAIN_RESULT__;\n}`}}),Ae=e((e,t)=>{t.exports={vertexShader:"#version 300 es\n__FLOAT_TACTIC_DECLARATION__;\n__INT_TACTIC_DECLARATION__;\n__SAMPLER_2D_TACTIC_DECLARATION__;\n\nin vec2 aPos;\nin vec2 aTexCoord;\n\nout vec2 vTexCoord;\nuniform vec2 ratio;\n\nvoid main(void) {\n gl_Position = vec4((aPos + vec2(1)) * ratio + vec2(-1), 0, 1);\n vTexCoord = aTexCoord;\n}"}}),we=e((e,t)=>{const{WebGLKernelValueBoolean:s}=B();t.exports={WebGL2KernelValueBoolean:class extends s{}}}),Ee=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueFloat:r}=K();t.exports={WebGL2KernelValueFloat:class extends r{}}}),_e=e((e,t)=>{const{WebGLKernelValueInteger:s}=W();t.exports={WebGL2KernelValueInteger:class extends s{getSource(e){const t=this.getVariablePrecisionString();return"constants"===this.origin?`const ${t} int ${this.id} = ${parseInt(e)};\n`:`uniform ${t} int ${this.id};\n`}updateValue(e){"constants"!==this.origin&&this.kernel.setUniform1i(this.id,this.uploadValue=e)}}}}),Ie=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueHTMLImage:r}=q();t.exports={WebGL2KernelValueHTMLImage:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}}}}),ke=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueDynamicHTMLImage:r}=X();t.exports={WebGL2KernelValueDynamicHTMLImage:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),Ce=e((e,t)=>{const{utils:s}=i(),{WebGLKernelArray:r}=j();t.exports={WebGL2KernelValueHTMLImageArray:class extends r{constructor(e,t){super(e,t),this.checkSize(e[0].width,e[0].height),this.dimensions=[e[0].width,e[0].height,e.length],this.textureSize=[e[0].width,e[0].height]}defineTexture(){const{context:e}=this;e.activeTexture(this.contextHandle),e.bindTexture(e.TEXTURE_2D_ARRAY,this.texture),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_MAG_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D_ARRAY,e.TEXTURE_MIN_FILTER,e.NEAREST)}getStringValueHandler(){return`const uploadValue_${this.name} = ${this.varName};\n`}getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2DArray ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){const{context:t}=this;t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D_ARRAY,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!0),t.texImage3D(t.TEXTURE_2D_ARRAY,0,t.RGBA,e[0].width,e[0].height,e.length,0,t.RGBA,t.UNSIGNED_BYTE,null);for(let s=0;s{const{utils:s}=i(),{WebGL2KernelValueHTMLImageArray:r}=Ce();t.exports={WebGL2KernelValueDynamicHTMLImageArray:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2DArray ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){const{width:t,height:s}=e[0];this.checkSize(t,s),this.dimensions=[t,s,e.length],this.textureSize=[t,s],this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),De=e((e,t)=>{const{utils:s}=i(),{WebGL2KernelValueHTMLImage:r}=Ie();t.exports={WebGL2KernelValueHTMLVideo:class extends r{}}}),Fe=e((e,t)=>{const{utils:s}=i(),{WebGL2KernelValueDynamicHTMLImage:r}=ke();t.exports={WebGL2KernelValueDynamicHTMLVideo:class extends r{}}}),$e=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueSingleInput:r}=Z();t.exports={WebGL2KernelValueSingleInput:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){const{context:t}=this;s.flattenTo(e.value,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Ne=e((e,t)=>{const{utils:s}=i(),{WebGL2KernelValueSingleInput:r}=$e();t.exports={WebGL2KernelValueDynamicSingleInput:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){let[t,r,n]=e.size;this.dimensions=new Int32Array([t||1,r||1,n||1]),this.textureSize=s.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Re=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueUnsignedInput:r}=Q();t.exports={WebGL2KernelValueUnsignedInput:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}}}}),Me=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueDynamicUnsignedInput:r}=ee();t.exports={WebGL2KernelValueDynamicUnsignedInput:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),Ge=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueMemoryOptimizedNumberTexture:r}=te();t.exports={WebGL2KernelValueMemoryOptimizedNumberTexture:class extends r{getSource(){const{id:e,sizeId:t,textureSize:r,dimensionsId:n,dimensions:i}=this,a=this.getVariablePrecisionString();return s.linesToString([`uniform sampler2D ${e}`,`${a} ivec2 ${t} = ivec2(${r[0]}, ${r[1]})`,`${a} ivec3 ${n} = ivec3(${i[0]}, ${i[1]}, ${i[2]})`])}}}}),Oe=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueDynamicMemoryOptimizedNumberTexture:r}=se();t.exports={WebGL2KernelValueDynamicMemoryOptimizedNumberTexture:class extends r{getSource(){return s.linesToString([`uniform sampler2D ${this.id}`,`uniform ivec2 ${this.sizeId}`,`uniform ivec3 ${this.dimensionsId}`])}}}}),Ve=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueNumberTexture:r}=re();t.exports={WebGL2KernelValueNumberTexture:class extends r{getSource(){const{id:e,sizeId:t,textureSize:r,dimensionsId:n,dimensions:i}=this,a=this.getVariablePrecisionString();return s.linesToString([`uniform ${a} sampler2D ${e}`,`${a} ivec2 ${t} = ivec2(${r[0]}, ${r[1]})`,`${a} ivec3 ${n} = ivec3(${i[0]}, ${i[1]}, ${i[2]})`])}}}}),Pe=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueDynamicNumberTexture:r}=ne();t.exports={WebGL2KernelValueDynamicNumberTexture:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),ze=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueSingleArray:r}=ie();t.exports={WebGL2KernelValueSingleArray:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}updateValue(e){if(!s.isArray(e))return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;s.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Ue=e((e,t)=>{const{utils:s}=i(),{WebGL2KernelValueSingleArray:r}=ze();t.exports={WebGL2KernelValueDynamicSingleArray:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.dimensions=s.getDimensions(e,!0),this.textureSize=s.getMemoryOptimizedFloatTextureSize(this.dimensions,this.bitRatio),this.uploadArrayLength=this.textureSize[0]*this.textureSize[1]*this.bitRatio,this.checkSize(this.textureSize[0],this.textureSize[1]),this.uploadValue=new Float32Array(this.uploadArrayLength),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),Be=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueSingleArray1DI:r}=oe();t.exports={WebGL2KernelValueSingleArray1DI:class extends r{updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;s.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Ke=e((e,t)=>{const{utils:s}=i(),{WebGL2KernelValueSingleArray1DI:r}=Be();t.exports={WebGL2KernelValueDynamicSingleArray1DI:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),We=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueSingleArray2DI:r}=le();t.exports={WebGL2KernelValueSingleArray2DI:class extends r{updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;s.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),je=e((e,t)=>{const{utils:s}=i(),{WebGL2KernelValueSingleArray2DI:r}=We();t.exports={WebGL2KernelValueDynamicSingleArray2DI:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),qe=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueSingleArray3DI:r}=ce();t.exports={WebGL2KernelValueSingleArray3DI:class extends r{updateValue(e){if(e.constructor!==this.initialValueConstructor)return void this.onUpdateValueMismatch(e.constructor);const{context:t}=this;s.flattenTo(e,this.uploadValue),t.activeTexture(this.contextHandle),t.bindTexture(t.TEXTURE_2D,this.texture),t.pixelStorei(t.UNPACK_FLIP_Y_WEBGL,!1),t.texImage2D(t.TEXTURE_2D,0,t.RGBA32F,this.textureSize[0],this.textureSize[1],0,t.RGBA,t.FLOAT,this.uploadValue),this.kernel.setUniform1i(this.id,this.index)}}}}),Xe=e((e,t)=>{const{utils:s}=i(),{WebGL2KernelValueSingleArray3DI:r}=qe();t.exports={WebGL2KernelValueDynamicSingleArray3DI:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}updateValue(e){this.setShape(e),this.kernel.setUniform3iv(this.dimensionsId,this.dimensions),this.kernel.setUniform2iv(this.sizeId,this.textureSize),super.updateValue(e)}}}}),He=e((e,t)=>{const{WebGLKernelValueArray2:s}=de();t.exports={WebGL2KernelValueArray2:class extends s{}}}),Ye=e((e,t)=>{const{WebGLKernelValueArray3:s}=fe();t.exports={WebGL2KernelValueArray3:class extends s{}}}),Ze=e((e,t)=>{const{WebGLKernelValueArray4:s}=me();t.exports={WebGL2KernelValueArray4:class extends s{}}}),Je=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueUnsignedArray:r}=ge();t.exports={WebGL2KernelValueUnsignedArray:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2D ${this.id}`,`${e} ivec2 ${this.sizeId} = ivec2(${this.textureSize[0]}, ${this.textureSize[1]})`,`${e} ivec3 ${this.dimensionsId} = ivec3(${this.dimensions[0]}, ${this.dimensions[1]}, ${this.dimensions[2]})`])}}}}),Qe=e((e,t)=>{const{utils:s}=i(),{WebGLKernelValueDynamicUnsignedArray:r}=xe();t.exports={WebGL2KernelValueDynamicUnsignedArray:class extends r{getSource(){const e=this.getVariablePrecisionString();return s.linesToString([`uniform ${e} sampler2D ${this.id}`,`uniform ${e} ivec2 ${this.sizeId}`,`uniform ${e} ivec3 ${this.dimensionsId}`])}}}}),et=e((e,t)=>{const{WebGL2KernelValueBoolean:s}=we(),{WebGL2KernelValueFloat:r}=Ee(),{WebGL2KernelValueInteger:n}=_e(),{WebGL2KernelValueHTMLImage:i}=Ie(),{WebGL2KernelValueDynamicHTMLImage:a}=ke(),{WebGL2KernelValueHTMLImageArray:o}=Ce(),{WebGL2KernelValueDynamicHTMLImageArray:u}=Le(),{WebGL2KernelValueHTMLVideo:l}=De(),{WebGL2KernelValueDynamicHTMLVideo:h}=Fe(),{WebGL2KernelValueSingleInput:c}=$e(),{WebGL2KernelValueDynamicSingleInput:p}=Ne(),{WebGL2KernelValueUnsignedInput:d}=Re(),{WebGL2KernelValueDynamicUnsignedInput:f}=Me(),{WebGL2KernelValueMemoryOptimizedNumberTexture:m}=Ge(),{WebGL2KernelValueDynamicMemoryOptimizedNumberTexture:g}=Oe(),{WebGL2KernelValueNumberTexture:x}=Ve(),{WebGL2KernelValueDynamicNumberTexture:y}=Pe(),{WebGL2KernelValueSingleArray:b}=ze(),{WebGL2KernelValueDynamicSingleArray:v}=Ue(),{WebGL2KernelValueSingleArray1DI:S}=Be(),{WebGL2KernelValueDynamicSingleArray1DI:T}=Ke(),{WebGL2KernelValueSingleArray2DI:A}=We(),{WebGL2KernelValueDynamicSingleArray2DI:w}=je(),{WebGL2KernelValueSingleArray3DI:E}=qe(),{WebGL2KernelValueDynamicSingleArray3DI:_}=Xe(),{WebGL2KernelValueArray2:I}=He(),{WebGL2KernelValueArray3:k}=Ye(),{WebGL2KernelValueArray4:C}=Ze(),{WebGL2KernelValueUnsignedArray:L}=Je(),{WebGL2KernelValueDynamicUnsignedArray:D}=Qe(),F={unsigned:{dynamic:{Boolean:s,Integer:n,Float:r,Array:D,"Array(2)":I,"Array(3)":k,"Array(4)":C,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:f,NumberTexture:y,"ArrayTexture(1)":y,"ArrayTexture(2)":y,"ArrayTexture(3)":y,"ArrayTexture(4)":y,MemoryOptimizedNumberTexture:g,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:u,HTMLVideo:h},static:{Boolean:s,Float:r,Integer:n,Array:L,"Array(2)":I,"Array(3)":k,"Array(4)":C,"Array1D(2)":!1,"Array1D(3)":!1,"Array1D(4)":!1,"Array2D(2)":!1,"Array2D(3)":!1,"Array2D(4)":!1,"Array3D(2)":!1,"Array3D(3)":!1,"Array3D(4)":!1,Input:d,NumberTexture:x,"ArrayTexture(1)":x,"ArrayTexture(2)":x,"ArrayTexture(3)":x,"ArrayTexture(4)":x,MemoryOptimizedNumberTexture:g,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:o,HTMLVideo:l}},single:{dynamic:{Boolean:s,Integer:n,Float:r,Array:v,"Array(2)":I,"Array(3)":k,"Array(4)":C,"Array1D(2)":T,"Array1D(3)":T,"Array1D(4)":T,"Array2D(2)":w,"Array2D(3)":w,"Array2D(4)":w,"Array3D(2)":_,"Array3D(3)":_,"Array3D(4)":_,Input:p,NumberTexture:y,"ArrayTexture(1)":y,"ArrayTexture(2)":y,"ArrayTexture(3)":y,"ArrayTexture(4)":y,MemoryOptimizedNumberTexture:g,HTMLCanvas:a,OffscreenCanvas:a,HTMLImage:a,ImageBitmap:a,ImageData:a,HTMLImageArray:u,HTMLVideo:h},static:{Boolean:s,Float:r,Integer:n,Array:b,"Array(2)":I,"Array(3)":k,"Array(4)":C,"Array1D(2)":S,"Array1D(3)":S,"Array1D(4)":S,"Array2D(2)":A,"Array2D(3)":A,"Array2D(4)":A,"Array3D(2)":E,"Array3D(3)":E,"Array3D(4)":E,Input:c,NumberTexture:x,"ArrayTexture(1)":x,"ArrayTexture(2)":x,"ArrayTexture(3)":x,"ArrayTexture(4)":x,MemoryOptimizedNumberTexture:m,HTMLCanvas:i,OffscreenCanvas:i,HTMLImage:i,ImageBitmap:i,ImageData:i,HTMLImageArray:o,HTMLVideo:l}}};t.exports={kernelValueMaps:F,lookupKernelValueType:function(e,t,s,r){if(!e)throw new Error("type missing");if(!t)throw new Error("dynamic missing");if(!s)throw new Error("precision missing");r.type&&(e=r.type);const n=F[s][t];if("WebGPUBuffer"===e)throw new Error("this kernel runs on WebGL but received a WebGPU pipeline buffer; await handle.toArray() first, or give this kernel the async contract (asyncMode: true / mode: 'async') so the readback happens for you");if(!1===n[e])return null;if(void 0===n[e])throw new Error(`Could not find a KernelValue for ${e}`);return n[e]}}}),tt=e((e,t)=>{const{WebGLKernel:s}=be(),{WebGL2FunctionNode:r}=Se(),{FunctionBuilder:n}=o(),{utils:a}=i(),{fragmentShader:u}=Te(),{vertexShader:l}=Ae(),{lookupKernelValueType:h}=et();let c=null,p=null,d=null,f=null;t.exports={WebGL2Kernel:class extends s{static get isSupported(){return null!==c||(this.setupFeatureChecks(),c=this.isContextMatch(d)),c}static setupFeatureChecks(){"undefined"!=typeof document?p=document.createElement("canvas"):"undefined"!=typeof OffscreenCanvas&&(p=new OffscreenCanvas(0,0)),p&&(d=p.getContext("webgl2"),d&&d.getExtension&&(d.getExtension("EXT_color_buffer_float"),d.getExtension("OES_texture_float_linear"),f=this.getFeatures()))}static isContextMatch(e){return"undefined"!=typeof WebGL2RenderingContext&&e instanceof WebGL2RenderingContext}static getFeatures(){const e=this.testContext;return Object.freeze({isFloatRead:this.getIsFloatRead(),isIntegerDivisionAccurate:this.getIsIntegerDivisionAccurate(),isSpeedTacticSupported:this.getIsSpeedTacticSupported(),kernelMap:!0,isTextureFloat:!0,isDrawBuffers:!0,channelCount:this.getChannelCount(),maxTextureSize:this.getMaxTextureSize(),lowIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_INT),lowFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.LOW_FLOAT),mediumIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_INT),mediumFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.MEDIUM_FLOAT),highIntPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_INT),highFloatPrecision:e.getShaderPrecisionFormat(e.FRAGMENT_SHADER,e.HIGH_FLOAT)})}static getIsTextureFloat(){return!0}static getChannelCount(){return d.getParameter(d.MAX_DRAW_BUFFERS)}static getMaxTextureSize(){return d.getParameter(d.MAX_TEXTURE_SIZE)}static lookupKernelValueType(e,t,s,r){return h(e,t,s,r)}static get testCanvas(){return p}static get testContext(){return d}static get features(){return f}static get fragmentShader(){return u}static get vertexShader(){return l}initContext(){return this.canvas.getContext("webgl2",{alpha:!1,depth:!1,antialias:!1})}initExtensions(){this.extensions={EXT_color_buffer_float:this.context.getExtension("EXT_color_buffer_float"),OES_texture_float_linear:this.context.getExtension("OES_texture_float_linear")}}validateSettings(e){if(!this.validate)return void(this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output));const{features:t}=this.constructor;if("single"===this.precision&&!t.isFloatRead)throw new Error("Float texture outputs are not supported");if(this.graphical||null!==this.precision||(this.precision=t.isFloatRead?"single":"unsigned"),null===this.fixIntegerDivisionAccuracy?this.fixIntegerDivisionAccuracy=!t.isIntegerDivisionAccurate:this.fixIntegerDivisionAccuracy&&t.isIntegerDivisionAccurate&&(this.fixIntegerDivisionAccuracy=!1),this.checkOutput(),!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=a.getVariableType(e[0],this.strictIntegers);switch(t){case"Array":this.output=a.getDimensions(t);break;case"NumberTexture":case"MemoryOptimizedNumberTexture":case"ArrayTexture(1)":case"ArrayTexture(2)":case"ArrayTexture(3)":case"ArrayTexture(4)":this.output=e[0].output;break;default:throw new Error("Auto output not supported for input type: "+t)}}if(this.graphical){if(2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");return"single"===this.precision&&(console.warn("Cannot use graphical mode and single precision at the same time"),this.precision="unsigned"),void(this.texSize=a.clone(this.output))}!this.graphical&&null===this.precision&&t.isTextureFloat&&(this.precision="single"),this.texSize=a.getKernelTextureSize({optimizeFloatMemory:this.optimizeFloatMemory,precision:this.precision},this.output),this.checkTextureSize()}translateSource(){const e=n.fromKernel(this,r,{fixIntegerDivisionAccuracy:this.fixIntegerDivisionAccuracy});this.translatedSource=e.getPrototypeString("kernel"),this.setupReturnTypes(e)}drawBuffers(){this.context.drawBuffers(this.drawBuffersMap)}getTextureFormat(){const{context:e}=this;switch(this.getInternalFormat()){case e.R32F:return e.RED;case e.RG32F:return e.RG;case e.RGBA32F:case e.RGBA:return e.RGBA;default:throw new Error("Unknown internal format")}}renderValues(){return void 0===this._tightRead&&this._detectTightRead(),super.renderValues()}renderKernelsToArrays(){return void 0===this._tightRead&&this._detectTightRead(),super.renderKernelsToArrays()}readFloatPixelsToFloat32Array(){if(!this._tightRead)return super.readFloatPixelsToFloat32Array();const{texSize:e,context:t}=this,s=e[0],r=e[1],n=new Float32Array(s*r);return t.readPixels(0,0,s,r,t.RED,t.FLOAT,n),n}renderOutputAsync(){return this.renderOutput!==this.renderValues?Promise.resolve(this.renderOutput()):this.renderValuesAsync()}renderValuesAsync(){void 0===this._tightRead&&this._detectTightRead();const e=this.formatValues,[t,s,r]=this.output;return this.transferValuesAsync().then(n=>e(n,t,s,r))}transferValuesAsync(){const{texSize:e,context:t}=this,s=e[0],r=e[1];let n,i,a;"single"===this.precision?(n=this._tightRead?t.RED:t.RGBA,i=t.FLOAT,a=new Float32Array(s*r*(this._tightRead?1:4))):(n=t.RGBA,i=t.UNSIGNED_BYTE,a=new Uint8Array(s*r*4));const o=t.createBuffer();t.bindBuffer(t.PIXEL_PACK_BUFFER,o),t.bufferData(t.PIXEL_PACK_BUFFER,a.byteLength,t.STREAM_READ),t.readPixels(0,0,s,r,n,i,0),t.bindBuffer(t.PIXEL_PACK_BUFFER,null);const u=t.fenceSync(t.SYNC_GPU_COMMANDS_COMPLETE,0);return t.flush(),this._pollFence(u).then(()=>(t.bindBuffer(t.PIXEL_PACK_BUFFER,o),t.getBufferSubData(t.PIXEL_PACK_BUFFER,0,a),t.bindBuffer(t.PIXEL_PACK_BUFFER,null),t.deleteBuffer(o),"single"===this.precision?a:new Float32Array(a.buffer)),e=>{throw t.deleteBuffer(o),e})}_pollFence(e){const t=this.context;return new Promise((s,r)=>{let n,i=null;"undefined"!=typeof MessageChannel?(i=new MessageChannel,i.port1.onmessage=()=>o(),n=()=>i.port2.postMessage(0)):n=()=>setTimeout(o,0);const a=(s,r)=>{t.deleteSync(e),i&&(i.port1.close(),i.port2.close()),s(r)},o=()=>{if(t.isContextLost())return a(r,new Error("WebGL context lost while awaiting kernel result"));const i=t.clientWaitSync(e,0,0);return i===t.ALREADY_SIGNALED||i===t.CONDITION_SATISFIED?a(s):i===t.WAIT_FAILED?a(r,new Error("clientWaitSync failed while awaiting kernel result")):void n()};o()})}_detectTightRead(){const e=this.context;this._tightRead=!1,e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer);const t="Number"===this.returnType||"Float"===this.returnType||"Integer"===this.returnType||"LiteralInteger"===this.returnType;if("single"===this.precision&&!this.optimizeFloatMemory&&!this.graphical&&t&&e.getParameter(e.IMPLEMENTATION_COLOR_READ_FORMAT)===e.RED&&e.getParameter(e.IMPLEMENTATION_COLOR_READ_TYPE)===e.FLOAT){if(this.formatValues===a.erectFloat)this.formatValues=a.erectMemoryOptimizedFloat;else if(this.formatValues===a.erect2DFloat)this.formatValues=a.erectMemoryOptimized2DFloat;else if(this.formatValues===a.erect3DFloat)this.formatValues=a.erectMemoryOptimized3DFloat;else if(this.formatValues!==a.erectMemoryOptimizedFloat&&this.formatValues!==a.erectMemoryOptimized2DFloat&&this.formatValues!==a.erectMemoryOptimized3DFloat)return;this._tightRead=!0}}getInternalFormat(){const{context:e}=this;if("single"===this.precision)switch(this.returnType){case"Number":case"Float":case"Integer":return this.optimizeFloatMemory?e.RGBA32F:e.R32F;case"Array(2)":return e.RG32F;case"Array(3)":case"Array(4)":return e.RGBA32F;default:throw new Error("Unhandled return type")}return e.RGBA}_setupOutputTexture(){const e=this.context;if(this.texture)return e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.texture.texture,0),void(this._tightRead=void 0);e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer);const t=e.createTexture(),s=this.texSize;e.activeTexture(e.TEXTURE0+this.constantTextureCount+this.argumentTextureCount),e.bindTexture(e.TEXTURE_2D,t),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.REPEAT),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.REPEAT),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,e.NEAREST);const r=this.getInternalFormat();"single"===this.precision?e.texStorage2D(e.TEXTURE_2D,1,r,s[0],s[1]):e.texImage2D(e.TEXTURE_2D,0,r,s[0],s[1],0,r,e.UNSIGNED_BYTE,null),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,t,0),this.texture=new this.TextureConstructor({texture:t,size:s,dimensions:this.threadDim,output:this.output,context:this.context,internalFormat:this.getInternalFormat(),textureFormat:this.getTextureFormat(),kernel:this}),this._tightRead=void 0}_setupSubOutputTextures(){const e=this.context;if(this.mappedTextures){for(let t=0;t{const{utils:s}=i(),{FunctionNode:r}=l();const n={Number:"f32",Float:"f32",Integer:"i32",LiteralInteger:"f32",Boolean:"bool","Array(2)":"vec2","Array(3)":"vec3","Array(4)":"vec4"},a={"===":"==","!==":"!="},o=["x","y","z","w"],u={pow:"_pow",round:"_round"},h={ceil:!0,floor:!0,_round:!0};t.exports={WGSLFunctionNode:class extends r{get requiresSequenceFreeForInit(){return!0}wgslFloat(e){if(e===1/0)return"0x1.fffffep+127";if(e===-1/0)return"-0x1.fffffep+127";if(e>34028234663852886e22)return"0x1.fffffep+127";if(e<-34028234663852886e22)return"-0x1.fffffep+127";const t=`${e}`;return-1!==t.indexOf(".")||-1!==t.indexOf("e")||-1!==t.indexOf("E")?t:`${t}.0`}wgslInt(e){return`${Math.round(e)}`}mangleFunctionName(e){return`fn_${s.sanitizeName(e)}`}getLookupType(e){return"WebGPUBuffer"===e?"Number":super.getLookupType(e)}astUpdateExpression(e,t){return this.astGeneric(e.argument,t),t.push(e.operator),t}getType(e){if(e&&"ConditionalExpression"===e.type){const t=this.getType(e.consequent);if("Integer"===t||"LiteralInteger"===t){const t=this.getType(e.alternate);if("Number"===t||"Float"===t)return"Number"}}return super.getType(e)}astConditionalExpression(e,t){if("ConditionalExpression"!==e.type)throw this.astErrorOutput("Not a conditional expression",e);const s=this.getType(e.consequent),r=this.getType(e.alternate);if(null===s&&null===r)return t.push("if ("),this.astGeneric(e.test,t),t.push(") {"),this.astGeneric(e.consequent,t),t.push(";"),t.push("} else {"),this.astGeneric(e.alternate,t),t.push(";"),t.push("}"),t;let n="LiteralInteger"===s?"Number":s;"Integer"!==n||"Number"!==r&&"Float"!==r||(n="Number");const i=e=>{const s=this.getType(e);switch(n){case"Number":case"Float":"Integer"===s?this.castValueToFloat(e,t):"LiteralInteger"===s?this.castLiteralToFloat(e,t):this.astGeneric(e,t);break;case"Integer":"Number"===s||"Float"===s?this.castValueToInteger(e,t):"LiteralInteger"===s?this.castLiteralToInteger(e,t):this.astGeneric(e,t);break;default:this.astGeneric(e,t)}};return t.push("select("),i(e.alternate),t.push(", "),i(e.consequent),t.push(", "),this.astGeneric(e.test,t),t.push(")"),t}astFunction(e,t){if(this.isRootKernel){for(let s=0;s0&&t.push(", ");let a=this.argumentTypes[this.argumentNames.indexOf(i)];if(!a)throw this.astErrorOutput(`Unknown argument ${i} type`,e);"LiteralInteger"===a&&(this.argumentTypes[r]=a="Number");const o=n[a];if(!o)throw this.astErrorOutput(`WebGPU backend does not yet support ${a} arguments to helper functions`,e);t.push(`user_${s.sanitizeName(i)} : ${o}`)}t.push(")"),i&&t.push(` -> ${i}`),t.push(" {\n");for(let s=0;s>":!0,">>>":!0}[e.operator])return null;const s=e=>{switch(this.getType(e)){case"Number":case"Float":this.castValueToInteger(e,t);break;case"LiteralInteger":this.castLiteralToInteger(e,t);break;default:this.pushState("building-integer"),this.astGeneric(e,t),this.popState("building-integer")}};return t.push("("),">>>"===e.operator?(t.push("bitcast(bitcast("),s(e.left),t.push(") >> u32("),s(e.right),t.push("))")):"<<"===e.operator||">>"===e.operator?(s(e.left),t.push(` ${e.operator} u32(`),s(e.right),t.push(")")):(s(e.left),t.push(` ${e.operator} `),s(e.right)),t.push(")"),t}checkAndUpconvertBitwiseUnary(e,t){if("~"!==e.operator)return null;switch(t.push("~("),this.getType(e.argument)){case"Number":case"Float":this.castValueToInteger(e.argument,t);break;case"LiteralInteger":this.castLiteralToInteger(e.argument,t);break;default:this.astGeneric(e.argument,t)}return t.push(")"),t}astUnaryExpression(e,t){return this.checkAndUpconvertBitwiseUnary(e,t)?t:"+"===e.operator?(this.astGeneric(e.argument,t),t):(e.prefix?(t.push(e.operator),this.astGeneric(e.argument,t)):(this.astGeneric(e.argument,t),t.push(e.operator)),t)}castLiteralToInteger(e,t){return this.pushState("casting-to-integer"),this.astGeneric(e,t),this.popState("casting-to-integer"),t}castLiteralToFloat(e,t){return this.pushState("casting-to-float"),this.astGeneric(e,t),this.popState("casting-to-float"),t}castValueToInteger(e,t){return this.pushState("casting-to-integer"),t.push("i32("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-integer"),t}castValueToFloat(e,t){return this.pushState("casting-to-float"),t.push("f32("),this.astGeneric(e,t),t.push(")"),this.popState("casting-to-float"),t}astIdentifierExpression(e,t){if("Identifier"!==e.type)throw this.astErrorOutput("IdentifierExpression - not an Identifier",e);const r=this.getType(e),n=s.sanitizeName(e.name);return"Infinity"===e.name?(t.push("0x1.fffffep+127"),t):!this.isRootKernel||-1===this.argumentNames.indexOf(e.name)||"Number"!==r&&"Float"!==r&&"Integer"!==r&&"Boolean"!==r?(t.push(`user_${n}`),t):("Boolean"===r?t.push(`bool(params.user_${n})`):t.push(`params.user_${n}`),t)}astForStatement(e,t){if("ForStatement"!==e.type)throw this.astErrorOutput("Invalid for statement",e);const s=[],r=[],n=[],i=[];let a=null;if(e.init){const{declarations:t}=e.init;t.length>1&&(a=!1),this.astGeneric(e.init,s);for(let e=0;e0&&t.push(s.join(""),"\n"),t.push(`for (var ${e} : i32 = 0;${e}0&&t.push(`if (!(${r.join("")})) { break; }\n`),t.push(i.join("")),t.push(`\n${n.join("")};`),t.push("}\n")}return t}astWhileStatement(e,t){if("WhileStatement"!==e.type)throw this.astErrorOutput("Invalid while statement",e);const s=this.getInternalVariableName("safeI");return t.push(`for (var ${s} : i32 = 0;${s}{if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(t);if("BreakStatement"===e.type)return!0;if("ForStatement"===e.type||"WhileStatement"===e.type||"DoWhileStatement"===e.type||"SwitchStatement"===e.type)return!1;for(const s in e)if("loc"!==s&&"range"!==s&&"parent"!==s&&t(e[s]))return!0;return!1};if(t(s[e]))throw this.astErrorOutput("break inside a switch case is only supported as the case terminator",s[e])}for(let e=0;ee+1){u=!0,this.astSwitchCaseConsequent(r[e].consequent,o);continue}t.push(" else {\n")}this.astSwitchCaseConsequent(r[e].consequent,t),t.push("\n}")}return u&&(t.push(" else {"),t.push(o.join("")),t.push("}")),t.push("\n"),t}astThisExpression(e,t){return t.push("this"),t}astSequenceExpression(e,t){const{expressions:s}=e;if(1===s.length)return this.astGeneric(s[0],t),t;throw this.astErrorOutput("WebGPU backend does not yet support the comma operator",e)}astMemberExpression(e,t){const{property:r,name:i,signature:a,origin:o,type:u,xProperty:l,yProperty:h,zProperty:c}=this.getMemberExpressionDetails(e);switch(a){case"value.thread.value":case"this.thread.value":if("x"!==i&&"y"!==i&&"z"!==i)throw this.astErrorOutput("Unexpected expression, expected `this.thread.x`, `this.thread.y`, or `this.thread.z`",e);return t.push(`i32(threadGid.${i})`),t;case"this.output.value":{const s={x:0,y:1,z:2}[i];if(void 0===s)throw this.astErrorOutput("Unexpected expression",e);if(this.dynamicOutput){const e=`params.output${i.toUpperCase()}`;this.isState("casting-to-float")?t.push(`f32(${e})`):t.push(`i32(${e})`)}else this.isState("casting-to-integer")?t.push(`${this.output[s]}`):t.push(`${this.output[s]}.0`);return t}case"value":throw this.astErrorOutput("Unexpected expression",e);case"value[]":case"value[][]":case"value[][][]":case"value[][][][]":case"value.value":if("Math"===o)return t.push(this.wgslFloat(Math[i])),t;switch(r){case"r":return t.push(`user_${s.sanitizeName(i)}.x`),t;case"g":return t.push(`user_${s.sanitizeName(i)}.y`),t;case"b":return t.push(`user_${s.sanitizeName(i)}.z`),t;case"a":return t.push(`user_${s.sanitizeName(i)}.w`),t}break;case"this.constants.value":{const s=this.constants[i];switch(u){case"Integer":return this.isState("casting-to-float")?t.push(this.wgslFloat(s)):t.push(this.wgslInt(s)),t;case"Number":case"Float":return this.isState("casting-to-integer")?t.push(this.wgslInt(s)):t.push(this.wgslFloat(s)),t;case"Boolean":return t.push(s?"true":"false"),t;case"Array(2)":case"Array(3)":case"Array(4)":{const e=parseInt(u.substring(6),10),r=[];for(let t=0;t4)throw this.astErrorOutput("this.color takes (r, g, b) or (r, g, b, a)",e);t.push("kernelColor(data_index");for(let s=0;s0&&t.push(", "),n){case"Integer":this.castValueToFloat(r,t);break;case"LiteralInteger":this.castLiteralToFloat(r,t);break;default:this.astGeneric(r,t)}}else{const n=this.lookupFunctionArgumentTypes(r)||[];for(let i=0;i0&&t.push(", ");const u=this.getType(a);switch(o||(this.triggerImplyArgumentType(r,i,u,this),o=u),u){case"Boolean":this.astGeneric(a,t);continue;case"Number":case"Float":if("Integer"===o){t.push("i32("),this.astGeneric(a,t),t.push(")");continue}if("Number"===o||"Float"===o){this.astGeneric(a,t);continue}if("LiteralInteger"===o){this.castLiteralToFloat(a,t);continue}break;case"Integer":if("Number"===o||"Float"===o){t.push("f32("),this.astGeneric(a,t),t.push(")");continue}if("Integer"===o){this.astGeneric(a,t);continue}break;case"LiteralInteger":if("Integer"===o){this.castLiteralToInteger(a,t);continue}if("Number"===o||"Float"===o){this.castLiteralToFloat(a,t);continue}if("LiteralInteger"===o){this.astGeneric(a,t);continue}break;case"Array(2)":case"Array(3)":case"Array(4)":if(o===u){"Identifier"===a.type?t.push(`user_${s.sanitizeName(a.name)}`):this.astGeneric(a,t);continue}break;case"Array":case"Array2D":case"Array3D":case"Input":case"WebGPUBuffer":throw this.astErrorOutput("WebGPU backend does not yet support array arguments to helper functions",e)}throw this.astErrorOutput(`Unhandled argument combination of ${u} and ${o} for argument named "${a.name}"`,e)}}return t.push(")"),a&&t.push(")"),t}astArrayExpression(e,t){switch(this.getType(e)){case"Matrix(2)":case"Matrix(3)":case"Matrix(4)":throw this.astErrorOutput("WebGPU backend does not yet support Matrix types",e)}const s=e.elements.length;t.push(`vec${s}(`);for(let r=0;r0&&t.push(", ");const s=e.elements[r];switch(this.getType(s)){case"Integer":this.castValueToFloat(s,t);break;case"LiteralInteger":this.castLiteralToFloat(s,t);break;default:this.astGeneric(s,t)}}return t.push(")"),t}memberExpressionXYZ(e,t,s,r){return s?r.push(this.memberExpressionPropertyMarkup(s),", "):r.push("0, "),t?r.push(this.memberExpressionPropertyMarkup(t),", "):r.push("0, "),r.push(this.memberExpressionPropertyMarkup(e)),r}memberExpressionPropertyMarkup(e){if(!e)throw new Error("Property not set");const t=[];switch(this.getType(e)){case"Number":case"Float":this.castValueToInteger(e,t);break;case"LiteralInteger":this.castLiteralToInteger(e,t);break;case"Integer":this.pushState("building-integer"),t.push("i32("),this.astGeneric(e,t),t.push(")"),this.popState("building-integer");break;default:this.astGeneric(e,t)}return t.join("")}}}}),rt=e((e,t)=>{let s=null;t.exports={WebGPUContext:class e{static get isSupported(){return"undefined"!=typeof navigator&&!!navigator.gpu}static acquire(){if(s)return s;const t=(async()=>{if(!e.isSupported)throw new Error("WebGPU is not supported on this platform (navigator.gpu is missing)");const r=await navigator.gpu.requestAdapter();if(!r)throw new Error("WebGPU is present (navigator.gpu) but no adapter is available. On headless Chromium there is no adapter; run headed. Use `await GPU.isWebGPUAvailable()` to feature-detect.");const n=await r.requestDevice({requiredLimits:{maxStorageBufferBindingSize:r.limits.maxStorageBufferBindingSize,maxBufferSize:r.limits.maxBufferSize}}),i={adapter:r,device:n,isLost:!1};return n.lost.then(e=>{i.isLost=!0,"destroyed"!==e.reason&&console.error(`gpu.js [webgpu]: device lost: ${e.message}`),s===t&&(s=null)}),n.onuncapturederror=e=>{console.error(`gpu.js [webgpu]: ${e.error.message}`)},i})();return t.catch(()=>{s===t&&(s=null)}),s=t}static destroy(){if(!s)return Promise.resolve();const e=s;return s=null,e.then(({device:e})=>{e.destroy()},()=>{})}}}}),nt=e((e,t)=>{t.exports={WebGPUBufferResult:class e{constructor(e){this.buffer=e.buffer,this.output=e.output,this.componentCount=e.componentCount||1,this.context=e.context,this.kernel=e.kernel,this.type="WebGPUBuffer",this._deleted=!1,this.buffer._refs?this.buffer._refs++:this.buffer._refs=1}toArray(){return this._deleted?Promise.reject(new Error("WebGPUBufferResult has been deleted")):this.kernel.readBufferResult(this)}delete(){this._deleted||(this._deleted=!0,0===--this.buffer._refs&&this.buffer.destroy())}clone(){return new e(this)}}}}),it=e((e,t)=>{const{Kernel:s}=a(),{FunctionBuilder:n}=o(),{WGSLFunctionNode:u}=st(),{WebGPUContext:l}=rt(),{WebGPUBufferResult:h}=nt(),{utils:c}=i(),{Input:p}=r(),d=Object.freeze({kernelMap:!1,isIntegerDivisionAccurate:!0,isSpeedTacticSupported:!1,isTextureFloat:!0,isDrawBuffers:!1,kernelMapSize:0,channelCount:1,maxTextureSize:1/0,isFloatRead:!0}),f={_pow:"fn _pow(v1 : f32, v2 : f32) -> f32 {\n if (v2 == 0.0) { return 1.0; }\n return pow(v1, v2);\n}",_round:"fn _round(x : f32) -> f32 {\n return floor(x + 0.5);\n}",cbrt:"fn cbrt(x : f32) -> f32 {\n return sign(x) * pow(abs(x), 1.0 / 3.0);\n}",expm1:"fn expm1(x : f32) -> f32 {\n return exp(x) - 1.0;\n}",fround:"fn fround(x : f32) -> f32 {\n return x;\n}",imul:"fn imul(a : f32, b : f32) -> f32 {\n return f32(i32(a) * i32(b));\n}",log10:`fn log10(x : f32) -> f32 {\n return log2(x) * ${1/Math.log2(10)};\n}`,log1p:"fn log1p(x : f32) -> f32 {\n return log(1.0 + x);\n}",clz32:"fn clz32(x : f32) -> f32 {\n return f32(countLeadingZeros(u32(x)));\n}"};t.exports={WebGPUKernel:class extends s{static get isSupported(){return l.isSupported}static get isAsync(){return!0}static isContextMatch(e){return Boolean(e&&"function"==typeof e.createShaderModule&&"function"==typeof e.createComputePipeline)}static getFeatures(){return d}static get features(){return d}static get mode(){return"webgpu"}static getSignature(e,t){return"webgpu"+(t.length>0?":"+t.join(","):"")}static destroyContext(e){}static nativeFunctionArguments(){throw new Error("WebGPU backend does not yet support native functions")}static nativeFunctionReturnType(){throw new Error("WebGPU backend does not yet support native functions")}static combineKernels(){throw new Error("WebGPU backend does not yet support combineKernels; chain kernels with `await` and pipeline mode instead")}constructor(e,t){if(super(e,t),t){if("unsigned"===t.precision&&!t.graphical)throw new Error("WebGPU backend does not yet support precision: 'unsigned'; it is single precision only");if(t.subKernels)throw new Error("WebGPU backend does not yet support createKernelMap")}this.mergeSettings(e.settings||t),(null===this.precision||this.graphical)&&(this.precision="single"),this.asyncMode=!0,this.threadDim=null,this.componentCount=1,this.compiledSource=null,this.translatedBody=null,this.translatedFunctions=null,this.paramsLayout=null,this._buildPromise=null,this._device=null,this.computePipeline=null,this.bindGroupLayout=null,this.bindGroup=null,this.bindGroupDirty=!0,this.paramsBuffer=null,this.paramsMirror=null,this.outputBuffer=null,this.argumentBuffers=null,this.constantBuffers=null,this.stagingPool=[],this._canvasContext=null,this._blitPipeline=null,this._blitParamsBuffer=null,this._blitBindGroup=null,this._blitBoundOutputBuffer=null}initCanvas(){return this.graphical&&"undefined"!=typeof document?document.createElement("canvas"):null}initContext(){return null}initPlugins(e){return[]}setOutput(e){const t=this.toKernelOutput(e);if(this.built){if(!this.dynamicOutput)throw new Error("Resizing a kernel with dynamicOutput: false is not possible");if(t.length!==this.output.length)throw new Error("WebGPU backend does not yet support changing the output rank of a built kernel; the workgroup shape is fixed at build")}return this.output=t,this}toString(){throw new Error("WebGPU backend does not yet support toString")}validateSettings(e){if(this.graphical){if(!this.output||2!==this.output.length)throw new Error("Output must have 2 dimensions on graphical mode");if(this.pipeline)throw new Error("graphical mode and pipeline mode are mutually exclusive");if(!this.canvas)throw new Error("graphical mode requires a canvas (none could be created; pass one in settings)")}if("unsigned"===this.precision)throw new Error("WebGPU backend does not yet support precision: 'unsigned'; it is single precision only");if(this.precision="single",this.subKernels&&this.subKernels.length>0)throw new Error("WebGPU backend does not yet support createKernelMap");if(!this.output||0===this.output.length){if(1!==e.length)throw new Error("Auto output only supported for kernels with only one input");const t=c.getVariableType(e[0],this.strictIntegers);if("Array"===t)this.output=Array.from(c.getDimensions(e[0]));else{if("WebGPUBuffer"!==t)throw new Error("Auto output not supported for input type: "+t);this.output=Array.from(e[0].output)}}this.checkOutput()}setupArguments(e){super.setupArguments(e);for(let e=0;e,`);for(let e=0;e params : Params;");for(let t=0;t user_${e[t].name} : array;`);const i=1+e.length;r.push(`@group(0) @binding(${i}) var result : array;`),this.graphical&&r.push("fn kernelColor(index : i32, r : f32, g : f32, b : f32, a : f32) {\n result[index * 4] = r;\n result[index * 4 + 1] = g;\n result[index * 4 + 2] = b;\n result[index * 4 + 3] = a;\n}");for(let e=0;e constants_${s[e].name} : array;`);r.push("var threadGid : vec3;"),null!==this.paramsLayout.randomSeedOffset&&r.push("var pcgState : u32;\nfn pcg_random() -> f32 {\n pcgState = pcgState * 747796405u + 2891336453u;\n let word = ((pcgState >> ((pcgState >> 28u) + 4u)) ^ pcgState) * 277803737u;\n let mixed = (word >> 22u) ^ word;\n return f32(mixed >> 8u) / 16777216.0;\n}");const a=`${this.translatedFunctions}\n${this.translatedBody}`;/\bLOOP_MAX\b/.test(a)&&r.push(`const LOOP_MAX : i32 = ${parseInt(this.loopMaxIterations,10)||1e3};`);for(const e in f)new RegExp(`\\b${e}\\(`).test(a)&&r.push(f[e]);for(let t=0;t f32 {\n return user_${s}[u32(x + i32(params.user_${s}_dims.x) * (y + i32(params.user_${s}_dims.y) * z))];\n}`)}for(let e=0;e f32 {\n return constants_${t.name}[u32(x + ${i[0]} * (y + ${i[1]} * z))];\n}`)}this.translatedFunctions&&r.push(this.translatedFunctions);const o=1===this.output.length?[64,1,1]:[8,8,1];return this.workgroupSize=o,1===this.output.length?r.push(`@compute @workgroup_size(${o[0]}, ${o[1]}, ${o[2]})\nfn main(@builtin(global_invocation_id) gid : vec3) {\n let flat_index : u32 = gid.x + gid.y * params.dispatchWidth;\n threadGid = vec3(flat_index, 0u, 0u);\n if (flat_index >= params.outputX) { return; }\n let data_index : i32 = i32(flat_index);\n${null!==this.paramsLayout.randomSeedOffset?" pcgState = (params.randomSeed + u32(data_index) * 2654435769u) * 747796405u + 2891336453u;\n":""}${this.translatedBody}\n}`):r.push(`@compute @workgroup_size(${o[0]}, ${o[1]}, ${o[2]})\nfn main(@builtin(global_invocation_id) gid : vec3) {\n threadGid = gid;\n if (gid.x >= params.outputX || gid.y >= params.outputY || gid.z >= params.outputZ) { return; }\n let data_index : i32 = i32(gid.x + params.outputX * (gid.y + params.outputY * gid.z));\n${null!==this.paramsLayout.randomSeedOffset?" pcgState = (params.randomSeed + u32(data_index) * 2654435769u) * 747796405u + 2891336453u;\n":""}${this.translatedBody}\n}`),r.join("\n")}constantDimensions(e){const t=e instanceof p?Array.from(e.size):Array.from(c.getDimensions(e));for(;t.length<3;)t.push(1);return t}async _buildAsync(){const e=await l.acquire();this.context=e;const t=this._device=e.device,s=t.createShaderModule({code:this.compiledSource}),r=(await s.getCompilationInfo()).messages.filter(e=>"error"===e.type);if(r.length>0)throw new Error("Error compiling WGSL compute shader:\n"+r.map(e=>` ${e.lineNum}:${e.linePos} ${e.message}`).join("\n")+`\n--- generated WGSL ---\n${this.compiledSource}`);const{arrayArgs:n,bufferConstants:i,byteLength:a}=this.paramsLayout,o=[{binding:0,visibility:4,buffer:{type:"uniform"}}];for(let e=0;ei&&(n[1]=Math.ceil(n[0]/i),n[0]=Math.ceil(n[0]/n[1])),a=n[0]*t);for(let e=0;e<3;e++)if(n[e]>i)throw new Error(`output dimension ${e} needs ${n[e]} workgroups, over this device's limit of ${i}`);return{groups:n,dispatchWidth:a}}async _buildBlitPipeline(e){if(this.canvas.width=this.output[0],this.canvas.height=this.output[1],this._canvasContext=this.canvas.getContext("webgpu"),!this._canvasContext)throw new Error("could not get a webgpu context from the canvas");const t=navigator.gpu.getPreferredCanvasFormat();this._canvasContext.configure({device:e,format:t,alphaMode:"premultiplied"});const s=e.createShaderModule({code:"struct BlitParams { width : u32, height : u32, pad0 : u32, pad1 : u32 }\n@group(0) @binding(0) var blit : BlitParams;\n@group(0) @binding(1) var pixels : array;\n@vertex fn vs(@builtin(vertex_index) vi : u32) -> @builtin(position) vec4 {\n var pos = array, 3>(vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));\n return vec4(pos[vi], 0.0, 1.0);\n}\n@fragment fn fs(@builtin(position) pos : vec4) -> @location(0) vec4 {\n let x = u32(pos.x);\n let y = u32(pos.y);\n let row = blit.height - 1u - y;\n let i = (row * blit.width + x) * 4u;\n let a = pixels[i + 3u];\n return vec4(pixels[i] * a, pixels[i + 1u] * a, pixels[i + 2u] * a, a);\n}"}),r=(await s.getCompilationInfo()).messages.filter(e=>"error"===e.type);if(r.length>0)throw new Error("Error compiling the graphical blit shader:\n"+r.map(e=>` ${e.lineNum}:${e.linePos} ${e.message}`).join("\n"));this._blitBindGroupLayout=e.createBindGroupLayout({entries:[{binding:0,visibility:2,buffer:{type:"uniform"}},{binding:1,visibility:2,buffer:{type:"read-only-storage"}}]}),this._blitPipeline=e.createRenderPipeline({layout:e.createPipelineLayout({bindGroupLayouts:[this._blitBindGroupLayout]}),vertex:{module:s,entryPoint:"vs"},fragment:{module:s,entryPoint:"fs",targets:[{format:t}]},primitive:{topology:"triangle-list"}}),this._blitParamsBuffer=e.createBuffer({size:16,usage:72})}_ensureOutputBuffer(){const[e,t,s]=this.threadDim,r=e*t*s*4*this.componentCount;this.immutable&&this.pipeline&&this.outputBuffer&&(0===--this.outputBuffer._refs&&this.outputBuffer.destroy(),this.outputBuffer=null,this.bindGroupDirty=!0),this.outputBuffer&&this.outputBuffer.size>=r||(this.outputBuffer&&0===--this.outputBuffer._refs&&this.outputBuffer.destroy(),this._checkBufferSize(r,`output [${this.output.join(", ")}]`),this.outputBuffer=this._device.createBuffer({size:r,usage:132}),this.outputBuffer._refs=1,this.bindGroupDirty=!0)}_checkBufferSize(e,t){const s=this._device.limits,r=Math.min(s.maxStorageBufferBindingSize,s.maxBufferSize);if(e>r)throw new Error(`WebGPU backend: ${t} needs ${e} bytes but this device allows ${r} per storage buffer (maxStorageBufferBindingSize/maxBufferSize); reduce the output or split the work across kernels`)}_snapshotArguments(e){const t=new Array(e.length);for(let s=0;sthis._runInternal(e))}_runInternal(e){if(this.context&&this.context.isLost)throw new Error("WebGPU device was lost; call kernel.destroy() (or gpu.destroy()) and run again to rebuild on a fresh device");const t=this._device,s=t.queue,{arrayArgs:r,scalarArgs:n,bufferConstants:i}=this.paramsLayout,a=this.threadDim=Array.from(this.output);for(;a.length<3;)a.push(1);if(this._ensureOutputBuffer(),null!==this.paramsLayout.randomSeedOffset){const e=null!==this.randomSeed?this.randomSeed>>>0:4294967296*Math.random()>>>0;this.paramsU32[this.paramsLayout.randomSeedOffset/4]=e}this.paramsU32[0]=a[0],this.paramsU32[1]=a[1],this.paramsU32[2]=a[2],this.paramsU32[3]=this._computeDispatch(a).dispatchWidth;for(let n=0;n{const e=new Float32Array(p.buffer.getMappedRange(0,u).slice(0));return p.buffer.unmap(),this._releaseStaging(p),this._shapeOutput(e,d,this.componentCount)},e=>{throw this._releaseStaging(p),e})}_acquireStaging(e){for(let t=0;t=e)return s.busy=!0,s}const t={buffer:this._device.createBuffer({size:e,usage:9}),size:e,busy:!0,pooled:this.stagingPool.length<3};return t.pooled&&this.stagingPool.push(t),t}_releaseStaging(e){e.pooled?e.busy=!1:e.buffer.destroy()}_shapeOutput(e,t,s){const[r,n,i]=[t[0],t[1]||1,t[2]||1];if(1===s)switch(t.length){case 1:return c.erectMemoryOptimizedFloat(e,r);case 2:return c.erectMemoryOptimized2DFloat(e,r,n);default:return c.erectMemoryOptimized3DFloat(e,r,n,i)}const a=s,o=t=>{const s=new Array(r);for(let n=0;n{const t=new Float32Array(i.buffer.getMappedRange(0,n).slice(0));return i.buffer.unmap(),this._releaseStaging(i),this._shapeOutput(t,s,e.componentCount)},e=>{throw this._releaseStaging(i),e})}getPixels(e){if(!this.graphical)return Promise.reject(new Error("getPixels only works on a graphical kernel"));if(!this.outputBuffer)return Promise.reject(new Error("run the kernel before reading its pixels"));const[t,s]=this.output,r=t*s*4*4,n=this._acquireStaging(r),i=this._device.createCommandEncoder();return i.copyBufferToBuffer(this.outputBuffer,0,n.buffer,0,r),this._device.queue.submit([i.finish()]),n.buffer.mapAsync(1,0,r).then(()=>{const i=new Float32Array(n.buffer.getMappedRange(0,r).slice(0));n.buffer.unmap(),this._releaseStaging(n);const a=new Uint8ClampedArray(t*s*4);for(let r=0;r{throw this._releaseStaging(n),e})}destroy(e){if(this._blitParamsBuffer&&(this._blitParamsBuffer.destroy(),this._blitParamsBuffer=null),this._canvasContext&&(this._canvasContext.unconfigure(),this._canvasContext=null),this._blitPipeline=null,this._blitBindGroup=null,this._blitBoundOutputBuffer=null,this.paramsBuffer&&(this.paramsBuffer.destroy(),this.paramsBuffer=null),this.paramsLayout)for(let e=0;e{const s={i32:127,i64:126,f32:125,f64:124,v128:123},r=new DataView(new ArrayBuffer(16));function n(e,t){let s=e>>>0;do{let e=127&s;s>>>=7,0!==s&&(e|=128),t.push(e)}while(0!==s)}function i(e,t){let s=0|e;for(;;){const e=127&s;if(s>>=7,0===s&&!(64&e)||-1===s&&64&e)return void t.push(e);t.push(128|e)}}function a(e,t,s){let r=e>>>0;for(let e=0;e<4;e++)t[s+e]=127&r|128,r>>>=7;t[s+4]=127&r}function o(e,t){const s=[];for(let t=0;t65535&&t++,r<128?s.push(r):r<2048?s.push(192|r>>6,128|63&r):r<65536?s.push(224|r>>12,128|r>>6&63,128|63&r):s.push(240|r>>18,128|r>>12&63,128|r>>6&63,128|63&r)}n(s.length,t);for(let e=0;e3)throw new Error(`WasmModuleBuilder: lane index ${t} out of range for 4-lane shape`);return this.bytes.push(253,e,t),this}_push(e){for(let t=0;t${t.join(",")}`;if(s in this.typeIndexByKey)return this.typeIndexByKey[s];const r=this.types.length;return this.types.push({params:e,results:t}),this.typeIndexByKey[s]=r,r}addMemoryImport(e,t,s=!1){if(s&&null==t)throw new Error("WasmModuleBuilder: shared memory import requires a maximum");return this.memoryImport={initial:e,maximum:t,shared:s},this}addFuncImport(e,t,s,r="env"){if(e in this.funcImportIndexByName||e in this.functionIndexByName)throw new Error(`WasmModuleBuilder: duplicate function name "${e}"`);const n=this.funcImports.length;return this.funcImports.push({name:e,module:r,typeIndex:this._typeIndex(t,s)}),this.funcImportIndexByName[e]=n,n}addGlobal(e,t,s){return u(e),this.globals.push({type:e,mutable:t,initialValue:s}),this.globals.length-1}addFunction(e,{params:t=[],results:s=[],locals:r=[]}={}){if(e in this.funcImportIndexByName||e in this.functionIndexByName)throw new Error(`WasmModuleBuilder: duplicate function name "${e}"`);t.forEach(u),s.forEach(u),r.forEach(u);const n=new h(this,e,t,s,r);return this.functionIndexByName[e]=this.functions.length,this.functions.push({name:e,emitter:n,typeIndex:this._typeIndex(t,s)}),n}exportFunction(e,t=e){return this.exports.push({name:e,exportName:t}),this}_resolveFuncIndex(e){if(e in this.funcImportIndexByName)return this.funcImportIndexByName[e];if(e in this.functionIndexByName)return this.funcImports.length+this.functionIndexByName[e];throw new Error(`WasmModuleBuilder: call target "${e}" is not an import or a defined function`)}_section(e,t,s){s.push(e),n(t.length,s);for(let e=0;e0){const t=[];n(this.types.length,t);for(const{params:e,results:s}of this.types){t.push(96),n(e.length,t);for(const s of e)t.push(u(s));n(s.length,t);for(const e of s)t.push(u(e))}this._section(1,t,e)}if(null!==this.memoryImport||this.funcImports.length>0){const t=[];if(n((null!==this.memoryImport?1:0)+this.funcImports.length,t),null!==this.memoryImport){const{initial:e,maximum:s,shared:r}=this.memoryImport;o("env",t),o("memory",t),t.push(2);const i=null!=s;t.push(r?3:i?1:0),n(e,t),i&&n(s,t)}for(const{name:e,module:s,typeIndex:r}of this.funcImports)o(s,t),o(e,t),t.push(0),n(r,t);this._section(2,t,e)}if(this.functions.length>0){const t=[];n(this.functions.length,t);for(const{typeIndex:e}of this.functions)n(e,t);this._section(3,t,e)}if(this.globals.length>0){const t=[];n(this.globals.length,t);for(const{type:e,mutable:s,initialValue:n}of this.globals){if(t.push(u(e),s?1:0),"i32"===e)t.push(65),i(n,t);else if("f32"===e){t.push(67),r.setFloat32(0,n,!0);for(let e=0;e<4;e++)t.push(r.getUint8(e))}else{if("v128"!==e)throw new Error(`WasmModuleBuilder: no initializer encoding for global type "${e}"`);t.push(253,12);for(let e=0;e<16;e++)t.push(0)}t.push(11)}this._section(6,t,e)}if(this.exports.length>0){const t=[];n(this.exports.length,t);for(const{name:e,exportName:s}of this.exports)o(s,t),t.push(0),n(this._resolveFuncIndex(e),t);this._section(7,t,e)}if(this.functions.length>0){const t=[];n(this.functions.length,t);for(const{emitter:e}of this.functions){const s=e.bytes.slice();for(const{at:t,name:r}of e.callFixups)a(this._resolveFuncIndex(r),s,t);const r=[],i=[];for(const t of e.locals){const e=u(t);i.length>0&&i[i.length-1].type===e?i[i.length-1].count++:i.push({type:e,count:1})}n(i.length,r);for(const{type:e,count:t}of i)n(t,r),r.push(e);for(let e=0;e{const{utils:s}=i(),{FunctionNode:r}=l(),{WasmFunctionEmitter:n}=at();var a=class{constructor(){this.localCount=0}addLocal(){return this.localCount++}};for(const e of Object.getOwnPropertyNames(n.prototype))"constructor"!==e&&"addLocal"!==e&&"function"==typeof n.prototype[e]&&(a.prototype[e]=function(){return this});const o={sin:1,cos:1,tan:1,asin:1,acos:1,atan:1,atan2:2,sinh:1,cosh:1,tanh:1,asinh:1,acosh:1,atanh:1,exp:1,expm1:1,log:1,log2:1,log10:1,log1p:1,cbrt:1,pow:2,sign:1},u={abs:"f32Abs",floor:"f32Floor",ceil:"f32Ceil",sqrt:"f32Sqrt",trunc:"f32Trunc"},h={"+":"f32Add","-":"f32Sub","*":"f32Mul"},c={"+":"i32Add","-":"i32Sub","*":"i32Mul"},p={"==":"f32Eq","===":"f32Eq","!=":"f32Ne","!==":"f32Ne","<":"f32Lt",">":"f32Gt","<=":"f32Le",">=":"f32Ge"},d={"==":"i32Eq","===":"i32Eq","!=":"i32Ne","!==":"i32Ne","<":"i32LtS",">":"i32GtS","<=":"i32LeS",">=":"i32GeS"},f={"&":"i32And","|":"i32Or","^":"i32Xor","<<":"i32Shl",">>":"i32ShrS",">>>":"i32ShrU"},m={"+":"f32x4Add","-":"f32x4Sub","*":"f32x4Mul"},g={"+":"i32x4Add","-":"i32x4Sub","*":"i32x4Mul"},x={"==":"f32x4Eq","===":"f32x4Eq","!=":"f32x4Ne","!==":"f32x4Ne","<":"f32x4Lt",">":"f32x4Gt","<=":"f32x4Le",">=":"f32x4Ge"},y={"==":"i32x4Eq","===":"i32x4Eq","!=":"i32x4Ne","!==":"i32x4Ne","<":"i32x4LtS",">":"i32x4GtS","<=":"i32x4LeS",">=":"i32x4GeS"},b={"<<":"i32x4Shl",">>":"i32x4ShrS",">>>":"i32x4ShrU"},v={abs:"f32x4Abs",floor:"f32x4Floor",ceil:"f32x4Ceil",sqrt:"f32x4Sqrt",trunc:"f32x4Trunc"};function S(e){switch(e){case"Number":case"Float":case"LiteralInteger":return"f32";case"Integer":case"Boolean":return"i32";default:throw new Error(`WebAssembly backend does not yet support ${e} arguments to helper functions`)}}t.exports={WebAssemblyFunctionNode:class extends r{constructor(e,t){super(e,t),this.assembler=null,this.em=null,this.locals=null,this.depth=0,this.loopStack=null,this.usedMathImports=new Set,this.usesRandom=!1,this.readsThread=!1,this.taintedLocals=null,this.uniformity=[],this._analysisDone=!1,this._analysisPass=!1,this.vec=!1,this.vMaskDepth=0,this.vCur=-1,this.vRetMask=-1,this.vTerminated=!1,this.vInfo=null,this._vBaseX=-1}mangleFunctionName(e){return`fn_${s.sanitizeName(e)}`}getType(e){if(e&&"ConditionalExpression"===e.type){const t=this.getType(e.consequent);if("Integer"===t||"LiteralInteger"===t){const t=this.getType(e.alternate);if("Number"===t||"Float"===t)return"Number"}}return super.getType(e)}toString(){return this._analysisDone||(this._analysisDone=!0,this._analysisPass=!0,this.walkFunction(new a),this._analysisPass=!1),""}emitFunction(e){this.assembler=e;const{module:t}=e;let s;if(this.isRootKernel)s=t.addFunction("kernel",{params:[],results:[]});else{const e=this.argumentTypes.map(e=>S("LiteralInteger"===e?"Number":e)),r=[];if(this.returnType)switch(this.returnType){case"Integer":case"Boolean":r.push("i32");break;case"Number":case"Float":case"LiteralInteger":r.push("f32");break;default:throw new Error(`WebAssembly backend does not yet support helper functions returning ${this.returnType}`)}s=t.addFunction(this.mangleFunctionName(this.name),{params:e,results:r})}return this.walkFunction(s),!this.isRootKernel&&this.returnType&&s.unreachable(),s}walkFunction(e){this.em=e,this.locals=new Map,this.depth=0,this.loopStack=[],this.taintedLocals=new Set;const t=this.getJsAST();if(this.isRootKernel)for(const s of this.collectAssignedArgumentNames(t)){const t=this.argumentNames.indexOf(s),r=this.argumentTypes[t];if("Number"!==r&&"Float"!==r&&"Integer"!==r&&"Boolean"!==r)continue;const n=this.assembler?this.assembler.layout.scalars[s]:null,i=n?n.offset:0,a="Integer"===r||"Boolean"===r?"i32":"f32",o=e.addLocal(a);e.i32Const(0),"i32"===a?e.i32Load(i):e.f32Load(i),e.localSet(o),this.locals.set(s,{kind:"scalar",index:o,wtype:a,gtype:r})}if(!this.isRootKernel){for(let e=0;e{if(r&&"object"==typeof r){if(Array.isArray(r))return r.forEach(s);if("FunctionDeclaration"!==r.type||r===e){"AssignmentExpression"===r.type&&"Identifier"===r.left.type&&-1!==this.argumentNames.indexOf(r.left.name)&&t.add(r.left.name),"UpdateExpression"===r.type&&"Identifier"===r.argument.type&&-1!==this.argumentNames.indexOf(r.argument.name)&&t.add(r.argument.name);for(const e in r){if("loc"===e||"start"===e||"end"===e||"parent"===e)continue;const t=r[e];t&&"object"==typeof t&&s(t)}}}};return s(e.body),t}enterBlock(e){this.em.block(e),this.depth++}enterLoop(e){this.em.loop(e),this.depth++}enterIf(e){this.em.if_(e),this.depth++}exit(){this.em.end(),this.depth--}brTo(e){this.em.br(this.depth-e)}brIfTo(e){this.em.brIf(this.depth-e)}get loopMax(){return parseInt(this.loopMaxIterations,10)||1e3}coerce(e,t){if(e===t)return t;if("void"===e)throw new Error("cannot use a void expression as a value");switch(t){case"f32":return this.em.f32ConvertI32S(),"f32";case"i32":return"f32"===e&&this.em.i32TruncSatF32S(),"i32";case"bool":return"f32"===e?this.em.f32Const(0).f32Ne():this.em.i32Eqz().i32Eqz(),"bool";default:throw new Error(`unknown wasm value category ${t}`)}}castLiteralToInteger(e){this.pushState("casting-to-integer");const t=this.expression(e);return this.popState("casting-to-integer"),this.coerce(t,"i32"),"i32"}castLiteralToFloat(e){this.pushState("casting-to-float");const t=this.expression(e);return this.popState("casting-to-float"),this.coerce(t,"f32"),"f32"}castValueToInteger(e){this.pushState("casting-to-integer");const t=this.expression(e);return this.popState("casting-to-integer"),this.coerce(t,"i32"),"i32"}castValueToFloat(e){this.pushState("casting-to-float");const t=this.expression(e);return this.popState("casting-to-float"),this.coerce(t,"f32"),"f32"}emitByType(e,t){const s=this.getType(e);return"f32"===t?"Integer"===s?this.castValueToFloat(e):"LiteralInteger"===s?this.castLiteralToFloat(e):(this.coerce(this.expression(e),"f32"),"f32"):"Number"===s||"Float"===s?this.castValueToInteger(e):"LiteralInteger"===s?this.castLiteralToInteger(e):(this.coerce(this.expression(e),"i32"),"i32")}emitCondition(e){const t=this.expression(e);if("bool"!==t)if("i32"!==t){if("f32"!==t)throw this.astErrorOutput("cannot use a void expression as a condition",e);this.em.f32Const(0).f32Ne()}else this.em.i32Eqz().i32Eqz()}statement(e){switch(e.type){case"VariableDeclaration":return this.stmtVariableDeclaration(e);case"ExpressionStatement":return this.statementExpression(e.expression);case"ReturnStatement":return this.stmtReturn(e);case"IfStatement":return this.stmtIf(e);case"ForStatement":return this.stmtFor(e);case"WhileStatement":return this.stmtWhile(e);case"DoWhileStatement":return this.stmtDoWhile(e);case"BlockStatement":for(let t=0;tthis.castValueToFloat(n));else switch(i.valueType=u,u){case"Number":case"Float":this.setScalarLocal(o,"f32",u,()=>{"LiteralInteger"===a?this.castLiteralToFloat(n):"Integer"===a?this.castValueToFloat(n):this.coerce(this.expression(n),"f32")});break;case"Integer":this.setScalarLocal(o,"i32","Integer",()=>{"LiteralInteger"===a?this.castLiteralToInteger(n):"Number"===a||"Float"===a?this.castValueToInteger(n):this.coerce(this.expression(n),"i32")});break;case"Boolean":this.setScalarLocal(o,"i32","Boolean",()=>this.emitCondition(n));break;default:throw this.astErrorOutput(`WebAssembly backend does not yet support declaring type ${u}`,e)}this.isThreadDependent(n)&&this.taintedLocals.add(o)}}setScalarLocal(e,t,s,r){let n=this.locals.get(e);n&&"scalar"===n.kind&&n.wtype===t?n.gtype=s:(n={kind:"scalar",index:this.em.addLocal(t),wtype:t,gtype:s},this.locals.set(e,n)),r(),this.em.localSet(n.index)}declareVecLocal(e,t,s,r,n){const i=parseInt(t.substring(6),10);r.valueType=t;let a=this.locals.get(e);if(!a||"vec"!==a.kind||a.n!==i){const s=[];for(let e=0;ethis.em.localSet(s.index);else{if(s||!this.isRootKernel||-1===this.argumentNames.indexOf(t))throw this.astErrorOutput(`cannot assign to "${t}"`,e);{const s=this.argumentTypes[this.argumentNames.indexOf(t)],i=this.assembler?this.assembler.layout.scalars[t]:null;if(this.assembler&&!i)throw this.astErrorOutput(`WebAssembly backend does not yet support assigning to the array argument "${t}"`,e);const a=i?i.offset:0;r="Integer"===s||"Boolean"===s?"i32":"f32",this.em.i32Const(0),n=()=>"i32"===r?this.em.i32Store(a):this.em.f32Store(a)}}if("="===e.operator){const t=this.getType(e.left),s=this.getType(e.right);"Integer"!==t&&"Integer"===s?(this.castValueToFloat(e.right),this.coerce("f32",r)):"Integer"!==t&&"LiteralInteger"===s?(this.castLiteralToFloat(e.right),this.coerce("f32",r)):"Integer"===t&&"LiteralInteger"===s?(this.castLiteralToInteger(e.right),this.coerce("i32",r)):"Integer"!==t||"Number"!==s&&"Float"!==s?this.coerce(this.expression(e.right),r):(this.castValueToInteger(e.right),this.coerce("i32",r))}else{const t={type:"BinaryExpression",operator:e.operator.slice(0,-1),left:e.left,right:e.right};this.coerce(this.exprBinary(t),r)}n(),(this.isThreadDependent(e.right)||"="!==e.operator&&this.taintedLocals.has(t))&&this.taintedLocals.add(t)}emitUpdate(e,t){if("Identifier"!==e.argument.type)throw this.astErrorOutput("update expression needs a variable",e);const s=this.locals.get(e.argument.name);if(!s||"scalar"!==s.kind)throw this.astErrorOutput(`cannot update "${e.argument.name}"`,e);const r="i32"===s.wtype,n=()=>r?this.em.i32Const(1):this.em.f32Const(1),i="++"===e.operator?r?"i32Add":"f32Add":r?"i32Sub":"f32Sub";return t?(this.em.localGet(s.index),n(),this.em[i]().localSet(s.index),"void"):(e.prefix?(this.em.localGet(s.index),n(),this.em[i]().localTee(s.index)):(this.em.localGet(s.index).localGet(s.index),n(),this.em[i]().localSet(s.index)),s.wtype)}stmtReturn(e){if(!e.argument){if(this.isRootKernel)return void this.em.return_();throw this.astErrorOutput("Unexpected return statement",e)}this.pushState("skip-literal-correction");const t=this.getType(e.argument);if(this.popState("skip-literal-correction"),this.returnType||(this.returnType="LiteralInteger"===t||"Integer"===t?"Number":t),this.isRootKernel)return this.stmtRootReturn(e,t);if(this.isSubKernel)throw this.astErrorOutput("WebAssembly backend does not yet support createKernelMap",e);switch(this.returnType){case"LiteralInteger":case"Number":case"Float":"Integer"===t?this.castValueToFloat(e.argument):"LiteralInteger"===t?this.castLiteralToFloat(e.argument):this.coerce(this.expression(e.argument),"f32");break;case"Integer":"Float"===t||"Number"===t?this.castValueToInteger(e.argument):"LiteralInteger"===t?this.castLiteralToInteger(e.argument):this.coerce(this.expression(e.argument),"i32");break;case"Boolean":this.emitCondition(e.argument);break;default:throw this.astErrorOutput(`unhandled return type ${this.returnType}`,e)}this.em.return_()}stmtRootReturn(e,t){const s=this.assembler?this.assembler.globals:{dataIndex:0},r=this.assembler?this.assembler.layout.outputOffset:0;switch(this.returnType){case"Array(2)":case"Array(3)":case"Array(4)":{const t=parseInt(this.returnType.substring(6),10),n=e.argument;if("ArrayExpression"===n.type){if(n.elements.length!==t)throw this.astErrorOutput(`expected ${t} array elements to match return type ${this.returnType}`,e);for(let e=0;e1&&(t=!1);for(let e=0;e{if(e===a.length)return o&&this.emitSwitchConsequent(o),!1;const{tests:t,consequent:s}=a[e];for(let e=0;e0&&this.em.i32Or();return this.enterIf(),this.emitSwitchConsequent(s),(e+10&&(s.push({tests:r,consequent:e[n].consequent}),r=[])):t=e[n].consequent;return{groups:s,defaultConsequent:t}}collectSwitchCaseStatements(e){const t=[];for(let s=0;s{if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(s);if("BreakStatement"===e.type)return!0;if("ForStatement"===e.type||"WhileStatement"===e.type||"DoWhileStatement"===e.type||"SwitchStatement"===e.type)return!1;for(const t in e)if("loc"!==t&&"range"!==t&&"parent"!==t&&s(e[t]))return!0;return!1};for(let e=0;e{const s=this.getType(t);switch(r){case"Number":case"Float":"Integer"===s?this.castValueToFloat(t):"LiteralInteger"===s?this.castLiteralToFloat(t):this.coerce(this.expression(t),"f32");break;case"Integer":"Number"===s||"Float"===s?this.castValueToInteger(t):"LiteralInteger"===s?this.castLiteralToInteger(t):this.coerce(this.expression(t),"i32");break;case"Boolean":this.emitCondition(t);break;default:throw this.astErrorOutput(`WebAssembly backend does not yet support a ternary of type ${r}`,e)}};return this.emitCondition(e.test),this.enterIf(n),i(e.consequent),this.em.else_(),i(e.alternate),this.exit(),"Boolean"===r?"bool":n}exprCall(e){if(!e.callee)throw this.astErrorOutput("Unknown CallExpression",e);if("MemberExpression"===e.callee.type&&"this.color"===this.getVariableSignature(e.callee,!0))throw this.astErrorOutput("WebAssembly backend does not yet support graphical mode (this.color)",e);let t=null;const s=this.isAstMathFunction(e);if(t=s||e.callee.object&&"ThisExpression"===e.callee.object.type?e.callee.property.name:"SequenceExpression"!==e.callee.type||"Literal"!==e.callee.expressions[0].type||isNaN(e.callee.expressions[0].raw)?e.callee.name:e.callee.expressions[1].property.name,!t)throw this.astErrorOutput("Unhandled function, couldn't find name",e);if(this.calledFunctions.indexOf(t)<0&&this.calledFunctions.push(t),this.onFunctionCall&&this.onFunctionCall(this.name,t,e.arguments),s)return this.emitMathCall(t,e);const r=this.getType(e),n=this.lookupFunctionArgumentTypes(t)||[];for(let s=0;s{switch(this.getType(e)){case"Integer":this.castValueToFloat(e);break;case"LiteralInteger":this.castLiteralToFloat(e);break;default:this.coerce(this.expression(e),"f32")}},r=u[e];if(r)return s(t.arguments[0]),this.em[r](),"f32";switch(e){case"round":return s(t.arguments[0]),this.em.f32Const(.5).f32Add().f32Floor(),"f32";case"fround":return s(t.arguments[0]),"f32";case"min":case"max":{const r="min"===e?"f32Min":"f32Max";s(t.arguments[0]);for(let e=1;e0&&this.emitClampScalarIndex(a.dims[0]*a.dims[1]*a.dims[2]-1),this.em.i32Const(2).i32Shl(),this.em.f32Load(a.offset),"f32"}emitClampScalarIndex(e){const t=this.em.addLocal("i32");this.em.localSet(t),this.em.localGet(t).i32Const(0).localGet(t).i32Const(0).i32GeS().select(),this.em.localSet(t),this.em.localGet(t).i32Const(e).localGet(t).i32Const(e).i32LeS().select()}emitVecIndex(e,t){if("Literal"===t.type&&Number.isInteger(t.value)){if(t.value<0||t.value>=e.n)throw this.astErrorOutput(`index ${t.value} out of range for Array(${e.n})`,t);return this.em.localGet(e.indices[t.value]),"f32"}const s=this.em.addLocal("i32");this.emitIndex(t),this.em.localSet(s),this.em.localGet(e.indices[0]);for(let t=1;t{if(!e||"object"!=typeof e)return!1;switch(e.type){case"Literal":case"ThisExpression":return!1;case"Identifier":return t.has(e.name);case"MemberExpression":return e.computed||"MemberExpression"!==e.object.type||e.object.computed||!e.object.property||"thread"!==e.object.property.name?e.computed?a(e.object)||a(e.property):a(e.object):"x"===e.property.name;case"BinaryExpression":case"LogicalExpression":return a(e.left)||a(e.right);case"UnaryExpression":case"UpdateExpression":return a(e.argument);case"ConditionalExpression":return a(e.test)||a(e.consequent)||a(e.alternate);case"CallExpression":return!i.isAstMathFunction(e)||("random"===e.callee.property.name||e.arguments.some(a));case"SequenceExpression":return e.expressions.some(a);case"ArrayExpression":return e.elements.some(a);case"AssignmentExpression":return a(e.right)||"Identifier"===e.left.type&&t.has(e.left.name);default:return!0}},o=e=>{e&&!t.has(e)&&(t.add(e),n=!0)},u=(e,t)=>{if(e&&"object"==typeof e){if(Array.isArray(e))return e.forEach(e=>u(e,t));switch(e.type){case"UpdateExpression":return"Identifier"===e.argument.type&&(-1!==i.argumentNames.indexOf(e.argument.name)&&(s.has(e.argument.name)||(s.add(e.argument.name),n=!0),o(e.argument.name)),t&&o(e.argument.name)),u(e.argument,t);case"AssignmentExpression":return"Identifier"===e.left.type&&(-1!==i.argumentNames.indexOf(e.left.name)&&(s.has(e.left.name)||(s.add(e.left.name),n=!0),o(e.left.name)),t&&o(e.left.name)),u(e.left,t),u(e.right,t);case"ConditionalExpression":{u(e.test,t);const s=t||a(e.test);return u(e.consequent,s),u(e.alternate,s)}case"LogicalExpression":return u(e.left,t),u(e.right,!0);default:for(const s in e){if("loc"===s||"start"===s||"end"===s||"parent"===s)continue;const r=e[s];r&&"object"==typeof r&&u(r,t)}}}},l=(e,t)=>{if(e&&"object"==typeof e){if(Array.isArray(e))return e.forEach(e=>l(e,t));switch(e.type){case"VariableDeclarator":e.id&&"Identifier"===e.id.type&&t.push(e.id.name);break;case"AssignmentExpression":"Identifier"===e.left.type&&t.push(e.left.name);break;case"UpdateExpression":"Identifier"===e.argument.type&&t.push(e.argument.name);break;case"FunctionDeclaration":return}for(const s in e){if("loc"===s||"start"===s||"end"===s||"parent"===s)continue;const r=e[s];r&&"object"==typeof r&&l(r,t)}}},h=(e,t)=>{if(!e||"object"!=typeof e)return!1;if(Array.isArray(e))return e.some(e=>h(e,t));switch(e.type){case"BreakStatement":case"ContinueStatement":return t;case"ForStatement":case"WhileStatement":case"DoWhileStatement":case"FunctionDeclaration":return!1;case"IfStatement":{const s=t||a(e.test);return!!h(e.consequent,s)||!!e.alternate&&h(e.alternate,s)}case"ConditionalExpression":{const s=t||a(e.test);return h(e.consequent,s)||h(e.alternate,s)}case"SwitchStatement":{const s=t||a(e.discriminant)||e.cases.some(e=>e.test&&a(e.test));return e.cases.some(e=>e.consequent.some(e=>"BreakStatement"!==e.type&&h(e,s)))}default:for(const s in e){if("loc"===s||"start"===s||"end"===s||"parent"===s)continue;const r=e[s];if(r&&"object"==typeof r&&h(r,t))return!0}return!1}},c=(e,r)=>{switch(e.type){case"AssignmentExpression":if("Identifier"===e.left.type){const u=e.left.name;-1!==i.argumentNames.indexOf(u)&&(s.has(u)||(s.add(u),n=!0),o(u)),(r||a(e.right)||"="!==e.operator&&t.has(u))&&o(u)}return u(e.right,r);case"UpdateExpression":if("Identifier"===e.argument.type){const t=e.argument.name;-1!==i.argumentNames.indexOf(t)&&(s.has(t)||(s.add(t),n=!0),o(t)),r&&o(t)}return;case"SequenceExpression":return e.expressions.forEach(e=>c(e,r));default:return u(e,r)}},p=(e,t)=>{if(e)switch(e.type){case"VariableDeclaration":for(const s of e.declarations)s.init&&((t||a(s.init))&&o(s.id.name),u(s.init,t));return;case"ExpressionStatement":return c(e.expression,t);case"ReturnStatement":return t&&(r=!0),void(e.argument&&u(e.argument,t));case"IfStatement":{u(e.test,t);const s=t||a(e.test);return p(e.consequent,s),void(e.alternate&&p(e.alternate,s))}case"ForStatement":case"WhileStatement":case"DoWhileStatement":{const s=t||!!e.test&&a(e.test)||h(e.body,!1);if(s){const t=[];e.init&&l(e.init,t),l(e.body,t),e.update&&l(e.update,t),t.forEach(o)}return e.init&&("VariableDeclaration"===e.init.type?p(e.init,t):c(e.init,t)),p(e.body,s),e.update&&c(e.update,s),void(e.test&&u(e.test,s))}case"SwitchStatement":{const s=t||a(e.discriminant)||e.cases.some(e=>e.test&&a(e.test));for(const t of e.cases)for(const e of t.consequent)p(e,s);return}case"BlockStatement":return e.body.forEach(e=>p(e,t));default:return}};for(;n;)n=!1,p(e.body,!1);return{varying:t,varyingReturn:r,assignedArgs:s,exprVarying:a,hasVaryingExit:h}}vZero(){return this.em.v128ConstI32x4(0,0,0,0),this}vInnermostVaryingLoop(){const e=this.vLoopStack[this.vLoopStack.length-1];return e&&e.varying?e:null}vRecomputeCur(e){const t=this.em;t.localGet(e),-1!==this.vRetMask&&t.localGet(this.vRetMask).v128Andnot();const s=this.vInnermostVaryingLoop();s&&(-1!==s.vBrk&&t.localGet(s.vBrk).v128Andnot(),-1!==s.vCnt&&t.localGet(s.vCnt).v128Andnot()),t.localSet(this.vCur)}vLoopBodyExits(e){let t=!1,s=!1;const r=e=>{if(!(!e||"object"!=typeof e||t&&s)){if(Array.isArray(e))return e.forEach(r);switch(e.type){case"BreakStatement":return void(t=!0);case"ContinueStatement":return void(s=!0);case"ForStatement":case"WhileStatement":case"DoWhileStatement":case"FunctionDeclaration":return;case"SwitchStatement":for(const t of e.cases)for(const e of t.consequent)"BreakStatement"!==e.type&&r(e);return}for(const t in e){if("loc"===t||"start"===t||"end"===t||"parent"===t)continue;const s=e[t];s&&"object"==typeof s&&r(s)}}};return r(e),{hasBreak:t,hasContinue:s}}vSetLocal(e){const t=this.em;this.vMaskDepth>0&&t.localGet(e).localGet(this.vCur).v128Bitselect(),t.localSet(e)}vCoerce(e,t){if(e===t)return t;const s=this.em;switch(e){case"f32":case"i32":case"bool":if("vf32"===t)return this.coerce(e,"f32"),s.f32x4Splat(),t;if("vi32"===t)return this.coerce(e,"i32"),s.i32x4Splat(),t;if("vbool"===t)return this.coerce(e,"i32"),s.i32x4Splat(),this.vZero(),s.i32x4Ne(),t;break;case"vf32":if("vi32"===t)return s.i32x4TruncSatF32x4S(),t;if("vbool"===t)return s.v128ConstF32x4(0,0,0,0).f32x4Ne(),t;break;case"vi32":if("vf32"===t)return s.f32x4ConvertI32x4S(),t;if("vbool"===t)return this.vZero(),s.i32x4Ne(),t;break;case"vbool":if("vi32"===t)return s.v128ConstI32x4(1,1,1,1).v128And(),t;if("vf32"===t)return s.v128ConstI32x4(1,1,1,1).v128And().f32x4ConvertI32x4S(),t}throw new Error(`cannot convert ${e} to ${t}`)}vCastLiteralToInteger(e){this.pushState("casting-to-integer");const t=this.vexpr(e);return this.popState("casting-to-integer"),this.vCoerce(t,"vi32"),"vi32"}vCastLiteralToFloat(e){this.pushState("casting-to-float");const t=this.vexpr(e);return this.popState("casting-to-float"),this.vCoerce(t,"vf32"),"vf32"}vCastValueToInteger(e){this.pushState("casting-to-integer");const t=this.vexpr(e);return this.popState("casting-to-integer"),this.vCoerce(t,"vi32"),"vi32"}vCastValueToFloat(e){this.pushState("casting-to-float");const t=this.vexpr(e);return this.popState("casting-to-float"),this.vCoerce(t,"vf32"),"vf32"}vEmitByType(e,t){const s=this.getType(e);return"vf32"===t?"Integer"===s?this.vCastValueToFloat(e):"LiteralInteger"===s?this.vCastLiteralToFloat(e):(this.vCoerce(this.vexpr(e),"vf32"),"vf32"):"Number"===s||"Float"===s?this.vCastValueToInteger(e):"LiteralInteger"===s?this.vCastLiteralToInteger(e):(this.vCoerce(this.vexpr(e),"vi32"),"vi32")}vexprMask(e){const t=this.vexpr(e);if("vbool"!==t)return"vi32"===t?(this.vZero(),void this.em.i32x4Ne()):void("vf32"!==t?(this.coerce(t,"bool"),this.em.i32x4Splat(),this.vZero(),this.em.i32x4Ne()):this.em.v128ConstF32x4(0,0,0,0).f32x4Ne())}vstatement(e){switch(e.type){case"VariableDeclaration":return this.vstmtVariableDeclaration(e);case"ExpressionStatement":return this.vstatementExpression(e.expression);case"ReturnStatement":return this.vstmtReturn(e);case"IfStatement":return this.vstmtIf(e);case"ForStatement":return this.vstmtFor(e);case"WhileStatement":return this.vstmtWhile(e);case"DoWhileStatement":return this.vstmtDoWhile(e);case"BlockStatement":for(let t=0;tthis.vCastValueToFloat(r));switch(i.valueType=o,o){case"Number":case"Float":this.vSetVaryingScalar(n,"vf32",o,()=>{"LiteralInteger"===a?this.vCastLiteralToFloat(r):"Integer"===a?this.vCastValueToFloat(r):this.vCoerce(this.vexpr(r),"vf32")});break;case"Integer":this.vSetVaryingScalar(n,"vi32","Integer",()=>{"LiteralInteger"===a?this.vCastLiteralToInteger(r):"Number"===a||"Float"===a?this.vCastValueToInteger(r):this.vCoerce(this.vexpr(r),"vi32")});break;case"Boolean":this.vSetVaryingScalar(n,"vi32","Boolean",()=>{this.vexprMask(r),this.em.v128ConstI32x4(1,1,1,1).v128And()});break;default:throw this.astErrorOutput(`WebAssembly backend does not yet support declaring type ${o}`,t)}}vSetVaryingScalar(e,t,s,r){let n=this.locals.get(e);n&&"vscalar"===n.kind&&n.wtype===t?n.gtype=s:(n={kind:"vscalar",index:this.em.addLocal("v128"),wtype:t,gtype:s},this.locals.set(e,n)),r(),this.vSetLocal(n.index)}vEmitArrayElement(e){switch(this.getType(e)){case"Integer":this.vCastValueToFloat(e);break;case"LiteralInteger":this.vCastLiteralToFloat(e);break;default:this.vCoerce(this.vexpr(e),"vf32")}}vAssign(e){if("Identifier"!==e.left.type)throw this.astErrorOutput(`WebAssembly backend does not yet support assignment to ${e.left.type}`,e);const t=e.left.name,s=this.locals.get(t);if(s&&"scalar"===s.kind)return this.emitAssignment(e);if(!s||"vscalar"!==s.kind)throw this.astErrorOutput(`cannot assign to "${t}"`,e);const r=s.wtype;if("="===e.operator){const t=this.getType(e.left),s=this.getType(e.right);"Integer"!==t&&"Integer"===s?(this.vCastValueToFloat(e.right),this.vCoerce("vf32",r)):"Integer"!==t&&"LiteralInteger"===s?(this.vCastLiteralToFloat(e.right),this.vCoerce("vf32",r)):"Integer"===t&&"LiteralInteger"===s?(this.vCastLiteralToInteger(e.right),this.vCoerce("vi32",r)):"Integer"!==t||"Number"!==s&&"Float"!==s?this.vCoerce(this.vexpr(e.right),r):(this.vCastValueToInteger(e.right),this.vCoerce("vi32",r))}else{const t={type:"BinaryExpression",operator:e.operator.slice(0,-1),left:e.left,right:e.right};this.vCoerce(this.vexprBinary(t),r)}this.vSetLocal(s.index)}vUpdate(e,t){if("Identifier"!==e.argument.type)throw this.astErrorOutput("update expression needs a variable",e);const s=this.locals.get(e.argument.name);if(s&&"scalar"===s.kind)return this.emitUpdate(e,t);if(!s||"vscalar"!==s.kind)throw this.astErrorOutput(`cannot update "${e.argument.name}"`,e);const r=this.em,n="vi32"===s.wtype,i=()=>n?r.v128ConstI32x4(1,1,1,1):r.v128ConstF32x4(1,1,1,1),a="++"===e.operator?n?"i32x4Add":"f32x4Add":n?"i32x4Sub":"f32x4Sub";if(t)return r.localGet(s.index),i(),r[a](),this.vSetLocal(s.index),"void";if(e.prefix)r.localGet(s.index),i(),r[a](),this.vSetLocal(s.index),r.localGet(s.index);else{const e=r.addLocal("v128");r.localGet(s.index).localSet(e),r.localGet(s.index),i(),r[a](),this.vSetLocal(s.index),r.localGet(e)}return s.wtype}vstmtIf(e){const t=this.em;if(!this.vInfo.exprVarying(e.test))return this.emitCondition(e.test),this.enterIf(),this.vstatementBody(e.consequent),e.alternate&&(t.else_(),this.vstatementBody(e.alternate)),void this.exit();const s=t.addLocal("v128");this.vexprMask(e.test),t.localSet(s);const r=t.addLocal("v128");t.localGet(this.vCur).localSet(r),t.localGet(r).localGet(s).v128And().localSet(this.vCur),t.localGet(this.vCur).v128AnyTrue(),this.enterIf(),this.vMaskDepth++,this.vstatementBody(e.consequent),this.vMaskDepth--,this.exit(),e.alternate&&(t.localGet(r).localGet(s).v128Andnot().localSet(this.vCur),t.localGet(this.vCur).v128AnyTrue(),this.enterIf(),this.vMaskDepth++,this.vstatementBody(e.alternate),this.vMaskDepth--,this.exit()),this.vRecomputeCur(r)}vstmtReturn(e){const t=this.em;if(!e.argument)return void this.vRetireOrReturn();this.pushState("skip-literal-correction");const s=this.getType(e.argument);switch(this.popState("skip-literal-correction"),this.returnType){case"Array(2)":case"Array(3)":case"Array(4)":{const s=parseInt(this.returnType.substring(6),10),r=e.argument,n=[];if("ArrayExpression"===r.type){if(r.elements.length!==s)throw this.astErrorOutput(`expected ${s} array elements to match return type ${this.returnType}`,e);for(let e=0;e0?i=this.vCur:-1!==this.vRetMask&&(i=t.addLocal("v128"),t.localGet(this.vRetMask).v128Not().localSet(i));const a=t.addLocal("i32");if(1===n)return t.globalGet(s.dataIndex).i32Const(2).i32Shl().localSet(a),void(-1===i?t.localGet(a).localGet(e[0]).v128Store(r,2):(t.localGet(a),t.localGet(e[0]),t.localGet(a).v128Load(r,2),t.localGet(i).v128Bitselect(),t.v128Store(r,2)));t.globalGet(s.dataIndex).i32Const(n).i32Mul().i32Const(2).i32Shl().localSet(a);for(let s=0;s<4;s++)for(let o=0;oe.test&&this.vInfo.exprVarying(e.test)),i=this.getType(t);if(!n){let n,a;switch(i){case"Float":case"Number":a=!1,n=r.addLocal("f32"),this.coerce(this.expression(t),"f32"),r.localSet(n);break;case"Integer":a=!0,n=r.addLocal("i32"),this.coerce(this.expression(t),"i32"),r.localSet(n);break;default:throw this.astErrorOutput(`Unhandled switch discriminant type "${i}"`,e)}if(1===s.length&&!s[0].test)return void this.vEmitSwitchConsequent(s[0].consequent);const{groups:o,defaultConsequent:u}=this.collectSwitchGroups(s),l=e=>{if(e===o.length)return void(u&&this.vEmitSwitchConsequent(u));const{tests:t,consequent:s}=o[e];for(let e=0;e0&&r.i32Or();this.enterIf(),this.vEmitSwitchConsequent(s),(e+10&&r.v128Or();r.localSet(p),this.vRecomputeCur(h),r.localGet(this.vCur).localGet(p).v128And().localGet(c).v128Andnot().localSet(this.vCur),r.localGet(c).localGet(p).v128Or().localSet(c),r.localGet(this.vCur).v128AnyTrue(),this.enterIf(),this.vEmitSwitchConsequent(s),this.exit()}l&&(this.vRecomputeCur(h),r.localGet(this.vCur).localGet(c).v128Andnot().localSet(this.vCur),r.localGet(this.vCur).v128AnyTrue(),this.enterIf(),this.vEmitSwitchConsequent(l),this.exit()),this.vMaskDepth--,this.vRecomputeCur(h)}vEmitSwitchTest(e,t){const s=this.getType(e);t?"Number"===s||"Float"===s?this.vCastValueToInteger(e):"LiteralInteger"===s?this.vCastLiteralToInteger(e):this.vCoerce(this.vexpr(e),"vi32"):"LiteralInteger"===s?this.vCastLiteralToFloat(e):"Integer"===s?this.vCastValueToFloat(e):this.vCoerce(this.vexpr(e),"vf32")}vEmitSwitchConsequent(e){const t=this.collectSwitchCaseStatements(e),s=this.vTerminated;this.vTerminated=!1;for(let e=0;e{const s=this.getType(t);switch(n){case"Number":case"Float":"Integer"===s?this.vCastValueToFloat(t):"LiteralInteger"===s?this.vCastLiteralToFloat(t):this.vCoerce(this.vexpr(t),"vf32");break;case"Integer":"Number"===s||"Float"===s?this.vCastValueToInteger(t):"LiteralInteger"===s?this.vCastLiteralToInteger(t):this.vCoerce(this.vexpr(t),"vi32");break;case"Boolean":this.vexprMask(t);break;default:throw this.astErrorOutput(`WebAssembly backend does not yet support a ternary of type ${n}`,e)}},a="Integer"===n?"vi32":"Boolean"===n?"vbool":"vf32";if(!this.vInfo.exprVarying(e.test))return this.emitCondition(e.test),this.enterIf("v128"),i(e.consequent),t.else_(),i(e.alternate),this.exit(),a;const o=t.addLocal("v128");this.vexprMask(e.test),t.localSet(o);const u=t.addLocal("v128");t.localGet(this.vCur).localSet(u);const l=t.addLocal("v128"),h=t.addLocal("v128");return t.localGet(u).localGet(o).v128And().localSet(this.vCur),this.vMaskDepth++,i(e.consequent),t.localSet(l),t.localGet(u).localGet(o).v128Andnot().localSet(this.vCur),i(e.alternate),t.localSet(h),this.vMaskDepth--,t.localGet(u).localSet(this.vCur),t.localGet(l).localGet(h).localGet(o).v128Bitselect(),a}vTernaryStatement(e){const t=this.em;if(!this.vInfo.exprVarying(e.test))return this.emitCondition(e.test),this.enterIf(),this.vstatementExpression(e.consequent),t.else_(),this.vstatementExpression(e.alternate),void this.exit();const s=t.addLocal("v128");this.vexprMask(e.test),t.localSet(s);const r=t.addLocal("v128");t.localGet(this.vCur).localSet(r),t.localGet(r).localGet(s).v128And().localSet(this.vCur),this.vMaskDepth++,this.vstatementExpression(e.consequent),t.localGet(r).localGet(s).v128Andnot().localSet(this.vCur),this.vstatementExpression(e.alternate),this.vMaskDepth--,t.localGet(r).localSet(this.vCur)}vexprCall(e){if(!e.callee)throw this.astErrorOutput("Unknown CallExpression",e);if("MemberExpression"===e.callee.type&&"this.color"===this.getVariableSignature(e.callee,!0))throw this.astErrorOutput("WebAssembly backend does not yet support graphical mode (this.color)",e);let t=null;const s=this.isAstMathFunction(e);if(t=s||e.callee.object&&"ThisExpression"===e.callee.object.type?e.callee.property.name:"SequenceExpression"!==e.callee.type||"Literal"!==e.callee.expressions[0].type||isNaN(e.callee.expressions[0].raw)?e.callee.name:e.callee.expressions[1].property.name,!t)throw this.astErrorOutput("Unhandled function, couldn't find name",e);return s?this.vMathCall(t,e):this.vUserCall(t,e)}vUserCall(e,t){const s=this.em,r=this.assembler.helperInfo||{readsThread:!1,usesRandom:!1},n=this.assembler.globals,i=this.getType(t),a=this.lookupFunctionArgumentTypes(e)||[],o=[];for(let r=0;r0&&s.i32Const(t).i32Add(),s.globalSet(n.threadX)),r.usesRandom&&s.localGet(c).i32x4ExtractLane(t).globalSet(n.pcgState);for(const e of o)s.localGet(e.index),"vi32"===e.wtype?s.i32x4ExtractLane(t):s.f32x4ExtractLane(t);s.call(this.mangleFunctionName(e)),"void"!==u&&s.localSet(l),r.usesRandom&&s.localGet(c).globalGet(n.pcgState).i32x4ReplaceLane(t).localSet(c),"void"!==u&&(0===t?(s.localGet(l),"i32"===u?s.i32x4Splat():s.f32x4Splat(),s.localSet(h)):(s.localGet(h).localGet(l),"i32"===u?s.i32x4ReplaceLane(t):s.f32x4ReplaceLane(t),s.localSet(h)))}return r.readsThread&&s.localGet(this._vBaseX).globalSet(n.threadX),r.usesRandom&&(s.localGet(c).globalGet(n.pcgStateV),this.vMaskDepth>0?s.localGet(this.vCur):s.v128ConstI32x4(-1,-1,-1,-1),s.v128Bitselect().globalSet(n.pcgStateV)),"void"===u?"void":(s.localGet(h),"i32"===u?"vi32":"vf32")}vMathCall(e,t){const s=this.em;if("random"===e)return this.usesRandom=!0,this.vMaskDepth>0?s.localGet(this.vCur):s.v128ConstI32x4(-1,-1,-1,-1),s.call("pcg_random_v"),"vf32";const r=e=>{switch(this.getType(e)){case"Integer":this.vCastValueToFloat(e);break;case"LiteralInteger":this.vCastLiteralToFloat(e);break;default:this.vCoerce(this.vexpr(e),"vf32")}},n=v[e];if(n)return r(t.arguments[0]),s[n](),"vf32";switch(e){case"round":return r(t.arguments[0]),s.v128ConstF32x4(.5,.5,.5,.5).f32x4Add().f32x4Floor(),"vf32";case"fround":return r(t.arguments[0]),"vf32";case"min":case"max":{const n="min"===e?"f32x4Min":"f32x4Max";r(t.arguments[0]);for(let e=1;e{s.localGet(e.indices[t]),"vec"===e.kind&&s.f32x4Splat()};if("Literal"===t.type&&Number.isInteger(t.value)){if(t.value<0||t.value>=e.n)throw this.astErrorOutput(`index ${t.value} out of range for Array(${e.n})`,t);return r(t.value),"vf32"}const n=s.addLocal("v128");this.vEmitIndex(t),s.localSet(n);const i=s.addLocal("v128");r(0),s.localSet(i);for(let t=1;tthis.isThreadDependent(e));switch(e.type){case"MemberExpression":{const t=this.getVariableSignature(e);if("this.thread.value"===t||"value.thread.value"===t)return"x"===e.property.name;break}case"CallExpression":if(this.isAstMathFunction(e)){if("random"===e.callee.property.name)return!0;break}return!0;case"Identifier":return!!this.taintedLocals&&this.taintedLocals.has(e.name);case"ThisExpression":return!1}for(const t in e){if("loc"===t||"start"===t||"end"===t||"parent"===t)continue;const s=e[t];if(s&&"object"==typeof s&&this.isThreadDependent(s))return!0}return!1}recordUniformity(e,t){this._analysisPass&&this.uniformity.push({kind:e,threadDependent:!t||this.isThreadDependent(t)})}}}}),ut=e((e,t)=>{let s=null;try{s=d()}catch(e){}const r="function"==typeof Worker;const n="\nvar entries = {};\nfunction handleMessage(message, post) {\n if (message.type === 'setup') {\n var imports = { env: { memory: message.memory } };\n for (var i = 0; i < message.mathImports.length; i++) {\n imports.env['math_' + message.mathImports[i]] = Math[message.mathImports[i]];\n }\n var instance = new WebAssembly.Instance(message.module, imports);\n entries[message.id] = {\n run: instance.exports.run,\n runSimd: instance.exports.run_simd || null,\n sizeX: message.sizeX\n };\n post({ type: 'ready', id: message.id });\n } else if (message.type === 'release') {\n delete entries[message.id];\n } else if (message.type === 'run') {\n var entry = entries[message.id];\n var start = message.start;\n var end = message.end;\n var seed = message.seed;\n if (entry.runSimd && (entry.sizeX & 3) === 0 && (start & 3) === 0) {\n var quadEnd = end - ((end - start) & 3);\n if (quadEnd > start) entry.runSimd(start, quadEnd, seed);\n if (quadEnd < end) entry.run(quadEnd, end, seed);\n } else {\n entry.run(start, end, seed);\n }\n post({ type: 'done', taskId: message.taskId });\n }\n}\nif (typeof self !== 'undefined' && typeof postMessage === 'function') {\n self.onmessage = function(event) {\n handleMessage(event.data, function(message) { postMessage(message); });\n };\n} else {\n var parentPort = require('worker_threads').parentPort;\n parentPort.on('message', function(message) {\n handleMessage(message, function(reply) { parentPort.postMessage(reply); });\n });\n}\n";t.exports={WebAssemblyWorkerPool:class{constructor(e){this.size=e||function(){if("undefined"!=typeof navigator&&navigator.hardwareConcurrency)return navigator.hardwareConcurrency;if(s&&"function"==typeof s.cpus){const e=s.cpus().length;if(e)return e}return 4}(),this.workers=[],this.destroyed=!1,this.dispatchCount=0,this.lastDispatch=null,this._taskId=0}get liveWorkerCount(){let e=0;for(const t of this.workers)t.dead||e++;return e}_spawn(){const e={handle:null,dead:!1,state:{setup:new Set,settingUp:new Map,pending:new Map},fail:null,die:null},t=e.state;e.fail=e=>{for(const s of t.settingUp.values())s.reject(e);t.settingUp.clear();for(const s of t.pending.values())s.reject(e);t.pending.clear()},e.die=t=>{if(!e.dead&&(e.dead=!0,e.fail(t),e.handle&&"function"==typeof e.handle.terminate))try{e.handle.terminate()}catch(e){}};const s=s=>{if("ready"===s.type){const r=t.settingUp.get(s.id);r&&(t.settingUp.delete(s.id),t.setup.add(s.id),this._updateRef(e),r.resolve())}else if("done"===s.type){const r=t.pending.get(s.taskId);r&&(t.pending.delete(s.taskId),this._updateRef(e),r.resolve())}};let i;if(r){const t=URL.createObjectURL(new Blob([n],{type:"text/javascript"}));i=new Worker(t),URL.revokeObjectURL(t),i.onmessage=e=>s(e.data),i.onerror=t=>e.die(new Error(t.message||"WebAssembly worker error"))}else{const{Worker:t}=d();i=new t(n,{eval:!0}),i.on("message",s),i.on("error",t=>e.die(t)),i.on("exit",t=>{e.die(new Error(`WebAssembly worker exited with code ${t}`))}),i.unref()}return e.handle=i,e}_worker(e){for(;this.workers.length<=e;)this.workers.push(this._spawn());return this.workers[e].dead&&(this.workers[e]=this._spawn()),this.workers[e]}_updateRef(e){!e.dead&&e.handle&&"function"==typeof e.handle.ref&&(e.state.settingUp.size+e.state.pending.size>0?e.handle.ref():e.handle.unref())}_ensureSetup(e,t){if(e.state.setup.has(t.id))return Promise.resolve();let s=e.state.settingUp.get(t.id);return s||(s={},s.promise=new Promise((e,t)=>{s.resolve=e,s.reject=t}),e.state.settingUp.set(t.id,s),this._updateRef(e),e.handle.postMessage({type:"setup",id:t.id,module:t.module,memory:t.memory,mathImports:t.mathImports,sizeX:t.sizeX})),s.promise}dispatch(e,t){if(this.destroyed)return Promise.reject(new Error("WebAssembly worker pool has been destroyed"));this.dispatchCount++,this.lastDispatch={workerCount:t.length,ranges:t.map(e=>[e.start,e.end])};const s=t.map((t,s)=>{const r=this._worker(s);return this._ensureSetup(r,e).then(()=>new Promise((s,n)=>{if(r.dead)return void n(new Error("WebAssembly worker died before the task could run"));const i=++this._taskId;r.state.pending.set(i,{resolve:s,reject:n}),this._updateRef(r),r.handle.postMessage({type:"run",id:e.id,taskId:i,start:t.start,end:t.end,seed:t.seed})}))});return Promise.all(s).then(()=>{})}release(e){if(!this.destroyed)for(const t of this.workers){if(t.dead)continue;t.state.setup.delete(e);const s=t.state.settingUp.get(e);s&&(t.state.settingUp.delete(e),s.reject(new Error("WebAssembly kernel entry released during setup")),this._updateRef(t)),t.handle.postMessage({type:"release",id:e})}}destroy(){if(this.destroyed)return;this.destroyed=!0;const e=new Error("WebAssembly worker pool has been destroyed");for(const t of this.workers)t.dead=!0,t.fail(e),t.handle.terminate();this.workers=[]}}}}),lt=e((e,t)=>{const{Kernel:s}=a(),{FunctionBuilder:n}=o(),{WebAssemblyFunctionNode:u}=ot(),{WasmModuleBuilder:l}=at(),{WebAssemblyWorkerPool:h}=ut(),{utils:c}=i(),{Input:p}=r(),d=Object.freeze({kernelMap:!1,isIntegerDivisionAccurate:!0,isSpeedTacticSupported:!1,isTextureFloat:!0,isDrawBuffers:!1,kernelMapSize:0,channelCount:1,maxTextureSize:1/0,isFloatRead:!0});let f=null,m=null,g=1;t.exports={WebAssemblyKernel:class e extends s{static get isSupported(){return"object"==typeof WebAssembly&&null!==WebAssembly&&WebAssembly.validate(new Uint8Array([0,97,115,109,1,0,0,0]))}static get isSIMDSupported(){if(null===f)try{const e=new l;e.addFunction("t",{params:[],results:[]}).v128ConstI32x4(0,0,0,0).drop(),f=WebAssembly.validate(e.toBytes())}catch(e){f=!1}return f}static get isThreadsSupported(){if(null===m)try{if("undefined"==typeof SharedArrayBuffer)m=!1;else{const e=new l;e.addMemoryImport(1,1,!0);const t=new WebAssembly.Memory({initial:1,maximum:1,shared:!0});new WebAssembly.Instance(new WebAssembly.Module(e.toBytes()),{env:{memory:t}}),m=!0}}catch(e){m=!1}return m}static isContextMatch(e){return!1}static getFeatures(){return d}static get features(){return d}static get mode(){return"webasm"}static getSignature(e,t){return"webasm"+(t.length>0?":"+t.join(","):"")}static destroyContext(e){}static nativeFunctionArguments(){throw new Error("WebAssembly backend does not yet support native functions")}static nativeFunctionReturnType(){throw new Error("WebAssembly backend does not yet support native functions")}static combineKernels(){throw new Error("WebAssembly backend does not yet support combineKernels")}constructor(e,t){super(e,t),this.poolSize=null,this.mergeSettings(e.settings||t),null===this.precision&&(this.precision="single"),this.threadDim=null,this.componentCount=1,this.moduleCacheLimit=8,this.functionBuilder=null,this.tracedFunctions=null,this.usesRandom=!1,this.usedMathImports=null,this._moduleCache=new Map,this._active=null,this._lastRunPath=null,this._pool=null,this._threadedTail=Promise.resolve()}initCanvas(){return this.graphical&&"undefined"!=typeof document?document.createElement("canvas"):null}initContext(){return null}initPlugins(e){return[]}setOutput(e){const t=this.toKernelOutput(e);if(this.built&&!this.dynamicOutput)throw new Error("Resizing a kernel with dynamicOutput: false is not possible");return this.output=t,this}toString(){throw new Error("WebAssembly backend does not yet support toString")}build(){if(this.built)return;if(this.gpu&&this.gpu.kernels&&-1===this.gpu.kernels.indexOf(this)&&this.gpu.kernels.push(this),this.graphical)return this.requestFallback(arguments,"graphical mode is not supported on the webasm backend");if(this.subKernels&&this.subKernels.length>0)return this.requestFallback(arguments,"kernel maps are not supported on the webasm backend");this.setupConstants(),this.setupArguments(arguments);for(let e=0;e16*Math.ceil(e/16);let s=0;const r={},n={};for(let i=0;i=4096}_entryKey(e){return this._computeSizeSignature(e)+(this._threadable()?"|shared":"")}_assembleModule(t,s,r){const n=new l,i=t.outputOffset+s*this.componentCount*4,a=Math.ceil(i/65536)+16,o=Math.max(a,4096);n.addMemoryImport(a,o,r);const u=Array.from(this.usedMathImports).sort();for(const e of u){const t="pow"===e||"atan2"===e?["f32","f32"]:["f32"];n.addFuncImport("math_"+e,t,["f32"])}const h={threadX:n.addGlobal("i32",!0,0),threadY:n.addGlobal("i32",!0,0),threadZ:n.addGlobal("i32",!0,0),dataIndex:n.addGlobal("i32",!0,0)};this.usesRandom&&(h.pcgState=n.addGlobal("i32",!0,0),this._emitPcgRandom(n,h.pcgState));const c={module:n,layout:t,globals:h};for(let e=this.tracedFunctions.length-1;e>=0;e--){const t=this.tracedFunctions[e];if("kernel"===t)continue;const s=this.functionBuilder.functionMap[t];s&&(s.output=this.output,s.emitFunction(c))}this.functionBuilder.functionMap.kernel.output=this.output,this.functionBuilder.functionMap.kernel.emitFunction(c);const[p,d]=this.threadDim,f=n.addFunction("run",{params:["i32","i32","i32"],locals:["i32"]});if(f.localGet(0).localSet(3),1===this.output.length?(f.i32Const(0).globalSet(h.threadY),f.i32Const(0).globalSet(h.threadZ)):2===this.output.length&&f.i32Const(0).globalSet(h.threadZ),f.block(),f.localGet(3).localGet(1).i32GeS().brIf(0),f.loop(),f.localGet(3).globalSet(h.dataIndex),1===this.output.length?f.localGet(3).globalSet(h.threadX):2===this.output.length?(f.localGet(3).i32Const(p).i32RemU().globalSet(h.threadX),f.localGet(3).i32Const(p).i32DivU().globalSet(h.threadY)):(f.localGet(3).i32Const(p).i32RemU().globalSet(h.threadX),f.localGet(3).i32Const(p).i32DivU().i32Const(d).i32RemU().globalSet(h.threadY),f.localGet(3).i32Const(p*d).i32DivU().globalSet(h.threadZ)),this.usesRandom&&f.localGet(2).localGet(3).i32Const(-1640531527).i32Mul().i32Add().i32Const(747796405).i32Mul().i32Const(-1403630843).i32Add().globalSet(h.pcgState),f.call("kernel"),f.localGet(3).i32Const(1).i32Add().localSet(3),f.localGet(3).localGet(1).i32LtS().brIf(0),f.end(),f.end(),n.exportFunction("run"),e.isSIMDSupported){this.usesRandom&&(h.pcgStateV=n.addGlobal("v128",!0,0),this._emitPcgRandomVector(n,h.pcgStateV));let e=null;for(const t of this.tracedFunctions){if("kernel"===t)continue;const s=this.functionBuilder.functionMap[t];s&&(e||(e={readsThread:!1,usesRandom:!1}),s.readsThread&&(e.readsThread=!0),s.usesRandom&&(e.usesRandom=!0))}c.helperInfo=e,this.functionBuilder.functionMap.kernel.emitVectorFunction(c),this._emitRunSimd(n,h),n.exportFunction("run_simd")}return{bytes:n.toBytes(),initial:a,maximum:o}}_emitRunSimd(e,t){const[s,r]=this.threadDim,n=e.addFunction("run_simd",{params:["i32","i32","i32"],locals:["i32"]});n.localGet(0).localSet(3),1===this.output.length?(n.i32Const(0).globalSet(t.threadY),n.i32Const(0).globalSet(t.threadZ)):2===this.output.length&&n.i32Const(0).globalSet(t.threadZ),n.block(),n.localGet(3).localGet(1).i32GeS().brIf(0),n.loop(),n.localGet(3).globalSet(t.dataIndex),1===this.output.length?n.localGet(3).globalSet(t.threadX):2===this.output.length?(n.localGet(3).i32Const(s).i32RemU().globalSet(t.threadX),n.localGet(3).i32Const(s).i32DivU().globalSet(t.threadY)):(n.localGet(3).i32Const(s).i32RemU().globalSet(t.threadX),n.localGet(3).i32Const(s).i32DivU().i32Const(r).i32RemU().globalSet(t.threadY),n.localGet(3).i32Const(s*r).i32DivU().globalSet(t.threadZ)),this.usesRandom&&(n.localGet(3).i32x4Splat().v128ConstI32x4(0,1,2,3).i32x4Add(),n.v128ConstI32x4(-1640531527,-1640531527,-1640531527,-1640531527).i32x4Mul(),n.localGet(2).i32x4Splat().i32x4Add(),n.v128ConstI32x4(747796405,747796405,747796405,747796405).i32x4Mul(),n.v128ConstI32x4(-1403630843,-1403630843,-1403630843,-1403630843).i32x4Add(),n.globalSet(t.pcgStateV)),n.call("kernel_simd"),n.localGet(3).i32Const(4).i32Add().localSet(3),n.localGet(3).localGet(1).i32LtS().brIf(0),n.end(),n.end()}_emitPcgRandomVector(e,t){const s=e.addFunction("pcg_random_v",{params:["v128"],results:["v128"]}),r=s.addLocal("v128"),n=s.addLocal("i32");s.globalGet(t).v128ConstI32x4(747796405,747796405,747796405,747796405).i32x4Mul().v128ConstI32x4(-1403630843,-1403630843,-1403630843,-1403630843).i32x4Add().globalGet(t).localGet(0).v128Bitselect().globalSet(t),s.globalGet(t).localSet(r),s.localGet(r).i32x4ExtractLane(0).localSet(n),s.localGet(n).localGet(n).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU().i32x4Splat();for(let e=1;e<4;e++)s.localGet(r).i32x4ExtractLane(e).localSet(n),s.localGet(n).localGet(n).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU().i32x4ReplaceLane(e);s.localGet(r).v128Xor(),s.v128ConstI32x4(277803737,277803737,277803737,277803737).i32x4Mul();const i=s.addLocal("v128");s.localTee(i),s.i32Const(22).i32x4ShrU().localGet(i).v128Xor(),s.i32Const(8).i32x4ShrU(),s.f32x4ConvertI32x4U(),s.v128ConstF32x4(16777216,16777216,16777216,16777216).f32x4Div()}_emitPcgRandom(e,t){const s=e.addFunction("pcg_random",{params:[],results:["f32"]}),r=s.addLocal("i32");s.globalGet(t).i32Const(747796405).i32Mul().i32Const(-1403630843).i32Add().globalSet(t),s.globalGet(t).globalGet(t).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU().globalGet(t).i32Xor().i32Const(277803737).i32Mul().localTee(r),s.i32Const(22).i32ShrU().localGet(r).i32Xor().i32Const(8).i32ShrU().f32ConvertI32U().f32Const(16777216).f32Div()}_releaseEntry(e){const t=()=>{e.instance=null,e.module=null,e.memory=null,e.run=null,e.runSimd=null,e.f32=null,e.i32=null,e.bytes=null};if(e.shared&&this._pool){const s=this._pool;this._threadedTail.then(()=>{s.release(e.id),t()},t)}else t()}_instantiate(e,t){let s=this._moduleCache.get(e);if(s&&(this._moduleCache.delete(e),this._moduleCache.set(e,s)),!s){const r=this._threadable(),n=this.computeLayout(t),[i,a,o]=this.threadDim,u=i*a*o,{bytes:l,initial:h,maximum:d}=this._assembleModule(n,u,r);if(!WebAssembly.validate(l))throw new Error("WebAssembly backend: generated module failed validation (internal error)");const f=r?new WebAssembly.Memory({initial:h,maximum:d,shared:!0}):new WebAssembly.Memory({initial:h,maximum:d}),m={env:{memory:f}};for(const e of this.usedMathImports)m.env["math_"+e]=Math[e];const x=new WebAssembly.Module(l),y=new WebAssembly.Instance(x,m);s={id:g++,sizeSignature:e,shared:r,layout:n,cells:u,bytes:l,module:x,memory:f,mathImports:Array.from(this.usedMathImports).sort(),sizeX:i,instance:y,run:y.exports.run,runSimd:y.exports.run_simd||null,f32:new Float32Array(f.buffer),i32:new Int32Array(f.buffer)};for(const e in n.constantArrays){const t=n.constantArrays[e],r=this.constants[e];c.flattenTo(r instanceof p?r.value:r,s.f32.subarray(t.offset/4,t.offset/4+t.flatLength))}for(this._moduleCache.set(e,s);this._moduleCache.size>Math.max(this.moduleCacheLimit,1);){const e=this._moduleCache.keys().next().value,t=this._moduleCache.get(e);this._moduleCache.delete(e),this._releaseEntry(t)}}this._active=s}checkArgumentTypes(e){if(super.checkArgumentTypes(e),!this.argumentTypes)return;const t=Math.min(e.length,this.argumentTypes.length);for(let s=0;s>>0:4294967296*Math.random()>>>0),u|=0,o&&r>0){const t=e[0];if(3&t){const e=-4&t,s=r/t;for(let r=0;r0&&o(s,s+e,u),a(s+e,s+t,u)}this._lastRunPath=e>0?"simd+scalar-tail":"scalar"}else o(0,r,u),this._lastRunPath="simd"}else a(0,r,u),this._lastRunPath="scalar";const l=s.outputOffset/4,h=n.slice(l,l+r*this.componentCount);return this._shapeOutput(h,Array.from(this.output),this.componentCount)}_runThreaded(e){const t=this._active,{layout:s,cells:r}=t,n=[];for(const t in s.arrays){const r=s.arrays[t],i=e[r.index],a=new Float32Array(r.flatLength);c.flattenTo(i instanceof p?i.value:i,a),n.push({record:r,flat:a})}const i=[];for(const t in s.scalars){const r=s.scalars[t];i.push({record:r,value:e[r.index]})}let a=0;this.usesRandom&&(a=null!==this.randomSeed?this.randomSeed>>>0:4294967296*Math.random()>>>0),a|=0,this._pool||(this._pool=new h(this.poolSize||void 0));const o=this._pool,u=this.componentCount,l=Array.from(this.output),d=this._threadedTail.then(()=>{if(!t.f32)throw new Error("WebAssembly kernel was destroyed");for(let e=0;e=r)break;c.push({start:s,end:t===e-1?r:Math.min(s+h,r),seed:a})}return this._lastRunPath="threaded",o.dispatch(t,c).then(()=>{if(!t.f32)throw new Error("WebAssembly kernel was destroyed");const e=s.outputOffset/4,n=t.f32.slice(e,e+r*u);return this._shapeOutput(n,l,u)})});return this._threadedTail=d.then(()=>{},()=>{}),d}_shapeOutput(e,t,s){const[r,n,i]=[t[0],t[1]||1,t[2]||1];if(1===s)switch(t.length){case 1:return c.erectMemoryOptimizedFloat(e,r);case 2:return c.erectMemoryOptimized2DFloat(e,r,n);default:return c.erectMemoryOptimized3DFloat(e,r,n,i)}const a=s,o=t=>{const s=new Array(r);for(let n=0;n{const{utils:s}=i(),{Input:n}=r();function a(e,t){if(t.kernel)return void(t.kernel=e);const r=s.allPropertiesOf(e);for(let s=0;st.kernel[n]),t.__defineSetter__(n,e=>{t.kernel[n]=e})))}t.kernel=e}t.exports={kernelRunShortcut:function(e){function t(t){e.build.apply(e,t),e.checkArgumentTypes(t);let r=e.switchingKernels?void 0:e.run.apply(e,t);for(let n=0;e.switchingKernels;n++){if(n>=4){const t=e.resetSwitchingKernels();throw new Error(`this kernel cannot run the arguments it was given (${s(t)}); it did not settle on a kernel for them after 4 attempts. Create a separate kernel for this call's argument types.`)}const i=e.resetSwitchingKernels(),a=e.onRequestSwitchKernel(i,t,e);c.kernel=e=a,a.checkArgumentTypes(t),r=a.switchingKernels?void 0:a.run.apply(a,t),a.fallbackRequested&&(r=e.run.apply(e,t))}return r}function s(e){return e&&e.length?e.map(e=>"argumentTypeMismatch"===e.type?`argument ${e.index} is now ${e.needed}`:e.type).join(", "):"unknown reason"}function r(s){if(e.onAsyncModeUpgrade){const t=e.onAsyncModeUpgrade;e.onAsyncModeUpgrade=null;const n=u(s);return t(n,e).then(e=>(e&&c.replaceKernel(e),r(n)))}try{if(!0===e.constructor.isAsync)return e.build.apply(e,s),Promise.resolve(e.run.apply(e,s));for(let e=0;er(e));const n=t(s);return e.renderKernels?Promise.resolve(e.renderKernels()):e.renderOutput?e.renderOutputAsync?e.renderOutputAsync():Promise.resolve(e.renderOutput()):Promise.resolve(n)}catch(e){return Promise.reject(e)}}function i(e){return Boolean(e)&&"WebGPUBuffer"===e.type}function o(e){const t=u(e),s=[];for(let e=0;e{t[r]=e}))}return Promise.all(s).then(()=>t)}function u(e){const t=new Array(e.length);for(let s=0;s{try{e(h.apply(this,arguments))}catch(e){t(e)}})},c.replaceKernel=function(t){a(e=t,c)},a(e,c),c}}}),ct=e((e,s)=>{const{gpuMock:r}=t(),{utils:n}=i(),{Kernel:o}=a(),{CPUKernel:u}=p(),{HeadlessGLKernel:l}=ve(),{WebGL2Kernel:h}=tt(),{WebGLKernel:c}=be(),{WebGPUKernel:d}=it(),{WebAssemblyKernel:f}=lt(),{kernelRunShortcut:m}=ht(),g=[l,h,c,f],x=["gpu","cpu"],y={headlessgl:l,webgl2:h,webgl:c,webgpu:d,webasm:f};let b=!0;function v(e){if(!e)return{};const t=Object.assign({},e);return e.hasOwnProperty("floatOutput")&&(n.warnDeprecated("setting","floatOutput","precision"),t.precision=e.floatOutput?"single":"unsigned"),e.hasOwnProperty("outputToTexture")&&(n.warnDeprecated("setting","outputToTexture","pipeline"),t.pipeline=Boolean(e.outputToTexture)),e.hasOwnProperty("outputImmutable")&&(n.warnDeprecated("setting","outputImmutable","immutable"),t.immutable=Boolean(e.outputImmutable)),e.hasOwnProperty("floatTextures")&&(n.warnDeprecated("setting","floatTextures","optimizeFloatMemory"),t.optimizeFloatMemory=Boolean(e.floatTextures)),t}s.exports={GPU:class e{static disableValidation(){b=!1}static enableValidation(){b=!0}static get isGPUSupported(){return g.some(e=>e.isSupported)}static get isKernelMapSupported(){return g.some(e=>e.isSupported&&e.features.kernelMap)}static get isOffscreenCanvasSupported(){return"undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas||"undefined"!=typeof importScripts}static get isWebGLSupported(){return c.isSupported}static get isWebGL2Supported(){return h.isSupported}static get isHeadlessGLSupported(){return l.isSupported}static get isWebGPUSupported(){return d.isSupported}static isWebGPUAvailable(){return d.isSupported?navigator.gpu.requestAdapter().then(e=>null!==e,()=>!1):Promise.resolve(!1)}static get isWebAssemblySupported(){return f.isSupported}static get isCanvasSupported(){return"undefined"!=typeof HTMLCanvasElement}static get isGPUHTMLImageArraySupported(){return h.isSupported}static get isSinglePrecisionSupported(){return g.some(e=>e.isSupported&&e.features.isFloatRead&&e.features.isTextureFloat)}constructor(t){if(t=t||{},this.canvas=t.canvas||null,this.context=t.context||null,this.mode=t.mode,this.Kernel=null,this._webGPUDecision=null,"async"===t.mode&&(d.isSupported?e.isWebGPUAvailable().then(e=>{this._webGPUDecision=e},()=>{this._webGPUDecision=!1}):this._webGPUDecision=!1),this.kernels=[],this.functions=[],this.nativeFunctions=[],this.injectedNative=null,"dev"!==this.mode){if(this.chooseKernel(),t.functions)for(let e=0;es.argumentTypes[e]));const l=this;function h(e){console.warn("Falling back to CPU"+(x.fallbackReason?`: ${x.fallbackReason}`:""));const s=new u(t,{argumentTypes:x.argumentTypes,constantTypes:x.constantTypes,graphical:x.graphical,loopMaxIterations:x.loopMaxIterations,constants:x.constants,dynamicOutput:x.dynamicOutput,dynamicArgument:x.dynamicArguments,output:x.output,precision:x.precision,pipeline:x.pipeline,immutable:x.immutable,optimizeFloatMemory:x.optimizeFloatMemory,fixIntegerDivisionAccuracy:x.fixIntegerDivisionAccuracy,functions:x.functions,nativeFunctions:x.nativeFunctions,injectedNative:x.injectedNative,subKernels:x.subKernels,strictIntegers:x.strictIntegers,randomSeed:x.randomSeed,debug:x.debug,asyncMode:x.asyncMode,onRequestFallback:h,onRequestSwitchKernel:c,canvas:x.graphical&&!x.context?x.canvas:null});s.fallbackReason=x.fallbackReason,s.build.apply(s,e);const r=s.run.apply(s,e);return x.replaceKernel(s),!l.canvas&&s.canvas&&(l.canvas=s.canvas),!l.context&&s.context&&(l.context=s.context),r}function c(e,s,r){r.debug&&console.warn("Switching kernels");let n=null;if(r.signature&&!a[r.signature]&&(a[r.signature]=r),r.dynamicOutput)for(let t=e.length-1;t>=0;t--){const s=e[t];"outputPrecisionMismatch"===s.type&&(n=s.needed)}const o=r.constructor,u=o.getArgumentTypes(r,s),l=o.getSignature(r,u),p=a[l];if(p)return p.onActivate(r),p;const d=a[l]=new o(t,{argumentTypes:u,constantTypes:r.constantTypes,graphical:r.graphical,loopMaxIterations:r.loopMaxIterations,constants:r.constants,dynamicOutput:r.dynamicOutput,dynamicArgument:r.dynamicArguments,context:r.context,canvas:r.canvas,output:n||r.output,precision:r.precision,pipeline:r.pipeline,immutable:r.immutable,optimizeFloatMemory:r.optimizeFloatMemory,fixIntegerDivisionAccuracy:r.fixIntegerDivisionAccuracy,functions:r.functions,nativeFunctions:r.nativeFunctions,injectedNative:r.injectedNative,subKernels:r.subKernels,strictIntegers:r.strictIntegers,randomSeed:r.randomSeed,debug:r.debug,asyncMode:r.asyncMode,gpu:r.gpu,validate:b,returnType:r.returnType,tactic:r.tactic,onRequestFallback:h,onRequestSwitchKernel:c,texture:r.texture,mappedTextures:r.mappedTextures,drawBuffersMap:r.drawBuffersMap});return d.build.apply(d,s),x.replaceKernel(d),i.push(d),d}const p=Object.assign({context:this.context,canvas:this.canvas,functions:this.functions,nativeFunctions:this.nativeFunctions,injectedNative:this.injectedNative,gpu:this,validate:b,onRequestFallback:h,onRequestSwitchKernel:c},o);"async"===this.mode&&(p.asyncMode=!0);let f,g=this.Kernel;"async"===this.mode&&o.graphical&&!0===this._webGPUDecision&&(g=d,p.canvas===this.canvas&&(p.canvas=o.canvas||null),p.context===this.context&&(p.context=o.context||null),p.asyncMode=!0);try{f=new g(t,p)}catch(e){if(g===this.Kernel)throw e;f=new this.Kernel(t,Object.assign({},p,{canvas:this.canvas,context:this.context}))}const x=m(f);if("async"===this.mode&&d.isSupported&&!(f instanceof d)){const s=this;f.onAsyncModeUpgrade=function(r,n){return e.isWebGPUAvailable().then(e=>{if(!e)return null;if(n.graphical)return n.debug&&console.warn("webgpu upgrade declined: graphical kernels keep their canvas"),null;let a;try{a=new d(t,{functions:n.functions,nativeFunctions:n.nativeFunctions,injectedNative:n.injectedNative,gpu:s,validate:b,asyncMode:!0,output:n.output,pipeline:n.pipeline,immutable:n.immutable,dynamicOutput:n.dynamicOutput,dynamicArguments:!0,loopMaxIterations:n.loopMaxIterations,constants:n.constants,constantTypes:n.constantTypes,argumentTypes:n.argumentTypes,precision:n.precision,tactic:n.tactic,strictIntegers:n.strictIntegers,fixIntegerDivisionAccuracy:n.fixIntegerDivisionAccuracy,subKernels:n.subKernels,graphical:n.graphical,debug:n.debug}),a.build.apply(a,r)}catch(e){return n.debug&&console.warn("webgpu upgrade declined: "+e.message),null}return a._buildPromise.then(()=>(i.push(a),a),e=>(n.debug&&console.warn("webgpu upgrade declined: "+e.message),a.destroy(),null))},()=>null)}}return this.canvas||(this.canvas=f.canvas),this.context||(this.context=f.context),i.push(f),x}createKernelMap(){let e,t;const s=typeof arguments[arguments.length-2];if("function"===s||"string"===s?(e=arguments[arguments.length-2],t=arguments[arguments.length-1]):e=arguments[arguments.length-1],!("dev"===this.mode||this.Kernel.isSupported&&this.Kernel.features.kernelMap)){if("webgpu"===this.Kernel.mode)throw new Error("WebGPU backend does not yet support createKernelMap");if(this.mode&&x.indexOf(this.mode)<0&&"webasm"!==this.Kernel.mode)throw new Error(`kernelMap not supported on ${this.Kernel.name}`)}const r=v(t);if(t&&"object"==typeof t.argumentTypes&&(r.argumentTypes=Object.keys(t.argumentTypes).map(e=>t.argumentTypes[e])),Array.isArray(arguments[0])){r.subKernels=[];const e=arguments[0];for(let t=0;t0)throw new Error('Cannot call "addNativeFunction" after "createKernels" has been called.');return this.nativeFunctions.push(Object.assign({name:e,source:t},s)),this}injectNative(e){return this.injectedNative=e,this}destroy(){return new Promise((e,t)=>{this.kernels||e(),setTimeout(()=>{try{const e=this.kernels.slice();for(let t=0;t{const{utils:s}=i();t.exports={alias:function(e,t){const r=t.toString();return new Function(`return function ${e} (${s.getArgumentNamesFromString(r).join(", ")}) {\n ${s.getFunctionBodyFromString(r)}\n}`)()}}}),dt=e((e,t)=>{const{GPU:s}=ct(),{alias:c}=pt(),{utils:d}=i(),{Input:f,input:m}=r(),{Texture:g}=n(),{FunctionBuilder:x}=o(),{FunctionNode:y}=l(),{CPUFunctionNode:b}=h(),{CPUKernel:v}=p(),{HeadlessGLKernel:S}=ve(),{WebGLFunctionNode:T}=R(),{WebGLKernel:A}=be(),{kernelValueMaps:w}=ye(),{WebGL2FunctionNode:E}=Se(),{WebGL2Kernel:_}=tt(),{kernelValueMaps:I}=et(),{WGSLFunctionNode:k}=st(),{WebGPUKernel:C}=it(),{WebGPUContext:L}=rt(),{WebGPUBufferResult:D}=nt(),{WebAssemblyFunctionNode:F}=ot(),{WebAssemblyKernel:$}=lt(),{GLKernel:G}=N(),{Kernel:O}=a(),{FunctionTracer:V}=u();t.exports={alias:c,CPUFunctionNode:b,CPUKernel:v,GPU:s,FunctionBuilder:x,FunctionNode:y,HeadlessGLKernel:S,Input:f,input:m,Texture:g,utils:d,WebGL2FunctionNode:E,WebGL2Kernel:_,webGL2KernelValueMaps:I,WebGLFunctionNode:T,WebGLKernel:A,webGLKernelValueMaps:w,WGSLFunctionNode:k,WebGPUKernel:C,WebGPUContext:L,WebGPUBufferResult:D,WebAssemblyFunctionNode:F,WebAssemblyKernel:$,GLKernel:G,Kernel:O,FunctionTracer:V,plugins:{mathRandom:M()}}});return e((e,t)=>{const s=dt(),r=s.GPU;for(const e in s)s.hasOwnProperty(e)&&"GPU"!==e&&(r[e]=s[e]);function n(e){e.GPU&&e.GPU.prototype&&e.GPU.prototype.createKernel||Object.defineProperty(e,"GPU",{configurable:!0,get:()=>r,set(){}})}r.GPU=r,"undefined"!=typeof window&&n(window),"undefined"!=typeof self&&n(self),t.exports=r})()}); \ No newline at end of file diff --git a/scripts/benchmark-webasm.mjs b/scripts/benchmark-webasm.mjs new file mode 100644 index 00000000..a04581f5 --- /dev/null +++ b/scripts/benchmark-webasm.mjs @@ -0,0 +1,202 @@ +#!/usr/bin/env node +// Benchmarks the webasm backend against cpu and headlessgl in plain Node — +// no browser needed, which is itself the point of this backend. Prints a +// GitHub-markdown table plus raw JSON to stdout. +// +// node scripts/benchmark-webasm.mjs +// +// Methodology (matches scripts/benchmark-webgpu.mjs): +// - every mode's results are cross-checked against cpu (relative 1e-4) +// before timing; a mismatch aborts the run +// - timed runs ping-pong between two input sets so no cache or memoization +// can elide repeated work +// - median of >= 9 runs, warmup excluded; cpu capped to 3 runs when a +// single run exceeds 2 s +// - webasm rows: scalar (run_simd disabled through the same dispatch the +// kernel uses), SIMD (the sync default), and threaded+SIMD (asyncMode, +// the worker pool -- each worker runs the same run_simd export, so this +// row is both axes compounded; result copied out of shared memory like +// any real caller) +// - the divergent workload exists to price mask predication honestly: +// both branch sides execute for every lane + +import { createRequire } from 'node:module'; +const require = createRequire(import.meta.url); +const { GPU } = require('../src'); + +const MEDIAN_RUNS = 9; + +function median(times) { + const sorted = [...times].sort((a, b) => a - b); + return sorted[Math.floor(sorted.length / 2)]; +} + +function relativeError(a, b) { + let worst = 0; + for (let i = 0; i < a.length; i++) { + const denominator = Math.max(Math.abs(a[i]), Math.abs(b[i]), 1e-20); + worst = Math.max(worst, Math.abs(a[i] - b[i]) / denominator); + } + return worst; +} + +function flatten(result) { + if (result[0] && result[0].length !== undefined) { + const out = []; + for (const row of result) out.push(...row); + return out; + } + return Array.from(result); +} + +const SIZE = 512; +function makeMatrix(seed) { + const m = []; + for (let y = 0; y < SIZE; y++) { + const row = new Float32Array(SIZE); + for (let x = 0; x < SIZE; x++) row[x] = ((x * 31 + y * 17 + seed) % 100) / 100; + m.push(row); + } + return m; +} +const MAP_N = 4 * 1024 * 1024; +function makeVector(seed, n) { + const v = new Float32Array(n); + for (let i = 0; i < n; i++) v[i] = ((i * 13 + seed) % 1000) / 500 - 1; + return v; +} + +const WORKLOADS = [ + { + name: `matmul ${ SIZE }×${ SIZE }`, + source: function (a, b) { + let sum = 0; + for (let i = 0; i < 512; i++) { + sum += a[this.thread.y][i] * b[i][this.thread.x]; + } + return sum; + }, + output: [SIZE, SIZE], + inputs: [[makeMatrix(1), makeMatrix(2)], [makeMatrix(3), makeMatrix(4)]], + }, + { + name: '4M-element map', + source: function (v) { + const x = v[this.thread.x]; + return x * x * 0.5 + Math.sqrt(Math.abs(x)) - x * 0.25; + }, + output: [MAP_N], + inputs: [[makeVector(1, MAP_N)], [makeVector(2, MAP_N)]], + }, + { + name: 'divergent piecewise, 1M cells', + source: function (v) { + // three lane-dependent branches plus a lane-varying trip count: the + // shape mask predication exists for + const x = v[this.thread.x]; + let acc = 0; + if (x > 0.5) { + acc = x * x * 3; + } else if (x > 0) { + acc = Math.sqrt(x) * 2; + } else { + acc = -x; + } + for (let i = 0; i < (this.thread.x % 7) + 1; i++) { + acc += 0.125; + } + return acc; + }, + output: [1024 * 1024], + inputs: [[makeVector(5, 1024 * 1024)], [makeVector(6, 1024 * 1024)]], + loopMaxIterations: 16, + }, +]; + +async function timeMode(workload, label, makeKernel, runKernel) { + const kernel = makeKernel(); + // correctness gate against cpu before any timing + const cpuGpu = new GPU({ mode: 'cpu' }); + const cpuKernel = cpuGpu.createKernel(workload.source, { + output: workload.output, + loopMaxIterations: workload.loopMaxIterations || 1000, + }); + const expected = flatten(cpuKernel.apply(null, workload.inputs[0])); + const actual = flatten(await runKernel(kernel, workload.inputs[0])); + const err = relativeError(expected, actual); + if (err > 1e-4) { + throw new Error(`RESULT MISMATCH in ${ workload.name } (${ label }): relative error ${ err }`); + } + cpuGpu.destroy(); + + await runKernel(kernel, workload.inputs[1]); // warmup second shape + const times = []; + const runs = label === 'cpu' ? 3 : MEDIAN_RUNS; + for (let i = 0; i < runs; i++) { + const inputs = workload.inputs[i % 2]; + const start = process.hrtime.bigint(); + await runKernel(kernel, inputs); + times.push(Number(process.hrtime.bigint() - start) / 1e6); + } + return { label, ms: +median(times).toFixed(2), err }; +} + +async function main() { + const rows = []; + for (const workload of WORKLOADS) { + const row = { name: workload.name, modes: {} }; + const settings = { output: workload.output, loopMaxIterations: workload.loopMaxIterations || 1000 }; + + const gpus = []; + const make = (mode, extra) => { + const gpu = new GPU({ mode }); + gpus.push(gpu); + return gpu.createKernel(workload.source, Object.assign({}, settings, extra)); + }; + + const configs = [ + ['cpu', () => make('cpu'), (k, i) => k.apply(null, i)], + ['headlessgl', () => make('headlessgl'), (k, i) => k.apply(null, i)], + ['webasm scalar', () => { + const kernel = make('webasm'); + kernel.apply(null, workload.inputs[0]); // build, then disable simd + kernel.kernel._active.runSimd = null; + return kernel; + }, (k, i) => k.apply(null, i)], + ['webasm SIMD', () => make('webasm'), (k, i) => k.apply(null, i)], + ['webasm threaded+SIMD', () => make('webasm', { asyncMode: true }), (k, i) => k.apply(null, i)], + ]; + for (const [label, makeKernel, runKernel] of configs) { + try { + const result = await timeMode(workload, label, makeKernel, runKernel); + row.modes[label] = result.ms; + process.stderr.write(`${ workload.name } / ${ label }: ${ result.ms } ms (err ${ result.err.toExponential(1) })\n`); + } catch (error) { + row.modes[label] = null; + process.stderr.write(`${ workload.name } / ${ label }: FAILED ${ error.message }\n`); + throw error; + } + } + for (const gpu of gpus) await gpu.destroy(); + rows.push(row); + } + + const labels = ['cpu', 'headlessgl', 'webasm scalar', 'webasm SIMD', 'webasm threaded+SIMD']; + console.log(`\n| Workload | ${ labels.join(' | ') } |`); + console.log(`|---|${ labels.map(() => '---').join('|') }|`); + for (const row of rows) { + const cpuMs = row.modes['cpu']; + console.log(`| ${ row.name } | ${ labels.map(label => { + const ms = row.modes[label]; + if (ms === null) return 'n/a'; + const speedup = label === 'cpu' ? '' : ` (${ (cpuMs / ms).toFixed(1) }×)`; + return `${ ms } ms${ speedup }`; + }).join(' | ') } |`); + } + console.log('\n' + JSON.stringify(rows, null, 2)); +} + +main().catch(error => { + console.error(error); + process.exit(1); +}); diff --git a/scripts/build.js b/scripts/build.js index 09e78a5c..4bbe7375 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -62,10 +62,12 @@ async function toAscii(code, name) { } async function build() { - const full = await bundle(['gl']); + // worker_threads and os are the wasm worker pool's Node half; in the + // browser it detects `Worker` first and never touches them + const full = await bundle(['gl', 'worker_threads', 'os']); write('dist/gpu-browser.js', withBanner(await toAscii(decomment(full), 'gpu-browser.js'))); - const core = await bundle(['gl', 'acorn']); + const core = await bundle(['gl', 'acorn', 'worker_threads', 'os']); write('dist/gpu-browser-core.js', withBanner(await toAscii(decomment(core), 'gpu-browser-core.js'))); } diff --git a/scripts/dev.js b/scripts/dev.js index b3d549a3..28a14e56 100644 --- a/scripts/dev.js +++ b/scripts/dev.js @@ -31,6 +31,11 @@ http.createServer((req, res) => { } res.writeHead(200, { 'Content-Type': MIME[path.extname(filePath).toLowerCase()] || 'application/octet-stream', + // cross-origin isolation: without these two headers browsers hide + // SharedArrayBuffer and the webasm backend's threaded path can never + // run in the browser suite. Everything served here is same-origin. + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'require-corp', 'Cache-Control': 'no-store', }); res.end(data); diff --git a/src/backend/cpu/function-node.js b/src/backend/cpu/function-node.js index c4476601..0d7ff86c 100644 --- a/src/backend/cpu/function-node.js +++ b/src/backend/cpu/function-node.js @@ -12,6 +12,21 @@ class CPUFunctionNode extends FunctionNode { * @param {Array} retArr - return array string * @returns {Array} the append retArr */ + /** + * @desc The generated cell loop binds arguments once for the whole run, so + * an assignment would leak into every later cell (#865); assigned arguments + * get a per-cell shadow local instead. The cpu backend never sanitizes + * names, so the shadow lives OUTSIDE the `user_` namespace (like the GL + * backends' `cellShadow_`): a `$cell` suffix could collide with a user + * identifier literally named that. + */ + markupUserName(name) { + if (this.isRootKernel && this.getAssignedArguments().has(name)) { + return `cellShadow_user_${ name }`; + } + return `user_${ name }`; + } + astFunction(ast, retArr) { // Setup function return type and name @@ -36,11 +51,24 @@ class CPUFunctionNode extends FunctionNode { retArr.push(') {\n'); } + if (this.isRootKernel) { + for (const name of this.getAssignedArguments()) { + retArr.push(`let cellShadow_user_${ name } = user_${ name };\n`); + } + // an early return breaks out of this block -- a plain `continue` only + // reaches the cell loop from the body's top level, so a return inside + // a user loop used to fall through and let later statements overwrite + // the result (#865) + retArr.push('kernelBody: {\n'); + } // Body statement iteration for (let i = 0; i < ast.body.body.length; ++i) { this.astGeneric(ast.body.body[i], retArr); retArr.push('\n'); } + if (this.isRootKernel) { + retArr.push('}\n'); + } if (!this.isRootKernel) { // Function closing @@ -67,7 +95,7 @@ class CPUFunctionNode extends FunctionNode { this.astGeneric(ast.argument, retArr); retArr.push(';\n'); retArr.push(this.followingReturnStatement); - retArr.push('continue;\n'); + retArr.push('break kernelBody;\n'); } else if (this.isSubKernel) { retArr.push(`subKernelResult_${ this.name } = `); this.astGeneric(ast.argument, retArr); @@ -147,6 +175,12 @@ class CPUFunctionNode extends FunctionNode { this.constants && this.constants.hasOwnProperty(idtNode.name) ) { retArr.push('constants_' + idtNode.name); + } else if ( + !this.getDeclaration(idtNode) && + this.isRootKernel && this.getAssignedArguments().has(idtNode.name) + ) { + // an assigned argument reads and writes its per-cell shadow (#865) + retArr.push(this.markupUserName(idtNode.name)); } else { retArr.push('user_' + idtNode.name); } @@ -272,14 +306,16 @@ class CPUFunctionNode extends FunctionNode { ); } - retArr.push('for (let i = 0; i < LOOP_MAX; i++) {'); + // a native do-while: `continue` must jump to the test, which the old + // for-wrapped form skipped (#865). The iteration cap rides in the + // condition; the counter name is keyed to the node so nesting works. + const safeName = `safeI${ this.astKey(doWhileNode, '_') }`; + retArr.push(`let ${ safeName } = 0;\n`); + retArr.push('do {'); this.astGeneric(doWhileNode.body, retArr); - retArr.push('if (!'); + retArr.push('} while (('); this.astGeneric(doWhileNode.test, retArr); - retArr.push(') {\n'); - retArr.push('break;\n'); - retArr.push('}\n'); - retArr.push('}\n'); + retArr.push(`) && ++${ safeName } < LOOP_MAX);\n`); return retArr; @@ -521,14 +557,14 @@ class CPUFunctionNode extends FunctionNode { case 'Integer': case 'Float': case 'Boolean': - retArr.push(`${origin}_${name}`); + retArr.push(origin === 'user' ? this.markupUserName(name) : `${origin}_${name}`); return retArr; } } // handle more complex types // argument may have come from a parent - const markupName = `${origin}_${name}`; + const markupName = origin === 'user' ? this.markupUserName(name) : `${origin}_${name}`; switch (type) { case 'Array(2)': diff --git a/src/backend/function-node.js b/src/backend/function-node.js index 30e26769..d3635cc4 100644 --- a/src/backend/function-node.js +++ b/src/backend/function-node.js @@ -299,6 +299,48 @@ class FunctionNode { return this.ast = functionAST; } + /** + * @desc Argument names the function body assigns to. Backends whose + * arguments are not plain per-invocation locals (the cpu backend's + * run-wide bindings, the GL backends' uniforms) use this to decide which + * arguments need a per-cell shadow local (#865, #867). + * @returns {Set} original (unsanitized) argument names + */ + getAssignedArguments() { + if (this._assignedArguments) return this._assignedArguments; + const assigned = new Set(); + const redeclared = new Set(); + const names = this.argumentNames || []; + const walk = node => { + if (!node || typeof node !== 'object') return; + if (Array.isArray(node)) { + for (const child of node) walk(child); + return; + } + if (node.type === 'AssignmentExpression' && node.left.type === 'Identifier' && names.indexOf(node.left.name) !== -1) { + assigned.add(node.left.name); + } + if (node.type === 'UpdateExpression' && node.argument.type === 'Identifier' && names.indexOf(node.argument.name) !== -1) { + assigned.add(node.argument.name); + } + // `var x` redeclaring a parameter is one binding in JavaScript; the + // backends emit the declaration as an ordinary local, which already + // shadows the argument — adding a per-cell shadow on top would split + // the binding in two + if (node.type === 'VariableDeclarator' && node.id.type === 'Identifier' && names.indexOf(node.id.name) !== -1) { + redeclared.add(node.id.name); + } + for (const key in node) { + if (key === 'loc' || key === 'range' || key === 'parent') continue; + const child = node[key]; + if (child && typeof child === 'object') walk(child); + } + }; + walk(this.getJsAST()); + for (const name of redeclared) assigned.delete(name); + return this._assignedArguments = assigned; + } + traceFunctionAST(ast) { const { contexts, declarations, functions, identifiers, functionCalls } = new FunctionTracer(ast); this.contexts = contexts; diff --git a/src/backend/gl/kernel.js b/src/backend/gl/kernel.js index 96d44e0b..12498ca9 100644 --- a/src/backend/gl/kernel.js +++ b/src/backend/gl/kernel.js @@ -398,7 +398,8 @@ class GLKernel extends Kernel { case 'Array(2)': case 'Array(3)': case 'Array(4)': - return this.requestFallback(args); + return this.requestFallback(args, + `${ this.returnType } output requires single precision, which this context does not support`); } } else { if (this.subKernels !== null) { @@ -426,7 +427,8 @@ class GLKernel extends Kernel { case 'Array(2)': case 'Array(3)': case 'Array(4)': - return this.requestFallback(args); + return this.requestFallback(args, + `${ this.returnType } output requires single precision, which this context does not support`); } } } else if (this.precision === 'single') { diff --git a/src/backend/kernel.js b/src/backend/kernel.js index 3447b107..340040b5 100644 --- a/src/backend/kernel.js +++ b/src/backend/kernel.js @@ -57,6 +57,7 @@ class Kernel { } this.useLegacyEncoder = false; this.fallbackRequested = false; + this.fallbackReason = null; this.onRequestFallback = null; /** @@ -783,11 +784,18 @@ class Kernel { return this; } - requestFallback(args) { + /** + * @param {IArguments} args + * @param {String} [reason] - why this kernel cannot run here; carried onto + * the replacement kernel as `fallbackReason` and named in the console + * warning, so the degradation is discoverable (#868) + */ + requestFallback(args, reason) { if (!this.onRequestFallback) { throw new Error(`"onRequestFallback" not defined on ${ this.constructor.name }`); } this.fallbackRequested = true; + this.fallbackReason = reason || null; return this.onRequestFallback(args); } diff --git a/src/backend/web-assembly/function-node.js b/src/backend/web-assembly/function-node.js new file mode 100644 index 00000000..5e75f6f2 --- /dev/null +++ b/src/backend/web-assembly/function-node.js @@ -0,0 +1,4355 @@ +const { utils } = require('../../utils'); +const { FunctionNode } = require('../function-node'); +const { WasmFunctionEmitter } = require('./wasm-builder'); + +/** + * @desc [INTERNAL] Walks the traced AST and drives the WasmModuleBuilder to + * emit one wasm function per kernel/helper function. Extends the base + * FunctionNode: the type discipline (Integer/Number/LiteralInteger and the + * numeric-promotion rules) is the WGSL node's, replicated as SEMANTICS — + * every value is f32 unless the type system says Integer (i32) or Boolean + * (i32 0/1). `/` and `%` are always f32; bitwise operators are real i32 ops. + * + * The walk runs twice per function. toString() is the ANALYSIS pass over a + * NoopEmitter: it resolves types (return types, helper argument inference), + * records calledFunctions for FunctionBuilder's trace, and collects which + * math imports / Math.random the function uses — all before any module + * exists. emitFunction() is the BYTECODE pass over a real emitter; it can + * run more than once (the kernel rebuilds per size signature, offsets are + * baked) and every walk resets its own locals/depth state. + * + * Thread-dependence (for the SIMD phase's lane-divergence qualification) is + * tracked during analysis: `this.thread.x` is the lane axis, so a value is + * thread-dependent when its expression reads thread.x, draws Math.random + * (per-cell stream), calls a user function (conservative — helpers may read + * thread state internally), or reads a local previously assigned from a + * thread-dependent expression (linear-order taint, never cleared). Every + * if/ternary/loop/switch condition is recorded in `this.uniformity` with + * its thread-dependence. + */ + +// silently swallows every opcode so the analysis pass shares the emission +// walk verbatim; local indices still advance so shapes stay plausible +class NoopEmitter { + constructor() { + this.localCount = 0; + } + addLocal() { + return this.localCount++; + } +} +for (const name of Object.getOwnPropertyNames(WasmFunctionEmitter.prototype)) { + if (name === 'constructor' || name === 'addLocal') continue; + if (typeof WasmFunctionEmitter.prototype[name] !== 'function') continue; + NoopEmitter.prototype[name] = function() { + return this; + }; +} + +// Math.* with no native wasm opcode, imported as env.math_; the JS +// function computes in f64 and the (f32)->f32 import signature demotes the +// result, matching the fround() precision of the GL backends +const MATH_IMPORT_ARITY = { + sin: 1, + cos: 1, + tan: 1, + asin: 1, + acos: 1, + atan: 1, + atan2: 2, + sinh: 1, + cosh: 1, + tanh: 1, + asinh: 1, + acosh: 1, + atanh: 1, + exp: 1, + expm1: 1, + log: 1, + log2: 1, + log10: 1, + log1p: 1, + cbrt: 1, + pow: 2, + sign: 1, +}; + +// Math.* with a native f32 opcode +const MATH_NATIVE_OPS = { + abs: 'f32Abs', + floor: 'f32Floor', + ceil: 'f32Ceil', + sqrt: 'f32Sqrt', + trunc: 'f32Trunc', +}; + +const F32_ARITH = { + '+': 'f32Add', + '-': 'f32Sub', + '*': 'f32Mul', +}; +const I32_ARITH = { + '+': 'i32Add', + '-': 'i32Sub', + '*': 'i32Mul', +}; +const F32_COMPARE = { + '==': 'f32Eq', + '===': 'f32Eq', + '!=': 'f32Ne', + '!==': 'f32Ne', + '<': 'f32Lt', + '>': 'f32Gt', + '<=': 'f32Le', + '>=': 'f32Ge', +}; +const I32_COMPARE = { + '==': 'i32Eq', + '===': 'i32Eq', + '!=': 'i32Ne', + '!==': 'i32Ne', + '<': 'i32LtS', + '>': 'i32GtS', + '<=': 'i32LeS', + '>=': 'i32GeS', +}; +const BITWISE_OPS = { + '&': 'i32And', + '|': 'i32Or', + '^': 'i32Xor', + '<<': 'i32Shl', + '>>': 'i32ShrS', + '>>>': 'i32ShrU', +}; + +// f32x4/i32x4 lane ops are IEEE/two's-complement identical to their scalar +// counterparts, which is what makes run() and run_simd() bit-identical +const VF32_ARITH = { + '+': 'f32x4Add', + '-': 'f32x4Sub', + '*': 'f32x4Mul', +}; +const VI32_ARITH = { + '+': 'i32x4Add', + '-': 'i32x4Sub', + '*': 'i32x4Mul', +}; +const VF32_COMPARE = { + '==': 'f32x4Eq', + '===': 'f32x4Eq', + '!=': 'f32x4Ne', + '!==': 'f32x4Ne', + '<': 'f32x4Lt', + '>': 'f32x4Gt', + '<=': 'f32x4Le', + '>=': 'f32x4Ge', +}; +const VI32_COMPARE = { + '==': 'i32x4Eq', + '===': 'i32x4Eq', + '!=': 'i32x4Ne', + '!==': 'i32x4Ne', + '<': 'i32x4LtS', + '>': 'i32x4GtS', + '<=': 'i32x4LeS', + '>=': 'i32x4GeS', +}; +const VECTOR_SHIFT_OPS = { + '<<': 'i32x4Shl', + '>>': 'i32x4ShrS', + '>>>': 'i32x4ShrU', +}; +const VECTOR_MATH_NATIVE_OPS = { + abs: 'f32x4Abs', + floor: 'f32x4Floor', + ceil: 'f32x4Ceil', + sqrt: 'f32x4Sqrt', + trunc: 'f32x4Trunc', +}; + +function scalarWasmType(type) { + switch (type) { + case 'Number': + case 'Float': + case 'LiteralInteger': + return 'f32'; + case 'Integer': + case 'Boolean': + return 'i32'; + default: + throw new Error(`WebAssembly backend does not yet support ${ type } arguments to helper functions`); + } +} + +class WebAssemblyFunctionNode extends FunctionNode { + constructor(source, settings) { + super(source, settings); + this.assembler = null; + this.em = null; + this.locals = null; + this.depth = 0; + this.loopStack = null; + this.usedMathImports = new Set(); + this.usesRandom = false; + this.readsThread = false; + this.taintedLocals = null; + this.uniformity = []; + this._analysisDone = false; + this._analysisPass = false; + // SIMD (f32x4) emission state; vec is false for every scalar walk + this.vec = false; + this.vMaskDepth = 0; + this.vCur = -1; + this.vRetMask = -1; + this.vTerminated = false; + this.vInfo = null; + this._vBaseX = -1; + } + + // wasm function names live in their own namespace but the fn_ prefix keeps + // user names clear of 'kernel', 'run', 'pcg_random' and the math_ imports + mangleFunctionName(name) { + return `fn_${ utils.sanitizeName(name) }`; + } + + /** + * A ternary with an integer consequent but a float alternate promotes to + * float (the WGSL node's rule); the type system must agree with what + * exprConditional emits or the enclosing expression converts wrongly. + */ + getType(ast) { + if (ast && ast.type === 'ConditionalExpression') { + const consequentType = this.getType(ast.consequent); + if (consequentType === 'Integer' || consequentType === 'LiteralInteger') { + const alternateType = this.getType(ast.alternate); + if (alternateType === 'Number' || alternateType === 'Float') { + return 'Number'; + } + } + } + return super.getType(ast); + } + + /** + * FunctionBuilder drives tracing through toString(); for this backend that + * is the analysis pass — no text exists, the return value is always ''. + */ + toString() { + if (!this._analysisDone) { + this._analysisDone = true; + this._analysisPass = true; + this.walkFunction(new NoopEmitter()); + this._analysisPass = false; + } + return ''; + } + + /** + * Bytecode pass. `assembler` carries the module builder, the kernel's + * baked memory layout and the shared global indices; it changes per size + * signature, so this may run repeatedly on one node. + * @param {Object} assembler + */ + emitFunction(assembler) { + this.assembler = assembler; + const { module } = assembler; + let em; + if (this.isRootKernel) { + em = module.addFunction('kernel', { params: [], results: [] }); + } else { + const params = this.argumentTypes.map(type => scalarWasmType(type === 'LiteralInteger' ? 'Number' : type)); + const results = []; + if (this.returnType) { + switch (this.returnType) { + case 'Integer': + case 'Boolean': + results.push('i32'); + break; + case 'Number': + case 'Float': + case 'LiteralInteger': + results.push('f32'); + break; + default: + throw new Error(`WebAssembly backend does not yet support helper functions returning ${ this.returnType }`); + } + } + em = module.addFunction(this.mangleFunctionName(this.name), { params, results }); + } + this.walkFunction(em); + if (!this.isRootKernel && this.returnType) { + // a fall-off path in a result-typed function cannot validate; in JS it + // would return undefined, which no kernel contract allows either + em.unreachable(); + } + return em; + } + + walkFunction(em) { + this.em = em; + this.locals = new Map(); + this.depth = 0; + this.loopStack = []; + this.taintedLocals = new Set(); + const ast = this.getJsAST(); + if (this.isRootKernel) { + // a scalar argument the kernel assigns to gets a local copy per cell: + // JS (and the cpu backend) give every cell a fresh binding, so writing + // the shared memory slot would leak the mutation into later cells + for (const name of this.collectAssignedArgumentNames(ast)) { + const argumentIndex = this.argumentNames.indexOf(name); + const gtype = this.argumentTypes[argumentIndex]; + if (gtype !== 'Number' && gtype !== 'Float' && gtype !== 'Integer' && gtype !== 'Boolean') continue; + const slot = this.assembler ? this.assembler.layout.scalars[name] : null; + const offset = slot ? slot.offset : 0; + const wtype = gtype === 'Integer' || gtype === 'Boolean' ? 'i32' : 'f32'; + const index = em.addLocal(wtype); + em.i32Const(0); + if (wtype === 'i32') em.i32Load(offset); + else em.f32Load(offset); + em.localSet(index); + this.locals.set(name, { kind: 'scalar', index, wtype, gtype }); + } + } + if (!this.isRootKernel) { + for (let i = 0; i < this.argumentNames.length; i++) { + const name = this.argumentNames[i]; + let argumentType = this.argumentTypes[i]; + if (!argumentType) { + throw this.astErrorOutput(`Unknown argument ${ name } type`, ast); + } + if (argumentType === 'LiteralInteger') { + this.argumentTypes[i] = argumentType = 'Number'; + } + this.locals.set(name, { + kind: 'scalar', + index: i, + wtype: scalarWasmType(argumentType), + gtype: argumentType, + }); + } + if (!this.returnType) { + const lastReturn = this.findLastReturn(); + if (lastReturn) { + this.returnType = this.getType(ast.body); + if (this.returnType === 'LiteralInteger') { + this.returnType = 'Number'; + } + } + } + } + const body = ast.body.body; + for (let i = 0; i < body.length; i++) { + this.statement(body[i]); + } + } + + collectAssignedArgumentNames(ast) { + const names = new Set(); + const walk = (node) => { + if (!node || typeof node !== 'object') return; + if (Array.isArray(node)) return node.forEach(walk); + if (node.type === 'FunctionDeclaration' && node !== ast) return; + if (node.type === 'AssignmentExpression' && node.left.type === 'Identifier' && + this.argumentNames.indexOf(node.left.name) !== -1) { + names.add(node.left.name); + } + if (node.type === 'UpdateExpression' && node.argument.type === 'Identifier' && + this.argumentNames.indexOf(node.argument.name) !== -1) { + names.add(node.argument.name); + } + for (const key in node) { + if (key === 'loc' || key === 'start' || key === 'end' || key === 'parent') continue; + const child = node[key]; + if (child && typeof child === 'object') walk(child); + } + }; + walk(ast.body); + return names; + } + + // block-depth bookkeeping: br targets are recorded as the depth right + // after their construct opened, so a branch is always depth - level + enterBlock(type) { + this.em.block(type); + this.depth++; + } + enterLoop(type) { + this.em.loop(type); + this.depth++; + } + enterIf(type) { + this.em.if_(type); + this.depth++; + } + exit() { + this.em.end(); + this.depth--; + } + brTo(level) { + this.em.br(this.depth - level); + } + brIfTo(level) { + this.em.brIf(this.depth - level); + } + + get loopMax() { + return parseInt(this.loopMaxIterations, 10) || 1000; + } + + // ------------------------------------------------------------------ types + + /** + * Converts the wasm value on the stack top between categories. bool is an + * i32 constrained to 0/1, so bool→i32 is free and i32→bool renormalizes. + */ + coerce(from, to) { + if (from === to) return to; + if (from === 'void') { + throw new Error('cannot use a void expression as a value'); + } + switch (to) { + case 'f32': + this.em.f32ConvertI32S(); + return 'f32'; + case 'i32': + if (from === 'f32') this.em.i32TruncSatF32S(); + return 'i32'; + case 'bool': + if (from === 'f32') { + this.em.f32Const(0).f32Ne(); + } else { + this.em.i32Eqz().i32Eqz(); + } + return 'bool'; + default: + throw new Error(`unknown wasm value category ${ to }`); + } + } + + castLiteralToInteger(ast) { + this.pushState('casting-to-integer'); + const type = this.expression(ast); + this.popState('casting-to-integer'); + this.coerce(type, 'i32'); + return 'i32'; + } + + castLiteralToFloat(ast) { + this.pushState('casting-to-float'); + const type = this.expression(ast); + this.popState('casting-to-float'); + this.coerce(type, 'f32'); + return 'f32'; + } + + castValueToInteger(ast) { + this.pushState('casting-to-integer'); + const type = this.expression(ast); + this.popState('casting-to-integer'); + this.coerce(type, 'i32'); + return 'i32'; + } + + castValueToFloat(ast) { + this.pushState('casting-to-float'); + const type = this.expression(ast); + this.popState('casting-to-float'); + this.coerce(type, 'f32'); + return 'f32'; + } + + /** + * Emits `ast` guaranteed to leave `want` on the stack, choosing the cast + * path by the type system's verdict, like the WGSL node's per-case + * castValue/castLiteral dispatches. + */ + emitByType(ast, want) { + const type = this.getType(ast); + if (want === 'f32') { + if (type === 'Integer') return this.castValueToFloat(ast); + if (type === 'LiteralInteger') return this.castLiteralToFloat(ast); + this.coerce(this.expression(ast), 'f32'); + return 'f32'; + } + if (type === 'Number' || type === 'Float') return this.castValueToInteger(ast); + if (type === 'LiteralInteger') return this.castLiteralToInteger(ast); + this.coerce(this.expression(ast), 'i32'); + return 'i32'; + } + + /** + * JS truthiness for conditions: comparisons pass through, numbers test + * against zero. Guards short-circuit code from ever seeing a raw f32. + */ + emitCondition(ast) { + const type = this.expression(ast); + if (type === 'bool') return; + if (type === 'i32') { + this.em.i32Eqz().i32Eqz(); + return; + } + if (type === 'f32') { + this.em.f32Const(0).f32Ne(); + return; + } + throw this.astErrorOutput('cannot use a void expression as a condition', ast); + } + + // ------------------------------------------------------------- statements + + statement(ast) { + switch (ast.type) { + case 'VariableDeclaration': + return this.stmtVariableDeclaration(ast); + case 'ExpressionStatement': + return this.statementExpression(ast.expression); + case 'ReturnStatement': + return this.stmtReturn(ast); + case 'IfStatement': + return this.stmtIf(ast); + case 'ForStatement': + return this.stmtFor(ast); + case 'WhileStatement': + return this.stmtWhile(ast); + case 'DoWhileStatement': + return this.stmtDoWhile(ast); + case 'BlockStatement': { + for (let i = 0; i < ast.body.length; i++) { + this.statement(ast.body[i]); + } + return; + } + case 'BreakStatement': + return this.stmtBreak(ast); + case 'ContinueStatement': + return this.stmtContinue(ast); + case 'SwitchStatement': + return this.stmtSwitch(ast); + case 'FunctionDeclaration': + // nested helpers are separate function nodes via onNestedFunction + if (this.isChildFunction(ast)) return; + throw this.astErrorOutput('unexpected function declaration', ast); + case 'EmptyStatement': + case 'DebuggerStatement': + return; + default: + throw this.astErrorOutput(`Unknown statement type ${ ast.type }`, ast); + } + } + + statementExpression(expression) { + switch (expression.type) { + case 'AssignmentExpression': + return this.emitAssignment(expression); + case 'UpdateExpression': + this.emitUpdate(expression, true); + return; + case 'SequenceExpression': { + for (let i = 0; i < expression.expressions.length; i++) { + this.statementExpression(expression.expressions[i]); + } + return; + } + case 'Identifier': + case 'Literal': + return; // a discarded value is a no-op + default: { + const type = this.expression(expression); + if (type !== 'void') this.em.drop(); + } + } + } + + stmtVariableDeclaration(varDecNode) { + const declarations = varDecNode.declarations; + if (!declarations || !declarations[0] || !declarations[0].init) { + throw this.astErrorOutput('Unexpected expression', varDecNode); + } + for (let i = 0; i < declarations.length; i++) { + const declaration = declarations[i]; + const init = declaration.init; + const info = this.getDeclaration(declaration.id); + const actualType = this.getType(init); + const name = declaration.id.name; + + if (actualType === 'Array(2)' || actualType === 'Array(3)' || actualType === 'Array(4)') { + this.declareVecLocal(name, actualType, init, info, varDecNode); + if (this.isThreadDependent(init)) this.taintedLocals.add(name); + continue; + } + + let type = actualType; + if (type === 'LiteralInteger') { + type = info.suggestedType === 'Integer' ? 'Integer' : 'Number'; + } + if (actualType === 'Integer' && type === 'Integer') { + // int-typed initializers decay to float declarations (the WebGL + // backend's long-standing behavior; tests depend on the decay) + info.valueType = 'Number'; + this.setScalarLocal(name, 'f32', 'Number', () => this.castValueToFloat(init)); + } else { + info.valueType = type; + switch (type) { + case 'Number': + case 'Float': + this.setScalarLocal(name, 'f32', type, () => { + if (actualType === 'LiteralInteger') this.castLiteralToFloat(init); + else if (actualType === 'Integer') this.castValueToFloat(init); + else this.coerce(this.expression(init), 'f32'); + }); + break; + case 'Integer': + this.setScalarLocal(name, 'i32', 'Integer', () => { + if (actualType === 'LiteralInteger') this.castLiteralToInteger(init); + else if (actualType === 'Number' || actualType === 'Float') this.castValueToInteger(init); + else this.coerce(this.expression(init), 'i32'); + }); + break; + case 'Boolean': + this.setScalarLocal(name, 'i32', 'Boolean', () => this.emitCondition(init)); + break; + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support declaring type ${ type }`, varDecNode); + } + } + if (this.isThreadDependent(init)) this.taintedLocals.add(name); + } + } + + setScalarLocal(name, wtype, gtype, emitInit) { + let local = this.locals.get(name); + if (!local || local.kind !== 'scalar' || local.wtype !== wtype) { + local = { + kind: 'scalar', + index: this.em.addLocal(wtype), + wtype, + gtype + }; + this.locals.set(name, local); + } else { + local.gtype = gtype; + } + emitInit(); + this.em.localSet(local.index); + } + + /** + * Array(n) locals live as n consecutive f32 locals — wasm has no aggregate + * values outside memory, and these never escape the function. + */ + declareVecLocal(name, type, init, info, varDecNode) { + const n = parseInt(type.substring(6), 10); + info.valueType = type; + let local = this.locals.get(name); + if (!local || local.kind !== 'vec' || local.n !== n) { + const indices = []; + for (let c = 0; c < n; c++) indices.push(this.em.addLocal('f32')); + local = { + kind: 'vec', + indices, + n, + gtype: type + }; + this.locals.set(name, local); + } + if (init.type === 'ArrayExpression') { + for (let c = 0; c < n; c++) { + this.emitArrayElement(init.elements[c]); + this.em.localSet(local.indices[c]); + } + return; + } + if (init.type === 'Identifier') { + const source = this.locals.get(init.name); + if (source && source.kind === 'vec' && source.n === n) { + for (let c = 0; c < n; c++) { + this.em.localGet(source.indices[c]).localSet(local.indices[c]); + } + return; + } + } + throw this.astErrorOutput(`WebAssembly backend does not yet support ${ type } initializer of type ${ init.type }`, varDecNode); + } + + emitArrayElement(element) { + switch (this.getType(element)) { + case 'Integer': + this.castValueToFloat(element); + break; + case 'LiteralInteger': + this.castLiteralToFloat(element); + break; + default: + this.coerce(this.expression(element), 'f32'); + } + } + + emitAssignment(assNode) { + if (assNode.left.type !== 'Identifier') { + throw this.astErrorOutput(`WebAssembly backend does not yet support assignment to ${ assNode.left.type }`, assNode); + } + const name = assNode.left.name; + const local = this.locals.get(name); + let wtype = null; + let store = null; + if (local && local.kind === 'scalar') { + wtype = local.wtype; + store = () => this.em.localSet(local.index); + } else if (!local && this.isRootKernel && this.argumentNames.indexOf(name) !== -1) { + // scalar kernel arguments live in memory; JS allows assigning to them + const gtype = this.argumentTypes[this.argumentNames.indexOf(name)]; + const slot = this.assembler ? this.assembler.layout.scalars[name] : null; + // an array-typed argument has no scalar slot; defaulting its offset + // would emit a store into the args region's base -- a silent clobber + // of the first argument's first element + if (this.assembler && !slot) { + throw this.astErrorOutput( + `WebAssembly backend does not yet support assigning to the array argument "${ name }"`, assNode); + } + const offset = slot ? slot.offset : 0; + wtype = gtype === 'Integer' || gtype === 'Boolean' ? 'i32' : 'f32'; + this.em.i32Const(0); // store address before the value + store = () => (wtype === 'i32' ? this.em.i32Store(offset) : this.em.f32Store(offset)); + } else { + throw this.astErrorOutput(`cannot assign to "${ name }"`, assNode); + } + + if (assNode.operator === '=') { + const leftType = this.getType(assNode.left); + const rightType = this.getType(assNode.right); + if (leftType !== 'Integer' && rightType === 'Integer') { + this.castValueToFloat(assNode.right); + this.coerce('f32', wtype); + } else if (leftType !== 'Integer' && rightType === 'LiteralInteger') { + this.castLiteralToFloat(assNode.right); + this.coerce('f32', wtype); + } else if (leftType === 'Integer' && rightType === 'LiteralInteger') { + this.castLiteralToInteger(assNode.right); + this.coerce('i32', wtype); + } else if (leftType === 'Integer' && (rightType === 'Number' || rightType === 'Float')) { + this.castValueToInteger(assNode.right); + this.coerce('i32', wtype); + } else { + this.coerce(this.expression(assNode.right), wtype); + } + } else { + // `x op= y` lowers through the binary machinery as `x op y`; the + // synthetic node has no positions and the type walk never keys on it + const synthetic = { + type: 'BinaryExpression', + operator: assNode.operator.slice(0, -1), + left: assNode.left, + right: assNode.right, + }; + this.coerce(this.exprBinary(synthetic), wtype); + } + store(); + if (this.isThreadDependent(assNode.right) || (assNode.operator !== '=' && this.taintedLocals.has(name))) { + this.taintedLocals.add(name); + } + } + + emitUpdate(uNode, isStatement) { + if (uNode.argument.type !== 'Identifier') { + throw this.astErrorOutput('update expression needs a variable', uNode); + } + const local = this.locals.get(uNode.argument.name); + if (!local || local.kind !== 'scalar') { + throw this.astErrorOutput(`cannot update "${ uNode.argument.name }"`, uNode); + } + const isInt = local.wtype === 'i32'; + const one = () => (isInt ? this.em.i32Const(1) : this.em.f32Const(1)); + const op = uNode.operator === '++' ? (isInt ? 'i32Add' : 'f32Add') : (isInt ? 'i32Sub' : 'f32Sub'); + if (isStatement) { + this.em.localGet(local.index); + one(); + this.em[op]().localSet(local.index); + return 'void'; + } + if (uNode.prefix) { + this.em.localGet(local.index); + one(); + this.em[op]().localTee(local.index); + } else { + this.em.localGet(local.index).localGet(local.index); + one(); + this.em[op]().localSet(local.index); + } + return local.wtype; + } + + stmtReturn(ast) { + if (!ast.argument) { + if (this.isRootKernel) { + this.em.return_(); + return; + } + throw this.astErrorOutput('Unexpected return statement', ast); + } + this.pushState('skip-literal-correction'); + const type = this.getType(ast.argument); + this.popState('skip-literal-correction'); + if (!this.returnType) { + this.returnType = type === 'LiteralInteger' || type === 'Integer' ? 'Number' : type; + } + if (this.isRootKernel) { + return this.stmtRootReturn(ast, type); + } + if (this.isSubKernel) { + throw this.astErrorOutput('WebAssembly backend does not yet support createKernelMap', ast); + } + switch (this.returnType) { + case 'LiteralInteger': + case 'Number': + case 'Float': + if (type === 'Integer') this.castValueToFloat(ast.argument); + else if (type === 'LiteralInteger') this.castLiteralToFloat(ast.argument); + else this.coerce(this.expression(ast.argument), 'f32'); + break; + case 'Integer': + if (type === 'Float' || type === 'Number') this.castValueToInteger(ast.argument); + else if (type === 'LiteralInteger') this.castLiteralToInteger(ast.argument); + else this.coerce(this.expression(ast.argument), 'i32'); + break; + case 'Boolean': + this.emitCondition(ast.argument); + break; + default: + throw this.astErrorOutput(`unhandled return type ${ this.returnType }`, ast); + } + this.em.return_(); + } + + /** + * The root kernel stores into the output region at data_index (a shared + * global the run loop advances) and returns — the wasm-level return makes + * JS early returns exact at any nesting depth. + */ + stmtRootReturn(ast, type) { + const globals = this.assembler ? this.assembler.globals : { dataIndex: 0 }; + const outputOffset = this.assembler ? this.assembler.layout.outputOffset : 0; + switch (this.returnType) { + case 'Array(2)': + case 'Array(3)': + case 'Array(4)': { + const n = parseInt(this.returnType.substring(6), 10); + const argument = ast.argument; + if (argument.type === 'ArrayExpression') { + if (argument.elements.length !== n) { + throw this.astErrorOutput(`expected ${ n } array elements to match return type ${ this.returnType }`, ast); + } + for (let c = 0; c < n; c++) { + this.emitComponentAddress(globals.dataIndex, n, c); + this.emitArrayElement(argument.elements[c]); + this.em.f32Store(outputOffset); + } + } else if (argument.type === 'Identifier') { + const local = this.locals.get(argument.name); + if (!local || local.kind !== 'vec' || local.n !== n) { + throw this.astErrorOutput(`"${ argument.name }" is not an Array(${ n }) variable`, ast); + } + for (let c = 0; c < n; c++) { + this.emitComponentAddress(globals.dataIndex, n, c); + this.em.localGet(local.indices[c]); + this.em.f32Store(outputOffset); + } + } else { + throw this.astErrorOutput(`WebAssembly backend does not yet support returning ${ this.returnType } from a ${ argument.type }`, ast); + } + this.em.return_(); + return; + } + default: { + this.emitComponentAddress(globals.dataIndex, 1, 0); + switch (this.returnType) { + case 'Integer': + // result[data_index] = f32(i32(value)) — the WGSL node's exact + // double conversion, truncation included + if (type === 'Float' || type === 'Number') this.castValueToInteger(ast.argument); + else if (type === 'LiteralInteger') this.castLiteralToInteger(ast.argument); + else this.coerce(this.expression(ast.argument), 'i32'); + this.em.f32ConvertI32S(); + break; + case 'LiteralInteger': + case 'Number': + case 'Float': + if (type === 'Integer') this.castValueToFloat(ast.argument); + else if (type === 'LiteralInteger') this.castLiteralToFloat(ast.argument); + else this.coerce(this.expression(ast.argument), 'f32'); + break; + case 'Boolean': + this.emitCondition(ast.argument); + this.em.f32ConvertI32S(); + break; + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support returning ${ this.returnType }`, ast); + } + this.em.f32Store(outputOffset); + this.em.return_(); + } + } + } + + emitComponentAddress(dataIndexGlobal, componentCount, component) { + this.em.globalGet(dataIndexGlobal); + if (componentCount !== 1) { + this.em.i32Const(componentCount).i32Mul(); + if (component !== 0) this.em.i32Const(component).i32Add(); + } + this.em.i32Const(2).i32Shl(); + } + + stmtIf(ifNode) { + this.recordUniformity('if', ifNode.test); + this.emitCondition(ifNode.test); + this.enterIf(); + this.statement(ifNode.consequent); + if (ifNode.alternate) { + this.em.else_(); + this.statement(ifNode.alternate); + } + this.exit(); + } + + /** + * Safe loops (literal-init counter, safe test — the WGSL node's exact + * criteria) run unbounded; everything else is capped at loopMaxIterations + * like the GL backends' LOOP_MAX. The continue target sits BEFORE the + * update clause, so `continue` still advances the counter. + */ + /** + * The WGSL node's exact safe-loop criteria: literal-init single declarator, + * safe test and init, both test and update present. Shared with the SIMD + * walk so the LOOP_MAX cap fires identically on both paths. + */ + forLoopIsSafe(forNode) { + let isSafe = null; + if (forNode.init) { + const declarations = forNode.init.declarations; + if (declarations) { + if (declarations.length > 1) isSafe = false; + for (let i = 0; i < declarations.length; i++) { + if (declarations[i].init && declarations[i].init.type !== 'Literal') isSafe = false; + } + } else { + isSafe = false; + } + } else { + isSafe = false; + } + if (!forNode.test || !forNode.update) isSafe = false; + if (isSafe === null) { + isSafe = this.isSafe(forNode.init) && this.isSafe(forNode.test); + } + return isSafe; + } + + stmtFor(forNode) { + if (forNode.type !== 'ForStatement') { + throw this.astErrorOutput('Invalid for statement', forNode); + } + const isSafe = this.forLoopIsSafe(forNode); + this.recordUniformity('for', forNode.test || null); + + if (forNode.init) { + if (forNode.init.type === 'VariableDeclaration') this.stmtVariableDeclaration(forNode.init); + else this.statementExpression(forNode.init); + } + let safeI = -1; + if (!isSafe) { + safeI = this.em.addLocal('i32'); + this.em.i32Const(0).localSet(safeI); + } + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + if (!isSafe) { + this.em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + } + if (forNode.test) { + this.emitCondition(forNode.test); + this.em.i32Eqz(); + this.brIfTo(breakLevel); + } + this.enterBlock(); + const continueLevel = this.depth; + this.loopStack.push({ breakLevel, continueLevel }); + if (forNode.body) this.statement(forNode.body); + this.loopStack.pop(); + this.exit(); + if (forNode.update) this.statementExpression(forNode.update); + if (!isSafe) { + this.em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + } + this.brTo(loopLevel); + this.exit(); + this.exit(); + } + + stmtWhile(whileNode) { + if (whileNode.type !== 'WhileStatement') { + throw this.astErrorOutput('Invalid while statement', whileNode); + } + this.recordUniformity('while', whileNode.test); + const safeI = this.em.addLocal('i32'); + this.em.i32Const(0).localSet(safeI); + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + this.em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + this.emitCondition(whileNode.test); + this.em.i32Eqz(); + this.brIfTo(breakLevel); + this.enterBlock(); + const continueLevel = this.depth; + this.loopStack.push({ breakLevel, continueLevel }); + this.statement(whileNode.body); + this.loopStack.pop(); + this.exit(); + this.em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + } + + stmtDoWhile(doWhileNode) { + if (doWhileNode.type !== 'DoWhileStatement') { + throw this.astErrorOutput('Invalid while statement', doWhileNode); + } + this.recordUniformity('do-while', doWhileNode.test); + const safeI = this.em.addLocal('i32'); + this.em.i32Const(0).localSet(safeI); + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + this.em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + this.enterBlock(); + // JS continue in do-while jumps to the test, which sits after the body + const continueLevel = this.depth; + this.loopStack.push({ breakLevel, continueLevel }); + this.statement(doWhileNode.body); + this.loopStack.pop(); + this.exit(); + this.em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.emitCondition(doWhileNode.test); + this.brIfTo(loopLevel); + this.exit(); + this.exit(); + } + + stmtBreak(brNode) { + const target = this.loopStack[this.loopStack.length - 1]; + if (!target) { + throw this.astErrorOutput('break used outside of a loop', brNode); + } + this.brTo(target.breakLevel); + } + + stmtContinue(crNode) { + const target = this.loopStack[this.loopStack.length - 1]; + if (!target) { + throw this.astErrorOutput('continue used outside of a loop', crNode); + } + this.brTo(target.continueLevel); + } + + /** + * The switch lowers to an if/else chain on a discriminant local, exactly + * like the WGSL node: a case-terminating break is consumed, empty cases + * fall through by OR-ing their tests into the next case, a non-final + * default moves to the chain's end. + */ + stmtSwitch(ast) { + if (ast.type !== 'SwitchStatement') { + throw this.astErrorOutput('Invalid switch statement', ast); + } + const { discriminant, cases } = ast; + const type = this.getType(discriminant); + this.recordUniformity('switch', discriminant); + let dLocal; + let dIsInt; + switch (type) { + case 'Float': + case 'Number': + dIsInt = false; + dLocal = this.em.addLocal('f32'); + this.coerce(this.expression(discriminant), 'f32'); + this.em.localSet(dLocal); + break; + case 'Integer': + dIsInt = true; + dLocal = this.em.addLocal('i32'); + this.coerce(this.expression(discriminant), 'i32'); + this.em.localSet(dLocal); + break; + default: + throw this.astErrorOutput(`Unhandled switch discriminant type "${ type }"`, ast); + } + if (cases.length === 1 && !cases[0].test) { + this.emitSwitchConsequent(cases[0].consequent); + return; + } + const { groups, defaultConsequent } = this.collectSwitchGroups(cases); + const emitChain = (index) => { + if (index === groups.length) { + if (defaultConsequent) this.emitSwitchConsequent(defaultConsequent); + return false; + } + const { tests, consequent } = groups[index]; + for (let i = 0; i < tests.length; i++) { + this.em.localGet(dLocal); + this.emitSwitchTest(tests[i], dIsInt); + if (dIsInt) this.em.i32Eq(); + else this.em.f32Eq(); + if (i > 0) this.em.i32Or(); + } + this.enterIf(); + this.emitSwitchConsequent(consequent); + const hasMore = index + 1 < groups.length || defaultConsequent; + if (hasMore) { + this.em.else_(); + emitChain(index + 1); + } + this.exit(); + return true; + }; + emitChain(0); + } + + emitSwitchTest(test, dIsInt) { + const testType = this.getType(test); + if (dIsInt) { + if (testType === 'Number' || testType === 'Float') this.castValueToInteger(test); + else if (testType === 'LiteralInteger') this.castLiteralToInteger(test); + else this.coerce(this.expression(test), 'i32'); + } else { + if (testType === 'LiteralInteger') this.castLiteralToFloat(test); + else if (testType === 'Integer') this.castValueToFloat(test); + else this.coerce(this.expression(test), 'f32'); + } + } + + /** + * Fallthrough-empty-case grouping shared between the scalar and SIMD + * lowering: empty cases OR their tests into the next non-empty case, a + * non-final default moves to the chain's end. + */ + collectSwitchGroups(cases) { + let defaultConsequent = null; + const groups = []; + let pendingTests = []; + for (let i = 0; i < cases.length; i++) { + if (!cases[i].test) { + defaultConsequent = cases[i].consequent; + continue; + } + pendingTests.push(cases[i].test); + if (cases[i].consequent && cases[i].consequent.length > 0) { + groups.push({ tests: pendingTests, consequent: cases[i].consequent }); + pendingTests = []; + } + } + return { groups, defaultConsequent }; + } + + collectSwitchCaseStatements(consequent) { + const statements = []; + for (let i = 0; i < consequent.length; i++) { + if (consequent[i].type === 'BreakStatement') break; + statements.push(consequent[i]); + } + // a break deeper inside a case would emit as a loop break; same guard as + // the WGSL and GL backends + const containsBreak = (node) => { + if (!node || typeof node !== 'object') return false; + if (Array.isArray(node)) return node.some(containsBreak); + if (node.type === 'BreakStatement') return true; + if ( + node.type === 'ForStatement' || + node.type === 'WhileStatement' || + node.type === 'DoWhileStatement' || + node.type === 'SwitchStatement' + ) { + return false; + } + for (const key in node) { + if (key === 'loc' || key === 'range' || key === 'parent') continue; + if (containsBreak(node[key])) return true; + } + return false; + }; + for (let i = 0; i < statements.length; i++) { + if (containsBreak(statements[i])) { + throw this.astErrorOutput('break inside a switch case is only supported as the case terminator', statements[i]); + } + } + return statements; + } + + emitSwitchConsequent(consequent) { + const statements = this.collectSwitchCaseStatements(consequent); + for (let i = 0; i < statements.length; i++) { + this.statement(statements[i]); + } + } + + // ------------------------------------------------------------ expressions + + /** + * Emits `ast`, leaving exactly one value on the stack; returns its wasm + * category: 'f32' | 'i32' | 'bool' (i32 0/1) | 'void'. + */ + expression(ast) { + switch (ast.type) { + case 'Literal': + return this.exprLiteral(ast); + case 'Identifier': + return this.exprIdentifier(ast); + case 'BinaryExpression': + return this.exprBinary(ast); + case 'LogicalExpression': + return this.exprLogical(ast); + case 'UnaryExpression': + return this.exprUnary(ast); + case 'UpdateExpression': + return this.emitUpdate(ast, false); + case 'ConditionalExpression': + return this.exprConditional(ast); + case 'CallExpression': + return this.exprCall(ast); + case 'MemberExpression': + return this.exprMember(ast); + case 'ThisExpression': + throw this.astErrorOutput('unexpected bare `this`', ast); + case 'SequenceExpression': { + if (ast.expressions.length === 1) return this.expression(ast.expressions[0]); + throw this.astErrorOutput('WebAssembly backend does not yet support the comma operator', ast); + } + case 'AssignmentExpression': + throw this.astErrorOutput('WebAssembly backend does not yet support assignment used as an expression', ast); + case 'ArrayExpression': + throw this.astErrorOutput('array literals are only supported as variable initializers and kernel returns', ast); + default: + throw this.astErrorOutput(`Unknown expression type ${ ast.type }`, ast); + } + } + + exprLiteral(ast) { + if (ast.value === true || ast.value === false) { + this.em.i32Const(ast.value ? 1 : 0); + return 'bool'; + } + if (isNaN(ast.value)) { + throw this.astErrorOutput('Non-numeric literal not supported : ' + ast.value, ast); + } + const key = this.astKey(ast); + if (this.isState('casting-to-integer') || this.isState('building-integer')) { + // the vector walk re-visits every literal after the scalar walk froze + // its type; recording again could flip a type between the two walks + // and break scalar/SIMD bit-identity on the next rebuild + if (!this.vec) this.literalTypes[key] = 'Integer'; + this.em.i32Const(Math.round(ast.value)); + return 'i32'; + } + if (!this.vec) this.literalTypes[key] = 'Number'; + this.em.f32Const(ast.value); + return 'f32'; + } + + exprIdentifier(idtNode) { + if (idtNode.type !== 'Identifier') { + throw this.astErrorOutput('IdentifierExpression - not an Identifier', idtNode); + } + if (idtNode.name === 'Infinity') { + this.em.f32Const(Infinity); + return 'f32'; + } + const local = this.locals.get(idtNode.name); + if (local) { + if (local.kind === 'vec') { + throw this.astErrorOutput(`array-valued variable "${ idtNode.name }" can only be indexed or returned`, idtNode); + } + this.em.localGet(local.index); + return local.gtype === 'Boolean' ? 'bool' : local.wtype; + } + const argumentIndex = this.argumentNames.indexOf(idtNode.name); + if (argumentIndex !== -1 && this.isRootKernel) { + const type = this.argumentTypes[argumentIndex]; + const slot = this.assembler ? this.assembler.layout.scalars[idtNode.name] : null; + const offset = slot ? slot.offset : 0; + this.em.i32Const(0); + switch (type) { + case 'Integer': + this.em.i32Load(offset); + return 'i32'; + case 'Boolean': + this.em.i32Load(offset); + return 'bool'; + case 'Number': + case 'Float': + this.em.f32Load(offset); + return 'f32'; + default: + throw this.astErrorOutput(`argument "${ idtNode.name }" of type ${ type } cannot be read as a scalar`, idtNode); + } + } + throw this.astErrorOutput(`Unhandled identifier "${ idtNode.name }"`, idtNode); + } + + exprBinary(ast) { + const operator = ast.operator; + + if (operator === '**') { + // JS Math.pow semantics exactly (pow(x, 0) === 1 for all x) + this.emitByType(ast.left, 'f32'); + this.emitByType(ast.right, 'f32'); + this.usedMathImports.add('pow'); + this.em.call('math_pow'); + return 'f32'; + } + + if (BITWISE_OPS[operator]) { + this.emitAsIntegerOperand(ast.left); + this.emitAsIntegerOperand(ast.right); + this.em[BITWISE_OPS[operator]](); + return 'i32'; + } + + // `/` and `%` are always fractional in JavaScript, whatever the operand + // types (base getType agrees); `%` is JS-truncated: a - trunc(a/b)*b + if (operator === '/' || operator === '%') { + if (operator === '/') { + this.emitByType(ast.left, 'f32'); + this.emitByType(ast.right, 'f32'); + this.em.f32Div(); + return 'f32'; + } + const a = this.em.addLocal('f32'); + const b = this.em.addLocal('f32'); + this.emitByType(ast.left, 'f32'); + this.em.localSet(a); + this.emitByType(ast.right, 'f32'); + this.em.localSet(b); + this.em.localGet(a).localGet(a).localGet(b).f32Div().f32Trunc().localGet(b).f32Mul().f32Sub(); + return 'f32'; + } + + const leftType = this.getType(ast.left) || 'Number'; + const rightType = this.getType(ast.right) || 'Number'; + const key = leftType + ' & ' + rightType; + let category; + switch (key) { + case 'Integer & Integer': + this.pushState('building-integer'); + this.coerce(this.expression(ast.left), 'i32'); + this.coerce(this.expression(ast.right), 'i32'); + this.popState('building-integer'); + category = 'i32'; + break; + case 'Number & Float': + case 'Float & Number': + case 'Float & Float': + case 'Number & Number': + this.pushState('building-float'); + this.coerce(this.expression(ast.left), 'f32'); + this.coerce(this.expression(ast.right), 'f32'); + this.popState('building-float'); + category = 'f32'; + break; + case 'LiteralInteger & LiteralInteger': + if (this.isState('casting-to-integer') || this.isState('building-integer')) { + this.pushState('building-integer'); + this.coerce(this.expression(ast.left), 'i32'); + this.coerce(this.expression(ast.right), 'i32'); + this.popState('building-integer'); + category = 'i32'; + } else { + this.pushState('building-float'); + this.castLiteralToFloat(ast.left); + this.castLiteralToFloat(ast.right); + this.popState('building-float'); + category = 'f32'; + } + break; + case 'Integer & Float': + case 'Integer & Number': + // JavaScript promotes an integer combined with a fractional value to + // fractional, whichever side the integer is on — `x * 0.5` must + // agree with `0.5 * x` + this.pushState('building-float'); + this.castValueToFloat(ast.left); + this.coerce(this.expression(ast.right), 'f32'); + this.popState('building-float'); + category = 'f32'; + break; + case 'Integer & LiteralInteger': + this.pushState('building-integer'); + this.coerce(this.expression(ast.left), 'i32'); + this.castLiteralToInteger(ast.right); + this.popState('building-integer'); + category = 'i32'; + break; + case 'Number & Integer': + case 'Float & Integer': + this.pushState('building-float'); + this.coerce(this.expression(ast.left), 'f32'); + this.castValueToFloat(ast.right); + this.popState('building-float'); + category = 'f32'; + break; + case 'Float & LiteralInteger': + case 'Number & LiteralInteger': + this.pushState('building-float'); + this.coerce(this.expression(ast.left), 'f32'); + this.castLiteralToFloat(ast.right); + this.popState('building-float'); + category = 'f32'; + break; + case 'LiteralInteger & Float': + case 'LiteralInteger & Number': + if (this.isState('casting-to-integer')) { + this.pushState('building-integer'); + this.castLiteralToInteger(ast.left); + this.castValueToInteger(ast.right); + this.popState('building-integer'); + category = 'i32'; + } else { + this.pushState('building-float'); + this.castLiteralToFloat(ast.left); + this.pushState('casting-to-float'); + this.coerce(this.expression(ast.right), 'f32'); + this.popState('casting-to-float'); + this.popState('building-float'); + category = 'f32'; + } + break; + case 'LiteralInteger & Integer': + this.pushState('building-integer'); + this.castLiteralToInteger(ast.left); + this.coerce(this.expression(ast.right), 'i32'); + this.popState('building-integer'); + category = 'i32'; + break; + case 'Boolean & Boolean': + this.coerce(this.expression(ast.left), 'i32'); + this.coerce(this.expression(ast.right), 'i32'); + category = 'i32'; + break; + default: + throw this.astErrorOutput(`Unhandled binary expression between ${ key }`, ast); + } + + const compareOp = category === 'i32' ? I32_COMPARE[operator] : F32_COMPARE[operator]; + if (compareOp) { + this.em[compareOp](); + return 'bool'; + } + const arithOp = category === 'i32' ? I32_ARITH[operator] : F32_ARITH[operator]; + if (!arithOp) { + throw this.astErrorOutput(`Unhandled operator ${ operator }`, ast); + } + this.em[arithOp](); + return category; + } + + emitAsIntegerOperand(side) { + switch (this.getType(side)) { + case 'Number': + case 'Float': + this.castValueToInteger(side); + break; + case 'LiteralInteger': + this.castLiteralToInteger(side); + break; + default: { + this.pushState('building-integer'); + const type = this.expression(side); + this.popState('building-integer'); + this.coerce(type, 'i32'); + } + } + } + + /** + * Short-circuit is load-bearing, not an optimization: the right side may + * guard an out-of-range memory read (`x > 0 && a[x - 1] > 0`). + */ + exprLogical(logNode) { + this.emitCondition(logNode.left); + this.enterIf('i32'); + if (logNode.operator === '&&') { + this.emitCondition(logNode.right); + this.em.else_(); + this.em.i32Const(0); + } else if (logNode.operator === '||') { + this.em.i32Const(1); + this.em.else_(); + this.emitCondition(logNode.right); + } else { + throw this.astErrorOutput(`Unhandled logical operator ${ logNode.operator }`, logNode); + } + this.exit(); + return 'bool'; + } + + exprUnary(uNode) { + switch (uNode.operator) { + case '~': + this.emitAsIntegerOperand(uNode.argument); + this.em.i32Const(-1).i32Xor(); + return 'i32'; + case '!': + this.emitCondition(uNode.argument); + this.em.i32Eqz(); + return 'bool'; + case '+': + return this.expression(uNode.argument); + case '-': { + const type = this.getType(uNode.argument); + const wantsInteger = type === 'Integer' || + (type === 'LiteralInteger' && (this.isState('casting-to-integer') || this.isState('building-integer'))); + if (wantsInteger) { + this.em.i32Const(0); + this.emitByType(uNode.argument, 'i32'); + this.em.i32Sub(); + return 'i32'; + } + this.emitByType(uNode.argument, 'f32'); + this.em.f32Neg(); + return 'f32'; + } + default: + throw this.astErrorOutput(`Unhandled unary operator ${ uNode.operator }`, uNode); + } + } + + exprConditional(ast) { + if (ast.type !== 'ConditionalExpression') { + throw this.astErrorOutput('Not a conditional expression', ast); + } + const consequentType = this.getType(ast.consequent); + const alternateType = this.getType(ast.alternate); + this.recordUniformity('ternary', ast.test); + if (consequentType === null && alternateType === null) { + this.emitCondition(ast.test); + this.enterIf(); + this.statementExpression(ast.consequent); + this.em.else_(); + this.statementExpression(ast.alternate); + this.exit(); + return 'void'; + } + // the consequent's type wins; mixed int/float branches promote to float + // — getType's ConditionalExpression override reports the same promotion + let targetType = consequentType === 'LiteralInteger' ? 'Number' : consequentType; + if (targetType === 'Integer' && (alternateType === 'Number' || alternateType === 'Float')) { + targetType = 'Number'; + } + const wtype = targetType === 'Integer' || targetType === 'Boolean' ? 'i32' : 'f32'; + const emitBranch = (branch) => { + const branchType = this.getType(branch); + switch (targetType) { + case 'Number': + case 'Float': + if (branchType === 'Integer') this.castValueToFloat(branch); + else if (branchType === 'LiteralInteger') this.castLiteralToFloat(branch); + else this.coerce(this.expression(branch), 'f32'); + break; + case 'Integer': + if (branchType === 'Number' || branchType === 'Float') this.castValueToInteger(branch); + else if (branchType === 'LiteralInteger') this.castLiteralToInteger(branch); + else this.coerce(this.expression(branch), 'i32'); + break; + case 'Boolean': + this.emitCondition(branch); + break; + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support a ternary of type ${ targetType }`, ast); + } + }; + this.emitCondition(ast.test); + this.enterIf(wtype); + emitBranch(ast.consequent); + this.em.else_(); + emitBranch(ast.alternate); + this.exit(); + return targetType === 'Boolean' ? 'bool' : wtype; + } + + exprCall(ast) { + if (!ast.callee) { + throw this.astErrorOutput('Unknown CallExpression', ast); + } + if (ast.callee.type === 'MemberExpression' && this.getVariableSignature(ast.callee, true) === 'this.color') { + throw this.astErrorOutput('WebAssembly backend does not yet support graphical mode (this.color)', ast); + } + + let functionName = null; + const isMathFunction = this.isAstMathFunction(ast); + if (isMathFunction || (ast.callee.object && ast.callee.object.type === 'ThisExpression')) { + functionName = ast.callee.property.name; + } else if ( + ast.callee.type === 'SequenceExpression' && + ast.callee.expressions[0].type === 'Literal' && + !isNaN(ast.callee.expressions[0].raw) + ) { + functionName = ast.callee.expressions[1].property.name; + } else { + functionName = ast.callee.name; + } + if (!functionName) { + throw this.astErrorOutput(`Unhandled function, couldn't find name`, ast); + } + + if (this.calledFunctions.indexOf(functionName) < 0) { + this.calledFunctions.push(functionName); + } + if (this.onFunctionCall) { + this.onFunctionCall(this.name, functionName, ast.arguments); + } + + if (isMathFunction) { + return this.emitMathCall(functionName, ast); + } + + // resolves (and caches) the callee's return type; also runs argument + // type inference so lookupFunctionArgumentTypes below is populated + const returnType = this.getType(ast); + + const targetTypes = this.lookupFunctionArgumentTypes(functionName) || []; + for (let i = 0; i < ast.arguments.length; ++i) { + const argument = ast.arguments[i]; + let targetType = targetTypes[i]; + const argumentType = this.getType(argument); + if (!targetType) { + this.triggerImplyArgumentType(functionName, i, argumentType, this); + targetType = argumentType; + } + switch (argumentType) { + case 'Boolean': + this.coerce(this.expression(argument), 'i32'); + continue; + case 'Number': + case 'Float': + if (targetType === 'Integer') { + this.castValueToInteger(argument); + continue; + } else if (targetType === 'Number' || targetType === 'Float' || targetType === 'LiteralInteger') { + this.coerce(this.expression(argument), 'f32'); + continue; + } + break; + case 'Integer': + if (targetType === 'Number' || targetType === 'Float') { + this.castValueToFloat(argument); + continue; + } else if (targetType === 'Integer') { + this.coerce(this.expression(argument), 'i32'); + continue; + } + break; + case 'LiteralInteger': + if (targetType === 'Integer') { + this.castLiteralToInteger(argument); + continue; + } else if (targetType === 'Number' || targetType === 'Float' || targetType === 'LiteralInteger') { + this.castLiteralToFloat(argument); + continue; + } + break; + case 'Array(2)': + case 'Array(3)': + case 'Array(4)': + case 'Array': + case 'Array2D': + case 'Array3D': + case 'Input': + throw this.astErrorOutput('WebAssembly backend does not yet support array arguments to helper functions', ast); + } + throw this.astErrorOutput(`Unhandled argument combination of ${ argumentType } and ${ targetType } for argument named "${ argument.name }"`, ast); + } + this.em.call(this.mangleFunctionName(functionName)); + switch (returnType) { + case null: + case undefined: + return 'void'; + case 'Integer': + return 'i32'; + case 'Boolean': + return 'bool'; + default: + return 'f32'; + } + } + + /** + * Math.* calls compute in f32; native wasm opcodes where they exist, + * imports only for what the module actually uses (the kernel scans + * usedMathImports after analysis). All arguments go through the float + * ladder, matching the WGSL node's math-call casting. + */ + emitMathCall(functionName, ast) { + if (functionName === 'random') { + this.usesRandom = true; + this.em.call('pcg_random'); + return 'f32'; + } + const emitMathArg = (argument) => { + switch (this.getType(argument)) { + case 'Integer': + this.castValueToFloat(argument); + break; + case 'LiteralInteger': + this.castLiteralToFloat(argument); + break; + default: + this.coerce(this.expression(argument), 'f32'); + } + }; + const nativeOp = MATH_NATIVE_OPS[functionName]; + if (nativeOp) { + emitMathArg(ast.arguments[0]); + this.em[nativeOp](); + return 'f32'; + } + switch (functionName) { + case 'round': + // JS rounds half UP; f32.nearest rounds half to even + emitMathArg(ast.arguments[0]); + this.em.f32Const(0.5).f32Add().f32Floor(); + return 'f32'; + case 'fround': + // everything here is already f32 + emitMathArg(ast.arguments[0]); + return 'f32'; + case 'min': + case 'max': { + const op = functionName === 'min' ? 'f32Min' : 'f32Max'; + emitMathArg(ast.arguments[0]); + for (let i = 1; i < ast.arguments.length; i++) { + emitMathArg(ast.arguments[i]); + this.em[op](); + } + return 'f32'; + } + case 'imul': + emitMathArg(ast.arguments[0]); + this.em.i32TruncSatF32S(); + emitMathArg(ast.arguments[1]); + this.em.i32TruncSatF32S(); + this.em.i32Mul().f32ConvertI32S(); + return 'f32'; + case 'clz32': + emitMathArg(ast.arguments[0]); + this.em.i32TruncSatF32U().i32Clz().f32ConvertI32S(); + return 'f32'; + default: { + const arity = MATH_IMPORT_ARITY[functionName]; + if (!arity) { + throw this.astErrorOutput(`WebAssembly backend does not yet support Math.${ functionName }`, ast); + } + for (let i = 0; i < arity; i++) { + emitMathArg(ast.arguments[i]); + } + this.usedMathImports.add(functionName); + this.em.call('math_' + functionName); + return 'f32'; + } + } + } + + exprMember(mNode) { + const details = this.getMemberExpressionDetails(mNode); + if (!details) { + throw this.astErrorOutput('Unexpected expression', mNode); + } + const { signature, name, origin, type, property, xProperty, yProperty, zProperty } = details; + switch (signature) { + case 'value.thread.value': + case 'this.thread.value': { + if (name !== 'x' && name !== 'y' && name !== 'z') { + throw this.astErrorOutput('Unexpected expression, expected `this.thread.x`, `this.thread.y`, or `this.thread.z`', mNode); + } + this.readsThread = true; + const globals = this.assembler ? this.assembler.globals : null; + this.em.globalGet(globals ? globals['thread' + name.toUpperCase()] : 0); + return 'i32'; + } + case 'this.output.value': { + const axisIndex = { x: 0, y: 1, z: 2 } [name]; + if (axisIndex === undefined) { + throw this.astErrorOutput('Unexpected expression', mNode); + } + // output dims bake in even with dynamicOutput: the kernel rebuilds + // the module per size signature + const value = this.output[axisIndex]; + if (this.isState('casting-to-float')) { + this.em.f32Const(value); + return 'f32'; + } + this.em.i32Const(value); + return 'i32'; + } + case 'value.value': { + if (origin === 'Math') { + this.em.f32Const(Math[name]); + return 'f32'; + } + const component = { r: 0, g: 1, b: 2, a: 3 } [property]; + if (component !== undefined) { + const local = this.locals.get(name); + if (local && local.kind === 'vec' && component < local.n) { + this.em.localGet(local.indices[component]); + return 'f32'; + } + } + throw this.astErrorOutput('Unexpected expression', mNode); + } + case 'this.constants.value': { + // constants are fixed at build; scalars bake straight into the code + const value = this.constants[name]; + switch (type) { + case 'Integer': + if (this.isState('casting-to-float')) { + this.em.f32Const(value); + return 'f32'; + } + this.em.i32Const(Math.round(value)); + return 'i32'; + case 'Number': + case 'Float': + if (this.isState('casting-to-integer')) { + this.em.i32Const(Math.round(value)); + return 'i32'; + } + this.em.f32Const(value); + return 'f32'; + case 'Boolean': + this.em.i32Const(value ? 1 : 0); + return 'bool'; + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support constant type ${ type }`, mNode); + } + } + case 'value[]': + case 'value[][]': + case 'value[][][]': + case 'value[][][][]': { + const local = this.locals.get(name); + if (local && local.kind === 'vec') { + if (signature !== 'value[]') { + throw this.astErrorOutput('Unexpected expression', mNode); + } + return this.emitVecIndex(local, xProperty); + } + return this.emitFlatLoad('arrays', name, xProperty, yProperty, zProperty, mNode); + } + case 'this.constants.value[]': + case 'this.constants.value[][]': + case 'this.constants.value[][][]': + case 'this.constants.value[][][][]': + return this.emitFlatLoad('constantArrays', name, xProperty, yProperty, zProperty, mNode); + case 'fn()[]': + throw this.astErrorOutput('WebAssembly backend does not yet support indexing a function call result', mNode); + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support expression signature "${ signature }"`, mNode); + } + } + + /** + * Flat row-major load, index = x + sizeX * (y + sizeY * z) — the same + * formula as the GL path's get32 and web-gpu's get_user_X, with missing + * y/z as zero. Dims and the region offset are baked; the kernel rebuilds + * per size signature. + */ + emitFlatLoad(table, name, xProperty, yProperty, zProperty, mNode) { + let layout; + if (this.assembler) { + layout = this.assembler.layout[table][name]; + if (!layout) { + throw this.astErrorOutput(`no memory layout for "${ name }" — arrays are only readable as kernel arguments or constants`, mNode); + } + } else { + layout = { offset: 0, dims: [1, 1, 1] }; + } + this.emitIndex(xProperty); + if (yProperty) { + this.emitIndex(yProperty); + this.em.i32Const(layout.dims[0]).i32Mul().i32Add(); + } + if (zProperty) { + this.emitIndex(zProperty); + this.em.i32Const(layout.dims[0] * layout.dims[1]).i32Mul().i32Add(); + } + if (this.vec && this.vMaskDepth > 0) { + // predicated SIMD code evaluates both sides of a divergent branch, so + // a uniform index that the branch condition was guarding can be wild + // for the not-taken lanes; clamping keeps the load from trapping while + // leaving every in-bounds (contract-conforming) index untouched + this.emitClampScalarIndex(layout.dims[0] * layout.dims[1] * layout.dims[2] - 1); + } + this.em.i32Const(2).i32Shl(); + this.em.f32Load(layout.offset); + return 'f32'; + } + + /** + * Clamps the i32 index on the stack top into [0, max]. i32 has no native + * min/max, so two selects. + */ + emitClampScalarIndex(max) { + const t = this.em.addLocal('i32'); + this.em.localSet(t); + this.em.localGet(t).i32Const(0).localGet(t).i32Const(0).i32GeS().select(); + this.em.localSet(t); + this.em.localGet(t).i32Const(max).localGet(t).i32Const(max).i32LeS().select(); + } + + emitVecIndex(local, xProperty) { + if (xProperty.type === 'Literal' && Number.isInteger(xProperty.value)) { + if (xProperty.value < 0 || xProperty.value >= local.n) { + throw this.astErrorOutput(`index ${ xProperty.value } out of range for Array(${ local.n })`, xProperty); + } + this.em.localGet(local.indices[xProperty.value]); + return 'f32'; + } + // no dynamic indexing into locals in wasm: a select chain, keyed off a + // scratch copy of the index + const idx = this.em.addLocal('i32'); + this.emitIndex(xProperty); + this.em.localSet(idx); + this.em.localGet(local.indices[0]); + for (let k = 1; k < local.n; k++) { + this.em.localGet(local.indices[k]); + this.em.localGet(idx).i32Const(k).i32Ne(); + this.em.select(); + } + return 'f32'; + } + + emitIndex(property) { + if (!property) { + throw new Error('Property not set'); + } + const type = this.getType(property); + switch (type) { + case 'Number': + case 'Float': + this.castValueToInteger(property); + return; + case 'LiteralInteger': + this.castLiteralToInteger(property); + return; + case 'Integer': { + // Integer-typed expressions can still land as f32 (Math.floor is + // 'Integer' to the type system but computes in f32); always coerce + this.pushState('building-integer'); + const emitted = this.expression(property); + this.popState('building-integer'); + this.coerce(emitted, 'i32'); + return; + } + default: + this.coerce(this.expression(property), 'i32'); + } + } + + // -------------------------------------------------- SIMD (f32x4) emission + // + // The vector walk emits `kernel_simd`, one call = 4 consecutive x cells + // (thread.x = base + [0,1,2,3]; y/z uniform per quad — the run_simd caller + // never lets a quad cross an x-row). Divergent control flow VECTORIZES via + // mask predication: + // - values are uniform (one scalar wasm value shared by all lanes, emitted + // by the untouched scalar walk) or varying (one v128); vAnalyze decides + // per local before emission, so no mid-function repromotion exists + // - a varying if evaluates BOTH branches; every store while a branch mask + // is live goes through v128.bitselect, which blends exact bit patterns — + // predication cannot perturb IEEE results + // - varying-trip loops run while v128.any_true(live); break ORs the + // current mask into a per-loop retire mask, continue into a per- + // iteration one, early return into a function-level one plus a masked + // output store; masks are monotone accumulators, so `saved & ~each` + // reconstructs the live mask after any construct + // - transcendentals, variable-count shifts, clz and user helper calls + // lane-scalarize through the exact scalar opcodes/imports; helpers stay + // scalar functions, with thread.x and PCG state swapped per lane + // No masking bailout shapes were needed: every construct of the supported + // kernel language lowers through the model above. + + /** + * Bytecode pass for `kernel_simd`. Root kernel only; may run once per size + * signature like emitFunction. + */ + emitVectorFunction(assembler) { + if (!this.isRootKernel) { + throw new Error('only the root kernel is vectorized; helpers are lane-scalarized at call sites'); + } + this.assembler = assembler; + const em = assembler.module.addFunction('kernel_simd', { params: [], results: [] }); + this.em = em; + this.vec = true; + try { + this.locals = new Map(); + this.depth = 0; + this.loopStack = []; + this.vLoopStack = []; + this.taintedLocals = new Set(); + const ast = this.getJsAST(); + if (!this.vInfo) this.vInfo = this.vAnalyze(ast); + this.vMaskDepth = 0; + this.vTerminated = false; + this.vCur = em.addLocal('v128'); + em.v128ConstI32x4(-1, -1, -1, -1).localSet(this.vCur); + this.vRetMask = this.vInfo.varyingReturn ? em.addLocal('v128') : -1; // locals zero-init + this._vBaseX = -1; + if (assembler.helperInfo) { + this._vBaseX = em.addLocal('i32'); + em.globalGet(assembler.globals.threadX).localSet(this._vBaseX); + } + // a scalar kernel argument the kernel assigns to lives in ONE memory + // slot shared by the quad; per-lane writes need a per-lane home, so + // assigned arguments get a varying shadow local seeded from the slot + for (const name of this.vInfo.assignedArgs) { + const argumentIndex = this.argumentNames.indexOf(name); + const gtype = this.argumentTypes[argumentIndex]; + const slot = assembler.layout.scalars[name]; + if (!slot) { + throw this.astErrorOutput( + `WebAssembly backend does not yet support assigning to the array argument "${ name }"`, + this.getJsAST()); + } + const isInt = gtype === 'Integer' || gtype === 'Boolean'; + const index = em.addLocal('v128'); + em.i32Const(0); + if (isInt) em.i32Load(slot.offset).i32x4Splat(); + else em.f32Load(slot.offset).f32x4Splat(); + em.localSet(index); + this.locals.set(name, { kind: 'vscalar', index, wtype: isInt ? 'vi32' : 'vf32', gtype }); + } + const body = ast.body.body; + for (let i = 0; i < body.length; i++) { + this.vstatement(body[i]); + if (this.vTerminated) break; + } + } finally { + this.vec = false; + this.vMaskDepth = 0; + } + return em; + } + + /** + * Emission-time variance analysis, run once per node and cached. Fixpoint + * over the local set: a local is varying when it is ever assigned a + * lane-varying value OR assigned at all under lane-varying control + * (divergent branch, varying-trip loop, ternary branch, short-circuit + * right side). A loop is varying-controlled when its test is varying or a + * break/continue reaches it from under a varying condition. + */ + vAnalyze(ast) { + const varying = new Set(); + const assignedArgs = new Set(); + let varyingReturn = false; + let changed = true; + const self = this; + + const exprVarying = (node) => { + if (!node || typeof node !== 'object') return false; + switch (node.type) { + case 'Literal': + case 'ThisExpression': + return false; + case 'Identifier': + return varying.has(node.name); + case 'MemberExpression': + if ( + !node.computed && + node.object.type === 'MemberExpression' && + !node.object.computed && + node.object.property && + node.object.property.name === 'thread' + ) { + return node.property.name === 'x'; + } + if (node.computed) { + return exprVarying(node.object) || exprVarying(node.property); + } + return exprVarying(node.object); + case 'BinaryExpression': + case 'LogicalExpression': + return exprVarying(node.left) || exprVarying(node.right); + case 'UnaryExpression': + case 'UpdateExpression': + return exprVarying(node.argument); + case 'ConditionalExpression': + return exprVarying(node.test) || exprVarying(node.consequent) || exprVarying(node.alternate); + case 'CallExpression': + if (self.isAstMathFunction(node)) { + if (node.callee.property.name === 'random') return true; + return node.arguments.some(exprVarying); + } + // user helpers may read this.thread.x or draw Math.random inside + return true; + case 'SequenceExpression': + return node.expressions.some(exprVarying); + case 'ArrayExpression': + return node.elements.some(exprVarying); + case 'AssignmentExpression': + return exprVarying(node.right) || (node.left.type === 'Identifier' && varying.has(node.left.name)); + default: + return true; + } + }; + + const taint = (name) => { + if (name && !varying.has(name)) { + varying.add(name); + changed = true; + } + }; + + // update/assignment expressions buried under a varying condition inside + // a larger expression (ternary branch, short-circuit RHS) mutate per lane + const scanExprTaints = (node, cv) => { + if (!node || typeof node !== 'object') return; + if (Array.isArray(node)) return node.forEach(sub => scanExprTaints(sub, cv)); + switch (node.type) { + case 'UpdateExpression': + if (node.argument.type === 'Identifier') { + // an argument updated in EXPRESSION position (`let y = a++`) + // needs the same shadow-local membership the statement walk + // records, or the vector emitter rejects the update outright + if (self.argumentNames.indexOf(node.argument.name) !== -1) { + if (!assignedArgs.has(node.argument.name)) { + assignedArgs.add(node.argument.name); + changed = true; + } + taint(node.argument.name); + } + if (cv) taint(node.argument.name); + } + return scanExprTaints(node.argument, cv); + case 'AssignmentExpression': + if (node.left.type === 'Identifier') { + if (self.argumentNames.indexOf(node.left.name) !== -1) { + if (!assignedArgs.has(node.left.name)) { + assignedArgs.add(node.left.name); + changed = true; + } + taint(node.left.name); + } + if (cv) taint(node.left.name); + } + scanExprTaints(node.left, cv); + return scanExprTaints(node.right, cv); + case 'ConditionalExpression': { + scanExprTaints(node.test, cv); + const branchCv = cv || exprVarying(node.test); + scanExprTaints(node.consequent, branchCv); + return scanExprTaints(node.alternate, branchCv); + } + case 'LogicalExpression': { + scanExprTaints(node.left, cv); + // the RHS of && / || is conditionally executed no matter whether + // the left operand varies per lane -- with a lane-uniform left the + // vector emitter still evaluates the RHS for all lanes under the + // combined mask, so an untainted (scalar) update target there would + // write unmasked and run when JS short-circuiting skips it. Taint + // unconditionally; the blend machinery does the rest. + return scanExprTaints(node.right, true); + } + default: { + for (const key in node) { + if (key === 'loc' || key === 'start' || key === 'end' || key === 'parent') continue; + const child = node[key]; + if (child && typeof child === 'object') scanExprTaints(child, cv); + } + } + } + }; + + const collectAssigned = (node, out) => { + if (!node || typeof node !== 'object') return; + if (Array.isArray(node)) return node.forEach(sub => collectAssigned(sub, out)); + switch (node.type) { + case 'VariableDeclarator': + if (node.id && node.id.type === 'Identifier') out.push(node.id.name); + break; + case 'AssignmentExpression': + if (node.left.type === 'Identifier') out.push(node.left.name); + break; + case 'UpdateExpression': + if (node.argument.type === 'Identifier') out.push(node.argument.name); + break; + case 'FunctionDeclaration': + return; + } + for (const key in node) { + if (key === 'loc' || key === 'start' || key === 'end' || key === 'parent') continue; + const child = node[key]; + if (child && typeof child === 'object') collectAssigned(child, out); + } + }; + + // a break/continue reaching THIS loop from under a lane-varying + // condition makes the trip count lane-varying even with a uniform test + const hasVaryingExit = (node, cv) => { + if (!node || typeof node !== 'object') return false; + if (Array.isArray(node)) return node.some(sub => hasVaryingExit(sub, cv)); + switch (node.type) { + case 'BreakStatement': + case 'ContinueStatement': + return cv; + case 'ForStatement': + case 'WhileStatement': + case 'DoWhileStatement': + case 'FunctionDeclaration': + return false; // their exits are their own + case 'IfStatement': { + const branchCv = cv || exprVarying(node.test); + if (hasVaryingExit(node.consequent, branchCv)) return true; + return node.alternate ? hasVaryingExit(node.alternate, branchCv) : false; + } + case 'ConditionalExpression': { + const branchCv = cv || exprVarying(node.test); + return hasVaryingExit(node.consequent, branchCv) || hasVaryingExit(node.alternate, branchCv); + } + case 'SwitchStatement': { + // case-terminator breaks belong to the switch; continue is ours + const switchCv = cv || exprVarying(node.discriminant) || + node.cases.some(c => c.test && exprVarying(c.test)); + return node.cases.some(c => c.consequent.some(stmt => + stmt.type === 'BreakStatement' ? false : hasVaryingExit(stmt, switchCv))); + } + default: { + for (const key in node) { + if (key === 'loc' || key === 'start' || key === 'end' || key === 'parent') continue; + const child = node[key]; + if (child && typeof child === 'object' && hasVaryingExit(child, cv)) return true; + } + return false; + } + } + }; + + const walkExprStatement = (node, cv) => { + switch (node.type) { + case 'AssignmentExpression': { + if (node.left.type === 'Identifier') { + const name = node.left.name; + if (self.argumentNames.indexOf(name) !== -1) { + if (!assignedArgs.has(name)) { + assignedArgs.add(name); + changed = true; + } + taint(name); + } + if (cv || exprVarying(node.right) || (node.operator !== '=' && varying.has(name))) taint(name); + } + return scanExprTaints(node.right, cv); + } + case 'UpdateExpression': { + if (node.argument.type === 'Identifier') { + const name = node.argument.name; + if (self.argumentNames.indexOf(name) !== -1) { + if (!assignedArgs.has(name)) { + assignedArgs.add(name); + changed = true; + } + taint(name); + } + if (cv) taint(name); + } + return; + } + case 'SequenceExpression': + return node.expressions.forEach(e => walkExprStatement(e, cv)); + default: + return scanExprTaints(node, cv); + } + }; + + const walkStatement = (node, cv) => { + if (!node) return; + switch (node.type) { + case 'VariableDeclaration': + for (const declaration of node.declarations) { + if (!declaration.init) continue; + if (cv || exprVarying(declaration.init)) taint(declaration.id.name); + scanExprTaints(declaration.init, cv); + } + return; + case 'ExpressionStatement': + return walkExprStatement(node.expression, cv); + case 'ReturnStatement': + if (cv) varyingReturn = true; + if (node.argument) scanExprTaints(node.argument, cv); + return; + case 'IfStatement': { + scanExprTaints(node.test, cv); + const branchCv = cv || exprVarying(node.test); + walkStatement(node.consequent, branchCv); + if (node.alternate) walkStatement(node.alternate, branchCv); + return; + } + case 'ForStatement': + case 'WhileStatement': + case 'DoWhileStatement': { + const loopVarying = + cv || + (node.test ? exprVarying(node.test) : false) || + hasVaryingExit(node.body, false); + if (loopVarying) { + const assigned = []; + if (node.init) collectAssigned(node.init, assigned); + collectAssigned(node.body, assigned); + if (node.update) collectAssigned(node.update, assigned); + assigned.forEach(taint); + } + if (node.init) { + if (node.init.type === 'VariableDeclaration') walkStatement(node.init, cv); + else walkExprStatement(node.init, cv); + } + walkStatement(node.body, loopVarying); + if (node.update) walkExprStatement(node.update, loopVarying); + if (node.test) scanExprTaints(node.test, loopVarying); + return; + } + case 'SwitchStatement': { + const switchCv = cv || exprVarying(node.discriminant) || + node.cases.some(c => c.test && exprVarying(c.test)); + for (const switchCase of node.cases) { + for (const stmt of switchCase.consequent) walkStatement(stmt, switchCv); + } + return; + } + case 'BlockStatement': + return node.body.forEach(stmt => walkStatement(stmt, cv)); + default: + return; + } + }; + + while (changed) { + changed = false; + walkStatement(ast.body, false); + } + return { varying, varyingReturn, assignedArgs, exprVarying, hasVaryingExit }; + } + + // ------------------------------------------------------- mask bookkeeping + + vZero() { + this.em.v128ConstI32x4(0, 0, 0, 0); + return this; + } + + vInnermostVaryingLoop() { + const top = this.vLoopStack[this.vLoopStack.length - 1]; + return top && top.varying ? top : null; + } + + /** + * Rebuilds vCur from a saved base after a construct. Retire masks are + * monotone accumulators within their scope, so `base & ~each` is exact at + * any later point; break/continue always target the innermost loop and the + * analysis forces any loop with a masked exit to be a varying loop, so + * only the top varying entry's masks apply. + */ + vRecomputeCur(savedIndex) { + const em = this.em; + em.localGet(savedIndex); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + const loop = this.vInnermostVaryingLoop(); + if (loop) { + if (loop.vBrk !== -1) em.localGet(loop.vBrk).v128Andnot(); + if (loop.vCnt !== -1) em.localGet(loop.vCnt).v128Andnot(); + } + em.localSet(this.vCur); + } + + // break/continue reaching this loop (per-loop retire masks are emitted + // only when they can actually accumulate) + vLoopBodyExits(body) { + let hasBreak = false; + let hasContinue = false; + const walk = (node) => { + if (!node || typeof node !== 'object' || (hasBreak && hasContinue)) return; + if (Array.isArray(node)) return node.forEach(walk); + switch (node.type) { + case 'BreakStatement': + hasBreak = true; + return; + case 'ContinueStatement': + hasContinue = true; + return; + case 'ForStatement': + case 'WhileStatement': + case 'DoWhileStatement': + case 'FunctionDeclaration': + return; // their exits are their own + case 'SwitchStatement': + // terminator breaks belong to the switch; continue is ours + for (const switchCase of node.cases) { + for (const stmt of switchCase.consequent) { + if (stmt.type !== 'BreakStatement') walk(stmt); + } + } + return; + } + for (const key in node) { + if (key === 'loc' || key === 'start' || key === 'end' || key === 'parent') continue; + const child = node[key]; + if (child && typeof child === 'object') walk(child); + } + }; + walk(body); + return { hasBreak, hasContinue }; + } + + /** + * Stores the stack top into a v128 local; under a live branch mask the + * inactive lanes keep their previous value. bitselect copies exact bit + * patterns, so predication never perturbs IEEE results. + */ + vSetLocal(index) { + const em = this.em; + if (this.vMaskDepth > 0) { + em.localGet(index).localGet(this.vCur).v128Bitselect(); + } + em.localSet(index); + } + + // ------------------------------------------------------ vector conversion + + vCoerce(from, to) { + if (from === to) return to; + const em = this.em; + switch (from) { + case 'f32': + case 'i32': + case 'bool': + // uniform value entering a varying context: convert scalar, splat + if (to === 'vf32') { + this.coerce(from, 'f32'); + em.f32x4Splat(); + return to; + } + if (to === 'vi32') { + this.coerce(from, 'i32'); + em.i32x4Splat(); + return to; + } + if (to === 'vbool') { + this.coerce(from, 'i32'); + em.i32x4Splat(); + this.vZero(); + em.i32x4Ne(); + return to; + } + break; + case 'vf32': + if (to === 'vi32') { + em.i32x4TruncSatF32x4S(); + return to; + } + if (to === 'vbool') { + em.v128ConstF32x4(0, 0, 0, 0).f32x4Ne(); + return to; + } + break; + case 'vi32': + if (to === 'vf32') { + em.f32x4ConvertI32x4S(); + return to; + } + if (to === 'vbool') { + this.vZero(); + em.i32x4Ne(); + return to; + } + break; + case 'vbool': + // masks are all-ones/all-zeros; numeric use is 0/1 like scalar bool + if (to === 'vi32') { + em.v128ConstI32x4(1, 1, 1, 1).v128And(); + return to; + } + if (to === 'vf32') { + em.v128ConstI32x4(1, 1, 1, 1).v128And().f32x4ConvertI32x4S(); + return to; + } + break; + } + throw new Error(`cannot convert ${ from } to ${ to }`); + } + + vCastLiteralToInteger(ast) { + this.pushState('casting-to-integer'); + const type = this.vexpr(ast); + this.popState('casting-to-integer'); + this.vCoerce(type, 'vi32'); + return 'vi32'; + } + + vCastLiteralToFloat(ast) { + this.pushState('casting-to-float'); + const type = this.vexpr(ast); + this.popState('casting-to-float'); + this.vCoerce(type, 'vf32'); + return 'vf32'; + } + + vCastValueToInteger(ast) { + this.pushState('casting-to-integer'); + const type = this.vexpr(ast); + this.popState('casting-to-integer'); + this.vCoerce(type, 'vi32'); + return 'vi32'; + } + + vCastValueToFloat(ast) { + this.pushState('casting-to-float'); + const type = this.vexpr(ast); + this.popState('casting-to-float'); + this.vCoerce(type, 'vf32'); + return 'vf32'; + } + + vEmitByType(ast, want) { + const type = this.getType(ast); + if (want === 'vf32') { + if (type === 'Integer') return this.vCastValueToFloat(ast); + if (type === 'LiteralInteger') return this.vCastLiteralToFloat(ast); + this.vCoerce(this.vexpr(ast), 'vf32'); + return 'vf32'; + } + if (type === 'Number' || type === 'Float') return this.vCastValueToInteger(ast); + if (type === 'LiteralInteger') return this.vCastLiteralToInteger(ast); + this.vCoerce(this.vexpr(ast), 'vi32'); + return 'vi32'; + } + + /** + * Leaves an i32x4 lane mask (all-ones/all-zeros) for `ast` as a condition; + * lane truth matches the scalar emitCondition exactly. + */ + vexprMask(ast) { + const type = this.vexpr(ast); + if (type === 'vbool') return; + if (type === 'vi32') { + this.vZero(); + this.em.i32x4Ne(); + return; + } + if (type === 'vf32') { + this.em.v128ConstF32x4(0, 0, 0, 0).f32x4Ne(); + return; + } + // uniform condition entering a varying context + this.coerce(type, 'bool'); + this.em.i32x4Splat(); + this.vZero(); + this.em.i32x4Ne(); + } + + // ------------------------------------------------------ vector statements + + vstatement(ast) { + switch (ast.type) { + case 'VariableDeclaration': + return this.vstmtVariableDeclaration(ast); + case 'ExpressionStatement': + return this.vstatementExpression(ast.expression); + case 'ReturnStatement': + return this.vstmtReturn(ast); + case 'IfStatement': + return this.vstmtIf(ast); + case 'ForStatement': + return this.vstmtFor(ast); + case 'WhileStatement': + return this.vstmtWhile(ast); + case 'DoWhileStatement': + return this.vstmtDoWhile(ast); + case 'BlockStatement': { + for (let i = 0; i < ast.body.length; i++) { + this.vstatement(ast.body[i]); + if (this.vTerminated) break; + } + return; + } + case 'BreakStatement': + return this.vstmtBreak(ast); + case 'ContinueStatement': + return this.vstmtContinue(ast); + case 'SwitchStatement': + return this.vstmtSwitch(ast); + case 'FunctionDeclaration': + if (this.isChildFunction(ast)) return; + throw this.astErrorOutput('unexpected function declaration', ast); + case 'EmptyStatement': + case 'DebuggerStatement': + return; + default: + throw this.astErrorOutput(`Unknown statement type ${ ast.type }`, ast); + } + } + + /** + * A break/continue/return retires every lane that reached it, so the rest + * of its block is dead on both paths; the walk stops emitting there, and + * termination never leaks past the construct boundary. + */ + vstatementBody(node) { + if (!node) return; + const previous = this.vTerminated; + this.vTerminated = false; + this.vstatement(node); + this.vTerminated = previous; + } + + vstatementExpression(expression) { + switch (expression.type) { + case 'AssignmentExpression': + return this.vAssign(expression); + case 'UpdateExpression': + this.vUpdate(expression, true); + return; + case 'SequenceExpression': { + for (let i = 0; i < expression.expressions.length; i++) { + this.vstatementExpression(expression.expressions[i]); + } + return; + } + case 'Identifier': + case 'Literal': + return; + default: { + const type = this.vexpr(expression); + if (type !== 'void') this.em.drop(); + } + } + } + + vstmtVariableDeclaration(varDecNode) { + const declarations = varDecNode.declarations; + if (!declarations || !declarations[0] || !declarations[0].init) { + throw this.astErrorOutput('Unexpected expression', varDecNode); + } + for (let i = 0; i < declarations.length; i++) { + const declaration = declarations[i]; + if (!this.vInfo.varying.has(declaration.id.name)) { + // never assigned varying data nor under a varying mask: the scalar + // declaration path is exact, one shared scalar for all lanes + this.stmtVariableDeclaration(Object.assign({}, varDecNode, { declarations: [declaration] })); + continue; + } + this.vDeclareVarying(declaration, varDecNode); + } + } + + vDeclareVarying(declaration, varDecNode) { + const em = this.em; + const init = declaration.init; + const name = declaration.id.name; + const info = this.getDeclaration(declaration.id); + const actualType = this.getType(init); + + if (actualType === 'Array(2)' || actualType === 'Array(3)' || actualType === 'Array(4)') { + const n = parseInt(actualType.substring(6), 10); + info.valueType = actualType; + let local = this.locals.get(name); + if (!local || local.kind !== 'vvec' || local.n !== n) { + const indices = []; + for (let c = 0; c < n; c++) indices.push(em.addLocal('v128')); + local = { kind: 'vvec', indices, n, gtype: actualType }; + this.locals.set(name, local); + } + if (init.type === 'ArrayExpression') { + for (let c = 0; c < n; c++) { + this.vEmitArrayElement(init.elements[c]); + this.vSetLocal(local.indices[c]); + } + return; + } + if (init.type === 'Identifier') { + const source = this.locals.get(init.name); + if (source && source.kind === 'vvec' && source.n === n) { + for (let c = 0; c < n; c++) { + em.localGet(source.indices[c]); + this.vSetLocal(local.indices[c]); + } + return; + } + if (source && source.kind === 'vec' && source.n === n) { + for (let c = 0; c < n; c++) { + em.localGet(source.indices[c]).f32x4Splat(); + this.vSetLocal(local.indices[c]); + } + return; + } + } + throw this.astErrorOutput(`WebAssembly backend does not yet support ${ actualType } initializer of type ${ init.type }`, varDecNode); + } + + let type = actualType; + if (type === 'LiteralInteger') { + type = info.suggestedType === 'Integer' ? 'Integer' : 'Number'; + } + if (actualType === 'Integer' && type === 'Integer') { + // the scalar walk's int-initializer decay, lane-wise + info.valueType = 'Number'; + this.vSetVaryingScalar(name, 'vf32', 'Number', () => this.vCastValueToFloat(init)); + return; + } + info.valueType = type; + switch (type) { + case 'Number': + case 'Float': + this.vSetVaryingScalar(name, 'vf32', type, () => { + if (actualType === 'LiteralInteger') this.vCastLiteralToFloat(init); + else if (actualType === 'Integer') this.vCastValueToFloat(init); + else this.vCoerce(this.vexpr(init), 'vf32'); + }); + break; + case 'Integer': + this.vSetVaryingScalar(name, 'vi32', 'Integer', () => { + if (actualType === 'LiteralInteger') this.vCastLiteralToInteger(init); + else if (actualType === 'Number' || actualType === 'Float') this.vCastValueToInteger(init); + else this.vCoerce(this.vexpr(init), 'vi32'); + }); + break; + case 'Boolean': + // varying booleans hold 0/1 like scalar bools; conditions renorm + this.vSetVaryingScalar(name, 'vi32', 'Boolean', () => { + this.vexprMask(init); + this.em.v128ConstI32x4(1, 1, 1, 1).v128And(); + }); + break; + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support declaring type ${ type }`, varDecNode); + } + } + + vSetVaryingScalar(name, wtype, gtype, emitInit) { + let local = this.locals.get(name); + if (!local || local.kind !== 'vscalar' || local.wtype !== wtype) { + local = { + kind: 'vscalar', + index: this.em.addLocal('v128'), + wtype, + gtype + }; + this.locals.set(name, local); + } else { + local.gtype = gtype; + } + emitInit(); + this.vSetLocal(local.index); + } + + vEmitArrayElement(element) { + switch (this.getType(element)) { + case 'Integer': + this.vCastValueToFloat(element); + break; + case 'LiteralInteger': + this.vCastLiteralToFloat(element); + break; + default: + this.vCoerce(this.vexpr(element), 'vf32'); + } + } + + vAssign(assNode) { + if (assNode.left.type !== 'Identifier') { + throw this.astErrorOutput(`WebAssembly backend does not yet support assignment to ${ assNode.left.type }`, assNode); + } + const name = assNode.left.name; + const local = this.locals.get(name); + if (local && local.kind === 'scalar') { + // uniform target: the analysis guarantees uniform value and control + return this.emitAssignment(assNode); + } + if (!local || local.kind !== 'vscalar') { + throw this.astErrorOutput(`cannot assign to "${ name }"`, assNode); + } + const wtype = local.wtype; + if (assNode.operator === '=') { + const leftType = this.getType(assNode.left); + const rightType = this.getType(assNode.right); + if (leftType !== 'Integer' && rightType === 'Integer') { + this.vCastValueToFloat(assNode.right); + this.vCoerce('vf32', wtype); + } else if (leftType !== 'Integer' && rightType === 'LiteralInteger') { + this.vCastLiteralToFloat(assNode.right); + this.vCoerce('vf32', wtype); + } else if (leftType === 'Integer' && rightType === 'LiteralInteger') { + this.vCastLiteralToInteger(assNode.right); + this.vCoerce('vi32', wtype); + } else if (leftType === 'Integer' && (rightType === 'Number' || rightType === 'Float')) { + this.vCastValueToInteger(assNode.right); + this.vCoerce('vi32', wtype); + } else { + this.vCoerce(this.vexpr(assNode.right), wtype); + } + } else { + const synthetic = { + type: 'BinaryExpression', + operator: assNode.operator.slice(0, -1), + left: assNode.left, + right: assNode.right, + }; + this.vCoerce(this.vexprBinary(synthetic), wtype); + } + this.vSetLocal(local.index); + } + + vUpdate(uNode, isStatement) { + if (uNode.argument.type !== 'Identifier') { + throw this.astErrorOutput('update expression needs a variable', uNode); + } + const local = this.locals.get(uNode.argument.name); + if (local && local.kind === 'scalar') { + return this.emitUpdate(uNode, isStatement); + } + if (!local || local.kind !== 'vscalar') { + throw this.astErrorOutput(`cannot update "${ uNode.argument.name }"`, uNode); + } + const em = this.em; + const isInt = local.wtype === 'vi32'; + const one = () => (isInt ? em.v128ConstI32x4(1, 1, 1, 1) : em.v128ConstF32x4(1, 1, 1, 1)); + const op = uNode.operator === '++' ? (isInt ? 'i32x4Add' : 'f32x4Add') : (isInt ? 'i32x4Sub' : 'f32x4Sub'); + if (isStatement) { + em.localGet(local.index); + one(); + em[op](); + this.vSetLocal(local.index); + return 'void'; + } + if (uNode.prefix) { + em.localGet(local.index); + one(); + em[op](); + this.vSetLocal(local.index); + em.localGet(local.index); + } else { + const old = em.addLocal('v128'); + em.localGet(local.index).localSet(old); + em.localGet(local.index); + one(); + em[op](); + this.vSetLocal(local.index); + em.localGet(old); + } + return local.wtype; + } + + vstmtIf(ifNode) { + const em = this.em; + if (!this.vInfo.exprVarying(ifNode.test)) { + // uniform condition: every lane agrees, a real branch is exact + this.emitCondition(ifNode.test); + this.enterIf(); + this.vstatementBody(ifNode.consequent); + if (ifNode.alternate) { + em.else_(); + this.vstatementBody(ifNode.alternate); + } + this.exit(); + return; + } + const m = em.addLocal('v128'); + this.vexprMask(ifNode.test); + em.localSet(m); + const saved = em.addLocal('v128'); + em.localGet(this.vCur).localSet(saved); + em.localGet(saved).localGet(m).v128And().localSet(this.vCur); + // any_true guard is speed only — an empty mask already makes the body a + // no-op through the blends + em.localGet(this.vCur).v128AnyTrue(); + this.enterIf(); + this.vMaskDepth++; + this.vstatementBody(ifNode.consequent); + this.vMaskDepth--; + this.exit(); + if (ifNode.alternate) { + em.localGet(saved).localGet(m).v128Andnot().localSet(this.vCur); + em.localGet(this.vCur).v128AnyTrue(); + this.enterIf(); + this.vMaskDepth++; + this.vstatementBody(ifNode.alternate); + this.vMaskDepth--; + this.exit(); + } + this.vRecomputeCur(saved); + } + + vstmtReturn(ast) { + const em = this.em; + if (!ast.argument) { + this.vRetireOrReturn(); + return; + } + this.pushState('skip-literal-correction'); + const type = this.getType(ast.argument); + this.popState('skip-literal-correction'); + switch (this.returnType) { + case 'Array(2)': + case 'Array(3)': + case 'Array(4)': { + const n = parseInt(this.returnType.substring(6), 10); + const argument = ast.argument; + const comps = []; + if (argument.type === 'ArrayExpression') { + if (argument.elements.length !== n) { + throw this.astErrorOutput(`expected ${ n } array elements to match return type ${ this.returnType }`, ast); + } + for (let c = 0; c < n; c++) { + const t = em.addLocal('v128'); + this.vEmitArrayElement(argument.elements[c]); + em.localSet(t); + comps.push(t); + } + } else if (argument.type === 'Identifier') { + const local = this.locals.get(argument.name); + if (local && local.kind === 'vvec' && local.n === n) { + for (let c = 0; c < n; c++) comps.push(local.indices[c]); + } else if (local && local.kind === 'vec' && local.n === n) { + for (let c = 0; c < n; c++) { + const t = em.addLocal('v128'); + em.localGet(local.indices[c]).f32x4Splat().localSet(t); + comps.push(t); + } + } else { + throw this.astErrorOutput(`"${ argument.name }" is not an Array(${ n }) variable`, ast); + } + } else { + throw this.astErrorOutput(`WebAssembly backend does not yet support returning ${ this.returnType } from a ${ argument.type }`, ast); + } + this.vStoreOutput(comps); + this.vRetireOrReturn(); + return; + } + default: { + const t = em.addLocal('v128'); + switch (this.returnType) { + case 'Integer': + // f32(i32(value)): the scalar path's double conversion lane-wise + if (type === 'Float' || type === 'Number') this.vCastValueToInteger(ast.argument); + else if (type === 'LiteralInteger') this.vCastLiteralToInteger(ast.argument); + else this.vCoerce(this.vexpr(ast.argument), 'vi32'); + em.f32x4ConvertI32x4S(); + break; + case 'LiteralInteger': + case 'Number': + case 'Float': + if (type === 'Integer') this.vCastValueToFloat(ast.argument); + else if (type === 'LiteralInteger') this.vCastLiteralToFloat(ast.argument); + else this.vCoerce(this.vexpr(ast.argument), 'vf32'); + break; + case 'Boolean': + this.vexprMask(ast.argument); + em.v128ConstI32x4(1, 1, 1, 1).v128And().f32x4ConvertI32x4S(); + break; + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support returning ${ this.returnType }`, ast); + } + em.localSet(t); + this.vStoreOutput([t]); + this.vRetireOrReturn(); + } + } + } + + /** + * Stores the quad's output. componentCount 1 is 4 consecutive f32 — one + * v128 store (load+blend+store when a mask is live). componentCount n is + * lane-strided, so components store scalar with a per-lane select. + */ + vStoreOutput(comps) { + const em = this.em; + const globals = this.assembler.globals; + const outputOffset = this.assembler.layout.outputOffset; + const n = comps.length; + let maskLocal = -1; + if (this.vMaskDepth > 0) { + maskLocal = this.vCur; + } else if (this.vRetMask !== -1) { + // depth 0 after a divergent return: live lanes are ~retired + maskLocal = em.addLocal('v128'); + em.localGet(this.vRetMask).v128Not().localSet(maskLocal); + } + const addr = em.addLocal('i32'); + if (n === 1) { + em.globalGet(globals.dataIndex).i32Const(2).i32Shl().localSet(addr); + if (maskLocal === -1) { + em.localGet(addr).localGet(comps[0]).v128Store(outputOffset, 2); + } else { + em.localGet(addr); + em.localGet(comps[0]); + em.localGet(addr).v128Load(outputOffset, 2); + em.localGet(maskLocal).v128Bitselect(); + em.v128Store(outputOffset, 2); + } + return; + } + em.globalGet(globals.dataIndex).i32Const(n).i32Mul().i32Const(2).i32Shl().localSet(addr); + for (let lane = 0; lane < 4; lane++) { + for (let c = 0; c < n; c++) { + const offset = outputOffset + (lane * n + c) * 4; + em.localGet(addr); + em.localGet(comps[c]).f32x4ExtractLane(lane); + if (maskLocal !== -1) { + em.localGet(addr).f32Load(offset); + em.localGet(maskLocal).i32x4ExtractLane(lane); + em.select(); + } + em.f32Store(offset); + } + } + } + + vRetireOrReturn() { + const em = this.em; + if (this.vMaskDepth === 0) { + em.return_(); + this.vTerminated = true; + return; + } + // divergent return: retire the active lanes, the others keep running + em.localGet(this.vRetMask).localGet(this.vCur).v128Or().localSet(this.vRetMask); + this.vZero(); + em.localSet(this.vCur); + this.vTerminated = true; + } + + vstmtBreak(brNode) { + const target = this.vLoopStack[this.vLoopStack.length - 1]; + if (!target) { + throw this.astErrorOutput('break used outside of a loop', brNode); + } + if (!target.varying) { + this.brTo(target.breakLevel); + this.vTerminated = true; + return; + } + if (target.vBrk === -1) { + throw this.astErrorOutput('internal: loop exit scan missed a break', brNode); + } + const em = this.em; + em.localGet(target.vBrk).localGet(this.vCur).v128Or().localSet(target.vBrk); + this.vZero(); + em.localSet(this.vCur); + this.vTerminated = true; + } + + vstmtContinue(crNode) { + const target = this.vLoopStack[this.vLoopStack.length - 1]; + if (!target) { + throw this.astErrorOutput('continue used outside of a loop', crNode); + } + if (!target.varying) { + this.brTo(target.continueLevel); + this.vTerminated = true; + return; + } + if (target.vCnt === -1) { + throw this.astErrorOutput('internal: loop exit scan missed a continue', crNode); + } + const em = this.em; + em.localGet(target.vCnt).localGet(this.vCur).v128Or().localSet(target.vCnt); + this.vZero(); + em.localSet(this.vCur); + this.vTerminated = true; + } + + vstmtFor(forNode) { + if (forNode.type !== 'ForStatement') { + throw this.astErrorOutput('Invalid for statement', forNode); + } + const em = this.em; + const varying = (forNode.test ? this.vInfo.exprVarying(forNode.test) : false) || + this.vInfo.hasVaryingExit(forNode.body, false); + const isSafe = this.forLoopIsSafe(forNode); + if (forNode.init) { + if (forNode.init.type === 'VariableDeclaration') this.vstmtVariableDeclaration(forNode.init); + else this.vstatementExpression(forNode.init); + } + if (!varying) { + // uniform trip count: the scalar loop shape, vector body + let safeI = -1; + if (!isSafe) { + safeI = em.addLocal('i32'); + em.i32Const(0).localSet(safeI); + } + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + if (!isSafe) { + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + } + if (forNode.test) { + this.emitCondition(forNode.test); + em.i32Eqz(); + this.brIfTo(breakLevel); + } + this.enterBlock(); + const continueLevel = this.depth; + this.vLoopStack.push({ varying: false, breakLevel, continueLevel }); + if (forNode.body) this.vstatementBody(forNode.body); + this.vLoopStack.pop(); + this.exit(); + if (forNode.update) this.vstatementExpression(forNode.update); + if (!isSafe) { + em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + } + this.brTo(loopLevel); + this.exit(); + this.exit(); + return; + } + // lane-varying trip count: iterate while any lane is live; per-lane + // iteration counts match scalar exactly (test masks each lane out at its + // own boundary, the shared safety counter caps at the same loopMax) + const saved = em.addLocal('v128'); + em.localGet(this.vCur).localSet(saved); + const vLive = em.addLocal('v128'); + em.localGet(this.vCur).localSet(vLive); + const exits = this.vLoopBodyExits(forNode.body); + let vBrk = -1; + if (exits.hasBreak) { + vBrk = em.addLocal('v128'); + this.vZero(); + em.localSet(vBrk); + } + const vCnt = exits.hasContinue ? em.addLocal('v128') : -1; + let safeI = -1; + if (!isSafe) { + safeI = em.addLocal('i32'); + em.i32Const(0).localSet(safeI); + } + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + if (!isSafe) { + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + } + if (vBrk !== -1 || this.vRetMask !== -1) { + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(vLive); + } + if (vCnt !== -1) { + this.vZero(); + em.localSet(vCnt); + } + this.vMaskDepth++; + em.localGet(vLive).localSet(this.vCur); + if (forNode.test) { + em.localGet(vLive); + this.vexprMask(forNode.test); + em.v128And().localSet(vLive); + } + em.localGet(vLive).v128AnyTrue().i32Eqz(); + this.brIfTo(breakLevel); + em.localGet(vLive).localSet(this.vCur); + this.vLoopStack.push({ varying: true, vLive, vBrk, vCnt, breakLevel, loopLevel }); + if (forNode.body) this.vstatementBody(forNode.body); + this.vLoopStack.pop(); + // continued lanes rejoin for the update clause; broke/returned stay out + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(this.vCur); + if (forNode.update) this.vstatementExpression(forNode.update); + this.vMaskDepth--; + if (!isSafe) { + em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + } + this.brTo(loopLevel); + this.exit(); + this.exit(); + this.vRecomputeCur(saved); + } + + vstmtWhile(whileNode) { + if (whileNode.type !== 'WhileStatement') { + throw this.astErrorOutput('Invalid while statement', whileNode); + } + const em = this.em; + const varying = this.vInfo.exprVarying(whileNode.test) || + this.vInfo.hasVaryingExit(whileNode.body, false); + const safeI = em.addLocal('i32'); + em.i32Const(0).localSet(safeI); + if (!varying) { + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + this.emitCondition(whileNode.test); + em.i32Eqz(); + this.brIfTo(breakLevel); + this.enterBlock(); + const continueLevel = this.depth; + this.vLoopStack.push({ varying: false, breakLevel, continueLevel }); + this.vstatementBody(whileNode.body); + this.vLoopStack.pop(); + this.exit(); + em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + return; + } + const saved = em.addLocal('v128'); + em.localGet(this.vCur).localSet(saved); + const vLive = em.addLocal('v128'); + em.localGet(this.vCur).localSet(vLive); + const exits = this.vLoopBodyExits(whileNode.body); + let vBrk = -1; + if (exits.hasBreak) { + vBrk = em.addLocal('v128'); + this.vZero(); + em.localSet(vBrk); + } + const vCnt = exits.hasContinue ? em.addLocal('v128') : -1; + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + if (vBrk !== -1 || this.vRetMask !== -1) { + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(vLive); + } + if (vCnt !== -1) { + this.vZero(); + em.localSet(vCnt); + } + this.vMaskDepth++; + em.localGet(vLive).localSet(this.vCur); + em.localGet(vLive); + this.vexprMask(whileNode.test); + em.v128And().localSet(vLive); + em.localGet(vLive).v128AnyTrue().i32Eqz(); + this.brIfTo(breakLevel); + em.localGet(vLive).localSet(this.vCur); + this.vLoopStack.push({ varying: true, vLive, vBrk, vCnt, breakLevel, loopLevel }); + this.vstatementBody(whileNode.body); + this.vLoopStack.pop(); + this.vMaskDepth--; + em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.brTo(loopLevel); + this.exit(); + this.exit(); + this.vRecomputeCur(saved); + } + + vstmtDoWhile(doWhileNode) { + if (doWhileNode.type !== 'DoWhileStatement') { + throw this.astErrorOutput('Invalid while statement', doWhileNode); + } + const em = this.em; + const varying = this.vInfo.exprVarying(doWhileNode.test) || + this.vInfo.hasVaryingExit(doWhileNode.body, false); + const safeI = em.addLocal('i32'); + em.i32Const(0).localSet(safeI); + if (!varying) { + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + this.enterBlock(); + const continueLevel = this.depth; + this.vLoopStack.push({ varying: false, breakLevel, continueLevel }); + this.vstatementBody(doWhileNode.body); + this.vLoopStack.pop(); + this.exit(); + em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + this.emitCondition(doWhileNode.test); + this.brIfTo(loopLevel); + this.exit(); + this.exit(); + return; + } + const saved = em.addLocal('v128'); + em.localGet(this.vCur).localSet(saved); + const vLive = em.addLocal('v128'); + em.localGet(this.vCur).localSet(vLive); + const exits = this.vLoopBodyExits(doWhileNode.body); + let vBrk = -1; + if (exits.hasBreak) { + vBrk = em.addLocal('v128'); + this.vZero(); + em.localSet(vBrk); + } + const vCnt = exits.hasContinue ? em.addLocal('v128') : -1; + this.enterBlock(); + const breakLevel = this.depth; + this.enterLoop(); + const loopLevel = this.depth; + em.localGet(safeI).i32Const(this.loopMax).i32GeS(); + this.brIfTo(breakLevel); + if (vBrk !== -1 || this.vRetMask !== -1) { + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(vLive); + } + if (vCnt !== -1) { + this.vZero(); + em.localSet(vCnt); + } + this.vMaskDepth++; + em.localGet(vLive).localSet(this.vCur); + this.vLoopStack.push({ varying: true, vLive, vBrk, vCnt, breakLevel, loopLevel }); + this.vstatementBody(doWhileNode.body); + this.vLoopStack.pop(); + // continued lanes rejoin for the test, broke/returned lanes stay out + if (vBrk !== -1 || this.vRetMask !== -1) { + em.localGet(vLive); + if (vBrk !== -1) em.localGet(vBrk).v128Andnot(); + if (this.vRetMask !== -1) em.localGet(this.vRetMask).v128Andnot(); + em.localSet(vLive); + } + em.localGet(vLive).localSet(this.vCur); + em.localGet(vLive); + this.vexprMask(doWhileNode.test); + em.v128And().localSet(vLive); + this.vMaskDepth--; + em.localGet(safeI).i32Const(1).i32Add().localSet(safeI); + em.localGet(vLive).v128AnyTrue(); + this.brIfTo(loopLevel); + this.exit(); + this.exit(); + this.vRecomputeCur(saved); + } + + vstmtSwitch(ast) { + if (ast.type !== 'SwitchStatement') { + throw this.astErrorOutput('Invalid switch statement', ast); + } + const { discriminant, cases } = ast; + const em = this.em; + const varying = this.vInfo.exprVarying(discriminant) || + cases.some(c => c.test && this.vInfo.exprVarying(c.test)); + const type = this.getType(discriminant); + if (!varying) { + let dLocal; + let dIsInt; + switch (type) { + case 'Float': + case 'Number': + dIsInt = false; + dLocal = em.addLocal('f32'); + this.coerce(this.expression(discriminant), 'f32'); + em.localSet(dLocal); + break; + case 'Integer': + dIsInt = true; + dLocal = em.addLocal('i32'); + this.coerce(this.expression(discriminant), 'i32'); + em.localSet(dLocal); + break; + default: + throw this.astErrorOutput(`Unhandled switch discriminant type "${ type }"`, ast); + } + if (cases.length === 1 && !cases[0].test) { + this.vEmitSwitchConsequent(cases[0].consequent); + return; + } + const { groups, defaultConsequent } = this.collectSwitchGroups(cases); + const emitChain = (index) => { + if (index === groups.length) { + if (defaultConsequent) this.vEmitSwitchConsequent(defaultConsequent); + return; + } + const { tests, consequent } = groups[index]; + for (let i = 0; i < tests.length; i++) { + em.localGet(dLocal); + this.emitSwitchTest(tests[i], dIsInt); + if (dIsInt) em.i32Eq(); + else em.f32Eq(); + if (i > 0) em.i32Or(); + } + this.enterIf(); + this.vEmitSwitchConsequent(consequent); + if (index + 1 < groups.length || defaultConsequent) { + em.else_(); + emitChain(index + 1); + } + this.exit(); + }; + emitChain(0); + return; + } + // varying discriminant: per-group masks with earlier matches excluded — + // the same first-match-wins the scalar if/else chain encodes + let dLocal; + let dIsInt; + switch (type) { + case 'Float': + case 'Number': + dIsInt = false; + dLocal = em.addLocal('v128'); + this.vCoerce(this.vexpr(discriminant), 'vf32'); + em.localSet(dLocal); + break; + case 'Integer': + dIsInt = true; + dLocal = em.addLocal('v128'); + this.vCoerce(this.vexpr(discriminant), 'vi32'); + em.localSet(dLocal); + break; + default: + throw this.astErrorOutput(`Unhandled switch discriminant type "${ type }"`, ast); + } + if (cases.length === 1 && !cases[0].test) { + this.vEmitSwitchConsequent(cases[0].consequent); + return; + } + const { groups, defaultConsequent } = this.collectSwitchGroups(cases); + const saved = em.addLocal('v128'); + em.localGet(this.vCur).localSet(saved); + const prior = em.addLocal('v128'); + this.vZero(); + em.localSet(prior); + const gm = em.addLocal('v128'); + this.vMaskDepth++; + for (let g = 0; g < groups.length; g++) { + const { tests, consequent } = groups[g]; + for (let i = 0; i < tests.length; i++) { + em.localGet(dLocal); + this.vEmitSwitchTest(tests[i], dIsInt); + if (dIsInt) em.i32x4Eq(); + else em.f32x4Eq(); + if (i > 0) em.v128Or(); + } + em.localSet(gm); + this.vRecomputeCur(saved); + em.localGet(this.vCur).localGet(gm).v128And().localGet(prior).v128Andnot().localSet(this.vCur); + em.localGet(prior).localGet(gm).v128Or().localSet(prior); + em.localGet(this.vCur).v128AnyTrue(); + this.enterIf(); + this.vEmitSwitchConsequent(consequent); + this.exit(); + } + if (defaultConsequent) { + this.vRecomputeCur(saved); + em.localGet(this.vCur).localGet(prior).v128Andnot().localSet(this.vCur); + em.localGet(this.vCur).v128AnyTrue(); + this.enterIf(); + this.vEmitSwitchConsequent(defaultConsequent); + this.exit(); + } + this.vMaskDepth--; + this.vRecomputeCur(saved); + } + + vEmitSwitchTest(test, dIsInt) { + const testType = this.getType(test); + if (dIsInt) { + if (testType === 'Number' || testType === 'Float') this.vCastValueToInteger(test); + else if (testType === 'LiteralInteger') this.vCastLiteralToInteger(test); + else this.vCoerce(this.vexpr(test), 'vi32'); + } else { + if (testType === 'LiteralInteger') this.vCastLiteralToFloat(test); + else if (testType === 'Integer') this.vCastValueToFloat(test); + else this.vCoerce(this.vexpr(test), 'vf32'); + } + } + + vEmitSwitchConsequent(consequent) { + const statements = this.collectSwitchCaseStatements(consequent); + const previous = this.vTerminated; + this.vTerminated = false; + for (let i = 0; i < statements.length; i++) { + this.vstatement(statements[i]); + if (this.vTerminated) break; + } + this.vTerminated = previous; + } + + // ----------------------------------------------------- vector expressions + + /** + * Emits `ast` in the vector walk. Uniform expressions go through the + * scalar walk untouched (one shared value; splatted only where a varying + * context needs it) and return scalar categories; varying expressions + * return 'vf32' | 'vi32' | 'vbool' (i32x4 lane mask) | 'void'. + */ + vexpr(ast) { + if (!this.vInfo.exprVarying(ast)) { + return this.expression(ast); + } + switch (ast.type) { + case 'Identifier': + return this.vexprIdentifier(ast); + case 'BinaryExpression': + return this.vexprBinary(ast); + case 'LogicalExpression': + return this.vexprLogical(ast); + case 'UnaryExpression': + return this.vexprUnary(ast); + case 'UpdateExpression': + return this.vUpdate(ast, false); + case 'ConditionalExpression': + return this.vexprConditional(ast); + case 'CallExpression': + return this.vexprCall(ast); + case 'MemberExpression': + return this.vexprMember(ast); + case 'SequenceExpression': + if (ast.expressions.length === 1) return this.vexpr(ast.expressions[0]); + throw this.astErrorOutput('WebAssembly backend does not yet support the comma operator', ast); + case 'AssignmentExpression': + throw this.astErrorOutput('WebAssembly backend does not yet support assignment used as an expression', ast); + default: + throw this.astErrorOutput(`Unknown expression type ${ ast.type }`, ast); + } + } + + vexprIdentifier(ast) { + const local = this.locals.get(ast.name); + if (!local) { + throw this.astErrorOutput(`Unhandled varying identifier "${ ast.name }"`, ast); + } + if (local.kind === 'vvec') { + throw this.astErrorOutput(`array-valued variable "${ ast.name }" can only be indexed or returned`, ast); + } + if (local.kind !== 'vscalar') { + throw this.astErrorOutput(`internal: varying read of uniform local "${ ast.name }"`, ast); + } + this.em.localGet(local.index); + return local.wtype; + } + + vexprBinary(ast) { + const operator = ast.operator; + const em = this.em; + + if (operator === '**') { + const a = em.addLocal('v128'); + const b = em.addLocal('v128'); + this.vEmitByType(ast.left, 'vf32'); + em.localSet(a); + this.vEmitByType(ast.right, 'vf32'); + em.localSet(b); + this.usedMathImports.add('pow'); + this.vLaneCall2('math_pow', a, b); + return 'vf32'; + } + + if (BITWISE_OPS[operator]) { + if (VECTOR_SHIFT_OPS[operator]) return this.vexprShift(ast); + this.vEmitAsIntegerOperand(ast.left); + this.vEmitAsIntegerOperand(ast.right); + em[{ '&': 'v128And', '|': 'v128Or', '^': 'v128Xor' } [operator]](); + return 'vi32'; + } + + if (operator === '/' || operator === '%') { + if (operator === '/') { + this.vEmitByType(ast.left, 'vf32'); + this.vEmitByType(ast.right, 'vf32'); + em.f32x4Div(); + return 'vf32'; + } + const a = em.addLocal('v128'); + const b = em.addLocal('v128'); + this.vEmitByType(ast.left, 'vf32'); + em.localSet(a); + this.vEmitByType(ast.right, 'vf32'); + em.localSet(b); + em.localGet(a).localGet(a).localGet(b).f32x4Div().f32x4Trunc().localGet(b).f32x4Mul().f32x4Sub(); + return 'vf32'; + } + + const leftType = this.getType(ast.left) || 'Number'; + const rightType = this.getType(ast.right) || 'Number'; + const key = leftType + ' & ' + rightType; + let category; + switch (key) { + case 'Integer & Integer': + this.pushState('building-integer'); + this.vCoerce(this.vexpr(ast.left), 'vi32'); + this.vCoerce(this.vexpr(ast.right), 'vi32'); + this.popState('building-integer'); + category = 'vi32'; + break; + case 'Number & Float': + case 'Float & Number': + case 'Float & Float': + case 'Number & Number': + this.pushState('building-float'); + this.vCoerce(this.vexpr(ast.left), 'vf32'); + this.vCoerce(this.vexpr(ast.right), 'vf32'); + this.popState('building-float'); + category = 'vf32'; + break; + case 'LiteralInteger & LiteralInteger': + if (this.isState('casting-to-integer') || this.isState('building-integer')) { + this.pushState('building-integer'); + this.vCoerce(this.vexpr(ast.left), 'vi32'); + this.vCoerce(this.vexpr(ast.right), 'vi32'); + this.popState('building-integer'); + category = 'vi32'; + } else { + this.pushState('building-float'); + this.vCastLiteralToFloat(ast.left); + this.vCastLiteralToFloat(ast.right); + this.popState('building-float'); + category = 'vf32'; + } + break; + case 'Integer & Float': + case 'Integer & Number': + this.pushState('building-float'); + this.vCastValueToFloat(ast.left); + this.vCoerce(this.vexpr(ast.right), 'vf32'); + this.popState('building-float'); + category = 'vf32'; + break; + case 'Integer & LiteralInteger': + this.pushState('building-integer'); + this.vCoerce(this.vexpr(ast.left), 'vi32'); + this.vCastLiteralToInteger(ast.right); + this.popState('building-integer'); + category = 'vi32'; + break; + case 'Number & Integer': + case 'Float & Integer': + this.pushState('building-float'); + this.vCoerce(this.vexpr(ast.left), 'vf32'); + this.vCastValueToFloat(ast.right); + this.popState('building-float'); + category = 'vf32'; + break; + case 'Float & LiteralInteger': + case 'Number & LiteralInteger': + this.pushState('building-float'); + this.vCoerce(this.vexpr(ast.left), 'vf32'); + this.vCastLiteralToFloat(ast.right); + this.popState('building-float'); + category = 'vf32'; + break; + case 'LiteralInteger & Float': + case 'LiteralInteger & Number': + if (this.isState('casting-to-integer')) { + this.pushState('building-integer'); + this.vCastLiteralToInteger(ast.left); + this.vCastValueToInteger(ast.right); + this.popState('building-integer'); + category = 'vi32'; + } else { + this.pushState('building-float'); + this.vCastLiteralToFloat(ast.left); + this.pushState('casting-to-float'); + this.vCoerce(this.vexpr(ast.right), 'vf32'); + this.popState('casting-to-float'); + this.popState('building-float'); + category = 'vf32'; + } + break; + case 'LiteralInteger & Integer': + this.pushState('building-integer'); + this.vCastLiteralToInteger(ast.left); + this.vCoerce(this.vexpr(ast.right), 'vi32'); + this.popState('building-integer'); + category = 'vi32'; + break; + case 'Boolean & Boolean': + this.vCoerce(this.vexpr(ast.left), 'vi32'); + this.vCoerce(this.vexpr(ast.right), 'vi32'); + category = 'vi32'; + break; + default: + throw this.astErrorOutput(`Unhandled binary expression between ${ key }`, ast); + } + + const compareOp = category === 'vi32' ? VI32_COMPARE[operator] : VF32_COMPARE[operator]; + if (compareOp) { + em[compareOp](); + return 'vbool'; + } + const arithOp = category === 'vi32' ? VI32_ARITH[operator] : VF32_ARITH[operator]; + if (!arithOp) { + throw this.astErrorOutput(`Unhandled operator ${ operator }`, ast); + } + em[arithOp](); + return category; + } + + /** + * i32x4 shifts take ONE scalar count for all lanes; a lane-varying count + * lane-scalarizes through the scalar opcode (same mod-32 masking). + */ + vexprShift(ast) { + const em = this.em; + this.vEmitAsIntegerOperand(ast.left); + if (!this.vInfo.exprVarying(ast.right)) { + this.emitAsIntegerOperand(ast.right); + em[VECTOR_SHIFT_OPS[ast.operator]](); + return 'vi32'; + } + const a = em.addLocal('v128'); + const b = em.addLocal('v128'); + em.localSet(a); + this.vEmitAsIntegerOperand(ast.right); + em.localSet(b); + const op = BITWISE_OPS[ast.operator]; + for (let lane = 0; lane < 4; lane++) { + em.localGet(a).i32x4ExtractLane(lane); + em.localGet(b).i32x4ExtractLane(lane); + em[op](); + if (lane === 0) em.i32x4Splat(); + else em.i32x4ReplaceLane(lane); + } + return 'vi32'; + } + + vEmitAsIntegerOperand(side) { + switch (this.getType(side)) { + case 'Number': + case 'Float': + this.vCastValueToInteger(side); + break; + case 'LiteralInteger': + this.vCastLiteralToInteger(side); + break; + default: { + this.pushState('building-integer'); + const type = this.vexpr(side); + this.popState('building-integer'); + this.vCoerce(type, 'vi32'); + } + } + } + + /** + * Predicated logic evaluates BOTH operands as masks (per-lane skipping + * cannot exist); side effects in the right operand still predicate + * correctly because vCur narrows to the left verdict while it runs, and + * the gather clamps keep formerly short-circuit-guarded reads from + * trapping. + */ + vexprLogical(ast) { + const em = this.em; + const mLeft = em.addLocal('v128'); + this.vexprMask(ast.left); + em.localSet(mLeft); + const saved = em.addLocal('v128'); + em.localGet(this.vCur).localSet(saved); + em.localGet(this.vCur).localGet(mLeft); + if (ast.operator === '&&') em.v128And(); + else if (ast.operator === '||') em.v128Andnot(); + else throw this.astErrorOutput(`Unhandled logical operator ${ ast.operator }`, ast); + em.localSet(this.vCur); + this.vMaskDepth++; + this.vexprMask(ast.right); + this.vMaskDepth--; + em.localGet(saved).localSet(this.vCur); + em.localGet(mLeft); + if (ast.operator === '&&') em.v128And(); + else em.v128Or(); + return 'vbool'; + } + + vexprUnary(ast) { + const em = this.em; + switch (ast.operator) { + case '~': + this.vEmitAsIntegerOperand(ast.argument); + em.v128ConstI32x4(-1, -1, -1, -1).v128Xor(); + return 'vi32'; + case '!': + this.vexprMask(ast.argument); + em.v128Not(); + return 'vbool'; + case '+': + return this.vexpr(ast.argument); + case '-': { + const type = this.getType(ast.argument); + const wantsInteger = type === 'Integer' || + (type === 'LiteralInteger' && (this.isState('casting-to-integer') || this.isState('building-integer'))); + if (wantsInteger) { + this.vZero(); + this.vEmitByType(ast.argument, 'vi32'); + em.i32x4Sub(); + return 'vi32'; + } + this.vEmitByType(ast.argument, 'vf32'); + em.f32x4Neg(); + return 'vf32'; + } + default: + throw this.astErrorOutput(`Unhandled unary operator ${ ast.operator }`, ast); + } + } + + vexprConditional(ast) { + const em = this.em; + const consequentType = this.getType(ast.consequent); + const alternateType = this.getType(ast.alternate); + if (consequentType === null && alternateType === null) { + this.vTernaryStatement(ast); + return 'void'; + } + let targetType = consequentType === 'LiteralInteger' ? 'Number' : consequentType; + if (targetType === 'Integer' && (alternateType === 'Number' || alternateType === 'Float')) { + targetType = 'Number'; + } + const emitBranch = (branch) => { + const branchType = this.getType(branch); + switch (targetType) { + case 'Number': + case 'Float': + if (branchType === 'Integer') this.vCastValueToFloat(branch); + else if (branchType === 'LiteralInteger') this.vCastLiteralToFloat(branch); + else this.vCoerce(this.vexpr(branch), 'vf32'); + break; + case 'Integer': + if (branchType === 'Number' || branchType === 'Float') this.vCastValueToInteger(branch); + else if (branchType === 'LiteralInteger') this.vCastLiteralToInteger(branch); + else this.vCoerce(this.vexpr(branch), 'vi32'); + break; + case 'Boolean': + this.vexprMask(branch); + break; + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support a ternary of type ${ targetType }`, ast); + } + }; + const resultCategory = targetType === 'Integer' ? 'vi32' : targetType === 'Boolean' ? 'vbool' : 'vf32'; + if (!this.vInfo.exprVarying(ast.test)) { + // uniform test: a real branch evaluates one side, exactly like scalar + this.emitCondition(ast.test); + this.enterIf('v128'); + emitBranch(ast.consequent); + em.else_(); + emitBranch(ast.alternate); + this.exit(); + return resultCategory; + } + const m = em.addLocal('v128'); + this.vexprMask(ast.test); + em.localSet(m); + const saved = em.addLocal('v128'); + em.localGet(this.vCur).localSet(saved); + const v1 = em.addLocal('v128'); + const v2 = em.addLocal('v128'); + em.localGet(saved).localGet(m).v128And().localSet(this.vCur); + this.vMaskDepth++; + emitBranch(ast.consequent); + em.localSet(v1); + em.localGet(saved).localGet(m).v128Andnot().localSet(this.vCur); + emitBranch(ast.alternate); + em.localSet(v2); + this.vMaskDepth--; + em.localGet(saved).localSet(this.vCur); + em.localGet(v1).localGet(v2).localGet(m).v128Bitselect(); + return resultCategory; + } + + vTernaryStatement(ast) { + const em = this.em; + if (!this.vInfo.exprVarying(ast.test)) { + this.emitCondition(ast.test); + this.enterIf(); + this.vstatementExpression(ast.consequent); + em.else_(); + this.vstatementExpression(ast.alternate); + this.exit(); + return; + } + const m = em.addLocal('v128'); + this.vexprMask(ast.test); + em.localSet(m); + const saved = em.addLocal('v128'); + em.localGet(this.vCur).localSet(saved); + em.localGet(saved).localGet(m).v128And().localSet(this.vCur); + this.vMaskDepth++; + this.vstatementExpression(ast.consequent); + em.localGet(saved).localGet(m).v128Andnot().localSet(this.vCur); + this.vstatementExpression(ast.alternate); + this.vMaskDepth--; + em.localGet(saved).localSet(this.vCur); + } + + vexprCall(ast) { + if (!ast.callee) { + throw this.astErrorOutput('Unknown CallExpression', ast); + } + if (ast.callee.type === 'MemberExpression' && this.getVariableSignature(ast.callee, true) === 'this.color') { + throw this.astErrorOutput('WebAssembly backend does not yet support graphical mode (this.color)', ast); + } + let functionName = null; + const isMathFunction = this.isAstMathFunction(ast); + if (isMathFunction || (ast.callee.object && ast.callee.object.type === 'ThisExpression')) { + functionName = ast.callee.property.name; + } else if ( + ast.callee.type === 'SequenceExpression' && + ast.callee.expressions[0].type === 'Literal' && + !isNaN(ast.callee.expressions[0].raw) + ) { + functionName = ast.callee.expressions[1].property.name; + } else { + functionName = ast.callee.name; + } + if (!functionName) { + throw this.astErrorOutput(`Unhandled function, couldn't find name`, ast); + } + if (isMathFunction) { + return this.vMathCall(functionName, ast); + } + return this.vUserCall(functionName, ast); + } + + /** + * Helpers stay scalar; a varying call lane-scalarizes: per lane, set that + * lane's thread.x and PCG state, extract the lane's arguments, call, and + * rebuild the result vector. Same function bodies and imports as the + * scalar path, so every lane is bit-identical to its scalar run. + */ + vUserCall(functionName, ast) { + const em = this.em; + const info = this.assembler.helperInfo || { readsThread: false, usesRandom: false }; + const globals = this.assembler.globals; + const returnType = this.getType(ast); + const targetTypes = this.lookupFunctionArgumentTypes(functionName) || []; + const argLocals = []; + for (let i = 0; i < ast.arguments.length; ++i) { + const argument = ast.arguments[i]; + let targetType = targetTypes[i]; + const argumentType = this.getType(argument); + if (!targetType) { + this.triggerImplyArgumentType(functionName, i, argumentType, this); + targetType = argumentType; + } + let wtype; + switch (argumentType) { + case 'Boolean': + this.vCoerce(this.vexpr(argument), 'vi32'); + wtype = 'vi32'; + break; + case 'Number': + case 'Float': + if (targetType === 'Integer') { + this.vCastValueToInteger(argument); + wtype = 'vi32'; + } else { + this.vCoerce(this.vexpr(argument), 'vf32'); + wtype = 'vf32'; + } + break; + case 'Integer': + if (targetType === 'Number' || targetType === 'Float') { + this.vCastValueToFloat(argument); + wtype = 'vf32'; + } else { + this.vCoerce(this.vexpr(argument), 'vi32'); + wtype = 'vi32'; + } + break; + case 'LiteralInteger': + if (targetType === 'Integer') { + this.vCastLiteralToInteger(argument); + wtype = 'vi32'; + } else { + this.vCastLiteralToFloat(argument); + wtype = 'vf32'; + } + break; + default: + throw this.astErrorOutput('WebAssembly backend does not yet support array arguments to helper functions', ast); + } + const index = em.addLocal('v128'); + em.localSet(index); + argLocals.push({ index, wtype }); + } + const resultKind = returnType === null || returnType === undefined ? 'void' : + returnType === 'Integer' || returnType === 'Boolean' ? 'i32' : 'f32'; + const resultTmp = resultKind === 'void' ? -1 : em.addLocal(resultKind); + const resultVec = resultKind === 'void' ? -1 : em.addLocal('v128'); + let stateTmp = -1; + if (info.usesRandom) { + // candidate post-call states; blended under the live mask afterwards + // so a call evaluated for inactive lanes cannot advance their streams + stateTmp = em.addLocal('v128'); + em.globalGet(globals.pcgStateV).localSet(stateTmp); + } + for (let lane = 0; lane < 4; lane++) { + if (info.readsThread) { + em.localGet(this._vBaseX); + if (lane > 0) em.i32Const(lane).i32Add(); + em.globalSet(globals.threadX); + } + if (info.usesRandom) { + em.localGet(stateTmp).i32x4ExtractLane(lane).globalSet(globals.pcgState); + } + for (const arg of argLocals) { + em.localGet(arg.index); + if (arg.wtype === 'vi32') em.i32x4ExtractLane(lane); + else em.f32x4ExtractLane(lane); + } + em.call(this.mangleFunctionName(functionName)); + if (resultKind !== 'void') em.localSet(resultTmp); + if (info.usesRandom) { + em.localGet(stateTmp).globalGet(globals.pcgState).i32x4ReplaceLane(lane).localSet(stateTmp); + } + if (resultKind !== 'void') { + if (lane === 0) { + em.localGet(resultTmp); + if (resultKind === 'i32') em.i32x4Splat(); + else em.f32x4Splat(); + em.localSet(resultVec); + } else { + em.localGet(resultVec).localGet(resultTmp); + if (resultKind === 'i32') em.i32x4ReplaceLane(lane); + else em.f32x4ReplaceLane(lane); + em.localSet(resultVec); + } + } + } + if (info.readsThread) { + em.localGet(this._vBaseX).globalSet(globals.threadX); + } + if (info.usesRandom) { + em.localGet(stateTmp).globalGet(globals.pcgStateV); + if (this.vMaskDepth > 0) em.localGet(this.vCur); + else em.v128ConstI32x4(-1, -1, -1, -1); + em.v128Bitselect().globalSet(globals.pcgStateV); + } + if (resultKind === 'void') return 'void'; + em.localGet(resultVec); + // Boolean results are 0/1 i32 lanes, the scalar convention + return resultKind === 'i32' ? 'vi32' : 'vf32'; + } + + vMathCall(functionName, ast) { + const em = this.em; + if (functionName === 'random') { + this.usesRandom = true; + // only the active lanes' states may advance (see _emitPcgRandomVector) + if (this.vMaskDepth > 0) em.localGet(this.vCur); + else em.v128ConstI32x4(-1, -1, -1, -1); + em.call('pcg_random_v'); + return 'vf32'; + } + const emitArg = (argument) => { + switch (this.getType(argument)) { + case 'Integer': + this.vCastValueToFloat(argument); + break; + case 'LiteralInteger': + this.vCastLiteralToFloat(argument); + break; + default: + this.vCoerce(this.vexpr(argument), 'vf32'); + } + }; + const nativeOp = VECTOR_MATH_NATIVE_OPS[functionName]; + if (nativeOp) { + emitArg(ast.arguments[0]); + em[nativeOp](); + return 'vf32'; + } + switch (functionName) { + case 'round': + emitArg(ast.arguments[0]); + em.v128ConstF32x4(0.5, 0.5, 0.5, 0.5).f32x4Add().f32x4Floor(); + return 'vf32'; + case 'fround': + emitArg(ast.arguments[0]); + return 'vf32'; + case 'min': + case 'max': { + // f32x4.min/max share f32.min/max NaN and -0 semantics + const op = functionName === 'min' ? 'f32x4Min' : 'f32x4Max'; + emitArg(ast.arguments[0]); + for (let i = 1; i < ast.arguments.length; i++) { + emitArg(ast.arguments[i]); + em[op](); + } + return 'vf32'; + } + case 'imul': + emitArg(ast.arguments[0]); + em.i32x4TruncSatF32x4S(); + emitArg(ast.arguments[1]); + em.i32x4TruncSatF32x4S(); + em.i32x4Mul().f32x4ConvertI32x4S(); + return 'vf32'; + case 'clz32': { + emitArg(ast.arguments[0]); + em.i32x4TruncSatF32x4U(); + const t = em.addLocal('v128'); + em.localSet(t); + // no SIMD clz: lane-scalarized through the same scalar opcode + em.localGet(t).i32x4ExtractLane(0).i32Clz().i32x4Splat(); + for (let lane = 1; lane < 4; lane++) { + em.localGet(t).i32x4ExtractLane(lane).i32Clz().i32x4ReplaceLane(lane); + } + em.f32x4ConvertI32x4S(); + return 'vf32'; + } + default: { + const arity = MATH_IMPORT_ARITY[functionName]; + if (!arity) { + throw this.astErrorOutput(`WebAssembly backend does not yet support Math.${ functionName }`, ast); + } + this.usedMathImports.add(functionName); + if (arity === 1) { + emitArg(ast.arguments[0]); + const t = em.addLocal('v128'); + em.localSet(t); + this.vLaneCall1('math_' + functionName, t); + } else { + const a = em.addLocal('v128'); + const b = em.addLocal('v128'); + emitArg(ast.arguments[0]); + em.localSet(a); + emitArg(ast.arguments[1]); + em.localSet(b); + this.vLaneCall2('math_' + functionName, a, b); + } + return 'vf32'; + } + } + } + + // transcendentals have no SIMD form: 4 extracts through the same scalar + // import keep every lane bit-identical to the scalar path + vLaneCall1(name, argLocal) { + const em = this.em; + em.localGet(argLocal).f32x4ExtractLane(0).call(name).f32x4Splat(); + for (let lane = 1; lane < 4; lane++) { + em.localGet(argLocal).f32x4ExtractLane(lane).call(name).f32x4ReplaceLane(lane); + } + } + + vLaneCall2(name, aLocal, bLocal) { + const em = this.em; + em.localGet(aLocal).f32x4ExtractLane(0).localGet(bLocal).f32x4ExtractLane(0).call(name).f32x4Splat(); + for (let lane = 1; lane < 4; lane++) { + em.localGet(aLocal).f32x4ExtractLane(lane).localGet(bLocal).f32x4ExtractLane(lane).call(name).f32x4ReplaceLane(lane); + } + } + + vexprMember(mNode) { + const details = this.getMemberExpressionDetails(mNode); + if (!details) { + throw this.astErrorOutput('Unexpected expression', mNode); + } + const { signature, name, property, xProperty, yProperty, zProperty } = details; + const em = this.em; + switch (signature) { + case 'value.thread.value': + case 'this.thread.value': { + if (name !== 'x') { + throw this.astErrorOutput(`internal: thread.${ name } is uniform along the lane axis`, mNode); + } + this.readsThread = true; + em.globalGet(this.assembler.globals.threadX).i32x4Splat(); + em.v128ConstI32x4(0, 1, 2, 3).i32x4Add(); + return 'vi32'; + } + case 'value.value': { + const component = { r: 0, g: 1, b: 2, a: 3 } [property]; + if (component !== undefined) { + const local = this.locals.get(name); + if (local && local.kind === 'vvec' && component < local.n) { + em.localGet(local.indices[component]); + return 'vf32'; + } + } + throw this.astErrorOutput('Unexpected expression', mNode); + } + case 'value[]': + case 'value[][]': + case 'value[][][]': + case 'value[][][][]': { + const local = this.locals.get(name); + if (local && (local.kind === 'vec' || local.kind === 'vvec')) { + if (signature !== 'value[]') { + throw this.astErrorOutput('Unexpected expression', mNode); + } + return this.vVecIndex(local, xProperty); + } + return this.vGather('arrays', name, xProperty, yProperty, zProperty, mNode); + } + case 'this.constants.value[]': + case 'this.constants.value[][]': + case 'this.constants.value[][][]': + case 'this.constants.value[][][][]': + return this.vGather('constantArrays', name, xProperty, yProperty, zProperty, mNode); + case 'fn()[]': + throw this.astErrorOutput('WebAssembly backend does not yet support indexing a function call result', mNode); + default: + throw this.astErrorOutput(`WebAssembly backend does not yet support expression signature "${ signature }"`, mNode); + } + } + + vVecIndex(local, xProperty) { + const em = this.em; + const getComponent = (k) => { + em.localGet(local.indices[k]); + if (local.kind === 'vec') em.f32x4Splat(); + }; + if (xProperty.type === 'Literal' && Number.isInteger(xProperty.value)) { + if (xProperty.value < 0 || xProperty.value >= local.n) { + throw this.astErrorOutput(`index ${ xProperty.value } out of range for Array(${ local.n })`, xProperty); + } + getComponent(xProperty.value); + return 'vf32'; + } + // per-lane component choice: the scalar select chain as bitselects + const idx = em.addLocal('v128'); + this.vEmitIndex(xProperty); + em.localSet(idx); + const acc = em.addLocal('v128'); + getComponent(0); + em.localSet(acc); + for (let k = 1; k < local.n; k++) { + getComponent(k); + em.localGet(acc); + em.localGet(idx).v128ConstI32x4(k, k, k, k).i32x4Eq(); + em.v128Bitselect(); + em.localSet(acc); + } + em.localGet(acc); + return 'vf32'; + } + + vEmitIndex(property) { + if (!property) { + throw new Error('Property not set'); + } + const type = this.getType(property); + switch (type) { + case 'Number': + case 'Float': + this.vCastValueToInteger(property); + return; + case 'LiteralInteger': + this.vCastLiteralToInteger(property); + return; + case 'Integer': { + this.pushState('building-integer'); + const emitted = this.vexpr(property); + this.popState('building-integer'); + this.vCoerce(emitted, 'vi32'); + return; + } + default: + this.vCoerce(this.vexpr(property), 'vi32'); + } + } + + /** + * Lane-varying gather: flat row-major index in i32x4 (the scalar formula + * lane-wise), clamped into the region so lanes a divergent branch turned + * off cannot trap, then 4 scalar loads + lane inserts — v128 has no + * gather. In-bounds lanes are untouched by the clamp. + */ + vGather(table, name, xProperty, yProperty, zProperty, mNode) { + const em = this.em; + const layout = this.assembler.layout[table][name]; + if (!layout) { + throw this.astErrorOutput(`no memory layout for "${ name }" — arrays are only readable as kernel arguments or constants`, mNode); + } + this.vEmitIndex(xProperty); + if (yProperty) { + this.vEmitIndex(yProperty); + const d = layout.dims[0]; + em.v128ConstI32x4(d, d, d, d).i32x4Mul().i32x4Add(); + } + if (zProperty) { + this.vEmitIndex(zProperty); + const d = layout.dims[0] * layout.dims[1]; + em.v128ConstI32x4(d, d, d, d).i32x4Mul().i32x4Add(); + } + this.vZero(); + em.i32x4MaxS(); + const max = layout.flatLength - 1; + em.v128ConstI32x4(max, max, max, max).i32x4MinS(); + const idx = em.addLocal('v128'); + em.localSet(idx); + em.localGet(idx).i32x4ExtractLane(0).i32Const(2).i32Shl().f32Load(layout.offset).f32x4Splat(); + for (let lane = 1; lane < 4; lane++) { + em.localGet(idx).i32x4ExtractLane(lane).i32Const(2).i32Shl().f32Load(layout.offset).f32x4ReplaceLane(lane); + } + return 'vf32'; + } + + // ---------------------------------------------- SIMD uniformity analysis + + /** + * Conservative thread-dependence for the SIMD phase: thread.x is the lane + * axis (thread.y/z are uniform across an x-row), Math.random is per-cell, + * user helper calls may read thread state internally, tainted locals + * propagate in walk order and never clear. + */ + isThreadDependent(ast) { + if (!ast || typeof ast !== 'object') return false; + if (Array.isArray(ast)) return ast.some(node => this.isThreadDependent(node)); + switch (ast.type) { + case 'MemberExpression': { + const signature = this.getVariableSignature(ast); + if (signature === 'this.thread.value' || signature === 'value.thread.value') { + return ast.property.name === 'x'; + } + break; + } + case 'CallExpression': + if (this.isAstMathFunction(ast)) { + if (ast.callee.property.name === 'random') return true; + break; + } + return true; + case 'Identifier': + return this.taintedLocals ? this.taintedLocals.has(ast.name) : false; + case 'ThisExpression': + return false; + } + for (const key in ast) { + if (key === 'loc' || key === 'start' || key === 'end' || key === 'parent') continue; + const child = ast[key]; + if (child && typeof child === 'object' && this.isThreadDependent(child)) return true; + } + return false; + } + + recordUniformity(kind, testAst) { + if (!this._analysisPass) return; + this.uniformity.push({ + kind, + threadDependent: testAst ? this.isThreadDependent(testAst) : true, + }); + } +} + +module.exports = { + WebAssemblyFunctionNode +}; \ No newline at end of file diff --git a/src/backend/web-assembly/kernel.js b/src/backend/web-assembly/kernel.js new file mode 100644 index 00000000..79e4a1a3 --- /dev/null +++ b/src/backend/web-assembly/kernel.js @@ -0,0 +1,986 @@ +const { Kernel } = require('../kernel'); +const { FunctionBuilder } = require('../function-builder'); +const { WebAssemblyFunctionNode } = require('./function-node'); +const { WasmModuleBuilder } = require('./wasm-builder'); +const { WebAssemblyWorkerPool } = require('./worker-pool'); +const { utils } = require('../../utils'); +const { Input } = require('../../input'); + +const features = Object.freeze({ + kernelMap: false, + isIntegerDivisionAccurate: true, + isSpeedTacticSupported: false, + isTextureFloat: true, + isDrawBuffers: false, + kernelMapSize: 0, + channelCount: 1, + maxTextureSize: Infinity, + isFloatRead: true, +}); + +const PAGE_BYTES = 65536; + +let simdSupported = null; +let threadsSupported = null; +// worker-side instance caches key on this, so it must be unique across every +// kernel and size signature in the process, not per kernel +let nextEntryId = 1; + +/** + * @desc Kernel implementation over a generated WebAssembly module. run() is + * fully synchronous: the module exports `run(start, end, seed)` which loops + * cells [start, end) in wasm, calling the compiled kernel body per cell with + * thread ids and data_index in mutable globals. + * + * Memory is one imported env.memory laid out `[ args | constants | output ]` + * (regions 16-byte aligned); every offset and dimension bakes into the + * bytecode as i32 consts, so a size change (dynamicArguments/dynamicOutput) + * rebuilds the module — compiles are fast at these sizes and instances are + * cached by size signature like signature-switched kernels. + * + * Math.random is PCG (RXS-M-XS on u32 state), the web-gpu kernel's exact + * stream: per-cell state seeds from (seed + cellIndex * 0x9E3779B9) then one + * LCG advance, so draws are independent of any future work split; unseeded + * runs reseed from the host per run, `randomSeed` pins the stream bit-exact. + */ +class WebAssemblyKernel extends Kernel { + static get isSupported() { + if (typeof WebAssembly !== 'object' || WebAssembly === null) return false; + return WebAssembly.validate(new Uint8Array([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00])); + } + + static get isSIMDSupported() { + if (simdSupported === null) { + try { + const builder = new WasmModuleBuilder(); + builder.addFunction('t', { params: [], results: [] }).v128ConstI32x4(0, 0, 0, 0).drop(); + simdSupported = WebAssembly.validate(builder.toBytes()); + } catch (e) { + simdSupported = false; + } + } + return simdSupported; + } + + static get isThreadsSupported() { + if (threadsSupported === null) { + try { + if (typeof SharedArrayBuffer === 'undefined') { + threadsSupported = false; + } else { + const builder = new WasmModuleBuilder(); + builder.addMemoryImport(1, 1, true); + const memory = new WebAssembly.Memory({ initial: 1, maximum: 1, shared: true }); + new WebAssembly.Instance(new WebAssembly.Module(builder.toBytes()), { env: { memory } }); + threadsSupported = true; + } + } catch (e) { + threadsSupported = false; + } + } + return threadsSupported; + } + + static isContextMatch(context) { + return false; + } + + static getFeatures() { + return features; + } + + static get features() { + return features; + } + + static get mode() { + return 'webasm'; + } + + static getSignature(kernel, argumentTypes) { + return 'webasm' + (argumentTypes.length > 0 ? ':' + argumentTypes.join(',') : ''); + } + + static destroyContext(context) {} + + static nativeFunctionArguments() { + throw new Error('WebAssembly backend does not yet support native functions'); + } + + static nativeFunctionReturnType() { + throw new Error('WebAssembly backend does not yet support native functions'); + } + + static combineKernels() { + throw new Error('WebAssembly backend does not yet support combineKernels'); + } + + constructor(source, settings) { + super(source, settings); + // must exist before mergeSettings so `poolSize` can arrive as a setting; + // null means the pool decides (hardwareConcurrency) + this.poolSize = null; + this.mergeSettings(source.settings || settings); + if (this.precision === null) { + this.precision = 'single'; + } + // precision 'unsigned' is accepted and treated as single: wasm has no + // packed storage, numbers are identical, and this backend sits in the + // auto chain so it must not reject settings cpu accepts + + this.threadDim = null; + this.componentCount = 1; + // wasm memories are near-invisible to JS heap accounting and each one + // also holds a large virtual guard reservation, so an unbounded + // per-size-signature cache can pin hundreds of MB the GC feels no + // pressure to collect (#870); size sweeps evict LRU past this bound + this.moduleCacheLimit = 8; + this.functionBuilder = null; + this.tracedFunctions = null; + this.usesRandom = false; + this.usedMathImports = null; + this._moduleCache = new Map(); + this._active = null; + this._lastRunPath = null; + this._pool = null; + // threaded runs serialize on this chain: they share one wasm memory, so + // a second call must not overwrite the args region mid-run. It tracks + // settlement, never failure, so one rejected run cannot wedge the kernel + this._threadedTail = Promise.resolve(); + } + + initCanvas() { + // graphical kernels degrade to cpu at build, but kernel.canvas must be a + // real element from creation -- the house contract on every backend, and + // the fallback renders into this same canvas so its identity never + // changes. In Node this stays null and the cpu fallback's 'no canvas + // available' throw is exact parity with mode: 'cpu'. + if (this.graphical && typeof document !== 'undefined') { + return document.createElement('canvas'); + } + return null; + } + + initContext() { + return null; + } + + initPlugins(settings) { + return []; + } + + setOutput(output) { + const newOutput = this.toKernelOutput(output); + if (this.built && !this.dynamicOutput) { + throw new Error('Resizing a kernel with dynamicOutput: false is not possible'); + } + this.output = newOutput; + return this; + } + + toString() { + throw new Error('WebAssembly backend does not yet support toString'); + } + + build() { + if (this.built) return; + // a destroyed kernel that gets called again rebuilds -- including a fresh + // worker pool. gpu.destroy() must be able to reach that pool, so a + // revived kernel re-registers with the GPU that spliced it out. + if (this.gpu && this.gpu.kernels && this.gpu.kernels.indexOf(this) === -1) { + this.gpu.kernels.push(this); + } + if (this.graphical) { + return this.requestFallback(arguments, 'graphical mode is not supported on the webasm backend'); + } + if (this.subKernels && this.subKernels.length > 0) { + return this.requestFallback(arguments, 'kernel maps are not supported on the webasm backend'); + } + // pipeline is accepted the way the cpu backend accepts it: there is no + // device memory to pipeline into, so the result is the plain typed array + // the run already produces -- a fresh copy per call, valid as input to + // any downstream kernel (#868) + this.setupConstants(); + this.setupArguments(arguments); + for (let i = 0; i < this.argumentTypes.length; i++) { + switch (this.argumentTypes[i]) { + case 'Array': + case 'Input': + case 'Number': + case 'Float': + case 'Integer': + case 'Boolean': + continue; + default: + // HTMLImage, textures, pipeline handles: degrade like the GL + // backends do for unsupported kernel values + return this.requestFallback(arguments, + `argument "${ this.argumentNames[i] }" of type ${ this.argumentTypes[i] } is not supported on the webasm backend`); + } + } + for (const name in this.constantTypes) { + switch (this.constantTypes[name]) { + case 'Array': + case 'Input': + case 'Number': + case 'Float': + case 'Integer': + case 'Boolean': + continue; + default: + return this.requestFallback(arguments, + `constant "${ name }" of type ${ this.constantTypes[name] } is not supported on the webasm backend`); + } + } + this.validateSettings(arguments); + const threadDim = this.threadDim = Array.from(this.output); + while (threadDim.length < 3) { + threadDim.push(1); + } + if (!this.translateSource()) { + return this.requestFallback(arguments, + `return type ${ this.returnType } is not supported on the webasm backend`); + } + this.buildSignature(arguments); + this._instantiate(this._entryKey(arguments), arguments); + this.built = true; + } + + validateSettings(args) { + if (!this.output || this.output.length === 0) { + if (args.length !== 1) { + throw new Error('Auto output only supported for kernels with only one input'); + } + const argType = utils.getVariableType(args[0], this.strictIntegers); + if (argType === 'Array') { + this.output = Array.from(utils.getDimensions(args[0])); + } else { + throw new Error('Auto output not supported for input type: ' + argType); + } + } + this.checkOutput(); + } + + /** + * The analysis pass: FunctionBuilder's trace runs each node's toString(), + * which for this backend resolves types and collects math-import/random + * usage without emitting a byte. Returns false for a return type this + * backend cannot store, so build() can degrade to cpu. + */ + translateSource() { + const functionBuilder = this.functionBuilder = FunctionBuilder.fromKernel(this, WebAssemblyFunctionNode); + this.tracedFunctions = functionBuilder.traceFunctionCalls('kernel', []); + if (!this.returnType) { + this.returnType = functionBuilder.getKernelResultType(); + } + switch (this.returnType) { + case 'Number': + case 'Float': + case 'Integer': + case 'LiteralInteger': + this.componentCount = 1; + break; + case 'Array(2)': + this.componentCount = 2; + break; + case 'Array(3)': + this.componentCount = 3; + break; + case 'Array(4)': + this.componentCount = 4; + break; + default: + return false; + } + this.usesRandom = false; + this.usedMathImports = new Set(); + for (const name of this.tracedFunctions) { + const node = functionBuilder.functionMap[name]; + if (!node) continue; + if (node.usesRandom) this.usesRandom = true; + for (const importName of node.usedMathImports) { + this.usedMathImports.add(importName); + } + } + return true; + } + + /** + * `[ args | constants | output ]`, each record 16-byte aligned, flat f32 + * (scalars are one 4-byte slot, Integer/Boolean viewed as i32). Dims come + * from the actual argument values, so the layout is per size signature. + */ + computeLayout(args) { + const align16 = value => Math.ceil(value / 16) * 16; + let offset = 0; + const arrays = {}; + const scalars = {}; + for (let i = 0; i < this.argumentTypes.length; i++) { + const name = this.argumentNames[i]; + const type = this.argumentTypes[i]; + if (type === 'Array' || type === 'Input') { + const dims = this.valueDimensions(args[i]); + const flatLength = dims[0] * dims[1] * dims[2]; + arrays[name] = { index: i, offset, dims, flatLength }; + offset = align16(offset + flatLength * 4); + } else { + scalars[name] = { index: i, offset, type }; + offset = align16(offset + 4); + } + } + const constantArrays = {}; + if (this.constants) { + for (const name in this.constants) { + if (!this.constants.hasOwnProperty(name)) continue; + const type = this.constantTypes[name]; + if (type === 'Array' || type === 'Input') { + const dims = this.valueDimensions(this.constants[name]); + const flatLength = dims[0] * dims[1] * dims[2]; + constantArrays[name] = { offset, dims, flatLength }; + offset = align16(offset + flatLength * 4); + } + } + } + return { + arrays, + scalars, + constantArrays, + outputOffset: offset + }; + } + + valueDimensions(value) { + const dims = value instanceof Input ? + Array.from(value.size) : + Array.from(utils.getDimensions(value)); + while (dims.length < 3) { + dims.push(1); + } + return dims; + } + + _computeSizeSignature(args) { + const parts = [this.output.join('x')]; + for (let i = 0; i < this.argumentTypes.length; i++) { + const type = this.argumentTypes[i]; + if (type === 'Array' || type === 'Input') { + parts.push(this.valueDimensions(args[i]).join('x')); + } + } + return parts.join('|'); + } + + /** + * Threaded only under the async contract, only when threads exist, and + * only when the output is big enough (4096 cells) that splitting beats + * the postMessage round trip. + */ + _threadable() { + if (this.asyncMode !== true || !WebAssemblyKernel.isThreadsSupported) return false; + const [tx, ty, tz] = this.threadDim; + return tx * ty * tz >= 4096; + } + + /** + * Sharedness is part of the cache key: a wasm memory import declares + * shared or not at compile time, so the same size signature needs a + * distinct module when the async contract routes it to the pool. + */ + _entryKey(args) { + return this._computeSizeSignature(args) + (this._threadable() ? '|shared' : ''); + } + + /** + * The bytecode pass plus the run(start, end, seed) driver. The driver + * derives thread ids from the flat cell index with baked output dims + * (x fastest: x + sizeX * (y + sizeY * z), the storage order every + * backend shares) and seeds the PCG state per cell. + */ + _assembleModule(layout, cells, shared) { + const builder = new WasmModuleBuilder(); + const totalBytes = layout.outputOffset + cells * this.componentCount * 4; + const initial = Math.ceil(totalBytes / PAGE_BYTES) + 16; + const maximum = Math.max(initial, 4096); + builder.addMemoryImport(initial, maximum, shared); + + const mathImports = Array.from(this.usedMathImports).sort(); + for (const name of mathImports) { + const params = name === 'pow' || name === 'atan2' ? ['f32', 'f32'] : ['f32']; + builder.addFuncImport('math_' + name, params, ['f32']); + } + + const globals = { + threadX: builder.addGlobal('i32', true, 0), + threadY: builder.addGlobal('i32', true, 0), + threadZ: builder.addGlobal('i32', true, 0), + dataIndex: builder.addGlobal('i32', true, 0), + }; + if (this.usesRandom) { + globals.pcgState = builder.addGlobal('i32', true, 0); + this._emitPcgRandom(builder, globals.pcgState); + } + + const assembler = { module: builder, layout, globals }; + for (let i = this.tracedFunctions.length - 1; i >= 0; i--) { + const name = this.tracedFunctions[i]; + if (name === 'kernel') continue; + const node = this.functionBuilder.functionMap[name]; + if (!node) continue; // math names in the trace have no node + // setOutput replaces the kernel's output array; the baked + // this.output.x/y/z consts must follow it on every re-emission + node.output = this.output; + node.emitFunction(assembler); + } + this.functionBuilder.functionMap['kernel'].output = this.output; + this.functionBuilder.functionMap['kernel'].emitFunction(assembler); + + const [sizeX, sizeY] = this.threadDim; + const run = builder.addFunction('run', { + params: ['i32', 'i32', 'i32'], + locals: ['i32'] + }); + const cell = 3; + run.localGet(0).localSet(cell); + if (this.output.length === 1) { + run.i32Const(0).globalSet(globals.threadY); + run.i32Const(0).globalSet(globals.threadZ); + } else if (this.output.length === 2) { + run.i32Const(0).globalSet(globals.threadZ); + } + run.block(); + run.localGet(cell).localGet(1).i32GeS().brIf(0); + run.loop(); + run.localGet(cell).globalSet(globals.dataIndex); + if (this.output.length === 1) { + run.localGet(cell).globalSet(globals.threadX); + } else if (this.output.length === 2) { + run.localGet(cell).i32Const(sizeX).i32RemU().globalSet(globals.threadX); + run.localGet(cell).i32Const(sizeX).i32DivU().globalSet(globals.threadY); + } else { + run.localGet(cell).i32Const(sizeX).i32RemU().globalSet(globals.threadX); + run.localGet(cell).i32Const(sizeX).i32DivU().i32Const(sizeY).i32RemU().globalSet(globals.threadY); + run.localGet(cell).i32Const(sizeX * sizeY).i32DivU().globalSet(globals.threadZ); + } + if (this.usesRandom) { + run.localGet(2).localGet(cell).i32Const(0x9E3779B9 | 0).i32Mul().i32Add() + .i32Const(747796405).i32Mul().i32Const(2891336453 | 0).i32Add() + .globalSet(globals.pcgState); + } + run.call('kernel'); + run.localGet(cell).i32Const(1).i32Add().localSet(cell); + run.localGet(cell).localGet(1).i32LtS().brIf(0); + run.end(); + run.end(); + builder.exportFunction('run'); + + if (WebAssemblyKernel.isSIMDSupported) { + if (this.usesRandom) { + globals.pcgStateV = builder.addGlobal('v128', true, 0); + this._emitPcgRandomVector(builder, globals.pcgStateV); + } + // coarse info for lane-scalarized helper calls: whether ANY traced + // helper reads thread state or draws random, so the call site knows + // to swap thread.x / PCG state per lane + let helperInfo = null; + for (const name of this.tracedFunctions) { + if (name === 'kernel') continue; + const node = this.functionBuilder.functionMap[name]; + if (!node) continue; + if (!helperInfo) helperInfo = { readsThread: false, usesRandom: false }; + if (node.readsThread) helperInfo.readsThread = true; + if (node.usesRandom) helperInfo.usesRandom = true; + } + assembler.helperInfo = helperInfo; + this.functionBuilder.functionMap['kernel'].emitVectorFunction(assembler); + this._emitRunSimd(builder, globals); + builder.exportFunction('run_simd'); + } + + return { + bytes: builder.toBytes(), + initial, + maximum + }; + } + + /** + * run_simd(start, end, seed): 4 consecutive x cells per step. The caller + * guarantees (end - start) % 4 == 0 AND that no quad crosses an x-row, so + * thread.y/z are uniform per quad and thread.x is base + [0,1,2,3]. + */ + _emitRunSimd(builder, globals) { + const [sizeX, sizeY] = this.threadDim; + const run = builder.addFunction('run_simd', { + params: ['i32', 'i32', 'i32'], + locals: ['i32'] + }); + const cell = 3; + run.localGet(0).localSet(cell); + if (this.output.length === 1) { + run.i32Const(0).globalSet(globals.threadY); + run.i32Const(0).globalSet(globals.threadZ); + } else if (this.output.length === 2) { + run.i32Const(0).globalSet(globals.threadZ); + } + run.block(); + run.localGet(cell).localGet(1).i32GeS().brIf(0); + run.loop(); + run.localGet(cell).globalSet(globals.dataIndex); + if (this.output.length === 1) { + run.localGet(cell).globalSet(globals.threadX); + } else if (this.output.length === 2) { + run.localGet(cell).i32Const(sizeX).i32RemU().globalSet(globals.threadX); + run.localGet(cell).i32Const(sizeX).i32DivU().globalSet(globals.threadY); + } else { + run.localGet(cell).i32Const(sizeX).i32RemU().globalSet(globals.threadX); + run.localGet(cell).i32Const(sizeX).i32DivU().i32Const(sizeY).i32RemU().globalSet(globals.threadY); + run.localGet(cell).i32Const(sizeX * sizeY).i32DivU().globalSet(globals.threadZ); + } + if (this.usesRandom) { + // the scalar per-cell seeding lane-wise, so draws are independent of + // stride and split: (seed + cell*GOLDEN)*LCG_MUL + LCG_ADD + run.localGet(cell).i32x4Splat().v128ConstI32x4(0, 1, 2, 3).i32x4Add(); + run.v128ConstI32x4(0x9E3779B9 | 0, 0x9E3779B9 | 0, 0x9E3779B9 | 0, 0x9E3779B9 | 0).i32x4Mul(); + run.localGet(2).i32x4Splat().i32x4Add(); + run.v128ConstI32x4(747796405, 747796405, 747796405, 747796405).i32x4Mul(); + run.v128ConstI32x4(2891336453 | 0, 2891336453 | 0, 2891336453 | 0, 2891336453 | 0).i32x4Add(); + run.globalSet(globals.pcgStateV); + } + run.call('kernel_simd'); + run.localGet(cell).i32Const(4).i32Add().localSet(cell); + run.localGet(cell).localGet(1).i32LtS().brIf(0); + run.end(); + run.end(); + } + + /** + * The scalar pcg_random lane-wise on an i32x4 state. Uniform-count shifts + * vectorize; the RXS shift count is per-lane, so that one step runs + * through the scalar opcodes per lane. The mask parameter predicates the + * state advance: a draw evaluated for an inactive lane (the untaken side + * of a divergent branch) must not advance that lane's stream, or every + * later draw in reconverged code desynchronizes from the scalar run. + */ + _emitPcgRandomVector(builder, stateGlobal) { + const em = builder.addFunction('pcg_random_v', { params: ['v128'], results: ['v128'] }); + const s = em.addLocal('v128'); + const w = em.addLocal('i32'); + em.globalGet(stateGlobal) + .v128ConstI32x4(747796405, 747796405, 747796405, 747796405).i32x4Mul() + .v128ConstI32x4(2891336453 | 0, 2891336453 | 0, 2891336453 | 0, 2891336453 | 0).i32x4Add() + .globalGet(stateGlobal).localGet(0).v128Bitselect() + .globalSet(stateGlobal); + em.globalGet(stateGlobal).localSet(s); + em.localGet(s).i32x4ExtractLane(0).localSet(w); + em.localGet(w).localGet(w).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU().i32x4Splat(); + for (let lane = 1; lane < 4; lane++) { + em.localGet(s).i32x4ExtractLane(lane).localSet(w); + em.localGet(w).localGet(w).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU().i32x4ReplaceLane(lane); + } + em.localGet(s).v128Xor(); + em.v128ConstI32x4(277803737, 277803737, 277803737, 277803737).i32x4Mul(); + const wv = em.addLocal('v128'); + em.localTee(wv); + em.i32Const(22).i32x4ShrU().localGet(wv).v128Xor(); + em.i32Const(8).i32x4ShrU(); + em.f32x4ConvertI32x4U(); + em.v128ConstF32x4(16777216, 16777216, 16777216, 16777216).f32x4Div(); + } + + /** + * PCG (permuted congruential, RXS-M-XS output) — the web-gpu kernel's + * pcg_random verbatim in i32 ops: bit-exact across platforms, top 24 bits + * scale into [0, 1) at full f32 mantissa resolution. + */ + _emitPcgRandom(builder, stateGlobal) { + const em = builder.addFunction('pcg_random', { params: [], results: ['f32'] }); + const word = em.addLocal('i32'); + em.globalGet(stateGlobal).i32Const(747796405).i32Mul().i32Const(2891336453 | 0).i32Add().globalSet(stateGlobal); + em.globalGet(stateGlobal) + .globalGet(stateGlobal).i32Const(28).i32ShrU().i32Const(4).i32Add().i32ShrU() + .globalGet(stateGlobal).i32Xor() + .i32Const(277803737).i32Mul() + .localTee(word); + em.i32Const(22).i32ShrU().localGet(word).i32Xor() + .i32Const(8).i32ShrU() + .f32ConvertI32U().f32Const(16777216).f32Div(); + } + + /** + * Frees everything an entry pins. The Memory itself has no explicit + * free, but dropping every reference (including the workers' — their + * instantiations hold the shared buffer) is the most a library can do + * to let it die young (#870). A shared entry defers until the threaded + * tail settles so an in-flight dispatch keeps what it captured. + */ + _releaseEntry(entry) { + const scrub = () => { + entry.instance = null; + entry.module = null; + entry.memory = null; + entry.run = null; + entry.runSimd = null; + entry.f32 = null; + entry.i32 = null; + entry.bytes = null; + }; + if (entry.shared && this._pool) { + const pool = this._pool; + this._threadedTail.then(() => { + pool.release(entry.id); + scrub(); + }, scrub); + } else { + scrub(); + } + } + + _instantiate(entryKey, args) { + let entry = this._moduleCache.get(entryKey); + if (entry) { + // Map order is the LRU order: refresh on hit + this._moduleCache.delete(entryKey); + this._moduleCache.set(entryKey, entry); + } + if (!entry) { + const shared = this._threadable(); + const layout = this.computeLayout(args); + const [tx, ty, tz] = this.threadDim; + const cells = tx * ty * tz; + const { bytes, initial, maximum } = this._assembleModule(layout, cells, shared); + if (!WebAssembly.validate(bytes)) { + throw new Error('WebAssembly backend: generated module failed validation (internal error)'); + } + const memory = shared ? + new WebAssembly.Memory({ initial, maximum, shared: true }) : + new WebAssembly.Memory({ initial, maximum }); + const imports = { env: { memory } }; + for (const name of this.usedMathImports) { + imports.env['math_' + name] = Math[name]; + } + const module = new WebAssembly.Module(bytes); + const instance = new WebAssembly.Instance(module, imports); + entry = { + // what the worker pool needs to re-instantiate elsewhere: the + // compiled Module and shared Memory (both structured-cloneable), + // the import names, and the row width for the SIMD span logic + id: nextEntryId++, + sizeSignature: entryKey, + shared, + layout, + cells, + bytes, + module, + memory, + mathImports: Array.from(this.usedMathImports).sort(), + sizeX: tx, + instance, + run: instance.exports.run, + runSimd: instance.exports.run_simd || null, + f32: new Float32Array(memory.buffer), + i32: new Int32Array(memory.buffer), + }; + for (const name in layout.constantArrays) { + const record = layout.constantArrays[name]; + const value = this.constants[name]; + utils.flattenTo( + value instanceof Input ? value.value : value, + entry.f32.subarray(record.offset / 4, record.offset / 4 + record.flatLength) + ); + } + this._moduleCache.set(entryKey, entry); + while (this._moduleCache.size > Math.max(this.moduleCacheLimit, 1)) { + const oldestKey = this._moduleCache.keys().next().value; + const oldest = this._moduleCache.get(oldestKey); + this._moduleCache.delete(oldestKey); + this._releaseEntry(oldest); + } + } + this._active = entry; + } + + /** + * @desc Self-typed values (GL textures, pipeline handles) pass the base + * check on the assumption that a kernel-value lookup will re-map them; this + * backend has no kernel values, so a texture handed to a kernel built for + * plain arrays would reach utils.flattenTo and crash. Flag it as a type + * mismatch instead: the switched kernel builds for the texture type and + * degrades to cpu through the usual fallback. Guarded on the DECLARED type + * being one this backend supports, so the switched kernel (declared for + * the texture type) does not flag the same value again and loop. + */ + checkArgumentTypes(args) { + super.checkArgumentTypes(args); + if (!this.argumentTypes) return; + const length = Math.min(args.length, this.argumentTypes.length); + for (let i = 0; i < length; i++) { + const value = args[i]; + if (!value || !value.type) continue; + switch (this.argumentTypes[i]) { + case 'Array': + case 'Input': + case 'Number': + case 'Float': + case 'Integer': + case 'Boolean': + this.switchKernels({ + type: 'argumentTypeMismatch', + index: i, + needed: utils.getVariableType(value, this.strictIntegers), + }); + break; + } + } + } + + run() { + if (!this.built) { + this.build.apply(this, arguments); + if (this.fallbackRequested) return null; + } + const threadDim = this.threadDim = Array.from(this.output); + while (threadDim.length < 3) { + threadDim.push(1); + } + const entryKey = this._entryKey(arguments); + if (!this._active || this._active.sizeSignature !== entryKey) { + const previous = this._active ? this._active.layout.arrays : {}; + for (const name in previous) { + const record = previous[name]; + const dims = this.valueDimensions(arguments[record.index]); + if (!this.dynamicArguments && (dims[0] !== record.dims[0] || dims[1] !== record.dims[1] || dims[2] !== record.dims[2])) { + throw new Error( + `argument "${ name }" changed size from [${ record.dims.join(', ') }] to [${ dims.join(', ') }]; ` + + `use dynamicArguments: true for varying input sizes`); + } + } + this._instantiate(entryKey, arguments); + } + if (this._active.shared && this._threadable()) { + return this._runThreaded(arguments); + } + const { layout, cells, f32, i32, run, runSimd } = this._active; + + for (const name in layout.arrays) { + const record = layout.arrays[name]; + const value = arguments[record.index]; + utils.flattenTo( + value instanceof Input ? value.value : value, + f32.subarray(record.offset / 4, record.offset / 4 + record.flatLength) + ); + } + for (const name in layout.scalars) { + const record = layout.scalars[name]; + const value = arguments[record.index]; + if (record.type === 'Integer') { + i32[record.offset / 4] = value | 0; + } else if (record.type === 'Boolean') { + i32[record.offset / 4] = value ? 1 : 0; + } else { + f32[record.offset / 4] = value; + } + } + + let seed = 0; + if (this.usesRandom) { + seed = this.randomSeed !== null ? + (this.randomSeed >>> 0) : + ((Math.random() * 0x100000000) >>> 0); + } + seed = seed | 0; + // SIMD quads must not cross an x-row (thread.y/z are uniform per quad): + // rows a multiple of 4 wide vectorize in one span, otherwise each row + // gets a vector span plus a scalar epilogue for its remainder cells + if (runSimd && cells > 0) { + const sizeX = threadDim[0]; + if ((sizeX & 3) === 0) { + runSimd(0, cells, seed); + this._lastRunPath = 'simd'; + } else { + const quadSpan = sizeX & ~3; + const rows = cells / sizeX; + for (let row = 0; row < rows; row++) { + const base = row * sizeX; + if (quadSpan > 0) runSimd(base, base + quadSpan, seed); + run(base + quadSpan, base + sizeX, seed); + } + this._lastRunPath = quadSpan > 0 ? 'simd+scalar-tail' : 'scalar'; + } + } else { + run(0, cells, seed); + this._lastRunPath = 'scalar'; + } + + const base = layout.outputOffset / 4; + const data = f32.slice(base, base + cells * this.componentCount); + return this._shapeOutput(data, Array.from(this.output), this.componentCount); + } + + /** + * The pool path, only ever reached under the async contract. Two timing + * constraints shape it: arguments must be sampled at CALL time (the sync + * contract's semantics), but the shared args region may still be feeding + * an in-flight run — so arguments flatten into staging copies now and are + * copied into wasm memory only when this run's turn on the memory comes + * up (`_threadedTail`). The seed is also drawn now so an unseeded kernel + * reseeds per call, not per settlement order. + * + * The split follows the contract: min(pool, ceil(cells/4096)) contiguous + * ranges, each start aligned down to a multiple of 4 so every worker can + * enter run_simd; the last worker absorbs the tail. + */ + _runThreaded(args) { + const entry = this._active; + const { layout, cells } = entry; + const staged = []; + for (const name in layout.arrays) { + const record = layout.arrays[name]; + const value = args[record.index]; + const flat = new Float32Array(record.flatLength); + utils.flattenTo(value instanceof Input ? value.value : value, flat); + staged.push({ record, flat }); + } + const scalarValues = []; + for (const name in layout.scalars) { + const record = layout.scalars[name]; + scalarValues.push({ record, value: args[record.index] }); + } + let seed = 0; + if (this.usesRandom) { + seed = this.randomSeed !== null ? + (this.randomSeed >>> 0) : + ((Math.random() * 0x100000000) >>> 0); + } + seed = seed | 0; + if (!this._pool) { + this._pool = new WebAssemblyWorkerPool(this.poolSize || undefined); + } + const pool = this._pool; + const componentCount = this.componentCount; + const output = Array.from(this.output); + const result = this._threadedTail.then(() => { + // destroy() scrubs entries; a run queued behind the tail must reject + // cleanly rather than dereference the scrubbed views + if (!entry.f32) { + throw new Error('WebAssembly kernel was destroyed'); + } + for (let i = 0; i < staged.length; i++) { + entry.f32.set(staged[i].flat, staged[i].record.offset / 4); + } + for (let i = 0; i < scalarValues.length; i++) { + const { record, value } = scalarValues[i]; + if (record.type === 'Integer') { + entry.i32[record.offset / 4] = value | 0; + } else if (record.type === 'Boolean') { + entry.i32[record.offset / 4] = value ? 1 : 0; + } else { + entry.f32[record.offset / 4] = value; + } + } + const workerCount = Math.min(pool.size, Math.ceil(cells / 4096)); + let chunk = Math.ceil(cells / workerCount) & ~3; + if (chunk < 4) chunk = 4; + const tasks = []; + for (let i = 0; i < workerCount; i++) { + const start = i * chunk; + if (start >= cells) break; + tasks.push({ + start, + end: i === workerCount - 1 ? cells : Math.min(start + chunk, cells), + seed, + }); + } + this._lastRunPath = 'threaded'; + return pool.dispatch(entry, tasks).then(() => { + if (!entry.f32) { + throw new Error('WebAssembly kernel was destroyed'); + } + const base = layout.outputOffset / 4; + // slice copies out of the SharedArrayBuffer, so the caller's result + // is ordinary non-shared data + const data = entry.f32.slice(base, base + cells * componentCount); + return this._shapeOutput(data, output, componentCount); + }); + }); + this._threadedTail = result.then(() => undefined, () => undefined); + return result; + } + + /** + * The output region is tightly packed, so scalar returns reuse the + * memory-optimized erectors; Array(n) returns are stride n, shaped + * locally — the web-gpu kernel's exact conventions. + */ + _shapeOutput(data, output, componentCount) { + const [width, height, depth] = [output[0], output[1] || 1, output[2] || 1]; + if (componentCount === 1) { + switch (output.length) { + case 1: + return utils.erectMemoryOptimizedFloat(data, width); + case 2: + return utils.erectMemoryOptimized2DFloat(data, width, height); + default: + return utils.erectMemoryOptimized3DFloat(data, width, height, depth); + } + } + const n = componentCount; + const erectRow = (offset) => { + const row = new Array(width); + for (let x = 0; x < width; x++) { + row[x] = data.subarray(offset + x * n, offset + x * n + n); + } + return row; + }; + switch (output.length) { + case 1: + return erectRow(0); + case 2: { + const rows = new Array(height); + for (let y = 0; y < height; y++) { + rows[y] = erectRow(y * width * n); + } + return rows; + } + default: { + const layers = new Array(depth); + for (let z = 0; z < depth; z++) { + const rows = new Array(height); + for (let y = 0; y < height; y++) { + rows[y] = erectRow((z * height + y) * width * n); + } + layers[z] = rows; + } + return layers; + } + } + } + + destroy(removeCanvasReferences) { + if (this._pool) { + this._pool.destroy(); + this._pool = null; + } + this._threadedTail = Promise.resolve(); + // scrub entries rather than only dropping the map: anything still + // holding the kernel (the run shortcut closure, user code) would + // otherwise keep every cached wasm memory alive with it (#870). The + // pool is already destroyed, so no dispatch holds an entry. + for (const entry of this._moduleCache.values()) { + entry.shared = false; + this._releaseEntry(entry); + } + this._moduleCache = new Map(); + this._active = null; + this.built = false; + if (this.gpu && this.gpu.kernels) { + const index = this.gpu.kernels.indexOf(this); + if (index !== -1) { + this.gpu.kernels.splice(index, 1); + } + } + } +} + +module.exports = { + WebAssemblyKernel +}; \ No newline at end of file diff --git a/src/backend/web-assembly/wasm-builder.js b/src/backend/web-assembly/wasm-builder.js new file mode 100644 index 00000000..cfc3c155 --- /dev/null +++ b/src/backend/web-assembly/wasm-builder.js @@ -0,0 +1,720 @@ +/** + * @desc [INTERNAL] Assembles a complete WebAssembly binary (Uint8Array) + * from typed builder calls. No AST knowledge lives here — the function-node + * drives one emitter method per wasm opcode. Hand-rolled because the + * browser bundle cannot carry a wasm toolchain: the encoder is just + * sections + LEB128, and the scalar/SIMD subset this backend needs is + * fixed. + * + * Index spaces: function imports occupy indices [0, imports.length) and + * defined functions follow. Call sites therefore reference targets by NAME + * and are patched at toBytes(), so imports and functions may be declared in + * any order. The patch slot is a 5-byte non-minimal ULEB128 — legal for u32 + * (ceil(32/7) bytes, zero spare bits in the last byte). + */ + +const VAL_TYPES = { + i32: 0x7f, + i64: 0x7e, + f32: 0x7d, + f64: 0x7c, + v128: 0x7b, +}; + +const SECTION_TYPE = 1; +const SECTION_IMPORT = 2; +const SECTION_FUNCTION = 3; +const SECTION_GLOBAL = 6; +const SECTION_EXPORT = 7; +const SECTION_CODE = 10; + +// shared scratch for f32 <-> bytes; wasm is little-endian by spec +const f32Scratch = new DataView(new ArrayBuffer(16)); + +/** + * Unsigned LEB128. Values are coerced through >>> so i32 bit patterns + * passed as negative JS numbers encode as their u32 counterpart. + */ +function uleb(value, out) { + let v = value >>> 0; + do { + let byte = v & 0x7f; + v >>>= 7; + if (v !== 0) byte |= 0x80; + out.push(byte); + } while (v !== 0); +} + +/** + * Signed LEB128 for i32 immediates. The |0 coercion pins the value into + * i32 range so constants supplied as u32 bit patterns (0x9E3779B9-style + * hash multipliers) encode to the same 32 bits. + */ +function sleb(value, out) { + let v = value | 0; + for (;;) { + const byte = v & 0x7f; + v >>= 7; + if ((v === 0 && (byte & 0x40) === 0) || (v === -1 && (byte & 0x40) !== 0)) { + out.push(byte); + return; + } + out.push(byte | 0x80); + } +} + +/** + * Fixed-width 5-byte ULEB128, written into an existing buffer. Used for + * call-target patch slots whose value is unknown when the body is emitted. + */ +function uleb5At(value, bytes, at) { + let v = value >>> 0; + for (let i = 0; i < 4; i++) { + bytes[at + i] = (v & 0x7f) | 0x80; + v >>>= 7; + } + bytes[at + 4] = v & 0x7f; +} + +/** + * Minimal UTF-8 encoder so the builder stays dependency-free in both Node + * and the browser bundle (no Buffer, no assumed TextEncoder). + */ +function utf8(str, out) { + const bytes = []; + for (let i = 0; i < str.length; i++) { + let code = str.codePointAt(i); + if (code > 0xffff) i++; + if (code < 0x80) { + bytes.push(code); + } else if (code < 0x800) { + bytes.push(0xc0 | (code >> 6), 0x80 | (code & 0x3f)); + } else if (code < 0x10000) { + bytes.push(0xe0 | (code >> 12), 0x80 | ((code >> 6) & 0x3f), 0x80 | (code & 0x3f)); + } else { + bytes.push(0xf0 | (code >> 18), 0x80 | ((code >> 12) & 0x3f), 0x80 | ((code >> 6) & 0x3f), 0x80 | (code & 0x3f)); + } + } + uleb(bytes.length, out); + for (let i = 0; i < bytes.length; i++) out.push(bytes[i]); +} + +function valType(type) { + const byte = VAL_TYPES[type]; + if (byte === undefined) { + throw new Error(`WasmModuleBuilder: unknown value type "${ type }"`); + } + return byte; +} + +// blocktype immediate: 0x40 for empty, else the single result's valtype +function blockType(type) { + if (type === undefined || type === null || type === 'void') return 0x40; + return valType(type); +} + +/** + * @desc Per-function body emitter. One method per opcode, each pushing the + * exact encoding and returning `this` for chaining. Stack discipline is the + * caller's job — anything malformed is caught by WebAssembly.validate, and + * this backend never ships a module that has not been validated. + * + * The function-terminating `end` is appended by the builder at assembly + * time; `end()` here closes blocks/loops/ifs only. This removes the + * easiest way to build an imbalanced body. + */ +class WasmFunctionEmitter { + constructor(builder, name, params, results, locals) { + this.builder = builder; + this.name = name; + this.params = params; + this.results = results; + this.locals = locals.slice(); + this.bytes = []; + this.callFixups = []; + } + + /** + * @returns {number} local index (params occupy the leading indices) + */ + addLocal(type) { + valType(type); + this.locals.push(type); + return this.params.length + this.locals.length - 1; + } + + // control flow ----------------------------------------------------------- + + block(type) { + this.bytes.push(0x02, blockType(type)); + return this; + } + + loop(type) { + this.bytes.push(0x03, blockType(type)); + return this; + } + + if_(type) { + this.bytes.push(0x04, blockType(type)); + return this; + } + + br(depth) { + this.bytes.push(0x0c); + uleb(depth, this.bytes); + return this; + } + + brIf(depth) { + this.bytes.push(0x0d); + uleb(depth, this.bytes); + return this; + } + + /** + * Target is a NAME (import or defined function); the index is patched in + * at toBytes() so declaration order never matters. + */ + call(name) { + this.bytes.push(0x10); + this.callFixups.push({ at: this.bytes.length, name }); + this.bytes.push(0, 0, 0, 0, 0); + return this; + } + + // variables -------------------------------------------------------------- + + localGet(index) { + this.bytes.push(0x20); + uleb(index, this.bytes); + return this; + } + + localSet(index) { + this.bytes.push(0x21); + uleb(index, this.bytes); + return this; + } + + localTee(index) { + this.bytes.push(0x22); + uleb(index, this.bytes); + return this; + } + + globalGet(index) { + this.bytes.push(0x23); + uleb(index, this.bytes); + return this; + } + + globalSet(index) { + this.bytes.push(0x24); + uleb(index, this.bytes); + return this; + } + + // constants -------------------------------------------------------------- + + i32Const(value) { + this.bytes.push(0x41); + sleb(value, this.bytes); + return this; + } + + f32Const(value) { + this.bytes.push(0x43); + f32Scratch.setFloat32(0, value, true); + for (let i = 0; i < 4; i++) this.bytes.push(f32Scratch.getUint8(i)); + return this; + } + + /** + * @param {ArrayLike} lanes 16 bytes, little-endian lane order + */ + v128Const(lanes) { + if (lanes.length !== 16) { + throw new Error('WasmModuleBuilder: v128.const requires exactly 16 bytes'); + } + this.bytes.push(0xfd, 0x0c); + for (let i = 0; i < 16; i++) this.bytes.push(lanes[i] & 0xff); + return this; + } + + v128ConstI32x4(a, b, c, d) { + f32Scratch.setInt32(0, a, true); + f32Scratch.setInt32(4, b, true); + f32Scratch.setInt32(8, c, true); + f32Scratch.setInt32(12, d, true); + this.bytes.push(0xfd, 0x0c); + for (let i = 0; i < 16; i++) this.bytes.push(f32Scratch.getUint8(i)); + return this; + } + + v128ConstF32x4(a, b, c, d) { + f32Scratch.setFloat32(0, a, true); + f32Scratch.setFloat32(4, b, true); + f32Scratch.setFloat32(8, c, true); + f32Scratch.setFloat32(12, d, true); + this.bytes.push(0xfd, 0x0c); + for (let i = 0; i < 16; i++) this.bytes.push(f32Scratch.getUint8(i)); + return this; + } + + // memory (memarg encodes align exponent then offset) --------------------- + + i32Load(offset = 0, align = 2) { + this.bytes.push(0x28); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; + } + + f32Load(offset = 0, align = 2) { + this.bytes.push(0x2a); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; + } + + i32Store(offset = 0, align = 2) { + this.bytes.push(0x36); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; + } + + f32Store(offset = 0, align = 2) { + this.bytes.push(0x38); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; + } + + v128Load(offset = 0, align = 4) { + this.bytes.push(0xfd, 0x00); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; + } + + v128Store(offset = 0, align = 4) { + this.bytes.push(0xfd, 0x0b); + uleb(align, this.bytes); + uleb(offset, this.bytes); + return this; + } + + // SIMD lane accessors ---------------------------------------------------- + + i32x4ExtractLane(lane) { + return this._lane(0x1b, lane); + } + + i32x4ReplaceLane(lane) { + return this._lane(0x1c, lane); + } + + f32x4ExtractLane(lane) { + return this._lane(0x1f, lane); + } + + f32x4ReplaceLane(lane) { + return this._lane(0x20, lane); + } + + _lane(op, lane) { + if (!Number.isInteger(lane) || lane < 0 || lane > 3) { + throw new Error(`WasmModuleBuilder: lane index ${ lane } out of range for 4-lane shape`); + } + this.bytes.push(0xfd, op, lane); + return this; + } + + _push(bytes) { + for (let i = 0; i < bytes.length; i++) this.bytes.push(bytes[i]); + return this; + } +} + +// All immediate-free opcodes, generated onto the prototype from encoding +// tables so a typo is a missing method (loud) rather than a wrong byte +// (silent until validation). +const PLAIN_OPS = { + unreachable: [0x00], + nop: [0x01], + else_: [0x05], + end: [0x0b], + return_: [0x0f], + drop: [0x1a], + select: [0x1b], + i32Eqz: [0x45], + i32Eq: [0x46], + i32Ne: [0x47], + i32LtS: [0x48], + i32LtU: [0x49], + i32GtS: [0x4a], + i32GtU: [0x4b], + i32LeS: [0x4c], + i32LeU: [0x4d], + i32GeS: [0x4e], + i32GeU: [0x4f], + f32Eq: [0x5b], + f32Ne: [0x5c], + f32Lt: [0x5d], + f32Gt: [0x5e], + f32Le: [0x5f], + f32Ge: [0x60], + i32Clz: [0x67], + i32Ctz: [0x68], + i32Popcnt: [0x69], + i32Add: [0x6a], + i32Sub: [0x6b], + i32Mul: [0x6c], + i32DivS: [0x6d], + i32DivU: [0x6e], + i32RemS: [0x6f], + i32RemU: [0x70], + i32And: [0x71], + i32Or: [0x72], + i32Xor: [0x73], + i32Shl: [0x74], + i32ShrS: [0x75], + i32ShrU: [0x76], + i32Rotl: [0x77], + i32Rotr: [0x78], + f32Abs: [0x8b], + f32Neg: [0x8c], + f32Ceil: [0x8d], + f32Floor: [0x8e], + f32Trunc: [0x8f], + f32Nearest: [0x90], + f32Sqrt: [0x91], + f32Add: [0x92], + f32Sub: [0x93], + f32Mul: [0x94], + f32Div: [0x95], + f32Min: [0x96], + f32Max: [0x97], + f32Copysign: [0x98], + i32TruncF32S: [0xa8], + i32TruncF32U: [0xa9], + f32ConvertI32S: [0xb2], + f32ConvertI32U: [0xb3], + i32ReinterpretF32: [0xbc], + f32ReinterpretI32: [0xbe], + // 0xFC-prefixed saturating truncation (never traps on NaN/overflow) + i32TruncSatF32S: [0xfc, 0x00], + i32TruncSatF32U: [0xfc, 0x01], +}; + +// SIMD opcodes: 0xFD prefix + opcode as ULEB128 (>= 0x80 encodes to 2 bytes) +const SIMD_OPS = { + i32x4Splat: 0x11, + f32x4Splat: 0x13, + i32x4Eq: 0x37, + i32x4Ne: 0x38, + i32x4LtS: 0x39, + i32x4GtS: 0x3b, + i32x4LeS: 0x3d, + i32x4GeS: 0x3f, + f32x4Eq: 0x41, + f32x4Ne: 0x42, + f32x4Lt: 0x43, + f32x4Gt: 0x44, + f32x4Le: 0x45, + f32x4Ge: 0x46, + v128Not: 0x4d, + v128And: 0x4e, + v128Andnot: 0x4f, + v128Or: 0x50, + v128Xor: 0x51, + v128Bitselect: 0x52, + v128AnyTrue: 0x53, + f32x4Ceil: 0x67, + f32x4Floor: 0x68, + f32x4Trunc: 0x69, + f32x4Nearest: 0x6a, + i32x4Abs: 0xa0, + i32x4Neg: 0xa1, + i32x4AllTrue: 0xa3, + i32x4Bitmask: 0xa4, + i32x4Shl: 0xab, + i32x4ShrS: 0xac, + i32x4ShrU: 0xad, + i32x4Add: 0xae, + i32x4Sub: 0xb1, + i32x4Mul: 0xb5, + i32x4MinS: 0xb6, + i32x4MinU: 0xb7, + i32x4MaxS: 0xb8, + i32x4MaxU: 0xb9, + f32x4Abs: 0xe0, + f32x4Neg: 0xe1, + f32x4Sqrt: 0xe3, + f32x4Add: 0xe4, + f32x4Sub: 0xe5, + f32x4Mul: 0xe6, + f32x4Div: 0xe7, + f32x4Min: 0xe8, + f32x4Max: 0xe9, + f32x4Pmin: 0xea, + f32x4Pmax: 0xeb, + i32x4TruncSatF32x4S: 0xf8, + i32x4TruncSatF32x4U: 0xf9, + f32x4ConvertI32x4S: 0xfa, + f32x4ConvertI32x4U: 0xfb, +}; + +for (const name of Object.keys(PLAIN_OPS)) { + const bytes = PLAIN_OPS[name]; + WasmFunctionEmitter.prototype[name] = function() { + return this._push(bytes); + }; +} + +for (const name of Object.keys(SIMD_OPS)) { + const bytes = [0xfd]; + uleb(SIMD_OPS[name], bytes); + WasmFunctionEmitter.prototype[name] = function() { + return this._push(bytes); + }; +} + +/** + * @desc Whole-module assembler. Declare imports, globals and functions in + * any order, then toBytes() lays out sections in the mandatory order + * (type, import, function, global, export, code) and patches call targets. + */ +class WasmModuleBuilder { + constructor() { + this.types = []; + this.typeIndexByKey = {}; + this.memoryImport = null; + this.funcImports = []; + this.funcImportIndexByName = {}; + this.functions = []; + this.functionIndexByName = {}; + this.globals = []; + this.exports = []; + } + + _typeIndex(params, results) { + const key = `${ params.join(',') }=>${ results.join(',') }`; + if (key in this.typeIndexByKey) return this.typeIndexByKey[key]; + const index = this.types.length; + this.types.push({ params, results }); + this.typeIndexByKey[key] = index; + return index; + } + + /** + * One imported memory (env.memory) so a single compiled module can bind + * either a plain or a shared WebAssembly.Memory. Shared memories require + * a maximum by spec. + */ + addMemoryImport(initial, maximum, shared = false) { + if (shared && (maximum === undefined || maximum === null)) { + throw new Error('WasmModuleBuilder: shared memory import requires a maximum'); + } + this.memoryImport = { initial, maximum, shared }; + return this; + } + + /** + * @returns {number} function index (imports lead the index space) + */ + addFuncImport(name, params, results, module = 'env') { + if (name in this.funcImportIndexByName || name in this.functionIndexByName) { + throw new Error(`WasmModuleBuilder: duplicate function name "${ name }"`); + } + const index = this.funcImports.length; + this.funcImports.push({ + name, + module, + typeIndex: this._typeIndex(params, results) + }); + this.funcImportIndexByName[name] = index; + return index; + } + + /** + * @returns {number} global index + */ + addGlobal(type, mutable, initialValue) { + valType(type); + this.globals.push({ type, mutable, initialValue }); + return this.globals.length - 1; + } + + /** + * @param {String} name + * @param {Object} signature + * @param {String[]} [signature.params] + * @param {String[]} [signature.results] + * @param {String[]} [signature.locals] + * @returns {WasmFunctionEmitter} body emitter; more locals via addLocal() + */ + addFunction(name, { params = [], results = [], locals = [] } = {}) { + if (name in this.funcImportIndexByName || name in this.functionIndexByName) { + throw new Error(`WasmModuleBuilder: duplicate function name "${ name }"`); + } + params.forEach(valType); + results.forEach(valType); + locals.forEach(valType); + const emitter = new WasmFunctionEmitter(this, name, params, results, locals); + this.functionIndexByName[name] = this.functions.length; + this.functions.push({ + name, + emitter, + typeIndex: this._typeIndex(params, results) + }); + return emitter; + } + + exportFunction(name, exportName = name) { + this.exports.push({ name, exportName }); + return this; + } + + _resolveFuncIndex(name) { + if (name in this.funcImportIndexByName) { + return this.funcImportIndexByName[name]; + } + if (name in this.functionIndexByName) { + return this.funcImports.length + this.functionIndexByName[name]; + } + throw new Error(`WasmModuleBuilder: call target "${ name }" is not an import or a defined function`); + } + + _section(id, payload, out) { + out.push(id); + uleb(payload.length, out); + for (let i = 0; i < payload.length; i++) out.push(payload[i]); + } + + /** + * @returns {Uint8Array} the complete module binary + */ + toBytes() { + const out = [0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]; + + if (this.types.length > 0) { + const payload = []; + uleb(this.types.length, payload); + for (const { params, results } of this.types) { + payload.push(0x60); + uleb(params.length, payload); + for (const p of params) payload.push(valType(p)); + uleb(results.length, payload); + for (const r of results) payload.push(valType(r)); + } + this._section(SECTION_TYPE, payload, out); + } + + if (this.memoryImport !== null || this.funcImports.length > 0) { + const payload = []; + uleb((this.memoryImport !== null ? 1 : 0) + this.funcImports.length, payload); + if (this.memoryImport !== null) { + const { initial, maximum, shared } = this.memoryImport; + utf8('env', payload); + utf8('memory', payload); + payload.push(0x02); + const hasMax = maximum !== undefined && maximum !== null; + payload.push(shared ? 0x03 : (hasMax ? 0x01 : 0x00)); + uleb(initial, payload); + if (hasMax) uleb(maximum, payload); + } + for (const { name, module, typeIndex } of this.funcImports) { + utf8(module, payload); + utf8(name, payload); + payload.push(0x00); + uleb(typeIndex, payload); + } + this._section(SECTION_IMPORT, payload, out); + } + + if (this.functions.length > 0) { + const payload = []; + uleb(this.functions.length, payload); + for (const { typeIndex } of this.functions) uleb(typeIndex, payload); + this._section(SECTION_FUNCTION, payload, out); + } + + if (this.globals.length > 0) { + const payload = []; + uleb(this.globals.length, payload); + for (const { type, mutable, initialValue } of this.globals) { + payload.push(valType(type), mutable ? 0x01 : 0x00); + if (type === 'i32') { + payload.push(0x41); + sleb(initialValue, payload); + } else if (type === 'f32') { + payload.push(0x43); + f32Scratch.setFloat32(0, initialValue, true); + for (let i = 0; i < 4; i++) payload.push(f32Scratch.getUint8(i)); + } else if (type === 'v128') { + // always zero-initialized; the only v128 global is PCG state, + // reseeded per quad before any read + payload.push(0xfd, 0x0c); + for (let i = 0; i < 16; i++) payload.push(0); + } else { + throw new Error(`WasmModuleBuilder: no initializer encoding for global type "${ type }"`); + } + payload.push(0x0b); + } + this._section(SECTION_GLOBAL, payload, out); + } + + if (this.exports.length > 0) { + const payload = []; + uleb(this.exports.length, payload); + for (const { name, exportName } of this.exports) { + utf8(exportName, payload); + payload.push(0x00); + uleb(this._resolveFuncIndex(name), payload); + } + this._section(SECTION_EXPORT, payload, out); + } + + if (this.functions.length > 0) { + const payload = []; + uleb(this.functions.length, payload); + for (const { emitter } of this.functions) { + const body = emitter.bytes.slice(); + for (const { at, name } of emitter.callFixups) { + uleb5At(this._resolveFuncIndex(name), body, at); + } + const entry = []; + // locals are RLE-compressed (count, type) runs per spec + const runs = []; + for (const local of emitter.locals) { + const type = valType(local); + if (runs.length > 0 && runs[runs.length - 1].type === type) { + runs[runs.length - 1].count++; + } else { + runs.push({ type, count: 1 }); + } + } + uleb(runs.length, entry); + for (const { type, count } of runs) { + uleb(count, entry); + entry.push(type); + } + for (let i = 0; i < body.length; i++) entry.push(body[i]); + entry.push(0x0b); + uleb(entry.length, payload); + for (let i = 0; i < entry.length; i++) payload.push(entry[i]); + } + this._section(SECTION_CODE, payload, out); + } + + return Uint8Array.from(out); + } +} + +module.exports = { + WasmModuleBuilder, + WasmFunctionEmitter +}; \ No newline at end of file diff --git a/src/backend/web-assembly/worker-pool.js b/src/backend/web-assembly/worker-pool.js new file mode 100644 index 00000000..1410444d --- /dev/null +++ b/src/backend/web-assembly/worker-pool.js @@ -0,0 +1,326 @@ +// `os` resolves to the empty module in the browser bundles (aliased like +// `gl`), so its shape is probed before use rather than assumed +let os = null; +try { + os = require('os'); +} catch (e) {} + +// Node has no global Worker; browsers with workers always do. Decided once — +// the two paths differ only in construction and event wiring, the protocol +// is identical +const IS_BROWSER_WORKER = typeof Worker === 'function'; + +function defaultConcurrency() { + if (typeof navigator !== 'undefined' && navigator.hardwareConcurrency) { + return navigator.hardwareConcurrency; + } + if (os && typeof os.cpus === 'function') { + const count = os.cpus().length; + if (count) return count; + } + return 4; +} + +/** + * The worker body. A template string with NO closure captures: it must + * survive being evaluated from a blob URL (browser) or `eval: true` (Node), + * where nothing from this module's scope exists. Everything a task needs + * arrives by message: the compiled WebAssembly.Module and the shared + * WebAssembly.Memory structured-clone once per (worker, entry), then + * {start, end, seed} per task — results are written straight into the + * shared memory, so acks carry no data. + * + * The run dispatch mirrors the kernel's sync path: quads must not cross an + * x-row, so run_simd is used only when the row width is a multiple of 4 (a + * 4-aligned range start then lands every quad inside one row); other shapes + * take the scalar export, which is bit-identical by the SIMD contract. + */ +const WORKER_SOURCE = ` +var entries = {}; +function handleMessage(message, post) { + if (message.type === 'setup') { + var imports = { env: { memory: message.memory } }; + for (var i = 0; i < message.mathImports.length; i++) { + imports.env['math_' + message.mathImports[i]] = Math[message.mathImports[i]]; + } + var instance = new WebAssembly.Instance(message.module, imports); + entries[message.id] = { + run: instance.exports.run, + runSimd: instance.exports.run_simd || null, + sizeX: message.sizeX + }; + post({ type: 'ready', id: message.id }); + } else if (message.type === 'release') { + delete entries[message.id]; + } else if (message.type === 'run') { + var entry = entries[message.id]; + var start = message.start; + var end = message.end; + var seed = message.seed; + if (entry.runSimd && (entry.sizeX & 3) === 0 && (start & 3) === 0) { + var quadEnd = end - ((end - start) & 3); + if (quadEnd > start) entry.runSimd(start, quadEnd, seed); + if (quadEnd < end) entry.run(quadEnd, end, seed); + } else { + entry.run(start, end, seed); + } + post({ type: 'done', taskId: message.taskId }); + } +} +if (typeof self !== 'undefined' && typeof postMessage === 'function') { + self.onmessage = function(event) { + handleMessage(event.data, function(message) { postMessage(message); }); + }; +} else { + var parentPort = require('worker_threads').parentPort; + parentPort.on('message', function(message) { + handleMessage(message, function(reply) { parentPort.postMessage(reply); }); + }); +} +`; + +/** + * @desc Lazy worker pool for the threaded run path. Workers spawn on first + * use and only as many as a dispatch actually assigns; each holds + * instantiations keyed by entry id (one per kernel size signature) over the + * entry's shared memory, so a module and memory cross the postMessage + * boundary exactly once per worker. + * + * The main thread never blocks: dispatch returns a Promise resolved by the + * workers' completion acks — no Atomics.wait anywhere. + * + * Lifecycle rules the runtime review demanded: + * - A worker that dies (wasm trap, OOM, eviction) rejects its in-flight + * tasks AND is retired from the pool; the next dispatch that needs its + * slot spawns a replacement with fresh setup state. A dead worker can + * never be handed a task — that message would vanish and the task's + * Promise would hang forever. + * - Node workers are unref'd while idle and ref'd only while tasks are in + * flight, so a script that runs a threaded kernel and ends actually + * exits — without letting a fully-unref'd pool drop the process mid + * dispatch. + */ +class WebAssemblyWorkerPool { + constructor(size) { + this.size = size || defaultConcurrency(); + this.workers = []; + this.destroyed = false; + // instrumentation the thread tests assert on: how a dispatch was split + // and how many dispatches this pool has served + this.dispatchCount = 0; + this.lastDispatch = null; + this._taskId = 0; + } + + get liveWorkerCount() { + let count = 0; + for (const worker of this.workers) { + if (!worker.dead) count++; + } + return count; + } + + _spawn() { + const worker = { + handle: null, + dead: false, + state: { + setup: new Set(), + settingUp: new Map(), + pending: new Map(), + }, + fail: null, + die: null, + }; + const state = worker.state; + worker.fail = error => { + for (const wait of state.settingUp.values()) wait.reject(error); + state.settingUp.clear(); + for (const task of state.pending.values()) { + task.reject(error); + } + state.pending.clear(); + }; + // death retires the worker: its instantiations and setup cache died with + // the thread, and a message posted to a corpse never answers. The handle + // is terminated explicitly -- an uncaught exception does NOT kill a + // browser worker, so without this a "dead" worker would live on as a + // zombie thread pinning every wasm memory it ever instantiated + worker.die = error => { + if (worker.dead) return; + worker.dead = true; + worker.fail(error); + if (worker.handle && typeof worker.handle.terminate === 'function') { + try { + worker.handle.terminate(); + } catch (e) {} + } + }; + const onMessage = message => { + if (message.type === 'ready') { + const wait = state.settingUp.get(message.id); + if (wait) { + state.settingUp.delete(message.id); + state.setup.add(message.id); + this._updateRef(worker); + wait.resolve(); + } + } else if (message.type === 'done') { + const task = state.pending.get(message.taskId); + if (task) { + state.pending.delete(message.taskId); + this._updateRef(worker); + task.resolve(); + } + } + }; + let handle; + if (IS_BROWSER_WORKER) { + // revoked immediately: the worker holds its own reference once created + const url = URL.createObjectURL(new Blob([WORKER_SOURCE], { type: 'text/javascript' })); + handle = new Worker(url); + URL.revokeObjectURL(url); + handle.onmessage = event => onMessage(event.data); + handle.onerror = event => worker.die(new Error(event.message || 'WebAssembly worker error')); + } else { + const { Worker: NodeWorker } = require('worker_threads'); + handle = new NodeWorker(WORKER_SOURCE, { eval: true }); + handle.on('message', onMessage); + handle.on('error', error => worker.die(error)); + handle.on('exit', code => { + worker.die(new Error(`WebAssembly worker exited with code ${ code }`)); + }); + // idle by default; _taskStarted refs while work is in flight + handle.unref(); + } + worker.handle = handle; + return worker; + } + + _worker(index) { + while (this.workers.length <= index) { + this.workers.push(this._spawn()); + } + if (this.workers[index].dead) { + this.workers[index] = this._spawn(); + } + return this.workers[index]; + } + + /** + * Event-loop handle accounting, per worker: ref'd while it has a setup OR + * a task in flight, unref'd when idle. The setup window matters -- a + * pending Promise does not hold Node's event loop, so a pool unref'd + * during module setup lets the process exit silently mid-dispatch. + * Browser workers have no ref/unref and need none. + */ + _updateRef(worker) { + if (worker.dead || !worker.handle || typeof worker.handle.ref !== 'function') return; + if (worker.state.settingUp.size + worker.state.pending.size > 0) { + worker.handle.ref(); + } else { + worker.handle.unref(); + } + } + + /** + * One setup message per (worker, entry) — concurrent tasks for the same + * entry share the in-flight ready wait rather than re-sending the module + */ + _ensureSetup(worker, entry) { + if (worker.state.setup.has(entry.id)) return Promise.resolve(); + let wait = worker.state.settingUp.get(entry.id); + if (!wait) { + wait = {}; + wait.promise = new Promise((resolve, reject) => { + wait.resolve = resolve; + wait.reject = reject; + }); + worker.state.settingUp.set(entry.id, wait); + this._updateRef(worker); + worker.handle.postMessage({ + type: 'setup', + id: entry.id, + module: entry.module, + memory: entry.memory, + mathImports: entry.mathImports, + sizeX: entry.sizeX, + }); + } + return wait.promise; + } + + /** + * @param {Object} entry kernel module entry: {id, module, memory, mathImports, sizeX} + * @param {Array} tasks contiguous {start, end, seed} ranges, one per worker + * @returns {Promise} resolves when every range has been computed into + * the entry's shared memory + */ + dispatch(entry, tasks) { + if (this.destroyed) return Promise.reject(new Error('WebAssembly worker pool has been destroyed')); + this.dispatchCount++; + this.lastDispatch = { + workerCount: tasks.length, + ranges: tasks.map(task => [task.start, task.end]), + }; + const runs = tasks.map((task, index) => { + const worker = this._worker(index); + return this._ensureSetup(worker, entry).then(() => new Promise((resolve, reject) => { + if (worker.dead) { + reject(new Error('WebAssembly worker died before the task could run')); + return; + } + const taskId = ++this._taskId; + worker.state.pending.set(taskId, { resolve, reject }); + this._updateRef(worker); + worker.handle.postMessage({ + type: 'run', + id: entry.id, + taskId, + start: task.start, + end: task.end, + seed: task.seed, + }); + })); + }); + return Promise.all(runs).then(() => undefined); + } + + /** + * Drops an entry's instantiation from every live worker: the worker-side + * instances are what keep an evicted entry's shared memory alive (#870). + * The caller guarantees no task for this entry is still in flight. + */ + release(entryId) { + if (this.destroyed) return; + for (const worker of this.workers) { + if (worker.dead) continue; + worker.state.setup.delete(entryId); + const wait = worker.state.settingUp.get(entryId); + if (wait) { + // the caller's no-in-flight guarantee makes this unreachable, but a + // silently deleted wait would hang its dispatch forever; reject loud + worker.state.settingUp.delete(entryId); + wait.reject(new Error('WebAssembly kernel entry released during setup')); + this._updateRef(worker); + } + worker.handle.postMessage({ type: 'release', id: entryId }); + } + } + + destroy() { + if (this.destroyed) return; + this.destroyed = true; + const error = new Error('WebAssembly worker pool has been destroyed'); + for (const worker of this.workers) { + worker.dead = true; + worker.fail(error); + worker.handle.terminate(); + } + this.workers = []; + } +} + +module.exports = { + WebAssemblyWorkerPool +}; \ No newline at end of file diff --git a/src/backend/web-gl/function-node.js b/src/backend/web-gl/function-node.js index c2dfc306..a066e0f0 100644 --- a/src/backend/web-gl/function-node.js +++ b/src/backend/web-gl/function-node.js @@ -121,6 +121,23 @@ class WebGLFunctionNode extends FunctionNode { // Function opening retArr.push(') {\n'); + if (this.isRootKernel) { + // Scalar arguments are uniforms, and GLSL rejects assignment to a + // uniform outright. Assigned scalar arguments get a per-invocation + // shadow local instead, mirroring the cpu backend's `user_X$cell` + // shadows (#867). The `cellShadow_` namespace cannot collide: every + // user identifier emits with a `user_` prefix. + const assignedArguments = this.getAssignedArguments(); + for (let i = 0; i < this.argumentNames.length; ++i) { + const argumentName = this.argumentNames[i]; + if (!assignedArguments.has(argumentName)) continue; + const type = typeMap[this.argumentTypes[i]]; + if (type !== 'float' && type !== 'int' && type !== 'bool') continue; + const name = utils.sanitizeName(argumentName); + retArr.push(`${type} cellShadow_user_${name}=user_${name};\n`); + } + } + // Body statement iteration for (let i = 0; i < ast.body.body.length; ++i) { this.astStatementWithHoisting(ast.body.body[i], retArr); @@ -628,17 +645,38 @@ class WebGLFunctionNode extends FunctionNode { retArr.push('3.402823466e+38'); } else if (type === 'Boolean') { if (this.argumentNames.indexOf(name) > -1) { - retArr.push(`bool(user_${name})`); + const marked = this.markupUserName(idtNode.name); + // a shadow local is declared bool already; wrapping it would also + // break assignment targets (`bool(x) = ...` is not an lvalue) + retArr.push(marked.startsWith('cellShadow_') ? marked : `bool(${marked})`); } else { retArr.push(`user_${name}`); } } else { - retArr.push(`user_${name}`); + retArr.push(this.markupUserName(idtNode.name)); } return retArr; } + /** + * @desc Emitted name for a user identifier. Assigned scalar arguments in + * the root kernel route through their per-invocation `cellShadow_` local + * (declared in astFunction) because the argument itself is an unassignable + * uniform (#867). + */ + markupUserName(name) { + const sanitized = utils.sanitizeName(name); + if (this.isRootKernel && this.getAssignedArguments().has(name)) { + const index = this.argumentNames.indexOf(name); + const type = index === -1 ? null : typeMap[this.argumentTypes[index]]; + if (type === 'float' || type === 'int' || type === 'bool') { + return `cellShadow_user_${sanitized}`; + } + } + return `user_${sanitized}`; + } + /** * @desc Parses the abstract syntax tree for *for-loop* expression * @param {Object} forNode - An ast Node @@ -747,6 +785,18 @@ class WebGLFunctionNode extends FunctionNode { * @param {Array} retArr - return array string * @returns {Array} the parsed webgl string */ + /** + * @desc Parses the abstract syntax tree for *do while* loop. GLSL ES 1.00 + * has no do-while, so the loop is rotated into a for: the exit test sits + * at the TOP, guarded to skip the first iteration. A `continue` in the + * body then lands on the test naturally — JavaScript's exact do-while + * continue semantics (#867) — with no body rewriting, so it holds inside + * switch lowerings and unbraced bodies alike, and the test is evaluated + * exactly once per iteration boundary. + * @param {Object} doWhileNode - An ast Node + * @param {Array} retArr - return array string + * @returns {Array} the parsed webgl string + */ astDoWhileStatement(doWhileNode, retArr) { if (doWhileNode.type !== 'DoWhileStatement') { throw this.astErrorOutput('Invalid while statement', doWhileNode); @@ -754,10 +804,10 @@ class WebGLFunctionNode extends FunctionNode { const iVariableName = this.getInternalVariableName('safeI'); retArr.push(`for (int ${iVariableName}=0;${iVariableName}0){if (!`); this.astGeneric(doWhileNode.test, retArr); - retArr.push(') break;\n'); + retArr.push(') break;}\n'); + this.astGeneric(doWhileNode.body, retArr); retArr.push('}\n'); return retArr; @@ -807,6 +857,11 @@ class WebGLFunctionNode extends FunctionNode { retArr.push('float('); this.astGeneric(assNode.right, retArr); retArr.push(')'); + } else if (leftType === 'Integer' && rightType === 'LiteralInteger') { + // an int lvalue (an Integer argument's shadow local) with a literal + // right side: the literal must print as int, GLSL has no implicit + // float conversion + this.castLiteralToInteger(assNode.right, retArr); } else { this.astGeneric(assNode.right, retArr); } @@ -1101,7 +1156,16 @@ class WebGLFunctionNode extends FunctionNode { ], }; - // synthetic nodes need the unique positions the type cache expects + this.stampSyntheticNodes(replacement); + + return replacement; + } + + /** + * @desc Synthetic nodes need the unique positions the type cache expects; + * cloned nodes keep their original positions and are left alone. + */ + stampSyntheticNodes(root) { let syntheticId = this.syntheticNodeId || 0x40000000; const stamp = node => { if (!node || typeof node !== 'object') return; @@ -1119,10 +1183,8 @@ class WebGLFunctionNode extends FunctionNode { stamp(node[key]); } }; - stamp(replacement); + stamp(root); this.syntheticNodeId = syntheticId; - - return replacement; } linearizeStatement(statement) { diff --git a/src/backend/web-gl/kernel.js b/src/backend/web-gl/kernel.js index 0d3cd76f..96b79a16 100644 --- a/src/backend/web-gl/kernel.js +++ b/src/backend/web-gl/kernel.js @@ -399,7 +399,8 @@ class WebGLKernel extends GLKernel { } const KernelValue = this.constructor.lookupKernelValueType(type, this.dynamicArguments ? 'dynamic' : 'static', this.precision, args[index]); if (KernelValue === null) { - return this.requestFallback(args); + return this.requestFallback(args, + `argument "${ this.argumentNames[index] }" of type ${ type } is not supported by ${ this.constructor.name }`); } const kernelArgument = new KernelValue(value, { name, @@ -466,7 +467,8 @@ class WebGLKernel extends GLKernel { } const KernelValue = this.constructor.lookupKernelValueType(type, 'static', this.precision, value); if (KernelValue === null) { - return this.requestFallback(args); + return this.requestFallback(args, + `constant "${ name }" of type ${ type } is not supported by ${ this.constructor.name }`); } const kernelValue = new KernelValue(value, { name, diff --git a/src/backend/web-gl2/function-node.js b/src/backend/web-gl2/function-node.js index 69b96e14..4439a7ac 100644 --- a/src/backend/web-gl2/function-node.js +++ b/src/backend/web-gl2/function-node.js @@ -30,12 +30,15 @@ class WebGL2FunctionNode extends WebGLFunctionNode { retArr.push('intBitsToFloat(2139095039)'); } else if (type === 'Boolean') { if (this.argumentNames.indexOf(name) > -1) { - retArr.push(`bool(user_${name})`); + const marked = this.markupUserName(idtNode.name); + // a shadow local is declared bool already; wrapping it would also + // break assignment targets (`bool(x) = ...` is not an lvalue) + retArr.push(marked.startsWith('cellShadow_') ? marked : `bool(${marked})`); } else { retArr.push(`user_${name}`); } } else { - retArr.push(`user_${name}`); + retArr.push(this.markupUserName(idtNode.name)); } return retArr; diff --git a/src/gpu.js b/src/gpu.js index 5165744d..95070e02 100644 --- a/src/gpu.js +++ b/src/gpu.js @@ -6,14 +6,16 @@ const { HeadlessGLKernel } = require('./backend/headless-gl/kernel'); const { WebGL2Kernel } = require('./backend/web-gl2/kernel'); const { WebGLKernel } = require('./backend/web-gl/kernel'); const { WebGPUKernel } = require('./backend/web-gpu/kernel'); +const { WebAssemblyKernel } = require('./backend/web-assembly/kernel'); const { kernelRunShortcut } = require('./kernel-run-shortcut'); /** - * + * webasm sits last, one step above the cpu fallback: any working GL backend + * outranks it, so auto modes only reach it where no GL context exists * @type {Array.} */ -const kernelOrder = [HeadlessGLKernel, WebGL2Kernel, WebGLKernel]; +const kernelOrder = [HeadlessGLKernel, WebGL2Kernel, WebGLKernel, WebAssemblyKernel]; /** * @@ -29,6 +31,7 @@ const internalKernels = { // (navigator.gpu presence) does not prove an adapter exists, so webgpu is // explicit opt-in via `new GPU({ mode: 'webgpu' })` only 'webgpu': WebGPUKernel, + 'webasm': WebAssemblyKernel, }; let validate = true; @@ -106,6 +109,13 @@ class GPU { return navigator.gpu.requestAdapter().then(adapter => adapter !== null, () => false); } + /** + * @desc TRUE if platform supports WebAssembly + */ + static get isWebAssemblySupported() { + return WebAssemblyKernel.isSupported; + } + /** * * @desc TRUE if platform supports Canvas @@ -291,8 +301,10 @@ class GPU { settingsCopy.argumentTypes = Object.keys(settings.argumentTypes).map(argumentName => settings.argumentTypes[argumentName]); } + const gpuInstance = this; + function onRequestFallback(args) { - console.warn('Falling back to CPU'); + console.warn(`Falling back to CPU${ kernelRun.fallbackReason ? `: ${ kernelRun.fallbackReason }` : '' }`); const fallbackKernel = new CPUKernel(source, { argumentTypes: kernelRun.argumentTypes, constantTypes: kernelRun.constantTypes, @@ -315,10 +327,33 @@ class GPU { randomSeed: kernelRun.randomSeed, debug: kernelRun.debug, asyncMode: kernelRun.asyncMode, + // the fallback kernel lives as long as the shortcut: without these + // hooks a later argument-type change on it throws instead of + // switching (the run shortcut assumes every kernel carries them) + onRequestFallback, + onRequestSwitchKernel, + // ONLY a graphical fallback whose canvas is still uncommitted (webasm + // creates the element but never touches a context) inherits it, so + // the element the user appended keeps rendering. Any canvas that + // already has a rendering context -- every GL kernel's -- is + // permanently committed to it and would break the cpu kernel's 2d + // context instead. + canvas: kernelRun.graphical && !kernelRun.context ? kernelRun.canvas : null, }); + // the requesting kernel is about to be swapped out; the reason stays + // queryable on the kernel that survives + fallbackKernel.fallbackReason = kernelRun.fallbackReason; fallbackKernel.build.apply(fallbackKernel, args); const result = fallbackKernel.run.apply(fallbackKernel, args); kernelRun.replaceKernel(fallbackKernel); + // gpu.canvas was sampled once at createKernel, possibly from a kernel + // with no canvas; the fallback may be the first to have one + if (!gpuInstance.canvas && fallbackKernel.canvas) { + gpuInstance.canvas = fallbackKernel.canvas; + } + if (!gpuInstance.context && fallbackKernel.context) { + gpuInstance.context = fallbackKernel.context; + } return result; } @@ -583,7 +618,13 @@ class GPU { if (this.Kernel.mode === 'webgpu') { throw new Error('WebGPU backend does not yet support createKernelMap'); } - if (this.mode && kernelTypes.indexOf(this.mode) < 0) { + // webasm sits in the auto chain one step above cpu; its build() + // degrades kernel maps to cpu via requestFallback, so throwing here + // would remove the cpu fallback from exactly the GL-less environments + // the backend exists for. chooseKernel rewrites this.mode to the + // chosen backend's name, so the mode check alone cannot tell an + // explicit request from auto-selection -- let webasm fall through. + if (this.mode && kernelTypes.indexOf(this.mode) < 0 && this.Kernel.mode !== 'webasm') { throw new Error(`kernelMap not supported on ${this.Kernel.name}`); } } diff --git a/src/index.d.ts b/src/index.d.ts index 29461bea..36afedf4 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -11,6 +11,7 @@ export class GPU { /** WebGPU API surface exists (navigator.gpu); an adapter may still be absent — await isWebGPUAvailable() for the authoritative answer */ static isWebGPUSupported: boolean; static isWebGPUAvailable(): Promise; + static isWebAssemblySupported: boolean; constructor(settings?: IGPUSettings); functions: GPUFunction[]; nativeFunctions: IGPUNativeFunction[]; @@ -104,7 +105,7 @@ export interface INativeFunctionList { } export type GPUMode = 'gpu' | 'cpu' | 'dev' | 'async'; -export type GPUInternalMode = 'webgl' | 'webgl2' | 'headlessgl' | 'webgpu'; +export type GPUInternalMode = 'webgl' | 'webgl2' | 'headlessgl' | 'webgpu' | 'webasm'; export interface IGPUSettings { mode?: GPUMode | GPUInternalMode; @@ -191,6 +192,8 @@ export class Kernel { hasPrependString(value: string): boolean; constructor(kernel: KernelFunction|IKernelJSON|string, settings?: IDirectKernelSettings); onRequestSwitchKernel?: Kernel; + /** why this kernel's work was degraded to the cpu backend, when it was (#868) */ + fallbackReason: string | null; onActivate(previousKernel: Kernel): void; build(...args: KernelVariable[]): void; run(...args: KernelVariable[]): KernelVariable; @@ -258,6 +261,12 @@ export type Precision = 'single' | 'unsigned'; export class CPUKernel extends Kernel { +} +export class WebAssemblyKernel extends Kernel { + /** LRU bound on cached per-size-signature wasm instantiations (#870) */ + moduleCacheLimit: number; + /** worker-pool size cap for threaded runs; null lets the pool decide */ + poolSize: number | null; } export class GLKernel extends Kernel { @@ -343,6 +352,8 @@ export interface IKernelSettings { graphical?: boolean; /** every call returns a Promise of the result; non-blocking readback where the backend supports it (webgl2, webgpu) */ asyncMode?: boolean; + /** webasm only: caps the worker pool for threaded runs; defaults to hardwareConcurrency (or 4 when unreadable) */ + poolSize?: number; onRequestFallback?: () => Kernel; optimizeFloatMemory?: boolean; dynamicOutput?: boolean; @@ -573,6 +584,7 @@ export interface IFunctionNodeSettings extends IFunctionSettings { export class WebGLFunctionNode extends FunctionNode {} export class WebGL2FunctionNode extends WebGLFunctionNode {} export class CPUFunctionNode extends FunctionNode {} +export class WebAssemblyFunctionNode extends FunctionNode {} export interface IGPUTextureSettings { texture: WebGLTexture; diff --git a/src/index.js b/src/index.js index 2d74696c..480975a1 100644 --- a/src/index.js +++ b/src/index.js @@ -23,6 +23,9 @@ const { WebGPUKernel } = require('./backend/web-gpu/kernel'); const { WebGPUContext } = require('./backend/web-gpu/context'); const { WebGPUBufferResult } = require('./backend/web-gpu/buffer-result'); +const { WebAssemblyFunctionNode } = require('./backend/web-assembly/function-node'); +const { WebAssemblyKernel } = require('./backend/web-assembly/kernel'); + const { GLKernel } = require('./backend/gl/kernel'); const { Kernel } = require('./backend/kernel'); @@ -57,6 +60,9 @@ module.exports = { WebGPUContext, WebGPUBufferResult, + WebAssemblyFunctionNode, + WebAssemblyKernel, + GLKernel, Kernel, FunctionTracer, diff --git a/src/kernel-run-shortcut.js b/src/kernel-run-shortcut.js index ec2d1bd1..84195a65 100644 --- a/src/kernel-run-shortcut.js +++ b/src/kernel-run-shortcut.js @@ -33,6 +33,13 @@ function kernelRunShortcut(kernel) { shortcut.kernel = kernel = newKernel; newKernel.checkArgumentTypes(args); result = newKernel.switchingKernels ? undefined : newKernel.run.apply(newKernel, args); + if (newKernel.fallbackRequested) { + // the switched kernel degraded at build: the fallback already + // replaced the shortcut's kernel (the closure variable), but this + // loop ran the pre-replacement kernel, whose run() reports null on + // fallback -- the replacement holds the real result path + result = kernel.run.apply(kernel, args); + } } return result; } diff --git a/src/utils.js b/src/utils.js index 63b5c90b..e18c2b6c 100644 --- a/src/utils.js +++ b/src/utils.js @@ -380,6 +380,9 @@ const utils = { }, getAstString(source, ast) { + // synthetic nodes (loop normalization) carry no loc; a diagnostic on one + // must still report rather than crash the error path itself + if (!ast.loc) return '[synthetic node]'; const lines = Array.isArray(source) ? source : source.split(/\r?\n/g); const start = ast.loc.start; const end = ast.loc.end; diff --git a/test/all.html b/test/all.html index 5ffb63a2..3d5f308f 100644 --- a/test/all.html +++ b/test/all.html @@ -302,9 +302,19 @@ + + + + + + + + + + diff --git a/test/browserstack/smoke.html b/test/browserstack/smoke.html index b1745058..0a79fd99 100644 --- a/test/browserstack/smoke.html +++ b/test/browserstack/smoke.html @@ -57,7 +57,7 @@

GPU.JS smoke test

async function test(name, fn) { let gpu = null; try { - const made = fn(function track(instance) { gpu = instance; return instance; }); + const made = await fn(function track(instance) { gpu = instance; return instance; }); if (made === 'skip') { record(name, 'skip', 'not supported here'); } else { @@ -93,13 +93,17 @@

GPU.JS smoke test

isKernelMapSupported: GPU.isKernelMapSupported, isOffscreenCanvasSupported: GPU.isOffscreenCanvasSupported, isSinglePrecisionSupported: GPU.isSinglePrecisionSupported, - isGPUHTMLImageArraySupported: GPU.isGPUHTMLImageArraySupported + isGPUHTMLImageArraySupported: GPU.isGPUHTMLImageArraySupported, + isWebAssemblySupported: GPU.isWebAssemblySupported, + sharedArrayBuffer: typeof SharedArrayBuffer !== 'undefined', + crossOriginIsolated: !!self.crossOriginIsolated }; document.getElementById('env').textContent = JSON.stringify(results.env, null, 2); const modes = ['cpu']; if (GPU.isWebGLSupported) modes.push('webgl'); if (GPU.isWebGL2Supported) modes.push('webgl2'); + if (GPU.isWebAssemblySupported) modes.push('webasm'); results.env.modes = modes; // ---- library-level checks ------------------------------------------- @@ -117,6 +121,9 @@

GPU.JS smoke test

// ---- per-mode checks ------------------------------------------------- for (const mode of modes) { const isGPUMode = mode !== 'cpu'; + // webasm accepts pipeline but returns plain typed arrays (the cpu + // contract); only the GL modes hand back Texture objects + const isTextureMode = mode === 'webgl' || mode === 'webgl2'; const label = function (name) { return '[' + mode + '] ' + name; }; await test(label('1D kernel adds two arrays'), function (track) { @@ -337,7 +344,7 @@

GPU.JS smoke test

}); await test(label('texture pipeline round-trip'), function (track) { - if (!isGPUMode) return 'skip'; + if (!isTextureMode) return 'skip'; const gpu = track(new GPU({ mode: mode })); const kernel = gpu.createKernel(function (a) { return a[this.thread.x] * 2; @@ -408,6 +415,61 @@

GPU.JS smoke test

}); }); + await test(label('webasm kernels actually run on WebAssembly'), function (track) { + if (mode !== 'webasm') return 'skip'; + const gpu = track(new GPU({ mode: mode })); + const kernel = gpu.createKernel(function (a) { + let acc = 0; + for (let i = 0; i < 8; i++) { + if (a[this.thread.x] > i) acc += 1; + } + return acc; + }, { output: [8] }); + const out = kernel([0, 1, 2, 3, 4, 5, 6, 7]); + [0, 1, 2, 3, 4, 5, 6, 7].forEach(function (expected, i) { + assertClose(out[i], expected, 'index ' + i); + }); + assert(kernel.kernel.constructor.name === 'WebAssemblyKernel', + 'silently degraded to ' + kernel.kernel.constructor.name + + (kernel.kernel.fallbackReason ? ' (' + kernel.kernel.fallbackReason + ')' : '')); + // which execution path this device actually took (simd vs scalar) + results.env.webasmRunPath = kernel.kernel._lastRunPath; + }); + + await test(label('webasm pipeline returns a plain array that chains'), function (track) { + if (mode !== 'webasm') return 'skip'; + const gpu = track(new GPU({ mode: mode })); + const first = gpu.createKernel(function (a) { + return a[this.thread.x] * 2; + }, { output: [4], pipeline: true }); + const handle = first([1, 2, 3, 4]); + assert(handle && typeof handle.length === 'number', 'pipeline result is not array-like'); + assert(first.kernel.constructor.name === 'WebAssemblyKernel', 'pipeline degraded off webasm'); + const second = gpu.createKernel(function (a) { + return a[this.thread.x] + 1; + }, { output: [4] }); + const out = second(handle); + [3, 5, 7, 9].forEach(function (expected, i) { + assertClose(out[i], expected, 'index ' + i); + }); + }); + + await test(label('asyncMode resolves without SharedArrayBuffer'), async function (track) { + if (mode !== 'webasm') return 'skip'; + // BrowserStack pages are not cross-origin isolated, so this is the + // no-threads path: the async contract must still hold + const gpu = track(new GPU({ mode: mode })); + const kernel = gpu.createKernel(function (a) { + return a[this.thread.x] * 3; + }, { output: [4], asyncMode: true }); + const pending = kernel([1, 2, 3, 4]); + assert(typeof pending.then === 'function', 'asyncMode did not return a Promise'); + const out = await pending; + [3, 6, 9, 12].forEach(function (expected, i) { + assertClose(out[i], expected, 'index ' + i); + }); + }); + await test(label('single precision'), function (track) { if (!isGPUMode) return 'skip'; const gpu = track(new GPU({ mode: mode })); diff --git a/test/features/webasm/arguments-and-constants.js b/test/features/webasm/arguments-and-constants.js new file mode 100644 index 00000000..5c098af2 --- /dev/null +++ b/test/features/webasm/arguments-and-constants.js @@ -0,0 +1,165 @@ +const { assert, test, module: describe } = require('qunit'); +const { GPU, input } = require('../../../src'); + +describe('features: webasm arguments and constants'); + +test('1d array argument webasm', assert => { + assert.expect(1); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function(a) { + return a[this.thread.x] * 2; + }, { output: [4] }); + assert.deepEqual(Array.from(kernel([1, 2, 3, 4])), [2, 4, 6, 8]); + gpu.destroy(); +}); + +test('2d array argument webasm', assert => { + assert.expect(1); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function(a) { + return a[this.thread.y][this.thread.x] + 10; + }, { output: [3, 2] }); + const result = kernel([[1, 2, 3], [4, 5, 6]]); + assert.deepEqual(result.map(row => Array.from(row)), [[11, 12, 13], [14, 15, 16]]); + gpu.destroy(); +}); + +test('3d array argument webasm', assert => { + assert.expect(1); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function(a) { + return a[this.thread.z][this.thread.y][this.thread.x] * 10; + }, { output: [2, 2, 2] }); + const result = kernel([ + [[1, 2], [3, 4]], + [[5, 6], [7, 8]], + ]); + assert.deepEqual(result.map(layer => layer.map(row => Array.from(row))), [ + [[10, 20], [30, 40]], + [[50, 60], [70, 80]], + ]); + gpu.destroy(); +}); + +test('Input argument webasm', assert => { + assert.expect(1); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function(a) { + return a[this.thread.y][this.thread.x]; + }, { output: [4, 2] }); + const flat = new Float32Array([1, 2, 3, 4, 5, 6, 7, 8]); + const result = kernel(input(flat, [4, 2])); + assert.deepEqual(result.map(row => Array.from(row)), [[1, 2, 3, 4], [5, 6, 7, 8]]); + gpu.destroy(); +}); + +test('scalar number and boolean arguments webasm', assert => { + assert.expect(2); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function(scale, offset) { + return this.thread.x * scale + offset; + }, { output: [4] }); + assert.deepEqual(Array.from(kernel(2, 0.5)), [0.5, 2.5, 4.5, 6.5]); + const gate = gpu.createKernel(function(flag) { + if (flag) { + return 1; + } + return 0; + }, { output: [2] }); + assert.deepEqual([Array.from(gate(true)), Array.from(gate(false))], [[1, 1], [0, 0]]); + gpu.destroy(); +}); + +test('integer argument does real i32 bitwise webasm', assert => { + assert.expect(1); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function(n) { + return ((n & 12) | (n << 2)) ^ (n >> 1); + }, { output: [1], argumentTypes: { n: 'Integer' } }); + const n = 27; + assert.equal(kernel(n)[0], ((n & 12) | (n << 2)) ^ (n >> 1)); + gpu.destroy(); +}); + +test('constants: array, float, integer, boolean webasm', assert => { + assert.expect(1); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function() { + let value = this.constants.arr[this.thread.x] * this.constants.scale; + if (this.constants.enabled) { + value += this.constants.bump; + } + return value; + }, { + output: [4], + constants: { arr: [1, 2, 3, 4], scale: 0.5, bump: 10, enabled: true }, + }); + assert.deepEqual(Array.from(kernel()), [10.5, 11, 11.5, 12]); + gpu.destroy(); +}); + +test('constants array via Input webasm', assert => { + assert.expect(1); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function() { + return this.constants.grid[this.thread.y][this.thread.x]; + }, { + output: [2, 2], + constants: { grid: input(new Float32Array([1, 2, 3, 4]), [2, 2]) }, + }); + assert.deepEqual(kernel().map(row => Array.from(row)), [[1, 2], [3, 4]]); + gpu.destroy(); +}); + +test('dynamicArguments accepts changing sizes webasm', assert => { + assert.expect(2); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function(a) { + return a[this.thread.x] + 1; + }, { output: [4], dynamicArguments: true }); + assert.deepEqual(Array.from(kernel([1, 2, 3, 4])), [2, 3, 4, 5]); + // a longer input reads its own layout, not the first call's + assert.deepEqual(Array.from(kernel([9, 8, 7, 6, 5, 4, 3, 2])), [10, 9, 8, 7]); + gpu.destroy(); +}); + +test('argument size change without dynamicArguments throws webasm', assert => { + assert.expect(2); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function(a) { + return a[this.thread.x]; + }, { output: [4] }); + assert.deepEqual(Array.from(kernel([1, 2, 3, 4])), [1, 2, 3, 4]); + assert.throws(() => kernel([1, 2, 3, 4, 5, 6]), /changed size/); + gpu.destroy(); +}); + +test('one kernel\'s arguments do not clobber another\'s webasm', assert => { + assert.expect(2); + const gpu = new GPU({ mode: 'webasm' }); + const first = gpu.createKernel(function(a) { + return a[this.thread.x] * 2; + }, { output: [4] }); + const second = gpu.createKernel(function(a) { + return a[this.thread.x] * 3; + }, { output: [4] }); + const firstResult = first([1, 2, 3, 4]); + second([10, 20, 30, 40]); + assert.deepEqual(Array.from(first([1, 2, 3, 4])), [2, 4, 6, 8]); + assert.deepEqual(Array.from(firstResult), [2, 4, 6, 8]); + gpu.destroy(); +}); + +test('argument updated in expression position vectorizes webasm', assert => { + // `let y = a++` reaches the variance analysis through the expression walk, + // which must record the argument's shadow membership exactly like the + // statement walk does -- it used to reject the kernel outright on any + // SIMD-capable host + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function (a) { + let y = a++; + return y + a; + }, { output: [4] }); + assert.deepEqual(Array.from(kernel(5)), [11, 11, 11, 11]); + gpu.destroy(); +}); diff --git a/test/features/webasm/basics.js b/test/features/webasm/basics.js new file mode 100644 index 00000000..22b5b474 --- /dev/null +++ b/test/features/webasm/basics.js @@ -0,0 +1,158 @@ +const { assert, test, module: describe } = require('qunit'); +const { GPU, HeadlessGLKernel, WebGL2Kernel, WebGLKernel, WebAssemblyKernel } = require('../../../src'); + +describe('features: webasm basics'); + +// No support guards: wasm ships in every environment this suite runs in +// (Node and every browser BrowserStack fields), so a missing WebAssembly is +// itself a failure worth hearing about. + +test('isWebAssemblySupported webasm', assert => { + assert.expect(1); + assert.equal(GPU.isWebAssemblySupported, true); +}); + +test('returns a constant 1d webasm', assert => { + assert.expect(3); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function() { + return 42; + }, { output: [8] }); + const result = kernel(); + assert.equal(result.constructor, Float32Array); + assert.equal(result.length, 8); + assert.deepEqual(Array.from(result), [42, 42, 42, 42, 42, 42, 42, 42]); + gpu.destroy(); +}); + +test('scalar map 1d webasm', assert => { + assert.expect(2); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function() { + return this.thread.x; + }, { output: [8] }); + const first = kernel(); + assert.deepEqual(Array.from(first), [0, 1, 2, 3, 4, 5, 6, 7]); + // second call must reuse the built module, not rebuild + const second = kernel(); + assert.deepEqual(Array.from(second), [0, 1, 2, 3, 4, 5, 6, 7]); + gpu.destroy(); +}); + +test('scalar map 2d webasm', assert => { + assert.expect(3); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function() { + return this.thread.y * 100 + this.thread.x; + }, { output: [4, 3] }); + const result = kernel(); + assert.equal(result.length, 3); + assert.equal(result[0].constructor, Float32Array); + assert.deepEqual(result.map(row => Array.from(row)), [ + [0, 1, 2, 3], + [100, 101, 102, 103], + [200, 201, 202, 203], + ]); + gpu.destroy(); +}); + +test('scalar map 3d webasm', assert => { + assert.expect(2); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function() { + return this.thread.z * 100 + this.thread.y * 10 + this.thread.x; + }, { output: [2, 3, 2] }); + const result = kernel(); + assert.equal(result.length, 2); + assert.deepEqual(result.map(layer => layer.map(row => Array.from(row))), [ + [[0, 1], [10, 11], [20, 21]], + [[100, 101], [110, 111], [120, 121]], + ]); + gpu.destroy(); +}); + +test('array returns webasm', assert => { + assert.expect(3); + const gpu = new GPU({ mode: 'webasm' }); + const kernel2 = gpu.createKernel(function() { + return [this.thread.x, this.thread.x + 0.5]; + }, { output: [3] }); + assert.deepEqual(kernel2().map(v => Array.from(v)), [[0, 0.5], [1, 1.5], [2, 2.5]]); + const kernel3 = gpu.createKernel(function() { + return [1, this.thread.x, 3]; + }, { output: [2] }); + assert.deepEqual(kernel3().map(v => Array.from(v)), [[1, 0, 3], [1, 1, 3]]); + const kernel4 = gpu.createKernel(function() { + return [1, 2, 3, this.thread.x]; + }, { output: [2] }); + assert.deepEqual(kernel4().map(v => Array.from(v)), [[1, 2, 3, 0], [1, 2, 3, 1]]); + gpu.destroy(); +}); + +test('matches cpu on transcendental math webasm', assert => { + const source = function(a) { + return Math.sin(a[this.thread.x]) * Math.exp(a[this.thread.x] / 10) + Math.sqrt(a[this.thread.x] + 1) - Math.log(a[this.thread.x] + 2); + }; + const values = [0, 0.25, 0.5, 1, 2, 3, 4.5, 9]; + const webasm = new GPU({ mode: 'webasm' }); + const cpu = new GPU({ mode: 'cpu' }); + const expected = cpu.createKernel(source, { output: [8] })(values); + const actual = webasm.createKernel(source, { output: [8] })(values); + assert.expect(values.length); + for (let i = 0; i < values.length; i++) { + const relative = Math.abs(actual[i] - expected[i]) / Math.max(Math.abs(expected[i]), 1e-6); + assert.ok(relative <= 1e-6, `cell ${ i }: ${ actual[i] } vs cpu ${ expected[i] }`); + } + webasm.destroy(); + cpu.destroy(); +}); + +test('mode gpu auto-selection is not displaced by webasm', assert => { + assert.expect(2); + const gpu = new GPU({ mode: 'gpu' }); + assert.notEqual(gpu.Kernel, WebAssemblyKernel, 'a GL backend outranks webasm'); + if (GPU.isHeadlessGLSupported) { + assert.equal(gpu.Kernel, HeadlessGLKernel, 'Node still lands on headlessgl'); + } else { + assert.ok(gpu.Kernel === WebGL2Kernel || gpu.Kernel === WebGLKernel, 'browser still lands on a WebGL backend'); + } + gpu.destroy(); +}); + +test('kernelOrder holds webasm last, one step above the cpu fallback', assert => { + assert.expect(1); + let kernelOrder = null; + try { + kernelOrder = require('../../../src/gpu').kernelOrder; + } catch (e) { + // the browser shim resolves only '../src'; there the ordering is proven + // behaviorally by the auto-selection test above + } + if (kernelOrder) { + assert.deepEqual(kernelOrder, [HeadlessGLKernel, WebGL2Kernel, WebGLKernel, WebAssemblyKernel]); + } else { + assert.ok(true, 'kernelOrder not reachable from the bundle'); + } +}); + +test('precision unsigned is accepted and computes as single webasm', assert => { + assert.expect(1); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function(a) { + return a[this.thread.x] * 1.5; + }, { output: [4], precision: 'unsigned' }); + assert.deepEqual(Array.from(kernel([1, 2, 3, 4])), [1.5, 3, 4.5, 6]); + gpu.destroy(); +}); + +test('setOutput resizes with dynamicOutput webasm', assert => { + assert.expect(2); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function() { + return this.thread.x; + }, { output: [4], dynamicOutput: true }); + assert.deepEqual(Array.from(kernel()), [0, 1, 2, 3]); + kernel.setOutput([6]); + assert.deepEqual(Array.from(kernel()), [0, 1, 2, 3, 4, 5]); + gpu.destroy(); +}); diff --git a/test/features/webasm/control-flow.js b/test/features/webasm/control-flow.js new file mode 100644 index 00000000..a9c4bf8d --- /dev/null +++ b/test/features/webasm/control-flow.js @@ -0,0 +1,206 @@ +const { assert, test, module: describe } = require('qunit'); +const { GPU } = require('../../../src'); + +describe('features: webasm control flow'); + +// Every shape here runs against mode 'cpu' on the same source and inputs — +// the cpu backend is the reference for correctness. +function compare(assert, source, output, settings, args) { + const webasm = new GPU({ mode: 'webasm' }); + const cpu = new GPU({ mode: 'cpu' }); + const expected = cpu.createKernel(source, Object.assign({ output }, settings)).apply(null, args || []); + const actual = webasm.createKernel(source, Object.assign({ output }, settings)).apply(null, args || []); + assert.deepEqual(Array.from(actual), Array.from(expected)); + webasm.destroy(); + cpu.destroy(); +} + +test('if / else webasm', assert => { + assert.expect(1); + compare(assert, function(a) { + if (a[this.thread.x] > 2) { + return a[this.thread.x] * 10; + } else { + return a[this.thread.x] - 1; + } + }, [6], {}, [[1, 2, 3, 4, 5, 6]]); +}); + +test('ternary webasm', assert => { + assert.expect(1); + compare(assert, function(a) { + return a[this.thread.x] % 2 === 0 ? a[this.thread.x] / 2 : a[this.thread.x] * 3 + 1; + }, [8], {}, [[1, 2, 3, 4, 5, 6, 7, 8]]); +}); + +test('fixed-trip for loop webasm', assert => { + assert.expect(1); + compare(assert, function(a, b) { + let sum = 0; + for (let i = 0; i < 8; i++) { + sum += a[i] * b[i]; + } + return sum + this.thread.x; + }, [4], {}, [[1, 2, 3, 4, 5, 6, 7, 8], [8, 7, 6, 5, 4, 3, 2, 1]]); +}); + +test('argument-dependent trip count webasm', assert => { + assert.expect(1); + compare(assert, function(a) { + let sum = 0; + for (let i = 0; i < a[this.thread.x]; i++) { + sum += i + 1; + } + return sum; + }, [5], {}, [[0, 1, 3, 5, 7]]); +}); + +test('break and continue webasm', assert => { + assert.expect(1); + compare(assert, function(limit) { + let sum = 0; + for (let i = 0; i < 32; i++) { + if (i > limit + this.thread.x) { + break; + } + if (i % 3 === 0) { + continue; + } + sum += i; + } + return sum; + }, [6], {}, [7]); +}); + +test('early return webasm', assert => { + assert.expect(1); + compare(assert, function(a) { + if (a[this.thread.x] < 0) { + return -1; + } + let value = a[this.thread.x]; + for (let i = 0; i < 3; i++) { + value = value * 2; + } + return value; + }, [6], {}, [[3, -5, 2, -1, 0, 7]]); +}); + +test('nested if in loop webasm', assert => { + assert.expect(1); + compare(assert, function(a) { + let count = 0; + for (let i = 0; i < 16; i++) { + if (a[i] > 4) { + if (a[i] < 12) { + count += 2; + } else { + count += 1; + } + } + } + return count + this.thread.x; + }, [4], {}, [[1, 5, 13, 7, 2, 11, 15, 4, 9, 3, 14, 6, 8, 10, 12, 0]]); +}); + +test('while loop webasm', assert => { + assert.expect(1); + compare(assert, function(a) { + let n = a[this.thread.x]; + let steps = 0; + while (n > 1) { + n = n / 2; + steps++; + } + return steps; + }, [4], {}, [[16, 8, 5, 1]]); +}); + +test('helper function via addFunction webasm', assert => { + assert.expect(1); + function square(x) { + return x * x; + } + const webasm = new GPU({ mode: 'webasm' }); + const cpu = new GPU({ mode: 'cpu' }); + webasm.addFunction(square); + cpu.addFunction(square); + const source = function(a) { + return square(a[this.thread.x]) + square(2); + }; + const expected = cpu.createKernel(source, { output: [4] })([1, 2, 3, 4]); + const actual = webasm.createKernel(source, { output: [4] })([1, 2, 3, 4]); + assert.deepEqual(Array.from(actual), Array.from(expected)); + webasm.destroy(); + cpu.destroy(); +}); + +test('modulo stays float like the GL backends webasm', assert => { + assert.expect(1); + compare(assert, function(a) { + return a[this.thread.x] % 2.5; + }, [4], {}, [[5, 6.25, -3, 7.5]]); +}); + +// Three shapes where the cpu backend disagrees with plain JavaScript (the +// review caught cpu returning wrong numbers on all three) -- so these compare +// against a per-cell PLAIN JS reference, never against mode: 'cpu'. + +test('early return inside a loop matches plain JavaScript', () => { + const source = function (x) { + for (let i = 0; i < 20; i++) { + if (i * i > x) { + return i * 100 + x; + } + } + return -1; + }; + const expected = [0, 1, 2, 3, 4, 5].map(x => source(x)); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function () { + for (let i = 0; i < 20; i++) { + if (i * i > this.thread.x) { + return i * 100 + this.thread.x; + } + } + return -1; + }, { output: [6], loopMaxIterations: 30 }); + assert.deepEqual(Array.from(kernel()), expected); + gpu.destroy(); +}); + +test('do-while with continue matches plain JavaScript', () => { + const reference = (() => { + let i = 0; + let acc = 0; + do { + i++; + if (i % 3 === 0) continue; + acc += i; + } while (i < 12); + return acc; + })(); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function () { + let i = 0; + let acc = 0; + do { + i++; + if (i % 3 === 0) continue; + acc += i; + } while (i < 12); + return acc; + }, { output: [4], loopMaxIterations: 30 }); + assert.deepEqual(Array.from(kernel()), [reference, reference, reference, reference]); + gpu.destroy(); +}); + +test('assigning to a scalar argument stays per-cell, like plain JavaScript', () => { + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function (base) { + base = base + this.thread.x; + return base; + }, { output: [4] }); + assert.deepEqual(Array.from(kernel(10)), [10, 11, 12, 13], 'a fresh binding per cell'); + gpu.destroy(); +}); diff --git a/test/features/webasm/fallbacks.js b/test/features/webasm/fallbacks.js new file mode 100644 index 00000000..51a94f42 --- /dev/null +++ b/test/features/webasm/fallbacks.js @@ -0,0 +1,115 @@ +const { assert, skip, test, module: describe } = require('qunit'); +const { GPU, input } = require('../../../src'); + +describe('features: webasm fallbacks'); + +// webasm sits in the auto chain one step above cpu, so everything it cannot +// take must DEGRADE, not throw -- these tests pin every requestFallback path +// so a reordering in build() cannot silently remove the degradation. + +test('kernel maps degrade to cpu', () => { + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernelMap({ + doubled: function d(x) { return x * 2; }, + }, function (a) { + return d(a[this.thread.x]) + 1; + }, { output: [4] }); + const { result, doubled } = kernel([1, 2, 3, 4]); + assert.deepEqual(Array.from(result), [3, 5, 7, 9]); + assert.deepEqual(Array.from(doubled), [2, 4, 6, 8]); + assert.equal(kernel.kernel.constructor.name, 'CPUKernel'); + // the degradation is queryable, not just a console line (#868) + assert.ok(/kernel maps/.test(kernel.kernel.fallbackReason), `names the reason: ${ kernel.kernel.fallbackReason }`); + gpu.destroy(); +}); + +(GPU.isHeadlessGLSupported ? test : skip)('a texture argument degrades to cpu', () => { + const glGpu = new GPU({ mode: 'headlessgl' }); + const texture = glGpu.createKernel(function () { + return this.thread.x * 10; + }, { output: [4], pipeline: true })(); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function (v) { + return v[this.thread.x] + 1; + }, { output: [4] }); + const result = kernel(texture); + assert.deepEqual(Array.from(result), [1, 11, 21, 31]); + assert.equal(kernel.kernel.constructor.name, 'CPUKernel'); + assert.ok(/argument "v"/.test(kernel.kernel.fallbackReason), `names the argument: ${ kernel.kernel.fallbackReason }`); + gpu.destroy(); + glGpu.destroy(); +}); + +(GPU.isCanvasSupported ? skip : test)('graphical without a canvas throws exactly what cpu throws', () => { + // no DOM: the error is cpu parity, not a webasm invention + const gpu = new GPU({ mode: 'webasm' }); + assert.throws(() => { + gpu.createKernel(function () { + this.color(1, 0, 0, 1); + }, { output: [4, 4], graphical: true })(); + }, /no canvas available/); + gpu.destroy(); +}); + +(GPU.isCanvasSupported ? test : skip)('graphical degrades to cpu and keeps its canvas', () => { + // the webasm kernel creates the canvas element without committing a + // context, so the cpu fallback renders into that same element -- the one + // the user may already have appended + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function () { + this.color(1, 0, 0, 1); + }, { output: [4, 4], graphical: true }); + const canvasBefore = kernel.canvas; + assert.ok(canvasBefore, 'canvas exists at creation'); + kernel(); + assert.equal(kernel.kernel.constructor.name, 'CPUKernel', 'degraded to cpu'); + assert.equal(kernel.canvas, canvasBefore, 'same canvas element after the fallback'); + const pixels = kernel.kernel.getPixels(); + assert.deepEqual(Array.from(pixels.slice(0, 4)), [255, 0, 0, 255], 'and it rendered'); + gpu.destroy(); +}); + +test('toString throws its deferral clearly', () => { + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function () { + return this.thread.x; + }, { output: [4] }); + kernel(); + assert.throws(() => kernel.toString(), /WebAssembly backend does not yet support/); + gpu.destroy(); +}); + +(GPU.isHeadlessGLSupported ? test : skip)('a texture argument AFTER a plain-array build switches and degrades', () => { + // self-typed values pass the base type check (kernel-value machinery + // handles them elsewhere); this backend has none, so an already-built + // kernel must flag the switch itself instead of crashing in flattenTo + const glGpu = new GPU({ mode: 'headlessgl' }); + const texture = glGpu.createKernel(function () { + return this.thread.x * 10; + }, { output: [4], pipeline: true })(); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function (v) { + return v[this.thread.x] + 1; + }, { output: [4] }); + assert.deepEqual(Array.from(kernel([5, 6, 7, 8])), [6, 7, 8, 9], 'builds on webasm first'); + assert.equal(kernel.kernel.constructor.name, 'WebAssemblyKernel'); + assert.deepEqual(Array.from(kernel(texture)), [1, 11, 21, 31], 'the texture call still computes'); + assert.deepEqual(Array.from(kernel([5, 6, 7, 8])), [6, 7, 8, 9], 'plain arrays still work after'); + gpu.destroy(); + glGpu.destroy(); +}); + +test('the fallback cpu kernel can itself switch on an argument-type change', () => { + // the kernel constructed by onRequestFallback lives as long as the + // shortcut; without the switch hooks a later type change threw + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernelMap({ + doubled: function d(x) { return x * 2; }, + }, function (a) { + return d(a[this.thread.x]) + 1; + }, { output: [4] }); + assert.deepEqual(Array.from(kernel([1, 2, 3, 4]).result), [3, 5, 7, 9], 'kernel map degrades and runs'); + const viaInput = kernel(input(new Float32Array([5, 6, 7, 8]), [4])); + assert.deepEqual(Array.from(viaInput.result), [11, 13, 15, 17], 'an Input after an Array switches cleanly'); + gpu.destroy(); +}); diff --git a/test/features/webasm/module-cache.js b/test/features/webasm/module-cache.js new file mode 100644 index 00000000..292f538c --- /dev/null +++ b/test/features/webasm/module-cache.js @@ -0,0 +1,74 @@ +const { assert, skip, test, module: describe } = require('qunit'); +const { GPU } = require('../../../src'); + +describe('features: webasm module cache'); + +const THREADS_AVAILABLE = GPU.isWebAssemblySupported && typeof SharedArrayBuffer !== 'undefined'; + +// every size signature instantiates a module over its own WebAssembly.Memory, +// which is near-invisible to JS heap accounting and pins a large virtual +// reservation -- so the cache is LRU-bounded and evicted entries are scrubbed +// (#870). Correctness must survive eviction: a revisited size re-instantiates. + +test('a size sweep does not grow the cache past the bound', () => { + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function (a) { + return a[this.thread.x] + 1; + }, { output: [4], dynamicOutput: true, dynamicArguments: true }); + kernel.setOutput([4]); + assert.deepEqual(Array.from(kernel([1, 2, 3, 4])), [2, 3, 4, 5]); + const inner = kernel.kernel; + inner.moduleCacheLimit = 3; + for (let size = 5; size <= 14; size++) { + kernel.setOutput([size]); + const input = new Float32Array(size).fill(size); + assert.equal(kernel(input)[0], size + 1, `size ${ size } computes`); + } + assert.ok(inner._moduleCache.size <= 3, `cache stays bounded (${ inner._moduleCache.size })`); + // the first size was evicted long ago; revisiting must re-instantiate + kernel.setOutput([4]); + assert.deepEqual(Array.from(kernel([1, 2, 3, 4])), [2, 3, 4, 5], 'evicted signature revives'); + gpu.destroy(); +}); + +test('destroy scrubs every cached entry', async assert => { + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function () { + return this.thread.x; + }, { output: [8] }); + kernel(); + const entries = Array.from(kernel.kernel._moduleCache.values()); + assert.equal(entries.length, 1); + await gpu.destroy(); + assert.equal(entries[0].memory, null, 'the wasm memory reference is dropped'); + assert.equal(entries[0].instance, null, 'the instance reference is dropped'); +}); + +(THREADS_AVAILABLE ? test : skip)('threaded entries survive eviction and release worker instantiations', async assert => { + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function (a) { + return a[this.thread.x] * 2; + }, { output: [8192], asyncMode: true, dynamicOutput: true, dynamicArguments: true }); + const first = new Float32Array(8192).fill(3); + assert.equal((await kernel(first))[0], 6); + const firstEntry = kernel.kernel._active; + const firstId = firstEntry.id; + kernel.kernel.moduleCacheLimit = 1; + // each size change now evicts the previous shared entry after its tail + // settles; the pool must drop the worker-side instantiation and the next + // revisit must set a fresh one up + kernel.setOutput([12288]); + const second = new Float32Array(12288).fill(5); + assert.equal((await kernel(second))[0], 10); + // the eviction's deferred release has settled by now (it was queued on + // the tail ahead of the run just awaited): the entry must be scrubbed and + // no worker may still hold its instantiation + assert.equal(firstEntry.memory, null, 'evicted shared entry is scrubbed'); + const pool = kernel.kernel._pool; + assert.ok(pool.workers.every(worker => !worker.state.setup.has(firstId)), + 'no worker retains the evicted instantiation'); + kernel.setOutput([8192]); + assert.equal((await kernel(first))[0], 6, 'revisiting the evicted size still computes threaded'); + assert.equal(kernel.kernel._moduleCache.size, 1); + await gpu.destroy(); +}); diff --git a/test/features/webasm/pipeline.js b/test/features/webasm/pipeline.js new file mode 100644 index 00000000..45ecf1eb --- /dev/null +++ b/test/features/webasm/pipeline.js @@ -0,0 +1,71 @@ +const { assert, test, module: describe } = require('qunit'); +const { GPU } = require('../../../src'); + +describe('features: webasm pipeline'); + +// pipeline is accepted the way the cpu backend accepts it (#868): there is +// no device memory to pipeline into, so the result is the plain typed array +// the run already produces -- a fresh copy per call, valid as input to any +// downstream kernel. Before #868 these kernels silently degraded to cpu, +// which cost 17 of 30 workloads on the gpu.rocks suite their backend. + +test('a pipelined kernel stays on webasm', () => { + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function (a) { + return a[this.thread.x] + 1; + }, { output: [4], pipeline: true }); + const result = kernel([1, 2, 3, 4]); + assert.deepEqual(Array.from(result), [2, 3, 4, 5]); + assert.equal(kernel.kernel.constructor.name, 'WebAssemblyKernel', 'not degraded to cpu'); + gpu.destroy(); +}); + +test('pipelined output feeds a downstream webasm kernel', () => { + const gpu = new GPU({ mode: 'webasm' }); + const first = gpu.createKernel(function (a) { + return a[this.thread.x] * 2; + }, { output: [4], pipeline: true }); + const second = gpu.createKernel(function (v) { + return v[this.thread.x] + 100; + }, { output: [4], pipeline: true }); + const result = second(first([1, 2, 3, 4])); + assert.deepEqual(Array.from(result), [102, 104, 106, 108]); + assert.equal(first.kernel.constructor.name, 'WebAssemblyKernel'); + assert.equal(second.kernel.constructor.name, 'WebAssemblyKernel'); + gpu.destroy(); +}); + +test('ping-pong through the same pipelined kernel iterates correctly', () => { + // the multi-pass shape pipelining exists for: feed a kernel its own + // output. Arguments copy into wasm memory before the run and the output + // copies out after, so self-feeding cannot alias mid-run. + const gpu = new GPU({ mode: 'webasm' }); + const step = gpu.createKernel(function (v) { + return v[this.thread.x] * 2 + 1; + }, { output: [4], pipeline: true }); + let state = [0, 1, 2, 3]; + let expected = state.slice(); + for (let i = 0; i < 5; i++) { + state = step(state); + expected = expected.map(x => x * 2 + 1); + } + assert.deepEqual(Array.from(state), expected); + assert.equal(step.kernel.constructor.name, 'WebAssemblyKernel'); + gpu.destroy(); +}); + +test('each pipelined call returns a fresh array, immutable or not', () => { + // no reuse surprises: the readback slice is a new copy per call, so an + // earlier result is not clobbered by a later run (the cpu backend's + // mutable-reuse optimization does clobber; webasm's contract is stricter + // and that is fine -- callers holding old results keep them) + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function (a) { + return a[this.thread.x] + 1; + }, { output: [3], pipeline: true }); + const first = kernel([1, 2, 3]); + const second = kernel([10, 20, 30]); + assert.deepEqual(Array.from(first), [2, 3, 4], 'first result survives the second run'); + assert.deepEqual(Array.from(second), [11, 21, 31]); + gpu.destroy(); +}); diff --git a/test/features/webasm/random.js b/test/features/webasm/random.js new file mode 100644 index 00000000..bd2459e3 --- /dev/null +++ b/test/features/webasm/random.js @@ -0,0 +1,93 @@ +const { assert, skip, test, module: describe } = require('qunit'); +const { GPU, WebAssemblyKernel } = require('../../../src'); + +describe('features: webasm random'); + +// Math.random on webasm is the webgpu backend's PCG in native i32 wasm: +// per-cell state seeded from (seed + cellIndex * 0x9E3779B9) plus one LCG +// advance, RXS-M-XS output, top 24 bits into [0, 1). Integer arithmetic end +// to end, so with randomSeed the stream is bit-exact across runs, platforms, +// and any future work split. + +test('draws land in [0, 1) and vary per thread webasm', assert => { + assert.expect(4); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function() { + return Math.random(); + }, { output: [4096] }); + const draws = kernel(); + assert.ok(draws.every(v => v >= 0 && v < 1), 'all in [0, 1)'); + const mean = draws.reduce((a, b) => a + b, 0) / draws.length; + assert.ok(Math.abs(mean - 0.5) < 0.05, `mean near 0.5 (${ mean.toFixed(4) })`); + const distinct = new Set(draws).size; + assert.ok(distinct > 4000, `threads decorrelated (${ distinct } distinct of 4096)`); + let adjacentEqual = 0; + for (let i = 1; i < draws.length; i++) { + if (draws[i] === draws[i - 1]) adjacentEqual++; + } + assert.equal(adjacentEqual, 0, 'no adjacent-thread repeats'); + gpu.destroy(); +}); + +test('draws advance within a thread webasm', assert => { + assert.expect(1); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function() { + const a = Math.random(); + const b = Math.random(); + return a === b ? 1 : 0; + }, { output: [1024] }); + const stuck = kernel().reduce((sum, v) => sum + v, 0); + assert.equal(stuck, 0, 'consecutive draws differ in every thread'); + gpu.destroy(); +}); + +test('unseeded runs differ webasm', assert => { + assert.expect(1); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function() { + return Math.random(); + }, { output: [64] }); + const first = Array.from(kernel()); + const second = Array.from(kernel()); + assert.notDeepEqual(first, second, 'the host reseeds every run'); + gpu.destroy(); +}); + +test('randomSeed pins the stream bit-exact webasm', assert => { + assert.expect(2); + const gpu = new GPU({ mode: 'webasm' }); + const seeded = gpu.createKernel(function() { + return Math.random(); + }, { output: [64], randomSeed: 1234 }); + const first = Array.from(seeded()); + const second = Array.from(seeded()); + assert.deepEqual(first, second, 'same seed, same stream, every run'); + const other = gpu.createKernel(function() { + return Math.random(); + }, { output: [64], randomSeed: 4321 }); + assert.notDeepEqual(first, Array.from(other()), 'a different seed is a different stream'); + gpu.destroy(); +}); + +const SIMD_AVAILABLE = GPU.isWebAssemblySupported && WebAssemblyKernel.isSIMDSupported; + +(SIMD_AVAILABLE ? test : skip)('seeded stream is identical on the SIMD and scalar paths webasm', assert => { + assert.expect(3); + // width 64 runs entirely through run_simd, width 63 mostly scalar-tails — + // the first 63 draws must match bit for bit because seeding is per cell, + // not per stride + const gpu = new GPU({ mode: 'webasm' }); + const wide = gpu.createKernel(function() { + return Math.random(); + }, { output: [64], randomSeed: 99 }); + const narrow = gpu.createKernel(function() { + return Math.random(); + }, { output: [63], randomSeed: 99 }); + const wideDraws = wide(); + const narrowDraws = narrow(); + assert.equal(wide.kernel._lastRunPath, 'simd'); + assert.equal(narrow.kernel._lastRunPath, 'simd+scalar-tail'); + assert.deepEqual(Array.from(narrowDraws), Array.from(wideDraws.slice(0, 63))); + gpu.destroy(); +}); diff --git a/test/features/webasm/simd-and-threads.js b/test/features/webasm/simd-and-threads.js new file mode 100644 index 00000000..1cb178e1 --- /dev/null +++ b/test/features/webasm/simd-and-threads.js @@ -0,0 +1,191 @@ +const { assert, skip, test, module: describe } = require('qunit'); +const { GPU, WebAssemblyKernel } = require('../../../src'); + +describe('features: webasm simd and threads'); + +// The discriminating assertions here follow the backend's contract: every +// kernel's module carries a run_simd export next to run, the two are +// bit-identical per cell, and the threaded path must produce exactly the +// sync path's numbers however the work is split. + +// a kernel with everything the vectorizer has to predicate: divergent +// if/else, a lane-varying trip count, a lane-scalarized import, and a +// lane-varying array load +function divergentSource(a) { + let sum = 0; + for (let i = 0; i < a[this.thread.x]; i++) { + sum += Math.sin(i + 1); + } + if (a[this.thread.x] > 4) { + sum = sum * 2 + a[this.thread.x]; + } else { + sum = sum - 1; + } + return sum; +} + +// the threaded path needs SharedArrayBuffer, which browsers only expose under +// cross-origin isolation (the dev server sends the headers; BrowserStack +// targets may not) -- Node always has it, so the thread tests always run there +const THREADS_AVAILABLE = typeof SharedArrayBuffer !== 'undefined'; +// wasm SIMD itself is optional (Safari before 16.4): the backend falls back +// to the scalar export, so path assertions only hold where SIMD exists +const SIMD_AVAILABLE = GPU.isWebAssemblySupported && WebAssemblyKernel.isSIMDSupported; + +(SIMD_AVAILABLE ? test : skip)('every module exports run_simd webasm', assert => { + assert.expect(3); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(divergentSource, { output: [8] }); + kernel([1, 6, 3, 8, 2, 7, 4, 5]); + const entry = kernel.kernel._active; + assert.equal(typeof entry.instance.exports.run, 'function'); + assert.equal(typeof entry.instance.exports.run_simd, 'function', 'divergent control flow vectorizes, it does not bail out'); + assert.equal(kernel.kernel._lastRunPath, 'simd', 'a width divisible by 4 runs entirely vectorized'); + gpu.destroy(); +}); + +(SIMD_AVAILABLE ? test : skip)('run and run_simd are bit-identical webasm', assert => { + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(divergentSource, { output: [16] }); + const args = [1, 6, 3, 8, 2, 7, 4, 5, 0, 9, 12, 3, 6, 1, 8, 2]; + kernel(args); // uploads arguments and proves the kernel runs + const entry = kernel.kernel._active; + const cells = entry.cells; + const base = entry.layout.outputOffset / 4; + const span = cells * kernel.kernel.componentCount; + const capture = runner => { + entry.f32.fill(-999, base, base + span); // any stale cell would survive as -999 + runner(0, cells, 7); + // Int32 views compare bit patterns, so "identical" means identical f32s, + // not merely close ones + return new Int32Array(entry.f32.slice(base, base + span).buffer); + }; + const scalar = capture(entry.instance.exports.run); + const simd = capture(entry.instance.exports.run_simd); + assert.expect(span); + for (let i = 0; i < span; i++) { + assert.equal(simd[i], scalar[i], `cell ${ i }: simd bits ${ simd[i] } vs scalar bits ${ scalar[i] }`); + } + gpu.destroy(); +}); + +(SIMD_AVAILABLE ? test : skip)('non-multiple-of-4 rows take the scalar tail and still match cpu webasm', assert => { + assert.expect(2); + const gpu = new GPU({ mode: 'webasm' }); + const cpu = new GPU({ mode: 'cpu' }); + const source = function(a) { + return a[this.thread.y][this.thread.x] * 2 + this.thread.y; + }; + const args = [[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]]; + const kernel = gpu.createKernel(source, { output: [6, 2] }); + const actual = kernel(args); + const expected = cpu.createKernel(source, { output: [6, 2] })(args); + assert.equal(kernel.kernel._lastRunPath, 'simd+scalar-tail'); + assert.deepEqual(actual.map(row => Array.from(row)), expected.map(row => Array.from(row))); + gpu.destroy(); + cpu.destroy(); +}); + +(THREADS_AVAILABLE ? test : skip)('asyncMode with a large output runs on the pool webasm', async assert => { + const gpu = new GPU({ mode: 'webasm' }); + const sync = new GPU({ mode: 'webasm' }); + const source = function(a) { + return a[this.thread.x] * 2 + Math.sqrt(this.thread.x); + }; + const args = new Float32Array(16384); + for (let i = 0; i < args.length; i++) args[i] = (i * 7919) % 1000 / 10; + const kernel = gpu.createKernel(source, { output: [16384], asyncMode: true }); + const pending = kernel(args); + assert.ok(pending instanceof Promise, 'the async contract returns a Promise'); + const result = await pending; + const expected = sync.createKernel(source, { output: [16384] })(args); + assert.equal(kernel.kernel._lastRunPath, 'threaded'); + const pool = kernel.kernel._pool; + assert.ok(pool !== null, 'the pool exists only after a threaded dispatch'); + assert.equal(pool.dispatchCount, 1); + const expectedWorkers = Math.min(pool.size, Math.ceil(16384 / 4096)); + assert.equal(pool.lastDispatch.workerCount, expectedWorkers, `split across ${ expectedWorkers } workers`); + assert.equal(pool.liveWorkerCount, expectedWorkers, 'exactly the assigned workers were spawned'); + const ranges = pool.lastDispatch.ranges; + let covered = 0; + let aligned = true; + for (let i = 0; i < ranges.length; i++) { + if (ranges[i][0] % 4 !== 0) aligned = false; + if (ranges[i][0] !== covered) aligned = false; + covered = ranges[i][1]; + } + assert.ok(aligned && covered === 16384, 'contiguous 4-aligned ranges covering every cell'); + assert.deepEqual(Array.from(result), Array.from(expected), 'threaded result equals the sync path'); + gpu.destroy(); + sync.destroy(); +}); + +(THREADS_AVAILABLE ? test : skip)('poolSize setting caps the split webasm', async assert => { + assert.expect(2); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function() { + return this.thread.x; + }, { output: [16384], asyncMode: true, poolSize: 2 }); + await kernel(); + const pool = kernel.kernel._pool; + assert.equal(pool.size, 2); + assert.equal(pool.lastDispatch.workerCount, 2); + gpu.destroy(); +}); + +(THREADS_AVAILABLE ? test : skip)('seeded random is identical however the work splits webasm', async assert => { + assert.expect(1); + const gpu = new GPU({ mode: 'webasm' }); + const sync = new GPU({ mode: 'webasm' }); + const threaded = gpu.createKernel(function() { + return Math.random(); + }, { output: [16384], asyncMode: true, randomSeed: 5 }); + const reference = sync.createKernel(function() { + return Math.random(); + }, { output: [16384], randomSeed: 5 }); + const threadedDraws = await threaded(); // per-cell seeding: the split cannot show + assert.deepEqual(Array.from(threadedDraws), Array.from(reference())); + gpu.destroy(); + sync.destroy(); +}); + +(THREADS_AVAILABLE ? test : skip)('threaded arguments are sampled at call time webasm', async assert => { + assert.expect(1); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function(a) { + return a[this.thread.x]; + }, { output: [4096], asyncMode: true }); + const buffer = new Float32Array(4096).fill(1); + const pending = kernel(buffer); + buffer[0] = 999; // after the call, before settlement: must not be seen + const result = await pending; + assert.equal(result[0], 1, 'the sync contract\'s call-time sampling holds under threads'); + gpu.destroy(); +}); + +test('asyncMode below the threading threshold resolves the sync result webasm', async assert => { + assert.expect(3); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function() { + return this.thread.x * 2; + }, { output: [64], asyncMode: true }); + const pending = kernel(); + assert.ok(pending instanceof Promise); + const result = await pending; + assert.deepEqual(Array.from(result.slice(0, 4)), [0, 2, 4, 6]); + assert.equal(kernel.kernel._pool, null, 'no pool for a 64-cell output'); + gpu.destroy(); +}); + +(THREADS_AVAILABLE ? test : skip)('destroy terminates the pool webasm', async assert => { + assert.expect(2); + const gpu = new GPU({ mode: 'webasm' }); + const kernel = gpu.createKernel(function() { + return 1; + }, { output: [8192], asyncMode: true }); + await kernel(); + const pool = kernel.kernel._pool; + assert.ok(pool !== null && pool.destroyed === false); + await gpu.destroy(); + assert.equal(pool.destroyed, true, 'gpu.destroy() tears the workers down'); +}); diff --git a/test/internal/function-composition.js b/test/internal/function-composition.js index a65cc81d..0c585475 100644 --- a/test/internal/function-composition.js +++ b/test/internal/function-composition.js @@ -98,7 +98,11 @@ test('CPUFunctionNode', () => { assert.equal(numberFunctionCompositionFunctionBuilder(CPUFunctionNode), 'function inner() {' + '\nreturn 1;' + '\n}' - + '\nresultX[x] = inner();\ncontinue;'); + + '\nkernelBody: {' + + '\n' + + '\nresultX[x] = inner();\nbreak kernelBody;' + + '\n' + + '\n}'); }); test('WebGLFunctionNode', () => { assert.equal(numberFunctionCompositionFunctionBuilder(WebGLFunctionNode), 'float inner() {' @@ -144,7 +148,11 @@ test('CPUFunctionNode', () => { assert.equal(array2FunctionCompositionFunctionBuilder(CPUFunctionNode), 'function inner() {' + '\nreturn new Float32Array([1, 2, 3, 4]);' + '\n}' - + '\nresultX[x] = inner()[0];\ncontinue;'); + + '\nkernelBody: {' + + '\n' + + '\nresultX[x] = inner()[0];\nbreak kernelBody;' + + '\n' + + '\n}'); }); test('WebGLFunctionNode', () => { assert.equal(array2FunctionCompositionFunctionBuilder(WebGLFunctionNode), 'vec4 inner() {' diff --git a/test/issues/865-cpu-control-flow.js b/test/issues/865-cpu-control-flow.js new file mode 100644 index 00000000..1e319bb4 --- /dev/null +++ b/test/issues/865-cpu-control-flow.js @@ -0,0 +1,140 @@ +const { assert, skip, test, module: describe } = require('qunit'); +const { GPU } = require('../../src'); + +describe('issue #865'); + +// Three shapes where the cpu backend disagreed with plain JavaScript. Every +// expectation here is computed by running the same logic as plain JS -- cpu +// was the reference everywhere else, so these are the shapes where the +// reference itself had to be fixed. Each runs across all backends so the +// agreement is total, not pairwise. + +const MODES = [ + ['cpu', true], + ['webgl', GPU.isWebGLSupported], + ['webgl2', GPU.isWebGL2Supported], + ['headlessgl', GPU.isHeadlessGLSupported], + ['webasm', GPU.isWebAssemblySupported], +]; + +function eachMode(name, run) { + for (const [mode, supported] of MODES) { + (supported ? test : skip)(`Issue #865 - ${ name } ${ mode }`, assert => run(assert, mode)); + } +} + +eachMode('early return inside a loop returns that cell\'s value', (assert, mode) => { + const reference = x => { + for (let i = 0; i < 20; i++) { + if (i * i > x) return i * 100 + x; + } + return -1; + }; + const gpu = new GPU({ mode }); + const kernel = gpu.createKernel(function () { + for (let i = 0; i < 20; i++) { + if (i * i > this.thread.x) { + return i * 100 + this.thread.x; + } + } + return -1; + }, { output: [6], loopMaxIterations: 30 }); + assert.deepEqual(Array.from(kernel()), [0, 1, 2, 3, 4, 5].map(reference)); + gpu.destroy(); +}); + +eachMode('do-while continue jumps to the test', (assert, mode) => { + const reference = (() => { + let i = 0; + let acc = 0; + do { + i++; + if (i % 3 === 0) continue; + acc += i; + } while (i < 12); + return acc; + })(); + const gpu = new GPU({ mode }); + const kernel = gpu.createKernel(function () { + let i = 0; + let acc = 0; + do { + i++; + if (i % 3 === 0) continue; + acc += i; + } while (i < 12); + return acc; + }, { output: [3], loopMaxIterations: 30 }); + assert.deepEqual(Array.from(kernel()), [reference, reference, reference]); + gpu.destroy(); +}); + +// GL scalar arguments are uniforms; assignment routes through a +// per-invocation shadow local there (#867) -- cpu and webasm bind per cell +eachMode('assigning to a scalar argument stays per-cell', (assert, mode) => { + const gpu = new GPU({ mode }); + const kernel = gpu.createKernel(function (base) { + base = base + this.thread.x; + return base; + }, { output: [4] }); + assert.deepEqual(Array.from(kernel(10)), [10, 11, 12, 13]); + gpu.destroy(); +}); + +test('Issue #865 - a reassigned array argument reads the new array cpu', assert => { + // the shadow must carry reads too, not only writes + const gpu = new GPU({ mode: 'cpu' }); + const kernel = gpu.createKernel(function (b, a) { + a = b; + return a[this.thread.x]; + }, { output: [3] }); + assert.deepEqual(Array.from(kernel([7, 8, 9], [1, 2, 3])), [7, 8, 9]); + gpu.destroy(); +}); + +test('Issue #865 - the do-while iteration cap still holds cpu', assert => { + // the native do-while form must not lose loopMaxIterations protection + const gpu = new GPU({ mode: 'cpu' }); + const kernel = gpu.createKernel(function () { + let i = 0; + do { + i++; + } while (true); + return i; + }, { output: [2], loopMaxIterations: 25 }); + const result = Array.from(kernel()); + assert.ok(result[0] <= 26, `capped near LOOP_MAX (got ${ result[0] })`); + gpu.destroy(); +}); + +test('Issue #865 - nested do-whiles keep separate safety counters cpu', assert => { + const reference = (() => { + let total = 0; + let i = 0; + do { + let j = 0; + do { + total += 1; + j++; + } while (j < 3); + i++; + } while (i < 4); + return total; + })(); + const gpu = new GPU({ mode: 'cpu' }); + const kernel = gpu.createKernel(function () { + let total = 0; + let i = 0; + do { + let j = 0; + do { + total += 1; + j++; + } while (j < 3); + i++; + } while (i < 4); + return total; + }, { output: [2], loopMaxIterations: 50 }); + assert.deepEqual(Array.from(kernel()), [reference, reference]); + gpu.destroy(); +}); diff --git a/test/issues/867-gl-edge-shapes.js b/test/issues/867-gl-edge-shapes.js new file mode 100644 index 00000000..159890b2 --- /dev/null +++ b/test/issues/867-gl-edge-shapes.js @@ -0,0 +1,126 @@ +const { assert, skip, test, module: describe } = require('qunit'); +const { GPU } = require('../../src'); + +describe('issue #867 edge shapes'); + +// Shapes the pre-merge adversarial review of #866 proved wrong or crashing +// after the first #867 fix: the do-while rotation and the argument shadow +// locals must hold under switch lowerings, unbraced bodies, and every scalar +// argument type. Expectations are plain-JS computed, agreement is total. + +const MODES = [ + ['cpu', true], + ['webgl', GPU.isWebGLSupported], + ['webgl2', GPU.isWebGL2Supported], + ['headlessgl', GPU.isHeadlessGLSupported], + ['webasm', GPU.isWebAssemblySupported], +]; + +function eachMode(name, run) { + for (const [mode, supported] of MODES) { + (supported ? test : skip)(`Issue #867 - ${ name } ${ mode }`, assert => run(assert, mode)); + } +} + +eachMode('do-while continue inside a switch case matches JavaScript', (assert, mode) => { + // the continue-rewrite approach injected a break the switch lowering + // rejected, and the error path itself crashed on the synthetic node; the + // rotated loop needs no body rewriting at all + const reference = (() => { + let i = 0; + let acc = 0; + do { + i += 1; + switch (i) { + case 2: + continue; + } + acc += 100; + } while (i < 2); + return acc; + })(); + const gpu = new GPU({ mode }); + const kernel = gpu.createKernel(function () { + let i = 0; + let acc = 0; + do { + i += 1; + switch (i) { + case 2: + continue; + } + acc += 100; + } while (i < 2); + return acc; + }, { output: [2], loopMaxIterations: 30 }); + assert.deepEqual(Array.from(kernel()), [reference, reference]); + gpu.destroy(); +}); + +eachMode('unbraced do-while as an if consequent honors continue', (assert, mode) => { + // the body-rewrite ran only for do-whiles sitting directly in a block, so + // an unbraced branch position silently kept the skipped-exit-test bug + const reference = (n => { + let acc = 0; + let j = 0; + if (n > 0) do { + j++; + if (j >= 3) continue; + acc += j; + } while (j < 3); + return acc + j; + })(1); + const gpu = new GPU({ mode }); + const kernel = gpu.createKernel(function (n) { + let acc = 0; + let j = 0; + if (n > 0) do { + j++; + if (j >= 3) continue; + acc += j; + } while (j < 3); + return acc + j; + }, { output: [2], loopMaxIterations: 30 }); + assert.deepEqual(Array.from(kernel(1)), [reference, reference]); + gpu.destroy(); +}); + +eachMode('assigning to a Boolean argument stays per-cell', (assert, mode) => { + // the bool(...) uniform wrap must not apply to the shadow local -- on the + // assignment's left side it is not even an lvalue + const gpu = new GPU({ mode }); + const kernel = gpu.createKernel(function (flag) { + if (this.thread.x > 0) { + flag = false; + } + return flag ? 1 : 0; + }, { output: [4] }); + assert.deepEqual(Array.from(kernel(true)), [1, 0, 0, 0]); + gpu.destroy(); +}); + +eachMode('assigning a literal to an Integer argument compiles and computes', (assert, mode) => { + // the shadow local is declared int; a float-printed literal on the right + // side was a GLSL compile error + const gpu = new GPU({ mode }); + const kernel = gpu.createKernel(function (n) { + n += 1; + return n; + }, { output: [3], argumentTypes: { n: 'Integer' } }); + assert.deepEqual(Array.from(kernel(10)), [11, 11, 11]); + gpu.destroy(); +}); + +eachMode('var redeclaration of an argument is one binding, like JavaScript', (assert, mode) => { + // `var x` redeclaring a parameter must not get a per-cell shadow on top of + // the local the declaration already emits -- that split one JS binding + // into two variables + const gpu = new GPU({ mode }); + const kernel = gpu.createKernel(function (x) { + var x = 5; + x += 1; + return x; + }, { output: [2] }); + assert.deepEqual(Array.from(kernel(40)), [6, 6]); + gpu.destroy(); +});