@graphty/webgpu-graph-algorithms 0.6.8 → 0.6.10
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 +104 -53
- package/dist/browser.js +1 -1
- package/dist/chunks/{context-Cezi7qpi.js → context-Bi6AhScG.js} +16 -6
- package/dist/chunks/context-Bi6AhScG.js.map +1 -0
- package/dist/node.js +1 -1
- package/dist/src/kernel/kernel.d.ts +10 -1
- package/dist/src/kernel/kernel.d.ts.map +1 -1
- package/dist/src/kernel/kernel.js +16 -1
- package/dist/src/kernel/kernel.js.map +1 -1
- package/dist/webgpu-graph-algorithms.js +2 -2
- package/package.json +12 -9
- package/src/kernel/kernel.ts +31 -7
- package/dist/chunks/context-Cezi7qpi.js.map +0 -1
package/dist/node.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { W as WebGpuGraphError, G as GpuContext } from "./chunks/context-
|
|
1
|
+
import { W as WebGpuGraphError, G as GpuContext } from "./chunks/context-Bi6AhScG.js";
|
|
2
2
|
const INSTALL_HINT = "install the optional peer dependency webgpu@0.4.0";
|
|
3
3
|
const instances = /* @__PURE__ */ new Map();
|
|
4
4
|
function isDawnModule(loaded) {
|
|
@@ -19,6 +19,15 @@ export interface BoundKernel {
|
|
|
19
19
|
}
|
|
20
20
|
/** Bytes of one indirect args slot: (x, y, 1, count) as four u32 (spec 5.4; P4 PD-2). */
|
|
21
21
|
export declare const INDIRECT_ARGS_STRIDE = 16;
|
|
22
|
+
/**
|
|
23
|
+
* The most buffer sets one Kernel keeps bind groups for; binding one more forgets the least recently bound. A
|
|
24
|
+
* Kernel lives as long as its context (the PipelineCache holds it), so an unbounded cache kept the bind groups --
|
|
25
|
+
* and, on Dawn, the native memory behind them -- of every simulation and scratch lease ever bound, disposed or not
|
|
26
|
+
* (issue #162). A caller keeps the BoundKernel it was given, so eviction only costs a later bind() of the same
|
|
27
|
+
* buffers a new createBindGroup. One simulation binds at most a dozen sets per kernel (the scan's levels).
|
|
28
|
+
* ponytail: a count bound, not a lifetime one; a per-buffer destroy hook would free a set as soon as its buffer goes.
|
|
29
|
+
*/
|
|
30
|
+
export declare const BIND_GROUP_CACHE_LIMIT = 32;
|
|
22
31
|
/** A compiled pipeline plus the binding list of its spec (spec 5.1). */
|
|
23
32
|
export declare class Kernel {
|
|
24
33
|
/** The module spec the pipeline was compiled from (its bindings drive bind()). */
|
|
@@ -36,7 +45,7 @@ export declare class Kernel {
|
|
|
36
45
|
private readonly groups;
|
|
37
46
|
/** The uniform-binding count of each group (the dynamic offsets a setBindGroup takes). */
|
|
38
47
|
private readonly dynamicCounts;
|
|
39
|
-
/** Cached bind groups by buffer identity + offset + size. */
|
|
48
|
+
/** Cached bind groups by buffer identity + offset + size, least recently bound first (at most BIND_GROUP_CACHE_LIMIT). */
|
|
40
49
|
private readonly cache;
|
|
41
50
|
/**
|
|
42
51
|
* Wraps a compiled pipeline.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../../../src/kernel/kernel.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;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;AAED,yFAAyF;AACzF,eAAO,MAAM,oBAAoB,KAAK,CAAC;AA+
|
|
1
|
+
{"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../../../src/kernel/kernel.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;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;AAED,yFAAyF;AACzF,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,KAAK,CAAC;AA+BzC,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,0HAA0H;IAC1H,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;IA6H5C;;;;;;;;;;;;OAYG;IACH,QAAQ,CACJ,IAAI,EAAE,qBAAqB,EAC3B,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,YAAY,EAClB,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,GACnC,IAAI;IASP;;;;;;;;;OASG;IACH,gBAAgB,CACZ,IAAI,EAAE,qBAAqB,EAC3B,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,MAAM,EACZ,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,GACnC,IAAI;IAiBP;;;;;OAKG;IACH,OAAO,CAAC,KAAK;IA0Bb;;;;;;OAMG;IACH,OAAO,CAAC,KAAK;IAuBb,6DAA6D;IAC7D,UAAU,IAAI,IAAI;CAGrB"}
|
|
@@ -9,6 +9,15 @@ import { STORAGE_ALIGN } from "../constants.js";
|
|
|
9
9
|
import { WebGpuGraphError } from "../errors.js";
|
|
10
10
|
/** Bytes of one indirect args slot: (x, y, 1, count) as four u32 (spec 5.4; P4 PD-2). */
|
|
11
11
|
export const INDIRECT_ARGS_STRIDE = 16;
|
|
12
|
+
/**
|
|
13
|
+
* The most buffer sets one Kernel keeps bind groups for; binding one more forgets the least recently bound. A
|
|
14
|
+
* Kernel lives as long as its context (the PipelineCache holds it), so an unbounded cache kept the bind groups --
|
|
15
|
+
* and, on Dawn, the native memory behind them -- of every simulation and scratch lease ever bound, disposed or not
|
|
16
|
+
* (issue #162). A caller keeps the BoundKernel it was given, so eviction only costs a later bind() of the same
|
|
17
|
+
* buffers a new createBindGroup. One simulation binds at most a dozen sets per kernel (the scan's levels).
|
|
18
|
+
* ponytail: a count bound, not a lifetime one; a per-buffer destroy hook would free a set as soon as its buffer goes.
|
|
19
|
+
*/
|
|
20
|
+
export const BIND_GROUP_CACHE_LIMIT = 32;
|
|
12
21
|
/** Buffer identities for the bind-group cache key: every GPUBuffer seen by any Kernel gets one number, once. */
|
|
13
22
|
const bufferIds = new WeakMap();
|
|
14
23
|
let nextBufferId = 1;
|
|
@@ -46,7 +55,7 @@ export class Kernel {
|
|
|
46
55
|
* @param layouts - the explicit bind-group layouts, one per group 0..maxGroup
|
|
47
56
|
*/
|
|
48
57
|
constructor(device, spec, composed, pipeline, layouts) {
|
|
49
|
-
/** Cached bind groups by buffer identity + offset + size. */
|
|
58
|
+
/** Cached bind groups by buffer identity + offset + size, least recently bound first (at most BIND_GROUP_CACHE_LIMIT). */
|
|
50
59
|
this.cache = new Map();
|
|
51
60
|
this.device = device;
|
|
52
61
|
this.spec = spec;
|
|
@@ -155,6 +164,9 @@ export class Kernel {
|
|
|
155
164
|
.join("|");
|
|
156
165
|
const cached = this.cache.get(key);
|
|
157
166
|
if (cached !== undefined) {
|
|
167
|
+
// re-insert: the Map's insertion order is the recency order the eviction below reads
|
|
168
|
+
this.cache.delete(key);
|
|
169
|
+
this.cache.set(key, cached);
|
|
158
170
|
return cached;
|
|
159
171
|
}
|
|
160
172
|
const byName = new Map(resolved.map(({ decl, binding }) => [decl.name, binding]));
|
|
@@ -181,6 +193,9 @@ export class Kernel {
|
|
|
181
193
|
dynamicGroups: Object.freeze(dynamicGroups),
|
|
182
194
|
});
|
|
183
195
|
this.cache.set(key, bound);
|
|
196
|
+
if (this.cache.size > BIND_GROUP_CACHE_LIMIT) {
|
|
197
|
+
this.cache.delete(this.cache.keys().next().value);
|
|
198
|
+
}
|
|
184
199
|
return bound;
|
|
185
200
|
}
|
|
186
201
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kernel.js","sourceRoot":"","sources":["../../../src/kernel/kernel.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAehD,yFAAyF;AACzF,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEvC,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,
|
|
1
|
+
{"version":3,"file":"kernel.js","sourceRoot":"","sources":["../../../src/kernel/kernel.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { W as WebGpuGraphError, U as UNIFORM_SLOT_BYTES, B as BufferUsage, M as MAX_WORKGROUPS_PER_DIM, a as WGSL_RESERVED_WORDS, S as STATE_HEADER_BYTES, d as deviceLostError, i as isWebGpuGraphError, b as U32_MAX$2, c as MAX_LEVELS_PER_SUBMIT, R as RADIX_BINS, F as FUSED_FRONTIER_MAX, e as BEAMER_BETA, f as SSSP_DELTA_FACTOR, g as F32_INF_BITS, h as GRID_COARSEST_SIDE, j as GRID_MIN_SIDE, k as GRID_SORT_BITS, l as FA2_DEFAULTS, m as MAX_ITERATIONS_PER_STEP, n as MAX_1D_ITEMS, o as hasErrorCode, p as FA2_FLAG_FIRST, P as PARTIAL_BYTES, E as EXACT_TILES_PER_PASS, I as INDIRECT_ARGS_STRIDE, q as GRID_HUB_CELL, L as LAYOUT_TUNING_DEFAULTS, r as EXACT_MAX_NODES, s as SETTLE_FLOOR_UNBOUNDED, T as TRACE_RECORD_BYTES, t as GRID_BBOX_MARGIN, u as GRID_EXTENT_FLOOR, v as FR_ADAPTIVE_MAX_ITERATIONS, w as FR_START_TEMPERATURE, x as FA2_FLAG_ADAPTIVE, y as SETTLE_FLOOR_FRACTION, z as FR_REHEAT_FRACTION, A as FR_DEFAULTS, C as SE_DEFAULTS, D as SETTLE_FLOOR_REFERENCE_NODES, H as SE_SCALE_REFERENCE_NODES } from "./chunks/context-
|
|
2
|
-
import { J, G, K, N, O, Q } from "./chunks/context-
|
|
1
|
+
import { W as WebGpuGraphError, U as UNIFORM_SLOT_BYTES, B as BufferUsage, M as MAX_WORKGROUPS_PER_DIM, a as WGSL_RESERVED_WORDS, S as STATE_HEADER_BYTES, d as deviceLostError, i as isWebGpuGraphError, b as U32_MAX$2, c as MAX_LEVELS_PER_SUBMIT, R as RADIX_BINS, F as FUSED_FRONTIER_MAX, e as BEAMER_BETA, f as SSSP_DELTA_FACTOR, g as F32_INF_BITS, h as GRID_COARSEST_SIDE, j as GRID_MIN_SIDE, k as GRID_SORT_BITS, l as FA2_DEFAULTS, m as MAX_ITERATIONS_PER_STEP, n as MAX_1D_ITEMS, o as hasErrorCode, p as FA2_FLAG_FIRST, P as PARTIAL_BYTES, E as EXACT_TILES_PER_PASS, I as INDIRECT_ARGS_STRIDE, q as GRID_HUB_CELL, L as LAYOUT_TUNING_DEFAULTS, r as EXACT_MAX_NODES, s as SETTLE_FLOOR_UNBOUNDED, T as TRACE_RECORD_BYTES, t as GRID_BBOX_MARGIN, u as GRID_EXTENT_FLOOR, v as FR_ADAPTIVE_MAX_ITERATIONS, w as FR_START_TEMPERATURE, x as FA2_FLAG_ADAPTIVE, y as SETTLE_FLOOR_FRACTION, z as FR_REHEAT_FRACTION, A as FR_DEFAULTS, C as SE_DEFAULTS, D as SETTLE_FLOOR_REFERENCE_NODES, H as SE_SCALE_REFERENCE_NODES } from "./chunks/context-Bi6AhScG.js";
|
|
2
|
+
import { J, G, K, N, O, Q } from "./chunks/context-Bi6AhScG.js";
|
|
3
3
|
import { renumberPartition, INVALID_INDEX, makeMask, maskTest, expandEdges, fromEdgeArrays } from "@graphty/graph-format";
|
|
4
4
|
class UniformRing {
|
|
5
5
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphty/webgpu-graph-algorithms",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.10",
|
|
4
4
|
"description": "WebGPU-accelerated graph algorithms and layouts over the @graphty/graph-format snapshot, for Node (Dawn) and browsers",
|
|
5
5
|
"author": "Adam Powers <apowers@ato.ms>",
|
|
6
6
|
"type": "module",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"homepage": "https://github.com/graphty-org/graphty-monorepo/tree/master/webgpu-graph-algorithms#readme",
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@webgpu/types": "^0.1.72",
|
|
64
|
-
"@graphty/graph-format": "^1.0
|
|
64
|
+
"@graphty/graph-format": "^1.1.0"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"@graphty/algorithms": "^1.0.0 || ^2.0.0",
|
|
@@ -81,23 +81,25 @@
|
|
|
81
81
|
}
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
|
-
"@vitest/browser": "
|
|
85
|
-
"@vitest/coverage-v8": "
|
|
86
|
-
"@vitest/ui": "
|
|
84
|
+
"@vitest/browser-playwright": "4.1.11",
|
|
85
|
+
"@vitest/coverage-v8": "4.1.11",
|
|
86
|
+
"@vitest/ui": "4.1.11",
|
|
87
|
+
"eslint": "^9.29.0",
|
|
87
88
|
"fast-check": "^4.2.0",
|
|
88
89
|
"ngraph.forcelayout": "^3.3.1",
|
|
89
90
|
"ngraph.graph": "^20.0.1",
|
|
90
91
|
"playwright": "^1.54.1",
|
|
91
92
|
"tsx": "^4.20.3",
|
|
92
93
|
"typescript": "^5.9.3",
|
|
94
|
+
"typescript-eslint": "^8.34.1",
|
|
93
95
|
"vite": "^7.0.5",
|
|
94
|
-
"vitest": "
|
|
96
|
+
"vitest": "4.1.11",
|
|
95
97
|
"webgpu": "0.4.0",
|
|
96
|
-
"@graphty/
|
|
97
|
-
"@graphty/
|
|
98
|
+
"@graphty/algorithms": "^2.1.0",
|
|
99
|
+
"@graphty/layout": "^1.10.3"
|
|
98
100
|
},
|
|
99
101
|
"scripts": {
|
|
100
|
-
"build": "tsc -p tsconfig.build.json",
|
|
102
|
+
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json",
|
|
101
103
|
"build:bundle": "node scripts/build-bundle.js",
|
|
102
104
|
"build:all": "npm run build && npm run build:bundle",
|
|
103
105
|
"lint": "eslint && tsc --noEmit -p tsconfig.json && tsc -p tsconfig.strict-consumer.json",
|
|
@@ -118,6 +120,7 @@
|
|
|
118
120
|
"bench:ab": "node scripts/bench-ab.js",
|
|
119
121
|
"bench:compare": "node scripts/bench-compare.js",
|
|
120
122
|
"bench:append": "node scripts/bench-append-session.js",
|
|
123
|
+
"bench:readme": "node scripts/bench-readme-tables.js",
|
|
121
124
|
"benchmark": "tsx benchmarks/run.ts",
|
|
122
125
|
"gpu:report": "node scripts/gpu-report.js",
|
|
123
126
|
"ready:commit": "npm run build:all && npm run lint && npm run test:node"
|
package/src/kernel/kernel.ts
CHANGED
|
@@ -25,6 +25,16 @@ export interface BoundKernel {
|
|
|
25
25
|
/** Bytes of one indirect args slot: (x, y, 1, count) as four u32 (spec 5.4; P4 PD-2). */
|
|
26
26
|
export const INDIRECT_ARGS_STRIDE = 16;
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* The most buffer sets one Kernel keeps bind groups for; binding one more forgets the least recently bound. A
|
|
30
|
+
* Kernel lives as long as its context (the PipelineCache holds it), so an unbounded cache kept the bind groups --
|
|
31
|
+
* and, on Dawn, the native memory behind them -- of every simulation and scratch lease ever bound, disposed or not
|
|
32
|
+
* (issue #162). A caller keeps the BoundKernel it was given, so eviction only costs a later bind() of the same
|
|
33
|
+
* buffers a new createBindGroup. One simulation binds at most a dozen sets per kernel (the scan's levels).
|
|
34
|
+
* ponytail: a count bound, not a lifetime one; a per-buffer destroy hook would free a set as soon as its buffer goes.
|
|
35
|
+
*/
|
|
36
|
+
export const BIND_GROUP_CACHE_LIMIT = 32;
|
|
37
|
+
|
|
28
38
|
/** Buffer identities for the bind-group cache key: every GPUBuffer seen by any Kernel gets one number, once. */
|
|
29
39
|
const bufferIds = new WeakMap<GPUBuffer, number>();
|
|
30
40
|
let nextBufferId = 1;
|
|
@@ -71,7 +81,7 @@ export class Kernel {
|
|
|
71
81
|
private readonly groups: readonly (readonly BindingDecl[])[];
|
|
72
82
|
/** The uniform-binding count of each group (the dynamic offsets a setBindGroup takes). */
|
|
73
83
|
private readonly dynamicCounts: readonly number[];
|
|
74
|
-
/** Cached bind groups by buffer identity + offset + size. */
|
|
84
|
+
/** Cached bind groups by buffer identity + offset + size, least recently bound first (at most BIND_GROUP_CACHE_LIMIT). */
|
|
75
85
|
private readonly cache = new Map<string, BoundKernel>();
|
|
76
86
|
|
|
77
87
|
/**
|
|
@@ -213,6 +223,9 @@ export class Kernel {
|
|
|
213
223
|
.join("|");
|
|
214
224
|
const cached = this.cache.get(key);
|
|
215
225
|
if (cached !== undefined) {
|
|
226
|
+
// re-insert: the Map's insertion order is the recency order the eviction below reads
|
|
227
|
+
this.cache.delete(key);
|
|
228
|
+
this.cache.set(key, cached);
|
|
216
229
|
return cached;
|
|
217
230
|
}
|
|
218
231
|
const byName = new Map(resolved.map(({ decl, binding }) => [decl.name, binding] as const));
|
|
@@ -241,6 +254,9 @@ export class Kernel {
|
|
|
241
254
|
dynamicGroups: Object.freeze(dynamicGroups),
|
|
242
255
|
});
|
|
243
256
|
this.cache.set(key, bound);
|
|
257
|
+
if (this.cache.size > BIND_GROUP_CACHE_LIMIT) {
|
|
258
|
+
this.cache.delete(this.cache.keys().next().value as string);
|
|
259
|
+
}
|
|
244
260
|
return bound;
|
|
245
261
|
}
|
|
246
262
|
|
|
@@ -290,11 +306,15 @@ export class Kernel {
|
|
|
290
306
|
): void {
|
|
291
307
|
this.check(bound, dynamicOffsets);
|
|
292
308
|
if (!Number.isInteger(slot) || slot < 0 || (slot + 1) * INDIRECT_ARGS_STRIDE > args.size) {
|
|
293
|
-
throw new WebGpuGraphError(
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
309
|
+
throw new WebGpuGraphError(
|
|
310
|
+
"E_INVALID_ARGUMENT",
|
|
311
|
+
`${this.spec.id}: args slot ${slot} is outside the binding`,
|
|
312
|
+
{
|
|
313
|
+
argument: "slot",
|
|
314
|
+
value: slot,
|
|
315
|
+
expected: `0 <= slot < ${Math.floor(args.size / INDIRECT_ARGS_STRIDE)}`,
|
|
316
|
+
},
|
|
317
|
+
);
|
|
298
318
|
}
|
|
299
319
|
this.setUp(pass, bound, dynamicOffsets);
|
|
300
320
|
pass.dispatchWorkgroupsIndirect(args.buffer, args.offset + INDIRECT_ARGS_STRIDE * slot);
|
|
@@ -339,7 +359,11 @@ export class Kernel {
|
|
|
339
359
|
* @param bound - a BoundKernel of this kernel
|
|
340
360
|
* @param dynamicOffsets - one byte offset per entry of bound.dynamicGroups (absent = 0)
|
|
341
361
|
*/
|
|
342
|
-
private setUp(
|
|
362
|
+
private setUp(
|
|
363
|
+
pass: GPUComputePassEncoder,
|
|
364
|
+
bound: BoundKernel,
|
|
365
|
+
dynamicOffsets: readonly number[] | undefined,
|
|
366
|
+
): void {
|
|
343
367
|
pass.setPipeline(this.pipeline);
|
|
344
368
|
let next = 0;
|
|
345
369
|
bound.bindGroups.forEach((bindGroup, group) => {
|