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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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/index.cjs CHANGED
@@ -472,58 +472,53 @@ var init_webgpu_texture = __esm({
472
472
  };
473
473
  }
474
474
  readBuffer(options = {}, buffer) {
475
+ if (!buffer) {
476
+ throw new Error(`${this} readBuffer requires a destination buffer`);
477
+ }
475
478
  const { x, y, z, width, height, depthOrArrayLayers, mipLevel, aspect } = this._getSupportedColorReadOptions(options);
476
- const layout = this.computeMemoryLayout({ x, y, z, width, height, depthOrArrayLayers, mipLevel });
477
- const { bytesPerRow, rowsPerImage, byteLength } = layout;
478
- const readBuffer = buffer || this.device.createBuffer({
479
- byteLength,
480
- usage: import_core4.Buffer.COPY_DST | import_core4.Buffer.MAP_READ
481
- });
482
- if (readBuffer.byteLength < byteLength) {
483
- throw new Error(`${this} readBuffer target is too small (${readBuffer.byteLength} < ${byteLength})`);
479
+ const byteOffset = options.byteOffset ?? 0;
480
+ const layout = this.computeMemoryLayout({ width, height, depthOrArrayLayers, mipLevel });
481
+ const { byteLength } = layout;
482
+ if (buffer.byteLength < byteOffset + byteLength) {
483
+ throw new Error(`${this} readBuffer target is too small (${buffer.byteLength} < ${byteOffset + byteLength})`);
484
484
  }
485
- const gpuReadBuffer = readBuffer.handle;
486
485
  const gpuDevice = this.device.handle;
487
486
  this.device.pushErrorScope("validation");
488
487
  const commandEncoder = gpuDevice.createCommandEncoder();
489
- commandEncoder.copyTextureToBuffer(
490
- // source
491
- {
492
- texture: this.handle,
493
- origin: { x, y, z },
494
- // origin: [options.x, options.y, 0], // options.depth],
495
- mipLevel,
496
- aspect
497
- // colorSpace: options.colorSpace,
498
- // premultipliedAlpha: options.premultipliedAlpha
499
- },
500
- // destination
501
- {
502
- buffer: gpuReadBuffer,
503
- offset: 0,
504
- bytesPerRow,
505
- rowsPerImage
506
- },
507
- // copy size
508
- {
509
- width,
510
- height,
511
- depthOrArrayLayers
512
- }
513
- );
488
+ this.copyToBuffer(commandEncoder, { x, y, z, width, height, depthOrArrayLayers, mipLevel, aspect, byteOffset }, buffer);
514
489
  const commandBuffer = commandEncoder.finish();
515
490
  this.device.handle.queue.submit([commandBuffer]);
516
491
  this.device.popErrorScope((error) => {
517
492
  this.device.reportError(new Error(`${this} readBuffer: ${error.message}`), this)();
518
493
  this.device.debug();
519
494
  });
520
- return readBuffer;
495
+ return buffer;
521
496
  }
522
497
  async readDataAsync(options = {}) {
523
- const buffer = this.readBuffer(options);
524
- const data = await buffer.readAsync();
525
- buffer.destroy();
526
- return data.buffer;
498
+ throw new Error(`${this} readDataAsync is deprecated; use readBuffer() with an explicit destination buffer or DynamicTexture.readAsync()`);
499
+ }
500
+ copyToBuffer(commandEncoder, options = {}, buffer) {
501
+ const { byteOffset = 0, bytesPerRow: requestedBytesPerRow, rowsPerImage: requestedRowsPerImage, ...textureReadOptions } = options;
502
+ const { x, y, z, width, height, depthOrArrayLayers, mipLevel, aspect } = this._getSupportedColorReadOptions(textureReadOptions);
503
+ const layout = this.computeMemoryLayout({ width, height, depthOrArrayLayers, mipLevel });
504
+ const effectiveBytesPerRow = requestedBytesPerRow ?? layout.bytesPerRow;
505
+ const effectiveRowsPerImage = requestedRowsPerImage ?? layout.rowsPerImage;
506
+ const webgpuBuffer = buffer;
507
+ commandEncoder.copyTextureToBuffer({
508
+ texture: this.handle,
509
+ origin: { x, y, z },
510
+ mipLevel,
511
+ aspect
512
+ }, {
513
+ buffer: webgpuBuffer.handle,
514
+ offset: byteOffset,
515
+ bytesPerRow: effectiveBytesPerRow,
516
+ rowsPerImage: effectiveRowsPerImage
517
+ }, {
518
+ width,
519
+ height,
520
+ depthOrArrayLayers
521
+ });
527
522
  }
528
523
  writeBuffer(buffer, options_ = {}) {
529
524
  const options = this._normalizeTextureWriteOptions(options_);
@@ -711,7 +706,19 @@ var init_webgpu_shader = __esm({
711
706
  }
712
707
  /** Returns compilation info for this shader */
713
708
  async getCompilationInfo() {
714
- const compilationInfo = await this.handle.getCompilationInfo();
709
+ const handle = this.handle;
710
+ if (!handle) {
711
+ return [];
712
+ }
713
+ let compilationInfo;
714
+ try {
715
+ compilationInfo = await handle.getCompilationInfo();
716
+ } catch (error) {
717
+ if (this.device.shouldIgnoreDroppedInstanceError(error, "getCompilationInfo")) {
718
+ return [];
719
+ }
720
+ throw error;
721
+ }
715
722
  return compilationInfo.messages;
716
723
  }
717
724
  };
@@ -802,6 +809,7 @@ var init_webgpu_parameters = __esm({
802
809
  const depthStencil = addDepthStencil(descriptor);
803
810
  depthStencil.format = value;
804
811
  },
812
+ clearDepth: notSupported,
805
813
  depthBias: (_, value, descriptor) => {
806
814
  const depthStencil = addDepthStencil(descriptor);
807
815
  depthStencil.depthBias = value;
@@ -940,94 +948,6 @@ var init_webgpu_parameters = __esm({
940
948
  }
941
949
  });
942
950
 
943
- // dist/adapter/helpers/get-bind-group.js
944
- function getBindGroup(device, bindGroupLayout, shaderLayout, bindings) {
945
- const entries = getBindGroupEntries(bindings, shaderLayout);
946
- device.pushErrorScope("validation");
947
- const bindGroup = device.handle.createBindGroup({
948
- layout: bindGroupLayout,
949
- entries
950
- });
951
- device.popErrorScope((error) => {
952
- import_core8.log.error(`bindGroup creation: ${error.message}`, bindGroup)();
953
- });
954
- return bindGroup;
955
- }
956
- function getShaderLayoutBinding(shaderLayout, bindingName, options) {
957
- const bindingLayout = shaderLayout.bindings.find((binding) => binding.name === bindingName || `${binding.name.toLocaleLowerCase()}uniforms` === bindingName.toLocaleLowerCase());
958
- if (!bindingLayout && !(options == null ? void 0 : options.ignoreWarnings)) {
959
- import_core8.log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();
960
- }
961
- return bindingLayout || null;
962
- }
963
- function getBindGroupEntries(bindings, shaderLayout) {
964
- const entries = [];
965
- for (const [bindingName, value] of Object.entries(bindings)) {
966
- const exactBindingLayout = shaderLayout.bindings.find((binding) => binding.name === bindingName);
967
- const bindingLayout = exactBindingLayout || getShaderLayoutBinding(shaderLayout, bindingName);
968
- const isShadowedAlias = !exactBindingLayout && bindingLayout ? bindingLayout.name in bindings : false;
969
- if (!isShadowedAlias) {
970
- const entry = bindingLayout ? getBindGroupEntry(value, bindingLayout.location, void 0, bindingName) : null;
971
- if (entry) {
972
- entries.push(entry);
973
- }
974
- if (value instanceof import_core8.Texture) {
975
- const samplerBindingLayout = getShaderLayoutBinding(shaderLayout, `${bindingName}Sampler`, {
976
- ignoreWarnings: true
977
- });
978
- const samplerEntry = samplerBindingLayout ? getBindGroupEntry(value, samplerBindingLayout.location, { sampler: true }, bindingName) : null;
979
- if (samplerEntry) {
980
- entries.push(samplerEntry);
981
- }
982
- }
983
- }
984
- }
985
- return entries;
986
- }
987
- function getBindGroupEntry(binding, index, options, bindingName = "unknown") {
988
- if (binding instanceof import_core8.Buffer) {
989
- return {
990
- binding: index,
991
- resource: {
992
- buffer: binding.handle
993
- }
994
- };
995
- }
996
- if (binding instanceof import_core8.Sampler) {
997
- return {
998
- binding: index,
999
- resource: binding.handle
1000
- };
1001
- }
1002
- if (binding instanceof import_core8.TextureView) {
1003
- return {
1004
- binding: index,
1005
- resource: binding.handle
1006
- };
1007
- }
1008
- if (binding instanceof import_core8.Texture) {
1009
- if (options == null ? void 0 : options.sampler) {
1010
- return {
1011
- binding: index,
1012
- resource: binding.sampler.handle
1013
- };
1014
- }
1015
- return {
1016
- binding: index,
1017
- resource: binding.view.handle
1018
- };
1019
- }
1020
- import_core8.log.warn(`invalid binding ${bindingName}`, binding);
1021
- return null;
1022
- }
1023
- var import_core8;
1024
- var init_get_bind_group = __esm({
1025
- "dist/adapter/helpers/get-bind-group.js"() {
1026
- "use strict";
1027
- import_core8 = require("@luma.gl/core");
1028
- }
1029
- });
1030
-
1031
951
  // dist/adapter/helpers/get-vertex-buffer-layout.js
1032
952
  function getWebGPUVertexFormat(format) {
1033
953
  if (format.endsWith("-webgl")) {
@@ -1035,9 +955,10 @@ function getWebGPUVertexFormat(format) {
1035
955
  }
1036
956
  return format;
1037
957
  }
1038
- function getVertexBufferLayout(shaderLayout, bufferLayout) {
958
+ function getVertexBufferLayout(shaderLayout, bufferLayout, options) {
1039
959
  const vertexBufferLayouts = [];
1040
960
  const usedAttributes = /* @__PURE__ */ new Set();
961
+ const shaderAttributes = shaderLayout.attributes || [];
1041
962
  for (const mapping of bufferLayout) {
1042
963
  const vertexAttributes = [];
1043
964
  let stepMode = "vertex";
@@ -1046,7 +967,7 @@ function getVertexBufferLayout(shaderLayout, bufferLayout) {
1046
967
  if (mapping.attributes) {
1047
968
  for (const attributeMapping of mapping.attributes) {
1048
969
  const attributeName = attributeMapping.attribute;
1049
- const attributeLayout = findAttributeLayout(shaderLayout, attributeName, usedAttributes);
970
+ const attributeLayout = findAttributeLayout(shaderLayout, attributeName, usedAttributes, options);
1050
971
  const location = attributeLayout == null ? void 0 : attributeLayout.location;
1051
972
  format = attributeMapping.format || mapping.format;
1052
973
  stepMode = (attributeLayout == null ? void 0 : attributeLayout.stepMode) || ((attributeLayout == null ? void 0 : attributeLayout.name.startsWith("instance")) ? "instance" : "vertex");
@@ -1055,14 +976,14 @@ function getVertexBufferLayout(shaderLayout, bufferLayout) {
1055
976
  offset: attributeMapping.byteOffset,
1056
977
  shaderLocation: location
1057
978
  });
1058
- byteStride += (0, import_core9.getVertexFormatInfo)(format).byteLength;
979
+ byteStride += import_core8.vertexFormatDecoder.getVertexFormatInfo(format).byteLength;
1059
980
  }
1060
981
  } else {
1061
- const attributeLayout = findAttributeLayout(shaderLayout, mapping.name, usedAttributes);
982
+ const attributeLayout = findAttributeLayout(shaderLayout, mapping.name, usedAttributes, options);
1062
983
  if (!attributeLayout) {
1063
984
  continue;
1064
985
  }
1065
- byteStride = (0, import_core9.getVertexFormatInfo)(format).byteLength;
986
+ byteStride = import_core8.vertexFormatDecoder.getVertexFormatInfo(format).byteLength;
1066
987
  stepMode = attributeLayout.stepMode || (attributeLayout.name.startsWith("instance") ? "instance" : "vertex");
1067
988
  vertexAttributes.push({
1068
989
  format: getWebGPUVertexFormat(format),
@@ -1077,10 +998,10 @@ function getVertexBufferLayout(shaderLayout, bufferLayout) {
1077
998
  attributes: vertexAttributes
1078
999
  });
1079
1000
  }
1080
- for (const attribute of shaderLayout.attributes) {
1001
+ for (const attribute of shaderAttributes) {
1081
1002
  if (!usedAttributes.has(attribute.name)) {
1082
1003
  vertexBufferLayouts.push({
1083
- arrayStride: (0, import_core9.getVertexFormatInfo)("float32x3").byteLength,
1004
+ arrayStride: import_core8.vertexFormatDecoder.getVertexFormatInfo("float32x3").byteLength,
1084
1005
  stepMode: attribute.stepMode || (attribute.name.startsWith("instance") ? "instance" : "vertex"),
1085
1006
  attributes: [
1086
1007
  {
@@ -1099,10 +1020,12 @@ function getVertexBufferLayout(shaderLayout, bufferLayout) {
1099
1020
  });
1100
1021
  return vertexBufferLayouts;
1101
1022
  }
1102
- function findAttributeLayout(shaderLayout, name, attributeNames) {
1103
- const attribute = shaderLayout.attributes.find((attribute_) => attribute_.name === name);
1023
+ function findAttributeLayout(shaderLayout, name, attributeNames, options) {
1024
+ var _a;
1025
+ const attribute = (_a = shaderLayout.attributes) == null ? void 0 : _a.find((attribute_) => attribute_.name === name);
1104
1026
  if (!attribute) {
1105
- import_core9.log.warn(`Supplied attribute not present in shader layout: ${name}`)();
1027
+ const pipelineContext = (options == null ? void 0 : options.pipelineId) ? `RenderPipeline(${options.pipelineId})` : "RenderPipeline";
1028
+ import_core8.log.warn(`${pipelineContext}: Ignoring "${name}" attribute, since it is not present in shader layout.`)();
1106
1029
  return null;
1107
1030
  }
1108
1031
  if (attributeNames) {
@@ -1113,47 +1036,58 @@ function findAttributeLayout(shaderLayout, name, attributeNames) {
1113
1036
  }
1114
1037
  return attribute;
1115
1038
  }
1116
- var import_core9;
1039
+ var import_core8;
1117
1040
  var init_get_vertex_buffer_layout = __esm({
1118
1041
  "dist/adapter/helpers/get-vertex-buffer-layout.js"() {
1119
1042
  "use strict";
1120
- import_core9 = require("@luma.gl/core");
1043
+ import_core8 = require("@luma.gl/core");
1121
1044
  }
1122
1045
  });
1123
1046
 
1124
1047
  // dist/adapter/resources/webgpu-render-pipeline.js
1125
- var import_core10, EMPTY_BINDINGS, WebGPURenderPipeline;
1048
+ function createBindGroupCacheKeys(bindingsByGroup) {
1049
+ const bindGroupCacheKeys = {};
1050
+ for (const [groupKey, groupBindings] of Object.entries(bindingsByGroup)) {
1051
+ if (groupBindings && Object.keys(groupBindings).length > 0) {
1052
+ bindGroupCacheKeys[Number(groupKey)] = {};
1053
+ }
1054
+ }
1055
+ return bindGroupCacheKeys;
1056
+ }
1057
+ var import_core9, WebGPURenderPipeline;
1126
1058
  var init_webgpu_render_pipeline = __esm({
1127
1059
  "dist/adapter/resources/webgpu-render-pipeline.js"() {
1128
1060
  "use strict";
1129
- import_core10 = require("@luma.gl/core");
1061
+ import_core9 = require("@luma.gl/core");
1130
1062
  init_webgpu_parameters();
1131
1063
  init_convert_texture_format();
1132
- init_get_bind_group();
1133
1064
  init_get_vertex_buffer_layout();
1134
- EMPTY_BINDINGS = {};
1135
- WebGPURenderPipeline = class extends import_core10.RenderPipeline {
1065
+ WebGPURenderPipeline = class extends import_core9.RenderPipeline {
1136
1066
  device;
1137
1067
  handle;
1068
+ descriptor;
1138
1069
  vs;
1139
1070
  fs = null;
1140
1071
  /** Compatibility path for direct pipeline.setBindings() usage */
1141
- _bindings;
1142
- /** For internal use to create BindGroups */
1143
- _bindGroupLayout = null;
1144
- _bindGroup = null;
1072
+ _bindingsByGroup;
1073
+ _bindGroupCacheKeysByGroup = {};
1145
1074
  get [Symbol.toStringTag]() {
1146
1075
  return "WebGPURenderPipeline";
1147
1076
  }
1148
1077
  constructor(device, props) {
1149
1078
  super(device, props);
1150
1079
  this.device = device;
1080
+ this.shaderLayout ||= this.device.getShaderLayout(props.vs.source) || {
1081
+ attributes: [],
1082
+ bindings: []
1083
+ };
1151
1084
  this.handle = this.props.handle;
1085
+ let descriptor = null;
1152
1086
  if (!this.handle) {
1153
- const descriptor = this._getRenderPipelineDescriptor();
1154
- import_core10.log.groupCollapsed(1, `new WebGPURenderPipeline(${this.id})`)();
1155
- import_core10.log.probe(1, JSON.stringify(descriptor, null, 2))();
1156
- import_core10.log.groupEnd(1)();
1087
+ descriptor = this._getRenderPipelineDescriptor();
1088
+ import_core9.log.groupCollapsed(1, `new WebGPURenderPipeline(${this.id})`)();
1089
+ import_core9.log.probe(1, JSON.stringify(descriptor, null, 2))();
1090
+ import_core9.log.groupEnd(1)();
1157
1091
  this.device.pushErrorScope("validation");
1158
1092
  this.handle = this.device.handle.createRenderPipeline(descriptor);
1159
1093
  this.device.popErrorScope((error) => {
@@ -1162,10 +1096,12 @@ var init_webgpu_render_pipeline = __esm({
1162
1096
  this.device.debug();
1163
1097
  });
1164
1098
  }
1099
+ this.descriptor = descriptor;
1165
1100
  this.handle.label = this.props.id;
1166
1101
  this.vs = props.vs;
1167
1102
  this.fs = props.fs;
1168
- this._bindings = props.bindings || EMPTY_BINDINGS;
1103
+ this._bindingsByGroup = props.bindGroups || (0, import_core9.normalizeBindingsByGroup)(this.shaderLayout, props.bindings);
1104
+ this._bindGroupCacheKeysByGroup = createBindGroupCacheKeys(this._bindingsByGroup);
1169
1105
  }
1170
1106
  destroy() {
1171
1107
  this.handle = null;
@@ -1175,21 +1111,20 @@ var init_webgpu_render_pipeline = __esm({
1175
1111
  * The shared-model path passes bindings per draw and does not rely on this state.
1176
1112
  */
1177
1113
  setBindings(bindings) {
1178
- let bindingsChanged = false;
1179
- for (const [name, binding] of Object.entries(bindings)) {
1180
- if (this._bindings[name] !== binding) {
1181
- if (!bindingsChanged) {
1182
- if (this._bindings === this.props.bindings || this._bindings === EMPTY_BINDINGS) {
1183
- this._bindings = { ...this._bindings };
1114
+ const nextBindingsByGroup = (0, import_core9.normalizeBindingsByGroup)(this.shaderLayout, bindings);
1115
+ for (const [groupKey, groupBindings] of Object.entries(nextBindingsByGroup)) {
1116
+ const group = Number(groupKey);
1117
+ for (const [name, binding] of Object.entries(groupBindings || {})) {
1118
+ const currentGroupBindings = this._bindingsByGroup[group] || {};
1119
+ if (currentGroupBindings[name] !== binding) {
1120
+ if (!this._bindingsByGroup[group] || this._bindingsByGroup[group] === currentGroupBindings) {
1121
+ this._bindingsByGroup[group] = { ...currentGroupBindings };
1184
1122
  }
1185
- bindingsChanged = true;
1123
+ this._bindingsByGroup[group][name] = binding;
1124
+ this._bindGroupCacheKeysByGroup[group] = {};
1186
1125
  }
1187
- this._bindings[name] = binding;
1188
1126
  }
1189
1127
  }
1190
- if (bindingsChanged) {
1191
- this._bindGroup = null;
1192
- }
1193
1128
  }
1194
1129
  /** @todo - should this be moved to renderpass? */
1195
1130
  draw(options) {
@@ -1202,9 +1137,12 @@ var init_webgpu_render_pipeline = __esm({
1202
1137
  "${error.message}"`), this)();
1203
1138
  this.device.debug();
1204
1139
  });
1205
- const bindGroup = this._getBindGroup(options.bindings);
1206
- if (bindGroup) {
1207
- webgpuRenderPass.handle.setBindGroup(0, bindGroup);
1140
+ const hasExplicitBindings = Boolean(options.bindGroups || options.bindings);
1141
+ const bindGroups = (0, import_core9._getDefaultBindGroupFactory)(this.device).getBindGroups(this, hasExplicitBindings ? options.bindGroups || options.bindings : this._bindingsByGroup, hasExplicitBindings ? options._bindGroupCacheKeys : this._bindGroupCacheKeysByGroup);
1142
+ for (const [group, bindGroup] of Object.entries(bindGroups)) {
1143
+ if (bindGroup) {
1144
+ webgpuRenderPass.handle.setBindGroup(Number(group), bindGroup);
1145
+ }
1208
1146
  }
1209
1147
  options.vertexArray.bindBeforeRender(options.renderPass);
1210
1148
  if (options.indexCount) {
@@ -1215,17 +1153,11 @@ var init_webgpu_render_pipeline = __esm({
1215
1153
  options.vertexArray.unbindAfterRender(options.renderPass);
1216
1154
  return true;
1217
1155
  }
1218
- /** Return a bind group created by setBindings */
1219
- _getBindGroup(bindings) {
1220
- if (this.shaderLayout.bindings.length === 0) {
1221
- return null;
1222
- }
1223
- this._bindGroupLayout = this._bindGroupLayout || this.handle.getBindGroupLayout(0);
1224
- if (bindings) {
1225
- return getBindGroup(this.device, this._bindGroupLayout, this.shaderLayout, bindings);
1226
- }
1227
- this._bindGroup = this._bindGroup || getBindGroup(this.device, this._bindGroupLayout, this.shaderLayout, this._bindings);
1228
- return this._bindGroup;
1156
+ _getBindingsByGroupWebGPU() {
1157
+ return this._bindingsByGroup;
1158
+ }
1159
+ _getBindGroupCacheKeysWebGPU() {
1160
+ return this._bindGroupCacheKeysByGroup;
1229
1161
  }
1230
1162
  /**
1231
1163
  * Populate the complex WebGPU GPURenderPipelineDescriptor
@@ -1234,7 +1166,9 @@ var init_webgpu_render_pipeline = __esm({
1234
1166
  const vertex = {
1235
1167
  module: this.props.vs.handle,
1236
1168
  entryPoint: this.props.vertexEntryPoint || "main",
1237
- buffers: getVertexBufferLayout(this.shaderLayout, this.props.bufferLayout)
1169
+ buffers: getVertexBufferLayout(this.shaderLayout, this.props.bufferLayout, {
1170
+ pipelineId: this.id
1171
+ })
1238
1172
  };
1239
1173
  const targets = [];
1240
1174
  if (this.props.colorAttachmentFormats) {
@@ -1274,12 +1208,12 @@ var init_webgpu_render_pipeline = __esm({
1274
1208
  });
1275
1209
 
1276
1210
  // dist/adapter/resources/webgpu-framebuffer.js
1277
- var import_core11, WebGPUFramebuffer;
1211
+ var import_core10, WebGPUFramebuffer;
1278
1212
  var init_webgpu_framebuffer = __esm({
1279
1213
  "dist/adapter/resources/webgpu-framebuffer.js"() {
1280
1214
  "use strict";
1281
- import_core11 = require("@luma.gl/core");
1282
- WebGPUFramebuffer = class extends import_core11.Framebuffer {
1215
+ import_core10 = require("@luma.gl/core");
1216
+ WebGPUFramebuffer = class extends import_core10.Framebuffer {
1283
1217
  device;
1284
1218
  handle = null;
1285
1219
  colorAttachments = [];
@@ -1311,21 +1245,17 @@ var init_webgpu_framebuffer = __esm({
1311
1245
  });
1312
1246
 
1313
1247
  // dist/adapter/resources/webgpu-compute-pipeline.js
1314
- var import_core12, EMPTY_BINDINGS2, WebGPUComputePipeline;
1248
+ var import_core11, EMPTY_BIND_GROUPS, WebGPUComputePipeline;
1315
1249
  var init_webgpu_compute_pipeline = __esm({
1316
1250
  "dist/adapter/resources/webgpu-compute-pipeline.js"() {
1317
1251
  "use strict";
1318
- import_core12 = require("@luma.gl/core");
1319
- init_get_bind_group();
1320
- EMPTY_BINDINGS2 = {};
1321
- WebGPUComputePipeline = class extends import_core12.ComputePipeline {
1252
+ import_core11 = require("@luma.gl/core");
1253
+ EMPTY_BIND_GROUPS = {};
1254
+ WebGPUComputePipeline = class extends import_core11.ComputePipeline {
1322
1255
  device;
1323
1256
  handle;
1324
- /** For internal use to create BindGroups */
1325
- _bindGroupLayout = null;
1326
- _bindGroup = null;
1327
- /** For internal use to create BindGroups */
1328
- _bindings;
1257
+ _bindingsByGroup;
1258
+ _bindGroupCacheKeysByGroup;
1329
1259
  constructor(device, props) {
1330
1260
  super(device, props);
1331
1261
  this.device = device;
@@ -1339,47 +1269,51 @@ var init_webgpu_compute_pipeline = __esm({
1339
1269
  },
1340
1270
  layout: "auto"
1341
1271
  });
1342
- this._bindings = EMPTY_BINDINGS2;
1272
+ this._bindingsByGroup = EMPTY_BIND_GROUPS;
1273
+ this._bindGroupCacheKeysByGroup = {};
1343
1274
  }
1344
1275
  /**
1345
1276
  * @todo Use renderpass.setBindings() ?
1346
1277
  * @todo Do we want to expose BindGroups in the API and remove this?
1347
1278
  */
1348
1279
  setBindings(bindings) {
1349
- let bindingsChanged = false;
1350
- for (const [name, binding] of Object.entries(bindings)) {
1351
- if (this._bindings[name] !== binding) {
1352
- if (!bindingsChanged) {
1353
- if (this._bindings === EMPTY_BINDINGS2) {
1354
- this._bindings = {};
1280
+ const nextBindingsByGroup = (0, import_core11.normalizeBindingsByGroup)(this.shaderLayout, bindings);
1281
+ for (const [groupKey, groupBindings] of Object.entries(nextBindingsByGroup)) {
1282
+ const group = Number(groupKey);
1283
+ for (const [name, binding] of Object.entries(groupBindings || {})) {
1284
+ const currentGroupBindings = this._bindingsByGroup[group] || {};
1285
+ if (currentGroupBindings[name] !== binding) {
1286
+ if (!this._bindingsByGroup[group] || this._bindingsByGroup[group] === currentGroupBindings) {
1287
+ this._bindingsByGroup[group] = { ...currentGroupBindings };
1355
1288
  }
1356
- bindingsChanged = true;
1289
+ this._bindingsByGroup[group][name] = binding;
1290
+ this._bindGroupCacheKeysByGroup[group] = {};
1357
1291
  }
1358
- this._bindings[name] = binding;
1359
1292
  }
1360
1293
  }
1361
- if (bindingsChanged) {
1362
- this._bindGroup = null;
1363
- }
1364
1294
  }
1365
- /** Return a bind group created by setBindings */
1366
- _getBindGroup() {
1367
- this._bindGroupLayout = this._bindGroupLayout || this.handle.getBindGroupLayout(0);
1368
- this._bindGroup = this._bindGroup || getBindGroup(this.device, this._bindGroupLayout, this.shaderLayout, this._bindings);
1369
- return this._bindGroup;
1295
+ _getBindGroups(bindings, bindGroupCacheKeys) {
1296
+ const hasExplicitBindings = Boolean(bindings);
1297
+ return (0, import_core11._getDefaultBindGroupFactory)(this.device).getBindGroups(this, hasExplicitBindings ? bindings : this._bindingsByGroup, hasExplicitBindings ? bindGroupCacheKeys : this._bindGroupCacheKeysByGroup);
1298
+ }
1299
+ _getBindingsByGroupWebGPU() {
1300
+ return this._bindingsByGroup;
1301
+ }
1302
+ _getBindGroupCacheKeysWebGPU() {
1303
+ return this._bindGroupCacheKeysByGroup;
1370
1304
  }
1371
1305
  };
1372
1306
  }
1373
1307
  });
1374
1308
 
1375
1309
  // dist/adapter/resources/webgpu-vertex-array.js
1376
- var import_core13, import_env, WebGPUVertexArray;
1310
+ var import_core12, import_env, WebGPUVertexArray;
1377
1311
  var init_webgpu_vertex_array = __esm({
1378
1312
  "dist/adapter/resources/webgpu-vertex-array.js"() {
1379
1313
  "use strict";
1380
- import_core13 = require("@luma.gl/core");
1314
+ import_core12 = require("@luma.gl/core");
1381
1315
  import_env = require("@probe.gl/env");
1382
- WebGPUVertexArray = class extends import_core13.VertexArray {
1316
+ WebGPUVertexArray = class extends import_core12.VertexArray {
1383
1317
  get [Symbol.toStringTag]() {
1384
1318
  return "VertexArray";
1385
1319
  }
@@ -1408,7 +1342,7 @@ var init_webgpu_vertex_array = __esm({
1408
1342
  const webgpuRenderPass = renderPass;
1409
1343
  const webgpuIndexBuffer = this.indexBuffer;
1410
1344
  if (webgpuIndexBuffer == null ? void 0 : webgpuIndexBuffer.handle) {
1411
- import_core13.log.info(3, "setting index buffer", webgpuIndexBuffer == null ? void 0 : webgpuIndexBuffer.handle, webgpuIndexBuffer == null ? void 0 : webgpuIndexBuffer.indexType)();
1345
+ import_core12.log.info(3, "setting index buffer", webgpuIndexBuffer == null ? void 0 : webgpuIndexBuffer.handle, webgpuIndexBuffer == null ? void 0 : webgpuIndexBuffer.indexType)();
1412
1346
  webgpuRenderPass.handle.setIndexBuffer(
1413
1347
  webgpuIndexBuffer == null ? void 0 : webgpuIndexBuffer.handle,
1414
1348
  // @ts-expect-error TODO - we must enforce type
@@ -1418,7 +1352,7 @@ var init_webgpu_vertex_array = __esm({
1418
1352
  for (let location = 0; location < this.maxVertexAttributes; location++) {
1419
1353
  const webgpuBuffer = this.attributes[location];
1420
1354
  if (webgpuBuffer == null ? void 0 : webgpuBuffer.handle) {
1421
- import_core13.log.info(3, `setting vertex buffer ${location}`, webgpuBuffer == null ? void 0 : webgpuBuffer.handle)();
1355
+ import_core12.log.info(3, `setting vertex buffer ${location}`, webgpuBuffer == null ? void 0 : webgpuBuffer.handle)();
1422
1356
  webgpuRenderPass.handle.setVertexBuffer(location, webgpuBuffer == null ? void 0 : webgpuBuffer.handle);
1423
1357
  }
1424
1358
  }
@@ -1438,14 +1372,14 @@ var init_webgpu_vertex_array = __esm({
1438
1372
  });
1439
1373
 
1440
1374
  // dist/adapter/webgpu-canvas-context.js
1441
- var import_core14, WebGPUCanvasContext;
1375
+ var import_core13, WebGPUCanvasContext;
1442
1376
  var init_webgpu_canvas_context = __esm({
1443
1377
  "dist/adapter/webgpu-canvas-context.js"() {
1444
1378
  "use strict";
1445
- import_core14 = require("@luma.gl/core");
1379
+ import_core13 = require("@luma.gl/core");
1446
1380
  init_webgpu_framebuffer();
1447
1381
  init_cpu_hotspot_profiler();
1448
- WebGPUCanvasContext = class extends import_core14.CanvasContext {
1382
+ WebGPUCanvasContext = class extends import_core13.CanvasContext {
1449
1383
  device;
1450
1384
  handle;
1451
1385
  colorAttachment = null;
@@ -1517,7 +1451,7 @@ var init_webgpu_canvas_context = __esm({
1517
1451
  const [oldWidth, oldHeight] = this.getDrawingBufferSize();
1518
1452
  this.drawingBufferWidth = currentColorAttachment.width;
1519
1453
  this.drawingBufferHeight = currentColorAttachment.height;
1520
- import_core14.log.log(1, `${this}: Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`)();
1454
+ import_core13.log.log(1, `${this}: Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`)();
1521
1455
  }
1522
1456
  if (options == null ? void 0 : options.depthStencilFormat) {
1523
1457
  this._createDepthStencilAttachment(options == null ? void 0 : options.depthStencilFormat);
@@ -1572,7 +1506,7 @@ var init_webgpu_canvas_context = __esm({
1572
1506
  (_a = this.depthStencilAttachment) == null ? void 0 : _a.destroy();
1573
1507
  this.depthStencilAttachment = this.device.createTexture({
1574
1508
  id: `${this.id}#depth-stencil-texture`,
1575
- usage: import_core14.Texture.RENDER_ATTACHMENT,
1509
+ usage: import_core13.Texture.RENDER_ATTACHMENT,
1576
1510
  format: depthStencilFormat,
1577
1511
  width: this.drawingBufferWidth,
1578
1512
  height: this.drawingBufferHeight
@@ -1585,14 +1519,14 @@ var init_webgpu_canvas_context = __esm({
1585
1519
  });
1586
1520
 
1587
1521
  // dist/adapter/webgpu-presentation-context.js
1588
- var import_core15, WebGPUPresentationContext;
1522
+ var import_core14, WebGPUPresentationContext;
1589
1523
  var init_webgpu_presentation_context = __esm({
1590
1524
  "dist/adapter/webgpu-presentation-context.js"() {
1591
1525
  "use strict";
1592
- import_core15 = require("@luma.gl/core");
1526
+ import_core14 = require("@luma.gl/core");
1593
1527
  init_webgpu_framebuffer();
1594
1528
  init_cpu_hotspot_profiler();
1595
- WebGPUPresentationContext = class extends import_core15.PresentationContext {
1529
+ WebGPUPresentationContext = class extends import_core14.PresentationContext {
1596
1530
  device;
1597
1531
  handle;
1598
1532
  colorAttachment = null;
@@ -1661,7 +1595,7 @@ var init_webgpu_presentation_context = __esm({
1661
1595
  const [oldWidth, oldHeight] = this.getDrawingBufferSize();
1662
1596
  this.drawingBufferWidth = currentColorAttachment.width;
1663
1597
  this.drawingBufferHeight = currentColorAttachment.height;
1664
- import_core15.log.log(1, `${this[Symbol.toStringTag]}(${this.id}): Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`)();
1598
+ import_core14.log.log(1, `${this[Symbol.toStringTag]}(${this.id}): Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`)();
1665
1599
  }
1666
1600
  if (options == null ? void 0 : options.depthStencilFormat) {
1667
1601
  this._createDepthStencilAttachment(options.depthStencilFormat);
@@ -1712,7 +1646,7 @@ var init_webgpu_presentation_context = __esm({
1712
1646
  (_a = this.depthStencilAttachment) == null ? void 0 : _a.destroy();
1713
1647
  this.depthStencilAttachment = this.device.createTexture({
1714
1648
  id: `${this.id}#depth-stencil-texture`,
1715
- usage: import_core15.Texture.RENDER_ATTACHMENT,
1649
+ usage: import_core14.Texture.RENDER_ATTACHMENT,
1716
1650
  format: depthStencilFormat,
1717
1651
  width: this.drawingBufferWidth,
1718
1652
  height: this.drawingBufferHeight
@@ -1725,12 +1659,12 @@ var init_webgpu_presentation_context = __esm({
1725
1659
  });
1726
1660
 
1727
1661
  // dist/adapter/resources/webgpu-command-buffer.js
1728
- var import_core16, WebGPUCommandBuffer;
1662
+ var import_core15, WebGPUCommandBuffer;
1729
1663
  var init_webgpu_command_buffer = __esm({
1730
1664
  "dist/adapter/resources/webgpu-command-buffer.js"() {
1731
1665
  "use strict";
1732
- import_core16 = require("@luma.gl/core");
1733
- WebGPUCommandBuffer = class extends import_core16.CommandBuffer {
1666
+ import_core15 = require("@luma.gl/core");
1667
+ WebGPUCommandBuffer = class extends import_core15.CommandBuffer {
1734
1668
  device;
1735
1669
  handle;
1736
1670
  constructor(commandEncoder, props) {
@@ -1748,13 +1682,13 @@ var init_webgpu_command_buffer = __esm({
1748
1682
  function convertColor(color) {
1749
1683
  return { r: color[0], g: color[1], b: color[2], a: color[3] };
1750
1684
  }
1751
- var import_core17, WebGPURenderPass;
1685
+ var import_core16, WebGPURenderPass;
1752
1686
  var init_webgpu_render_pass = __esm({
1753
1687
  "dist/adapter/resources/webgpu-render-pass.js"() {
1754
1688
  "use strict";
1755
- import_core17 = require("@luma.gl/core");
1689
+ import_core16 = require("@luma.gl/core");
1756
1690
  init_cpu_hotspot_profiler();
1757
- WebGPURenderPass = class extends import_core17.RenderPass {
1691
+ WebGPURenderPass = class extends import_core16.RenderPass {
1758
1692
  device;
1759
1693
  handle;
1760
1694
  framebuffer;
@@ -1762,7 +1696,7 @@ var init_webgpu_render_pass = __esm({
1762
1696
  pipeline = null;
1763
1697
  /** Latest bindings applied to this pass */
1764
1698
  bindings = {};
1765
- constructor(device, props = {}) {
1699
+ constructor(device, props = {}, commandEncoder = device.commandEncoder.handle) {
1766
1700
  super(device, props);
1767
1701
  this.device = device;
1768
1702
  const { props: renderPassProps } = this;
@@ -1792,12 +1726,9 @@ var init_webgpu_render_pass = __esm({
1792
1726
  profiler.renderPassDescriptorAssemblyCount = (profiler.renderPassDescriptorAssemblyCount || 0) + 1;
1793
1727
  profiler.renderPassDescriptorAssemblyTimeMs = (profiler.renderPassDescriptorAssemblyTimeMs || 0) + (getTimestamp() - descriptorAssemblyStartTime);
1794
1728
  }
1795
- if (!device.commandEncoder) {
1796
- throw new Error("commandEncoder not available");
1797
- }
1798
1729
  this.device.pushErrorScope("validation");
1799
1730
  const beginRenderPassStartTime = profiler ? getTimestamp() : 0;
1800
- this.handle = this.props.handle || device.commandEncoder.handle.beginRenderPass(renderPassDescriptor);
1731
+ this.handle = this.props.handle || commandEncoder.beginRenderPass(renderPassDescriptor);
1801
1732
  if (profiler) {
1802
1733
  profiler.renderPassBeginCount = (profiler.renderPassBeginCount || 0) + 1;
1803
1734
  profiler.renderPassBeginTimeMs = (profiler.renderPassBeginTimeMs || 0) + (getTimestamp() - beginRenderPassStartTime);
@@ -1808,9 +1739,9 @@ var init_webgpu_render_pass = __esm({
1808
1739
  this.device.debug();
1809
1740
  });
1810
1741
  this.handle.label = this.props.id;
1811
- import_core17.log.groupCollapsed(3, `new WebGPURenderPass(${this.id})`)();
1812
- import_core17.log.probe(3, JSON.stringify(renderPassDescriptor, null, 2))();
1813
- import_core17.log.groupEnd(3)();
1742
+ import_core16.log.groupCollapsed(3, `new WebGPURenderPass(${this.id})`)();
1743
+ import_core16.log.probe(3, JSON.stringify(renderPassDescriptor, null, 2))();
1744
+ import_core16.log.groupEnd(3)();
1814
1745
  } finally {
1815
1746
  if (profiler) {
1816
1747
  profiler.renderPassSetupCount = (profiler.renderPassSetupCount || 0) + 1;
@@ -1840,11 +1771,12 @@ var init_webgpu_render_pass = __esm({
1840
1771
  }
1841
1772
  /** Sets an array of bindings (uniform buffers, samplers, textures, ...) */
1842
1773
  setBindings(bindings) {
1843
- var _a;
1844
1774
  this.bindings = bindings;
1845
- const bindGroup = (_a = this.pipeline) == null ? void 0 : _a._getBindGroup(bindings);
1846
- if (bindGroup) {
1847
- this.handle.setBindGroup(0, bindGroup);
1775
+ const bindGroups = this.pipeline && (0, import_core16._getDefaultBindGroupFactory)(this.device).getBindGroups(this.pipeline, bindings) || {};
1776
+ for (const [group, bindGroup] of Object.entries(bindGroups)) {
1777
+ if (bindGroup) {
1778
+ this.handle.setBindGroup(Number(group), bindGroup);
1779
+ }
1848
1780
  }
1849
1781
  }
1850
1782
  setIndexBuffer(buffer, indexFormat, offset = 0, size) {
@@ -1907,7 +1839,7 @@ var init_webgpu_render_pass = __esm({
1907
1839
  return {
1908
1840
  // clear values
1909
1841
  loadOp: this.props.clearColor !== false ? "clear" : "load",
1910
- clearValue: convertColor(((_a = this.props.clearColors) == null ? void 0 : _a[index]) || this.props.clearColor || import_core17.RenderPass.defaultClearColor),
1842
+ clearValue: convertColor(((_a = this.props.clearColors) == null ? void 0 : _a[index]) || this.props.clearColor || import_core16.RenderPass.defaultClearColor),
1911
1843
  storeOp: this.props.discard ? "discard" : "store",
1912
1844
  // ...colorAttachment,
1913
1845
  view: colorAttachment.handle
@@ -1942,16 +1874,16 @@ var init_webgpu_render_pass = __esm({
1942
1874
  });
1943
1875
 
1944
1876
  // dist/adapter/resources/webgpu-compute-pass.js
1945
- var import_core18, WebGPUComputePass;
1877
+ var import_core17, WebGPUComputePass;
1946
1878
  var init_webgpu_compute_pass = __esm({
1947
1879
  "dist/adapter/resources/webgpu-compute-pass.js"() {
1948
1880
  "use strict";
1949
- import_core18 = require("@luma.gl/core");
1950
- WebGPUComputePass = class extends import_core18.ComputePass {
1881
+ import_core17 = require("@luma.gl/core");
1882
+ WebGPUComputePass = class extends import_core17.ComputePass {
1951
1883
  device;
1952
1884
  handle;
1953
1885
  _webgpuPipeline = null;
1954
- constructor(device, props = {}) {
1886
+ constructor(device, props = {}, commandEncoder = device.commandEncoder.handle) {
1955
1887
  super(device, props);
1956
1888
  this.device = device;
1957
1889
  const { props: computePassProps } = this;
@@ -1967,7 +1899,7 @@ var init_webgpu_compute_pass = __esm({
1967
1899
  };
1968
1900
  }
1969
1901
  }
1970
- this.handle = this.props.handle || device.commandEncoder.handle.beginComputePass({
1902
+ this.handle = this.props.handle || commandEncoder.beginComputePass({
1971
1903
  label: this.props.id,
1972
1904
  timestampWrites
1973
1905
  });
@@ -1987,15 +1919,24 @@ var init_webgpu_compute_pass = __esm({
1987
1919
  const wgpuPipeline = pipeline;
1988
1920
  this.handle.setPipeline(wgpuPipeline.handle);
1989
1921
  this._webgpuPipeline = wgpuPipeline;
1990
- this.setBindings([]);
1922
+ const bindGroups = (0, import_core17._getDefaultBindGroupFactory)(this.device).getBindGroups(this._webgpuPipeline, this._webgpuPipeline._getBindingsByGroupWebGPU(), this._webgpuPipeline._getBindGroupCacheKeysWebGPU());
1923
+ for (const [group, bindGroup] of Object.entries(bindGroups)) {
1924
+ if (bindGroup) {
1925
+ this.handle.setBindGroup(Number(group), bindGroup);
1926
+ }
1927
+ }
1991
1928
  }
1992
1929
  /**
1993
1930
  * Sets an array of bindings (uniform buffers, samplers, textures, ...)
1994
1931
  * TODO - still some API confusion - does this method go here or on the pipeline?
1995
1932
  */
1996
1933
  setBindings(bindings) {
1997
- const bindGroup = this._webgpuPipeline._getBindGroup();
1998
- this.handle.setBindGroup(0, bindGroup);
1934
+ const bindGroups = this._webgpuPipeline && (0, import_core17._getDefaultBindGroupFactory)(this.device).getBindGroups(this._webgpuPipeline, bindings) || {};
1935
+ for (const [group, bindGroup] of Object.entries(bindGroups)) {
1936
+ if (bindGroup) {
1937
+ this.handle.setBindGroup(Number(group), bindGroup);
1938
+ }
1939
+ }
1999
1940
  }
2000
1941
  /**
2001
1942
  * Dispatch work to be performed with the current ComputePipeline.
@@ -2031,15 +1972,15 @@ var init_webgpu_compute_pass = __esm({
2031
1972
  });
2032
1973
 
2033
1974
  // dist/adapter/resources/webgpu-command-encoder.js
2034
- var import_core19, WebGPUCommandEncoder;
1975
+ var import_core18, WebGPUCommandEncoder;
2035
1976
  var init_webgpu_command_encoder = __esm({
2036
1977
  "dist/adapter/resources/webgpu-command-encoder.js"() {
2037
1978
  "use strict";
2038
- import_core19 = require("@luma.gl/core");
1979
+ import_core18 = require("@luma.gl/core");
2039
1980
  init_webgpu_command_buffer();
2040
1981
  init_webgpu_render_pass();
2041
1982
  init_webgpu_compute_pass();
2042
- WebGPUCommandEncoder = class extends import_core19.CommandEncoder {
1983
+ WebGPUCommandEncoder = class extends import_core18.CommandEncoder {
2043
1984
  device;
2044
1985
  handle;
2045
1986
  constructor(device, props = {}) {
@@ -2073,42 +2014,97 @@ var init_webgpu_command_encoder = __esm({
2073
2014
  * @todo need to support a "Framebuffer" equivalent (aka preconfigured RenderPassDescriptors?).
2074
2015
  */
2075
2016
  beginRenderPass(props = {}) {
2076
- return new WebGPURenderPass(this.device, this._applyTimeProfilingToPassProps(props));
2017
+ return new WebGPURenderPass(this.device, this._applyTimeProfilingToPassProps(props), this.handle);
2077
2018
  }
2078
2019
  beginComputePass(props = {}) {
2079
- return new WebGPUComputePass(this.device, this._applyTimeProfilingToPassProps(props));
2020
+ return new WebGPUComputePass(this.device, this._applyTimeProfilingToPassProps(props), this.handle);
2080
2021
  }
2081
2022
  // beginRenderPass(GPURenderPassDescriptor descriptor): GPURenderPassEncoder;
2082
2023
  // beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
2083
2024
  copyBufferToBuffer(options) {
2084
2025
  const webgpuSourceBuffer = options.sourceBuffer;
2085
- const WebGPUDestinationBuffer = options.destinationBuffer;
2086
- this.handle.copyBufferToBuffer(webgpuSourceBuffer.handle, options.sourceOffset ?? 0, WebGPUDestinationBuffer.handle, options.destinationOffset ?? 0, options.size ?? 0);
2026
+ const webgpuDestinationBuffer = options.destinationBuffer;
2027
+ this.handle.copyBufferToBuffer(webgpuSourceBuffer.handle, options.sourceOffset ?? 0, webgpuDestinationBuffer.handle, options.destinationOffset ?? 0, options.size ?? 0);
2087
2028
  }
2088
2029
  copyBufferToTexture(options) {
2089
- var _a, _b, _c;
2090
2030
  const webgpuSourceBuffer = options.sourceBuffer;
2091
- const WebGPUDestinationTexture = options.destinationTexture;
2031
+ const webgpuDestinationTexture = options.destinationTexture;
2032
+ const copyOrigin = options.origin ?? [0, 0, 0];
2033
+ const copySize = options.size;
2092
2034
  this.handle.copyBufferToTexture({
2093
2035
  buffer: webgpuSourceBuffer.handle,
2094
- offset: options.offset ?? 0,
2036
+ offset: options.byteOffset ?? 0,
2095
2037
  bytesPerRow: options.bytesPerRow,
2096
2038
  rowsPerImage: options.rowsPerImage
2097
2039
  }, {
2098
- texture: WebGPUDestinationTexture.handle,
2040
+ texture: webgpuDestinationTexture.handle,
2099
2041
  mipLevel: options.mipLevel ?? 0,
2100
- origin: options.origin ?? {}
2101
- // aspect: options.aspect
2042
+ origin: {
2043
+ x: copyOrigin[0] ?? 0,
2044
+ y: copyOrigin[1] ?? 0,
2045
+ z: copyOrigin[2] ?? 0
2046
+ },
2047
+ aspect: options.aspect
2102
2048
  }, {
2103
- // @ts-ignore
2104
- width: (_a = options.extent) == null ? void 0 : _a[0],
2105
- height: (_b = options.extent) == null ? void 0 : _b[1],
2106
- depthOrArrayLayers: (_c = options.extent) == null ? void 0 : _c[2]
2049
+ width: copySize[0],
2050
+ height: copySize[1],
2051
+ depthOrArrayLayers: copySize[2]
2107
2052
  });
2108
2053
  }
2109
2054
  copyTextureToBuffer(options) {
2055
+ const { sourceTexture, destinationBuffer, origin = [0, 0, 0], byteOffset = 0, width, height, depthOrArrayLayers, mipLevel, aspect } = options;
2056
+ const webgpuSourceTexture = sourceTexture;
2057
+ webgpuSourceTexture.copyToBuffer(this.handle, {
2058
+ x: origin[0] ?? 0,
2059
+ y: origin[1] ?? 0,
2060
+ z: origin[2] ?? 0,
2061
+ width,
2062
+ height,
2063
+ depthOrArrayLayers,
2064
+ mipLevel,
2065
+ aspect,
2066
+ byteOffset,
2067
+ bytesPerRow: options.bytesPerRow,
2068
+ rowsPerImage: options.rowsPerImage
2069
+ }, destinationBuffer);
2110
2070
  }
2111
2071
  copyTextureToTexture(options) {
2072
+ var _a, _b, _c, _d, _e, _f;
2073
+ const webgpuSourceTexture = options.sourceTexture;
2074
+ const webgpuDestinationTexture = options.destinationTexture;
2075
+ const sourceRegion = webgpuSourceTexture._normalizeTextureReadOptions({
2076
+ x: ((_a = options.origin) == null ? void 0 : _a[0]) ?? 0,
2077
+ y: ((_b = options.origin) == null ? void 0 : _b[1]) ?? 0,
2078
+ z: ((_c = options.origin) == null ? void 0 : _c[2]) ?? 0,
2079
+ width: options.width,
2080
+ height: options.height,
2081
+ depthOrArrayLayers: options.depthOrArrayLayers,
2082
+ mipLevel: options.mipLevel ?? 0,
2083
+ aspect: options.aspect ?? "all"
2084
+ });
2085
+ this.handle.copyTextureToTexture({
2086
+ texture: webgpuSourceTexture.handle,
2087
+ mipLevel: sourceRegion.mipLevel,
2088
+ origin: {
2089
+ x: sourceRegion.x,
2090
+ y: sourceRegion.y,
2091
+ z: sourceRegion.z
2092
+ },
2093
+ aspect: sourceRegion.aspect
2094
+ }, {
2095
+ texture: webgpuDestinationTexture.handle,
2096
+ mipLevel: options.destinationMipLevel ?? 0,
2097
+ origin: {
2098
+ x: ((_d = options.destinationOrigin) == null ? void 0 : _d[0]) ?? 0,
2099
+ y: ((_e = options.destinationOrigin) == null ? void 0 : _e[1]) ?? 0,
2100
+ z: ((_f = options.destinationOrigin) == null ? void 0 : _f[2]) ?? 0
2101
+ },
2102
+ aspect: options.destinationAspect ?? sourceRegion.aspect
2103
+ }, {
2104
+ width: sourceRegion.width,
2105
+ height: sourceRegion.height,
2106
+ depthOrArrayLayers: sourceRegion.depthOrArrayLayers
2107
+ });
2112
2108
  }
2113
2109
  pushDebugGroup(groupLabel) {
2114
2110
  this.handle.pushDebugGroup(groupLabel);
@@ -2144,13 +2140,13 @@ var init_webgpu_command_encoder = __esm({
2144
2140
  });
2145
2141
 
2146
2142
  // dist/adapter/resources/webgpu-query-set.js
2147
- var import_core20, WebGPUQuerySet;
2143
+ var import_core19, WebGPUQuerySet;
2148
2144
  var init_webgpu_query_set = __esm({
2149
2145
  "dist/adapter/resources/webgpu-query-set.js"() {
2150
2146
  "use strict";
2151
- import_core20 = require("@luma.gl/core");
2147
+ import_core19 = require("@luma.gl/core");
2152
2148
  init_cpu_hotspot_profiler();
2153
- WebGPUQuerySet = class extends import_core20.QuerySet {
2149
+ WebGPUQuerySet = class extends import_core19.QuerySet {
2154
2150
  device;
2155
2151
  handle;
2156
2152
  _resolveBuffer = null;
@@ -2259,13 +2255,13 @@ var init_webgpu_query_set = __esm({
2259
2255
  const byteLength = this.props.count * 8;
2260
2256
  this._resolveBuffer = this.device.createBuffer({
2261
2257
  id: `${this.id}-resolve-buffer`,
2262
- usage: import_core20.Buffer.QUERY_RESOLVE | import_core20.Buffer.COPY_SRC,
2258
+ usage: import_core19.Buffer.QUERY_RESOLVE | import_core19.Buffer.COPY_SRC,
2263
2259
  byteLength
2264
2260
  });
2265
2261
  this.attachResource(this._resolveBuffer);
2266
2262
  this._readBuffer = this.device.createBuffer({
2267
2263
  id: `${this.id}-read-buffer`,
2268
- usage: import_core20.Buffer.COPY_DST | import_core20.Buffer.MAP_READ,
2264
+ usage: import_core19.Buffer.COPY_DST | import_core19.Buffer.MAP_READ,
2269
2265
  byteLength
2270
2266
  });
2271
2267
  this.attachResource(this._readBuffer);
@@ -2302,36 +2298,32 @@ var init_webgpu_query_set = __esm({
2302
2298
  });
2303
2299
 
2304
2300
  // dist/adapter/resources/webgpu-pipeline-layout.js
2305
- var import_core21, WebGPUPipelineLayout, isStorageTextureBindingLayout;
2301
+ var import_core20, WebGPUPipelineLayout, isStorageTextureBindingLayout;
2306
2302
  var init_webgpu_pipeline_layout = __esm({
2307
2303
  "dist/adapter/resources/webgpu-pipeline-layout.js"() {
2308
2304
  "use strict";
2309
- import_core21 = require("@luma.gl/core");
2310
- WebGPUPipelineLayout = class extends import_core21.PipelineLayout {
2305
+ import_core20 = require("@luma.gl/core");
2306
+ WebGPUPipelineLayout = class extends import_core20.PipelineLayout {
2311
2307
  device;
2312
2308
  handle;
2313
2309
  constructor(device, props) {
2314
2310
  super(device, props);
2315
2311
  this.device = device;
2316
- const bindGroupEntries = this.mapShaderLayoutToBindGroupEntries();
2312
+ const bindGroupEntriesByGroup = this.mapShaderLayoutToBindGroupEntriesByGroup();
2317
2313
  this.handle = this.device.handle.createPipelineLayout({
2318
2314
  label: (props == null ? void 0 : props.id) ?? "unnamed-pipeline-layout",
2319
- bindGroupLayouts: [
2320
- // TODO (kaapp): We can cache these to re-use them across
2321
- // layers, particularly if using a separate group for injected
2322
- // bindings (e.g. project/lighting)
2323
- this.device.handle.createBindGroupLayout({
2324
- label: "bind-group-layout",
2325
- entries: bindGroupEntries
2326
- })
2327
- ]
2315
+ bindGroupLayouts: bindGroupEntriesByGroup.map((entries, group) => this.device.handle.createBindGroupLayout({
2316
+ label: `bind-group-layout-${group}`,
2317
+ entries
2318
+ }))
2328
2319
  });
2329
2320
  }
2330
2321
  destroy() {
2331
2322
  this.handle = null;
2332
2323
  }
2333
- mapShaderLayoutToBindGroupEntries() {
2334
- const bindGroupEntries = [];
2324
+ mapShaderLayoutToBindGroupEntriesByGroup() {
2325
+ const maxGroup = this.props.shaderLayout.bindings.reduce((highestGroup, binding) => Math.max(highestGroup, binding.group), -1);
2326
+ const bindGroupEntriesByGroup = Array.from({ length: maxGroup + 1 }, () => []);
2335
2327
  for (const binding of this.props.shaderLayout.bindings) {
2336
2328
  const bindingTypeInfo = {};
2337
2329
  switch (binding.type) {
@@ -2384,17 +2376,17 @@ var init_webgpu_pipeline_layout = __esm({
2384
2376
  break;
2385
2377
  }
2386
2378
  default: {
2387
- import_core21.log.warn("unhandled binding type when creating pipeline descriptor")();
2379
+ import_core20.log.warn("unhandled binding type when creating pipeline descriptor")();
2388
2380
  }
2389
2381
  }
2390
2382
  const VISIBILITY_ALL = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE;
2391
- bindGroupEntries.push({
2383
+ bindGroupEntriesByGroup[binding.group].push({
2392
2384
  binding: binding.location,
2393
2385
  visibility: binding.visibility || VISIBILITY_ALL,
2394
2386
  ...bindingTypeInfo
2395
2387
  });
2396
2388
  }
2397
- return bindGroupEntries;
2389
+ return bindGroupEntriesByGroup;
2398
2390
  }
2399
2391
  };
2400
2392
  isStorageTextureBindingLayout = (maybe) => {
@@ -2404,12 +2396,12 @@ var init_webgpu_pipeline_layout = __esm({
2404
2396
  });
2405
2397
 
2406
2398
  // dist/adapter/resources/webgpu-fence.js
2407
- var import_core22, WebGPUFence;
2399
+ var import_core21, WebGPUFence;
2408
2400
  var init_webgpu_fence = __esm({
2409
2401
  "dist/adapter/resources/webgpu-fence.js"() {
2410
2402
  "use strict";
2411
- import_core22 = require("@luma.gl/core");
2412
- WebGPUFence = class extends import_core22.Fence {
2403
+ import_core21 = require("@luma.gl/core");
2404
+ WebGPUFence = class extends import_core21.Fence {
2413
2405
  device;
2414
2406
  handle = null;
2415
2407
  signaled;
@@ -2419,6 +2411,11 @@ var init_webgpu_fence = __esm({
2419
2411
  this.device = device;
2420
2412
  this.signaled = device.handle.queue.onSubmittedWorkDone().then(() => {
2421
2413
  this._signaled = true;
2414
+ }).catch((error) => {
2415
+ if (this.device.shouldIgnoreDroppedInstanceError(error)) {
2416
+ return;
2417
+ }
2418
+ throw error;
2422
2419
  });
2423
2420
  }
2424
2421
  isSignaled() {
@@ -2438,7 +2435,7 @@ function getShaderLayoutFromWGSL(source) {
2438
2435
  try {
2439
2436
  parsedWGSL = parseWGSL(source);
2440
2437
  } catch (error) {
2441
- import_core23.log.error(error.message)();
2438
+ import_core22.log.error(error.message)();
2442
2439
  return shaderLayout;
2443
2440
  }
2444
2441
  for (const uniform of parsedWGSL.uniforms) {
@@ -2458,6 +2455,14 @@ function getShaderLayoutFromWGSL(source) {
2458
2455
  members
2459
2456
  });
2460
2457
  }
2458
+ for (const storageBuffer of parsedWGSL.storage) {
2459
+ shaderLayout.bindings.push({
2460
+ type: storageBuffer.access === "read" ? "read-only-storage" : "storage",
2461
+ name: storageBuffer.name,
2462
+ group: storageBuffer.group,
2463
+ location: storageBuffer.binding
2464
+ });
2465
+ }
2461
2466
  for (const texture of parsedWGSL.textures) {
2462
2467
  const bindingDeclaration = {
2463
2468
  type: "texture",
@@ -2532,11 +2537,11 @@ function getTextureBindingFromReflect(v, opts) {
2532
2537
  }
2533
2538
  return { viewDimension, sampleType, multisampled };
2534
2539
  }
2535
- var import_core23, import_wgsl_reflect;
2540
+ var import_core22, import_wgsl_reflect;
2536
2541
  var init_get_shader_layout_wgsl = __esm({
2537
2542
  "dist/wgsl/get-shader-layout-wgsl.js"() {
2538
2543
  "use strict";
2539
- import_core23 = require("@luma.gl/core");
2544
+ import_core22 = require("@luma.gl/core");
2540
2545
  import_wgsl_reflect = require("wgsl_reflect");
2541
2546
  }
2542
2547
  });
@@ -2564,7 +2569,7 @@ function generateMipmapsRender(device, texture) {
2564
2569
  const sampler = device.createSampler({ minFilter: "linear", magFilter: "linear" });
2565
2570
  const uniformsBuffer = device.createBuffer({
2566
2571
  byteLength: 16,
2567
- usage: import_core24.Buffer.UNIFORM | import_core24.Buffer.COPY_DST
2572
+ usage: import_core23.Buffer.UNIFORM | import_core23.Buffer.COPY_DST
2568
2573
  });
2569
2574
  const uniformValues = new Uint32Array(1);
2570
2575
  const sourceTextureLayout = {
@@ -2676,7 +2681,7 @@ function generateMipmapsRender(device, texture) {
2676
2681
  }
2677
2682
  }
2678
2683
  function getColorAttachmentFormat(format, path, dimension) {
2679
- if (import_core24.textureFormatDecoder.isColor(format)) {
2684
+ if (import_core23.textureFormatDecoder.isColor(format)) {
2680
2685
  return format;
2681
2686
  }
2682
2687
  throw new Error(`Cannot run ${path} mipmap generation for ${dimension} texture with format "${format}". Only color textures can be used for this operation. Required capabilities: color. Actual capabilities: color=false.`);
@@ -2710,7 +2715,7 @@ function generateMipmaps3D(device, texture) {
2710
2715
  });
2711
2716
  const uniformsBuffer = device.createBuffer({
2712
2717
  byteLength: 32,
2713
- usage: import_core24.Buffer.UNIFORM | import_core24.Buffer.COPY_DST
2718
+ usage: import_core23.Buffer.UNIFORM | import_core23.Buffer.COPY_DST
2714
2719
  });
2715
2720
  const uniformValues = new Uint32Array(8);
2716
2721
  let sourceWidth = texture.width;
@@ -2977,11 +2982,11 @@ fn main(@builtin(global_invocation_id) id: vec3<u32>) {
2977
2982
  }
2978
2983
  `;
2979
2984
  }
2980
- var import_core24, RENDER_DIMENSIONS, WORKGROUP_SIZE, RENDER_SOURCE_SAMPLER_LAYOUT, COMPUTE_SOURCE_TEXTURE_LAYOUT, COMPUTE_UNIFORMS_LAYOUT;
2985
+ var import_core23, RENDER_DIMENSIONS, WORKGROUP_SIZE, RENDER_SOURCE_SAMPLER_LAYOUT, COMPUTE_SOURCE_TEXTURE_LAYOUT, COMPUTE_UNIFORMS_LAYOUT;
2981
2986
  var init_generate_mipmaps_webgpu = __esm({
2982
2987
  "dist/adapter/helpers/generate-mipmaps-webgpu.js"() {
2983
2988
  "use strict";
2984
- import_core24 = require("@luma.gl/core");
2989
+ import_core23 = require("@luma.gl/core");
2985
2990
  RENDER_DIMENSIONS = [
2986
2991
  "2d",
2987
2992
  "2d-array",
@@ -3016,6 +3021,90 @@ var init_generate_mipmaps_webgpu = __esm({
3016
3021
  }
3017
3022
  });
3018
3023
 
3024
+ // dist/adapter/helpers/get-bind-group.js
3025
+ function getBindGroup(device, bindGroupLayout, shaderLayout, bindings, group) {
3026
+ const entries = getBindGroupEntries(bindings, shaderLayout, group);
3027
+ if (entries.length === 0) {
3028
+ return null;
3029
+ }
3030
+ device.pushErrorScope("validation");
3031
+ const bindGroup = device.handle.createBindGroup({
3032
+ layout: bindGroupLayout,
3033
+ entries
3034
+ });
3035
+ device.popErrorScope((error) => {
3036
+ import_core24.log.error(`bindGroup creation: ${error.message}`, bindGroup)();
3037
+ });
3038
+ return bindGroup;
3039
+ }
3040
+ function getBindGroupEntries(bindings, shaderLayout, group) {
3041
+ const entries = [];
3042
+ for (const [bindingName, value] of Object.entries(bindings)) {
3043
+ const exactBindingLayout = shaderLayout.bindings.find((binding) => binding.name === bindingName);
3044
+ const bindingLayout = exactBindingLayout || (0, import_core24.getShaderLayoutBinding)(shaderLayout, bindingName);
3045
+ const isShadowedAlias = !exactBindingLayout && bindingLayout ? bindingLayout.name in bindings : false;
3046
+ if (!isShadowedAlias && (bindingLayout == null ? void 0 : bindingLayout.group) === group) {
3047
+ const entry = bindingLayout ? getBindGroupEntry(value, bindingLayout.location, void 0, bindingName) : null;
3048
+ if (entry) {
3049
+ entries.push(entry);
3050
+ }
3051
+ if (value instanceof import_core24.Texture) {
3052
+ const samplerBindingLayout = (0, import_core24.getShaderLayoutBinding)(shaderLayout, `${bindingName}Sampler`, {
3053
+ ignoreWarnings: true
3054
+ });
3055
+ const samplerEntry = samplerBindingLayout ? samplerBindingLayout.group === group ? getBindGroupEntry(value, samplerBindingLayout.location, { sampler: true }, bindingName) : null : null;
3056
+ if (samplerEntry) {
3057
+ entries.push(samplerEntry);
3058
+ }
3059
+ }
3060
+ }
3061
+ }
3062
+ return entries;
3063
+ }
3064
+ function getBindGroupEntry(binding, index, options, bindingName = "unknown") {
3065
+ if (binding instanceof import_core24.Buffer) {
3066
+ return {
3067
+ binding: index,
3068
+ resource: {
3069
+ buffer: binding.handle
3070
+ }
3071
+ };
3072
+ }
3073
+ if (binding instanceof import_core24.Sampler) {
3074
+ return {
3075
+ binding: index,
3076
+ resource: binding.handle
3077
+ };
3078
+ }
3079
+ if (binding instanceof import_core24.TextureView) {
3080
+ return {
3081
+ binding: index,
3082
+ resource: binding.handle
3083
+ };
3084
+ }
3085
+ if (binding instanceof import_core24.Texture) {
3086
+ if (options == null ? void 0 : options.sampler) {
3087
+ return {
3088
+ binding: index,
3089
+ resource: binding.sampler.handle
3090
+ };
3091
+ }
3092
+ return {
3093
+ binding: index,
3094
+ resource: binding.view.handle
3095
+ };
3096
+ }
3097
+ import_core24.log.warn(`invalid binding ${bindingName}`, binding);
3098
+ return null;
3099
+ }
3100
+ var import_core24;
3101
+ var init_get_bind_group = __esm({
3102
+ "dist/adapter/helpers/get-bind-group.js"() {
3103
+ "use strict";
3104
+ import_core24 = require("@luma.gl/core");
3105
+ }
3106
+ });
3107
+
3019
3108
  // dist/adapter/webgpu-device.js
3020
3109
  var webgpu_device_exports = {};
3021
3110
  __export(webgpu_device_exports, {
@@ -3051,6 +3140,7 @@ var init_webgpu_device = __esm({
3051
3140
  init_webgpu_fence();
3052
3141
  init_get_shader_layout_wgsl();
3053
3142
  init_generate_mipmaps_webgpu();
3143
+ init_get_bind_group();
3054
3144
  init_cpu_hotspot_profiler();
3055
3145
  WebGPUDevice = class extends import_core25.Device {
3056
3146
  /** The underlying WebGPU device */
@@ -3182,23 +3272,22 @@ var init_webgpu_device = __esm({
3182
3272
  generateMipmapsWebGPU(texture) {
3183
3273
  generateMipmapsWebGPU(this, texture);
3184
3274
  }
3275
+ _createBindGroupLayoutWebGPU(pipeline, group) {
3276
+ return pipeline.handle.getBindGroupLayout(group);
3277
+ }
3278
+ _createBindGroupWebGPU(bindGroupLayout, shaderLayout, bindings, group) {
3279
+ if (Object.keys(bindings).length === 0) {
3280
+ return this.handle.createBindGroup({
3281
+ layout: bindGroupLayout,
3282
+ entries: []
3283
+ });
3284
+ }
3285
+ return getBindGroup(this, bindGroupLayout, shaderLayout, bindings, group);
3286
+ }
3185
3287
  submit(commandBuffer) {
3186
3288
  let submittedCommandEncoder = null;
3187
3289
  if (!commandBuffer) {
3188
- submittedCommandEncoder = this.commandEncoder;
3189
- if (submittedCommandEncoder.getTimeProfilingSlotCount() > 0 && submittedCommandEncoder.getTimeProfilingQuerySet() instanceof WebGPUQuerySet) {
3190
- const querySet = submittedCommandEncoder.getTimeProfilingQuerySet();
3191
- querySet._encodeResolveToReadBuffer(submittedCommandEncoder, {
3192
- firstQuery: 0,
3193
- queryCount: submittedCommandEncoder.getTimeProfilingSlotCount()
3194
- });
3195
- }
3196
- commandBuffer = submittedCommandEncoder.finish();
3197
- this.commandEncoder.destroy();
3198
- this.commandEncoder = this.createCommandEncoder({
3199
- id: submittedCommandEncoder.props.id,
3200
- timeProfilingQuerySet: submittedCommandEncoder.getTimeProfilingQuerySet()
3201
- });
3290
+ ({ submittedCommandEncoder, commandBuffer } = this._finalizeDefaultCommandEncoderForSubmit());
3202
3291
  }
3203
3292
  const profiler = getCpuHotspotProfiler(this);
3204
3293
  const startTime = profiler ? getTimestamp() : 0;
@@ -3245,6 +3334,23 @@ var init_webgpu_device = __esm({
3245
3334
  }
3246
3335
  }
3247
3336
  }
3337
+ _finalizeDefaultCommandEncoderForSubmit() {
3338
+ const submittedCommandEncoder = this.commandEncoder;
3339
+ if (submittedCommandEncoder.getTimeProfilingSlotCount() > 0 && submittedCommandEncoder.getTimeProfilingQuerySet() instanceof WebGPUQuerySet) {
3340
+ const querySet = submittedCommandEncoder.getTimeProfilingQuerySet();
3341
+ querySet._encodeResolveToReadBuffer(submittedCommandEncoder, {
3342
+ firstQuery: 0,
3343
+ queryCount: submittedCommandEncoder.getTimeProfilingSlotCount()
3344
+ });
3345
+ }
3346
+ const commandBuffer = submittedCommandEncoder.finish();
3347
+ this.commandEncoder.destroy();
3348
+ this.commandEncoder = this.createCommandEncoder({
3349
+ id: submittedCommandEncoder.props.id,
3350
+ timeProfilingQuerySet: submittedCommandEncoder.getTimeProfilingQuerySet()
3351
+ });
3352
+ return { submittedCommandEncoder, commandBuffer };
3353
+ }
3248
3354
  // WebGPU specific
3249
3355
  pushErrorScope(scope) {
3250
3356
  if (!this.props.debug) {
@@ -3268,6 +3374,13 @@ var init_webgpu_device = __esm({
3268
3374
  if (error) {
3269
3375
  handler(error);
3270
3376
  }
3377
+ }).catch((error) => {
3378
+ if (this.shouldIgnoreDroppedInstanceError(error, "popErrorScope")) {
3379
+ return;
3380
+ }
3381
+ const errorMessage = error instanceof Error ? error.message : String(error);
3382
+ this.reportError(new Error(`${this} popErrorScope failed: ${errorMessage}`), this)();
3383
+ this.debug();
3271
3384
  });
3272
3385
  if (profiler) {
3273
3386
  profiler.errorScopePopCount = (profiler.errorScopePopCount || 0) + 1;
@@ -3280,10 +3393,12 @@ var init_webgpu_device = __esm({
3280
3393
  const vendor = this.adapterInfo.vendor || this.adapter.__brand || "unknown";
3281
3394
  const renderer = driver || "";
3282
3395
  const version = driverVersion || "";
3283
- const gpu = vendor === "apple" ? "apple" : "unknown";
3396
+ const fallback = Boolean(this.adapterInfo.isFallbackAdapter ?? this.adapter.isFallbackAdapter ?? false);
3397
+ const softwareRenderer = /SwiftShader/i.test(`${vendor} ${renderer} ${this.adapterInfo.architecture || ""}`);
3398
+ const gpu = vendor === "apple" ? "apple" : softwareRenderer || fallback ? "software" : "unknown";
3284
3399
  const gpuArchitecture = this.adapterInfo.architecture || "unknown";
3285
3400
  const gpuBackend = this.adapterInfo.backend || "unknown";
3286
- const gpuType = (this.adapterInfo.type || "").split(" ")[0].toLowerCase() || "unknown";
3401
+ const gpuType = (this.adapterInfo.type || "").split(" ")[0].toLowerCase() || (softwareRenderer || fallback ? "cpu" : "unknown");
3287
3402
  return {
3288
3403
  type: "webgpu",
3289
3404
  vendor,
@@ -3293,10 +3408,15 @@ var init_webgpu_device = __esm({
3293
3408
  gpuType,
3294
3409
  gpuBackend,
3295
3410
  gpuArchitecture,
3411
+ fallback,
3296
3412
  shadingLanguage: "wgsl",
3297
3413
  shadingLanguageVersion: 100
3298
3414
  };
3299
3415
  }
3416
+ shouldIgnoreDroppedInstanceError(error, operation) {
3417
+ const errorMessage = error instanceof Error ? error.message : String(error);
3418
+ return errorMessage.includes("Instance dropped") && (!operation || errorMessage.includes(operation)) && (this._isLost || this.info.gpu === "software" || this.info.gpuType === "cpu" || Boolean(this.info.fallback));
3419
+ }
3300
3420
  _getFeatures() {
3301
3421
  const features = new Set(this.handle.features);
3302
3422
  if (features.has("depth-clamping")) {