@fjandin/react-shader 0.0.19 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +248 -22
- package/dist/ReactGpuShader.d.ts +3 -4
- package/dist/ReactGpuShader.d.ts.map +1 -1
- package/dist/hooks/useWebGPU.d.ts +2 -2
- package/dist/hooks/useWebGPU.d.ts.map +1 -1
- package/dist/index.cjs +174 -134
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +174 -134
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -266,30 +266,15 @@ function isVec3(value) {
|
|
|
266
266
|
function isVec4(value) {
|
|
267
267
|
return Array.isArray(value) && value.length === 4 && typeof value[0] === "number";
|
|
268
268
|
}
|
|
269
|
-
function isVec4Array(value) {
|
|
270
|
-
return Array.isArray(value) && value.length > 0 && Array.isArray(value[0]) && value[0].length === 4;
|
|
271
|
-
}
|
|
272
269
|
function inferWgslType(value) {
|
|
273
|
-
if (typeof value === "number")
|
|
274
|
-
return
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
arrayLength: 100
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
if (isVec4(value)) {
|
|
285
|
-
return { wgslType: "vec4f", baseType: "vec4f", isArray: false, arrayLength: 0 };
|
|
286
|
-
}
|
|
287
|
-
if (isVec3(value)) {
|
|
288
|
-
return { wgslType: "vec3f", baseType: "vec3f", isArray: false, arrayLength: 0 };
|
|
289
|
-
}
|
|
290
|
-
if (isVec2(value)) {
|
|
291
|
-
return { wgslType: "vec2f", baseType: "vec2f", isArray: false, arrayLength: 0 };
|
|
292
|
-
}
|
|
270
|
+
if (typeof value === "number")
|
|
271
|
+
return "f32";
|
|
272
|
+
if (isVec4(value))
|
|
273
|
+
return "vec4f";
|
|
274
|
+
if (isVec3(value))
|
|
275
|
+
return "vec3f";
|
|
276
|
+
if (isVec2(value))
|
|
277
|
+
return "vec2f";
|
|
293
278
|
throw new Error(`Unsupported uniform value type: ${typeof value}`);
|
|
294
279
|
}
|
|
295
280
|
function getTypeAlignment(type) {
|
|
@@ -315,7 +300,6 @@ function getTypeSize(type) {
|
|
|
315
300
|
return 16;
|
|
316
301
|
}
|
|
317
302
|
}
|
|
318
|
-
var UNIFORM_ARRAY_STRIDE = 16;
|
|
319
303
|
var DEFAULT_UNIFORMS = [
|
|
320
304
|
{ name: "iTime", baseType: "f32" },
|
|
321
305
|
{ name: "iMouseLeftDown", baseType: "f32" },
|
|
@@ -330,49 +314,20 @@ function calculateUniformLayout(customUniforms) {
|
|
|
330
314
|
const alignment = getTypeAlignment(baseType);
|
|
331
315
|
const size = getTypeSize(baseType);
|
|
332
316
|
offset = Math.ceil(offset / alignment) * alignment;
|
|
333
|
-
fields.push({ name, type: baseType, offset, size
|
|
317
|
+
fields.push({ name, type: baseType, offset, size });
|
|
334
318
|
offset += size;
|
|
335
319
|
};
|
|
336
|
-
const addArrayField = (name, baseType, arrayLength) => {
|
|
337
|
-
offset = Math.ceil(offset / 16) * 16;
|
|
338
|
-
const totalSize = arrayLength * UNIFORM_ARRAY_STRIDE;
|
|
339
|
-
fields.push({
|
|
340
|
-
name,
|
|
341
|
-
type: `array<${baseType}, ${arrayLength}>`,
|
|
342
|
-
offset,
|
|
343
|
-
size: totalSize,
|
|
344
|
-
isArray: true,
|
|
345
|
-
arrayLength,
|
|
346
|
-
elementStride: UNIFORM_ARRAY_STRIDE
|
|
347
|
-
});
|
|
348
|
-
offset += totalSize;
|
|
349
|
-
};
|
|
350
320
|
for (const u of DEFAULT_UNIFORMS) {
|
|
351
321
|
addField(u.name, u.baseType);
|
|
352
322
|
}
|
|
353
323
|
if (customUniforms) {
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
scalarEntries.push({ name, inferred });
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
for (const { name } of arrayEntries) {
|
|
365
|
-
scalarEntries.push({
|
|
366
|
-
name: `${name}_count`,
|
|
367
|
-
inferred: { wgslType: "f32", baseType: "f32", isArray: false, arrayLength: 0 }
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
scalarEntries.sort((a, b) => getTypeAlignment(b.inferred.baseType) - getTypeAlignment(a.inferred.baseType));
|
|
371
|
-
for (const { name, inferred } of scalarEntries) {
|
|
372
|
-
addField(name, inferred.baseType);
|
|
373
|
-
}
|
|
374
|
-
for (const { name, inferred } of arrayEntries) {
|
|
375
|
-
addArrayField(name, inferred.baseType, inferred.arrayLength);
|
|
324
|
+
const entries = Object.entries(customUniforms).map(([name, value]) => ({
|
|
325
|
+
name,
|
|
326
|
+
baseType: inferWgslType(value)
|
|
327
|
+
}));
|
|
328
|
+
entries.sort((a, b) => getTypeAlignment(b.baseType) - getTypeAlignment(a.baseType));
|
|
329
|
+
for (const { name, baseType } of entries) {
|
|
330
|
+
addField(name, baseType);
|
|
376
331
|
}
|
|
377
332
|
}
|
|
378
333
|
const bufferSize = Math.ceil(offset / 16) * 16;
|
|
@@ -387,21 +342,9 @@ ${members}
|
|
|
387
342
|
}
|
|
388
343
|
function packUniformValue(field, value, floatData) {
|
|
389
344
|
const floatOffset = field.offset / 4;
|
|
390
|
-
if (
|
|
391
|
-
const stride = field.elementStride / 4;
|
|
392
|
-
const maxLen = field.arrayLength;
|
|
393
|
-
if (isVec4Array(value)) {
|
|
394
|
-
for (let i = 0;i < value.length && i < maxLen; i++) {
|
|
395
|
-
const elemOffset = floatOffset + i * stride;
|
|
396
|
-
floatData[elemOffset] = value[i][0];
|
|
397
|
-
floatData[elemOffset + 1] = value[i][1];
|
|
398
|
-
floatData[elemOffset + 2] = value[i][2];
|
|
399
|
-
floatData[elemOffset + 3] = value[i][3];
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
} else if (typeof value === "number") {
|
|
345
|
+
if (typeof value === "number") {
|
|
403
346
|
floatData[floatOffset] = value;
|
|
404
|
-
} else if (Array.isArray(value)
|
|
347
|
+
} else if (Array.isArray(value)) {
|
|
405
348
|
for (let i = 0;i < value.length; i++) {
|
|
406
349
|
floatData[floatOffset + i] = value[i];
|
|
407
350
|
}
|
|
@@ -429,11 +372,60 @@ fn main(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
|
|
|
429
372
|
return output;
|
|
430
373
|
}
|
|
431
374
|
`;
|
|
432
|
-
function
|
|
375
|
+
function getStorageBufferNames(defs) {
|
|
376
|
+
if (!defs)
|
|
377
|
+
return [];
|
|
378
|
+
return Object.keys(defs).sort();
|
|
379
|
+
}
|
|
380
|
+
function createStorageBuffer(device, name, binding, data) {
|
|
381
|
+
const length = Math.max(data.length, 1);
|
|
382
|
+
const byteSize = length * 16;
|
|
383
|
+
const buffer = device.createBuffer({
|
|
384
|
+
label: `storage: ${name}`,
|
|
385
|
+
size: byteSize,
|
|
386
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
|
|
387
|
+
});
|
|
388
|
+
const packingArray = new Float32Array(length * 4);
|
|
389
|
+
for (let i = 0;i < data.length; i++) {
|
|
390
|
+
const off = i * 4;
|
|
391
|
+
packingArray[off] = data[i][0];
|
|
392
|
+
packingArray[off + 1] = data[i][1];
|
|
393
|
+
packingArray[off + 2] = data[i][2];
|
|
394
|
+
packingArray[off + 3] = data[i][3];
|
|
395
|
+
}
|
|
396
|
+
device.queue.writeBuffer(buffer, 0, packingArray);
|
|
397
|
+
return { name, binding, buffer, currentLength: length, dataLength: data.length, packingArray };
|
|
398
|
+
}
|
|
399
|
+
function packAndUploadStorageBuffer(device, entry, data) {
|
|
400
|
+
const arr = entry.packingArray;
|
|
401
|
+
for (let i = 0;i < data.length; i++) {
|
|
402
|
+
const off = i * 4;
|
|
403
|
+
arr[off] = data[i][0];
|
|
404
|
+
arr[off + 1] = data[i][1];
|
|
405
|
+
arr[off + 2] = data[i][2];
|
|
406
|
+
arr[off + 3] = data[i][3];
|
|
407
|
+
}
|
|
408
|
+
const uploadLength = Math.max(entry.dataLength, 1);
|
|
409
|
+
device.queue.writeBuffer(entry.buffer, 0, arr, 0, uploadLength * 4);
|
|
410
|
+
}
|
|
411
|
+
function rebuildBindGroup(state) {
|
|
412
|
+
const entries = [{ binding: 0, resource: { buffer: state.uniformBuffer } }];
|
|
413
|
+
for (const sb of state.storageBuffers) {
|
|
414
|
+
entries.push({ binding: sb.binding, resource: { buffer: sb.buffer } });
|
|
415
|
+
}
|
|
416
|
+
return state.device.createBindGroup({
|
|
417
|
+
layout: state.bindGroupLayout,
|
|
418
|
+
entries
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
function createFragmentShader(userCode, layout, storageBufferNames) {
|
|
422
|
+
const storageDeclarations = storageBufferNames.map((name, i) => `@group(0) @binding(${i + 1}) var<storage, read> ${name}: array<vec4f>;`).join(`
|
|
423
|
+
`);
|
|
433
424
|
return `
|
|
434
425
|
${generateUniformStruct(layout)}
|
|
435
426
|
|
|
436
427
|
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
|
428
|
+
${storageDeclarations}
|
|
437
429
|
|
|
438
430
|
${userCode}
|
|
439
431
|
|
|
@@ -446,7 +438,7 @@ fn main(@location(0) uv: vec2f) -> @location(0) vec4f {
|
|
|
446
438
|
}
|
|
447
439
|
`;
|
|
448
440
|
}
|
|
449
|
-
async function initializeWebGPU(canvas, fragmentSource, customUniforms) {
|
|
441
|
+
async function initializeWebGPU(canvas, fragmentSource, customUniforms, storageBufferDefs) {
|
|
450
442
|
if (!navigator.gpu) {
|
|
451
443
|
throw new Error("WebGPU not supported in this browser");
|
|
452
444
|
}
|
|
@@ -469,36 +461,43 @@ async function initializeWebGPU(canvas, fragmentSource, customUniforms) {
|
|
|
469
461
|
alphaMode: "premultiplied"
|
|
470
462
|
});
|
|
471
463
|
const uniformLayout = calculateUniformLayout(customUniforms);
|
|
464
|
+
const storageBufferNames = getStorageBufferNames(storageBufferDefs);
|
|
472
465
|
const vertexModule = device.createShaderModule({
|
|
473
466
|
label: "vertex shader",
|
|
474
467
|
code: VERTEX_SHADER
|
|
475
468
|
});
|
|
476
469
|
const fragmentModule = device.createShaderModule({
|
|
477
470
|
label: "fragment shader",
|
|
478
|
-
code: createFragmentShader(fragmentSource, uniformLayout)
|
|
471
|
+
code: createFragmentShader(fragmentSource, uniformLayout, storageBufferNames)
|
|
479
472
|
});
|
|
480
473
|
const uniformBuffer = device.createBuffer({
|
|
481
474
|
label: "uniforms",
|
|
482
475
|
size: uniformLayout.bufferSize,
|
|
483
476
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
484
477
|
});
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
478
|
+
const storageBuffers = storageBufferNames.map((name, i) => createStorageBuffer(device, name, i + 1, storageBufferDefs?.[name] ?? []));
|
|
479
|
+
const layoutEntries = [
|
|
480
|
+
{
|
|
481
|
+
binding: 0,
|
|
482
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
483
|
+
buffer: { type: "uniform" }
|
|
484
|
+
}
|
|
485
|
+
];
|
|
486
|
+
for (const sb of storageBuffers) {
|
|
487
|
+
layoutEntries.push({
|
|
488
|
+
binding: sb.binding,
|
|
489
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
490
|
+
buffer: { type: "read-only-storage" }
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
const bindGroupLayout = device.createBindGroupLayout({ entries: layoutEntries });
|
|
494
|
+
const bindGroupEntries = [{ binding: 0, resource: { buffer: uniformBuffer } }];
|
|
495
|
+
for (const sb of storageBuffers) {
|
|
496
|
+
bindGroupEntries.push({ binding: sb.binding, resource: { buffer: sb.buffer } });
|
|
497
|
+
}
|
|
494
498
|
const uniformBindGroup = device.createBindGroup({
|
|
495
499
|
layout: bindGroupLayout,
|
|
496
|
-
entries:
|
|
497
|
-
{
|
|
498
|
-
binding: 0,
|
|
499
|
-
resource: { buffer: uniformBuffer }
|
|
500
|
-
}
|
|
501
|
-
]
|
|
500
|
+
entries: bindGroupEntries
|
|
502
501
|
});
|
|
503
502
|
const pipelineLayout = device.createPipelineLayout({
|
|
504
503
|
bindGroupLayouts: [bindGroupLayout]
|
|
@@ -522,10 +521,26 @@ async function initializeWebGPU(canvas, fragmentSource, customUniforms) {
|
|
|
522
521
|
pipeline,
|
|
523
522
|
uniformBuffer,
|
|
524
523
|
uniformBindGroup,
|
|
525
|
-
uniformLayout
|
|
524
|
+
uniformLayout,
|
|
525
|
+
bindGroupLayout,
|
|
526
|
+
storageBuffers,
|
|
527
|
+
renderPassDescriptor: {
|
|
528
|
+
colorAttachments: [
|
|
529
|
+
{
|
|
530
|
+
view: undefined,
|
|
531
|
+
clearValue: { r: 0, g: 0, b: 0, a: 1 },
|
|
532
|
+
loadOp: "clear",
|
|
533
|
+
storeOp: "store"
|
|
534
|
+
}
|
|
535
|
+
]
|
|
536
|
+
},
|
|
537
|
+
submitArray: [null]
|
|
526
538
|
};
|
|
527
539
|
}
|
|
528
540
|
function cleanupWebGPU(state) {
|
|
541
|
+
for (const sb of state.storageBuffers) {
|
|
542
|
+
sb.buffer.destroy();
|
|
543
|
+
}
|
|
529
544
|
state.uniformBuffer.destroy();
|
|
530
545
|
state.device.destroy();
|
|
531
546
|
}
|
|
@@ -537,6 +552,7 @@ function useWebGPU(options) {
|
|
|
537
552
|
const lastFrameTimeRef = import_react2.useRef(0);
|
|
538
553
|
const mouseRef = import_react2.useRef([0, 0]);
|
|
539
554
|
const mouseNormalizedRef = import_react2.useRef([0, 0]);
|
|
555
|
+
const resolutionRef = import_react2.useRef([0, 0]);
|
|
540
556
|
const mouseLeftDownRef = import_react2.useRef(false);
|
|
541
557
|
const canvasRectRef = import_react2.useRef(null);
|
|
542
558
|
const onErrorRef = import_react2.useRef(options.onError);
|
|
@@ -549,7 +565,10 @@ function useWebGPU(options) {
|
|
|
549
565
|
const timeScaleRef = import_react2.useRef(options.timeScale ?? 1);
|
|
550
566
|
const fragmentRef = import_react2.useRef(options.fragment);
|
|
551
567
|
const uniformsRef = import_react2.useRef(options.uniforms);
|
|
568
|
+
const storageBuffersRef = import_react2.useRef(options.storageBuffers);
|
|
552
569
|
const dprRef = import_react2.useRef(window.devicePixelRatio || 1);
|
|
570
|
+
const uniformDataRef = import_react2.useRef(null);
|
|
571
|
+
const allValuesRef = import_react2.useRef({});
|
|
553
572
|
const frameInfoRef = import_react2.useRef({
|
|
554
573
|
deltaTime: 0,
|
|
555
574
|
time: 0,
|
|
@@ -568,6 +587,7 @@ function useWebGPU(options) {
|
|
|
568
587
|
timeScaleRef.current = options.timeScale ?? 1;
|
|
569
588
|
fragmentRef.current = options.fragment;
|
|
570
589
|
uniformsRef.current = options.uniforms;
|
|
590
|
+
storageBuffersRef.current = options.storageBuffers;
|
|
571
591
|
const render = import_react2.useCallback((time) => {
|
|
572
592
|
const state = stateRef.current;
|
|
573
593
|
const canvas = canvasRef.current;
|
|
@@ -577,18 +597,18 @@ function useWebGPU(options) {
|
|
|
577
597
|
const deltaTime = lastFrameTimeRef.current === 0 ? 0 : (time - lastFrameTimeRef.current) / 1000;
|
|
578
598
|
lastFrameTimeRef.current = time;
|
|
579
599
|
elapsedTimeRef.current += deltaTime * timeScaleRef.current;
|
|
580
|
-
frameInfoRef.current
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
600
|
+
const info = frameInfoRef.current;
|
|
601
|
+
info.deltaTime = deltaTime;
|
|
602
|
+
info.time = elapsedTimeRef.current;
|
|
603
|
+
info.resolution[0] = canvas.width;
|
|
604
|
+
info.resolution[1] = canvas.height;
|
|
605
|
+
info.mouse = mouseRef.current;
|
|
606
|
+
info.mouseNormalized = mouseNormalizedRef.current;
|
|
607
|
+
info.mouseLeftDown = mouseLeftDownRef.current;
|
|
588
608
|
if (onFrameRef.current) {
|
|
589
609
|
onFrameRef.current(frameInfoRef.current);
|
|
590
610
|
}
|
|
591
|
-
const { device, context, pipeline, uniformBuffer,
|
|
611
|
+
const { device, context, pipeline, uniformBuffer, uniformLayout } = state;
|
|
592
612
|
const dpr = dprRef.current;
|
|
593
613
|
const displayWidth = canvas.clientWidth;
|
|
594
614
|
const displayHeight = canvas.clientHeight;
|
|
@@ -602,22 +622,21 @@ function useWebGPU(options) {
|
|
|
602
622
|
canvas.width = bufferWidth;
|
|
603
623
|
canvas.height = bufferHeight;
|
|
604
624
|
}
|
|
605
|
-
const
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
}
|
|
625
|
+
const allValues = allValuesRef.current;
|
|
626
|
+
allValues.iTime = elapsedTimeRef.current;
|
|
627
|
+
allValues.iMouseLeftDown = mouseLeftDownRef.current ? 1 : 0;
|
|
628
|
+
resolutionRef.current[0] = canvas.width;
|
|
629
|
+
resolutionRef.current[1] = canvas.height;
|
|
630
|
+
allValues.iResolution = resolutionRef.current;
|
|
631
|
+
allValues.iMouse = mouseRef.current;
|
|
632
|
+
allValues.iMouseNormalized = mouseNormalizedRef.current;
|
|
633
|
+
const customs = uniformsRef.current;
|
|
634
|
+
if (customs) {
|
|
635
|
+
for (const name in customs) {
|
|
636
|
+
allValues[name] = customs[name];
|
|
618
637
|
}
|
|
619
638
|
}
|
|
620
|
-
const uniformData =
|
|
639
|
+
const uniformData = uniformDataRef.current;
|
|
621
640
|
for (const field of uniformLayout.fields) {
|
|
622
641
|
const value = allValues[field.name];
|
|
623
642
|
if (value === undefined) {
|
|
@@ -626,23 +645,41 @@ function useWebGPU(options) {
|
|
|
626
645
|
packUniformValue(field, value, uniformData);
|
|
627
646
|
}
|
|
628
647
|
device.queue.writeBuffer(uniformBuffer, 0, uniformData);
|
|
648
|
+
let needsBindGroupRebuild = false;
|
|
649
|
+
for (const entry of state.storageBuffers) {
|
|
650
|
+
const data = storageBuffersRef.current?.[entry.name];
|
|
651
|
+
if (!data)
|
|
652
|
+
continue;
|
|
653
|
+
const requiredLength = Math.max(data.length, 1);
|
|
654
|
+
if (requiredLength > entry.currentLength || requiredLength < entry.currentLength / 2) {
|
|
655
|
+
const allocLength = Math.max(Math.ceil(requiredLength * 1.5), 1);
|
|
656
|
+
entry.buffer.destroy();
|
|
657
|
+
const byteSize = allocLength * 16;
|
|
658
|
+
entry.buffer = device.createBuffer({
|
|
659
|
+
label: `storage: ${entry.name}`,
|
|
660
|
+
size: byteSize,
|
|
661
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
|
|
662
|
+
});
|
|
663
|
+
entry.packingArray = new Float32Array(allocLength * 4);
|
|
664
|
+
entry.currentLength = allocLength;
|
|
665
|
+
needsBindGroupRebuild = true;
|
|
666
|
+
}
|
|
667
|
+
entry.dataLength = data.length;
|
|
668
|
+
packAndUploadStorageBuffer(device, entry, data);
|
|
669
|
+
}
|
|
670
|
+
if (needsBindGroupRebuild) {
|
|
671
|
+
state.uniformBindGroup = rebuildBindGroup(state);
|
|
672
|
+
}
|
|
629
673
|
const commandEncoder = device.createCommandEncoder();
|
|
630
674
|
const textureView = context.getCurrentTexture().createView();
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
{
|
|
634
|
-
view: textureView,
|
|
635
|
-
clearValue: { r: 0, g: 0, b: 0, a: 1 },
|
|
636
|
-
loadOp: "clear",
|
|
637
|
-
storeOp: "store"
|
|
638
|
-
}
|
|
639
|
-
]
|
|
640
|
-
});
|
|
675
|
+
state.renderPassDescriptor.colorAttachments[0].view = textureView;
|
|
676
|
+
const renderPass = commandEncoder.beginRenderPass(state.renderPassDescriptor);
|
|
641
677
|
renderPass.setPipeline(pipeline);
|
|
642
|
-
renderPass.setBindGroup(0, uniformBindGroup);
|
|
678
|
+
renderPass.setBindGroup(0, state.uniformBindGroup);
|
|
643
679
|
renderPass.draw(3);
|
|
644
680
|
renderPass.end();
|
|
645
|
-
|
|
681
|
+
state.submitArray[0] = commandEncoder.finish();
|
|
682
|
+
device.queue.submit(state.submitArray);
|
|
646
683
|
animationFrameRef.current = requestAnimationFrame(render);
|
|
647
684
|
}, []);
|
|
648
685
|
import_react2.useEffect(() => {
|
|
@@ -652,12 +689,13 @@ function useWebGPU(options) {
|
|
|
652
689
|
let mounted = true;
|
|
653
690
|
const initialize = async () => {
|
|
654
691
|
try {
|
|
655
|
-
const state = await initializeWebGPU(canvas, fragmentRef.current, uniformsRef.current);
|
|
692
|
+
const state = await initializeWebGPU(canvas, fragmentRef.current, uniformsRef.current, storageBuffersRef.current);
|
|
656
693
|
if (!mounted) {
|
|
657
694
|
cleanupWebGPU(state);
|
|
658
695
|
return;
|
|
659
696
|
}
|
|
660
697
|
stateRef.current = state;
|
|
698
|
+
uniformDataRef.current = new Float32Array(state.uniformLayout.bufferSize / 4);
|
|
661
699
|
elapsedTimeRef.current = 0;
|
|
662
700
|
lastFrameTimeRef.current = 0;
|
|
663
701
|
animationFrameRef.current = requestAnimationFrame(render);
|
|
@@ -774,6 +812,7 @@ function ReactGpuShader({
|
|
|
774
812
|
className,
|
|
775
813
|
fragment,
|
|
776
814
|
uniforms,
|
|
815
|
+
storageBuffers,
|
|
777
816
|
fullscreen = false,
|
|
778
817
|
timeScale,
|
|
779
818
|
onFrame,
|
|
@@ -794,6 +833,7 @@ function ReactGpuShader({
|
|
|
794
833
|
const { canvasRef } = useWebGPU({
|
|
795
834
|
fragment,
|
|
796
835
|
uniforms,
|
|
836
|
+
storageBuffers,
|
|
797
837
|
onError: handleError,
|
|
798
838
|
timeScale,
|
|
799
839
|
onFrame,
|
|
@@ -1045,11 +1085,11 @@ function isVec2Array(value) {
|
|
|
1045
1085
|
function isVec3Array(value) {
|
|
1046
1086
|
return Array.isArray(value) && value.length > 0 && Array.isArray(value[0]) && value[0].length === 3;
|
|
1047
1087
|
}
|
|
1048
|
-
function
|
|
1088
|
+
function isVec4Array(value) {
|
|
1049
1089
|
return Array.isArray(value) && value.length > 0 && Array.isArray(value[0]) && value[0].length === 4;
|
|
1050
1090
|
}
|
|
1051
1091
|
function isArrayUniform(value) {
|
|
1052
|
-
return isFloatArray(value) || isVec2Array(value) || isVec3Array(value) ||
|
|
1092
|
+
return isFloatArray(value) || isVec2Array(value) || isVec3Array(value) || isVec4Array(value);
|
|
1053
1093
|
}
|
|
1054
1094
|
function setUniform(gl, location, value) {
|
|
1055
1095
|
if (location === null) {
|
|
@@ -1057,7 +1097,7 @@ function setUniform(gl, location, value) {
|
|
|
1057
1097
|
}
|
|
1058
1098
|
if (typeof value === "number") {
|
|
1059
1099
|
gl.uniform1f(location, value);
|
|
1060
|
-
} else if (
|
|
1100
|
+
} else if (isVec4Array(value)) {
|
|
1061
1101
|
gl.uniform4fv(location, value.flat());
|
|
1062
1102
|
} else if (isVec3Array(value)) {
|
|
1063
1103
|
gl.uniform3fv(location, value.flat());
|
|
@@ -1113,7 +1153,7 @@ function getUniformType(value) {
|
|
|
1113
1153
|
if (typeof value === "number") {
|
|
1114
1154
|
return "float";
|
|
1115
1155
|
}
|
|
1116
|
-
if (
|
|
1156
|
+
if (isVec4Array(value)) {
|
|
1117
1157
|
return `vec4[${MAX_ARRAY_LENGTH}]`;
|
|
1118
1158
|
}
|
|
1119
1159
|
if (isVec3Array(value)) {
|
package/dist/index.d.ts
CHANGED
|
@@ -11,5 +11,5 @@ export { generateSceneCirclesFunctionGpu } from "./shaders/scene-circles-gpu";
|
|
|
11
11
|
export { generateSimplexNoiseFunction } from "./shaders/simplex-noise";
|
|
12
12
|
export { generateSimplexNoiseFunctionGpu } from "./shaders/simplex-noise-gpu";
|
|
13
13
|
export { generateUtilsFunction } from "./shaders/utils";
|
|
14
|
-
export type { AudioConnectionState, AudioLevels, AudioSourceType, DefaultUniforms, FloatArray, FrameInfo, ReactShaderProps, TextureMagFilter, TextureMinFilter, TextureOptions, TextureSource, TextureWrap, UniformValue, UseAudioOptions, UseAudioReturn, Vec2, Vec2Array, Vec3, Vec3Array, Vec4, Vec4Array, } from "./types";
|
|
14
|
+
export type { AudioConnectionState, AudioLevels, AudioSourceType, DefaultUniforms, FloatArray, FrameInfo, GpuStorageBuffers, ReactShaderProps, TextureMagFilter, TextureMinFilter, TextureOptions, TextureSource, TextureWrap, UniformValue, UseAudioOptions, UseAudioReturn, Vec2, Vec2Array, Vec3, Vec3Array, Vec4, Vec4Array, } from "./types";
|
|
15
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAA;AACtE,OAAO,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAA;AAC7E,OAAO,EAAE,gCAAgC,EAAE,MAAM,6BAA6B,CAAA;AAC9E,OAAO,EAAE,mCAAmC,EAAE,MAAM,iCAAiC,CAAA;AACrF,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAA;AACtE,OAAO,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAA;AAC7E,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAA;AACtE,OAAO,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAA;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACvD,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,eAAe,EACf,eAAe,EACf,UAAU,EACV,SAAS,EACT,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,WAAW,EACX,YAAY,EACZ,eAAe,EACf,cAAc,EACd,IAAI,EACJ,SAAS,EACT,IAAI,EACJ,SAAS,EACT,IAAI,EACJ,SAAS,GACV,MAAM,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC3C,YAAY,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAA;AACtE,OAAO,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAA;AAC7E,OAAO,EAAE,gCAAgC,EAAE,MAAM,6BAA6B,CAAA;AAC9E,OAAO,EAAE,mCAAmC,EAAE,MAAM,iCAAiC,CAAA;AACrF,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAA;AACtE,OAAO,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAA;AAC7E,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAA;AACtE,OAAO,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAA;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AACvD,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,eAAe,EACf,eAAe,EACf,UAAU,EACV,SAAS,EACT,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,WAAW,EACX,YAAY,EACZ,eAAe,EACf,cAAc,EACd,IAAI,EACJ,SAAS,EACT,IAAI,EACJ,SAAS,EACT,IAAI,EACJ,SAAS,GACV,MAAM,SAAS,CAAA"}
|