@luma.gl/effects 9.1.9 → 9.2.0-alpha.2

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 (100) hide show
  1. package/dist/dist.dev.js +1162 -851
  2. package/dist/dist.min.js +7 -6
  3. package/dist/index.cjs +560 -65
  4. package/dist/index.cjs.map +3 -3
  5. package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.d.ts +3 -3
  6. package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.d.ts.map +1 -1
  7. package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.js +9 -9
  8. package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.js.map +1 -1
  9. package/dist/passes/postprocessing/image-adjust-filters/denoise.d.ts +2 -2
  10. package/dist/passes/postprocessing/image-adjust-filters/denoise.d.ts.map +1 -1
  11. package/dist/passes/postprocessing/image-adjust-filters/denoise.js +9 -5
  12. package/dist/passes/postprocessing/image-adjust-filters/denoise.js.map +1 -1
  13. package/dist/passes/postprocessing/image-adjust-filters/huesaturation.d.ts +1 -1
  14. package/dist/passes/postprocessing/image-adjust-filters/huesaturation.d.ts.map +1 -1
  15. package/dist/passes/postprocessing/image-adjust-filters/huesaturation.js +5 -4
  16. package/dist/passes/postprocessing/image-adjust-filters/huesaturation.js.map +1 -1
  17. package/dist/passes/postprocessing/image-adjust-filters/noise.d.ts +3 -3
  18. package/dist/passes/postprocessing/image-adjust-filters/noise.d.ts.map +1 -1
  19. package/dist/passes/postprocessing/image-adjust-filters/noise.js +7 -7
  20. package/dist/passes/postprocessing/image-adjust-filters/noise.js.map +1 -1
  21. package/dist/passes/postprocessing/image-adjust-filters/sepia.d.ts +1 -0
  22. package/dist/passes/postprocessing/image-adjust-filters/sepia.d.ts.map +1 -1
  23. package/dist/passes/postprocessing/image-adjust-filters/sepia.js +25 -0
  24. package/dist/passes/postprocessing/image-adjust-filters/sepia.js.map +1 -1
  25. package/dist/passes/postprocessing/image-adjust-filters/vibrance.d.ts +1 -0
  26. package/dist/passes/postprocessing/image-adjust-filters/vibrance.d.ts.map +1 -1
  27. package/dist/passes/postprocessing/image-adjust-filters/vibrance.js +20 -0
  28. package/dist/passes/postprocessing/image-adjust-filters/vibrance.js.map +1 -1
  29. package/dist/passes/postprocessing/image-adjust-filters/vignette.d.ts +1 -1
  30. package/dist/passes/postprocessing/image-adjust-filters/vignette.d.ts.map +1 -1
  31. package/dist/passes/postprocessing/image-adjust-filters/vignette.js +19 -9
  32. package/dist/passes/postprocessing/image-adjust-filters/vignette.js.map +1 -1
  33. package/dist/passes/postprocessing/image-blur-filters/tiltshift.d.ts +5 -3
  34. package/dist/passes/postprocessing/image-blur-filters/tiltshift.d.ts.map +1 -1
  35. package/dist/passes/postprocessing/image-blur-filters/tiltshift.js +52 -4
  36. package/dist/passes/postprocessing/image-blur-filters/tiltshift.js.map +1 -1
  37. package/dist/passes/postprocessing/image-blur-filters/triangleblur.d.ts +8 -6
  38. package/dist/passes/postprocessing/image-blur-filters/triangleblur.d.ts.map +1 -1
  39. package/dist/passes/postprocessing/image-blur-filters/triangleblur.js +41 -3
  40. package/dist/passes/postprocessing/image-blur-filters/triangleblur.js.map +1 -1
  41. package/dist/passes/postprocessing/image-blur-filters/zoomblur.d.ts +8 -6
  42. package/dist/passes/postprocessing/image-blur-filters/zoomblur.d.ts.map +1 -1
  43. package/dist/passes/postprocessing/image-blur-filters/zoomblur.js +42 -4
  44. package/dist/passes/postprocessing/image-blur-filters/zoomblur.js.map +1 -1
  45. package/dist/passes/postprocessing/image-fun-filters/colorhalftone.d.ts +3 -2
  46. package/dist/passes/postprocessing/image-fun-filters/colorhalftone.d.ts.map +1 -1
  47. package/dist/passes/postprocessing/image-fun-filters/colorhalftone.js +41 -2
  48. package/dist/passes/postprocessing/image-fun-filters/colorhalftone.js.map +1 -1
  49. package/dist/passes/postprocessing/image-fun-filters/dotscreen.d.ts +3 -2
  50. package/dist/passes/postprocessing/image-fun-filters/dotscreen.d.ts.map +1 -1
  51. package/dist/passes/postprocessing/image-fun-filters/dotscreen.js +29 -2
  52. package/dist/passes/postprocessing/image-fun-filters/dotscreen.js.map +1 -1
  53. package/dist/passes/postprocessing/image-fun-filters/edgework.d.ts +4 -2
  54. package/dist/passes/postprocessing/image-fun-filters/edgework.d.ts.map +1 -1
  55. package/dist/passes/postprocessing/image-fun-filters/edgework.js +36 -2
  56. package/dist/passes/postprocessing/image-fun-filters/edgework.js.map +1 -1
  57. package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.d.ts +3 -2
  58. package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.d.ts.map +1 -1
  59. package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.js +49 -2
  60. package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.js.map +1 -1
  61. package/dist/passes/postprocessing/image-fun-filters/ink.d.ts +3 -2
  62. package/dist/passes/postprocessing/image-fun-filters/ink.d.ts.map +1 -1
  63. package/dist/passes/postprocessing/image-fun-filters/ink.js +34 -2
  64. package/dist/passes/postprocessing/image-fun-filters/ink.js.map +1 -1
  65. package/dist/passes/postprocessing/image-fun-filters/magnify.d.ts +2 -1
  66. package/dist/passes/postprocessing/image-fun-filters/magnify.d.ts.map +1 -1
  67. package/dist/passes/postprocessing/image-fun-filters/magnify.js +26 -1
  68. package/dist/passes/postprocessing/image-fun-filters/magnify.js.map +1 -1
  69. package/dist/passes/postprocessing/image-warp-filters/bulgepinch.d.ts +5 -3
  70. package/dist/passes/postprocessing/image-warp-filters/bulgepinch.d.ts.map +1 -1
  71. package/dist/passes/postprocessing/image-warp-filters/bulgepinch.js +33 -2
  72. package/dist/passes/postprocessing/image-warp-filters/bulgepinch.js.map +1 -1
  73. package/dist/passes/postprocessing/image-warp-filters/swirl.d.ts +5 -3
  74. package/dist/passes/postprocessing/image-warp-filters/swirl.d.ts.map +1 -1
  75. package/dist/passes/postprocessing/image-warp-filters/swirl.js +35 -2
  76. package/dist/passes/postprocessing/image-warp-filters/swirl.js.map +1 -1
  77. package/dist/passes/postprocessing/image-warp-filters/warp.d.ts +2 -1
  78. package/dist/passes/postprocessing/image-warp-filters/warp.d.ts.map +1 -1
  79. package/dist/passes/postprocessing/image-warp-filters/warp.js +14 -3
  80. package/dist/passes/postprocessing/image-warp-filters/warp.js.map +1 -1
  81. package/package.json +3 -3
  82. package/src/passes/postprocessing/image-adjust-filters/brightnesscontrast.ts +10 -10
  83. package/src/passes/postprocessing/image-adjust-filters/denoise.ts +9 -5
  84. package/src/passes/postprocessing/image-adjust-filters/huesaturation.ts +5 -4
  85. package/src/passes/postprocessing/image-adjust-filters/noise.ts +9 -8
  86. package/src/passes/postprocessing/image-adjust-filters/sepia.ts +26 -0
  87. package/src/passes/postprocessing/image-adjust-filters/vibrance.ts +21 -0
  88. package/src/passes/postprocessing/image-adjust-filters/vignette.ts +20 -10
  89. package/src/passes/postprocessing/image-blur-filters/tiltshift.ts +55 -5
  90. package/src/passes/postprocessing/image-blur-filters/triangleblur.ts +44 -4
  91. package/src/passes/postprocessing/image-blur-filters/zoomblur.ts +45 -5
  92. package/src/passes/postprocessing/image-fun-filters/colorhalftone.ts +44 -3
  93. package/src/passes/postprocessing/image-fun-filters/dotscreen.ts +32 -3
  94. package/src/passes/postprocessing/image-fun-filters/edgework.ts +38 -3
  95. package/src/passes/postprocessing/image-fun-filters/hexagonalpixelate.ts +52 -3
  96. package/src/passes/postprocessing/image-fun-filters/ink.ts +36 -3
  97. package/src/passes/postprocessing/image-fun-filters/magnify.ts +29 -1
  98. package/src/passes/postprocessing/image-warp-filters/bulgepinch.ts +36 -3
  99. package/src/passes/postprocessing/image-warp-filters/swirl.ts +36 -3
  100. package/src/passes/postprocessing/image-warp-filters/warp.ts +16 -3
package/dist/dist.dev.js CHANGED
@@ -73,62 +73,33 @@ var __exports__ = (() => {
73
73
  Sampler: () => Sampler,
74
74
  Shader: () => Shader,
75
75
  Texture: () => Texture,
76
+ TextureFormatDecoder: () => TextureFormatDecoder,
76
77
  TextureView: () => TextureView,
77
78
  TransformFeedback: () => TransformFeedback,
78
79
  UniformBlock: () => UniformBlock,
79
80
  UniformBufferLayout: () => UniformBufferLayout,
80
81
  UniformStore: () => UniformStore,
81
82
  VertexArray: () => VertexArray,
82
- _BufferLayoutHelper: () => BufferLayoutHelper,
83
83
  _getTextureFormatDefinition: () => getTextureFormatDefinition,
84
84
  _getTextureFormatTable: () => getTextureFormatTable,
85
- decodeShaderAttributeType: () => decodeShaderAttributeType,
86
- decodeShaderUniformType: () => decodeShaderUniformType,
87
- decodeTextureFormat: () => decodeTextureFormat,
88
- decodeVertexFormat: () => decodeVertexFormat,
89
85
  getAttributeInfosFromLayouts: () => getAttributeInfosFromLayouts,
90
- getDataTypeFromTypedArray: () => getDataTypeFromTypedArray,
86
+ getAttributeShaderTypeInfo: () => getAttributeShaderTypeInfo,
87
+ getDataType: () => getDataType,
88
+ getDataTypeInfo: () => getDataTypeInfo,
89
+ getNormalizedDataType: () => getNormalizedDataType,
91
90
  getScratchArray: () => getScratchArray,
92
- getTextureFormatCapabilities: () => getTextureFormatCapabilities,
93
- getTypedArrayFromDataType: () => getTypedArrayFromDataType,
91
+ getTypedArrayConstructor: () => getTypedArrayConstructor,
92
+ getVariableShaderTypeInfo: () => getVariableShaderTypeInfo,
94
93
  getVertexFormatFromAttribute: () => getVertexFormatFromAttribute,
94
+ getVertexFormatInfo: () => getVertexFormatInfo,
95
95
  log: () => log,
96
96
  luma: () => luma,
97
- sortedBufferLayoutByShaderSourceLocations: () => sortedBufferLayoutByShaderSourceLocations
97
+ makeVertexFormat: () => makeVertexFormat,
98
+ readPixel: () => readPixel,
99
+ textureFormatDecoder: () => textureFormatDecoder,
100
+ writePixel: () => writePixel
98
101
  });
99
102
 
100
- // ../../node_modules/@probe.gl/env/dist/lib/globals.js
101
- var window_ = globalThis;
102
- var document_ = globalThis.document || {};
103
- var process_ = globalThis.process || {};
104
- var console_ = globalThis.console;
105
- var navigator_ = globalThis.navigator || {};
106
-
107
- // ../../node_modules/@probe.gl/env/dist/lib/is-electron.js
108
- function isElectron(mockUserAgent) {
109
- if (typeof window !== "undefined" && window.process?.type === "renderer") {
110
- return true;
111
- }
112
- if (typeof process !== "undefined" && Boolean(process.versions?.["electron"])) {
113
- return true;
114
- }
115
- const realUserAgent = typeof navigator !== "undefined" && navigator.userAgent;
116
- const userAgent = mockUserAgent || realUserAgent;
117
- return Boolean(userAgent && userAgent.indexOf("Electron") >= 0);
118
- }
119
-
120
- // ../../node_modules/@probe.gl/env/dist/lib/is-browser.js
121
- function isBrowser() {
122
- const isNode = (
123
- // @ts-expect-error
124
- typeof process === "object" && String(process) === "[object process]" && !process?.browser
125
- );
126
- return !isNode || isElectron();
127
- }
128
-
129
- // ../../node_modules/@probe.gl/env/dist/index.js
130
- var VERSION = true ? "4.0.7" : "untranspiled source";
131
-
132
103
  // ../../node_modules/@probe.gl/stats/dist/utils/hi-res-timestamp.js
133
104
  function getHiResTimestamp() {
134
105
  let timestamp;
@@ -337,6 +308,38 @@ var __exports__ = (() => {
337
308
  };
338
309
  var lumaStats = new StatsManager();
339
310
 
311
+ // ../../node_modules/@probe.gl/env/dist/lib/globals.js
312
+ var window_ = globalThis;
313
+ var document_ = globalThis.document || {};
314
+ var process_ = globalThis.process || {};
315
+ var console_ = globalThis.console;
316
+ var navigator_ = globalThis.navigator || {};
317
+
318
+ // ../../node_modules/@probe.gl/env/dist/lib/is-electron.js
319
+ function isElectron(mockUserAgent) {
320
+ if (typeof window !== "undefined" && window.process?.type === "renderer") {
321
+ return true;
322
+ }
323
+ if (typeof process !== "undefined" && Boolean(process.versions?.["electron"])) {
324
+ return true;
325
+ }
326
+ const realUserAgent = typeof navigator !== "undefined" && navigator.userAgent;
327
+ const userAgent = mockUserAgent || realUserAgent;
328
+ return Boolean(userAgent && userAgent.indexOf("Electron") >= 0);
329
+ }
330
+
331
+ // ../../node_modules/@probe.gl/env/dist/lib/is-browser.js
332
+ function isBrowser() {
333
+ const isNode = (
334
+ // @ts-expect-error
335
+ typeof process === "object" && String(process) === "[object process]" && !process?.browser
336
+ );
337
+ return !isNode || isElectron();
338
+ }
339
+
340
+ // ../../node_modules/@probe.gl/env/dist/index.js
341
+ var VERSION = true ? "4.1.0" : "untranspiled source";
342
+
340
343
  // ../../node_modules/@probe.gl/log/dist/utils/local-storage.js
341
344
  function getStorage(type) {
342
345
  try {
@@ -910,10 +913,6 @@ var __exports__ = (() => {
910
913
  clone(props) {
911
914
  return this.device.createBuffer({ ...this.props, ...props });
912
915
  }
913
- /** Read data synchronously. @note WebGL2 only */
914
- readSyncWebGL(byteOffset, byteLength) {
915
- throw new Error("not implemented");
916
- }
917
916
  /** A partial CPU-side copy of the data in this buffer, for debugging purposes */
918
917
  debugData = new ArrayBuffer(0);
919
918
  /** This doesn't handle partial non-zero offset updates correctly */
@@ -933,21 +932,6 @@ var __exports__ = (() => {
933
932
  }
934
933
  };
935
934
  var Buffer2 = _Buffer;
936
- __publicField(Buffer2, "defaultProps", {
937
- ...Resource.defaultProps,
938
- usage: 0,
939
- // Buffer.COPY_DST | Buffer.COPY_SRC
940
- byteLength: 0,
941
- byteOffset: 0,
942
- data: null,
943
- indexType: "uint16",
944
- mappedAtCreation: false
945
- });
946
- // Usage Flags
947
- __publicField(Buffer2, "MAP_READ", 1);
948
- __publicField(Buffer2, "MAP_WRITE", 2);
949
- __publicField(Buffer2, "COPY_SRC", 4);
950
- __publicField(Buffer2, "COPY_DST", 8);
951
935
  /** Index buffer */
952
936
  __publicField(Buffer2, "INDEX", 16);
953
937
  /** Vertex buffer */
@@ -958,55 +942,176 @@ var __exports__ = (() => {
958
942
  __publicField(Buffer2, "STORAGE", 128);
959
943
  __publicField(Buffer2, "INDIRECT", 256);
960
944
  __publicField(Buffer2, "QUERY_RESOLVE", 512);
945
+ // Usage Flags
946
+ __publicField(Buffer2, "MAP_READ", 1);
947
+ __publicField(Buffer2, "MAP_WRITE", 2);
948
+ __publicField(Buffer2, "COPY_SRC", 4);
949
+ __publicField(Buffer2, "COPY_DST", 8);
961
950
  // PROTECTED METHODS (INTENDED FOR USE BY OTHER FRAMEWORK CODE ONLY)
962
951
  /** Max amount of debug data saved. Two vec4's */
963
952
  __publicField(Buffer2, "DEBUG_DATA_MAX_LENGTH", 32);
953
+ __publicField(Buffer2, "defaultProps", {
954
+ ...Resource.defaultProps,
955
+ usage: 0,
956
+ // Buffer.COPY_DST | Buffer.COPY_SRC
957
+ byteLength: 0,
958
+ byteOffset: 0,
959
+ data: null,
960
+ indexType: "uint16",
961
+ onMapped: void 0
962
+ });
964
963
 
965
- // ../core/src/gpu-type-utils/decode-data-type.ts
966
- function decodeVertexType(type) {
967
- const dataType = TYPE_MAP[type];
968
- const bytes = getDataTypeBytes(dataType);
964
+ // ../core/src/shadertypes/data-types/decode-data-types.ts
965
+ function getDataTypeInfo(type) {
966
+ const [signedType, primitiveType, byteLength] = NORMALIZED_TYPE_MAP[type];
969
967
  const normalized = type.includes("norm");
970
968
  const integer = !normalized && !type.startsWith("float");
971
969
  const signed = type.startsWith("s");
972
970
  return {
973
- dataType: TYPE_MAP[type],
974
- byteLength: bytes,
971
+ signedType,
972
+ primitiveType,
973
+ byteLength,
974
+ normalized,
975
975
  integer,
976
- signed,
977
- normalized
976
+ signed
978
977
  };
979
978
  }
980
- function getDataTypeBytes(type) {
981
- const bytes = TYPE_SIZES[type];
982
- return bytes;
983
- }
984
- var TYPE_MAP = {
985
- uint8: "uint8",
986
- sint8: "sint8",
987
- unorm8: "uint8",
988
- snorm8: "sint8",
989
- uint16: "uint16",
990
- sint16: "sint16",
991
- unorm16: "uint16",
992
- snorm16: "sint16",
993
- float16: "float16",
994
- float32: "float32",
995
- uint32: "uint32",
996
- sint32: "sint32"
997
- };
998
- var TYPE_SIZES = {
999
- uint8: 1,
1000
- sint8: 1,
1001
- uint16: 2,
1002
- sint16: 2,
1003
- float16: 2,
1004
- float32: 4,
1005
- uint32: 4,
1006
- sint32: 4
979
+ function getNormalizedDataType(signedDataType) {
980
+ const dataType = signedDataType;
981
+ switch (dataType) {
982
+ case "uint8":
983
+ return "unorm8";
984
+ case "sint8":
985
+ return "snorm8";
986
+ case "uint16":
987
+ return "unorm16";
988
+ case "sint16":
989
+ return "snorm16";
990
+ default:
991
+ return dataType;
992
+ }
993
+ }
994
+ function alignTo(size, count) {
995
+ switch (count) {
996
+ case 1:
997
+ return size;
998
+ case 2:
999
+ return size + size % 2;
1000
+ default:
1001
+ return size + (4 - size % 4) % 4;
1002
+ }
1003
+ }
1004
+ function getDataType(arrayOrType) {
1005
+ const Constructor = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType;
1006
+ if (Constructor === Uint8ClampedArray) {
1007
+ return "uint8";
1008
+ }
1009
+ const info = Object.values(NORMALIZED_TYPE_MAP).find((entry) => Constructor === entry[4]);
1010
+ if (!info) {
1011
+ throw new Error(Constructor.name);
1012
+ }
1013
+ return info[0];
1014
+ }
1015
+ function getTypedArrayConstructor(type) {
1016
+ const [, , , , Constructor] = NORMALIZED_TYPE_MAP[type];
1017
+ return Constructor;
1018
+ }
1019
+ var NORMALIZED_TYPE_MAP = {
1020
+ uint8: ["uint8", "u32", 1, false, Uint8Array],
1021
+ sint8: ["sint8", "i32", 1, false, Int8Array],
1022
+ unorm8: ["uint8", "f32", 1, true, Uint8Array],
1023
+ snorm8: ["sint8", "f32", 1, true, Int8Array],
1024
+ uint16: ["uint16", "u32", 2, false, Uint16Array],
1025
+ sint16: ["sint16", "i32", 2, false, Int16Array],
1026
+ unorm16: ["uint16", "u32", 2, true, Uint16Array],
1027
+ snorm16: ["sint16", "i32", 2, true, Int16Array],
1028
+ float16: ["float16", "f16", 2, false, Uint16Array],
1029
+ float32: ["float32", "f32", 4, false, Float32Array],
1030
+ uint32: ["uint32", "u32", 4, false, Uint32Array],
1031
+ sint32: ["sint32", "i32", 4, false, Int32Array]
1007
1032
  };
1008
1033
 
1009
- // ../core/src/gpu-type-utils/texture-format-table.ts
1034
+ // ../core/src/shadertypes/vertex-arrays/decode-vertex-format.ts
1035
+ function getVertexFormatInfo(format) {
1036
+ let webglOnly;
1037
+ if (format.endsWith("-webgl")) {
1038
+ format.replace("-webgl", "");
1039
+ webglOnly = true;
1040
+ }
1041
+ const [type_, count] = format.split("x");
1042
+ const type = type_;
1043
+ const components = count ? parseInt(count) : 1;
1044
+ const decodedType = getDataTypeInfo(type);
1045
+ const result = {
1046
+ type,
1047
+ components,
1048
+ byteLength: decodedType.byteLength * components,
1049
+ integer: decodedType.integer,
1050
+ signed: decodedType.signed,
1051
+ normalized: decodedType.normalized
1052
+ };
1053
+ if (webglOnly) {
1054
+ result.webglOnly = true;
1055
+ }
1056
+ return result;
1057
+ }
1058
+ function makeVertexFormat(signedDataType, components, normalized) {
1059
+ const dataType = normalized ? getNormalizedDataType(signedDataType) : signedDataType;
1060
+ switch (dataType) {
1061
+ case "unorm8":
1062
+ if (components === 1) {
1063
+ return "unorm8";
1064
+ }
1065
+ if (components === 3) {
1066
+ return "unorm8x3-webgl";
1067
+ }
1068
+ return `${dataType}x${components}`;
1069
+ case "snorm8":
1070
+ case "uint8":
1071
+ case "sint8":
1072
+ case "uint16":
1073
+ case "sint16":
1074
+ case "unorm16":
1075
+ case "snorm16":
1076
+ case "float16":
1077
+ if (components === 1 || components === 3) {
1078
+ throw new Error(`size: ${components}`);
1079
+ }
1080
+ return `${dataType}x${components}`;
1081
+ default:
1082
+ return components === 1 ? dataType : `${dataType}x${components}`;
1083
+ }
1084
+ }
1085
+ function getVertexFormatFromAttribute(typedArray, size, normalized) {
1086
+ if (!size || size > 4) {
1087
+ throw new Error(`size ${size}`);
1088
+ }
1089
+ const components = size;
1090
+ const signedDataType = getDataType(typedArray);
1091
+ return makeVertexFormat(signedDataType, components, normalized);
1092
+ }
1093
+ function getCompatibleVertexFormat(opts) {
1094
+ let vertexType;
1095
+ switch (opts.primitiveType) {
1096
+ case "f32":
1097
+ vertexType = "float32";
1098
+ break;
1099
+ case "i32":
1100
+ vertexType = "sint32";
1101
+ break;
1102
+ case "u32":
1103
+ vertexType = "uint32";
1104
+ break;
1105
+ case "f16":
1106
+ return opts.components <= 2 ? "float16x2" : "float16x4";
1107
+ }
1108
+ if (opts.components === 1) {
1109
+ return vertexType;
1110
+ }
1111
+ return `${vertexType}x${opts.components}`;
1112
+ }
1113
+
1114
+ // ../core/src/shadertypes/textures/texture-format-table.ts
1010
1115
  var texture_compression_bc = "texture-compression-bc";
1011
1116
  var texture_compression_astc = "texture-compression-astc";
1012
1117
  var texture_compression_etc2 = "texture-compression-etc2";
@@ -1031,73 +1136,65 @@ var __exports__ = (() => {
1031
1136
  function getTextureFormatTable() {
1032
1137
  return TEXTURE_FORMAT_TABLE;
1033
1138
  }
1034
- var TEXTURE_FORMAT_TABLE = {
1139
+ var TEXTURE_FORMAT_COLOR_DEPTH_TABLE = {
1035
1140
  // 8-bit formats
1036
1141
  "r8unorm": {},
1037
- "r8snorm": { render: snorm8_renderable },
1038
- "r8uint": {},
1039
- "r8sint": {},
1040
- // 16-bit formats
1041
1142
  "rg8unorm": {},
1042
- "rg8snorm": { render: snorm8_renderable },
1043
- "rg8uint": {},
1044
- "rg8sint": {},
1045
- "r16uint": {},
1046
- "r16sint": {},
1047
- "r16float": { render: float16_renderable, filter: "float16-filterable-webgl" },
1048
- "r16unorm-webgl": { f: norm16_renderable },
1049
- "r16snorm-webgl": { f: snorm16_renderable },
1050
- // Packed 16-bit formats
1051
- "rgba4unorm-webgl": { channels: "rgba", bitsPerChannel: [4, 4, 4, 4], packed: true },
1052
- "rgb565unorm-webgl": { channels: "rgb", bitsPerChannel: [5, 6, 5, 0], packed: true },
1053
- "rgb5a1unorm-webgl": { channels: "rgba", bitsPerChannel: [5, 5, 5, 1], packed: true },
1054
- // 24-bit formats
1055
1143
  "rgb8unorm-webgl": {},
1056
- "rgb8snorm-webgl": {},
1057
- // 32-bit formats
1058
1144
  "rgba8unorm": {},
1059
1145
  "rgba8unorm-srgb": {},
1146
+ "r8snorm": { render: snorm8_renderable },
1147
+ "rg8snorm": { render: snorm8_renderable },
1148
+ "rgb8snorm-webgl": {},
1060
1149
  "rgba8snorm": { render: snorm8_renderable },
1150
+ "r8uint": {},
1151
+ "rg8uint": {},
1061
1152
  "rgba8uint": {},
1153
+ "r8sint": {},
1154
+ "rg8sint": {},
1062
1155
  "rgba8sint": {},
1063
- // 32-bit, reverse colors, webgpu only
1064
1156
  "bgra8unorm": {},
1065
1157
  "bgra8unorm-srgb": {},
1158
+ "r16unorm": { f: norm16_renderable },
1159
+ "rg16unorm": { render: norm16_renderable },
1160
+ "rgb16unorm-webgl": { f: norm16_renderable },
1161
+ // rgb not renderable
1162
+ "rgba16unorm": { render: norm16_renderable },
1163
+ "r16snorm": { f: snorm16_renderable },
1164
+ "rg16snorm": { render: snorm16_renderable },
1165
+ "rgb16snorm-webgl": { f: norm16_renderable },
1166
+ // rgb not renderable
1167
+ "rgba16snorm": { render: snorm16_renderable },
1168
+ "r16uint": {},
1066
1169
  "rg16uint": {},
1170
+ "rgba16uint": {},
1171
+ "r16sint": {},
1067
1172
  "rg16sint": {},
1173
+ "rgba16sint": {},
1174
+ "r16float": { render: float16_renderable, filter: "float16-filterable-webgl" },
1068
1175
  "rg16float": { render: float16_renderable, filter: float16_filterable },
1069
- "rg16unorm-webgl": { render: norm16_renderable },
1070
- "rg16snorm-webgl": { render: snorm16_renderable },
1176
+ "rgba16float": { render: float16_renderable, filter: float16_filterable },
1071
1177
  "r32uint": {},
1178
+ "rg32uint": {},
1179
+ "rgba32uint": {},
1072
1180
  "r32sint": {},
1181
+ "rg32sint": {},
1182
+ "rgba32sint": {},
1073
1183
  "r32float": { render: float32_renderable, filter: float32_filterable },
1184
+ "rg32float": { render: false, filter: float32_filterable },
1185
+ "rgb32float-webgl": { render: float32_renderable, filter: float32_filterable },
1186
+ "rgba32float": { render: float32_renderable, filter: float32_filterable },
1187
+ // Packed 16-bit formats
1188
+ "rgba4unorm-webgl": { channels: "rgba", bitsPerChannel: [4, 4, 4, 4], packed: true },
1189
+ "rgb565unorm-webgl": { channels: "rgb", bitsPerChannel: [5, 6, 5, 0], packed: true },
1190
+ "rgb5a1unorm-webgl": { channels: "rgba", bitsPerChannel: [5, 5, 5, 1], packed: true },
1074
1191
  // Packed 32 bit formats
1075
1192
  "rgb9e5ufloat": { channels: "rgb", packed: true, render: rgb9e5ufloat_renderable },
1076
1193
  // , filter: true},
1077
1194
  "rg11b10ufloat": { channels: "rgb", bitsPerChannel: [11, 11, 10, 0], packed: true, p: 1, render: float32_renderable },
1078
1195
  "rgb10a2unorm": { channels: "rgba", bitsPerChannel: [10, 10, 10, 2], packed: true, p: 1 },
1079
- "rgb10a2uint-webgl": { channels: "rgba", bitsPerChannel: [10, 10, 10, 2], packed: true, p: 1, wgpu: false },
1080
- // 48-bit formats
1081
- "rgb16unorm-webgl": { f: norm16_renderable },
1082
- // rgb not renderable
1083
- "rgb16snorm-webgl": { f: norm16_renderable },
1084
- // rgb not renderable
1085
- // 64-bit formats
1086
- "rg32uint": {},
1087
- "rg32sint": {},
1088
- "rg32float": { render: false, filter: float32_filterable },
1089
- "rgba16uint": {},
1090
- "rgba16sint": {},
1091
- "rgba16float": { render: float16_renderable, filter: float16_filterable },
1092
- "rgba16unorm-webgl": { render: norm16_renderable },
1093
- "rgba16snorm-webgl": { render: snorm16_renderable },
1094
- // 96-bit formats (deprecated!)
1095
- "rgb32float-webgl": { render: float32_renderable, filter: float32_filterable },
1096
- // 128-bit formats
1097
- "rgba32uint": {},
1098
- "rgba32sint": {},
1099
- "rgba32float": { render: float32_renderable, filter: float32_filterable },
1100
- // Depth/stencil
1196
+ "rgb10a2uint": { channels: "rgba", bitsPerChannel: [10, 10, 10, 2], packed: true, p: 1 },
1197
+ // Depth/stencil Formats
1101
1198
  // Depth and stencil formats
1102
1199
  stencil8: { attachment: "stencil", bitsPerChannel: [8, 0, 0, 0], dataType: "uint8" },
1103
1200
  "depth16unorm": { attachment: "depth", bitsPerChannel: [16, 0, 0, 0], dataType: "uint16" },
@@ -1106,7 +1203,9 @@ var __exports__ = (() => {
1106
1203
  // The depth component of the "depth24plus" and "depth24plus-stencil8" formats may be implemented as either a 24-bit depth value or a "depth32float" value.
1107
1204
  "depth24plus-stencil8": { attachment: "depth-stencil", bitsPerChannel: [24, 8, 0, 0], packed: true },
1108
1205
  // "depth32float-stencil8" feature
1109
- "depth32float-stencil8": { attachment: "depth-stencil", bitsPerChannel: [32, 8, 0, 0], packed: true },
1206
+ "depth32float-stencil8": { attachment: "depth-stencil", bitsPerChannel: [32, 8, 0, 0], packed: true }
1207
+ };
1208
+ var TEXTURE_FORMAT_COMPRESSED_TABLE = {
1110
1209
  // BC compressed formats: check device.features.has("texture-compression-bc");
1111
1210
  "bc1-rgb-unorm-webgl": { f: texture_compression_bc },
1112
1211
  "bc1-rgb-unorm-srgb-webgl": { f: texture_compression_bc },
@@ -1177,8 +1276,12 @@ var __exports__ = (() => {
1177
1276
  "atc-rgba-unorm-webgl": { f: texture_compression_atc_webgl },
1178
1277
  "atc-rgbai-unorm-webgl": { f: texture_compression_atc_webgl }
1179
1278
  };
1279
+ var TEXTURE_FORMAT_TABLE = {
1280
+ ...TEXTURE_FORMAT_COLOR_DEPTH_TABLE,
1281
+ ...TEXTURE_FORMAT_COMPRESSED_TABLE
1282
+ };
1180
1283
 
1181
- // ../core/src/gpu-type-utils/decode-texture-format.ts
1284
+ // ../core/src/shadertypes/textures/texture-format-decoder.ts
1182
1285
  var COMPRESSED_TEXTURE_FORMAT_PREFIXES = [
1183
1286
  "bc1",
1184
1287
  "bc2",
@@ -1195,12 +1298,51 @@ var __exports__ = (() => {
1195
1298
  "pvrtc"
1196
1299
  ];
1197
1300
  var RGB_FORMAT_REGEX = /^(r|rg|rgb|rgba|bgra)([0-9]*)([a-z]*)(-srgb)?(-webgl)?$/;
1198
- function isTextureFormatCompressed(format) {
1199
- return COMPRESSED_TEXTURE_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
1200
- }
1201
- function decodeTextureFormat(format) {
1202
- let formatInfo = decodeTextureFormatUsingTable(format);
1203
- if (isTextureFormatCompressed(format)) {
1301
+ var TextureFormatDecoder = class {
1302
+ /** Returns information about a texture format, e.g. attatchment type, components, byte length and flags (integer, signed, normalized) */
1303
+ getInfo(format) {
1304
+ return getTextureFormatInfo(format);
1305
+ }
1306
+ /** Checks if a texture format is color */
1307
+ isColor(format) {
1308
+ return format.startsWith("rgba") || format.startsWith("bgra") || format.startsWith("rgb");
1309
+ }
1310
+ /** Checks if a texture format is depth or stencil */
1311
+ isDepthStencil(format) {
1312
+ return format.startsWith("depth") || format.startsWith("stencil");
1313
+ }
1314
+ /** Checks if a texture format is compressed */
1315
+ isCompressed(format) {
1316
+ return COMPRESSED_TEXTURE_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
1317
+ }
1318
+ /**
1319
+ * Returns the "static" capabilities of a texture format.
1320
+ * @note Needs to be checked against current device
1321
+ */
1322
+ getCapabilities(format) {
1323
+ const info = getTextureFormatDefinition(format);
1324
+ const formatCapabilities = {
1325
+ format,
1326
+ create: info.f ?? true,
1327
+ render: info.render ?? true,
1328
+ filter: info.filter ?? true,
1329
+ blend: info.blend ?? true,
1330
+ store: info.store ?? true
1331
+ };
1332
+ const formatInfo = getTextureFormatInfo(format);
1333
+ const isDepthStencil = format.startsWith("depth") || format.startsWith("stencil");
1334
+ const isSigned = formatInfo?.signed;
1335
+ const isInteger = formatInfo?.integer;
1336
+ const isWebGLSpecific = formatInfo?.webgl;
1337
+ formatCapabilities.render &&= !isSigned;
1338
+ formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
1339
+ return formatCapabilities;
1340
+ }
1341
+ };
1342
+ var textureFormatDecoder = new TextureFormatDecoder();
1343
+ function getTextureFormatInfo(format) {
1344
+ let formatInfo = getTextureFormatInfoUsingTable(format);
1345
+ if (textureFormatDecoder.isCompressed(format)) {
1204
1346
  formatInfo.channels = "rgb";
1205
1347
  formatInfo.components = 3;
1206
1348
  formatInfo.bytesPerPixel = 1;
@@ -1216,7 +1358,7 @@ var __exports__ = (() => {
1216
1358
  if (matches) {
1217
1359
  const [, channels, length, type, srgb, suffix] = matches;
1218
1360
  const dataType = `${type}${length}`;
1219
- const decodedType = decodeVertexType(dataType);
1361
+ const decodedType = getDataTypeInfo(dataType);
1220
1362
  const bits = decodedType.byteLength * 8;
1221
1363
  const components = channels.length;
1222
1364
  const bitsPerChannel = [
@@ -1228,7 +1370,7 @@ var __exports__ = (() => {
1228
1370
  formatInfo = {
1229
1371
  format,
1230
1372
  attachment: formatInfo.attachment,
1231
- dataType: decodedType.dataType,
1373
+ dataType: decodedType.signedType,
1232
1374
  components,
1233
1375
  channels,
1234
1376
  integer: decodedType.integer,
@@ -1254,7 +1396,7 @@ var __exports__ = (() => {
1254
1396
  }
1255
1397
  return formatInfo;
1256
1398
  }
1257
- function decodeTextureFormatUsingTable(format) {
1399
+ function getTextureFormatInfoUsingTable(format) {
1258
1400
  const info = getTextureFormatDefinition(format);
1259
1401
  const bytesPerPixel = info.bytesPerPixel || 1;
1260
1402
  const bitsPerChannel = info.bitsPerChannel || [8, 8, 8, 8];
@@ -1294,25 +1436,24 @@ var __exports__ = (() => {
1294
1436
  return null;
1295
1437
  }
1296
1438
 
1297
- // ../core/src/gpu-type-utils/texture-format-capabilities.ts
1298
- function getTextureFormatCapabilities(format) {
1299
- const info = getTextureFormatDefinition(format);
1300
- const formatCapabilities = {
1301
- format,
1302
- create: info.f ?? true,
1303
- render: info.render ?? true,
1304
- filter: info.filter ?? true,
1305
- blend: info.blend ?? true,
1306
- store: info.store ?? true
1307
- };
1308
- const formatInfo = decodeTextureFormat(format);
1309
- const isDepthStencil = format.startsWith("depth") || format.startsWith("stencil");
1310
- const isSigned = formatInfo?.signed;
1311
- const isInteger = formatInfo?.integer;
1312
- const isWebGLSpecific = formatInfo?.webgl;
1313
- formatCapabilities.render &&= !isSigned;
1314
- formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
1315
- return formatCapabilities;
1439
+ // ../core/src/image-utils/image-types.ts
1440
+ function isExternalImage(data) {
1441
+ return typeof ImageData !== "undefined" && data instanceof ImageData || typeof ImageBitmap !== "undefined" && data instanceof ImageBitmap || typeof HTMLImageElement !== "undefined" && data instanceof HTMLImageElement || typeof HTMLVideoElement !== "undefined" && data instanceof HTMLVideoElement || typeof VideoFrame !== "undefined" && data instanceof VideoFrame || typeof HTMLCanvasElement !== "undefined" && data instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && data instanceof OffscreenCanvas;
1442
+ }
1443
+ function getExternalImageSize(data) {
1444
+ if (typeof ImageData !== "undefined" && data instanceof ImageData || typeof ImageBitmap !== "undefined" && data instanceof ImageBitmap || typeof HTMLCanvasElement !== "undefined" && data instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && data instanceof OffscreenCanvas) {
1445
+ return { width: data.width, height: data.height };
1446
+ }
1447
+ if (typeof HTMLImageElement !== "undefined" && data instanceof HTMLImageElement) {
1448
+ return { width: data.naturalWidth, height: data.naturalHeight };
1449
+ }
1450
+ if (typeof HTMLVideoElement !== "undefined" && data instanceof HTMLVideoElement) {
1451
+ return { width: data.videoWidth, height: data.videoHeight };
1452
+ }
1453
+ if (typeof VideoFrame !== "undefined" && data instanceof VideoFrame) {
1454
+ return { width: data.displayWidth, height: data.displayHeight };
1455
+ }
1456
+ throw new Error("Unknown image type");
1316
1457
  }
1317
1458
 
1318
1459
  // ../core/src/adapter/device.ts
@@ -1336,9 +1477,8 @@ var __exports__ = (() => {
1336
1477
  get [Symbol.toStringTag]() {
1337
1478
  return "Device";
1338
1479
  }
1339
- constructor(props) {
1340
- this.props = { ..._Device.defaultProps, ...props };
1341
- this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase());
1480
+ toString() {
1481
+ return `Device(${this.id})`;
1342
1482
  }
1343
1483
  /** id of this device, primarily for debugging */
1344
1484
  id;
@@ -1354,23 +1494,46 @@ var __exports__ = (() => {
1354
1494
  _reused = false;
1355
1495
  /** Used by other luma.gl modules to store data on the device */
1356
1496
  _lumaData = {};
1357
- /** Determines what operations are supported on a texture format, checking against supported device features */
1497
+ _textureCaps = {};
1498
+ constructor(props) {
1499
+ this.props = { ..._Device.defaultProps, ...props };
1500
+ this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase());
1501
+ }
1502
+ getVertexFormatInfo(format) {
1503
+ return getVertexFormatInfo(format);
1504
+ }
1505
+ isVertexFormatSupported(format) {
1506
+ return true;
1507
+ }
1508
+ /** Returns information about a texture format, such as data type, channels, bits per channel, compression etc */
1509
+ getTextureFormatInfo(format) {
1510
+ return textureFormatDecoder.getInfo(format);
1511
+ }
1512
+ /** Determines what operations are supported on a texture format on this particular device (checks against supported device features) */
1358
1513
  getTextureFormatCapabilities(format) {
1359
- const genericCapabilities = getTextureFormatCapabilities(format);
1360
- const checkFeature = (featureOrBoolean) => (typeof featureOrBoolean === "string" ? this.features.has(featureOrBoolean) : featureOrBoolean) ?? true;
1361
- const supported = checkFeature(genericCapabilities.create);
1362
- const deviceCapabilities = {
1363
- format,
1364
- create: supported,
1365
- render: supported && checkFeature(genericCapabilities.render),
1366
- filter: supported && checkFeature(genericCapabilities.filter),
1367
- blend: supported && checkFeature(genericCapabilities.blend),
1368
- store: supported && checkFeature(genericCapabilities.store)
1369
- };
1370
- return this._getDeviceSpecificTextureFormatCapabilities(deviceCapabilities);
1514
+ let textureCaps = this._textureCaps[format];
1515
+ if (!textureCaps) {
1516
+ const capabilities = this._getDeviceTextureFormatCapabilities(format);
1517
+ textureCaps = this._getDeviceSpecificTextureFormatCapabilities(capabilities);
1518
+ this._textureCaps[format] = textureCaps;
1519
+ }
1520
+ return textureCaps;
1521
+ }
1522
+ /** Calculates the number of mip levels for a texture of width, height and in case of 3d textures only, depth */
1523
+ getMipLevelCount(width, height, depth3d = 1) {
1524
+ const maxSize = Math.max(width, height, depth3d);
1525
+ return 1 + Math.floor(Math.log2(maxSize));
1526
+ }
1527
+ /** Check if data is an external image */
1528
+ isExternalImage(data) {
1529
+ return isExternalImage(data);
1530
+ }
1531
+ /** Get the size of an external image */
1532
+ getExternalImageSize(data) {
1533
+ return getExternalImageSize(data);
1371
1534
  }
1372
1535
  /** Check if device supports a specific texture format (creation and `nearest` sampling) */
1373
- isTextureFormatSupported(format, capabilities) {
1536
+ isTextureFormatSupported(format) {
1374
1537
  return this.getTextureFormatCapabilities(format).create;
1375
1538
  }
1376
1539
  /** Check if linear filtering (sampler interpolation) is supported for a specific texture format */
@@ -1383,7 +1546,17 @@ var __exports__ = (() => {
1383
1546
  }
1384
1547
  /** Check if a specific texture format is GPU compressed */
1385
1548
  isTextureFormatCompressed(format) {
1386
- return isTextureFormatCompressed(format);
1549
+ return textureFormatDecoder.isCompressed(format);
1550
+ }
1551
+ // DEBUG METHODS
1552
+ pushDebugGroup(groupLabel) {
1553
+ this.commandEncoder.pushDebugGroup(groupLabel);
1554
+ }
1555
+ popDebugGroup() {
1556
+ this.commandEncoder?.popDebugGroup();
1557
+ }
1558
+ insertDebugMarker(markerLabel) {
1559
+ this.commandEncoder?.insertDebugMarker(markerLabel);
1387
1560
  }
1388
1561
  /**
1389
1562
  * Trigger device loss.
@@ -1393,9 +1566,44 @@ var __exports__ = (() => {
1393
1566
  loseDevice() {
1394
1567
  return false;
1395
1568
  }
1396
- /** Report error (normally called for unhandled device errors) */
1397
- reportError(error) {
1398
- this.props.onError(error);
1569
+ /** A monotonic counter for tracking buffer and texture updates */
1570
+ incrementTimestamp() {
1571
+ return this.timestamp++;
1572
+ }
1573
+ /**
1574
+ * Reports Device errors in a way that optimizes for developer experience / debugging.
1575
+ * - Logs so that the console error links directly to the source code that generated the error.
1576
+ * - Includes the object that reported the error in the log message, even if the error is asynchronous.
1577
+ *
1578
+ * Conventions when calling reportError():
1579
+ * - Always call the returned function - to ensure error is logged, at the error site
1580
+ * - Follow with a call to device.debug() - to ensure that the debugger breaks at the error site
1581
+ *
1582
+ * @param error - the error to report. If needed, just create a new Error object with the appropriate message.
1583
+ * @param context - pass `this` as context, otherwise it may not be available in the debugger for async errors.
1584
+ * @returns the logger function returned by device.props.onError() so that it can be called from the error site.
1585
+ *
1586
+ * @example
1587
+ * device.reportError(new Error(...), this)();
1588
+ * device.debug();
1589
+ */
1590
+ reportError(error, context, ...args) {
1591
+ const isHandled = this.props.onError(error, context);
1592
+ if (!isHandled) {
1593
+ return log.error(error.message, context, ...args);
1594
+ }
1595
+ return () => {
1596
+ };
1597
+ }
1598
+ /** Break in the debugger - if device.props.debug is true */
1599
+ debug() {
1600
+ if (this.props.debug) {
1601
+ debugger;
1602
+ } else {
1603
+ const message = `'Type luma.log.set({debug: true}) in console to enable debug breakpoints',
1604
+ or create a device with the 'debug: true' prop.`;
1605
+ log.once(0, message)();
1606
+ }
1399
1607
  }
1400
1608
  /** Returns the default / primary canvas context. Throws an error if no canvas context is available (a WebGPU compute device) */
1401
1609
  getDefaultCanvasContext() {
@@ -1404,17 +1612,13 @@ var __exports__ = (() => {
1404
1612
  }
1405
1613
  return this.canvasContext;
1406
1614
  }
1407
- createCommandEncoder(props = {}) {
1408
- throw new Error("not implemented");
1409
- }
1410
- /** A monotonic counter for tracking buffer and texture updates */
1411
- incrementTimestamp() {
1412
- return this.timestamp++;
1615
+ /** Create a RenderPass using the default CommandEncoder */
1616
+ beginRenderPass(props) {
1617
+ return this.commandEncoder.beginRenderPass(props);
1413
1618
  }
1414
- // Error Handling
1415
- /** Report unhandled device errors */
1416
- onError(error) {
1417
- this.props.onError(error);
1619
+ /** Create a ComputePass using the default CommandEncoder*/
1620
+ beginComputePass(props) {
1621
+ return this.commandEncoder.beginComputePass(props);
1418
1622
  }
1419
1623
  // DEPRECATED METHODS
1420
1624
  /** @deprecated Use getDefaultCanvasContext() */
@@ -1456,19 +1660,36 @@ var __exports__ = (() => {
1456
1660
  static _getCanvasContextProps(props) {
1457
1661
  return props.createCanvasContext === true ? {} : props.createCanvasContext;
1458
1662
  }
1663
+ _getDeviceTextureFormatCapabilities(format) {
1664
+ const genericCapabilities = textureFormatDecoder.getCapabilities(format);
1665
+ const checkFeature = (feature) => (typeof feature === "string" ? this.features.has(feature) : feature) ?? true;
1666
+ const supported = checkFeature(genericCapabilities.create);
1667
+ return {
1668
+ format,
1669
+ create: supported,
1670
+ render: supported && checkFeature(genericCapabilities.render),
1671
+ filter: supported && checkFeature(genericCapabilities.filter),
1672
+ blend: supported && checkFeature(genericCapabilities.blend),
1673
+ store: supported && checkFeature(genericCapabilities.store)
1674
+ };
1675
+ }
1459
1676
  /** Subclasses use this to support .createBuffer() overloads */
1460
1677
  _normalizeBufferProps(props) {
1461
1678
  if (props instanceof ArrayBuffer || ArrayBuffer.isView(props)) {
1462
1679
  props = { data: props };
1463
1680
  }
1464
1681
  const newProps = { ...props };
1465
- if ((props.usage || 0) & Buffer2.INDEX && !props.indexType) {
1466
- if (props.data instanceof Uint32Array) {
1467
- newProps.indexType = "uint32";
1468
- } else if (props.data instanceof Uint16Array) {
1469
- newProps.indexType = "uint16";
1470
- } else {
1471
- log.warn("indices buffer content must be of integer type")();
1682
+ const usage = props.usage || 0;
1683
+ if (usage & Buffer2.INDEX) {
1684
+ if (!props.indexType) {
1685
+ if (props.data instanceof Uint32Array) {
1686
+ newProps.indexType = "uint32";
1687
+ } else if (props.data instanceof Uint16Array) {
1688
+ newProps.indexType = "uint16";
1689
+ }
1690
+ }
1691
+ if (!newProps.indexType) {
1692
+ throw new Error("indices buffer content must be of type uint16 or uint32");
1472
1693
  }
1473
1694
  }
1474
1695
  return newProps;
@@ -1480,34 +1701,47 @@ var __exports__ = (() => {
1480
1701
  powerPreference: "high-performance",
1481
1702
  failIfMajorPerformanceCaveat: false,
1482
1703
  createCanvasContext: void 0,
1483
- // Callbacks
1484
- onError: (error) => log.error(error.message)(),
1485
- // Experimental
1486
- _reuseDevices: false,
1487
- _requestMaxLimits: true,
1488
- _factoryDestroyPolicy: "unused",
1489
- // TODO - Change these after confirming things work as expected
1490
- _initializeFeatures: true,
1491
- _disabledFeatures: {
1492
- "compilation-status-async-webgl": true
1493
- },
1494
- _resourceDefaults: {},
1495
1704
  // WebGL specific
1496
1705
  webgl: {},
1706
+ // Callbacks
1707
+ // eslint-disable-next-line handle-callback-err
1708
+ onError: (error, context) => {
1709
+ },
1710
+ onResize: (context, info) => {
1711
+ const [width, height] = context.getDevicePixelSize();
1712
+ log.log(1, `${context} resized => ${width}x${height}px`)();
1713
+ },
1714
+ onPositionChange: (context, info) => {
1715
+ const [left, top] = context.getPosition();
1716
+ log.log(1, `${context} repositioned => ${left},${top}`)();
1717
+ },
1718
+ onVisibilityChange: (context) => log.log(1, `${context} Visibility changed ${context.isVisible}`)(),
1719
+ onDevicePixelRatioChange: (context, info) => log.log(1, `${context} DPR changed ${info.oldRatio} => ${context.devicePixelRatio}`)(),
1720
+ // Debug flags
1497
1721
  debug: log.get("debug") || void 0,
1498
1722
  debugShaders: log.get("debug-shaders") || void 0,
1499
1723
  debugFramebuffers: Boolean(log.get("debug-framebuffers")),
1724
+ debugFactories: Boolean(log.get("debug-factories")),
1500
1725
  debugWebGL: Boolean(log.get("debug-webgl")),
1501
1726
  debugSpectorJS: void 0,
1502
1727
  // Note: log setting is queried by the spector.js code
1503
1728
  debugSpectorJSUrl: void 0,
1729
+ // Experimental
1730
+ _reuseDevices: false,
1731
+ _requestMaxLimits: true,
1732
+ _cacheShaders: false,
1733
+ _cachePipelines: false,
1734
+ _cacheDestroyPolicy: "unused",
1735
+ // TODO - Change these after confirming things work as expected
1736
+ _initializeFeatures: true,
1737
+ _disabledFeatures: {
1738
+ "compilation-status-async-webgl": true
1739
+ },
1504
1740
  // INTERNAL
1505
1741
  _handle: void 0
1506
1742
  });
1507
1743
 
1508
1744
  // ../core/src/adapter/luma.ts
1509
- var isPage = isBrowser() && typeof document !== "undefined";
1510
- var isPageLoaded = () => isPage && document.readyState === "complete";
1511
1745
  var STARTUP_MESSAGE = "set luma.log.level=1 (or higher) to trace rendering";
1512
1746
  var ERROR_MESSAGE = "No matching device found. Ensure `@luma.gl/webgl` and/or `@luma.gl/webgpu` modules are imported.";
1513
1747
  var _Luma = class {
@@ -1541,6 +1775,34 @@ var __exports__ = (() => {
1541
1775
  log.log(1, `${this.VERSION} - ${STARTUP_MESSAGE}`)();
1542
1776
  globalThis.luma = this;
1543
1777
  }
1778
+ /** Creates a device. Asynchronously. */
1779
+ async createDevice(props_ = {}) {
1780
+ const props = { ..._Luma.defaultProps, ...props_ };
1781
+ const adapter = this.selectAdapter(props.type, props.adapters);
1782
+ if (!adapter) {
1783
+ throw new Error(ERROR_MESSAGE);
1784
+ }
1785
+ if (props.waitForPageLoad) {
1786
+ await adapter.pageLoaded;
1787
+ }
1788
+ return await adapter.create(props);
1789
+ }
1790
+ /**
1791
+ * Attach to an existing GPU API handle (WebGL2RenderingContext or GPUDevice).
1792
+ * @param handle Externally created WebGL context or WebGPU device
1793
+ */
1794
+ async attachDevice(handle, props) {
1795
+ const type = this._getTypeFromHandle(handle, props.adapters);
1796
+ const adapter = type && this.selectAdapter(type, props.adapters);
1797
+ if (!adapter) {
1798
+ throw new Error(ERROR_MESSAGE);
1799
+ }
1800
+ return await adapter?.attach?.(handle, props);
1801
+ }
1802
+ /**
1803
+ * Global adapter registration.
1804
+ * @deprecated Use props.adapters instead
1805
+ */
1544
1806
  registerAdapters(adapters) {
1545
1807
  for (const deviceClass of adapters) {
1546
1808
  this.preregisteredAdapters.set(deviceClass.type, deviceClass);
@@ -1548,92 +1810,75 @@ var __exports__ = (() => {
1548
1810
  }
1549
1811
  /** Get type strings for supported Devices */
1550
1812
  getSupportedAdapters(adapters = []) {
1551
- const adapterMap = this.getAdapterMap(adapters);
1813
+ const adapterMap = this._getAdapterMap(adapters);
1552
1814
  return Array.from(adapterMap).map(([, adapter]) => adapter).filter((adapter) => adapter.isSupported?.()).map((adapter) => adapter.type);
1553
1815
  }
1554
1816
  /** Get type strings for best available Device */
1555
- getBestAvailableAdapter(adapters = []) {
1556
- const adapterMap = this.getAdapterMap(adapters);
1557
- if (adapterMap.get("webgpu")?.isSupported?.()) {
1558
- return "webgpu";
1559
- }
1560
- if (adapterMap.get("webgl")?.isSupported?.()) {
1561
- return "webgl";
1817
+ getBestAvailableAdapterType(adapters = []) {
1818
+ const KNOWN_ADAPTERS = ["webgpu", "webgl", "null"];
1819
+ const adapterMap = this._getAdapterMap(adapters);
1820
+ for (const type of KNOWN_ADAPTERS) {
1821
+ if (adapterMap.get(type)?.isSupported?.()) {
1822
+ return type;
1823
+ }
1562
1824
  }
1563
1825
  return null;
1564
1826
  }
1565
- setDefaultDeviceProps(props) {
1566
- Object.assign(_Luma.defaultProps, props);
1567
- }
1568
- /** Creates a device. Asynchronously. */
1569
- async createDevice(props = {}) {
1570
- props = { ..._Luma.defaultProps, ...props };
1571
- if (props.waitForPageLoad) {
1572
- await _Luma.pageLoaded;
1573
- }
1574
- const adapterMap = this.getAdapterMap(props.adapters);
1575
- let type = props.type || "";
1827
+ /** Select adapter of type from registered adapters */
1828
+ selectAdapter(type, adapters = []) {
1829
+ let selectedType = type;
1576
1830
  if (type === "best-available") {
1577
- type = this.getBestAvailableAdapter(props.adapters) || type;
1578
- }
1579
- const adapters = this.getAdapterMap(props.adapters) || adapterMap;
1580
- const adapter = adapters.get(type);
1581
- const device = await adapter?.create?.(props);
1582
- if (device) {
1583
- return device;
1584
- }
1585
- throw new Error(ERROR_MESSAGE);
1586
- }
1587
- /** Attach to an existing GPU API handle (WebGL2RenderingContext or GPUDevice). */
1588
- async attachDevice(props) {
1589
- const adapters = this.getAdapterMap(props.adapters);
1590
- let type = "";
1591
- if (props.handle instanceof WebGL2RenderingContext) {
1592
- type = "webgl";
1593
- }
1594
- if (props.createCanvasContext) {
1595
- await _Luma.pageLoaded;
1596
- }
1597
- if (props.handle === null) {
1598
- type = "unknown";
1599
- }
1600
- const adapter = adapters.get(type);
1601
- const device = await adapter?.attach?.(null);
1602
- if (device) {
1603
- return device;
1831
+ selectedType = this.getBestAvailableAdapterType(adapters);
1604
1832
  }
1605
- throw new Error(ERROR_MESSAGE);
1833
+ const adapterMap = this._getAdapterMap(adapters);
1834
+ return selectedType && adapterMap.get(selectedType) || null;
1606
1835
  }
1607
1836
  /**
1608
1837
  * Override `HTMLCanvasContext.getCanvas()` to always create WebGL2 contexts with additional WebGL1 compatibility.
1609
1838
  * Useful when attaching luma to a context from an external library does not support creating WebGL2 contexts.
1610
1839
  */
1611
1840
  enforceWebGL2(enforce = true, adapters = []) {
1612
- const adapterMap = this.getAdapterMap(adapters);
1841
+ const adapterMap = this._getAdapterMap(adapters);
1613
1842
  const webgl2Adapter = adapterMap.get("webgl");
1614
1843
  if (!webgl2Adapter) {
1615
1844
  log.warn("enforceWebGL2: webgl adapter not found")();
1616
1845
  }
1617
1846
  webgl2Adapter?.enforceWebGL2?.(enforce);
1618
1847
  }
1848
+ // DEPRECATED
1849
+ /** @deprecated */
1850
+ setDefaultDeviceProps(props) {
1851
+ Object.assign(_Luma.defaultProps, props);
1852
+ }
1853
+ // HELPERS
1619
1854
  /** Convert a list of adapters to a map */
1620
- getAdapterMap(adapters = []) {
1855
+ _getAdapterMap(adapters = []) {
1621
1856
  const map = new Map(this.preregisteredAdapters);
1622
1857
  for (const adapter of adapters) {
1623
1858
  map.set(adapter.type, adapter);
1624
1859
  }
1625
1860
  return map;
1626
1861
  }
1627
- // DEPRECATED
1628
- /** @deprecated Use registerAdapters */
1629
- registerDevices(deviceClasses) {
1630
- log.warn("luma.registerDevices() is deprecated, use luma.registerAdapters() instead");
1631
- for (const deviceClass of deviceClasses) {
1632
- const adapter = deviceClass.adapter;
1633
- if (adapter) {
1634
- this.preregisteredAdapters.set(adapter.type, adapter);
1635
- }
1862
+ /** Get type of a handle (for attachDevice) */
1863
+ _getTypeFromHandle(handle, adapters = []) {
1864
+ if (handle instanceof WebGL2RenderingContext) {
1865
+ return "webgl";
1866
+ }
1867
+ if (typeof GPUDevice !== "undefined" && handle instanceof GPUDevice) {
1868
+ return "webgpu";
1869
+ }
1870
+ if (handle?.queue) {
1871
+ return "webgpu";
1872
+ }
1873
+ if (handle === null) {
1874
+ return "null";
1636
1875
  }
1876
+ if (handle instanceof WebGLRenderingContext) {
1877
+ log.warn("WebGL1 is not supported", handle)();
1878
+ } else {
1879
+ log.warn("Unknown handle type", handle)();
1880
+ }
1881
+ return null;
1637
1882
  }
1638
1883
  };
1639
1884
  var Luma = _Luma;
@@ -1643,224 +1888,326 @@ var __exports__ = (() => {
1643
1888
  adapters: void 0,
1644
1889
  waitForPageLoad: true
1645
1890
  });
1646
- /**
1647
- * Page load promise
1648
- * Get a 'lazy' promise that resolves when the DOM is loaded.
1649
- * @note Since there may be limitations on number of `load` event listeners,
1650
- * it is recommended avoid calling this function until actually needed.
1651
- * I.e. don't call it until you know that you will be looking up a string in the DOM.
1652
- */
1653
- __publicField(Luma, "pageLoaded", getPageLoadPromise().then(() => {
1654
- log.probe(2, "DOM is loaded")();
1655
- }));
1656
1891
  var luma = new Luma();
1657
- function getPageLoadPromise() {
1658
- if (isPageLoaded() || typeof window === "undefined") {
1659
- return Promise.resolve();
1660
- }
1661
- return new Promise((resolve) => {
1662
- window.addEventListener("load", () => resolve());
1663
- });
1664
- }
1665
1892
 
1666
1893
  // ../core/src/adapter/adapter.ts
1667
1894
  var Adapter = class {
1895
+ /**
1896
+ * Page load promise
1897
+ * Resolves when the DOM is loaded.
1898
+ * @note Since are be limitations on number of `load` event listeners,
1899
+ * it is recommended avoid calling this accessor until actually needed.
1900
+ * I.e. we don't call it unless you know that you will be looking up a string in the DOM.
1901
+ */
1902
+ get pageLoaded() {
1903
+ return getPageLoadPromise();
1904
+ }
1668
1905
  };
1906
+ var isPage = isBrowser() && typeof document !== "undefined";
1907
+ var isPageLoaded = () => isPage && document.readyState === "complete";
1908
+ var pageLoadPromise = null;
1909
+ function getPageLoadPromise() {
1910
+ if (!pageLoadPromise) {
1911
+ if (isPageLoaded() || typeof window === "undefined") {
1912
+ pageLoadPromise = Promise.resolve();
1913
+ } else {
1914
+ pageLoadPromise = new Promise((resolve) => window.addEventListener("load", () => resolve()));
1915
+ }
1916
+ }
1917
+ return pageLoadPromise;
1918
+ }
1919
+
1920
+ // ../core/src/utils/promise-utils.ts
1921
+ function withResolvers() {
1922
+ let resolve;
1923
+ let reject;
1924
+ const promise = new Promise((_resolve, _reject) => {
1925
+ resolve = _resolve;
1926
+ reject = _reject;
1927
+ });
1928
+ return { promise, resolve, reject };
1929
+ }
1669
1930
 
1670
1931
  // ../core/src/adapter/canvas-context.ts
1671
1932
  var _CanvasContext = class {
1933
+ static isHTMLCanvas(canvas) {
1934
+ return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
1935
+ }
1936
+ static isOffscreenCanvas(canvas) {
1937
+ return typeof OffscreenCanvas !== "undefined" && canvas instanceof OffscreenCanvas;
1938
+ }
1672
1939
  id;
1673
1940
  props;
1674
1941
  canvas;
1942
+ /** Handle to HTML canvas */
1675
1943
  htmlCanvas;
1944
+ /** Handle to wrapped OffScreenCanvas */
1676
1945
  offscreenCanvas;
1677
1946
  type;
1678
- width = 1;
1679
- height = 1;
1680
- resizeObserver;
1681
- /** State used by luma.gl classes: TODO - move to canvasContext*/
1682
- _canvasSizeInfo = { clientWidth: 0, clientHeight: 0, devicePixelRatio: 1 };
1947
+ /** Promise that resolved once the resize observer has updated the pixel size */
1948
+ initialized;
1949
+ isInitialized = false;
1950
+ /** Visibility is automatically updated (via an IntersectionObserver) */
1951
+ isVisible = true;
1952
+ /** Width of canvas in CSS units (tracked by a ResizeObserver) */
1953
+ cssWidth;
1954
+ /** Height of canvas in CSS units (tracked by a ResizeObserver) */
1955
+ cssHeight;
1956
+ /** Device pixel ratio. Automatically updated via media queries */
1957
+ devicePixelRatio;
1958
+ /** Exact width of canvas in physical pixels (tracked by a ResizeObserver) */
1959
+ devicePixelWidth;
1960
+ /** Exact height of canvas in physical pixels (tracked by a ResizeObserver) */
1961
+ devicePixelHeight;
1962
+ /** Width of drawing buffer: automatically tracks this.pixelWidth if props.autoResize is true */
1963
+ drawingBufferWidth;
1964
+ /** Height of drawing buffer: automatically tracks this.pixelHeight if props.autoResize is true */
1965
+ drawingBufferHeight;
1966
+ _initializedResolvers = withResolvers();
1967
+ _resizeObserver;
1968
+ _intersectionObserver;
1969
+ _position;
1970
+ destroyed = false;
1683
1971
  toString() {
1684
1972
  return `${this[Symbol.toStringTag]}(${this.id})`;
1685
1973
  }
1686
1974
  constructor(props) {
1687
1975
  this.props = { ..._CanvasContext.defaultProps, ...props };
1688
1976
  props = this.props;
1977
+ this.initialized = this._initializedResolvers.promise;
1689
1978
  if (!isBrowser()) {
1690
- this.id = "node-canvas-context";
1691
- this.type = "node";
1692
- this.width = this.props.width;
1693
- this.height = this.props.height;
1694
- this.canvas = null;
1695
- return;
1696
- }
1697
- if (!props.canvas) {
1698
- const canvas = createCanvas(props);
1699
- const container = getContainer(props?.container || null);
1700
- container.insertBefore(canvas, container.firstChild);
1701
- this.canvas = canvas;
1702
- if (!props?.visible) {
1703
- this.canvas.style.visibility = "hidden";
1704
- }
1979
+ this.canvas = { width: props.width || 1, height: props.height || 1 };
1980
+ } else if (!props.canvas) {
1981
+ this.canvas = createCanvasElement(props);
1705
1982
  } else if (typeof props.canvas === "string") {
1706
1983
  this.canvas = getCanvasFromDOM(props.canvas);
1707
1984
  } else {
1708
1985
  this.canvas = props.canvas;
1709
1986
  }
1710
- if (this.canvas instanceof HTMLCanvasElement) {
1711
- this.id = this.canvas.id;
1987
+ if (_CanvasContext.isHTMLCanvas(this.canvas)) {
1988
+ this.id = props.id || this.canvas.id;
1712
1989
  this.type = "html-canvas";
1713
1990
  this.htmlCanvas = this.canvas;
1714
- } else {
1715
- this.id = "offscreen-canvas";
1991
+ } else if (_CanvasContext.isOffscreenCanvas(this.canvas)) {
1992
+ this.id = props.id || "offscreen-canvas";
1716
1993
  this.type = "offscreen-canvas";
1717
1994
  this.offscreenCanvas = this.canvas;
1995
+ } else {
1996
+ this.id = props.id || "node-canvas-context";
1997
+ this.type = "node";
1718
1998
  }
1719
- if (this.canvas instanceof HTMLCanvasElement && props.autoResize) {
1720
- this.resizeObserver = new ResizeObserver((entries) => {
1721
- for (const entry of entries) {
1722
- if (entry.target === this.canvas) {
1723
- this.update();
1724
- }
1725
- }
1726
- });
1727
- this.resizeObserver.observe(this.canvas);
1999
+ this.cssWidth = this.htmlCanvas?.clientWidth || this.canvas.width;
2000
+ this.cssHeight = this.htmlCanvas?.clientHeight || this.canvas.height;
2001
+ this.devicePixelWidth = this.canvas.width;
2002
+ this.devicePixelHeight = this.canvas.height;
2003
+ this.drawingBufferWidth = this.canvas.width;
2004
+ this.drawingBufferHeight = this.canvas.height;
2005
+ this.devicePixelRatio = globalThis.devicePixelRatio || 1;
2006
+ this._position = [0, 0];
2007
+ if (_CanvasContext.isHTMLCanvas(this.canvas)) {
2008
+ this._intersectionObserver = new IntersectionObserver(
2009
+ (entries) => this._handleIntersection(entries)
2010
+ );
2011
+ this._intersectionObserver.observe(this.canvas);
2012
+ this._resizeObserver = new ResizeObserver((entries) => this._handleResize(entries));
2013
+ try {
2014
+ this._resizeObserver.observe(this.canvas, { box: "device-pixel-content-box" });
2015
+ } catch {
2016
+ this._resizeObserver.observe(this.canvas, { box: "content-box" });
2017
+ }
2018
+ setTimeout(() => this._observeDevicePixelRatio(), 0);
2019
+ if (this.props.trackPosition) {
2020
+ this._trackPosition();
2021
+ }
1728
2022
  }
1729
2023
  }
2024
+ destroy() {
2025
+ this.destroyed = true;
2026
+ }
2027
+ // SIZE METHODS
1730
2028
  /**
1731
- * Returns the current DPR, if props.useDevicePixels is true
1732
- * Device refers to physical
2029
+ * Returns the size covered by the canvas in CSS pixels
2030
+ * @note This can be different from the actual device pixel size of a canvas due to DPR scaling, and rounding to integer pixels
2031
+ * @note This is independent of the canvas' internal drawing buffer size (.width, .height).
1733
2032
  */
1734
- getDevicePixelRatio(useDevicePixels) {
1735
- if (typeof OffscreenCanvas !== "undefined" && this.canvas instanceof OffscreenCanvas) {
1736
- return 1;
1737
- }
1738
- useDevicePixels = useDevicePixels === void 0 ? this.props.useDevicePixels : useDevicePixels;
1739
- if (!useDevicePixels || useDevicePixels <= 0) {
1740
- return 1;
1741
- }
1742
- if (useDevicePixels === true) {
1743
- const dpr = typeof window !== "undefined" && window.devicePixelRatio;
1744
- return dpr || 1;
1745
- }
1746
- return useDevicePixels;
2033
+ getCSSSize() {
2034
+ return [this.cssWidth, this.cssHeight];
2035
+ }
2036
+ getPosition() {
2037
+ return this._position;
2038
+ }
2039
+ /**
2040
+ * Returns the size covered by the canvas in actual device pixels.
2041
+ * @note This can be different from the 'CSS' size of a canvas due to DPR scaling, and rounding to integer pixels
2042
+ * @note This is independent of the canvas' internal drawing buffer size (.width, .height).
2043
+ */
2044
+ getDevicePixelSize() {
2045
+ return [this.devicePixelWidth, this.devicePixelHeight];
2046
+ }
2047
+ /** Get the drawing buffer size (number of pixels GPU is rendering into, can be different from CSS size) */
2048
+ getDrawingBufferSize() {
2049
+ return [this.drawingBufferWidth, this.drawingBufferHeight];
2050
+ }
2051
+ /** Returns the biggest allowed framebuffer size. @todo Allow the application to limit this? */
2052
+ getMaxDrawingBufferSize() {
2053
+ const maxTextureDimension = this.device.limits.maxTextureDimension2D;
2054
+ return [maxTextureDimension, maxTextureDimension];
2055
+ }
2056
+ /** Update the canvas drawing buffer size. Called automatically if props.autoResize is true. */
2057
+ setDrawingBufferSize(width, height) {
2058
+ this.canvas.width = width;
2059
+ this.canvas.height = height;
2060
+ this.drawingBufferWidth = width;
2061
+ this.drawingBufferHeight = height;
1747
2062
  }
1748
2063
  /**
1749
- * Returns the size of drawing buffer in device pixels.
1750
- * @note This can be different from the 'CSS' size of a canvas, and also from the
1751
- * canvas' internal drawing buffer size (.width, .height).
1752
- * This is the size required to cover the canvas, adjusted for DPR
2064
+ * Returns the current DPR (number of physical pixels per CSS pixel), if props.useDevicePixels is true
2065
+ * @note This can be a fractional (non-integer) number, e.g. when the user zooms in the browser.
2066
+ * @note This function handles the non-HTML canvas cases
1753
2067
  */
2068
+ getDevicePixelRatio() {
2069
+ const dpr = typeof window !== "undefined" && window.devicePixelRatio;
2070
+ return dpr || 1;
2071
+ }
2072
+ // DEPRECATED METHODS
2073
+ /**
2074
+ * Maps CSS pixel position to device pixel position
2075
+ */
2076
+ cssToDevicePixels(cssPixel, yInvert = true) {
2077
+ const ratio = this.cssToDeviceRatio();
2078
+ const [width, height] = this.getDrawingBufferSize();
2079
+ return scalePixels(cssPixel, ratio, width, height, yInvert);
2080
+ }
2081
+ /** @deprecated - use .getDevicePixelSize() */
1754
2082
  getPixelSize() {
1755
- switch (this.type) {
1756
- case "node":
1757
- return [this.width, this.height];
1758
- case "offscreen-canvas":
1759
- return [this.canvas.width, this.canvas.height];
1760
- case "html-canvas":
1761
- const dpr = this.getDevicePixelRatio();
1762
- const canvas = this.canvas;
1763
- return canvas.parentElement ? [canvas.clientWidth * dpr, canvas.clientHeight * dpr] : [this.canvas.width, this.canvas.height];
1764
- default:
1765
- throw new Error(this.type);
1766
- }
2083
+ return this.getDevicePixelSize();
1767
2084
  }
2085
+ /** @deprecated - TODO which values should we use for aspect */
1768
2086
  getAspect() {
1769
- const [width, height] = this.getPixelSize();
2087
+ const [width, height] = this.getDevicePixelSize();
1770
2088
  return width / height;
1771
2089
  }
1772
- /**
1773
- * Returns multiplier need to convert CSS size to Device size
1774
- */
2090
+ /** @deprecated Returns multiplier need to convert CSS size to Device size */
1775
2091
  cssToDeviceRatio() {
1776
2092
  try {
1777
2093
  const [drawingBufferWidth] = this.getDrawingBufferSize();
1778
- const clientWidth = this._canvasSizeInfo.clientWidth || this.htmlCanvas?.clientWidth;
1779
- return clientWidth ? drawingBufferWidth / clientWidth : 1;
2094
+ const [cssWidth] = this.getCSSSize();
2095
+ return cssWidth ? drawingBufferWidth / cssWidth : 1;
1780
2096
  } catch {
1781
2097
  return 1;
1782
2098
  }
1783
2099
  }
2100
+ /** @deprecated Use canvasContext.setDrawingBufferSize() */
2101
+ resize(size) {
2102
+ this.setDrawingBufferSize(size.width, size.height);
2103
+ }
2104
+ // IMPLEMENTATION
1784
2105
  /**
1785
- * Maps CSS pixel position to device pixel position
2106
+ * Allows subclass constructor to override the canvas id for auto created canvases.
2107
+ * This can really help when debugging DOM in apps that create multiple devices
1786
2108
  */
1787
- cssToDevicePixels(cssPixel, yInvert = true) {
1788
- const ratio = this.cssToDeviceRatio();
1789
- const [width, height] = this.getDrawingBufferSize();
1790
- return scalePixels(cssPixel, ratio, width, height, yInvert);
2109
+ _setAutoCreatedCanvasId(id) {
2110
+ if (this.htmlCanvas?.id === "lumagl-auto-created-canvas") {
2111
+ this.htmlCanvas.id = id;
2112
+ }
2113
+ }
2114
+ /** reacts to an observed intersection */
2115
+ _handleIntersection(entries) {
2116
+ const entry = entries.find((entry_) => entry_.target === this.canvas);
2117
+ if (!entry) {
2118
+ return;
2119
+ }
2120
+ const isVisible = entry.isIntersecting;
2121
+ if (this.isVisible !== isVisible) {
2122
+ this.isVisible = isVisible;
2123
+ this.device.props.onVisibilityChange(this);
2124
+ }
1791
2125
  }
1792
2126
  /**
1793
- * Use devicePixelRatio to set canvas width and height
1794
- * @note this is a raw port of luma.gl v8 code. Might be worth a review
2127
+ * Reacts to an observed resize by using the most accurate pixel size information the browser can provide
2128
+ * @see https://web.dev/articles/device-pixel-content-box
2129
+ * @see https://webgpufundamentals.org/webgpu/lessons/webgpu-resizing-the-canvas.html
1795
2130
  */
1796
- setDevicePixelRatio(devicePixelRatio, options = {}) {
1797
- if (!this.htmlCanvas) {
2131
+ _handleResize(entries) {
2132
+ const entry = entries.find((entry_) => entry_.target === this.canvas);
2133
+ if (!entry) {
1798
2134
  return;
1799
2135
  }
1800
- let clientWidth = "width" in options ? options.width : this.htmlCanvas.clientWidth;
1801
- let clientHeight = "height" in options ? options.height : this.htmlCanvas.clientHeight;
1802
- if (!clientWidth || !clientHeight) {
1803
- log.log(1, "Canvas clientWidth/clientHeight is 0")();
1804
- devicePixelRatio = 1;
1805
- clientWidth = this.htmlCanvas.width || 1;
1806
- clientHeight = this.htmlCanvas.height || 1;
1807
- }
1808
- const cachedSize = this._canvasSizeInfo;
1809
- if (cachedSize.clientWidth !== clientWidth || cachedSize.clientHeight !== clientHeight || cachedSize.devicePixelRatio !== devicePixelRatio) {
1810
- let clampedPixelRatio = devicePixelRatio;
1811
- const canvasWidth = Math.floor(clientWidth * clampedPixelRatio);
1812
- const canvasHeight = Math.floor(clientHeight * clampedPixelRatio);
1813
- this.htmlCanvas.width = canvasWidth;
1814
- this.htmlCanvas.height = canvasHeight;
1815
- const gl = this.device.gl;
1816
- if (gl) {
1817
- const [drawingBufferWidth, drawingBufferHeight] = this.getDrawingBufferSize();
1818
- if (drawingBufferWidth !== canvasWidth || drawingBufferHeight !== canvasHeight) {
1819
- clampedPixelRatio = Math.min(
1820
- drawingBufferWidth / clientWidth,
1821
- drawingBufferHeight / clientHeight
1822
- );
1823
- this.htmlCanvas.width = Math.floor(clientWidth * clampedPixelRatio);
1824
- this.htmlCanvas.height = Math.floor(clientHeight * clampedPixelRatio);
1825
- log.warn("Device pixel ratio clamped")();
1826
- }
1827
- this._canvasSizeInfo.clientWidth = clientWidth;
1828
- this._canvasSizeInfo.clientHeight = clientHeight;
1829
- this._canvasSizeInfo.devicePixelRatio = devicePixelRatio;
2136
+ this.cssWidth = entry.contentBoxSize[0].inlineSize;
2137
+ this.cssHeight = entry.contentBoxSize[0].blockSize;
2138
+ const oldPixelSize = this.getDevicePixelSize();
2139
+ const devicePixelWidth = entry.devicePixelContentBoxSize?.[0].inlineSize || entry.contentBoxSize[0].inlineSize * devicePixelRatio;
2140
+ const devicePixelHeight = entry.devicePixelContentBoxSize?.[0].blockSize || entry.contentBoxSize[0].blockSize * devicePixelRatio;
2141
+ const [maxDevicePixelWidth, maxDevicePixelHeight] = this.getMaxDrawingBufferSize();
2142
+ this.devicePixelWidth = Math.max(1, Math.min(devicePixelWidth, maxDevicePixelWidth));
2143
+ this.devicePixelHeight = Math.max(1, Math.min(devicePixelHeight, maxDevicePixelHeight));
2144
+ if (this.props.autoResize) {
2145
+ if (this.props.useDevicePixels) {
2146
+ this.setDrawingBufferSize(this.devicePixelWidth, this.devicePixelHeight);
2147
+ } else {
2148
+ this.setDrawingBufferSize(this.cssWidth, this.cssHeight);
1830
2149
  }
1831
- }
2150
+ this._updateDevice();
2151
+ }
2152
+ this._initializedResolvers.resolve();
2153
+ this.isInitialized = true;
2154
+ this.updatePosition();
2155
+ this.device.props.onResize(this, { oldPixelSize });
2156
+ }
2157
+ /** Monitor DPR changes */
2158
+ _observeDevicePixelRatio() {
2159
+ const oldRatio = this.devicePixelRatio;
2160
+ this.devicePixelRatio = window.devicePixelRatio;
2161
+ this.updatePosition();
2162
+ this.device.props.onDevicePixelRatioChange(this, { oldRatio });
2163
+ matchMedia(`(resolution: ${this.devicePixelRatio}dppx)`).addEventListener(
2164
+ "change",
2165
+ () => this._observeDevicePixelRatio(),
2166
+ { once: true }
2167
+ );
1832
2168
  }
1833
- // PRIVATE
1834
- /** @todo Major hack done to port the CSS methods above, base canvas context should not depend on WebGL */
1835
- getDrawingBufferSize() {
1836
- const gl = this.device.gl;
1837
- if (!gl) {
1838
- return this.getPixelSize();
1839
- }
1840
- return [gl.drawingBufferWidth, gl.drawingBufferHeight];
2169
+ /** Start tracking positions with a timer */
2170
+ _trackPosition(intervalMs = 100) {
2171
+ const intervalId = setInterval(() => {
2172
+ if (this.destroyed) {
2173
+ clearInterval(intervalId);
2174
+ } else {
2175
+ this.updatePosition();
2176
+ }
2177
+ }, intervalMs);
1841
2178
  }
1842
2179
  /**
1843
- * Allows subclass constructor to override the canvas id for auto created canvases.
1844
- * This can really help when debugging DOM in apps that create multiple devices
2180
+ * Calculated the absolute position of the canvas
2181
+ * @note - getBoundingClientRect() is normally cheap but can be expensive
2182
+ * if called before browser has finished a reflow. Should not be the case here.
1845
2183
  */
1846
- _setAutoCreatedCanvasId(id) {
1847
- if (this.htmlCanvas?.id === "lumagl-auto-created-canvas") {
1848
- this.htmlCanvas.id = id;
2184
+ updatePosition() {
2185
+ const newRect = this.htmlCanvas?.getBoundingClientRect();
2186
+ if (newRect) {
2187
+ const position = [newRect.left, newRect.top];
2188
+ this._position ??= position;
2189
+ const positionChanged = position[0] !== this._position[0] || position[1] !== this._position[1];
2190
+ if (positionChanged) {
2191
+ const oldPosition = this._position;
2192
+ this._position = position;
2193
+ this.device.props.onPositionChange?.(this, { oldPosition });
2194
+ }
1849
2195
  }
1850
2196
  }
1851
2197
  };
1852
2198
  var CanvasContext = _CanvasContext;
1853
2199
  __publicField(CanvasContext, "defaultProps", {
2200
+ id: void 0,
1854
2201
  canvas: null,
1855
2202
  width: 800,
1856
- // width are height are only used by headless gl
1857
2203
  height: 600,
1858
2204
  useDevicePixels: true,
1859
2205
  autoResize: true,
1860
2206
  container: null,
1861
2207
  visible: true,
1862
2208
  alphaMode: "opaque",
1863
- colorSpace: "srgb"
2209
+ colorSpace: "srgb",
2210
+ trackPosition: false
1864
2211
  });
1865
2212
  function getContainer(container) {
1866
2213
  if (typeof container === "string") {
@@ -1869,27 +2216,33 @@ var __exports__ = (() => {
1869
2216
  throw new Error(`${container} is not an HTML element`);
1870
2217
  }
1871
2218
  return element;
1872
- } else if (container) {
2219
+ }
2220
+ if (container) {
1873
2221
  return container;
1874
2222
  }
1875
2223
  return document.body;
1876
2224
  }
1877
2225
  function getCanvasFromDOM(canvasId) {
1878
2226
  const canvas = document.getElementById(canvasId);
1879
- if (!(canvas instanceof HTMLCanvasElement)) {
2227
+ if (!CanvasContext.isHTMLCanvas(canvas)) {
1880
2228
  throw new Error("Object is not a canvas element");
1881
2229
  }
1882
2230
  return canvas;
1883
2231
  }
1884
- function createCanvas(props) {
2232
+ function createCanvasElement(props) {
1885
2233
  const { width, height } = props;
1886
- const targetCanvas = document.createElement("canvas");
1887
- targetCanvas.id = uid("lumagl-auto-created-canvas");
1888
- targetCanvas.width = width || 1;
1889
- targetCanvas.height = height || 1;
1890
- targetCanvas.style.width = Number.isFinite(width) ? `${width}px` : "100%";
1891
- targetCanvas.style.height = Number.isFinite(height) ? `${height}px` : "100%";
1892
- return targetCanvas;
2234
+ const newCanvas = document.createElement("canvas");
2235
+ newCanvas.id = uid("lumagl-auto-created-canvas");
2236
+ newCanvas.width = width || 1;
2237
+ newCanvas.height = height || 1;
2238
+ newCanvas.style.width = Number.isFinite(width) ? `${width}px` : "100%";
2239
+ newCanvas.style.height = Number.isFinite(height) ? `${height}px` : "100%";
2240
+ if (!props?.visible) {
2241
+ newCanvas.style.visibility = "hidden";
2242
+ }
2243
+ const container = getContainer(props?.container || null);
2244
+ container.insertBefore(newCanvas, container.firstChild);
2245
+ return newCanvas;
1893
2246
  }
1894
2247
  function scalePixels(pixel, ratio, width, height, yInvert) {
1895
2248
  const point = pixel;
@@ -1922,16 +2275,50 @@ var __exports__ = (() => {
1922
2275
  return yInvert ? Math.max(0, height - 1 - Math.round(y * ratio)) : Math.min(Math.round(y * ratio), height - 1);
1923
2276
  }
1924
2277
 
1925
- // ../core/src/adapter/resources/texture.ts
1926
- var _Texture = class extends Resource {
2278
+ // ../core/src/adapter/resources/sampler.ts
2279
+ var _Sampler = class extends Resource {
1927
2280
  get [Symbol.toStringTag]() {
1928
- return "Texture";
2281
+ return "Sampler";
1929
2282
  }
1930
- toString() {
1931
- return `Texture(${this.id},${this.format},${this.width}x${this.height})`;
2283
+ constructor(device, props) {
2284
+ props = _Sampler.normalizeProps(device, props);
2285
+ super(device, props, _Sampler.defaultProps);
2286
+ }
2287
+ static normalizeProps(device, props) {
2288
+ return props;
1932
2289
  }
2290
+ };
2291
+ var Sampler = _Sampler;
2292
+ __publicField(Sampler, "defaultProps", {
2293
+ ...Resource.defaultProps,
2294
+ type: "color-sampler",
2295
+ addressModeU: "clamp-to-edge",
2296
+ addressModeV: "clamp-to-edge",
2297
+ addressModeW: "clamp-to-edge",
2298
+ magFilter: "nearest",
2299
+ minFilter: "nearest",
2300
+ mipmapFilter: "none",
2301
+ lodMinClamp: 0,
2302
+ lodMaxClamp: 32,
2303
+ // Per WebGPU spec
2304
+ compare: "less-equal",
2305
+ maxAnisotropy: 1
2306
+ });
2307
+
2308
+ // ../core/src/adapter/resources/texture.ts
2309
+ var BASE_DIMENSIONS = {
2310
+ "1d": "1d",
2311
+ "2d": "2d",
2312
+ "2d-array": "2d",
2313
+ cube: "2d",
2314
+ "cube-array": "2d",
2315
+ "3d": "3d"
2316
+ };
2317
+ var _Texture = class extends Resource {
1933
2318
  /** dimension of this texture */
1934
2319
  dimension;
2320
+ /** base dimension of this texture */
2321
+ baseDimension;
1935
2322
  /** format of this texture */
1936
2323
  format;
1937
2324
  /** width in pixels of this texture */
@@ -1944,133 +2331,55 @@ var __exports__ = (() => {
1944
2331
  mipLevels;
1945
2332
  /** "Time" of last update. Monotonically increasing timestamp. TODO move to AsyncTexture? */
1946
2333
  updateTimestamp;
2334
+ get [Symbol.toStringTag]() {
2335
+ return "Texture";
2336
+ }
2337
+ toString() {
2338
+ return `Texture(${this.id},${this.format},${this.width}x${this.height})`;
2339
+ }
1947
2340
  /** Do not use directly. Create with device.createTexture() */
1948
2341
  constructor(device, props) {
1949
2342
  props = _Texture.normalizeProps(device, props);
1950
2343
  super(device, props, _Texture.defaultProps);
1951
2344
  this.dimension = this.props.dimension;
2345
+ this.baseDimension = BASE_DIMENSIONS[this.dimension];
1952
2346
  this.format = this.props.format;
1953
2347
  this.width = this.props.width;
1954
2348
  this.height = this.props.height;
1955
2349
  this.depth = this.props.depth;
2350
+ this.mipLevels = this.props.mipLevels;
1956
2351
  if (this.props.width === void 0 || this.props.height === void 0) {
1957
- const size = _Texture.getTextureDataSize(this.props.data);
1958
- this.width = size?.width || 1;
1959
- this.height = size?.height || 1;
1960
- }
1961
- if (this.props.mipmaps && this.props.mipLevels === void 0) {
1962
- this.props.mipLevels = "pyramid";
2352
+ if (device.isExternalImage(props.data)) {
2353
+ const size = device.getExternalImageSize(props.data);
2354
+ this.width = size?.width || 1;
2355
+ this.height = size?.height || 1;
2356
+ } else {
2357
+ this.width = 1;
2358
+ this.height = 1;
2359
+ if (this.props.width === void 0 || this.props.height === void 0) {
2360
+ log.warn(
2361
+ `${this} created with undefined width or height. This is deprecated. Use AsyncTexture instead.`
2362
+ )();
2363
+ }
2364
+ }
1963
2365
  }
1964
- this.mipLevels = this.props.mipLevels === "pyramid" ? _Texture.getMipLevelCount(this.width, this.height) : this.props.mipLevels || 1;
1965
2366
  this.updateTimestamp = device.incrementTimestamp();
1966
2367
  }
2368
+ /** Set sampler props associated with this texture */
2369
+ setSampler(sampler) {
2370
+ this.sampler = sampler instanceof Sampler ? sampler : this.device.createSampler(sampler);
2371
+ }
1967
2372
  /**
1968
- * Create a new texture with the same parameters and optionally, a different size
2373
+ * Create a new texture with the same parameters and optionally a different size
1969
2374
  * @note Textures are immutable and cannot be resized after creation, but we can create a similar texture with the same parameters but a new size.
1970
2375
  * @note Does not copy contents of the texture
1971
2376
  */
1972
2377
  clone(size) {
1973
2378
  return this.device.createTexture({ ...this.props, ...size });
1974
2379
  }
1975
- /** Check if data is an external image */
1976
- static isExternalImage(data) {
1977
- return typeof ImageData !== "undefined" && data instanceof ImageData || typeof ImageBitmap !== "undefined" && data instanceof ImageBitmap || typeof HTMLImageElement !== "undefined" && data instanceof HTMLImageElement || typeof HTMLVideoElement !== "undefined" && data instanceof HTMLVideoElement || typeof VideoFrame !== "undefined" && data instanceof VideoFrame || typeof HTMLCanvasElement !== "undefined" && data instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && data instanceof OffscreenCanvas;
1978
- }
1979
- /** Determine size (width and height) of provided image data */
1980
- static getExternalImageSize(data) {
1981
- if (typeof ImageData !== "undefined" && data instanceof ImageData || typeof ImageBitmap !== "undefined" && data instanceof ImageBitmap || typeof HTMLCanvasElement !== "undefined" && data instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && data instanceof OffscreenCanvas) {
1982
- return { width: data.width, height: data.height };
1983
- }
1984
- if (typeof HTMLImageElement !== "undefined" && data instanceof HTMLImageElement) {
1985
- return { width: data.naturalWidth, height: data.naturalHeight };
1986
- }
1987
- if (typeof HTMLVideoElement !== "undefined" && data instanceof HTMLVideoElement) {
1988
- return { width: data.videoWidth, height: data.videoHeight };
1989
- }
1990
- if (typeof VideoFrame !== "undefined" && data instanceof VideoFrame) {
1991
- return { width: data.displayWidth, height: data.displayHeight };
1992
- }
1993
- throw new Error("Unknown image type");
1994
- }
1995
- /** Check if texture data is a typed array */
1996
- static isTextureLevelData(data) {
1997
- const typedArray = data?.data;
1998
- return ArrayBuffer.isView(typedArray);
1999
- }
2000
- /** Get the size of the texture described by the provided TextureData */
2001
- static getTextureDataSize(data) {
2002
- if (!data) {
2003
- return null;
2004
- }
2005
- if (ArrayBuffer.isView(data)) {
2006
- return null;
2007
- }
2008
- if (Array.isArray(data)) {
2009
- return _Texture.getTextureDataSize(data[0]);
2010
- }
2011
- if (_Texture.isExternalImage(data)) {
2012
- return _Texture.getExternalImageSize(data);
2013
- }
2014
- if (data && typeof data === "object" && data.constructor === Object) {
2015
- const textureDataArray = Object.values(data);
2016
- const untypedData = textureDataArray[0];
2017
- return { width: untypedData.width, height: untypedData.height };
2018
- }
2019
- throw new Error("texture size deduction failed");
2020
- }
2021
- /**
2022
- * Normalize TextureData to an array of TextureLevelData / ExternalImages
2023
- * @param data
2024
- * @param options
2025
- * @returns array of TextureLevelData / ExternalImages
2026
- */
2027
- static normalizeTextureData(data, options) {
2028
- let lodArray;
2029
- if (ArrayBuffer.isView(data)) {
2030
- lodArray = [
2031
- {
2032
- // ts-expect-error does data really need to be Uint8ClampedArray?
2033
- data,
2034
- width: options.width,
2035
- height: options.height
2036
- // depth: options.depth
2037
- }
2038
- ];
2039
- } else if (!Array.isArray(data)) {
2040
- lodArray = [data];
2041
- } else {
2042
- lodArray = data;
2043
- }
2044
- return lodArray;
2045
- }
2046
- /** Calculate the number of mip levels for a texture of width and height */
2047
- static getMipLevelCount(width, height) {
2048
- return Math.floor(Math.log2(Math.max(width, height))) + 1;
2049
- }
2050
- /** Convert luma.gl cubemap face constants to depth index */
2051
- static getCubeFaceDepth(face) {
2052
- switch (face) {
2053
- case "+X":
2054
- return 0;
2055
- case "-X":
2056
- return 1;
2057
- case "+Y":
2058
- return 2;
2059
- case "-Y":
2060
- return 3;
2061
- case "+Z":
2062
- return 4;
2063
- case "-Z":
2064
- return 5;
2065
- default:
2066
- throw new Error(face);
2067
- }
2068
- }
2069
2380
  /** Ensure we have integer coordinates */
2070
2381
  static normalizeProps(device, props) {
2071
2382
  const newProps = { ...props };
2072
- const overriddenDefaultProps = device?.props?._resourceDefaults?.texture || {};
2073
- Object.assign(newProps, overriddenDefaultProps);
2074
2383
  const { width, height } = newProps;
2075
2384
  if (typeof width === "number") {
2076
2385
  newProps.width = Math.max(1, Math.ceil(width));
@@ -2080,30 +2389,98 @@ var __exports__ = (() => {
2080
2389
  }
2081
2390
  return newProps;
2082
2391
  }
2392
+ // HELPERS
2393
+ /** Initialize texture with supplied props */
2394
+ // eslint-disable-next-line max-statements
2395
+ _initializeData(data) {
2396
+ if (this.device.isExternalImage(data)) {
2397
+ this.copyExternalImage({
2398
+ image: data,
2399
+ width: this.width,
2400
+ height: this.height,
2401
+ depth: this.depth,
2402
+ mipLevel: 0,
2403
+ x: 0,
2404
+ y: 0,
2405
+ z: 0,
2406
+ aspect: "all",
2407
+ colorSpace: "srgb",
2408
+ premultipliedAlpha: false,
2409
+ flipY: false
2410
+ });
2411
+ } else if (data) {
2412
+ this.copyImageData({
2413
+ data,
2414
+ // width: this.width,
2415
+ // height: this.height,
2416
+ // depth: this.depth,
2417
+ mipLevel: 0,
2418
+ x: 0,
2419
+ y: 0,
2420
+ z: 0,
2421
+ aspect: "all"
2422
+ });
2423
+ }
2424
+ }
2425
+ _normalizeCopyImageDataOptions(options_) {
2426
+ const { width, height, depth } = this;
2427
+ const options = { ..._Texture.defaultCopyDataOptions, width, height, depth, ...options_ };
2428
+ const info = this.device.getTextureFormatInfo(this.format);
2429
+ if (!options_.bytesPerRow && !info.bytesPerPixel) {
2430
+ throw new Error(`bytesPerRow must be provided for texture format ${this.format}`);
2431
+ }
2432
+ options.bytesPerRow = options_.bytesPerRow || width * (info.bytesPerPixel || 4);
2433
+ options.rowsPerImage = options_.rowsPerImage || height;
2434
+ return options;
2435
+ }
2436
+ _normalizeCopyExternalImageOptions(options_) {
2437
+ const size = this.device.getExternalImageSize(options_.image);
2438
+ const options = { ..._Texture.defaultCopyExternalImageOptions, ...size, ...options_ };
2439
+ options.width = Math.min(options.width, this.width - options.x);
2440
+ options.height = Math.min(options.height, this.height - options.y);
2441
+ return options;
2442
+ }
2083
2443
  };
2084
2444
  var Texture = _Texture;
2445
+ /** The texture can be bound for use as a sampled texture in a shader */
2446
+ __publicField(Texture, "SAMPLE", 4);
2447
+ /** The texture can be bound for use as a storage texture in a shader */
2448
+ __publicField(Texture, "STORAGE", 8);
2449
+ /** The texture can be used as a color or depth/stencil attachment in a render pass */
2450
+ __publicField(Texture, "RENDER", 16);
2451
+ /** The texture can be used as the source of a copy operation */
2085
2452
  __publicField(Texture, "COPY_SRC", 1);
2453
+ /** he texture can be used as the destination of a copy or write operation */
2086
2454
  __publicField(Texture, "COPY_DST", 2);
2455
+ /** @deprecated Use Texture.SAMPLE */
2087
2456
  __publicField(Texture, "TEXTURE", 4);
2088
- __publicField(Texture, "STORAGE", 8);
2457
+ /** @deprecated Use Texture.RENDER */
2089
2458
  __publicField(Texture, "RENDER_ATTACHMENT", 16);
2090
- __publicField(Texture, "CubeFaces", ["+X", "-X", "+Y", "-Y", "+Z", "-Z"]);
2459
+ /** Default options */
2091
2460
  __publicField(Texture, "defaultProps", {
2092
2461
  ...Resource.defaultProps,
2093
2462
  data: null,
2094
2463
  dimension: "2d",
2095
2464
  format: "rgba8unorm",
2465
+ usage: _Texture.TEXTURE | _Texture.RENDER_ATTACHMENT | _Texture.COPY_DST,
2096
2466
  width: void 0,
2097
2467
  height: void 0,
2098
2468
  depth: 1,
2099
- mipmaps: false,
2100
- compressed: false,
2101
- usage: 0,
2102
- mipLevels: void 0,
2469
+ mipLevels: 1,
2103
2470
  samples: void 0,
2104
2471
  sampler: {},
2105
- view: void 0,
2106
- flipY: void 0
2472
+ view: void 0
2473
+ });
2474
+ __publicField(Texture, "defaultCopyDataOptions", {
2475
+ data: void 0,
2476
+ byteOffset: 0,
2477
+ bytesPerRow: void 0,
2478
+ rowsPerImage: void 0,
2479
+ mipLevel: 0,
2480
+ x: 0,
2481
+ y: 0,
2482
+ z: 0,
2483
+ aspect: "all"
2107
2484
  });
2108
2485
  /** Default options */
2109
2486
  __publicField(Texture, "defaultCopyExternalImageOptions", {
@@ -2179,6 +2556,13 @@ var __exports__ = (() => {
2179
2556
  });
2180
2557
  }
2181
2558
  }
2559
+ while (log2.length > currentMessage) {
2560
+ const message = log2[currentMessage++];
2561
+ formattedLog += formatCompilerMessage(message, [], 0, {
2562
+ ...options,
2563
+ inlineSource: false
2564
+ });
2565
+ }
2182
2566
  return formattedLog;
2183
2567
  case "issues":
2184
2568
  case "no":
@@ -2274,19 +2658,19 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
2274
2658
  if (trigger === "warnings" && messages?.length === 0) {
2275
2659
  return;
2276
2660
  }
2277
- this._displayShaderLog(messages);
2661
+ this._displayShaderLog(messages, this.id);
2278
2662
  }
2279
2663
  // PRIVATE
2280
2664
  /**
2281
2665
  * In-browser UI logging of errors
2282
2666
  * TODO - this HTML formatting code should not be in Device, should be pluggable
2283
2667
  */
2284
- _displayShaderLog(messages) {
2668
+ _displayShaderLog(messages, shaderId) {
2285
2669
  if (typeof document === "undefined" || !document?.createElement) {
2286
2670
  return;
2287
2671
  }
2288
- const shaderName = getShaderName(this.source);
2289
- const shaderTitle = `${this.stage} ${shaderName}`;
2672
+ const shaderName = shaderId;
2673
+ const shaderTitle = `${this.stage} shader "${shaderName}"`;
2290
2674
  let htmlLog = formatCompilerLog(messages, this.source, { showSourceCode: "all", html: true });
2291
2675
  const translatedSource = this.getTranslatedSource();
2292
2676
  if (translatedSource) {
@@ -2294,7 +2678,7 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
2294
2678
  }
2295
2679
  const button = document.createElement("Button");
2296
2680
  button.innerHTML = `
2297
- <h1>Shader Compilation Error in ${shaderTitle}</h1><br /><br />
2681
+ <h1>Compilation error in ${shaderTitle}</h1><br /><br />
2298
2682
  <code style="user-select:text;"><pre>
2299
2683
  ${htmlLog}
2300
2684
  </pre></code>`;
@@ -2332,38 +2716,6 @@ ${htmlLog}
2332
2716
  return match ? match[1] : defaultName;
2333
2717
  }
2334
2718
 
2335
- // ../core/src/adapter/resources/sampler.ts
2336
- var _Sampler = class extends Resource {
2337
- get [Symbol.toStringTag]() {
2338
- return "Sampler";
2339
- }
2340
- constructor(device, props) {
2341
- props = _Sampler.normalizeProps(device, props);
2342
- super(device, props, _Sampler.defaultProps);
2343
- }
2344
- static normalizeProps(device, props) {
2345
- const overriddenDefaultProps = device?.props?._resourceDefaults?.sampler || {};
2346
- const newProps = { ...props, ...overriddenDefaultProps };
2347
- return newProps;
2348
- }
2349
- };
2350
- var Sampler = _Sampler;
2351
- __publicField(Sampler, "defaultProps", {
2352
- ...Resource.defaultProps,
2353
- type: "color-sampler",
2354
- addressModeU: "clamp-to-edge",
2355
- addressModeV: "clamp-to-edge",
2356
- addressModeW: "clamp-to-edge",
2357
- magFilter: "nearest",
2358
- minFilter: "nearest",
2359
- mipmapFilter: "none",
2360
- lodMinClamp: 0,
2361
- lodMaxClamp: 32,
2362
- // Per WebGPU spec
2363
- compare: "less-equal",
2364
- maxAnisotropy: 1
2365
- });
2366
-
2367
2719
  // ../core/src/adapter/resources/framebuffer.ts
2368
2720
  var _Framebuffer = class extends Resource {
2369
2721
  get [Symbol.toStringTag]() {
@@ -2453,8 +2805,7 @@ ${htmlLog}
2453
2805
  usage: Texture.RENDER_ATTACHMENT,
2454
2806
  format,
2455
2807
  width: this.width,
2456
- height: this.height,
2457
- mipmaps: false
2808
+ height: this.height
2458
2809
  });
2459
2810
  }
2460
2811
  /**
@@ -2515,16 +2866,6 @@ ${htmlLog}
2515
2866
  this.shaderLayout = this.props.shaderLayout;
2516
2867
  this.bufferLayout = this.props.bufferLayout || [];
2517
2868
  }
2518
- // DEPRECATED METHODS
2519
- /**
2520
- * Uniforms
2521
- * @deprecated Use uniforms buffers
2522
- * @note textures, samplers and uniform buffers should be set via `setBindings()`, these are not considered uniforms.
2523
- * @note In WebGL uniforms have a performance penalty, they are reset before each call to enable pipeline sharing.
2524
- */
2525
- setUniformsWebGL(uniforms) {
2526
- throw new Error("Use uniform blocks");
2527
- }
2528
2869
  };
2529
2870
  var RenderPipeline = _RenderPipeline;
2530
2871
  __publicField(RenderPipeline, "defaultProps", {
@@ -2538,10 +2879,9 @@ ${htmlLog}
2538
2879
  shaderLayout: null,
2539
2880
  bufferLayout: [],
2540
2881
  topology: "triangle-list",
2882
+ colorAttachmentFormats: void 0,
2883
+ depthStencilAttachmentFormat: void 0,
2541
2884
  parameters: {},
2542
- // isInstanced: false,
2543
- // instanceCount: 0,
2544
- // vertexCount: 0,
2545
2885
  bindings: {},
2546
2886
  uniforms: {}
2547
2887
  });
@@ -2556,9 +2896,7 @@ ${htmlLog}
2556
2896
  super(device, props, _RenderPass.defaultProps);
2557
2897
  }
2558
2898
  static normalizeProps(device, props) {
2559
- const overriddenDefaultProps = device.props._resourceDefaults?.renderPass;
2560
- const newProps = { ...overriddenDefaultProps, ...props };
2561
- return newProps;
2899
+ return props;
2562
2900
  }
2563
2901
  };
2564
2902
  var RenderPass = _RenderPass;
@@ -2610,12 +2948,12 @@ ${htmlLog}
2610
2948
 
2611
2949
  // ../core/src/adapter/resources/compute-pass.ts
2612
2950
  var _ComputePass = class extends Resource {
2613
- get [Symbol.toStringTag]() {
2614
- return "ComputePass";
2615
- }
2616
2951
  constructor(device, props) {
2617
2952
  super(device, props, _ComputePass.defaultProps);
2618
2953
  }
2954
+ get [Symbol.toStringTag]() {
2955
+ return "ComputePass";
2956
+ }
2619
2957
  };
2620
2958
  var ComputePass = _ComputePass;
2621
2959
  __publicField(ComputePass, "defaultProps", {
@@ -2633,11 +2971,11 @@ ${htmlLog}
2633
2971
  constructor(device, props) {
2634
2972
  super(device, props, _CommandEncoder.defaultProps);
2635
2973
  }
2636
- // TODO - luma.gl has these on the device, should we align with WebGPU API?
2637
- // beginRenderPass(GPURenderPassDescriptor descriptor): GPURenderPassEncoder;
2638
- // beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
2639
2974
  };
2640
2975
  var CommandEncoder = _CommandEncoder;
2976
+ // TODO - luma.gl has these on the device, should we align with WebGPU API?
2977
+ // beginRenderPass(GPURenderPassDescriptor descriptor): GPURenderPassEncoder;
2978
+ // beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
2641
2979
  __publicField(CommandEncoder, "defaultProps", {
2642
2980
  ...Resource.defaultProps,
2643
2981
  measureExecutionTime: void 0
@@ -2657,42 +2995,31 @@ ${htmlLog}
2657
2995
  ...Resource.defaultProps
2658
2996
  });
2659
2997
 
2660
- // ../core/src/gpu-type-utils/decode-attribute-type.ts
2661
- function decodeShaderAttributeType(attributeType) {
2662
- const [dataType, components] = TYPE_INFO[attributeType];
2663
- const integer = dataType === "i32" || dataType === "u32";
2664
- const signed = dataType !== "u32";
2665
- const byteLength = TYPE_SIZES2[dataType] * components;
2666
- const defaultVertexFormat = getCompatibleVertexFormat(dataType, components);
2998
+ // ../core/src/shadertypes/data-types/decode-shader-types.ts
2999
+ function getVariableShaderTypeInfo(format) {
3000
+ const decoded = UNIFORM_FORMATS[format];
3001
+ return decoded;
3002
+ }
3003
+ function getAttributeShaderTypeInfo(attributeType) {
3004
+ const [primitiveType, components] = TYPE_INFO[attributeType];
3005
+ const integer = primitiveType === "i32" || primitiveType === "u32";
3006
+ const signed = primitiveType !== "u32";
3007
+ const byteLength = PRIMITIVE_TYPE_SIZES[primitiveType] * components;
2667
3008
  return {
2668
- dataType,
3009
+ primitiveType,
2669
3010
  components,
2670
- defaultVertexFormat,
2671
3011
  byteLength,
2672
3012
  integer,
2673
3013
  signed
2674
3014
  };
2675
3015
  }
2676
- function getCompatibleVertexFormat(dataType, components) {
2677
- let vertexType;
2678
- switch (dataType) {
2679
- case "f32":
2680
- vertexType = "float32";
2681
- break;
2682
- case "i32":
2683
- vertexType = "sint32";
2684
- break;
2685
- case "u32":
2686
- vertexType = "uint32";
2687
- break;
2688
- case "f16":
2689
- return components <= 2 ? "float16x2" : "float16x4";
2690
- }
2691
- if (components === 1) {
2692
- return vertexType;
2693
- }
2694
- return `${vertexType}x${components}`;
2695
- }
3016
+ var PRIMITIVE_TYPE_SIZES = {
3017
+ f32: 4,
3018
+ f16: 2,
3019
+ i32: 4,
3020
+ u32: 4
3021
+ // 'bool-webgl': 4,
3022
+ };
2696
3023
  var TYPE_INFO = {
2697
3024
  f32: ["f32", 1],
2698
3025
  "vec2<f32>": ["f32", 2],
@@ -2711,38 +3038,115 @@ ${htmlLog}
2711
3038
  "vec3<u32>": ["u32", 3],
2712
3039
  "vec4<u32>": ["u32", 4]
2713
3040
  };
2714
- var TYPE_SIZES2 = {
2715
- f32: 4,
2716
- f16: 2,
2717
- i32: 4,
2718
- u32: 4
2719
- // 'bool-webgl': 4,
3041
+ var UNIFORM_FORMATS = {
3042
+ f32: { type: "f32", components: 1 },
3043
+ f16: { type: "f16", components: 1 },
3044
+ i32: { type: "i32", components: 1 },
3045
+ u32: { type: "u32", components: 1 },
3046
+ // 'bool-webgl': {type: 'bool-webgl', components: 1},
3047
+ "vec2<f32>": { type: "f32", components: 2 },
3048
+ "vec3<f32>": { type: "f32", components: 3 },
3049
+ "vec4<f32>": { type: "f32", components: 4 },
3050
+ "vec2<f16>": { type: "f16", components: 2 },
3051
+ "vec3<f16>": { type: "f16", components: 3 },
3052
+ "vec4<f16>": { type: "f16", components: 4 },
3053
+ "vec2<i32>": { type: "i32", components: 2 },
3054
+ "vec3<i32>": { type: "i32", components: 3 },
3055
+ "vec4<i32>": { type: "i32", components: 4 },
3056
+ "vec2<u32>": { type: "u32", components: 2 },
3057
+ "vec3<u32>": { type: "u32", components: 3 },
3058
+ "vec4<u32>": { type: "u32", components: 4 },
3059
+ "mat2x2<f32>": { type: "f32", components: 4 },
3060
+ "mat2x3<f32>": { type: "f32", components: 6 },
3061
+ "mat2x4<f32>": { type: "f32", components: 8 },
3062
+ "mat3x2<f32>": { type: "f32", components: 6 },
3063
+ "mat3x3<f32>": { type: "f32", components: 9 },
3064
+ "mat3x4<f32>": { type: "f32", components: 12 },
3065
+ "mat4x2<f32>": { type: "f32", components: 8 },
3066
+ "mat4x3<f32>": { type: "f32", components: 12 },
3067
+ "mat4x4<f32>": { type: "f32", components: 16 },
3068
+ "mat2x2<f16>": { type: "f16", components: 4 },
3069
+ "mat2x3<f16>": { type: "f16", components: 6 },
3070
+ "mat2x4<f16>": { type: "f16", components: 8 },
3071
+ "mat3x2<f16>": { type: "f16", components: 6 },
3072
+ "mat3x3<f16>": { type: "f16", components: 9 },
3073
+ "mat3x4<f16>": { type: "f16", components: 12 },
3074
+ "mat4x2<f16>": { type: "f16", components: 8 },
3075
+ "mat4x3<f16>": { type: "f16", components: 12 },
3076
+ "mat4x4<f16>": { type: "f16", components: 16 },
3077
+ "mat2x2<i32>": { type: "i32", components: 4 },
3078
+ "mat2x3<i32>": { type: "i32", components: 6 },
3079
+ "mat2x4<i32>": { type: "i32", components: 8 },
3080
+ "mat3x2<i32>": { type: "i32", components: 6 },
3081
+ "mat3x3<i32>": { type: "i32", components: 9 },
3082
+ "mat3x4<i32>": { type: "i32", components: 12 },
3083
+ "mat4x2<i32>": { type: "i32", components: 8 },
3084
+ "mat4x3<i32>": { type: "i32", components: 12 },
3085
+ "mat4x4<i32>": { type: "i32", components: 16 },
3086
+ "mat2x2<u32>": { type: "u32", components: 4 },
3087
+ "mat2x3<u32>": { type: "u32", components: 6 },
3088
+ "mat2x4<u32>": { type: "u32", components: 8 },
3089
+ "mat3x2<u32>": { type: "u32", components: 6 },
3090
+ "mat3x3<u32>": { type: "u32", components: 9 },
3091
+ "mat3x4<u32>": { type: "u32", components: 12 },
3092
+ "mat4x2<u32>": { type: "u32", components: 8 },
3093
+ "mat4x3<u32>": { type: "u32", components: 12 },
3094
+ "mat4x4<u32>": { type: "u32", components: 16 }
3095
+ };
3096
+ var WGSL_ATTRIBUTE_TYPE_ALIAS_MAP = {
3097
+ vec2i: "vec2<i32>",
3098
+ vec3i: "vec3<i32>",
3099
+ vec4i: "vec4<i32>",
3100
+ vec2u: "vec2<u32>",
3101
+ vec3u: "vec3<u32>",
3102
+ vec4u: "vec4<u32>",
3103
+ vec2f: "vec2<f32>",
3104
+ vec3f: "vec3<f32>",
3105
+ vec4f: "vec4<f32>",
3106
+ // Requires the f16 extension.
3107
+ vec2h: "vec2<f16>",
3108
+ vec3h: "vec3<f16>",
3109
+ vec4h: "vec4<f16>"
3110
+ };
3111
+ var WGSL_VARIABLE_TYPE_ALIAS_MAP = {
3112
+ ...WGSL_ATTRIBUTE_TYPE_ALIAS_MAP,
3113
+ mat2x2f: "mat2x2<f32>",
3114
+ mat2x3f: "mat2x3<f32>",
3115
+ mat2x4f: "mat2x4<f32>",
3116
+ mat3x2f: "mat3x2<f32>",
3117
+ mat3x3f: "mat3x3<f32>",
3118
+ mat3x4f: "mat3x4<f32>",
3119
+ mat4x2f: "mat4x2<f32>",
3120
+ mat4x3f: "mat4x3<f32>",
3121
+ mat4x4f: "mat4x4<f32>",
3122
+ mat2x2i: "mat2x2<i32>",
3123
+ mat2x3i: "mat2x3<i32>",
3124
+ mat2x4i: "mat2x4<i32>",
3125
+ mat3x2i: "mat3x2<i32>",
3126
+ mat3x3i: "mat3x3<i32>",
3127
+ mat3x4i: "mat3x4<i32>",
3128
+ mat4x2i: "mat4x2<i32>",
3129
+ mat4x3i: "mat4x3<i32>",
3130
+ mat4x4i: "mat4x4<i32>",
3131
+ mat2x2u: "mat2x2<u32>",
3132
+ mat2x3u: "mat2x3<u32>",
3133
+ mat2x4u: "mat2x4<u32>",
3134
+ mat3x2u: "mat3x2<u32>",
3135
+ mat3x3u: "mat3x3<u32>",
3136
+ mat3x4u: "mat3x4<u32>",
3137
+ mat4x2u: "mat4x2<u32>",
3138
+ mat4x3u: "mat4x3<u32>",
3139
+ mat4x4u: "mat4x4<u32>",
3140
+ mat2x2h: "mat2x2<f16>",
3141
+ mat2x3h: "mat2x3<f16>",
3142
+ mat2x4h: "mat2x4<f16>",
3143
+ mat3x2h: "mat3x2<f16>",
3144
+ mat3x3h: "mat3x3<f16>",
3145
+ mat3x4h: "mat3x4<f16>",
3146
+ mat4x2h: "mat4x2<f16>",
3147
+ mat4x3h: "mat4x3<f16>",
3148
+ mat4x4h: "mat4x4<f16>"
2720
3149
  };
2721
-
2722
- // ../core/src/gpu-type-utils/decode-vertex-format.ts
2723
- function decodeVertexFormat(format) {
2724
- let webglOnly;
2725
- if (format.endsWith("-webgl")) {
2726
- format.replace("-webgl", "");
2727
- webglOnly = true;
2728
- }
2729
- const [type_, count] = format.split("x");
2730
- const type = type_;
2731
- const components = count ? parseInt(count) : 1;
2732
- const decodedType = decodeVertexType(type);
2733
- const result = {
2734
- type,
2735
- components,
2736
- byteLength: decodedType.byteLength * components,
2737
- integer: decodedType.integer,
2738
- signed: decodedType.signed,
2739
- normalized: decodedType.normalized
2740
- };
2741
- if (webglOnly) {
2742
- result.webglOnly = true;
2743
- }
2744
- return result;
2745
- }
2746
3150
 
2747
3151
  // ../core/src/adapter-utils/get-attribute-from-layouts.ts
2748
3152
  function getAttributeInfosFromLayouts(shaderLayout, bufferLayout) {
@@ -2772,15 +3176,16 @@ ${htmlLog}
2772
3176
  if (!shaderDeclaration) {
2773
3177
  return null;
2774
3178
  }
2775
- const attributeTypeInfo = decodeShaderAttributeType(shaderDeclaration.type);
2776
- const vertexFormat = bufferMapping?.vertexFormat || attributeTypeInfo.defaultVertexFormat;
2777
- const vertexFormatInfo = decodeVertexFormat(vertexFormat);
3179
+ const attributeTypeInfo = getAttributeShaderTypeInfo(shaderDeclaration.type);
3180
+ const defaultVertexFormat = getCompatibleVertexFormat(attributeTypeInfo);
3181
+ const vertexFormat = bufferMapping?.vertexFormat || defaultVertexFormat;
3182
+ const vertexFormatInfo = getVertexFormatInfo(vertexFormat);
2778
3183
  return {
2779
3184
  attributeName: bufferMapping?.attributeName || shaderDeclaration.name,
2780
3185
  bufferName: bufferMapping?.bufferName || shaderDeclaration.name,
2781
3186
  location: shaderDeclaration.location,
2782
3187
  shaderType: shaderDeclaration.type,
2783
- shaderDataType: attributeTypeInfo.dataType,
3188
+ primitiveType: attributeTypeInfo.primitiveType,
2784
3189
  shaderComponents: attributeTypeInfo.components,
2785
3190
  vertexFormat,
2786
3191
  bufferDataType: vertexFormatInfo.type,
@@ -2842,7 +3247,7 @@ ${htmlLog}
2842
3247
  let byteStride = bufferLayout.byteStride;
2843
3248
  if (typeof bufferLayout.byteStride !== "number") {
2844
3249
  for (const attributeMapping2 of bufferLayout.attributes || []) {
2845
- const info = decodeVertexFormat(attributeMapping2.format);
3250
+ const info = getVertexFormatInfo(attributeMapping2.format);
2846
3251
  byteStride += info.byteLength;
2847
3252
  }
2848
3253
  }
@@ -2879,26 +3284,23 @@ ${htmlLog}
2879
3284
  super(device, props, _VertexArray.defaultProps);
2880
3285
  this.maxVertexAttributes = device.limits.maxVertexAttributes;
2881
3286
  this.attributes = new Array(this.maxVertexAttributes).fill(null);
2882
- const { shaderLayout, bufferLayout } = props.renderPipeline || {};
2883
- if (!shaderLayout || !bufferLayout) {
2884
- throw new Error("VertexArray");
2885
- }
2886
3287
  this.attributeInfos = getAttributeInfosByLocation(
2887
- shaderLayout,
2888
- bufferLayout,
3288
+ props.shaderLayout,
3289
+ props.bufferLayout,
2889
3290
  this.maxVertexAttributes
2890
3291
  );
2891
3292
  }
2892
3293
  // DEPRECATED METHODS
2893
3294
  /** @deprecated Set constant attributes (WebGL only) */
2894
3295
  setConstantWebGL(location, value) {
2895
- this.device.reportError(new Error("constant attributes not supported"));
3296
+ this.device.reportError(new Error("constant attributes not supported"), this)();
2896
3297
  }
2897
3298
  };
2898
3299
  var VertexArray = _VertexArray;
2899
3300
  __publicField(VertexArray, "defaultProps", {
2900
3301
  ...Resource.defaultProps,
2901
- renderPipeline: null
3302
+ shaderLayout: void 0,
3303
+ bufferLayout: []
2902
3304
  });
2903
3305
 
2904
3306
  // ../core/src/adapter/resources/transform-feedback.ts
@@ -2951,46 +3353,6 @@ ${htmlLog}
2951
3353
  }
2952
3354
  });
2953
3355
 
2954
- // ../core/src/gpu-type-utils/decode-shader-types.ts
2955
- var UNIFORM_FORMATS = {
2956
- f32: { type: "f32", components: 1 },
2957
- i32: { type: "i32", components: 1 },
2958
- u32: { type: "u32", components: 1 },
2959
- // 'bool-webgl': {type: 'bool-webgl', components: 1},
2960
- "vec2<f32>": { type: "f32", components: 2 },
2961
- "vec3<f32>": { type: "f32", components: 3 },
2962
- "vec4<f32>": { type: "f32", components: 4 },
2963
- "vec2<i32>": { type: "i32", components: 2 },
2964
- "vec3<i32>": { type: "i32", components: 3 },
2965
- "vec4<i32>": { type: "i32", components: 4 },
2966
- "vec2<u32>": { type: "u32", components: 2 },
2967
- "vec3<u32>": { type: "u32", components: 3 },
2968
- "vec4<u32>": { type: "u32", components: 4 },
2969
- "mat2x2<f32>": { type: "f32", components: 4 },
2970
- "mat2x3<f32>": { type: "f32", components: 6 },
2971
- "mat2x4<f32>": { type: "f32", components: 8 },
2972
- "mat3x2<f32>": { type: "f32", components: 6 },
2973
- "mat3x3<f32>": { type: "f32", components: 9 },
2974
- "mat3x4<f32>": { type: "f32", components: 12 },
2975
- "mat4x2<f32>": { type: "f32", components: 8 },
2976
- "mat4x3<f32>": { type: "f32", components: 12 },
2977
- "mat4x4<f32>": { type: "f32", components: 16 }
2978
- };
2979
- function decodeShaderUniformType(format) {
2980
- const decoded = UNIFORM_FORMATS[format];
2981
- return decoded;
2982
- }
2983
- function alignTo(size, count) {
2984
- switch (count) {
2985
- case 1:
2986
- return size;
2987
- case 2:
2988
- return size + size % 2;
2989
- default:
2990
- return size + (4 - size % 4) % 4;
2991
- }
2992
- }
2993
-
2994
3356
  // ../core/src/utils/array-utils-flat.ts
2995
3357
  var arrayBuffer;
2996
3358
  function getScratchArrayBuffer(byteLength) {
@@ -3025,7 +3387,7 @@ ${htmlLog}
3025
3387
  constructor(uniformTypes) {
3026
3388
  let size = 0;
3027
3389
  for (const [key, uniformType] of Object.entries(uniformTypes)) {
3028
- const typeAndComponents = decodeShaderUniformType(uniformType);
3390
+ const typeAndComponents = getVariableShaderTypeInfo(uniformType);
3029
3391
  const { type, components: count } = typeAndComponents;
3030
3392
  size = alignTo(size, count);
3031
3393
  const offset = size;
@@ -3274,137 +3636,86 @@ ${htmlLog}
3274
3636
  }
3275
3637
  };
3276
3638
 
3277
- // ../core/src/gpu-type-utils/vertex-format-from-attribute.ts
3278
- function getDataTypeFromTypedArray(arrayOrType) {
3279
- const type = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType;
3280
- switch (type) {
3281
- case Float32Array:
3282
- return "float32";
3283
- case Uint16Array:
3284
- return "uint16";
3285
- case Uint32Array:
3286
- return "uint32";
3287
- case Uint8Array:
3288
- case Uint8ClampedArray:
3289
- return "uint8";
3290
- case Int8Array:
3291
- return "sint8";
3292
- case Int16Array:
3293
- return "sint16";
3294
- case Int32Array:
3295
- return "sint32";
3296
- default:
3297
- throw new Error(type.constructor.name);
3298
- }
3299
- }
3300
- function getTypedArrayFromDataType(dataType) {
3301
- switch (dataType) {
3302
- case "float32":
3303
- return Float32Array;
3304
- case "uint32":
3305
- return Uint32Array;
3306
- case "sint32":
3307
- return Int32Array;
3308
- case "uint16":
3309
- case "unorm16":
3310
- return Uint16Array;
3311
- case "sint16":
3312
- case "snorm16":
3313
- return Int16Array;
3314
- case "uint8":
3315
- case "unorm8":
3316
- return Uint8Array;
3317
- case "sint8":
3318
- case "snorm8":
3319
- return Int8Array;
3320
- default:
3321
- throw new Error(dataType);
3322
- }
3323
- }
3324
- function getVertexFormatFromAttribute(typedArray, size, normalized) {
3325
- if (!size || size > 4) {
3326
- throw new Error(`size ${size}`);
3327
- }
3328
- const components = size;
3329
- let dataType = getDataTypeFromTypedArray(typedArray);
3330
- if (dataType === "uint8" && normalized && components === 1) {
3331
- return "unorm8-webgl";
3332
- }
3333
- if (dataType === "uint8" && normalized && components === 3) {
3334
- return "unorm8x3-webgl";
3335
- }
3336
- if (dataType === "uint8" || dataType === "sint8") {
3337
- if (components === 1 || components === 3) {
3338
- throw new Error(`size: ${size}`);
3339
- }
3340
- if (normalized) {
3341
- dataType = dataType.replace("int", "norm");
3342
- }
3343
- return `${dataType}x${components}`;
3344
- }
3345
- if (dataType === "uint16" || dataType === "sint16") {
3346
- if (components === 1 || components === 3) {
3347
- throw new Error(`size: ${size}`);
3348
- }
3349
- if (normalized) {
3350
- dataType = dataType.replace("int", "norm");
3351
- }
3352
- return `${dataType}x${components}`;
3353
- }
3354
- if (components === 1) {
3355
- return dataType;
3639
+ // ../core/src/shadertypes/textures/pixel-utils.ts
3640
+ function readPixel(pixelData, x, y, bitsPerChannel) {
3641
+ if (x < 0 || x >= pixelData.width || y < 0 || y >= pixelData.height) {
3642
+ throw new Error("Coordinates out of bounds.");
3643
+ }
3644
+ const byteOffset = y * pixelData.bytesPerRow + x * pixelData.bytesPerPixel;
3645
+ const pixelDataView = new DataView(pixelData.arrayBuffer, byteOffset, pixelData.bytesPerPixel);
3646
+ let bitOffsetWithinPixel = 0;
3647
+ const channels = [];
3648
+ for (let i = 0; i < 4; i++) {
3649
+ const bits = bitsPerChannel[i];
3650
+ if (bits <= 0) {
3651
+ channels.push(0);
3652
+ } else {
3653
+ const channelValue = readBitsFromDataView(pixelDataView, bitOffsetWithinPixel, bits);
3654
+ channels.push(channelValue);
3655
+ bitOffsetWithinPixel += bits;
3656
+ }
3657
+ }
3658
+ return [channels[0], channels[1], channels[2], channels[3]];
3659
+ }
3660
+ function writePixel(dataView, bitOffset, bitsPerChannel, pixel) {
3661
+ let currentBitOffset = bitOffset;
3662
+ for (let channel = 0; channel < 4; channel++) {
3663
+ const bits = bitsPerChannel[channel];
3664
+ const maxValue = (1 << bits) - 1;
3665
+ const channelValue = pixel[channel] & maxValue;
3666
+ writeBitsToDataView(dataView, currentBitOffset, bits, channelValue);
3667
+ currentBitOffset += bits;
3668
+ }
3669
+ }
3670
+ function readBitsFromDataView(dataView, bitOffset, bitCount) {
3671
+ if (bitOffset % 8 === 0) {
3672
+ const byteOffset = bitOffset / 8;
3673
+ if (bitCount === 8 && byteOffset + 1 <= dataView.byteLength) {
3674
+ return dataView.getUint8(byteOffset);
3675
+ } else if (bitCount === 16 && byteOffset + 2 <= dataView.byteLength) {
3676
+ return dataView.getUint16(byteOffset, false);
3677
+ } else if (bitCount === 32 && byteOffset + 4 <= dataView.byteLength) {
3678
+ return dataView.getUint32(byteOffset, false);
3679
+ }
3680
+ }
3681
+ let value = 0;
3682
+ for (let i = 0; i < bitCount; i++) {
3683
+ const overallBitIndex = bitOffset + i;
3684
+ const byteIndex = Math.floor(overallBitIndex / 8);
3685
+ const bitIndex = overallBitIndex % 8;
3686
+ const byteValue = dataView.getUint8(byteIndex);
3687
+ const bit = byteValue >> 7 - bitIndex & 1;
3688
+ value = value << 1 | bit;
3356
3689
  }
3357
- return `${dataType}x${components}`;
3690
+ return value;
3358
3691
  }
3359
-
3360
- // ../core/src/adapter-utils/buffer-layout-helper.ts
3361
- var BufferLayoutHelper = class {
3362
- bufferLayouts;
3363
- constructor(bufferLayouts) {
3364
- this.bufferLayouts = bufferLayouts;
3365
- }
3366
- getBufferLayout(name2) {
3367
- return this.bufferLayouts.find((layout) => layout.name === name2) || null;
3368
- }
3369
- /** Get attribute names from a BufferLayout */
3370
- getAttributeNamesForBuffer(bufferLayout) {
3371
- return bufferLayout.attributes ? bufferLayout.attributes?.map((layout) => layout.attribute) : [bufferLayout.name];
3372
- }
3373
- mergeBufferLayouts(bufferLayouts1, bufferLayouts2) {
3374
- const mergedLayouts = [...bufferLayouts1];
3375
- for (const attribute of bufferLayouts2) {
3376
- const index = mergedLayouts.findIndex((attribute2) => attribute2.name === attribute.name);
3377
- if (index < 0) {
3378
- mergedLayouts.push(attribute);
3379
- } else {
3380
- mergedLayouts[index] = attribute;
3381
- }
3692
+ function writeBitsToDataView(dataView, bitOffset, bitCount, value) {
3693
+ if (bitOffset % 8 === 0) {
3694
+ const byteOffset = bitOffset / 8;
3695
+ if (bitCount === 8 && byteOffset + 1 <= dataView.byteLength) {
3696
+ dataView.setUint8(byteOffset, value & 255);
3697
+ return;
3698
+ } else if (bitCount === 16 && byteOffset + 2 <= dataView.byteLength) {
3699
+ dataView.setUint16(byteOffset, value & 65535, false);
3700
+ return;
3701
+ } else if (bitCount === 32 && byteOffset + 4 <= dataView.byteLength) {
3702
+ dataView.setUint32(byteOffset, value, false);
3703
+ return;
3382
3704
  }
3383
- return mergedLayouts;
3384
3705
  }
3385
- getBufferIndex(bufferName) {
3386
- const bufferIndex = this.bufferLayouts.findIndex((layout) => layout.name === bufferName);
3387
- if (bufferIndex === -1) {
3388
- log.warn(`BufferLayout: Missing buffer for "${bufferName}".`)();
3706
+ for (let i = 0; i < bitCount; i++) {
3707
+ const overallBitIndex = bitOffset + i;
3708
+ const byteIndex = Math.floor(overallBitIndex / 8);
3709
+ const bitIndex = overallBitIndex % 8;
3710
+ const mask = 1 << 7 - bitIndex;
3711
+ const bitValue = value >> bitCount - 1 - i & 1;
3712
+ let currentByte = dataView.getUint8(byteIndex);
3713
+ currentByte &= ~mask;
3714
+ if (bitValue) {
3715
+ currentByte |= mask;
3389
3716
  }
3390
- return bufferIndex;
3717
+ dataView.setUint8(byteIndex, currentByte);
3391
3718
  }
3392
- };
3393
-
3394
- // ../core/src/adapter-utils/buffer-layout-order.ts
3395
- function sortedBufferLayoutByShaderSourceLocations(shaderLayout, bufferLayout) {
3396
- const shaderLayoutMap = Object.fromEntries(
3397
- shaderLayout.attributes.map((attr) => [attr.name, attr.location])
3398
- );
3399
- const sortedLayout = bufferLayout.slice();
3400
- sortedLayout.sort((a, b) => {
3401
- const attributeNamesA = a.attributes ? a.attributes.map((attr) => attr.attribute) : [a.name];
3402
- const attributeNamesB = b.attributes ? b.attributes.map((attr) => attr.attribute) : [b.name];
3403
- const minLocationA = Math.min(...attributeNamesA.map((name2) => shaderLayoutMap[name2]));
3404
- const minLocationB = Math.min(...attributeNamesB.map((name2) => shaderLayoutMap[name2]));
3405
- return minLocationA - minLocationB;
3406
- });
3407
- return sortedLayout;
3408
3719
  }
3409
3720
 
3410
3721
  // bundle.ts