@graphty/webgpu-graph-algorithms 0.6.3 → 0.6.5
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 +62 -32
- package/dist/browser.js +1 -1
- package/dist/chunks/{context-BXqgCifx.js → context-hzGggHeM.js} +68 -24
- package/dist/chunks/context-hzGggHeM.js.map +1 -0
- package/dist/node.js +1 -1
- package/dist/src/accelerator.d.ts +8 -6
- package/dist/src/accelerator.d.ts.map +1 -1
- package/dist/src/accelerator.js +57 -6
- package/dist/src/accelerator.js.map +1 -1
- package/dist/src/algorithms/bellman-ford.d.ts +60 -0
- package/dist/src/algorithms/bellman-ford.d.ts.map +1 -0
- package/dist/src/algorithms/bellman-ford.js +301 -0
- package/dist/src/algorithms/bellman-ford.js.map +1 -0
- package/dist/src/algorithms/bfs.d.ts +67 -0
- package/dist/src/algorithms/bfs.d.ts.map +1 -0
- package/dist/src/algorithms/bfs.js +534 -0
- package/dist/src/algorithms/bfs.js.map +1 -0
- package/dist/src/algorithms/closeness.d.ts +53 -0
- package/dist/src/algorithms/closeness.d.ts.map +1 -0
- package/dist/src/algorithms/closeness.js +323 -0
- package/dist/src/algorithms/closeness.js.map +1 -0
- package/dist/src/algorithms/scope.d.ts +3 -1
- package/dist/src/algorithms/scope.d.ts.map +1 -1
- package/dist/src/algorithms/scope.js +1 -0
- package/dist/src/algorithms/scope.js.map +1 -1
- package/dist/src/algorithms/sssp.d.ts +72 -0
- package/dist/src/algorithms/sssp.d.ts.map +1 -0
- package/dist/src/algorithms/sssp.js +586 -0
- package/dist/src/algorithms/sssp.js.map +1 -0
- package/dist/src/constants.d.ts +10 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +10 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/index.d.ts +8 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +7 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/kernel/prelude.d.ts +4 -4
- package/dist/src/kernel/prelude.d.ts.map +1 -1
- package/dist/src/kernel/prelude.js +39 -5
- package/dist/src/kernel/prelude.js.map +1 -1
- package/dist/src/kernel/uniform-ring.d.ts +8 -0
- package/dist/src/kernel/uniform-ring.d.ts.map +1 -1
- package/dist/src/kernel/uniform-ring.js +13 -0
- package/dist/src/kernel/uniform-ring.js.map +1 -1
- package/dist/src/kernels.d.ts +45 -4
- package/dist/src/kernels.d.ts.map +1 -1
- package/dist/src/kernels.js +368 -3
- package/dist/src/kernels.js.map +1 -1
- package/dist/src/primitives/advance.d.ts +63 -0
- package/dist/src/primitives/advance.d.ts.map +1 -0
- package/dist/src/primitives/advance.js +95 -0
- package/dist/src/primitives/advance.js.map +1 -0
- package/dist/src/primitives/compact.d.ts +89 -0
- package/dist/src/primitives/compact.d.ts.map +1 -0
- package/dist/src/primitives/compact.js +233 -0
- package/dist/src/primitives/compact.js.map +1 -0
- package/dist/src/primitives/core-shape.d.ts +22 -1
- package/dist/src/primitives/core-shape.d.ts.map +1 -1
- package/dist/src/primitives/core-shape.js +33 -3
- package/dist/src/primitives/core-shape.js.map +1 -1
- package/dist/src/primitives/frontier.d.ts +151 -0
- package/dist/src/primitives/frontier.d.ts.map +1 -0
- package/dist/src/primitives/frontier.js +250 -0
- package/dist/src/primitives/frontier.js.map +1 -0
- package/dist/src/types/accelerator.d.ts +16 -7
- package/dist/src/types/accelerator.d.ts.map +1 -1
- package/dist/src/types/traversal.d.ts +53 -0
- package/dist/src/types/traversal.d.ts.map +1 -0
- package/dist/src/types/traversal.js +10 -0
- package/dist/src/types/traversal.js.map +1 -0
- package/dist/src/wgsl/advance-expand.wgsl.d.ts +19 -0
- package/dist/src/wgsl/advance-expand.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/advance-expand.wgsl.js +69 -0
- package/dist/src/wgsl/advance-expand.wgsl.js.map +1 -0
- package/dist/src/wgsl/bf-relax.wgsl.d.ts +22 -0
- package/dist/src/wgsl/bf-relax.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/bf-relax.wgsl.js +58 -0
- package/dist/src/wgsl/bf-relax.wgsl.js.map +1 -0
- package/dist/src/wgsl/bfs-bitset-build.wgsl.d.ts +15 -0
- package/dist/src/wgsl/bfs-bitset-build.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/bfs-bitset-build.wgsl.js +24 -0
- package/dist/src/wgsl/bfs-bitset-build.wgsl.js.map +1 -0
- package/dist/src/wgsl/bfs-bottom-up.wgsl.d.ts +20 -0
- package/dist/src/wgsl/bfs-bottom-up.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/bfs-bottom-up.wgsl.js +67 -0
- package/dist/src/wgsl/bfs-bottom-up.wgsl.js.map +1 -0
- package/dist/src/wgsl/bfs-contract.wgsl.d.ts +20 -0
- package/dist/src/wgsl/bfs-contract.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/bfs-contract.wgsl.js +55 -0
- package/dist/src/wgsl/bfs-contract.wgsl.js.map +1 -0
- package/dist/src/wgsl/bfs-fused.wgsl.d.ts +25 -0
- package/dist/src/wgsl/bfs-fused.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/bfs-fused.wgsl.js +78 -0
- package/dist/src/wgsl/bfs-fused.wgsl.js.map +1 -0
- package/dist/src/wgsl/bfs-unvisited-flags.wgsl.d.ts +18 -0
- package/dist/src/wgsl/bfs-unvisited-flags.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/bfs-unvisited-flags.wgsl.js +42 -0
- package/dist/src/wgsl/bfs-unvisited-flags.wgsl.js.map +1 -0
- package/dist/src/wgsl/closeness-reduce.wgsl.d.ts +17 -0
- package/dist/src/wgsl/closeness-reduce.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/closeness-reduce.wgsl.js +65 -0
- package/dist/src/wgsl/closeness-reduce.wgsl.js.map +1 -0
- package/dist/src/wgsl/closeness-sweep.wgsl.d.ts +20 -0
- package/dist/src/wgsl/closeness-sweep.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/closeness-sweep.wgsl.js +96 -0
- package/dist/src/wgsl/closeness-sweep.wgsl.js.map +1 -0
- package/dist/src/wgsl/compact-scatter.wgsl.d.ts +9 -0
- package/dist/src/wgsl/compact-scatter.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/compact-scatter.wgsl.js +17 -0
- package/dist/src/wgsl/compact-scatter.wgsl.js.map +1 -0
- package/dist/src/wgsl/dedupe-claim.wgsl.d.ts +10 -0
- package/dist/src/wgsl/dedupe-claim.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/dedupe-claim.wgsl.js +19 -0
- package/dist/src/wgsl/dedupe-claim.wgsl.js.map +1 -0
- package/dist/src/wgsl/dedupe-filter.wgsl.d.ts +12 -0
- package/dist/src/wgsl/dedupe-filter.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/dedupe-filter.wgsl.js +46 -0
- package/dist/src/wgsl/dedupe-filter.wgsl.js.map +1 -0
- package/dist/src/wgsl/frontier-finalize.wgsl.d.ts +53 -0
- package/dist/src/wgsl/frontier-finalize.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/frontier-finalize.wgsl.js +164 -0
- package/dist/src/wgsl/frontier-finalize.wgsl.js.map +1 -0
- package/dist/src/wgsl/sssp-pred.wgsl.d.ts +28 -0
- package/dist/src/wgsl/sssp-pred.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/sssp-pred.wgsl.js +80 -0
- package/dist/src/wgsl/sssp-pred.wgsl.js.map +1 -0
- package/dist/src/wgsl/sssp-relax.wgsl.d.ts +30 -0
- package/dist/src/wgsl/sssp-relax.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/sssp-relax.wgsl.js +72 -0
- package/dist/src/wgsl/sssp-relax.wgsl.js.map +1 -0
- package/dist/webgpu-graph-algorithms.js +3155 -384
- package/dist/webgpu-graph-algorithms.js.map +1 -1
- package/package.json +5 -4
- package/src/accelerator.ts +65 -7
- package/src/algorithms/bellman-ford.ts +387 -0
- package/src/algorithms/bfs.ts +626 -0
- package/src/algorithms/closeness.ts +395 -0
- package/src/algorithms/scope.ts +4 -1
- package/src/algorithms/sssp.ts +768 -0
- package/src/constants.ts +10 -0
- package/src/index.ts +14 -1
- package/src/kernel/prelude.ts +39 -4
- package/src/kernel/uniform-ring.ts +14 -0
- package/src/kernels.ts +447 -6
- package/src/primitives/advance.ts +131 -0
- package/src/primitives/compact.ts +323 -0
- package/src/primitives/core-shape.ts +41 -3
- package/src/primitives/frontier.ts +372 -0
- package/src/types/accelerator.ts +18 -5
- package/src/types/traversal.ts +56 -0
- package/src/wgsl/advance-expand.wgsl.ts +68 -0
- package/src/wgsl/bf-relax.wgsl.ts +57 -0
- package/src/wgsl/bfs-bitset-build.wgsl.ts +23 -0
- package/src/wgsl/bfs-bottom-up.wgsl.ts +66 -0
- package/src/wgsl/bfs-contract.wgsl.ts +54 -0
- package/src/wgsl/bfs-fused.wgsl.ts +77 -0
- package/src/wgsl/bfs-unvisited-flags.wgsl.ts +41 -0
- package/src/wgsl/closeness-reduce.wgsl.ts +64 -0
- package/src/wgsl/closeness-sweep.wgsl.ts +95 -0
- package/src/wgsl/compact-scatter.wgsl.ts +16 -0
- package/src/wgsl/dedupe-claim.wgsl.ts +18 -0
- package/src/wgsl/dedupe-filter.wgsl.ts +45 -0
- package/src/wgsl/frontier-finalize.wgsl.ts +163 -0
- package/src/wgsl/sssp-pred.wgsl.ts +79 -0
- package/src/wgsl/sssp-relax.wgsl.ts +71 -0
- package/dist/chunks/context-BXqgCifx.js.map +0 -1
package/src/constants.ts
CHANGED
|
@@ -214,3 +214,13 @@ export const GRID_EXTENT_FLOOR = 1e-6;
|
|
|
214
214
|
export const GRID_BBOX_MARGIN = 1.01;
|
|
215
215
|
/** The key width the grid always sorts with (P4 PD-5): three 8-bit passes cover the 19-bit 2D keys at G = 512 and the 22-bit 3D keys at G = 128, and an odd pass count leaves `sortedIdx` in the scratch pair. */
|
|
216
216
|
export const GRID_SORT_BITS = 24;
|
|
217
|
+
/** Design 8.4 (P8 PD-7): traversal levels recorded per submit -- one four-byte readback per 32 BFS levels, SSSP rounds or closeness levels. */
|
|
218
|
+
export const MAX_LEVELS_PER_SUBMIT = 32;
|
|
219
|
+
/** Design 8.4 and 6 row 8 (P8): a frontier at most this long runs the fused expand-contract kernel (Merrill's "fleeting iterations"); the default of the `fusedMax` uniform, which a test may set to 0 or `U32_MAX`. */
|
|
220
|
+
export const FUSED_FRONTIER_MAX = 4096;
|
|
221
|
+
/** Design 8.4 (P8 PD-21): Beamer's beta -- switch back to top-down when `frontierCount * BEAMER_BETA < unvisitedCount` and the frontier is shrinking; alpha is derived from the graph, so it has no constant. */
|
|
222
|
+
export const BEAMER_BETA = 24;
|
|
223
|
+
/** Design 8.4 (P8 PD-22): the near-far split `delta = SSSP_DELTA_FACTOR * avgWeight / avgDegree`, computed on the host from the weight vector the run uses. */
|
|
224
|
+
export const SSSP_DELTA_FACTOR = 32;
|
|
225
|
+
/** The bit pattern of +Infinity, the unreached sentinel of `dist` (P8 PD-9); interpolated into the prelude as `F32_INF_BITS` so no body types the literal. */
|
|
226
|
+
export const F32_INF_BITS = 0x7f800000;
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
* isSoftwareAdapter. P1 adds GpuContext and degree (values) and the context / run / profiler types. P2 adds nothing
|
|
9
9
|
* (Lease, CommandBatch, UniformRing are internal). P3 adds the layout factory, the accelerator, the two default
|
|
10
10
|
* tables, the seeder and the layout / accelerator types. P5 adds the two factories, the two default tables and the
|
|
11
|
-
* two stats records. P4 adds calibrateLayout and its two records.
|
|
11
|
+
* two stats records. P4 adds calibrateLayout and its two records. P8 adds the four traversals and their three result
|
|
12
|
+
* records. test/index.test.ts pins the value list and
|
|
12
13
|
* test/types/public-api.test-d.ts the type list. This comment must never spell the internal
|
|
13
14
|
* JSDoc tag: it is the leading comment of the first export statement, and stripInternal would drop that statement
|
|
14
15
|
* from the emitted declarations.
|
|
@@ -54,6 +55,12 @@ export { connectedComponents } from "./algorithms/components.js";
|
|
|
54
55
|
export { pageRank, personalizedPageRank } from "./algorithms/pagerank.js";
|
|
55
56
|
export { eigenvectorCentrality, hits, katzCentrality } from "./algorithms/spectral.js";
|
|
56
57
|
|
|
58
|
+
// ==================== algorithms (P8: the frontier family, spec 3.3 lines 807-810, 8.4; the seam's option types in)
|
|
59
|
+
export { bellmanFord } from "./algorithms/bellman-ford.js";
|
|
60
|
+
export { breadthFirstSearch } from "./algorithms/bfs.js";
|
|
61
|
+
export { closenessCentrality } from "./algorithms/closeness.js";
|
|
62
|
+
export { sssp } from "./algorithms/sssp.js";
|
|
63
|
+
|
|
57
64
|
// ==================== layouts and the accelerator (P3; the two P5 factories; P4's calibrateLayout, spec 2.2)
|
|
58
65
|
export { createAccelerator } from "./accelerator.js";
|
|
59
66
|
export { calibrateLayout } from "./layouts/calibrate.js";
|
|
@@ -70,6 +77,7 @@ export type {
|
|
|
70
77
|
ApspResultLike,
|
|
71
78
|
BellmanFordResultLike,
|
|
72
79
|
BetweennessAcceleratorOptions,
|
|
80
|
+
BfsOptions,
|
|
73
81
|
BfsResultLike,
|
|
74
82
|
CommunityResultLike,
|
|
75
83
|
CorenessResultLike,
|
|
@@ -83,9 +91,14 @@ export type {
|
|
|
83
91
|
MstResultLike,
|
|
84
92
|
PageRankResultLike,
|
|
85
93
|
ScoresResultLike,
|
|
94
|
+
SsspOptions,
|
|
86
95
|
SsspResultLike,
|
|
87
96
|
} from "./types/accelerator.js";
|
|
88
97
|
|
|
98
|
+
// ==================== types: the P8 traversal results (spec 3.3 lines 830-832, 9.7); the option types are the seam's
|
|
99
|
+
// BfsOptions / SsspOptions / HitsOptionsLike above (P8 PD-19)
|
|
100
|
+
export type { GpuBellmanFordResult, GpuBfsResult, GpuSsspResult } from "./types/traversal.js";
|
|
101
|
+
|
|
89
102
|
// ==================== types: the P7 algorithm results and option records (spec 3.3 lines 815-828, 9.7)
|
|
90
103
|
export type {
|
|
91
104
|
ComponentsOptions,
|
package/src/kernel/prelude.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { INVALID_INDEX } from "@graphty/graph-format";
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
|
+
F32_INF_BITS,
|
|
15
16
|
FA2_COINCIDENT_SQ,
|
|
16
17
|
FA2_DISTANCE_FLOOR,
|
|
17
18
|
FA2_DISTANCE_FLOOR_SQ,
|
|
@@ -51,6 +52,7 @@ export function wgslF32Literal(value: number): string {
|
|
|
51
52
|
export const PRELUDE_WGSL: string = /* wgsl */ `// ---- prelude: constants, standard overrides, helpers (every module receives this text first)
|
|
52
53
|
const INVALID_INDEX: u32 = ${INVALID_INDEX}u;
|
|
53
54
|
const U32_MAX: u32 = ${U32_MAX}u;
|
|
55
|
+
const F32_INF_BITS: u32 = ${F32_INF_BITS}u;
|
|
54
56
|
const MAX_WORKGROUPS_PER_DIM: u32 = ${MAX_WORKGROUPS_PER_DIM}u;
|
|
55
57
|
const FA2_DIST_FLOOR: f32 = ${wgslF32Literal(FA2_DISTANCE_FLOOR)};
|
|
56
58
|
const FA2_DIST_FLOOR_SQ: f32 = ${wgslF32Literal(FA2_DISTANCE_FLOOR_SQ)};
|
|
@@ -101,7 +103,7 @@ fn kick_dir(i: u32, j: u32, dim: u32) -> vec3f {
|
|
|
101
103
|
/** Line count of PRELUDE_WGSL (the compilation-info formatter subtracts it plus the emitted declarations). */
|
|
102
104
|
export const PRELUDE_LINES: number = PRELUDE_WGSL.split("\n").length;
|
|
103
105
|
|
|
104
|
-
/** The workgroup-memory reduction helpers (the twin) (4.3). */
|
|
106
|
+
/** The workgroup-memory reduction helpers (the twin) (4.3), plus the workgroup-memory form of the P8 scan helper. */
|
|
105
107
|
export const REDUCE_HELPERS_WORKGROUP_WGSL: string = /* wgsl */ `var<workgroup> wg_scratch_v: array<vec4f, WG>;
|
|
106
108
|
var<workgroup> wg_scratch_u: array<u32, WG>;
|
|
107
109
|
fn combine_v(a: vec4f, b: vec4f, op: u32) -> vec4f {
|
|
@@ -138,9 +140,24 @@ fn wg_reduce_u32(v: u32, lid: u32, op: u32) -> u32 {
|
|
|
138
140
|
workgroupBarrier();
|
|
139
141
|
return total;
|
|
140
142
|
}
|
|
143
|
+
fn wg_scan_u32(v: u32, lid: u32) -> u32 {
|
|
144
|
+
workgroupBarrier();
|
|
145
|
+
wg_scratch_u[lid] = v;
|
|
146
|
+
workgroupBarrier();
|
|
147
|
+
for (var s = 1u; s < WG; s = s * 2u) { // Hillis-Steele inclusive scan (scan-block's body); uniform: every lane runs every round
|
|
148
|
+
var t = 0u;
|
|
149
|
+
if (lid >= s) { t = wg_scratch_u[lid - s]; }
|
|
150
|
+
workgroupBarrier();
|
|
151
|
+
wg_scratch_u[lid] = wg_scratch_u[lid] + t;
|
|
152
|
+
workgroupBarrier();
|
|
153
|
+
}
|
|
154
|
+
let inclusive = wg_scratch_u[lid];
|
|
155
|
+
workgroupBarrier(); // the scratch is free for the next call
|
|
156
|
+
return inclusive;
|
|
157
|
+
}
|
|
141
158
|
fn wg_reduce_f32(v: f32, lid: u32, op: u32) -> f32 { return wg_reduce_vec4(vec4f(v, 0.0, 0.0, 0.0), lid, op).x; }`;
|
|
142
159
|
|
|
143
|
-
/** The subgroup reduction helpers, spliced only with `enable subgroups;` (4.3). */
|
|
160
|
+
/** The subgroup reduction helpers, spliced only with `enable subgroups;` (4.3), plus the subgroup form of the P8 scan helper. */
|
|
144
161
|
export const REDUCE_HELPERS_SUBGROUP_WGSL: string = /* wgsl */ `override SG_SLOTS: u32 = (WG + SUBGROUP_MIN - 1u) / SUBGROUP_MIN; // one slot per subgroup; the count is largest when the compiler picks the SMALLEST size
|
|
145
162
|
var<workgroup> sg_counter: atomic<u32>;
|
|
146
163
|
var<workgroup> sg_val_v: array<vec4f, SG_SLOTS>;
|
|
@@ -216,10 +233,28 @@ fn wg_reduce_u32(v: u32, lid: u32, op: u32) -> u32 {
|
|
|
216
233
|
workgroupBarrier();
|
|
217
234
|
return total;
|
|
218
235
|
}
|
|
236
|
+
fn wg_scan_u32(v: u32, lid: u32) -> u32 {
|
|
237
|
+
workgroupBarrier();
|
|
238
|
+
if (lid == 0u) { atomicStore(&sg_counter, 0u); }
|
|
239
|
+
workgroupBarrier();
|
|
240
|
+
let inSub = subgroupExclusiveAdd(v) + v; // the lane's inclusive sum within its subgroup
|
|
241
|
+
let total = subgroupAdd(v);
|
|
242
|
+
let key = subgroupMin(lid); // the subgroup's identity: its smallest local id (D16)
|
|
243
|
+
var slot = 0u;
|
|
244
|
+
if (subgroupElect()) { slot = atomicAdd(&sg_counter, 1u); }
|
|
245
|
+
slot = subgroupBroadcast(slot, 0u);
|
|
246
|
+
if (subgroupElect()) { sg_val_u[slot] = total; sg_key[slot] = key; }
|
|
247
|
+
workgroupBarrier();
|
|
248
|
+
let count = atomicLoad(&sg_counter);
|
|
249
|
+
var carry = 0u; // the totals of every subgroup whose key is below this lane's: LANE order, whatever order the slots were taken in
|
|
250
|
+
for (var k = 0u; k < count; k = k + 1u) { if (sg_key[k] < key) { carry = carry + sg_val_u[k]; } }
|
|
251
|
+
workgroupBarrier(); // the slots are free for the next call
|
|
252
|
+
return inSub + carry;
|
|
253
|
+
}
|
|
219
254
|
fn wg_reduce_f32(v: f32, lid: u32, op: u32) -> f32 { return wg_reduce_vec4(vec4f(v, 0.0, 0.0, 0.0), lid, op).x; }`;
|
|
220
255
|
|
|
221
|
-
/** The helper function names a body may call when its spec lists needs: ["subgroups"]. */
|
|
222
|
-
export const REDUCE_HELPER_NAMES = ["wg_reduce_f32", "wg_reduce_u32", "wg_reduce_vec4"] as const;
|
|
256
|
+
/** The helper function names a body may call when its spec lists needs: ["subgroups"]; `wg_scan_u32(v, lid)` is an INCLUSIVE prefix sum over the workgroup in lane order (P8-T1), bitwise the same in both forms. */
|
|
257
|
+
export const REDUCE_HELPER_NAMES = ["wg_reduce_f32", "wg_reduce_u32", "wg_reduce_vec4", "wg_scan_u32"] as const;
|
|
223
258
|
|
|
224
259
|
/**
|
|
225
260
|
* The WGSL reserved words of spec section 16.2 (the `_reserved` production), frozen; composeWgsl rejects a body or
|
|
@@ -18,6 +18,14 @@ import type { UniformBlock, UniformValues } from "./struct-block.js";
|
|
|
18
18
|
export class UniformRing {
|
|
19
19
|
/** Number of slots. */
|
|
20
20
|
readonly slots: number;
|
|
21
|
+
/**
|
|
22
|
+
* How many reservations covered a DIRTY slot (written since the last `flush()`): the one reuse that corrupts,
|
|
23
|
+
* because the batch being recorded still reads that record and the shadow overwrites it before the flush sends
|
|
24
|
+
* either. A wrap onto slots an earlier, flushed batch wrote is harmless: its `writeBuffer` is ordered before that
|
|
25
|
+
* batch's submit and the next flush after it. A driver sizes its ring so this stays 0 (P8-T12: `bfsRingSlots`).
|
|
26
|
+
*/
|
|
27
|
+
overruns = 0;
|
|
28
|
+
private readonly dirty: Uint8Array;
|
|
21
29
|
private readonly device: GPUDevice;
|
|
22
30
|
private readonly allocator: AllocationTracker;
|
|
23
31
|
private readonly buffer: GPUBuffer;
|
|
@@ -54,6 +62,7 @@ export class UniformRing {
|
|
|
54
62
|
this.label = label;
|
|
55
63
|
this.shadow = new ArrayBuffer(slots * UNIFORM_SLOT_BYTES);
|
|
56
64
|
this.view = new DataView(this.shadow);
|
|
65
|
+
this.dirty = new Uint8Array(slots);
|
|
57
66
|
this.buffer = allocator.createBuffer({
|
|
58
67
|
label,
|
|
59
68
|
size: slots * UNIFORM_SLOT_BYTES,
|
|
@@ -105,6 +114,9 @@ export class UniformRing {
|
|
|
105
114
|
}
|
|
106
115
|
const first = this.next;
|
|
107
116
|
this.next += count;
|
|
117
|
+
if (this.dirty.subarray(first, first + count).includes(1)) {
|
|
118
|
+
this.overruns += 1;
|
|
119
|
+
}
|
|
108
120
|
return first;
|
|
109
121
|
}
|
|
110
122
|
|
|
@@ -118,6 +130,7 @@ export class UniformRing {
|
|
|
118
130
|
this.checkSlot(slot);
|
|
119
131
|
this.assertFits(block);
|
|
120
132
|
block.write(this.view, values, slot * UNIFORM_SLOT_BYTES);
|
|
133
|
+
this.dirty[slot] = 1;
|
|
121
134
|
if (this.dirtyLo < 0 || slot < this.dirtyLo) {
|
|
122
135
|
this.dirtyLo = slot;
|
|
123
136
|
}
|
|
@@ -138,6 +151,7 @@ export class UniformRing {
|
|
|
138
151
|
const begin = this.dirtyLo * UNIFORM_SLOT_BYTES;
|
|
139
152
|
const end = (this.dirtyHi + 1) * UNIFORM_SLOT_BYTES;
|
|
140
153
|
this.device.queue.writeBuffer(this.buffer, begin, this.shadow, begin, end - begin);
|
|
154
|
+
this.dirty.fill(0);
|
|
141
155
|
this.dirtyLo = -1;
|
|
142
156
|
this.dirtyHi = -1;
|
|
143
157
|
}
|