@luma.gl/webgl 9.0.0-alpha.26 → 9.0.0-alpha.29

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 (56) hide show
  1. package/dist/adapter/helpers/get-shader-layout.d.ts +8 -5
  2. package/dist/adapter/helpers/get-shader-layout.d.ts.map +1 -1
  3. package/dist/adapter/helpers/get-shader-layout.js +59 -16
  4. package/dist/adapter/helpers/get-shader-layout.js.map +1 -1
  5. package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts +12 -0
  6. package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts.map +1 -0
  7. package/dist/adapter/helpers/get-vertex-buffer-layout.js +84 -0
  8. package/dist/adapter/helpers/get-vertex-buffer-layout.js.map +1 -0
  9. package/dist/adapter/objects/webgl-vertex-array-object.d.ts +35 -8
  10. package/dist/adapter/objects/webgl-vertex-array-object.d.ts.map +1 -1
  11. package/dist/adapter/objects/webgl-vertex-array-object.js +116 -16
  12. package/dist/adapter/objects/webgl-vertex-array-object.js.map +1 -1
  13. package/dist/adapter/resources/webgl-buffer.d.ts +13 -4
  14. package/dist/adapter/resources/webgl-buffer.d.ts.map +1 -1
  15. package/dist/adapter/resources/webgl-buffer.js +23 -21
  16. package/dist/adapter/resources/webgl-buffer.js.map +1 -1
  17. package/dist/adapter/resources/webgl-external-texture.js.map +1 -1
  18. package/dist/adapter/resources/webgl-render-pipeline.d.ts +38 -5
  19. package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
  20. package/dist/adapter/resources/webgl-render-pipeline.js +35 -7
  21. package/dist/adapter/resources/webgl-render-pipeline.js.map +1 -1
  22. package/dist/adapter/webgl-device.d.ts.map +1 -1
  23. package/dist/adapter/webgl-device.js +5 -2
  24. package/dist/adapter/webgl-device.js.map +1 -1
  25. package/dist/classic/buffer-with-accessor.d.ts +5 -15
  26. package/dist/classic/buffer-with-accessor.d.ts.map +1 -1
  27. package/dist/classic/buffer-with-accessor.js +25 -30
  28. package/dist/classic/buffer-with-accessor.js.map +1 -1
  29. package/dist/classic/copy-and-blit.d.ts.map +1 -1
  30. package/dist/classic/copy-and-blit.js +2 -2
  31. package/dist/classic/copy-and-blit.js.map +1 -1
  32. package/dist/context/debug/webgl-developer-tools.d.ts.map +1 -1
  33. package/dist/context/debug/webgl-developer-tools.js +2 -1
  34. package/dist/context/debug/webgl-developer-tools.js.map +1 -1
  35. package/dist/context/parameters/webgl-parameter-tables.js +2 -2
  36. package/dist/context/parameters/webgl-parameter-tables.js.map +1 -1
  37. package/dist/dist.dev.js +350 -99
  38. package/dist/index.cjs +343 -157
  39. package/dist/index.d.ts +1 -1
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +1 -1
  42. package/dist/index.js.map +1 -1
  43. package/dist.min.js +22 -22
  44. package/package.json +5 -5
  45. package/src/adapter/helpers/get-shader-layout.ts +93 -33
  46. package/src/adapter/helpers/get-vertex-buffer-layout.ts +123 -0
  47. package/src/adapter/objects/webgl-vertex-array-object.ts +192 -28
  48. package/src/adapter/resources/webgl-buffer.ts +40 -41
  49. package/src/adapter/resources/webgl-external-texture.ts +1 -1
  50. package/src/adapter/resources/webgl-render-pipeline.ts +73 -36
  51. package/src/adapter/webgl-device.ts +4 -2
  52. package/src/classic/buffer-with-accessor.ts +42 -43
  53. package/src/classic/copy-and-blit.ts +2 -3
  54. package/src/context/debug/webgl-developer-tools.ts +8 -2
  55. package/src/context/parameters/webgl-parameter-tables.ts +2 -2
  56. package/src/index.ts +1 -1
package/dist/dist.dev.js CHANGED
@@ -55,11 +55,11 @@ var __exports__ = (() => {
55
55
  convertGLToTextureFormat: () => convertGLToTextureFormat,
56
56
  copyToTexture: () => copyToTexture,
57
57
  getParameters: () => getParameters,
58
- getProgramBindings: () => getProgramBindings,
59
58
  getShaderLayout: () => getShaderLayout,
60
59
  getWebGL2Context: () => getWebGL2Context,
61
60
  isWebGL: () => isWebGL,
62
61
  isWebGL2: () => isWebGL2,
62
+ mergeShaderLayout: () => mergeShaderLayout,
63
63
  polyfillContext: () => polyfillContext,
64
64
  popContextState: () => popContextState,
65
65
  pushContextState: () => pushContextState,
@@ -1851,6 +1851,7 @@ var __exports__ = (() => {
1851
1851
  };
1852
1852
  /** Set attributes (stored on pipeline and set before each call) */
1853
1853
  /** Set attributes (stored on pipeline and set before each call) */
1854
+ /** Set constant attributes (WebGL only) */
1854
1855
  /** Set bindings (stored on pipeline and set before each call) */
1855
1856
  /** Uniforms (only supported on WebGL devices. Reset before each call to enable pipeline sharing) */
1856
1857
  /** Draw call */
@@ -1969,8 +1970,8 @@ var __exports__ = (() => {
1969
1970
  function decodeVertexType(type) {
1970
1971
  const dataType = TYPE_MAP[type];
1971
1972
  const bytes = getDataTypeBytes(dataType);
1972
- const integer = !type.startsWith("float");
1973
1973
  const normalized = type.includes("norm");
1974
+ const integer = !normalized && !type.startsWith("float");
1974
1975
  const signed = type.startsWith("s");
1975
1976
  return {
1976
1977
  dataType: TYPE_MAP[type],
@@ -2256,6 +2257,43 @@ var __exports__ = (() => {
2256
2257
  });
2257
2258
  }
2258
2259
 
2260
+ // ../api/src/lib/utils/array-utils-flat.ts
2261
+ var arrayBuffer;
2262
+ function getScratchArrayBuffer(byteLength) {
2263
+ if (!arrayBuffer || arrayBuffer.byteLength < byteLength) {
2264
+ arrayBuffer = new ArrayBuffer(byteLength);
2265
+ }
2266
+ return arrayBuffer;
2267
+ }
2268
+ function getScratchArray(Type, length) {
2269
+ const scratchArrayBuffer = getScratchArrayBuffer(Type.BYTES_PER_ELEMENT * length);
2270
+ return new Type(scratchArrayBuffer, 0, length);
2271
+ }
2272
+ function fillArray(options) {
2273
+ const {
2274
+ target,
2275
+ source,
2276
+ start = 0,
2277
+ count = 1
2278
+ } = options;
2279
+ const length = source.length;
2280
+ const total = count * length;
2281
+ let copied = 0;
2282
+ for (let i = start; copied < length; copied++) {
2283
+ target[i++] = source[copied];
2284
+ }
2285
+ while (copied < total) {
2286
+ if (copied < total - copied) {
2287
+ target.copyWithin(start + copied, start, start + copied);
2288
+ copied *= 2;
2289
+ } else {
2290
+ target.copyWithin(start + copied, start, start + total - copied);
2291
+ copied = total;
2292
+ }
2293
+ }
2294
+ return options.target;
2295
+ }
2296
+
2259
2297
  // src/context/polyfill/polyfill-vertex-array-object.ts
2260
2298
  var glErrorShadow = {};
2261
2299
  function error(msg) {
@@ -3665,8 +3703,8 @@ var __exports__ = (() => {
3665
3703
  [GL.PIXEL_PACK_BUFFER_BINDING]: GL.PIXEL_PACK_BUFFER,
3666
3704
  [GL.PIXEL_UNPACK_BUFFER_BINDING]: GL.PIXEL_UNPACK_BUFFER
3667
3705
  };
3668
- const target = bindingMap[key];
3669
- gl2.bindBuffer(target, value);
3706
+ const glTarget = bindingMap[key];
3707
+ gl2.bindBuffer(glTarget, value);
3670
3708
  };
3671
3709
  function isArray(array) {
3672
3710
  return Array.isArray(array) || ArrayBuffer.isView(array) && !(array instanceof DataView);
@@ -5790,8 +5828,14 @@ void main(void) {}`;
5790
5828
  // src/adapter/resources/webgl-buffer.ts
5791
5829
  var DEBUG_DATA_LENGTH = 10;
5792
5830
  var WEBGLBuffer = class extends Buffer2 {
5831
+ /** Target in OpenGL defines the type of buffer */
5832
+ /** Usage is a hint on how frequently the buffer will be updates */
5833
+ /** Index type is needed when issuing draw calls, so we pre-compute it */
5834
+ glIndexType = GL.UNSIGNED_SHORT;
5835
+ /** Number of bytes allocated on the GPU for this buffer */
5836
+ /** Number of bytes used */
5837
+ /** A partial CPU-side copy of the data in this buffer, for debugging purposes */
5793
5838
  debugData = null;
5794
- // accessor: {};
5795
5839
  constructor(device, props = {}) {
5796
5840
  super(device, props);
5797
5841
  this.device = device;
@@ -5803,8 +5847,9 @@ void main(void) {}`;
5803
5847
  ...this.props,
5804
5848
  data: typeof this.props.data
5805
5849
  });
5806
- this.target = this.props.target || getWebGLTarget(this.props.usage);
5807
- this.webglUsage = this.props.webglUsage || getWebGLUsage(this.props.usage);
5850
+ this.glTarget = getWebGLTarget(this.props.usage);
5851
+ this.glUsage = getWebGLUsage(this.props.usage);
5852
+ this.glIndexType = this.props.indexType === "uint32" ? GL.UNSIGNED_INT : GL.UNSIGNED_SHORT;
5808
5853
  this.debugData = null;
5809
5854
  if (props.data) {
5810
5855
  this._initWithData(props.data, props.byteOffset, props.byteLength);
@@ -5813,14 +5858,14 @@ void main(void) {}`;
5813
5858
  }
5814
5859
  }
5815
5860
  // PRIVATE METHODS
5816
- // Allocate a new buffer and initialize to contents of typed array
5861
+ /** Allocate a new buffer and initialize to contents of typed array */
5817
5862
  _initWithData(data, byteOffset = 0, byteLength = data.byteLength + byteOffset) {
5818
5863
  assert2(ArrayBuffer.isView(data));
5819
- const target = this._getWriteTarget();
5820
- this.gl.bindBuffer(target, this.handle);
5821
- this.gl.bufferData(target, byteLength, this.webglUsage);
5822
- this.gl.bufferSubData(target, byteOffset, data);
5823
- this.gl.bindBuffer(target, null);
5864
+ const glTarget = this._getWriteTarget();
5865
+ this.gl.bindBuffer(glTarget, this.handle);
5866
+ this.gl.bufferData(glTarget, byteLength, this.glUsage);
5867
+ this.gl.bufferSubData(glTarget, byteOffset, data);
5868
+ this.gl.bindBuffer(glTarget, null);
5824
5869
  this.debugData = data.slice(0, DEBUG_DATA_LENGTH);
5825
5870
  this.bytesUsed = byteLength;
5826
5871
  this.byteLength = byteLength;
@@ -5834,10 +5879,10 @@ void main(void) {}`;
5834
5879
  if (byteLength === 0) {
5835
5880
  data = new Float32Array(0);
5836
5881
  }
5837
- const target = this._getWriteTarget();
5838
- this.gl.bindBuffer(target, this.handle);
5839
- this.gl.bufferData(target, data, this.webglUsage);
5840
- this.gl.bindBuffer(target, null);
5882
+ const glTarget = this._getWriteTarget();
5883
+ this.gl.bindBuffer(glTarget, this.handle);
5884
+ this.gl.bufferData(glTarget, data, this.glUsage);
5885
+ this.gl.bindBuffer(glTarget, null);
5841
5886
  this.debugData = null;
5842
5887
  this.bytesUsed = byteLength;
5843
5888
  this.byteLength = byteLength;
@@ -5855,15 +5900,15 @@ void main(void) {}`;
5855
5900
  write(data, byteOffset = 0) {
5856
5901
  const srcOffset = 0;
5857
5902
  const byteLength = void 0;
5858
- const target = this.device.isWebGL2 ? GL.COPY_WRITE_BUFFER : this.target;
5859
- this.gl.bindBuffer(target, this.handle);
5903
+ const glTarget = this.device.isWebGL2 ? GL.COPY_WRITE_BUFFER : this.glTarget;
5904
+ this.gl.bindBuffer(glTarget, this.handle);
5860
5905
  if (srcOffset !== 0 || byteLength !== void 0) {
5861
5906
  this.device.assertWebGL2();
5862
- this.gl2.bufferSubData(target, byteOffset, data, srcOffset, byteLength);
5907
+ this.gl2.bufferSubData(glTarget, byteOffset, data, srcOffset, byteLength);
5863
5908
  } else {
5864
- this.gl.bufferSubData(target, byteOffset, data);
5909
+ this.gl.bufferSubData(glTarget, byteOffset, data);
5865
5910
  }
5866
- this.gl.bindBuffer(target, null);
5911
+ this.gl.bindBuffer(glTarget, null);
5867
5912
  }
5868
5913
  /** Read data from the buffer */
5869
5914
  async readAsync(byteOffset = 0, byteLength) {
@@ -5880,10 +5925,10 @@ void main(void) {}`;
5880
5925
  this.debugData = null;
5881
5926
  }
5882
5927
  _getWriteTarget() {
5883
- return this.target;
5928
+ return this.glTarget;
5884
5929
  }
5885
5930
  _getReadTarget() {
5886
- return this.target;
5931
+ return this.glTarget;
5887
5932
  }
5888
5933
  };
5889
5934
  function getWebGLTarget(usage) {
@@ -5908,7 +5953,7 @@ void main(void) {}`;
5908
5953
  if (usage & Buffer2.UNIFORM) {
5909
5954
  return GL.DYNAMIC_DRAW;
5910
5955
  }
5911
- return GL.DYNAMIC_DRAW;
5956
+ return GL.STATIC_DRAW;
5912
5957
  }
5913
5958
 
5914
5959
  // src/adapter/resources/webgl-sampler.ts
@@ -7329,7 +7374,7 @@ void main(void) {}`;
7329
7374
  return gl2.luma;
7330
7375
  }
7331
7376
  async function loadWebGLDeveloperTools() {
7332
- if (!globalThis.WebGLDebugUtils) {
7377
+ if (isBrowser() && !globalThis.WebGLDebugUtils) {
7333
7378
  globalThis.global = globalThis.global || globalThis;
7334
7379
  globalThis.global.module = {};
7335
7380
  await loadScript(WEBGL_DEBUG_CDN_URL);
@@ -7626,9 +7671,6 @@ void main(void) {}`;
7626
7671
  const bufferProps = {
7627
7672
  ...props
7628
7673
  };
7629
- if (bufferProps.offset) {
7630
- bufferProps.byteOffset = bufferProps.offset;
7631
- }
7632
7674
  return bufferProps;
7633
7675
  }
7634
7676
  var BufferWithAccessor = class extends WEBGLBuffer {
@@ -7671,11 +7713,11 @@ void main(void) {}`;
7671
7713
  };
7672
7714
  }
7673
7715
  props = checkProps("Buffer", props, PROP_CHECKS_INITIALIZE);
7674
- this.webglUsage = props.webglUsage || GL.STATIC_DRAW;
7716
+ this.glUsage = props.glUsage || GL.STATIC_DRAW;
7675
7717
  this.debugData = null;
7676
7718
  this.setAccessor(Object.assign({}, props, props.accessor));
7677
7719
  if (props.data) {
7678
- this._setData(props.data, props.offset, props.byteLength);
7720
+ this._setData(props.data, props.byteOffset, props.byteLength);
7679
7721
  } else {
7680
7722
  this._setByteLength(props.byteLength || 0);
7681
7723
  }
@@ -7731,15 +7773,15 @@ void main(void) {}`;
7731
7773
  } = options;
7732
7774
  const byteLength = options.byteLength || options.length;
7733
7775
  assert2(data);
7734
- const target = this.gl.webgl2 ? GL.COPY_WRITE_BUFFER : this.target;
7735
- this.gl.bindBuffer(target, this.handle);
7776
+ const glTarget = this.gl.webgl2 ? GL.COPY_WRITE_BUFFER : this.glTarget;
7777
+ this.gl.bindBuffer(glTarget, this.handle);
7736
7778
  if (srcOffset !== 0 || byteLength !== void 0) {
7737
7779
  assertWebGL2Context(this.gl);
7738
- this.gl.bufferSubData(this.target, offset, data, srcOffset, byteLength);
7780
+ this.gl.bufferSubData(this.glTarget, offset, data, srcOffset, byteLength);
7739
7781
  } else {
7740
- this.gl.bufferSubData(target, offset, data);
7782
+ this.gl.bufferSubData(glTarget, offset, data);
7741
7783
  }
7742
- this.gl.bindBuffer(target, null);
7784
+ this.gl.bindBuffer(glTarget, null);
7743
7785
  this.debugData = null;
7744
7786
  this._inferType(data);
7745
7787
  return this;
@@ -7814,35 +7856,35 @@ void main(void) {}`;
7814
7856
  */
7815
7857
  bind(options) {
7816
7858
  const {
7817
- target = this.target,
7859
+ glTarget = this.glTarget,
7818
7860
  // target for the bind operation
7819
7861
  index = this.accessor && this.accessor.index,
7820
7862
  // index = index of target (indexed bind point)
7821
7863
  offset = 0,
7822
7864
  size
7823
7865
  } = options || {};
7824
- if (target === GL.UNIFORM_BUFFER || target === GL.TRANSFORM_FEEDBACK_BUFFER) {
7866
+ if (glTarget === GL.UNIFORM_BUFFER || glTarget === GL.TRANSFORM_FEEDBACK_BUFFER) {
7825
7867
  if (size !== void 0) {
7826
- this.gl2?.bindBufferRange(target, index, this.handle, offset, size);
7868
+ this.gl2?.bindBufferRange(glTarget, index, this.handle, offset, size);
7827
7869
  } else {
7828
7870
  assert2(offset === 0);
7829
- this.gl2?.bindBufferBase(target, index, this.handle);
7871
+ this.gl2?.bindBufferBase(glTarget, index, this.handle);
7830
7872
  }
7831
7873
  } else {
7832
- this.gl.bindBuffer(target, this.handle);
7874
+ this.gl.bindBuffer(glTarget, this.handle);
7833
7875
  }
7834
7876
  return this;
7835
7877
  }
7836
7878
  unbind(options) {
7837
7879
  const {
7838
- target = this.target,
7880
+ glTarget = this.glTarget,
7839
7881
  index = this.accessor && this.accessor.index
7840
7882
  } = options || {};
7841
- const isIndexedBuffer = target === GL.UNIFORM_BUFFER || target === GL.TRANSFORM_FEEDBACK_BUFFER;
7883
+ const isIndexedBuffer = glTarget === GL.UNIFORM_BUFFER || glTarget === GL.TRANSFORM_FEEDBACK_BUFFER;
7842
7884
  if (isIndexedBuffer) {
7843
- this.gl2?.bindBufferBase(target, index, null);
7885
+ this.gl2?.bindBufferBase(glTarget, index, null);
7844
7886
  } else {
7845
- this.gl.bindBuffer(target, null);
7887
+ this.gl.bindBuffer(glTarget, null);
7846
7888
  }
7847
7889
  return this;
7848
7890
  }
@@ -7873,7 +7915,7 @@ void main(void) {}`;
7873
7915
  this.trackDeallocatedMemory();
7874
7916
  const target = this._getTarget();
7875
7917
  this.gl.bindBuffer(target, this.handle);
7876
- this.gl.bufferData(target, byteLength, this.webglUsage);
7918
+ this.gl.bufferData(target, byteLength, this.glUsage);
7877
7919
  this.gl.bufferSubData(target, offset, data);
7878
7920
  this.gl.bindBuffer(target, null);
7879
7921
  this.debugData = data.slice(0, DEBUG_DATA_LENGTH2);
@@ -7888,18 +7930,17 @@ void main(void) {}`;
7888
7930
  return this;
7889
7931
  }
7890
7932
  // Allocate a GPU buffer of specified size.
7891
- _setByteLength(byteLength, webglUsage = this.webglUsage) {
7933
+ _setByteLength(byteLength) {
7892
7934
  assert2(byteLength >= 0);
7893
7935
  this.trackDeallocatedMemory();
7894
7936
  let data = byteLength;
7895
7937
  if (byteLength === 0) {
7896
7938
  data = new Float32Array(0);
7897
7939
  }
7898
- const target = this._getTarget();
7899
- this.gl.bindBuffer(target, this.handle);
7900
- this.gl.bufferData(target, data, webglUsage);
7901
- this.gl.bindBuffer(target, null);
7902
- this.webglUsage = webglUsage;
7940
+ const glTarget = this._getTarget();
7941
+ this.gl.bindBuffer(glTarget, this.handle);
7942
+ this.gl.bufferData(glTarget, data, this.glUsage);
7943
+ this.gl.bindBuffer(glTarget, null);
7903
7944
  this.debugData = null;
7904
7945
  this.bytesUsed = byteLength;
7905
7946
  this.byteLength = byteLength;
@@ -7909,7 +7950,7 @@ void main(void) {}`;
7909
7950
  // Binding a buffer for the first time locks the type
7910
7951
  // In WebGL2, use GL.COPY_WRITE_BUFFER to avoid locking the type
7911
7952
  _getTarget() {
7912
- return this.gl.webgl2 ? GL.COPY_WRITE_BUFFER : this.target;
7953
+ return this.gl.webgl2 ? GL.COPY_WRITE_BUFFER : this.glTarget;
7913
7954
  }
7914
7955
  _getAvailableElementCount(srcByteOffset) {
7915
7956
  const ArrayType = getTypedArrayFromGLType(this.accessor.type || GL.FLOAT, {
@@ -7929,9 +7970,9 @@ void main(void) {}`;
7929
7970
  }
7930
7971
  // RESOURCE METHODS
7931
7972
  getParameter(pname) {
7932
- this.gl.bindBuffer(this.target, this.handle);
7933
- const value = this.gl.getBufferParameter(this.target, pname);
7934
- this.gl.bindBuffer(this.target, null);
7973
+ this.gl.bindBuffer(this.glTarget, this.handle);
7974
+ const value = this.gl.getBufferParameter(this.glTarget, pname);
7975
+ this.gl.bindBuffer(this.glTarget, null);
7935
7976
  return value;
7936
7977
  }
7937
7978
  // DEPRECATIONS - v7.0
@@ -8277,12 +8318,12 @@ ${formattedLog}`)();
8277
8318
 
8278
8319
  // src/adapter/helpers/get-shader-layout.ts
8279
8320
  function getShaderLayout(gl2, program) {
8280
- const programBindings = getProgramBindings(gl2, program);
8281
8321
  const shaderLayout = {
8282
8322
  attributes: [],
8283
8323
  bindings: []
8284
8324
  };
8285
- for (const attribute of programBindings.attributes) {
8325
+ const attributes = readAttributeBindings(gl2, program);
8326
+ for (const attribute of attributes) {
8286
8327
  const size = Math.min(attribute.accessor.size, 4);
8287
8328
  const format = (
8288
8329
  // attribute.accessor.format ||
@@ -8295,7 +8336,8 @@ ${formattedLog}`)();
8295
8336
  stepMode: attribute.accessor.divisor === 1 ? "instance" : "vertex"
8296
8337
  });
8297
8338
  }
8298
- for (const uniformBlock of programBindings.uniformBlocks) {
8339
+ const uniformBlocks = readUniformBlocks(gl2, program);
8340
+ for (const uniformBlock of uniformBlocks) {
8299
8341
  const uniforms2 = uniformBlock.uniforms.map((uniform) => ({
8300
8342
  name: uniform.name,
8301
8343
  format: uniform.format,
@@ -8312,8 +8354,9 @@ ${formattedLog}`)();
8312
8354
  uniforms: uniforms2
8313
8355
  });
8314
8356
  }
8357
+ const uniforms = readUniformBindings(gl2, program);
8315
8358
  let textureUnit = 0;
8316
- for (const uniform of programBindings.uniforms) {
8359
+ for (const uniform of uniforms) {
8317
8360
  if (isSamplerUniform(uniform.type)) {
8318
8361
  const {
8319
8362
  viewDimension,
@@ -8330,24 +8373,65 @@ ${formattedLog}`)();
8330
8373
  textureUnit += 1;
8331
8374
  }
8332
8375
  }
8333
- const uniforms = programBindings.uniforms?.filter((uniform) => uniform.location !== null) || [];
8334
8376
  if (uniforms.length) {
8335
8377
  shaderLayout.uniforms = uniforms;
8336
8378
  }
8337
- if (programBindings.varyings?.length) {
8338
- shaderLayout.varyings = programBindings.varyings;
8379
+ const varyings = readVaryings(gl2, program);
8380
+ if (varyings?.length) {
8381
+ shaderLayout.varyings = varyings;
8339
8382
  }
8340
8383
  return shaderLayout;
8341
8384
  }
8342
- function getProgramBindings(gl2, program) {
8343
- const config = {
8344
- attributes: readAttributeBindings(gl2, program),
8345
- uniforms: readUniformBindings(gl2, program),
8346
- uniformBlocks: readUniformBlocks(gl2, program),
8347
- varyings: readVaryings(gl2, program)
8385
+ function mergeShaderLayout(baseLayout, overrideLayout) {
8386
+ const mergedLayout = {
8387
+ ...baseLayout,
8388
+ attributes: baseLayout.attributes.map((attribute) => ({
8389
+ ...attribute
8390
+ }))
8348
8391
  };
8349
- Object.seal(config);
8350
- return config;
8392
+ for (const attribute of overrideLayout?.attributes || []) {
8393
+ const baseAttribute = mergedLayout.attributes.find((attr) => attr.name === attribute.name);
8394
+ if (!baseAttribute) {
8395
+ log.warn(`shader layout attribute ${attribute.name} not present in shader`);
8396
+ } else {
8397
+ baseAttribute.format = attribute.format || baseAttribute.format;
8398
+ baseAttribute.stepMode = attribute.stepMode || baseAttribute.stepMode;
8399
+ }
8400
+ }
8401
+ return mergedLayout;
8402
+ }
8403
+ function mergeBufferMap(baseLayout, bufferMap) {
8404
+ const mergedLayout = {
8405
+ ...baseLayout,
8406
+ attributes: baseLayout.attributes.map((attribute) => ({
8407
+ ...attribute
8408
+ }))
8409
+ };
8410
+ for (const bufferMapping of bufferMap) {
8411
+ switch (bufferMapping.type) {
8412
+ case "interleave":
8413
+ for (const attributeOverride of bufferMapping.attributes) {
8414
+ overrideShaderLayoutAttribute(mergedLayout, attributeOverride);
8415
+ }
8416
+ break;
8417
+ default:
8418
+ overrideShaderLayoutAttribute(mergedLayout, bufferMapping);
8419
+ }
8420
+ }
8421
+ return mergedLayout;
8422
+ }
8423
+ function overrideShaderLayoutAttribute(layout, attributeOverride) {
8424
+ const attribute = getAttributeFromLayout(layout, attributeOverride.name);
8425
+ if (attribute && attributeOverride.format) {
8426
+ attribute.format = attributeOverride.format;
8427
+ }
8428
+ }
8429
+ function getAttributeFromLayout(shaderLayout, name) {
8430
+ const attribute = shaderLayout.attributes.find((attr) => attr.name === name);
8431
+ if (!attribute) {
8432
+ log.warn(`shader layout attribute "${name}" not present in shader`);
8433
+ }
8434
+ return attribute || null;
8351
8435
  }
8352
8436
  function readAttributeBindings(gl2, program) {
8353
8437
  const attributes = [];
@@ -8646,8 +8730,25 @@ ${formattedLog}`)();
8646
8730
  get [Symbol.toStringTag]() {
8647
8731
  return "BaseVertexArrayObject";
8648
8732
  }
8733
+ /** Buffer constant */
8734
+ buffer = null;
8735
+ bufferValue = null;
8736
+ static isConstantAttributeZeroSupported(device) {
8737
+ return device.info.type === "webgl2" || getBrowser() === "Chrome";
8738
+ }
8739
+ // Create a VertexArray
8649
8740
  constructor(device, props) {
8650
- super(device, props, {});
8741
+ super(device, props, {
8742
+ ...Resource.defaultProps,
8743
+ constantAttributeZero: false
8744
+ });
8745
+ Object.seal(this);
8746
+ }
8747
+ destroy() {
8748
+ super.destroy();
8749
+ if (this.buffer) {
8750
+ this.buffer?.destroy();
8751
+ }
8651
8752
  }
8652
8753
  _createHandle() {
8653
8754
  return this.gl2.createVertexArray();
@@ -8659,19 +8760,33 @@ ${formattedLog}`)();
8659
8760
  _bindHandle(handle) {
8660
8761
  this.gl2.bindVertexArray(handle);
8661
8762
  }
8763
+ /**
8764
+ * Enabling an attribute location makes it reference the currently bound buffer
8765
+ * Disabling an attribute location makes it reference the global constant value
8766
+ * TODO - handle single values for size 1 attributes?
8767
+ * TODO - convert classic arrays based on known type?
8768
+ */
8769
+ enable(location, enable2 = true) {
8770
+ const canDisableAttributeZero = this.device.isWebGL2 || getBrowser() === "Chrome";
8771
+ const canDisableAttribute = canDisableAttributeZero || location !== 0;
8772
+ if (enable2 || canDisableAttribute) {
8773
+ location = Number(location);
8774
+ this.bind(() => enable2 ? this.gl.enableVertexAttribArray(location) : this.gl.disableVertexAttribArray(location));
8775
+ }
8776
+ }
8662
8777
  // Set (bind) an elements buffer, for indexed rendering.
8663
8778
  // Must be a Buffer bound to GL.ELEMENT_ARRAY_BUFFER. Constants not supported
8664
8779
  setElementBuffer(elementBuffer = null, opts = {}) {
8665
- assert2(!elementBuffer || elementBuffer.target === GL.ELEMENT_ARRAY_BUFFER, ERR_ELEMENTS);
8780
+ assert2(!elementBuffer || elementBuffer.glTarget === GL.ELEMENT_ARRAY_BUFFER, ERR_ELEMENTS);
8666
8781
  this.bind(() => {
8667
8782
  this.gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, elementBuffer ? elementBuffer.handle : null);
8668
8783
  });
8669
- return this;
8670
8784
  }
8671
8785
  /** Set a location in vertex attributes array to a buffer, enables the location, sets divisor */
8672
8786
  setBuffer(location, buffer, accessor) {
8673
- if (buffer.target === GL.ELEMENT_ARRAY_BUFFER) {
8674
- return this.setElementBuffer(buffer, accessor);
8787
+ if (buffer.glTarget === GL.ELEMENT_ARRAY_BUFFER) {
8788
+ this.setElementBuffer(buffer, accessor);
8789
+ return;
8675
8790
  }
8676
8791
  const {
8677
8792
  size,
@@ -8698,33 +8813,127 @@ ${formattedLog}`)();
8698
8813
  gl2.enableVertexAttribArray(location);
8699
8814
  gl22.vertexAttribDivisor(location, divisor || 0);
8700
8815
  });
8701
- return this;
8702
8816
  }
8703
8817
  /**
8704
- * Enabling an attribute location makes it reference the currently bound buffer
8705
- * Disabling an attribute location makes it reference the global constant value
8706
- * TODO - handle single values for size 1 attributes?
8707
- * TODO - convert classic arrays based on known type?
8818
+ * Set an attribute to a constant value
8819
+ * @param device
8820
+ * @param location
8821
+ * @param array
8822
+ *
8823
+ * @note Constants are stored globally on the WebGL context, not the VAO
8824
+ * so they need to be updated before every render
8825
+ * @todo - use known type (in configuration or passed in) to allow non-typed arrays?
8826
+ * @todo - remember/cache values to avoid setting them unnecessarily?
8708
8827
  */
8709
- enable(location, enable2 = true) {
8710
- const canDisableAttributeZero = this.device.isWebGL2 || getBrowser() === "Chrome";
8711
- const canDisableAttribute = canDisableAttributeZero || location !== 0;
8712
- if (enable2 || canDisableAttribute) {
8713
- location = Number(location);
8714
- this.bind(() => enable2 ? this.gl.enableVertexAttribArray(location) : this.gl.disableVertexAttribArray(location));
8828
+ setConstant(location, array) {
8829
+ switch (array.constructor) {
8830
+ case Float32Array:
8831
+ setConstantFloatArray(this.device, location, array);
8832
+ break;
8833
+ case Int32Array:
8834
+ setConstantIntArray(this.device, location, array);
8835
+ break;
8836
+ case Uint32Array:
8837
+ setConstantUintArray(this.device, location, array);
8838
+ break;
8839
+ default:
8840
+ assert2(false);
8715
8841
  }
8716
- return this;
8842
+ }
8843
+ /**
8844
+ * Provide a means to create a buffer that is equivalent to a constant.
8845
+ * NOTE: Desktop OpenGL cannot disable attribute 0.
8846
+ * https://stackoverflow.com/questions/20305231/webgl-warning-attribute-0-is-disabled-
8847
+ * this-has-significant-performance-penalty
8848
+ */
8849
+ getConstantBuffer(elementCount, value) {
8850
+ const constantValue = normalizeConstantArrayValue(value);
8851
+ const byteLength = constantValue.byteLength * elementCount;
8852
+ const length = constantValue.length * elementCount;
8853
+ let updateNeeded = !this.buffer;
8854
+ this.buffer = this.buffer || this.device.createBuffer({
8855
+ byteLength
8856
+ });
8857
+ updateNeeded = updateNeeded || this.buffer.reallocate(byteLength);
8858
+ updateNeeded = updateNeeded || !compareConstantArrayValues(constantValue, this.bufferValue);
8859
+ if (updateNeeded) {
8860
+ const typedArray = getScratchArray(value.constructor, length);
8861
+ fillArray({
8862
+ target: typedArray,
8863
+ source: constantValue,
8864
+ start: 0,
8865
+ count: length
8866
+ });
8867
+ this.buffer.subData(typedArray);
8868
+ this.bufferValue = value;
8869
+ }
8870
+ return this.buffer;
8717
8871
  }
8718
8872
  };
8873
+ function setConstantFloatArray(device, location, array) {
8874
+ switch (array.length) {
8875
+ case 1:
8876
+ device.gl.vertexAttrib1fv(location, array);
8877
+ break;
8878
+ case 2:
8879
+ device.gl.vertexAttrib2fv(location, array);
8880
+ break;
8881
+ case 3:
8882
+ device.gl.vertexAttrib3fv(location, array);
8883
+ break;
8884
+ case 4:
8885
+ device.gl.vertexAttrib4fv(location, array);
8886
+ break;
8887
+ default:
8888
+ assert2(false);
8889
+ }
8890
+ }
8891
+ function setConstantIntArray(device, location, array) {
8892
+ device.assertWebGL2();
8893
+ device.gl2?.vertexAttribI4iv(location, array);
8894
+ }
8895
+ function setConstantUintArray(device, location, array) {
8896
+ device.assertWebGL2();
8897
+ device.gl2?.vertexAttribI4uiv(location, array);
8898
+ }
8899
+ function normalizeConstantArrayValue(arrayValue) {
8900
+ if (Array.isArray(arrayValue)) {
8901
+ return new Float32Array(arrayValue);
8902
+ }
8903
+ return arrayValue;
8904
+ }
8905
+ function compareConstantArrayValues(v1, v2) {
8906
+ if (!v1 || !v2 || v1.length !== v2.length || v1.constructor !== v2.constructor) {
8907
+ return false;
8908
+ }
8909
+ for (let i = 0; i < v1.length; ++i) {
8910
+ if (v1[i] !== v2[i]) {
8911
+ return false;
8912
+ }
8913
+ }
8914
+ return true;
8915
+ }
8719
8916
 
8720
8917
  // src/adapter/resources/webgl-render-pipeline.ts
8721
8918
  var LOG_PROGRAM_PERF_PRIORITY = 4;
8722
8919
  var WEBGLRenderPipeline = class extends RenderPipeline {
8723
- // configuration: ProgramConfiguration;
8724
- // Experimental flag to avoid deleting Program object while it is cached
8725
- varyings = null;
8920
+ /** The WebGL device that created this render pipeline */
8921
+ /** Handle to underlying WebGL program */
8922
+ /** vertex shader */
8923
+ /** fragment shader */
8924
+ /** The merged layout */
8925
+ /** The layout extracted from shader by WebGL introspection APIs */
8926
+ /** Buffer map describing buffer interleaving etc */
8927
+ /** Uniforms set on this model */
8726
8928
  uniforms = {};
8929
+ /** Bindings set on this model */
8727
8930
  bindings = {};
8931
+ /** Any constant attributes */
8932
+ constantAttributes = {};
8933
+ /** Index buffer is stored separately */
8934
+ /** WebGL varyings */
8935
+ varyings = null;
8936
+ /** Stores attribute bindings */
8728
8937
  _textureUniforms = {};
8729
8938
  _textureIndexCounter = 0;
8730
8939
  _uniformCount = 0;
@@ -8749,7 +8958,10 @@ ${formattedLog}`)();
8749
8958
  this.device.gl2?.transformFeedbackVaryings(this.handle, varyings, bufferMode);
8750
8959
  }
8751
8960
  this._compileAndLink();
8752
- this.layout = props.layout || getShaderLayout(this.device.gl, this.handle);
8961
+ this.introspectedLayout = getShaderLayout(this.device.gl, this.handle);
8962
+ this.layout = mergeShaderLayout(this.introspectedLayout, props.layout);
8963
+ this.bufferMap = props.bufferMap || [];
8964
+ this.layout = mergeBufferMap(this.layout, this.bufferMap);
8753
8965
  this.vertexArrayObject = new WEBGLVertexArrayObject(this.device);
8754
8966
  }
8755
8967
  destroy() {
@@ -8761,7 +8973,7 @@ ${formattedLog}`)();
8761
8973
  setIndexBuffer(indexBuffer) {
8762
8974
  const webglBuffer = cast(indexBuffer);
8763
8975
  this.vertexArrayObject.setElementBuffer(webglBuffer);
8764
- this._indexBuffer = indexBuffer;
8976
+ this._indexBuffer = webglBuffer;
8765
8977
  }
8766
8978
  /** @todo needed for portable model */
8767
8979
  setAttributes(attributes) {
@@ -8793,7 +9005,27 @@ ${formattedLog}`)();
8793
9005
  });
8794
9006
  }
8795
9007
  }
8796
- /** @todo needed for portable model */
9008
+ /**
9009
+ * Constant attributes are only supported in WebGL, not in WebGPU
9010
+ * Any attribute that is disabled in the current vertex array object
9011
+ * is read from the context's global constant value for that attribute location.
9012
+ * @param attributes
9013
+ */
9014
+ setConstantAttributes(attributes) {
9015
+ for (const [name, value] of Object.entries(attributes)) {
9016
+ const attribute = getAttributeLayout(this.layout, name);
9017
+ if (!attribute) {
9018
+ log.warn(`Ignoring constant value supplied for unknown attribute "${name}" in pipeline "${this.id}"`)();
9019
+ continue;
9020
+ }
9021
+ this.vertexArrayObject.setConstant(attribute.location, value);
9022
+ }
9023
+ Object.assign(this.constantAttributes, attributes);
9024
+ }
9025
+ /**
9026
+ * Bindings include: textures, samplers and uniform buffers
9027
+ * @todo needed for portable model
9028
+ */
8797
9029
  setBindings(bindings) {
8798
9030
  for (const [name, value] of Object.entries(bindings)) {
8799
9031
  const binding = this.layout.bindings.find((binding2) => binding2.name === name);
@@ -8844,7 +9076,7 @@ ${formattedLog}`)();
8844
9076
  } = options;
8845
9077
  const drawMode = getDrawMode(this.props.topology);
8846
9078
  const isIndexed = Boolean(this._indexBuffer);
8847
- const indexType = this._indexBuffer?.props.indexType === "uint16" ? GL.UNSIGNED_SHORT : GL.UNSIGNED_INT;
9079
+ const indexType = this._indexBuffer?.glIndexType;
8848
9080
  const isInstanced = Number(options.instanceCount) > 0;
8849
9081
  if (!this._areTexturesRenderable() || options.vertexCount === 0) {
8850
9082
  return false;
@@ -8858,6 +9090,7 @@ ${formattedLog}`)();
8858
9090
  }
8859
9091
  this._applyBindings();
8860
9092
  this._applyUniforms();
9093
+ this._applyConstantAttributes();
8861
9094
  const webglRenderPass = renderPass;
8862
9095
  withDeviceParameters(this.device, this.props.parameters, () => {
8863
9096
  withGLParameters(this.device, webglRenderPass.glParameters, () => {
@@ -8991,6 +9224,21 @@ ${formattedLog}`)();
8991
9224
  }
8992
9225
  }
8993
9226
  }
9227
+ /**
9228
+ * Constant attributes are only supported in WebGL, not in WebGPU
9229
+ * Any attribute that is disabled in the current vertex array object
9230
+ * is read from the context's global constant value for that attribute location.
9231
+ */
9232
+ _applyConstantAttributes() {
9233
+ for (const [name, value] of Object.entries(this.constantAttributes)) {
9234
+ const attribute = getAttributeLayout(this.layout, name);
9235
+ if (!attribute) {
9236
+ log.warn(`Ignoring constant value supplied for unknown attribute "${name}" in pipeline "${this.id}"`)();
9237
+ continue;
9238
+ }
9239
+ this.vertexArrayObject.setConstant(attribute.location, value);
9240
+ }
9241
+ }
8994
9242
  };
8995
9243
  function getDrawMode(topology) {
8996
9244
  switch (topology) {
@@ -9329,10 +9577,13 @@ ${formattedLog}`)();
9329
9577
  if (typeof props.canvas === "string") {
9330
9578
  await CanvasContext.pageLoaded;
9331
9579
  }
9332
- if (props.debug) {
9580
+ if (log.get("debug") || props.debug) {
9333
9581
  await loadWebGLDeveloperTools();
9334
9582
  }
9335
- if (props.spector) {
9583
+ const {
9584
+ spector: spector2
9585
+ } = props;
9586
+ if (log.get("spector") || spector2) {
9336
9587
  await loadSpectorJS();
9337
9588
  }
9338
9589
  log.probe(LOG_LEVEL2 + 1, "DOM is loaded")();
@@ -9750,7 +10001,7 @@ ${formattedLog}`)();
9750
10001
  });
9751
10002
  }
9752
10003
  target.bind({
9753
- target: GL.PIXEL_PACK_BUFFER
10004
+ glTarget: GL.PIXEL_PACK_BUFFER
9754
10005
  });
9755
10006
  withParameters(gl2, {
9756
10007
  framebuffer
@@ -9758,7 +10009,7 @@ ${formattedLog}`)();
9758
10009
  gl2.readPixels(sourceX, sourceY, sourceWidth, sourceHeight, sourceFormat, sourceType, targetByteOffset);
9759
10010
  });
9760
10011
  target.unbind({
9761
- target: GL.PIXEL_PACK_BUFFER
10012
+ glTarget: GL.PIXEL_PACK_BUFFER
9762
10013
  });
9763
10014
  if (deleteFramebuffer) {
9764
10015
  framebuffer.destroy();