webgpu-computed 0.0.17 → 0.0.19

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webgpu-computed",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
4
4
  "description": "对webgpu的封装,处理了繁琐的前置工作,只关注wgsl本身逻辑",
5
5
  "main": "./src/index.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -40,28 +40,28 @@ function U(f) {
40
40
  const e = Object.keys(f), r = e.map((c) => {
41
41
  const l = f[c];
42
42
  if (Array.isArray(l)) {
43
- for (const d of ["vec2", "vec3", "vec4", "mat3x3", "mat4x4"])
44
- if ($[d] === l.length) return d;
43
+ for (const y of ["vec2", "vec3", "vec4", "mat3x3", "mat4x4"])
44
+ if ($[y] === l.length) return y;
45
45
  throw new Error(`${c} 不支持的数组长度 ${l.length}`);
46
46
  }
47
47
  if (typeof l == "number") return "f32";
48
48
  throw new Error(`${c} 不支持的类型`);
49
49
  });
50
50
  if (e.length !== r.length) throw new Error("keys 与 types 长度不一致");
51
- let s = 0;
51
+ let i = 0;
52
52
  const u = e.map((c, l) => {
53
- const d = r[l];
54
- s += _(s, d);
53
+ const y = r[l];
54
+ i += _(i, y);
55
55
  const a = {
56
56
  name: c,
57
- type: d,
58
- offset: s,
59
- size: $[d]
57
+ type: y,
58
+ offset: i,
59
+ size: $[y]
60
60
  };
61
- return s += $[d], a;
61
+ return i += $[y], a;
62
62
  }), t = Math.max(...r.map((c) => E[c]));
63
63
  return {
64
- stride: s + (t - s % t) % t,
64
+ stride: i + (t - i % t) % t,
65
65
  layout: u
66
66
  };
67
67
  }
@@ -107,16 +107,16 @@ class T {
107
107
  t.forEach((c) => {
108
108
  n += _(n, c.type), c.offset = n, c.size = $[c.type], n += c.size;
109
109
  });
110
- }, s = (t) => {
110
+ }, i = (t) => {
111
111
  r(t.layout);
112
112
  const n = t.layout[t.layout.length - 1], c = n.offset + n.size;
113
113
  let l = 1;
114
- for (const d of t.layout) l = Math.max(l, E[d.type]);
114
+ for (const y of t.layout) l = Math.max(l, E[y.type]);
115
115
  t.stride = P(c, l);
116
116
  };
117
117
  Object.keys(e).forEach((t) => {
118
118
  const n = e[t];
119
- m(n) ? r(n) : B(n) ? s(n) : Array.isArray(n) && typeof n[0] == "number" && (e[t] = new Float32Array());
119
+ m(n) ? r(n) : B(n) ? i(n) : Array.isArray(n) && typeof n[0] == "number" && (e[t] = new Float32Array());
120
120
  });
121
121
  }
122
122
  /** 获取Gpu设备
@@ -132,43 +132,43 @@ class T {
132
132
  async initPipeline() {
133
133
  if (!this.template) throw new Error("初始化计算管线错误,未找到可用数据模版");
134
134
  await T.init();
135
- const e = this.template, { device: r } = await this.getDevice(), s = [], u = [], t = [];
136
- this.device = r, Object.keys(e).forEach((i, y) => {
135
+ const e = this.template, { device: r } = await this.getDevice(), i = [], u = [], t = [];
136
+ this.device = r, Object.keys(e).forEach((s, d) => {
137
137
  if (t.push({
138
- binding: y,
138
+ binding: d,
139
139
  // 绑定到组里的0号位插槽
140
140
  visibility: GPUShaderStage.COMPUTE,
141
141
  // 数据在哪些阶段可以使用, 计算着色器、片元着色器、顶点着色器
142
142
  buffer: {
143
143
  type: "storage"
144
144
  }
145
- }), m(e[i])) {
146
- const g = e[i], h = g.map((b) => `${b.name}:${b.type === "f32" ? "f32" : b.type + "<f32>"}`).join(","), v = `${S(i)}Struct`;
147
- s.push(`struct ${S(i)}Struct {${h}};`), u.push(`@group(0) @binding(${y}) var<storage, read_write> ${i}: ${v};`);
148
- } else if (B(e[i])) {
149
- const g = e[i], h = g.layout.map((b) => `${b.name}:${b.type === "f32" ? "f32" : b.type + "<f32>"}`).join(","), v = `${S(i)}Struct`;
150
- s.push(`struct ${v} {${h}};`), u.push(`@group(0) @binding(${y}) var<storage, read_write> ${i}: array<${v}>;`);
151
- } else if (ArrayBuffer.isView(e[i]) && !(e[i] instanceof DataView)) {
152
- const g = e[i], h = q(g);
153
- g instanceof D ? u.push(`@group(0) @binding(${y}) var<storage, read_write> ${i}: array<atomic<${h}>>;`) : u.push(`@group(0) @binding(${y}) var<storage, read_write> ${i}: array<${h}>;`);
145
+ }), m(e[s])) {
146
+ const g = e[s], h = g.map((b) => `${b.name}:${b.type === "f32" ? "f32" : b.type + "<f32>"}`).join(","), v = `${S(s)}Struct`;
147
+ i.push(`struct ${S(s)}Struct {${h}};`), u.push(`@group(0) @binding(${d}) var<storage, read_write> ${s}: ${v};`);
148
+ } else if (B(e[s])) {
149
+ const g = e[s], h = g.layout.map((b) => `${b.name}:${b.type === "f32" ? "f32" : b.type + "<f32>"}`).join(","), v = `${S(s)}Struct`;
150
+ i.push(`struct ${v} {${h}};`), u.push(`@group(0) @binding(${d}) var<storage, read_write> ${s}: array<${v}>;`);
151
+ } else if (ArrayBuffer.isView(e[s]) && !(e[s] instanceof DataView)) {
152
+ const g = e[s], h = q(g);
153
+ g instanceof D ? u.push(`@group(0) @binding(${d}) var<storage, read_write> ${s}: array<atomic<${h}>>;`) : u.push(`@group(0) @binding(${d}) var<storage, read_write> ${s}: array<${h}>;`);
154
154
  }
155
155
  });
156
156
  const {
157
157
  beforeCodes: n = [],
158
158
  workgroupSize: c = [32, 1, 1],
159
159
  globalInvocationIdName: l = "grid",
160
- workgroupIndexName: d = "index",
160
+ workgroupIndexName: y = "index",
161
161
  code: a = ""
162
162
  } = this.option ?? {}, o = (
163
163
  /*wgsl*/
164
164
  `
165
- ${s.join("")}
165
+ ${i.join("")}
166
166
  ${u.join("")}
167
167
  ${n.join(" ") ?? ""}
168
168
 
169
169
  @compute @workgroup_size(${c.join(",")})
170
170
  fn main(@builtin(global_invocation_id) ${l}: vec3<u32>) {
171
- var ${d} = ${l}.x;
171
+ var ${y} = ${l}.x;
172
172
  ${a}
173
173
  }
174
174
  `
@@ -196,28 +196,28 @@ ${u.join("")}
196
196
  createBindGroup(e, r) {
197
197
  if (!this.template) throw new Error("创建buffer组错误,未找到可用数据模版");
198
198
  if (!this.device) throw new Error("创建buffer组错误,未找到可用的gpu设备,请确保初始化完计算管线");
199
- const s = this.device, u = this.template, t = [], n = r?.buffers?.reduce((a, o) => (a.set(o.name, o.buffer), a), /* @__PURE__ */ new Map());
200
- function c(a, o, p = 0, i) {
199
+ const i = this.device, u = this.template, t = [], n = r?.buffers?.reduce((a, o) => (a.set(o.name, o.buffer), a), /* @__PURE__ */ new Map());
200
+ function c(a, o, p = 0, s) {
201
201
  if (ArrayBuffer.isView(a) || Array.isArray(a)) return a;
202
- if (!i) {
203
- const y = o[o.length - 1], g = y.offset + y.size;
202
+ if (!s) {
203
+ const d = o[o.length - 1], g = d.offset + d.size;
204
204
  let h = 1;
205
205
  for (const v of o) h = Math.max(h, E[v.type]);
206
- i = i ?? new Float32Array(P(g, h)).fill(0);
206
+ s = s ?? new Float32Array(P(g, h)).fill(0);
207
207
  }
208
- return o.forEach((y) => {
209
- let g = a[y.name];
208
+ return o.forEach((d) => {
209
+ let g = a[d.name];
210
210
  Array.isArray(g) || (g = [g]);
211
- for (let h = 0; h < y.size; h++)
212
- i[p + y.offset + h] = Number(g[h] ?? 0);
213
- }), i;
211
+ for (let h = 0; h < d.size; h++)
212
+ s[p + d.offset + h] = Number(g[h] ?? 0);
213
+ }), s;
214
214
  }
215
215
  function l(a, o) {
216
216
  if (ArrayBuffer.isView(a) || typeof a[0] == "number") return a;
217
217
  const p = new Float32Array(o.stride * a.length).fill(0);
218
- return a.forEach((i, y) => {
219
- const g = y * o.stride;
220
- c(i, o.layout, g, p);
218
+ return a.forEach((s, d) => {
219
+ const g = d * o.stride;
220
+ c(s, o.layout, g, p);
221
221
  }), p;
222
222
  }
223
223
  return Object.keys(u).forEach((a) => {
@@ -227,17 +227,17 @@ ${u.join("")}
227
227
  throw new Error(`传入的数据中,不存在${a}字段`);
228
228
  }
229
229
  const o = u[a], p = e[a];
230
- let i = [];
231
- m(o) ? i = c(p, o) : B(o) ? i = l(p, o) : (Array.isArray(p) || ArrayBuffer.isView(p)) && (i = p);
232
- let y = null;
233
- if (o instanceof Float32Array ? y = new Float32Array(i) : o instanceof Uint32Array ? y = new Uint32Array(i) : o instanceof Int32Array ? y = new Int32Array(i) : y = new Float32Array(i), !y) throw new Error("不支持的数组类型" + o);
234
- const g = s.createBuffer({
235
- size: y.byteLength,
230
+ let s = [];
231
+ m(o) ? s = c(p, o) : B(o) ? s = l(p, o) : (Array.isArray(p) || ArrayBuffer.isView(p)) && (s = p);
232
+ let d = null;
233
+ if (o instanceof Float32Array ? d = new Float32Array(s) : o instanceof Uint32Array ? d = new Uint32Array(s) : o instanceof Int32Array ? d = new Int32Array(s) : d = new Float32Array(s), !d) throw new Error("不支持的数组类型" + o);
234
+ const g = i.createBuffer({
235
+ size: d.byteLength,
236
236
  usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE
237
237
  });
238
- s.queue.writeBuffer(g, 0, y), t.push({ name: a, buffer: g });
238
+ i.queue.writeBuffer(g, 0, d), t.push({ name: a, buffer: g });
239
239
  }), {
240
- group: s.createBindGroup({
240
+ group: i.createBindGroup({
241
241
  layout: this.groupLayout,
242
242
  entries: t.map((a, o) => ({
243
243
  binding: o,
@@ -254,21 +254,21 @@ ${u.join("")}
254
254
  dataMap(e, r) {
255
255
  if (!(r in this.template)) throw new Error("未找到数据字段:" + r);
256
256
  if (B(this.template[r])) {
257
- const s = this.template[r], u = e.length / s.stride, t = [];
257
+ const i = this.template[r], u = e.length / i.stride, t = [];
258
258
  for (let n = 0; n < u; n++) {
259
- const c = n * s.stride, l = {};
260
- s.layout.forEach((d) => {
261
- const a = e.slice(c + d.offset, c + d.offset + d.size);
262
- l[d.name] = a.length === 1 ? a[0] : a;
259
+ const c = n * i.stride, l = {};
260
+ i.layout.forEach((y) => {
261
+ const a = e.slice(c + y.offset, c + y.offset + y.size);
262
+ l[y.name] = a.length === 1 ? a[0] : [...a];
263
263
  }), t.push(l);
264
264
  }
265
265
  return t;
266
266
  }
267
267
  if (m(this.template[r])) {
268
- const s = this.template[r], u = {};
269
- return s.forEach((t) => {
268
+ const i = this.template[r], u = {};
269
+ return i.forEach((t) => {
270
270
  const n = e.slice(t.offset, t.offset + t.size);
271
- u[t.name] = n.length === 1 ? n[0] : n;
271
+ u[t.name] = n.length === 1 ? n[0] : [...n];
272
272
  }), u;
273
273
  }
274
274
  return e;
@@ -279,12 +279,12 @@ ${u.join("")}
279
279
  * @param synchronize 需要同步的数据字段
280
280
  * @returns
281
281
  */
282
- async computed(e, r, s = []) {
282
+ async computed(e, r, i = []) {
283
283
  if (!this.pipeline) throw new Error("未找到可用计算管线,请确保计算管线已经创建成功");
284
284
  const u = this.device, t = this.pipeline, n = u.createCommandEncoder(), c = n.beginComputePass();
285
285
  c.setPipeline(t), c.setBindGroup(0, e.group), c.dispatchWorkgroups(r[0], r[1], r[2]), c.end();
286
286
  const l = e.buffers?.map((o) => {
287
- if (s?.includes(o.name)) {
287
+ if (i?.includes(o.name)) {
288
288
  const p = u.createBuffer({
289
289
  size: o.buffer.size,
290
290
  usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST
@@ -293,30 +293,28 @@ ${u.join("")}
293
293
  }
294
294
  }).filter((o) => !!o);
295
295
  u.queue.submit([n.finish()]), await u.queue.onSubmittedWorkDone();
296
- const d = /* @__PURE__ */ new Map();
296
+ const y = /* @__PURE__ */ new Map();
297
297
  return await Promise.all(
298
298
  l.map(async (o) => {
299
299
  await o.buffer.mapAsync(GPUMapMode.READ);
300
300
  const p = o.buffer.getMappedRange();
301
- let i = null;
302
- this.template[o.name] instanceof Float32Array ? i = new Float32Array(p) : this.template[o.name] instanceof Uint32Array ? i = new Uint32Array(p) : this.template[o.name] instanceof Int32Array ? i = new Int32Array(p) : i = new Float32Array(p);
303
- const y = [...i];
304
- d.set(o.name, y);
301
+ let s = null;
302
+ this.template[o.name] instanceof Float32Array ? s = new Float32Array(p) : this.template[o.name] instanceof Uint32Array ? s = new Uint32Array(p) : this.template[o.name] instanceof Int32Array ? s = new Int32Array(p) : s = new Float32Array(p), y.set(o.name, s);
305
303
  })
306
- ), s.map((o) => d.get(o));
304
+ ), i.map((o) => y.get(o));
307
305
  }
308
306
  /** 初始化gpu设备
309
307
  * @returns
310
308
  */
311
- static async init() {
309
+ static async init(e = {}) {
312
310
  if (!(w && A)) {
313
311
  if (typeof globalThis < "u" && typeof window > "u") {
314
- const { create: e, globals: r } = await z("webgpu", !1);
315
- Object.assign(globalThis, r), globalThis.navigator || (globalThis.navigator = {}), Object.assign(globalThis.navigator, { gpu: e([]) });
312
+ const { create: r, globals: i } = await z("webgpu", !1);
313
+ Object.assign(globalThis, i), globalThis.navigator || (globalThis.navigator = {}), Object.assign(globalThis.navigator, { gpu: r([]) });
316
314
  }
317
315
  if (!navigator.gpu) throw new Error("该环境不支持webgpu");
318
- if (w || (w = await navigator.gpu.requestAdapter({})), !w) throw new Error("获取适配器失败");
319
- if (A = await w.requestDevice(), !w) throw new Error("获取设备失败");
316
+ if (w || (w = await navigator.gpu.requestAdapter(e)), !w) throw new Error("获取适配器失败");
317
+ if (A = await w.requestDevice(e), !w) throw new Error("获取设备失败");
320
318
  }
321
319
  }
322
320
  /** 注销gpu设备
@@ -328,20 +326,20 @@ ${u.join("")}
328
326
  * @param data
329
327
  */
330
328
  static buildBufferTypeByData(e) {
331
- return Object.keys(e).reduce((s, u) => {
329
+ return Object.keys(e).reduce((i, u) => {
332
330
  let t = e[u];
333
331
  if (Array.isArray(t) && typeof t[0] == "number" && (t = new Float32Array()), Array.isArray(t))
334
332
  if (typeof t[0] == "object" || t.length) {
335
333
  const n = U(t[0]);
336
- s[u] = n;
334
+ i[u] = n;
337
335
  } else console.log(`字段:${u}, 不支持该值对应数据类型或数组为空`);
338
336
  else if (ArrayBuffer.isView(t) && !(t instanceof DataView))
339
- s[u] = t;
337
+ i[u] = t;
340
338
  else if (typeof t == "object") {
341
339
  const n = U(t);
342
- s[u] = n.layout;
340
+ i[u] = n.layout;
343
341
  } else console.log(`字段:${u}, 不支持的数据类型`);
344
- return s;
342
+ return i;
345
343
  }, {});
346
344
  }
347
345
  /** 通过数据创建
@@ -349,8 +347,8 @@ ${u.join("")}
349
347
  * @returns
350
348
  */
351
349
  static async fromByData(e) {
352
- let { data: r, ...s } = e;
353
- const u = this.buildBufferTypeByData(r), t = new T(u, s);
350
+ let { data: r, ...i } = e;
351
+ const u = this.buildBufferTypeByData(r), t = new T(u, i);
354
352
  return await t.initPipeline(), t;
355
353
  }
356
354
  /** 快捷计算方法
@@ -358,9 +356,9 @@ ${u.join("")}
358
356
  * @returns
359
357
  */
360
358
  static async computed(e) {
361
- let { data: r, map: s = !1, workgroupCount: u, synchronize: t, onSuccess: n, ...c } = e;
362
- const l = await this.fromByData({ data: r, ...c }), d = l.createBindGroup(r), a = await l.computed(d, u, t);
363
- return n && n({ gpuComputed: l, group: d, results: a }), s ? a.map((o, p) => l.dataMap(o, t[p])) : a;
359
+ let { data: r, map: i = !1, workgroupCount: u, synchronize: t, onSuccess: n, ...c } = e;
360
+ const l = await this.fromByData({ data: r, ...c }), y = l.createBindGroup(r), a = await l.computed(y, u, t);
361
+ return n && n({ gpuComputed: l, group: y, results: a }), i ? a.map((o, p) => l.dataMap(o, t[p])) : a;
364
362
  }
365
363
  }
366
364
  const M = (
@@ -26,6 +26,15 @@ interface IStructArray {
26
26
  layout: IStruct;
27
27
  }
28
28
  type BufferDataType = Record<string, (number[]) | ArrayBufferView | IStruct | IStructArray>;
29
+ type InitOption = {
30
+ featureLevel?: string;
31
+ powerPreference?: GPUPowerPreference;
32
+ forceFallbackAdapter?: boolean;
33
+ xrCompatible?: boolean;
34
+ requiredFeatures?: Iterable<GPUFeatureName>;
35
+ requiredLimits?: Record<string, GPUSize64 | undefined>;
36
+ defaultQueue?: GPUQueueDescriptor;
37
+ };
29
38
  export declare class AtomicUint32Array extends Uint32Array {
30
39
  }
31
40
  export declare class GpuComputed {
@@ -74,18 +83,18 @@ export declare class GpuComputed {
74
83
  * @param array
75
84
  * @param key
76
85
  */
77
- dataMap(array: number[], key: string): number[] | Record<string, number | number[]> | Record<string, number | number[]>[];
86
+ dataMap(array: Float32Array | Uint32Array | Int32Array, key: string): Float32Array<ArrayBufferLike> | Int32Array<ArrayBufferLike> | Uint32Array<ArrayBufferLike> | Record<string, number | number[]> | Record<string, number | number[]>[];
78
87
  /** 开始计算
79
88
  * @param group 数据组
80
89
  * @param workgroupCount 工作组大小
81
90
  * @param synchronize 需要同步的数据字段
82
91
  * @returns
83
92
  */
84
- computed(group: BufferGroup, workgroupCount: [number, number?, number?], synchronize?: string[]): Promise<number[][]>;
93
+ computed(group: BufferGroup, workgroupCount: [number, number?, number?], synchronize?: string[]): Promise<(Float32Array<ArrayBufferLike> | Int32Array<ArrayBufferLike> | Uint32Array<ArrayBufferLike>)[]>;
85
94
  /** 初始化gpu设备
86
95
  * @returns
87
96
  */
88
- static init(): Promise<void>;
97
+ static init(opt?: InitOption): Promise<void>;
89
98
  /** 注销gpu设备
90
99
  */
91
100
  static destroy(): void;
@@ -112,8 +121,8 @@ export declare class GpuComputed {
112
121
  onSuccess?: (opt: {
113
122
  gpuComputed: GpuComputed;
114
123
  group: BufferGroup;
115
- results: number[][];
124
+ results: (Float32Array | Uint32Array | Int32Array)[];
116
125
  }) => void;
117
- } & GpuComputedOption): Promise<(number[] | Record<string, number | number[]> | Record<string, number | number[]>[])[]>;
126
+ } & GpuComputedOption): Promise<(Float32Array<ArrayBufferLike> | Int32Array<ArrayBufferLike> | Uint32Array<ArrayBufferLike> | Record<string, number | number[]> | Record<string, number | number[]>[])[]>;
118
127
  }
119
128
  export {};