@multiplekex/shallot 0.2.5 → 0.3.0

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 (41) hide show
  1. package/package.json +1 -1
  2. package/src/core/component.ts +1 -1
  3. package/src/core/index.ts +1 -13
  4. package/src/core/math.ts +186 -0
  5. package/src/core/state.ts +1 -1
  6. package/src/core/xml.ts +56 -41
  7. package/src/extras/orbit/index.ts +1 -1
  8. package/src/extras/text/index.ts +10 -65
  9. package/src/extras/{water.ts → water/index.ts} +59 -4
  10. package/src/standard/raster/batch.ts +149 -0
  11. package/src/standard/raster/forward.ts +832 -0
  12. package/src/standard/raster/index.ts +146 -472
  13. package/src/standard/raster/shadow.ts +408 -0
  14. package/src/standard/raytracing/bvh/blas.ts +335 -87
  15. package/src/standard/raytracing/bvh/radix.ts +225 -228
  16. package/src/standard/raytracing/bvh/refit.ts +711 -0
  17. package/src/standard/raytracing/bvh/structs.ts +0 -55
  18. package/src/standard/raytracing/bvh/tlas.ts +153 -141
  19. package/src/standard/raytracing/bvh/traverse.ts +72 -64
  20. package/src/standard/raytracing/index.ts +233 -204
  21. package/src/standard/raytracing/instance.ts +30 -18
  22. package/src/standard/raytracing/ray.ts +1 -1
  23. package/src/standard/raytracing/shaders.ts +23 -40
  24. package/src/standard/render/camera.ts +10 -28
  25. package/src/standard/render/data.ts +1 -1
  26. package/src/standard/render/index.ts +68 -12
  27. package/src/standard/render/light.ts +2 -2
  28. package/src/standard/render/mesh.ts +404 -0
  29. package/src/standard/render/overlay.ts +5 -2
  30. package/src/standard/render/postprocess.ts +263 -267
  31. package/src/standard/render/surface/index.ts +81 -12
  32. package/src/standard/render/surface/shaders.ts +265 -11
  33. package/src/standard/render/surface/structs.ts +10 -0
  34. package/src/standard/tween/tween.ts +44 -115
  35. package/src/standard/render/mesh/box.ts +0 -20
  36. package/src/standard/render/mesh/index.ts +0 -315
  37. package/src/standard/render/mesh/plane.ts +0 -11
  38. package/src/standard/render/mesh/sphere.ts +0 -40
  39. package/src/standard/render/mesh/unified.ts +0 -96
  40. package/src/standard/render/surface/compile.ts +0 -65
  41. package/src/standard/render/surface/noise.ts +0 -58
@@ -195,77 +195,81 @@ interface PrefixPass {
195
195
  dispatch: [number, number];
196
196
  }
197
197
 
198
- class PrefixSum {
199
- private constructor(private passes: PrefixPass[]) {}
200
-
201
- static async create(device: GPUDevice, data: GPUBuffer, count: number): Promise<PrefixSum> {
202
- const passes: PrefixPass[] = [];
203
- const module = device.createShaderModule({ code: prefixSumShader });
204
- await PrefixSum.build(device, module, data, count, passes);
205
- return new PrefixSum(passes);
206
- }
207
-
208
- private static async build(
209
- device: GPUDevice,
210
- module: GPUShaderModule,
211
- data: GPUBuffer,
212
- count: number,
213
- passes: PrefixPass[]
214
- ): Promise<void> {
215
- const wgCount = Math.ceil(count / ITEMS_PER_WG);
216
- const dispatch = dispatchSize(device, wgCount);
217
-
218
- const blockSums = device.createBuffer({
219
- size: Math.max(wgCount * 4, 4),
220
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
221
- });
222
-
223
- const layout = device.createBindGroupLayout({
224
- entries: [
225
- { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
226
- { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
227
- ],
228
- });
229
-
230
- const bindGroup = device.createBindGroup({
231
- layout,
232
- entries: [
233
- { binding: 0, resource: { buffer: data } },
234
- { binding: 1, resource: { buffer: blockSums } },
235
- ],
236
- });
198
+ interface PrefixSumState {
199
+ passes: PrefixPass[];
200
+ }
237
201
 
238
- const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [layout] });
202
+ async function buildPrefixPasses(
203
+ device: GPUDevice,
204
+ module: GPUShaderModule,
205
+ data: GPUBuffer,
206
+ count: number,
207
+ passes: PrefixPass[]
208
+ ): Promise<void> {
209
+ const wgCount = Math.ceil(count / ITEMS_PER_WG);
210
+ const dispatch = dispatchSize(device, wgCount);
211
+
212
+ const blockSums = device.createBuffer({
213
+ size: Math.max(wgCount * 4, 4),
214
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
215
+ });
216
+
217
+ const layout = device.createBindGroupLayout({
218
+ entries: [
219
+ { binding: 0, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
220
+ { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
221
+ ],
222
+ });
223
+
224
+ const bindGroup = device.createBindGroup({
225
+ layout,
226
+ entries: [
227
+ { binding: 0, resource: { buffer: data } },
228
+ { binding: 1, resource: { buffer: blockSums } },
229
+ ],
230
+ });
231
+
232
+ const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [layout] });
233
+
234
+ passes.push({
235
+ pipeline: await device.createComputePipelineAsync({
236
+ layout: pipelineLayout,
237
+ compute: { module, entryPoint: "scan", constants: { COUNT: count } },
238
+ }),
239
+ bindGroup,
240
+ dispatch,
241
+ });
242
+
243
+ if (wgCount > 1) {
244
+ await buildPrefixPasses(device, module, blockSums, wgCount, passes);
239
245
 
240
246
  passes.push({
241
247
  pipeline: await device.createComputePipelineAsync({
242
248
  layout: pipelineLayout,
243
- compute: { module, entryPoint: "scan", constants: { COUNT: count } },
249
+ compute: { module, entryPoint: "addBlocks", constants: { COUNT: count } },
244
250
  }),
245
251
  bindGroup,
246
252
  dispatch,
247
253
  });
248
-
249
- if (wgCount > 1) {
250
- await PrefixSum.build(device, module, blockSums, wgCount, passes);
251
-
252
- passes.push({
253
- pipeline: await device.createComputePipelineAsync({
254
- layout: pipelineLayout,
255
- compute: { module, entryPoint: "addBlocks", constants: { COUNT: count } },
256
- }),
257
- bindGroup,
258
- dispatch,
259
- });
260
- }
261
254
  }
255
+ }
262
256
 
263
- dispatch(pass: GPUComputePassEncoder): void {
264
- for (const p of this.passes) {
265
- pass.setPipeline(p.pipeline);
266
- pass.setBindGroup(0, p.bindGroup);
267
- pass.dispatchWorkgroups(p.dispatch[0], p.dispatch[1], 1);
268
- }
257
+ async function createPrefixSum(
258
+ device: GPUDevice,
259
+ data: GPUBuffer,
260
+ count: number
261
+ ): Promise<PrefixSumState> {
262
+ const passes: PrefixPass[] = [];
263
+ const module = device.createShaderModule({ code: prefixSumShader });
264
+ await buildPrefixPasses(device, module, data, count, passes);
265
+ return { passes };
266
+ }
267
+
268
+ function dispatchPrefixSum(state: PrefixSumState, pass: GPUComputePassEncoder): void {
269
+ for (const p of state.passes) {
270
+ pass.setPipeline(p.pipeline);
271
+ pass.setBindGroup(0, p.bindGroup);
272
+ pass.dispatchWorkgroups(p.dispatch[0], p.dispatch[1], 1);
269
273
  }
270
274
  }
271
275
 
@@ -274,189 +278,182 @@ interface RadixPass {
274
278
  reorder: { pipeline: GPUComputePipeline; bindGroup: GPUBindGroup };
275
279
  }
276
280
 
277
- class RadixSort {
278
- private constructor(
279
- private passes: RadixPass[],
280
- private prefixSum: PrefixSum,
281
- private workgroups: [number, number]
282
- ) {}
283
-
284
- static async create(
285
- device: GPUDevice,
286
- keys: GPUBuffer,
287
- values: GPUBuffer,
288
- count: number
289
- ): Promise<RadixSort> {
290
- const wgCount = Math.ceil(count / WG_SIZE);
291
- const workgroups = dispatchSize(device, wgCount);
292
-
293
- const tmpKeys = device.createBuffer({
294
- size: count * 4,
295
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
296
- });
297
- const tmpVals = device.createBuffer({
298
- size: count * 4,
299
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
300
- });
301
- const localSums = device.createBuffer({
302
- size: count * 4,
303
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
304
- });
305
- const blockSums = device.createBuffer({
306
- size: 4 * wgCount * 4,
307
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
308
- });
309
-
310
- const prefixSum = await PrefixSum.create(device, blockSums, 4 * wgCount);
311
-
312
- const blockSumModule = device.createShaderModule({ code: blockSumShader });
313
- const reorderModule = device.createShaderModule({ code: reorderShader });
314
-
315
- const blockSumLayout = device.createBindGroupLayout({
316
- entries: [
317
- {
318
- binding: 0,
319
- visibility: GPUShaderStage.COMPUTE,
320
- buffer: { type: "read-only-storage" },
321
- },
322
- { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
323
- { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
324
- ],
325
- });
281
+ interface RadixSortState {
282
+ passes: RadixPass[];
283
+ prefixSum: PrefixSumState;
284
+ workgroups: [number, number];
285
+ }
326
286
 
327
- const reorderLayout = device.createBindGroupLayout({
328
- entries: [
329
- {
330
- binding: 0,
331
- visibility: GPUShaderStage.COMPUTE,
332
- buffer: { type: "read-only-storage" },
333
- },
334
- { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
335
- {
336
- binding: 2,
337
- visibility: GPUShaderStage.COMPUTE,
338
- buffer: { type: "read-only-storage" },
339
- },
340
- {
341
- binding: 3,
342
- visibility: GPUShaderStage.COMPUTE,
343
- buffer: { type: "read-only-storage" },
344
- },
345
- {
346
- binding: 4,
347
- visibility: GPUShaderStage.COMPUTE,
348
- buffer: { type: "read-only-storage" },
349
- },
350
- { binding: 5, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
351
- ],
352
- });
287
+ export interface RadixSortConfig {
288
+ keys: GPUBuffer;
289
+ values: GPUBuffer;
290
+ count: number;
291
+ }
353
292
 
354
- const pipelinePromises: Promise<{
355
- blockSum: GPUComputePipeline;
356
- reorder: GPUComputePipeline;
357
- }>[] = [];
358
-
359
- for (let bit = 0; bit < 32; bit += 2) {
360
- pipelinePromises.push(
361
- (async () => {
362
- const [blockSumPipeline, reorderPipeline] = await Promise.all([
363
- device.createComputePipelineAsync({
364
- layout: device.createPipelineLayout({
365
- bindGroupLayouts: [blockSumLayout],
366
- }),
367
- compute: {
368
- module: blockSumModule,
369
- entryPoint: "main",
370
- constants: { WG_COUNT: wgCount, BIT: bit, COUNT: count },
371
- },
372
- }),
373
- device.createComputePipelineAsync({
374
- layout: device.createPipelineLayout({
375
- bindGroupLayouts: [reorderLayout],
376
- }),
377
- compute: {
378
- module: reorderModule,
379
- entryPoint: "main",
380
- constants: { WG_COUNT: wgCount, BIT: bit, COUNT: count },
381
- },
293
+ export async function createRadixSort(
294
+ device: GPUDevice,
295
+ config: RadixSortConfig
296
+ ): Promise<RadixSortState> {
297
+ const { keys, values, count } = config;
298
+ const wgCount = Math.ceil(count / WG_SIZE);
299
+ const workgroups = dispatchSize(device, wgCount);
300
+
301
+ const tmpKeys = device.createBuffer({
302
+ size: count * 4,
303
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
304
+ });
305
+ const tmpVals = device.createBuffer({
306
+ size: count * 4,
307
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
308
+ });
309
+ const localSums = device.createBuffer({
310
+ size: count * 4,
311
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
312
+ });
313
+ const blockSums = device.createBuffer({
314
+ size: 4 * wgCount * 4,
315
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
316
+ });
317
+
318
+ const prefixSum = await createPrefixSum(device, blockSums, 4 * wgCount);
319
+
320
+ const blockSumModule = device.createShaderModule({ code: blockSumShader });
321
+ const reorderModule = device.createShaderModule({ code: reorderShader });
322
+
323
+ const blockSumLayout = device.createBindGroupLayout({
324
+ entries: [
325
+ {
326
+ binding: 0,
327
+ visibility: GPUShaderStage.COMPUTE,
328
+ buffer: { type: "read-only-storage" },
329
+ },
330
+ { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
331
+ { binding: 2, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
332
+ ],
333
+ });
334
+
335
+ const reorderLayout = device.createBindGroupLayout({
336
+ entries: [
337
+ {
338
+ binding: 0,
339
+ visibility: GPUShaderStage.COMPUTE,
340
+ buffer: { type: "read-only-storage" },
341
+ },
342
+ { binding: 1, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
343
+ {
344
+ binding: 2,
345
+ visibility: GPUShaderStage.COMPUTE,
346
+ buffer: { type: "read-only-storage" },
347
+ },
348
+ {
349
+ binding: 3,
350
+ visibility: GPUShaderStage.COMPUTE,
351
+ buffer: { type: "read-only-storage" },
352
+ },
353
+ {
354
+ binding: 4,
355
+ visibility: GPUShaderStage.COMPUTE,
356
+ buffer: { type: "read-only-storage" },
357
+ },
358
+ { binding: 5, visibility: GPUShaderStage.COMPUTE, buffer: { type: "storage" } },
359
+ ],
360
+ });
361
+
362
+ const pipelinePromises: Promise<{
363
+ blockSum: GPUComputePipeline;
364
+ reorder: GPUComputePipeline;
365
+ }>[] = [];
366
+
367
+ for (let bit = 0; bit < 32; bit += 2) {
368
+ pipelinePromises.push(
369
+ (async () => {
370
+ const [blockSumPipeline, reorderPipeline] = await Promise.all([
371
+ device.createComputePipelineAsync({
372
+ layout: device.createPipelineLayout({
373
+ bindGroupLayouts: [blockSumLayout],
382
374
  }),
383
- ]);
384
- return { blockSum: blockSumPipeline, reorder: reorderPipeline };
385
- })()
386
- );
387
- }
388
-
389
- const pipelines = await Promise.all(pipelinePromises);
390
- const passes: RadixPass[] = [];
391
-
392
- for (let i = 0; i < 16; i++) {
393
- const bit = i * 2;
394
- const even = bit % 4 === 0;
395
- const inK = even ? keys : tmpKeys;
396
- const inV = even ? values : tmpVals;
397
- const outK = even ? tmpKeys : keys;
398
- const outV = even ? tmpVals : values;
399
-
400
- passes.push({
401
- blockSum: {
402
- pipeline: pipelines[i].blockSum,
403
- bindGroup: device.createBindGroup({
404
- layout: blockSumLayout,
405
- entries: [
406
- { binding: 0, resource: { buffer: inK } },
407
- { binding: 1, resource: { buffer: localSums } },
408
- { binding: 2, resource: { buffer: blockSums } },
409
- ],
375
+ compute: {
376
+ module: blockSumModule,
377
+ entryPoint: "main",
378
+ constants: { WG_COUNT: wgCount, BIT: bit, COUNT: count },
379
+ },
410
380
  }),
411
- },
412
- reorder: {
413
- pipeline: pipelines[i].reorder,
414
- bindGroup: device.createBindGroup({
415
- layout: reorderLayout,
416
- entries: [
417
- { binding: 0, resource: { buffer: inK } },
418
- { binding: 1, resource: { buffer: outK } },
419
- { binding: 2, resource: { buffer: localSums } },
420
- { binding: 3, resource: { buffer: blockSums } },
421
- { binding: 4, resource: { buffer: inV } },
422
- { binding: 5, resource: { buffer: outV } },
423
- ],
381
+ device.createComputePipelineAsync({
382
+ layout: device.createPipelineLayout({
383
+ bindGroupLayouts: [reorderLayout],
384
+ }),
385
+ compute: {
386
+ module: reorderModule,
387
+ entryPoint: "main",
388
+ constants: { WG_COUNT: wgCount, BIT: bit, COUNT: count },
389
+ },
424
390
  }),
425
- },
426
- });
427
- }
428
-
429
- return new RadixSort(passes, prefixSum, workgroups);
391
+ ]);
392
+ return { blockSum: blockSumPipeline, reorder: reorderPipeline };
393
+ })()
394
+ );
430
395
  }
431
396
 
432
- dispatch(pass: GPUComputePassEncoder): void {
433
- const [x, y] = this.workgroups;
434
- for (const p of this.passes) {
435
- pass.setPipeline(p.blockSum.pipeline);
436
- pass.setBindGroup(0, p.blockSum.bindGroup);
437
- pass.dispatchWorkgroups(x, y, 1);
397
+ const pipelines = await Promise.all(pipelinePromises);
398
+ const passes: RadixPass[] = [];
438
399
 
439
- this.prefixSum.dispatch(pass);
400
+ for (let i = 0; i < 16; i++) {
401
+ const bit = i * 2;
402
+ const even = bit % 4 === 0;
403
+ const inK = even ? keys : tmpKeys;
404
+ const inV = even ? values : tmpVals;
405
+ const outK = even ? tmpKeys : keys;
406
+ const outV = even ? tmpVals : values;
440
407
 
441
- pass.setPipeline(p.reorder.pipeline);
442
- pass.setBindGroup(0, p.reorder.bindGroup);
443
- pass.dispatchWorkgroups(x, y, 1);
444
- }
408
+ passes.push({
409
+ blockSum: {
410
+ pipeline: pipelines[i].blockSum,
411
+ bindGroup: device.createBindGroup({
412
+ layout: blockSumLayout,
413
+ entries: [
414
+ { binding: 0, resource: { buffer: inK } },
415
+ { binding: 1, resource: { buffer: localSums } },
416
+ { binding: 2, resource: { buffer: blockSums } },
417
+ ],
418
+ }),
419
+ },
420
+ reorder: {
421
+ pipeline: pipelines[i].reorder,
422
+ bindGroup: device.createBindGroup({
423
+ layout: reorderLayout,
424
+ entries: [
425
+ { binding: 0, resource: { buffer: inK } },
426
+ { binding: 1, resource: { buffer: outK } },
427
+ { binding: 2, resource: { buffer: localSums } },
428
+ { binding: 3, resource: { buffer: blockSums } },
429
+ { binding: 4, resource: { buffer: inV } },
430
+ { binding: 5, resource: { buffer: outV } },
431
+ ],
432
+ }),
433
+ },
434
+ });
445
435
  }
446
- }
447
436
 
448
- export interface RadixSortConfig {
449
- keys: GPUBuffer;
450
- values: GPUBuffer;
451
- count: number;
437
+ return { passes, prefixSum, workgroups };
452
438
  }
453
439
 
454
- export function createRadixSort(device: GPUDevice, config: RadixSortConfig): Promise<RadixSort> {
455
- return RadixSort.create(device, config.keys, config.values, config.count);
440
+ export function dispatchRadixSort(state: RadixSortState, pass: GPUComputePassEncoder): void {
441
+ const [x, y] = state.workgroups;
442
+ for (const p of state.passes) {
443
+ pass.setPipeline(p.blockSum.pipeline);
444
+ pass.setBindGroup(0, p.blockSum.bindGroup);
445
+ pass.dispatchWorkgroups(x, y, 1);
446
+
447
+ dispatchPrefixSum(state.prefixSum, pass);
448
+
449
+ pass.setPipeline(p.reorder.pipeline);
450
+ pass.setBindGroup(0, p.reorder.bindGroup);
451
+ pass.dispatchWorkgroups(x, y, 1);
452
+ }
456
453
  }
457
454
 
458
455
  export function createRadixSortNode(config: RadixSortConfig): ComputeNode {
459
- let sort: RadixSort | null = null;
456
+ let sort: RadixSortState | null = null;
460
457
 
461
458
  return {
462
459
  id: "radix-sort",
@@ -469,7 +466,7 @@ export function createRadixSortNode(config: RadixSortConfig): ComputeNode {
469
466
 
470
467
  execute(ctx: ExecutionContext) {
471
468
  const pass = ctx.encoder.beginComputePass();
472
- sort!.dispatch(pass);
469
+ dispatchRadixSort(sort!, pass);
473
470
  pass.end();
474
471
  },
475
472
  };