@graphty/webgpu-graph-algorithms 0.0.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +344 -23
- package/dist/browser.d.ts +1 -0
- package/dist/browser.js +32 -0
- package/dist/browser.js.map +1 -0
- package/dist/chunks/context-E6iKaeuJ.js +3136 -0
- package/dist/chunks/context-E6iKaeuJ.js.map +1 -0
- package/dist/node.d.ts +1 -0
- package/dist/node.js +131 -0
- package/dist/node.js.map +1 -0
- package/dist/src/accelerator.d.ts +26 -0
- package/dist/src/accelerator.d.ts.map +1 -0
- package/dist/src/accelerator.js +101 -0
- package/dist/src/accelerator.js.map +1 -0
- package/dist/src/algorithms/degree.d.ts +35 -0
- package/dist/src/algorithms/degree.d.ts.map +1 -0
- package/dist/src/algorithms/degree.js +119 -0
- package/dist/src/algorithms/degree.js.map +1 -0
- package/dist/src/browser/index.d.ts +23 -0
- package/dist/src/browser/index.d.ts.map +1 -0
- package/dist/src/browser/index.js +48 -0
- package/dist/src/browser/index.js.map +1 -0
- package/dist/src/constants.d.ts +92 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +92 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/context.d.ts +84 -0
- package/dist/src/context.d.ts.map +1 -0
- package/dist/src/context.js +304 -0
- package/dist/src/context.js.map +1 -0
- package/dist/src/device/acquire.d.ts +57 -0
- package/dist/src/device/acquire.d.ts.map +1 -0
- package/dist/src/device/acquire.js +232 -0
- package/dist/src/device/acquire.js.map +1 -0
- package/dist/src/device/caps.d.ts +43 -0
- package/dist/src/device/caps.d.ts.map +1 -0
- package/dist/src/device/caps.js +104 -0
- package/dist/src/device/caps.js.map +1 -0
- package/dist/src/device/error-scope.d.ts +75 -0
- package/dist/src/device/error-scope.d.ts.map +1 -0
- package/dist/src/device/error-scope.js +152 -0
- package/dist/src/device/error-scope.js.map +1 -0
- package/dist/src/device/lost.d.ts +51 -0
- package/dist/src/device/lost.d.ts.map +1 -0
- package/dist/src/device/lost.js +130 -0
- package/dist/src/device/lost.js.map +1 -0
- package/dist/src/device/webgpu-constants.d.ts +31 -0
- package/dist/src/device/webgpu-constants.d.ts.map +1 -0
- package/dist/src/device/webgpu-constants.js +31 -0
- package/dist/src/device/webgpu-constants.js.map +1 -0
- package/dist/src/errors.d.ts +56 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +57 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/index.d.ts +29 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +27 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/kernel/batch.d.ts +116 -0
- package/dist/src/kernel/batch.d.ts.map +1 -0
- package/dist/src/kernel/batch.js +335 -0
- package/dist/src/kernel/batch.js.map +1 -0
- package/dist/src/kernel/dispatch.d.ts +59 -0
- package/dist/src/kernel/dispatch.d.ts.map +1 -0
- package/dist/src/kernel/dispatch.js +139 -0
- package/dist/src/kernel/dispatch.js.map +1 -0
- package/dist/src/kernel/kernel.d.ts +84 -0
- package/dist/src/kernel/kernel.d.ts.map +1 -0
- package/dist/src/kernel/kernel.js +239 -0
- package/dist/src/kernel/kernel.js.map +1 -0
- package/dist/src/kernel/pipeline-cache.d.ts +90 -0
- package/dist/src/kernel/pipeline-cache.d.ts.map +1 -0
- package/dist/src/kernel/pipeline-cache.js +251 -0
- package/dist/src/kernel/pipeline-cache.js.map +1 -0
- package/dist/src/kernel/prelude.d.ts +35 -0
- package/dist/src/kernel/prelude.d.ts.map +1 -0
- package/dist/src/kernel/prelude.js +211 -0
- package/dist/src/kernel/prelude.js.map +1 -0
- package/dist/src/kernel/profiler.d.ts +64 -0
- package/dist/src/kernel/profiler.d.ts.map +1 -0
- package/dist/src/kernel/profiler.js +120 -0
- package/dist/src/kernel/profiler.js.map +1 -0
- package/dist/src/kernel/struct-block.d.ts +122 -0
- package/dist/src/kernel/struct-block.d.ts.map +1 -0
- package/dist/src/kernel/struct-block.js +353 -0
- package/dist/src/kernel/struct-block.js.map +1 -0
- package/dist/src/kernel/uniform-ring.d.ts +70 -0
- package/dist/src/kernel/uniform-ring.d.ts.map +1 -0
- package/dist/src/kernel/uniform-ring.js +146 -0
- package/dist/src/kernel/uniform-ring.js.map +1 -0
- package/dist/src/kernel/wgsl.d.ts +88 -0
- package/dist/src/kernel/wgsl.d.ts.map +1 -0
- package/dist/src/kernel/wgsl.js +390 -0
- package/dist/src/kernel/wgsl.js.map +1 -0
- package/dist/src/kernels.d.ts +81 -0
- package/dist/src/kernels.d.ts.map +1 -0
- package/dist/src/kernels.js +417 -0
- package/dist/src/kernels.js.map +1 -0
- package/dist/src/layouts/force-simulation.d.ts +498 -0
- package/dist/src/layouts/force-simulation.d.ts.map +1 -0
- package/dist/src/layouts/force-simulation.js +1650 -0
- package/dist/src/layouts/force-simulation.js.map +1 -0
- package/dist/src/layouts/forceatlas2.d.ts +210 -0
- package/dist/src/layouts/forceatlas2.d.ts.map +1 -0
- package/dist/src/layouts/forceatlas2.js +759 -0
- package/dist/src/layouts/forceatlas2.js.map +1 -0
- package/dist/src/layouts/inputs.d.ts +40 -0
- package/dist/src/layouts/inputs.d.ts.map +1 -0
- package/dist/src/layouts/inputs.js +185 -0
- package/dist/src/layouts/inputs.js.map +1 -0
- package/dist/src/layouts/repulsion-exact.d.ts +85 -0
- package/dist/src/layouts/repulsion-exact.d.ts.map +1 -0
- package/dist/src/layouts/repulsion-exact.js +134 -0
- package/dist/src/layouts/repulsion-exact.js.map +1 -0
- package/dist/src/layouts/seed.d.ts +56 -0
- package/dist/src/layouts/seed.d.ts.map +1 -0
- package/dist/src/layouts/seed.js +173 -0
- package/dist/src/layouts/seed.js.map +1 -0
- package/dist/src/memory/buffer-pool.d.ts +73 -0
- package/dist/src/memory/buffer-pool.d.ts.map +1 -0
- package/dist/src/memory/buffer-pool.js +170 -0
- package/dist/src/memory/buffer-pool.js.map +1 -0
- package/dist/src/memory/lease.d.ts +53 -0
- package/dist/src/memory/lease.d.ts.map +1 -0
- package/dist/src/memory/lease.js +85 -0
- package/dist/src/memory/lease.js.map +1 -0
- package/dist/src/memory/readback.d.ts +143 -0
- package/dist/src/memory/readback.d.ts.map +1 -0
- package/dist/src/memory/readback.js +375 -0
- package/dist/src/memory/readback.js.map +1 -0
- package/dist/src/memory/residency.d.ts +83 -0
- package/dist/src/memory/residency.d.ts.map +1 -0
- package/dist/src/memory/residency.js +573 -0
- package/dist/src/memory/residency.js.map +1 -0
- package/dist/src/memory/upload-plan.d.ts +101 -0
- package/dist/src/memory/upload-plan.d.ts.map +1 -0
- package/dist/src/memory/upload-plan.js +265 -0
- package/dist/src/memory/upload-plan.js.map +1 -0
- package/dist/src/node/index.d.ts +64 -0
- package/dist/src/node/index.d.ts.map +1 -0
- package/dist/src/node/index.js +183 -0
- package/dist/src/node/index.js.map +1 -0
- package/dist/src/primitives/reduce.d.ts +57 -0
- package/dist/src/primitives/reduce.d.ts.map +1 -0
- package/dist/src/primitives/reduce.js +161 -0
- package/dist/src/primitives/reduce.js.map +1 -0
- package/dist/src/primitives/segmented-reduce.d.ts +38 -0
- package/dist/src/primitives/segmented-reduce.d.ts.map +1 -0
- package/dist/src/primitives/segmented-reduce.js +211 -0
- package/dist/src/primitives/segmented-reduce.js.map +1 -0
- package/dist/src/types/accelerator.d.ts +209 -0
- package/dist/src/types/accelerator.d.ts.map +1 -0
- package/dist/src/types/accelerator.js +8 -0
- package/dist/src/types/accelerator.js.map +1 -0
- package/dist/src/types/context.d.ts +114 -0
- package/dist/src/types/context.d.ts.map +1 -0
- package/dist/src/types/context.js +7 -0
- package/dist/src/types/context.js.map +1 -0
- package/dist/src/types/layout.d.ts +95 -0
- package/dist/src/types/layout.d.ts.map +1 -0
- package/dist/src/types/layout.js +6 -0
- package/dist/src/types/layout.js.map +1 -0
- package/dist/src/types/memory.d.ts +22 -0
- package/dist/src/types/memory.d.ts.map +1 -0
- package/dist/src/types/memory.js +7 -0
- package/dist/src/types/memory.js.map +1 -0
- package/dist/src/types/options.d.ts +78 -0
- package/dist/src/types/options.d.ts.map +1 -0
- package/dist/src/types/options.js +7 -0
- package/dist/src/types/options.js.map +1 -0
- package/dist/src/types/run.d.ts +13 -0
- package/dist/src/types/run.d.ts.map +1 -0
- package/dist/src/types/run.js +6 -0
- package/dist/src/types/run.js.map +1 -0
- package/dist/src/wgsl/degree.wgsl.d.ts +10 -0
- package/dist/src/wgsl/degree.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/degree.wgsl.js +25 -0
- package/dist/src/wgsl/degree.wgsl.js.map +1 -0
- package/dist/src/wgsl/fa2-attraction.wgsl.d.ts +12 -0
- package/dist/src/wgsl/fa2-attraction.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/fa2-attraction.wgsl.js +37 -0
- package/dist/src/wgsl/fa2-attraction.wgsl.js.map +1 -0
- package/dist/src/wgsl/fa2-integrate.wgsl.d.ts +13 -0
- package/dist/src/wgsl/fa2-integrate.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/fa2-integrate.wgsl.js +69 -0
- package/dist/src/wgsl/fa2-integrate.wgsl.js.map +1 -0
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts +12 -0
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js +79 -0
- package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js.map +1 -0
- package/dist/src/wgsl/fa2-speed-finalize.wgsl.d.ts +15 -0
- package/dist/src/wgsl/fa2-speed-finalize.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/fa2-speed-finalize.wgsl.js +54 -0
- package/dist/src/wgsl/fa2-speed-finalize.wgsl.js.map +1 -0
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts +14 -0
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.js +57 -0
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.js.map +1 -0
- package/dist/src/wgsl/fa2-to-scene.wgsl.d.ts +11 -0
- package/dist/src/wgsl/fa2-to-scene.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/fa2-to-scene.wgsl.js +19 -0
- package/dist/src/wgsl/fa2-to-scene.wgsl.js.map +1 -0
- package/dist/src/wgsl/fill.wgsl.d.ts +7 -0
- package/dist/src/wgsl/fill.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/fill.wgsl.js +14 -0
- package/dist/src/wgsl/fill.wgsl.js.map +1 -0
- package/dist/src/wgsl/reduce.wgsl.d.ts +10 -0
- package/dist/src/wgsl/reduce.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/reduce.wgsl.js +63 -0
- package/dist/src/wgsl/reduce.wgsl.js.map +1 -0
- package/dist/src/wgsl/segmented-reduce.wgsl.d.ts +13 -0
- package/dist/src/wgsl/segmented-reduce.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/segmented-reduce.wgsl.js +35 -0
- package/dist/src/wgsl/segmented-reduce.wgsl.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/webgpu-graph-algorithms.d.ts +1 -0
- package/dist/webgpu-graph-algorithms.js +4454 -0
- package/dist/webgpu-graph-algorithms.js.map +1 -0
- package/package.json +108 -17
- package/src/accelerator.ts +117 -0
- package/src/algorithms/degree.ts +142 -0
- package/src/browser/index.ts +57 -0
- package/src/constants.ts +116 -0
- package/src/context.ts +399 -0
- package/src/device/acquire.ts +256 -0
- package/src/device/caps.ts +122 -0
- package/src/device/error-scope.ts +171 -0
- package/src/device/lost.ts +142 -0
- package/src/device/webgpu-constants.ts +44 -0
- package/src/errors.ts +94 -0
- package/src/index.ts +102 -0
- package/src/kernel/batch.ts +427 -0
- package/src/kernel/dispatch.ts +162 -0
- package/src/kernel/kernel.ts +311 -0
- package/src/kernel/pipeline-cache.ts +288 -0
- package/src/kernel/prelude.ts +229 -0
- package/src/kernel/profiler.ts +148 -0
- package/src/kernel/struct-block.ts +439 -0
- package/src/kernel/uniform-ring.ts +184 -0
- package/src/kernel/wgsl.ts +490 -0
- package/src/kernels.ts +511 -0
- package/src/layouts/force-simulation.ts +2111 -0
- package/src/layouts/forceatlas2.ts +942 -0
- package/src/layouts/inputs.ts +252 -0
- package/src/layouts/repulsion-exact.ts +183 -0
- package/src/layouts/seed.ts +198 -0
- package/src/memory/buffer-pool.ts +204 -0
- package/src/memory/lease.ts +93 -0
- package/src/memory/readback.ts +429 -0
- package/src/memory/residency.ts +753 -0
- package/src/memory/upload-plan.ts +350 -0
- package/src/node/index.ts +230 -0
- package/src/primitives/reduce.ts +233 -0
- package/src/primitives/segmented-reduce.ts +270 -0
- package/src/types/accelerator.ts +236 -0
- package/src/types/context.ts +135 -0
- package/src/types/layout.ts +103 -0
- package/src/types/memory.ts +23 -0
- package/src/types/options.ts +84 -0
- package/src/types/run.ts +13 -0
- package/src/wgsl/degree.wgsl.ts +24 -0
- package/src/wgsl/fa2-attraction.wgsl.ts +37 -0
- package/src/wgsl/fa2-integrate.wgsl.ts +69 -0
- package/src/wgsl/fa2-repulsion-exact.wgsl.ts +78 -0
- package/src/wgsl/fa2-speed-finalize.wgsl.ts +53 -0
- package/src/wgsl/fa2-stats-finalize.wgsl.ts +57 -0
- package/src/wgsl/fa2-to-scene.wgsl.ts +19 -0
- package/src/wgsl/fill.wgsl.ts +13 -0
- package/src/wgsl/reduce.wgsl.ts +62 -0
- package/src/wgsl/segmented-reduce.wgsl.ts +35 -0
package/src/kernels.ts
ADDED
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE kernel registry (spec 3.5; contract 3.10): every WGSL module the package compiles, keyed by id, with the
|
|
3
|
+
* binding table, the override declarations, the generated uniform / storage blocks and the feature needs from
|
|
4
|
+
* which src/kernel/wgsl.ts emits the bind declarations and src/kernel/pipeline-cache.ts derives the explicit
|
|
5
|
+
* bind-group layouts. A variant cannot exist without an entry here: the compile tests, the bind-group-budget
|
|
6
|
+
* test and PipelineCache.warm() iterate this table. P1-T4 lands degree, reduce, fill, fa2-repulsion-exact (K3)
|
|
7
|
+
* and fa2-speed-finalize (K4) together with every generated block of contract 3.10.2; P2-T2 lands
|
|
8
|
+
* segmented-reduce; P3-T2 adds fa2-stats-finalize (K1), fa2-attraction (K2), fa2-integrate (K5) and
|
|
9
|
+
* fa2-to-scene. This file is the only importer of src/wgsl/** (spec 3.2; test/layers.test.ts).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { STATE_HEADER_BYTES } from "./constants.js";
|
|
13
|
+
import { WebGpuGraphError } from "./errors.js";
|
|
14
|
+
import { UniformBlock } from "./kernel/struct-block.js";
|
|
15
|
+
import { type BindingDecl, type OverrideDecl, type WgslModuleSpec } from "./kernel/wgsl.js";
|
|
16
|
+
import { type CoreBinding } from "./memory/residency.js";
|
|
17
|
+
import { type Binding } from "./types/memory.js";
|
|
18
|
+
import { degreeWgsl } from "./wgsl/degree.wgsl.js";
|
|
19
|
+
import { fa2AttractionWgsl } from "./wgsl/fa2-attraction.wgsl.js";
|
|
20
|
+
import { fa2IntegrateWgsl } from "./wgsl/fa2-integrate.wgsl.js";
|
|
21
|
+
import { fa2RepulsionExactWgsl } from "./wgsl/fa2-repulsion-exact.wgsl.js";
|
|
22
|
+
import { fa2SpeedFinalizeWgsl } from "./wgsl/fa2-speed-finalize.wgsl.js";
|
|
23
|
+
import { fa2StatsFinalizeWgsl } from "./wgsl/fa2-stats-finalize.wgsl.js";
|
|
24
|
+
import { fa2ToSceneWgsl } from "./wgsl/fa2-to-scene.wgsl.js";
|
|
25
|
+
import { fillWgsl } from "./wgsl/fill.wgsl.js";
|
|
26
|
+
import { reduceWgsl } from "./wgsl/reduce.wgsl.js";
|
|
27
|
+
import { segmentedReduceWgsl } from "./wgsl/segmented-reduce.wgsl.js";
|
|
28
|
+
|
|
29
|
+
/** Every module id of P1-P3 (P4+ ids are appended, never renamed). */
|
|
30
|
+
export type KernelId =
|
|
31
|
+
| "degree"
|
|
32
|
+
| "reduce"
|
|
33
|
+
| "fill"
|
|
34
|
+
| "segmented-reduce"
|
|
35
|
+
| "fa2-stats-finalize"
|
|
36
|
+
| "fa2-attraction"
|
|
37
|
+
| "fa2-repulsion-exact"
|
|
38
|
+
| "fa2-speed-finalize"
|
|
39
|
+
| "fa2-integrate"
|
|
40
|
+
| "fa2-to-scene";
|
|
41
|
+
|
|
42
|
+
/** One registry entry: everything of a WgslModuleSpec except the per-variant overrides and snippets. */
|
|
43
|
+
export interface KernelEntry {
|
|
44
|
+
readonly id: KernelId;
|
|
45
|
+
readonly body: string;
|
|
46
|
+
readonly entryPoint: string;
|
|
47
|
+
readonly bindings: readonly BindingDecl[];
|
|
48
|
+
readonly overrideDecls: readonly OverrideDecl[];
|
|
49
|
+
readonly uniforms: readonly UniformBlock[];
|
|
50
|
+
/** ["subgroups"] when the body calls a reduction helper (the twin axis), else []. */
|
|
51
|
+
readonly needs: readonly "subgroups"[];
|
|
52
|
+
/** The snippet marker names the body carries (segmented-reduce: ["VALUE"]). */
|
|
53
|
+
readonly snippetSlots: readonly string[];
|
|
54
|
+
/** The phase the entry landed in (documentation and the compile-matrix filter). */
|
|
55
|
+
readonly phase: "P1" | "P2" | "P3";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ---- the generated blocks (spec 5.3; contract 3.10.2): field order = byte order, offsets in the JSDoc
|
|
59
|
+
|
|
60
|
+
/** `RangeParams` (uniform, 32 B): rows `[start, end)` @0 / @4 of the dispatch, the bound arc window `[arcBase, arcEnd)` @8 / @12 (0 and arcCount when not windowed), `accumulate` @16 (1 combines into `out[i]` instead of overwriting: the P4 windowed loop), `n` @20 (the node count that bounds neighbour indices), `pad0` @24, `pad1` @28. */
|
|
61
|
+
export const RANGE_PARAMS: UniformBlock = UniformBlock.define("RangeParams", [
|
|
62
|
+
["start", "u32"],
|
|
63
|
+
["end", "u32"],
|
|
64
|
+
["arcBase", "u32"],
|
|
65
|
+
["arcEnd", "u32"],
|
|
66
|
+
["accumulate", "u32"],
|
|
67
|
+
["n", "u32"],
|
|
68
|
+
["pad0", "u32"],
|
|
69
|
+
["pad1", "u32"],
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
/** `ReduceParams` (uniform, 16 B): `count` @0 elements of the level, `outOffset` @4 (the element index the level writes at), `level` @8, `pad0` @12. */
|
|
73
|
+
export const REDUCE_PARAMS: UniformBlock = UniformBlock.define("ReduceParams", [
|
|
74
|
+
["count", "u32"],
|
|
75
|
+
["outOffset", "u32"],
|
|
76
|
+
["level", "u32"],
|
|
77
|
+
["pad0", "u32"],
|
|
78
|
+
]);
|
|
79
|
+
|
|
80
|
+
/** `FillParams` (uniform, 16 B): `count` @0 words, `value` @4, `mode` @8 (0 = the constant `value`, 1 = iota `i + value`), `pad0` @12. */
|
|
81
|
+
export const FILL_PARAMS: UniformBlock = UniformBlock.define("FillParams", [
|
|
82
|
+
["count", "u32"],
|
|
83
|
+
["value", "u32"],
|
|
84
|
+
["mode", "u32"],
|
|
85
|
+
["pad0", "u32"],
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
/** `Fa2Params` (uniform, 96 B; spec 7.3): the per-iteration ForceAtlas2 parameters -- `n` @0, `dim` @4, `flags` @8 (bit 0 = FA2_FLAG_FIRST), `tierStart` @12, `tierEnd` @16, `iterationIndex` @20, `seed` @24, `nearMax` @28, `scalingRatio` @32, `gravity` @36, `jitterTolerance` @40, `scale` @44, `center` @48 (xyz, w 0), `settleThreshold` @64, `extentFactor` @68, `gridMax` @72, `levels` @76, `pad` @80 (reserved for the P4 GridSpec). */
|
|
89
|
+
export const FA2_PARAMS: UniformBlock = UniformBlock.define("Fa2Params", [
|
|
90
|
+
["n", "u32"],
|
|
91
|
+
["dim", "u32"],
|
|
92
|
+
["flags", "u32"],
|
|
93
|
+
["tierStart", "u32"],
|
|
94
|
+
["tierEnd", "u32"],
|
|
95
|
+
["iterationIndex", "u32"],
|
|
96
|
+
["seed", "u32"],
|
|
97
|
+
["nearMax", "u32"],
|
|
98
|
+
["scalingRatio", "f32"],
|
|
99
|
+
["gravity", "f32"],
|
|
100
|
+
["jitterTolerance", "f32"],
|
|
101
|
+
["scale", "f32"],
|
|
102
|
+
["center", "vec4f"],
|
|
103
|
+
["settleThreshold", "f32"],
|
|
104
|
+
["extentFactor", "f32"],
|
|
105
|
+
["gridMax", "u32"],
|
|
106
|
+
["levels", "u32"],
|
|
107
|
+
["pad", "vec4f"],
|
|
108
|
+
]);
|
|
109
|
+
|
|
110
|
+
/** `Fa2State` (storage, padded to STATE_HEADER_BYTES = 256; spec 7.3): the device-resident controller state the finalize kernels write and the host reads back for stats -- `speed` @0, `speedEfficiency` @4, `swing` @8, `traction` @12, `centroid` @16, `rmsRadius` @32, `radius` @36, `meanDisplacement` @40, `iteration` @44, `min` @48, `max` @64, `gridMin` @80 (P4), `eps` @96 (P4), `settledCount` @100, `outsideGrid` @104 (P4), `maxCellOccupancy` @108 (P4), `reserved0` .. `reserved8` @112 .. @240. */
|
|
111
|
+
export const FA2_STATE: UniformBlock = UniformBlock.define(
|
|
112
|
+
"Fa2State",
|
|
113
|
+
[
|
|
114
|
+
["speed", "f32"],
|
|
115
|
+
["speedEfficiency", "f32"],
|
|
116
|
+
["swing", "f32"],
|
|
117
|
+
["traction", "f32"],
|
|
118
|
+
["centroid", "vec4f"],
|
|
119
|
+
["rmsRadius", "f32"],
|
|
120
|
+
["radius", "f32"],
|
|
121
|
+
["meanDisplacement", "f32"],
|
|
122
|
+
["iteration", "u32"],
|
|
123
|
+
["min", "vec4f"],
|
|
124
|
+
["max", "vec4f"],
|
|
125
|
+
["gridMin", "vec4f"],
|
|
126
|
+
["eps", "f32"],
|
|
127
|
+
["settledCount", "u32"],
|
|
128
|
+
["outsideGrid", "u32"],
|
|
129
|
+
["maxCellOccupancy", "u32"],
|
|
130
|
+
["reserved0", "vec4f"],
|
|
131
|
+
["reserved1", "vec4f"],
|
|
132
|
+
["reserved2", "vec4f"],
|
|
133
|
+
["reserved3", "vec4f"],
|
|
134
|
+
["reserved4", "vec4f"],
|
|
135
|
+
["reserved5", "vec4f"],
|
|
136
|
+
["reserved6", "vec4f"],
|
|
137
|
+
["reserved7", "vec4f"],
|
|
138
|
+
["reserved8", "vec4f"],
|
|
139
|
+
],
|
|
140
|
+
{ layout: "storage", padTo: STATE_HEADER_BYTES },
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
/** `Fa2Trace` (storage record, 32 B; spec 7.3): one per-iteration trace record -- `swing` @0, `traction` @4, `speed` @8, `speedEfficiency` @12 (written by K4), `meanDisplacement` @16, `settledCount` @20, `iteration` @24 (written by K1), `pad0` @28; the trace region is `array<Fa2Trace>` at byte offset STATE_HEADER_BYTES of the state buffer. */
|
|
144
|
+
export const FA2_TRACE: UniformBlock = UniformBlock.define(
|
|
145
|
+
"Fa2Trace",
|
|
146
|
+
[
|
|
147
|
+
["swing", "f32"],
|
|
148
|
+
["traction", "f32"],
|
|
149
|
+
["speed", "f32"],
|
|
150
|
+
["speedEfficiency", "f32"],
|
|
151
|
+
["meanDisplacement", "f32"],
|
|
152
|
+
["settledCount", "u32"],
|
|
153
|
+
["iteration", "u32"],
|
|
154
|
+
["pad0", "u32"],
|
|
155
|
+
],
|
|
156
|
+
{ layout: "storage" },
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
/** `Fa2Partial` (storage record, 64 B; spec 7.3): one per-workgroup partial -- `sum` @0 (xyz = sum of positions, w = sum of |p - centroid|^2), `min` @16, `max` @32 (w = max of |p - centroid|^2, the exact layoutRadius source), written by K5; `swingTraction` @48 (written by K3's epilogue); `dispFree` @56 (x = sum |dp| over free rows, y = the free count as an f32 <= 256, written by K5). */
|
|
160
|
+
export const FA2_PARTIAL: UniformBlock = UniformBlock.define(
|
|
161
|
+
"Fa2Partial",
|
|
162
|
+
[
|
|
163
|
+
["sum", "vec4f"],
|
|
164
|
+
["min", "vec4f"],
|
|
165
|
+
["max", "vec4f"],
|
|
166
|
+
["swingTraction", "vec2f"],
|
|
167
|
+
["dispFree", "vec2f"],
|
|
168
|
+
],
|
|
169
|
+
{ layout: "storage" },
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
// ---- the entries (contract 3.10.1; group 0 = graph, 1 = state, 2 = params, 3 = cold)
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* One binding declaration of contract 3.9, so the tables below read like the rows of 3.10.1.
|
|
176
|
+
* @param group - the bind group (0 graph, 1 state, 2 params, 3 cold)
|
|
177
|
+
* @param binding - the slot inside the group
|
|
178
|
+
* @param name - the WGSL variable name (also the KernelBindings key)
|
|
179
|
+
* @param kind - "storage" (read_write), "storage-ro" (read) or "uniform"
|
|
180
|
+
* @param wgslType - the element / struct type text
|
|
181
|
+
* @returns the declaration
|
|
182
|
+
*/
|
|
183
|
+
function decl(
|
|
184
|
+
group: 0 | 1 | 2 | 3,
|
|
185
|
+
binding: number,
|
|
186
|
+
name: string,
|
|
187
|
+
kind: BindingDecl["kind"],
|
|
188
|
+
wgslType: string,
|
|
189
|
+
): BindingDecl {
|
|
190
|
+
return { group, binding, name, kind, wgslType };
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/** The four group-0 graph slots of every row-walking kernel (spec 3.5): rowPtr, colIdx, weights | dummy, perm | dummy -- all read-only, so the dummies never alias a writable slot (3.10.1). */
|
|
194
|
+
const GRAPH_SLOTS: readonly BindingDecl[] = [
|
|
195
|
+
decl(0, 0, "rowPtr", "storage-ro", "array<u32>"),
|
|
196
|
+
decl(0, 1, "colIdx", "storage-ro", "array<u32>"),
|
|
197
|
+
decl(0, 2, "weights", "storage-ro", "array<f32>"),
|
|
198
|
+
decl(0, 3, "perm", "storage-ro", "array<u32>"),
|
|
199
|
+
];
|
|
200
|
+
|
|
201
|
+
/** `degree` (3.10.1): 5 storage bindings; only the standard USE_PERM / HAS_WEIGHTS overrides. */
|
|
202
|
+
const DEGREE: KernelEntry = {
|
|
203
|
+
id: "degree",
|
|
204
|
+
body: degreeWgsl,
|
|
205
|
+
entryPoint: "degree",
|
|
206
|
+
bindings: GRAPH_SLOTS.concat(decl(1, 0, "out", "storage", "array<u32>"), decl(2, 0, "P", "uniform", "RangeParams")),
|
|
207
|
+
overrideDecls: [],
|
|
208
|
+
uniforms: [RANGE_PARAMS],
|
|
209
|
+
needs: [],
|
|
210
|
+
snippetSlots: [],
|
|
211
|
+
phase: "P1",
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
/** `reduce` (3.10.1): the multi-level reduction; OP 0 sum / 1 min / 2 max, DTYPE 0 f32 / 1 u32 / 2 vec4f, FINAL for the one-workgroup level; 2 storage bindings; calls the reduction helpers. */
|
|
215
|
+
const REDUCE: KernelEntry = {
|
|
216
|
+
id: "reduce",
|
|
217
|
+
body: reduceWgsl,
|
|
218
|
+
entryPoint: "reduce",
|
|
219
|
+
bindings: [
|
|
220
|
+
decl(1, 0, "src", "storage-ro", "array<u32>"),
|
|
221
|
+
decl(1, 1, "out", "storage", "array<u32>"),
|
|
222
|
+
decl(2, 0, "P", "uniform", "ReduceParams"),
|
|
223
|
+
],
|
|
224
|
+
overrideDecls: [
|
|
225
|
+
{ name: "OP", type: "u32", default: 0 },
|
|
226
|
+
{ name: "DTYPE", type: "u32", default: 0 },
|
|
227
|
+
{ name: "FINAL", type: "bool", default: false },
|
|
228
|
+
],
|
|
229
|
+
uniforms: [REDUCE_PARAMS],
|
|
230
|
+
needs: ["subgroups"],
|
|
231
|
+
snippetSlots: [],
|
|
232
|
+
phase: "P1",
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
/** `fill` (3.10.1): dst[i] = value (mode 0) or i + value (mode 1) over `count` words; 1 storage binding. */
|
|
236
|
+
const FILL: KernelEntry = {
|
|
237
|
+
id: "fill",
|
|
238
|
+
body: fillWgsl,
|
|
239
|
+
entryPoint: "fill",
|
|
240
|
+
bindings: [decl(1, 0, "dst", "storage", "array<u32>"), decl(2, 0, "P", "uniform", "FillParams")],
|
|
241
|
+
overrideDecls: [],
|
|
242
|
+
uniforms: [FILL_PARAMS],
|
|
243
|
+
needs: [],
|
|
244
|
+
snippetSlots: [],
|
|
245
|
+
phase: "P1",
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/** `segmented-reduce` (3.10.1): the per-row fold of the VALUE snippet over the CSR rows; OP 0 sum / 1 min / 2 max, TIER 0 (thread-per-row; the degreeOrder tiers land at P4) plus the standard USE_PERM / HAS_WEIGHTS; 5 storage bindings; one snippet slot. */
|
|
249
|
+
const SEGMENTED_REDUCE: KernelEntry = {
|
|
250
|
+
id: "segmented-reduce",
|
|
251
|
+
body: segmentedReduceWgsl,
|
|
252
|
+
entryPoint: "segmented_reduce",
|
|
253
|
+
bindings: GRAPH_SLOTS.concat(decl(1, 0, "out", "storage", "array<f32>"), decl(2, 0, "P", "uniform", "RangeParams")),
|
|
254
|
+
overrideDecls: [
|
|
255
|
+
{ name: "OP", type: "u32", default: 0 },
|
|
256
|
+
{ name: "TIER", type: "u32", default: 0 },
|
|
257
|
+
],
|
|
258
|
+
uniforms: [RANGE_PARAMS],
|
|
259
|
+
needs: [],
|
|
260
|
+
snippetSlots: ["VALUE"],
|
|
261
|
+
phase: "P2",
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
/** `fa2-stats-finalize` (K1, 3.10.1): the one-workgroup fold of the previous integrate's partials into the state block and the K1 half of the trace record; 3 storage bindings; calls the reduction helpers. */
|
|
265
|
+
const FA2_STATS_FINALIZE: KernelEntry = {
|
|
266
|
+
id: "fa2-stats-finalize",
|
|
267
|
+
body: fa2StatsFinalizeWgsl,
|
|
268
|
+
entryPoint: "stats_finalize",
|
|
269
|
+
bindings: [
|
|
270
|
+
decl(1, 0, "partials", "storage-ro", "array<Fa2Partial>"),
|
|
271
|
+
decl(1, 1, "S", "storage", "Fa2State"),
|
|
272
|
+
decl(1, 2, "T", "storage", "array<Fa2Trace>"),
|
|
273
|
+
decl(2, 0, "P", "uniform", "Fa2Params"),
|
|
274
|
+
],
|
|
275
|
+
overrideDecls: [],
|
|
276
|
+
uniforms: [FA2_PARAMS, FA2_STATE, FA2_TRACE, FA2_PARTIAL],
|
|
277
|
+
needs: ["subgroups"],
|
|
278
|
+
snippetSlots: [],
|
|
279
|
+
phase: "P3",
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
/** `fa2-attraction` (K2, 3.10.1): the thread-per-row attraction gather over the CSR rows (the first writer of `force` each iteration); LINLOG / DISTRIBUTED / TIER 0 plus the standard USE_PERM / HAS_WEIGHTS; 6 storage bindings. */
|
|
283
|
+
const FA2_ATTRACTION: KernelEntry = {
|
|
284
|
+
id: "fa2-attraction",
|
|
285
|
+
body: fa2AttractionWgsl,
|
|
286
|
+
entryPoint: "attraction",
|
|
287
|
+
bindings: GRAPH_SLOTS.concat(
|
|
288
|
+
decl(1, 0, "pos", "storage-ro", "array<vec4f>"),
|
|
289
|
+
decl(1, 1, "force", "storage", "array<f32>"),
|
|
290
|
+
decl(2, 0, "P", "uniform", "Fa2Params"),
|
|
291
|
+
),
|
|
292
|
+
overrideDecls: [
|
|
293
|
+
{ name: "LINLOG", type: "bool", default: false },
|
|
294
|
+
{ name: "DISTRIBUTED", type: "bool", default: false },
|
|
295
|
+
{ name: "TIER", type: "u32", default: 0 },
|
|
296
|
+
],
|
|
297
|
+
uniforms: [FA2_PARAMS],
|
|
298
|
+
needs: [],
|
|
299
|
+
snippetSlots: [],
|
|
300
|
+
phase: "P3",
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
/** `fa2-repulsion-exact` (K3, 3.10.1): the tiled all-pairs repulsion with the gravity and swing / traction epilogue; 6 storage bindings (`oldForce` read-only: it only calls load_old); calls the reduction helpers. */
|
|
304
|
+
const FA2_REPULSION_EXACT: KernelEntry = {
|
|
305
|
+
id: "fa2-repulsion-exact",
|
|
306
|
+
body: fa2RepulsionExactWgsl,
|
|
307
|
+
entryPoint: "repulsion",
|
|
308
|
+
bindings: [
|
|
309
|
+
decl(1, 0, "pos", "storage-ro", "array<vec4f>"),
|
|
310
|
+
decl(1, 1, "S", "storage", "Fa2State"),
|
|
311
|
+
decl(1, 2, "force", "storage", "array<f32>"),
|
|
312
|
+
decl(1, 3, "oldForce", "storage-ro", "array<f32>"),
|
|
313
|
+
decl(1, 4, "fixedMask", "storage-ro", "array<u32>"),
|
|
314
|
+
decl(1, 5, "partials", "storage", "array<Fa2Partial>"),
|
|
315
|
+
decl(2, 0, "P", "uniform", "Fa2Params"),
|
|
316
|
+
],
|
|
317
|
+
overrideDecls: [
|
|
318
|
+
{ name: "SWING_MODE", type: "u32", default: 0 },
|
|
319
|
+
{ name: "STRONG_GRAVITY", type: "bool", default: false },
|
|
320
|
+
{ name: "GRAVITY_CENTER", type: "u32", default: 0 },
|
|
321
|
+
],
|
|
322
|
+
uniforms: [FA2_PARAMS, FA2_STATE, FA2_PARTIAL],
|
|
323
|
+
needs: ["subgroups"],
|
|
324
|
+
snippetSlots: [],
|
|
325
|
+
phase: "P1",
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
/** `fa2-speed-finalize` (K4, 3.10.1): the one-workgroup partials fold and estimateFactor; 3 storage bindings; calls the reduction helpers. */
|
|
329
|
+
const FA2_SPEED_FINALIZE: KernelEntry = {
|
|
330
|
+
id: "fa2-speed-finalize",
|
|
331
|
+
body: fa2SpeedFinalizeWgsl,
|
|
332
|
+
entryPoint: "speed_finalize",
|
|
333
|
+
bindings: [
|
|
334
|
+
decl(1, 0, "partials", "storage-ro", "array<Fa2Partial>"),
|
|
335
|
+
decl(1, 1, "S", "storage", "Fa2State"),
|
|
336
|
+
decl(1, 2, "T", "storage", "array<Fa2Trace>"),
|
|
337
|
+
decl(2, 0, "P", "uniform", "Fa2Params"),
|
|
338
|
+
],
|
|
339
|
+
overrideDecls: [{ name: "SWING_MODE", type: "u32", default: 0 }],
|
|
340
|
+
uniforms: [FA2_PARAMS, FA2_STATE, FA2_TRACE, FA2_PARTIAL],
|
|
341
|
+
needs: ["subgroups"],
|
|
342
|
+
snippetSlots: [],
|
|
343
|
+
phase: "P1",
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
/** `fa2-integrate` (K5, 3.10.1): the per-node speed factor and position update (no clamp, D25), `oldForce` stored in SWING_MODE 0, and the partials A / C of the next K1; 6 storage bindings; calls the reduction helpers. */
|
|
347
|
+
const FA2_INTEGRATE: KernelEntry = {
|
|
348
|
+
id: "fa2-integrate",
|
|
349
|
+
body: fa2IntegrateWgsl,
|
|
350
|
+
entryPoint: "integrate",
|
|
351
|
+
bindings: [
|
|
352
|
+
decl(1, 0, "force", "storage-ro", "array<f32>"),
|
|
353
|
+
decl(1, 1, "oldForce", "storage", "array<f32>"),
|
|
354
|
+
decl(1, 2, "fixedMask", "storage-ro", "array<u32>"),
|
|
355
|
+
decl(1, 3, "S", "storage", "Fa2State"),
|
|
356
|
+
decl(1, 4, "pos", "storage", "array<vec4f>"),
|
|
357
|
+
decl(1, 5, "partials", "storage", "array<Fa2Partial>"),
|
|
358
|
+
decl(2, 0, "P", "uniform", "Fa2Params"),
|
|
359
|
+
],
|
|
360
|
+
overrideDecls: [{ name: "SWING_MODE", type: "u32", default: 0 }],
|
|
361
|
+
uniforms: [FA2_PARAMS, FA2_STATE, FA2_PARTIAL],
|
|
362
|
+
needs: ["subgroups"],
|
|
363
|
+
snippetSlots: [],
|
|
364
|
+
phase: "P3",
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
/** `fa2-to-scene` (3.10.1): the per-batch unpack of the vec4f layout positions into the stride-3 scene array with `scale` / `center` applied (z = center.z in 2D); 2 storage bindings. */
|
|
368
|
+
const FA2_TO_SCENE: KernelEntry = {
|
|
369
|
+
id: "fa2-to-scene",
|
|
370
|
+
body: fa2ToSceneWgsl,
|
|
371
|
+
entryPoint: "to_scene",
|
|
372
|
+
bindings: [
|
|
373
|
+
decl(1, 0, "pos", "storage-ro", "array<vec4f>"),
|
|
374
|
+
decl(1, 1, "scene", "storage", "array<f32>"),
|
|
375
|
+
decl(2, 0, "P", "uniform", "Fa2Params"),
|
|
376
|
+
],
|
|
377
|
+
overrideDecls: [],
|
|
378
|
+
uniforms: [FA2_PARAMS],
|
|
379
|
+
needs: [],
|
|
380
|
+
snippetSlots: [],
|
|
381
|
+
phase: "P3",
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* The entries by id, in dispatch order. PLAN DECISION: `KernelId` is declared in full (contract 3.10) while the
|
|
386
|
+
* entries landed phase by phase, so the table is built as a Partial record and exported below through the
|
|
387
|
+
* contract's `Readonly<Record<KernelId, KernelEntry>>` type by one assertion; the runtime membership check of
|
|
388
|
+
* `entryOf` is the E_INVALID_ARGUMENT the contract documents for a JS caller's unknown id. P1-T4 landed the five
|
|
389
|
+
* P1 entries, P2-T2 `"segmented-reduce"`, and P3-T2 `"fa2-stats-finalize"`, `"fa2-attraction"`, `"fa2-integrate"`
|
|
390
|
+
* and `"fa2-to-scene"`, so every member of `KernelId` is present and the assertion is exact.
|
|
391
|
+
*/
|
|
392
|
+
const REGISTRY: Readonly<Partial<Record<KernelId, KernelEntry>>> = Object.freeze({
|
|
393
|
+
degree: DEGREE,
|
|
394
|
+
reduce: REDUCE,
|
|
395
|
+
fill: FILL,
|
|
396
|
+
"segmented-reduce": SEGMENTED_REDUCE,
|
|
397
|
+
"fa2-stats-finalize": FA2_STATS_FINALIZE,
|
|
398
|
+
"fa2-attraction": FA2_ATTRACTION,
|
|
399
|
+
"fa2-repulsion-exact": FA2_REPULSION_EXACT,
|
|
400
|
+
"fa2-speed-finalize": FA2_SPEED_FINALIZE,
|
|
401
|
+
"fa2-integrate": FA2_INTEGRATE,
|
|
402
|
+
"fa2-to-scene": FA2_TO_SCENE,
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
/** THE registry (spec 3.5): every entry, keyed by id. */
|
|
406
|
+
export const KERNELS: Readonly<Record<KernelId, KernelEntry>> = REGISTRY as Readonly<Record<KernelId, KernelEntry>>;
|
|
407
|
+
|
|
408
|
+
/** The bodies installed by setKernelBodyOverride (the sabotage seam of spec 11.9 item 1), by id. */
|
|
409
|
+
const bodyOverrides = new Map<KernelId, string>();
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* The entry of an id, or E_INVALID_ARGUMENT for an id that is not (yet) registered.
|
|
413
|
+
* @param id - the module id
|
|
414
|
+
* @returns the entry
|
|
415
|
+
*/
|
|
416
|
+
function entryOf(id: KernelId): KernelEntry {
|
|
417
|
+
const entry = REGISTRY[id];
|
|
418
|
+
if (entry === undefined) {
|
|
419
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", `unknown kernel id "${id}"`, {
|
|
420
|
+
argument: "id",
|
|
421
|
+
value: id,
|
|
422
|
+
expected: Object.keys(REGISTRY),
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
return entry;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* A WgslModuleSpec for a variant: the entry plus the overrides / snippets given; unknown override names are
|
|
430
|
+
* rejected at compose time. A body override installed by setKernelBodyOverride is used instead of the entry's
|
|
431
|
+
* body.
|
|
432
|
+
* @param id - the module id
|
|
433
|
+
* @param overrides - the override values of this variant (the five standard names and the entry's overrideDecls)
|
|
434
|
+
* @param snippets - the texts substituted at the body's `//@@NAME@@` markers
|
|
435
|
+
* @returns the spec the PipelineCache compiles
|
|
436
|
+
*/
|
|
437
|
+
export function kernelSpec(
|
|
438
|
+
id: KernelId,
|
|
439
|
+
overrides?: Readonly<Record<string, number | boolean>>,
|
|
440
|
+
snippets?: Readonly<Record<string, string>>,
|
|
441
|
+
): WgslModuleSpec {
|
|
442
|
+
const entry = entryOf(id);
|
|
443
|
+
return {
|
|
444
|
+
id: entry.id,
|
|
445
|
+
body: bodyOverrides.get(id) ?? entry.body,
|
|
446
|
+
bindings: entry.bindings,
|
|
447
|
+
overrideDecls: entry.overrideDecls,
|
|
448
|
+
overrides: overrides ?? {},
|
|
449
|
+
needs: entry.needs,
|
|
450
|
+
uniforms: entry.uniforms,
|
|
451
|
+
snippets,
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* The sabotage seam (spec 11.9 item 1): replaces an entry's body for specs created afterwards (null restores).
|
|
457
|
+
* Tests use a FRESH context per mutation because the pipeline key does not include the body.
|
|
458
|
+
* @internal
|
|
459
|
+
* @param id - the module id
|
|
460
|
+
* @param body - the replacement body, or null to restore the normative one
|
|
461
|
+
*/
|
|
462
|
+
export function setKernelBodyOverride(id: KernelId, body: string | null): void {
|
|
463
|
+
entryOf(id);
|
|
464
|
+
if (body === null) {
|
|
465
|
+
bodyOverrides.delete(id);
|
|
466
|
+
} else {
|
|
467
|
+
bodyOverrides.set(id, body);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
/**
|
|
472
|
+
* The group-0 graph bindings of a core with the dummy rules applied (spec 3.5, 4.1): colIdx <- rowPtr when null,
|
|
473
|
+
* weights <- colIdx ?? rowPtr when null, perm <- rowPtr when null. `weights` is the binding to use in the weights
|
|
474
|
+
* slot: omitted -> core.weights (degree, segmented-reduce); a layout passes its RESOLVED weights
|
|
475
|
+
* (ModelResources.weights, 3.13), null meaning "attract with 1.0" even on a weighted snapshot.
|
|
476
|
+
* @param core - the resident core arrays of a snapshot
|
|
477
|
+
* @param perm - the degreeOrder row permutation, or null (rowPtr is bound as the dummy)
|
|
478
|
+
* @param weights - the weights binding to use; undefined takes the core's, null binds the colIdx dummy
|
|
479
|
+
* @returns the four bindings in slot order
|
|
480
|
+
*/
|
|
481
|
+
export function graphBindings(
|
|
482
|
+
core: CoreBinding,
|
|
483
|
+
perm: Binding | null,
|
|
484
|
+
weights?: Binding | null,
|
|
485
|
+
): Readonly<Record<"rowPtr" | "colIdx" | "weights" | "perm", Binding>> {
|
|
486
|
+
const colIdx = core.colIdx ?? core.rowPtr;
|
|
487
|
+
const resolved = weights === undefined ? core.weights : weights;
|
|
488
|
+
return {
|
|
489
|
+
rowPtr: core.rowPtr,
|
|
490
|
+
colIdx,
|
|
491
|
+
weights: resolved ?? colIdx,
|
|
492
|
+
perm: perm ?? core.rowPtr,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* The override values graphBindings implies: USE_PERM = perm !== null, HAS_WEIGHTS = (weights === undefined ?
|
|
498
|
+
* core.weights : weights) !== null.
|
|
499
|
+
* @param core - the resident core arrays of a snapshot
|
|
500
|
+
* @param perm - the row permutation binding, or null
|
|
501
|
+
* @param weights - the weights binding to use; undefined takes the core's, null means "unweighted"
|
|
502
|
+
* @returns the two standard override values of the variant
|
|
503
|
+
*/
|
|
504
|
+
export function graphOverrides(
|
|
505
|
+
core: CoreBinding,
|
|
506
|
+
perm: Binding | null,
|
|
507
|
+
weights?: Binding | null,
|
|
508
|
+
): Readonly<{ USE_PERM: boolean; HAS_WEIGHTS: boolean }> {
|
|
509
|
+
const resolved = weights === undefined ? core.weights : weights;
|
|
510
|
+
return { USE_PERM: perm !== null, HAS_WEIGHTS: resolved !== null };
|
|
511
|
+
}
|