@graphty/webgpu-graph-algorithms 0.5.1 → 0.6.1
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 +459 -58
- package/dist/browser.js +1 -1
- package/dist/chunks/{context-BR7fx3vR.js → context-BXqgCifx.js} +190 -40
- package/dist/chunks/context-BXqgCifx.js.map +1 -0
- package/dist/node.js +1 -1
- package/dist/src/algorithms/components.d.ts.map +1 -1
- package/dist/src/algorithms/components.js +12 -13
- package/dist/src/algorithms/components.js.map +1 -1
- package/dist/src/algorithms/degree.d.ts +6 -8
- package/dist/src/algorithms/degree.d.ts.map +1 -1
- package/dist/src/algorithms/degree.js +58 -35
- package/dist/src/algorithms/degree.js.map +1 -1
- package/dist/src/algorithms/pagerank.d.ts.map +1 -1
- package/dist/src/algorithms/pagerank.js +16 -14
- package/dist/src/algorithms/pagerank.js.map +1 -1
- package/dist/src/algorithms/power-iteration.d.ts +2 -2
- package/dist/src/algorithms/power-iteration.d.ts.map +1 -1
- package/dist/src/algorithms/power-iteration.js +17 -14
- package/dist/src/algorithms/power-iteration.js.map +1 -1
- package/dist/src/constants.d.ts +38 -8
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +38 -8
- package/dist/src/constants.js.map +1 -1
- package/dist/src/errors.d.ts +3 -2
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +2 -1
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +6 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/kernel/dispatch.d.ts +8 -3
- package/dist/src/kernel/dispatch.d.ts.map +1 -1
- package/dist/src/kernel/dispatch.js +18 -7
- package/dist/src/kernel/dispatch.js.map +1 -1
- package/dist/src/kernel/kernel.d.ts +30 -1
- package/dist/src/kernel/kernel.d.ts.map +1 -1
- package/dist/src/kernel/kernel.js +49 -5
- package/dist/src/kernel/kernel.js.map +1 -1
- package/dist/src/kernel/prelude.d.ts.map +1 -1
- package/dist/src/kernel/prelude.js +6 -1
- package/dist/src/kernel/prelude.js.map +1 -1
- package/dist/src/kernel/profiler.d.ts +15 -3
- package/dist/src/kernel/profiler.d.ts.map +1 -1
- package/dist/src/kernel/profiler.js +27 -4
- package/dist/src/kernel/profiler.js.map +1 -1
- package/dist/src/kernels.d.ts +17 -7
- package/dist/src/kernels.d.ts.map +1 -1
- package/dist/src/kernels.js +323 -16
- package/dist/src/kernels.js.map +1 -1
- package/dist/src/layouts/calibrate.d.ts +51 -0
- package/dist/src/layouts/calibrate.d.ts.map +1 -0
- package/dist/src/layouts/calibrate.js +172 -0
- package/dist/src/layouts/calibrate.js.map +1 -0
- package/dist/src/layouts/force-simulation.d.ts +39 -4
- package/dist/src/layouts/force-simulation.d.ts.map +1 -1
- package/dist/src/layouts/force-simulation.js +71 -19
- package/dist/src/layouts/force-simulation.js.map +1 -1
- package/dist/src/layouts/forceatlas2.d.ts +107 -36
- package/dist/src/layouts/forceatlas2.d.ts.map +1 -1
- package/dist/src/layouts/forceatlas2.js +296 -100
- package/dist/src/layouts/forceatlas2.js.map +1 -1
- package/dist/src/layouts/fruchterman-reingold.d.ts +73 -27
- package/dist/src/layouts/fruchterman-reingold.d.ts.map +1 -1
- package/dist/src/layouts/fruchterman-reingold.js +230 -70
- package/dist/src/layouts/fruchterman-reingold.js.map +1 -1
- package/dist/src/layouts/model-common.d.ts +41 -3
- package/dist/src/layouts/model-common.d.ts.map +1 -1
- package/dist/src/layouts/model-common.js +74 -3
- package/dist/src/layouts/model-common.js.map +1 -1
- package/dist/src/layouts/repulsion-grid.d.ts +152 -0
- package/dist/src/layouts/repulsion-grid.d.ts.map +1 -0
- package/dist/src/layouts/repulsion-grid.js +318 -0
- package/dist/src/layouts/repulsion-grid.js.map +1 -0
- package/dist/src/layouts/spring-electrical.d.ts +75 -30
- package/dist/src/layouts/spring-electrical.d.ts.map +1 -1
- package/dist/src/layouts/spring-electrical.js +231 -74
- package/dist/src/layouts/spring-electrical.js.map +1 -1
- package/dist/src/memory/residency.d.ts +6 -2
- package/dist/src/memory/residency.d.ts.map +1 -1
- package/dist/src/memory/residency.js +84 -14
- package/dist/src/memory/residency.js.map +1 -1
- package/dist/src/primitives/core-shape.d.ts +38 -2
- package/dist/src/primitives/core-shape.d.ts.map +1 -1
- package/dist/src/primitives/core-shape.js +71 -3
- package/dist/src/primitives/core-shape.js.map +1 -1
- package/dist/src/primitives/grid-pyramid.d.ts +71 -0
- package/dist/src/primitives/grid-pyramid.d.ts.map +1 -0
- package/dist/src/primitives/grid-pyramid.js +143 -0
- package/dist/src/primitives/grid-pyramid.js.map +1 -0
- package/dist/src/primitives/grid.d.ts +118 -0
- package/dist/src/primitives/grid.d.ts.map +1 -0
- package/dist/src/primitives/grid.js +225 -0
- package/dist/src/primitives/grid.js.map +1 -0
- package/dist/src/primitives/histogram.d.ts +67 -0
- package/dist/src/primitives/histogram.d.ts.map +1 -0
- package/dist/src/primitives/histogram.js +190 -0
- package/dist/src/primitives/histogram.js.map +1 -0
- package/dist/src/primitives/radix-sort.d.ts +75 -0
- package/dist/src/primitives/radix-sort.d.ts.map +1 -0
- package/dist/src/primitives/radix-sort.js +168 -0
- package/dist/src/primitives/radix-sort.js.map +1 -0
- package/dist/src/primitives/scan.d.ts +44 -0
- package/dist/src/primitives/scan.d.ts.map +1 -0
- package/dist/src/primitives/scan.js +151 -0
- package/dist/src/primitives/scan.js.map +1 -0
- package/dist/src/primitives/segmented-reduce.d.ts +25 -17
- package/dist/src/primitives/segmented-reduce.d.ts.map +1 -1
- package/dist/src/primitives/segmented-reduce.js +166 -47
- package/dist/src/primitives/segmented-reduce.js.map +1 -1
- package/dist/src/primitives/spmv.d.ts +18 -14
- package/dist/src/primitives/spmv.d.ts.map +1 -1
- package/dist/src/primitives/spmv.js +94 -58
- package/dist/src/primitives/spmv.js.map +1 -1
- package/dist/src/primitives/verify.d.ts +49 -0
- package/dist/src/primitives/verify.d.ts.map +1 -0
- package/dist/src/primitives/verify.js +229 -0
- package/dist/src/primitives/verify.js.map +1 -0
- package/dist/src/types/context.d.ts +53 -0
- package/dist/src/types/context.d.ts.map +1 -1
- package/dist/src/types/layout.d.ts +20 -0
- package/dist/src/types/layout.d.ts.map +1 -1
- package/dist/src/wgsl/counting-scatter.wgsl.d.ts +8 -0
- package/dist/src/wgsl/counting-scatter.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/counting-scatter.wgsl.js +17 -0
- package/dist/src/wgsl/counting-scatter.wgsl.js.map +1 -0
- package/dist/src/wgsl/fa2-attraction.wgsl.d.ts +23 -11
- package/dist/src/wgsl/fa2-attraction.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-attraction.wgsl.js +98 -20
- package/dist/src/wgsl/fa2-attraction.wgsl.js.map +1 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts +6 -2
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.js +22 -1
- package/dist/src/wgsl/fa2-stats-finalize.wgsl.js.map +1 -1
- package/dist/src/wgsl/grid-cell-key.wgsl.d.ts +8 -0
- package/dist/src/wgsl/grid-cell-key.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-cell-key.wgsl.js +30 -0
- package/dist/src/wgsl/grid-cell-key.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts +8 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.js +29 -0
- package/dist/src/wgsl/grid-centroid-hub.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-centroid.wgsl.d.ts +8 -0
- package/dist/src/wgsl/grid-centroid.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-centroid.wgsl.js +29 -0
- package/dist/src/wgsl/grid-centroid.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-downsample.wgsl.d.ts +7 -0
- package/dist/src/wgsl/grid-downsample.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-downsample.wgsl.js +28 -0
- package/dist/src/wgsl/grid-downsample.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-far-field.wgsl.d.ts +13 -0
- package/dist/src/wgsl/grid-far-field.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-far-field.wgsl.js +98 -0
- package/dist/src/wgsl/grid-far-field.wgsl.js.map +1 -0
- package/dist/src/wgsl/grid-near-field.wgsl.d.ts +19 -0
- package/dist/src/wgsl/grid-near-field.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/grid-near-field.wgsl.js +129 -0
- package/dist/src/wgsl/grid-near-field.wgsl.js.map +1 -0
- package/dist/src/wgsl/histogram.wgsl.d.ts +7 -0
- package/dist/src/wgsl/histogram.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/histogram.wgsl.js +15 -0
- package/dist/src/wgsl/histogram.wgsl.js.map +1 -0
- package/dist/src/wgsl/indirect-finalize.wgsl.d.ts +8 -0
- package/dist/src/wgsl/indirect-finalize.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/indirect-finalize.wgsl.js +26 -0
- package/dist/src/wgsl/indirect-finalize.wgsl.js.map +1 -0
- package/dist/src/wgsl/radix-hist.wgsl.d.ts +9 -0
- package/dist/src/wgsl/radix-hist.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/radix-hist.wgsl.js +31 -0
- package/dist/src/wgsl/radix-hist.wgsl.js.map +1 -0
- package/dist/src/wgsl/radix-scatter.wgsl.d.ts +9 -0
- package/dist/src/wgsl/radix-scatter.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/radix-scatter.wgsl.js +40 -0
- package/dist/src/wgsl/radix-scatter.wgsl.js.map +1 -0
- package/dist/src/wgsl/scan-add.wgsl.d.ts +6 -0
- package/dist/src/wgsl/scan-add.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/scan-add.wgsl.js +14 -0
- package/dist/src/wgsl/scan-add.wgsl.js.map +1 -0
- package/dist/src/wgsl/scan-block.wgsl.d.ts +8 -0
- package/dist/src/wgsl/scan-block.wgsl.d.ts.map +1 -0
- package/dist/src/wgsl/scan-block.wgsl.js +30 -0
- package/dist/src/wgsl/scan-block.wgsl.js.map +1 -0
- package/dist/src/wgsl/segmented-reduce.wgsl.d.ts +22 -8
- package/dist/src/wgsl/segmented-reduce.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/segmented-reduce.wgsl.js +84 -15
- package/dist/src/wgsl/segmented-reduce.wgsl.js.map +1 -1
- package/dist/src/wgsl/spmv-pull.wgsl.d.ts +22 -11
- package/dist/src/wgsl/spmv-pull.wgsl.d.ts.map +1 -1
- package/dist/src/wgsl/spmv-pull.wgsl.js +110 -36
- package/dist/src/wgsl/spmv-pull.wgsl.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/dist/webgpu-graph-algorithms.js +3815 -1003
- package/dist/webgpu-graph-algorithms.js.map +1 -1
- package/package.json +9 -8
- package/src/algorithms/components.ts +12 -16
- package/src/algorithms/degree.ts +58 -43
- package/src/algorithms/pagerank.ts +20 -18
- package/src/algorithms/power-iteration.ts +19 -18
- package/src/constants.ts +38 -8
- package/src/errors.ts +3 -1
- package/src/index.ts +14 -4
- package/src/kernel/dispatch.ts +18 -7
- package/src/kernel/kernel.ts +59 -5
- package/src/kernel/prelude.ts +9 -0
- package/src/kernel/profiler.ts +28 -4
- package/src/kernels.ts +356 -18
- package/src/layouts/calibrate.ts +187 -0
- package/src/layouts/force-simulation.ts +91 -23
- package/src/layouts/forceatlas2.ts +331 -106
- package/src/layouts/fruchterman-reingold.ts +255 -74
- package/src/layouts/model-common.ts +98 -3
- package/src/layouts/repulsion-grid.ts +451 -0
- package/src/layouts/spring-electrical.ts +257 -78
- package/src/memory/residency.ts +126 -20
- package/src/primitives/core-shape.ts +91 -4
- package/src/primitives/grid-pyramid.ts +221 -0
- package/src/primitives/grid.ts +349 -0
- package/src/primitives/histogram.ts +273 -0
- package/src/primitives/radix-sort.ts +246 -0
- package/src/primitives/scan.ts +197 -0
- package/src/primitives/segmented-reduce.ts +214 -56
- package/src/primitives/spmv.ts +125 -65
- package/src/primitives/verify.ts +249 -0
- package/src/types/context.ts +56 -0
- package/src/types/layout.ts +22 -0
- package/src/wgsl/counting-scatter.wgsl.ts +16 -0
- package/src/wgsl/fa2-attraction.wgsl.ts +98 -20
- package/src/wgsl/fa2-stats-finalize.wgsl.ts +22 -1
- package/src/wgsl/grid-cell-key.wgsl.ts +29 -0
- package/src/wgsl/grid-centroid-hub.wgsl.ts +28 -0
- package/src/wgsl/grid-centroid.wgsl.ts +28 -0
- package/src/wgsl/grid-downsample.wgsl.ts +27 -0
- package/src/wgsl/grid-far-field.wgsl.ts +97 -0
- package/src/wgsl/grid-near-field.wgsl.ts +128 -0
- package/src/wgsl/histogram.wgsl.ts +14 -0
- package/src/wgsl/indirect-finalize.wgsl.ts +25 -0
- package/src/wgsl/radix-hist.wgsl.ts +30 -0
- package/src/wgsl/radix-scatter.wgsl.ts +39 -0
- package/src/wgsl/scan-add.wgsl.ts +13 -0
- package/src/wgsl/scan-block.wgsl.ts +29 -0
- package/src/wgsl/segmented-reduce.wgsl.ts +84 -15
- package/src/wgsl/spmv-pull.wgsl.ts +110 -36
- package/dist/chunks/context-BR7fx3vR.js.map +0 -1
package/src/kernel/kernel.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Kernel (spec 5.1; contract 3.9): a compiled pipeline bound to the binding list of its spec. `bind()` creates the
|
|
3
3
|
* bind groups from a `Record<name, Binding>` keyed by the declared names and caches them by the identity of the
|
|
4
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)
|
|
5
|
+
* records setPipeline / setBindGroup / dispatchWorkgroups and skips an empty plan (spec 5.6); `dispatchIndirect()`
|
|
6
|
+
* (P4, spec 5.4) records the same prefix and a dispatchWorkgroupsIndirect over one 16-byte slot of an args buffer.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
9
|
import { STORAGE_ALIGN } from "../constants.js";
|
|
@@ -21,6 +22,9 @@ export interface BoundKernel {
|
|
|
21
22
|
readonly dynamicGroups: readonly number[];
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
/** Bytes of one indirect args slot: (x, y, 1, count) as four u32 (spec 5.4; P4 PD-2). */
|
|
26
|
+
export const INDIRECT_ARGS_STRIDE = 16;
|
|
27
|
+
|
|
24
28
|
/** Buffer identities for the bind-group cache key: every GPUBuffer seen by any Kernel gets one number, once. */
|
|
25
29
|
const bufferIds = new WeakMap<GPUBuffer, number>();
|
|
26
30
|
let nextBufferId = 1;
|
|
@@ -259,6 +263,50 @@ export class Kernel {
|
|
|
259
263
|
plan: DispatchPlan,
|
|
260
264
|
dynamicOffsets?: readonly number[],
|
|
261
265
|
): void {
|
|
266
|
+
this.check(bound, dynamicOffsets);
|
|
267
|
+
if (plan.x === 0) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
this.setUp(pass, bound, dynamicOffsets);
|
|
271
|
+
pass.dispatchWorkgroups(plan.x, plan.y, 1);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* setPipeline + the bind groups exactly as dispatch(), then dispatchWorkgroupsIndirect(args.buffer, args.offset +
|
|
276
|
+
* INDIRECT_ARGS_STRIDE * slot) (spec 5.4): the (x, y, 1) of the slot were written by the indirect-finalize kernel
|
|
277
|
+
* earlier in the same pass. A slot beyond the binding is E_INVALID_ARGUMENT.
|
|
278
|
+
* @param pass - the open compute pass
|
|
279
|
+
* @param bound - a BoundKernel of THIS kernel
|
|
280
|
+
* @param args - the args buffer range (usage INDIRECT | STORAGE)
|
|
281
|
+
* @param slot - the 16-byte slot index inside the range
|
|
282
|
+
* @param dynamicOffsets - one byte offset per entry of bound.dynamicGroups
|
|
283
|
+
*/
|
|
284
|
+
dispatchIndirect(
|
|
285
|
+
pass: GPUComputePassEncoder,
|
|
286
|
+
bound: BoundKernel,
|
|
287
|
+
args: Binding,
|
|
288
|
+
slot: number,
|
|
289
|
+
dynamicOffsets?: readonly number[],
|
|
290
|
+
): void {
|
|
291
|
+
this.check(bound, dynamicOffsets);
|
|
292
|
+
if (!Number.isInteger(slot) || slot < 0 || (slot + 1) * INDIRECT_ARGS_STRIDE > args.size) {
|
|
293
|
+
throw new WebGpuGraphError("E_INVALID_ARGUMENT", `${this.spec.id}: args slot ${slot} is outside the binding`, {
|
|
294
|
+
argument: "slot",
|
|
295
|
+
value: slot,
|
|
296
|
+
expected: `0 <= slot < ${Math.floor(args.size / INDIRECT_ARGS_STRIDE)}`,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
this.setUp(pass, bound, dynamicOffsets);
|
|
300
|
+
pass.dispatchWorkgroupsIndirect(args.buffer, args.offset + INDIRECT_ARGS_STRIDE * slot);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* The argument checks dispatch() and dispatchIndirect() share: a BoundKernel of another kernel or an offset list
|
|
305
|
+
* of the wrong length is E_INVALID_ARGUMENT.
|
|
306
|
+
* @param bound - the bound kernel
|
|
307
|
+
* @param dynamicOffsets - the offsets, if any
|
|
308
|
+
*/
|
|
309
|
+
private check(bound: BoundKernel, dynamicOffsets: readonly number[] | undefined): void {
|
|
262
310
|
const { id } = this.spec;
|
|
263
311
|
if (bound.kernel !== this) {
|
|
264
312
|
throw new WebGpuGraphError(
|
|
@@ -282,9 +330,16 @@ export class Kernel {
|
|
|
282
330
|
},
|
|
283
331
|
);
|
|
284
332
|
}
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* setPipeline + setBindGroup for every group (the dynamic offsets replicated over the uniform bindings of each
|
|
337
|
+
* dynamic group), the prefix dispatch() and dispatchIndirect() share.
|
|
338
|
+
* @param pass - the open compute pass
|
|
339
|
+
* @param bound - a BoundKernel of this kernel
|
|
340
|
+
* @param dynamicOffsets - one byte offset per entry of bound.dynamicGroups (absent = 0)
|
|
341
|
+
*/
|
|
342
|
+
private setUp(pass: GPUComputePassEncoder, bound: BoundKernel, dynamicOffsets: readonly number[] | undefined): void {
|
|
288
343
|
pass.setPipeline(this.pipeline);
|
|
289
344
|
let next = 0;
|
|
290
345
|
bound.bindGroups.forEach((bindGroup, group) => {
|
|
@@ -301,7 +356,6 @@ export class Kernel {
|
|
|
301
356
|
pass.setBindGroup(group, bindGroup);
|
|
302
357
|
}
|
|
303
358
|
});
|
|
304
|
-
pass.dispatchWorkgroups(plan.x, plan.y, 1);
|
|
305
359
|
}
|
|
306
360
|
|
|
307
361
|
/** Drops cached bind groups (a layout's buffers changed). */
|
package/src/kernel/prelude.ts
CHANGED
|
@@ -19,7 +19,11 @@ import {
|
|
|
19
19
|
FA2_FLAG_FIRST,
|
|
20
20
|
FR_COOLING_PATIENCE,
|
|
21
21
|
FR_COOLING_STEP,
|
|
22
|
+
GRID_BBOX_MARGIN,
|
|
23
|
+
GRID_EXTENT_FLOOR,
|
|
24
|
+
GRID_HUB_CELL,
|
|
22
25
|
MAX_WORKGROUPS_PER_DIM,
|
|
26
|
+
RADIX_BINS,
|
|
23
27
|
U32_MAX,
|
|
24
28
|
WORKGROUP_SIZE,
|
|
25
29
|
} from "../constants.js";
|
|
@@ -55,6 +59,11 @@ const FA2_FLAG_FIRST: u32 = ${FA2_FLAG_FIRST}u;
|
|
|
55
59
|
const FA2_FLAG_ADAPTIVE: u32 = ${FA2_FLAG_ADAPTIVE}u;
|
|
56
60
|
const FR_COOLING_STEP: f32 = ${wgslF32Literal(FR_COOLING_STEP)};
|
|
57
61
|
const FR_COOLING_PATIENCE: u32 = ${FR_COOLING_PATIENCE}u;
|
|
62
|
+
const GRID_HUB_CELL: u32 = ${GRID_HUB_CELL}u;
|
|
63
|
+
const GRID_EXTENT_FLOOR: f32 = ${wgslF32Literal(GRID_EXTENT_FLOOR)};
|
|
64
|
+
const GRID_BBOX_MARGIN: f32 = ${wgslF32Literal(GRID_BBOX_MARGIN)};
|
|
65
|
+
const RADIX_BINS: u32 = ${RADIX_BINS}u;
|
|
66
|
+
const RADIX_DIGIT_MASK: u32 = ${RADIX_BINS - 1}u;
|
|
58
67
|
const F32_MAX: f32 = 0x1.fffffep+127;
|
|
59
68
|
override WG: u32 = ${WORKGROUP_SIZE}u;
|
|
60
69
|
override USE_PERM: bool = false;
|
package/src/kernel/profiler.ts
CHANGED
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
* every CommandBatch pass; `resolveInto(batch)` records the resolve plus a copy into the batch's
|
|
5
5
|
* staging slot and `timings(bytes, request)` decodes `{ label, ns }` per pass from the batch's
|
|
6
6
|
* readback bytes. Chromium quantises timestamps to 100 us (`quantised: true`); Dawn-node reports
|
|
7
|
-
* 1,024 ns ticks (spec 2.6). The profiler never throws: a full query set drops timings
|
|
8
|
-
*
|
|
7
|
+
* 1,024 ns ticks (spec 2.6). The profiler never throws: a full query set drops the timings of the
|
|
8
|
+
* passes past the budget and marks the batch's request `partial(request)` so a caller summing the
|
|
9
|
+
* rows into a duration falls back to wall time; a device without the feature disables it. Slot
|
|
10
|
+
* pairs are handed out in order and the cursor restarts at 0
|
|
9
11
|
* after every resolve: queue order guarantees the resolve of batch A reads its slots before batch B
|
|
10
12
|
* overwrites them, and one resolve buffer suffices for the same reason.
|
|
11
13
|
*/
|
|
@@ -36,8 +38,10 @@ export class Profiler {
|
|
|
36
38
|
private readonly querySet: GPUQuerySet | null;
|
|
37
39
|
private readonly resolveBuffer: GPUBuffer | null;
|
|
38
40
|
private readonly labels = new WeakMap<ReadbackRequest, readonly string[]>();
|
|
41
|
+
private readonly partialRequests = new WeakSet<ReadbackRequest>();
|
|
39
42
|
private pending: PendingPass[] = [];
|
|
40
43
|
private cursor = 0;
|
|
44
|
+
private refused = 0;
|
|
41
45
|
private destroyed = false;
|
|
42
46
|
|
|
43
47
|
/**
|
|
@@ -69,12 +73,17 @@ export class Profiler {
|
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
/**
|
|
72
|
-
* The timestampWrites descriptor for a new pass, or undefined when disabled / out of slots.
|
|
76
|
+
* The timestampWrites descriptor for a new pass, or undefined when disabled / out of slots. A pass refused for
|
|
77
|
+
* want of slots is counted, and the next `resolveInto()` marks its request partial.
|
|
73
78
|
* @param label - the pass name reported by `timings()`
|
|
74
79
|
* @returns the descriptor a CommandBatch puts on beginComputePass, or undefined
|
|
75
80
|
*/
|
|
76
81
|
beginPass(label: string): GPUComputePassTimestampWrites | undefined {
|
|
77
|
-
if (this.querySet === null || this.destroyed
|
|
82
|
+
if (this.querySet === null || this.destroyed) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
if (this.cursor + 2 > this.slots) {
|
|
86
|
+
this.refused++;
|
|
78
87
|
return undefined;
|
|
79
88
|
}
|
|
80
89
|
const begin = this.cursor;
|
|
@@ -100,11 +109,25 @@ export class Profiler {
|
|
|
100
109
|
request,
|
|
101
110
|
this.pending.map((pass) => pass.label),
|
|
102
111
|
);
|
|
112
|
+
if (this.refused > 0) {
|
|
113
|
+
this.partialRequests.add(request);
|
|
114
|
+
}
|
|
103
115
|
this.pending = [];
|
|
104
116
|
this.cursor = 0;
|
|
117
|
+
this.refused = 0;
|
|
105
118
|
return request;
|
|
106
119
|
}
|
|
107
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Whether a pass of the batch was refused a slot pair, so `timings()` covers only its first slots / 2 passes
|
|
123
|
+
* and their sum is not the batch's duration.
|
|
124
|
+
* @param request - the request `resolveInto()` returned
|
|
125
|
+
* @returns true when at least one pass of that batch went untimed
|
|
126
|
+
*/
|
|
127
|
+
partial(request: ReadbackRequest): boolean {
|
|
128
|
+
return this.partialRequests.has(request);
|
|
129
|
+
}
|
|
130
|
+
|
|
108
131
|
/**
|
|
109
132
|
* Decodes the timings of a batch from its readback bytes.
|
|
110
133
|
* @param bytes - the resolved readback of the batch
|
|
@@ -138,6 +161,7 @@ export class Profiler {
|
|
|
138
161
|
this.destroyed = true;
|
|
139
162
|
this.pending = [];
|
|
140
163
|
this.cursor = 0;
|
|
164
|
+
this.refused = 0;
|
|
141
165
|
if (this.querySet !== null) {
|
|
142
166
|
this.querySet.destroy();
|
|
143
167
|
}
|