@luma.gl/webgpu 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 (76) hide show
  1. package/dist/adapter/helpers/get-bind-group.d.ts +3 -6
  2. package/dist/adapter/helpers/get-bind-group.d.ts.map +1 -1
  3. package/dist/adapter/helpers/get-bind-group.js +11 -14
  4. package/dist/adapter/helpers/get-bind-group.js.map +1 -1
  5. package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts +3 -1
  6. package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts.map +1 -1
  7. package/dist/adapter/helpers/get-vertex-buffer-layout.js +17 -12
  8. package/dist/adapter/helpers/get-vertex-buffer-layout.js.map +1 -1
  9. package/dist/adapter/helpers/webgpu-parameters.d.ts.map +1 -1
  10. package/dist/adapter/helpers/webgpu-parameters.js +1 -0
  11. package/dist/adapter/helpers/webgpu-parameters.js.map +1 -1
  12. package/dist/adapter/resources/webgpu-command-encoder.d.ts +3 -13
  13. package/dist/adapter/resources/webgpu-command-encoder.d.ts.map +1 -1
  14. package/dist/adapter/resources/webgpu-command-encoder.js +68 -29
  15. package/dist/adapter/resources/webgpu-command-encoder.js.map +1 -1
  16. package/dist/adapter/resources/webgpu-compute-pass.d.ts +3 -3
  17. package/dist/adapter/resources/webgpu-compute-pass.d.ts.map +1 -1
  18. package/dist/adapter/resources/webgpu-compute-pass.js +17 -7
  19. package/dist/adapter/resources/webgpu-compute-pass.js.map +1 -1
  20. package/dist/adapter/resources/webgpu-compute-pipeline.d.ts +7 -9
  21. package/dist/adapter/resources/webgpu-compute-pipeline.d.ts.map +1 -1
  22. package/dist/adapter/resources/webgpu-compute-pipeline.js +26 -29
  23. package/dist/adapter/resources/webgpu-compute-pipeline.js.map +1 -1
  24. package/dist/adapter/resources/webgpu-fence.d.ts.map +1 -1
  25. package/dist/adapter/resources/webgpu-fence.js +9 -1
  26. package/dist/adapter/resources/webgpu-fence.js.map +1 -1
  27. package/dist/adapter/resources/webgpu-pipeline-layout.d.ts +1 -1
  28. package/dist/adapter/resources/webgpu-pipeline-layout.d.ts.map +1 -1
  29. package/dist/adapter/resources/webgpu-pipeline-layout.js +10 -16
  30. package/dist/adapter/resources/webgpu-pipeline-layout.js.map +1 -1
  31. package/dist/adapter/resources/webgpu-render-pass.d.ts +4 -4
  32. package/dist/adapter/resources/webgpu-render-pass.d.ts.map +1 -1
  33. package/dist/adapter/resources/webgpu-render-pass.js +10 -10
  34. package/dist/adapter/resources/webgpu-render-pass.js.map +1 -1
  35. package/dist/adapter/resources/webgpu-render-pipeline.d.ts +10 -9
  36. package/dist/adapter/resources/webgpu-render-pipeline.d.ts.map +1 -1
  37. package/dist/adapter/resources/webgpu-render-pipeline.js +48 -38
  38. package/dist/adapter/resources/webgpu-render-pipeline.js.map +1 -1
  39. package/dist/adapter/resources/webgpu-shader.d.ts.map +1 -1
  40. package/dist/adapter/resources/webgpu-shader.js +17 -1
  41. package/dist/adapter/resources/webgpu-shader.js.map +1 -1
  42. package/dist/adapter/resources/webgpu-texture.d.ts +8 -1
  43. package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -1
  44. package/dist/adapter/resources/webgpu-texture.js +35 -43
  45. package/dist/adapter/resources/webgpu-texture.js.map +1 -1
  46. package/dist/adapter/webgpu-device.d.ts +6 -2
  47. package/dist/adapter/webgpu-device.d.ts.map +1 -1
  48. package/dist/adapter/webgpu-device.js +60 -18
  49. package/dist/adapter/webgpu-device.js.map +1 -1
  50. package/dist/dist.dev.js +508 -311
  51. package/dist/dist.min.js +13 -13
  52. package/dist/index.cjs +439 -319
  53. package/dist/index.cjs.map +4 -4
  54. package/dist/wgsl/get-shader-layout-wgsl.d.ts.map +1 -1
  55. package/dist/wgsl/get-shader-layout-wgsl.js +8 -0
  56. package/dist/wgsl/get-shader-layout-wgsl.js.map +1 -1
  57. package/package.json +3 -3
  58. package/src/adapter/helpers/get-bind-group.ts +18 -27
  59. package/src/adapter/helpers/get-vertex-buffer-layout.ts +31 -12
  60. package/src/adapter/helpers/webgpu-parameters.ts +2 -0
  61. package/src/adapter/resources/webgpu-command-encoder.ts +99 -46
  62. package/src/adapter/resources/webgpu-compute-pass.ts +35 -8
  63. package/src/adapter/resources/webgpu-compute-pipeline.ts +43 -30
  64. package/src/adapter/resources/webgpu-fence.ts +11 -3
  65. package/src/adapter/resources/webgpu-pipeline-layout.ts +16 -14
  66. package/src/adapter/resources/webgpu-render-pass.ts +18 -14
  67. package/src/adapter/resources/webgpu-render-pipeline.ts +68 -46
  68. package/src/adapter/resources/webgpu-shader.ts +16 -1
  69. package/src/adapter/resources/webgpu-texture.ts +61 -44
  70. package/src/adapter/webgpu-device.ts +101 -25
  71. package/src/wgsl/get-shader-layout-wgsl.ts +9 -0
  72. package/dist/adapter/helpers/accessor-to-format.d.ts +0 -1
  73. package/dist/adapter/helpers/accessor-to-format.d.ts.map +0 -1
  74. package/dist/adapter/helpers/accessor-to-format.js +0 -105
  75. package/dist/adapter/helpers/accessor-to-format.js.map +0 -1
  76. package/src/adapter/helpers/accessor-to-format.ts +0 -104
package/dist/dist.dev.js CHANGED
@@ -514,60 +514,70 @@ var __exports__ = (() => {
514
514
  };
515
515
  }
516
516
  readBuffer(options = {}, buffer) {
517
+ if (!buffer) {
518
+ throw new Error(`${this} readBuffer requires a destination buffer`);
519
+ }
517
520
  const { x: x2, y: y2, z: z2, width, height, depthOrArrayLayers, mipLevel, aspect } = this._getSupportedColorReadOptions(options);
518
- const layout = this.computeMemoryLayout({ x: x2, y: y2, z: z2, width, height, depthOrArrayLayers, mipLevel });
519
- const { bytesPerRow, rowsPerImage, byteLength } = layout;
520
- const readBuffer = buffer || this.device.createBuffer({
521
- byteLength,
522
- usage: import_core4.Buffer.COPY_DST | import_core4.Buffer.MAP_READ
523
- });
524
- if (readBuffer.byteLength < byteLength) {
521
+ const byteOffset = options.byteOffset ?? 0;
522
+ const layout = this.computeMemoryLayout({ width, height, depthOrArrayLayers, mipLevel });
523
+ const { byteLength } = layout;
524
+ if (buffer.byteLength < byteOffset + byteLength) {
525
525
  throw new Error(
526
- `${this} readBuffer target is too small (${readBuffer.byteLength} < ${byteLength})`
526
+ `${this} readBuffer target is too small (${buffer.byteLength} < ${byteOffset + byteLength})`
527
527
  );
528
528
  }
529
- const gpuReadBuffer = readBuffer.handle;
530
529
  const gpuDevice = this.device.handle;
531
530
  this.device.pushErrorScope("validation");
532
531
  const commandEncoder = gpuDevice.createCommandEncoder();
532
+ this.copyToBuffer(
533
+ commandEncoder,
534
+ { x: x2, y: y2, z: z2, width, height, depthOrArrayLayers, mipLevel, aspect, byteOffset },
535
+ buffer
536
+ );
537
+ const commandBuffer = commandEncoder.finish();
538
+ this.device.handle.queue.submit([commandBuffer]);
539
+ this.device.popErrorScope((error) => {
540
+ this.device.reportError(new Error(`${this} readBuffer: ${error.message}`), this)();
541
+ this.device.debug();
542
+ });
543
+ return buffer;
544
+ }
545
+ async readDataAsync(options = {}) {
546
+ throw new Error(
547
+ `${this} readDataAsync is deprecated; use readBuffer() with an explicit destination buffer or DynamicTexture.readAsync()`
548
+ );
549
+ }
550
+ copyToBuffer(commandEncoder, options = {}, buffer) {
551
+ const {
552
+ byteOffset = 0,
553
+ bytesPerRow: requestedBytesPerRow,
554
+ rowsPerImage: requestedRowsPerImage,
555
+ ...textureReadOptions
556
+ } = options;
557
+ const { x: x2, y: y2, z: z2, width, height, depthOrArrayLayers, mipLevel, aspect } = this._getSupportedColorReadOptions(textureReadOptions);
558
+ const layout = this.computeMemoryLayout({ width, height, depthOrArrayLayers, mipLevel });
559
+ const effectiveBytesPerRow = requestedBytesPerRow ?? layout.bytesPerRow;
560
+ const effectiveRowsPerImage = requestedRowsPerImage ?? layout.rowsPerImage;
561
+ const webgpuBuffer = buffer;
533
562
  commandEncoder.copyTextureToBuffer(
534
- // source
535
563
  {
536
564
  texture: this.handle,
537
565
  origin: { x: x2, y: y2, z: z2 },
538
- // origin: [options.x, options.y, 0], // options.depth],
539
566
  mipLevel,
540
567
  aspect
541
- // colorSpace: options.colorSpace,
542
- // premultipliedAlpha: options.premultipliedAlpha
543
568
  },
544
- // destination
545
569
  {
546
- buffer: gpuReadBuffer,
547
- offset: 0,
548
- bytesPerRow,
549
- rowsPerImage
570
+ buffer: webgpuBuffer.handle,
571
+ offset: byteOffset,
572
+ bytesPerRow: effectiveBytesPerRow,
573
+ rowsPerImage: effectiveRowsPerImage
550
574
  },
551
- // copy size
552
575
  {
553
576
  width,
554
577
  height,
555
578
  depthOrArrayLayers
556
579
  }
557
580
  );
558
- const commandBuffer = commandEncoder.finish();
559
- this.device.handle.queue.submit([commandBuffer]);
560
- this.device.popErrorScope((error) => {
561
- this.device.reportError(new Error(`${this} readBuffer: ${error.message}`), this)();
562
- this.device.debug();
563
- });
564
- return readBuffer;
565
- }
566
- async readDataAsync(options = {}) {
567
- const buffer = this.readBuffer(options);
568
- const data = await buffer.readAsync();
569
- buffer.destroy();
570
- return data.buffer;
571
581
  }
572
582
  writeBuffer(buffer, options_ = {}) {
573
583
  const options = this._normalizeTextureWriteOptions(options_);
@@ -780,7 +790,19 @@ var __exports__ = (() => {
780
790
  }
781
791
  /** Returns compilation info for this shader */
782
792
  async getCompilationInfo() {
783
- const compilationInfo = await this.handle.getCompilationInfo();
793
+ const handle = this.handle;
794
+ if (!handle) {
795
+ return [];
796
+ }
797
+ let compilationInfo;
798
+ try {
799
+ compilationInfo = await handle.getCompilationInfo();
800
+ } catch (error) {
801
+ if (this.device.shouldIgnoreDroppedInstanceError(error, "getCompilationInfo")) {
802
+ return [];
803
+ }
804
+ throw error;
805
+ }
784
806
  return compilationInfo.messages;
785
807
  }
786
808
  };
@@ -870,6 +892,7 @@ var __exports__ = (() => {
870
892
  const depthStencil = addDepthStencil(descriptor);
871
893
  depthStencil.format = value;
872
894
  },
895
+ clearDepth: notSupported,
873
896
  depthBias: (_2, value, descriptor) => {
874
897
  const depthStencil = addDepthStencil(descriptor);
875
898
  depthStencil.depthBias = value;
@@ -1008,96 +1031,6 @@ var __exports__ = (() => {
1008
1031
  }
1009
1032
  });
1010
1033
 
1011
- // src/adapter/helpers/get-bind-group.ts
1012
- function getBindGroup(device, bindGroupLayout, shaderLayout, bindings) {
1013
- const entries = getBindGroupEntries(bindings, shaderLayout);
1014
- device.pushErrorScope("validation");
1015
- const bindGroup = device.handle.createBindGroup({
1016
- layout: bindGroupLayout,
1017
- entries
1018
- });
1019
- device.popErrorScope((error) => {
1020
- import_core8.log.error(`bindGroup creation: ${error.message}`, bindGroup)();
1021
- });
1022
- return bindGroup;
1023
- }
1024
- function getShaderLayoutBinding(shaderLayout, bindingName, options) {
1025
- const bindingLayout = shaderLayout.bindings.find(
1026
- (binding) => binding.name === bindingName || `${binding.name.toLocaleLowerCase()}uniforms` === bindingName.toLocaleLowerCase()
1027
- );
1028
- if (!bindingLayout && !options?.ignoreWarnings) {
1029
- import_core8.log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();
1030
- }
1031
- return bindingLayout || null;
1032
- }
1033
- function getBindGroupEntries(bindings, shaderLayout) {
1034
- const entries = [];
1035
- for (const [bindingName, value] of Object.entries(bindings)) {
1036
- const exactBindingLayout = shaderLayout.bindings.find((binding) => binding.name === bindingName);
1037
- const bindingLayout = exactBindingLayout || getShaderLayoutBinding(shaderLayout, bindingName);
1038
- const isShadowedAlias = !exactBindingLayout && bindingLayout ? bindingLayout.name in bindings : false;
1039
- if (!isShadowedAlias) {
1040
- const entry = bindingLayout ? getBindGroupEntry(value, bindingLayout.location, void 0, bindingName) : null;
1041
- if (entry) {
1042
- entries.push(entry);
1043
- }
1044
- if (value instanceof import_core8.Texture) {
1045
- const samplerBindingLayout = getShaderLayoutBinding(shaderLayout, `${bindingName}Sampler`, {
1046
- ignoreWarnings: true
1047
- });
1048
- const samplerEntry = samplerBindingLayout ? getBindGroupEntry(value, samplerBindingLayout.location, { sampler: true }, bindingName) : null;
1049
- if (samplerEntry) {
1050
- entries.push(samplerEntry);
1051
- }
1052
- }
1053
- }
1054
- }
1055
- return entries;
1056
- }
1057
- function getBindGroupEntry(binding, index, options, bindingName = "unknown") {
1058
- if (binding instanceof import_core8.Buffer) {
1059
- return {
1060
- binding: index,
1061
- resource: {
1062
- buffer: binding.handle
1063
- }
1064
- };
1065
- }
1066
- if (binding instanceof import_core8.Sampler) {
1067
- return {
1068
- binding: index,
1069
- resource: binding.handle
1070
- };
1071
- }
1072
- if (binding instanceof import_core8.TextureView) {
1073
- return {
1074
- binding: index,
1075
- resource: binding.handle
1076
- };
1077
- }
1078
- if (binding instanceof import_core8.Texture) {
1079
- if (options?.sampler) {
1080
- return {
1081
- binding: index,
1082
- resource: binding.sampler.handle
1083
- };
1084
- }
1085
- return {
1086
- binding: index,
1087
- resource: binding.view.handle
1088
- };
1089
- }
1090
- import_core8.log.warn(`invalid binding ${bindingName}`, binding);
1091
- return null;
1092
- }
1093
- var import_core8;
1094
- var init_get_bind_group = __esm({
1095
- "src/adapter/helpers/get-bind-group.ts"() {
1096
- "use strict";
1097
- import_core8 = __toESM(require_core(), 1);
1098
- }
1099
- });
1100
-
1101
1034
  // src/adapter/helpers/get-vertex-buffer-layout.ts
1102
1035
  function getWebGPUVertexFormat(format) {
1103
1036
  if (format.endsWith("-webgl")) {
@@ -1105,9 +1038,10 @@ var __exports__ = (() => {
1105
1038
  }
1106
1039
  return format;
1107
1040
  }
1108
- function getVertexBufferLayout(shaderLayout, bufferLayout) {
1041
+ function getVertexBufferLayout(shaderLayout, bufferLayout, options) {
1109
1042
  const vertexBufferLayouts = [];
1110
1043
  const usedAttributes = /* @__PURE__ */ new Set();
1044
+ const shaderAttributes = shaderLayout.attributes || [];
1111
1045
  for (const mapping of bufferLayout) {
1112
1046
  const vertexAttributes = [];
1113
1047
  let stepMode = "vertex";
@@ -1116,7 +1050,12 @@ var __exports__ = (() => {
1116
1050
  if (mapping.attributes) {
1117
1051
  for (const attributeMapping of mapping.attributes) {
1118
1052
  const attributeName = attributeMapping.attribute;
1119
- const attributeLayout = findAttributeLayout(shaderLayout, attributeName, usedAttributes);
1053
+ const attributeLayout = findAttributeLayout(
1054
+ shaderLayout,
1055
+ attributeName,
1056
+ usedAttributes,
1057
+ options
1058
+ );
1120
1059
  const location = attributeLayout?.location;
1121
1060
  format = attributeMapping.format || mapping.format;
1122
1061
  stepMode = attributeLayout?.stepMode || (attributeLayout?.name.startsWith("instance") ? "instance" : "vertex");
@@ -1125,14 +1064,19 @@ var __exports__ = (() => {
1125
1064
  offset: attributeMapping.byteOffset,
1126
1065
  shaderLocation: location
1127
1066
  });
1128
- byteStride += (0, import_core9.getVertexFormatInfo)(format).byteLength;
1067
+ byteStride += import_core8.vertexFormatDecoder.getVertexFormatInfo(format).byteLength;
1129
1068
  }
1130
1069
  } else {
1131
- const attributeLayout = findAttributeLayout(shaderLayout, mapping.name, usedAttributes);
1070
+ const attributeLayout = findAttributeLayout(
1071
+ shaderLayout,
1072
+ mapping.name,
1073
+ usedAttributes,
1074
+ options
1075
+ );
1132
1076
  if (!attributeLayout) {
1133
1077
  continue;
1134
1078
  }
1135
- byteStride = (0, import_core9.getVertexFormatInfo)(format).byteLength;
1079
+ byteStride = import_core8.vertexFormatDecoder.getVertexFormatInfo(format).byteLength;
1136
1080
  stepMode = attributeLayout.stepMode || (attributeLayout.name.startsWith("instance") ? "instance" : "vertex");
1137
1081
  vertexAttributes.push({
1138
1082
  format: getWebGPUVertexFormat(format),
@@ -1147,10 +1091,10 @@ var __exports__ = (() => {
1147
1091
  attributes: vertexAttributes
1148
1092
  });
1149
1093
  }
1150
- for (const attribute of shaderLayout.attributes) {
1094
+ for (const attribute of shaderAttributes) {
1151
1095
  if (!usedAttributes.has(attribute.name)) {
1152
1096
  vertexBufferLayouts.push({
1153
- arrayStride: (0, import_core9.getVertexFormatInfo)("float32x3").byteLength,
1097
+ arrayStride: import_core8.vertexFormatDecoder.getVertexFormatInfo("float32x3").byteLength,
1154
1098
  stepMode: attribute.stepMode || (attribute.name.startsWith("instance") ? "instance" : "vertex"),
1155
1099
  attributes: [
1156
1100
  {
@@ -1169,10 +1113,13 @@ var __exports__ = (() => {
1169
1113
  });
1170
1114
  return vertexBufferLayouts;
1171
1115
  }
1172
- function findAttributeLayout(shaderLayout, name, attributeNames) {
1173
- const attribute = shaderLayout.attributes.find((attribute_) => attribute_.name === name);
1116
+ function findAttributeLayout(shaderLayout, name, attributeNames, options) {
1117
+ const attribute = shaderLayout.attributes?.find((attribute_) => attribute_.name === name);
1174
1118
  if (!attribute) {
1175
- import_core9.log.warn(`Supplied attribute not present in shader layout: ${name}`)();
1119
+ const pipelineContext = options?.pipelineId ? `RenderPipeline(${options.pipelineId})` : "RenderPipeline";
1120
+ import_core8.log.warn(
1121
+ `${pipelineContext}: Ignoring "${name}" attribute, since it is not present in shader layout.`
1122
+ )();
1176
1123
  return null;
1177
1124
  }
1178
1125
  if (attributeNames) {
@@ -1183,47 +1130,58 @@ var __exports__ = (() => {
1183
1130
  }
1184
1131
  return attribute;
1185
1132
  }
1186
- var import_core9;
1133
+ var import_core8;
1187
1134
  var init_get_vertex_buffer_layout = __esm({
1188
1135
  "src/adapter/helpers/get-vertex-buffer-layout.ts"() {
1189
1136
  "use strict";
1190
- import_core9 = __toESM(require_core(), 1);
1137
+ import_core8 = __toESM(require_core(), 1);
1191
1138
  }
1192
1139
  });
1193
1140
 
1194
1141
  // src/adapter/resources/webgpu-render-pipeline.ts
1195
- var import_core10, EMPTY_BINDINGS, WebGPURenderPipeline;
1142
+ function createBindGroupCacheKeys(bindingsByGroup) {
1143
+ const bindGroupCacheKeys = {};
1144
+ for (const [groupKey, groupBindings] of Object.entries(bindingsByGroup)) {
1145
+ if (groupBindings && Object.keys(groupBindings).length > 0) {
1146
+ bindGroupCacheKeys[Number(groupKey)] = {};
1147
+ }
1148
+ }
1149
+ return bindGroupCacheKeys;
1150
+ }
1151
+ var import_core9, WebGPURenderPipeline;
1196
1152
  var init_webgpu_render_pipeline = __esm({
1197
1153
  "src/adapter/resources/webgpu-render-pipeline.ts"() {
1198
1154
  "use strict";
1199
- import_core10 = __toESM(require_core(), 1);
1155
+ import_core9 = __toESM(require_core(), 1);
1200
1156
  init_webgpu_parameters();
1201
1157
  init_convert_texture_format();
1202
- init_get_bind_group();
1203
1158
  init_get_vertex_buffer_layout();
1204
- EMPTY_BINDINGS = {};
1205
- WebGPURenderPipeline = class extends import_core10.RenderPipeline {
1159
+ WebGPURenderPipeline = class extends import_core9.RenderPipeline {
1206
1160
  device;
1207
1161
  handle;
1162
+ descriptor;
1208
1163
  vs;
1209
1164
  fs = null;
1210
1165
  /** Compatibility path for direct pipeline.setBindings() usage */
1211
- _bindings;
1212
- /** For internal use to create BindGroups */
1213
- _bindGroupLayout = null;
1214
- _bindGroup = null;
1166
+ _bindingsByGroup;
1167
+ _bindGroupCacheKeysByGroup = {};
1215
1168
  get [Symbol.toStringTag]() {
1216
1169
  return "WebGPURenderPipeline";
1217
1170
  }
1218
1171
  constructor(device, props) {
1219
1172
  super(device, props);
1220
1173
  this.device = device;
1174
+ this.shaderLayout ||= this.device.getShaderLayout(props.vs.source) || {
1175
+ attributes: [],
1176
+ bindings: []
1177
+ };
1221
1178
  this.handle = this.props.handle;
1179
+ let descriptor = null;
1222
1180
  if (!this.handle) {
1223
- const descriptor = this._getRenderPipelineDescriptor();
1224
- import_core10.log.groupCollapsed(1, `new WebGPURenderPipeline(${this.id})`)();
1225
- import_core10.log.probe(1, JSON.stringify(descriptor, null, 2))();
1226
- import_core10.log.groupEnd(1)();
1181
+ descriptor = this._getRenderPipelineDescriptor();
1182
+ import_core9.log.groupCollapsed(1, `new WebGPURenderPipeline(${this.id})`)();
1183
+ import_core9.log.probe(1, JSON.stringify(descriptor, null, 2))();
1184
+ import_core9.log.groupEnd(1)();
1227
1185
  this.device.pushErrorScope("validation");
1228
1186
  this.handle = this.device.handle.createRenderPipeline(descriptor);
1229
1187
  this.device.popErrorScope((error) => {
@@ -1232,10 +1190,12 @@ var __exports__ = (() => {
1232
1190
  this.device.debug();
1233
1191
  });
1234
1192
  }
1193
+ this.descriptor = descriptor;
1235
1194
  this.handle.label = this.props.id;
1236
1195
  this.vs = props.vs;
1237
1196
  this.fs = props.fs;
1238
- this._bindings = props.bindings || EMPTY_BINDINGS;
1197
+ this._bindingsByGroup = props.bindGroups || (0, import_core9.normalizeBindingsByGroup)(this.shaderLayout, props.bindings);
1198
+ this._bindGroupCacheKeysByGroup = createBindGroupCacheKeys(this._bindingsByGroup);
1239
1199
  }
1240
1200
  destroy() {
1241
1201
  this.handle = null;
@@ -1245,21 +1205,20 @@ var __exports__ = (() => {
1245
1205
  * The shared-model path passes bindings per draw and does not rely on this state.
1246
1206
  */
1247
1207
  setBindings(bindings) {
1248
- let bindingsChanged = false;
1249
- for (const [name, binding] of Object.entries(bindings)) {
1250
- if (this._bindings[name] !== binding) {
1251
- if (!bindingsChanged) {
1252
- if (this._bindings === this.props.bindings || this._bindings === EMPTY_BINDINGS) {
1253
- this._bindings = { ...this._bindings };
1208
+ const nextBindingsByGroup = (0, import_core9.normalizeBindingsByGroup)(this.shaderLayout, bindings);
1209
+ for (const [groupKey, groupBindings] of Object.entries(nextBindingsByGroup)) {
1210
+ const group = Number(groupKey);
1211
+ for (const [name, binding] of Object.entries(groupBindings || {})) {
1212
+ const currentGroupBindings = this._bindingsByGroup[group] || {};
1213
+ if (currentGroupBindings[name] !== binding) {
1214
+ if (!this._bindingsByGroup[group] || this._bindingsByGroup[group] === currentGroupBindings) {
1215
+ this._bindingsByGroup[group] = { ...currentGroupBindings };
1254
1216
  }
1255
- bindingsChanged = true;
1217
+ this._bindingsByGroup[group][name] = binding;
1218
+ this._bindGroupCacheKeysByGroup[group] = {};
1256
1219
  }
1257
- this._bindings[name] = binding;
1258
1220
  }
1259
1221
  }
1260
- if (bindingsChanged) {
1261
- this._bindGroup = null;
1262
- }
1263
1222
  }
1264
1223
  /** @todo - should this be moved to renderpass? */
1265
1224
  draw(options) {
@@ -1272,9 +1231,16 @@ var __exports__ = (() => {
1272
1231
  "${error.message}"`), this)();
1273
1232
  this.device.debug();
1274
1233
  });
1275
- const bindGroup = this._getBindGroup(options.bindings);
1276
- if (bindGroup) {
1277
- webgpuRenderPass.handle.setBindGroup(0, bindGroup);
1234
+ const hasExplicitBindings = Boolean(options.bindGroups || options.bindings);
1235
+ const bindGroups = (0, import_core9._getDefaultBindGroupFactory)(this.device).getBindGroups(
1236
+ this,
1237
+ hasExplicitBindings ? options.bindGroups || options.bindings : this._bindingsByGroup,
1238
+ hasExplicitBindings ? options._bindGroupCacheKeys : this._bindGroupCacheKeysByGroup
1239
+ );
1240
+ for (const [group, bindGroup] of Object.entries(bindGroups)) {
1241
+ if (bindGroup) {
1242
+ webgpuRenderPass.handle.setBindGroup(Number(group), bindGroup);
1243
+ }
1278
1244
  }
1279
1245
  options.vertexArray.bindBeforeRender(options.renderPass);
1280
1246
  if (options.indexCount) {
@@ -1296,17 +1262,11 @@ var __exports__ = (() => {
1296
1262
  options.vertexArray.unbindAfterRender(options.renderPass);
1297
1263
  return true;
1298
1264
  }
1299
- /** Return a bind group created by setBindings */
1300
- _getBindGroup(bindings) {
1301
- if (this.shaderLayout.bindings.length === 0) {
1302
- return null;
1303
- }
1304
- this._bindGroupLayout = this._bindGroupLayout || this.handle.getBindGroupLayout(0);
1305
- if (bindings) {
1306
- return getBindGroup(this.device, this._bindGroupLayout, this.shaderLayout, bindings);
1307
- }
1308
- this._bindGroup = this._bindGroup || getBindGroup(this.device, this._bindGroupLayout, this.shaderLayout, this._bindings);
1309
- return this._bindGroup;
1265
+ _getBindingsByGroupWebGPU() {
1266
+ return this._bindingsByGroup;
1267
+ }
1268
+ _getBindGroupCacheKeysWebGPU() {
1269
+ return this._bindGroupCacheKeysByGroup;
1310
1270
  }
1311
1271
  /**
1312
1272
  * Populate the complex WebGPU GPURenderPipelineDescriptor
@@ -1315,7 +1275,9 @@ var __exports__ = (() => {
1315
1275
  const vertex = {
1316
1276
  module: this.props.vs.handle,
1317
1277
  entryPoint: this.props.vertexEntryPoint || "main",
1318
- buffers: getVertexBufferLayout(this.shaderLayout, this.props.bufferLayout)
1278
+ buffers: getVertexBufferLayout(this.shaderLayout, this.props.bufferLayout, {
1279
+ pipelineId: this.id
1280
+ })
1319
1281
  };
1320
1282
  const targets = [];
1321
1283
  if (this.props.colorAttachmentFormats) {
@@ -1355,12 +1317,12 @@ var __exports__ = (() => {
1355
1317
  });
1356
1318
 
1357
1319
  // src/adapter/resources/webgpu-framebuffer.ts
1358
- var import_core11, WebGPUFramebuffer;
1320
+ var import_core10, WebGPUFramebuffer;
1359
1321
  var init_webgpu_framebuffer = __esm({
1360
1322
  "src/adapter/resources/webgpu-framebuffer.ts"() {
1361
1323
  "use strict";
1362
- import_core11 = __toESM(require_core(), 1);
1363
- WebGPUFramebuffer = class extends import_core11.Framebuffer {
1324
+ import_core10 = __toESM(require_core(), 1);
1325
+ WebGPUFramebuffer = class extends import_core10.Framebuffer {
1364
1326
  device;
1365
1327
  handle = null;
1366
1328
  colorAttachments = [];
@@ -1392,21 +1354,17 @@ var __exports__ = (() => {
1392
1354
  });
1393
1355
 
1394
1356
  // src/adapter/resources/webgpu-compute-pipeline.ts
1395
- var import_core12, EMPTY_BINDINGS2, WebGPUComputePipeline;
1357
+ var import_core11, EMPTY_BIND_GROUPS, WebGPUComputePipeline;
1396
1358
  var init_webgpu_compute_pipeline = __esm({
1397
1359
  "src/adapter/resources/webgpu-compute-pipeline.ts"() {
1398
1360
  "use strict";
1399
- import_core12 = __toESM(require_core(), 1);
1400
- init_get_bind_group();
1401
- EMPTY_BINDINGS2 = {};
1402
- WebGPUComputePipeline = class extends import_core12.ComputePipeline {
1361
+ import_core11 = __toESM(require_core(), 1);
1362
+ EMPTY_BIND_GROUPS = {};
1363
+ WebGPUComputePipeline = class extends import_core11.ComputePipeline {
1403
1364
  device;
1404
1365
  handle;
1405
- /** For internal use to create BindGroups */
1406
- _bindGroupLayout = null;
1407
- _bindGroup = null;
1408
- /** For internal use to create BindGroups */
1409
- _bindings;
1366
+ _bindingsByGroup;
1367
+ _bindGroupCacheKeysByGroup;
1410
1368
  constructor(device, props) {
1411
1369
  super(device, props);
1412
1370
  this.device = device;
@@ -1420,34 +1378,42 @@ var __exports__ = (() => {
1420
1378
  },
1421
1379
  layout: "auto"
1422
1380
  });
1423
- this._bindings = EMPTY_BINDINGS2;
1381
+ this._bindingsByGroup = EMPTY_BIND_GROUPS;
1382
+ this._bindGroupCacheKeysByGroup = {};
1424
1383
  }
1425
1384
  /**
1426
1385
  * @todo Use renderpass.setBindings() ?
1427
1386
  * @todo Do we want to expose BindGroups in the API and remove this?
1428
1387
  */
1429
1388
  setBindings(bindings) {
1430
- let bindingsChanged = false;
1431
- for (const [name, binding] of Object.entries(bindings)) {
1432
- if (this._bindings[name] !== binding) {
1433
- if (!bindingsChanged) {
1434
- if (this._bindings === EMPTY_BINDINGS2) {
1435
- this._bindings = {};
1389
+ const nextBindingsByGroup = (0, import_core11.normalizeBindingsByGroup)(this.shaderLayout, bindings);
1390
+ for (const [groupKey, groupBindings] of Object.entries(nextBindingsByGroup)) {
1391
+ const group = Number(groupKey);
1392
+ for (const [name, binding] of Object.entries(groupBindings || {})) {
1393
+ const currentGroupBindings = this._bindingsByGroup[group] || {};
1394
+ if (currentGroupBindings[name] !== binding) {
1395
+ if (!this._bindingsByGroup[group] || this._bindingsByGroup[group] === currentGroupBindings) {
1396
+ this._bindingsByGroup[group] = { ...currentGroupBindings };
1436
1397
  }
1437
- bindingsChanged = true;
1398
+ this._bindingsByGroup[group][name] = binding;
1399
+ this._bindGroupCacheKeysByGroup[group] = {};
1438
1400
  }
1439
- this._bindings[name] = binding;
1440
1401
  }
1441
1402
  }
1442
- if (bindingsChanged) {
1443
- this._bindGroup = null;
1444
- }
1445
1403
  }
1446
- /** Return a bind group created by setBindings */
1447
- _getBindGroup() {
1448
- this._bindGroupLayout = this._bindGroupLayout || this.handle.getBindGroupLayout(0);
1449
- this._bindGroup = this._bindGroup || getBindGroup(this.device, this._bindGroupLayout, this.shaderLayout, this._bindings);
1450
- return this._bindGroup;
1404
+ _getBindGroups(bindings, bindGroupCacheKeys) {
1405
+ const hasExplicitBindings = Boolean(bindings);
1406
+ return (0, import_core11._getDefaultBindGroupFactory)(this.device).getBindGroups(
1407
+ this,
1408
+ hasExplicitBindings ? bindings : this._bindingsByGroup,
1409
+ hasExplicitBindings ? bindGroupCacheKeys : this._bindGroupCacheKeysByGroup
1410
+ );
1411
+ }
1412
+ _getBindingsByGroupWebGPU() {
1413
+ return this._bindingsByGroup;
1414
+ }
1415
+ _getBindGroupCacheKeysWebGPU() {
1416
+ return this._bindGroupCacheKeysByGroup;
1451
1417
  }
1452
1418
  };
1453
1419
  }
@@ -1534,13 +1500,13 @@ var __exports__ = (() => {
1534
1500
  });
1535
1501
 
1536
1502
  // src/adapter/resources/webgpu-vertex-array.ts
1537
- var import_core13, WebGPUVertexArray;
1503
+ var import_core12, WebGPUVertexArray;
1538
1504
  var init_webgpu_vertex_array = __esm({
1539
1505
  "src/adapter/resources/webgpu-vertex-array.ts"() {
1540
1506
  "use strict";
1541
- import_core13 = __toESM(require_core(), 1);
1507
+ import_core12 = __toESM(require_core(), 1);
1542
1508
  init_dist();
1543
- WebGPUVertexArray = class extends import_core13.VertexArray {
1509
+ WebGPUVertexArray = class extends import_core12.VertexArray {
1544
1510
  get [Symbol.toStringTag]() {
1545
1511
  return "VertexArray";
1546
1512
  }
@@ -1569,7 +1535,7 @@ var __exports__ = (() => {
1569
1535
  const webgpuRenderPass = renderPass;
1570
1536
  const webgpuIndexBuffer = this.indexBuffer;
1571
1537
  if (webgpuIndexBuffer?.handle) {
1572
- import_core13.log.info(
1538
+ import_core12.log.info(
1573
1539
  3,
1574
1540
  "setting index buffer",
1575
1541
  webgpuIndexBuffer?.handle,
@@ -1584,7 +1550,7 @@ var __exports__ = (() => {
1584
1550
  for (let location = 0; location < this.maxVertexAttributes; location++) {
1585
1551
  const webgpuBuffer = this.attributes[location];
1586
1552
  if (webgpuBuffer?.handle) {
1587
- import_core13.log.info(3, `setting vertex buffer ${location}`, webgpuBuffer?.handle)();
1553
+ import_core12.log.info(3, `setting vertex buffer ${location}`, webgpuBuffer?.handle)();
1588
1554
  webgpuRenderPass.handle.setVertexBuffer(location, webgpuBuffer?.handle);
1589
1555
  }
1590
1556
  }
@@ -1604,14 +1570,14 @@ var __exports__ = (() => {
1604
1570
  });
1605
1571
 
1606
1572
  // src/adapter/webgpu-canvas-context.ts
1607
- var import_core14, WebGPUCanvasContext;
1573
+ var import_core13, WebGPUCanvasContext;
1608
1574
  var init_webgpu_canvas_context = __esm({
1609
1575
  "src/adapter/webgpu-canvas-context.ts"() {
1610
1576
  "use strict";
1611
- import_core14 = __toESM(require_core(), 1);
1577
+ import_core13 = __toESM(require_core(), 1);
1612
1578
  init_webgpu_framebuffer();
1613
1579
  init_cpu_hotspot_profiler();
1614
- WebGPUCanvasContext = class extends import_core14.CanvasContext {
1580
+ WebGPUCanvasContext = class extends import_core13.CanvasContext {
1615
1581
  device;
1616
1582
  handle;
1617
1583
  colorAttachment = null;
@@ -1682,7 +1648,7 @@ var __exports__ = (() => {
1682
1648
  const [oldWidth, oldHeight] = this.getDrawingBufferSize();
1683
1649
  this.drawingBufferWidth = currentColorAttachment.width;
1684
1650
  this.drawingBufferHeight = currentColorAttachment.height;
1685
- import_core14.log.log(
1651
+ import_core13.log.log(
1686
1652
  1,
1687
1653
  `${this}: Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`
1688
1654
  )();
@@ -1742,7 +1708,7 @@ var __exports__ = (() => {
1742
1708
  this.depthStencilAttachment?.destroy();
1743
1709
  this.depthStencilAttachment = this.device.createTexture({
1744
1710
  id: `${this.id}#depth-stencil-texture`,
1745
- usage: import_core14.Texture.RENDER_ATTACHMENT,
1711
+ usage: import_core13.Texture.RENDER_ATTACHMENT,
1746
1712
  format: depthStencilFormat,
1747
1713
  width: this.drawingBufferWidth,
1748
1714
  height: this.drawingBufferHeight
@@ -1755,14 +1721,14 @@ var __exports__ = (() => {
1755
1721
  });
1756
1722
 
1757
1723
  // src/adapter/webgpu-presentation-context.ts
1758
- var import_core15, WebGPUPresentationContext;
1724
+ var import_core14, WebGPUPresentationContext;
1759
1725
  var init_webgpu_presentation_context = __esm({
1760
1726
  "src/adapter/webgpu-presentation-context.ts"() {
1761
1727
  "use strict";
1762
- import_core15 = __toESM(require_core(), 1);
1728
+ import_core14 = __toESM(require_core(), 1);
1763
1729
  init_webgpu_framebuffer();
1764
1730
  init_cpu_hotspot_profiler();
1765
- WebGPUPresentationContext = class extends import_core15.PresentationContext {
1731
+ WebGPUPresentationContext = class extends import_core14.PresentationContext {
1766
1732
  device;
1767
1733
  handle;
1768
1734
  colorAttachment = null;
@@ -1830,7 +1796,7 @@ var __exports__ = (() => {
1830
1796
  const [oldWidth, oldHeight] = this.getDrawingBufferSize();
1831
1797
  this.drawingBufferWidth = currentColorAttachment.width;
1832
1798
  this.drawingBufferHeight = currentColorAttachment.height;
1833
- import_core15.log.log(
1799
+ import_core14.log.log(
1834
1800
  1,
1835
1801
  `${this[Symbol.toStringTag]}(${this.id}): Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`
1836
1802
  )();
@@ -1886,7 +1852,7 @@ var __exports__ = (() => {
1886
1852
  this.depthStencilAttachment?.destroy();
1887
1853
  this.depthStencilAttachment = this.device.createTexture({
1888
1854
  id: `${this.id}#depth-stencil-texture`,
1889
- usage: import_core15.Texture.RENDER_ATTACHMENT,
1855
+ usage: import_core14.Texture.RENDER_ATTACHMENT,
1890
1856
  format: depthStencilFormat,
1891
1857
  width: this.drawingBufferWidth,
1892
1858
  height: this.drawingBufferHeight
@@ -1899,12 +1865,12 @@ var __exports__ = (() => {
1899
1865
  });
1900
1866
 
1901
1867
  // src/adapter/resources/webgpu-command-buffer.ts
1902
- var import_core16, WebGPUCommandBuffer;
1868
+ var import_core15, WebGPUCommandBuffer;
1903
1869
  var init_webgpu_command_buffer = __esm({
1904
1870
  "src/adapter/resources/webgpu-command-buffer.ts"() {
1905
1871
  "use strict";
1906
- import_core16 = __toESM(require_core(), 1);
1907
- WebGPUCommandBuffer = class extends import_core16.CommandBuffer {
1872
+ import_core15 = __toESM(require_core(), 1);
1873
+ WebGPUCommandBuffer = class extends import_core15.CommandBuffer {
1908
1874
  device;
1909
1875
  handle;
1910
1876
  constructor(commandEncoder, props) {
@@ -1922,13 +1888,13 @@ var __exports__ = (() => {
1922
1888
  function convertColor(color) {
1923
1889
  return { r: color[0], g: color[1], b: color[2], a: color[3] };
1924
1890
  }
1925
- var import_core17, WebGPURenderPass;
1891
+ var import_core16, WebGPURenderPass;
1926
1892
  var init_webgpu_render_pass = __esm({
1927
1893
  "src/adapter/resources/webgpu-render-pass.ts"() {
1928
1894
  "use strict";
1929
- import_core17 = __toESM(require_core(), 1);
1895
+ import_core16 = __toESM(require_core(), 1);
1930
1896
  init_cpu_hotspot_profiler();
1931
- WebGPURenderPass = class extends import_core17.RenderPass {
1897
+ WebGPURenderPass = class extends import_core16.RenderPass {
1932
1898
  device;
1933
1899
  handle;
1934
1900
  framebuffer;
@@ -1936,7 +1902,7 @@ var __exports__ = (() => {
1936
1902
  pipeline = null;
1937
1903
  /** Latest bindings applied to this pass */
1938
1904
  bindings = {};
1939
- constructor(device, props = {}) {
1905
+ constructor(device, props = {}, commandEncoder = device.commandEncoder.handle) {
1940
1906
  super(device, props);
1941
1907
  this.device = device;
1942
1908
  const { props: renderPassProps } = this;
@@ -1966,12 +1932,9 @@ var __exports__ = (() => {
1966
1932
  profiler.renderPassDescriptorAssemblyCount = (profiler.renderPassDescriptorAssemblyCount || 0) + 1;
1967
1933
  profiler.renderPassDescriptorAssemblyTimeMs = (profiler.renderPassDescriptorAssemblyTimeMs || 0) + (getTimestamp() - descriptorAssemblyStartTime);
1968
1934
  }
1969
- if (!device.commandEncoder) {
1970
- throw new Error("commandEncoder not available");
1971
- }
1972
1935
  this.device.pushErrorScope("validation");
1973
1936
  const beginRenderPassStartTime = profiler ? getTimestamp() : 0;
1974
- this.handle = this.props.handle || device.commandEncoder.handle.beginRenderPass(renderPassDescriptor);
1937
+ this.handle = this.props.handle || commandEncoder.beginRenderPass(renderPassDescriptor);
1975
1938
  if (profiler) {
1976
1939
  profiler.renderPassBeginCount = (profiler.renderPassBeginCount || 0) + 1;
1977
1940
  profiler.renderPassBeginTimeMs = (profiler.renderPassBeginTimeMs || 0) + (getTimestamp() - beginRenderPassStartTime);
@@ -1982,9 +1945,9 @@ var __exports__ = (() => {
1982
1945
  this.device.debug();
1983
1946
  });
1984
1947
  this.handle.label = this.props.id;
1985
- import_core17.log.groupCollapsed(3, `new WebGPURenderPass(${this.id})`)();
1986
- import_core17.log.probe(3, JSON.stringify(renderPassDescriptor, null, 2))();
1987
- import_core17.log.groupEnd(3)();
1948
+ import_core16.log.groupCollapsed(3, `new WebGPURenderPass(${this.id})`)();
1949
+ import_core16.log.probe(3, JSON.stringify(renderPassDescriptor, null, 2))();
1950
+ import_core16.log.groupEnd(3)();
1988
1951
  } finally {
1989
1952
  if (profiler) {
1990
1953
  profiler.renderPassSetupCount = (profiler.renderPassSetupCount || 0) + 1;
@@ -2015,9 +1978,11 @@ var __exports__ = (() => {
2015
1978
  /** Sets an array of bindings (uniform buffers, samplers, textures, ...) */
2016
1979
  setBindings(bindings) {
2017
1980
  this.bindings = bindings;
2018
- const bindGroup = this.pipeline?._getBindGroup(bindings);
2019
- if (bindGroup) {
2020
- this.handle.setBindGroup(0, bindGroup);
1981
+ const bindGroups = this.pipeline && (0, import_core16._getDefaultBindGroupFactory)(this.device).getBindGroups(this.pipeline, bindings) || {};
1982
+ for (const [group, bindGroup] of Object.entries(bindGroups)) {
1983
+ if (bindGroup) {
1984
+ this.handle.setBindGroup(Number(group), bindGroup);
1985
+ }
2021
1986
  }
2022
1987
  }
2023
1988
  setIndexBuffer(buffer, indexFormat, offset = 0, size) {
@@ -2098,7 +2063,7 @@ var __exports__ = (() => {
2098
2063
  // clear values
2099
2064
  loadOp: this.props.clearColor !== false ? "clear" : "load",
2100
2065
  clearValue: convertColor(
2101
- this.props.clearColors?.[index] || this.props.clearColor || import_core17.RenderPass.defaultClearColor
2066
+ this.props.clearColors?.[index] || this.props.clearColor || import_core16.RenderPass.defaultClearColor
2102
2067
  ),
2103
2068
  storeOp: this.props.discard ? "discard" : "store",
2104
2069
  // ...colorAttachment,
@@ -2134,16 +2099,16 @@ var __exports__ = (() => {
2134
2099
  });
2135
2100
 
2136
2101
  // src/adapter/resources/webgpu-compute-pass.ts
2137
- var import_core18, WebGPUComputePass;
2102
+ var import_core17, WebGPUComputePass;
2138
2103
  var init_webgpu_compute_pass = __esm({
2139
2104
  "src/adapter/resources/webgpu-compute-pass.ts"() {
2140
2105
  "use strict";
2141
- import_core18 = __toESM(require_core(), 1);
2142
- WebGPUComputePass = class extends import_core18.ComputePass {
2106
+ import_core17 = __toESM(require_core(), 1);
2107
+ WebGPUComputePass = class extends import_core17.ComputePass {
2143
2108
  device;
2144
2109
  handle;
2145
2110
  _webgpuPipeline = null;
2146
- constructor(device, props = {}) {
2111
+ constructor(device, props = {}, commandEncoder = device.commandEncoder.handle) {
2147
2112
  super(device, props);
2148
2113
  this.device = device;
2149
2114
  const { props: computePassProps } = this;
@@ -2159,7 +2124,7 @@ var __exports__ = (() => {
2159
2124
  };
2160
2125
  }
2161
2126
  }
2162
- this.handle = this.props.handle || device.commandEncoder.handle.beginComputePass({
2127
+ this.handle = this.props.handle || commandEncoder.beginComputePass({
2163
2128
  label: this.props.id,
2164
2129
  timestampWrites
2165
2130
  });
@@ -2179,15 +2144,28 @@ var __exports__ = (() => {
2179
2144
  const wgpuPipeline = pipeline;
2180
2145
  this.handle.setPipeline(wgpuPipeline.handle);
2181
2146
  this._webgpuPipeline = wgpuPipeline;
2182
- this.setBindings([]);
2147
+ const bindGroups = (0, import_core17._getDefaultBindGroupFactory)(this.device).getBindGroups(
2148
+ this._webgpuPipeline,
2149
+ this._webgpuPipeline._getBindingsByGroupWebGPU(),
2150
+ this._webgpuPipeline._getBindGroupCacheKeysWebGPU()
2151
+ );
2152
+ for (const [group, bindGroup] of Object.entries(bindGroups)) {
2153
+ if (bindGroup) {
2154
+ this.handle.setBindGroup(Number(group), bindGroup);
2155
+ }
2156
+ }
2183
2157
  }
2184
2158
  /**
2185
2159
  * Sets an array of bindings (uniform buffers, samplers, textures, ...)
2186
2160
  * TODO - still some API confusion - does this method go here or on the pipeline?
2187
2161
  */
2188
2162
  setBindings(bindings) {
2189
- const bindGroup = this._webgpuPipeline._getBindGroup();
2190
- this.handle.setBindGroup(0, bindGroup);
2163
+ const bindGroups = this._webgpuPipeline && (0, import_core17._getDefaultBindGroupFactory)(this.device).getBindGroups(this._webgpuPipeline, bindings) || {};
2164
+ for (const [group, bindGroup] of Object.entries(bindGroups)) {
2165
+ if (bindGroup) {
2166
+ this.handle.setBindGroup(Number(group), bindGroup);
2167
+ }
2168
+ }
2191
2169
  }
2192
2170
  /**
2193
2171
  * Dispatch work to be performed with the current ComputePipeline.
@@ -2223,15 +2201,15 @@ var __exports__ = (() => {
2223
2201
  });
2224
2202
 
2225
2203
  // src/adapter/resources/webgpu-command-encoder.ts
2226
- var import_core19, WebGPUCommandEncoder;
2204
+ var import_core18, WebGPUCommandEncoder;
2227
2205
  var init_webgpu_command_encoder = __esm({
2228
2206
  "src/adapter/resources/webgpu-command-encoder.ts"() {
2229
2207
  "use strict";
2230
- import_core19 = __toESM(require_core(), 1);
2208
+ import_core18 = __toESM(require_core(), 1);
2231
2209
  init_webgpu_command_buffer();
2232
2210
  init_webgpu_render_pass();
2233
2211
  init_webgpu_compute_pass();
2234
- WebGPUCommandEncoder = class extends import_core19.CommandEncoder {
2212
+ WebGPUCommandEncoder = class extends import_core18.CommandEncoder {
2235
2213
  device;
2236
2214
  handle;
2237
2215
  constructor(device, props = {}) {
@@ -2265,51 +2243,132 @@ var __exports__ = (() => {
2265
2243
  * @todo need to support a "Framebuffer" equivalent (aka preconfigured RenderPassDescriptors?).
2266
2244
  */
2267
2245
  beginRenderPass(props = {}) {
2268
- return new WebGPURenderPass(this.device, this._applyTimeProfilingToPassProps(props));
2246
+ return new WebGPURenderPass(
2247
+ this.device,
2248
+ this._applyTimeProfilingToPassProps(props),
2249
+ this.handle
2250
+ );
2269
2251
  }
2270
2252
  beginComputePass(props = {}) {
2271
- return new WebGPUComputePass(this.device, this._applyTimeProfilingToPassProps(props));
2253
+ return new WebGPUComputePass(
2254
+ this.device,
2255
+ this._applyTimeProfilingToPassProps(props),
2256
+ this.handle
2257
+ );
2272
2258
  }
2273
2259
  // beginRenderPass(GPURenderPassDescriptor descriptor): GPURenderPassEncoder;
2274
2260
  // beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
2275
2261
  copyBufferToBuffer(options) {
2276
2262
  const webgpuSourceBuffer = options.sourceBuffer;
2277
- const WebGPUDestinationBuffer = options.destinationBuffer;
2263
+ const webgpuDestinationBuffer = options.destinationBuffer;
2278
2264
  this.handle.copyBufferToBuffer(
2279
2265
  webgpuSourceBuffer.handle,
2280
2266
  options.sourceOffset ?? 0,
2281
- WebGPUDestinationBuffer.handle,
2267
+ webgpuDestinationBuffer.handle,
2282
2268
  options.destinationOffset ?? 0,
2283
2269
  options.size ?? 0
2284
2270
  );
2285
2271
  }
2286
2272
  copyBufferToTexture(options) {
2287
2273
  const webgpuSourceBuffer = options.sourceBuffer;
2288
- const WebGPUDestinationTexture = options.destinationTexture;
2274
+ const webgpuDestinationTexture = options.destinationTexture;
2275
+ const copyOrigin = options.origin ?? [0, 0, 0];
2276
+ const copySize = options.size;
2289
2277
  this.handle.copyBufferToTexture(
2290
2278
  {
2291
2279
  buffer: webgpuSourceBuffer.handle,
2292
- offset: options.offset ?? 0,
2280
+ offset: options.byteOffset ?? 0,
2293
2281
  bytesPerRow: options.bytesPerRow,
2294
2282
  rowsPerImage: options.rowsPerImage
2295
2283
  },
2296
2284
  {
2297
- texture: WebGPUDestinationTexture.handle,
2285
+ texture: webgpuDestinationTexture.handle,
2298
2286
  mipLevel: options.mipLevel ?? 0,
2299
- origin: options.origin ?? {}
2300
- // aspect: options.aspect
2287
+ origin: {
2288
+ x: copyOrigin[0] ?? 0,
2289
+ y: copyOrigin[1] ?? 0,
2290
+ z: copyOrigin[2] ?? 0
2291
+ },
2292
+ aspect: options.aspect
2301
2293
  },
2302
2294
  {
2303
- // @ts-ignore
2304
- width: options.extent?.[0],
2305
- height: options.extent?.[1],
2306
- depthOrArrayLayers: options.extent?.[2]
2295
+ width: copySize[0],
2296
+ height: copySize[1],
2297
+ depthOrArrayLayers: copySize[2]
2307
2298
  }
2308
2299
  );
2309
2300
  }
2310
2301
  copyTextureToBuffer(options) {
2302
+ const {
2303
+ sourceTexture,
2304
+ destinationBuffer,
2305
+ origin = [0, 0, 0],
2306
+ byteOffset = 0,
2307
+ width,
2308
+ height,
2309
+ depthOrArrayLayers,
2310
+ mipLevel,
2311
+ aspect
2312
+ } = options;
2313
+ const webgpuSourceTexture = sourceTexture;
2314
+ webgpuSourceTexture.copyToBuffer(
2315
+ this.handle,
2316
+ {
2317
+ x: origin[0] ?? 0,
2318
+ y: origin[1] ?? 0,
2319
+ z: origin[2] ?? 0,
2320
+ width,
2321
+ height,
2322
+ depthOrArrayLayers,
2323
+ mipLevel,
2324
+ aspect,
2325
+ byteOffset,
2326
+ bytesPerRow: options.bytesPerRow,
2327
+ rowsPerImage: options.rowsPerImage
2328
+ },
2329
+ destinationBuffer
2330
+ );
2311
2331
  }
2312
2332
  copyTextureToTexture(options) {
2333
+ const webgpuSourceTexture = options.sourceTexture;
2334
+ const webgpuDestinationTexture = options.destinationTexture;
2335
+ const sourceRegion = webgpuSourceTexture._normalizeTextureReadOptions({
2336
+ x: options.origin?.[0] ?? 0,
2337
+ y: options.origin?.[1] ?? 0,
2338
+ z: options.origin?.[2] ?? 0,
2339
+ width: options.width,
2340
+ height: options.height,
2341
+ depthOrArrayLayers: options.depthOrArrayLayers,
2342
+ mipLevel: options.mipLevel ?? 0,
2343
+ aspect: options.aspect ?? "all"
2344
+ });
2345
+ this.handle.copyTextureToTexture(
2346
+ {
2347
+ texture: webgpuSourceTexture.handle,
2348
+ mipLevel: sourceRegion.mipLevel,
2349
+ origin: {
2350
+ x: sourceRegion.x,
2351
+ y: sourceRegion.y,
2352
+ z: sourceRegion.z
2353
+ },
2354
+ aspect: sourceRegion.aspect
2355
+ },
2356
+ {
2357
+ texture: webgpuDestinationTexture.handle,
2358
+ mipLevel: options.destinationMipLevel ?? 0,
2359
+ origin: {
2360
+ x: options.destinationOrigin?.[0] ?? 0,
2361
+ y: options.destinationOrigin?.[1] ?? 0,
2362
+ z: options.destinationOrigin?.[2] ?? 0
2363
+ },
2364
+ aspect: options.destinationAspect ?? sourceRegion.aspect
2365
+ },
2366
+ {
2367
+ width: sourceRegion.width,
2368
+ height: sourceRegion.height,
2369
+ depthOrArrayLayers: sourceRegion.depthOrArrayLayers
2370
+ }
2371
+ );
2313
2372
  }
2314
2373
  pushDebugGroup(groupLabel) {
2315
2374
  this.handle.pushDebugGroup(groupLabel);
@@ -2351,13 +2410,13 @@ var __exports__ = (() => {
2351
2410
  });
2352
2411
 
2353
2412
  // src/adapter/resources/webgpu-query-set.ts
2354
- var import_core20, WebGPUQuerySet;
2413
+ var import_core19, WebGPUQuerySet;
2355
2414
  var init_webgpu_query_set = __esm({
2356
2415
  "src/adapter/resources/webgpu-query-set.ts"() {
2357
2416
  "use strict";
2358
- import_core20 = __toESM(require_core(), 1);
2417
+ import_core19 = __toESM(require_core(), 1);
2359
2418
  init_cpu_hotspot_profiler();
2360
- WebGPUQuerySet = class extends import_core20.QuerySet {
2419
+ WebGPUQuerySet = class extends import_core19.QuerySet {
2361
2420
  device;
2362
2421
  handle;
2363
2422
  _resolveBuffer = null;
@@ -2465,13 +2524,13 @@ var __exports__ = (() => {
2465
2524
  const byteLength = this.props.count * 8;
2466
2525
  this._resolveBuffer = this.device.createBuffer({
2467
2526
  id: `${this.id}-resolve-buffer`,
2468
- usage: import_core20.Buffer.QUERY_RESOLVE | import_core20.Buffer.COPY_SRC,
2527
+ usage: import_core19.Buffer.QUERY_RESOLVE | import_core19.Buffer.COPY_SRC,
2469
2528
  byteLength
2470
2529
  });
2471
2530
  this.attachResource(this._resolveBuffer);
2472
2531
  this._readBuffer = this.device.createBuffer({
2473
2532
  id: `${this.id}-read-buffer`,
2474
- usage: import_core20.Buffer.COPY_DST | import_core20.Buffer.MAP_READ,
2533
+ usage: import_core19.Buffer.COPY_DST | import_core19.Buffer.MAP_READ,
2475
2534
  byteLength
2476
2535
  });
2477
2536
  this.attachResource(this._readBuffer);
@@ -2508,36 +2567,40 @@ var __exports__ = (() => {
2508
2567
  });
2509
2568
 
2510
2569
  // src/adapter/resources/webgpu-pipeline-layout.ts
2511
- var import_core21, WebGPUPipelineLayout, isStorageTextureBindingLayout;
2570
+ var import_core20, WebGPUPipelineLayout, isStorageTextureBindingLayout;
2512
2571
  var init_webgpu_pipeline_layout = __esm({
2513
2572
  "src/adapter/resources/webgpu-pipeline-layout.ts"() {
2514
2573
  "use strict";
2515
- import_core21 = __toESM(require_core(), 1);
2516
- WebGPUPipelineLayout = class extends import_core21.PipelineLayout {
2574
+ import_core20 = __toESM(require_core(), 1);
2575
+ WebGPUPipelineLayout = class extends import_core20.PipelineLayout {
2517
2576
  device;
2518
2577
  handle;
2519
2578
  constructor(device, props) {
2520
2579
  super(device, props);
2521
2580
  this.device = device;
2522
- const bindGroupEntries = this.mapShaderLayoutToBindGroupEntries();
2581
+ const bindGroupEntriesByGroup = this.mapShaderLayoutToBindGroupEntriesByGroup();
2523
2582
  this.handle = this.device.handle.createPipelineLayout({
2524
2583
  label: props?.id ?? "unnamed-pipeline-layout",
2525
- bindGroupLayouts: [
2526
- // TODO (kaapp): We can cache these to re-use them across
2527
- // layers, particularly if using a separate group for injected
2528
- // bindings (e.g. project/lighting)
2529
- this.device.handle.createBindGroupLayout({
2530
- label: "bind-group-layout",
2531
- entries: bindGroupEntries
2584
+ bindGroupLayouts: bindGroupEntriesByGroup.map(
2585
+ (entries, group) => this.device.handle.createBindGroupLayout({
2586
+ label: `bind-group-layout-${group}`,
2587
+ entries
2532
2588
  })
2533
- ]
2589
+ )
2534
2590
  });
2535
2591
  }
2536
2592
  destroy() {
2537
2593
  this.handle = null;
2538
2594
  }
2539
- mapShaderLayoutToBindGroupEntries() {
2540
- const bindGroupEntries = [];
2595
+ mapShaderLayoutToBindGroupEntriesByGroup() {
2596
+ const maxGroup = this.props.shaderLayout.bindings.reduce(
2597
+ (highestGroup, binding) => Math.max(highestGroup, binding.group),
2598
+ -1
2599
+ );
2600
+ const bindGroupEntriesByGroup = Array.from(
2601
+ { length: maxGroup + 1 },
2602
+ () => []
2603
+ );
2541
2604
  for (const binding of this.props.shaderLayout.bindings) {
2542
2605
  const bindingTypeInfo = {};
2543
2606
  switch (binding.type) {
@@ -2590,17 +2653,17 @@ var __exports__ = (() => {
2590
2653
  break;
2591
2654
  }
2592
2655
  default: {
2593
- import_core21.log.warn("unhandled binding type when creating pipeline descriptor")();
2656
+ import_core20.log.warn("unhandled binding type when creating pipeline descriptor")();
2594
2657
  }
2595
2658
  }
2596
2659
  const VISIBILITY_ALL = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE;
2597
- bindGroupEntries.push({
2660
+ bindGroupEntriesByGroup[binding.group].push({
2598
2661
  binding: binding.location,
2599
2662
  visibility: binding.visibility || VISIBILITY_ALL,
2600
2663
  ...bindingTypeInfo
2601
2664
  });
2602
2665
  }
2603
- return bindGroupEntries;
2666
+ return bindGroupEntriesByGroup;
2604
2667
  }
2605
2668
  };
2606
2669
  isStorageTextureBindingLayout = (maybe) => {
@@ -2610,12 +2673,12 @@ var __exports__ = (() => {
2610
2673
  });
2611
2674
 
2612
2675
  // src/adapter/resources/webgpu-fence.ts
2613
- var import_core22, WebGPUFence;
2676
+ var import_core21, WebGPUFence;
2614
2677
  var init_webgpu_fence = __esm({
2615
2678
  "src/adapter/resources/webgpu-fence.ts"() {
2616
2679
  "use strict";
2617
- import_core22 = __toESM(require_core(), 1);
2618
- WebGPUFence = class extends import_core22.Fence {
2680
+ import_core21 = __toESM(require_core(), 1);
2681
+ WebGPUFence = class extends import_core21.Fence {
2619
2682
  device;
2620
2683
  handle = null;
2621
2684
  signaled;
@@ -2625,6 +2688,11 @@ var __exports__ = (() => {
2625
2688
  this.device = device;
2626
2689
  this.signaled = device.handle.queue.onSubmittedWorkDone().then(() => {
2627
2690
  this._signaled = true;
2691
+ }).catch((error) => {
2692
+ if (this.device.shouldIgnoreDroppedInstanceError(error)) {
2693
+ return;
2694
+ }
2695
+ throw error;
2628
2696
  });
2629
2697
  }
2630
2698
  isSignaled() {
@@ -8590,7 +8658,7 @@ var __exports__ = (() => {
8590
8658
  try {
8591
8659
  parsedWGSL = parseWGSL(source);
8592
8660
  } catch (error) {
8593
- import_core23.log.error(error.message)();
8661
+ import_core22.log.error(error.message)();
8594
8662
  return shaderLayout;
8595
8663
  }
8596
8664
  for (const uniform of parsedWGSL.uniforms) {
@@ -8610,6 +8678,14 @@ var __exports__ = (() => {
8610
8678
  members
8611
8679
  });
8612
8680
  }
8681
+ for (const storageBuffer of parsedWGSL.storage) {
8682
+ shaderLayout.bindings.push({
8683
+ type: storageBuffer.access === "read" ? "read-only-storage" : "storage",
8684
+ name: storageBuffer.name,
8685
+ group: storageBuffer.group,
8686
+ location: storageBuffer.binding
8687
+ });
8688
+ }
8613
8689
  for (const texture of parsedWGSL.textures) {
8614
8690
  const bindingDeclaration = {
8615
8691
  type: "texture",
@@ -8683,11 +8759,11 @@ var __exports__ = (() => {
8683
8759
  }
8684
8760
  return { viewDimension, sampleType, multisampled };
8685
8761
  }
8686
- var import_core23;
8762
+ var import_core22;
8687
8763
  var init_get_shader_layout_wgsl = __esm({
8688
8764
  "src/wgsl/get-shader-layout-wgsl.ts"() {
8689
8765
  "use strict";
8690
- import_core23 = __toESM(require_core(), 1);
8766
+ import_core22 = __toESM(require_core(), 1);
8691
8767
  init_wgsl_reflect_module();
8692
8768
  }
8693
8769
  });
@@ -8721,7 +8797,7 @@ var __exports__ = (() => {
8721
8797
  const sampler = device.createSampler({ minFilter: "linear", magFilter: "linear" });
8722
8798
  const uniformsBuffer = device.createBuffer({
8723
8799
  byteLength: 16,
8724
- usage: import_core24.Buffer.UNIFORM | import_core24.Buffer.COPY_DST
8800
+ usage: import_core23.Buffer.UNIFORM | import_core23.Buffer.COPY_DST
8725
8801
  });
8726
8802
  const uniformValues = new Uint32Array(1);
8727
8803
  const sourceTextureLayout = {
@@ -8839,7 +8915,7 @@ var __exports__ = (() => {
8839
8915
  }
8840
8916
  }
8841
8917
  function getColorAttachmentFormat(format, path, dimension) {
8842
- if (import_core24.textureFormatDecoder.isColor(format)) {
8918
+ if (import_core23.textureFormatDecoder.isColor(format)) {
8843
8919
  return format;
8844
8920
  }
8845
8921
  throw new Error(
@@ -8875,7 +8951,7 @@ var __exports__ = (() => {
8875
8951
  });
8876
8952
  const uniformsBuffer = device.createBuffer({
8877
8953
  byteLength: 32,
8878
- usage: import_core24.Buffer.UNIFORM | import_core24.Buffer.COPY_DST
8954
+ usage: import_core23.Buffer.UNIFORM | import_core23.Buffer.COPY_DST
8879
8955
  });
8880
8956
  const uniformValues = new Uint32Array(8);
8881
8957
  let sourceWidth = texture.width;
@@ -9144,11 +9220,11 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
9144
9220
  }
9145
9221
  `;
9146
9222
  }
9147
- var import_core24, RENDER_DIMENSIONS, WORKGROUP_SIZE, RENDER_SOURCE_SAMPLER_LAYOUT, COMPUTE_SOURCE_TEXTURE_LAYOUT, COMPUTE_UNIFORMS_LAYOUT;
9223
+ var import_core23, RENDER_DIMENSIONS, WORKGROUP_SIZE, RENDER_SOURCE_SAMPLER_LAYOUT, COMPUTE_SOURCE_TEXTURE_LAYOUT, COMPUTE_UNIFORMS_LAYOUT;
9148
9224
  var init_generate_mipmaps_webgpu = __esm({
9149
9225
  "src/adapter/helpers/generate-mipmaps-webgpu.ts"() {
9150
9226
  "use strict";
9151
- import_core24 = __toESM(require_core(), 1);
9227
+ import_core23 = __toESM(require_core(), 1);
9152
9228
  RENDER_DIMENSIONS = [
9153
9229
  "2d",
9154
9230
  "2d-array",
@@ -9183,6 +9259,90 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
9183
9259
  }
9184
9260
  });
9185
9261
 
9262
+ // src/adapter/helpers/get-bind-group.ts
9263
+ function getBindGroup(device, bindGroupLayout, shaderLayout, bindings, group) {
9264
+ const entries = getBindGroupEntries(bindings, shaderLayout, group);
9265
+ if (entries.length === 0) {
9266
+ return null;
9267
+ }
9268
+ device.pushErrorScope("validation");
9269
+ const bindGroup = device.handle.createBindGroup({
9270
+ layout: bindGroupLayout,
9271
+ entries
9272
+ });
9273
+ device.popErrorScope((error) => {
9274
+ import_core24.log.error(`bindGroup creation: ${error.message}`, bindGroup)();
9275
+ });
9276
+ return bindGroup;
9277
+ }
9278
+ function getBindGroupEntries(bindings, shaderLayout, group) {
9279
+ const entries = [];
9280
+ for (const [bindingName, value] of Object.entries(bindings)) {
9281
+ const exactBindingLayout = shaderLayout.bindings.find((binding) => binding.name === bindingName);
9282
+ const bindingLayout = exactBindingLayout || (0, import_core24.getShaderLayoutBinding)(shaderLayout, bindingName);
9283
+ const isShadowedAlias = !exactBindingLayout && bindingLayout ? bindingLayout.name in bindings : false;
9284
+ if (!isShadowedAlias && bindingLayout?.group === group) {
9285
+ const entry = bindingLayout ? getBindGroupEntry(value, bindingLayout.location, void 0, bindingName) : null;
9286
+ if (entry) {
9287
+ entries.push(entry);
9288
+ }
9289
+ if (value instanceof import_core24.Texture) {
9290
+ const samplerBindingLayout = (0, import_core24.getShaderLayoutBinding)(shaderLayout, `${bindingName}Sampler`, {
9291
+ ignoreWarnings: true
9292
+ });
9293
+ const samplerEntry = samplerBindingLayout ? samplerBindingLayout.group === group ? getBindGroupEntry(value, samplerBindingLayout.location, { sampler: true }, bindingName) : null : null;
9294
+ if (samplerEntry) {
9295
+ entries.push(samplerEntry);
9296
+ }
9297
+ }
9298
+ }
9299
+ }
9300
+ return entries;
9301
+ }
9302
+ function getBindGroupEntry(binding, index, options, bindingName = "unknown") {
9303
+ if (binding instanceof import_core24.Buffer) {
9304
+ return {
9305
+ binding: index,
9306
+ resource: {
9307
+ buffer: binding.handle
9308
+ }
9309
+ };
9310
+ }
9311
+ if (binding instanceof import_core24.Sampler) {
9312
+ return {
9313
+ binding: index,
9314
+ resource: binding.handle
9315
+ };
9316
+ }
9317
+ if (binding instanceof import_core24.TextureView) {
9318
+ return {
9319
+ binding: index,
9320
+ resource: binding.handle
9321
+ };
9322
+ }
9323
+ if (binding instanceof import_core24.Texture) {
9324
+ if (options?.sampler) {
9325
+ return {
9326
+ binding: index,
9327
+ resource: binding.sampler.handle
9328
+ };
9329
+ }
9330
+ return {
9331
+ binding: index,
9332
+ resource: binding.view.handle
9333
+ };
9334
+ }
9335
+ import_core24.log.warn(`invalid binding ${bindingName}`, binding);
9336
+ return null;
9337
+ }
9338
+ var import_core24;
9339
+ var init_get_bind_group = __esm({
9340
+ "src/adapter/helpers/get-bind-group.ts"() {
9341
+ "use strict";
9342
+ import_core24 = __toESM(require_core(), 1);
9343
+ }
9344
+ });
9345
+
9186
9346
  // src/adapter/webgpu-device.ts
9187
9347
  var webgpu_device_exports = {};
9188
9348
  __export(webgpu_device_exports, {
@@ -9218,6 +9378,7 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
9218
9378
  init_webgpu_fence();
9219
9379
  init_get_shader_layout_wgsl();
9220
9380
  init_generate_mipmaps_webgpu();
9381
+ init_get_bind_group();
9221
9382
  init_cpu_hotspot_profiler();
9222
9383
  WebGPUDevice = class extends import_core25.Device {
9223
9384
  /** The underlying WebGPU device */
@@ -9348,23 +9509,24 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
9348
9509
  generateMipmapsWebGPU(texture) {
9349
9510
  generateMipmapsWebGPU(this, texture);
9350
9511
  }
9512
+ _createBindGroupLayoutWebGPU(pipeline, group) {
9513
+ return pipeline.handle.getBindGroupLayout(
9514
+ group
9515
+ );
9516
+ }
9517
+ _createBindGroupWebGPU(bindGroupLayout, shaderLayout, bindings, group) {
9518
+ if (Object.keys(bindings).length === 0) {
9519
+ return this.handle.createBindGroup({
9520
+ layout: bindGroupLayout,
9521
+ entries: []
9522
+ });
9523
+ }
9524
+ return getBindGroup(this, bindGroupLayout, shaderLayout, bindings, group);
9525
+ }
9351
9526
  submit(commandBuffer) {
9352
9527
  let submittedCommandEncoder = null;
9353
9528
  if (!commandBuffer) {
9354
- submittedCommandEncoder = this.commandEncoder;
9355
- if (submittedCommandEncoder.getTimeProfilingSlotCount() > 0 && submittedCommandEncoder.getTimeProfilingQuerySet() instanceof WebGPUQuerySet) {
9356
- const querySet = submittedCommandEncoder.getTimeProfilingQuerySet();
9357
- querySet._encodeResolveToReadBuffer(submittedCommandEncoder, {
9358
- firstQuery: 0,
9359
- queryCount: submittedCommandEncoder.getTimeProfilingSlotCount()
9360
- });
9361
- }
9362
- commandBuffer = submittedCommandEncoder.finish();
9363
- this.commandEncoder.destroy();
9364
- this.commandEncoder = this.createCommandEncoder({
9365
- id: submittedCommandEncoder.props.id,
9366
- timeProfilingQuerySet: submittedCommandEncoder.getTimeProfilingQuerySet()
9367
- });
9529
+ ({ submittedCommandEncoder, commandBuffer } = this._finalizeDefaultCommandEncoderForSubmit());
9368
9530
  }
9369
9531
  const profiler = getCpuHotspotProfiler(this);
9370
9532
  const startTime = profiler ? getTimestamp() : 0;
@@ -9411,6 +9573,23 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
9411
9573
  }
9412
9574
  }
9413
9575
  }
9576
+ _finalizeDefaultCommandEncoderForSubmit() {
9577
+ const submittedCommandEncoder = this.commandEncoder;
9578
+ if (submittedCommandEncoder.getTimeProfilingSlotCount() > 0 && submittedCommandEncoder.getTimeProfilingQuerySet() instanceof WebGPUQuerySet) {
9579
+ const querySet = submittedCommandEncoder.getTimeProfilingQuerySet();
9580
+ querySet._encodeResolveToReadBuffer(submittedCommandEncoder, {
9581
+ firstQuery: 0,
9582
+ queryCount: submittedCommandEncoder.getTimeProfilingSlotCount()
9583
+ });
9584
+ }
9585
+ const commandBuffer = submittedCommandEncoder.finish();
9586
+ this.commandEncoder.destroy();
9587
+ this.commandEncoder = this.createCommandEncoder({
9588
+ id: submittedCommandEncoder.props.id,
9589
+ timeProfilingQuerySet: submittedCommandEncoder.getTimeProfilingQuerySet()
9590
+ });
9591
+ return { submittedCommandEncoder, commandBuffer };
9592
+ }
9414
9593
  // WebGPU specific
9415
9594
  pushErrorScope(scope) {
9416
9595
  if (!this.props.debug) {
@@ -9434,6 +9613,13 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
9434
9613
  if (error) {
9435
9614
  handler(error);
9436
9615
  }
9616
+ }).catch((error) => {
9617
+ if (this.shouldIgnoreDroppedInstanceError(error, "popErrorScope")) {
9618
+ return;
9619
+ }
9620
+ const errorMessage = error instanceof Error ? error.message : String(error);
9621
+ this.reportError(new Error(`${this} popErrorScope failed: ${errorMessage}`), this)();
9622
+ this.debug();
9437
9623
  });
9438
9624
  if (profiler) {
9439
9625
  profiler.errorScopePopCount = (profiler.errorScopePopCount || 0) + 1;
@@ -9446,10 +9632,16 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
9446
9632
  const vendor = this.adapterInfo.vendor || this.adapter.__brand || "unknown";
9447
9633
  const renderer = driver || "";
9448
9634
  const version = driverVersion || "";
9449
- const gpu = vendor === "apple" ? "apple" : "unknown";
9635
+ const fallback = Boolean(
9636
+ this.adapterInfo.isFallbackAdapter ?? this.adapter.isFallbackAdapter ?? false
9637
+ );
9638
+ const softwareRenderer = /SwiftShader/i.test(
9639
+ `${vendor} ${renderer} ${this.adapterInfo.architecture || ""}`
9640
+ );
9641
+ const gpu = vendor === "apple" ? "apple" : softwareRenderer || fallback ? "software" : "unknown";
9450
9642
  const gpuArchitecture = this.adapterInfo.architecture || "unknown";
9451
9643
  const gpuBackend = this.adapterInfo.backend || "unknown";
9452
- const gpuType = (this.adapterInfo.type || "").split(" ")[0].toLowerCase() || "unknown";
9644
+ const gpuType = (this.adapterInfo.type || "").split(" ")[0].toLowerCase() || (softwareRenderer || fallback ? "cpu" : "unknown");
9453
9645
  return {
9454
9646
  type: "webgpu",
9455
9647
  vendor,
@@ -9459,10 +9651,15 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
9459
9651
  gpuType,
9460
9652
  gpuBackend,
9461
9653
  gpuArchitecture,
9654
+ fallback,
9462
9655
  shadingLanguage: "wgsl",
9463
9656
  shadingLanguageVersion: 100
9464
9657
  };
9465
9658
  }
9659
+ shouldIgnoreDroppedInstanceError(error, operation) {
9660
+ const errorMessage = error instanceof Error ? error.message : String(error);
9661
+ return errorMessage.includes("Instance dropped") && (!operation || errorMessage.includes(operation)) && (this._isLost || this.info.gpu === "software" || this.info.gpuType === "cpu" || Boolean(this.info.fallback));
9662
+ }
9466
9663
  _getFeatures() {
9467
9664
  const features = new Set(this.handle.features);
9468
9665
  if (features.has("depth-clamping")) {