webgpu-computed 0.0.15 → 0.0.17

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 (3) hide show
  1. package/README.md +177 -37
  2. package/package.json +1 -1
  3. package/src/index.js +126 -124
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # webgpu-computed
2
2
 
3
3
  🌐 Other language versions:
4
- - [简体中文](https://github.com/xiaguochuqiu/webgpu-computed/blob/main/README.zh.md)
4
+ - [中文](https://github.com/xiaguochuqiu/webgpu-computed/blob/main/README.zh.md)
5
5
 
6
- A simplified WebGPU computing library that encapsulates tedious initialization and buffer management, allowing developers to focus on WGSL shader logic.
6
+ A simplified WebGPU compute library that encapsulates tedious initialization and buffer management, allowing developers to focus on WGSL shader logic.
7
7
 
8
8
  ## Features
9
9
 
@@ -14,7 +14,9 @@ A simplified WebGPU computing library that encapsulates tedious initialization a
14
14
  - 📚 Built-in common WGSL functions
15
15
  - ✅ Support for Node.js environment
16
16
  - 🛠️ TypeScript support
17
- - 📖 Detailed English documentation and examples
17
+ - 📖 Detailed Chinese documentation and examples
18
+ - 🔄 Support for buffer reuse
19
+ - ⚛️ Support for atomic operations (u32)
18
20
 
19
21
  ## Installation
20
22
 
@@ -26,7 +28,7 @@ npm install webgpu-computed
26
28
 
27
29
  ### 1. Initialize WebGPU
28
30
 
29
- Before using any computing features, you need to initialize the WebGPU environment:
31
+ Before using any compute features, you need to initialize the WebGPU environment:
30
32
 
31
33
  ```javascript
32
34
  import { GpuComputed } from 'webgpu-computed';
@@ -34,13 +36,13 @@ import { GpuComputed } from 'webgpu-computed';
34
36
  // Initialize WebGPU
35
37
  await GpuComputed.init();
36
38
 
37
- // After using in Node.js environment, please call:
39
+ // In Node.js environment, call after use:
38
40
  // GpuComputed.destroy()
39
41
  ```
40
42
 
41
43
  ### 2. Perform Simple Computation
42
44
 
43
- Here is a simple vector addition example:
45
+ Here's a simple vector addition example:
44
46
 
45
47
  ```javascript
46
48
  import { GpuComputed } from 'webgpu-computed';
@@ -52,7 +54,7 @@ const data = {
52
54
  output: new Array(4).fill(0) // Output buffer
53
55
  };
54
56
 
55
- // WGSL computation code
57
+ // WGSL compute code
56
58
  const code = `
57
59
  output[index] = inputA[index] + inputB[index];
58
60
  `;
@@ -62,7 +64,7 @@ GpuComputed.computed({
62
64
  code,
63
65
  data,
64
66
  synchronize: ["output"], // Fields to return
65
- workgroupCount: [1] // Number of workgroups
67
+ workgroupCount: [1] // Workgroup count
66
68
  }).then(results => {
67
69
  console.log(results); // [[1.5, 3.5, 5.5, 7.5]]
68
70
  })
@@ -91,15 +93,66 @@ GpuComputed.computed({
91
93
  code,
92
94
  data,
93
95
  synchronize: ["output"], // Fields to return
94
- workgroupCount: [1] // Number of workgroups
96
+ workgroupCount: [1] // Workgroup count
95
97
  }).then(results => {
96
98
  console.log(results); // [[1.100000023841858,2.200000047683716,3.299999952316284,0,0.20000000298023224,0.4000000059604645,0.6000000238418579,0,4.400000095367432,5.5,6.599999904632568,0,0.800000011920929,1,1.2000000476837158,0]]
97
99
  })
98
100
  ```
99
101
 
100
- ### 4. Manually Create GpuComputed Instance
102
+ ### 4. Using Different Data Types
101
103
 
102
- If you need more fine-grained control, you can directly create a GpuComputed instance:
104
+ #### Using Unsigned Integers (u32)
105
+
106
+ ```javascript
107
+ import { GpuComputed } from 'webgpu-computed';
108
+
109
+ const data = {
110
+ counters: new Uint32Array([0, 1, 2, 3]), // u32 array
111
+ output: new Uint32Array(4)
112
+ };
113
+
114
+ const code = `
115
+ output[index] = counters[index] * 2u;
116
+ `;
117
+
118
+ const results = await GpuComputed.computed({
119
+ code,
120
+ data,
121
+ synchronize: ["output"],
122
+ workgroupCount: [1]
123
+ });
124
+
125
+ console.log(results[0]); // [0, 2, 4, 6]
126
+ ```
127
+
128
+ #### Using Atomic Operations
129
+
130
+ ```javascript
131
+ import { GpuComputed, AtomicUint32Array } from 'webgpu-computed';
132
+
133
+ const data = {
134
+ atomicCounter: new AtomicUint32Array([0]), // Atomic counter
135
+ output: new Uint32Array(4)
136
+ };
137
+
138
+ const code = `
139
+ let old = atomicAdd(&atomicCounter[0], 1u);
140
+ output[index] = old + 1u;
141
+ `;
142
+
143
+ const results = await GpuComputed.computed({
144
+ code,
145
+ data,
146
+ synchronize: ["output"],
147
+ workgroupCount: [1]
148
+ });
149
+
150
+ console.log(results[0]); // [1, 2, 3, 4]
151
+ ```
152
+
153
+ ### 5. Manually Creating a GpuComputed Instance
154
+
155
+ If you need finer control, you can create a GpuComputed instance directly:
103
156
 
104
157
  ```javascript
105
158
  import { GpuComputed } from 'webgpu-computed';
@@ -116,7 +169,7 @@ const gpuComputed = new GpuComputed(template, {
116
169
  code: `
117
170
  output[index] = inputA[index] + inputB[index];
118
171
  `,
119
- workgroupSize: [32, 1, 1] // Optional: custom workgroup size
172
+ workgroupSize: [32, 1, 1] // Optional: Custom workgroup size
120
173
  });
121
174
 
122
175
  // 3. Initialize pipeline
@@ -138,6 +191,27 @@ const results = await gpuComputed.computed(bindGroup, [1], ['output']);
138
191
  console.log(results[0]); // [1.5, 3.5, 5.5, 7.5]
139
192
  ```
140
193
 
194
+ #### Buffer Reuse
195
+
196
+ ```javascript
197
+ // First computation
198
+ const data1 = { input: [1, 2, 3], output: [0, 0, 0] };
199
+ const bindGroup1 = gpuComputed.createBindGroup(data1);
200
+ const results1 = await gpuComputed.computed(bindGroup1, [1], ['output']);
201
+
202
+ // Reuse the output buffer from the first computation for the second
203
+ // Note: The template must still include output to build the compute code
204
+ // const template = {
205
+ // input: [] as number[],
206
+ // output: [] as number[]
207
+ // };
208
+ const data2 = { input: [4, 5, 6]};
209
+ const bindGroup2 = gpuComputed.createBindGroup(data2, bindGroup1); // Reuse output buffer
210
+ const results2 = await gpuComputed.computed(bindGroup2, [1], ['output']);
211
+
212
+ console.log(results2[0]); // [4, 5, 6] output buffer reused
213
+ ```
214
+
141
215
  #### Using Struct Data
142
216
 
143
217
  ```javascript
@@ -207,40 +281,49 @@ Initializes the WebGPU environment. Must be called before using other features.
207
281
 
208
282
  **Returns**: `Promise<void>`
209
283
 
210
- **Throws**: If the browser does not support WebGPU or fails to obtain adapter/device
284
+ **Throws**: If the browser does not support WebGPU or fails to get adapter/device
211
285
 
212
286
  ##### `GpuComputed.computed(options)`
213
287
 
214
- Executes a GPU computation task.
288
+ Executes a GPU compute task.
215
289
 
216
290
  **Parameters**:
217
291
 
218
- - `code` (string): WGSL computation code
292
+ - `code` (string): WGSL compute code
219
293
  - `data` (object): Input/output data object
220
- - `workgroupCount` (array): Number of workgroups [x, y?, z?]
294
+ - `workgroupCount` (array): Workgroup count [x, y?, z?]
221
295
  - `workgroupSize` (array, optional): Workgroup size, default [32, 1, 1]
222
296
  - `globalInvocationIdName` (string, optional): Global invocation ID variable name, default "grid"
223
297
  - `workgroupIndexName` (string, optional): Workgroup index variable name, default "index"
224
- - `synchronize` (array, optional): Array of buffer names to synchronize back to CPU
225
- - `beforeCodes` (array, optional): WGSL code snippets before the computation function
298
+ - `synchronize` (array, optional): Array of buffer names to sync back to CPU
299
+ - `beforeCodes` (array, optional): WGSL code snippets before the compute function
226
300
  - `onSuccess` (function, optional): Success callback function
227
301
 
228
- **Returns**: `Promise<Array<Float32Array>>` - Data from synchronized buffers
302
+ **Returns**: `Promise<Array<Float32Array | Uint32Array | Int32Array>>` - Data of synchronized buffers
229
303
 
230
304
  ### Data Types
231
305
 
232
306
  Supports the following WGSL types:
233
307
 
234
308
  - `f32`: Single-precision float
309
+ - `u32`: Unsigned 32-bit integer
235
310
  - `vec2`: 2D vector
236
311
  - `vec3`: 3D vector
237
312
  - `vec4`: 4D vector
238
313
  - `mat3x3`: 3x3 matrix
239
314
  - `mat4x4`: 4x4 matrix
240
315
 
316
+ ### Supported JavaScript Types
317
+
318
+ - `number[]`: Number array (automatically converted to Float32Array)
319
+ - `Float32Array`: 32-bit float array
320
+ - `Uint32Array`: 32-bit unsigned integer array
321
+ - `Int32Array`: 32-bit signed integer array
322
+ - `AtomicUint32Array`: Atomic unsigned integer array
323
+
241
324
  ### Built-in WGSL Functions
242
325
 
243
- The library provides some commonly used WGSL helper functions:
326
+ The library provides some common WGSL helper functions:
244
327
 
245
328
  #### Quaternion Rotation
246
329
 
@@ -279,20 +362,36 @@ await GpuComputed.computed({
279
362
  });
280
363
  ```
281
364
 
365
+ ### Buffer Reuse
366
+
367
+ ```javascript
368
+ // Create initial bind group
369
+ const initialData = { buffer: new Float32Array(1000) };
370
+ const bindGroup = gpuComputed.createBindGroup(initialData);
371
+
372
+ // Reuse buffer for multiple computations
373
+ for (let i = 0; i < 10; i++) {
374
+ const newData = { buffer: new Float32Array(1000).fill(i) };
375
+ const reusedBindGroup = gpuComputed.createBindGroup(newData, bindGroup);
376
+ const results = await gpuComputed.computed(reusedBindGroup, [32], ['buffer']);
377
+ // Process results...
378
+ }
379
+ ```
380
+
282
381
  ### Synchronizing Data Back to CPU
283
382
 
284
383
  ```javascript
285
384
  const results = await GpuComputed.computed({
286
385
  code: '...',
287
386
  data: {...},
288
- synchronize: ['output'], // Specify buffers to synchronize
387
+ synchronize: ['output'], // Specify buffers to sync
289
388
  workgroupCount: [1]
290
389
  });
291
390
 
292
391
  // results contains synchronized data
293
392
  ```
294
393
 
295
- ### Callback Function
394
+ ### Callback Functions
296
395
 
297
396
  ```javascript
298
397
  await GpuComputed.computed({
@@ -300,7 +399,7 @@ await GpuComputed.computed({
300
399
  data: {...},
301
400
  workgroupCount: [1],
302
401
  onSuccess: ({ gpuComputed, group, results }) => {
303
- console.log('Computation completed', results);
402
+ console.log('Computation complete', results);
304
403
  }
305
404
  });
306
405
  ```
@@ -335,9 +434,50 @@ const simpleResults = await GpuComputed.computed({
335
434
  synchronize: ['output']
336
435
  });
337
436
 
338
- console.log('Simple computation result:', simpleResults[0]); // [1.5, 3.5, 5.5, 7.5]
437
+ console.log('Simple computation results:', simpleResults[0]); // [1.5, 3.5, 5.5, 7.5]
438
+
439
+ // 3. Using u32 type example
440
+ console.log('\n=== Using u32 Type ===');
441
+ const u32Data = {
442
+ counters: new Uint32Array([10, 20, 30, 40]),
443
+ output: new Uint32Array(4)
444
+ };
445
+
446
+ const u32Code = `
447
+ output[index] = counters[index] + 5u;
448
+ `;
449
+
450
+ const u32Results = await GpuComputed.computed({
451
+ code: u32Code,
452
+ data: u32Data,
453
+ workgroupCount: [1],
454
+ synchronize: ['output']
455
+ });
456
+
457
+ console.log('u32 computation results:', u32Results[0]); // [15, 25, 35, 45]
458
+
459
+ // 4. Atomic operations example
460
+ console.log('\n=== Atomic Operations Example ===');
461
+ const atomicData = {
462
+ counter: new AtomicUint32Array([0]),
463
+ results: new Uint32Array(4)
464
+ };
465
+
466
+ const atomicCode = `
467
+ let oldValue = atomicAdd(&counter[0], 1u);
468
+ results[index] = oldValue;
469
+ `;
470
+
471
+ const atomicResults = await GpuComputed.computed({
472
+ code: atomicCode,
473
+ data: atomicData,
474
+ workgroupCount: [1],
475
+ synchronize: ['results']
476
+ });
477
+
478
+ console.log('Atomic operation results:', atomicResults[0]); // [0, 1, 2, 3]
339
479
 
340
- // 3. Complex data structure example (struct)
480
+ // 5. Complex data structure example (structs)
341
481
  console.log('\n=== Complex Data Structure Computation ===');
342
482
  const complexData = {
343
483
  particles: [
@@ -363,9 +503,9 @@ const complexResults = await GpuComputed.computed({
363
503
  synchronize: ['output']
364
504
  });
365
505
 
366
- console.log('Complex computation result:', complexResults[0]);
506
+ console.log('Complex computation results:', complexResults[0]);
367
507
 
368
- // 4. Using built-in WGSL functions example
508
+ // 6. Using built-in WGSL functions example
369
509
  console.log('\n=== Using Built-in WGSL Functions ===');
370
510
  const wgslFunData = {
371
511
  points: [
@@ -406,9 +546,9 @@ const wgslFunResults = await GpuComputed.computed({
406
546
  synchronize: ['results']
407
547
  });
408
548
 
409
- console.log('OBB detection result:', wgslFunResults[0]); // [1, 1, 1] All points are inside the OBB
549
+ console.log('OBB detection results:', wgslFunResults[0]); // [1, 1, 1] All points inside OBB
410
550
 
411
- // 5. Custom workgroup configuration example
551
+ // 7. Custom workgroup configuration example
412
552
  console.log('\n=== Custom Workgroup Configuration ===');
413
553
  const largeData = {
414
554
  largeArray: new Array(1024).fill(0).map((_, i) => i * 1.0),
@@ -427,10 +567,10 @@ const largeResults = await GpuComputed.computed({
427
567
  synchronize: ['output']
428
568
  });
429
569
 
430
- console.log('Large array computation result (first 10):', largeResults[0].slice(0, 10));
570
+ console.log('Large array computation results (first 10):', largeResults[0].slice(0, 10));
431
571
 
432
- // 6. Using callback function example
433
- console.log('\n=== Using Callback Function ===');
572
+ // 8. Using callback functions example
573
+ console.log('\n=== Using Callback Functions ===');
434
574
  const callbackData = {
435
575
  values: [10.0, 20.0, 30.0],
436
576
  squares: new Array(3).fill(0)
@@ -446,12 +586,12 @@ await GpuComputed.computed({
446
586
  workgroupCount: [1],
447
587
  synchronize: ['squares'],
448
588
  onSuccess: ({ gpuComputed, group, results }) => {
449
- console.log('Callback triggered, square computation result:', results[0]); // [100, 400, 900]
589
+ console.log('Callback triggered, square computation results:', results[0]); // [100, 400, 900]
450
590
  }
451
591
  });
452
592
 
453
- // 7. Multi-dimensional workgroup example
454
- console.log('\n=== Multi-dimensional Workgroup ===');
593
+ // 9. Multi-dimensional workgroups example
594
+ console.log('\n=== Multi-dimensional Workgroups ===');
455
595
  const matrixData = {
456
596
  matrixA: new Array(16).fill(0).map((_, i) => i * 1.0),
457
597
  matrixB: new Array(16).fill(0).map((_, i) => (i + 1) * 1.0),
@@ -473,7 +613,7 @@ const matrixResults = await GpuComputed.computed({
473
613
  synchronize: ['result']
474
614
  });
475
615
 
476
- console.log('Matrix computation result:', matrixResults[0]);
616
+ console.log('Matrix computation results:', matrixResults[0]);
477
617
 
478
618
  console.log('\nAll feature examples completed!');
479
619
  ```
@@ -489,7 +629,7 @@ Ensure the browser supports the WebGPU API.
489
629
 
490
630
  ## Contributing
491
631
 
492
- Welcome to submit Issues and Pull Requests!
632
+ Issues and Pull Requests are welcome!
493
633
 
494
634
  ## License
495
635
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "webgpu-computed",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "description": "对webgpu的封装,处理了繁琐的前置工作,只关注wgsl本身逻辑",
5
5
  "main": "./src/index.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -1,71 +1,71 @@
1
- async function z(s, e = !0) {
1
+ async function z(f, e = !0) {
2
2
  if (typeof global < "u" && typeof require < "u")
3
- return require(s);
3
+ return require(f);
4
4
  {
5
5
  let r = await import(
6
6
  /* @vite-ignore */
7
- s
7
+ f
8
8
  );
9
9
  return e && (r = r.default), r;
10
10
  }
11
11
  }
12
- function q(s) {
13
- if (s instanceof Float32Array) return "f32";
14
- if (s instanceof Int32Array) return "i32";
15
- if (s instanceof Uint32Array) return "u32";
12
+ function q(f) {
13
+ if (f instanceof Float32Array) return "f32";
14
+ if (f instanceof Int32Array) return "i32";
15
+ if (f instanceof Uint32Array) return "u32";
16
16
  throw new Error(
17
- `Unsupported ArrayBufferView type: ${s.constructor.name}`
17
+ `Unsupported ArrayBufferView type: ${f.constructor.name}`
18
18
  );
19
19
  }
20
- function S(s) {
21
- return s && s[0].toUpperCase() + s.slice(1);
20
+ function S(f) {
21
+ return f && f[0].toUpperCase() + f.slice(1);
22
22
  }
23
- function x(s) {
24
- return O.includes(s);
23
+ function x(f) {
24
+ return G.includes(f);
25
25
  }
26
- function m(s) {
27
- return s && Array.isArray(s) && s.length ? s.every((e) => e && typeof e == "object" && "name" in e && "type" in e && x(e.type)) : !1;
26
+ function m(f) {
27
+ return f && Array.isArray(f) && f.length ? f.every((e) => e && typeof e == "object" && "name" in e && "type" in e && x(e.type)) : !1;
28
28
  }
29
- function $(s) {
30
- return s && "layout" in s && m(s.layout);
29
+ function B(f) {
30
+ return f && "layout" in f && m(f.layout);
31
31
  }
32
- function _(s, e) {
32
+ function _(f, e) {
33
33
  const r = E[e];
34
- return (r - s % r) % r;
34
+ return (r - f % r) % r;
35
35
  }
36
- function P(s, e) {
37
- return s + (e - s % e) % e;
36
+ function P(f, e) {
37
+ return f + (e - f % e) % e;
38
38
  }
39
- function U(s) {
40
- const e = Object.keys(s), r = e.map((c) => {
41
- const l = s[c];
39
+ function U(f) {
40
+ const e = Object.keys(f), r = e.map((c) => {
41
+ const l = f[c];
42
42
  if (Array.isArray(l)) {
43
43
  for (const d of ["vec2", "vec3", "vec4", "mat3x3", "mat4x4"])
44
- if (B[d] === l.length) return d;
44
+ if ($[d] === l.length) return d;
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 i = 0;
52
- const f = e.map((c, l) => {
51
+ let s = 0;
52
+ const u = e.map((c, l) => {
53
53
  const d = r[l];
54
- i += _(i, d);
55
- const u = {
54
+ s += _(s, d);
55
+ const a = {
56
56
  name: c,
57
57
  type: d,
58
- offset: i,
59
- size: B[d]
58
+ offset: s,
59
+ size: $[d]
60
60
  };
61
- return i += B[d], u;
61
+ return s += $[d], a;
62
62
  }), t = Math.max(...r.map((c) => E[c]));
63
63
  return {
64
- stride: i + (t - i % t) % t,
65
- layout: f
64
+ stride: s + (t - s % t) % t,
65
+ layout: u
66
66
  };
67
67
  }
68
- const B = {
68
+ const $ = {
69
69
  f32: 1,
70
70
  u32: 1,
71
71
  vec2: 2,
@@ -86,8 +86,8 @@ const B = {
86
86
  };
87
87
  class D extends Uint32Array {
88
88
  }
89
- const O = ["f32", "u32", "vec2", "vec3", "vec4", "mat3x3", "mat4x4"];
90
- let w = null, v = null;
89
+ const G = ["f32", "u32", "vec2", "vec3", "vec4", "mat3x3", "mat4x4"];
90
+ let w = null, A = null;
91
91
  class T {
92
92
  template;
93
93
  option;
@@ -105,9 +105,9 @@ class T {
105
105
  const r = (t) => {
106
106
  let n = 0;
107
107
  t.forEach((c) => {
108
- n += _(n, c.type), c.offset = n, c.size = B[c.type], n += c.size;
108
+ n += _(n, c.type), c.offset = n, c.size = $[c.type], n += c.size;
109
109
  });
110
- }, i = (t) => {
110
+ }, s = (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;
@@ -116,15 +116,15 @@ class T {
116
116
  };
117
117
  Object.keys(e).forEach((t) => {
118
118
  const n = e[t];
119
- m(n) ? r(n) : $(n) ? i(n) : Array.isArray(n) && typeof n[0] == "number" && (e[t] = new Float32Array());
119
+ m(n) ? r(n) : B(n) ? s(n) : Array.isArray(n) && typeof n[0] == "number" && (e[t] = new Float32Array());
120
120
  });
121
121
  }
122
122
  /** 获取Gpu设备
123
123
  * @returns
124
124
  */
125
125
  async getDevice() {
126
- if (!w || !v) throw new Error("webgpu未初始化或不可用");
127
- return { adapter: w, device: v };
126
+ if (!w || !A) throw new Error("webgpu未初始化或不可用");
127
+ return { adapter: w, device: A };
128
128
  }
129
129
  /**
130
130
  * 初始化计算管线
@@ -132,8 +132,8 @@ 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(), i = [], f = [], t = [];
136
- this.device = r, Object.keys(e).forEach((a, y) => {
135
+ const e = this.template, { device: r } = await this.getDevice(), s = [], u = [], t = [];
136
+ this.device = r, Object.keys(e).forEach((i, y) => {
137
137
  if (t.push({
138
138
  binding: y,
139
139
  // 绑定到组里的0号位插槽
@@ -142,15 +142,15 @@ class T {
142
142
  buffer: {
143
143
  type: "storage"
144
144
  }
145
- }), m(e[a])) {
146
- const g = e[a], h = g.map((b) => `${b.name}:${b.type === "f32" ? "f32" : b.type + "<f32>"}`).join(","), A = `${S(a)}Struct`;
147
- i.push(`struct ${S(a)}Struct {${h}};`), f.push(`@group(0) @binding(${y}) var<storage, read_write> ${a}: ${A};`);
148
- } else if ($(e[a])) {
149
- const g = e[a], h = g.layout.map((b) => `${b.name}:${b.type === "f32" ? "f32" : b.type + "<f32>"}`).join(","), A = `${S(a)}Struct`;
150
- i.push(`struct ${A} {${h}};`), f.push(`@group(0) @binding(${y}) var<storage, read_write> ${a}: array<${A}>;`);
151
- } else if (ArrayBuffer.isView(e[a]) && !(e[a] instanceof DataView)) {
152
- const g = e[a], h = q(g);
153
- g instanceof D ? f.push(`@group(0) @binding(${y}) var<storage, read_write> ${a}: array<atomic<${h}>>;`) : f.push(`@group(0) @binding(${y}) var<storage, read_write> ${a}: array<${h}>;`);
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}>;`);
154
154
  }
155
155
  });
156
156
  const {
@@ -158,18 +158,18 @@ class T {
158
158
  workgroupSize: c = [32, 1, 1],
159
159
  globalInvocationIdName: l = "grid",
160
160
  workgroupIndexName: d = "index",
161
- code: u = ""
161
+ code: a = ""
162
162
  } = this.option ?? {}, o = (
163
163
  /*wgsl*/
164
164
  `
165
- ${i.join("")}
166
- ${f.join("")}
165
+ ${s.join("")}
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
171
  var ${d} = ${l}.x;
172
- ${u}
172
+ ${a}
173
173
  }
174
174
  `
175
175
  );
@@ -196,50 +196,52 @@ ${f.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 i = this.device, f = this.template, t = [], n = r?.buffers?.reduce((u, o) => (u.set(o.name, o.buffer), u), /* @__PURE__ */ new Map());
200
- function c(u, o, p = 0, a) {
201
- if (!a) {
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) {
201
+ if (ArrayBuffer.isView(a) || Array.isArray(a)) return a;
202
+ if (!i) {
202
203
  const y = o[o.length - 1], g = y.offset + y.size;
203
204
  let h = 1;
204
- for (const A of o) h = Math.max(h, E[A.type]);
205
- a = a ?? new Array(P(g, h)).fill(0);
205
+ for (const v of o) h = Math.max(h, E[v.type]);
206
+ i = i ?? new Float32Array(P(g, h)).fill(0);
206
207
  }
207
208
  return o.forEach((y) => {
208
- let g = u[y.name];
209
+ let g = a[y.name];
209
210
  Array.isArray(g) || (g = [g]);
210
211
  for (let h = 0; h < y.size; h++)
211
- a[p + y.offset + h] = Number(g[h] ?? 0);
212
- }), a;
212
+ i[p + y.offset + h] = Number(g[h] ?? 0);
213
+ }), i;
213
214
  }
214
- function l(u, o) {
215
- const p = new Array(o.stride * u.length).fill(0);
216
- return u.forEach((a, y) => {
215
+ function l(a, o) {
216
+ if (ArrayBuffer.isView(a) || typeof a[0] == "number") return a;
217
+ const p = new Float32Array(o.stride * a.length).fill(0);
218
+ return a.forEach((i, y) => {
217
219
  const g = y * o.stride;
218
- c(a, o.layout, g, p);
220
+ c(i, o.layout, g, p);
219
221
  }), p;
220
222
  }
221
- return Object.keys(f).forEach((u) => {
222
- if (!(u in e)) {
223
- if (n && n.has(u))
224
- return t.push({ name: u, buffer: n.get(u) });
225
- throw new Error(`传入的数据中,不存在${u}字段`);
223
+ return Object.keys(u).forEach((a) => {
224
+ if (!(a in e)) {
225
+ if (n && n.has(a))
226
+ return t.push({ name: a, buffer: n.get(a) });
227
+ throw new Error(`传入的数据中,不存在${a}字段`);
226
228
  }
227
- const o = f[u], p = e[u];
228
- let a = [];
229
- m(o) ? a = c(p, o) : $(o) ? a = l(p, o) : (Array.isArray(p) || ArrayBuffer.isView(p)) && (a = p);
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);
230
232
  let y = null;
231
- if (o instanceof Float32Array ? y = new Float32Array(a) : o instanceof Uint32Array ? y = new Uint32Array(a) : o instanceof Int32Array ? y = new Int32Array(a) : y = new Float32Array(a), !y) throw new Error("不支持的数组类型" + o);
232
- const g = i.createBuffer({
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({
233
235
  size: y.byteLength,
234
236
  usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE
235
237
  });
236
- i.queue.writeBuffer(g, 0, y), t.push({ name: u, buffer: g });
238
+ s.queue.writeBuffer(g, 0, y), t.push({ name: a, buffer: g });
237
239
  }), {
238
- group: i.createBindGroup({
240
+ group: s.createBindGroup({
239
241
  layout: this.groupLayout,
240
- entries: t.map((u, o) => ({
242
+ entries: t.map((a, o) => ({
241
243
  binding: o,
242
- resource: { buffer: u.buffer }
244
+ resource: { buffer: a.buffer }
243
245
  }))
244
246
  }),
245
247
  buffers: t
@@ -251,23 +253,23 @@ ${f.join("")}
251
253
  */
252
254
  dataMap(e, r) {
253
255
  if (!(r in this.template)) throw new Error("未找到数据字段:" + r);
254
- if ($(this.template[r])) {
255
- const i = this.template[r], f = e.length / i.stride, t = [];
256
- for (let n = 0; n < f; n++) {
257
- const c = n * i.stride, l = {};
258
- i.layout.forEach((d) => {
259
- const u = e.slice(c + d.offset, c + d.offset + d.size);
260
- l[d.name] = u.length === 1 ? u[0] : u;
256
+ if (B(this.template[r])) {
257
+ const s = this.template[r], u = e.length / s.stride, t = [];
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;
261
263
  }), t.push(l);
262
264
  }
263
265
  return t;
264
266
  }
265
267
  if (m(this.template[r])) {
266
- const i = this.template[r], f = {};
267
- return i.forEach((t) => {
268
+ const s = this.template[r], u = {};
269
+ return s.forEach((t) => {
268
270
  const n = e.slice(t.offset, t.offset + t.size);
269
- f[t.name] = n.length === 1 ? n[0] : n;
270
- }), f;
271
+ u[t.name] = n.length === 1 ? n[0] : n;
272
+ }), u;
271
273
  }
272
274
  return e;
273
275
  }
@@ -277,69 +279,69 @@ ${f.join("")}
277
279
  * @param synchronize 需要同步的数据字段
278
280
  * @returns
279
281
  */
280
- async computed(e, r, i = []) {
282
+ async computed(e, r, s = []) {
281
283
  if (!this.pipeline) throw new Error("未找到可用计算管线,请确保计算管线已经创建成功");
282
- const f = this.device, t = this.pipeline, n = f.createCommandEncoder(), c = n.beginComputePass();
284
+ const u = this.device, t = this.pipeline, n = u.createCommandEncoder(), c = n.beginComputePass();
283
285
  c.setPipeline(t), c.setBindGroup(0, e.group), c.dispatchWorkgroups(r[0], r[1], r[2]), c.end();
284
286
  const l = e.buffers?.map((o) => {
285
- if (i?.includes(o.name)) {
286
- const p = f.createBuffer({
287
+ if (s?.includes(o.name)) {
288
+ const p = u.createBuffer({
287
289
  size: o.buffer.size,
288
290
  usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST
289
291
  });
290
292
  return n.copyBufferToBuffer(o.buffer, 0, p, 0, p.size), { buffer: p, name: o.name };
291
293
  }
292
294
  }).filter((o) => !!o);
293
- f.queue.submit([n.finish()]), await f.queue.onSubmittedWorkDone();
295
+ u.queue.submit([n.finish()]), await u.queue.onSubmittedWorkDone();
294
296
  const d = /* @__PURE__ */ new Map();
295
297
  return await Promise.all(
296
298
  l.map(async (o) => {
297
299
  await o.buffer.mapAsync(GPUMapMode.READ);
298
300
  const p = o.buffer.getMappedRange();
299
- let a = null;
300
- this.template[o.name] instanceof Float32Array ? a = new Float32Array(p) : this.template[o.name] instanceof Uint32Array ? a = new Uint32Array(p) : this.template[o.name] instanceof Int32Array ? a = new Int32Array(p) : a = new Float32Array(p);
301
- const y = [...a];
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];
302
304
  d.set(o.name, y);
303
305
  })
304
- ), i.map((o) => d.get(o));
306
+ ), s.map((o) => d.get(o));
305
307
  }
306
308
  /** 初始化gpu设备
307
309
  * @returns
308
310
  */
309
311
  static async init() {
310
- if (!(w && v)) {
312
+ if (!(w && A)) {
311
313
  if (typeof globalThis < "u" && typeof window > "u") {
312
314
  const { create: e, globals: r } = await z("webgpu", !1);
313
315
  Object.assign(globalThis, r), globalThis.navigator || (globalThis.navigator = {}), Object.assign(globalThis.navigator, { gpu: e([]) });
314
316
  }
315
317
  if (!navigator.gpu) throw new Error("该环境不支持webgpu");
316
318
  if (w || (w = await navigator.gpu.requestAdapter({})), !w) throw new Error("获取适配器失败");
317
- if (v = await w.requestDevice(), !w) throw new Error("获取设备失败");
319
+ if (A = await w.requestDevice(), !w) throw new Error("获取设备失败");
318
320
  }
319
321
  }
320
322
  /** 注销gpu设备
321
323
  */
322
324
  static destroy() {
323
- v && v.destroy(), v = null;
325
+ A && A.destroy(), A = null;
324
326
  }
325
327
  /**
326
328
  * @param data
327
329
  */
328
330
  static buildBufferTypeByData(e) {
329
- return Object.keys(e).reduce((i, f) => {
330
- let t = e[f];
331
+ return Object.keys(e).reduce((s, u) => {
332
+ let t = e[u];
331
333
  if (Array.isArray(t) && typeof t[0] == "number" && (t = new Float32Array()), Array.isArray(t))
332
334
  if (typeof t[0] == "object" || t.length) {
333
335
  const n = U(t[0]);
334
- i[f] = n;
335
- } else console.log(`字段:${f}, 不支持该值对应数据类型或数组为空`);
336
+ s[u] = n;
337
+ } else console.log(`字段:${u}, 不支持该值对应数据类型或数组为空`);
336
338
  else if (ArrayBuffer.isView(t) && !(t instanceof DataView))
337
- i[f] = t;
339
+ s[u] = t;
338
340
  else if (typeof t == "object") {
339
341
  const n = U(t);
340
- i[f] = n.layout;
341
- } else console.log(`字段:${f}, 不支持的数据类型`);
342
- return i;
342
+ s[u] = n.layout;
343
+ } else console.log(`字段:${u}, 不支持的数据类型`);
344
+ return s;
343
345
  }, {});
344
346
  }
345
347
  /** 通过数据创建
@@ -347,8 +349,8 @@ ${f.join("")}
347
349
  * @returns
348
350
  */
349
351
  static async fromByData(e) {
350
- let { data: r, ...i } = e;
351
- const f = this.buildBufferTypeByData(r), t = new T(f, i);
352
+ let { data: r, ...s } = e;
353
+ const u = this.buildBufferTypeByData(r), t = new T(u, s);
352
354
  return await t.initPipeline(), t;
353
355
  }
354
356
  /** 快捷计算方法
@@ -356,12 +358,12 @@ ${f.join("")}
356
358
  * @returns
357
359
  */
358
360
  static async computed(e) {
359
- let { data: r, map: i = !1, workgroupCount: f, synchronize: t, onSuccess: n, ...c } = e;
360
- const l = await this.fromByData({ data: r, ...c }), d = l.createBindGroup(r), u = await l.computed(d, f, t);
361
- return n && n({ gpuComputed: l, group: d, results: u }), i ? u.map((o, p) => l.dataMap(o, t[p])) : u;
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;
362
364
  }
363
365
  }
364
- const j = (
366
+ const M = (
365
367
  /* wgsl */
366
368
  `
367
369
  fn quat_rotate(q: vec4<f32>, v: vec3<f32>) -> vec3<f32> {
@@ -370,7 +372,7 @@ const j = (
370
372
  return v + q.w * t + cross(q.xyz, t);
371
373
  }
372
374
  `
373
- ), G = (
375
+ ), O = (
374
376
  /* wgsl */
375
377
  `
376
378
  fn point_in_obb(
@@ -390,13 +392,13 @@ const j = (
390
392
  return all(abs(pLocal) <= halfSize);
391
393
  }
392
394
  `
393
- ), M = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
395
+ ), j = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
394
396
  __proto__: null,
395
- point_in_obb: G,
396
- quat_rotate: j
397
+ point_in_obb: O,
398
+ quat_rotate: M
397
399
  }, Symbol.toStringTag, { value: "Module" }));
398
400
  export {
399
401
  D as AtomicUint32Array,
400
402
  T as GpuComputed,
401
- M as WGSL_Fun
403
+ j as WGSL_Fun
402
404
  };