@manycore/aholo-splat-transform 1.2.8 → 1.2.9
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/CHANGELOG.md +120 -113
- package/README.md +39 -39
- package/THIRD_PARTY_LICENSES.txt +1373 -1373
- package/bin/cli.js +125 -118
- package/dist/SplatData.d.ts +67 -67
- package/dist/SplatData.js +167 -150
- package/dist/constant.d.ts +3 -3
- package/dist/constant.js +13 -13
- package/dist/file/IFile.d.ts +5 -5
- package/dist/file/IFile.js +1 -1
- package/dist/file/esz.d.ts +11 -11
- package/dist/file/esz.js +337 -322
- package/dist/file/index.d.ts +8 -8
- package/dist/file/index.js +7 -7
- package/dist/file/ksplat.d.ts +12 -12
- package/dist/file/ksplat.js +293 -231
- package/dist/file/lcc.d.ts +11 -11
- package/dist/file/lcc.js +161 -158
- package/dist/file/ply.d.ts +13 -13
- package/dist/file/ply.js +439 -390
- package/dist/file/sog.d.ts +80 -80
- package/dist/file/sog.js +525 -494
- package/dist/file/splat.d.ts +6 -6
- package/dist/file/splat.js +119 -99
- package/dist/file/spz.d.ts +11 -11
- package/dist/file/spz.js +597 -583
- package/dist/file/voxel.d.ts +43 -37
- package/dist/file/voxel.js +411 -280
- package/dist/index.d.ts +33 -33
- package/dist/index.js +54 -54
- package/dist/native/index.d.ts +54 -54
- package/dist/native/index.js +122 -129
- package/dist/native/utils.d.ts +1 -0
- package/dist/native/utils.js +54 -0
- package/dist/tasks/AutoChunkLodTask.d.ts +13 -13
- package/dist/tasks/AutoChunkLodTask.js +117 -117
- package/dist/tasks/AutoLodTask.d.ts +10 -10
- package/dist/tasks/AutoLodTask.js +20 -20
- package/dist/tasks/BaseTask.d.ts +15 -15
- package/dist/tasks/BaseTask.js +5 -5
- package/dist/tasks/FlexLodTask.d.ts +12 -12
- package/dist/tasks/FlexLodTask.js +54 -44
- package/dist/tasks/ModifyTask.d.ts +9 -9
- package/dist/tasks/ModifyTask.js +166 -156
- package/dist/tasks/ReadTask.d.ts +9 -9
- package/dist/tasks/ReadTask.js +29 -29
- package/dist/tasks/SkeletonLodTask.d.ts +10 -10
- package/dist/tasks/SkeletonLodTask.js +176 -156
- package/dist/tasks/VoxelTask.d.ts +35 -30
- package/dist/tasks/VoxelTask.js +40 -37
- package/dist/tasks/WriteTask.d.ts +12 -12
- package/dist/tasks/WriteTask.js +70 -70
- package/dist/utils/BufferReader.d.ts +12 -12
- package/dist/utils/BufferReader.js +45 -45
- package/dist/utils/Logger.d.ts +11 -11
- package/dist/utils/Logger.js +40 -40
- package/dist/utils/StreamChunkDecoder.d.ts +16 -16
- package/dist/utils/StreamChunkDecoder.js +31 -31
- package/dist/utils/index.d.ts +27 -27
- package/dist/utils/index.js +101 -101
- package/dist/utils/k-means.d.ts +4 -4
- package/dist/utils/k-means.js +340 -341
- package/dist/utils/math.d.ts +46 -46
- package/dist/utils/math.js +350 -346
- package/dist/utils/quantize-1d.d.ts +4 -4
- package/dist/utils/quantize-1d.js +164 -164
- package/dist/utils/sh-rotate.d.ts +2 -2
- package/dist/utils/sh-rotate.js +236 -175
- package/dist/utils/splat.d.ts +21 -21
- package/dist/utils/splat.js +397 -387
- package/dist/utils/voxel/binary.d.ts +8 -0
- package/dist/utils/voxel/binary.js +176 -0
- package/dist/utils/voxel/common.d.ts +178 -162
- package/dist/utils/voxel/common.js +1752 -1682
- package/dist/utils/voxel/coplanar-merge.d.ts +63 -63
- package/dist/utils/voxel/coplanar-merge.js +818 -819
- package/dist/utils/voxel/filter-cluster.d.ts +20 -0
- package/dist/utils/voxel/filter-cluster.js +628 -0
- package/dist/utils/voxel/gpu-dilation.d.ts +2 -2
- package/dist/utils/voxel/gpu-dilation.js +677 -656
- package/dist/utils/voxel/marching-cubes.d.ts +42 -42
- package/dist/utils/voxel/marching-cubes.js +1645 -1657
- package/dist/utils/voxel/mesh.d.ts +3 -3
- package/dist/utils/voxel/mesh.js +130 -130
- package/dist/utils/voxel/nav.d.ts +29 -29
- package/dist/utils/voxel/nav.js +1068 -1043
- package/dist/utils/voxel/postprocess.d.ts +23 -23
- package/dist/utils/voxel/postprocess.js +408 -375
- package/dist/utils/voxel/voxel-faces.d.ts +18 -18
- package/dist/utils/voxel/voxel-faces.js +662 -663
- package/dist/utils/voxel/voxelize.d.ts +34 -33
- package/dist/utils/voxel/voxelize.js +1208 -1193
- package/dist/utils/webgpu.d.ts +8 -8
- package/dist/utils/webgpu.js +122 -122
- package/package.json +37 -39
- package/dist/native/cpp/bin/linux/binding.node +0 -0
- package/dist/native/cpp/bin/windows/binding.node +0 -0
|
@@ -1,656 +1,677 @@
|
|
|
1
|
-
import { getOrCreateDevice } from '../webgpu.js';
|
|
2
|
-
import { BLOCK_EMPTY, BLOCK_MIXED, BLOCK_SOLID, SparseVoxelGrid, readBlockType } from './common.js';
|
|
3
|
-
const GPU_BUFFER_USAGE_STORAGE = 128;
|
|
4
|
-
const GPU_BUFFER_USAGE_COPY_DST = 8;
|
|
5
|
-
const GPU_BUFFER_USAGE_COPY_SRC = 4;
|
|
6
|
-
const GPU_BUFFER_USAGE_UNIFORM = 64;
|
|
7
|
-
const GPU_BUFFER_USAGE_MAP_READ = 1;
|
|
8
|
-
const GPU_MAP_MODE_READ = 1;
|
|
9
|
-
const CHUNK_INNER = 512;
|
|
10
|
-
const SOLID_WORD = 0x55555555 >>> 0;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
@group(0) @binding(
|
|
29
|
-
@group(0) @binding(
|
|
30
|
-
@group(0) @binding(
|
|
31
|
-
@group(0) @binding(
|
|
32
|
-
@group(0) @binding(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
let
|
|
40
|
-
let
|
|
41
|
-
let
|
|
42
|
-
let
|
|
43
|
-
let
|
|
44
|
-
|
|
45
|
-
if (globalBx
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
let
|
|
49
|
-
let
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
var
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
let
|
|
73
|
-
let
|
|
74
|
-
let
|
|
75
|
-
let
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
let
|
|
80
|
-
let
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
let
|
|
84
|
-
let
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
@group(0) @binding(
|
|
108
|
-
|
|
109
|
-
@
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
let
|
|
117
|
-
let
|
|
118
|
-
let
|
|
119
|
-
let
|
|
120
|
-
let
|
|
121
|
-
let
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
let
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
let
|
|
135
|
-
let
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
let
|
|
179
|
-
|
|
180
|
-
let
|
|
181
|
-
let
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
let
|
|
226
|
-
let
|
|
227
|
-
let
|
|
228
|
-
let
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
})
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
const
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
slot.
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
this.
|
|
437
|
-
this.
|
|
438
|
-
this.
|
|
439
|
-
this.
|
|
440
|
-
this.
|
|
441
|
-
this.
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
this.
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
encoder.
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
this.
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
const
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
slot.
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
slot.
|
|
567
|
-
slot.
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
const
|
|
629
|
-
const
|
|
630
|
-
const
|
|
631
|
-
const
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
cz,
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
}
|
|
1
|
+
import { getOrCreateDevice } from '../webgpu.js';
|
|
2
|
+
import { BLOCK_EMPTY, BLOCK_MIXED, BLOCK_SOLID, SparseVoxelGrid, readBlockType } from './common.js';
|
|
3
|
+
const GPU_BUFFER_USAGE_STORAGE = 128;
|
|
4
|
+
const GPU_BUFFER_USAGE_COPY_DST = 8;
|
|
5
|
+
const GPU_BUFFER_USAGE_COPY_SRC = 4;
|
|
6
|
+
const GPU_BUFFER_USAGE_UNIFORM = 64;
|
|
7
|
+
const GPU_BUFFER_USAGE_MAP_READ = 1;
|
|
8
|
+
const GPU_MAP_MODE_READ = 1;
|
|
9
|
+
const CHUNK_INNER = 512;
|
|
10
|
+
const SOLID_WORD = 0x55555555 >>> 0;
|
|
11
|
+
function extractWgsl() {
|
|
12
|
+
return /* wgsl */ `
|
|
13
|
+
struct ExtractUniforms {
|
|
14
|
+
minBx: i32,
|
|
15
|
+
minBy: i32,
|
|
16
|
+
minBz: i32,
|
|
17
|
+
outerBx: u32,
|
|
18
|
+
outerBy: u32,
|
|
19
|
+
outerBz: u32,
|
|
20
|
+
numXWords: u32,
|
|
21
|
+
srcNbx: u32,
|
|
22
|
+
srcNby: u32,
|
|
23
|
+
srcNbz: u32,
|
|
24
|
+
srcBStride: u32,
|
|
25
|
+
srcCapMinusOne: u32
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@group(0) @binding(0) var<uniform> u: ExtractUniforms;
|
|
29
|
+
@group(0) @binding(1) var<storage, read> srcTypes: array<u32>;
|
|
30
|
+
@group(0) @binding(2) var<storage, read> srcKeys: array<u32>;
|
|
31
|
+
@group(0) @binding(3) var<storage, read> srcLo: array<u32>;
|
|
32
|
+
@group(0) @binding(4) var<storage, read> srcHi: array<u32>;
|
|
33
|
+
@group(0) @binding(5) var<storage, read_write> dstDense: array<atomic<u32>>;
|
|
34
|
+
|
|
35
|
+
@compute @workgroup_size(8, 4, 8)
|
|
36
|
+
fn main(@builtin(global_invocation_id) gid: vec3u) {
|
|
37
|
+
if (gid.x >= u.outerBx || gid.y >= u.outerBy || gid.z >= u.outerBz) { return; }
|
|
38
|
+
|
|
39
|
+
let chunkBx = i32(gid.x);
|
|
40
|
+
let chunkBy = i32(gid.y);
|
|
41
|
+
let chunkBz = i32(gid.z);
|
|
42
|
+
let globalBx = u.minBx + chunkBx;
|
|
43
|
+
let globalBy = u.minBy + chunkBy;
|
|
44
|
+
let globalBz = u.minBz + chunkBz;
|
|
45
|
+
if (globalBx < 0 || globalBy < 0 || globalBz < 0) { return; }
|
|
46
|
+
if (globalBx >= i32(u.srcNbx) || globalBy >= i32(u.srcNby) || globalBz >= i32(u.srcNbz)) { return; }
|
|
47
|
+
|
|
48
|
+
let blockIdx = u32(globalBx) + u32(globalBy) * u.srcNbx + u32(globalBz) * u.srcBStride;
|
|
49
|
+
let typeWord = srcTypes[blockIdx >> 4u];
|
|
50
|
+
let bt = (typeWord >> ((blockIdx & 15u) * 2u)) & 3u;
|
|
51
|
+
if (bt == 0u) { return; }
|
|
52
|
+
|
|
53
|
+
var lo: u32;
|
|
54
|
+
var hi: u32;
|
|
55
|
+
if (bt == 1u) {
|
|
56
|
+
lo = 0xFFFFFFFFu;
|
|
57
|
+
hi = 0xFFFFFFFFu;
|
|
58
|
+
} else {
|
|
59
|
+
var i = (blockIdx * 0x9E3779B9u) & u.srcCapMinusOne;
|
|
60
|
+
loop {
|
|
61
|
+
let k = srcKeys[i];
|
|
62
|
+
if (k == blockIdx) {
|
|
63
|
+
lo = srcLo[i];
|
|
64
|
+
hi = srcHi[i];
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
if (k == 0xFFFFFFFFu) { return; }
|
|
68
|
+
i = (i + 1u) & u.srcCapMinusOne;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
let dx0 = u32(chunkBx) * 4u;
|
|
73
|
+
let wordOffsetX = dx0 / 32u;
|
|
74
|
+
let bitShiftX = dx0 & 31u;
|
|
75
|
+
let outerNy = u.outerBy * 4u;
|
|
76
|
+
let planeWords = u.numXWords * outerNy;
|
|
77
|
+
|
|
78
|
+
for (var lz = 0u; lz < 4u; lz = lz + 1u) {
|
|
79
|
+
let dz = u32(chunkBz) * 4u + lz;
|
|
80
|
+
let zBitBase = (lz & 1u) * 16u;
|
|
81
|
+
let word = select(lo, hi, lz >= 2u);
|
|
82
|
+
for (var ly = 0u; ly < 4u; ly = ly + 1u) {
|
|
83
|
+
let dy = u32(chunkBy) * 4u + ly;
|
|
84
|
+
let bitBase = zBitBase + ly * 4u;
|
|
85
|
+
let pattern = (word >> bitBase) & 0xFu;
|
|
86
|
+
if (pattern == 0u) { continue; }
|
|
87
|
+
let wordIdx = wordOffsetX + dy * u.numXWords + dz * planeWords;
|
|
88
|
+
atomicOr(&dstDense[wordIdx], pattern << bitShiftX);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
`;
|
|
93
|
+
}
|
|
94
|
+
function compactWgsl() {
|
|
95
|
+
return /* wgsl */ `
|
|
96
|
+
struct CompactUniforms {
|
|
97
|
+
haloBx: u32,
|
|
98
|
+
haloBy: u32,
|
|
99
|
+
haloBz: u32,
|
|
100
|
+
numXWords: u32,
|
|
101
|
+
innerBx: u32,
|
|
102
|
+
innerBy: u32,
|
|
103
|
+
innerBz: u32,
|
|
104
|
+
outerBy: u32
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
@group(0) @binding(0) var<uniform> u: CompactUniforms;
|
|
108
|
+
@group(0) @binding(1) var<storage, read> dilatedDense: array<u32>;
|
|
109
|
+
@group(0) @binding(2) var<storage, read_write> typesOut: array<atomic<u32>>;
|
|
110
|
+
@group(0) @binding(3) var<storage, read_write> masksOut: array<u32>;
|
|
111
|
+
|
|
112
|
+
@compute @workgroup_size(8, 4, 8)
|
|
113
|
+
fn main(@builtin(global_invocation_id) gid: vec3u) {
|
|
114
|
+
if (gid.x >= u.innerBx || gid.y >= u.innerBy || gid.z >= u.innerBz) { return; }
|
|
115
|
+
|
|
116
|
+
let innerBlockIdx = gid.x + gid.y * u.innerBx + gid.z * u.innerBx * u.innerBy;
|
|
117
|
+
let outerBx = gid.x + u.haloBx;
|
|
118
|
+
let outerBy = gid.y + u.haloBy;
|
|
119
|
+
let outerBz = gid.z + u.haloBz;
|
|
120
|
+
let dx0 = outerBx * 4u;
|
|
121
|
+
let wordOffsetX = dx0 / 32u;
|
|
122
|
+
let bitShiftX = dx0 & 31u;
|
|
123
|
+
let outerNy = u.outerBy * 4u;
|
|
124
|
+
let planeWords = u.numXWords * outerNy;
|
|
125
|
+
|
|
126
|
+
var lo = 0u;
|
|
127
|
+
var hi = 0u;
|
|
128
|
+
for (var lz = 0u; lz < 4u; lz = lz + 1u) {
|
|
129
|
+
let dz = outerBz * 4u + lz;
|
|
130
|
+
let zBitBase = (lz & 1u) * 16u;
|
|
131
|
+
let inHi = lz >= 2u;
|
|
132
|
+
let planeBase = dz * planeWords;
|
|
133
|
+
for (var ly = 0u; ly < 4u; ly = ly + 1u) {
|
|
134
|
+
let dy = outerBy * 4u + ly;
|
|
135
|
+
let bitBase = zBitBase + ly * 4u;
|
|
136
|
+
let wordIdx = wordOffsetX + dy * u.numXWords + planeBase;
|
|
137
|
+
let pattern = (dilatedDense[wordIdx] >> bitShiftX) & 0xFu;
|
|
138
|
+
let bits = pattern << bitBase;
|
|
139
|
+
if (inHi) { hi = hi | bits; } else { lo = lo | bits; }
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
masksOut[innerBlockIdx * 2u] = lo;
|
|
144
|
+
masksOut[innerBlockIdx * 2u + 1u] = hi;
|
|
145
|
+
|
|
146
|
+
var bt = 0u;
|
|
147
|
+
if (lo != 0u || hi != 0u) {
|
|
148
|
+
if (lo == 0xFFFFFFFFu && hi == 0xFFFFFFFFu) { bt = 1u; } else { bt = 2u; }
|
|
149
|
+
}
|
|
150
|
+
let typeWordIdx = innerBlockIdx >> 4u;
|
|
151
|
+
let typeBitShift = (innerBlockIdx & 15u) * 2u;
|
|
152
|
+
atomicOr(&typesOut[typeWordIdx], bt << typeBitShift);
|
|
153
|
+
}
|
|
154
|
+
`;
|
|
155
|
+
}
|
|
156
|
+
function dilateXWgsl() {
|
|
157
|
+
return /* wgsl */ `
|
|
158
|
+
struct DilateXUniforms {
|
|
159
|
+
numXWords: u32,
|
|
160
|
+
ny: u32,
|
|
161
|
+
nz: u32,
|
|
162
|
+
halfExtent: u32
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
@group(0) @binding(0) var<uniform> u: DilateXUniforms;
|
|
166
|
+
@group(0) @binding(1) var<storage, read> src: array<u32>;
|
|
167
|
+
@group(0) @binding(2) var<storage, read_write> dst: array<u32>;
|
|
168
|
+
|
|
169
|
+
fn readWord(rowOffset: u32, word: i32) -> u32 {
|
|
170
|
+
if (word < 0 || word >= i32(u.numXWords)) { return 0u; }
|
|
171
|
+
return src[rowOffset + u32(word)];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
@compute @workgroup_size(8, 4, 8)
|
|
175
|
+
fn main(@builtin(global_invocation_id) gid: vec3u) {
|
|
176
|
+
if (gid.x >= u.numXWords || gid.y >= u.ny || gid.z >= u.nz) { return; }
|
|
177
|
+
|
|
178
|
+
let xWord = gid.x;
|
|
179
|
+
let y = gid.y;
|
|
180
|
+
let z = gid.z;
|
|
181
|
+
let rowStride = u.numXWords;
|
|
182
|
+
let planeStride = rowStride * u.ny;
|
|
183
|
+
let rowOffset = y * rowStride + z * planeStride;
|
|
184
|
+
var output = src[rowOffset + xWord];
|
|
185
|
+
let rowBits = u.numXWords * 32u;
|
|
186
|
+
let r = min(u.halfExtent, rowBits);
|
|
187
|
+
for (var d = 1u; d <= r; d = d + 1u) {
|
|
188
|
+
let wordOffset = i32(d >> 5u);
|
|
189
|
+
let bitShift = d & 31u;
|
|
190
|
+
let baseWord = i32(xWord);
|
|
191
|
+
var shiftedPos = readWord(rowOffset, baseWord + wordOffset);
|
|
192
|
+
if (bitShift != 0u) {
|
|
193
|
+
shiftedPos = (shiftedPos >> bitShift) | (readWord(rowOffset, baseWord + wordOffset + 1) << (32u - bitShift));
|
|
194
|
+
}
|
|
195
|
+
var shiftedNeg = readWord(rowOffset, baseWord - wordOffset);
|
|
196
|
+
if (bitShift != 0u) {
|
|
197
|
+
shiftedNeg = (shiftedNeg << bitShift) | (readWord(rowOffset, baseWord - wordOffset - 1) >> (32u - bitShift));
|
|
198
|
+
}
|
|
199
|
+
output = output | shiftedPos | shiftedNeg;
|
|
200
|
+
if (output == 0xFFFFFFFFu) { break; }
|
|
201
|
+
}
|
|
202
|
+
dst[rowOffset + xWord] = output;
|
|
203
|
+
}
|
|
204
|
+
`;
|
|
205
|
+
}
|
|
206
|
+
function dilateYZWgsl() {
|
|
207
|
+
return /* wgsl */ `
|
|
208
|
+
struct DilateYZUniforms {
|
|
209
|
+
numXWords: u32,
|
|
210
|
+
ny: u32,
|
|
211
|
+
nz: u32,
|
|
212
|
+
halfExtent: u32,
|
|
213
|
+
stride: u32,
|
|
214
|
+
axisLen: u32
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
@group(0) @binding(0) var<uniform> u: DilateYZUniforms;
|
|
218
|
+
@group(0) @binding(1) var<storage, read> src: array<u32>;
|
|
219
|
+
@group(0) @binding(2) var<storage, read_write> dst: array<u32>;
|
|
220
|
+
|
|
221
|
+
@compute @workgroup_size(8, 4, 8)
|
|
222
|
+
fn main(@builtin(global_invocation_id) gid: vec3u) {
|
|
223
|
+
if (gid.x >= u.numXWords || gid.y >= u.ny || gid.z >= u.nz) { return; }
|
|
224
|
+
|
|
225
|
+
let xWord = gid.x;
|
|
226
|
+
let y = gid.y;
|
|
227
|
+
let z = gid.z;
|
|
228
|
+
let rowStride = u.numXWords;
|
|
229
|
+
let planeStride = rowStride * u.ny;
|
|
230
|
+
let outIdx = i32(xWord) + i32(y) * i32(rowStride) + i32(z) * i32(planeStride);
|
|
231
|
+
let pos = select(z, y, u.stride == rowStride);
|
|
232
|
+
let r = i32(u.halfExtent);
|
|
233
|
+
let lo = max(0, i32(pos) - r);
|
|
234
|
+
let hi = min(i32(u.axisLen) - 1, i32(pos) + r);
|
|
235
|
+
let baseIdx = outIdx - i32(pos) * i32(u.stride);
|
|
236
|
+
var output = 0u;
|
|
237
|
+
for (var p = lo; p <= hi; p = p + 1) {
|
|
238
|
+
output = output | src[baseIdx + p * i32(u.stride)];
|
|
239
|
+
if (output == 0xFFFFFFFFu) { break; }
|
|
240
|
+
}
|
|
241
|
+
dst[outIdx] = output;
|
|
242
|
+
}
|
|
243
|
+
`;
|
|
244
|
+
}
|
|
245
|
+
function makeBuffer(device, size, usage) {
|
|
246
|
+
return device.createBuffer({ size: Math.max(4, size), usage });
|
|
247
|
+
}
|
|
248
|
+
function writeUniform(device, values) {
|
|
249
|
+
const buffer = makeBuffer(device, 256, GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST);
|
|
250
|
+
device.queue.writeBuffer(buffer, 0, values.buffer, values.byteOffset, values.byteLength);
|
|
251
|
+
return buffer;
|
|
252
|
+
}
|
|
253
|
+
function createStoragePipeline(device, code) {
|
|
254
|
+
return device.createComputePipeline({
|
|
255
|
+
layout: 'auto',
|
|
256
|
+
compute: { module: device.createShaderModule({ code }), entryPoint: 'main' },
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
function blockAlignedExtent(halfExtent) {
|
|
260
|
+
return halfExtent === 0 ? 0 : Math.ceil(halfExtent / 4) * 4;
|
|
261
|
+
}
|
|
262
|
+
function chunkIsEmpty(src, ox, oy, oz, cx, cy, cz) {
|
|
263
|
+
const minBx = Math.max(0, Math.floor(ox / 4));
|
|
264
|
+
const minBy = Math.max(0, Math.floor(oy / 4));
|
|
265
|
+
const minBz = Math.max(0, Math.floor(oz / 4));
|
|
266
|
+
const maxBx = Math.min(src.nbx, Math.ceil((ox + cx) / 4));
|
|
267
|
+
const maxBy = Math.min(src.nby, Math.ceil((oy + cy) / 4));
|
|
268
|
+
const maxBz = Math.min(src.nbz, Math.ceil((oz + cz) / 4));
|
|
269
|
+
if (maxBx <= minBx || maxBy <= minBy || maxBz <= minBz) {
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
272
|
+
for (let bz = minBz; bz < maxBz; bz++) {
|
|
273
|
+
for (let by = minBy; by < maxBy; by++) {
|
|
274
|
+
for (let bx = minBx; bx < maxBx; bx++) {
|
|
275
|
+
const blockIdx = bx + by * src.nbx + bz * src.bStride;
|
|
276
|
+
if (readBlockType(src.types, blockIdx) !== BLOCK_EMPTY) {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
function chunkIsSaturated(src, ox, oy, oz, cx, cy, cz) {
|
|
285
|
+
if (ox < 0 || oy < 0 || oz < 0) {
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
if (ox + cx > src.nx || oy + cy > src.ny || oz + cz > src.nz) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
const minBx = ox >> 2;
|
|
292
|
+
const minBy = oy >> 2;
|
|
293
|
+
const minBz = oz >> 2;
|
|
294
|
+
const maxBx = (ox + cx + 3) >> 2;
|
|
295
|
+
const maxBy = (oy + cy + 3) >> 2;
|
|
296
|
+
const maxBz = (oz + cz + 3) >> 2;
|
|
297
|
+
for (let bz = minBz; bz < maxBz; bz++) {
|
|
298
|
+
for (let by = minBy; by < maxBy; by++) {
|
|
299
|
+
for (let bx = minBx; bx < maxBx; bx++) {
|
|
300
|
+
const blockIdx = bx + by * src.nbx + bz * src.bStride;
|
|
301
|
+
if (readBlockType(src.types, blockIdx) !== BLOCK_SOLID) {
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
function insertSaturatedInner(dst, innerOx, innerOy, innerOz, innerCx, innerCy, innerCz) {
|
|
310
|
+
const minBx = Math.max(0, innerOx >> 2);
|
|
311
|
+
const minBy = Math.max(0, innerOy >> 2);
|
|
312
|
+
const minBz = Math.max(0, innerOz >> 2);
|
|
313
|
+
const maxBx = Math.min(dst.nbx, (innerOx + innerCx + 3) >> 2);
|
|
314
|
+
const maxBy = Math.min(dst.nby, (innerOy + innerCy + 3) >> 2);
|
|
315
|
+
const maxBz = Math.min(dst.nbz, (innerOz + innerCz + 3) >> 2);
|
|
316
|
+
for (let bz = minBz; bz < maxBz; bz++) {
|
|
317
|
+
for (let by = minBy; by < maxBy; by++) {
|
|
318
|
+
const rowBase = by * dst.nbx + bz * dst.bStride;
|
|
319
|
+
let blockIdx = rowBase + minBx;
|
|
320
|
+
const endIdx = rowBase + maxBx;
|
|
321
|
+
while (blockIdx < endIdx) {
|
|
322
|
+
const w = blockIdx >>> 4;
|
|
323
|
+
const shift = (blockIdx & 15) << 1;
|
|
324
|
+
const remainingInWord = 16 - (blockIdx & 15);
|
|
325
|
+
const remainingInRow = endIdx - blockIdx;
|
|
326
|
+
const blocksToWrite = Math.min(remainingInWord, remainingInRow);
|
|
327
|
+
if (blocksToWrite === 16) {
|
|
328
|
+
dst.types[w] = SOLID_WORD;
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
const bits = blocksToWrite << 1;
|
|
332
|
+
const mask = (((1 << bits) - 1) >>> 0) << shift;
|
|
333
|
+
dst.types[w] = ((dst.types[w] & ~mask) | (SOLID_WORD & mask)) >>> 0;
|
|
334
|
+
}
|
|
335
|
+
blockIdx += blocksToWrite;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function applyChunkToDst(dst, typesOut, masksOut, cx, cy, cz, innerNx, innerNy, innerNz) {
|
|
341
|
+
const innerBx = innerNx >> 2;
|
|
342
|
+
const innerBy = innerNy >> 2;
|
|
343
|
+
const innerBz = innerNz >> 2;
|
|
344
|
+
const baseBx = cx >> 2;
|
|
345
|
+
const baseBy = cy >> 2;
|
|
346
|
+
const baseBz = cz >> 2;
|
|
347
|
+
let innerIdx = 0;
|
|
348
|
+
for (let bz = 0; bz < innerBz; bz++) {
|
|
349
|
+
const globalBz = baseBz + bz;
|
|
350
|
+
for (let by = 0; by < innerBy; by++) {
|
|
351
|
+
const globalBy = baseBy + by;
|
|
352
|
+
const baseGlobalIdx = baseBx + globalBy * dst.nbx + globalBz * dst.bStride;
|
|
353
|
+
for (let bx = 0; bx < innerBx; bx++, innerIdx++) {
|
|
354
|
+
const wordIdx = innerIdx >>> 4;
|
|
355
|
+
const bitShift = (innerIdx & 15) << 1;
|
|
356
|
+
const bt = (typesOut[wordIdx] >>> bitShift) & 3;
|
|
357
|
+
if (bt === BLOCK_EMPTY) {
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
const globalBlockIdx = baseGlobalIdx + bx;
|
|
361
|
+
const w = globalBlockIdx >>> 4;
|
|
362
|
+
const shift = (globalBlockIdx & 15) << 1;
|
|
363
|
+
dst.types[w] |= bt << shift;
|
|
364
|
+
if (bt === BLOCK_MIXED) {
|
|
365
|
+
const m2 = innerIdx * 2;
|
|
366
|
+
dst.masks.set(globalBlockIdx, masksOut[m2], masksOut[m2 + 1]);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
class GpuDilation {
|
|
373
|
+
static { this.NUM_SLOTS = 2; }
|
|
374
|
+
constructor(device) {
|
|
375
|
+
this.slots = [];
|
|
376
|
+
this.srcMeta = { nbx: 0, nby: 0, nbz: 0, bStride: 0, capMinusOne: 0 };
|
|
377
|
+
this.device = device;
|
|
378
|
+
this.extractPipeline = createStoragePipeline(device, extractWgsl());
|
|
379
|
+
this.compactPipeline = createStoragePipeline(device, compactWgsl());
|
|
380
|
+
this.dilateXPipeline = createStoragePipeline(device, dilateXWgsl());
|
|
381
|
+
this.dilateYZPipeline = createStoragePipeline(device, dilateYZWgsl());
|
|
382
|
+
for (let i = 0; i < GpuDilation.NUM_SLOTS; i++) {
|
|
383
|
+
const capacity = 1024 * 1024 * 4;
|
|
384
|
+
const typesOutCapacity = 64 * 1024;
|
|
385
|
+
const masksOutCapacity = 1024 * 1024;
|
|
386
|
+
this.slots.push({
|
|
387
|
+
bufferA: makeBuffer(device, capacity, GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_COPY_SRC),
|
|
388
|
+
bufferB: makeBuffer(device, capacity, GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_COPY_SRC),
|
|
389
|
+
readTypesBuffer: makeBuffer(device, typesOutCapacity, GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_MAP_READ),
|
|
390
|
+
readMasksBuffer: makeBuffer(device, masksOutCapacity, GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_MAP_READ),
|
|
391
|
+
typesOutBuffer: makeBuffer(device, typesOutCapacity, GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_COPY_SRC),
|
|
392
|
+
masksOutBuffer: makeBuffer(device, masksOutCapacity, GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_COPY_SRC),
|
|
393
|
+
capacity,
|
|
394
|
+
typesOutCapacity,
|
|
395
|
+
masksOutCapacity,
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
replaceBuffer(slot, key, size, usage) {
|
|
400
|
+
slot[key].destroy();
|
|
401
|
+
slot[key] = makeBuffer(this.device, size, usage);
|
|
402
|
+
}
|
|
403
|
+
ensureSlotBuffers(slot, numWords) {
|
|
404
|
+
const neededBytes = numWords * 4;
|
|
405
|
+
if (neededBytes <= slot.capacity) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
let cap = slot.capacity;
|
|
409
|
+
while (cap < neededBytes) {
|
|
410
|
+
cap *= 2;
|
|
411
|
+
}
|
|
412
|
+
this.replaceBuffer(slot, 'bufferA', cap, GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_COPY_SRC);
|
|
413
|
+
this.replaceBuffer(slot, 'bufferB', cap, GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_COPY_SRC);
|
|
414
|
+
slot.capacity = cap;
|
|
415
|
+
}
|
|
416
|
+
ensureSlotOutputBuffers(slot, innerBlocks) {
|
|
417
|
+
const typesBytes = ((innerBlocks + 15) >>> 4) * 4;
|
|
418
|
+
if (slot.typesOutCapacity < typesBytes) {
|
|
419
|
+
this.replaceBuffer(slot, 'typesOutBuffer', typesBytes, GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_COPY_SRC);
|
|
420
|
+
this.replaceBuffer(slot, 'readTypesBuffer', typesBytes, GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_MAP_READ);
|
|
421
|
+
slot.typesOutCapacity = typesBytes;
|
|
422
|
+
}
|
|
423
|
+
const masksBytes = innerBlocks * 8;
|
|
424
|
+
if (slot.masksOutCapacity < masksBytes) {
|
|
425
|
+
this.replaceBuffer(slot, 'masksOutBuffer', masksBytes, GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_COPY_SRC);
|
|
426
|
+
this.replaceBuffer(slot, 'readMasksBuffer', masksBytes, GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_MAP_READ);
|
|
427
|
+
slot.masksOutCapacity = masksBytes;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
uploadSrc(src) {
|
|
431
|
+
this.releaseSrc();
|
|
432
|
+
this.srcTypesBuffer = makeBuffer(this.device, src.types.byteLength, GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST);
|
|
433
|
+
this.device.queue.writeBuffer(this.srcTypesBuffer, 0, src.types.buffer, src.types.byteOffset, src.types.byteLength);
|
|
434
|
+
const keysU32 = new Uint32Array(src.masks.keys.buffer, src.masks.keys.byteOffset, src.masks.keys.length);
|
|
435
|
+
this.srcKeysBuffer = makeBuffer(this.device, keysU32.byteLength, GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST);
|
|
436
|
+
this.srcLoBuffer = makeBuffer(this.device, src.masks.lo.byteLength, GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST);
|
|
437
|
+
this.srcHiBuffer = makeBuffer(this.device, src.masks.hi.byteLength, GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST);
|
|
438
|
+
this.device.queue.writeBuffer(this.srcKeysBuffer, 0, keysU32.buffer, keysU32.byteOffset, keysU32.byteLength);
|
|
439
|
+
this.device.queue.writeBuffer(this.srcLoBuffer, 0, src.masks.lo.buffer, src.masks.lo.byteOffset, src.masks.lo.byteLength);
|
|
440
|
+
this.device.queue.writeBuffer(this.srcHiBuffer, 0, src.masks.hi.buffer, src.masks.hi.byteOffset, src.masks.hi.byteLength);
|
|
441
|
+
this.srcMeta = {
|
|
442
|
+
nbx: src.nbx,
|
|
443
|
+
nby: src.nby,
|
|
444
|
+
nbz: src.nbz,
|
|
445
|
+
bStride: src.bStride,
|
|
446
|
+
capMinusOne: src.masks.keys.length - 1,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
releaseSrc() {
|
|
450
|
+
this.srcTypesBuffer?.destroy();
|
|
451
|
+
this.srcKeysBuffer?.destroy();
|
|
452
|
+
this.srcLoBuffer?.destroy();
|
|
453
|
+
this.srcHiBuffer?.destroy();
|
|
454
|
+
this.srcTypesBuffer = undefined;
|
|
455
|
+
this.srcKeysBuffer = undefined;
|
|
456
|
+
this.srcLoBuffer = undefined;
|
|
457
|
+
this.srcHiBuffer = undefined;
|
|
458
|
+
}
|
|
459
|
+
submitChunkSparse(slotIdx, minBx, minBy, minBz, outerBx, outerBy, outerBz, haloBx, haloBy, haloBz, innerBx, innerBy, innerBz, halfExtentXZ, halfExtentY) {
|
|
460
|
+
if (!this.srcTypesBuffer || !this.srcKeysBuffer || !this.srcLoBuffer || !this.srcHiBuffer) {
|
|
461
|
+
throw new Error('GpuDilation: must call uploadSrc() before submitChunkSparse()');
|
|
462
|
+
}
|
|
463
|
+
const slot = this.slots[slotIdx];
|
|
464
|
+
const outerNx = outerBx * 4;
|
|
465
|
+
const outerNy = outerBy * 4;
|
|
466
|
+
const outerNz = outerBz * 4;
|
|
467
|
+
const numXWords = (outerNx + 31) >>> 5;
|
|
468
|
+
const numWords = numXWords * outerNy * outerNz;
|
|
469
|
+
const innerBlocks = innerBx * innerBy * innerBz;
|
|
470
|
+
const typesOutWords = (innerBlocks + 15) >>> 4;
|
|
471
|
+
this.ensureSlotBuffers(slot, numWords);
|
|
472
|
+
this.ensureSlotOutputBuffers(slot, innerBlocks);
|
|
473
|
+
const uniformBuffers = [];
|
|
474
|
+
const device = this.device;
|
|
475
|
+
function makeUniform(values) {
|
|
476
|
+
const buffer = writeUniform(device, values);
|
|
477
|
+
uniformBuffers.push(buffer);
|
|
478
|
+
return buffer;
|
|
479
|
+
}
|
|
480
|
+
{
|
|
481
|
+
const encoder = this.device.createCommandEncoder();
|
|
482
|
+
encoder.clearBuffer(slot.bufferA, 0, numWords * 4);
|
|
483
|
+
const uniforms = new Uint32Array([
|
|
484
|
+
minBx >>> 0,
|
|
485
|
+
minBy >>> 0,
|
|
486
|
+
minBz >>> 0,
|
|
487
|
+
outerBx,
|
|
488
|
+
outerBy,
|
|
489
|
+
outerBz,
|
|
490
|
+
numXWords,
|
|
491
|
+
this.srcMeta.nbx,
|
|
492
|
+
this.srcMeta.nby,
|
|
493
|
+
this.srcMeta.nbz,
|
|
494
|
+
this.srcMeta.bStride,
|
|
495
|
+
this.srcMeta.capMinusOne,
|
|
496
|
+
]);
|
|
497
|
+
const uniformBuffer = makeUniform(uniforms);
|
|
498
|
+
const bindGroup = this.device.createBindGroup({
|
|
499
|
+
layout: this.extractPipeline.getBindGroupLayout(0),
|
|
500
|
+
entries: [
|
|
501
|
+
{ binding: 0, resource: { buffer: uniformBuffer } },
|
|
502
|
+
{ binding: 1, resource: { buffer: this.srcTypesBuffer } },
|
|
503
|
+
{ binding: 2, resource: { buffer: this.srcKeysBuffer } },
|
|
504
|
+
{ binding: 3, resource: { buffer: this.srcLoBuffer } },
|
|
505
|
+
{ binding: 4, resource: { buffer: this.srcHiBuffer } },
|
|
506
|
+
{ binding: 5, resource: { buffer: slot.bufferA } },
|
|
507
|
+
],
|
|
508
|
+
});
|
|
509
|
+
const pass = encoder.beginComputePass();
|
|
510
|
+
pass.setPipeline(this.extractPipeline);
|
|
511
|
+
pass.setBindGroup(0, bindGroup);
|
|
512
|
+
pass.dispatchWorkgroups(Math.ceil(outerBx / 8), Math.ceil(outerBy / 4), Math.ceil(outerBz / 8));
|
|
513
|
+
pass.end();
|
|
514
|
+
this.device.queue.submit([encoder.finish()]);
|
|
515
|
+
}
|
|
516
|
+
{
|
|
517
|
+
const encoder = this.device.createCommandEncoder();
|
|
518
|
+
function dispatch(pipeline, src, dst, uniforms, wgX, wgY, wgZ) {
|
|
519
|
+
const uniformBuffer = makeUniform(uniforms);
|
|
520
|
+
const bindGroup = device.createBindGroup({
|
|
521
|
+
layout: pipeline.getBindGroupLayout(0),
|
|
522
|
+
entries: [
|
|
523
|
+
{ binding: 0, resource: { buffer: uniformBuffer } },
|
|
524
|
+
{ binding: 1, resource: { buffer: src } },
|
|
525
|
+
{ binding: 2, resource: { buffer: dst } },
|
|
526
|
+
],
|
|
527
|
+
});
|
|
528
|
+
const pass = encoder.beginComputePass();
|
|
529
|
+
pass.setPipeline(pipeline);
|
|
530
|
+
pass.setBindGroup(0, bindGroup);
|
|
531
|
+
pass.dispatchWorkgroups(wgX, wgY, wgZ);
|
|
532
|
+
pass.end();
|
|
533
|
+
}
|
|
534
|
+
dispatch(this.dilateXPipeline, slot.bufferA, slot.bufferB, new Uint32Array([numXWords, outerNy, outerNz, halfExtentXZ]), Math.ceil(numXWords / 8), Math.ceil(outerNy / 4), Math.ceil(outerNz / 8));
|
|
535
|
+
dispatch(this.dilateYZPipeline, slot.bufferB, slot.bufferA, new Uint32Array([numXWords, outerNy, outerNz, halfExtentXZ, numXWords * outerNy, outerNz]), Math.ceil(numXWords / 8), Math.ceil(outerNy / 4), Math.ceil(outerNz / 8));
|
|
536
|
+
dispatch(this.dilateYZPipeline, slot.bufferA, slot.bufferB, new Uint32Array([numXWords, outerNy, outerNz, halfExtentY, numXWords, outerNy]), Math.ceil(numXWords / 8), Math.ceil(outerNy / 4), Math.ceil(outerNz / 8));
|
|
537
|
+
encoder.clearBuffer(slot.typesOutBuffer, 0, typesOutWords * 4);
|
|
538
|
+
const compactUniformBuffer = makeUniform(new Uint32Array([haloBx, haloBy, haloBz, numXWords, innerBx, innerBy, innerBz, outerBy]));
|
|
539
|
+
const compactBindGroup = this.device.createBindGroup({
|
|
540
|
+
layout: this.compactPipeline.getBindGroupLayout(0),
|
|
541
|
+
entries: [
|
|
542
|
+
{ binding: 0, resource: { buffer: compactUniformBuffer } },
|
|
543
|
+
{ binding: 1, resource: { buffer: slot.bufferB } },
|
|
544
|
+
{ binding: 2, resource: { buffer: slot.typesOutBuffer } },
|
|
545
|
+
{ binding: 3, resource: { buffer: slot.masksOutBuffer } },
|
|
546
|
+
],
|
|
547
|
+
});
|
|
548
|
+
const pass = encoder.beginComputePass();
|
|
549
|
+
pass.setPipeline(this.compactPipeline);
|
|
550
|
+
pass.setBindGroup(0, compactBindGroup);
|
|
551
|
+
pass.dispatchWorkgroups(Math.ceil(innerBx / 8), Math.ceil(innerBy / 4), Math.ceil(innerBz / 8));
|
|
552
|
+
pass.end();
|
|
553
|
+
encoder.copyBufferToBuffer(slot.typesOutBuffer, 0, slot.readTypesBuffer, 0, typesOutWords * 4);
|
|
554
|
+
encoder.copyBufferToBuffer(slot.masksOutBuffer, 0, slot.readMasksBuffer, 0, innerBlocks * 8);
|
|
555
|
+
this.device.queue.submit([encoder.finish()]);
|
|
556
|
+
}
|
|
557
|
+
const typesPromise = (async () => {
|
|
558
|
+
await slot.readTypesBuffer.mapAsync(GPU_MAP_MODE_READ, 0, typesOutWords * 4);
|
|
559
|
+
const mapped = new Uint32Array(slot.readTypesBuffer.getMappedRange(0, typesOutWords * 4));
|
|
560
|
+
const out = new Uint32Array(typesOutWords);
|
|
561
|
+
out.set(mapped);
|
|
562
|
+
slot.readTypesBuffer.unmap();
|
|
563
|
+
return out;
|
|
564
|
+
})();
|
|
565
|
+
const masksPromise = (async () => {
|
|
566
|
+
await slot.readMasksBuffer.mapAsync(GPU_MAP_MODE_READ, 0, innerBlocks * 8);
|
|
567
|
+
const mapped = new Uint32Array(slot.readMasksBuffer.getMappedRange(0, innerBlocks * 8));
|
|
568
|
+
const out = new Uint32Array(innerBlocks * 2);
|
|
569
|
+
out.set(mapped);
|
|
570
|
+
slot.readMasksBuffer.unmap();
|
|
571
|
+
return out;
|
|
572
|
+
})();
|
|
573
|
+
void Promise.all([typesPromise, masksPromise]).then(() => {
|
|
574
|
+
for (const buffer of uniformBuffers) {
|
|
575
|
+
buffer.destroy();
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
return { types: typesPromise, masks: masksPromise };
|
|
579
|
+
}
|
|
580
|
+
destroy() {
|
|
581
|
+
this.releaseSrc();
|
|
582
|
+
for (const slot of this.slots) {
|
|
583
|
+
slot.bufferA.destroy();
|
|
584
|
+
slot.bufferB.destroy();
|
|
585
|
+
slot.readTypesBuffer.destroy();
|
|
586
|
+
slot.readMasksBuffer.destroy();
|
|
587
|
+
slot.typesOutBuffer.destroy();
|
|
588
|
+
slot.masksOutBuffer.destroy();
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
export async function gpuDilate3(src, halfExtentXZ, halfExtentY) {
|
|
593
|
+
if (halfExtentXZ === 0 && halfExtentY === 0) {
|
|
594
|
+
return src.clone();
|
|
595
|
+
}
|
|
596
|
+
if (!Number.isInteger(halfExtentXZ) || halfExtentXZ < 0) {
|
|
597
|
+
throw new Error(`gpuDilate3: halfExtentXZ=${halfExtentXZ} must be a non-negative integer`);
|
|
598
|
+
}
|
|
599
|
+
if (!Number.isInteger(halfExtentY) || halfExtentY < 0) {
|
|
600
|
+
throw new Error(`gpuDilate3: halfExtentY=${halfExtentY} must be a non-negative integer`);
|
|
601
|
+
}
|
|
602
|
+
const device = await getOrCreateDevice();
|
|
603
|
+
const gpu = new GpuDilation(device);
|
|
604
|
+
const dst = new SparseVoxelGrid(src.nx, src.ny, src.nz);
|
|
605
|
+
const haloX = blockAlignedExtent(halfExtentXZ);
|
|
606
|
+
const haloY = blockAlignedExtent(halfExtentY);
|
|
607
|
+
const haloZ = haloX;
|
|
608
|
+
const haloBx = haloX / 4;
|
|
609
|
+
const haloBy = haloY / 4;
|
|
610
|
+
const haloBz = haloZ / 4;
|
|
611
|
+
const innerStep = CHUNK_INNER & ~3;
|
|
612
|
+
let currentSlot = 0;
|
|
613
|
+
let inflight;
|
|
614
|
+
async function drainInflight() {
|
|
615
|
+
if (!inflight) {
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
const f = inflight;
|
|
619
|
+
inflight = undefined;
|
|
620
|
+
const [typesOut, masksOut] = await Promise.all([f.typesPromise, f.masksPromise]);
|
|
621
|
+
applyChunkToDst(dst, typesOut, masksOut, f.cx, f.cy, f.cz, f.innerNx, f.innerNy, f.innerNz);
|
|
622
|
+
}
|
|
623
|
+
gpu.uploadSrc(src);
|
|
624
|
+
try {
|
|
625
|
+
for (let cz = 0; cz < src.nz; cz += innerStep) {
|
|
626
|
+
for (let cy = 0; cy < src.ny; cy += innerStep) {
|
|
627
|
+
for (let cx = 0; cx < src.nx; cx += innerStep) {
|
|
628
|
+
const innerNx = Math.min(innerStep, src.nx - cx);
|
|
629
|
+
const innerNy = Math.min(innerStep, src.ny - cy);
|
|
630
|
+
const innerNz = Math.min(innerStep, src.nz - cz);
|
|
631
|
+
const ox = cx - haloX;
|
|
632
|
+
const oy = cy - haloY;
|
|
633
|
+
const oz = cz - haloZ;
|
|
634
|
+
const outerNx = innerNx + 2 * haloX;
|
|
635
|
+
const outerNy = innerNy + 2 * haloY;
|
|
636
|
+
const outerNz = innerNz + 2 * haloZ;
|
|
637
|
+
if (chunkIsEmpty(src, ox, oy, oz, outerNx, outerNy, outerNz)) {
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
if (chunkIsSaturated(src, ox, oy, oz, outerNx, outerNy, outerNz)) {
|
|
641
|
+
insertSaturatedInner(dst, cx, cy, cz, innerNx, innerNy, innerNz);
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
const innerBx = innerNx >> 2;
|
|
645
|
+
const innerBy = innerNy >> 2;
|
|
646
|
+
const innerBz = innerNz >> 2;
|
|
647
|
+
const outerBx = outerNx >> 2;
|
|
648
|
+
const outerBy = outerNy >> 2;
|
|
649
|
+
const outerBz = outerNz >> 2;
|
|
650
|
+
const minBx = Math.floor(ox / 4);
|
|
651
|
+
const minBy = Math.floor(oy / 4);
|
|
652
|
+
const minBz = Math.floor(oz / 4);
|
|
653
|
+
const { types, masks } = gpu.submitChunkSparse(currentSlot, minBx, minBy, minBz, outerBx, outerBy, outerBz, haloBx, haloBy, haloBz, innerBx, innerBy, innerBz, halfExtentXZ, halfExtentY);
|
|
654
|
+
if (inflight) {
|
|
655
|
+
await drainInflight();
|
|
656
|
+
}
|
|
657
|
+
inflight = {
|
|
658
|
+
typesPromise: types,
|
|
659
|
+
masksPromise: masks,
|
|
660
|
+
cx,
|
|
661
|
+
cy,
|
|
662
|
+
cz,
|
|
663
|
+
innerNx,
|
|
664
|
+
innerNy,
|
|
665
|
+
innerNz,
|
|
666
|
+
};
|
|
667
|
+
currentSlot = (currentSlot + 1) % GpuDilation.NUM_SLOTS;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
await drainInflight();
|
|
672
|
+
}
|
|
673
|
+
finally {
|
|
674
|
+
gpu.destroy();
|
|
675
|
+
}
|
|
676
|
+
return dst;
|
|
677
|
+
}
|