@graphty/webgpu-graph-algorithms 0.5.0 → 0.6.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.
Files changed (264) hide show
  1. package/README.md +104 -52
  2. package/dist/browser.js +1 -1
  3. package/dist/chunks/{context-CRbw2Wyo.js → context-BXqgCifx.js} +225 -33
  4. package/dist/chunks/context-BXqgCifx.js.map +1 -0
  5. package/dist/node.js +1 -1
  6. package/dist/src/accelerator.d.ts +12 -10
  7. package/dist/src/accelerator.d.ts.map +1 -1
  8. package/dist/src/accelerator.js +32 -10
  9. package/dist/src/accelerator.js.map +1 -1
  10. package/dist/src/algorithms/components.d.ts.map +1 -1
  11. package/dist/src/algorithms/components.js +12 -13
  12. package/dist/src/algorithms/components.js.map +1 -1
  13. package/dist/src/algorithms/degree.d.ts +6 -8
  14. package/dist/src/algorithms/degree.d.ts.map +1 -1
  15. package/dist/src/algorithms/degree.js +58 -35
  16. package/dist/src/algorithms/degree.js.map +1 -1
  17. package/dist/src/algorithms/pagerank.d.ts.map +1 -1
  18. package/dist/src/algorithms/pagerank.js +16 -14
  19. package/dist/src/algorithms/pagerank.js.map +1 -1
  20. package/dist/src/algorithms/power-iteration.d.ts +2 -2
  21. package/dist/src/algorithms/power-iteration.d.ts.map +1 -1
  22. package/dist/src/algorithms/power-iteration.js +17 -14
  23. package/dist/src/algorithms/power-iteration.js.map +1 -1
  24. package/dist/src/constants.d.ts +85 -8
  25. package/dist/src/constants.d.ts.map +1 -1
  26. package/dist/src/constants.js +85 -8
  27. package/dist/src/constants.js.map +1 -1
  28. package/dist/src/errors.d.ts +3 -2
  29. package/dist/src/errors.d.ts.map +1 -1
  30. package/dist/src/errors.js +2 -1
  31. package/dist/src/errors.js.map +1 -1
  32. package/dist/src/index.d.ts +10 -5
  33. package/dist/src/index.d.ts.map +1 -1
  34. package/dist/src/index.js +14 -5
  35. package/dist/src/index.js.map +1 -1
  36. package/dist/src/kernel/dispatch.d.ts +8 -3
  37. package/dist/src/kernel/dispatch.d.ts.map +1 -1
  38. package/dist/src/kernel/dispatch.js +18 -7
  39. package/dist/src/kernel/dispatch.js.map +1 -1
  40. package/dist/src/kernel/kernel.d.ts +30 -1
  41. package/dist/src/kernel/kernel.d.ts.map +1 -1
  42. package/dist/src/kernel/kernel.js +49 -5
  43. package/dist/src/kernel/kernel.js.map +1 -1
  44. package/dist/src/kernel/prelude.d.ts.map +1 -1
  45. package/dist/src/kernel/prelude.js +9 -1
  46. package/dist/src/kernel/prelude.js.map +1 -1
  47. package/dist/src/kernel/profiler.d.ts +15 -3
  48. package/dist/src/kernel/profiler.d.ts.map +1 -1
  49. package/dist/src/kernel/profiler.js +27 -4
  50. package/dist/src/kernel/profiler.js.map +1 -1
  51. package/dist/src/kernels.d.ts +18 -8
  52. package/dist/src/kernels.d.ts.map +1 -1
  53. package/dist/src/kernels.js +345 -22
  54. package/dist/src/kernels.js.map +1 -1
  55. package/dist/src/layouts/calibrate.d.ts +51 -0
  56. package/dist/src/layouts/calibrate.d.ts.map +1 -0
  57. package/dist/src/layouts/calibrate.js +172 -0
  58. package/dist/src/layouts/calibrate.js.map +1 -0
  59. package/dist/src/layouts/force-simulation.d.ts +42 -5
  60. package/dist/src/layouts/force-simulation.d.ts.map +1 -1
  61. package/dist/src/layouts/force-simulation.js +84 -22
  62. package/dist/src/layouts/force-simulation.js.map +1 -1
  63. package/dist/src/layouts/forceatlas2.d.ts +107 -38
  64. package/dist/src/layouts/forceatlas2.d.ts.map +1 -1
  65. package/dist/src/layouts/forceatlas2.js +297 -290
  66. package/dist/src/layouts/forceatlas2.js.map +1 -1
  67. package/dist/src/layouts/fruchterman-reingold.d.ts +241 -0
  68. package/dist/src/layouts/fruchterman-reingold.d.ts.map +1 -0
  69. package/dist/src/layouts/fruchterman-reingold.js +739 -0
  70. package/dist/src/layouts/fruchterman-reingold.js.map +1 -0
  71. package/dist/src/layouts/model-common.d.ts +140 -0
  72. package/dist/src/layouts/model-common.d.ts.map +1 -0
  73. package/dist/src/layouts/model-common.js +269 -0
  74. package/dist/src/layouts/model-common.js.map +1 -0
  75. package/dist/src/layouts/repulsion-grid.d.ts +152 -0
  76. package/dist/src/layouts/repulsion-grid.d.ts.map +1 -0
  77. package/dist/src/layouts/repulsion-grid.js +318 -0
  78. package/dist/src/layouts/repulsion-grid.js.map +1 -0
  79. package/dist/src/layouts/spring-electrical.d.ts +224 -0
  80. package/dist/src/layouts/spring-electrical.d.ts.map +1 -0
  81. package/dist/src/layouts/spring-electrical.js +665 -0
  82. package/dist/src/layouts/spring-electrical.js.map +1 -0
  83. package/dist/src/memory/residency.d.ts +6 -2
  84. package/dist/src/memory/residency.d.ts.map +1 -1
  85. package/dist/src/memory/residency.js +84 -14
  86. package/dist/src/memory/residency.js.map +1 -1
  87. package/dist/src/primitives/core-shape.d.ts +38 -2
  88. package/dist/src/primitives/core-shape.d.ts.map +1 -1
  89. package/dist/src/primitives/core-shape.js +71 -3
  90. package/dist/src/primitives/core-shape.js.map +1 -1
  91. package/dist/src/primitives/grid-pyramid.d.ts +71 -0
  92. package/dist/src/primitives/grid-pyramid.d.ts.map +1 -0
  93. package/dist/src/primitives/grid-pyramid.js +143 -0
  94. package/dist/src/primitives/grid-pyramid.js.map +1 -0
  95. package/dist/src/primitives/grid.d.ts +118 -0
  96. package/dist/src/primitives/grid.d.ts.map +1 -0
  97. package/dist/src/primitives/grid.js +225 -0
  98. package/dist/src/primitives/grid.js.map +1 -0
  99. package/dist/src/primitives/histogram.d.ts +67 -0
  100. package/dist/src/primitives/histogram.d.ts.map +1 -0
  101. package/dist/src/primitives/histogram.js +190 -0
  102. package/dist/src/primitives/histogram.js.map +1 -0
  103. package/dist/src/primitives/radix-sort.d.ts +75 -0
  104. package/dist/src/primitives/radix-sort.d.ts.map +1 -0
  105. package/dist/src/primitives/radix-sort.js +168 -0
  106. package/dist/src/primitives/radix-sort.js.map +1 -0
  107. package/dist/src/primitives/scan.d.ts +44 -0
  108. package/dist/src/primitives/scan.d.ts.map +1 -0
  109. package/dist/src/primitives/scan.js +151 -0
  110. package/dist/src/primitives/scan.js.map +1 -0
  111. package/dist/src/primitives/segmented-reduce.d.ts +25 -17
  112. package/dist/src/primitives/segmented-reduce.d.ts.map +1 -1
  113. package/dist/src/primitives/segmented-reduce.js +166 -47
  114. package/dist/src/primitives/segmented-reduce.js.map +1 -1
  115. package/dist/src/primitives/spmv.d.ts +18 -14
  116. package/dist/src/primitives/spmv.d.ts.map +1 -1
  117. package/dist/src/primitives/spmv.js +94 -58
  118. package/dist/src/primitives/spmv.js.map +1 -1
  119. package/dist/src/primitives/verify.d.ts +49 -0
  120. package/dist/src/primitives/verify.d.ts.map +1 -0
  121. package/dist/src/primitives/verify.js +229 -0
  122. package/dist/src/primitives/verify.js.map +1 -0
  123. package/dist/src/types/accelerator.d.ts +7 -3
  124. package/dist/src/types/accelerator.d.ts.map +1 -1
  125. package/dist/src/types/context.d.ts +53 -0
  126. package/dist/src/types/context.d.ts.map +1 -1
  127. package/dist/src/types/layout.d.ts +52 -0
  128. package/dist/src/types/layout.d.ts.map +1 -1
  129. package/dist/src/types/options.d.ts +43 -1
  130. package/dist/src/types/options.d.ts.map +1 -1
  131. package/dist/src/wgsl/counting-scatter.wgsl.d.ts +8 -0
  132. package/dist/src/wgsl/counting-scatter.wgsl.d.ts.map +1 -0
  133. package/dist/src/wgsl/counting-scatter.wgsl.js +17 -0
  134. package/dist/src/wgsl/counting-scatter.wgsl.js.map +1 -0
  135. package/dist/src/wgsl/fa2-attraction.wgsl.d.ts +23 -8
  136. package/dist/src/wgsl/fa2-attraction.wgsl.d.ts.map +1 -1
  137. package/dist/src/wgsl/fa2-attraction.wgsl.js +100 -17
  138. package/dist/src/wgsl/fa2-attraction.wgsl.js.map +1 -1
  139. package/dist/src/wgsl/fa2-integrate.wgsl.d.ts +7 -2
  140. package/dist/src/wgsl/fa2-integrate.wgsl.d.ts.map +1 -1
  141. package/dist/src/wgsl/fa2-integrate.wgsl.js +28 -2
  142. package/dist/src/wgsl/fa2-integrate.wgsl.js.map +1 -1
  143. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts +4 -2
  144. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.d.ts.map +1 -1
  145. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js +14 -5
  146. package/dist/src/wgsl/fa2-repulsion-exact.wgsl.js.map +1 -1
  147. package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts +12 -1
  148. package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts.map +1 -1
  149. package/dist/src/wgsl/fa2-stats-finalize.wgsl.js +54 -0
  150. package/dist/src/wgsl/fa2-stats-finalize.wgsl.js.map +1 -1
  151. package/dist/src/wgsl/grid-cell-key.wgsl.d.ts +8 -0
  152. package/dist/src/wgsl/grid-cell-key.wgsl.d.ts.map +1 -0
  153. package/dist/src/wgsl/grid-cell-key.wgsl.js +30 -0
  154. package/dist/src/wgsl/grid-cell-key.wgsl.js.map +1 -0
  155. package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts +8 -0
  156. package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts.map +1 -0
  157. package/dist/src/wgsl/grid-centroid-hub.wgsl.js +29 -0
  158. package/dist/src/wgsl/grid-centroid-hub.wgsl.js.map +1 -0
  159. package/dist/src/wgsl/grid-centroid.wgsl.d.ts +8 -0
  160. package/dist/src/wgsl/grid-centroid.wgsl.d.ts.map +1 -0
  161. package/dist/src/wgsl/grid-centroid.wgsl.js +29 -0
  162. package/dist/src/wgsl/grid-centroid.wgsl.js.map +1 -0
  163. package/dist/src/wgsl/grid-downsample.wgsl.d.ts +7 -0
  164. package/dist/src/wgsl/grid-downsample.wgsl.d.ts.map +1 -0
  165. package/dist/src/wgsl/grid-downsample.wgsl.js +28 -0
  166. package/dist/src/wgsl/grid-downsample.wgsl.js.map +1 -0
  167. package/dist/src/wgsl/grid-far-field.wgsl.d.ts +13 -0
  168. package/dist/src/wgsl/grid-far-field.wgsl.d.ts.map +1 -0
  169. package/dist/src/wgsl/grid-far-field.wgsl.js +98 -0
  170. package/dist/src/wgsl/grid-far-field.wgsl.js.map +1 -0
  171. package/dist/src/wgsl/grid-near-field.wgsl.d.ts +19 -0
  172. package/dist/src/wgsl/grid-near-field.wgsl.d.ts.map +1 -0
  173. package/dist/src/wgsl/grid-near-field.wgsl.js +129 -0
  174. package/dist/src/wgsl/grid-near-field.wgsl.js.map +1 -0
  175. package/dist/src/wgsl/histogram.wgsl.d.ts +7 -0
  176. package/dist/src/wgsl/histogram.wgsl.d.ts.map +1 -0
  177. package/dist/src/wgsl/histogram.wgsl.js +15 -0
  178. package/dist/src/wgsl/histogram.wgsl.js.map +1 -0
  179. package/dist/src/wgsl/indirect-finalize.wgsl.d.ts +8 -0
  180. package/dist/src/wgsl/indirect-finalize.wgsl.d.ts.map +1 -0
  181. package/dist/src/wgsl/indirect-finalize.wgsl.js +26 -0
  182. package/dist/src/wgsl/indirect-finalize.wgsl.js.map +1 -0
  183. package/dist/src/wgsl/radix-hist.wgsl.d.ts +9 -0
  184. package/dist/src/wgsl/radix-hist.wgsl.d.ts.map +1 -0
  185. package/dist/src/wgsl/radix-hist.wgsl.js +31 -0
  186. package/dist/src/wgsl/radix-hist.wgsl.js.map +1 -0
  187. package/dist/src/wgsl/radix-scatter.wgsl.d.ts +9 -0
  188. package/dist/src/wgsl/radix-scatter.wgsl.d.ts.map +1 -0
  189. package/dist/src/wgsl/radix-scatter.wgsl.js +40 -0
  190. package/dist/src/wgsl/radix-scatter.wgsl.js.map +1 -0
  191. package/dist/src/wgsl/scan-add.wgsl.d.ts +6 -0
  192. package/dist/src/wgsl/scan-add.wgsl.d.ts.map +1 -0
  193. package/dist/src/wgsl/scan-add.wgsl.js +14 -0
  194. package/dist/src/wgsl/scan-add.wgsl.js.map +1 -0
  195. package/dist/src/wgsl/scan-block.wgsl.d.ts +8 -0
  196. package/dist/src/wgsl/scan-block.wgsl.d.ts.map +1 -0
  197. package/dist/src/wgsl/scan-block.wgsl.js +30 -0
  198. package/dist/src/wgsl/scan-block.wgsl.js.map +1 -0
  199. package/dist/src/wgsl/segmented-reduce.wgsl.d.ts +22 -8
  200. package/dist/src/wgsl/segmented-reduce.wgsl.d.ts.map +1 -1
  201. package/dist/src/wgsl/segmented-reduce.wgsl.js +84 -15
  202. package/dist/src/wgsl/segmented-reduce.wgsl.js.map +1 -1
  203. package/dist/src/wgsl/spmv-pull.wgsl.d.ts +22 -11
  204. package/dist/src/wgsl/spmv-pull.wgsl.d.ts.map +1 -1
  205. package/dist/src/wgsl/spmv-pull.wgsl.js +110 -36
  206. package/dist/src/wgsl/spmv-pull.wgsl.js.map +1 -1
  207. package/dist/tsconfig.build.tsbuildinfo +1 -1
  208. package/dist/webgpu-graph-algorithms.js +5016 -1130
  209. package/dist/webgpu-graph-algorithms.js.map +1 -1
  210. package/package.json +10 -7
  211. package/src/accelerator.ts +46 -12
  212. package/src/algorithms/components.ts +12 -16
  213. package/src/algorithms/degree.ts +58 -43
  214. package/src/algorithms/pagerank.ts +20 -18
  215. package/src/algorithms/power-iteration.ts +19 -18
  216. package/src/constants.ts +108 -8
  217. package/src/errors.ts +3 -1
  218. package/src/index.ts +25 -5
  219. package/src/kernel/dispatch.ts +18 -7
  220. package/src/kernel/kernel.ts +59 -5
  221. package/src/kernel/prelude.ts +15 -0
  222. package/src/kernel/profiler.ts +28 -4
  223. package/src/kernels.ts +378 -24
  224. package/src/layouts/calibrate.ts +187 -0
  225. package/src/layouts/force-simulation.ts +111 -26
  226. package/src/layouts/forceatlas2.ts +346 -324
  227. package/src/layouts/fruchterman-reingold.ts +918 -0
  228. package/src/layouts/model-common.ts +323 -0
  229. package/src/layouts/repulsion-grid.ts +451 -0
  230. package/src/layouts/spring-electrical.ts +845 -0
  231. package/src/memory/residency.ts +126 -20
  232. package/src/primitives/core-shape.ts +91 -4
  233. package/src/primitives/grid-pyramid.ts +221 -0
  234. package/src/primitives/grid.ts +349 -0
  235. package/src/primitives/histogram.ts +273 -0
  236. package/src/primitives/radix-sort.ts +246 -0
  237. package/src/primitives/scan.ts +197 -0
  238. package/src/primitives/segmented-reduce.ts +214 -56
  239. package/src/primitives/spmv.ts +125 -65
  240. package/src/primitives/verify.ts +249 -0
  241. package/src/types/accelerator.ts +15 -3
  242. package/src/types/context.ts +56 -0
  243. package/src/types/layout.ts +58 -0
  244. package/src/types/options.ts +45 -1
  245. package/src/wgsl/counting-scatter.wgsl.ts +16 -0
  246. package/src/wgsl/fa2-attraction.wgsl.ts +100 -17
  247. package/src/wgsl/fa2-integrate.wgsl.ts +28 -2
  248. package/src/wgsl/fa2-repulsion-exact.wgsl.ts +14 -5
  249. package/src/wgsl/fa2-stats-finalize.wgsl.ts +54 -0
  250. package/src/wgsl/grid-cell-key.wgsl.ts +29 -0
  251. package/src/wgsl/grid-centroid-hub.wgsl.ts +28 -0
  252. package/src/wgsl/grid-centroid.wgsl.ts +28 -0
  253. package/src/wgsl/grid-downsample.wgsl.ts +27 -0
  254. package/src/wgsl/grid-far-field.wgsl.ts +97 -0
  255. package/src/wgsl/grid-near-field.wgsl.ts +128 -0
  256. package/src/wgsl/histogram.wgsl.ts +14 -0
  257. package/src/wgsl/indirect-finalize.wgsl.ts +25 -0
  258. package/src/wgsl/radix-hist.wgsl.ts +30 -0
  259. package/src/wgsl/radix-scatter.wgsl.ts +39 -0
  260. package/src/wgsl/scan-add.wgsl.ts +13 -0
  261. package/src/wgsl/scan-block.wgsl.ts +29 -0
  262. package/src/wgsl/segmented-reduce.wgsl.ts +84 -15
  263. package/src/wgsl/spmv-pull.wgsl.ts +110 -36
  264. package/dist/chunks/context-CRbw2Wyo.js.map +0 -1
@@ -3,6 +3,7 @@ const WORKGROUP_SIZE = 256;
3
3
  const MAX_WORKGROUPS_PER_DIM = 65535;
4
4
  const MAX_1D_ITEMS = MAX_WORKGROUPS_PER_DIM * WORKGROUP_SIZE;
5
5
  const U32_MAX = 4294967295;
6
+ const RADIX_BINS = 256;
6
7
  const ARC_WINDOW_ALIGN = 64;
7
8
  const STORAGE_ALIGN = 256;
8
9
  const UNIFORM_SLOT_BYTES = 256;
@@ -49,6 +50,44 @@ const FA2_DISTANCE_FLOOR = 0.01;
49
50
  const FA2_DISTANCE_FLOOR_SQ = 1e-4;
50
51
  const FA2_COINCIDENT_SQ = 1e-8;
51
52
  const FA2_FLAG_FIRST = 1;
53
+ const FA2_FLAG_ADAPTIVE = 2;
54
+ const FR_START_TEMPERATURE = 0.1;
55
+ const FR_REHEAT_FRACTION = 0.7;
56
+ const FR_COOLING_STEP = 0.9;
57
+ const FR_COOLING_PATIENCE = 5;
58
+ const FR_ADAPTIVE_MAX_ITERATIONS = 1e4;
59
+ const FR_DEFAULTS = Object.freeze({
60
+ k: null,
61
+ iterations: 50,
62
+ fixed: null,
63
+ dim: 2,
64
+ scale: 1,
65
+ settleThreshold: 1e-3,
66
+ settleWindow: 10,
67
+ iterationsPerStep: 1,
68
+ maxInFlight: 2,
69
+ cooling: "linear"
70
+ });
71
+ const SE_SCALE_REFERENCE_NODES = 300;
72
+ const SE_DEFAULTS = Object.freeze({
73
+ springLength: 10,
74
+ springCoefficient: 0.8,
75
+ gravity: -12,
76
+ dragCoefficient: 0.9,
77
+ timeStep: 0.5,
78
+ dim: 2,
79
+ scale: 1,
80
+ settleThreshold: 1e-3,
81
+ settleWindow: 10,
82
+ iterationsPerStep: 1,
83
+ maxInFlight: 2
84
+ });
85
+ const GRID_MIN_SIDE = 8;
86
+ const GRID_COARSEST_SIDE = 4;
87
+ const GRID_HUB_CELL = 1024;
88
+ const GRID_EXTENT_FLOOR = 1e-6;
89
+ const GRID_BBOX_MARGIN = 1.01;
90
+ const GRID_SORT_BITS = 24;
52
91
  const PASSTHROUGH_FORMAT_CODES = Object.freeze(["E_GPU_INELIGIBLE", "E_UNKNOWN_NODE", "E_UNKNOWN_COLUMN", "E_COLUMN_LENGTH"]);
53
92
  const EMPTY_DETAILS = Object.freeze({});
54
93
  class WebGpuGraphError extends Error {
@@ -511,6 +550,7 @@ function deviceLostError(info) {
511
550
  message: info.message
512
551
  });
513
552
  }
553
+ const INDIRECT_ARGS_STRIDE = 16;
514
554
  const bufferIds = /* @__PURE__ */ new WeakMap();
515
555
  let nextBufferId = 1;
516
556
  function bufferId(buffer) {
@@ -701,6 +741,42 @@ class Kernel {
701
741
  * @param dynamicOffsets - one byte offset per entry of bound.dynamicGroups
702
742
  */
703
743
  dispatch(pass, bound, plan, dynamicOffsets) {
744
+ this.check(bound, dynamicOffsets);
745
+ if (plan.x === 0) {
746
+ return;
747
+ }
748
+ this.setUp(pass, bound, dynamicOffsets);
749
+ pass.dispatchWorkgroups(plan.x, plan.y, 1);
750
+ }
751
+ /**
752
+ * setPipeline + the bind groups exactly as dispatch(), then dispatchWorkgroupsIndirect(args.buffer, args.offset +
753
+ * INDIRECT_ARGS_STRIDE * slot) (spec 5.4): the (x, y, 1) of the slot were written by the indirect-finalize kernel
754
+ * earlier in the same pass. A slot beyond the binding is E_INVALID_ARGUMENT.
755
+ * @param pass - the open compute pass
756
+ * @param bound - a BoundKernel of THIS kernel
757
+ * @param args - the args buffer range (usage INDIRECT | STORAGE)
758
+ * @param slot - the 16-byte slot index inside the range
759
+ * @param dynamicOffsets - one byte offset per entry of bound.dynamicGroups
760
+ */
761
+ dispatchIndirect(pass, bound, args, slot, dynamicOffsets) {
762
+ this.check(bound, dynamicOffsets);
763
+ if (!Number.isInteger(slot) || slot < 0 || (slot + 1) * INDIRECT_ARGS_STRIDE > args.size) {
764
+ throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${this.spec.id}: args slot ${slot} is outside the binding`, {
765
+ argument: "slot",
766
+ value: slot,
767
+ expected: `0 <= slot < ${Math.floor(args.size / INDIRECT_ARGS_STRIDE)}`
768
+ });
769
+ }
770
+ this.setUp(pass, bound, dynamicOffsets);
771
+ pass.dispatchWorkgroupsIndirect(args.buffer, args.offset + INDIRECT_ARGS_STRIDE * slot);
772
+ }
773
+ /**
774
+ * The argument checks dispatch() and dispatchIndirect() share: a BoundKernel of another kernel or an offset list
775
+ * of the wrong length is E_INVALID_ARGUMENT.
776
+ * @param bound - the bound kernel
777
+ * @param dynamicOffsets - the offsets, if any
778
+ */
779
+ check(bound, dynamicOffsets) {
704
780
  const { id } = this.spec;
705
781
  if (bound.kernel !== this) {
706
782
  throw new WebGpuGraphError(
@@ -724,9 +800,15 @@ class Kernel {
724
800
  }
725
801
  );
726
802
  }
727
- if (plan.x === 0) {
728
- return;
729
- }
803
+ }
804
+ /**
805
+ * setPipeline + setBindGroup for every group (the dynamic offsets replicated over the uniform bindings of each
806
+ * dynamic group), the prefix dispatch() and dispatchIndirect() share.
807
+ * @param pass - the open compute pass
808
+ * @param bound - a BoundKernel of this kernel
809
+ * @param dynamicOffsets - one byte offset per entry of bound.dynamicGroups (absent = 0)
810
+ */
811
+ setUp(pass, bound, dynamicOffsets) {
730
812
  pass.setPipeline(this.pipeline);
731
813
  let next = 0;
732
814
  bound.bindGroups.forEach((bindGroup, group) => {
@@ -743,7 +825,6 @@ class Kernel {
743
825
  pass.setBindGroup(group, bindGroup);
744
826
  }
745
827
  });
746
- pass.dispatchWorkgroups(plan.x, plan.y, 1);
747
828
  }
748
829
  /** Drops cached bind groups (a layout's buffers changed). */
749
830
  invalidate() {
@@ -807,6 +888,14 @@ const FA2_DIST_FLOOR: f32 = ${wgslF32Literal(FA2_DISTANCE_FLOOR)};
807
888
  const FA2_DIST_FLOOR_SQ: f32 = ${wgslF32Literal(FA2_DISTANCE_FLOOR_SQ)};
808
889
  const FA2_COINCIDENT_SQ: f32 = ${wgslF32Literal(FA2_COINCIDENT_SQ)};
809
890
  const FA2_FLAG_FIRST: u32 = ${FA2_FLAG_FIRST}u;
891
+ const FA2_FLAG_ADAPTIVE: u32 = ${FA2_FLAG_ADAPTIVE}u;
892
+ const FR_COOLING_STEP: f32 = ${wgslF32Literal(FR_COOLING_STEP)};
893
+ const FR_COOLING_PATIENCE: u32 = ${FR_COOLING_PATIENCE}u;
894
+ const GRID_HUB_CELL: u32 = ${GRID_HUB_CELL}u;
895
+ const GRID_EXTENT_FLOOR: f32 = ${wgslF32Literal(GRID_EXTENT_FLOOR)};
896
+ const GRID_BBOX_MARGIN: f32 = ${wgslF32Literal(GRID_BBOX_MARGIN)};
897
+ const RADIX_BINS: u32 = ${RADIX_BINS}u;
898
+ const RADIX_DIGIT_MASK: u32 = ${RADIX_BINS - 1}u;
810
899
  const F32_MAX: f32 = 0x1.fffffep+127;
811
900
  override WG: u32 = ${WORKGROUP_SIZE}u;
812
901
  override USE_PERM: bool = false;
@@ -1475,8 +1564,10 @@ class Profiler {
1475
1564
  */
1476
1565
  constructor(device, enabled, quantised, slots) {
1477
1566
  this.labels = /* @__PURE__ */ new WeakMap();
1567
+ this.partialRequests = /* @__PURE__ */ new WeakSet();
1478
1568
  this.pending = [];
1479
1569
  this.cursor = 0;
1570
+ this.refused = 0;
1480
1571
  this.destroyed = false;
1481
1572
  const count = slots ?? PROFILER_QUERY_SLOTS;
1482
1573
  this.quantised = quantised;
@@ -1496,12 +1587,17 @@ class Profiler {
1496
1587
  }
1497
1588
  }
1498
1589
  /**
1499
- * The timestampWrites descriptor for a new pass, or undefined when disabled / out of slots.
1590
+ * The timestampWrites descriptor for a new pass, or undefined when disabled / out of slots. A pass refused for
1591
+ * want of slots is counted, and the next `resolveInto()` marks its request partial.
1500
1592
  * @param label - the pass name reported by `timings()`
1501
1593
  * @returns the descriptor a CommandBatch puts on beginComputePass, or undefined
1502
1594
  */
1503
1595
  beginPass(label) {
1504
- if (this.querySet === null || this.destroyed || this.cursor + 2 > this.slots) {
1596
+ if (this.querySet === null || this.destroyed) {
1597
+ return void 0;
1598
+ }
1599
+ if (this.cursor + 2 > this.slots) {
1600
+ this.refused++;
1505
1601
  return void 0;
1506
1602
  }
1507
1603
  const begin = this.cursor;
@@ -1526,10 +1622,23 @@ class Profiler {
1526
1622
  request,
1527
1623
  this.pending.map((pass) => pass.label)
1528
1624
  );
1625
+ if (this.refused > 0) {
1626
+ this.partialRequests.add(request);
1627
+ }
1529
1628
  this.pending = [];
1530
1629
  this.cursor = 0;
1630
+ this.refused = 0;
1531
1631
  return request;
1532
1632
  }
1633
+ /**
1634
+ * Whether a pass of the batch was refused a slot pair, so `timings()` covers only its first slots / 2 passes
1635
+ * and their sum is not the batch's duration.
1636
+ * @param request - the request `resolveInto()` returned
1637
+ * @returns true when at least one pass of that batch went untimed
1638
+ */
1639
+ partial(request) {
1640
+ return this.partialRequests.has(request);
1641
+ }
1533
1642
  /**
1534
1643
  * Decodes the timings of a batch from its readback bytes.
1535
1644
  * @param bytes - the resolved readback of the batch
@@ -1562,6 +1671,7 @@ class Profiler {
1562
1671
  this.destroyed = true;
1563
1672
  this.pending = [];
1564
1673
  this.cursor = 0;
1674
+ this.refused = 0;
1565
1675
  if (this.querySet !== null) {
1566
1676
  this.querySet.destroy();
1567
1677
  }
@@ -2130,7 +2240,7 @@ class Readback {
2130
2240
  }
2131
2241
  }
2132
2242
  const CORE_ORDER$1 = Object.freeze(["rowPtr", "colIdx", "weights", "arcToEdge", "edgeToArc"]);
2133
- const ARC_INDEXED = /* @__PURE__ */ new Set(["colIdx", "weights", "arcToEdge"]);
2243
+ const ARC_INDEXED$1 = /* @__PURE__ */ new Set(["colIdx", "weights", "arcToEdge"]);
2134
2244
  function coreByteLengths(s) {
2135
2245
  const arcs = s.arcCount;
2136
2246
  const identity = s.flags.arcToEdgeIsIdentity;
@@ -2304,13 +2414,17 @@ function planUpload(s, caps, need) {
2304
2414
  const windows = planArcWindows(s.rowPtr, s.arcCount, arcsPerWindow);
2305
2415
  const { buffers, placed } = placeWindows(windows, 4 * s.arcCount, bufferLimit);
2306
2416
  const arrays = names.map(
2307
- (name) => ARC_INDEXED.has(name) ? { name, byteLength: lengths[name], buffers } : { name, byteLength: lengths[name], buffers: [{ byteOffset: 0, byteLength: lengths[name] }] }
2417
+ (name) => ARC_INDEXED$1.has(name) ? { name, byteLength: lengths[name], buffers } : { name, byteLength: lengths[name], buffers: [{ byteOffset: 0, byteLength: lengths[name] }] }
2308
2418
  );
2309
2419
  return { kind: "windowed", arrays, windows: placed, arcsPerWindow };
2310
2420
  }
2311
2421
  const DEFAULT_NEED = Object.freeze(["rowPtr", "colIdx", "weights"]);
2312
2422
  const CORE_ORDER = Object.freeze(["rowPtr", "colIdx", "weights", "arcToEdge", "edgeToArc"]);
2423
+ const ARC_INDEXED = Object.freeze(["colIdx", "weights", "arcToEdge"]);
2313
2424
  const RESIDENT_USAGE = BufferUsage.STORAGE | BufferUsage.COPY_DST | BufferUsage.COPY_SRC;
2425
+ function isArcIndexed(name) {
2426
+ return ARC_INDEXED.includes(name);
2427
+ }
2314
2428
  function isSharedBuffer(buffer) {
2315
2429
  return Object.prototype.toString.call(buffer) === "[object SharedArrayBuffer]";
2316
2430
  }
@@ -2396,8 +2510,9 @@ class GraphResidency {
2396
2510
  }
2397
2511
  /**
2398
2512
  * Uploads (or finds) the core; `need` defaults to ["rowPtr", "colIdx", "weights"]; cold segments on demand
2399
- * (spec 4.2). Never materialises an identity permutation. A windowed plan throws E_TOO_LARGE { path: "windowed" }
2400
- * until P4 (PLAN DECISION 2); a tombstoned serial is lifted and re-uploaded (PLAN DECISION 7).
2513
+ * (spec 4.2). Never materialises an identity permutation. A windowed plan (spec 4.2, PD-8) uploads every
2514
+ * arc-indexed array as the plan's buffer ranges and binds window 0 as its default binding; rowPtr and edgeToArc
2515
+ * stay whole. A tombstoned serial is lifted and re-uploaded (PLAN DECISION 7).
2401
2516
  * @param s - the snapshot
2402
2517
  * @param need - the core arrays to bind (rowPtr is always included; absent arrays are ignored)
2403
2518
  * @returns the core binding (a frozen object; grows as cold segments are added)
@@ -2408,18 +2523,6 @@ class GraphResidency {
2408
2523
  const wanted = need ?? DEFAULT_NEED;
2409
2524
  const names = CORE_ORDER.filter((name) => (name === "rowPtr" || wanted.includes(name)) && isPresent(s, name));
2410
2525
  const plan = planUpload(s, this.caps, names);
2411
- if (plan.kind === "windowed") {
2412
- throw new WebGpuGraphError(
2413
- "E_TOO_LARGE",
2414
- `snapshot ${s.serial}: an arc array of ${4 * s.arcCount} bytes needs arc windows (${plan.windows.length}), which P1-P3 plan but do not execute`,
2415
- {
2416
- needed: 4 * s.arcCount,
2417
- limit: this.caps.limits.maxStorageBufferBindingSize,
2418
- path: "windowed",
2419
- algorithm: null
2420
- }
2421
- );
2422
- }
2423
2526
  const record = this.ensureRecord(s);
2424
2527
  if (record.plan === null) {
2425
2528
  record.plan = plan.kind;
@@ -2433,10 +2536,17 @@ class GraphResidency {
2433
2536
  );
2434
2537
  record.arena = { buffer: resident.buffer, segments: plan.segments };
2435
2538
  }
2539
+ if (plan.kind === "windowed") {
2540
+ record.windows = plan.windows;
2541
+ }
2436
2542
  }
2437
2543
  for (const name of names) {
2438
2544
  if (!record.bindings.has(name)) {
2439
- record.bindings.set(name, this.bindCore(record, s, name));
2545
+ const planned = plan.kind === "windowed" ? plan.arrays.find((a) => a.name === name) : void 0;
2546
+ record.bindings.set(
2547
+ name,
2548
+ planned !== void 0 && planned.buffers.length > 0 && record.windows !== null && isArcIndexed(name) ? this.bindWindowed(record, s, name, planned.buffers, record.windows[0]) : this.bindCore(record, s, name)
2549
+ );
2440
2550
  }
2441
2551
  }
2442
2552
  const rowPtr = record.bindings.get("rowPtr");
@@ -2452,7 +2562,12 @@ class GraphResidency {
2452
2562
  weights,
2453
2563
  arcToEdge: record.bindings.get("arcToEdge") ?? null,
2454
2564
  edgeToArc: record.bindings.get("edgeToArc") ?? null,
2455
- windows: null,
2565
+ windows: record.windows,
2566
+ arcBuffers: record.windows === null ? null : Object.freeze({
2567
+ colIdx: Object.freeze([...record.arcBuffers.get("colIdx") ?? []]),
2568
+ weights: Object.freeze([...record.arcBuffers.get("weights") ?? []]),
2569
+ arcToEdge: Object.freeze([...record.arcBuffers.get("arcToEdge") ?? []])
2570
+ }),
2456
2571
  hasWeights: weights !== null
2457
2572
  });
2458
2573
  }
@@ -2558,6 +2673,18 @@ class GraphResidency {
2558
2673
  const rev = s.reverse();
2559
2674
  if (!s.directed) {
2560
2675
  const core = this.core(s, ["rowPtr", "colIdx", "weights"]);
2676
+ if (core.plan === "windowed") {
2677
+ throw new WebGpuGraphError(
2678
+ "E_TOO_LARGE",
2679
+ `snapshot ${s.serial}: the undirected reverse view is the core, which needs arc windows (${core.windows?.length ?? 0}) that no view executes`,
2680
+ {
2681
+ needed: 4 * s.arcCount,
2682
+ limit: this.caps.limits.maxStorageBufferBindingSize,
2683
+ path: "windowed",
2684
+ algorithm: null
2685
+ }
2686
+ );
2687
+ }
2561
2688
  const bindings2 = { rowPtr: core.rowPtr };
2562
2689
  if (core.colIdx !== null) {
2563
2690
  bindings2.colIdx = core.colIdx;
@@ -2857,6 +2984,50 @@ class GraphResidency {
2857
2984
  const resident = this.upload(record, array, array, `residency:core:${record.serial}:${name}`);
2858
2985
  return { buffer: resident.buffer, offset: 0, size: resident.byteLength, window: null };
2859
2986
  }
2987
+ /**
2988
+ * Uploads one arc-indexed array as the windowed plan's buffer ranges (spec 4.2: an array above maxBufferSize is
2989
+ * split across buffers at window boundaries), each keyed on a marker object of the record (windowKey), and
2990
+ * returns window 0's binding so a caller that ignores windows still binds something valid (PD-8).
2991
+ * @param record - the snapshot's record
2992
+ * @param s - the snapshot
2993
+ * @param name - a PRESENT arc-indexed core array
2994
+ * @param ranges - the plan's buffer ranges of the array
2995
+ * @param first - window 0
2996
+ * @returns the binding of window 0
2997
+ */
2998
+ bindWindowed(record, s, name, ranges, first) {
2999
+ const array = coreArray(s, name);
3000
+ const buffers = ranges.map(
3001
+ (range, index) => this.upload(
3002
+ record,
3003
+ this.windowKey(record, `${name}:${index}`),
3004
+ new Uint8Array(array.buffer, array.byteOffset + range.byteOffset, range.byteLength),
3005
+ `residency:core:${record.serial}:${name}:w${index}`
3006
+ ).buffer
3007
+ );
3008
+ record.arcBuffers.set(name, buffers);
3009
+ return {
3010
+ buffer: buffers[first.bufferIndex],
3011
+ offset: first.offset,
3012
+ size: 4 * (first.end - first.start),
3013
+ window: first
3014
+ };
3015
+ }
3016
+ /**
3017
+ * The upload key of one window buffer: a marker object allocated once per record and `<name>:<bufferIndex>`.
3018
+ * @param record - the owning record
3019
+ * @param memoKey - `<name>:<bufferIndex>`
3020
+ * @returns the stable marker object
3021
+ */
3022
+ windowKey(record, memoKey) {
3023
+ const existing = record.windowKeys.get(memoKey);
3024
+ if (existing !== void 0) {
3025
+ return existing;
3026
+ }
3027
+ const created = {};
3028
+ record.windowKeys.set(memoKey, created);
3029
+ return created;
3030
+ }
2860
3031
  /**
2861
3032
  * Uploads `data` into a new buffer keyed on `key`, or returns the resident already uploaded for that key by
2862
3033
  * the same owner (PLAN DECISION 11: a resident belongs to one record).
@@ -2920,6 +3091,9 @@ class GraphResidency {
2920
3091
  record.bindings.clear();
2921
3092
  record.views.clear();
2922
3093
  record.packKeys.clear();
3094
+ record.windowKeys.clear();
3095
+ record.arcBuffers.clear();
3096
+ record.windows = null;
2923
3097
  record.arena = null;
2924
3098
  record.plan = null;
2925
3099
  this.bySerial.delete(record.serial);
@@ -2947,6 +3121,9 @@ class GraphResidency {
2947
3121
  bindings: /* @__PURE__ */ new Map(),
2948
3122
  views: /* @__PURE__ */ new Map(),
2949
3123
  packKeys: /* @__PURE__ */ new Map(),
3124
+ windowKeys: /* @__PURE__ */ new Map(),
3125
+ windows: null,
3126
+ arcBuffers: /* @__PURE__ */ new Map(),
2950
3127
  released: false
2951
3128
  };
2952
3129
  this.bySerial.set(s.serial, record);
@@ -3272,24 +3449,39 @@ export {
3272
3449
  EXACT_MAX_NODES as E,
3273
3450
  FA2_DEFAULTS as F,
3274
3451
  GpuContext as G,
3452
+ INDIRECT_ARGS_STRIDE as I,
3275
3453
  LAYOUT_TUNING_DEFAULTS as L,
3276
3454
  MAX_WORKGROUPS_PER_DIM as M,
3277
3455
  PARTIAL_BYTES as P,
3456
+ RADIX_BINS as R,
3278
3457
  STATE_HEADER_BYTES as S,
3279
3458
  TRACE_RECORD_BYTES as T,
3280
3459
  UNIFORM_SLOT_BYTES as U,
3281
3460
  WebGpuGraphError as W,
3282
3461
  WGSL_RESERVED_WORDS as a,
3283
3462
  U32_MAX as b,
3284
- MAX_ITERATIONS_PER_STEP as c,
3463
+ GRID_COARSEST_SIDE as c,
3285
3464
  deviceLostError as d,
3286
- MAX_1D_ITEMS as e,
3287
- FA2_FLAG_FIRST as f,
3288
- PASSTHROUGH_FORMAT_CODES as g,
3289
- hasErrorCode as h,
3465
+ GRID_MIN_SIDE as e,
3466
+ GRID_SORT_BITS as f,
3467
+ MAX_ITERATIONS_PER_STEP as g,
3468
+ MAX_1D_ITEMS as h,
3290
3469
  isWebGpuGraphError as i,
3291
- STORAGE_ALIGN as j,
3292
- WORKGROUP_SIZE as k,
3293
- isSoftwareAdapter as l
3470
+ hasErrorCode as j,
3471
+ FA2_FLAG_FIRST as k,
3472
+ GRID_HUB_CELL as l,
3473
+ GRID_BBOX_MARGIN as m,
3474
+ GRID_EXTENT_FLOOR as n,
3475
+ FR_ADAPTIVE_MAX_ITERATIONS as o,
3476
+ FR_START_TEMPERATURE as p,
3477
+ FA2_FLAG_ADAPTIVE as q,
3478
+ FR_REHEAT_FRACTION as r,
3479
+ FR_DEFAULTS as s,
3480
+ SE_DEFAULTS as t,
3481
+ SE_SCALE_REFERENCE_NODES as u,
3482
+ PASSTHROUGH_FORMAT_CODES as v,
3483
+ STORAGE_ALIGN as w,
3484
+ WORKGROUP_SIZE as x,
3485
+ isSoftwareAdapter as y
3294
3486
  };
3295
- //# sourceMappingURL=context-CRbw2Wyo.js.map
3487
+ //# sourceMappingURL=context-BXqgCifx.js.map