@luma.gl/effects 9.3.0-alpha.6 → 9.3.0-alpha.8

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 (72) hide show
  1. package/dist/dist.dev.js +983 -223
  2. package/dist/dist.min.js +5 -5
  3. package/dist/index.cjs +340 -50
  4. package/dist/index.cjs.map +3 -3
  5. package/dist/passes/postprocessing/fxaa/fxaa.d.ts +1 -0
  6. package/dist/passes/postprocessing/fxaa/fxaa.d.ts.map +1 -1
  7. package/dist/passes/postprocessing/fxaa/fxaa.js +287 -0
  8. package/dist/passes/postprocessing/fxaa/fxaa.js.map +1 -1
  9. package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.d.ts +1 -1
  10. package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.d.ts.map +1 -1
  11. package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.js +5 -7
  12. package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.js.map +1 -1
  13. package/dist/passes/postprocessing/image-adjust-filters/denoise.d.ts +2 -2
  14. package/dist/passes/postprocessing/image-adjust-filters/denoise.js +4 -4
  15. package/dist/passes/postprocessing/image-adjust-filters/huesaturation.d.ts +1 -1
  16. package/dist/passes/postprocessing/image-adjust-filters/huesaturation.d.ts.map +1 -1
  17. package/dist/passes/postprocessing/image-adjust-filters/huesaturation.js +9 -10
  18. package/dist/passes/postprocessing/image-adjust-filters/huesaturation.js.map +1 -1
  19. package/dist/passes/postprocessing/image-adjust-filters/noise.d.ts +1 -1
  20. package/dist/passes/postprocessing/image-adjust-filters/noise.js +1 -1
  21. package/dist/passes/postprocessing/image-adjust-filters/sepia.d.ts +1 -1
  22. package/dist/passes/postprocessing/image-adjust-filters/sepia.js +1 -1
  23. package/dist/passes/postprocessing/image-adjust-filters/vibrance.d.ts +1 -1
  24. package/dist/passes/postprocessing/image-adjust-filters/vibrance.d.ts.map +1 -1
  25. package/dist/passes/postprocessing/image-adjust-filters/vibrance.js +3 -4
  26. package/dist/passes/postprocessing/image-adjust-filters/vibrance.js.map +1 -1
  27. package/dist/passes/postprocessing/image-adjust-filters/vignette.d.ts +1 -1
  28. package/dist/passes/postprocessing/image-adjust-filters/vignette.js +1 -1
  29. package/dist/passes/postprocessing/image-blur-filters/tiltshift.d.ts +1 -1
  30. package/dist/passes/postprocessing/image-blur-filters/tiltshift.js +1 -1
  31. package/dist/passes/postprocessing/image-blur-filters/triangleblur.d.ts +1 -1
  32. package/dist/passes/postprocessing/image-blur-filters/triangleblur.js +6 -6
  33. package/dist/passes/postprocessing/image-blur-filters/zoomblur.d.ts +1 -1
  34. package/dist/passes/postprocessing/image-blur-filters/zoomblur.js +1 -1
  35. package/dist/passes/postprocessing/image-fun-filters/colorhalftone.d.ts +1 -1
  36. package/dist/passes/postprocessing/image-fun-filters/colorhalftone.js +1 -1
  37. package/dist/passes/postprocessing/image-fun-filters/dotscreen.d.ts +1 -1
  38. package/dist/passes/postprocessing/image-fun-filters/dotscreen.js +1 -1
  39. package/dist/passes/postprocessing/image-fun-filters/edgework.d.ts +1 -1
  40. package/dist/passes/postprocessing/image-fun-filters/edgework.js +1 -1
  41. package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.d.ts +1 -1
  42. package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.js +1 -1
  43. package/dist/passes/postprocessing/image-fun-filters/ink.d.ts +1 -1
  44. package/dist/passes/postprocessing/image-fun-filters/ink.js +1 -1
  45. package/dist/passes/postprocessing/image-fun-filters/magnify.d.ts +1 -1
  46. package/dist/passes/postprocessing/image-fun-filters/magnify.d.ts.map +1 -1
  47. package/dist/passes/postprocessing/image-fun-filters/magnify.js +8 -3
  48. package/dist/passes/postprocessing/image-fun-filters/magnify.js.map +1 -1
  49. package/dist/passes/postprocessing/image-warp-filters/bulgepinch.d.ts +2 -2
  50. package/dist/passes/postprocessing/image-warp-filters/bulgepinch.js +3 -3
  51. package/dist/passes/postprocessing/image-warp-filters/swirl.d.ts +2 -2
  52. package/dist/passes/postprocessing/image-warp-filters/swirl.js +3 -3
  53. package/package.json +3 -3
  54. package/src/passes/postprocessing/fxaa/fxaa.ts +288 -0
  55. package/src/passes/postprocessing/image-adjust-filters/brightnesscontrast.ts +5 -7
  56. package/src/passes/postprocessing/image-adjust-filters/denoise.ts +4 -4
  57. package/src/passes/postprocessing/image-adjust-filters/huesaturation.ts +9 -10
  58. package/src/passes/postprocessing/image-adjust-filters/noise.ts +1 -1
  59. package/src/passes/postprocessing/image-adjust-filters/sepia.ts +1 -1
  60. package/src/passes/postprocessing/image-adjust-filters/vibrance.ts +3 -4
  61. package/src/passes/postprocessing/image-adjust-filters/vignette.ts +1 -1
  62. package/src/passes/postprocessing/image-blur-filters/tiltshift.ts +1 -1
  63. package/src/passes/postprocessing/image-blur-filters/triangleblur.ts +6 -6
  64. package/src/passes/postprocessing/image-blur-filters/zoomblur.ts +1 -1
  65. package/src/passes/postprocessing/image-fun-filters/colorhalftone.ts +1 -1
  66. package/src/passes/postprocessing/image-fun-filters/dotscreen.ts +1 -1
  67. package/src/passes/postprocessing/image-fun-filters/edgework.ts +1 -1
  68. package/src/passes/postprocessing/image-fun-filters/hexagonalpixelate.ts +1 -1
  69. package/src/passes/postprocessing/image-fun-filters/ink.ts +1 -1
  70. package/src/passes/postprocessing/image-fun-filters/magnify.ts +8 -3
  71. package/src/passes/postprocessing/image-warp-filters/bulgepinch.ts +3 -3
  72. package/src/passes/postprocessing/image-warp-filters/swirl.ts +3 -3
package/dist/dist.dev.js CHANGED
@@ -66,6 +66,7 @@ var __exports__ = (() => {
66
66
  ExternalTexture: () => ExternalTexture,
67
67
  Fence: () => Fence,
68
68
  Framebuffer: () => Framebuffer,
69
+ PipelineFactory: () => PipelineFactory,
69
70
  PipelineLayout: () => PipelineLayout,
70
71
  PresentationContext: () => PresentationContext,
71
72
  QuerySet: () => QuerySet,
@@ -74,38 +75,39 @@ var __exports__ = (() => {
74
75
  Resource: () => Resource,
75
76
  Sampler: () => Sampler,
76
77
  Shader: () => Shader,
78
+ ShaderFactory: () => ShaderFactory,
77
79
  SharedRenderPipeline: () => SharedRenderPipeline,
78
80
  Texture: () => Texture,
79
- TextureFormatDecoder: () => TextureFormatDecoder,
80
81
  TextureView: () => TextureView,
81
82
  TransformFeedback: () => TransformFeedback,
82
83
  UniformBlock: () => UniformBlock,
83
84
  UniformBufferLayout: () => UniformBufferLayout,
84
85
  UniformStore: () => UniformStore,
85
86
  VertexArray: () => VertexArray,
87
+ _getDefaultBindGroupFactory: () => _getDefaultBindGroupFactory,
86
88
  _getTextureFormatDefinition: () => getTextureFormatDefinition,
87
89
  _getTextureFormatTable: () => getTextureFormatTable,
88
90
  assert: () => assert2,
89
91
  assertDefined: () => assertDefined,
92
+ dataTypeDecoder: () => dataTypeDecoder,
93
+ flattenBindingsByGroup: () => flattenBindingsByGroup,
90
94
  getAttributeInfosFromLayouts: () => getAttributeInfosFromLayouts,
91
95
  getAttributeShaderTypeInfo: () => getAttributeShaderTypeInfo,
92
- getDataType: () => getDataType,
93
- getDataTypeInfo: () => getDataTypeInfo,
94
96
  getExternalImageSize: () => getExternalImageSize,
95
- getNormalizedDataType: () => getNormalizedDataType,
96
97
  getScratchArray: () => getScratchArray,
98
+ getShaderLayoutBinding: () => getShaderLayoutBinding,
97
99
  getTextureImageView: () => getTextureImageView,
98
100
  getTypedArrayConstructor: () => getTypedArrayConstructor,
99
101
  getVariableShaderTypeInfo: () => getVariableShaderTypeInfo,
100
- getVertexFormatFromAttribute: () => getVertexFormatFromAttribute,
101
- getVertexFormatInfo: () => getVertexFormatInfo,
102
102
  isExternalImage: () => isExternalImage,
103
103
  log: () => log,
104
104
  luma: () => luma,
105
- makeVertexFormat: () => makeVertexFormat,
105
+ normalizeBindingsByGroup: () => normalizeBindingsByGroup,
106
106
  readPixel: () => readPixel,
107
107
  setTextureImageData: () => setTextureImageData,
108
+ shaderTypeDecoder: () => shaderTypeDecoder,
108
109
  textureFormatDecoder: () => textureFormatDecoder,
110
+ vertexFormatDecoder: () => vertexFormatDecoder,
109
111
  writePixel: () => writePixel
110
112
  });
111
113
 
@@ -1347,62 +1349,73 @@ var __exports__ = (() => {
1347
1349
  onMapped: void 0
1348
1350
  });
1349
1351
 
1350
- // ../core/src/shadertypes/data-types/decode-data-types.ts
1351
- function getDataTypeInfo(type) {
1352
- const normalized = type.includes("norm");
1353
- const integer = !normalized && !type.startsWith("float");
1354
- const signed = type.startsWith("s");
1355
- const typeInfo = NORMALIZED_TYPE_MAP[type];
1356
- const [signedType, primitiveType, byteLength] = typeInfo || ["uint8 ", "i32", 1];
1357
- return {
1358
- signedType,
1359
- primitiveType,
1360
- byteLength,
1361
- normalized,
1362
- integer,
1363
- signed
1364
- };
1365
- }
1366
- function getNormalizedDataType(signedDataType) {
1367
- const dataType = signedDataType;
1368
- switch (dataType) {
1369
- case "uint8":
1370
- return "unorm8";
1371
- case "sint8":
1372
- return "snorm8";
1373
- case "uint16":
1374
- return "unorm16";
1375
- case "sint16":
1376
- return "snorm16";
1377
- default:
1378
- return dataType;
1352
+ // ../core/src/shadertypes/data-types/data-type-decoder.ts
1353
+ var DataTypeDecoder = class {
1354
+ /**
1355
+ * Gets info about a data type constant (signed or normalized)
1356
+ * @returns underlying primitive / signed types, byte length, normalization, integer, signed flags
1357
+ */
1358
+ getDataTypeInfo(type) {
1359
+ const [signedType, primitiveType, byteLength] = NORMALIZED_TYPE_MAP[type];
1360
+ const normalized = type.includes("norm");
1361
+ const integer = !normalized && !type.startsWith("float");
1362
+ const signed = type.startsWith("s");
1363
+ return {
1364
+ signedType,
1365
+ primitiveType,
1366
+ byteLength,
1367
+ normalized,
1368
+ integer,
1369
+ signed
1370
+ // TODO - add webglOnly flag
1371
+ };
1379
1372
  }
1380
- }
1381
- function alignTo(size, count) {
1382
- switch (count) {
1383
- case 1:
1384
- return size;
1385
- case 2:
1386
- return size + size % 2;
1387
- default:
1388
- return size + (4 - size % 4) % 4;
1373
+ /** Build a vertex format from a signed data type and a component */
1374
+ getNormalizedDataType(signedDataType) {
1375
+ const dataType = signedDataType;
1376
+ switch (dataType) {
1377
+ case "uint8":
1378
+ return "unorm8";
1379
+ case "sint8":
1380
+ return "snorm8";
1381
+ case "uint16":
1382
+ return "unorm16";
1383
+ case "sint16":
1384
+ return "snorm16";
1385
+ default:
1386
+ return dataType;
1387
+ }
1389
1388
  }
1390
- }
1391
- function getDataType(arrayOrType) {
1392
- const Constructor = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType;
1393
- if (Constructor === Uint8ClampedArray) {
1394
- return "uint8";
1389
+ /** Align offset to 1, 2 or 4 elements (4, 8 or 16 bytes) */
1390
+ alignTo(size, count) {
1391
+ switch (count) {
1392
+ case 1:
1393
+ return size;
1394
+ case 2:
1395
+ return size + size % 2;
1396
+ default:
1397
+ return size + (4 - size % 4) % 4;
1398
+ }
1395
1399
  }
1396
- const info = Object.values(NORMALIZED_TYPE_MAP).find((entry) => Constructor === entry[4]);
1397
- if (!info) {
1398
- throw new Error(Constructor.name);
1400
+ /** Returns the VariableShaderType that corresponds to a typed array */
1401
+ getDataType(arrayOrType) {
1402
+ const Constructor = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType;
1403
+ if (Constructor === Uint8ClampedArray) {
1404
+ return "uint8";
1405
+ }
1406
+ const info = Object.values(NORMALIZED_TYPE_MAP).find((entry) => Constructor === entry[4]);
1407
+ if (!info) {
1408
+ throw new Error(Constructor.name);
1409
+ }
1410
+ return info[0];
1399
1411
  }
1400
- return info[0];
1401
- }
1402
- function getTypedArrayConstructor(type) {
1403
- const [, , , , Constructor] = NORMALIZED_TYPE_MAP[type];
1404
- return Constructor;
1405
- }
1412
+ /** Returns the TypedArray that corresponds to a shader data type */
1413
+ getTypedArrayConstructor(type) {
1414
+ const [, , , , Constructor] = NORMALIZED_TYPE_MAP[type];
1415
+ return Constructor;
1416
+ }
1417
+ };
1418
+ var dataTypeDecoder = new DataTypeDecoder();
1406
1419
  var NORMALIZED_TYPE_MAP = {
1407
1420
  uint8: ["uint8", "u32", 1, false, Uint8Array],
1408
1421
  sint8: ["sint8", "i32", 1, false, Int8Array],
@@ -1418,87 +1431,99 @@ var __exports__ = (() => {
1418
1431
  sint32: ["sint32", "i32", 4, false, Int32Array]
1419
1432
  };
1420
1433
 
1421
- // ../core/src/shadertypes/vertex-arrays/decode-vertex-format.ts
1422
- function getVertexFormatInfo(format) {
1423
- let webglOnly;
1424
- if (format.endsWith("-webgl")) {
1425
- format.replace("-webgl", "");
1426
- webglOnly = true;
1427
- }
1428
- const [type_, count] = format.split("x");
1429
- const type = type_;
1430
- const components = count ? parseInt(count) : 1;
1431
- const decodedType = getDataTypeInfo(type);
1432
- const result = {
1433
- type,
1434
- components,
1435
- byteLength: decodedType.byteLength * components,
1436
- integer: decodedType.integer,
1437
- signed: decodedType.signed,
1438
- normalized: decodedType.normalized
1439
- };
1440
- if (webglOnly) {
1441
- result.webglOnly = true;
1442
- }
1443
- return result;
1444
- }
1445
- function makeVertexFormat(signedDataType, components, normalized) {
1446
- const dataType = normalized ? getNormalizedDataType(signedDataType) : signedDataType;
1447
- switch (dataType) {
1448
- case "unorm8":
1449
- if (components === 1) {
1450
- return "unorm8";
1451
- }
1452
- if (components === 3) {
1453
- return "unorm8x3-webgl";
1454
- }
1455
- return `${dataType}x${components}`;
1456
- case "snorm8":
1457
- case "uint8":
1458
- case "sint8":
1459
- case "uint16":
1460
- case "sint16":
1461
- case "unorm16":
1462
- case "snorm16":
1463
- case "float16":
1464
- if (components === 1 || components === 3) {
1465
- throw new Error(`size: ${components}`);
1466
- }
1467
- return `${dataType}x${components}`;
1468
- default:
1469
- return components === 1 ? dataType : `${dataType}x${components}`;
1434
+ // ../core/src/shadertypes/vertex-types/vertex-format-decoder.ts
1435
+ var VertexFormatDecoder = class {
1436
+ /**
1437
+ * Decodes a vertex format, returning type, components, byte length and flags (integer, signed, normalized)
1438
+ */
1439
+ getVertexFormatInfo(format) {
1440
+ let webglOnly;
1441
+ if (format.endsWith("-webgl")) {
1442
+ format.replace("-webgl", "");
1443
+ webglOnly = true;
1444
+ }
1445
+ const [type_, count] = format.split("x");
1446
+ const type = type_;
1447
+ const components = count ? parseInt(count) : 1;
1448
+ const decodedType = dataTypeDecoder.getDataTypeInfo(type);
1449
+ const result = {
1450
+ type,
1451
+ components,
1452
+ byteLength: decodedType.byteLength * components,
1453
+ integer: decodedType.integer,
1454
+ signed: decodedType.signed,
1455
+ normalized: decodedType.normalized
1456
+ };
1457
+ if (webglOnly) {
1458
+ result.webglOnly = true;
1459
+ }
1460
+ return result;
1470
1461
  }
1471
- }
1472
- function getVertexFormatFromAttribute(typedArray, size, normalized) {
1473
- if (!size || size > 4) {
1474
- throw new Error(`size ${size}`);
1462
+ /** Build a vertex format from a signed data type and a component */
1463
+ makeVertexFormat(signedDataType, components, normalized) {
1464
+ const dataType = normalized ? dataTypeDecoder.getNormalizedDataType(signedDataType) : signedDataType;
1465
+ switch (dataType) {
1466
+ case "unorm8":
1467
+ if (components === 1) {
1468
+ return "unorm8";
1469
+ }
1470
+ if (components === 3) {
1471
+ return "unorm8x3-webgl";
1472
+ }
1473
+ return `${dataType}x${components}`;
1474
+ case "snorm8":
1475
+ case "uint8":
1476
+ case "sint8":
1477
+ case "uint16":
1478
+ case "sint16":
1479
+ case "unorm16":
1480
+ case "snorm16":
1481
+ case "float16":
1482
+ if (components === 1 || components === 3) {
1483
+ throw new Error(`size: ${components}`);
1484
+ }
1485
+ return `${dataType}x${components}`;
1486
+ default:
1487
+ return components === 1 ? dataType : `${dataType}x${components}`;
1488
+ }
1475
1489
  }
1476
- const components = size;
1477
- const signedDataType = getDataType(typedArray);
1478
- return makeVertexFormat(signedDataType, components, normalized);
1479
- }
1480
- function getCompatibleVertexFormat(opts) {
1481
- let vertexType;
1482
- switch (opts.primitiveType) {
1483
- case "f32":
1484
- vertexType = "float32";
1485
- break;
1486
- case "i32":
1487
- vertexType = "sint32";
1488
- break;
1489
- case "u32":
1490
- vertexType = "uint32";
1491
- break;
1492
- case "f16":
1493
- return opts.components <= 2 ? "float16x2" : "float16x4";
1490
+ /** Get the vertex format for an attribute with TypedArray and size */
1491
+ getVertexFormatFromAttribute(typedArray, size, normalized) {
1492
+ if (!size || size > 4) {
1493
+ throw new Error(`size ${size}`);
1494
+ }
1495
+ const components = size;
1496
+ const signedDataType = dataTypeDecoder.getDataType(typedArray);
1497
+ return this.makeVertexFormat(signedDataType, components, normalized);
1494
1498
  }
1495
- if (opts.components === 1) {
1496
- return vertexType;
1499
+ /**
1500
+ * Return a "default" vertex format for a certain shader data type
1501
+ * The simplest vertex format that matches the shader attribute's data type
1502
+ */
1503
+ getCompatibleVertexFormat(opts) {
1504
+ let vertexType;
1505
+ switch (opts.primitiveType) {
1506
+ case "f32":
1507
+ vertexType = "float32";
1508
+ break;
1509
+ case "i32":
1510
+ vertexType = "sint32";
1511
+ break;
1512
+ case "u32":
1513
+ vertexType = "uint32";
1514
+ break;
1515
+ case "f16":
1516
+ return opts.components <= 2 ? "float16x2" : "float16x4";
1517
+ }
1518
+ if (opts.components === 1) {
1519
+ return vertexType;
1520
+ }
1521
+ return `${vertexType}x${opts.components}`;
1497
1522
  }
1498
- return `${vertexType}x${opts.components}`;
1499
- }
1523
+ };
1524
+ var vertexFormatDecoder = new VertexFormatDecoder();
1500
1525
 
1501
- // ../core/src/shadertypes/textures/texture-format-table.ts
1526
+ // ../core/src/shadertypes/texture-types/texture-format-table.ts
1502
1527
  var texture_compression_bc = "texture-compression-bc";
1503
1528
  var texture_compression_astc = "texture-compression-astc";
1504
1529
  var texture_compression_etc2 = "texture-compression-etc2";
@@ -1669,7 +1694,7 @@ var __exports__ = (() => {
1669
1694
  ...TEXTURE_FORMAT_COMPRESSED_TABLE
1670
1695
  };
1671
1696
 
1672
- // ../core/src/shadertypes/textures/texture-format-decoder.ts
1697
+ // ../core/src/shadertypes/texture-types/texture-format-decoder.ts
1673
1698
  var RGB_FORMAT_REGEX = /^(r|rg|rgb|rgba|bgra)([0-9]*)([a-z]*)(-srgb)?(-webgl)?$/;
1674
1699
  var COLOR_FORMAT_PREFIXES = ["rgb", "rgba", "bgra"];
1675
1700
  var DEPTH_FORMAT_PREFIXES = ["depth", "stencil"];
@@ -1780,11 +1805,11 @@ var __exports__ = (() => {
1780
1805
  formatInfo.blockHeight = blockSize.blockHeight;
1781
1806
  }
1782
1807
  }
1783
- const matches = RGB_FORMAT_REGEX.exec(format);
1808
+ const matches = !formatInfo.packed ? RGB_FORMAT_REGEX.exec(format) : null;
1784
1809
  if (matches) {
1785
1810
  const [, channels, length, type, srgb, suffix] = matches;
1786
1811
  const dataType = `${type}${length}`;
1787
- const decodedType = getDataTypeInfo(dataType);
1812
+ const decodedType = dataTypeDecoder.getDataTypeInfo(dataType);
1788
1813
  const bits = decodedType.byteLength * 8;
1789
1814
  const components = channels?.length ?? 1;
1790
1815
  const bitsPerChannel = [
@@ -1883,7 +1908,7 @@ var __exports__ = (() => {
1883
1908
  return 16;
1884
1909
  }
1885
1910
 
1886
- // ../core/src/image-utils/image-types.ts
1911
+ // ../core/src/shadertypes/image-types/image-types.ts
1887
1912
  function isExternalImage(data) {
1888
1913
  return typeof ImageData !== "undefined" && data instanceof ImageData || typeof ImageBitmap !== "undefined" && data instanceof ImageBitmap || typeof HTMLImageElement !== "undefined" && data instanceof HTMLImageElement || typeof HTMLVideoElement !== "undefined" && data instanceof HTMLVideoElement || typeof VideoFrame !== "undefined" && data instanceof VideoFrame || typeof HTMLCanvasElement !== "undefined" && data instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && data instanceof OffscreenCanvas;
1889
1914
  }
@@ -1906,6 +1931,52 @@ var __exports__ = (() => {
1906
1931
  // ../core/src/adapter/device.ts
1907
1932
  var DeviceLimits = class {
1908
1933
  };
1934
+ function formatErrorLogArguments(context, args) {
1935
+ const formattedContext = formatErrorLogValue(context);
1936
+ const formattedArgs = args.map(formatErrorLogValue).filter((arg) => arg !== void 0);
1937
+ return [formattedContext, ...formattedArgs].filter((arg) => arg !== void 0);
1938
+ }
1939
+ function formatErrorLogValue(value) {
1940
+ if (value === void 0) {
1941
+ return void 0;
1942
+ }
1943
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1944
+ return value;
1945
+ }
1946
+ if (value instanceof Error) {
1947
+ return value.message;
1948
+ }
1949
+ if (Array.isArray(value)) {
1950
+ return value.map(formatErrorLogValue);
1951
+ }
1952
+ if (typeof value === "object") {
1953
+ if (hasCustomToString(value)) {
1954
+ const stringValue = String(value);
1955
+ if (stringValue !== "[object Object]") {
1956
+ return stringValue;
1957
+ }
1958
+ }
1959
+ if (looksLikeGPUCompilationMessage(value)) {
1960
+ return formatGPUCompilationMessage(value);
1961
+ }
1962
+ return value.constructor?.name || "Object";
1963
+ }
1964
+ return String(value);
1965
+ }
1966
+ function hasCustomToString(value) {
1967
+ return "toString" in value && typeof value.toString === "function" && value.toString !== Object.prototype.toString;
1968
+ }
1969
+ function looksLikeGPUCompilationMessage(value) {
1970
+ return "message" in value && "type" in value;
1971
+ }
1972
+ function formatGPUCompilationMessage(value) {
1973
+ const type = typeof value.type === "string" ? value.type : "message";
1974
+ const message = typeof value.message === "string" ? value.message : "";
1975
+ const lineNum = typeof value.lineNum === "number" ? value.lineNum : null;
1976
+ const linePos = typeof value.linePos === "number" ? value.linePos : null;
1977
+ const location = lineNum !== null && linePos !== null ? ` @ ${lineNum}:${linePos}` : lineNum !== null ? ` @ ${lineNum}` : "";
1978
+ return `${type}${location}: ${message}`.trim();
1979
+ }
1909
1980
  var DeviceFeatures = class {
1910
1981
  features;
1911
1982
  disabledFeatures;
@@ -1935,6 +2006,8 @@ var __exports__ = (() => {
1935
2006
  userData = {};
1936
2007
  /** stats */
1937
2008
  statsManager = lumaStats;
2009
+ /** Internal per-device factory storage */
2010
+ _factories = {};
1938
2011
  /** An abstract timestamp used for change tracking */
1939
2012
  timestamp = 0;
1940
2013
  /** True if this device has been reused during device creation (app has multiple references) */
@@ -1948,8 +2021,9 @@ var __exports__ = (() => {
1948
2021
  this.props = { ..._Device.defaultProps, ...props };
1949
2022
  this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase());
1950
2023
  }
2024
+ // TODO - just expose the shadertypes decoders?
1951
2025
  getVertexFormatInfo(format) {
1952
- return getVertexFormatInfo(format);
2026
+ return vertexFormatDecoder.getVertexFormatInfo(format);
1953
2027
  }
1954
2028
  isVertexFormatSupported(format) {
1955
2029
  return true;
@@ -2049,12 +2123,12 @@ var __exports__ = (() => {
2049
2123
  reportError(error, context, ...args) {
2050
2124
  const isHandled = this.props.onError(error, context);
2051
2125
  if (!isHandled) {
2126
+ const logArguments = formatErrorLogArguments(context, args);
2052
2127
  return log.error(
2053
2128
  this.type === "webgl" ? "%cWebGL" : "%cWebGPU",
2054
2129
  "color: white; background: red; padding: 2px 6px; border-radius: 3px;",
2055
2130
  error.message,
2056
- context,
2057
- ...args
2131
+ ...logArguments
2058
2132
  );
2059
2133
  }
2060
2134
  return () => {
@@ -2101,6 +2175,14 @@ or create a device with the 'debug: true' prop.`;
2101
2175
  _createSharedRenderPipelineWebGL(_props) {
2102
2176
  throw new Error("_createSharedRenderPipelineWebGL() not implemented");
2103
2177
  }
2178
+ /** Internal WebGPU-only helper for retrieving the native bind-group layout for a pipeline group. */
2179
+ _createBindGroupLayoutWebGPU(_pipeline, _group) {
2180
+ throw new Error("_createBindGroupLayoutWebGPU() not implemented");
2181
+ }
2182
+ /** Internal WebGPU-only helper for creating a native bind group. */
2183
+ _createBindGroupWebGPU(_bindGroupLayout, _shaderLayout, _bindings, _group) {
2184
+ throw new Error("_createBindGroupWebGPU() not implemented");
2185
+ }
2104
2186
  /**
2105
2187
  * Internal helper that returns `true` when timestamp-query GPU timing should be
2106
2188
  * collected for this device.
@@ -3128,8 +3210,8 @@ or create a device with the 'debug: true' prop.`;
3128
3210
  *
3129
3211
  * @note The memory layout of the texture data is determined by the texture format and dimensions.
3130
3212
  * @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
3131
- * @note The application can call Buffer.readAsync()
3132
- * @note If not supplied a buffer will be created and the application needs to call Buffer.destroy
3213
+ * @note The application can call Buffer.readAsync() to read the returned buffer on the CPU.
3214
+ * @note The destination buffer must be supplied by the caller and must be large enough for the requested region.
3133
3215
  * @note On WebGPU this corresponds to a texture-to-buffer copy and uses buffer-copy alignment rules.
3134
3216
  * @note On WebGL, luma.gl emulates the same logical readback behavior.
3135
3217
  */
@@ -3142,6 +3224,7 @@ or create a device with the 'debug: true' prop.`;
3142
3224
  *
3143
3225
  * @note The memory layout of the texture data is determined by the texture format and dimensions.
3144
3226
  * @note The application can call Texture.computeMemoryLayout() to compute the layout.
3227
+ * @deprecated Use Texture.readBuffer() with an explicit destination buffer, or DynamicTexture.readAsync() for convenience readback.
3145
3228
  */
3146
3229
  readDataAsync(options) {
3147
3230
  throw new Error("readBuffer not implemented");
@@ -3888,7 +3971,8 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
3888
3971
  bufferMode: void 0,
3889
3972
  disableWarnings: false,
3890
3973
  _sharedRenderPipeline: void 0,
3891
- bindings: void 0
3974
+ bindings: void 0,
3975
+ bindGroups: void 0
3892
3976
  });
3893
3977
 
3894
3978
  // ../core/src/adapter/resources/shared-render-pipeline.ts
@@ -3908,6 +3992,482 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
3908
3992
  }
3909
3993
  };
3910
3994
 
3995
+ // ../core/src/adapter/resources/compute-pipeline.ts
3996
+ var _ComputePipeline = class extends Resource {
3997
+ get [Symbol.toStringTag]() {
3998
+ return "ComputePipeline";
3999
+ }
4000
+ hash = "";
4001
+ /** The merged shader layout */
4002
+ shaderLayout;
4003
+ constructor(device, props) {
4004
+ super(device, props, _ComputePipeline.defaultProps);
4005
+ this.shaderLayout = props.shaderLayout;
4006
+ }
4007
+ };
4008
+ var ComputePipeline = _ComputePipeline;
4009
+ __publicField(ComputePipeline, "defaultProps", {
4010
+ ...Resource.defaultProps,
4011
+ shader: void 0,
4012
+ entryPoint: void 0,
4013
+ constants: {},
4014
+ shaderLayout: void 0
4015
+ });
4016
+
4017
+ // ../core/src/factories/pipeline-factory.ts
4018
+ var _PipelineFactory = class {
4019
+ /** Get the singleton default pipeline factory for the specified device */
4020
+ static getDefaultPipelineFactory(device) {
4021
+ const moduleData = device.getModuleData("@luma.gl/core");
4022
+ moduleData.defaultPipelineFactory ||= new _PipelineFactory(device);
4023
+ return moduleData.defaultPipelineFactory;
4024
+ }
4025
+ device;
4026
+ _hashCounter = 0;
4027
+ _hashes = {};
4028
+ _renderPipelineCache = {};
4029
+ _computePipelineCache = {};
4030
+ _sharedRenderPipelineCache = {};
4031
+ get [Symbol.toStringTag]() {
4032
+ return "PipelineFactory";
4033
+ }
4034
+ toString() {
4035
+ return `PipelineFactory(${this.device.id})`;
4036
+ }
4037
+ constructor(device) {
4038
+ this.device = device;
4039
+ }
4040
+ /**
4041
+ * WebGL has two cache layers with different priorities:
4042
+ * - `_sharedRenderPipelineCache` owns `WEBGLSharedRenderPipeline` / `WebGLProgram` reuse.
4043
+ * - `_renderPipelineCache` owns `RenderPipeline` wrapper reuse.
4044
+ *
4045
+ * Shared WebGL program reuse is the hard requirement. Wrapper reuse is beneficial,
4046
+ * but wrapper cache misses are acceptable if that keeps the cache logic simple and
4047
+ * prevents incorrect cache hits.
4048
+ *
4049
+ * In particular, wrapper hash logic must never force program creation or linked-program
4050
+ * introspection just to decide whether a shared WebGL program can be reused.
4051
+ */
4052
+ /** Return a RenderPipeline matching supplied props. Reuses an equivalent pipeline if already created. */
4053
+ createRenderPipeline(props) {
4054
+ if (!this.device.props._cachePipelines) {
4055
+ return this.device.createRenderPipeline(props);
4056
+ }
4057
+ const allProps = { ...RenderPipeline.defaultProps, ...props };
4058
+ const cache = this._renderPipelineCache;
4059
+ const hash = this._hashRenderPipeline(allProps);
4060
+ let pipeline = cache[hash]?.resource;
4061
+ if (!pipeline) {
4062
+ const sharedRenderPipeline = this.device.type === "webgl" && this.device.props._sharePipelines ? this.createSharedRenderPipeline(allProps) : void 0;
4063
+ pipeline = this.device.createRenderPipeline({
4064
+ ...allProps,
4065
+ id: allProps.id ? `${allProps.id}-cached` : uid("unnamed-cached"),
4066
+ _sharedRenderPipeline: sharedRenderPipeline
4067
+ });
4068
+ pipeline.hash = hash;
4069
+ cache[hash] = { resource: pipeline, useCount: 1 };
4070
+ if (this.device.props.debugFactories) {
4071
+ log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
4072
+ }
4073
+ } else {
4074
+ cache[hash].useCount++;
4075
+ if (this.device.props.debugFactories) {
4076
+ log.log(
4077
+ 3,
4078
+ `${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`
4079
+ )();
4080
+ }
4081
+ }
4082
+ return pipeline;
4083
+ }
4084
+ /** Return a ComputePipeline matching supplied props. Reuses an equivalent pipeline if already created. */
4085
+ createComputePipeline(props) {
4086
+ if (!this.device.props._cachePipelines) {
4087
+ return this.device.createComputePipeline(props);
4088
+ }
4089
+ const allProps = { ...ComputePipeline.defaultProps, ...props };
4090
+ const cache = this._computePipelineCache;
4091
+ const hash = this._hashComputePipeline(allProps);
4092
+ let pipeline = cache[hash]?.resource;
4093
+ if (!pipeline) {
4094
+ pipeline = this.device.createComputePipeline({
4095
+ ...allProps,
4096
+ id: allProps.id ? `${allProps.id}-cached` : void 0
4097
+ });
4098
+ pipeline.hash = hash;
4099
+ cache[hash] = { resource: pipeline, useCount: 1 };
4100
+ if (this.device.props.debugFactories) {
4101
+ log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
4102
+ }
4103
+ } else {
4104
+ cache[hash].useCount++;
4105
+ if (this.device.props.debugFactories) {
4106
+ log.log(
4107
+ 3,
4108
+ `${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`
4109
+ )();
4110
+ }
4111
+ }
4112
+ return pipeline;
4113
+ }
4114
+ release(pipeline) {
4115
+ if (!this.device.props._cachePipelines) {
4116
+ pipeline.destroy();
4117
+ return;
4118
+ }
4119
+ const cache = this._getCache(pipeline);
4120
+ const hash = pipeline.hash;
4121
+ cache[hash].useCount--;
4122
+ if (cache[hash].useCount === 0) {
4123
+ this._destroyPipeline(pipeline);
4124
+ if (this.device.props.debugFactories) {
4125
+ log.log(3, `${this}: ${pipeline} released and destroyed`)();
4126
+ }
4127
+ } else if (cache[hash].useCount < 0) {
4128
+ log.error(`${this}: ${pipeline} released, useCount < 0, resetting`)();
4129
+ cache[hash].useCount = 0;
4130
+ } else if (this.device.props.debugFactories) {
4131
+ log.log(3, `${this}: ${pipeline} released, count=${cache[hash].useCount}`)();
4132
+ }
4133
+ }
4134
+ createSharedRenderPipeline(props) {
4135
+ const sharedPipelineHash = this._hashSharedRenderPipeline(props);
4136
+ let sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
4137
+ if (!sharedCacheItem) {
4138
+ const sharedRenderPipeline = this.device._createSharedRenderPipelineWebGL(props);
4139
+ sharedCacheItem = { resource: sharedRenderPipeline, useCount: 0 };
4140
+ this._sharedRenderPipelineCache[sharedPipelineHash] = sharedCacheItem;
4141
+ }
4142
+ sharedCacheItem.useCount++;
4143
+ return sharedCacheItem.resource;
4144
+ }
4145
+ releaseSharedRenderPipeline(pipeline) {
4146
+ if (!pipeline.sharedRenderPipeline) {
4147
+ return;
4148
+ }
4149
+ const sharedPipelineHash = this._hashSharedRenderPipeline(pipeline.sharedRenderPipeline.props);
4150
+ const sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
4151
+ if (!sharedCacheItem) {
4152
+ return;
4153
+ }
4154
+ sharedCacheItem.useCount--;
4155
+ if (sharedCacheItem.useCount === 0) {
4156
+ sharedCacheItem.resource.destroy();
4157
+ delete this._sharedRenderPipelineCache[sharedPipelineHash];
4158
+ }
4159
+ }
4160
+ // PRIVATE
4161
+ /** Destroy a cached pipeline, removing it from the cache if configured to do so. */
4162
+ _destroyPipeline(pipeline) {
4163
+ const cache = this._getCache(pipeline);
4164
+ if (!this.device.props._destroyPipelines) {
4165
+ return false;
4166
+ }
4167
+ delete cache[pipeline.hash];
4168
+ pipeline.destroy();
4169
+ if (pipeline instanceof RenderPipeline) {
4170
+ this.releaseSharedRenderPipeline(pipeline);
4171
+ }
4172
+ return true;
4173
+ }
4174
+ /** Get the appropriate cache for the type of pipeline */
4175
+ _getCache(pipeline) {
4176
+ let cache;
4177
+ if (pipeline instanceof ComputePipeline) {
4178
+ cache = this._computePipelineCache;
4179
+ }
4180
+ if (pipeline instanceof RenderPipeline) {
4181
+ cache = this._renderPipelineCache;
4182
+ }
4183
+ if (!cache) {
4184
+ throw new Error(`${this}`);
4185
+ }
4186
+ if (!cache[pipeline.hash]) {
4187
+ throw new Error(`${this}: ${pipeline} matched incorrect entry`);
4188
+ }
4189
+ return cache;
4190
+ }
4191
+ /** Calculate a hash based on all the inputs for a compute pipeline */
4192
+ _hashComputePipeline(props) {
4193
+ const { type } = this.device;
4194
+ const shaderHash = this._getHash(props.shader.source);
4195
+ const shaderLayoutHash = this._getHash(JSON.stringify(props.shaderLayout));
4196
+ return `${type}/C/${shaderHash}SL${shaderLayoutHash}`;
4197
+ }
4198
+ /** Calculate a hash based on all the inputs for a render pipeline */
4199
+ _hashRenderPipeline(props) {
4200
+ const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
4201
+ const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
4202
+ const varyingHash = this._getWebGLVaryingHash(props);
4203
+ const shaderLayoutHash = this._getHash(JSON.stringify(props.shaderLayout));
4204
+ const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
4205
+ const { type } = this.device;
4206
+ switch (type) {
4207
+ case "webgl":
4208
+ const webglParameterHash = this._getHash(JSON.stringify(props.parameters));
4209
+ return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${webglParameterHash}SL${shaderLayoutHash}BL${bufferLayoutHash}`;
4210
+ case "webgpu":
4211
+ default:
4212
+ const entryPointHash = this._getHash(
4213
+ JSON.stringify({
4214
+ vertexEntryPoint: props.vertexEntryPoint,
4215
+ fragmentEntryPoint: props.fragmentEntryPoint
4216
+ })
4217
+ );
4218
+ const parameterHash = this._getHash(JSON.stringify(props.parameters));
4219
+ const attachmentHash = this._getWebGPUAttachmentHash(props);
4220
+ return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}EP${entryPointHash}P${parameterHash}SL${shaderLayoutHash}BL${bufferLayoutHash}A${attachmentHash}`;
4221
+ }
4222
+ }
4223
+ // This is the only gate for shared `WebGLProgram` reuse.
4224
+ // Only include inputs that affect program linking or transform-feedback linkage.
4225
+ // Wrapper-only concerns such as topology, parameters, attachment formats and layout
4226
+ // overrides must not be added here.
4227
+ _hashSharedRenderPipeline(props) {
4228
+ const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
4229
+ const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
4230
+ const varyingHash = this._getWebGLVaryingHash(props);
4231
+ return `webgl/S/${vsHash}/${fsHash}V${varyingHash}`;
4232
+ }
4233
+ _getHash(key) {
4234
+ if (this._hashes[key] === void 0) {
4235
+ this._hashes[key] = this._hashCounter++;
4236
+ }
4237
+ return this._hashes[key];
4238
+ }
4239
+ _getWebGLVaryingHash(props) {
4240
+ const { varyings = [], bufferMode = null } = props;
4241
+ return this._getHash(JSON.stringify({ varyings, bufferMode }));
4242
+ }
4243
+ _getWebGPUAttachmentHash(props) {
4244
+ const colorAttachmentFormats = props.colorAttachmentFormats ?? [
4245
+ this.device.preferredColorFormat
4246
+ ];
4247
+ const depthStencilAttachmentFormat = props.parameters?.depthWriteEnabled ? props.depthStencilAttachmentFormat || this.device.preferredDepthFormat : null;
4248
+ return this._getHash(
4249
+ JSON.stringify({
4250
+ colorAttachmentFormats,
4251
+ depthStencilAttachmentFormat
4252
+ })
4253
+ );
4254
+ }
4255
+ };
4256
+ var PipelineFactory = _PipelineFactory;
4257
+ __publicField(PipelineFactory, "defaultProps", { ...RenderPipeline.defaultProps });
4258
+
4259
+ // ../core/src/factories/shader-factory.ts
4260
+ var _ShaderFactory = class {
4261
+ /** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
4262
+ static getDefaultShaderFactory(device) {
4263
+ const moduleData = device.getModuleData("@luma.gl/core");
4264
+ moduleData.defaultShaderFactory ||= new _ShaderFactory(device);
4265
+ return moduleData.defaultShaderFactory;
4266
+ }
4267
+ device;
4268
+ _cache = {};
4269
+ get [Symbol.toStringTag]() {
4270
+ return "ShaderFactory";
4271
+ }
4272
+ toString() {
4273
+ return `${this[Symbol.toStringTag]}(${this.device.id})`;
4274
+ }
4275
+ /** @internal */
4276
+ constructor(device) {
4277
+ this.device = device;
4278
+ }
4279
+ /** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
4280
+ createShader(props) {
4281
+ if (!this.device.props._cacheShaders) {
4282
+ return this.device.createShader(props);
4283
+ }
4284
+ const key = this._hashShader(props);
4285
+ let cacheEntry = this._cache[key];
4286
+ if (!cacheEntry) {
4287
+ const resource = this.device.createShader({
4288
+ ...props,
4289
+ id: props.id ? `${props.id}-cached` : void 0
4290
+ });
4291
+ this._cache[key] = cacheEntry = { resource, useCount: 1 };
4292
+ if (this.device.props.debugFactories) {
4293
+ log.log(3, `${this}: Created new shader ${resource.id}`)();
4294
+ }
4295
+ } else {
4296
+ cacheEntry.useCount++;
4297
+ if (this.device.props.debugFactories) {
4298
+ log.log(
4299
+ 3,
4300
+ `${this}: Reusing shader ${cacheEntry.resource.id} count=${cacheEntry.useCount}`
4301
+ )();
4302
+ }
4303
+ }
4304
+ return cacheEntry.resource;
4305
+ }
4306
+ /** Releases a previously-requested {@link Shader}, destroying it if no users remain. */
4307
+ release(shader) {
4308
+ if (!this.device.props._cacheShaders) {
4309
+ shader.destroy();
4310
+ return;
4311
+ }
4312
+ const key = this._hashShader(shader);
4313
+ const cacheEntry = this._cache[key];
4314
+ if (cacheEntry) {
4315
+ cacheEntry.useCount--;
4316
+ if (cacheEntry.useCount === 0) {
4317
+ if (this.device.props._destroyShaders) {
4318
+ delete this._cache[key];
4319
+ cacheEntry.resource.destroy();
4320
+ if (this.device.props.debugFactories) {
4321
+ log.log(3, `${this}: Releasing shader ${shader.id}, destroyed`)();
4322
+ }
4323
+ }
4324
+ } else if (cacheEntry.useCount < 0) {
4325
+ throw new Error(`ShaderFactory: Shader ${shader.id} released too many times`);
4326
+ } else if (this.device.props.debugFactories) {
4327
+ log.log(3, `${this}: Releasing shader ${shader.id} count=${cacheEntry.useCount}`)();
4328
+ }
4329
+ }
4330
+ }
4331
+ // PRIVATE
4332
+ _hashShader(value) {
4333
+ return `${value.stage}:${value.source}`;
4334
+ }
4335
+ };
4336
+ var ShaderFactory = _ShaderFactory;
4337
+ __publicField(ShaderFactory, "defaultProps", { ...Shader.defaultProps });
4338
+
4339
+ // ../core/src/adapter-utils/bind-groups.ts
4340
+ function getShaderLayoutBinding(shaderLayout, bindingName, options) {
4341
+ const bindingLayout = shaderLayout.bindings.find(
4342
+ (binding) => binding.name === bindingName || `${binding.name.toLocaleLowerCase()}uniforms` === bindingName.toLocaleLowerCase()
4343
+ );
4344
+ if (!bindingLayout && !options?.ignoreWarnings) {
4345
+ log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();
4346
+ }
4347
+ return bindingLayout || null;
4348
+ }
4349
+ function normalizeBindingsByGroup(shaderLayout, bindingsOrBindGroups) {
4350
+ if (!bindingsOrBindGroups) {
4351
+ return {};
4352
+ }
4353
+ if (areBindingsGrouped(bindingsOrBindGroups)) {
4354
+ const bindGroups2 = bindingsOrBindGroups;
4355
+ return Object.fromEntries(
4356
+ Object.entries(bindGroups2).map(([group, bindings]) => [Number(group), { ...bindings }])
4357
+ );
4358
+ }
4359
+ const bindGroups = {};
4360
+ for (const [bindingName, binding] of Object.entries(bindingsOrBindGroups)) {
4361
+ const bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
4362
+ const group = bindingLayout?.group ?? 0;
4363
+ bindGroups[group] ||= {};
4364
+ bindGroups[group][bindingName] = binding;
4365
+ }
4366
+ return bindGroups;
4367
+ }
4368
+ function flattenBindingsByGroup(bindGroups) {
4369
+ const bindings = {};
4370
+ for (const groupBindings of Object.values(bindGroups)) {
4371
+ Object.assign(bindings, groupBindings);
4372
+ }
4373
+ return bindings;
4374
+ }
4375
+ function areBindingsGrouped(bindingsOrBindGroups) {
4376
+ const keys = Object.keys(bindingsOrBindGroups);
4377
+ return keys.length > 0 && keys.every((key) => /^\d+$/.test(key));
4378
+ }
4379
+
4380
+ // ../core/src/factories/bind-group-factory.ts
4381
+ var BindGroupFactory = class {
4382
+ device;
4383
+ _layoutCacheByPipeline = /* @__PURE__ */ new WeakMap();
4384
+ _bindGroupCacheByLayout = /* @__PURE__ */ new WeakMap();
4385
+ constructor(device) {
4386
+ this.device = device;
4387
+ }
4388
+ getBindGroups(pipeline, bindings, bindGroupCacheKeys) {
4389
+ if (this.device.type !== "webgpu" || pipeline.shaderLayout.bindings.length === 0) {
4390
+ return {};
4391
+ }
4392
+ const bindingsByGroup = normalizeBindingsByGroup(pipeline.shaderLayout, bindings);
4393
+ const resolvedBindGroups = {};
4394
+ for (const group of getBindGroupIndicesUpToMax(pipeline.shaderLayout.bindings)) {
4395
+ const groupBindings = bindingsByGroup[group];
4396
+ const bindGroupLayout = this._getBindGroupLayout(pipeline, group);
4397
+ if (!groupBindings || Object.keys(groupBindings).length === 0) {
4398
+ if (!hasBindingsInGroup(pipeline.shaderLayout.bindings, group)) {
4399
+ resolvedBindGroups[group] = this._getEmptyBindGroup(
4400
+ bindGroupLayout,
4401
+ pipeline.shaderLayout,
4402
+ group
4403
+ );
4404
+ }
4405
+ continue;
4406
+ }
4407
+ const bindGroupCacheKey = bindGroupCacheKeys?.[group];
4408
+ if (bindGroupCacheKey) {
4409
+ const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
4410
+ if (layoutCache.bindGroupsBySource.has(bindGroupCacheKey)) {
4411
+ resolvedBindGroups[group] = layoutCache.bindGroupsBySource.get(bindGroupCacheKey) || null;
4412
+ continue;
4413
+ }
4414
+ const bindGroup = this.device._createBindGroupWebGPU(
4415
+ bindGroupLayout,
4416
+ pipeline.shaderLayout,
4417
+ groupBindings,
4418
+ group
4419
+ );
4420
+ layoutCache.bindGroupsBySource.set(bindGroupCacheKey, bindGroup);
4421
+ resolvedBindGroups[group] = bindGroup;
4422
+ } else {
4423
+ resolvedBindGroups[group] = this.device._createBindGroupWebGPU(
4424
+ bindGroupLayout,
4425
+ pipeline.shaderLayout,
4426
+ groupBindings,
4427
+ group
4428
+ );
4429
+ }
4430
+ }
4431
+ return resolvedBindGroups;
4432
+ }
4433
+ _getBindGroupLayout(pipeline, group) {
4434
+ let layoutCache = this._layoutCacheByPipeline.get(pipeline);
4435
+ if (!layoutCache) {
4436
+ layoutCache = {};
4437
+ this._layoutCacheByPipeline.set(pipeline, layoutCache);
4438
+ }
4439
+ layoutCache[group] ||= this.device._createBindGroupLayoutWebGPU(pipeline, group);
4440
+ return layoutCache[group];
4441
+ }
4442
+ _getEmptyBindGroup(bindGroupLayout, shaderLayout, group) {
4443
+ const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
4444
+ layoutCache.emptyBindGroup ||= this.device._createBindGroupWebGPU(bindGroupLayout, shaderLayout, {}, group) || null;
4445
+ return layoutCache.emptyBindGroup;
4446
+ }
4447
+ _getLayoutBindGroupCache(bindGroupLayout) {
4448
+ let layoutCache = this._bindGroupCacheByLayout.get(bindGroupLayout);
4449
+ if (!layoutCache) {
4450
+ layoutCache = { bindGroupsBySource: /* @__PURE__ */ new WeakMap() };
4451
+ this._bindGroupCacheByLayout.set(bindGroupLayout, layoutCache);
4452
+ }
4453
+ return layoutCache;
4454
+ }
4455
+ };
4456
+ function _getDefaultBindGroupFactory(device) {
4457
+ device._factories.bindGroupFactory ||= new BindGroupFactory(device);
4458
+ return device._factories.bindGroupFactory;
4459
+ }
4460
+ function getBindGroupIndicesUpToMax(bindings) {
4461
+ const maxGroup = bindings.reduce(
4462
+ (highestGroup, binding) => Math.max(highestGroup, binding.group),
4463
+ -1
4464
+ );
4465
+ return Array.from({ length: maxGroup + 1 }, (_, group) => group);
4466
+ }
4467
+ function hasBindingsInGroup(bindings, group) {
4468
+ return bindings.some((binding) => binding.group === group);
4469
+ }
4470
+
3911
4471
  // ../core/src/adapter/resources/render-pass.ts
3912
4472
  var _RenderPass = class extends Resource {
3913
4473
  get [Symbol.toStringTag]() {
@@ -3946,28 +4506,6 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
3946
4506
  endTimestampIndex: void 0
3947
4507
  });
3948
4508
 
3949
- // ../core/src/adapter/resources/compute-pipeline.ts
3950
- var _ComputePipeline = class extends Resource {
3951
- get [Symbol.toStringTag]() {
3952
- return "ComputePipeline";
3953
- }
3954
- hash = "";
3955
- /** The merged shader layout */
3956
- shaderLayout;
3957
- constructor(device, props) {
3958
- super(device, props, _ComputePipeline.defaultProps);
3959
- this.shaderLayout = props.shaderLayout;
3960
- }
3961
- };
3962
- var ComputePipeline = _ComputePipeline;
3963
- __publicField(ComputePipeline, "defaultProps", {
3964
- ...Resource.defaultProps,
3965
- shader: void 0,
3966
- entryPoint: void 0,
3967
- constants: {},
3968
- shaderLayout: void 0
3969
- });
3970
-
3971
4509
  // ../core/src/adapter/resources/compute-pass.ts
3972
4510
  var _ComputePass = class extends Resource {
3973
4511
  constructor(device, props) {
@@ -4079,7 +4617,7 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4079
4617
  ...Resource.defaultProps
4080
4618
  });
4081
4619
 
4082
- // ../core/src/shadertypes/data-types/decode-shader-types.ts
4620
+ // ../core/src/shadertypes/shader-types/shader-type-decoder.ts
4083
4621
  function getVariableShaderTypeInfo(format) {
4084
4622
  const resolvedFormat = resolveVariableShaderTypeAlias(format);
4085
4623
  const decoded = UNIFORM_FORMATS[resolvedFormat];
@@ -4106,12 +4644,33 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4106
4644
  signed
4107
4645
  };
4108
4646
  }
4647
+ var ShaderTypeDecoder = class {
4648
+ getVariableShaderTypeInfo(format) {
4649
+ return getVariableShaderTypeInfo(format);
4650
+ }
4651
+ getAttributeShaderTypeInfo(attributeType) {
4652
+ return getAttributeShaderTypeInfo(attributeType);
4653
+ }
4654
+ makeShaderAttributeType(primitiveType, components) {
4655
+ return makeShaderAttributeType(primitiveType, components);
4656
+ }
4657
+ resolveAttributeShaderTypeAlias(alias) {
4658
+ return resolveAttributeShaderTypeAlias(alias);
4659
+ }
4660
+ resolveVariableShaderTypeAlias(alias) {
4661
+ return resolveVariableShaderTypeAlias(alias);
4662
+ }
4663
+ };
4664
+ function makeShaderAttributeType(primitiveType, components) {
4665
+ return components === 1 ? primitiveType : `vec${components}<${primitiveType}>`;
4666
+ }
4109
4667
  function resolveAttributeShaderTypeAlias(alias) {
4110
4668
  return WGSL_ATTRIBUTE_TYPE_ALIAS_MAP[alias] || alias;
4111
4669
  }
4112
4670
  function resolveVariableShaderTypeAlias(alias) {
4113
4671
  return WGSL_VARIABLE_TYPE_ALIAS_MAP[alias] || alias;
4114
4672
  }
4673
+ var shaderTypeDecoder = new ShaderTypeDecoder();
4115
4674
  var PRIMITIVE_TYPE_SIZES = {
4116
4675
  f32: 4,
4117
4676
  f16: 2,
@@ -4208,7 +4767,18 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4208
4767
  vec4h: "vec4<f16>"
4209
4768
  };
4210
4769
  var WGSL_VARIABLE_TYPE_ALIAS_MAP = {
4211
- ...WGSL_ATTRIBUTE_TYPE_ALIAS_MAP,
4770
+ vec2i: "vec2<i32>",
4771
+ vec3i: "vec3<i32>",
4772
+ vec4i: "vec4<i32>",
4773
+ vec2u: "vec2<u32>",
4774
+ vec3u: "vec3<u32>",
4775
+ vec4u: "vec4<u32>",
4776
+ vec2f: "vec2<f32>",
4777
+ vec3f: "vec3<f32>",
4778
+ vec4f: "vec4<f32>",
4779
+ vec2h: "vec2<f16>",
4780
+ vec3h: "vec3<f16>",
4781
+ vec4h: "vec4<f16>",
4212
4782
  mat2x2f: "mat2x2<f32>",
4213
4783
  mat2x3f: "mat2x3<f32>",
4214
4784
  mat2x4f: "mat2x4<f32>",
@@ -4275,10 +4845,10 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4275
4845
  if (!shaderDeclaration) {
4276
4846
  return null;
4277
4847
  }
4278
- const attributeTypeInfo = getAttributeShaderTypeInfo(shaderDeclaration.type);
4279
- const defaultVertexFormat = getCompatibleVertexFormat(attributeTypeInfo);
4848
+ const attributeTypeInfo = shaderTypeDecoder.getAttributeShaderTypeInfo(shaderDeclaration.type);
4849
+ const defaultVertexFormat = vertexFormatDecoder.getCompatibleVertexFormat(attributeTypeInfo);
4280
4850
  const vertexFormat = bufferMapping?.vertexFormat || defaultVertexFormat;
4281
- const vertexFormatInfo = getVertexFormatInfo(vertexFormat);
4851
+ const vertexFormatInfo = vertexFormatDecoder.getVertexFormatInfo(vertexFormat);
4282
4852
  return {
4283
4853
  attributeName: bufferMapping?.attributeName || shaderDeclaration.name,
4284
4854
  bufferName: bufferMapping?.bufferName || shaderDeclaration.name,
@@ -4346,7 +4916,7 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4346
4916
  let byteStride = bufferLayout.byteStride;
4347
4917
  if (typeof bufferLayout.byteStride !== "number") {
4348
4918
  for (const attributeMapping2 of bufferLayout.attributes || []) {
4349
- const info = getVertexFormatInfo(attributeMapping2.format);
4919
+ const info = vertexFormatDecoder.getVertexFormatInfo(attributeMapping2.format);
4350
4920
  byteStride += info.byteLength;
4351
4921
  }
4352
4922
  }
@@ -4466,6 +5036,36 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4466
5036
  }
4467
5037
  });
4468
5038
 
5039
+ // ../core/src/shadertypes/data-types/decode-data-types.ts
5040
+ function alignTo(size, count) {
5041
+ switch (count) {
5042
+ case 1:
5043
+ return size;
5044
+ case 2:
5045
+ return size + size % 2;
5046
+ default:
5047
+ return size + (4 - size % 4) % 4;
5048
+ }
5049
+ }
5050
+ function getTypedArrayConstructor(type) {
5051
+ const [, , , , Constructor] = NORMALIZED_TYPE_MAP2[type];
5052
+ return Constructor;
5053
+ }
5054
+ var NORMALIZED_TYPE_MAP2 = {
5055
+ uint8: ["uint8", "u32", 1, false, Uint8Array],
5056
+ sint8: ["sint8", "i32", 1, false, Int8Array],
5057
+ unorm8: ["uint8", "f32", 1, true, Uint8Array],
5058
+ snorm8: ["sint8", "f32", 1, true, Int8Array],
5059
+ uint16: ["uint16", "u32", 2, false, Uint16Array],
5060
+ sint16: ["sint16", "i32", 2, false, Int16Array],
5061
+ unorm16: ["uint16", "u32", 2, true, Uint16Array],
5062
+ snorm16: ["sint16", "i32", 2, true, Int16Array],
5063
+ float16: ["float16", "f16", 2, false, Uint16Array],
5064
+ float32: ["float32", "f32", 4, false, Float32Array],
5065
+ uint32: ["uint32", "u32", 4, false, Uint32Array],
5066
+ sint32: ["sint32", "i32", 4, false, Int32Array]
5067
+ };
5068
+
4469
5069
  // ../core/src/utils/array-utils-flat.ts
4470
5070
  var arrayBuffer;
4471
5071
  function getScratchArrayBuffer(byteLength) {
@@ -4479,19 +5079,32 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4479
5079
  return new Type(scratchArrayBuffer, 0, length);
4480
5080
  }
4481
5081
 
5082
+ // ../core/src/utils/is-array.ts
5083
+ function isTypedArray(value) {
5084
+ return ArrayBuffer.isView(value) && !(value instanceof DataView);
5085
+ }
5086
+ function isNumberArray(value) {
5087
+ if (Array.isArray(value)) {
5088
+ return value.length === 0 || typeof value[0] === "number";
5089
+ }
5090
+ return isTypedArray(value);
5091
+ }
5092
+
4482
5093
  // ../core/src/portable/uniform-buffer-layout.ts
4483
5094
  var minBufferSize = 1024;
4484
5095
  var UniformBufferLayout = class {
4485
5096
  layout = {};
5097
+ uniformTypes;
4486
5098
  /** number of bytes needed for buffer allocation */
4487
5099
  byteLength;
4488
5100
  /** Create a new UniformBufferLayout given a map of attributes. */
4489
- constructor(uniformTypes, uniformSizes = {}) {
5101
+ constructor(uniformTypes) {
5102
+ this.uniformTypes = { ...uniformTypes };
4490
5103
  let size = 0;
4491
- for (const [key, uniformType] of Object.entries(uniformTypes)) {
4492
- size = this._addToLayout(key, uniformType, size, uniformSizes?.[key]);
5104
+ for (const [key, uniformType] of Object.entries(this.uniformTypes)) {
5105
+ size = this._addToLayout(key, uniformType, size);
4493
5106
  }
4494
- size += (4 - size % 4) % 4;
5107
+ size = alignTo(size, 4);
4495
5108
  this.byteLength = Math.max(size * 4, minBufferSize);
4496
5109
  }
4497
5110
  /** Does this layout have a field with specified name */
@@ -4503,98 +5116,241 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4503
5116
  const layout = this.layout[name2];
4504
5117
  return layout;
4505
5118
  }
5119
+ /** Flatten nested uniform values into leaf-path values understood by UniformBlock. */
5120
+ getFlatUniformValues(uniformValues) {
5121
+ const flattenedUniformValues = {};
5122
+ for (const [name2, value] of Object.entries(uniformValues)) {
5123
+ const uniformType = this.uniformTypes[name2];
5124
+ if (uniformType) {
5125
+ this._flattenCompositeValue(flattenedUniformValues, name2, uniformType, value);
5126
+ } else if (this.layout[name2]) {
5127
+ flattenedUniformValues[name2] = value;
5128
+ }
5129
+ }
5130
+ return flattenedUniformValues;
5131
+ }
4506
5132
  /** Get the data for the complete buffer */
4507
5133
  getData(uniformValues) {
4508
5134
  const buffer = getScratchArrayBuffer(this.byteLength);
5135
+ new Uint8Array(buffer, 0, this.byteLength).fill(0);
4509
5136
  const typedArrays = {
4510
5137
  i32: new Int32Array(buffer),
4511
5138
  u32: new Uint32Array(buffer),
4512
5139
  f32: new Float32Array(buffer),
4513
5140
  f16: new Uint16Array(buffer)
4514
5141
  };
4515
- for (const [name2, value] of Object.entries(uniformValues)) {
4516
- this._writeCompositeValue(typedArrays, name2, value);
5142
+ const flattenedUniformValues = this.getFlatUniformValues(uniformValues);
5143
+ for (const [name2, value] of Object.entries(flattenedUniformValues)) {
5144
+ this._writeLeafValue(typedArrays, name2, value);
4517
5145
  }
4518
5146
  return new Uint8Array(buffer, 0, this.byteLength);
4519
5147
  }
4520
5148
  // Recursively add a uniform to the layout
4521
- _addToLayout(name2, type, offset, count = 1) {
5149
+ _addToLayout(name2, type, offset) {
4522
5150
  if (typeof type === "string") {
4523
- const info = getVariableShaderTypeInfo(type);
4524
- const sizeInSlots = info.components * count;
4525
- const alignedOffset = alignTo(offset, info.components);
5151
+ const info = getLeafLayoutInfo(type);
5152
+ const alignedOffset = alignTo(offset, info.alignment);
4526
5153
  this.layout[name2] = {
4527
5154
  offset: alignedOffset,
4528
- size: sizeInSlots,
4529
- type: info.type
5155
+ ...info
4530
5156
  };
4531
- return alignedOffset + sizeInSlots;
5157
+ return alignedOffset + info.size;
4532
5158
  }
4533
5159
  if (Array.isArray(type)) {
5160
+ if (Array.isArray(type[0])) {
5161
+ throw new Error(`Nested arrays are not supported for ${name2}`);
5162
+ }
4534
5163
  const elementType = type[0];
4535
- const length = count > 1 ? count : type.length > 1 ? type[1] : 1;
4536
- let arrayOffset = alignTo(offset, 4);
5164
+ const length = type[1];
5165
+ const stride = alignTo(getTypeSize(elementType), 4);
5166
+ const arrayOffset = alignTo(offset, 4);
4537
5167
  for (let i = 0; i < length; i++) {
4538
- arrayOffset = this._addToLayout(`${name2}[${i}]`, elementType, arrayOffset);
5168
+ this._addToLayout(`${name2}[${i}]`, elementType, arrayOffset + i * stride);
4539
5169
  }
4540
- return arrayOffset;
5170
+ return arrayOffset + stride * length;
4541
5171
  }
4542
- if (typeof type === "object") {
5172
+ if (isCompositeShaderTypeStruct(type)) {
4543
5173
  let structOffset = alignTo(offset, 4);
4544
5174
  for (const [memberName, memberType] of Object.entries(type)) {
4545
5175
  structOffset = this._addToLayout(`${name2}.${memberName}`, memberType, structOffset);
4546
5176
  }
4547
- return structOffset;
5177
+ return alignTo(structOffset, 4);
4548
5178
  }
4549
5179
  throw new Error(`Unsupported CompositeShaderType for ${name2}`);
4550
5180
  }
4551
- _writeCompositeValue(typedArrays, baseName, value) {
4552
- if (this.layout[baseName]) {
4553
- this._writeToBuffer(typedArrays, baseName, value);
5181
+ _flattenCompositeValue(flattenedUniformValues, baseName, uniformType, value) {
5182
+ if (value === void 0) {
5183
+ return;
5184
+ }
5185
+ if (typeof uniformType === "string" || this.layout[baseName]) {
5186
+ flattenedUniformValues[baseName] = value;
4554
5187
  return;
4555
5188
  }
4556
- if (Array.isArray(value)) {
4557
- for (let i = 0; i < value.length; i++) {
4558
- const element = value[i];
4559
- const indexedName = `${baseName}[${i}]`;
4560
- this._writeCompositeValue(typedArrays, indexedName, element);
5189
+ if (Array.isArray(uniformType)) {
5190
+ const elementType = uniformType[0];
5191
+ const length = uniformType[1];
5192
+ if (Array.isArray(elementType)) {
5193
+ throw new Error(`Nested arrays are not supported for ${baseName}`);
5194
+ }
5195
+ if (typeof elementType === "string" && isNumberArray(value)) {
5196
+ this._flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value);
5197
+ return;
5198
+ }
5199
+ if (!Array.isArray(value)) {
5200
+ log.warn(`Unsupported uniform array value for ${baseName}:`, value)();
5201
+ return;
5202
+ }
5203
+ for (let index = 0; index < Math.min(value.length, length); index++) {
5204
+ const elementValue = value[index];
5205
+ if (elementValue === void 0) {
5206
+ continue;
5207
+ }
5208
+ this._flattenCompositeValue(
5209
+ flattenedUniformValues,
5210
+ `${baseName}[${index}]`,
5211
+ elementType,
5212
+ elementValue
5213
+ );
4561
5214
  }
4562
5215
  return;
4563
5216
  }
4564
- if (typeof value === "object" && value !== null) {
5217
+ if (isCompositeShaderTypeStruct(uniformType) && isCompositeUniformObject(value)) {
4565
5218
  for (const [key, subValue] of Object.entries(value)) {
5219
+ if (subValue === void 0) {
5220
+ continue;
5221
+ }
4566
5222
  const nestedName = `${baseName}.${key}`;
4567
- this._writeCompositeValue(typedArrays, nestedName, subValue);
5223
+ this._flattenCompositeValue(flattenedUniformValues, nestedName, uniformType[key], subValue);
4568
5224
  }
4569
5225
  return;
4570
5226
  }
4571
5227
  log.warn(`Unsupported uniform value for ${baseName}:`, value)();
4572
5228
  }
4573
- _writeToBuffer(typedArrays, name2, value) {
5229
+ _flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value) {
5230
+ const numericValue = value;
5231
+ const elementLayout = getLeafLayoutInfo(elementType);
5232
+ const packedElementLength = elementLayout.components;
5233
+ for (let index = 0; index < length; index++) {
5234
+ const start = index * packedElementLength;
5235
+ if (start >= numericValue.length) {
5236
+ break;
5237
+ }
5238
+ if (packedElementLength === 1) {
5239
+ flattenedUniformValues[`${baseName}[${index}]`] = Number(numericValue[start]);
5240
+ } else {
5241
+ flattenedUniformValues[`${baseName}[${index}]`] = sliceNumericArray(
5242
+ value,
5243
+ start,
5244
+ start + packedElementLength
5245
+ );
5246
+ }
5247
+ }
5248
+ }
5249
+ _writeLeafValue(typedArrays, name2, value) {
4574
5250
  const layout = this.layout[name2];
4575
5251
  if (!layout) {
4576
5252
  log.warn(`Uniform ${name2} not found in layout`)();
4577
5253
  return;
4578
5254
  }
4579
- const { type, size, offset } = layout;
5255
+ const { type, components, columns, rows, offset } = layout;
4580
5256
  const array = typedArrays[type];
4581
- if (size === 1) {
5257
+ if (components === 1) {
4582
5258
  array[offset] = Number(value);
4583
- } else {
4584
- array.set(value, offset);
5259
+ return;
5260
+ }
5261
+ const sourceValue = value;
5262
+ if (columns === 1) {
5263
+ for (let componentIndex = 0; componentIndex < components; componentIndex++) {
5264
+ array[offset + componentIndex] = Number(sourceValue[componentIndex] ?? 0);
5265
+ }
5266
+ return;
5267
+ }
5268
+ let sourceIndex = 0;
5269
+ for (let columnIndex = 0; columnIndex < columns; columnIndex++) {
5270
+ const columnOffset = offset + columnIndex * 4;
5271
+ for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
5272
+ array[columnOffset + rowIndex] = Number(sourceValue[sourceIndex++] ?? 0);
5273
+ }
4585
5274
  }
4586
5275
  }
4587
5276
  };
4588
-
4589
- // ../core/src/utils/is-array.ts
4590
- function isTypedArray(value) {
4591
- return ArrayBuffer.isView(value) && !(value instanceof DataView);
5277
+ function getTypeSize(type) {
5278
+ if (typeof type === "string") {
5279
+ return getLeafLayoutInfo(type).size;
5280
+ }
5281
+ if (Array.isArray(type)) {
5282
+ const elementType = type[0];
5283
+ const length = type[1];
5284
+ if (Array.isArray(elementType)) {
5285
+ throw new Error("Nested arrays are not supported");
5286
+ }
5287
+ return alignTo(getTypeSize(elementType), 4) * length;
5288
+ }
5289
+ let size = 0;
5290
+ for (const memberType of Object.values(type)) {
5291
+ const compositeMemberType = memberType;
5292
+ size = alignTo(size, getTypeAlignment(compositeMemberType));
5293
+ size += getTypeSize(compositeMemberType);
5294
+ }
5295
+ return alignTo(size, 4);
4592
5296
  }
4593
- function isNumberArray(value) {
4594
- if (Array.isArray(value)) {
4595
- return value.length === 0 || typeof value[0] === "number";
5297
+ function getTypeAlignment(type) {
5298
+ if (typeof type === "string") {
5299
+ return getLeafLayoutInfo(type).alignment;
4596
5300
  }
4597
- return isTypedArray(value);
5301
+ if (Array.isArray(type)) {
5302
+ return 4;
5303
+ }
5304
+ return 4;
5305
+ }
5306
+ function getLeafLayoutInfo(type) {
5307
+ const resolvedType = resolveVariableShaderTypeAlias(type);
5308
+ const decodedType = getVariableShaderTypeInfo(resolvedType);
5309
+ const matrixMatch = /^mat(\d)x(\d)<.+>$/.exec(resolvedType);
5310
+ if (matrixMatch) {
5311
+ const columns = Number(matrixMatch[1]);
5312
+ const rows = Number(matrixMatch[2]);
5313
+ return {
5314
+ alignment: 4,
5315
+ size: columns * 4,
5316
+ components: columns * rows,
5317
+ columns,
5318
+ rows,
5319
+ shaderType: resolvedType,
5320
+ type: decodedType.type
5321
+ };
5322
+ }
5323
+ const vectorMatch = /^vec(\d)<.+>$/.exec(resolvedType);
5324
+ if (vectorMatch) {
5325
+ const components = Number(vectorMatch[1]);
5326
+ return {
5327
+ alignment: components === 2 ? 2 : 4,
5328
+ size: components === 3 ? 4 : components,
5329
+ components,
5330
+ columns: 1,
5331
+ rows: components,
5332
+ shaderType: resolvedType,
5333
+ type: decodedType.type
5334
+ };
5335
+ }
5336
+ return {
5337
+ alignment: 1,
5338
+ size: 1,
5339
+ components: 1,
5340
+ columns: 1,
5341
+ rows: 1,
5342
+ shaderType: resolvedType,
5343
+ type: decodedType.type
5344
+ };
5345
+ }
5346
+ function isCompositeShaderTypeStruct(value) {
5347
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5348
+ }
5349
+ function isCompositeUniformObject(value) {
5350
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value) && !ArrayBuffer.isView(value);
5351
+ }
5352
+ function sliceNumericArray(value, start, end) {
5353
+ return Array.prototype.slice.call(value, start, end);
4598
5354
  }
4599
5355
 
4600
5356
  // ../core/src/utils/array-equal.ts
@@ -4696,13 +5452,12 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4696
5452
  constructor(blocks) {
4697
5453
  for (const [bufferName, block] of Object.entries(blocks)) {
4698
5454
  const uniformBufferName = bufferName;
4699
- const uniformBufferLayout = new UniformBufferLayout(
4700
- block.uniformTypes ?? {},
4701
- block.uniformSizes ?? {}
4702
- );
5455
+ const uniformBufferLayout = new UniformBufferLayout(block.uniformTypes ?? {});
4703
5456
  this.uniformBufferLayouts.set(uniformBufferName, uniformBufferLayout);
4704
5457
  const uniformBlock = new UniformBlock({ name: bufferName });
4705
- uniformBlock.setUniforms(block.defaultUniforms || {});
5458
+ uniformBlock.setUniforms(
5459
+ uniformBufferLayout.getFlatUniformValues(block.defaultUniforms || {})
5460
+ );
4706
5461
  this.uniformBlocks.set(uniformBufferName, uniformBlock);
4707
5462
  }
4708
5463
  }
@@ -4718,7 +5473,12 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4718
5473
  */
4719
5474
  setUniforms(uniforms) {
4720
5475
  for (const [blockName, uniformValues] of Object.entries(uniforms)) {
4721
- this.uniformBlocks.get(blockName)?.setUniforms(uniformValues);
5476
+ const uniformBufferName = blockName;
5477
+ const uniformBufferLayout = this.uniformBufferLayouts.get(uniformBufferName);
5478
+ const flattenedUniforms = uniformBufferLayout?.getFlatUniformValues(
5479
+ uniformValues || {}
5480
+ );
5481
+ this.uniformBlocks.get(uniformBufferName)?.setUniforms(flattenedUniforms || {});
4722
5482
  }
4723
5483
  this.updateUniformBuffers();
4724
5484
  }
@@ -4794,7 +5554,7 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4794
5554
  }
4795
5555
  };
4796
5556
 
4797
- // ../core/src/shadertypes/textures/texture-layout.ts
5557
+ // ../core/src/shadertypes/texture-types/texture-layout.ts
4798
5558
  function getTextureImageView(arrayBuffer2, memoryLayout, format, image = 0) {
4799
5559
  const formatInfo = textureFormatDecoder.getInfo(format);
4800
5560
  const bytesPerComponent = formatInfo.bytesPerPixel / formatInfo.components;
@@ -4832,7 +5592,7 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4832
5592
  typedArray.set(subArray, offset);
4833
5593
  }
4834
5594
 
4835
- // ../core/src/shadertypes/textures/pixel-utils.ts
5595
+ // ../core/src/shadertypes/texture-types/pixel-utils.ts
4836
5596
  function readPixel(pixelData, x, y, bitsPerChannel) {
4837
5597
  if (x < 0 || x >= pixelData.width || y < 0 || y >= pixelData.height) {
4838
5598
  throw new Error("Coordinates out of bounds.");