@luma.gl/core 9.3.0-alpha.6 → 9.3.0-alpha.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/dist/adapter/canvas-surface.d.ts +1 -1
  2. package/dist/adapter/canvas-surface.d.ts.map +1 -1
  3. package/dist/adapter/device.d.ts +13 -3
  4. package/dist/adapter/device.d.ts.map +1 -1
  5. package/dist/adapter/device.js +73 -6
  6. package/dist/adapter/device.js.map +1 -1
  7. package/dist/adapter/luma.js +1 -1
  8. package/dist/adapter/resources/command-buffer.d.ts +3 -1
  9. package/dist/adapter/resources/command-buffer.d.ts.map +1 -1
  10. package/dist/adapter/resources/command-buffer.js +3 -1
  11. package/dist/adapter/resources/command-buffer.js.map +1 -1
  12. package/dist/adapter/resources/command-encoder.d.ts +3 -1
  13. package/dist/adapter/resources/command-encoder.d.ts.map +1 -1
  14. package/dist/adapter/resources/command-encoder.js +3 -1
  15. package/dist/adapter/resources/command-encoder.js.map +1 -1
  16. package/dist/adapter/resources/compute-pipeline.d.ts +2 -2
  17. package/dist/adapter/resources/compute-pipeline.d.ts.map +1 -1
  18. package/dist/adapter/resources/framebuffer.d.ts +1 -1
  19. package/dist/adapter/resources/framebuffer.d.ts.map +1 -1
  20. package/dist/adapter/resources/render-pipeline.d.ts +10 -4
  21. package/dist/adapter/resources/render-pipeline.d.ts.map +1 -1
  22. package/dist/adapter/resources/render-pipeline.js +2 -1
  23. package/dist/adapter/resources/render-pipeline.js.map +1 -1
  24. package/dist/adapter/resources/texture-view.d.ts +1 -1
  25. package/dist/adapter/resources/texture-view.d.ts.map +1 -1
  26. package/dist/adapter/resources/texture.d.ts +5 -4
  27. package/dist/adapter/resources/texture.d.ts.map +1 -1
  28. package/dist/adapter/resources/texture.js +4 -3
  29. package/dist/adapter/resources/texture.js.map +1 -1
  30. package/dist/adapter/types/attachments.d.ts +1 -1
  31. package/dist/adapter/types/attachments.d.ts.map +1 -1
  32. package/dist/adapter/types/buffer-layout.d.ts +1 -1
  33. package/dist/adapter/types/buffer-layout.d.ts.map +1 -1
  34. package/dist/adapter/types/parameters.d.ts +3 -1
  35. package/dist/adapter/types/parameters.d.ts.map +1 -1
  36. package/dist/adapter/types/parameters.js +1 -0
  37. package/dist/adapter/types/parameters.js.map +1 -1
  38. package/dist/adapter/types/shader-layout.d.ts +10 -6
  39. package/dist/adapter/types/shader-layout.d.ts.map +1 -1
  40. package/dist/adapter/types/uniforms.d.ts +6 -0
  41. package/dist/adapter/types/uniforms.d.ts.map +1 -1
  42. package/dist/adapter-utils/bind-groups.d.ts +9 -0
  43. package/dist/adapter-utils/bind-groups.d.ts.map +1 -0
  44. package/dist/adapter-utils/bind-groups.js +41 -0
  45. package/dist/adapter-utils/bind-groups.js.map +1 -0
  46. package/dist/adapter-utils/get-attribute-from-layouts.d.ts +2 -2
  47. package/dist/adapter-utils/get-attribute-from-layouts.d.ts.map +1 -1
  48. package/dist/adapter-utils/get-attribute-from-layouts.js +6 -6
  49. package/dist/adapter-utils/get-attribute-from-layouts.js.map +1 -1
  50. package/dist/dist.dev.js +983 -223
  51. package/dist/dist.min.js +5 -5
  52. package/dist/factories/bind-group-factory.d.ts +20 -0
  53. package/dist/factories/bind-group-factory.d.ts.map +1 -0
  54. package/dist/factories/bind-group-factory.js +79 -0
  55. package/dist/factories/bind-group-factory.js.map +1 -0
  56. package/dist/factories/core-module-state.d.ts +7 -0
  57. package/dist/factories/core-module-state.d.ts.map +1 -0
  58. package/dist/{shadertypes/data-types/shader-types.js → factories/core-module-state.js} +1 -1
  59. package/dist/factories/core-module-state.js.map +1 -0
  60. package/dist/factories/pipeline-factory.d.ts +54 -0
  61. package/dist/factories/pipeline-factory.d.ts.map +1 -0
  62. package/dist/factories/pipeline-factory.js +270 -0
  63. package/dist/factories/pipeline-factory.js.map +1 -0
  64. package/dist/factories/shader-factory.d.ts +20 -0
  65. package/dist/factories/shader-factory.d.ts.map +1 -0
  66. package/dist/factories/shader-factory.js +84 -0
  67. package/dist/factories/shader-factory.js.map +1 -0
  68. package/dist/index.cjs +942 -221
  69. package/dist/index.cjs.map +4 -4
  70. package/dist/index.d.ts +22 -14
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +13 -9
  73. package/dist/index.js.map +1 -1
  74. package/dist/portable/uniform-block.d.ts +1 -1
  75. package/dist/portable/uniform-block.d.ts.map +1 -1
  76. package/dist/portable/uniform-buffer-layout.d.ts +20 -15
  77. package/dist/portable/uniform-buffer-layout.d.ts.map +1 -1
  78. package/dist/portable/uniform-buffer-layout.js +188 -43
  79. package/dist/portable/uniform-buffer-layout.js.map +1 -1
  80. package/dist/portable/uniform-store.d.ts +5 -6
  81. package/dist/portable/uniform-store.d.ts.map +1 -1
  82. package/dist/portable/uniform-store.js +6 -3
  83. package/dist/portable/uniform-store.js.map +1 -1
  84. package/dist/shadertypes/data-types/data-type-decoder.d.ts +20 -0
  85. package/dist/shadertypes/data-types/data-type-decoder.d.ts.map +1 -0
  86. package/dist/shadertypes/data-types/data-type-decoder.js +79 -0
  87. package/dist/shadertypes/data-types/data-type-decoder.js.map +1 -0
  88. package/dist/shadertypes/data-types/data-types.d.ts +31 -12
  89. package/dist/shadertypes/data-types/data-types.d.ts.map +1 -1
  90. package/dist/{image-utils → shadertypes/image-types}/image-types.d.ts +0 -6
  91. package/dist/shadertypes/image-types/image-types.d.ts.map +1 -0
  92. package/dist/shadertypes/image-types/image-types.js.map +1 -0
  93. package/dist/shadertypes/shader-types/shader-type-decoder.d.ts +41 -0
  94. package/dist/shadertypes/shader-types/shader-type-decoder.d.ts.map +1 -0
  95. package/dist/shadertypes/{data-types/decode-shader-types.js → shader-types/shader-type-decoder.js} +32 -2
  96. package/dist/shadertypes/shader-types/shader-type-decoder.js.map +1 -0
  97. package/dist/shadertypes/shader-types/shader-types.d.ts +101 -0
  98. package/dist/shadertypes/shader-types/shader-types.d.ts.map +1 -0
  99. package/dist/shadertypes/shader-types/shader-types.js +30 -0
  100. package/dist/shadertypes/shader-types/shader-types.js.map +1 -0
  101. package/dist/shadertypes/texture-types/pixel-utils.d.ts.map +1 -0
  102. package/dist/shadertypes/texture-types/pixel-utils.js.map +1 -0
  103. package/dist/shadertypes/{textures → texture-types}/texture-format-decoder.d.ts +1 -0
  104. package/dist/shadertypes/texture-types/texture-format-decoder.d.ts.map +1 -0
  105. package/dist/shadertypes/{textures → texture-types}/texture-format-decoder.js +4 -3
  106. package/dist/shadertypes/texture-types/texture-format-decoder.js.map +1 -0
  107. package/dist/shadertypes/texture-types/texture-format-generics.d.ts +34 -0
  108. package/dist/shadertypes/texture-types/texture-format-generics.d.ts.map +1 -0
  109. package/dist/shadertypes/texture-types/texture-format-generics.js.map +1 -0
  110. package/dist/shadertypes/texture-types/texture-format-table.d.ts.map +1 -0
  111. package/dist/shadertypes/texture-types/texture-format-table.js.map +1 -0
  112. package/dist/shadertypes/{textures → texture-types}/texture-formats.d.ts +5 -1
  113. package/dist/shadertypes/texture-types/texture-formats.d.ts.map +1 -0
  114. package/dist/shadertypes/{textures → texture-types}/texture-formats.js +1 -0
  115. package/dist/shadertypes/texture-types/texture-formats.js.map +1 -0
  116. package/dist/shadertypes/{textures → texture-types}/texture-layout.d.ts +1 -1
  117. package/dist/shadertypes/texture-types/texture-layout.d.ts.map +1 -0
  118. package/dist/shadertypes/texture-types/texture-layout.js.map +1 -0
  119. package/dist/shadertypes/vertex-types/vertex-format-decoder.d.ts +24 -0
  120. package/dist/shadertypes/vertex-types/vertex-format-decoder.d.ts.map +1 -0
  121. package/dist/shadertypes/vertex-types/vertex-format-decoder.js +106 -0
  122. package/dist/shadertypes/vertex-types/vertex-format-decoder.js.map +1 -0
  123. package/dist/shadertypes/vertex-types/vertex-formats.d.ts +50 -0
  124. package/dist/shadertypes/vertex-types/vertex-formats.d.ts.map +1 -0
  125. package/dist/shadertypes/vertex-types/vertex-formats.js.map +1 -0
  126. package/package.json +2 -2
  127. package/src/adapter/canvas-surface.ts +1 -1
  128. package/src/adapter/device.ts +115 -10
  129. package/src/adapter/resources/command-buffer.ts +3 -1
  130. package/src/adapter/resources/command-encoder.ts +3 -1
  131. package/src/adapter/resources/compute-pipeline.ts +2 -2
  132. package/src/adapter/resources/framebuffer.ts +1 -1
  133. package/src/adapter/resources/render-pipeline.ts +12 -5
  134. package/src/adapter/resources/texture-view.ts +1 -1
  135. package/src/adapter/resources/texture.ts +6 -5
  136. package/src/adapter/types/attachments.ts +1 -1
  137. package/src/adapter/types/buffer-layout.ts +1 -1
  138. package/src/adapter/types/parameters.ts +4 -1
  139. package/src/adapter/types/shader-layout.ts +15 -9
  140. package/src/adapter/types/uniforms.ts +12 -0
  141. package/src/adapter-utils/bind-groups.ts +71 -0
  142. package/src/adapter-utils/get-attribute-from-layouts.ts +8 -11
  143. package/src/factories/bind-group-factory.ts +139 -0
  144. package/src/factories/core-module-state.ts +11 -0
  145. package/src/factories/pipeline-factory.ts +328 -0
  146. package/src/factories/shader-factory.ts +103 -0
  147. package/src/index.ts +47 -26
  148. package/src/portable/uniform-block.ts +1 -1
  149. package/src/portable/uniform-buffer-layout.ts +269 -62
  150. package/src/portable/uniform-store.ts +14 -11
  151. package/src/shadertypes/data-types/data-type-decoder.ts +105 -0
  152. package/src/shadertypes/data-types/data-types.ts +100 -48
  153. package/src/{image-utils → shadertypes/image-types}/image-types.ts +0 -7
  154. package/src/shadertypes/{data-types/decode-shader-types.ts → shader-types/shader-type-decoder.ts} +76 -11
  155. package/src/shadertypes/shader-types/shader-types.ts +207 -0
  156. package/src/shadertypes/{textures → texture-types}/texture-format-decoder.ts +4 -3
  157. package/src/shadertypes/{textures → texture-types}/texture-format-generics.ts +42 -48
  158. package/src/shadertypes/{textures → texture-types}/texture-formats.ts +14 -2
  159. package/src/shadertypes/vertex-types/vertex-format-decoder.ts +131 -0
  160. package/src/shadertypes/vertex-types/vertex-formats.ts +183 -0
  161. package/dist/image-utils/image-types.d.ts.map +0 -1
  162. package/dist/image-utils/image-types.js.map +0 -1
  163. package/dist/shadertypes/data-types/decode-shader-types.d.ts +0 -17
  164. package/dist/shadertypes/data-types/decode-shader-types.d.ts.map +0 -1
  165. package/dist/shadertypes/data-types/decode-shader-types.js.map +0 -1
  166. package/dist/shadertypes/data-types/shader-types.d.ts +0 -43
  167. package/dist/shadertypes/data-types/shader-types.d.ts.map +0 -1
  168. package/dist/shadertypes/data-types/shader-types.js.map +0 -1
  169. package/dist/shadertypes/textures/pixel-utils.d.ts.map +0 -1
  170. package/dist/shadertypes/textures/pixel-utils.js.map +0 -1
  171. package/dist/shadertypes/textures/texture-format-decoder.d.ts.map +0 -1
  172. package/dist/shadertypes/textures/texture-format-decoder.js.map +0 -1
  173. package/dist/shadertypes/textures/texture-format-generics.d.ts +0 -33
  174. package/dist/shadertypes/textures/texture-format-generics.d.ts.map +0 -1
  175. package/dist/shadertypes/textures/texture-format-generics.js.map +0 -1
  176. package/dist/shadertypes/textures/texture-format-table.d.ts.map +0 -1
  177. package/dist/shadertypes/textures/texture-format-table.js.map +0 -1
  178. package/dist/shadertypes/textures/texture-formats.d.ts.map +0 -1
  179. package/dist/shadertypes/textures/texture-formats.js.map +0 -1
  180. package/dist/shadertypes/textures/texture-layout.d.ts.map +0 -1
  181. package/dist/shadertypes/textures/texture-layout.js.map +0 -1
  182. package/dist/shadertypes/vertex-arrays/decode-vertex-format.d.ts +0 -18
  183. package/dist/shadertypes/vertex-arrays/decode-vertex-format.d.ts.map +0 -1
  184. package/dist/shadertypes/vertex-arrays/decode-vertex-format.js +0 -100
  185. package/dist/shadertypes/vertex-arrays/decode-vertex-format.js.map +0 -1
  186. package/dist/shadertypes/vertex-arrays/vertex-formats.d.ts +0 -27
  187. package/dist/shadertypes/vertex-arrays/vertex-formats.d.ts.map +0 -1
  188. package/dist/shadertypes/vertex-arrays/vertex-formats.js.map +0 -1
  189. package/src/shadertypes/data-types/shader-types.ts +0 -94
  190. package/src/shadertypes/vertex-arrays/decode-vertex-format.ts +0 -124
  191. package/src/shadertypes/vertex-arrays/vertex-formats.ts +0 -91
  192. /package/dist/{image-utils → shadertypes/image-types}/image-types.js +0 -0
  193. /package/dist/shadertypes/{textures → texture-types}/pixel-utils.d.ts +0 -0
  194. /package/dist/shadertypes/{textures → texture-types}/pixel-utils.js +0 -0
  195. /package/dist/shadertypes/{textures → texture-types}/texture-format-generics.js +0 -0
  196. /package/dist/shadertypes/{textures → texture-types}/texture-format-table.d.ts +0 -0
  197. /package/dist/shadertypes/{textures → texture-types}/texture-format-table.js +0 -0
  198. /package/dist/shadertypes/{textures → texture-types}/texture-layout.js +0 -0
  199. /package/dist/shadertypes/{vertex-arrays → vertex-types}/vertex-formats.js +0 -0
  200. /package/src/shadertypes/{textures → texture-types}/pixel-utils.ts +0 -0
  201. /package/src/shadertypes/{textures → texture-types}/texture-format-table.ts +0 -0
  202. /package/src/shadertypes/{textures → texture-types}/texture-layout.ts +0 -0
package/dist/dist.dev.js CHANGED
@@ -45,6 +45,7 @@ var __exports__ = (() => {
45
45
  ExternalTexture: () => ExternalTexture,
46
46
  Fence: () => Fence,
47
47
  Framebuffer: () => Framebuffer,
48
+ PipelineFactory: () => PipelineFactory,
48
49
  PipelineLayout: () => PipelineLayout,
49
50
  PresentationContext: () => PresentationContext,
50
51
  QuerySet: () => QuerySet,
@@ -53,38 +54,39 @@ var __exports__ = (() => {
53
54
  Resource: () => Resource,
54
55
  Sampler: () => Sampler,
55
56
  Shader: () => Shader,
57
+ ShaderFactory: () => ShaderFactory,
56
58
  SharedRenderPipeline: () => SharedRenderPipeline,
57
59
  Texture: () => Texture,
58
- TextureFormatDecoder: () => TextureFormatDecoder,
59
60
  TextureView: () => TextureView,
60
61
  TransformFeedback: () => TransformFeedback,
61
62
  UniformBlock: () => UniformBlock,
62
63
  UniformBufferLayout: () => UniformBufferLayout,
63
64
  UniformStore: () => UniformStore,
64
65
  VertexArray: () => VertexArray,
66
+ _getDefaultBindGroupFactory: () => _getDefaultBindGroupFactory,
65
67
  _getTextureFormatDefinition: () => getTextureFormatDefinition,
66
68
  _getTextureFormatTable: () => getTextureFormatTable,
67
69
  assert: () => assert2,
68
70
  assertDefined: () => assertDefined,
71
+ dataTypeDecoder: () => dataTypeDecoder,
72
+ flattenBindingsByGroup: () => flattenBindingsByGroup,
69
73
  getAttributeInfosFromLayouts: () => getAttributeInfosFromLayouts,
70
74
  getAttributeShaderTypeInfo: () => getAttributeShaderTypeInfo,
71
- getDataType: () => getDataType,
72
- getDataTypeInfo: () => getDataTypeInfo,
73
75
  getExternalImageSize: () => getExternalImageSize,
74
- getNormalizedDataType: () => getNormalizedDataType,
75
76
  getScratchArray: () => getScratchArray,
77
+ getShaderLayoutBinding: () => getShaderLayoutBinding,
76
78
  getTextureImageView: () => getTextureImageView,
77
79
  getTypedArrayConstructor: () => getTypedArrayConstructor,
78
80
  getVariableShaderTypeInfo: () => getVariableShaderTypeInfo,
79
- getVertexFormatFromAttribute: () => getVertexFormatFromAttribute,
80
- getVertexFormatInfo: () => getVertexFormatInfo,
81
81
  isExternalImage: () => isExternalImage,
82
82
  log: () => log,
83
83
  luma: () => luma,
84
- makeVertexFormat: () => makeVertexFormat,
84
+ normalizeBindingsByGroup: () => normalizeBindingsByGroup,
85
85
  readPixel: () => readPixel,
86
86
  setTextureImageData: () => setTextureImageData,
87
+ shaderTypeDecoder: () => shaderTypeDecoder,
87
88
  textureFormatDecoder: () => textureFormatDecoder,
89
+ vertexFormatDecoder: () => vertexFormatDecoder,
88
90
  writePixel: () => writePixel
89
91
  });
90
92
 
@@ -1326,62 +1328,73 @@ var __exports__ = (() => {
1326
1328
  onMapped: void 0
1327
1329
  });
1328
1330
 
1329
- // src/shadertypes/data-types/decode-data-types.ts
1330
- function getDataTypeInfo(type) {
1331
- const normalized = type.includes("norm");
1332
- const integer = !normalized && !type.startsWith("float");
1333
- const signed = type.startsWith("s");
1334
- const typeInfo = NORMALIZED_TYPE_MAP[type];
1335
- const [signedType, primitiveType, byteLength] = typeInfo || ["uint8 ", "i32", 1];
1336
- return {
1337
- signedType,
1338
- primitiveType,
1339
- byteLength,
1340
- normalized,
1341
- integer,
1342
- signed
1343
- };
1344
- }
1345
- function getNormalizedDataType(signedDataType) {
1346
- const dataType = signedDataType;
1347
- switch (dataType) {
1348
- case "uint8":
1349
- return "unorm8";
1350
- case "sint8":
1351
- return "snorm8";
1352
- case "uint16":
1353
- return "unorm16";
1354
- case "sint16":
1355
- return "snorm16";
1356
- default:
1357
- return dataType;
1331
+ // src/shadertypes/data-types/data-type-decoder.ts
1332
+ var DataTypeDecoder = class {
1333
+ /**
1334
+ * Gets info about a data type constant (signed or normalized)
1335
+ * @returns underlying primitive / signed types, byte length, normalization, integer, signed flags
1336
+ */
1337
+ getDataTypeInfo(type) {
1338
+ const [signedType, primitiveType, byteLength] = NORMALIZED_TYPE_MAP[type];
1339
+ const normalized = type.includes("norm");
1340
+ const integer = !normalized && !type.startsWith("float");
1341
+ const signed = type.startsWith("s");
1342
+ return {
1343
+ signedType,
1344
+ primitiveType,
1345
+ byteLength,
1346
+ normalized,
1347
+ integer,
1348
+ signed
1349
+ // TODO - add webglOnly flag
1350
+ };
1358
1351
  }
1359
- }
1360
- function alignTo(size, count) {
1361
- switch (count) {
1362
- case 1:
1363
- return size;
1364
- case 2:
1365
- return size + size % 2;
1366
- default:
1367
- return size + (4 - size % 4) % 4;
1352
+ /** Build a vertex format from a signed data type and a component */
1353
+ getNormalizedDataType(signedDataType) {
1354
+ const dataType = signedDataType;
1355
+ switch (dataType) {
1356
+ case "uint8":
1357
+ return "unorm8";
1358
+ case "sint8":
1359
+ return "snorm8";
1360
+ case "uint16":
1361
+ return "unorm16";
1362
+ case "sint16":
1363
+ return "snorm16";
1364
+ default:
1365
+ return dataType;
1366
+ }
1368
1367
  }
1369
- }
1370
- function getDataType(arrayOrType) {
1371
- const Constructor = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType;
1372
- if (Constructor === Uint8ClampedArray) {
1373
- return "uint8";
1368
+ /** Align offset to 1, 2 or 4 elements (4, 8 or 16 bytes) */
1369
+ alignTo(size, count) {
1370
+ switch (count) {
1371
+ case 1:
1372
+ return size;
1373
+ case 2:
1374
+ return size + size % 2;
1375
+ default:
1376
+ return size + (4 - size % 4) % 4;
1377
+ }
1374
1378
  }
1375
- const info = Object.values(NORMALIZED_TYPE_MAP).find((entry) => Constructor === entry[4]);
1376
- if (!info) {
1377
- throw new Error(Constructor.name);
1379
+ /** Returns the VariableShaderType that corresponds to a typed array */
1380
+ getDataType(arrayOrType) {
1381
+ const Constructor = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType;
1382
+ if (Constructor === Uint8ClampedArray) {
1383
+ return "uint8";
1384
+ }
1385
+ const info = Object.values(NORMALIZED_TYPE_MAP).find((entry) => Constructor === entry[4]);
1386
+ if (!info) {
1387
+ throw new Error(Constructor.name);
1388
+ }
1389
+ return info[0];
1378
1390
  }
1379
- return info[0];
1380
- }
1381
- function getTypedArrayConstructor(type) {
1382
- const [, , , , Constructor] = NORMALIZED_TYPE_MAP[type];
1383
- return Constructor;
1384
- }
1391
+ /** Returns the TypedArray that corresponds to a shader data type */
1392
+ getTypedArrayConstructor(type) {
1393
+ const [, , , , Constructor] = NORMALIZED_TYPE_MAP[type];
1394
+ return Constructor;
1395
+ }
1396
+ };
1397
+ var dataTypeDecoder = new DataTypeDecoder();
1385
1398
  var NORMALIZED_TYPE_MAP = {
1386
1399
  uint8: ["uint8", "u32", 1, false, Uint8Array],
1387
1400
  sint8: ["sint8", "i32", 1, false, Int8Array],
@@ -1397,87 +1410,99 @@ var __exports__ = (() => {
1397
1410
  sint32: ["sint32", "i32", 4, false, Int32Array]
1398
1411
  };
1399
1412
 
1400
- // src/shadertypes/vertex-arrays/decode-vertex-format.ts
1401
- function getVertexFormatInfo(format) {
1402
- let webglOnly;
1403
- if (format.endsWith("-webgl")) {
1404
- format.replace("-webgl", "");
1405
- webglOnly = true;
1406
- }
1407
- const [type_, count] = format.split("x");
1408
- const type = type_;
1409
- const components = count ? parseInt(count) : 1;
1410
- const decodedType = getDataTypeInfo(type);
1411
- const result = {
1412
- type,
1413
- components,
1414
- byteLength: decodedType.byteLength * components,
1415
- integer: decodedType.integer,
1416
- signed: decodedType.signed,
1417
- normalized: decodedType.normalized
1418
- };
1419
- if (webglOnly) {
1420
- result.webglOnly = true;
1421
- }
1422
- return result;
1423
- }
1424
- function makeVertexFormat(signedDataType, components, normalized) {
1425
- const dataType = normalized ? getNormalizedDataType(signedDataType) : signedDataType;
1426
- switch (dataType) {
1427
- case "unorm8":
1428
- if (components === 1) {
1429
- return "unorm8";
1430
- }
1431
- if (components === 3) {
1432
- return "unorm8x3-webgl";
1433
- }
1434
- return `${dataType}x${components}`;
1435
- case "snorm8":
1436
- case "uint8":
1437
- case "sint8":
1438
- case "uint16":
1439
- case "sint16":
1440
- case "unorm16":
1441
- case "snorm16":
1442
- case "float16":
1443
- if (components === 1 || components === 3) {
1444
- throw new Error(`size: ${components}`);
1445
- }
1446
- return `${dataType}x${components}`;
1447
- default:
1448
- return components === 1 ? dataType : `${dataType}x${components}`;
1413
+ // src/shadertypes/vertex-types/vertex-format-decoder.ts
1414
+ var VertexFormatDecoder = class {
1415
+ /**
1416
+ * Decodes a vertex format, returning type, components, byte length and flags (integer, signed, normalized)
1417
+ */
1418
+ getVertexFormatInfo(format) {
1419
+ let webglOnly;
1420
+ if (format.endsWith("-webgl")) {
1421
+ format.replace("-webgl", "");
1422
+ webglOnly = true;
1423
+ }
1424
+ const [type_, count] = format.split("x");
1425
+ const type = type_;
1426
+ const components = count ? parseInt(count) : 1;
1427
+ const decodedType = dataTypeDecoder.getDataTypeInfo(type);
1428
+ const result = {
1429
+ type,
1430
+ components,
1431
+ byteLength: decodedType.byteLength * components,
1432
+ integer: decodedType.integer,
1433
+ signed: decodedType.signed,
1434
+ normalized: decodedType.normalized
1435
+ };
1436
+ if (webglOnly) {
1437
+ result.webglOnly = true;
1438
+ }
1439
+ return result;
1449
1440
  }
1450
- }
1451
- function getVertexFormatFromAttribute(typedArray, size, normalized) {
1452
- if (!size || size > 4) {
1453
- throw new Error(`size ${size}`);
1441
+ /** Build a vertex format from a signed data type and a component */
1442
+ makeVertexFormat(signedDataType, components, normalized) {
1443
+ const dataType = normalized ? dataTypeDecoder.getNormalizedDataType(signedDataType) : signedDataType;
1444
+ switch (dataType) {
1445
+ case "unorm8":
1446
+ if (components === 1) {
1447
+ return "unorm8";
1448
+ }
1449
+ if (components === 3) {
1450
+ return "unorm8x3-webgl";
1451
+ }
1452
+ return `${dataType}x${components}`;
1453
+ case "snorm8":
1454
+ case "uint8":
1455
+ case "sint8":
1456
+ case "uint16":
1457
+ case "sint16":
1458
+ case "unorm16":
1459
+ case "snorm16":
1460
+ case "float16":
1461
+ if (components === 1 || components === 3) {
1462
+ throw new Error(`size: ${components}`);
1463
+ }
1464
+ return `${dataType}x${components}`;
1465
+ default:
1466
+ return components === 1 ? dataType : `${dataType}x${components}`;
1467
+ }
1454
1468
  }
1455
- const components = size;
1456
- const signedDataType = getDataType(typedArray);
1457
- return makeVertexFormat(signedDataType, components, normalized);
1458
- }
1459
- function getCompatibleVertexFormat(opts) {
1460
- let vertexType;
1461
- switch (opts.primitiveType) {
1462
- case "f32":
1463
- vertexType = "float32";
1464
- break;
1465
- case "i32":
1466
- vertexType = "sint32";
1467
- break;
1468
- case "u32":
1469
- vertexType = "uint32";
1470
- break;
1471
- case "f16":
1472
- return opts.components <= 2 ? "float16x2" : "float16x4";
1469
+ /** Get the vertex format for an attribute with TypedArray and size */
1470
+ getVertexFormatFromAttribute(typedArray, size, normalized) {
1471
+ if (!size || size > 4) {
1472
+ throw new Error(`size ${size}`);
1473
+ }
1474
+ const components = size;
1475
+ const signedDataType = dataTypeDecoder.getDataType(typedArray);
1476
+ return this.makeVertexFormat(signedDataType, components, normalized);
1473
1477
  }
1474
- if (opts.components === 1) {
1475
- return vertexType;
1478
+ /**
1479
+ * Return a "default" vertex format for a certain shader data type
1480
+ * The simplest vertex format that matches the shader attribute's data type
1481
+ */
1482
+ getCompatibleVertexFormat(opts) {
1483
+ let vertexType;
1484
+ switch (opts.primitiveType) {
1485
+ case "f32":
1486
+ vertexType = "float32";
1487
+ break;
1488
+ case "i32":
1489
+ vertexType = "sint32";
1490
+ break;
1491
+ case "u32":
1492
+ vertexType = "uint32";
1493
+ break;
1494
+ case "f16":
1495
+ return opts.components <= 2 ? "float16x2" : "float16x4";
1496
+ }
1497
+ if (opts.components === 1) {
1498
+ return vertexType;
1499
+ }
1500
+ return `${vertexType}x${opts.components}`;
1476
1501
  }
1477
- return `${vertexType}x${opts.components}`;
1478
- }
1502
+ };
1503
+ var vertexFormatDecoder = new VertexFormatDecoder();
1479
1504
 
1480
- // src/shadertypes/textures/texture-format-table.ts
1505
+ // src/shadertypes/texture-types/texture-format-table.ts
1481
1506
  var texture_compression_bc = "texture-compression-bc";
1482
1507
  var texture_compression_astc = "texture-compression-astc";
1483
1508
  var texture_compression_etc2 = "texture-compression-etc2";
@@ -1648,7 +1673,7 @@ var __exports__ = (() => {
1648
1673
  ...TEXTURE_FORMAT_COMPRESSED_TABLE
1649
1674
  };
1650
1675
 
1651
- // src/shadertypes/textures/texture-format-decoder.ts
1676
+ // src/shadertypes/texture-types/texture-format-decoder.ts
1652
1677
  var RGB_FORMAT_REGEX = /^(r|rg|rgb|rgba|bgra)([0-9]*)([a-z]*)(-srgb)?(-webgl)?$/;
1653
1678
  var COLOR_FORMAT_PREFIXES = ["rgb", "rgba", "bgra"];
1654
1679
  var DEPTH_FORMAT_PREFIXES = ["depth", "stencil"];
@@ -1759,11 +1784,11 @@ var __exports__ = (() => {
1759
1784
  formatInfo.blockHeight = blockSize.blockHeight;
1760
1785
  }
1761
1786
  }
1762
- const matches = RGB_FORMAT_REGEX.exec(format);
1787
+ const matches = !formatInfo.packed ? RGB_FORMAT_REGEX.exec(format) : null;
1763
1788
  if (matches) {
1764
1789
  const [, channels, length, type, srgb, suffix] = matches;
1765
1790
  const dataType = `${type}${length}`;
1766
- const decodedType = getDataTypeInfo(dataType);
1791
+ const decodedType = dataTypeDecoder.getDataTypeInfo(dataType);
1767
1792
  const bits = decodedType.byteLength * 8;
1768
1793
  const components = channels?.length ?? 1;
1769
1794
  const bitsPerChannel = [
@@ -1862,7 +1887,7 @@ var __exports__ = (() => {
1862
1887
  return 16;
1863
1888
  }
1864
1889
 
1865
- // src/image-utils/image-types.ts
1890
+ // src/shadertypes/image-types/image-types.ts
1866
1891
  function isExternalImage(data) {
1867
1892
  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;
1868
1893
  }
@@ -1885,6 +1910,52 @@ var __exports__ = (() => {
1885
1910
  // src/adapter/device.ts
1886
1911
  var DeviceLimits = class {
1887
1912
  };
1913
+ function formatErrorLogArguments(context, args) {
1914
+ const formattedContext = formatErrorLogValue(context);
1915
+ const formattedArgs = args.map(formatErrorLogValue).filter((arg) => arg !== void 0);
1916
+ return [formattedContext, ...formattedArgs].filter((arg) => arg !== void 0);
1917
+ }
1918
+ function formatErrorLogValue(value) {
1919
+ if (value === void 0) {
1920
+ return void 0;
1921
+ }
1922
+ if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1923
+ return value;
1924
+ }
1925
+ if (value instanceof Error) {
1926
+ return value.message;
1927
+ }
1928
+ if (Array.isArray(value)) {
1929
+ return value.map(formatErrorLogValue);
1930
+ }
1931
+ if (typeof value === "object") {
1932
+ if (hasCustomToString(value)) {
1933
+ const stringValue = String(value);
1934
+ if (stringValue !== "[object Object]") {
1935
+ return stringValue;
1936
+ }
1937
+ }
1938
+ if (looksLikeGPUCompilationMessage(value)) {
1939
+ return formatGPUCompilationMessage(value);
1940
+ }
1941
+ return value.constructor?.name || "Object";
1942
+ }
1943
+ return String(value);
1944
+ }
1945
+ function hasCustomToString(value) {
1946
+ return "toString" in value && typeof value.toString === "function" && value.toString !== Object.prototype.toString;
1947
+ }
1948
+ function looksLikeGPUCompilationMessage(value) {
1949
+ return "message" in value && "type" in value;
1950
+ }
1951
+ function formatGPUCompilationMessage(value) {
1952
+ const type = typeof value.type === "string" ? value.type : "message";
1953
+ const message = typeof value.message === "string" ? value.message : "";
1954
+ const lineNum = typeof value.lineNum === "number" ? value.lineNum : null;
1955
+ const linePos = typeof value.linePos === "number" ? value.linePos : null;
1956
+ const location = lineNum !== null && linePos !== null ? ` @ ${lineNum}:${linePos}` : lineNum !== null ? ` @ ${lineNum}` : "";
1957
+ return `${type}${location}: ${message}`.trim();
1958
+ }
1888
1959
  var DeviceFeatures = class {
1889
1960
  features;
1890
1961
  disabledFeatures;
@@ -1914,6 +1985,8 @@ var __exports__ = (() => {
1914
1985
  userData = {};
1915
1986
  /** stats */
1916
1987
  statsManager = lumaStats;
1988
+ /** Internal per-device factory storage */
1989
+ _factories = {};
1917
1990
  /** An abstract timestamp used for change tracking */
1918
1991
  timestamp = 0;
1919
1992
  /** True if this device has been reused during device creation (app has multiple references) */
@@ -1927,8 +2000,9 @@ var __exports__ = (() => {
1927
2000
  this.props = { ..._Device.defaultProps, ...props };
1928
2001
  this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase());
1929
2002
  }
2003
+ // TODO - just expose the shadertypes decoders?
1930
2004
  getVertexFormatInfo(format) {
1931
- return getVertexFormatInfo(format);
2005
+ return vertexFormatDecoder.getVertexFormatInfo(format);
1932
2006
  }
1933
2007
  isVertexFormatSupported(format) {
1934
2008
  return true;
@@ -2028,12 +2102,12 @@ var __exports__ = (() => {
2028
2102
  reportError(error, context, ...args) {
2029
2103
  const isHandled = this.props.onError(error, context);
2030
2104
  if (!isHandled) {
2105
+ const logArguments = formatErrorLogArguments(context, args);
2031
2106
  return log.error(
2032
2107
  this.type === "webgl" ? "%cWebGL" : "%cWebGPU",
2033
2108
  "color: white; background: red; padding: 2px 6px; border-radius: 3px;",
2034
2109
  error.message,
2035
- context,
2036
- ...args
2110
+ ...logArguments
2037
2111
  );
2038
2112
  }
2039
2113
  return () => {
@@ -2080,6 +2154,14 @@ or create a device with the 'debug: true' prop.`;
2080
2154
  _createSharedRenderPipelineWebGL(_props) {
2081
2155
  throw new Error("_createSharedRenderPipelineWebGL() not implemented");
2082
2156
  }
2157
+ /** Internal WebGPU-only helper for retrieving the native bind-group layout for a pipeline group. */
2158
+ _createBindGroupLayoutWebGPU(_pipeline, _group) {
2159
+ throw new Error("_createBindGroupLayoutWebGPU() not implemented");
2160
+ }
2161
+ /** Internal WebGPU-only helper for creating a native bind group. */
2162
+ _createBindGroupWebGPU(_bindGroupLayout, _shaderLayout, _bindings, _group) {
2163
+ throw new Error("_createBindGroupWebGPU() not implemented");
2164
+ }
2083
2165
  /**
2084
2166
  * Internal helper that returns `true` when timestamp-query GPU timing should be
2085
2167
  * collected for this device.
@@ -3107,8 +3189,8 @@ or create a device with the 'debug: true' prop.`;
3107
3189
  *
3108
3190
  * @note The memory layout of the texture data is determined by the texture format and dimensions.
3109
3191
  * @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
3110
- * @note The application can call Buffer.readAsync()
3111
- * @note If not supplied a buffer will be created and the application needs to call Buffer.destroy
3192
+ * @note The application can call Buffer.readAsync() to read the returned buffer on the CPU.
3193
+ * @note The destination buffer must be supplied by the caller and must be large enough for the requested region.
3112
3194
  * @note On WebGPU this corresponds to a texture-to-buffer copy and uses buffer-copy alignment rules.
3113
3195
  * @note On WebGL, luma.gl emulates the same logical readback behavior.
3114
3196
  */
@@ -3121,6 +3203,7 @@ or create a device with the 'debug: true' prop.`;
3121
3203
  *
3122
3204
  * @note The memory layout of the texture data is determined by the texture format and dimensions.
3123
3205
  * @note The application can call Texture.computeMemoryLayout() to compute the layout.
3206
+ * @deprecated Use Texture.readBuffer() with an explicit destination buffer, or DynamicTexture.readAsync() for convenience readback.
3124
3207
  */
3125
3208
  readDataAsync(options) {
3126
3209
  throw new Error("readBuffer not implemented");
@@ -3867,7 +3950,8 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
3867
3950
  bufferMode: void 0,
3868
3951
  disableWarnings: false,
3869
3952
  _sharedRenderPipeline: void 0,
3870
- bindings: void 0
3953
+ bindings: void 0,
3954
+ bindGroups: void 0
3871
3955
  });
3872
3956
 
3873
3957
  // src/adapter/resources/shared-render-pipeline.ts
@@ -3887,6 +3971,482 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
3887
3971
  }
3888
3972
  };
3889
3973
 
3974
+ // src/adapter/resources/compute-pipeline.ts
3975
+ var _ComputePipeline = class extends Resource {
3976
+ get [Symbol.toStringTag]() {
3977
+ return "ComputePipeline";
3978
+ }
3979
+ hash = "";
3980
+ /** The merged shader layout */
3981
+ shaderLayout;
3982
+ constructor(device, props) {
3983
+ super(device, props, _ComputePipeline.defaultProps);
3984
+ this.shaderLayout = props.shaderLayout;
3985
+ }
3986
+ };
3987
+ var ComputePipeline = _ComputePipeline;
3988
+ __publicField(ComputePipeline, "defaultProps", {
3989
+ ...Resource.defaultProps,
3990
+ shader: void 0,
3991
+ entryPoint: void 0,
3992
+ constants: {},
3993
+ shaderLayout: void 0
3994
+ });
3995
+
3996
+ // src/factories/pipeline-factory.ts
3997
+ var _PipelineFactory = class {
3998
+ /** Get the singleton default pipeline factory for the specified device */
3999
+ static getDefaultPipelineFactory(device) {
4000
+ const moduleData = device.getModuleData("@luma.gl/core");
4001
+ moduleData.defaultPipelineFactory ||= new _PipelineFactory(device);
4002
+ return moduleData.defaultPipelineFactory;
4003
+ }
4004
+ device;
4005
+ _hashCounter = 0;
4006
+ _hashes = {};
4007
+ _renderPipelineCache = {};
4008
+ _computePipelineCache = {};
4009
+ _sharedRenderPipelineCache = {};
4010
+ get [Symbol.toStringTag]() {
4011
+ return "PipelineFactory";
4012
+ }
4013
+ toString() {
4014
+ return `PipelineFactory(${this.device.id})`;
4015
+ }
4016
+ constructor(device) {
4017
+ this.device = device;
4018
+ }
4019
+ /**
4020
+ * WebGL has two cache layers with different priorities:
4021
+ * - `_sharedRenderPipelineCache` owns `WEBGLSharedRenderPipeline` / `WebGLProgram` reuse.
4022
+ * - `_renderPipelineCache` owns `RenderPipeline` wrapper reuse.
4023
+ *
4024
+ * Shared WebGL program reuse is the hard requirement. Wrapper reuse is beneficial,
4025
+ * but wrapper cache misses are acceptable if that keeps the cache logic simple and
4026
+ * prevents incorrect cache hits.
4027
+ *
4028
+ * In particular, wrapper hash logic must never force program creation or linked-program
4029
+ * introspection just to decide whether a shared WebGL program can be reused.
4030
+ */
4031
+ /** Return a RenderPipeline matching supplied props. Reuses an equivalent pipeline if already created. */
4032
+ createRenderPipeline(props) {
4033
+ if (!this.device.props._cachePipelines) {
4034
+ return this.device.createRenderPipeline(props);
4035
+ }
4036
+ const allProps = { ...RenderPipeline.defaultProps, ...props };
4037
+ const cache = this._renderPipelineCache;
4038
+ const hash = this._hashRenderPipeline(allProps);
4039
+ let pipeline = cache[hash]?.resource;
4040
+ if (!pipeline) {
4041
+ const sharedRenderPipeline = this.device.type === "webgl" && this.device.props._sharePipelines ? this.createSharedRenderPipeline(allProps) : void 0;
4042
+ pipeline = this.device.createRenderPipeline({
4043
+ ...allProps,
4044
+ id: allProps.id ? `${allProps.id}-cached` : uid("unnamed-cached"),
4045
+ _sharedRenderPipeline: sharedRenderPipeline
4046
+ });
4047
+ pipeline.hash = hash;
4048
+ cache[hash] = { resource: pipeline, useCount: 1 };
4049
+ if (this.device.props.debugFactories) {
4050
+ log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
4051
+ }
4052
+ } else {
4053
+ cache[hash].useCount++;
4054
+ if (this.device.props.debugFactories) {
4055
+ log.log(
4056
+ 3,
4057
+ `${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`
4058
+ )();
4059
+ }
4060
+ }
4061
+ return pipeline;
4062
+ }
4063
+ /** Return a ComputePipeline matching supplied props. Reuses an equivalent pipeline if already created. */
4064
+ createComputePipeline(props) {
4065
+ if (!this.device.props._cachePipelines) {
4066
+ return this.device.createComputePipeline(props);
4067
+ }
4068
+ const allProps = { ...ComputePipeline.defaultProps, ...props };
4069
+ const cache = this._computePipelineCache;
4070
+ const hash = this._hashComputePipeline(allProps);
4071
+ let pipeline = cache[hash]?.resource;
4072
+ if (!pipeline) {
4073
+ pipeline = this.device.createComputePipeline({
4074
+ ...allProps,
4075
+ id: allProps.id ? `${allProps.id}-cached` : void 0
4076
+ });
4077
+ pipeline.hash = hash;
4078
+ cache[hash] = { resource: pipeline, useCount: 1 };
4079
+ if (this.device.props.debugFactories) {
4080
+ log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
4081
+ }
4082
+ } else {
4083
+ cache[hash].useCount++;
4084
+ if (this.device.props.debugFactories) {
4085
+ log.log(
4086
+ 3,
4087
+ `${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`
4088
+ )();
4089
+ }
4090
+ }
4091
+ return pipeline;
4092
+ }
4093
+ release(pipeline) {
4094
+ if (!this.device.props._cachePipelines) {
4095
+ pipeline.destroy();
4096
+ return;
4097
+ }
4098
+ const cache = this._getCache(pipeline);
4099
+ const hash = pipeline.hash;
4100
+ cache[hash].useCount--;
4101
+ if (cache[hash].useCount === 0) {
4102
+ this._destroyPipeline(pipeline);
4103
+ if (this.device.props.debugFactories) {
4104
+ log.log(3, `${this}: ${pipeline} released and destroyed`)();
4105
+ }
4106
+ } else if (cache[hash].useCount < 0) {
4107
+ log.error(`${this}: ${pipeline} released, useCount < 0, resetting`)();
4108
+ cache[hash].useCount = 0;
4109
+ } else if (this.device.props.debugFactories) {
4110
+ log.log(3, `${this}: ${pipeline} released, count=${cache[hash].useCount}`)();
4111
+ }
4112
+ }
4113
+ createSharedRenderPipeline(props) {
4114
+ const sharedPipelineHash = this._hashSharedRenderPipeline(props);
4115
+ let sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
4116
+ if (!sharedCacheItem) {
4117
+ const sharedRenderPipeline = this.device._createSharedRenderPipelineWebGL(props);
4118
+ sharedCacheItem = { resource: sharedRenderPipeline, useCount: 0 };
4119
+ this._sharedRenderPipelineCache[sharedPipelineHash] = sharedCacheItem;
4120
+ }
4121
+ sharedCacheItem.useCount++;
4122
+ return sharedCacheItem.resource;
4123
+ }
4124
+ releaseSharedRenderPipeline(pipeline) {
4125
+ if (!pipeline.sharedRenderPipeline) {
4126
+ return;
4127
+ }
4128
+ const sharedPipelineHash = this._hashSharedRenderPipeline(pipeline.sharedRenderPipeline.props);
4129
+ const sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
4130
+ if (!sharedCacheItem) {
4131
+ return;
4132
+ }
4133
+ sharedCacheItem.useCount--;
4134
+ if (sharedCacheItem.useCount === 0) {
4135
+ sharedCacheItem.resource.destroy();
4136
+ delete this._sharedRenderPipelineCache[sharedPipelineHash];
4137
+ }
4138
+ }
4139
+ // PRIVATE
4140
+ /** Destroy a cached pipeline, removing it from the cache if configured to do so. */
4141
+ _destroyPipeline(pipeline) {
4142
+ const cache = this._getCache(pipeline);
4143
+ if (!this.device.props._destroyPipelines) {
4144
+ return false;
4145
+ }
4146
+ delete cache[pipeline.hash];
4147
+ pipeline.destroy();
4148
+ if (pipeline instanceof RenderPipeline) {
4149
+ this.releaseSharedRenderPipeline(pipeline);
4150
+ }
4151
+ return true;
4152
+ }
4153
+ /** Get the appropriate cache for the type of pipeline */
4154
+ _getCache(pipeline) {
4155
+ let cache;
4156
+ if (pipeline instanceof ComputePipeline) {
4157
+ cache = this._computePipelineCache;
4158
+ }
4159
+ if (pipeline instanceof RenderPipeline) {
4160
+ cache = this._renderPipelineCache;
4161
+ }
4162
+ if (!cache) {
4163
+ throw new Error(`${this}`);
4164
+ }
4165
+ if (!cache[pipeline.hash]) {
4166
+ throw new Error(`${this}: ${pipeline} matched incorrect entry`);
4167
+ }
4168
+ return cache;
4169
+ }
4170
+ /** Calculate a hash based on all the inputs for a compute pipeline */
4171
+ _hashComputePipeline(props) {
4172
+ const { type } = this.device;
4173
+ const shaderHash = this._getHash(props.shader.source);
4174
+ const shaderLayoutHash = this._getHash(JSON.stringify(props.shaderLayout));
4175
+ return `${type}/C/${shaderHash}SL${shaderLayoutHash}`;
4176
+ }
4177
+ /** Calculate a hash based on all the inputs for a render pipeline */
4178
+ _hashRenderPipeline(props) {
4179
+ const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
4180
+ const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
4181
+ const varyingHash = this._getWebGLVaryingHash(props);
4182
+ const shaderLayoutHash = this._getHash(JSON.stringify(props.shaderLayout));
4183
+ const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
4184
+ const { type } = this.device;
4185
+ switch (type) {
4186
+ case "webgl":
4187
+ const webglParameterHash = this._getHash(JSON.stringify(props.parameters));
4188
+ return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${webglParameterHash}SL${shaderLayoutHash}BL${bufferLayoutHash}`;
4189
+ case "webgpu":
4190
+ default:
4191
+ const entryPointHash = this._getHash(
4192
+ JSON.stringify({
4193
+ vertexEntryPoint: props.vertexEntryPoint,
4194
+ fragmentEntryPoint: props.fragmentEntryPoint
4195
+ })
4196
+ );
4197
+ const parameterHash = this._getHash(JSON.stringify(props.parameters));
4198
+ const attachmentHash = this._getWebGPUAttachmentHash(props);
4199
+ return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}EP${entryPointHash}P${parameterHash}SL${shaderLayoutHash}BL${bufferLayoutHash}A${attachmentHash}`;
4200
+ }
4201
+ }
4202
+ // This is the only gate for shared `WebGLProgram` reuse.
4203
+ // Only include inputs that affect program linking or transform-feedback linkage.
4204
+ // Wrapper-only concerns such as topology, parameters, attachment formats and layout
4205
+ // overrides must not be added here.
4206
+ _hashSharedRenderPipeline(props) {
4207
+ const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
4208
+ const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
4209
+ const varyingHash = this._getWebGLVaryingHash(props);
4210
+ return `webgl/S/${vsHash}/${fsHash}V${varyingHash}`;
4211
+ }
4212
+ _getHash(key) {
4213
+ if (this._hashes[key] === void 0) {
4214
+ this._hashes[key] = this._hashCounter++;
4215
+ }
4216
+ return this._hashes[key];
4217
+ }
4218
+ _getWebGLVaryingHash(props) {
4219
+ const { varyings = [], bufferMode = null } = props;
4220
+ return this._getHash(JSON.stringify({ varyings, bufferMode }));
4221
+ }
4222
+ _getWebGPUAttachmentHash(props) {
4223
+ const colorAttachmentFormats = props.colorAttachmentFormats ?? [
4224
+ this.device.preferredColorFormat
4225
+ ];
4226
+ const depthStencilAttachmentFormat = props.parameters?.depthWriteEnabled ? props.depthStencilAttachmentFormat || this.device.preferredDepthFormat : null;
4227
+ return this._getHash(
4228
+ JSON.stringify({
4229
+ colorAttachmentFormats,
4230
+ depthStencilAttachmentFormat
4231
+ })
4232
+ );
4233
+ }
4234
+ };
4235
+ var PipelineFactory = _PipelineFactory;
4236
+ __publicField(PipelineFactory, "defaultProps", { ...RenderPipeline.defaultProps });
4237
+
4238
+ // src/factories/shader-factory.ts
4239
+ var _ShaderFactory = class {
4240
+ /** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
4241
+ static getDefaultShaderFactory(device) {
4242
+ const moduleData = device.getModuleData("@luma.gl/core");
4243
+ moduleData.defaultShaderFactory ||= new _ShaderFactory(device);
4244
+ return moduleData.defaultShaderFactory;
4245
+ }
4246
+ device;
4247
+ _cache = {};
4248
+ get [Symbol.toStringTag]() {
4249
+ return "ShaderFactory";
4250
+ }
4251
+ toString() {
4252
+ return `${this[Symbol.toStringTag]}(${this.device.id})`;
4253
+ }
4254
+ /** @internal */
4255
+ constructor(device) {
4256
+ this.device = device;
4257
+ }
4258
+ /** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
4259
+ createShader(props) {
4260
+ if (!this.device.props._cacheShaders) {
4261
+ return this.device.createShader(props);
4262
+ }
4263
+ const key = this._hashShader(props);
4264
+ let cacheEntry = this._cache[key];
4265
+ if (!cacheEntry) {
4266
+ const resource = this.device.createShader({
4267
+ ...props,
4268
+ id: props.id ? `${props.id}-cached` : void 0
4269
+ });
4270
+ this._cache[key] = cacheEntry = { resource, useCount: 1 };
4271
+ if (this.device.props.debugFactories) {
4272
+ log.log(3, `${this}: Created new shader ${resource.id}`)();
4273
+ }
4274
+ } else {
4275
+ cacheEntry.useCount++;
4276
+ if (this.device.props.debugFactories) {
4277
+ log.log(
4278
+ 3,
4279
+ `${this}: Reusing shader ${cacheEntry.resource.id} count=${cacheEntry.useCount}`
4280
+ )();
4281
+ }
4282
+ }
4283
+ return cacheEntry.resource;
4284
+ }
4285
+ /** Releases a previously-requested {@link Shader}, destroying it if no users remain. */
4286
+ release(shader) {
4287
+ if (!this.device.props._cacheShaders) {
4288
+ shader.destroy();
4289
+ return;
4290
+ }
4291
+ const key = this._hashShader(shader);
4292
+ const cacheEntry = this._cache[key];
4293
+ if (cacheEntry) {
4294
+ cacheEntry.useCount--;
4295
+ if (cacheEntry.useCount === 0) {
4296
+ if (this.device.props._destroyShaders) {
4297
+ delete this._cache[key];
4298
+ cacheEntry.resource.destroy();
4299
+ if (this.device.props.debugFactories) {
4300
+ log.log(3, `${this}: Releasing shader ${shader.id}, destroyed`)();
4301
+ }
4302
+ }
4303
+ } else if (cacheEntry.useCount < 0) {
4304
+ throw new Error(`ShaderFactory: Shader ${shader.id} released too many times`);
4305
+ } else if (this.device.props.debugFactories) {
4306
+ log.log(3, `${this}: Releasing shader ${shader.id} count=${cacheEntry.useCount}`)();
4307
+ }
4308
+ }
4309
+ }
4310
+ // PRIVATE
4311
+ _hashShader(value) {
4312
+ return `${value.stage}:${value.source}`;
4313
+ }
4314
+ };
4315
+ var ShaderFactory = _ShaderFactory;
4316
+ __publicField(ShaderFactory, "defaultProps", { ...Shader.defaultProps });
4317
+
4318
+ // src/adapter-utils/bind-groups.ts
4319
+ function getShaderLayoutBinding(shaderLayout, bindingName, options) {
4320
+ const bindingLayout = shaderLayout.bindings.find(
4321
+ (binding) => binding.name === bindingName || `${binding.name.toLocaleLowerCase()}uniforms` === bindingName.toLocaleLowerCase()
4322
+ );
4323
+ if (!bindingLayout && !options?.ignoreWarnings) {
4324
+ log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();
4325
+ }
4326
+ return bindingLayout || null;
4327
+ }
4328
+ function normalizeBindingsByGroup(shaderLayout, bindingsOrBindGroups) {
4329
+ if (!bindingsOrBindGroups) {
4330
+ return {};
4331
+ }
4332
+ if (areBindingsGrouped(bindingsOrBindGroups)) {
4333
+ const bindGroups2 = bindingsOrBindGroups;
4334
+ return Object.fromEntries(
4335
+ Object.entries(bindGroups2).map(([group, bindings]) => [Number(group), { ...bindings }])
4336
+ );
4337
+ }
4338
+ const bindGroups = {};
4339
+ for (const [bindingName, binding] of Object.entries(bindingsOrBindGroups)) {
4340
+ const bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
4341
+ const group = bindingLayout?.group ?? 0;
4342
+ bindGroups[group] ||= {};
4343
+ bindGroups[group][bindingName] = binding;
4344
+ }
4345
+ return bindGroups;
4346
+ }
4347
+ function flattenBindingsByGroup(bindGroups) {
4348
+ const bindings = {};
4349
+ for (const groupBindings of Object.values(bindGroups)) {
4350
+ Object.assign(bindings, groupBindings);
4351
+ }
4352
+ return bindings;
4353
+ }
4354
+ function areBindingsGrouped(bindingsOrBindGroups) {
4355
+ const keys = Object.keys(bindingsOrBindGroups);
4356
+ return keys.length > 0 && keys.every((key) => /^\d+$/.test(key));
4357
+ }
4358
+
4359
+ // src/factories/bind-group-factory.ts
4360
+ var BindGroupFactory = class {
4361
+ device;
4362
+ _layoutCacheByPipeline = /* @__PURE__ */ new WeakMap();
4363
+ _bindGroupCacheByLayout = /* @__PURE__ */ new WeakMap();
4364
+ constructor(device) {
4365
+ this.device = device;
4366
+ }
4367
+ getBindGroups(pipeline, bindings, bindGroupCacheKeys) {
4368
+ if (this.device.type !== "webgpu" || pipeline.shaderLayout.bindings.length === 0) {
4369
+ return {};
4370
+ }
4371
+ const bindingsByGroup = normalizeBindingsByGroup(pipeline.shaderLayout, bindings);
4372
+ const resolvedBindGroups = {};
4373
+ for (const group of getBindGroupIndicesUpToMax(pipeline.shaderLayout.bindings)) {
4374
+ const groupBindings = bindingsByGroup[group];
4375
+ const bindGroupLayout = this._getBindGroupLayout(pipeline, group);
4376
+ if (!groupBindings || Object.keys(groupBindings).length === 0) {
4377
+ if (!hasBindingsInGroup(pipeline.shaderLayout.bindings, group)) {
4378
+ resolvedBindGroups[group] = this._getEmptyBindGroup(
4379
+ bindGroupLayout,
4380
+ pipeline.shaderLayout,
4381
+ group
4382
+ );
4383
+ }
4384
+ continue;
4385
+ }
4386
+ const bindGroupCacheKey = bindGroupCacheKeys?.[group];
4387
+ if (bindGroupCacheKey) {
4388
+ const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
4389
+ if (layoutCache.bindGroupsBySource.has(bindGroupCacheKey)) {
4390
+ resolvedBindGroups[group] = layoutCache.bindGroupsBySource.get(bindGroupCacheKey) || null;
4391
+ continue;
4392
+ }
4393
+ const bindGroup = this.device._createBindGroupWebGPU(
4394
+ bindGroupLayout,
4395
+ pipeline.shaderLayout,
4396
+ groupBindings,
4397
+ group
4398
+ );
4399
+ layoutCache.bindGroupsBySource.set(bindGroupCacheKey, bindGroup);
4400
+ resolvedBindGroups[group] = bindGroup;
4401
+ } else {
4402
+ resolvedBindGroups[group] = this.device._createBindGroupWebGPU(
4403
+ bindGroupLayout,
4404
+ pipeline.shaderLayout,
4405
+ groupBindings,
4406
+ group
4407
+ );
4408
+ }
4409
+ }
4410
+ return resolvedBindGroups;
4411
+ }
4412
+ _getBindGroupLayout(pipeline, group) {
4413
+ let layoutCache = this._layoutCacheByPipeline.get(pipeline);
4414
+ if (!layoutCache) {
4415
+ layoutCache = {};
4416
+ this._layoutCacheByPipeline.set(pipeline, layoutCache);
4417
+ }
4418
+ layoutCache[group] ||= this.device._createBindGroupLayoutWebGPU(pipeline, group);
4419
+ return layoutCache[group];
4420
+ }
4421
+ _getEmptyBindGroup(bindGroupLayout, shaderLayout, group) {
4422
+ const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
4423
+ layoutCache.emptyBindGroup ||= this.device._createBindGroupWebGPU(bindGroupLayout, shaderLayout, {}, group) || null;
4424
+ return layoutCache.emptyBindGroup;
4425
+ }
4426
+ _getLayoutBindGroupCache(bindGroupLayout) {
4427
+ let layoutCache = this._bindGroupCacheByLayout.get(bindGroupLayout);
4428
+ if (!layoutCache) {
4429
+ layoutCache = { bindGroupsBySource: /* @__PURE__ */ new WeakMap() };
4430
+ this._bindGroupCacheByLayout.set(bindGroupLayout, layoutCache);
4431
+ }
4432
+ return layoutCache;
4433
+ }
4434
+ };
4435
+ function _getDefaultBindGroupFactory(device) {
4436
+ device._factories.bindGroupFactory ||= new BindGroupFactory(device);
4437
+ return device._factories.bindGroupFactory;
4438
+ }
4439
+ function getBindGroupIndicesUpToMax(bindings) {
4440
+ const maxGroup = bindings.reduce(
4441
+ (highestGroup, binding) => Math.max(highestGroup, binding.group),
4442
+ -1
4443
+ );
4444
+ return Array.from({ length: maxGroup + 1 }, (_, group) => group);
4445
+ }
4446
+ function hasBindingsInGroup(bindings, group) {
4447
+ return bindings.some((binding) => binding.group === group);
4448
+ }
4449
+
3890
4450
  // src/adapter/resources/render-pass.ts
3891
4451
  var _RenderPass = class extends Resource {
3892
4452
  get [Symbol.toStringTag]() {
@@ -3925,28 +4485,6 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
3925
4485
  endTimestampIndex: void 0
3926
4486
  });
3927
4487
 
3928
- // src/adapter/resources/compute-pipeline.ts
3929
- var _ComputePipeline = class extends Resource {
3930
- get [Symbol.toStringTag]() {
3931
- return "ComputePipeline";
3932
- }
3933
- hash = "";
3934
- /** The merged shader layout */
3935
- shaderLayout;
3936
- constructor(device, props) {
3937
- super(device, props, _ComputePipeline.defaultProps);
3938
- this.shaderLayout = props.shaderLayout;
3939
- }
3940
- };
3941
- var ComputePipeline = _ComputePipeline;
3942
- __publicField(ComputePipeline, "defaultProps", {
3943
- ...Resource.defaultProps,
3944
- shader: void 0,
3945
- entryPoint: void 0,
3946
- constants: {},
3947
- shaderLayout: void 0
3948
- });
3949
-
3950
4488
  // src/adapter/resources/compute-pass.ts
3951
4489
  var _ComputePass = class extends Resource {
3952
4490
  constructor(device, props) {
@@ -4058,7 +4596,7 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4058
4596
  ...Resource.defaultProps
4059
4597
  });
4060
4598
 
4061
- // src/shadertypes/data-types/decode-shader-types.ts
4599
+ // src/shadertypes/shader-types/shader-type-decoder.ts
4062
4600
  function getVariableShaderTypeInfo(format) {
4063
4601
  const resolvedFormat = resolveVariableShaderTypeAlias(format);
4064
4602
  const decoded = UNIFORM_FORMATS[resolvedFormat];
@@ -4085,12 +4623,33 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4085
4623
  signed
4086
4624
  };
4087
4625
  }
4626
+ var ShaderTypeDecoder = class {
4627
+ getVariableShaderTypeInfo(format) {
4628
+ return getVariableShaderTypeInfo(format);
4629
+ }
4630
+ getAttributeShaderTypeInfo(attributeType) {
4631
+ return getAttributeShaderTypeInfo(attributeType);
4632
+ }
4633
+ makeShaderAttributeType(primitiveType, components) {
4634
+ return makeShaderAttributeType(primitiveType, components);
4635
+ }
4636
+ resolveAttributeShaderTypeAlias(alias) {
4637
+ return resolveAttributeShaderTypeAlias(alias);
4638
+ }
4639
+ resolveVariableShaderTypeAlias(alias) {
4640
+ return resolveVariableShaderTypeAlias(alias);
4641
+ }
4642
+ };
4643
+ function makeShaderAttributeType(primitiveType, components) {
4644
+ return components === 1 ? primitiveType : `vec${components}<${primitiveType}>`;
4645
+ }
4088
4646
  function resolveAttributeShaderTypeAlias(alias) {
4089
4647
  return WGSL_ATTRIBUTE_TYPE_ALIAS_MAP[alias] || alias;
4090
4648
  }
4091
4649
  function resolveVariableShaderTypeAlias(alias) {
4092
4650
  return WGSL_VARIABLE_TYPE_ALIAS_MAP[alias] || alias;
4093
4651
  }
4652
+ var shaderTypeDecoder = new ShaderTypeDecoder();
4094
4653
  var PRIMITIVE_TYPE_SIZES = {
4095
4654
  f32: 4,
4096
4655
  f16: 2,
@@ -4187,7 +4746,18 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4187
4746
  vec4h: "vec4<f16>"
4188
4747
  };
4189
4748
  var WGSL_VARIABLE_TYPE_ALIAS_MAP = {
4190
- ...WGSL_ATTRIBUTE_TYPE_ALIAS_MAP,
4749
+ vec2i: "vec2<i32>",
4750
+ vec3i: "vec3<i32>",
4751
+ vec4i: "vec4<i32>",
4752
+ vec2u: "vec2<u32>",
4753
+ vec3u: "vec3<u32>",
4754
+ vec4u: "vec4<u32>",
4755
+ vec2f: "vec2<f32>",
4756
+ vec3f: "vec3<f32>",
4757
+ vec4f: "vec4<f32>",
4758
+ vec2h: "vec2<f16>",
4759
+ vec3h: "vec3<f16>",
4760
+ vec4h: "vec4<f16>",
4191
4761
  mat2x2f: "mat2x2<f32>",
4192
4762
  mat2x3f: "mat2x3<f32>",
4193
4763
  mat2x4f: "mat2x4<f32>",
@@ -4254,10 +4824,10 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4254
4824
  if (!shaderDeclaration) {
4255
4825
  return null;
4256
4826
  }
4257
- const attributeTypeInfo = getAttributeShaderTypeInfo(shaderDeclaration.type);
4258
- const defaultVertexFormat = getCompatibleVertexFormat(attributeTypeInfo);
4827
+ const attributeTypeInfo = shaderTypeDecoder.getAttributeShaderTypeInfo(shaderDeclaration.type);
4828
+ const defaultVertexFormat = vertexFormatDecoder.getCompatibleVertexFormat(attributeTypeInfo);
4259
4829
  const vertexFormat = bufferMapping?.vertexFormat || defaultVertexFormat;
4260
- const vertexFormatInfo = getVertexFormatInfo(vertexFormat);
4830
+ const vertexFormatInfo = vertexFormatDecoder.getVertexFormatInfo(vertexFormat);
4261
4831
  return {
4262
4832
  attributeName: bufferMapping?.attributeName || shaderDeclaration.name,
4263
4833
  bufferName: bufferMapping?.bufferName || shaderDeclaration.name,
@@ -4325,7 +4895,7 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4325
4895
  let byteStride = bufferLayout.byteStride;
4326
4896
  if (typeof bufferLayout.byteStride !== "number") {
4327
4897
  for (const attributeMapping2 of bufferLayout.attributes || []) {
4328
- const info = getVertexFormatInfo(attributeMapping2.format);
4898
+ const info = vertexFormatDecoder.getVertexFormatInfo(attributeMapping2.format);
4329
4899
  byteStride += info.byteLength;
4330
4900
  }
4331
4901
  }
@@ -4445,6 +5015,36 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4445
5015
  }
4446
5016
  });
4447
5017
 
5018
+ // src/shadertypes/data-types/decode-data-types.ts
5019
+ function alignTo(size, count) {
5020
+ switch (count) {
5021
+ case 1:
5022
+ return size;
5023
+ case 2:
5024
+ return size + size % 2;
5025
+ default:
5026
+ return size + (4 - size % 4) % 4;
5027
+ }
5028
+ }
5029
+ function getTypedArrayConstructor(type) {
5030
+ const [, , , , Constructor] = NORMALIZED_TYPE_MAP2[type];
5031
+ return Constructor;
5032
+ }
5033
+ var NORMALIZED_TYPE_MAP2 = {
5034
+ uint8: ["uint8", "u32", 1, false, Uint8Array],
5035
+ sint8: ["sint8", "i32", 1, false, Int8Array],
5036
+ unorm8: ["uint8", "f32", 1, true, Uint8Array],
5037
+ snorm8: ["sint8", "f32", 1, true, Int8Array],
5038
+ uint16: ["uint16", "u32", 2, false, Uint16Array],
5039
+ sint16: ["sint16", "i32", 2, false, Int16Array],
5040
+ unorm16: ["uint16", "u32", 2, true, Uint16Array],
5041
+ snorm16: ["sint16", "i32", 2, true, Int16Array],
5042
+ float16: ["float16", "f16", 2, false, Uint16Array],
5043
+ float32: ["float32", "f32", 4, false, Float32Array],
5044
+ uint32: ["uint32", "u32", 4, false, Uint32Array],
5045
+ sint32: ["sint32", "i32", 4, false, Int32Array]
5046
+ };
5047
+
4448
5048
  // src/utils/array-utils-flat.ts
4449
5049
  var arrayBuffer;
4450
5050
  function getScratchArrayBuffer(byteLength) {
@@ -4458,19 +5058,32 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4458
5058
  return new Type(scratchArrayBuffer, 0, length);
4459
5059
  }
4460
5060
 
5061
+ // src/utils/is-array.ts
5062
+ function isTypedArray(value) {
5063
+ return ArrayBuffer.isView(value) && !(value instanceof DataView);
5064
+ }
5065
+ function isNumberArray(value) {
5066
+ if (Array.isArray(value)) {
5067
+ return value.length === 0 || typeof value[0] === "number";
5068
+ }
5069
+ return isTypedArray(value);
5070
+ }
5071
+
4461
5072
  // src/portable/uniform-buffer-layout.ts
4462
5073
  var minBufferSize = 1024;
4463
5074
  var UniformBufferLayout = class {
4464
5075
  layout = {};
5076
+ uniformTypes;
4465
5077
  /** number of bytes needed for buffer allocation */
4466
5078
  byteLength;
4467
5079
  /** Create a new UniformBufferLayout given a map of attributes. */
4468
- constructor(uniformTypes, uniformSizes = {}) {
5080
+ constructor(uniformTypes) {
5081
+ this.uniformTypes = { ...uniformTypes };
4469
5082
  let size = 0;
4470
- for (const [key, uniformType] of Object.entries(uniformTypes)) {
4471
- size = this._addToLayout(key, uniformType, size, uniformSizes?.[key]);
5083
+ for (const [key, uniformType] of Object.entries(this.uniformTypes)) {
5084
+ size = this._addToLayout(key, uniformType, size);
4472
5085
  }
4473
- size += (4 - size % 4) % 4;
5086
+ size = alignTo(size, 4);
4474
5087
  this.byteLength = Math.max(size * 4, minBufferSize);
4475
5088
  }
4476
5089
  /** Does this layout have a field with specified name */
@@ -4482,98 +5095,241 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4482
5095
  const layout = this.layout[name2];
4483
5096
  return layout;
4484
5097
  }
5098
+ /** Flatten nested uniform values into leaf-path values understood by UniformBlock. */
5099
+ getFlatUniformValues(uniformValues) {
5100
+ const flattenedUniformValues = {};
5101
+ for (const [name2, value] of Object.entries(uniformValues)) {
5102
+ const uniformType = this.uniformTypes[name2];
5103
+ if (uniformType) {
5104
+ this._flattenCompositeValue(flattenedUniformValues, name2, uniformType, value);
5105
+ } else if (this.layout[name2]) {
5106
+ flattenedUniformValues[name2] = value;
5107
+ }
5108
+ }
5109
+ return flattenedUniformValues;
5110
+ }
4485
5111
  /** Get the data for the complete buffer */
4486
5112
  getData(uniformValues) {
4487
5113
  const buffer = getScratchArrayBuffer(this.byteLength);
5114
+ new Uint8Array(buffer, 0, this.byteLength).fill(0);
4488
5115
  const typedArrays = {
4489
5116
  i32: new Int32Array(buffer),
4490
5117
  u32: new Uint32Array(buffer),
4491
5118
  f32: new Float32Array(buffer),
4492
5119
  f16: new Uint16Array(buffer)
4493
5120
  };
4494
- for (const [name2, value] of Object.entries(uniformValues)) {
4495
- this._writeCompositeValue(typedArrays, name2, value);
5121
+ const flattenedUniformValues = this.getFlatUniformValues(uniformValues);
5122
+ for (const [name2, value] of Object.entries(flattenedUniformValues)) {
5123
+ this._writeLeafValue(typedArrays, name2, value);
4496
5124
  }
4497
5125
  return new Uint8Array(buffer, 0, this.byteLength);
4498
5126
  }
4499
5127
  // Recursively add a uniform to the layout
4500
- _addToLayout(name2, type, offset, count = 1) {
5128
+ _addToLayout(name2, type, offset) {
4501
5129
  if (typeof type === "string") {
4502
- const info = getVariableShaderTypeInfo(type);
4503
- const sizeInSlots = info.components * count;
4504
- const alignedOffset = alignTo(offset, info.components);
5130
+ const info = getLeafLayoutInfo(type);
5131
+ const alignedOffset = alignTo(offset, info.alignment);
4505
5132
  this.layout[name2] = {
4506
5133
  offset: alignedOffset,
4507
- size: sizeInSlots,
4508
- type: info.type
5134
+ ...info
4509
5135
  };
4510
- return alignedOffset + sizeInSlots;
5136
+ return alignedOffset + info.size;
4511
5137
  }
4512
5138
  if (Array.isArray(type)) {
5139
+ if (Array.isArray(type[0])) {
5140
+ throw new Error(`Nested arrays are not supported for ${name2}`);
5141
+ }
4513
5142
  const elementType = type[0];
4514
- const length = count > 1 ? count : type.length > 1 ? type[1] : 1;
4515
- let arrayOffset = alignTo(offset, 4);
5143
+ const length = type[1];
5144
+ const stride = alignTo(getTypeSize(elementType), 4);
5145
+ const arrayOffset = alignTo(offset, 4);
4516
5146
  for (let i = 0; i < length; i++) {
4517
- arrayOffset = this._addToLayout(`${name2}[${i}]`, elementType, arrayOffset);
5147
+ this._addToLayout(`${name2}[${i}]`, elementType, arrayOffset + i * stride);
4518
5148
  }
4519
- return arrayOffset;
5149
+ return arrayOffset + stride * length;
4520
5150
  }
4521
- if (typeof type === "object") {
5151
+ if (isCompositeShaderTypeStruct(type)) {
4522
5152
  let structOffset = alignTo(offset, 4);
4523
5153
  for (const [memberName, memberType] of Object.entries(type)) {
4524
5154
  structOffset = this._addToLayout(`${name2}.${memberName}`, memberType, structOffset);
4525
5155
  }
4526
- return structOffset;
5156
+ return alignTo(structOffset, 4);
4527
5157
  }
4528
5158
  throw new Error(`Unsupported CompositeShaderType for ${name2}`);
4529
5159
  }
4530
- _writeCompositeValue(typedArrays, baseName, value) {
4531
- if (this.layout[baseName]) {
4532
- this._writeToBuffer(typedArrays, baseName, value);
5160
+ _flattenCompositeValue(flattenedUniformValues, baseName, uniformType, value) {
5161
+ if (value === void 0) {
5162
+ return;
5163
+ }
5164
+ if (typeof uniformType === "string" || this.layout[baseName]) {
5165
+ flattenedUniformValues[baseName] = value;
4533
5166
  return;
4534
5167
  }
4535
- if (Array.isArray(value)) {
4536
- for (let i = 0; i < value.length; i++) {
4537
- const element = value[i];
4538
- const indexedName = `${baseName}[${i}]`;
4539
- this._writeCompositeValue(typedArrays, indexedName, element);
5168
+ if (Array.isArray(uniformType)) {
5169
+ const elementType = uniformType[0];
5170
+ const length = uniformType[1];
5171
+ if (Array.isArray(elementType)) {
5172
+ throw new Error(`Nested arrays are not supported for ${baseName}`);
5173
+ }
5174
+ if (typeof elementType === "string" && isNumberArray(value)) {
5175
+ this._flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value);
5176
+ return;
5177
+ }
5178
+ if (!Array.isArray(value)) {
5179
+ log.warn(`Unsupported uniform array value for ${baseName}:`, value)();
5180
+ return;
5181
+ }
5182
+ for (let index = 0; index < Math.min(value.length, length); index++) {
5183
+ const elementValue = value[index];
5184
+ if (elementValue === void 0) {
5185
+ continue;
5186
+ }
5187
+ this._flattenCompositeValue(
5188
+ flattenedUniformValues,
5189
+ `${baseName}[${index}]`,
5190
+ elementType,
5191
+ elementValue
5192
+ );
4540
5193
  }
4541
5194
  return;
4542
5195
  }
4543
- if (typeof value === "object" && value !== null) {
5196
+ if (isCompositeShaderTypeStruct(uniformType) && isCompositeUniformObject(value)) {
4544
5197
  for (const [key, subValue] of Object.entries(value)) {
5198
+ if (subValue === void 0) {
5199
+ continue;
5200
+ }
4545
5201
  const nestedName = `${baseName}.${key}`;
4546
- this._writeCompositeValue(typedArrays, nestedName, subValue);
5202
+ this._flattenCompositeValue(flattenedUniformValues, nestedName, uniformType[key], subValue);
4547
5203
  }
4548
5204
  return;
4549
5205
  }
4550
5206
  log.warn(`Unsupported uniform value for ${baseName}:`, value)();
4551
5207
  }
4552
- _writeToBuffer(typedArrays, name2, value) {
5208
+ _flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value) {
5209
+ const numericValue = value;
5210
+ const elementLayout = getLeafLayoutInfo(elementType);
5211
+ const packedElementLength = elementLayout.components;
5212
+ for (let index = 0; index < length; index++) {
5213
+ const start = index * packedElementLength;
5214
+ if (start >= numericValue.length) {
5215
+ break;
5216
+ }
5217
+ if (packedElementLength === 1) {
5218
+ flattenedUniformValues[`${baseName}[${index}]`] = Number(numericValue[start]);
5219
+ } else {
5220
+ flattenedUniformValues[`${baseName}[${index}]`] = sliceNumericArray(
5221
+ value,
5222
+ start,
5223
+ start + packedElementLength
5224
+ );
5225
+ }
5226
+ }
5227
+ }
5228
+ _writeLeafValue(typedArrays, name2, value) {
4553
5229
  const layout = this.layout[name2];
4554
5230
  if (!layout) {
4555
5231
  log.warn(`Uniform ${name2} not found in layout`)();
4556
5232
  return;
4557
5233
  }
4558
- const { type, size, offset } = layout;
5234
+ const { type, components, columns, rows, offset } = layout;
4559
5235
  const array = typedArrays[type];
4560
- if (size === 1) {
5236
+ if (components === 1) {
4561
5237
  array[offset] = Number(value);
4562
- } else {
4563
- array.set(value, offset);
5238
+ return;
5239
+ }
5240
+ const sourceValue = value;
5241
+ if (columns === 1) {
5242
+ for (let componentIndex = 0; componentIndex < components; componentIndex++) {
5243
+ array[offset + componentIndex] = Number(sourceValue[componentIndex] ?? 0);
5244
+ }
5245
+ return;
5246
+ }
5247
+ let sourceIndex = 0;
5248
+ for (let columnIndex = 0; columnIndex < columns; columnIndex++) {
5249
+ const columnOffset = offset + columnIndex * 4;
5250
+ for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
5251
+ array[columnOffset + rowIndex] = Number(sourceValue[sourceIndex++] ?? 0);
5252
+ }
4564
5253
  }
4565
5254
  }
4566
5255
  };
4567
-
4568
- // src/utils/is-array.ts
4569
- function isTypedArray(value) {
4570
- return ArrayBuffer.isView(value) && !(value instanceof DataView);
5256
+ function getTypeSize(type) {
5257
+ if (typeof type === "string") {
5258
+ return getLeafLayoutInfo(type).size;
5259
+ }
5260
+ if (Array.isArray(type)) {
5261
+ const elementType = type[0];
5262
+ const length = type[1];
5263
+ if (Array.isArray(elementType)) {
5264
+ throw new Error("Nested arrays are not supported");
5265
+ }
5266
+ return alignTo(getTypeSize(elementType), 4) * length;
5267
+ }
5268
+ let size = 0;
5269
+ for (const memberType of Object.values(type)) {
5270
+ const compositeMemberType = memberType;
5271
+ size = alignTo(size, getTypeAlignment(compositeMemberType));
5272
+ size += getTypeSize(compositeMemberType);
5273
+ }
5274
+ return alignTo(size, 4);
4571
5275
  }
4572
- function isNumberArray(value) {
4573
- if (Array.isArray(value)) {
4574
- return value.length === 0 || typeof value[0] === "number";
5276
+ function getTypeAlignment(type) {
5277
+ if (typeof type === "string") {
5278
+ return getLeafLayoutInfo(type).alignment;
4575
5279
  }
4576
- return isTypedArray(value);
5280
+ if (Array.isArray(type)) {
5281
+ return 4;
5282
+ }
5283
+ return 4;
5284
+ }
5285
+ function getLeafLayoutInfo(type) {
5286
+ const resolvedType = resolveVariableShaderTypeAlias(type);
5287
+ const decodedType = getVariableShaderTypeInfo(resolvedType);
5288
+ const matrixMatch = /^mat(\d)x(\d)<.+>$/.exec(resolvedType);
5289
+ if (matrixMatch) {
5290
+ const columns = Number(matrixMatch[1]);
5291
+ const rows = Number(matrixMatch[2]);
5292
+ return {
5293
+ alignment: 4,
5294
+ size: columns * 4,
5295
+ components: columns * rows,
5296
+ columns,
5297
+ rows,
5298
+ shaderType: resolvedType,
5299
+ type: decodedType.type
5300
+ };
5301
+ }
5302
+ const vectorMatch = /^vec(\d)<.+>$/.exec(resolvedType);
5303
+ if (vectorMatch) {
5304
+ const components = Number(vectorMatch[1]);
5305
+ return {
5306
+ alignment: components === 2 ? 2 : 4,
5307
+ size: components === 3 ? 4 : components,
5308
+ components,
5309
+ columns: 1,
5310
+ rows: components,
5311
+ shaderType: resolvedType,
5312
+ type: decodedType.type
5313
+ };
5314
+ }
5315
+ return {
5316
+ alignment: 1,
5317
+ size: 1,
5318
+ components: 1,
5319
+ columns: 1,
5320
+ rows: 1,
5321
+ shaderType: resolvedType,
5322
+ type: decodedType.type
5323
+ };
5324
+ }
5325
+ function isCompositeShaderTypeStruct(value) {
5326
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5327
+ }
5328
+ function isCompositeUniformObject(value) {
5329
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value) && !ArrayBuffer.isView(value);
5330
+ }
5331
+ function sliceNumericArray(value, start, end) {
5332
+ return Array.prototype.slice.call(value, start, end);
4577
5333
  }
4578
5334
 
4579
5335
  // src/utils/array-equal.ts
@@ -4675,13 +5431,12 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4675
5431
  constructor(blocks) {
4676
5432
  for (const [bufferName, block] of Object.entries(blocks)) {
4677
5433
  const uniformBufferName = bufferName;
4678
- const uniformBufferLayout = new UniformBufferLayout(
4679
- block.uniformTypes ?? {},
4680
- block.uniformSizes ?? {}
4681
- );
5434
+ const uniformBufferLayout = new UniformBufferLayout(block.uniformTypes ?? {});
4682
5435
  this.uniformBufferLayouts.set(uniformBufferName, uniformBufferLayout);
4683
5436
  const uniformBlock = new UniformBlock({ name: bufferName });
4684
- uniformBlock.setUniforms(block.defaultUniforms || {});
5437
+ uniformBlock.setUniforms(
5438
+ uniformBufferLayout.getFlatUniformValues(block.defaultUniforms || {})
5439
+ );
4685
5440
  this.uniformBlocks.set(uniformBufferName, uniformBlock);
4686
5441
  }
4687
5442
  }
@@ -4697,7 +5452,12 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4697
5452
  */
4698
5453
  setUniforms(uniforms) {
4699
5454
  for (const [blockName, uniformValues] of Object.entries(uniforms)) {
4700
- this.uniformBlocks.get(blockName)?.setUniforms(uniformValues);
5455
+ const uniformBufferName = blockName;
5456
+ const uniformBufferLayout = this.uniformBufferLayouts.get(uniformBufferName);
5457
+ const flattenedUniforms = uniformBufferLayout?.getFlatUniformValues(
5458
+ uniformValues || {}
5459
+ );
5460
+ this.uniformBlocks.get(uniformBufferName)?.setUniforms(flattenedUniforms || {});
4701
5461
  }
4702
5462
  this.updateUniformBuffers();
4703
5463
  }
@@ -4773,7 +5533,7 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4773
5533
  }
4774
5534
  };
4775
5535
 
4776
- // src/shadertypes/textures/texture-layout.ts
5536
+ // src/shadertypes/texture-types/texture-layout.ts
4777
5537
  function getTextureImageView(arrayBuffer2, memoryLayout, format, image = 0) {
4778
5538
  const formatInfo = textureFormatDecoder.getInfo(format);
4779
5539
  const bytesPerComponent = formatInfo.bytesPerPixel / formatInfo.components;
@@ -4811,7 +5571,7 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4811
5571
  typedArray.set(subArray, offset);
4812
5572
  }
4813
5573
 
4814
- // src/shadertypes/textures/pixel-utils.ts
5574
+ // src/shadertypes/texture-types/pixel-utils.ts
4815
5575
  function readPixel(pixelData, x, y, bitsPerChannel) {
4816
5576
  if (x < 0 || x >= pixelData.width || y < 0 || y >= pixelData.height) {
4817
5577
  throw new Error("Coordinates out of bounds.");