@luma.gl/effects 9.3.0-alpha.9 → 9.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/dist.dev.js +328 -173
  2. package/dist/dist.min.js +5 -5
  3. package/dist/index.cjs +18 -18
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.d.ts +1 -1
  6. package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.js +1 -1
  7. package/dist/passes/postprocessing/image-adjust-filters/denoise.d.ts +1 -1
  8. package/dist/passes/postprocessing/image-adjust-filters/denoise.js +1 -1
  9. package/dist/passes/postprocessing/image-adjust-filters/huesaturation.d.ts +1 -1
  10. package/dist/passes/postprocessing/image-adjust-filters/huesaturation.js +1 -1
  11. package/dist/passes/postprocessing/image-adjust-filters/noise.d.ts +1 -1
  12. package/dist/passes/postprocessing/image-adjust-filters/noise.js +1 -1
  13. package/dist/passes/postprocessing/image-adjust-filters/sepia.d.ts +1 -1
  14. package/dist/passes/postprocessing/image-adjust-filters/sepia.js +1 -1
  15. package/dist/passes/postprocessing/image-adjust-filters/vibrance.d.ts +1 -1
  16. package/dist/passes/postprocessing/image-adjust-filters/vibrance.js +1 -1
  17. package/dist/passes/postprocessing/image-adjust-filters/vignette.d.ts +1 -1
  18. package/dist/passes/postprocessing/image-adjust-filters/vignette.js +1 -1
  19. package/dist/passes/postprocessing/image-blur-filters/tiltshift.d.ts +1 -1
  20. package/dist/passes/postprocessing/image-blur-filters/tiltshift.js +1 -1
  21. package/dist/passes/postprocessing/image-blur-filters/triangleblur.d.ts +1 -1
  22. package/dist/passes/postprocessing/image-blur-filters/triangleblur.js +1 -1
  23. package/dist/passes/postprocessing/image-blur-filters/zoomblur.d.ts +1 -1
  24. package/dist/passes/postprocessing/image-blur-filters/zoomblur.js +1 -1
  25. package/dist/passes/postprocessing/image-fun-filters/colorhalftone.d.ts +1 -1
  26. package/dist/passes/postprocessing/image-fun-filters/colorhalftone.js +1 -1
  27. package/dist/passes/postprocessing/image-fun-filters/dotscreen.d.ts +1 -1
  28. package/dist/passes/postprocessing/image-fun-filters/dotscreen.js +1 -1
  29. package/dist/passes/postprocessing/image-fun-filters/edgework.d.ts +1 -1
  30. package/dist/passes/postprocessing/image-fun-filters/edgework.js +1 -1
  31. package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.d.ts +1 -1
  32. package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.js +1 -1
  33. package/dist/passes/postprocessing/image-fun-filters/ink.d.ts +1 -1
  34. package/dist/passes/postprocessing/image-fun-filters/ink.js +1 -1
  35. package/dist/passes/postprocessing/image-fun-filters/magnify.d.ts +1 -1
  36. package/dist/passes/postprocessing/image-fun-filters/magnify.js +1 -1
  37. package/dist/passes/postprocessing/image-warp-filters/bulgepinch.d.ts +1 -1
  38. package/dist/passes/postprocessing/image-warp-filters/bulgepinch.js +1 -1
  39. package/dist/passes/postprocessing/image-warp-filters/swirl.d.ts +1 -1
  40. package/dist/passes/postprocessing/image-warp-filters/swirl.js +1 -1
  41. package/package.json +2 -2
  42. package/src/passes/postprocessing/image-adjust-filters/brightnesscontrast.ts +1 -1
  43. package/src/passes/postprocessing/image-adjust-filters/denoise.ts +1 -1
  44. package/src/passes/postprocessing/image-adjust-filters/huesaturation.ts +1 -1
  45. package/src/passes/postprocessing/image-adjust-filters/noise.ts +1 -1
  46. package/src/passes/postprocessing/image-adjust-filters/sepia.ts +1 -1
  47. package/src/passes/postprocessing/image-adjust-filters/vibrance.ts +1 -1
  48. package/src/passes/postprocessing/image-adjust-filters/vignette.ts +1 -1
  49. package/src/passes/postprocessing/image-blur-filters/tiltshift.ts +1 -1
  50. package/src/passes/postprocessing/image-blur-filters/triangleblur.ts +1 -1
  51. package/src/passes/postprocessing/image-blur-filters/zoomblur.ts +1 -1
  52. package/src/passes/postprocessing/image-fun-filters/colorhalftone.ts +1 -1
  53. package/src/passes/postprocessing/image-fun-filters/dotscreen.ts +1 -1
  54. package/src/passes/postprocessing/image-fun-filters/edgework.ts +1 -1
  55. package/src/passes/postprocessing/image-fun-filters/hexagonalpixelate.ts +1 -1
  56. package/src/passes/postprocessing/image-fun-filters/ink.ts +1 -1
  57. package/src/passes/postprocessing/image-fun-filters/magnify.ts +1 -1
  58. package/src/passes/postprocessing/image-warp-filters/bulgepinch.ts +1 -1
  59. package/src/passes/postprocessing/image-warp-filters/swirl.ts +1 -1
package/dist/dist.dev.js CHANGED
@@ -75,13 +75,13 @@ var __exports__ = (() => {
75
75
  Resource: () => Resource,
76
76
  Sampler: () => Sampler,
77
77
  Shader: () => Shader,
78
+ ShaderBlockWriter: () => ShaderBlockWriter,
78
79
  ShaderFactory: () => ShaderFactory,
79
80
  SharedRenderPipeline: () => SharedRenderPipeline,
80
81
  Texture: () => Texture,
81
82
  TextureView: () => TextureView,
82
83
  TransformFeedback: () => TransformFeedback,
83
84
  UniformBlock: () => UniformBlock,
84
- UniformBufferLayout: () => UniformBufferLayout,
85
85
  UniformStore: () => UniformStore,
86
86
  VertexArray: () => VertexArray,
87
87
  _getDefaultBindGroupFactory: () => _getDefaultBindGroupFactory,
@@ -102,6 +102,7 @@ var __exports__ = (() => {
102
102
  isExternalImage: () => isExternalImage,
103
103
  log: () => log,
104
104
  luma: () => luma,
105
+ makeShaderBlockLayout: () => makeShaderBlockLayout,
105
106
  normalizeBindingsByGroup: () => normalizeBindingsByGroup,
106
107
  readPixel: () => readPixel,
107
108
  setTextureImageData: () => setTextureImageData,
@@ -1472,12 +1473,51 @@ var __exports__ = (() => {
1472
1473
  }
1473
1474
  return `${dataType}x${components}`;
1474
1475
  case "snorm8":
1476
+ if (components === 1) {
1477
+ return "snorm8";
1478
+ }
1479
+ if (components === 3) {
1480
+ return "snorm8x3-webgl";
1481
+ }
1482
+ return `${dataType}x${components}`;
1475
1483
  case "uint8":
1476
1484
  case "sint8":
1485
+ if (components === 1 || components === 3) {
1486
+ throw new Error(`size: ${components}`);
1487
+ }
1488
+ return `${dataType}x${components}`;
1477
1489
  case "uint16":
1490
+ if (components === 1) {
1491
+ return "uint16";
1492
+ }
1493
+ if (components === 3) {
1494
+ return "uint16x3-webgl";
1495
+ }
1496
+ return `${dataType}x${components}`;
1478
1497
  case "sint16":
1498
+ if (components === 1) {
1499
+ return "sint16";
1500
+ }
1501
+ if (components === 3) {
1502
+ return "sint16x3-webgl";
1503
+ }
1504
+ return `${dataType}x${components}`;
1479
1505
  case "unorm16":
1506
+ if (components === 1) {
1507
+ return "unorm16";
1508
+ }
1509
+ if (components === 3) {
1510
+ return "unorm16x3-webgl";
1511
+ }
1512
+ return `${dataType}x${components}`;
1480
1513
  case "snorm16":
1514
+ if (components === 1) {
1515
+ return "snorm16";
1516
+ }
1517
+ if (components === 3) {
1518
+ return "snorm16x3-webgl";
1519
+ }
1520
+ return `${dataType}x${components}`;
1481
1521
  case "float16":
1482
1522
  if (components === 1 || components === 3) {
1483
1523
  throw new Error(`size: ${components}`);
@@ -2180,7 +2220,7 @@ or create a device with the 'debug: true' prop.`;
2180
2220
  throw new Error("_createBindGroupLayoutWebGPU() not implemented");
2181
2221
  }
2182
2222
  /** Internal WebGPU-only helper for creating a native bind group. */
2183
- _createBindGroupWebGPU(_bindGroupLayout, _shaderLayout, _bindings, _group) {
2223
+ _createBindGroupWebGPU(_bindGroupLayout, _shaderLayout, _bindings, _group, _label) {
2184
2224
  throw new Error("_createBindGroupWebGPU() not implemented");
2185
2225
  }
2186
2226
  /**
@@ -4394,12 +4434,14 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4394
4434
  for (const group of getBindGroupIndicesUpToMax(pipeline.shaderLayout.bindings)) {
4395
4435
  const groupBindings = bindingsByGroup[group];
4396
4436
  const bindGroupLayout = this._getBindGroupLayout(pipeline, group);
4437
+ const bindGroupLabel = getBindGroupLabel(pipeline, pipeline.shaderLayout, group);
4397
4438
  if (!groupBindings || Object.keys(groupBindings).length === 0) {
4398
4439
  if (!hasBindingsInGroup(pipeline.shaderLayout.bindings, group)) {
4399
4440
  resolvedBindGroups[group] = this._getEmptyBindGroup(
4400
4441
  bindGroupLayout,
4401
4442
  pipeline.shaderLayout,
4402
- group
4443
+ group,
4444
+ bindGroupLabel
4403
4445
  );
4404
4446
  }
4405
4447
  continue;
@@ -4415,7 +4457,8 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4415
4457
  bindGroupLayout,
4416
4458
  pipeline.shaderLayout,
4417
4459
  groupBindings,
4418
- group
4460
+ group,
4461
+ bindGroupLabel
4419
4462
  );
4420
4463
  layoutCache.bindGroupsBySource.set(bindGroupCacheKey, bindGroup);
4421
4464
  resolvedBindGroups[group] = bindGroup;
@@ -4424,7 +4467,8 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4424
4467
  bindGroupLayout,
4425
4468
  pipeline.shaderLayout,
4426
4469
  groupBindings,
4427
- group
4470
+ group,
4471
+ bindGroupLabel
4428
4472
  );
4429
4473
  }
4430
4474
  }
@@ -4439,9 +4483,9 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4439
4483
  layoutCache[group] ||= this.device._createBindGroupLayoutWebGPU(pipeline, group);
4440
4484
  return layoutCache[group];
4441
4485
  }
4442
- _getEmptyBindGroup(bindGroupLayout, shaderLayout, group) {
4486
+ _getEmptyBindGroup(bindGroupLayout, shaderLayout, group, label) {
4443
4487
  const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
4444
- layoutCache.emptyBindGroup ||= this.device._createBindGroupWebGPU(bindGroupLayout, shaderLayout, {}, group) || null;
4488
+ layoutCache.emptyBindGroup ||= this.device._createBindGroupWebGPU(bindGroupLayout, shaderLayout, {}, group, label) || null;
4445
4489
  return layoutCache.emptyBindGroup;
4446
4490
  }
4447
4491
  _getLayoutBindGroupCache(bindGroupLayout) {
@@ -4467,6 +4511,11 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
4467
4511
  function hasBindingsInGroup(bindings, group) {
4468
4512
  return bindings.some((binding) => binding.group === group);
4469
4513
  }
4514
+ function getBindGroupLabel(pipeline, shaderLayout, group) {
4515
+ const bindingNames = shaderLayout.bindings.filter((binding) => binding.group === group).sort((left, right) => left.location - right.location).map((binding) => binding.name);
4516
+ const bindingSuffix = bindingNames.length > 0 ? bindingNames.join(",") : "empty";
4517
+ return `${pipeline.id}/group${group}[${bindingSuffix}]`;
4518
+ }
4470
4519
 
4471
4520
  // ../core/src/adapter/resources/render-pass.ts
4472
4521
  var _RenderPass = class extends Resource {
@@ -5066,6 +5115,170 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
5066
5115
  sint32: ["sint32", "i32", 4, false, Int32Array]
5067
5116
  };
5068
5117
 
5118
+ // ../core/src/shadertypes/shader-types/shader-block-layout.ts
5119
+ function makeShaderBlockLayout(uniformTypes, options = {}) {
5120
+ const copiedUniformTypes = { ...uniformTypes };
5121
+ const layout = options.layout ?? "std140";
5122
+ const fields = {};
5123
+ let size = 0;
5124
+ for (const [key, uniformType] of Object.entries(copiedUniformTypes)) {
5125
+ size = addToLayout(fields, key, uniformType, size, layout);
5126
+ }
5127
+ size = alignTo(size, getTypeAlignment(copiedUniformTypes, layout));
5128
+ return {
5129
+ layout,
5130
+ byteLength: size * 4,
5131
+ uniformTypes: copiedUniformTypes,
5132
+ fields
5133
+ };
5134
+ }
5135
+ function getLeafLayoutInfo(type, layout) {
5136
+ const resolvedType = resolveVariableShaderTypeAlias(type);
5137
+ const decodedType = getVariableShaderTypeInfo(resolvedType);
5138
+ const matrixMatch = /^mat(\d)x(\d)<.+>$/.exec(resolvedType);
5139
+ if (matrixMatch) {
5140
+ const columns = Number(matrixMatch[1]);
5141
+ const rows = Number(matrixMatch[2]);
5142
+ const columnInfo = getVectorLayoutInfo(
5143
+ rows,
5144
+ resolvedType,
5145
+ decodedType.type,
5146
+ layout
5147
+ );
5148
+ const columnStride = getMatrixColumnStride(columnInfo.size, columnInfo.alignment, layout);
5149
+ return {
5150
+ alignment: columnInfo.alignment,
5151
+ size: columns * columnStride,
5152
+ components: columns * rows,
5153
+ columns,
5154
+ rows,
5155
+ columnStride,
5156
+ shaderType: resolvedType,
5157
+ type: decodedType.type
5158
+ };
5159
+ }
5160
+ const vectorMatch = /^vec(\d)<.+>$/.exec(resolvedType);
5161
+ if (vectorMatch) {
5162
+ return getVectorLayoutInfo(
5163
+ Number(vectorMatch[1]),
5164
+ resolvedType,
5165
+ decodedType.type,
5166
+ layout
5167
+ );
5168
+ }
5169
+ return {
5170
+ alignment: 1,
5171
+ size: 1,
5172
+ components: 1,
5173
+ columns: 1,
5174
+ rows: 1,
5175
+ columnStride: 1,
5176
+ shaderType: resolvedType,
5177
+ type: decodedType.type
5178
+ };
5179
+ }
5180
+ function isCompositeShaderTypeStruct(value) {
5181
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
5182
+ }
5183
+ function addToLayout(fields, name2, type, offset, layout) {
5184
+ if (typeof type === "string") {
5185
+ const info = getLeafLayoutInfo(type, layout);
5186
+ const alignedOffset = alignTo(offset, info.alignment);
5187
+ fields[name2] = {
5188
+ offset: alignedOffset,
5189
+ ...info
5190
+ };
5191
+ return alignedOffset + info.size;
5192
+ }
5193
+ if (Array.isArray(type)) {
5194
+ if (Array.isArray(type[0])) {
5195
+ throw new Error(`Nested arrays are not supported for ${name2}`);
5196
+ }
5197
+ const elementType = type[0];
5198
+ const length = type[1];
5199
+ const stride = getArrayStride(elementType, layout);
5200
+ const arrayOffset = alignTo(offset, getTypeAlignment(type, layout));
5201
+ for (let i = 0; i < length; i++) {
5202
+ addToLayout(fields, `${name2}[${i}]`, elementType, arrayOffset + i * stride, layout);
5203
+ }
5204
+ return arrayOffset + stride * length;
5205
+ }
5206
+ if (isCompositeShaderTypeStruct(type)) {
5207
+ const structAlignment = getTypeAlignment(type, layout);
5208
+ let structOffset = alignTo(offset, structAlignment);
5209
+ for (const [memberName, memberType] of Object.entries(type)) {
5210
+ structOffset = addToLayout(fields, `${name2}.${memberName}`, memberType, structOffset, layout);
5211
+ }
5212
+ return alignTo(structOffset, structAlignment);
5213
+ }
5214
+ throw new Error(`Unsupported CompositeShaderType for ${name2}`);
5215
+ }
5216
+ function getTypeSize(type, layout) {
5217
+ if (typeof type === "string") {
5218
+ return getLeafLayoutInfo(type, layout).size;
5219
+ }
5220
+ if (Array.isArray(type)) {
5221
+ const elementType = type[0];
5222
+ const length = type[1];
5223
+ if (Array.isArray(elementType)) {
5224
+ throw new Error("Nested arrays are not supported");
5225
+ }
5226
+ return getArrayStride(elementType, layout) * length;
5227
+ }
5228
+ let size = 0;
5229
+ for (const memberType of Object.values(type)) {
5230
+ const compositeMemberType = memberType;
5231
+ size = alignTo(size, getTypeAlignment(compositeMemberType, layout));
5232
+ size += getTypeSize(compositeMemberType, layout);
5233
+ }
5234
+ return alignTo(size, getTypeAlignment(type, layout));
5235
+ }
5236
+ function getTypeAlignment(type, layout) {
5237
+ if (typeof type === "string") {
5238
+ return getLeafLayoutInfo(type, layout).alignment;
5239
+ }
5240
+ if (Array.isArray(type)) {
5241
+ const elementType = type[0];
5242
+ const elementAlignment = getTypeAlignment(elementType, layout);
5243
+ return uses16ByteArrayAlignment(layout) ? Math.max(elementAlignment, 4) : elementAlignment;
5244
+ }
5245
+ let maxAlignment = 1;
5246
+ for (const memberType of Object.values(type)) {
5247
+ const memberAlignment = getTypeAlignment(memberType, layout);
5248
+ maxAlignment = Math.max(maxAlignment, memberAlignment);
5249
+ }
5250
+ return uses16ByteStructAlignment(layout) ? Math.max(maxAlignment, 4) : maxAlignment;
5251
+ }
5252
+ function getVectorLayoutInfo(components, shaderType, type, layout) {
5253
+ return {
5254
+ alignment: components === 2 ? 2 : 4,
5255
+ size: components === 3 ? 3 : components,
5256
+ components,
5257
+ columns: 1,
5258
+ rows: components,
5259
+ columnStride: components === 3 ? 3 : components,
5260
+ shaderType,
5261
+ type
5262
+ };
5263
+ }
5264
+ function getArrayStride(elementType, layout) {
5265
+ const elementSize = getTypeSize(elementType, layout);
5266
+ const elementAlignment = getTypeAlignment(elementType, layout);
5267
+ return getArrayLikeStride(elementSize, elementAlignment, layout);
5268
+ }
5269
+ function getArrayLikeStride(size, alignment, layout) {
5270
+ return alignTo(size, uses16ByteArrayAlignment(layout) ? 4 : alignment);
5271
+ }
5272
+ function getMatrixColumnStride(size, alignment, layout) {
5273
+ return layout === "std140" ? 4 : alignTo(size, alignment);
5274
+ }
5275
+ function uses16ByteArrayAlignment(layout) {
5276
+ return layout === "std140" || layout === "wgsl-uniform";
5277
+ }
5278
+ function uses16ByteStructAlignment(layout) {
5279
+ return layout === "std140" || layout === "wgsl-uniform";
5280
+ }
5281
+
5069
5282
  // ../core/src/utils/array-utils-flat.ts
5070
5283
  var arrayBuffer;
5071
5284
  function getScratchArrayBuffer(byteLength) {
@@ -5090,49 +5303,56 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
5090
5303
  return isTypedArray(value);
5091
5304
  }
5092
5305
 
5093
- // ../core/src/portable/uniform-buffer-layout.ts
5094
- var minBufferSize = 1024;
5095
- var UniformBufferLayout = class {
5096
- layout = {};
5097
- uniformTypes;
5098
- /** number of bytes needed for buffer allocation */
5099
- byteLength;
5100
- /** Create a new UniformBufferLayout given a map of attributes. */
5101
- constructor(uniformTypes) {
5102
- this.uniformTypes = { ...uniformTypes };
5103
- let size = 0;
5104
- for (const [key, uniformType] of Object.entries(this.uniformTypes)) {
5105
- size = this._addToLayout(key, uniformType, size);
5106
- }
5107
- size = alignTo(size, 4);
5108
- this.byteLength = Math.max(size * 4, minBufferSize);
5109
- }
5110
- /** Does this layout have a field with specified name */
5306
+ // ../core/src/portable/shader-block-writer.ts
5307
+ var ShaderBlockWriter = class {
5308
+ /** Layout metadata used to flatten and serialize values. */
5309
+ layout;
5310
+ /**
5311
+ * Creates a writer for a precomputed shader-block layout.
5312
+ */
5313
+ constructor(layout) {
5314
+ this.layout = layout;
5315
+ }
5316
+ /**
5317
+ * Returns `true` if the flattened layout contains the given field.
5318
+ */
5111
5319
  has(name2) {
5112
- return Boolean(this.layout[name2]);
5320
+ return Boolean(this.layout.fields[name2]);
5113
5321
  }
5114
- /** Get offset and size for a field with specified name */
5322
+ /**
5323
+ * Returns offset and size metadata for a flattened field.
5324
+ */
5115
5325
  get(name2) {
5116
- const layout = this.layout[name2];
5117
- return layout;
5326
+ const entry = this.layout.fields[name2];
5327
+ return entry ? { offset: entry.offset, size: entry.size } : void 0;
5118
5328
  }
5119
- /** Flatten nested uniform values into leaf-path values understood by UniformBlock. */
5329
+ /**
5330
+ * Flattens nested composite values into leaf-path values understood by {@link UniformBlock}.
5331
+ *
5332
+ * Top-level values may be supplied either in nested object form matching the
5333
+ * declared composite shader types or as already-flattened leaf-path values.
5334
+ */
5120
5335
  getFlatUniformValues(uniformValues) {
5121
5336
  const flattenedUniformValues = {};
5122
5337
  for (const [name2, value] of Object.entries(uniformValues)) {
5123
- const uniformType = this.uniformTypes[name2];
5338
+ const uniformType = this.layout.uniformTypes[name2];
5124
5339
  if (uniformType) {
5125
5340
  this._flattenCompositeValue(flattenedUniformValues, name2, uniformType, value);
5126
- } else if (this.layout[name2]) {
5341
+ } else if (this.layout.fields[name2]) {
5127
5342
  flattenedUniformValues[name2] = value;
5128
5343
  }
5129
5344
  }
5130
5345
  return flattenedUniformValues;
5131
5346
  }
5132
- /** Get the data for the complete buffer */
5347
+ /**
5348
+ * Serializes the supplied values into buffer-backed binary data.
5349
+ *
5350
+ * The returned view length matches {@link ShaderBlockLayout.byteLength}, which
5351
+ * is the exact packed size of the block.
5352
+ */
5133
5353
  getData(uniformValues) {
5134
- const buffer = getScratchArrayBuffer(this.byteLength);
5135
- new Uint8Array(buffer, 0, this.byteLength).fill(0);
5354
+ const buffer = getScratchArrayBuffer(this.layout.byteLength);
5355
+ new Uint8Array(buffer, 0, this.layout.byteLength).fill(0);
5136
5356
  const typedArrays = {
5137
5357
  i32: new Int32Array(buffer),
5138
5358
  u32: new Uint32Array(buffer),
@@ -5143,46 +5363,16 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
5143
5363
  for (const [name2, value] of Object.entries(flattenedUniformValues)) {
5144
5364
  this._writeLeafValue(typedArrays, name2, value);
5145
5365
  }
5146
- return new Uint8Array(buffer, 0, this.byteLength);
5147
- }
5148
- // Recursively add a uniform to the layout
5149
- _addToLayout(name2, type, offset) {
5150
- if (typeof type === "string") {
5151
- const info = getLeafLayoutInfo(type);
5152
- const alignedOffset = alignTo(offset, info.alignment);
5153
- this.layout[name2] = {
5154
- offset: alignedOffset,
5155
- ...info
5156
- };
5157
- return alignedOffset + info.size;
5158
- }
5159
- if (Array.isArray(type)) {
5160
- if (Array.isArray(type[0])) {
5161
- throw new Error(`Nested arrays are not supported for ${name2}`);
5162
- }
5163
- const elementType = type[0];
5164
- const length = type[1];
5165
- const stride = alignTo(getTypeSize(elementType), 4);
5166
- const arrayOffset = alignTo(offset, 4);
5167
- for (let i = 0; i < length; i++) {
5168
- this._addToLayout(`${name2}[${i}]`, elementType, arrayOffset + i * stride);
5169
- }
5170
- return arrayOffset + stride * length;
5171
- }
5172
- if (isCompositeShaderTypeStruct(type)) {
5173
- let structOffset = alignTo(offset, 4);
5174
- for (const [memberName, memberType] of Object.entries(type)) {
5175
- structOffset = this._addToLayout(`${name2}.${memberName}`, memberType, structOffset);
5176
- }
5177
- return alignTo(structOffset, 4);
5178
- }
5179
- throw new Error(`Unsupported CompositeShaderType for ${name2}`);
5366
+ return new Uint8Array(buffer, 0, this.layout.byteLength);
5180
5367
  }
5368
+ /**
5369
+ * Recursively flattens nested values using the declared composite shader type.
5370
+ */
5181
5371
  _flattenCompositeValue(flattenedUniformValues, baseName, uniformType, value) {
5182
5372
  if (value === void 0) {
5183
5373
  return;
5184
5374
  }
5185
- if (typeof uniformType === "string" || this.layout[baseName]) {
5375
+ if (typeof uniformType === "string" || this.layout.fields[baseName]) {
5186
5376
  flattenedUniformValues[baseName] = value;
5187
5377
  return;
5188
5378
  }
@@ -5226,9 +5416,12 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
5226
5416
  }
5227
5417
  log.warn(`Unsupported uniform value for ${baseName}:`, value)();
5228
5418
  }
5419
+ /**
5420
+ * Expands tightly packed numeric arrays into per-element leaf fields.
5421
+ */
5229
5422
  _flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value) {
5230
5423
  const numericValue = value;
5231
- const elementLayout = getLeafLayoutInfo(elementType);
5424
+ const elementLayout = getLeafLayoutInfo(elementType, this.layout.layout);
5232
5425
  const packedElementLength = elementLayout.components;
5233
5426
  for (let index = 0; index < length; index++) {
5234
5427
  const start = index * packedElementLength;
@@ -5246,13 +5439,16 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
5246
5439
  }
5247
5440
  }
5248
5441
  }
5442
+ /**
5443
+ * Writes one flattened leaf value into its typed-array view.
5444
+ */
5249
5445
  _writeLeafValue(typedArrays, name2, value) {
5250
- const layout = this.layout[name2];
5251
- if (!layout) {
5446
+ const entry = this.layout.fields[name2];
5447
+ if (!entry) {
5252
5448
  log.warn(`Uniform ${name2} not found in layout`)();
5253
5449
  return;
5254
5450
  }
5255
- const { type, components, columns, rows, offset } = layout;
5451
+ const { type, components, columns, rows, offset, columnStride } = entry;
5256
5452
  const array = typedArrays[type];
5257
5453
  if (components === 1) {
5258
5454
  array[offset] = Number(value);
@@ -5267,85 +5463,13 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
5267
5463
  }
5268
5464
  let sourceIndex = 0;
5269
5465
  for (let columnIndex = 0; columnIndex < columns; columnIndex++) {
5270
- const columnOffset = offset + columnIndex * 4;
5466
+ const columnOffset = offset + columnIndex * columnStride;
5271
5467
  for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
5272
5468
  array[columnOffset + rowIndex] = Number(sourceValue[sourceIndex++] ?? 0);
5273
5469
  }
5274
5470
  }
5275
5471
  }
5276
5472
  };
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);
5296
- }
5297
- function getTypeAlignment(type) {
5298
- if (typeof type === "string") {
5299
- return getLeafLayoutInfo(type).alignment;
5300
- }
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
5473
  function isCompositeUniformObject(value) {
5350
5474
  return Boolean(value) && typeof value === "object" && !Array.isArray(value) && !ArrayBuffer.isView(value);
5351
5475
  }
@@ -5438,26 +5562,33 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
5438
5562
  };
5439
5563
 
5440
5564
  // ../core/src/portable/uniform-store.ts
5565
+ var minUniformBufferSize = 1024;
5441
5566
  var UniformStore = class {
5567
+ /** Device used to infer layout and allocate buffers. */
5568
+ device;
5442
5569
  /** Stores the uniform values for each uniform block */
5443
5570
  uniformBlocks = /* @__PURE__ */ new Map();
5444
- /** Can generate data for a uniform buffer for each block from data */
5445
- uniformBufferLayouts = /* @__PURE__ */ new Map();
5571
+ /** Flattened layout metadata for each block. */
5572
+ shaderBlockLayouts = /* @__PURE__ */ new Map();
5573
+ /** Serializers for block-backed uniform data. */
5574
+ shaderBlockWriters = /* @__PURE__ */ new Map();
5446
5575
  /** Actual buffer for the blocks */
5447
5576
  uniformBuffers = /* @__PURE__ */ new Map();
5448
5577
  /**
5449
- * Create a new UniformStore instance
5450
- * @param blocks
5578
+ * Creates a new {@link UniformStore} for the supplied device and block definitions.
5451
5579
  */
5452
- constructor(blocks) {
5580
+ constructor(device, blocks) {
5581
+ this.device = device;
5453
5582
  for (const [bufferName, block] of Object.entries(blocks)) {
5454
5583
  const uniformBufferName = bufferName;
5455
- const uniformBufferLayout = new UniformBufferLayout(block.uniformTypes ?? {});
5456
- this.uniformBufferLayouts.set(uniformBufferName, uniformBufferLayout);
5584
+ const shaderBlockLayout = makeShaderBlockLayout(block.uniformTypes ?? {}, {
5585
+ layout: block.layout ?? getDefaultUniformBufferLayout(device)
5586
+ });
5587
+ const shaderBlockWriter = new ShaderBlockWriter(shaderBlockLayout);
5588
+ this.shaderBlockLayouts.set(uniformBufferName, shaderBlockLayout);
5589
+ this.shaderBlockWriters.set(uniformBufferName, shaderBlockWriter);
5457
5590
  const uniformBlock = new UniformBlock({ name: bufferName });
5458
- uniformBlock.setUniforms(
5459
- uniformBufferLayout.getFlatUniformValues(block.defaultUniforms || {})
5460
- );
5591
+ uniformBlock.setUniforms(shaderBlockWriter.getFlatUniformValues(block.defaultUniforms || {}));
5461
5592
  this.uniformBlocks.set(uniformBufferName, uniformBlock);
5462
5593
  }
5463
5594
  }
@@ -5469,38 +5600,51 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
5469
5600
  }
5470
5601
  /**
5471
5602
  * Set uniforms
5472
- * Makes all properties partial
5603
+ *
5604
+ * Makes all group properties partial and eagerly propagates changes to any
5605
+ * managed GPU buffers.
5473
5606
  */
5474
5607
  setUniforms(uniforms) {
5475
5608
  for (const [blockName, uniformValues] of Object.entries(uniforms)) {
5476
5609
  const uniformBufferName = blockName;
5477
- const uniformBufferLayout = this.uniformBufferLayouts.get(uniformBufferName);
5478
- const flattenedUniforms = uniformBufferLayout?.getFlatUniformValues(
5610
+ const shaderBlockWriter = this.shaderBlockWriters.get(uniformBufferName);
5611
+ const flattenedUniforms = shaderBlockWriter?.getFlatUniformValues(
5479
5612
  uniformValues || {}
5480
5613
  );
5481
5614
  this.uniformBlocks.get(uniformBufferName)?.setUniforms(flattenedUniforms || {});
5482
5615
  }
5483
5616
  this.updateUniformBuffers();
5484
5617
  }
5485
- /** Get the required minimum length of the uniform buffer */
5618
+ /**
5619
+ * Returns the allocation size for the named uniform buffer.
5620
+ *
5621
+ * This may exceed the packed layout size because minimum buffer-size policy is
5622
+ * applied at the store layer.
5623
+ */
5486
5624
  getUniformBufferByteLength(uniformBufferName) {
5487
- return this.uniformBufferLayouts.get(uniformBufferName)?.byteLength || 0;
5625
+ const packedByteLength = this.shaderBlockLayouts.get(uniformBufferName)?.byteLength || 0;
5626
+ return Math.max(packedByteLength, minUniformBufferSize);
5488
5627
  }
5489
- /** Get formatted binary memory that can be uploaded to a buffer */
5628
+ /**
5629
+ * Returns packed binary data that can be uploaded to the named uniform buffer.
5630
+ *
5631
+ * The returned view length matches the packed block size and is not padded to
5632
+ * the store's minimum allocation size.
5633
+ */
5490
5634
  getUniformBufferData(uniformBufferName) {
5491
5635
  const uniformValues = this.uniformBlocks.get(uniformBufferName)?.getAllUniforms() || {};
5492
- return this.uniformBufferLayouts.get(uniformBufferName)?.getData(uniformValues);
5636
+ const shaderBlockWriter = this.shaderBlockWriters.get(uniformBufferName);
5637
+ return shaderBlockWriter?.getData(uniformValues) || new Uint8Array(0);
5493
5638
  }
5494
5639
  /**
5495
- * Creates an unmanaged uniform buffer (umnanaged means that application is responsible for destroying it)
5496
- * The new buffer is initialized with current / supplied values
5640
+ * Creates an unmanaged uniform buffer initialized with the current or supplied values.
5497
5641
  */
5498
- createUniformBuffer(device, uniformBufferName, uniforms) {
5642
+ createUniformBuffer(uniformBufferName, uniforms) {
5499
5643
  if (uniforms) {
5500
5644
  this.setUniforms(uniforms);
5501
5645
  }
5502
5646
  const byteLength = this.getUniformBufferByteLength(uniformBufferName);
5503
- const uniformBuffer = device.createBuffer({
5647
+ const uniformBuffer = this.device.createBuffer({
5504
5648
  usage: Buffer2.UNIFORM | Buffer2.COPY_DST,
5505
5649
  byteLength
5506
5650
  });
@@ -5508,11 +5652,11 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
5508
5652
  uniformBuffer.write(uniformBufferData);
5509
5653
  return uniformBuffer;
5510
5654
  }
5511
- /** Get the managed uniform buffer. "managed" resources are destroyed when the uniformStore is destroyed. */
5512
- getManagedUniformBuffer(device, uniformBufferName) {
5655
+ /** Returns the managed uniform buffer for the named block. */
5656
+ getManagedUniformBuffer(uniformBufferName) {
5513
5657
  if (!this.uniformBuffers.get(uniformBufferName)) {
5514
5658
  const byteLength = this.getUniformBufferByteLength(uniformBufferName);
5515
- const uniformBuffer = device.createBuffer({
5659
+ const uniformBuffer = this.device.createBuffer({
5516
5660
  usage: Buffer2.UNIFORM | Buffer2.COPY_DST,
5517
5661
  byteLength
5518
5662
  });
@@ -5520,7 +5664,11 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
5520
5664
  }
5521
5665
  return this.uniformBuffers.get(uniformBufferName);
5522
5666
  }
5523
- /** Updates all uniform buffers where values have changed */
5667
+ /**
5668
+ * Updates every managed uniform buffer whose source uniforms have changed.
5669
+ *
5670
+ * @returns The first redraw reason encountered, or `false` if nothing changed.
5671
+ */
5524
5672
  updateUniformBuffers() {
5525
5673
  let reason = false;
5526
5674
  for (const uniformBufferName of this.uniformBlocks.keys()) {
@@ -5532,7 +5680,11 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
5532
5680
  }
5533
5681
  return reason;
5534
5682
  }
5535
- /** Update one uniform buffer. Only updates if values have changed */
5683
+ /**
5684
+ * Updates one managed uniform buffer if its corresponding block is dirty.
5685
+ *
5686
+ * @returns The redraw reason for the update, or `false` if no write occurred.
5687
+ */
5536
5688
  updateUniformBuffer(uniformBufferName) {
5537
5689
  const uniformBlock = this.uniformBlocks.get(uniformBufferName);
5538
5690
  let uniformBuffer = this.uniformBuffers.get(uniformBufferName);
@@ -5553,6 +5705,9 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
5553
5705
  return reason;
5554
5706
  }
5555
5707
  };
5708
+ function getDefaultUniformBufferLayout(device) {
5709
+ return device.type === "webgpu" ? "wgsl-uniform" : "std140";
5710
+ }
5556
5711
 
5557
5712
  // ../core/src/shadertypes/texture-types/texture-layout.ts
5558
5713
  function getTextureImageView(arrayBuffer2, memoryLayout, format, image = 0) {