@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
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispatch planning (spec 5.2; contract 3.9): the 16,776,960 rule. `ceil(items / wg)` workgroups as a 1D dispatch
|
|
3
|
+
* while the count fits one dimension (65,535 groups x 256 = 16,776,960 items, NOT 2^24), else a 2D grid whose
|
|
4
|
+
* kernels linearise their id with the prelude's `linear_id()` and guard `id >= items`. Pure functions with no
|
|
5
|
+
* device: every branch is unit-tested against faked capability tables.
|
|
6
|
+
*/
|
|
7
|
+
import { MAX_WORKGROUPS_PER_DIM } from "../constants.js";
|
|
8
|
+
import { WebGpuGraphError } from "../errors.js";
|
|
9
|
+
/**
|
|
10
|
+
* The per-dimension workgroup limit a plan honours. PLAN DECISION: the minimum of the spec constant and the table's
|
|
11
|
+
* `maxComputeWorkgroupsPerDimension`; the two are asserted equal on a real device at create() (spec 2.2), so every
|
|
12
|
+
* capability table of the tests yields the same plans and a faked table below the constant is still honoured.
|
|
13
|
+
* @param caps - the capability table
|
|
14
|
+
* @returns the limit
|
|
15
|
+
*/
|
|
16
|
+
function perDimension(caps) {
|
|
17
|
+
return Math.min(MAX_WORKGROUPS_PER_DIM, caps.limits.maxComputeWorkgroupsPerDimension);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Validates a non-negative integer argument.
|
|
21
|
+
* @param argument - the argument name
|
|
22
|
+
* @param value - the value
|
|
23
|
+
*/
|
|
24
|
+
function assertCount(argument, value) {
|
|
25
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
26
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${argument} must be a non-negative integer, got ${value}`, {
|
|
27
|
+
argument,
|
|
28
|
+
value,
|
|
29
|
+
expected: "a non-negative integer",
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Validates a workgroup size: a power of two >= 1 (the reduction trees of 4.3 need it). Arithmetic, no bit tricks.
|
|
35
|
+
* @param wg - the workgroup size
|
|
36
|
+
*/
|
|
37
|
+
function assertWorkgroupSize(wg) {
|
|
38
|
+
let rest = wg;
|
|
39
|
+
while (Number.isInteger(rest) && rest > 1 && rest % 2 === 0) {
|
|
40
|
+
rest /= 2;
|
|
41
|
+
}
|
|
42
|
+
if (rest !== 1) {
|
|
43
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", `wg must be a power of two, got ${wg}`, {
|
|
44
|
+
argument: "wg",
|
|
45
|
+
value: wg,
|
|
46
|
+
expected: "a power of two >= 1",
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The grid of `groups` workgroups: 1D up to the per-dimension limit, else `x = limit`, `y = ceil(groups / limit)`.
|
|
52
|
+
* @param groups - the workgroup count
|
|
53
|
+
* @param items - the item count the plan covers (recorded in the plan)
|
|
54
|
+
* @param caps - the capability table
|
|
55
|
+
* @returns the plan
|
|
56
|
+
*/
|
|
57
|
+
function grid(groups, items, caps) {
|
|
58
|
+
const limit = perDimension(caps);
|
|
59
|
+
if (groups === 0) {
|
|
60
|
+
return { x: 0, y: 1, z: 1, items, stride: null };
|
|
61
|
+
}
|
|
62
|
+
if (groups <= limit) {
|
|
63
|
+
return { x: groups, y: 1, z: 1, items, stride: null };
|
|
64
|
+
}
|
|
65
|
+
const y = Math.ceil(groups / limit);
|
|
66
|
+
if (y > limit) {
|
|
67
|
+
throw new WebGpuGraphError("E_TOO_LARGE", `${groups} workgroups exceed the 2D dispatch limit of ${limit * limit}`, {
|
|
68
|
+
needed: groups,
|
|
69
|
+
limit: limit * limit,
|
|
70
|
+
path: "dispatch",
|
|
71
|
+
algorithm: null,
|
|
72
|
+
items,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return { x: limit, y, z: 1, items, stride: null };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* ceil(items / wg) groups as 1D up to MAX_WORKGROUPS_PER_DIM, else a 2D grid; items 0 -> { x: 0, y: 1 }; y above the limit -> E_TOO_LARGE.
|
|
79
|
+
* @param items - the item count
|
|
80
|
+
* @param wg - the workgroup size (a power of two)
|
|
81
|
+
* @param caps - the capability table
|
|
82
|
+
* @returns the plan
|
|
83
|
+
*/
|
|
84
|
+
export function plan1d(items, wg, caps) {
|
|
85
|
+
assertCount("items", items);
|
|
86
|
+
assertWorkgroupSize(wg);
|
|
87
|
+
return grid(Math.ceil(items / wg), items, caps);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* The 2D form for a group count (x = MAX_WORKGROUPS_PER_DIM, y = ceil(groups / x)); exported for the indirect finalize kernel's host twin (P4).
|
|
91
|
+
* PLAN DECISION: plan1d's rule applied to a group count (spec 5.4: the finalize kernel uses "the same rule as
|
|
92
|
+
* plan1d") -- 1D `{ x: groups, y: 1 }` up to the per-dimension limit and the `x = limit` split only above it, through
|
|
93
|
+
* the same `grid()` as plan1d so the two cannot drift; P4's finalize WGSL mirrors exactly this rule. `items` of the
|
|
94
|
+
* returned plan is `groups` (the caller knows its own wg); groups 0 -> { x: 0, y: 1 }.
|
|
95
|
+
* @param groups - the workgroup count
|
|
96
|
+
* @param caps - the capability table
|
|
97
|
+
* @returns the plan
|
|
98
|
+
*/
|
|
99
|
+
export function plan2d(groups, caps) {
|
|
100
|
+
assertCount("groups", groups);
|
|
101
|
+
return grid(groups, groups, caps);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* P7 (spec 5.2): groups = min(groups, maxGroups ?? (caps.software ? 64 : 4096)) with the kernel looping by stride. P1-P3: throws E_UNSUPPORTED { feature: "planGridStride" } (lead f).
|
|
105
|
+
* PLAN DECISION: `maxGroups?` is spelled `?: number` rather than the contract's `?: number | undefined` because the
|
|
106
|
+
* root ESLint rule no-duplicate-type-constituents rejects the explicit undefined on an optional parameter (the call
|
|
107
|
+
* signature is identical).
|
|
108
|
+
* @param items - the item count
|
|
109
|
+
* @param wg - the workgroup size
|
|
110
|
+
* @param caps - the capability table
|
|
111
|
+
* @param maxGroups - the group cap
|
|
112
|
+
*/
|
|
113
|
+
export function planGridStride(items, wg, caps, maxGroups) {
|
|
114
|
+
throw new WebGpuGraphError("E_UNSUPPORTED", "planGridStride lands with the grid-stride kernels of P7 (spec 5.2)", {
|
|
115
|
+
feature: "planGridStride",
|
|
116
|
+
hint: `items ${items}, wg ${wg}, maxGroups ${maxGroups ?? (caps.software ? 64 : 4096)}`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* P4 (spec 5.4): the (x, y, 1) args a device-side finalize kernel writes for a count. P1-P3: throws E_UNSUPPORTED { feature: "planIndirect" } (lead f).
|
|
121
|
+
* @param count - the device-side count
|
|
122
|
+
* @param wg - the workgroup size
|
|
123
|
+
* @param caps - the capability table
|
|
124
|
+
*/
|
|
125
|
+
export function planIndirect(count, wg, caps) {
|
|
126
|
+
throw new WebGpuGraphError("E_UNSUPPORTED", "planIndirect lands with the indirect dispatch of P4 (spec 5.4)", {
|
|
127
|
+
feature: "planIndirect",
|
|
128
|
+
hint: `count ${count}, wg ${wg}, limit ${perDimension(caps)}`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The workgroup count of a plan (x * y).
|
|
133
|
+
* @param plan - the plan
|
|
134
|
+
* @returns the count
|
|
135
|
+
*/
|
|
136
|
+
export function groupsOf(plan) {
|
|
137
|
+
return plan.x * plan.y;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../../src/kernel/dispatch.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAYhD;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,IAAc;IAChC,OAAO,IAAI,CAAC,GAAG,CAAC,sBAAsB,EAAE,IAAI,CAAC,MAAM,CAAC,gCAAgC,CAAC,CAAC;AAC1F,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CAAC,QAAgB,EAAE,KAAa;IAChD,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,gBAAgB,CAAC,oBAAoB,EAAE,GAAG,QAAQ,wCAAwC,KAAK,EAAE,EAAE;YACzG,QAAQ;YACR,KAAK;YACL,QAAQ,EAAE,wBAAwB;SACrC,CAAC,CAAC;IACP,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAAC,EAAU;IACnC,IAAI,IAAI,GAAG,EAAE,CAAC;IACd,OAAO,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1D,IAAI,IAAI,CAAC,CAAC;IACd,CAAC;IACD,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;QACb,MAAM,IAAI,gBAAgB,CAAC,oBAAoB,EAAE,kCAAkC,EAAE,EAAE,EAAE;YACrF,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,EAAE;YACT,QAAQ,EAAE,qBAAqB;SAClC,CAAC,CAAC;IACP,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,SAAS,IAAI,CAAC,MAAc,EAAE,KAAa,EAAE,IAAc;IACvD,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACjC,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;QACf,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACrD,CAAC;IACD,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;QAClB,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC1D,CAAC;IACD,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;IACpC,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC;QACZ,MAAM,IAAI,gBAAgB,CACtB,aAAa,EACb,GAAG,MAAM,+CAA+C,KAAK,GAAG,KAAK,EAAE,EACvE;YACI,MAAM,EAAE,MAAM;YACd,KAAK,EAAE,KAAK,GAAG,KAAK;YACpB,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,IAAI;YACf,KAAK;SACR,CACJ,CAAC;IACN,CAAC;IACD,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AACtD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CAAC,KAAa,EAAE,EAAU,EAAE,IAAc;IAC5D,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC5B,mBAAmB,CAAC,EAAE,CAAC,CAAC;IACxB,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;AACpD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,MAAM,CAAC,MAAc,EAAE,IAAc;IACjD,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC9B,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa,EAAE,EAAU,EAAE,IAAc,EAAE,SAAkB;IACxF,MAAM,IAAI,gBAAgB,CAAC,eAAe,EAAE,oEAAoE,EAAE;QAC9G,OAAO,EAAE,gBAAgB;QACzB,IAAI,EAAE,SAAS,KAAK,QAAQ,EAAE,eAAe,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE;KAC1F,CAAC,CAAC;AACP,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,EAAU,EAAE,IAAc;IAClE,MAAM,IAAI,gBAAgB,CAAC,eAAe,EAAE,gEAAgE,EAAE;QAC1G,OAAO,EAAE,cAAc;QACvB,IAAI,EAAE,SAAS,KAAK,QAAQ,EAAE,WAAW,YAAY,CAAC,IAAI,CAAC,EAAE;KAChE,CAAC,CAAC;AACP,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAkB;IACvC,OAAO,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kernel (spec 5.1; contract 3.9): a compiled pipeline bound to the binding list of its spec. `bind()` creates the
|
|
3
|
+
* bind groups from a `Record<name, Binding>` keyed by the declared names and caches them by the identity of the
|
|
4
|
+
* buffers, offsets and sizes (a layout's bind groups are created once per load(), not per iteration); `dispatch()`
|
|
5
|
+
* records setPipeline / setBindGroup / dispatchWorkgroups and skips an empty plan (spec 5.6).
|
|
6
|
+
*/
|
|
7
|
+
import { type Binding } from "../types/memory.js";
|
|
8
|
+
import { type DispatchPlan } from "./dispatch.js";
|
|
9
|
+
import { type ComposedModule, type WgslModuleSpec } from "./wgsl.js";
|
|
10
|
+
/** The resources of one bind(): one Binding per BindingDecl name; a uniform decl takes the ring's whole-buffer binding (the slot is chosen by the dynamic offset at dispatch). */
|
|
11
|
+
export type KernelBindings = Readonly<Record<string, Binding>>;
|
|
12
|
+
/** A kernel with its bind groups created (spec 5.1: cached per set of buffers and offsets). */
|
|
13
|
+
export interface BoundKernel {
|
|
14
|
+
readonly kernel: Kernel;
|
|
15
|
+
readonly bindGroups: readonly GPUBindGroup[];
|
|
16
|
+
/** Group indices whose bind group takes a dynamic offset (the uniform groups), in group order. */
|
|
17
|
+
readonly dynamicGroups: readonly number[];
|
|
18
|
+
}
|
|
19
|
+
/** A compiled pipeline plus the binding list of its spec (spec 5.1). */
|
|
20
|
+
export declare class Kernel {
|
|
21
|
+
/** The module spec the pipeline was compiled from (its bindings drive bind()). */
|
|
22
|
+
readonly spec: WgslModuleSpec;
|
|
23
|
+
/** The compiled compute pipeline. */
|
|
24
|
+
readonly pipeline: GPUComputePipeline;
|
|
25
|
+
/** The explicit bind group layouts, one per group index (an empty layout for an unused index). */
|
|
26
|
+
readonly layouts: readonly GPUBindGroupLayout[];
|
|
27
|
+
/** The workgroup size the pipeline was compiled with (the effective WG override). */
|
|
28
|
+
readonly workgroupSize: number;
|
|
29
|
+
/** The entry point name the pipeline was compiled with. */
|
|
30
|
+
readonly entryPoint: string;
|
|
31
|
+
private readonly device;
|
|
32
|
+
/** The declarations of each group in binding order (index = group). */
|
|
33
|
+
private readonly groups;
|
|
34
|
+
/** The uniform-binding count of each group (the dynamic offsets a setBindGroup takes). */
|
|
35
|
+
private readonly dynamicCounts;
|
|
36
|
+
/** Cached bind groups by buffer identity + offset + size. */
|
|
37
|
+
private readonly cache;
|
|
38
|
+
/**
|
|
39
|
+
* Wraps a compiled pipeline.
|
|
40
|
+
* @param device - the device the bind groups are created on
|
|
41
|
+
* @param spec - the module
|
|
42
|
+
* @param composed - the composed text (workgroup size and entry point)
|
|
43
|
+
* @param pipeline - the compiled pipeline
|
|
44
|
+
* @param layouts - the explicit bind-group layouts, one per group 0..maxGroup
|
|
45
|
+
*/
|
|
46
|
+
constructor(device: GPUDevice, spec: WgslModuleSpec, composed: ComposedModule, pipeline: GPUComputePipeline, layouts: readonly GPUBindGroupLayout[]);
|
|
47
|
+
/**
|
|
48
|
+
* Creates (or reuses, keyed by every buffer identity + offset + size) the bind groups, each labelled
|
|
49
|
+
* `<spec.id>/<group>`; a missing or extra name is E_INVALID_ARGUMENT; two bindings of one call whose ranges
|
|
50
|
+
* intersect on one buffer while either slot is `storage` (read_write) is E_INVALID_ARGUMENT
|
|
51
|
+
* { argument: "aliasing" } (the host-side mirror of WebGPU's writable buffer-binding-aliasing rule, 3.10.1, so
|
|
52
|
+
* the failure is synchronous and labelled). CONTRACT DECISION: bind() is synchronous, so a createBindGroup
|
|
53
|
+
* validation error (a wrong-size uniform binding, a usage mismatch) is NOT thrown here -- it reaches the
|
|
54
|
+
* pending-error slot as E_VALIDATION { label: "<spec.id>/<group>" } and is thrown by the batch's readback
|
|
55
|
+
* (Dawn-node) or the next assertReady() (browser), spec 5.7. An empty bind group is created for every empty
|
|
56
|
+
* layout index so setBindGroup is called for 0..maxGroup.
|
|
57
|
+
* PLAN DECISION (verified on Dawn 0.4.0 / lavapipe): one buffer bound with two DIFFERENT access modes when one is
|
|
58
|
+
* `storage` is also E_INVALID_ARGUMENT { argument: "aliasing", reason: "usage" } even with disjoint ranges, because
|
|
59
|
+
* WebGPU's usage-scope rule rejects "writable usage and another usage in the same synchronization scope" per
|
|
60
|
+
* BUFFER; two `storage` slots with disjoint ranges (the state header / trace pattern) are accepted; a zero-size
|
|
61
|
+
* binding (never bind a zero-length buffer, spec 3.6) and an offset that is not a multiple of STORAGE_ALIGN = 256
|
|
62
|
+
* (spec 2.6; Dawn: "does not satisfy the minimum ... alignment (256)") are E_INVALID_ARGUMENT.
|
|
63
|
+
* @param resources - one Binding per declared name
|
|
64
|
+
* @returns the bound kernel (the same object for the same buffers, offsets and sizes until invalidate())
|
|
65
|
+
*/
|
|
66
|
+
bind(resources: KernelBindings): BoundKernel;
|
|
67
|
+
/**
|
|
68
|
+
* setPipeline + setBindGroup for every group (dynamic offsets in dynamicGroups order) + dispatchWorkgroups(plan.x, plan.y, 1); a plan with x === 0 records nothing (spec 5.6).
|
|
69
|
+
* PLAN DECISION: one dynamic offset per dynamic GROUP, replicated over every uniform binding of that group (every
|
|
70
|
+
* P1-P3 kernel has exactly one params uniform per group); absent offsets mean 0; a BoundKernel of another kernel
|
|
71
|
+
* or an offset list of the wrong length is E_INVALID_ARGUMENT.
|
|
72
|
+
* PLAN DECISION: `dynamicOffsets?` is spelled `?: readonly number[]` rather than the contract's
|
|
73
|
+
* `?: readonly number[] | undefined` because the root ESLint rule no-duplicate-type-constituents rejects the
|
|
74
|
+
* explicit undefined on an optional parameter (the call signature is identical).
|
|
75
|
+
* @param pass - the open compute pass
|
|
76
|
+
* @param bound - a BoundKernel of THIS kernel
|
|
77
|
+
* @param plan - the dispatch shape
|
|
78
|
+
* @param dynamicOffsets - one byte offset per entry of bound.dynamicGroups
|
|
79
|
+
*/
|
|
80
|
+
dispatch(pass: GPUComputePassEncoder, bound: BoundKernel, plan: DispatchPlan, dynamicOffsets?: readonly number[]): void;
|
|
81
|
+
/** Drops cached bind groups (a layout's buffers changed). */
|
|
82
|
+
invalidate(): void;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=kernel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../../../src/kernel/kernel.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAoB,KAAK,cAAc,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AAEvF,kLAAkL;AAClL,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAC/D,+FAA+F;AAC/F,MAAM,WAAW,WAAW;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAC;IAC7C,kGAAkG;IAClG,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AA+BD,wEAAwE;AACxE,qBAAa,MAAM;IACf,kFAAkF;IAClF,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,qCAAqC;IACrC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,kGAAkG;IAClG,QAAQ,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAChD,qFAAqF;IACrF,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,uEAAuE;IACvE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsC;IAC7D,0FAA0F;IAC1F,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAClD,6DAA6D;IAC7D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IAExD;;;;;;;OAOG;gBAEC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,cAAc,EACpB,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,EAAE,SAAS,kBAAkB,EAAE;IAmB1C;;;;;;;;;;;;;;;;;;OAkBG;IACH,IAAI,CAAC,SAAS,EAAE,cAAc,GAAG,WAAW;IAuH5C;;;;;;;;;;;;OAYG;IACH,QAAQ,CACJ,IAAI,EAAE,qBAAqB,EAC3B,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,YAAY,EAClB,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,GACnC,IAAI;IA8CP,6DAA6D;IAC7D,UAAU,IAAI,IAAI;CAGrB"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kernel (spec 5.1; contract 3.9): a compiled pipeline bound to the binding list of its spec. `bind()` creates the
|
|
3
|
+
* bind groups from a `Record<name, Binding>` keyed by the declared names and caches them by the identity of the
|
|
4
|
+
* buffers, offsets and sizes (a layout's bind groups are created once per load(), not per iteration); `dispatch()`
|
|
5
|
+
* records setPipeline / setBindGroup / dispatchWorkgroups and skips an empty plan (spec 5.6).
|
|
6
|
+
*/
|
|
7
|
+
import { STORAGE_ALIGN } from "../constants.js";
|
|
8
|
+
import { WebGpuGraphError } from "../errors.js";
|
|
9
|
+
/** Buffer identities for the bind-group cache key: every GPUBuffer seen by any Kernel gets one number, once. */
|
|
10
|
+
const bufferIds = new WeakMap();
|
|
11
|
+
let nextBufferId = 1;
|
|
12
|
+
/**
|
|
13
|
+
* The identity number of a buffer.
|
|
14
|
+
* @param buffer - the buffer
|
|
15
|
+
* @returns its number
|
|
16
|
+
*/
|
|
17
|
+
function bufferId(buffer) {
|
|
18
|
+
let id = bufferIds.get(buffer);
|
|
19
|
+
if (id === undefined) {
|
|
20
|
+
id = nextBufferId;
|
|
21
|
+
nextBufferId += 1;
|
|
22
|
+
bufferIds.set(buffer, id);
|
|
23
|
+
}
|
|
24
|
+
return id;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* True when two byte ranges intersect.
|
|
28
|
+
* @param a - one binding
|
|
29
|
+
* @param b - the other binding
|
|
30
|
+
* @returns whether [a.offset, a.offset + a.size) and [b.offset, b.offset + b.size) overlap
|
|
31
|
+
*/
|
|
32
|
+
function rangesIntersect(a, b) {
|
|
33
|
+
return a.offset < b.offset + b.size && b.offset < a.offset + a.size;
|
|
34
|
+
}
|
|
35
|
+
/** A compiled pipeline plus the binding list of its spec (spec 5.1). */
|
|
36
|
+
export class Kernel {
|
|
37
|
+
/**
|
|
38
|
+
* Wraps a compiled pipeline.
|
|
39
|
+
* @param device - the device the bind groups are created on
|
|
40
|
+
* @param spec - the module
|
|
41
|
+
* @param composed - the composed text (workgroup size and entry point)
|
|
42
|
+
* @param pipeline - the compiled pipeline
|
|
43
|
+
* @param layouts - the explicit bind-group layouts, one per group 0..maxGroup
|
|
44
|
+
*/
|
|
45
|
+
constructor(device, spec, composed, pipeline, layouts) {
|
|
46
|
+
/** Cached bind groups by buffer identity + offset + size. */
|
|
47
|
+
this.cache = new Map();
|
|
48
|
+
this.device = device;
|
|
49
|
+
this.spec = spec;
|
|
50
|
+
this.pipeline = pipeline;
|
|
51
|
+
this.layouts = layouts;
|
|
52
|
+
this.workgroupSize = composed.overrides.WG;
|
|
53
|
+
this.entryPoint = composed.entryPoint;
|
|
54
|
+
const groups = layouts.map(() => []);
|
|
55
|
+
for (const decl of spec.bindings) {
|
|
56
|
+
groups[decl.group].push(decl);
|
|
57
|
+
}
|
|
58
|
+
for (const group of groups) {
|
|
59
|
+
group.sort((a, b) => a.binding - b.binding);
|
|
60
|
+
}
|
|
61
|
+
this.groups = groups;
|
|
62
|
+
this.dynamicCounts = groups.map((group) => group.filter((decl) => decl.kind === "uniform").length);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Creates (or reuses, keyed by every buffer identity + offset + size) the bind groups, each labelled
|
|
66
|
+
* `<spec.id>/<group>`; a missing or extra name is E_INVALID_ARGUMENT; two bindings of one call whose ranges
|
|
67
|
+
* intersect on one buffer while either slot is `storage` (read_write) is E_INVALID_ARGUMENT
|
|
68
|
+
* { argument: "aliasing" } (the host-side mirror of WebGPU's writable buffer-binding-aliasing rule, 3.10.1, so
|
|
69
|
+
* the failure is synchronous and labelled). CONTRACT DECISION: bind() is synchronous, so a createBindGroup
|
|
70
|
+
* validation error (a wrong-size uniform binding, a usage mismatch) is NOT thrown here -- it reaches the
|
|
71
|
+
* pending-error slot as E_VALIDATION { label: "<spec.id>/<group>" } and is thrown by the batch's readback
|
|
72
|
+
* (Dawn-node) or the next assertReady() (browser), spec 5.7. An empty bind group is created for every empty
|
|
73
|
+
* layout index so setBindGroup is called for 0..maxGroup.
|
|
74
|
+
* PLAN DECISION (verified on Dawn 0.4.0 / lavapipe): one buffer bound with two DIFFERENT access modes when one is
|
|
75
|
+
* `storage` is also E_INVALID_ARGUMENT { argument: "aliasing", reason: "usage" } even with disjoint ranges, because
|
|
76
|
+
* WebGPU's usage-scope rule rejects "writable usage and another usage in the same synchronization scope" per
|
|
77
|
+
* BUFFER; two `storage` slots with disjoint ranges (the state header / trace pattern) are accepted; a zero-size
|
|
78
|
+
* binding (never bind a zero-length buffer, spec 3.6) and an offset that is not a multiple of STORAGE_ALIGN = 256
|
|
79
|
+
* (spec 2.6; Dawn: "does not satisfy the minimum ... alignment (256)") are E_INVALID_ARGUMENT.
|
|
80
|
+
* @param resources - one Binding per declared name
|
|
81
|
+
* @returns the bound kernel (the same object for the same buffers, offsets and sizes until invalidate())
|
|
82
|
+
*/
|
|
83
|
+
bind(resources) {
|
|
84
|
+
const { id } = this.spec;
|
|
85
|
+
const declared = new Map(this.spec.bindings.map((decl) => [decl.name, decl]));
|
|
86
|
+
for (const name of Object.keys(resources)) {
|
|
87
|
+
if (!declared.has(name)) {
|
|
88
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${id}: no binding named "${name}"`, {
|
|
89
|
+
argument: "bindings",
|
|
90
|
+
value: name,
|
|
91
|
+
expected: [...declared.keys()].join(", "),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const resolved = [];
|
|
96
|
+
for (const decl of this.spec.bindings) {
|
|
97
|
+
const binding = resources[decl.name];
|
|
98
|
+
if (binding === undefined) {
|
|
99
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${id}: binding "${decl.name}" is missing`, {
|
|
100
|
+
argument: "bindings",
|
|
101
|
+
value: decl.name,
|
|
102
|
+
expected: "a Binding for every declared name",
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (!(Number.isInteger(binding.size) && binding.size > 0)) {
|
|
106
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${id}: binding "${decl.name}" has size ${binding.size}`, {
|
|
107
|
+
argument: decl.name,
|
|
108
|
+
value: binding.size,
|
|
109
|
+
expected: "size > 0 (a zero-length buffer is never bound)",
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (!(Number.isInteger(binding.offset) && binding.offset >= 0 && binding.offset % STORAGE_ALIGN === 0)) {
|
|
113
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${id}: binding "${decl.name}" has offset ${binding.offset}`, {
|
|
114
|
+
argument: decl.name,
|
|
115
|
+
value: binding.offset,
|
|
116
|
+
expected: `a multiple of ${STORAGE_ALIGN} (spec 2.6: the offset alignment the package always honours)`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
resolved.push({ decl, binding });
|
|
120
|
+
}
|
|
121
|
+
for (let i = 0; i < resolved.length; i++) {
|
|
122
|
+
for (let j = i + 1; j < resolved.length; j++) {
|
|
123
|
+
const a = resolved[i];
|
|
124
|
+
const b = resolved[j];
|
|
125
|
+
if (a.binding.buffer !== b.binding.buffer) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const writable = a.decl.kind === "storage" || b.decl.kind === "storage";
|
|
129
|
+
if (!writable) {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (a.decl.kind !== b.decl.kind) {
|
|
133
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${id}: "${a.decl.name}" and "${b.decl.name}" bind one buffer with different access modes (writable usage next to another usage)`, {
|
|
134
|
+
argument: "aliasing",
|
|
135
|
+
value: [a.decl.name, b.decl.name],
|
|
136
|
+
expected: "one access mode per buffer when a slot is read_write",
|
|
137
|
+
reason: "usage",
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (rangesIntersect(a.binding, b.binding)) {
|
|
141
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${id}: "${a.decl.name}" and "${b.decl.name}" bind intersecting ranges of one read_write buffer`, {
|
|
142
|
+
argument: "aliasing",
|
|
143
|
+
value: [a.decl.name, b.decl.name],
|
|
144
|
+
expected: "disjoint ranges",
|
|
145
|
+
reason: "range",
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
const key = resolved
|
|
151
|
+
.map(({ binding }) => `${bufferId(binding.buffer)}:${binding.offset}:${binding.size}`)
|
|
152
|
+
.join("|");
|
|
153
|
+
const cached = this.cache.get(key);
|
|
154
|
+
if (cached !== undefined) {
|
|
155
|
+
return cached;
|
|
156
|
+
}
|
|
157
|
+
const byName = new Map(resolved.map(({ decl, binding }) => [decl.name, binding]));
|
|
158
|
+
const bindGroups = this.layouts.map((layout, group) => this.device.createBindGroup({
|
|
159
|
+
label: `${id}/${group}`,
|
|
160
|
+
layout,
|
|
161
|
+
entries: this.groups[group].map((decl) => {
|
|
162
|
+
const binding = byName.get(decl.name);
|
|
163
|
+
return {
|
|
164
|
+
binding: decl.binding,
|
|
165
|
+
resource: { buffer: binding.buffer, offset: binding.offset, size: binding.size },
|
|
166
|
+
};
|
|
167
|
+
}),
|
|
168
|
+
}));
|
|
169
|
+
const dynamicGroups = [];
|
|
170
|
+
this.dynamicCounts.forEach((count, group) => {
|
|
171
|
+
if (count > 0) {
|
|
172
|
+
dynamicGroups.push(group);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
const bound = Object.freeze({
|
|
176
|
+
kernel: this,
|
|
177
|
+
bindGroups: Object.freeze(bindGroups),
|
|
178
|
+
dynamicGroups: Object.freeze(dynamicGroups),
|
|
179
|
+
});
|
|
180
|
+
this.cache.set(key, bound);
|
|
181
|
+
return bound;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* setPipeline + setBindGroup for every group (dynamic offsets in dynamicGroups order) + dispatchWorkgroups(plan.x, plan.y, 1); a plan with x === 0 records nothing (spec 5.6).
|
|
185
|
+
* PLAN DECISION: one dynamic offset per dynamic GROUP, replicated over every uniform binding of that group (every
|
|
186
|
+
* P1-P3 kernel has exactly one params uniform per group); absent offsets mean 0; a BoundKernel of another kernel
|
|
187
|
+
* or an offset list of the wrong length is E_INVALID_ARGUMENT.
|
|
188
|
+
* PLAN DECISION: `dynamicOffsets?` is spelled `?: readonly number[]` rather than the contract's
|
|
189
|
+
* `?: readonly number[] | undefined` because the root ESLint rule no-duplicate-type-constituents rejects the
|
|
190
|
+
* explicit undefined on an optional parameter (the call signature is identical).
|
|
191
|
+
* @param pass - the open compute pass
|
|
192
|
+
* @param bound - a BoundKernel of THIS kernel
|
|
193
|
+
* @param plan - the dispatch shape
|
|
194
|
+
* @param dynamicOffsets - one byte offset per entry of bound.dynamicGroups
|
|
195
|
+
*/
|
|
196
|
+
dispatch(pass, bound, plan, dynamicOffsets) {
|
|
197
|
+
const { id } = this.spec;
|
|
198
|
+
if (bound.kernel !== this) {
|
|
199
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${id}: the bound kernel belongs to "${bound.kernel.spec.id}"`, {
|
|
200
|
+
argument: "bound",
|
|
201
|
+
value: bound.kernel.spec.id,
|
|
202
|
+
expected: id,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
if (dynamicOffsets !== undefined && dynamicOffsets.length !== bound.dynamicGroups.length) {
|
|
206
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${id}: ${dynamicOffsets.length} dynamic offsets for ${bound.dynamicGroups.length} dynamic groups`, {
|
|
207
|
+
argument: "dynamicOffsets",
|
|
208
|
+
value: dynamicOffsets.length,
|
|
209
|
+
expected: bound.dynamicGroups.length,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
if (plan.x === 0) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
pass.setPipeline(this.pipeline);
|
|
216
|
+
let next = 0;
|
|
217
|
+
bound.bindGroups.forEach((bindGroup, group) => {
|
|
218
|
+
const count = this.dynamicCounts[group];
|
|
219
|
+
if (count > 0) {
|
|
220
|
+
const offset = dynamicOffsets?.[next] ?? 0;
|
|
221
|
+
next += 1;
|
|
222
|
+
const offsets = [];
|
|
223
|
+
for (let k = 0; k < count; k++) {
|
|
224
|
+
offsets.push(offset);
|
|
225
|
+
}
|
|
226
|
+
pass.setBindGroup(group, bindGroup, offsets);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
pass.setBindGroup(group, bindGroup);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
pass.dispatchWorkgroups(plan.x, plan.y, 1);
|
|
233
|
+
}
|
|
234
|
+
/** Drops cached bind groups (a layout's buffers changed). */
|
|
235
|
+
invalidate() {
|
|
236
|
+
this.cache.clear();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=kernel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kernel.js","sourceRoot":"","sources":["../../../src/kernel/kernel.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAehD,gHAAgH;AAChH,MAAM,SAAS,GAAG,IAAI,OAAO,EAAqB,CAAC;AACnD,IAAI,YAAY,GAAG,CAAC,CAAC;AAErB;;;;GAIG;AACH,SAAS,QAAQ,CAAC,MAAiB;IAC/B,IAAI,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACnB,EAAE,GAAG,YAAY,CAAC;QAClB,YAAY,IAAI,CAAC,CAAC;QAClB,SAAS,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,EAAE,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAC,CAAU,EAAE,CAAU;IAC3C,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC;AACxE,CAAC;AAED,wEAAwE;AACxE,MAAM,OAAO,MAAM;IAmBf;;;;;;;OAOG;IACH,YACI,MAAiB,EACjB,IAAoB,EACpB,QAAwB,EACxB,QAA4B,EAC5B,OAAsC;QAhB1C,6DAA6D;QAC5C,UAAK,GAAG,IAAI,GAAG,EAAuB,CAAC;QAiBpD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAC,SAAS,CAAC,EAAY,CAAC;QACrD,IAAI,CAAC,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC;QACtC,MAAM,MAAM,GAAoB,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACtD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC/B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YACzB,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;QAChD,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;IACvG,CAAC;IAED;;;;;;;;;;;;;;;;;;OAkBG;IACH,IAAI,CAAC,SAAyB;QAC1B,MAAM,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC;QACzB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAU,CAAC,CAAC,CAAC;QACvF,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YACxC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtB,MAAM,IAAI,gBAAgB,CAAC,oBAAoB,EAAE,GAAG,EAAE,uBAAuB,IAAI,GAAG,EAAE;oBAClF,QAAQ,EAAE,UAAU;oBACpB,KAAK,EAAE,IAAI;oBACX,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;iBAC5C,CAAC,CAAC;YACP,CAAC;QACL,CAAC;QACD,MAAM,QAAQ,GAAgE,EAAE,CAAC;QACjF,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAwB,CAAC;YAC5D,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBACxB,MAAM,IAAI,gBAAgB,CAAC,oBAAoB,EAAE,GAAG,EAAE,cAAc,IAAI,CAAC,IAAI,cAAc,EAAE;oBACzF,QAAQ,EAAE,UAAU;oBACpB,KAAK,EAAE,IAAI,CAAC,IAAI;oBAChB,QAAQ,EAAE,mCAAmC;iBAChD,CAAC,CAAC;YACP,CAAC;YACD,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC;gBACxD,MAAM,IAAI,gBAAgB,CACtB,oBAAoB,EACpB,GAAG,EAAE,cAAc,IAAI,CAAC,IAAI,cAAc,OAAO,CAAC,IAAI,EAAE,EACxD;oBACI,QAAQ,EAAE,IAAI,CAAC,IAAI;oBACnB,KAAK,EAAE,OAAO,CAAC,IAAI;oBACnB,QAAQ,EAAE,gDAAgD;iBAC7D,CACJ,CAAC;YACN,CAAC;YACD,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,aAAa,KAAK,CAAC,CAAC,EAAE,CAAC;gBACrG,MAAM,IAAI,gBAAgB,CACtB,oBAAoB,EACpB,GAAG,EAAE,cAAc,IAAI,CAAC,IAAI,gBAAgB,OAAO,CAAC,MAAM,EAAE,EAC5D;oBACI,QAAQ,EAAE,IAAI,CAAC,IAAI;oBACnB,KAAK,EAAE,OAAO,CAAC,MAAM;oBACrB,QAAQ,EAAE,iBAAiB,aAAa,8DAA8D;iBACzG,CACJ,CAAC;YACN,CAAC;YACD,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACrC,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC3C,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACtB,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;oBACxC,SAAS;gBACb,CAAC;gBACD,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC;gBACxE,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACZ,SAAS;gBACb,CAAC;gBACD,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;oBAC9B,MAAM,IAAI,gBAAgB,CACtB,oBAAoB,EACpB,GAAG,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,sFAAsF,EACjI;wBACI,QAAQ,EAAE,UAAU;wBACpB,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;wBACjC,QAAQ,EAAE,sDAAsD;wBAChE,MAAM,EAAE,OAAO;qBAClB,CACJ,CAAC;gBACN,CAAC;gBACD,IAAI,eAAe,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;oBACxC,MAAM,IAAI,gBAAgB,CACtB,oBAAoB,EACpB,GAAG,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,qDAAqD,EAChG;wBACI,QAAQ,EAAE,UAAU;wBACpB,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;wBACjC,QAAQ,EAAE,iBAAiB;wBAC3B,MAAM,EAAE,OAAO;qBAClB,CACJ,CAAC;gBACN,CAAC;YACL,CAAC;QACL,CAAC;QACD,MAAM,GAAG,GAAG,QAAQ;aACf,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;aACrF,IAAI,CAAC,GAAG,CAAC,CAAC;QACf,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,MAAM,CAAC;QAClB,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAU,CAAC,CAAC,CAAC;QAC3F,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAClD,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC;YACxB,KAAK,EAAE,GAAG,EAAE,IAAI,KAAK,EAAE;YACvB,MAAM;YACN,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;gBACrC,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAY,CAAC;gBACjD,OAAO;oBACH,OAAO,EAAE,IAAI,CAAC,OAAO;oBACrB,QAAQ,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE;iBACnF,CAAC;YACN,CAAC,CAAC;SACL,CAAC,CACL,CAAC;QACF,MAAM,aAAa,GAAa,EAAE,CAAC;QACnC,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;YACxC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACZ,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC9B,CAAC;QACL,CAAC,CAAC,CAAC;QACH,MAAM,KAAK,GAAgB,MAAM,CAAC,MAAM,CAAC;YACrC,MAAM,EAAE,IAAI;YACZ,UAAU,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC;YACrC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC;SAC9C,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC3B,OAAO,KAAK,CAAC;IACjB,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,QAAQ,CACJ,IAA2B,EAC3B,KAAkB,EAClB,IAAkB,EAClB,cAAkC;QAElC,MAAM,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC;QACzB,IAAI,KAAK,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YACxB,MAAM,IAAI,gBAAgB,CACtB,oBAAoB,EACpB,GAAG,EAAE,kCAAkC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,EAC9D;gBACI,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;gBAC3B,QAAQ,EAAE,EAAE;aACf,CACJ,CAAC;QACN,CAAC;QACD,IAAI,cAAc,KAAK,SAAS,IAAI,cAAc,CAAC,MAAM,KAAK,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC;YACvF,MAAM,IAAI,gBAAgB,CACtB,oBAAoB,EACpB,GAAG,EAAE,KAAK,cAAc,CAAC,MAAM,wBAAwB,KAAK,CAAC,aAAa,CAAC,MAAM,iBAAiB,EAClG;gBACI,QAAQ,EAAE,gBAAgB;gBAC1B,KAAK,EAAE,cAAc,CAAC,MAAM;gBAC5B,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAC,MAAM;aACvC,CACJ,CAAC;QACN,CAAC;QACD,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;YACf,OAAO;QACX,CAAC;QACD,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAChC,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE;YAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YACxC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;gBACZ,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC3C,IAAI,IAAI,CAAC,CAAC;gBACV,MAAM,OAAO,GAAa,EAAE,CAAC;gBAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;oBAC7B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACzB,CAAC;gBACD,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;YACjD,CAAC;iBAAM,CAAC;gBACJ,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACxC,CAAC;QACL,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/C,CAAC;IAED,6DAA6D;IAC7D,UAAU;QACN,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACJ"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PipelineCache (spec 5.1; contract 3.9): compile-once compute pipelines keyed by
|
|
3
|
+
* `(id, overrides, needs present on the device, snippets)` with EXPLICIT bind-group layouts derived from
|
|
4
|
+
* `spec.bindings` (never `layout: "auto"`, so one layout serves every dummy-binding variant and bind groups are
|
|
5
|
+
* reused across variants). A WGSL error is `E_SHADER_COMPILE { stage: "compile", messages, lines }` with
|
|
6
|
+
* body-relative line numbers; a pipeline error that is not a compilation message (an oversized workgroup, an
|
|
7
|
+
* invalid layout) is `E_VALIDATION`.
|
|
8
|
+
*/
|
|
9
|
+
import { type PlanCaps } from "../types/context.js";
|
|
10
|
+
import { Kernel } from "./kernel.js";
|
|
11
|
+
import { type WgslModuleSpec } from "./wgsl.js";
|
|
12
|
+
/**
|
|
13
|
+
* The cache key of a spec on a device (pure; PLAN DECISION: exported so the override-matrix helper of P2-T2 can
|
|
14
|
+
* compute keys without a device): `id + "|" + stableJson(overrides) + "|" + needs.filter(present).join(",") + "|" + hash(snippets)`.
|
|
15
|
+
* @param spec - the module
|
|
16
|
+
* @param caps - the device capabilities (the feature set decides which needs are present)
|
|
17
|
+
* @returns the key
|
|
18
|
+
*/
|
|
19
|
+
export declare function pipelineKey(spec: WgslModuleSpec, caps: PlanCaps): string;
|
|
20
|
+
/** Compile-once pipelines keyed by (id, overrides, needs present on the device, snippets) with explicit bind-group layouts (spec 5.1). */
|
|
21
|
+
export declare class PipelineCache {
|
|
22
|
+
private readonly device;
|
|
23
|
+
private readonly caps;
|
|
24
|
+
/** In-flight and finished compiles by key (a promise, so two concurrent get() calls share one compile). */
|
|
25
|
+
private readonly pending;
|
|
26
|
+
/** Finished compiles by key. */
|
|
27
|
+
private readonly entries;
|
|
28
|
+
/** Keys in the order their compiles were started (a failed compile is removed again). */
|
|
29
|
+
private readonly order;
|
|
30
|
+
private disposed;
|
|
31
|
+
/**
|
|
32
|
+
* Builds a cache over a device.
|
|
33
|
+
* @param device - the device pipelines are created on
|
|
34
|
+
* @param caps - its capabilities (WG, subgroup sizes, features)
|
|
35
|
+
*/
|
|
36
|
+
constructor(device: GPUDevice, caps: PlanCaps);
|
|
37
|
+
/**
|
|
38
|
+
* The cache key of a spec on this device: `id + "|" + stableJson(overrides) + "|" + needs.filter(present).join(",") + "|" + hash(snippets)`.
|
|
39
|
+
* @param spec - the module
|
|
40
|
+
* @returns the key
|
|
41
|
+
*/
|
|
42
|
+
key(spec: WgslModuleSpec): string;
|
|
43
|
+
/**
|
|
44
|
+
* createComputePipelineAsync inside a validation scope with the layouts derived from spec.bindings; compilation messages become E_SHADER_COMPILE { id, stage: "compile", messages } with body-relative lines.
|
|
45
|
+
* @param spec - the module
|
|
46
|
+
* @returns the pipeline (the same object for the same key)
|
|
47
|
+
*/
|
|
48
|
+
get(spec: WgslModuleSpec): Promise<GPUComputePipeline>;
|
|
49
|
+
/**
|
|
50
|
+
* The Kernel (pipeline + layouts + binding names) for a spec; cached with the pipeline.
|
|
51
|
+
* @param spec - the module
|
|
52
|
+
* @returns the kernel (the same object for the same key)
|
|
53
|
+
*/
|
|
54
|
+
kernel(spec: WgslModuleSpec): Promise<Kernel>;
|
|
55
|
+
/**
|
|
56
|
+
* Compiles every spec not yet cached (load() calls it so the first step() does not compile).
|
|
57
|
+
* @param specs - the modules
|
|
58
|
+
*/
|
|
59
|
+
warm(specs: readonly WgslModuleSpec[]): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Number of cached pipelines.
|
|
62
|
+
* @returns the count of finished compiles
|
|
63
|
+
*/
|
|
64
|
+
get size(): number;
|
|
65
|
+
/**
|
|
66
|
+
* PLAN DECISION: forgets every pipeline and refuses further compiles with E_DISPOSED (the context's dispose()
|
|
67
|
+
* may call it; a GPUComputePipeline has no destroy(), so the objects are simply released).
|
|
68
|
+
*/
|
|
69
|
+
dispose(): void;
|
|
70
|
+
/**
|
|
71
|
+
* The cached entry of a spec, compiling it once per key.
|
|
72
|
+
* @param spec - the module
|
|
73
|
+
* @returns the entry
|
|
74
|
+
*/
|
|
75
|
+
private entry;
|
|
76
|
+
/**
|
|
77
|
+
* One compile: compose, create the shader module inside a synchronous push / pop validation pair (so concurrent
|
|
78
|
+
* compiles never interleave scopes), check the compilation info, create the layouts and the pipeline.
|
|
79
|
+
* PLAN DECISION: `E_SHADER_COMPILE` at stage "compile" also carries `lines` (the body-relative 1-based line of every
|
|
80
|
+
* error message, from `composed.bodyLine`) next to the contract's `messages`; a `createComputePipelineAsync`
|
|
81
|
+
* rejection (a GPUPipelineError, which pushes nothing into a validation scope on Dawn 0.4.0) is
|
|
82
|
+
* `E_VALIDATION { label: "<id>|pipeline", message }`; bool overrides travel as the pipeline constants 1 / 0
|
|
83
|
+
* because dawn.node's WebIDL layer rejects a boolean constant.
|
|
84
|
+
* @param spec - the module
|
|
85
|
+
* @param key - its key (the pipeline label)
|
|
86
|
+
* @returns the entry
|
|
87
|
+
*/
|
|
88
|
+
private compile;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=pipeline-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline-cache.d.ts","sourceRoot":"","sources":["../../../src/kernel/pipeline-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAgE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AA+C9G;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,CAGxE;AAWD,0IAA0I;AAC1I,qBAAa,aAAa;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAW;IAChC,2GAA2G;IAC3G,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0C;IAClE,gCAAgC;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,yFAAyF;IACzF,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAS;IAEzB;;;;OAIG;gBACS,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ;IAK7C;;;;OAIG;IACH,GAAG,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM;IAIjC;;;;OAIG;IACG,GAAG,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAI5D;;;;OAIG;IACG,MAAM,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAInD;;;OAGG;IACG,IAAI,CAAC,KAAK,EAAE,SAAS,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D;;;OAGG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAuBD;;;OAGG;IACH,OAAO,IAAI,IAAI;IAOf;;;;OAIG;IACH,OAAO,CAAC,KAAK;IAgCb;;;;;;;;;;;OAWG;YACW,OAAO;CA4DxB"}
|