@luma.gl/webgl 9.3.0-alpha.2 → 9.3.0-alpha.6

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 (106) hide show
  1. package/dist/adapter/converters/webgl-texture-table.d.ts +7 -1
  2. package/dist/adapter/converters/webgl-texture-table.d.ts.map +1 -1
  3. package/dist/adapter/converters/webgl-texture-table.js +121 -43
  4. package/dist/adapter/converters/webgl-texture-table.js.map +1 -1
  5. package/dist/adapter/device-helpers/webgl-device-features.d.ts.map +1 -1
  6. package/dist/adapter/device-helpers/webgl-device-features.js +1 -2
  7. package/dist/adapter/device-helpers/webgl-device-features.js.map +1 -1
  8. package/dist/adapter/device-helpers/webgl-device-info.js +5 -0
  9. package/dist/adapter/device-helpers/webgl-device-info.js.map +1 -1
  10. package/dist/adapter/helpers/get-shader-layout-from-glsl.js +23 -21
  11. package/dist/adapter/helpers/get-shader-layout-from-glsl.js.map +1 -1
  12. package/dist/adapter/helpers/parse-shader-compiler-log.d.ts +1 -1
  13. package/dist/adapter/helpers/parse-shader-compiler-log.d.ts.map +1 -1
  14. package/dist/adapter/helpers/parse-shader-compiler-log.js +20 -0
  15. package/dist/adapter/helpers/parse-shader-compiler-log.js.map +1 -1
  16. package/dist/adapter/resources/webgl-buffer.d.ts.map +1 -1
  17. package/dist/adapter/resources/webgl-buffer.js +19 -4
  18. package/dist/adapter/resources/webgl-buffer.js.map +1 -1
  19. package/dist/adapter/resources/webgl-command-buffer.d.ts +3 -4
  20. package/dist/adapter/resources/webgl-command-buffer.d.ts.map +1 -1
  21. package/dist/adapter/resources/webgl-command-buffer.js +11 -7
  22. package/dist/adapter/resources/webgl-command-buffer.js.map +1 -1
  23. package/dist/adapter/resources/webgl-command-encoder.d.ts +5 -4
  24. package/dist/adapter/resources/webgl-command-encoder.d.ts.map +1 -1
  25. package/dist/adapter/resources/webgl-command-encoder.js +20 -7
  26. package/dist/adapter/resources/webgl-command-encoder.js.map +1 -1
  27. package/dist/adapter/resources/webgl-query-set.d.ts +29 -31
  28. package/dist/adapter/resources/webgl-query-set.d.ts.map +1 -1
  29. package/dist/adapter/resources/webgl-query-set.js +193 -97
  30. package/dist/adapter/resources/webgl-query-set.js.map +1 -1
  31. package/dist/adapter/resources/webgl-render-pass.d.ts.map +1 -1
  32. package/dist/adapter/resources/webgl-render-pass.js +17 -0
  33. package/dist/adapter/resources/webgl-render-pass.js.map +1 -1
  34. package/dist/adapter/resources/webgl-render-pipeline.d.ts +13 -19
  35. package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
  36. package/dist/adapter/resources/webgl-render-pipeline.js +36 -154
  37. package/dist/adapter/resources/webgl-render-pipeline.js.map +1 -1
  38. package/dist/adapter/resources/webgl-shared-render-pipeline.d.ts +24 -0
  39. package/dist/adapter/resources/webgl-shared-render-pipeline.d.ts.map +1 -0
  40. package/dist/adapter/resources/webgl-shared-render-pipeline.js +152 -0
  41. package/dist/adapter/resources/webgl-shared-render-pipeline.js.map +1 -0
  42. package/dist/adapter/resources/webgl-texture.d.ts +23 -4
  43. package/dist/adapter/resources/webgl-texture.d.ts.map +1 -1
  44. package/dist/adapter/resources/webgl-texture.js +203 -100
  45. package/dist/adapter/resources/webgl-texture.js.map +1 -1
  46. package/dist/adapter/resources/webgl-transform-feedback.js +5 -5
  47. package/dist/adapter/resources/webgl-transform-feedback.js.map +1 -1
  48. package/dist/adapter/webgl-adapter.d.ts.map +1 -1
  49. package/dist/adapter/webgl-adapter.js +3 -4
  50. package/dist/adapter/webgl-adapter.js.map +1 -1
  51. package/dist/adapter/webgl-device.d.ts +6 -3
  52. package/dist/adapter/webgl-device.d.ts.map +1 -1
  53. package/dist/adapter/webgl-device.js +56 -14
  54. package/dist/adapter/webgl-device.js.map +1 -1
  55. package/dist/adapter/webgl-presentation-context.d.ts +21 -0
  56. package/dist/adapter/webgl-presentation-context.d.ts.map +1 -0
  57. package/dist/adapter/webgl-presentation-context.js +64 -0
  58. package/dist/adapter/webgl-presentation-context.js.map +1 -0
  59. package/dist/context/debug/spector.d.ts.map +1 -1
  60. package/dist/context/debug/spector.js +4 -4
  61. package/dist/context/debug/spector.js.map +1 -1
  62. package/dist/context/debug/webgl-developer-tools.js +2 -0
  63. package/dist/context/debug/webgl-developer-tools.js.map +1 -1
  64. package/dist/context/helpers/create-browser-context.d.ts.map +1 -1
  65. package/dist/context/helpers/create-browser-context.js +6 -8
  66. package/dist/context/helpers/create-browser-context.js.map +1 -1
  67. package/dist/context/helpers/webgl-context-data.d.ts +5 -1
  68. package/dist/context/helpers/webgl-context-data.d.ts.map +1 -1
  69. package/dist/context/helpers/webgl-context-data.js +9 -10
  70. package/dist/context/helpers/webgl-context-data.js.map +1 -1
  71. package/dist/context/parameters/unified-parameter-api.d.ts +1 -1
  72. package/dist/context/parameters/unified-parameter-api.js +2 -2
  73. package/dist/context/parameters/unified-parameter-api.js.map +1 -1
  74. package/dist/context/state-tracker/webgl-state-tracker.js +2 -2
  75. package/dist/context/state-tracker/webgl-state-tracker.js.map +1 -1
  76. package/dist/dist.dev.js +1427 -828
  77. package/dist/dist.min.js +2 -2
  78. package/dist/index.cjs +1325 -811
  79. package/dist/index.cjs.map +4 -4
  80. package/dist/utils/fill-array.js +1 -1
  81. package/dist/utils/fill-array.js.map +1 -1
  82. package/package.json +4 -4
  83. package/src/adapter/converters/webgl-texture-table.ts +159 -47
  84. package/src/adapter/device-helpers/webgl-device-features.ts +1 -2
  85. package/src/adapter/device-helpers/webgl-device-info.ts +6 -0
  86. package/src/adapter/helpers/get-shader-layout-from-glsl.ts +25 -24
  87. package/src/adapter/helpers/parse-shader-compiler-log.ts +23 -1
  88. package/src/adapter/resources/webgl-buffer.ts +16 -4
  89. package/src/adapter/resources/webgl-command-buffer.ts +21 -24
  90. package/src/adapter/resources/webgl-command-encoder.ts +22 -7
  91. package/src/adapter/resources/webgl-query-set.ts +229 -102
  92. package/src/adapter/resources/webgl-render-pass.ts +19 -0
  93. package/src/adapter/resources/webgl-render-pipeline.ts +46 -181
  94. package/src/adapter/resources/webgl-shared-render-pipeline.ts +208 -0
  95. package/src/adapter/resources/webgl-texture.ts +326 -121
  96. package/src/adapter/resources/webgl-transform-feedback.ts +5 -5
  97. package/src/adapter/webgl-adapter.ts +3 -4
  98. package/src/adapter/webgl-device.ts +66 -19
  99. package/src/adapter/webgl-presentation-context.ts +93 -0
  100. package/src/context/debug/spector.ts +4 -4
  101. package/src/context/debug/webgl-developer-tools.ts +2 -0
  102. package/src/context/helpers/create-browser-context.ts +8 -8
  103. package/src/context/helpers/webgl-context-data.ts +17 -11
  104. package/src/context/parameters/unified-parameter-api.ts +2 -2
  105. package/src/context/state-tracker/webgl-state-tracker.ts +2 -2
  106. package/src/utils/fill-array.ts +1 -1
package/dist/dist.dev.js CHANGED
@@ -847,6 +847,24 @@ var __exports__ = (() => {
847
847
  }
848
848
  });
849
849
 
850
+ // src/context/helpers/webgl-context-data.ts
851
+ function getWebGLContextData(gl) {
852
+ const contextData = gl.luma || {
853
+ _polyfilled: false,
854
+ extensions: {},
855
+ softwareRenderer: false
856
+ };
857
+ contextData._polyfilled ??= false;
858
+ contextData.extensions ||= {};
859
+ gl.luma = contextData;
860
+ return contextData;
861
+ }
862
+ var init_webgl_context_data = __esm({
863
+ "src/context/helpers/webgl-context-data.ts"() {
864
+ "use strict";
865
+ }
866
+ });
867
+
850
868
  // src/context/debug/spector.ts
851
869
  async function loadSpectorJS(props) {
852
870
  if (!globalThis.SPECTOR) {
@@ -888,9 +906,10 @@ var __exports__ = (() => {
888
906
  }
889
907
  if (props.gl) {
890
908
  const gl = props.gl;
891
- const device = gl.device;
909
+ const contextData = getWebGLContextData(gl);
910
+ const device = contextData.device;
892
911
  spector?.startCapture(props.gl, 500);
893
- gl.device = device;
912
+ contextData.device = device;
894
913
  new Promise((resolve) => setTimeout(resolve, 2e3)).then((_) => {
895
914
  import_core.log.info("Spector capture stopped after 2 seconds")();
896
915
  spector?.stopCapture();
@@ -904,6 +923,7 @@ var __exports__ = (() => {
904
923
  "use strict";
905
924
  import_core = __toESM(require_core(), 1);
906
925
  init_load_script();
926
+ init_webgl_context_data();
907
927
  LOG_LEVEL = 1;
908
928
  spector = null;
909
929
  initialized = false;
@@ -1000,7 +1020,7 @@ var __exports__ = (() => {
1000
1020
  });
1001
1021
 
1002
1022
  // src/context/debug/webgl-developer-tools.ts
1003
- function getWebGLContextData(gl) {
1023
+ function getWebGLContextData2(gl) {
1004
1024
  gl.luma = gl.luma || {};
1005
1025
  return gl.luma;
1006
1026
  }
@@ -1015,7 +1035,7 @@ var __exports__ = (() => {
1015
1035
  return props.debugWebGL || props.traceWebGL ? getDebugContext(gl, props) : getRealContext(gl);
1016
1036
  }
1017
1037
  function getRealContext(gl) {
1018
- const data = getWebGLContextData(gl);
1038
+ const data = getWebGLContextData2(gl);
1019
1039
  return data.realContext ? data.realContext : gl;
1020
1040
  }
1021
1041
  function getDebugContext(gl, props) {
@@ -1023,7 +1043,7 @@ var __exports__ = (() => {
1023
1043
  import_core2.log.warn("webgl-debug not loaded")();
1024
1044
  return gl;
1025
1045
  }
1026
- const data = getWebGLContextData(gl);
1046
+ const data = getWebGLContextData2(gl);
1027
1047
  if (data.debugContext) {
1028
1048
  return data.debugContext;
1029
1049
  }
@@ -1045,6 +1065,7 @@ var __exports__ = (() => {
1045
1065
  const debugContext = Object.create(WebGLDebugContext);
1046
1066
  data.realContext = gl;
1047
1067
  data.debugContext = debugContext;
1068
+ debugContext.luma = data;
1048
1069
  debugContext.debug = true;
1049
1070
  return debugContext;
1050
1071
  }
@@ -1629,7 +1650,7 @@ var __exports__ = (() => {
1629
1650
  }
1630
1651
  }
1631
1652
  }
1632
- const cache = gl.state && gl.state.cache;
1653
+ const cache = gl.lumaState?.cache;
1633
1654
  if (cache) {
1634
1655
  for (const key in compositeSetters) {
1635
1656
  const compositeSetter = GL_COMPOSITE_PARAMETER_SETTERS[key];
@@ -1752,7 +1773,7 @@ var __exports__ = (() => {
1752
1773
  init_webgl_parameter_tables();
1753
1774
  WebGLStateTracker = class {
1754
1775
  static get(gl) {
1755
- return gl.state;
1776
+ return gl.lumaState;
1756
1777
  }
1757
1778
  gl;
1758
1779
  program = null;
@@ -1790,7 +1811,7 @@ var __exports__ = (() => {
1790
1811
  throw new Error("WebGLStateTracker");
1791
1812
  }
1792
1813
  this.initialized = true;
1793
- this.gl.state = this;
1814
+ this.gl.lumaState = this;
1794
1815
  installProgramSpy(gl);
1795
1816
  for (const key in GL_HOOKED_SETTERS) {
1796
1817
  const setter = GL_HOOKED_SETTERS[key];
@@ -1850,13 +1871,11 @@ var __exports__ = (() => {
1850
1871
  if (!gl && webglProps.failIfMajorPerformanceCaveat) {
1851
1872
  errorMessage ||= "Only software GPU is available. Set `failIfMajorPerformanceCaveat: false` to allow.";
1852
1873
  }
1874
+ let softwareRenderer = false;
1853
1875
  if (!gl && allowSoftwareRenderer) {
1854
1876
  webglProps.failIfMajorPerformanceCaveat = false;
1855
1877
  gl = canvas.getContext("webgl2", webglProps);
1856
- if (gl) {
1857
- gl.luma ||= {};
1858
- gl.luma.softwareRenderer = true;
1859
- }
1878
+ softwareRenderer = true;
1860
1879
  }
1861
1880
  if (!gl) {
1862
1881
  gl = canvas.getContext("webgl", {});
@@ -1869,6 +1888,8 @@ var __exports__ = (() => {
1869
1888
  errorMessage ||= "Your browser does not support WebGL";
1870
1889
  throw new Error(`Failed to create WebGL context: ${errorMessage}`);
1871
1890
  }
1891
+ const luma = getWebGLContextData(gl);
1892
+ luma.softwareRenderer = softwareRenderer;
1872
1893
  const { onContextLost, onContextRestored } = props;
1873
1894
  canvas.addEventListener("webglcontextlost", (event) => onContextLost(event), false);
1874
1895
  canvas.addEventListener(
@@ -1876,7 +1897,6 @@ var __exports__ = (() => {
1876
1897
  (event) => onContextRestored(event),
1877
1898
  false
1878
1899
  );
1879
- gl.luma ||= {};
1880
1900
  return gl;
1881
1901
  } finally {
1882
1902
  canvas.removeEventListener("webglcontextcreationerror", onCreateError, false);
@@ -1885,6 +1905,7 @@ var __exports__ = (() => {
1885
1905
  var init_create_browser_context = __esm({
1886
1906
  "src/context/helpers/create-browser-context.ts"() {
1887
1907
  "use strict";
1908
+ init_webgl_context_data();
1888
1909
  }
1889
1910
  });
1890
1911
 
@@ -1962,6 +1983,8 @@ var __exports__ = (() => {
1962
1983
  }
1963
1984
  const gpuVendor = identifyGPUVendor(vendor, renderer);
1964
1985
  switch (gpuVendor) {
1986
+ case "apple":
1987
+ return isAppleSiliconGPU(vendor, renderer) ? "integrated" : "unknown";
1965
1988
  case "intel":
1966
1989
  return "integrated";
1967
1990
  case "software":
@@ -1972,6 +1995,9 @@ var __exports__ = (() => {
1972
1995
  return "discrete";
1973
1996
  }
1974
1997
  }
1998
+ function isAppleSiliconGPU(vendor, renderer) {
1999
+ return /Apple (M\d|A\d|GPU)/i.test(`${vendor} ${renderer}`);
2000
+ }
1975
2001
  var init_webgl_device_info = __esm({
1976
2002
  "src/adapter/device-helpers/webgl-device-info.ts"() {
1977
2003
  "use strict";
@@ -2020,8 +2046,27 @@ var __exports__ = (() => {
2020
2046
  return feature in TEXTURE_FEATURES;
2021
2047
  }
2022
2048
  function checkTextureFeature(gl, feature, extensions) {
2023
- const textureExtensions = TEXTURE_FEATURES[feature] || [];
2024
- return textureExtensions.every((extension) => getWebGLExtension(gl, extension, extensions));
2049
+ return hasTextureFeature(gl, feature, extensions, /* @__PURE__ */ new Set());
2050
+ }
2051
+ function hasTextureFeature(gl, feature, extensions, seenFeatures) {
2052
+ const definition = TEXTURE_FEATURES[feature];
2053
+ if (!definition) {
2054
+ return false;
2055
+ }
2056
+ if (seenFeatures.has(feature)) {
2057
+ return false;
2058
+ }
2059
+ seenFeatures.add(feature);
2060
+ const hasDependentFeatures = (definition.features || []).every(
2061
+ (dependentFeature) => hasTextureFeature(gl, dependentFeature, extensions, seenFeatures)
2062
+ );
2063
+ seenFeatures.delete(feature);
2064
+ if (!hasDependentFeatures) {
2065
+ return false;
2066
+ }
2067
+ return (definition.extensions || []).every(
2068
+ (extension) => Boolean(getWebGLExtension(gl, extension, extensions))
2069
+ );
2025
2070
  }
2026
2071
  function getTextureFormatCapabilitiesWebGL(gl, formatSupport, extensions) {
2027
2072
  let supported = formatSupport.create;
@@ -2032,12 +2077,17 @@ var __exports__ = (() => {
2032
2077
  if (webglFormatInfo?.x) {
2033
2078
  supported = supported && Boolean(getWebGLExtension(gl, webglFormatInfo.x, extensions));
2034
2079
  }
2080
+ if (formatSupport.format === "stencil8") {
2081
+ supported = false;
2082
+ }
2083
+ const renderFeatureSupported = webglFormatInfo?.r === false ? false : webglFormatInfo?.r === void 0 || checkTextureFeature(gl, webglFormatInfo.r, extensions);
2084
+ const renderable = supported && formatSupport.render && renderFeatureSupported && isColorRenderableTextureFormat(gl, formatSupport.format, extensions);
2035
2085
  return {
2036
2086
  format: formatSupport.format,
2037
2087
  // @ts-ignore
2038
2088
  create: supported && formatSupport.create,
2039
2089
  // @ts-ignore
2040
- render: supported && formatSupport.render,
2090
+ render: renderable,
2041
2091
  // @ts-ignore
2042
2092
  filter: supported && formatSupport.filter,
2043
2093
  // @ts-ignore
@@ -2046,6 +2096,45 @@ var __exports__ = (() => {
2046
2096
  store: supported && formatSupport.store
2047
2097
  };
2048
2098
  }
2099
+ function isColorRenderableTextureFormat(gl, format, extensions) {
2100
+ const webglFormatInfo = WEBGL_TEXTURE_FORMATS[format];
2101
+ const internalFormat = webglFormatInfo?.gl;
2102
+ if (internalFormat === void 0) {
2103
+ return false;
2104
+ }
2105
+ if (webglFormatInfo?.x && !getWebGLExtension(gl, webglFormatInfo.x, extensions)) {
2106
+ return false;
2107
+ }
2108
+ const previousTexture = gl.getParameter(32873 /* TEXTURE_BINDING_2D */);
2109
+ const previousFramebuffer = gl.getParameter(36006 /* FRAMEBUFFER_BINDING */);
2110
+ const texture = gl.createTexture();
2111
+ const framebuffer = gl.createFramebuffer();
2112
+ if (!texture || !framebuffer) {
2113
+ return false;
2114
+ }
2115
+ const noError = Number(0 /* NO_ERROR */);
2116
+ let error = Number(gl.getError());
2117
+ while (error !== noError) {
2118
+ error = gl.getError();
2119
+ }
2120
+ let renderable = false;
2121
+ try {
2122
+ gl.bindTexture(3553 /* TEXTURE_2D */, texture);
2123
+ gl.texStorage2D(3553 /* TEXTURE_2D */, 1, internalFormat, 1, 1);
2124
+ if (Number(gl.getError()) !== noError) {
2125
+ return false;
2126
+ }
2127
+ gl.bindFramebuffer(36160 /* FRAMEBUFFER */, framebuffer);
2128
+ gl.framebufferTexture2D(36160 /* FRAMEBUFFER */, 36064 /* COLOR_ATTACHMENT0 */, 3553 /* TEXTURE_2D */, texture, 0);
2129
+ renderable = Number(gl.checkFramebufferStatus(36160 /* FRAMEBUFFER */)) === Number(36053 /* FRAMEBUFFER_COMPLETE */) && Number(gl.getError()) === noError;
2130
+ } finally {
2131
+ gl.bindFramebuffer(36160 /* FRAMEBUFFER */, previousFramebuffer);
2132
+ gl.deleteFramebuffer(framebuffer);
2133
+ gl.bindTexture(3553 /* TEXTURE_2D */, previousTexture);
2134
+ gl.deleteTexture(texture);
2135
+ }
2136
+ return renderable;
2137
+ }
2049
2138
  function getTextureFormatWebGL(format) {
2050
2139
  const formatData = WEBGL_TEXTURE_FORMATS[format];
2051
2140
  const webglFormat = convertTextureFormatToGL(format);
@@ -2101,7 +2190,7 @@ var __exports__ = (() => {
2101
2190
  }
2102
2191
  return webglFormat;
2103
2192
  }
2104
- var import_core3, X_S3TC, X_S3TC_SRGB, X_RGTC, X_BPTC, X_ETC2, X_ASTC, X_ETC1, X_PVRTC, X_ATC, EXT_texture_norm16, EXT_render_snorm, EXT_color_buffer_float, TEXTURE_FEATURES, WEBGL_TEXTURE_FORMATS;
2193
+ var import_core3, X_S3TC, X_S3TC_SRGB, X_RGTC, X_BPTC, X_ETC2, X_ASTC, X_ETC1, X_PVRTC, X_ATC, EXT_texture_norm16, EXT_render_snorm, EXT_color_buffer_float, SNORM8_COLOR_RENDERABLE, NORM16_COLOR_RENDERABLE, SNORM16_COLOR_RENDERABLE, FLOAT16_COLOR_RENDERABLE, FLOAT32_COLOR_RENDERABLE, RGB9E5UFLOAT_COLOR_RENDERABLE, TEXTURE_FEATURES, WEBGL_TEXTURE_FORMATS;
2105
2194
  var init_webgl_texture_table = __esm({
2106
2195
  "src/adapter/converters/webgl-texture-table.ts"() {
2107
2196
  "use strict";
@@ -2120,44 +2209,51 @@ var __exports__ = (() => {
2120
2209
  EXT_texture_norm16 = "EXT_texture_norm16";
2121
2210
  EXT_render_snorm = "EXT_render_snorm";
2122
2211
  EXT_color_buffer_float = "EXT_color_buffer_float";
2212
+ SNORM8_COLOR_RENDERABLE = "snorm8-renderable-webgl";
2213
+ NORM16_COLOR_RENDERABLE = "norm16-renderable-webgl";
2214
+ SNORM16_COLOR_RENDERABLE = "snorm16-renderable-webgl";
2215
+ FLOAT16_COLOR_RENDERABLE = "float16-renderable-webgl";
2216
+ FLOAT32_COLOR_RENDERABLE = "float32-renderable-webgl";
2217
+ RGB9E5UFLOAT_COLOR_RENDERABLE = "rgb9e5ufloat-renderable-webgl";
2123
2218
  TEXTURE_FEATURES = {
2124
- "float32-renderable-webgl": ["EXT_color_buffer_float"],
2125
- "float16-renderable-webgl": ["EXT_color_buffer_half_float"],
2126
- "rgb9e5ufloat-renderable-webgl": ["WEBGL_render_shared_exponent"],
2127
- "snorm8-renderable-webgl": [EXT_render_snorm],
2128
- "norm16-renderable-webgl": [EXT_texture_norm16],
2129
- "snorm16-renderable-webgl": [EXT_texture_norm16, EXT_render_snorm],
2130
- "float32-filterable": ["OES_texture_float_linear"],
2131
- "float16-filterable-webgl": ["OES_texture_half_float_linear"],
2132
- "texture-filterable-anisotropic-webgl": ["EXT_texture_filter_anisotropic"],
2133
- "texture-blend-float-webgl": ["EXT_float_blend"],
2134
- "texture-compression-bc": [X_S3TC, X_S3TC_SRGB, X_RGTC, X_BPTC],
2219
+ "float32-renderable-webgl": { extensions: [EXT_color_buffer_float] },
2220
+ "float16-renderable-webgl": { extensions: ["EXT_color_buffer_half_float"] },
2221
+ "rgb9e5ufloat-renderable-webgl": { extensions: ["WEBGL_render_shared_exponent"] },
2222
+ "snorm8-renderable-webgl": { extensions: [EXT_render_snorm] },
2223
+ "norm16-webgl": { extensions: [EXT_texture_norm16] },
2224
+ "norm16-renderable-webgl": { features: ["norm16-webgl"] },
2225
+ "snorm16-renderable-webgl": { features: ["norm16-webgl"], extensions: [EXT_render_snorm] },
2226
+ "float32-filterable": { extensions: ["OES_texture_float_linear"] },
2227
+ "float16-filterable-webgl": { extensions: ["OES_texture_half_float_linear"] },
2228
+ "texture-filterable-anisotropic-webgl": { extensions: ["EXT_texture_filter_anisotropic"] },
2229
+ "texture-blend-float-webgl": { extensions: ["EXT_float_blend"] },
2230
+ "texture-compression-bc": { extensions: [X_S3TC, X_S3TC_SRGB, X_RGTC, X_BPTC] },
2135
2231
  // 'texture-compression-bc3-srgb-webgl': [X_S3TC_SRGB],
2136
2232
  // 'texture-compression-bc3-webgl': [X_S3TC],
2137
- "texture-compression-bc5-webgl": [X_RGTC],
2138
- "texture-compression-bc7-webgl": [X_BPTC],
2139
- "texture-compression-etc2": [X_ETC2],
2140
- "texture-compression-astc": [X_ASTC],
2141
- "texture-compression-etc1-webgl": [X_ETC1],
2142
- "texture-compression-pvrtc-webgl": [X_PVRTC],
2143
- "texture-compression-atc-webgl": [X_ATC]
2233
+ "texture-compression-bc5-webgl": { extensions: [X_RGTC] },
2234
+ "texture-compression-bc7-webgl": { extensions: [X_BPTC] },
2235
+ "texture-compression-etc2": { extensions: [X_ETC2] },
2236
+ "texture-compression-astc": { extensions: [X_ASTC] },
2237
+ "texture-compression-etc1-webgl": { extensions: [X_ETC1] },
2238
+ "texture-compression-pvrtc-webgl": { extensions: [X_PVRTC] },
2239
+ "texture-compression-atc-webgl": { extensions: [X_ATC] }
2144
2240
  };
2145
2241
  WEBGL_TEXTURE_FORMATS = {
2146
2242
  // 8-bit formats
2147
2243
  "r8unorm": { gl: 33321 /* R8 */, rb: true },
2148
- "r8snorm": { gl: 36756 /* R8_SNORM */ },
2244
+ "r8snorm": { gl: 36756 /* R8_SNORM */, r: SNORM8_COLOR_RENDERABLE },
2149
2245
  "r8uint": { gl: 33330 /* R8UI */, rb: true },
2150
2246
  "r8sint": { gl: 33329 /* R8I */, rb: true },
2151
2247
  // 16-bit formats
2152
2248
  "rg8unorm": { gl: 33323 /* RG8 */, rb: true },
2153
- "rg8snorm": { gl: 36757 /* RG8_SNORM */ },
2249
+ "rg8snorm": { gl: 36757 /* RG8_SNORM */, r: SNORM8_COLOR_RENDERABLE },
2154
2250
  "rg8uint": { gl: 33336 /* RG8UI */, rb: true },
2155
2251
  "rg8sint": { gl: 33335 /* RG8I */, rb: true },
2156
2252
  "r16uint": { gl: 33332 /* R16UI */, rb: true },
2157
2253
  "r16sint": { gl: 33331 /* R16I */, rb: true },
2158
- "r16float": { gl: 33325 /* R16F */, rb: true },
2159
- "r16unorm": { gl: 33322 /* R16_EXT */, rb: true },
2160
- "r16snorm": { gl: 36760 /* R16_SNORM_EXT */ },
2254
+ "r16float": { gl: 33325 /* R16F */, rb: true, r: FLOAT16_COLOR_RENDERABLE },
2255
+ "r16unorm": { gl: 33322 /* R16_EXT */, rb: true, r: NORM16_COLOR_RENDERABLE },
2256
+ "r16snorm": { gl: 36760 /* R16_SNORM_EXT */, r: SNORM16_COLOR_RENDERABLE },
2161
2257
  // Packed 16-bit formats
2162
2258
  "rgba4unorm-webgl": { gl: 32854 /* RGBA4 */, rb: true },
2163
2259
  "rgb565unorm-webgl": { gl: 36194 /* RGB565 */, rb: true },
@@ -2168,7 +2264,7 @@ var __exports__ = (() => {
2168
2264
  // 32-bit formats
2169
2265
  "rgba8unorm": { gl: 32856 /* RGBA8 */ },
2170
2266
  "rgba8unorm-srgb": { gl: 35907 /* SRGB8_ALPHA8 */ },
2171
- "rgba8snorm": { gl: 36759 /* RGBA8_SNORM */ },
2267
+ "rgba8snorm": { gl: 36759 /* RGBA8_SNORM */, r: SNORM8_COLOR_RENDERABLE },
2172
2268
  "rgba8uint": { gl: 36220 /* RGBA8UI */ },
2173
2269
  "rgba8sint": { gl: 36238 /* RGBA8I */ },
2174
2270
  // reverse colors, webgpu only
@@ -2176,38 +2272,38 @@ var __exports__ = (() => {
2176
2272
  "bgra8unorm-srgb": {},
2177
2273
  "rg16uint": { gl: 33338 /* RG16UI */ },
2178
2274
  "rg16sint": { gl: 33337 /* RG16I */ },
2179
- "rg16float": { gl: 33327 /* RG16F */, rb: true },
2180
- "rg16unorm": { gl: 33324 /* RG16_EXT */ },
2181
- "rg16snorm": { gl: 36761 /* RG16_SNORM_EXT */ },
2275
+ "rg16float": { gl: 33327 /* RG16F */, rb: true, r: FLOAT16_COLOR_RENDERABLE },
2276
+ "rg16unorm": { gl: 33324 /* RG16_EXT */, r: NORM16_COLOR_RENDERABLE },
2277
+ "rg16snorm": { gl: 36761 /* RG16_SNORM_EXT */, r: SNORM16_COLOR_RENDERABLE },
2182
2278
  "r32uint": { gl: 33334 /* R32UI */, rb: true },
2183
2279
  "r32sint": { gl: 33333 /* R32I */, rb: true },
2184
- "r32float": { gl: 33326 /* R32F */ },
2280
+ "r32float": { gl: 33326 /* R32F */, r: FLOAT32_COLOR_RENDERABLE },
2185
2281
  // Packed 32-bit formats
2186
- "rgb9e5ufloat": { gl: 35901 /* RGB9_E5 */ },
2282
+ "rgb9e5ufloat": { gl: 35901 /* RGB9_E5 */, r: RGB9E5UFLOAT_COLOR_RENDERABLE },
2187
2283
  // , filter: true},
2188
2284
  "rg11b10ufloat": { gl: 35898 /* R11F_G11F_B10F */, rb: true },
2189
2285
  "rgb10a2unorm": { gl: 32857 /* RGB10_A2 */, rb: true },
2190
2286
  "rgb10a2uint": { gl: 36975 /* RGB10_A2UI */, rb: true },
2191
2287
  // 48-bit formats
2192
- "rgb16unorm-webgl": { gl: 32852 /* RGB16_EXT */ },
2288
+ "rgb16unorm-webgl": { gl: 32852 /* RGB16_EXT */, r: false },
2193
2289
  // rgb not renderable
2194
- "rgb16snorm-webgl": { gl: 36762 /* RGB16_SNORM_EXT */ },
2290
+ "rgb16snorm-webgl": { gl: 36762 /* RGB16_SNORM_EXT */, r: false },
2195
2291
  // rgb not renderable
2196
2292
  // 64-bit formats
2197
2293
  "rg32uint": { gl: 33340 /* RG32UI */, rb: true },
2198
2294
  "rg32sint": { gl: 33339 /* RG32I */, rb: true },
2199
- "rg32float": { gl: 33328 /* RG32F */, rb: true },
2295
+ "rg32float": { gl: 33328 /* RG32F */, rb: true, r: FLOAT32_COLOR_RENDERABLE },
2200
2296
  "rgba16uint": { gl: 36214 /* RGBA16UI */, rb: true },
2201
2297
  "rgba16sint": { gl: 36232 /* RGBA16I */, rb: true },
2202
- "rgba16float": { gl: 34842 /* RGBA16F */ },
2203
- "rgba16unorm": { gl: 32859 /* RGBA16_EXT */, rb: true },
2204
- "rgba16snorm": { gl: 36763 /* RGBA16_SNORM_EXT */ },
2298
+ "rgba16float": { gl: 34842 /* RGBA16F */, r: FLOAT16_COLOR_RENDERABLE },
2299
+ "rgba16unorm": { gl: 32859 /* RGBA16_EXT */, rb: true, r: NORM16_COLOR_RENDERABLE },
2300
+ "rgba16snorm": { gl: 36763 /* RGBA16_SNORM_EXT */, r: SNORM16_COLOR_RENDERABLE },
2205
2301
  // 96-bit formats (deprecated!)
2206
- "rgb32float-webgl": { gl: 34837 /* RGB32F */, x: EXT_color_buffer_float, dataFormat: 6407 /* RGB */, types: [5126 /* FLOAT */] },
2302
+ "rgb32float-webgl": { gl: 34837 /* RGB32F */, x: EXT_color_buffer_float, r: FLOAT32_COLOR_RENDERABLE, dataFormat: 6407 /* RGB */, types: [5126 /* FLOAT */] },
2207
2303
  // 128-bit formats
2208
2304
  "rgba32uint": { gl: 36208 /* RGBA32UI */, rb: true },
2209
2305
  "rgba32sint": { gl: 36226 /* RGBA32I */, rb: true },
2210
- "rgba32float": { gl: 34836 /* RGBA32F */, rb: true },
2306
+ "rgba32float": { gl: 34836 /* RGBA32F */, rb: true, r: FLOAT32_COLOR_RENDERABLE },
2211
2307
  // Depth and stencil formats
2212
2308
  "stencil8": { gl: 36168 /* STENCIL_INDEX8 */, rb: true },
2213
2309
  // 8 stencil bits
@@ -2265,8 +2361,8 @@ var __exports__ = (() => {
2265
2361
  "astc-8x6-unorm-srgb": { gl: 37846 /* COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR */ },
2266
2362
  "astc-8x8-unorm": { gl: 37815 /* COMPRESSED_RGBA_ASTC_8x8_KHR */ },
2267
2363
  "astc-8x8-unorm-srgb": { gl: 37847 /* COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR */ },
2268
- "astc-10x5-unorm": { gl: 37819 /* COMPRESSED_RGBA_ASTC_10x10_KHR */ },
2269
- "astc-10x5-unorm-srgb": { gl: 37851 /* COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR */ },
2364
+ "astc-10x5-unorm": { gl: 37816 /* COMPRESSED_RGBA_ASTC_10x5_KHR */ },
2365
+ "astc-10x5-unorm-srgb": { gl: 37848 /* COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR */ },
2270
2366
  "astc-10x6-unorm": { gl: 37817 /* COMPRESSED_RGBA_ASTC_10x6_KHR */ },
2271
2367
  "astc-10x6-unorm-srgb": { gl: 37849 /* COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR */ },
2272
2368
  "astc-10x8-unorm": { gl: 37818 /* COMPRESSED_RGBA_ASTC_10x8_KHR */ },
@@ -2280,7 +2376,7 @@ var __exports__ = (() => {
2280
2376
  // WEBGL_compressed_texture_pvrtc
2281
2377
  "pvrtc-rgb4unorm-webgl": { gl: 35840 /* COMPRESSED_RGB_PVRTC_4BPPV1_IMG */ },
2282
2378
  "pvrtc-rgba4unorm-webgl": { gl: 35842 /* COMPRESSED_RGBA_PVRTC_4BPPV1_IMG */ },
2283
- "pvrtc-rbg2unorm-webgl": { gl: 35841 /* COMPRESSED_RGB_PVRTC_2BPPV1_IMG */ },
2379
+ "pvrtc-rgb2unorm-webgl": { gl: 35841 /* COMPRESSED_RGB_PVRTC_2BPPV1_IMG */ },
2284
2380
  "pvrtc-rgba2unorm-webgl": { gl: 35843 /* COMPRESSED_RGBA_PVRTC_2BPPV1_IMG */ },
2285
2381
  // WEBGL_compressed_texture_etc1
2286
2382
  "etc1-rbg-unorm-webgl": { gl: 36196 /* COMPRESSED_RGB_ETC1_WEBGL */ },
@@ -2304,12 +2400,11 @@ var __exports__ = (() => {
2304
2400
  // optional WebGPU features
2305
2401
  "depth-clip-control": "EXT_depth_clamp",
2306
2402
  // TODO these seem subtly different
2307
- // 'timestamp-query' // GPUQueryType "timestamp-query"
2403
+ "timestamp-query": "EXT_disjoint_timer_query_webgl2",
2308
2404
  // "indirect-first-instance"
2309
2405
  // Textures are handled by getTextureFeatures()
2310
2406
  // 'depth32float-stencil8' // GPUTextureFormat 'depth32float-stencil8'
2311
2407
  // optional WebGL features
2312
- "timer-query-webgl": "EXT_disjoint_timer_query_webgl2",
2313
2408
  "compilation-status-async-webgl": "KHR_parallel_shader_compile",
2314
2409
  "polygon-mode-webgl": "WEBGL_polygon_mode",
2315
2410
  "provoking-vertex-webgl": "WEBGL_provoking_vertex",
@@ -2654,6 +2749,65 @@ var __exports__ = (() => {
2654
2749
  }
2655
2750
  });
2656
2751
 
2752
+ // src/adapter/webgl-presentation-context.ts
2753
+ var import_core8, WebGLPresentationContext;
2754
+ var init_webgl_presentation_context = __esm({
2755
+ "src/adapter/webgl-presentation-context.ts"() {
2756
+ "use strict";
2757
+ import_core8 = __toESM(require_core(), 1);
2758
+ WebGLPresentationContext = class extends import_core8.PresentationContext {
2759
+ device;
2760
+ handle = null;
2761
+ context2d;
2762
+ get [Symbol.toStringTag]() {
2763
+ return "WebGLPresentationContext";
2764
+ }
2765
+ constructor(device, props = {}) {
2766
+ super(props);
2767
+ this.device = device;
2768
+ const contextLabel = `${this[Symbol.toStringTag]}(${this.id})`;
2769
+ const defaultCanvasContext = this.device.getDefaultCanvasContext();
2770
+ if (!defaultCanvasContext.offscreenCanvas) {
2771
+ throw new Error(
2772
+ `${contextLabel}: WebGL PresentationContext requires the default CanvasContext canvas to be an OffscreenCanvas`
2773
+ );
2774
+ }
2775
+ const context2d = this.canvas.getContext("2d");
2776
+ if (!context2d) {
2777
+ throw new Error(`${contextLabel}: Failed to create 2d presentation context`);
2778
+ }
2779
+ this.context2d = context2d;
2780
+ this._setAutoCreatedCanvasId(`${this.device.id}-presentation-canvas`);
2781
+ this._configureDevice();
2782
+ this._startObservers();
2783
+ }
2784
+ present() {
2785
+ this._resizeDrawingBufferIfNeeded();
2786
+ this.device.submit();
2787
+ const defaultCanvasContext = this.device.getDefaultCanvasContext();
2788
+ const [sourceWidth, sourceHeight] = defaultCanvasContext.getDrawingBufferSize();
2789
+ if (this.drawingBufferWidth === 0 || this.drawingBufferHeight === 0 || sourceWidth === 0 || sourceHeight === 0 || defaultCanvasContext.canvas.width === 0 || defaultCanvasContext.canvas.height === 0) {
2790
+ return;
2791
+ }
2792
+ if (sourceWidth !== this.drawingBufferWidth || sourceHeight !== this.drawingBufferHeight || defaultCanvasContext.canvas.width !== this.drawingBufferWidth || defaultCanvasContext.canvas.height !== this.drawingBufferHeight) {
2793
+ throw new Error(
2794
+ `${this[Symbol.toStringTag]}(${this.id}): Default canvas context size ${sourceWidth}x${sourceHeight} does not match presentation size ${this.drawingBufferWidth}x${this.drawingBufferHeight}`
2795
+ );
2796
+ }
2797
+ this.context2d.clearRect(0, 0, this.drawingBufferWidth, this.drawingBufferHeight);
2798
+ this.context2d.drawImage(defaultCanvasContext.canvas, 0, 0);
2799
+ }
2800
+ _configureDevice() {
2801
+ }
2802
+ _getCurrentFramebuffer(options) {
2803
+ const defaultCanvasContext = this.device.getDefaultCanvasContext();
2804
+ defaultCanvasContext.setDrawingBufferSize(this.drawingBufferWidth, this.drawingBufferHeight);
2805
+ return defaultCanvasContext.getCurrentFramebuffer(options);
2806
+ }
2807
+ };
2808
+ }
2809
+ });
2810
+
2657
2811
  // src/utils/uid.ts
2658
2812
  function uid(id = "id") {
2659
2813
  uidCounters[id] = uidCounters[id] || 1;
@@ -2670,35 +2824,35 @@ var __exports__ = (() => {
2670
2824
 
2671
2825
  // src/adapter/resources/webgl-buffer.ts
2672
2826
  function getWebGLTarget(usage) {
2673
- if (usage & import_core8.Buffer.INDEX) {
2827
+ if (usage & import_core9.Buffer.INDEX) {
2674
2828
  return 34963 /* ELEMENT_ARRAY_BUFFER */;
2675
2829
  }
2676
- if (usage & import_core8.Buffer.VERTEX) {
2830
+ if (usage & import_core9.Buffer.VERTEX) {
2677
2831
  return 34962 /* ARRAY_BUFFER */;
2678
2832
  }
2679
- if (usage & import_core8.Buffer.UNIFORM) {
2833
+ if (usage & import_core9.Buffer.UNIFORM) {
2680
2834
  return 35345 /* UNIFORM_BUFFER */;
2681
2835
  }
2682
2836
  return 34962 /* ARRAY_BUFFER */;
2683
2837
  }
2684
2838
  function getWebGLUsage(usage) {
2685
- if (usage & import_core8.Buffer.INDEX) {
2839
+ if (usage & import_core9.Buffer.INDEX) {
2686
2840
  return 35044 /* STATIC_DRAW */;
2687
2841
  }
2688
- if (usage & import_core8.Buffer.VERTEX) {
2842
+ if (usage & import_core9.Buffer.VERTEX) {
2689
2843
  return 35044 /* STATIC_DRAW */;
2690
2844
  }
2691
- if (usage & import_core8.Buffer.UNIFORM) {
2845
+ if (usage & import_core9.Buffer.UNIFORM) {
2692
2846
  return 35048 /* DYNAMIC_DRAW */;
2693
2847
  }
2694
2848
  return 35044 /* STATIC_DRAW */;
2695
2849
  }
2696
- var import_core8, WEBGLBuffer;
2850
+ var import_core9, WEBGLBuffer;
2697
2851
  var init_webgl_buffer = __esm({
2698
2852
  "src/adapter/resources/webgl-buffer.ts"() {
2699
2853
  "use strict";
2700
- import_core8 = __toESM(require_core(), 1);
2701
- WEBGLBuffer = class extends import_core8.Buffer {
2854
+ import_core9 = __toESM(require_core(), 1);
2855
+ WEBGLBuffer = class extends import_core9.Buffer {
2702
2856
  device;
2703
2857
  gl;
2704
2858
  handle;
@@ -2733,8 +2887,12 @@ var __exports__ = (() => {
2733
2887
  destroy() {
2734
2888
  if (!this.destroyed && this.handle) {
2735
2889
  this.removeStats();
2736
- this.trackDeallocatedMemory();
2737
- this.gl.deleteBuffer(this.handle);
2890
+ if (!this.props.handle) {
2891
+ this.trackDeallocatedMemory();
2892
+ this.gl.deleteBuffer(this.handle);
2893
+ } else {
2894
+ this.trackDeallocatedReferencedMemory("Buffer");
2895
+ }
2738
2896
  this.destroyed = true;
2739
2897
  this.handle = null;
2740
2898
  }
@@ -2749,7 +2907,11 @@ var __exports__ = (() => {
2749
2907
  this.bytesUsed = byteLength;
2750
2908
  this.byteLength = byteLength;
2751
2909
  this._setDebugData(data, byteOffset, byteLength);
2752
- this.trackAllocatedMemory(byteLength);
2910
+ if (!this.props.handle) {
2911
+ this.trackAllocatedMemory(byteLength);
2912
+ } else {
2913
+ this.trackReferencedMemory(byteLength, "Buffer");
2914
+ }
2753
2915
  }
2754
2916
  // Allocate a GPU buffer of specified size.
2755
2917
  _initWithByteLength(byteLength) {
@@ -2764,7 +2926,11 @@ var __exports__ = (() => {
2764
2926
  this.bytesUsed = byteLength;
2765
2927
  this.byteLength = byteLength;
2766
2928
  this._setDebugData(null, 0, byteLength);
2767
- this.trackAllocatedMemory(byteLength);
2929
+ if (!this.props.handle) {
2930
+ this.trackAllocatedMemory(byteLength);
2931
+ } else {
2932
+ this.trackReferencedMemory(byteLength, "Buffer");
2933
+ }
2768
2934
  return this;
2769
2935
  }
2770
2936
  write(data, byteOffset = 0) {
@@ -2815,9 +2981,20 @@ var __exports__ = (() => {
2815
2981
  if (line.length <= 1) {
2816
2982
  continue;
2817
2983
  }
2984
+ const lineWithTrimmedWhitespace = line.trim();
2818
2985
  const segments = line.split(":");
2986
+ const trimmedMessageType = segments[0]?.trim();
2819
2987
  if (segments.length === 2) {
2820
2988
  const [messageType2, message2] = segments;
2989
+ if (!messageType2 || !message2) {
2990
+ messages.push({
2991
+ message: lineWithTrimmedWhitespace,
2992
+ type: getMessageType(trimmedMessageType || "info"),
2993
+ lineNum: 0,
2994
+ linePos: 0
2995
+ });
2996
+ continue;
2997
+ }
2821
2998
  messages.push({
2822
2999
  message: message2.trim(),
2823
3000
  type: getMessageType(messageType2),
@@ -2827,6 +3004,15 @@ var __exports__ = (() => {
2827
3004
  continue;
2828
3005
  }
2829
3006
  const [messageType, linePosition, lineNumber, ...rest] = segments;
3007
+ if (!messageType || !linePosition || !lineNumber) {
3008
+ messages.push({
3009
+ message: segments.slice(1).join(":").trim() || lineWithTrimmedWhitespace,
3010
+ type: getMessageType(trimmedMessageType || "info"),
3011
+ lineNum: 0,
3012
+ linePos: 0
3013
+ });
3014
+ continue;
3015
+ }
2830
3016
  let lineNum = parseInt(lineNumber, 10);
2831
3017
  if (isNaN(lineNum)) {
2832
3018
  lineNum = 0;
@@ -2857,13 +3043,13 @@ var __exports__ = (() => {
2857
3043
  });
2858
3044
 
2859
3045
  // src/adapter/resources/webgl-shader.ts
2860
- var import_core9, WEBGLShader;
3046
+ var import_core10, WEBGLShader;
2861
3047
  var init_webgl_shader = __esm({
2862
3048
  "src/adapter/resources/webgl-shader.ts"() {
2863
3049
  "use strict";
2864
- import_core9 = __toESM(require_core(), 1);
3050
+ import_core10 = __toESM(require_core(), 1);
2865
3051
  init_parse_shader_compiler_log();
2866
- WEBGLShader = class extends import_core9.Shader {
3052
+ WEBGLShader = class extends import_core10.Shader {
2867
3053
  device;
2868
3054
  handle;
2869
3055
  constructor(device, props) {
@@ -2929,9 +3115,9 @@ ${source}`;
2929
3115
  }
2930
3116
  return;
2931
3117
  }
2932
- import_core9.log.once(1, "Shader compilation is asynchronous")();
3118
+ import_core10.log.once(1, "Shader compilation is asynchronous")();
2933
3119
  await this._waitForCompilationComplete();
2934
- import_core9.log.info(2, `Shader ${this.id} - async compilation complete: ${this.compilationStatus}`)();
3120
+ import_core10.log.info(2, `Shader ${this.id} - async compilation complete: ${this.compilationStatus}`)();
2935
3121
  this._getCompilationStatus();
2936
3122
  this.debugShader();
2937
3123
  }
@@ -3098,7 +3284,7 @@ ${source}`;
3098
3284
  gl.stencilMaskSeparate(1029 /* BACK */, mask);
3099
3285
  }
3100
3286
  if (parameters.stencilReadMask) {
3101
- import_core10.log.warn("stencilReadMask not supported under WebGL");
3287
+ import_core11.log.warn("stencilReadMask not supported under WebGL");
3102
3288
  }
3103
3289
  if (parameters.stencilCompare) {
3104
3290
  const mask = parameters.stencilReadMask || 4294967295;
@@ -3232,11 +3418,11 @@ ${source}`;
3232
3418
  }
3233
3419
  return isEmpty;
3234
3420
  }
3235
- var import_core10;
3421
+ var import_core11;
3236
3422
  var init_device_parameters = __esm({
3237
3423
  "src/adapter/converters/device-parameters.ts"() {
3238
3424
  "use strict";
3239
- import_core10 = __toESM(require_core(), 1);
3425
+ import_core11 = __toESM(require_core(), 1);
3240
3426
  init_unified_parameter_api();
3241
3427
  }
3242
3428
  });
@@ -3329,13 +3515,13 @@ ${source}`;
3329
3515
  });
3330
3516
 
3331
3517
  // src/adapter/resources/webgl-sampler.ts
3332
- var import_core11, WEBGLSampler;
3518
+ var import_core12, WEBGLSampler;
3333
3519
  var init_webgl_sampler = __esm({
3334
3520
  "src/adapter/resources/webgl-sampler.ts"() {
3335
3521
  "use strict";
3336
- import_core11 = __toESM(require_core(), 1);
3522
+ import_core12 = __toESM(require_core(), 1);
3337
3523
  init_sampler_parameters();
3338
- WEBGLSampler = class extends import_core11.Sampler {
3524
+ WEBGLSampler = class extends import_core12.Sampler {
3339
3525
  device;
3340
3526
  handle;
3341
3527
  parameters;
@@ -3411,19 +3597,19 @@ ${source}`;
3411
3597
  });
3412
3598
 
3413
3599
  // src/adapter/resources/webgl-texture-view.ts
3414
- var import_core12, WEBGLTextureView;
3600
+ var import_core13, WEBGLTextureView;
3415
3601
  var init_webgl_texture_view = __esm({
3416
3602
  "src/adapter/resources/webgl-texture-view.ts"() {
3417
3603
  "use strict";
3418
- import_core12 = __toESM(require_core(), 1);
3419
- WEBGLTextureView = class extends import_core12.TextureView {
3604
+ import_core13 = __toESM(require_core(), 1);
3605
+ WEBGLTextureView = class extends import_core13.TextureView {
3420
3606
  device;
3421
3607
  gl;
3422
3608
  handle;
3423
3609
  // Does not have a WebGL representation
3424
3610
  texture;
3425
3611
  constructor(device, props) {
3426
- super(device, { ...import_core12.Texture.defaultProps, ...props });
3612
+ super(device, { ...import_core13.Texture.defaultProps, ...props });
3427
3613
  this.device = device;
3428
3614
  this.gl = this.device.gl;
3429
3615
  this.handle = null;
@@ -3433,98 +3619,6 @@ ${source}`;
3433
3619
  }
3434
3620
  });
3435
3621
 
3436
- // src/adapter/converters/webgl-shadertypes.ts
3437
- function convertDataTypeToGLDataType(normalizedType) {
3438
- return NORMALIZED_SHADER_TYPE_TO_WEBGL[normalizedType];
3439
- }
3440
- function convertGLUniformTypeToShaderVariableType(glUniformType) {
3441
- return WEBGL_SHADER_TYPES[glUniformType];
3442
- }
3443
- function isGLSamplerType(type) {
3444
- return Boolean(WEBGL_SAMPLER_TO_TEXTURE_BINDINGS[type]);
3445
- }
3446
- function getTextureBindingFromGLSamplerType(glSamplerType) {
3447
- return WEBGL_SAMPLER_TO_TEXTURE_BINDINGS[glSamplerType];
3448
- }
3449
- var WEBGL_SHADER_TYPES, WEBGL_SAMPLER_TO_TEXTURE_BINDINGS, NORMALIZED_SHADER_TYPE_TO_WEBGL, WEBGL_TO_NORMALIZED_DATA_TYPE;
3450
- var init_webgl_shadertypes = __esm({
3451
- "src/adapter/converters/webgl-shadertypes.ts"() {
3452
- "use strict";
3453
- WEBGL_SHADER_TYPES = {
3454
- [5126 /* FLOAT */]: "f32",
3455
- [35664 /* FLOAT_VEC2 */]: "vec2<f32>",
3456
- [35665 /* FLOAT_VEC3 */]: "vec3<f32>",
3457
- [35666 /* FLOAT_VEC4 */]: "vec4<f32>",
3458
- [5124 /* INT */]: "i32",
3459
- [35667 /* INT_VEC2 */]: "vec2<i32>",
3460
- [35668 /* INT_VEC3 */]: "vec3<i32>",
3461
- [35669 /* INT_VEC4 */]: "vec4<i32>",
3462
- [5125 /* UNSIGNED_INT */]: "u32",
3463
- [36294 /* UNSIGNED_INT_VEC2 */]: "vec2<u32>",
3464
- [36295 /* UNSIGNED_INT_VEC3 */]: "vec3<u32>",
3465
- [36296 /* UNSIGNED_INT_VEC4 */]: "vec4<u32>",
3466
- [35670 /* BOOL */]: "f32",
3467
- [35671 /* BOOL_VEC2 */]: "vec2<f32>",
3468
- [35672 /* BOOL_VEC3 */]: "vec3<f32>",
3469
- [35673 /* BOOL_VEC4 */]: "vec4<f32>",
3470
- // TODO - are sizes/components below correct?
3471
- [35674 /* FLOAT_MAT2 */]: "mat2x2<f32>",
3472
- [35685 /* FLOAT_MAT2x3 */]: "mat2x3<f32>",
3473
- [35686 /* FLOAT_MAT2x4 */]: "mat2x4<f32>",
3474
- [35687 /* FLOAT_MAT3x2 */]: "mat3x2<f32>",
3475
- [35675 /* FLOAT_MAT3 */]: "mat3x3<f32>",
3476
- [35688 /* FLOAT_MAT3x4 */]: "mat3x4<f32>",
3477
- [35689 /* FLOAT_MAT4x2 */]: "mat4x2<f32>",
3478
- [35690 /* FLOAT_MAT4x3 */]: "mat4x3<f32>",
3479
- [35676 /* FLOAT_MAT4 */]: "mat4x4<f32>"
3480
- };
3481
- WEBGL_SAMPLER_TO_TEXTURE_BINDINGS = {
3482
- [35678 /* SAMPLER_2D */]: { viewDimension: "2d", sampleType: "float" },
3483
- [35680 /* SAMPLER_CUBE */]: { viewDimension: "cube", sampleType: "float" },
3484
- [35679 /* SAMPLER_3D */]: { viewDimension: "3d", sampleType: "float" },
3485
- [35682 /* SAMPLER_2D_SHADOW */]: { viewDimension: "3d", sampleType: "depth" },
3486
- [36289 /* SAMPLER_2D_ARRAY */]: { viewDimension: "2d-array", sampleType: "float" },
3487
- [36292 /* SAMPLER_2D_ARRAY_SHADOW */]: { viewDimension: "2d-array", sampleType: "depth" },
3488
- [36293 /* SAMPLER_CUBE_SHADOW */]: { viewDimension: "cube", sampleType: "float" },
3489
- [36298 /* INT_SAMPLER_2D */]: { viewDimension: "2d", sampleType: "sint" },
3490
- [36299 /* INT_SAMPLER_3D */]: { viewDimension: "3d", sampleType: "sint" },
3491
- [36300 /* INT_SAMPLER_CUBE */]: { viewDimension: "cube", sampleType: "sint" },
3492
- [36303 /* INT_SAMPLER_2D_ARRAY */]: { viewDimension: "2d-array", sampleType: "uint" },
3493
- [36306 /* UNSIGNED_INT_SAMPLER_2D */]: { viewDimension: "2d", sampleType: "uint" },
3494
- [36307 /* UNSIGNED_INT_SAMPLER_3D */]: { viewDimension: "3d", sampleType: "uint" },
3495
- [36308 /* UNSIGNED_INT_SAMPLER_CUBE */]: { viewDimension: "cube", sampleType: "uint" },
3496
- [36311 /* UNSIGNED_INT_SAMPLER_2D_ARRAY */]: { viewDimension: "2d-array", sampleType: "uint" }
3497
- };
3498
- NORMALIZED_SHADER_TYPE_TO_WEBGL = {
3499
- uint8: 5121 /* UNSIGNED_BYTE */,
3500
- sint8: 5120 /* BYTE */,
3501
- unorm8: 5121 /* UNSIGNED_BYTE */,
3502
- snorm8: 5120 /* BYTE */,
3503
- uint16: 5123 /* UNSIGNED_SHORT */,
3504
- sint16: 5122 /* SHORT */,
3505
- unorm16: 5123 /* UNSIGNED_SHORT */,
3506
- snorm16: 5122 /* SHORT */,
3507
- uint32: 5125 /* UNSIGNED_INT */,
3508
- sint32: 5124 /* INT */,
3509
- // WebGPU does not support normalized 32 bit integer attributes
3510
- // 'unorm32': GL.UNSIGNED_INT,
3511
- // 'snorm32': GL.INT,
3512
- float16: 5131 /* HALF_FLOAT */,
3513
- float32: 5126 /* FLOAT */
3514
- };
3515
- WEBGL_TO_NORMALIZED_DATA_TYPE = {
3516
- [5120 /* BYTE */]: ["sint8", "snorm16"],
3517
- [5121 /* UNSIGNED_BYTE */]: ["uint8", "unorm8"],
3518
- [5122 /* SHORT */]: ["sint16", "unorm16"],
3519
- [5123 /* UNSIGNED_SHORT */]: ["uint16", "unorm16"],
3520
- [5124 /* INT */]: ["sint32", "sint32"],
3521
- [5125 /* UNSIGNED_INT */]: ["uint32", "uint32"],
3522
- [5126 /* FLOAT */]: ["float32", "float32"],
3523
- [5131 /* HALF_FLOAT */]: ["float16", "float16"]
3524
- };
3525
- }
3526
- });
3527
-
3528
3622
  // src/adapter/converters/shader-formats.ts
3529
3623
  function convertGLDataTypeToDataType(type) {
3530
3624
  return GL_DATA_TYPE_MAP[type];
@@ -3555,6 +3649,24 @@ ${source}`;
3555
3649
  });
3556
3650
 
3557
3651
  // src/adapter/resources/webgl-texture.ts
3652
+ function getArrayBufferView(typedArray, byteOffset = 0) {
3653
+ if (!byteOffset) {
3654
+ return typedArray;
3655
+ }
3656
+ return new typedArray.constructor(
3657
+ typedArray.buffer,
3658
+ typedArray.byteOffset + byteOffset,
3659
+ (typedArray.byteLength - byteOffset) / typedArray.BYTES_PER_ELEMENT
3660
+ );
3661
+ }
3662
+ function getWebGLTextureSourceElementOffset(typedArray, byteOffset) {
3663
+ if (byteOffset % typedArray.BYTES_PER_ELEMENT !== 0) {
3664
+ throw new Error(
3665
+ `Texture byteOffset ${byteOffset} must align to typed array element size ${typedArray.BYTES_PER_ELEMENT}`
3666
+ );
3667
+ }
3668
+ return byteOffset / typedArray.BYTES_PER_ELEMENT;
3669
+ }
3558
3670
  function getWebGLTextureTarget(dimension) {
3559
3671
  switch (dimension) {
3560
3672
  case "1d":
@@ -3575,19 +3687,18 @@ ${source}`;
3575
3687
  function getWebGLCubeFaceTarget(glTarget, dimension, level) {
3576
3688
  return dimension === "cube" ? 34069 /* TEXTURE_CUBE_MAP_POSITIVE_X */ + level : glTarget;
3577
3689
  }
3578
- var import_core13, import_core14, WEBGLTexture;
3690
+ var import_core14, import_core15, WEBGLTexture;
3579
3691
  var init_webgl_texture = __esm({
3580
3692
  "src/adapter/resources/webgl-texture.ts"() {
3581
3693
  "use strict";
3582
- import_core13 = __toESM(require_core(), 1);
3694
+ import_core14 = __toESM(require_core(), 1);
3583
3695
  init_webgl_texture_table();
3584
3696
  init_sampler_parameters();
3585
3697
  init_with_parameters();
3586
3698
  init_webgl_texture_view();
3587
- init_webgl_shadertypes();
3588
3699
  init_shader_formats();
3589
- import_core14 = __toESM(require_core(), 1);
3590
- WEBGLTexture = class extends import_core13.Texture {
3700
+ import_core15 = __toESM(require_core(), 1);
3701
+ WEBGLTexture = class extends import_core14.Texture {
3591
3702
  // readonly MAX_ATTRIBUTES: number;
3592
3703
  device;
3593
3704
  gl;
@@ -3616,8 +3727,10 @@ ${source}`;
3616
3727
  // state
3617
3728
  /** Texture binding slot - TODO - move to texture view? */
3618
3729
  _textureUnit = 0;
3619
- /** Chached framebuffer */
3730
+ /** Cached framebuffer reused for color texture readback. */
3620
3731
  _framebuffer = null;
3732
+ /** Cache key for the currently attached readback subresource `${mipLevel}:${layer}`. */
3733
+ _framebufferAttachmentKey = null;
3621
3734
  constructor(device, props) {
3622
3735
  super(device, props, { byteAlignment: 1 });
3623
3736
  this.device = device;
@@ -3632,20 +3745,27 @@ ${source}`;
3632
3745
  this.device._setWebGLDebugMetadata(this.handle, this, { spector: this.props });
3633
3746
  this.gl.bindTexture(this.glTarget, this.handle);
3634
3747
  const { dimension, width, height, depth, mipLevels, glTarget, glInternalFormat } = this;
3635
- switch (dimension) {
3636
- case "2d":
3637
- case "cube":
3638
- this.gl.texStorage2D(glTarget, mipLevels, glInternalFormat, width, height);
3639
- break;
3640
- case "2d-array":
3641
- case "3d":
3642
- this.gl.texStorage3D(glTarget, mipLevels, glInternalFormat, width, height, depth);
3643
- break;
3644
- default:
3645
- throw new Error(dimension);
3748
+ if (!this.compressed) {
3749
+ switch (dimension) {
3750
+ case "2d":
3751
+ case "cube":
3752
+ this.gl.texStorage2D(glTarget, mipLevels, glInternalFormat, width, height);
3753
+ break;
3754
+ case "2d-array":
3755
+ case "3d":
3756
+ this.gl.texStorage3D(glTarget, mipLevels, glInternalFormat, width, height, depth);
3757
+ break;
3758
+ default:
3759
+ throw new Error(dimension);
3760
+ }
3646
3761
  }
3647
3762
  this.gl.bindTexture(this.glTarget, null);
3648
3763
  this._initializeData(props.data);
3764
+ if (!this.props.handle) {
3765
+ this.trackAllocatedMemory(this.getAllocatedByteLength(), "Texture");
3766
+ } else {
3767
+ this.trackReferencedMemory(this.getAllocatedByteLength(), "Texture");
3768
+ }
3649
3769
  this.setSampler(this.props.sampler);
3650
3770
  this.view = new WEBGLTextureView(this.device, { ...this.props, texture: this });
3651
3771
  Object.seal(this);
@@ -3654,9 +3774,14 @@ ${source}`;
3654
3774
  if (this.handle) {
3655
3775
  this._framebuffer?.destroy();
3656
3776
  this._framebuffer = null;
3657
- this.gl.deleteTexture(this.handle);
3777
+ this._framebufferAttachmentKey = null;
3658
3778
  this.removeStats();
3659
- this.trackDeallocatedMemory("Texture");
3779
+ if (!this.props.handle) {
3780
+ this.gl.deleteTexture(this.handle);
3781
+ this.trackDeallocatedMemory("Texture");
3782
+ } else {
3783
+ this.trackDeallocatedReferencedMemory("Texture");
3784
+ }
3660
3785
  this.destroyed = true;
3661
3786
  }
3662
3787
  }
@@ -3695,99 +3820,180 @@ ${source}`;
3695
3820
  return { width: options.width, height: options.height };
3696
3821
  }
3697
3822
  copyImageData(options_) {
3698
- const options = this._normalizeCopyImageDataOptions(options_);
3699
- const typedArray = options.data;
3700
- const { width, height, depth, z = 0 } = options;
3701
- const { mipLevel = 0, byteOffset = 0, x = 0, y = 0 } = options;
3823
+ super.copyImageData(options_);
3824
+ }
3825
+ /**
3826
+ * Reads a color texture subresource into a GPU buffer using `PIXEL_PACK_BUFFER`.
3827
+ *
3828
+ * @note Only first-pass color readback is supported. Unsupported formats and aspects throw
3829
+ * before any WebGL calls are issued.
3830
+ */
3831
+ readBuffer(options = {}, buffer) {
3832
+ const normalizedOptions = this._getSupportedColorReadOptions(options);
3833
+ const memoryLayout = this.computeMemoryLayout(normalizedOptions);
3834
+ const readBuffer = buffer || this.device.createBuffer({
3835
+ byteLength: memoryLayout.byteLength,
3836
+ usage: import_core14.Buffer.COPY_DST | import_core14.Buffer.MAP_READ
3837
+ });
3838
+ if (readBuffer.byteLength < memoryLayout.byteLength) {
3839
+ throw new Error(
3840
+ `${this} readBuffer target is too small (${readBuffer.byteLength} < ${memoryLayout.byteLength})`
3841
+ );
3842
+ }
3843
+ const webglBuffer = readBuffer;
3844
+ this.gl.bindBuffer(35051 /* PIXEL_PACK_BUFFER */, webglBuffer.handle);
3845
+ try {
3846
+ this._readColorTextureLayers(normalizedOptions, memoryLayout, (destinationByteOffset) => {
3847
+ this.gl.readPixels(
3848
+ normalizedOptions.x,
3849
+ normalizedOptions.y,
3850
+ normalizedOptions.width,
3851
+ normalizedOptions.height,
3852
+ this.glFormat,
3853
+ this.glType,
3854
+ destinationByteOffset
3855
+ );
3856
+ });
3857
+ } finally {
3858
+ this.gl.bindBuffer(35051 /* PIXEL_PACK_BUFFER */, null);
3859
+ }
3860
+ return readBuffer;
3861
+ }
3862
+ async readDataAsync(options = {}) {
3863
+ const buffer = this.readBuffer(options);
3864
+ const data = await buffer.readAsync();
3865
+ buffer.destroy();
3866
+ return data.buffer;
3867
+ }
3868
+ writeBuffer(buffer, options_ = {}) {
3869
+ const options = this._normalizeTextureWriteOptions(options_);
3870
+ const { width, height, depthOrArrayLayers, mipLevel, byteOffset, x, y, z } = options;
3702
3871
  const { glFormat, glType, compressed } = this;
3703
3872
  const glTarget = getWebGLCubeFaceTarget(this.glTarget, this.dimension, z);
3704
- let unpackRowLength;
3705
- if (!this.compressed) {
3706
- const { bytesPerPixel } = this.device.getTextureFormatInfo(this.format);
3707
- if (bytesPerPixel) {
3708
- if (options.bytesPerRow % bytesPerPixel !== 0) {
3709
- throw new Error(
3710
- `bytesPerRow (${options.bytesPerRow}) must be a multiple of bytesPerPixel (${bytesPerPixel}) for ${this.format}`
3711
- );
3712
- }
3713
- unpackRowLength = options.bytesPerRow / bytesPerPixel;
3714
- }
3873
+ if (compressed) {
3874
+ throw new Error("writeBuffer for compressed textures is not implemented in WebGL");
3715
3875
  }
3716
- const glParameters = !this.compressed ? {
3876
+ const { bytesPerPixel } = this.device.getTextureFormatInfo(this.format);
3877
+ const unpackRowLength = bytesPerPixel ? options.bytesPerRow / bytesPerPixel : void 0;
3878
+ const glParameters = {
3717
3879
  [3317 /* UNPACK_ALIGNMENT */]: this.byteAlignment,
3718
3880
  ...unpackRowLength !== void 0 ? { [3314 /* UNPACK_ROW_LENGTH */]: unpackRowLength } : {},
3719
3881
  [32878 /* UNPACK_IMAGE_HEIGHT */]: options.rowsPerImage
3720
- } : {};
3882
+ };
3721
3883
  this.gl.bindTexture(this.glTarget, this.handle);
3884
+ this.gl.bindBuffer(35052 /* PIXEL_UNPACK_BUFFER */, buffer.handle);
3722
3885
  withGLParameters(this.gl, glParameters, () => {
3723
3886
  switch (this.dimension) {
3724
3887
  case "2d":
3725
3888
  case "cube":
3726
- if (compressed) {
3727
- this.gl.compressedTexSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, typedArray, byteOffset);
3728
- } else {
3729
- this.gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, typedArray, byteOffset);
3730
- }
3889
+ this.gl.texSubImage2D(
3890
+ glTarget,
3891
+ mipLevel,
3892
+ x,
3893
+ y,
3894
+ width,
3895
+ height,
3896
+ glFormat,
3897
+ glType,
3898
+ byteOffset
3899
+ );
3731
3900
  break;
3732
3901
  case "2d-array":
3733
3902
  case "3d":
3734
- if (compressed) {
3735
- this.gl.compressedTexSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, typedArray, byteOffset);
3736
- } else {
3737
- this.gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, typedArray, byteOffset);
3738
- }
3903
+ this.gl.texSubImage3D(
3904
+ glTarget,
3905
+ mipLevel,
3906
+ x,
3907
+ y,
3908
+ z,
3909
+ width,
3910
+ height,
3911
+ depthOrArrayLayers,
3912
+ glFormat,
3913
+ glType,
3914
+ byteOffset
3915
+ );
3739
3916
  break;
3740
3917
  default:
3741
3918
  }
3742
3919
  });
3920
+ this.gl.bindBuffer(35052 /* PIXEL_UNPACK_BUFFER */, null);
3743
3921
  this.gl.bindTexture(this.glTarget, null);
3744
3922
  }
3745
- readBuffer(options = {}, buffer) {
3746
- throw new Error("readBuffer not implemented");
3747
- }
3748
- async readDataAsync(options = {}) {
3749
- return this.readDataSyncWebGL(options);
3750
- }
3751
- writeBuffer(buffer, options_ = {}) {
3752
- }
3753
3923
  writeData(data, options_ = {}) {
3754
3924
  const options = this._normalizeTextureWriteOptions(options_);
3755
3925
  const typedArray = ArrayBuffer.isView(data) ? data : new Uint8Array(data);
3756
- const {} = this;
3757
- const { width, height, mipLevel, x, y, z } = options;
3926
+ const { width, height, depthOrArrayLayers, mipLevel, x, y, z, byteOffset } = options;
3758
3927
  const { glFormat, glType, compressed } = this;
3759
- const depth = 0;
3760
- const glTarget = getWebGLCubeFaceTarget(this.glTarget, this.dimension, depth);
3761
- const glParameters = !this.compressed ? {
3762
- // WebGL does not require byte alignment, but allows it to be specified
3763
- [3317 /* UNPACK_ALIGNMENT */]: this.byteAlignment
3764
- // [GL.UNPACK_ROW_LENGTH]: bytesPerRow,
3765
- // [GL.UNPACK_IMAGE_HEIGHT]: rowsPerImage
3766
- } : {};
3767
- this.gl.bindTexture(glTarget, this.handle);
3768
- this.gl.bindBuffer(35052 /* PIXEL_UNPACK_BUFFER */, null);
3928
+ const glTarget = getWebGLCubeFaceTarget(this.glTarget, this.dimension, z);
3929
+ let unpackRowLength;
3930
+ if (!compressed) {
3931
+ const { bytesPerPixel } = this.device.getTextureFormatInfo(this.format);
3932
+ if (bytesPerPixel) {
3933
+ unpackRowLength = options.bytesPerRow / bytesPerPixel;
3934
+ }
3935
+ }
3936
+ const glParameters = !this.compressed ? {
3937
+ [3317 /* UNPACK_ALIGNMENT */]: this.byteAlignment,
3938
+ ...unpackRowLength !== void 0 ? { [3314 /* UNPACK_ROW_LENGTH */]: unpackRowLength } : {},
3939
+ [32878 /* UNPACK_IMAGE_HEIGHT */]: options.rowsPerImage
3940
+ } : {};
3941
+ const sourceElementOffset = getWebGLTextureSourceElementOffset(typedArray, byteOffset);
3942
+ const compressedData = compressed ? getArrayBufferView(typedArray, byteOffset) : typedArray;
3943
+ const mipLevelSize = this._getMipLevelSize(mipLevel);
3944
+ const isFullMipUpload = x === 0 && y === 0 && z === 0 && width === mipLevelSize.width && height === mipLevelSize.height && depthOrArrayLayers === mipLevelSize.depthOrArrayLayers;
3945
+ this.gl.bindTexture(this.glTarget, this.handle);
3946
+ this.gl.bindBuffer(35052 /* PIXEL_UNPACK_BUFFER */, null);
3769
3947
  withGLParameters(this.gl, glParameters, () => {
3770
3948
  switch (this.dimension) {
3771
3949
  case "2d":
3772
3950
  case "cube":
3773
3951
  if (compressed) {
3774
- this.gl.compressedTexSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, typedArray);
3952
+ if (isFullMipUpload) {
3953
+ this.gl.compressedTexImage2D(glTarget, mipLevel, glFormat, width, height, 0, compressedData);
3954
+ } else {
3955
+ this.gl.compressedTexSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, compressedData);
3956
+ }
3775
3957
  } else {
3776
- this.gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, typedArray);
3958
+ this.gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, typedArray, sourceElementOffset);
3777
3959
  }
3778
3960
  break;
3779
3961
  case "2d-array":
3780
3962
  case "3d":
3781
3963
  if (compressed) {
3782
- this.gl.compressedTexSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, typedArray);
3964
+ if (isFullMipUpload) {
3965
+ this.gl.compressedTexImage3D(
3966
+ glTarget,
3967
+ mipLevel,
3968
+ glFormat,
3969
+ width,
3970
+ height,
3971
+ depthOrArrayLayers,
3972
+ 0,
3973
+ compressedData
3974
+ );
3975
+ } else {
3976
+ this.gl.compressedTexSubImage3D(
3977
+ glTarget,
3978
+ mipLevel,
3979
+ x,
3980
+ y,
3981
+ z,
3982
+ width,
3983
+ height,
3984
+ depthOrArrayLayers,
3985
+ glFormat,
3986
+ compressedData
3987
+ );
3988
+ }
3783
3989
  } else {
3784
- this.gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, typedArray);
3990
+ this.gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depthOrArrayLayers, glFormat, glType, typedArray, sourceElementOffset);
3785
3991
  }
3786
3992
  break;
3787
3993
  default:
3788
3994
  }
3789
3995
  });
3790
- this.gl.bindTexture(glTarget, null);
3996
+ this.gl.bindTexture(this.glTarget, null);
3791
3997
  }
3792
3998
  // IMPLEMENTATION SPECIFIC
3793
3999
  /** @todo - for now we always use 1 for maximum compatibility, we can fine tune later */
@@ -3809,30 +4015,107 @@ ${source}`;
3809
4015
  }
3810
4016
  // WEBGL SPECIFIC
3811
4017
  readDataSyncWebGL(options_ = {}) {
3812
- const options = this._normalizeTextureReadOptions(options_);
4018
+ const options = this._getSupportedColorReadOptions(options_);
3813
4019
  const memoryLayout = this.computeMemoryLayout(options);
3814
4020
  const shaderType = convertGLDataTypeToDataType(this.glType);
3815
- const ArrayType = (0, import_core14.getTypedArrayConstructor)(shaderType);
3816
- const targetArray = new ArrayType(memoryLayout.byteLength);
3817
- const signedType = (0, import_core14.getDataType)(targetArray);
3818
- const sourceType = convertDataTypeToGLDataType(signedType);
4021
+ const ArrayType = (0, import_core15.getTypedArrayConstructor)(shaderType);
4022
+ const targetArray = new ArrayType(memoryLayout.byteLength / ArrayType.BYTES_PER_ELEMENT);
4023
+ this._readColorTextureLayers(options, memoryLayout, (destinationByteOffset) => {
4024
+ const layerView = new ArrayType(
4025
+ targetArray.buffer,
4026
+ targetArray.byteOffset + destinationByteOffset,
4027
+ memoryLayout.bytesPerImage / ArrayType.BYTES_PER_ELEMENT
4028
+ );
4029
+ this.gl.readPixels(
4030
+ options.x,
4031
+ options.y,
4032
+ options.width,
4033
+ options.height,
4034
+ this.glFormat,
4035
+ this.glType,
4036
+ layerView
4037
+ );
4038
+ });
4039
+ return targetArray.buffer;
4040
+ }
4041
+ /**
4042
+ * Iterates the requested mip/layer/slice range, reattaching the cached read framebuffer as
4043
+ * needed before delegating the actual `readPixels()` call to the supplied callback.
4044
+ */
4045
+ _readColorTextureLayers(options, memoryLayout, readLayer) {
3819
4046
  const framebuffer = this._getFramebuffer();
4047
+ const packRowLength = memoryLayout.bytesPerRow / memoryLayout.bytesPerPixel;
4048
+ const glParameters = {
4049
+ [3333 /* PACK_ALIGNMENT */]: this.byteAlignment,
4050
+ ...packRowLength !== options.width ? { [3330 /* PACK_ROW_LENGTH */]: packRowLength } : {}
4051
+ };
4052
+ const prevReadBuffer = this.gl.getParameter(3074 /* READ_BUFFER */);
3820
4053
  const prevHandle = this.gl.bindFramebuffer(
3821
4054
  36160 /* FRAMEBUFFER */,
3822
4055
  framebuffer.handle
3823
4056
  );
3824
- this.gl.readBuffer(36064 /* COLOR_ATTACHMENT0 */);
3825
- this.gl.readPixels(
3826
- options.x,
3827
- options.y,
3828
- options.width,
3829
- options.height,
3830
- this.glFormat,
3831
- sourceType,
3832
- targetArray
3833
- );
3834
- this.gl.bindFramebuffer(36160 /* FRAMEBUFFER */, prevHandle || null);
3835
- return targetArray.buffer;
4057
+ try {
4058
+ this.gl.readBuffer(36064 /* COLOR_ATTACHMENT0 */);
4059
+ withGLParameters(this.gl, glParameters, () => {
4060
+ for (let layerIndex = 0; layerIndex < options.depthOrArrayLayers; layerIndex++) {
4061
+ this._attachReadSubresource(framebuffer, options.mipLevel, options.z + layerIndex);
4062
+ readLayer(layerIndex * memoryLayout.bytesPerImage);
4063
+ }
4064
+ });
4065
+ } finally {
4066
+ this.gl.bindFramebuffer(36160 /* FRAMEBUFFER */, prevHandle || null);
4067
+ this.gl.readBuffer(prevReadBuffer);
4068
+ }
4069
+ }
4070
+ /**
4071
+ * Attaches a single color subresource to the cached read framebuffer.
4072
+ *
4073
+ * @note Repeated attachments of the same `(mipLevel, layer)` tuple are skipped.
4074
+ */
4075
+ _attachReadSubresource(framebuffer, mipLevel, layer) {
4076
+ const attachmentKey = `${mipLevel}:${layer}`;
4077
+ if (this._framebufferAttachmentKey === attachmentKey) {
4078
+ return;
4079
+ }
4080
+ switch (this.dimension) {
4081
+ case "2d":
4082
+ this.gl.framebufferTexture2D(
4083
+ 36160 /* FRAMEBUFFER */,
4084
+ 36064 /* COLOR_ATTACHMENT0 */,
4085
+ 3553 /* TEXTURE_2D */,
4086
+ this.handle,
4087
+ mipLevel
4088
+ );
4089
+ break;
4090
+ case "cube":
4091
+ this.gl.framebufferTexture2D(
4092
+ 36160 /* FRAMEBUFFER */,
4093
+ 36064 /* COLOR_ATTACHMENT0 */,
4094
+ getWebGLCubeFaceTarget(this.glTarget, this.dimension, layer),
4095
+ this.handle,
4096
+ mipLevel
4097
+ );
4098
+ break;
4099
+ case "2d-array":
4100
+ case "3d":
4101
+ this.gl.framebufferTextureLayer(
4102
+ 36160 /* FRAMEBUFFER */,
4103
+ 36064 /* COLOR_ATTACHMENT0 */,
4104
+ this.handle,
4105
+ mipLevel,
4106
+ layer
4107
+ );
4108
+ break;
4109
+ default:
4110
+ throw new Error(`${this} color readback does not support ${this.dimension} textures`);
4111
+ }
4112
+ if (this.device.props.debug) {
4113
+ const status = Number(this.gl.checkFramebufferStatus(36160 /* FRAMEBUFFER */));
4114
+ if (status !== Number(36053 /* FRAMEBUFFER_COMPLETE */)) {
4115
+ throw new Error(`${framebuffer} incomplete for ${this} readback (${status})`);
4116
+ }
4117
+ }
4118
+ this._framebufferAttachmentKey = attachmentKey;
3836
4119
  }
3837
4120
  /**
3838
4121
  * @note - this is used by the DynamicTexture class to generate mipmaps on WebGL
@@ -3840,7 +4123,7 @@ ${source}`;
3840
4123
  generateMipmapsWebGL(options) {
3841
4124
  const isFilterableAndRenderable = this.device.isTextureFormatRenderable(this.props.format) && this.device.isTextureFormatFilterable(this.props.format);
3842
4125
  if (!isFilterableAndRenderable) {
3843
- import_core13.log.warn(`${this} is not renderable or filterable, may not be able to generate mipmaps`)();
4126
+ import_core14.log.warn(`${this} is not renderable or filterable, may not be able to generate mipmaps`)();
3844
4127
  if (!options?.force) {
3845
4128
  return;
3846
4129
  }
@@ -3849,7 +4132,7 @@ ${source}`;
3849
4132
  this.gl.bindTexture(this.glTarget, this.handle);
3850
4133
  this.gl.generateMipmap(this.glTarget);
3851
4134
  } catch (error) {
3852
- import_core13.log.warn(`Error generating mipmap for ${this}: ${error.message}`)();
4135
+ import_core14.log.warn(`Error generating mipmap for ${this}: ${error.message}`)();
3853
4136
  } finally {
3854
4137
  this.gl.bindTexture(this.glTarget, null);
3855
4138
  }
@@ -3859,7 +4142,7 @@ ${source}`;
3859
4142
  * Sets sampler parameters on texture
3860
4143
  */
3861
4144
  _setSamplerParameters(parameters) {
3862
- import_core13.log.log(2, `${this.id} sampler parameters`, this.device.getGLKeys(parameters))();
4145
+ import_core14.log.log(2, `${this.id} sampler parameters`, this.device.getGLKeys(parameters))();
3863
4146
  this.gl.bindTexture(this.glTarget, this.handle);
3864
4147
  for (const [pname, pvalue] of Object.entries(parameters)) {
3865
4148
  const param = Number(pname);
@@ -3916,207 +4199,6 @@ ${source}`;
3916
4199
  }
3917
4200
  });
3918
4201
 
3919
- // src/adapter/helpers/get-shader-layout-from-glsl.ts
3920
- function getShaderLayoutFromGLSL(gl, program) {
3921
- const shaderLayout = {
3922
- attributes: [],
3923
- bindings: []
3924
- };
3925
- shaderLayout.attributes = readAttributeDeclarations(gl, program);
3926
- const uniformBlocks = readUniformBlocks(gl, program);
3927
- for (const uniformBlock of uniformBlocks) {
3928
- const uniforms2 = uniformBlock.uniforms.map((uniform) => ({
3929
- name: uniform.name,
3930
- format: uniform.format,
3931
- byteOffset: uniform.byteOffset,
3932
- byteStride: uniform.byteStride,
3933
- arrayLength: uniform.arrayLength
3934
- }));
3935
- shaderLayout.bindings.push({
3936
- type: "uniform",
3937
- name: uniformBlock.name,
3938
- group: 0,
3939
- location: uniformBlock.location,
3940
- visibility: (uniformBlock.vertex ? 1 : 0) & (uniformBlock.fragment ? 2 : 0),
3941
- minBindingSize: uniformBlock.byteLength,
3942
- uniforms: uniforms2
3943
- });
3944
- }
3945
- const uniforms = readUniformBindings(gl, program);
3946
- let textureUnit = 0;
3947
- for (const uniform of uniforms) {
3948
- if (isGLSamplerType(uniform.type)) {
3949
- const { viewDimension, sampleType } = getTextureBindingFromGLSamplerType(uniform.type);
3950
- shaderLayout.bindings.push({
3951
- type: "texture",
3952
- name: uniform.name,
3953
- group: 0,
3954
- location: textureUnit,
3955
- viewDimension,
3956
- sampleType
3957
- });
3958
- uniform.textureUnit = textureUnit;
3959
- textureUnit += 1;
3960
- }
3961
- }
3962
- if (uniforms.length) {
3963
- shaderLayout.uniforms = uniforms;
3964
- }
3965
- const varyings = readVaryings(gl, program);
3966
- if (varyings?.length) {
3967
- shaderLayout.varyings = varyings;
3968
- }
3969
- return shaderLayout;
3970
- }
3971
- function readAttributeDeclarations(gl, program) {
3972
- const attributes = [];
3973
- const count = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
3974
- for (let index = 0; index < count; index++) {
3975
- const activeInfo = gl.getActiveAttrib(program, index);
3976
- if (!activeInfo) {
3977
- throw new Error("activeInfo");
3978
- }
3979
- const {
3980
- name,
3981
- type: compositeType
3982
- /* , size*/
3983
- } = activeInfo;
3984
- const location = gl.getAttribLocation(program, name);
3985
- if (location >= 0) {
3986
- const attributeType = convertGLUniformTypeToShaderVariableType(compositeType);
3987
- const stepMode = /instance/i.test(name) ? "instance" : "vertex";
3988
- attributes.push({
3989
- name,
3990
- location,
3991
- stepMode,
3992
- type: attributeType
3993
- // size - for arrays, size is the number of elements in the array
3994
- });
3995
- }
3996
- }
3997
- attributes.sort((a, b) => a.location - b.location);
3998
- return attributes;
3999
- }
4000
- function readVaryings(gl, program) {
4001
- const varyings = [];
4002
- const count = gl.getProgramParameter(program, 35971 /* TRANSFORM_FEEDBACK_VARYINGS */);
4003
- for (let location = 0; location < count; location++) {
4004
- const activeInfo = gl.getTransformFeedbackVarying(program, location);
4005
- if (!activeInfo) {
4006
- throw new Error("activeInfo");
4007
- }
4008
- const { name, type: glUniformType, size } = activeInfo;
4009
- const uniformType = convertGLUniformTypeToShaderVariableType(glUniformType);
4010
- const { type, components } = (0, import_core15.getVariableShaderTypeInfo)(uniformType);
4011
- varyings.push({ location, name, type, size: size * components });
4012
- }
4013
- varyings.sort((a, b) => a.location - b.location);
4014
- return varyings;
4015
- }
4016
- function readUniformBindings(gl, program) {
4017
- const uniforms = [];
4018
- const uniformCount = gl.getProgramParameter(program, 35718 /* ACTIVE_UNIFORMS */);
4019
- for (let i = 0; i < uniformCount; i++) {
4020
- const activeInfo = gl.getActiveUniform(program, i);
4021
- if (!activeInfo) {
4022
- throw new Error("activeInfo");
4023
- }
4024
- const { name: rawName, size, type } = activeInfo;
4025
- const { name, isArray: isArray3 } = parseUniformName(rawName);
4026
- let webglLocation = gl.getUniformLocation(program, name);
4027
- const uniformInfo = {
4028
- // WebGL locations are uniquely typed but just numbers
4029
- location: webglLocation,
4030
- name,
4031
- size,
4032
- type,
4033
- isArray: isArray3
4034
- };
4035
- uniforms.push(uniformInfo);
4036
- if (uniformInfo.size > 1) {
4037
- for (let j = 0; j < uniformInfo.size; j++) {
4038
- const elementName = `${name}[${j}]`;
4039
- webglLocation = gl.getUniformLocation(program, elementName);
4040
- const arrayElementUniformInfo = {
4041
- ...uniformInfo,
4042
- name: elementName,
4043
- location: webglLocation
4044
- };
4045
- uniforms.push(arrayElementUniformInfo);
4046
- }
4047
- }
4048
- }
4049
- return uniforms;
4050
- }
4051
- function readUniformBlocks(gl, program) {
4052
- const getBlockParameter = (blockIndex, pname) => gl.getActiveUniformBlockParameter(program, blockIndex, pname);
4053
- const uniformBlocks = [];
4054
- const blockCount = gl.getProgramParameter(program, 35382 /* ACTIVE_UNIFORM_BLOCKS */);
4055
- for (let blockIndex = 0; blockIndex < blockCount; blockIndex++) {
4056
- const blockInfo = {
4057
- name: gl.getActiveUniformBlockName(program, blockIndex) || "",
4058
- location: getBlockParameter(blockIndex, 35391 /* UNIFORM_BLOCK_BINDING */),
4059
- byteLength: getBlockParameter(blockIndex, 35392 /* UNIFORM_BLOCK_DATA_SIZE */),
4060
- vertex: getBlockParameter(blockIndex, 35396 /* UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER */),
4061
- fragment: getBlockParameter(blockIndex, 35398 /* UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER */),
4062
- uniformCount: getBlockParameter(blockIndex, 35394 /* UNIFORM_BLOCK_ACTIVE_UNIFORMS */),
4063
- uniforms: []
4064
- };
4065
- const uniformIndices = getBlockParameter(blockIndex, 35395 /* UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES */) || [];
4066
- const uniformType = gl.getActiveUniforms(program, uniformIndices, 35383 /* UNIFORM_TYPE */);
4067
- const uniformArrayLength = gl.getActiveUniforms(program, uniformIndices, 35384 /* UNIFORM_SIZE */);
4068
- const uniformOffset = gl.getActiveUniforms(program, uniformIndices, 35387 /* UNIFORM_OFFSET */);
4069
- const uniformStride = gl.getActiveUniforms(program, uniformIndices, 35388 /* UNIFORM_ARRAY_STRIDE */);
4070
- for (let i = 0; i < blockInfo.uniformCount; ++i) {
4071
- const activeInfo = gl.getActiveUniform(program, uniformIndices[i]);
4072
- if (!activeInfo) {
4073
- throw new Error("activeInfo");
4074
- }
4075
- const format = convertGLUniformTypeToShaderVariableType(uniformType[i]);
4076
- blockInfo.uniforms.push({
4077
- name: activeInfo.name,
4078
- format,
4079
- type: uniformType[i],
4080
- arrayLength: uniformArrayLength[i],
4081
- byteOffset: uniformOffset[i],
4082
- byteStride: uniformStride[i]
4083
- // matrixStride: uniformStride[i],
4084
- // rowMajor: uniformRowMajor[i]
4085
- });
4086
- }
4087
- uniformBlocks.push(blockInfo);
4088
- }
4089
- uniformBlocks.sort((a, b) => a.location - b.location);
4090
- return uniformBlocks;
4091
- }
4092
- function parseUniformName(name) {
4093
- if (name[name.length - 1] !== "]") {
4094
- return {
4095
- name,
4096
- length: 1,
4097
- isArray: false
4098
- };
4099
- }
4100
- const UNIFORM_NAME_REGEXP = /([^[]*)(\[[0-9]+\])?/;
4101
- const matches = UNIFORM_NAME_REGEXP.exec(name);
4102
- if (!matches || matches.length < 2) {
4103
- throw new Error(`Failed to parse GLSL uniform name ${name}`);
4104
- }
4105
- return {
4106
- name: matches[1],
4107
- length: matches[2] ? 1 : 0,
4108
- isArray: Boolean(matches[2])
4109
- };
4110
- }
4111
- var import_core15;
4112
- var init_get_shader_layout_from_glsl = __esm({
4113
- "src/adapter/helpers/get-shader-layout-from-glsl.ts"() {
4114
- "use strict";
4115
- import_core15 = __toESM(require_core(), 1);
4116
- init_webgl_shadertypes();
4117
- }
4118
- });
4119
-
4120
4202
  // src/adapter/helpers/set-uniform.ts
4121
4203
  function setUniform(gl, location, type, value) {
4122
4204
  const gl2 = gl;
@@ -4263,12 +4345,11 @@ ${source}`;
4263
4345
  }
4264
4346
  return mergedLayout;
4265
4347
  }
4266
- var import_core16, LOG_PROGRAM_PERF_PRIORITY, WEBGLRenderPipeline;
4348
+ var import_core16, WEBGLRenderPipeline;
4267
4349
  var init_webgl_render_pipeline = __esm({
4268
4350
  "src/adapter/resources/webgl-render-pipeline.ts"() {
4269
4351
  "use strict";
4270
4352
  import_core16 = __toESM(require_core(), 1);
4271
- init_get_shader_layout_from_glsl();
4272
4353
  init_device_parameters();
4273
4354
  init_set_uniform();
4274
4355
  init_webgl_buffer();
@@ -4276,7 +4357,6 @@ ${source}`;
4276
4357
  init_webgl_texture();
4277
4358
  init_webgl_texture_view();
4278
4359
  init_webgl_topology_utils();
4279
- LOG_PROGRAM_PERF_PRIORITY = 4;
4280
4360
  WEBGLRenderPipeline = class extends import_core16.RenderPipeline {
4281
4361
  /** The WebGL device that created this render pipeline */
4282
4362
  device;
@@ -4288,10 +4368,10 @@ ${source}`;
4288
4368
  fs;
4289
4369
  /** The layout extracted from shader by WebGL introspection APIs */
4290
4370
  introspectedLayout;
4291
- /** Uniforms set on this model */
4292
- uniforms = {};
4293
- /** Bindings set on this model */
4371
+ /** Compatibility path for direct pipeline.setBindings() usage */
4294
4372
  bindings = {};
4373
+ /** Compatibility path for direct pipeline.uniforms usage */
4374
+ uniforms = {};
4295
4375
  /** WebGL varyings */
4296
4376
  varyings = null;
4297
4377
  _uniformCount = 0;
@@ -4303,33 +4383,28 @@ ${source}`;
4303
4383
  constructor(device, props) {
4304
4384
  super(device, props);
4305
4385
  this.device = device;
4306
- this.handle = this.props.handle || this.device.gl.createProgram();
4386
+ const webglSharedRenderPipeline = this.sharedRenderPipeline || this.device._createSharedRenderPipelineWebGL(props);
4387
+ this.sharedRenderPipeline = webglSharedRenderPipeline;
4388
+ this.handle = webglSharedRenderPipeline.handle;
4389
+ this.vs = webglSharedRenderPipeline.vs;
4390
+ this.fs = webglSharedRenderPipeline.fs;
4391
+ this.linkStatus = webglSharedRenderPipeline.linkStatus;
4392
+ this.introspectedLayout = webglSharedRenderPipeline.introspectedLayout;
4307
4393
  this.device._setWebGLDebugMetadata(this.handle, this, { spector: { id: this.props.id } });
4308
- this.vs = props.vs;
4309
- this.fs = props.fs;
4310
- const { varyings, bufferMode = 35981 /* SEPARATE_ATTRIBS */ } = props;
4311
- if (varyings && varyings.length > 0) {
4312
- this.varyings = varyings;
4313
- this.device.gl.transformFeedbackVaryings(this.handle, varyings, bufferMode);
4314
- }
4315
- this._linkShaders();
4316
- import_core16.log.time(3, `RenderPipeline ${this.id} - shaderLayout introspection`)();
4317
- this.introspectedLayout = getShaderLayoutFromGLSL(this.device.gl, this.handle);
4318
- import_core16.log.timeEnd(3, `RenderPipeline ${this.id} - shaderLayout introspection`)();
4319
4394
  this.shaderLayout = props.shaderLayout ? mergeShaderLayout(this.introspectedLayout, props.shaderLayout) : this.introspectedLayout;
4320
4395
  }
4321
4396
  destroy() {
4322
- if (this.handle) {
4323
- this.device.gl.useProgram(null);
4324
- this.device.gl.deleteProgram(this.handle);
4325
- this.destroyed = true;
4326
- this.handle.destroyed = true;
4327
- this.handle = null;
4397
+ if (this.destroyed) {
4398
+ return;
4399
+ }
4400
+ if (this.sharedRenderPipeline && !this.props._sharedRenderPipeline) {
4401
+ this.sharedRenderPipeline.destroy();
4328
4402
  }
4403
+ this.destroyResource();
4329
4404
  }
4330
4405
  /**
4331
- * Bindings include: textures, samplers and uniform buffers
4332
- * @todo needed for portable model
4406
+ * Compatibility shim for code paths that still set bindings on the pipeline.
4407
+ * Shared-model draws pass bindings per draw and do not rely on this state.
4333
4408
  */
4334
4409
  setBindings(bindings, options) {
4335
4410
  for (const [name, value] of Object.entries(bindings)) {
@@ -4372,6 +4447,7 @@ ${source}`;
4372
4447
  * This function unifies those ways into a single call using common parameters with sane defaults
4373
4448
  */
4374
4449
  draw(options) {
4450
+ this._syncLinkStatus();
4375
4451
  const {
4376
4452
  renderPass,
4377
4453
  parameters = this.props.parameters,
@@ -4385,7 +4461,9 @@ ${source}`;
4385
4461
  // firstIndex,
4386
4462
  // firstInstance,
4387
4463
  // baseVertex,
4388
- transformFeedback
4464
+ transformFeedback,
4465
+ bindings = this.bindings,
4466
+ uniforms = this.uniforms
4389
4467
  } = options;
4390
4468
  const glDrawMode = getGLDrawMode(topology);
4391
4469
  const isIndexed = Boolean(vertexArray.indexBuffer);
@@ -4394,71 +4472,506 @@ ${source}`;
4394
4472
  import_core16.log.info(2, `RenderPipeline:${this.id}.draw() aborted - waiting for shader linking`)();
4395
4473
  return false;
4396
4474
  }
4397
- if (!this._areTexturesRenderable()) {
4475
+ if (!this._areTexturesRenderable(bindings)) {
4398
4476
  import_core16.log.info(2, `RenderPipeline:${this.id}.draw() aborted - textures not yet loaded`)();
4399
4477
  return false;
4400
4478
  }
4401
- this.device.gl.useProgram(this.handle);
4402
- vertexArray.bindBeforeRender(renderPass);
4403
- if (transformFeedback) {
4404
- transformFeedback.begin(this.props.topology);
4479
+ this.device.gl.useProgram(this.handle);
4480
+ vertexArray.bindBeforeRender(renderPass);
4481
+ if (transformFeedback) {
4482
+ transformFeedback.begin(this.props.topology);
4483
+ }
4484
+ this._applyBindings(bindings, { disableWarnings: this.props.disableWarnings });
4485
+ this._applyUniforms(uniforms);
4486
+ const webglRenderPass = renderPass;
4487
+ withDeviceAndGLParameters(this.device, parameters, webglRenderPass.glParameters, () => {
4488
+ if (isIndexed && isInstanced) {
4489
+ this.device.gl.drawElementsInstanced(
4490
+ glDrawMode,
4491
+ vertexCount || 0,
4492
+ // indexCount?
4493
+ glIndexType,
4494
+ firstVertex,
4495
+ instanceCount || 0
4496
+ );
4497
+ } else if (isIndexed) {
4498
+ this.device.gl.drawElements(glDrawMode, vertexCount || 0, glIndexType, firstVertex);
4499
+ } else if (isInstanced) {
4500
+ this.device.gl.drawArraysInstanced(
4501
+ glDrawMode,
4502
+ firstVertex,
4503
+ vertexCount || 0,
4504
+ instanceCount || 0
4505
+ );
4506
+ } else {
4507
+ this.device.gl.drawArrays(glDrawMode, firstVertex, vertexCount || 0);
4508
+ }
4509
+ if (transformFeedback) {
4510
+ transformFeedback.end();
4511
+ }
4512
+ });
4513
+ vertexArray.unbindAfterRender(renderPass);
4514
+ return true;
4515
+ }
4516
+ /**
4517
+ * Checks if all texture-values uniforms are renderable (i.e. loaded)
4518
+ * Update a texture if needed (e.g. from video)
4519
+ * Note: This is currently done before every draw call
4520
+ */
4521
+ _areTexturesRenderable(bindings) {
4522
+ let texturesRenderable = true;
4523
+ for (const bindingInfo of this.shaderLayout.bindings) {
4524
+ if (!bindings[bindingInfo.name] && !bindings[bindingInfo.name.replace(/Uniforms$/, "")]) {
4525
+ import_core16.log.warn(`Binding ${bindingInfo.name} not found in ${this.id}`)();
4526
+ texturesRenderable = false;
4527
+ }
4528
+ }
4529
+ return texturesRenderable;
4530
+ }
4531
+ /** Apply any bindings (before each draw call) */
4532
+ _applyBindings(bindings, _options) {
4533
+ this._syncLinkStatus();
4534
+ if (this.linkStatus !== "success") {
4535
+ return;
4536
+ }
4537
+ const { gl } = this.device;
4538
+ gl.useProgram(this.handle);
4539
+ let textureUnit = 0;
4540
+ let uniformBufferIndex = 0;
4541
+ for (const binding of this.shaderLayout.bindings) {
4542
+ const value = bindings[binding.name] || bindings[binding.name.replace(/Uniforms$/, "")];
4543
+ if (!value) {
4544
+ throw new Error(`No value for binding ${binding.name} in ${this.id}`);
4545
+ }
4546
+ switch (binding.type) {
4547
+ case "uniform":
4548
+ const { name } = binding;
4549
+ const location = gl.getUniformBlockIndex(this.handle, name);
4550
+ if (location === 4294967295 /* INVALID_INDEX */) {
4551
+ throw new Error(`Invalid uniform block name ${name}`);
4552
+ }
4553
+ gl.uniformBlockBinding(this.handle, location, uniformBufferIndex);
4554
+ if (value instanceof WEBGLBuffer) {
4555
+ gl.bindBufferBase(35345 /* UNIFORM_BUFFER */, uniformBufferIndex, value.handle);
4556
+ } else {
4557
+ gl.bindBufferRange(
4558
+ 35345 /* UNIFORM_BUFFER */,
4559
+ uniformBufferIndex,
4560
+ // @ts-expect-error
4561
+ value.buffer.handle,
4562
+ // @ts-expect-error
4563
+ value.offset || 0,
4564
+ // @ts-expect-error
4565
+ value.size || value.buffer.byteLength - value.offset
4566
+ );
4567
+ }
4568
+ uniformBufferIndex += 1;
4569
+ break;
4570
+ case "texture":
4571
+ if (!(value instanceof WEBGLTextureView || value instanceof WEBGLTexture || value instanceof WEBGLFramebuffer)) {
4572
+ throw new Error("texture");
4573
+ }
4574
+ let texture;
4575
+ if (value instanceof WEBGLTextureView) {
4576
+ texture = value.texture;
4577
+ } else if (value instanceof WEBGLTexture) {
4578
+ texture = value;
4579
+ } else if (value instanceof WEBGLFramebuffer && value.colorAttachments[0] instanceof WEBGLTextureView) {
4580
+ import_core16.log.warn(
4581
+ "Passing framebuffer in texture binding may be deprecated. Use fbo.colorAttachments[0] instead"
4582
+ )();
4583
+ texture = value.colorAttachments[0].texture;
4584
+ } else {
4585
+ throw new Error("No texture");
4586
+ }
4587
+ gl.activeTexture(33984 /* TEXTURE0 */ + textureUnit);
4588
+ gl.bindTexture(texture.glTarget, texture.handle);
4589
+ textureUnit += 1;
4590
+ break;
4591
+ case "sampler":
4592
+ break;
4593
+ case "storage":
4594
+ case "read-only-storage":
4595
+ throw new Error(`binding type '${binding.type}' not supported in WebGL`);
4596
+ }
4597
+ }
4598
+ }
4599
+ /**
4600
+ * Due to program sharing, uniforms need to be reset before every draw call
4601
+ * (though caching will avoid redundant WebGL calls)
4602
+ */
4603
+ _applyUniforms(uniforms) {
4604
+ for (const uniformLayout of this.shaderLayout.uniforms || []) {
4605
+ const { name, location, type, textureUnit } = uniformLayout;
4606
+ const value = uniforms[name] ?? textureUnit;
4607
+ if (value !== void 0) {
4608
+ setUniform(this.device.gl, location, type, value);
4609
+ }
4610
+ }
4611
+ }
4612
+ _syncLinkStatus() {
4613
+ this.linkStatus = this.sharedRenderPipeline.linkStatus;
4614
+ }
4615
+ };
4616
+ }
4617
+ });
4618
+
4619
+ // src/adapter/converters/webgl-shadertypes.ts
4620
+ function convertDataTypeToGLDataType(normalizedType) {
4621
+ return NORMALIZED_SHADER_TYPE_TO_WEBGL[normalizedType];
4622
+ }
4623
+ function convertGLUniformTypeToShaderVariableType(glUniformType) {
4624
+ return WEBGL_SHADER_TYPES[glUniformType];
4625
+ }
4626
+ function isGLSamplerType(type) {
4627
+ return Boolean(WEBGL_SAMPLER_TO_TEXTURE_BINDINGS[type]);
4628
+ }
4629
+ function getTextureBindingFromGLSamplerType(glSamplerType) {
4630
+ return WEBGL_SAMPLER_TO_TEXTURE_BINDINGS[glSamplerType];
4631
+ }
4632
+ var WEBGL_SHADER_TYPES, WEBGL_SAMPLER_TO_TEXTURE_BINDINGS, NORMALIZED_SHADER_TYPE_TO_WEBGL, WEBGL_TO_NORMALIZED_DATA_TYPE;
4633
+ var init_webgl_shadertypes = __esm({
4634
+ "src/adapter/converters/webgl-shadertypes.ts"() {
4635
+ "use strict";
4636
+ WEBGL_SHADER_TYPES = {
4637
+ [5126 /* FLOAT */]: "f32",
4638
+ [35664 /* FLOAT_VEC2 */]: "vec2<f32>",
4639
+ [35665 /* FLOAT_VEC3 */]: "vec3<f32>",
4640
+ [35666 /* FLOAT_VEC4 */]: "vec4<f32>",
4641
+ [5124 /* INT */]: "i32",
4642
+ [35667 /* INT_VEC2 */]: "vec2<i32>",
4643
+ [35668 /* INT_VEC3 */]: "vec3<i32>",
4644
+ [35669 /* INT_VEC4 */]: "vec4<i32>",
4645
+ [5125 /* UNSIGNED_INT */]: "u32",
4646
+ [36294 /* UNSIGNED_INT_VEC2 */]: "vec2<u32>",
4647
+ [36295 /* UNSIGNED_INT_VEC3 */]: "vec3<u32>",
4648
+ [36296 /* UNSIGNED_INT_VEC4 */]: "vec4<u32>",
4649
+ [35670 /* BOOL */]: "f32",
4650
+ [35671 /* BOOL_VEC2 */]: "vec2<f32>",
4651
+ [35672 /* BOOL_VEC3 */]: "vec3<f32>",
4652
+ [35673 /* BOOL_VEC4 */]: "vec4<f32>",
4653
+ // TODO - are sizes/components below correct?
4654
+ [35674 /* FLOAT_MAT2 */]: "mat2x2<f32>",
4655
+ [35685 /* FLOAT_MAT2x3 */]: "mat2x3<f32>",
4656
+ [35686 /* FLOAT_MAT2x4 */]: "mat2x4<f32>",
4657
+ [35687 /* FLOAT_MAT3x2 */]: "mat3x2<f32>",
4658
+ [35675 /* FLOAT_MAT3 */]: "mat3x3<f32>",
4659
+ [35688 /* FLOAT_MAT3x4 */]: "mat3x4<f32>",
4660
+ [35689 /* FLOAT_MAT4x2 */]: "mat4x2<f32>",
4661
+ [35690 /* FLOAT_MAT4x3 */]: "mat4x3<f32>",
4662
+ [35676 /* FLOAT_MAT4 */]: "mat4x4<f32>"
4663
+ };
4664
+ WEBGL_SAMPLER_TO_TEXTURE_BINDINGS = {
4665
+ [35678 /* SAMPLER_2D */]: { viewDimension: "2d", sampleType: "float" },
4666
+ [35680 /* SAMPLER_CUBE */]: { viewDimension: "cube", sampleType: "float" },
4667
+ [35679 /* SAMPLER_3D */]: { viewDimension: "3d", sampleType: "float" },
4668
+ [35682 /* SAMPLER_2D_SHADOW */]: { viewDimension: "3d", sampleType: "depth" },
4669
+ [36289 /* SAMPLER_2D_ARRAY */]: { viewDimension: "2d-array", sampleType: "float" },
4670
+ [36292 /* SAMPLER_2D_ARRAY_SHADOW */]: { viewDimension: "2d-array", sampleType: "depth" },
4671
+ [36293 /* SAMPLER_CUBE_SHADOW */]: { viewDimension: "cube", sampleType: "float" },
4672
+ [36298 /* INT_SAMPLER_2D */]: { viewDimension: "2d", sampleType: "sint" },
4673
+ [36299 /* INT_SAMPLER_3D */]: { viewDimension: "3d", sampleType: "sint" },
4674
+ [36300 /* INT_SAMPLER_CUBE */]: { viewDimension: "cube", sampleType: "sint" },
4675
+ [36303 /* INT_SAMPLER_2D_ARRAY */]: { viewDimension: "2d-array", sampleType: "uint" },
4676
+ [36306 /* UNSIGNED_INT_SAMPLER_2D */]: { viewDimension: "2d", sampleType: "uint" },
4677
+ [36307 /* UNSIGNED_INT_SAMPLER_3D */]: { viewDimension: "3d", sampleType: "uint" },
4678
+ [36308 /* UNSIGNED_INT_SAMPLER_CUBE */]: { viewDimension: "cube", sampleType: "uint" },
4679
+ [36311 /* UNSIGNED_INT_SAMPLER_2D_ARRAY */]: { viewDimension: "2d-array", sampleType: "uint" }
4680
+ };
4681
+ NORMALIZED_SHADER_TYPE_TO_WEBGL = {
4682
+ uint8: 5121 /* UNSIGNED_BYTE */,
4683
+ sint8: 5120 /* BYTE */,
4684
+ unorm8: 5121 /* UNSIGNED_BYTE */,
4685
+ snorm8: 5120 /* BYTE */,
4686
+ uint16: 5123 /* UNSIGNED_SHORT */,
4687
+ sint16: 5122 /* SHORT */,
4688
+ unorm16: 5123 /* UNSIGNED_SHORT */,
4689
+ snorm16: 5122 /* SHORT */,
4690
+ uint32: 5125 /* UNSIGNED_INT */,
4691
+ sint32: 5124 /* INT */,
4692
+ // WebGPU does not support normalized 32 bit integer attributes
4693
+ // 'unorm32': GL.UNSIGNED_INT,
4694
+ // 'snorm32': GL.INT,
4695
+ float16: 5131 /* HALF_FLOAT */,
4696
+ float32: 5126 /* FLOAT */
4697
+ };
4698
+ WEBGL_TO_NORMALIZED_DATA_TYPE = {
4699
+ [5120 /* BYTE */]: ["sint8", "snorm16"],
4700
+ [5121 /* UNSIGNED_BYTE */]: ["uint8", "unorm8"],
4701
+ [5122 /* SHORT */]: ["sint16", "unorm16"],
4702
+ [5123 /* UNSIGNED_SHORT */]: ["uint16", "unorm16"],
4703
+ [5124 /* INT */]: ["sint32", "sint32"],
4704
+ [5125 /* UNSIGNED_INT */]: ["uint32", "uint32"],
4705
+ [5126 /* FLOAT */]: ["float32", "float32"],
4706
+ [5131 /* HALF_FLOAT */]: ["float16", "float16"]
4707
+ };
4708
+ }
4709
+ });
4710
+
4711
+ // src/adapter/helpers/get-shader-layout-from-glsl.ts
4712
+ function getShaderLayoutFromGLSL(gl, program) {
4713
+ const shaderLayout = {
4714
+ attributes: [],
4715
+ bindings: []
4716
+ };
4717
+ shaderLayout.attributes = readAttributeDeclarations(gl, program);
4718
+ const uniformBlocks = readUniformBlocks(gl, program);
4719
+ for (const uniformBlock of uniformBlocks) {
4720
+ const uniforms2 = uniformBlock.uniforms.map((uniform) => ({
4721
+ name: uniform.name,
4722
+ format: uniform.format,
4723
+ byteOffset: uniform.byteOffset,
4724
+ byteStride: uniform.byteStride,
4725
+ arrayLength: uniform.arrayLength
4726
+ }));
4727
+ shaderLayout.bindings.push({
4728
+ type: "uniform",
4729
+ name: uniformBlock.name,
4730
+ group: 0,
4731
+ location: uniformBlock.location,
4732
+ visibility: (uniformBlock.vertex ? 1 : 0) & (uniformBlock.fragment ? 2 : 0),
4733
+ minBindingSize: uniformBlock.byteLength,
4734
+ uniforms: uniforms2
4735
+ });
4736
+ }
4737
+ const uniforms = readUniformBindings(gl, program);
4738
+ let textureUnit = 0;
4739
+ for (const uniform of uniforms) {
4740
+ if (isGLSamplerType(uniform.type)) {
4741
+ const { viewDimension, sampleType } = getTextureBindingFromGLSamplerType(uniform.type);
4742
+ shaderLayout.bindings.push({
4743
+ type: "texture",
4744
+ name: uniform.name,
4745
+ group: 0,
4746
+ location: textureUnit,
4747
+ viewDimension,
4748
+ sampleType
4749
+ });
4750
+ uniform.textureUnit = textureUnit;
4751
+ textureUnit += 1;
4752
+ }
4753
+ }
4754
+ if (uniforms.length) {
4755
+ shaderLayout.uniforms = uniforms;
4756
+ }
4757
+ const varyings = readVaryings(gl, program);
4758
+ if (varyings?.length) {
4759
+ shaderLayout.varyings = varyings;
4760
+ }
4761
+ return shaderLayout;
4762
+ }
4763
+ function readAttributeDeclarations(gl, program) {
4764
+ const attributes = [];
4765
+ const count = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
4766
+ for (let index = 0; index < count; index++) {
4767
+ const activeInfo = gl.getActiveAttrib(program, index);
4768
+ if (!activeInfo) {
4769
+ throw new Error("activeInfo");
4770
+ }
4771
+ const {
4772
+ name,
4773
+ type: compositeType
4774
+ /* , size*/
4775
+ } = activeInfo;
4776
+ const location = gl.getAttribLocation(program, name);
4777
+ if (location >= 0) {
4778
+ const attributeType = convertGLUniformTypeToShaderVariableType(compositeType);
4779
+ const stepMode = /instance/i.test(name) ? "instance" : "vertex";
4780
+ attributes.push({
4781
+ name,
4782
+ location,
4783
+ stepMode,
4784
+ type: attributeType
4785
+ // size - for arrays, size is the number of elements in the array
4786
+ });
4787
+ }
4788
+ }
4789
+ attributes.sort((a, b) => a.location - b.location);
4790
+ return attributes;
4791
+ }
4792
+ function readVaryings(gl, program) {
4793
+ const varyings = [];
4794
+ const count = gl.getProgramParameter(program, 35971 /* TRANSFORM_FEEDBACK_VARYINGS */);
4795
+ for (let location = 0; location < count; location++) {
4796
+ const activeInfo = gl.getTransformFeedbackVarying(program, location);
4797
+ if (!activeInfo) {
4798
+ throw new Error("activeInfo");
4799
+ }
4800
+ const { name, type: glUniformType, size } = activeInfo;
4801
+ const uniformType = convertGLUniformTypeToShaderVariableType(glUniformType);
4802
+ const { type, components } = (0, import_core17.getVariableShaderTypeInfo)(uniformType);
4803
+ varyings.push({ location, name, type, size: size * components });
4804
+ }
4805
+ varyings.sort((a, b) => a.location - b.location);
4806
+ return varyings;
4807
+ }
4808
+ function readUniformBindings(gl, program) {
4809
+ const uniforms = [];
4810
+ const uniformCount = gl.getProgramParameter(program, 35718 /* ACTIVE_UNIFORMS */);
4811
+ for (let i = 0; i < uniformCount; i++) {
4812
+ const activeInfo = gl.getActiveUniform(program, i);
4813
+ if (!activeInfo) {
4814
+ throw new Error("activeInfo");
4815
+ }
4816
+ const { name: rawName, size, type } = activeInfo;
4817
+ const { name, isArray: isArray3 } = parseUniformName(rawName);
4818
+ let webglLocation = gl.getUniformLocation(program, name);
4819
+ const uniformInfo = {
4820
+ // WebGL locations are uniquely typed but just numbers
4821
+ location: webglLocation,
4822
+ name,
4823
+ size,
4824
+ type,
4825
+ isArray: isArray3
4826
+ };
4827
+ uniforms.push(uniformInfo);
4828
+ if (uniformInfo.size > 1) {
4829
+ for (let j = 0; j < uniformInfo.size; j++) {
4830
+ const elementName = `${name}[${j}]`;
4831
+ webglLocation = gl.getUniformLocation(program, elementName);
4832
+ const arrayElementUniformInfo = {
4833
+ ...uniformInfo,
4834
+ name: elementName,
4835
+ location: webglLocation
4836
+ };
4837
+ uniforms.push(arrayElementUniformInfo);
4838
+ }
4839
+ }
4840
+ }
4841
+ return uniforms;
4842
+ }
4843
+ function readUniformBlocks(gl, program) {
4844
+ const getBlockParameter = (blockIndex, pname) => gl.getActiveUniformBlockParameter(program, blockIndex, pname);
4845
+ const uniformBlocks = [];
4846
+ const blockCount = gl.getProgramParameter(program, 35382 /* ACTIVE_UNIFORM_BLOCKS */);
4847
+ for (let blockIndex = 0; blockIndex < blockCount; blockIndex++) {
4848
+ const blockInfo = {
4849
+ name: gl.getActiveUniformBlockName(program, blockIndex) || "",
4850
+ location: getBlockParameter(blockIndex, 35391 /* UNIFORM_BLOCK_BINDING */),
4851
+ byteLength: getBlockParameter(blockIndex, 35392 /* UNIFORM_BLOCK_DATA_SIZE */),
4852
+ vertex: getBlockParameter(blockIndex, 35396 /* UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER */),
4853
+ fragment: getBlockParameter(blockIndex, 35398 /* UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER */),
4854
+ uniformCount: getBlockParameter(blockIndex, 35394 /* UNIFORM_BLOCK_ACTIVE_UNIFORMS */),
4855
+ uniforms: []
4856
+ };
4857
+ const uniformIndices = getBlockParameter(blockIndex, 35395 /* UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES */) || [];
4858
+ const uniformType = gl.getActiveUniforms(program, uniformIndices, 35383 /* UNIFORM_TYPE */);
4859
+ const uniformArrayLength = gl.getActiveUniforms(program, uniformIndices, 35384 /* UNIFORM_SIZE */);
4860
+ const uniformOffset = gl.getActiveUniforms(program, uniformIndices, 35387 /* UNIFORM_OFFSET */);
4861
+ const uniformStride = gl.getActiveUniforms(program, uniformIndices, 35388 /* UNIFORM_ARRAY_STRIDE */);
4862
+ for (let i = 0; i < blockInfo.uniformCount; ++i) {
4863
+ const uniformIndex = uniformIndices[i];
4864
+ if (uniformIndex !== void 0) {
4865
+ const activeInfo = gl.getActiveUniform(program, uniformIndex);
4866
+ if (!activeInfo) {
4867
+ throw new Error("activeInfo");
4868
+ }
4869
+ const format = convertGLUniformTypeToShaderVariableType(uniformType[i]);
4870
+ blockInfo.uniforms.push({
4871
+ name: activeInfo.name,
4872
+ format,
4873
+ type: uniformType[i],
4874
+ arrayLength: uniformArrayLength[i],
4875
+ byteOffset: uniformOffset[i],
4876
+ byteStride: uniformStride[i]
4877
+ // matrixStride: uniformStride[i],
4878
+ // rowMajor: uniformRowMajor[i]
4879
+ });
4880
+ }
4881
+ }
4882
+ uniformBlocks.push(blockInfo);
4883
+ }
4884
+ uniformBlocks.sort((a, b) => a.location - b.location);
4885
+ return uniformBlocks;
4886
+ }
4887
+ function parseUniformName(name) {
4888
+ if (name[name.length - 1] !== "]") {
4889
+ return {
4890
+ name,
4891
+ length: 1,
4892
+ isArray: false
4893
+ };
4894
+ }
4895
+ const UNIFORM_NAME_REGEXP = /([^[]*)(\[[0-9]+\])?/;
4896
+ const matches = UNIFORM_NAME_REGEXP.exec(name);
4897
+ const uniformName = (0, import_core17.assertDefined)(matches?.[1], `Failed to parse GLSL uniform name ${name}`);
4898
+ return {
4899
+ name: uniformName,
4900
+ // TODO - is this a bug, shouldn't we return the value?
4901
+ length: matches?.[2] ? 1 : 0,
4902
+ isArray: Boolean(matches?.[2])
4903
+ };
4904
+ }
4905
+ var import_core17;
4906
+ var init_get_shader_layout_from_glsl = __esm({
4907
+ "src/adapter/helpers/get-shader-layout-from-glsl.ts"() {
4908
+ "use strict";
4909
+ import_core17 = __toESM(require_core(), 1);
4910
+ init_webgl_shadertypes();
4911
+ }
4912
+ });
4913
+
4914
+ // src/adapter/resources/webgl-shared-render-pipeline.ts
4915
+ var import_core18, LOG_PROGRAM_PERF_PRIORITY, WEBGLSharedRenderPipeline;
4916
+ var init_webgl_shared_render_pipeline = __esm({
4917
+ "src/adapter/resources/webgl-shared-render-pipeline.ts"() {
4918
+ "use strict";
4919
+ import_core18 = __toESM(require_core(), 1);
4920
+ init_get_shader_layout_from_glsl();
4921
+ init_webgl_shadertypes();
4922
+ LOG_PROGRAM_PERF_PRIORITY = 4;
4923
+ WEBGLSharedRenderPipeline = class extends import_core18.SharedRenderPipeline {
4924
+ device;
4925
+ handle;
4926
+ vs;
4927
+ fs;
4928
+ introspectedLayout = { attributes: [], bindings: [], uniforms: [] };
4929
+ linkStatus = "pending";
4930
+ constructor(device, props) {
4931
+ super(device, props);
4932
+ this.device = device;
4933
+ this.handle = props.handle || this.device.gl.createProgram();
4934
+ this.vs = props.vs;
4935
+ this.fs = props.fs;
4936
+ if (props.varyings && props.varyings.length > 0) {
4937
+ this.device.gl.transformFeedbackVaryings(
4938
+ this.handle,
4939
+ props.varyings,
4940
+ props.bufferMode || 35981 /* SEPARATE_ATTRIBS */
4941
+ );
4942
+ }
4943
+ this._linkShaders();
4944
+ import_core18.log.time(3, `RenderPipeline ${this.id} - shaderLayout introspection`)();
4945
+ this.introspectedLayout = getShaderLayoutFromGLSL(this.device.gl, this.handle);
4946
+ import_core18.log.timeEnd(3, `RenderPipeline ${this.id} - shaderLayout introspection`)();
4947
+ }
4948
+ destroy() {
4949
+ if (this.destroyed) {
4950
+ return;
4405
4951
  }
4406
- this._applyBindings();
4407
- this._applyUniforms();
4408
- const webglRenderPass = renderPass;
4409
- withDeviceAndGLParameters(this.device, parameters, webglRenderPass.glParameters, () => {
4410
- if (isIndexed && isInstanced) {
4411
- this.device.gl.drawElementsInstanced(
4412
- glDrawMode,
4413
- vertexCount || 0,
4414
- // indexCount?
4415
- glIndexType,
4416
- firstVertex,
4417
- instanceCount || 0
4418
- );
4419
- } else if (isIndexed) {
4420
- this.device.gl.drawElements(glDrawMode, vertexCount || 0, glIndexType, firstVertex);
4421
- } else if (isInstanced) {
4422
- this.device.gl.drawArraysInstanced(
4423
- glDrawMode,
4424
- firstVertex,
4425
- vertexCount || 0,
4426
- instanceCount || 0
4427
- );
4428
- } else {
4429
- this.device.gl.drawArrays(glDrawMode, firstVertex, vertexCount || 0);
4430
- }
4431
- if (transformFeedback) {
4432
- transformFeedback.end();
4433
- }
4434
- });
4435
- vertexArray.unbindAfterRender(renderPass);
4436
- return true;
4952
+ this.device.gl.useProgram(null);
4953
+ this.device.gl.deleteProgram(this.handle);
4954
+ this.handle.destroyed = true;
4955
+ this.destroyResource();
4437
4956
  }
4438
- // PRIVATE METHODS
4439
- // setAttributes(attributes: Record<string, Buffer>): void {}
4440
- // setBindings(bindings: Record<string, Binding>): void {}
4441
4957
  async _linkShaders() {
4442
4958
  const { gl } = this.device;
4443
4959
  gl.attachShader(this.handle, this.vs.handle);
4444
4960
  gl.attachShader(this.handle, this.fs.handle);
4445
- import_core16.log.time(LOG_PROGRAM_PERF_PRIORITY, `linkProgram for ${this.id}`)();
4961
+ import_core18.log.time(LOG_PROGRAM_PERF_PRIORITY, `linkProgram for ${this.id}`)();
4446
4962
  gl.linkProgram(this.handle);
4447
- import_core16.log.timeEnd(LOG_PROGRAM_PERF_PRIORITY, `linkProgram for ${this.id}`)();
4448
- if (import_core16.log.level === 0) {
4449
- }
4963
+ import_core18.log.timeEnd(LOG_PROGRAM_PERF_PRIORITY, `linkProgram for ${this.id}`)();
4450
4964
  if (!this.device.features.has("compilation-status-async-webgl")) {
4451
4965
  const status2 = this._getLinkStatus();
4452
4966
  this._reportLinkStatus(status2);
4453
4967
  return;
4454
4968
  }
4455
- import_core16.log.once(1, "RenderPipeline linking is asynchronous")();
4969
+ import_core18.log.once(1, "RenderPipeline linking is asynchronous")();
4456
4970
  await this._waitForLinkComplete();
4457
- import_core16.log.info(2, `RenderPipeline ${this.id} - async linking complete: ${this.linkStatus}`)();
4971
+ import_core18.log.info(2, `RenderPipeline ${this.id} - async linking complete: ${this.linkStatus}`)();
4458
4972
  const status = this._getLinkStatus();
4459
4973
  this._reportLinkStatus(status);
4460
4974
  }
4461
- /** Report link status. First, check for shader compilation failures if linking fails */
4462
4975
  async _reportLinkStatus(status) {
4463
4976
  switch (status) {
4464
4977
  case "success":
@@ -4495,11 +5008,6 @@ ${source}`;
4495
5008
  this.device.debug();
4496
5009
  }
4497
5010
  }
4498
- /**
4499
- * Get the shader compilation status
4500
- * TODO - Load log even when no error reported, to catch warnings?
4501
- * https://gamedev.stackexchange.com/questions/30429/how-to-detect-glsl-warnings
4502
- */
4503
5011
  _getLinkStatus() {
4504
5012
  const { gl } = this.device;
4505
5013
  const linked = gl.getProgramParameter(this.handle, 35714 /* LINK_STATUS */);
@@ -4507,6 +5015,7 @@ ${source}`;
4507
5015
  this.linkStatus = "error";
4508
5016
  return "link-error";
4509
5017
  }
5018
+ this._initializeSamplerUniforms();
4510
5019
  gl.validateProgram(this.handle);
4511
5020
  const validated = gl.getProgramParameter(this.handle, 35715 /* VALIDATE_STATUS */);
4512
5021
  if (!validated) {
@@ -4516,7 +5025,36 @@ ${source}`;
4516
5025
  this.linkStatus = "success";
4517
5026
  return "success";
4518
5027
  }
4519
- /** Use KHR_parallel_shader_compile extension if available */
5028
+ _initializeSamplerUniforms() {
5029
+ const { gl } = this.device;
5030
+ gl.useProgram(this.handle);
5031
+ let textureUnit = 0;
5032
+ const uniformCount = gl.getProgramParameter(this.handle, 35718 /* ACTIVE_UNIFORMS */);
5033
+ for (let uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++) {
5034
+ const activeInfo = gl.getActiveUniform(this.handle, uniformIndex);
5035
+ if (activeInfo && isGLSamplerType(activeInfo.type)) {
5036
+ const isArray3 = activeInfo.name.endsWith("[0]");
5037
+ const uniformName = isArray3 ? activeInfo.name.slice(0, -3) : activeInfo.name;
5038
+ const location = gl.getUniformLocation(this.handle, uniformName);
5039
+ if (location !== null) {
5040
+ textureUnit = this._assignSamplerUniform(location, activeInfo, isArray3, textureUnit);
5041
+ }
5042
+ }
5043
+ }
5044
+ }
5045
+ _assignSamplerUniform(location, activeInfo, isArray3, textureUnit) {
5046
+ const { gl } = this.device;
5047
+ if (isArray3 && activeInfo.size > 1) {
5048
+ const textureUnits = Int32Array.from(
5049
+ { length: activeInfo.size },
5050
+ (_, arrayIndex) => textureUnit + arrayIndex
5051
+ );
5052
+ gl.uniform1iv(location, textureUnits);
5053
+ return textureUnit + activeInfo.size;
5054
+ }
5055
+ gl.uniform1i(location, textureUnit);
5056
+ return textureUnit + 1;
5057
+ }
4520
5058
  async _waitForLinkComplete() {
4521
5059
  const waitMs = async (ms) => await new Promise((resolve) => setTimeout(resolve, ms));
4522
5060
  const DELAY_MS = 10;
@@ -4533,101 +5071,6 @@ ${source}`;
4533
5071
  await waitMs(DELAY_MS);
4534
5072
  }
4535
5073
  }
4536
- /**
4537
- * Checks if all texture-values uniforms are renderable (i.e. loaded)
4538
- * Update a texture if needed (e.g. from video)
4539
- * Note: This is currently done before every draw call
4540
- */
4541
- _areTexturesRenderable() {
4542
- let texturesRenderable = true;
4543
- for (const bindingInfo of this.shaderLayout.bindings) {
4544
- if (!this.bindings[bindingInfo.name] && !this.bindings[bindingInfo.name.replace(/Uniforms$/, "")]) {
4545
- import_core16.log.warn(`Binding ${bindingInfo.name} not found in ${this.id}`)();
4546
- texturesRenderable = false;
4547
- }
4548
- }
4549
- return texturesRenderable;
4550
- }
4551
- /** Apply any bindings (before each draw call) */
4552
- _applyBindings() {
4553
- if (this.linkStatus !== "success") {
4554
- return;
4555
- }
4556
- const { gl } = this.device;
4557
- gl.useProgram(this.handle);
4558
- let textureUnit = 0;
4559
- let uniformBufferIndex = 0;
4560
- for (const binding of this.shaderLayout.bindings) {
4561
- const value = this.bindings[binding.name] || this.bindings[binding.name.replace(/Uniforms$/, "")];
4562
- if (!value) {
4563
- throw new Error(`No value for binding ${binding.name} in ${this.id}`);
4564
- }
4565
- switch (binding.type) {
4566
- case "uniform":
4567
- const { name } = binding;
4568
- const location = gl.getUniformBlockIndex(this.handle, name);
4569
- if (location === 4294967295 /* INVALID_INDEX */) {
4570
- throw new Error(`Invalid uniform block name ${name}`);
4571
- }
4572
- gl.uniformBlockBinding(this.handle, uniformBufferIndex, location);
4573
- if (value instanceof WEBGLBuffer) {
4574
- gl.bindBufferBase(35345 /* UNIFORM_BUFFER */, uniformBufferIndex, value.handle);
4575
- } else {
4576
- gl.bindBufferRange(
4577
- 35345 /* UNIFORM_BUFFER */,
4578
- uniformBufferIndex,
4579
- // @ts-expect-error
4580
- value.buffer.handle,
4581
- // @ts-expect-error
4582
- value.offset || 0,
4583
- // @ts-expect-error
4584
- value.size || value.buffer.byteLength - value.offset
4585
- );
4586
- }
4587
- uniformBufferIndex += 1;
4588
- break;
4589
- case "texture":
4590
- if (!(value instanceof WEBGLTextureView || value instanceof WEBGLTexture || value instanceof WEBGLFramebuffer)) {
4591
- throw new Error("texture");
4592
- }
4593
- let texture;
4594
- if (value instanceof WEBGLTextureView) {
4595
- texture = value.texture;
4596
- } else if (value instanceof WEBGLTexture) {
4597
- texture = value;
4598
- } else if (value instanceof WEBGLFramebuffer && value.colorAttachments[0] instanceof WEBGLTextureView) {
4599
- import_core16.log.warn(
4600
- "Passing framebuffer in texture binding may be deprecated. Use fbo.colorAttachments[0] instead"
4601
- )();
4602
- texture = value.colorAttachments[0].texture;
4603
- } else {
4604
- throw new Error("No texture");
4605
- }
4606
- gl.activeTexture(33984 /* TEXTURE0 */ + textureUnit);
4607
- gl.bindTexture(texture.glTarget, texture.handle);
4608
- textureUnit += 1;
4609
- break;
4610
- case "sampler":
4611
- break;
4612
- case "storage":
4613
- case "read-only-storage":
4614
- throw new Error(`binding type '${binding.type}' not supported in WebGL`);
4615
- }
4616
- }
4617
- }
4618
- /**
4619
- * Due to program sharing, uniforms need to be reset before every draw call
4620
- * (though caching will avoid redundant WebGL calls)
4621
- */
4622
- _applyUniforms() {
4623
- for (const uniformLayout of this.shaderLayout.uniforms || []) {
4624
- const { name, location, type, textureUnit } = uniformLayout;
4625
- const value = this.uniforms[name] ?? textureUnit;
4626
- if (value !== void 0) {
4627
- setUniform(this.device.gl, location, type, value);
4628
- }
4629
- }
4630
- }
4631
5074
  };
4632
5075
  }
4633
5076
  });
@@ -4665,7 +5108,7 @@ ${source}`;
4665
5108
  height = options.sourceTexture.height,
4666
5109
  depthOrArrayLayers = 0,
4667
5110
  /** Defines the origin of the copy - the minimum corner of the texture sub-region to copy to/from. */
4668
- origin = [0, 0],
5111
+ origin = [0, 0, 0],
4669
5112
  /** Destination buffer */
4670
5113
  destinationBuffer,
4671
5114
  /** Offset, in bytes, from the beginning of the buffer to the start of the image data (default 0) */
@@ -4694,9 +5137,8 @@ ${source}`;
4694
5137
  const webglBuffer = destinationBuffer;
4695
5138
  const sourceWidth = width || framebuffer.width;
4696
5139
  const sourceHeight = height || framebuffer.height;
4697
- const sourceParams = getTextureFormatWebGL(
4698
- framebuffer.colorAttachments[0].texture.props.format
4699
- );
5140
+ const colorAttachment0 = (0, import_core19.assertDefined)(framebuffer.colorAttachments[0]);
5141
+ const sourceParams = getTextureFormatWebGL(colorAttachment0.texture.props.format);
4700
5142
  const sourceFormat = sourceParams.format;
4701
5143
  const sourceType = sourceParams.type;
4702
5144
  device.gl.bindBuffer(35051 /* PIXEL_PACK_BUFFER */, webglBuffer.handle);
@@ -4731,7 +5173,7 @@ ${source}`;
4731
5173
  /** Defines the origin of the copy - the minimum corner of the texture sub-region to copy from. */
4732
5174
  origin = [0, 0],
4733
5175
  /** Defines the origin of the copy - the minimum corner of the texture sub-region to copy to. */
4734
- destinationOrigin = [0, 0],
5176
+ destinationOrigin = [0, 0, 0],
4735
5177
  /** Texture to copy to/from. */
4736
5178
  destinationTexture
4737
5179
  /** Mip-map level of the texture to copy to/from. (Default 0) */
@@ -4747,7 +5189,7 @@ ${source}`;
4747
5189
  // depthOrArrayLayers = 0
4748
5190
  } = options;
4749
5191
  const { framebuffer, destroyFramebuffer } = getFramebuffer(sourceTexture);
4750
- const [sourceX, sourceY] = origin;
5192
+ const [sourceX = 0, sourceY = 0] = origin;
4751
5193
  const [destinationX, destinationY, destinationZ] = destinationOrigin;
4752
5194
  const prevHandle = device.gl.bindFramebuffer(
4753
5195
  36160 /* FRAMEBUFFER */,
@@ -4803,7 +5245,7 @@ ${source}`;
4803
5245
  }
4804
5246
  }
4805
5247
  function getFramebuffer(source) {
4806
- if (source instanceof import_core17.Texture) {
5248
+ if (source instanceof import_core19.Texture) {
4807
5249
  const { width, height, id } = source;
4808
5250
  const framebuffer = source.device.createFramebuffer({
4809
5251
  id: `framebuffer-for-${id}`,
@@ -4815,19 +5257,19 @@ ${source}`;
4815
5257
  }
4816
5258
  return { framebuffer: source, destroyFramebuffer: false };
4817
5259
  }
4818
- var import_core17, WEBGLCommandBuffer;
5260
+ var import_core19, WEBGLCommandBuffer;
4819
5261
  var init_webgl_command_buffer = __esm({
4820
5262
  "src/adapter/resources/webgl-command-buffer.ts"() {
4821
5263
  "use strict";
4822
- import_core17 = __toESM(require_core(), 1);
5264
+ import_core19 = __toESM(require_core(), 1);
4823
5265
  init_webgl_texture();
4824
5266
  init_webgl_texture_table();
4825
- WEBGLCommandBuffer = class extends import_core17.CommandBuffer {
5267
+ WEBGLCommandBuffer = class extends import_core19.CommandBuffer {
4826
5268
  device;
4827
5269
  handle = null;
4828
5270
  commands = [];
4829
- constructor(device) {
4830
- super(device, {});
5271
+ constructor(device, props = {}) {
5272
+ super(device, props);
4831
5273
  this.device = device;
4832
5274
  }
4833
5275
  _executeCommands(commands = this.commands) {
@@ -4855,15 +5297,15 @@ ${source}`;
4855
5297
  });
4856
5298
 
4857
5299
  // src/adapter/resources/webgl-render-pass.ts
4858
- var import_core18, COLOR_CHANNELS, WEBGLRenderPass;
5300
+ var import_core20, COLOR_CHANNELS, WEBGLRenderPass;
4859
5301
  var init_webgl_render_pass = __esm({
4860
5302
  "src/adapter/resources/webgl-render-pass.ts"() {
4861
5303
  "use strict";
4862
- import_core18 = __toESM(require_core(), 1);
5304
+ import_core20 = __toESM(require_core(), 1);
4863
5305
  init_with_parameters();
4864
5306
  init_unified_parameter_api();
4865
5307
  COLOR_CHANNELS = [1, 2, 4, 8];
4866
- WEBGLRenderPass = class extends import_core18.RenderPass {
5308
+ WEBGLRenderPass = class extends import_core20.RenderPass {
4867
5309
  device;
4868
5310
  handle = null;
4869
5311
  /** Parameters that should be applied before each draw call */
@@ -4871,6 +5313,9 @@ ${source}`;
4871
5313
  constructor(device, props) {
4872
5314
  super(device, props);
4873
5315
  this.device = device;
5316
+ if (!props?.framebuffer) {
5317
+ device.getDefaultCanvasContext()._resizeDrawingBufferIfNeeded();
5318
+ }
4874
5319
  let viewport;
4875
5320
  if (!props?.parameters?.viewport) {
4876
5321
  if (props?.framebuffer) {
@@ -4893,9 +5338,21 @@ ${source}`;
4893
5338
  this.device.gl.drawBuffers([1029 /* BACK */]);
4894
5339
  }
4895
5340
  this.clear();
5341
+ if (this.props.timestampQuerySet && this.props.beginTimestampIndex !== void 0) {
5342
+ const webglQuerySet = this.props.timestampQuerySet;
5343
+ webglQuerySet.writeTimestamp(this.props.beginTimestampIndex);
5344
+ }
4896
5345
  }
4897
5346
  end() {
5347
+ if (this.destroyed) {
5348
+ return;
5349
+ }
5350
+ if (this.props.timestampQuerySet && this.props.endTimestampIndex !== void 0) {
5351
+ const webglQuerySet = this.props.timestampQuerySet;
5352
+ webglQuerySet.writeTimestamp(this.props.endTimestampIndex);
5353
+ }
4898
5354
  this.device.popState();
5355
+ this.destroy();
4899
5356
  }
4900
5357
  pushDebugGroup(groupLabel) {
4901
5358
  }
@@ -5037,31 +5494,39 @@ ${source}`;
5037
5494
  });
5038
5495
 
5039
5496
  // src/adapter/resources/webgl-command-encoder.ts
5040
- var import_core19, WEBGLCommandEncoder;
5497
+ var import_core21, WEBGLCommandEncoder;
5041
5498
  var init_webgl_command_encoder = __esm({
5042
5499
  "src/adapter/resources/webgl-command-encoder.ts"() {
5043
5500
  "use strict";
5044
- import_core19 = __toESM(require_core(), 1);
5501
+ import_core21 = __toESM(require_core(), 1);
5045
5502
  init_webgl_command_buffer();
5046
5503
  init_webgl_render_pass();
5047
- WEBGLCommandEncoder = class extends import_core19.CommandEncoder {
5504
+ WEBGLCommandEncoder = class extends import_core21.CommandEncoder {
5048
5505
  device;
5049
5506
  handle = null;
5050
5507
  commandBuffer;
5051
5508
  constructor(device, props) {
5052
5509
  super(device, props);
5053
5510
  this.device = device;
5054
- this.commandBuffer = new WEBGLCommandBuffer(device);
5511
+ this.commandBuffer = new WEBGLCommandBuffer(device, {
5512
+ id: `${this.props.id}-command-buffer`
5513
+ });
5055
5514
  }
5056
5515
  destroy() {
5516
+ this.destroyResource();
5057
5517
  }
5058
- finish() {
5518
+ finish(props) {
5519
+ if (props?.id && this.commandBuffer.id !== props.id) {
5520
+ this.commandBuffer.id = props.id;
5521
+ this.commandBuffer.props.id = props.id;
5522
+ }
5523
+ this.destroy();
5059
5524
  return this.commandBuffer;
5060
5525
  }
5061
- beginRenderPass(props) {
5062
- return new WEBGLRenderPass(this.device, props);
5526
+ beginRenderPass(props = {}) {
5527
+ return new WEBGLRenderPass(this.device, this._applyTimeProfilingToPassProps(props));
5063
5528
  }
5064
- beginComputePass(props) {
5529
+ beginComputePass(props = {}) {
5065
5530
  throw new Error("ComputePass not supported in WebGL");
5066
5531
  }
5067
5532
  copyBufferToBuffer(options) {
@@ -5087,6 +5552,10 @@ ${source}`;
5087
5552
  }
5088
5553
  resolveQuerySet(querySet, destination, options) {
5089
5554
  }
5555
+ writeTimestamp(querySet, queryIndex) {
5556
+ const webglQuerySet = querySet;
5557
+ webglQuerySet.writeTimestamp(queryIndex);
5558
+ }
5090
5559
  };
5091
5560
  }
5092
5561
  });
@@ -5098,7 +5567,7 @@ ${source}`;
5098
5567
  const total = count * length;
5099
5568
  let copied = 0;
5100
5569
  for (let i = start; copied < length; copied++) {
5101
- target2[i++] = source[copied];
5570
+ target2[i++] = source[copied] ?? 0;
5102
5571
  }
5103
5572
  while (copied < total) {
5104
5573
  if (copied < total - copied) {
@@ -5135,15 +5604,15 @@ ${source}`;
5135
5604
  }
5136
5605
  return true;
5137
5606
  }
5138
- var import_core20, WEBGLVertexArray;
5607
+ var import_core22, WEBGLVertexArray;
5139
5608
  var init_webgl_vertex_array = __esm({
5140
5609
  "src/adapter/resources/webgl-vertex-array.ts"() {
5141
5610
  "use strict";
5142
- import_core20 = __toESM(require_core(), 1);
5611
+ import_core22 = __toESM(require_core(), 1);
5143
5612
  init_dist();
5144
5613
  init_webgl_vertex_formats();
5145
5614
  init_fill_array();
5146
- WEBGLVertexArray = class extends import_core20.VertexArray {
5615
+ WEBGLVertexArray = class extends import_core22.VertexArray {
5147
5616
  get [Symbol.toStringTag]() {
5148
5617
  return "VertexArray";
5149
5618
  }
@@ -5311,7 +5780,7 @@ ${source}`;
5311
5780
  this.buffer = this.buffer || this.device.createBuffer({ byteLength });
5312
5781
  updateNeeded ||= !compareConstantArrayValues(constantValue, this.bufferValue);
5313
5782
  if (updateNeeded) {
5314
- const typedArray = (0, import_core20.getScratchArray)(value.constructor, length);
5783
+ const typedArray = (0, import_core22.getScratchArray)(value.constructor, length);
5315
5784
  fillArray({ target: typedArray, source: constantValue, start: 0, count: length });
5316
5785
  this.buffer.write(typedArray);
5317
5786
  this.bufferValue = value;
@@ -5329,14 +5798,14 @@ ${source}`;
5329
5798
  }
5330
5799
  return /^\d+$/.test(value);
5331
5800
  }
5332
- var import_core21, WEBGLTransformFeedback;
5801
+ var import_core23, WEBGLTransformFeedback;
5333
5802
  var init_webgl_transform_feedback = __esm({
5334
5803
  "src/adapter/resources/webgl-transform-feedback.ts"() {
5335
5804
  "use strict";
5336
- import_core21 = __toESM(require_core(), 1);
5805
+ import_core23 = __toESM(require_core(), 1);
5337
5806
  init_src2();
5338
5807
  init_webgl_topology_utils();
5339
- WEBGLTransformFeedback = class extends import_core21.TransformFeedback {
5808
+ WEBGLTransformFeedback = class extends import_core23.TransformFeedback {
5340
5809
  device;
5341
5810
  gl;
5342
5811
  handle;
@@ -5389,8 +5858,8 @@ ${source}`;
5389
5858
  this.buffers = {};
5390
5859
  this.unusedBuffers = {};
5391
5860
  this.bind(() => {
5392
- for (const bufferName in buffers) {
5393
- this.setBuffer(bufferName, buffers[bufferName]);
5861
+ for (const [bufferName, buffer] of Object.entries(buffers)) {
5862
+ this.setBuffer(bufferName, buffer);
5394
5863
  }
5395
5864
  });
5396
5865
  }
@@ -5399,7 +5868,7 @@ ${source}`;
5399
5868
  const { buffer, byteLength, byteOffset } = this._getBufferRange(bufferOrRange);
5400
5869
  if (location < 0) {
5401
5870
  this.unusedBuffers[locationOrName] = buffer;
5402
- import_core21.log.warn(`${this.id} unusedBuffers varying buffer ${locationOrName}`)();
5871
+ import_core23.log.warn(`${this.id} unusedBuffers varying buffer ${locationOrName}`)();
5403
5872
  return;
5404
5873
  }
5405
5874
  this.buffers[location] = { buffer, byteLength, byteOffset };
@@ -5412,7 +5881,7 @@ ${source}`;
5412
5881
  return this.buffers[locationOrName] || null;
5413
5882
  }
5414
5883
  const location = this._getVaryingIndex(locationOrName);
5415
- return location >= 0 ? this.buffers[location] : null;
5884
+ return this.buffers[location] ?? null;
5416
5885
  }
5417
5886
  bind(funcOrHandle = this.handle) {
5418
5887
  if (typeof funcOrHandle !== "function") {
@@ -5459,8 +5928,8 @@ ${source}`;
5459
5928
  * cannot be bound to 'TRANSFORM_FEEDBACK_BUFFER' target.
5460
5929
  */
5461
5930
  _bindBuffers() {
5462
- for (const bufferIndex in this.buffers) {
5463
- const { buffer, byteLength, byteOffset } = this._getBufferRange(this.buffers[bufferIndex]);
5931
+ for (const [bufferIndex, bufferEntry] of Object.entries(this.buffers)) {
5932
+ const { buffer, byteLength, byteOffset } = this._getBufferRange(bufferEntry);
5464
5933
  this._bindBuffer(Number(bufferIndex), buffer, byteOffset, byteLength);
5465
5934
  }
5466
5935
  }
@@ -5482,156 +5951,249 @@ ${source}`;
5482
5951
  });
5483
5952
 
5484
5953
  // src/adapter/resources/webgl-query-set.ts
5485
- var import_core22, WEBGLQuerySet;
5954
+ var import_core24, WEBGLQuerySet;
5486
5955
  var init_webgl_query_set = __esm({
5487
5956
  "src/adapter/resources/webgl-query-set.ts"() {
5488
5957
  "use strict";
5489
- import_core22 = __toESM(require_core(), 1);
5490
- WEBGLQuerySet = class extends import_core22.QuerySet {
5958
+ import_core24 = __toESM(require_core(), 1);
5959
+ WEBGLQuerySet = class extends import_core24.QuerySet {
5491
5960
  device;
5492
5961
  handle;
5493
- target = null;
5494
- _queryPending = false;
5495
- _pollingPromise = null;
5962
+ _timestampPairs = [];
5963
+ _occlusionQuery = null;
5964
+ _occlusionActive = false;
5496
5965
  get [Symbol.toStringTag]() {
5497
- return "Query";
5966
+ return "QuerySet";
5498
5967
  }
5499
- // Create a query class
5500
5968
  constructor(device, props) {
5501
5969
  super(device, props);
5502
5970
  this.device = device;
5503
- if (props.count > 1) {
5504
- throw new Error("WebGL QuerySet can only have one value");
5505
- }
5506
- const handle = this.device.gl.createQuery();
5507
- if (!handle) {
5508
- throw new Error("WebGL query not supported");
5971
+ if (props.type === "timestamp") {
5972
+ if (props.count < 2) {
5973
+ throw new Error("Timestamp QuerySet requires at least two query slots");
5974
+ }
5975
+ this._timestampPairs = new Array(Math.ceil(props.count / 2)).fill(null).map(() => ({ activeQuery: null, completedQueries: [] }));
5976
+ this.handle = null;
5977
+ } else {
5978
+ if (props.count > 1) {
5979
+ throw new Error("WebGL occlusion QuerySet can only have one value");
5980
+ }
5981
+ const handle = this.device.gl.createQuery();
5982
+ if (!handle) {
5983
+ throw new Error("WebGL query not supported");
5984
+ }
5985
+ this.handle = handle;
5509
5986
  }
5510
- this.handle = handle;
5511
5987
  Object.seal(this);
5512
5988
  }
5513
5989
  destroy() {
5514
- this.device.gl.deleteQuery(this.handle);
5990
+ if (this.destroyed) {
5991
+ return;
5992
+ }
5993
+ if (this.handle) {
5994
+ this.device.gl.deleteQuery(this.handle);
5995
+ }
5996
+ for (const pair of this._timestampPairs) {
5997
+ if (pair.activeQuery) {
5998
+ this.device.gl.deleteQuery(pair.activeQuery.handle);
5999
+ }
6000
+ for (const query of pair.completedQueries) {
6001
+ this.device.gl.deleteQuery(query.handle);
6002
+ }
6003
+ }
6004
+ if (this._occlusionQuery) {
6005
+ this.device.gl.deleteQuery(this._occlusionQuery.handle);
6006
+ }
6007
+ this.destroyResource();
5515
6008
  }
5516
- // FOR RENDER PASS AND COMMAND ENCODER
5517
- /**
5518
- * Shortcut for timer query (dependent on extension in both WebGL1 and 2)
5519
- * Measures GPU time delta between this call and a matching `end` call in the
5520
- * GPU instruction stream.
5521
- */
5522
- beginTimestampQuery() {
5523
- return this._begin(35007 /* TIME_ELAPSED_EXT */);
6009
+ isResultAvailable(queryIndex) {
6010
+ if (this.props.type === "timestamp") {
6011
+ if (queryIndex === void 0) {
6012
+ return this._timestampPairs.some(
6013
+ (_, pairIndex) => this._isTimestampPairAvailable(pairIndex)
6014
+ );
6015
+ }
6016
+ return this._isTimestampPairAvailable(this._getTimestampPairIndex(queryIndex));
6017
+ }
6018
+ if (!this._occlusionQuery) {
6019
+ return false;
6020
+ }
6021
+ return this._pollQueryAvailability(this._occlusionQuery);
6022
+ }
6023
+ async readResults(options) {
6024
+ const firstQuery = options?.firstQuery || 0;
6025
+ const queryCount = options?.queryCount || this.props.count - firstQuery;
6026
+ this._validateRange(firstQuery, queryCount);
6027
+ if (this.props.type === "timestamp") {
6028
+ const results = new Array(queryCount).fill(0n);
6029
+ const startPairIndex = Math.floor(firstQuery / 2);
6030
+ const endPairIndex = Math.floor((firstQuery + queryCount - 1) / 2);
6031
+ for (let pairIndex = startPairIndex; pairIndex <= endPairIndex; pairIndex++) {
6032
+ const duration = await this._consumeTimestampPairResult(pairIndex);
6033
+ const beginSlot = pairIndex * 2;
6034
+ const endSlot = beginSlot + 1;
6035
+ if (beginSlot >= firstQuery && beginSlot < firstQuery + queryCount) {
6036
+ results[beginSlot - firstQuery] = 0n;
6037
+ }
6038
+ if (endSlot >= firstQuery && endSlot < firstQuery + queryCount) {
6039
+ results[endSlot - firstQuery] = duration;
6040
+ }
6041
+ }
6042
+ return results;
6043
+ }
6044
+ if (!this._occlusionQuery) {
6045
+ throw new Error("Occlusion query has not been started");
6046
+ }
6047
+ return [await this._consumeQueryResult(this._occlusionQuery)];
5524
6048
  }
5525
- endTimestampQuery() {
5526
- this._end();
6049
+ async readTimestampDuration(beginIndex, endIndex) {
6050
+ if (this.props.type !== "timestamp") {
6051
+ throw new Error("Timestamp durations require a timestamp QuerySet");
6052
+ }
6053
+ if (beginIndex < 0 || endIndex >= this.props.count || endIndex <= beginIndex) {
6054
+ throw new Error("Timestamp duration range is out of bounds");
6055
+ }
6056
+ if (beginIndex % 2 !== 0 || endIndex !== beginIndex + 1) {
6057
+ throw new Error("WebGL timestamp durations require adjacent even/odd query indices");
6058
+ }
6059
+ const result = await this._consumeTimestampPairResult(this._getTimestampPairIndex(beginIndex));
6060
+ return Number(result) / 1e6;
5527
6061
  }
5528
- // Shortcut for occlusion queries
5529
- beginOcclusionQuery(options) {
5530
- return this._begin(
5531
- options?.conservative ? 36202 /* ANY_SAMPLES_PASSED_CONSERVATIVE */ : 35887 /* ANY_SAMPLES_PASSED */
5532
- );
6062
+ beginOcclusionQuery() {
6063
+ if (this.props.type !== "occlusion") {
6064
+ throw new Error("Occlusion queries require an occlusion QuerySet");
6065
+ }
6066
+ if (!this.handle) {
6067
+ throw new Error("WebGL occlusion query is not available");
6068
+ }
6069
+ if (this._occlusionActive) {
6070
+ throw new Error("Occlusion query is already active");
6071
+ }
6072
+ this.device.gl.beginQuery(35887 /* ANY_SAMPLES_PASSED */, this.handle);
6073
+ this._occlusionQuery = {
6074
+ handle: this.handle,
6075
+ promise: null,
6076
+ result: null,
6077
+ disjoint: false
6078
+ };
6079
+ this._occlusionActive = true;
5533
6080
  }
5534
6081
  endOcclusionQuery() {
5535
- this._end();
5536
- }
5537
- // Shortcut for transformFeedbackQuery
5538
- beginTransformFeedbackQuery() {
5539
- return this._begin(35976 /* TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN */);
5540
- }
5541
- endTransformFeedbackQuery() {
5542
- this._end();
5543
- }
5544
- async resolveQuery() {
5545
- const value = await this.pollQuery();
5546
- return [value];
6082
+ if (!this._occlusionActive) {
6083
+ throw new Error("Occlusion query is not active");
6084
+ }
6085
+ this.device.gl.endQuery(35887 /* ANY_SAMPLES_PASSED */);
6086
+ this._occlusionActive = false;
5547
6087
  }
5548
- // PRIVATE METHODS
5549
- /**
5550
- * Due to OpenGL API limitations, after calling `begin()` on one Query
5551
- * instance, `end()` must be called on that same instance before
5552
- * calling `begin()` on another query. While there can be multiple
5553
- * outstanding queries representing disjoint `begin()`/`end()` intervals.
5554
- * It is not possible to interleave or overlap `begin` and `end` calls.
5555
- */
5556
- _begin(target2) {
5557
- if (this._queryPending) {
6088
+ writeTimestamp(queryIndex) {
6089
+ if (this.props.type !== "timestamp") {
6090
+ throw new Error("Timestamp writes require a timestamp QuerySet");
6091
+ }
6092
+ const pairIndex = this._getTimestampPairIndex(queryIndex);
6093
+ const pair = this._timestampPairs[pairIndex];
6094
+ if (queryIndex % 2 === 0) {
6095
+ if (pair.activeQuery) {
6096
+ throw new Error("Timestamp query pair is already active");
6097
+ }
6098
+ const handle = this.device.gl.createQuery();
6099
+ if (!handle) {
6100
+ throw new Error("WebGL query not supported");
6101
+ }
6102
+ const query = {
6103
+ handle,
6104
+ promise: null,
6105
+ result: null,
6106
+ disjoint: false
6107
+ };
6108
+ this.device.gl.beginQuery(35007 /* TIME_ELAPSED_EXT */, handle);
6109
+ pair.activeQuery = query;
5558
6110
  return;
5559
6111
  }
5560
- this.target = target2;
5561
- this.device.gl.beginQuery(this.target, this.handle);
5562
- return;
6112
+ if (!pair.activeQuery) {
6113
+ throw new Error("Timestamp query pair was ended before it was started");
6114
+ }
6115
+ this.device.gl.endQuery(35007 /* TIME_ELAPSED_EXT */);
6116
+ pair.completedQueries.push(pair.activeQuery);
6117
+ pair.activeQuery = null;
5563
6118
  }
5564
- // ends the current query
5565
- _end() {
5566
- if (this._queryPending) {
5567
- return;
6119
+ _validateRange(firstQuery, queryCount) {
6120
+ if (firstQuery < 0 || queryCount < 0 || firstQuery + queryCount > this.props.count) {
6121
+ throw new Error("Query read range is out of bounds");
5568
6122
  }
5569
- if (this.target) {
5570
- this.device.gl.endQuery(this.target);
5571
- this.target = null;
5572
- this._queryPending = true;
6123
+ }
6124
+ _getTimestampPairIndex(queryIndex) {
6125
+ if (queryIndex < 0 || queryIndex >= this.props.count) {
6126
+ throw new Error("Query index is out of bounds");
5573
6127
  }
5574
- return;
6128
+ return Math.floor(queryIndex / 2);
5575
6129
  }
5576
- // Returns true if the query result is available
5577
- isResultAvailable() {
5578
- if (!this._queryPending) {
6130
+ _isTimestampPairAvailable(pairIndex) {
6131
+ const pair = this._timestampPairs[pairIndex];
6132
+ if (!pair || pair.completedQueries.length === 0) {
5579
6133
  return false;
5580
6134
  }
6135
+ return this._pollQueryAvailability(pair.completedQueries[0]);
6136
+ }
6137
+ _pollQueryAvailability(query) {
6138
+ if (query.result !== null || query.disjoint) {
6139
+ return true;
6140
+ }
5581
6141
  const resultAvailable = this.device.gl.getQueryParameter(
5582
- this.handle,
6142
+ query.handle,
5583
6143
  34919 /* QUERY_RESULT_AVAILABLE */
5584
6144
  );
5585
- if (resultAvailable) {
5586
- this._queryPending = false;
6145
+ if (!resultAvailable) {
6146
+ return false;
5587
6147
  }
5588
- return resultAvailable;
5589
- }
5590
- // Timing query is disjoint, i.e. results are invalid
5591
- isTimerDisjoint() {
5592
- return this.device.gl.getParameter(36795 /* GPU_DISJOINT_EXT */);
5593
- }
5594
- // Returns query result.
5595
- getResult() {
5596
- return this.device.gl.getQueryParameter(this.handle, 34918 /* QUERY_RESULT */);
6148
+ const isDisjoint = Boolean(this.device.gl.getParameter(36795 /* GPU_DISJOINT_EXT */));
6149
+ query.disjoint = isDisjoint;
6150
+ query.result = isDisjoint ? 0n : BigInt(this.device.gl.getQueryParameter(query.handle, 34918 /* QUERY_RESULT */));
6151
+ return true;
5597
6152
  }
5598
- // Returns the query result, converted to milliseconds to match JavaScript conventions.
5599
- getTimerMilliseconds() {
5600
- return this.getResult() / 1e6;
6153
+ async _consumeTimestampPairResult(pairIndex) {
6154
+ const pair = this._timestampPairs[pairIndex];
6155
+ if (!pair || pair.completedQueries.length === 0) {
6156
+ throw new Error("Timestamp query pair has no completed result");
6157
+ }
6158
+ const query = pair.completedQueries.shift();
6159
+ try {
6160
+ return await this._consumeQueryResult(query);
6161
+ } finally {
6162
+ this.device.gl.deleteQuery(query.handle);
6163
+ }
5601
6164
  }
5602
- // Polls the query
5603
- pollQuery(limit = Number.POSITIVE_INFINITY) {
5604
- if (this._pollingPromise) {
5605
- return this._pollingPromise;
6165
+ _consumeQueryResult(query) {
6166
+ if (query.promise) {
6167
+ return query.promise;
5606
6168
  }
5607
- let counter = 0;
5608
- this._pollingPromise = new Promise((resolve, reject) => {
6169
+ query.promise = new Promise((resolve, reject) => {
5609
6170
  const poll = () => {
5610
- if (this.isResultAvailable()) {
5611
- resolve(this.getResult());
5612
- this._pollingPromise = null;
5613
- } else if (counter++ > limit) {
5614
- reject("Timed out");
5615
- this._pollingPromise = null;
5616
- } else {
6171
+ if (!this._pollQueryAvailability(query)) {
5617
6172
  requestAnimationFrame(poll);
6173
+ return;
6174
+ }
6175
+ query.promise = null;
6176
+ if (query.disjoint) {
6177
+ reject(new Error("GPU timestamp query was invalidated by a disjoint event"));
6178
+ } else {
6179
+ resolve(query.result || 0n);
5618
6180
  }
5619
6181
  };
5620
- requestAnimationFrame(poll);
6182
+ poll();
5621
6183
  });
5622
- return this._pollingPromise;
6184
+ return query.promise;
5623
6185
  }
5624
6186
  };
5625
6187
  }
5626
6188
  });
5627
6189
 
5628
6190
  // src/adapter/resources/webgl-fence.ts
5629
- var import_core23, WEBGLFence;
6191
+ var import_core25, WEBGLFence;
5630
6192
  var init_webgl_fence = __esm({
5631
6193
  "src/adapter/resources/webgl-fence.ts"() {
5632
6194
  "use strict";
5633
- import_core23 = __toESM(require_core(), 1);
5634
- WEBGLFence = class extends import_core23.Fence {
6195
+ import_core25 = __toESM(require_core(), 1);
6196
+ WEBGLFence = class extends import_core25.Fence {
5635
6197
  device;
5636
6198
  gl;
5637
6199
  handle;
@@ -5751,7 +6313,7 @@ ${source}`;
5751
6313
  sourceFormat ||= texture?.glFormat || 6408 /* RGBA */;
5752
6314
  sourceType ||= texture?.glType || 5121 /* UNSIGNED_BYTE */;
5753
6315
  target2 = getPixelArray(target2, sourceType, sourceFormat, sourceWidth, sourceHeight, sourceDepth);
5754
- const signedType = (0, import_core24.getDataType)(target2);
6316
+ const signedType = (0, import_core26.getDataType)(target2);
5755
6317
  sourceType = sourceType || convertDataTypeToGLDataType(signedType);
5756
6318
  const prevHandle = gl.bindFramebuffer(
5757
6319
  36160 /* FRAMEBUFFER */,
@@ -5803,7 +6365,7 @@ ${source}`;
5803
6365
  return webglBufferTarget;
5804
6366
  }
5805
6367
  function getFramebuffer2(source) {
5806
- if (!(source instanceof import_core24.Framebuffer)) {
6368
+ if (!(source instanceof import_core26.Framebuffer)) {
5807
6369
  return { framebuffer: toFramebuffer(source), deleteFramebuffer: true };
5808
6370
  }
5809
6371
  return { framebuffer: source, deleteFramebuffer: false };
@@ -5825,15 +6387,15 @@ ${source}`;
5825
6387
  }
5826
6388
  glType ||= 5121 /* UNSIGNED_BYTE */;
5827
6389
  const shaderType = convertGLDataTypeToDataType(glType);
5828
- const ArrayType = (0, import_core24.getTypedArrayConstructor)(shaderType);
6390
+ const ArrayType = (0, import_core26.getTypedArrayConstructor)(shaderType);
5829
6391
  const components = glFormatToComponents(glFormat);
5830
6392
  return new ArrayType(width * height * components);
5831
6393
  }
5832
- var import_core24;
6394
+ var import_core26;
5833
6395
  var init_webgl_texture_utils = __esm({
5834
6396
  "src/adapter/helpers/webgl-texture-utils.ts"() {
5835
6397
  "use strict";
5836
- import_core24 = __toESM(require_core(), 1);
6398
+ import_core26 = __toESM(require_core(), 1);
5837
6399
  init_webgl_shadertypes();
5838
6400
  init_format_utils();
5839
6401
  init_shader_formats();
@@ -5879,17 +6441,19 @@ ${source}`;
5879
6441
  }
5880
6442
  return true;
5881
6443
  }
5882
- var import_core25, WebGLDevice;
6444
+ var import_core27, WebGLDevice;
5883
6445
  var init_webgl_device = __esm({
5884
6446
  "src/adapter/webgl-device.ts"() {
5885
6447
  "use strict";
5886
- import_core25 = __toESM(require_core(), 1);
6448
+ import_core27 = __toESM(require_core(), 1);
5887
6449
  init_webgl_state_tracker();
5888
6450
  init_create_browser_context();
6451
+ init_webgl_context_data();
5889
6452
  init_webgl_device_info();
5890
6453
  init_webgl_device_features();
5891
6454
  init_webgl_device_limits();
5892
6455
  init_webgl_canvas_context();
6456
+ init_webgl_presentation_context();
5893
6457
  init_spector();
5894
6458
  init_webgl_developer_tools();
5895
6459
  init_webgl_texture_table();
@@ -5900,6 +6464,7 @@ ${source}`;
5900
6464
  init_webgl_texture();
5901
6465
  init_webgl_framebuffer();
5902
6466
  init_webgl_render_pipeline();
6467
+ init_webgl_shared_render_pipeline();
5903
6468
  init_webgl_command_encoder();
5904
6469
  init_webgl_vertex_array();
5905
6470
  init_webgl_transform_feedback();
@@ -5909,7 +6474,13 @@ ${source}`;
5909
6474
  init_unified_parameter_api();
5910
6475
  init_with_parameters();
5911
6476
  init_webgl_extensions();
5912
- WebGLDevice = class extends import_core25.Device {
6477
+ WebGLDevice = class extends import_core27.Device {
6478
+ static getDeviceFromContext(gl) {
6479
+ if (!gl) {
6480
+ return null;
6481
+ }
6482
+ return gl.luma?.device ?? null;
6483
+ }
5913
6484
  // Public `Device` API
5914
6485
  /** type of this device */
5915
6486
  type = "webgl";
@@ -5931,7 +6502,7 @@ ${source}`;
5931
6502
  // @ts-ignore TODO fix
5932
6503
  _constants;
5933
6504
  /** State used by luma.gl classes - TODO - not used? */
5934
- _extensions = {};
6505
+ extensions;
5935
6506
  _polyfilled = false;
5936
6507
  /** Instance of Spector.js (if initialized) */
5937
6508
  spectorJS;
@@ -5954,11 +6525,12 @@ ${source}`;
5954
6525
  }
5955
6526
  constructor(props) {
5956
6527
  super({ ...props, id: props.id || uid("webgl-device") });
5957
- const canvasContextProps = import_core25.Device._getCanvasContextProps(props);
6528
+ const canvasContextProps = import_core27.Device._getCanvasContextProps(props);
5958
6529
  if (!canvasContextProps) {
5959
6530
  throw new Error("WebGLDevice requires props.createCanvasContext to be set");
5960
6531
  }
5961
- let device = canvasContextProps.canvas?.gl?.device;
6532
+ const existingContext = canvasContextProps.canvas?.gl ?? null;
6533
+ let device = WebGLDevice.getDeviceFromContext(existingContext);
5962
6534
  if (device) {
5963
6535
  throw new Error(`WebGL context already attached to device ${device.id}`);
5964
6536
  }
@@ -5992,14 +6564,15 @@ ${source}`;
5992
6564
  if (!gl) {
5993
6565
  throw new Error("WebGL context creation failed");
5994
6566
  }
5995
- device = gl.device;
6567
+ device = WebGLDevice.getDeviceFromContext(gl);
5996
6568
  if (device) {
5997
6569
  if (props._reuseDevices) {
5998
- import_core25.log.log(
6570
+ import_core27.log.log(
5999
6571
  1,
6000
6572
  `Not creating a new Device, instead returning a reference to Device ${device.id} already attached to WebGL context`,
6001
6573
  device
6002
6574
  )();
6575
+ this.canvasContext.destroy();
6003
6576
  device._reused = true;
6004
6577
  return device;
6005
6578
  }
@@ -6008,29 +6581,28 @@ ${source}`;
6008
6581
  this.handle = gl;
6009
6582
  this.gl = gl;
6010
6583
  this.spectorJS = initializeSpectorJS({ ...this.props, gl: this.handle });
6011
- this.gl.device = this;
6012
- this.info = getDeviceInfo(this.gl, this._extensions);
6584
+ const contextData = getWebGLContextData(this.handle);
6585
+ contextData.device = this;
6586
+ this.extensions = contextData.extensions || (contextData.extensions = {});
6587
+ this.info = getDeviceInfo(this.gl, this.extensions);
6013
6588
  this.limits = new WebGLDeviceLimits(this.gl);
6014
- this.features = new WebGLDeviceFeatures(
6015
- this.gl,
6016
- this._extensions,
6017
- this.props._disabledFeatures
6018
- );
6589
+ this.features = new WebGLDeviceFeatures(this.gl, this.extensions, this.props._disabledFeatures);
6019
6590
  if (this.props._initializeFeatures) {
6020
6591
  this.features.initializeFeatures();
6021
6592
  }
6022
6593
  const glState = new WebGLStateTracker(this.gl, {
6023
- log: (...args) => import_core25.log.log(1, ...args)()
6594
+ log: (...args) => import_core27.log.log(1, ...args)()
6024
6595
  });
6025
6596
  glState.trackState(this.gl, { copyState: false });
6026
6597
  if (props.debug || props.debugWebGL) {
6027
6598
  this.gl = makeDebugContext(this.gl, { debugWebGL: true, traceWebGL: props.debugWebGL });
6028
- import_core25.log.warn("WebGL debug mode activated. Performance reduced.")();
6599
+ import_core27.log.warn("WebGL debug mode activated. Performance reduced.")();
6029
6600
  }
6030
6601
  if (props.debugWebGL) {
6031
- import_core25.log.level = Math.max(import_core25.log.level, 1);
6602
+ import_core27.log.level = Math.max(import_core27.log.level, 1);
6032
6603
  }
6033
6604
  this.commandEncoder = new WEBGLCommandEncoder(this, { id: `${this}-command-encoder` });
6605
+ this.canvasContext._startObservers();
6034
6606
  }
6035
6607
  /**
6036
6608
  * Destroys the device
@@ -6043,8 +6615,10 @@ ${source}`;
6043
6615
  * browser API for destroying WebGL contexts.
6044
6616
  */
6045
6617
  destroy() {
6618
+ this.commandEncoder?.destroy();
6046
6619
  if (!this.props._reuseDevices && !this._reused) {
6047
- delete this.gl.device;
6620
+ const contextData = getWebGLContextData(this.handle);
6621
+ contextData.device = null;
6048
6622
  }
6049
6623
  }
6050
6624
  get isLost() {
@@ -6054,6 +6628,9 @@ ${source}`;
6054
6628
  createCanvasContext(props) {
6055
6629
  throw new Error("WebGL only supports a single canvas");
6056
6630
  }
6631
+ createPresentationContext(props) {
6632
+ return new WebGLPresentationContext(this, props || {});
6633
+ }
6057
6634
  createBuffer(props) {
6058
6635
  const newProps = this._normalizeBufferProps(props);
6059
6636
  return new WEBGLBuffer(this, newProps);
@@ -6088,6 +6665,12 @@ ${source}`;
6088
6665
  createRenderPipeline(props) {
6089
6666
  return new WEBGLRenderPipeline(this, props);
6090
6667
  }
6668
+ _createSharedRenderPipelineWebGL(props) {
6669
+ return new WEBGLSharedRenderPipeline(
6670
+ this,
6671
+ props
6672
+ );
6673
+ }
6091
6674
  createComputePipeline(props) {
6092
6675
  throw new Error("ComputePipeline not supported in WebGL");
6093
6676
  }
@@ -6100,12 +6683,27 @@ ${source}`;
6100
6683
  * Chrome's offscreen canvas does not require gl.commit
6101
6684
  */
6102
6685
  submit(commandBuffer) {
6686
+ let submittedCommandEncoder = null;
6103
6687
  if (!commandBuffer) {
6104
- commandBuffer = this.commandEncoder.finish();
6688
+ submittedCommandEncoder = this.commandEncoder;
6689
+ commandBuffer = submittedCommandEncoder.finish();
6105
6690
  this.commandEncoder.destroy();
6106
- this.commandEncoder = this.createCommandEncoder({ id: `${this.id}-default-encoder` });
6691
+ this.commandEncoder = this.createCommandEncoder({
6692
+ id: submittedCommandEncoder.props.id,
6693
+ timeProfilingQuerySet: submittedCommandEncoder.getTimeProfilingQuerySet()
6694
+ });
6695
+ }
6696
+ try {
6697
+ commandBuffer._executeCommands();
6698
+ if (submittedCommandEncoder) {
6699
+ submittedCommandEncoder.resolveTimeProfilingQuerySet().then(() => {
6700
+ this.commandEncoder._gpuTimeMs = submittedCommandEncoder._gpuTimeMs;
6701
+ }).catch(() => {
6702
+ });
6703
+ }
6704
+ } finally {
6705
+ commandBuffer.destroy();
6107
6706
  }
6108
- commandBuffer._executeCommands();
6109
6707
  }
6110
6708
  //
6111
6709
  // TEMPORARY HACKS - will be removed in v9.1
@@ -6128,11 +6726,11 @@ ${source}`;
6128
6726
  return withGLParameters(this.gl, parameters, func);
6129
6727
  }
6130
6728
  resetWebGL() {
6131
- import_core25.log.warn("WebGLDevice.resetWebGL is deprecated, use only for debugging")();
6729
+ import_core27.log.warn("WebGLDevice.resetWebGL is deprecated, use only for debugging")();
6132
6730
  resetGLParameters(this.gl);
6133
6731
  }
6134
6732
  _getDeviceSpecificTextureFormatCapabilities(capabilities) {
6135
- return getTextureFormatCapabilitiesWebGL(this.gl, capabilities, this._extensions);
6733
+ return getTextureFormatCapabilitiesWebGL(this.gl, capabilities, this.extensions);
6136
6734
  }
6137
6735
  //
6138
6736
  // WebGL-only API (not part of `Device` API)
@@ -6200,7 +6798,7 @@ ${source}`;
6200
6798
  this._constants = this._constants || new Array(maxVertexAttributes).fill(null);
6201
6799
  const currentConstant = this._constants[location];
6202
6800
  if (currentConstant && compareConstantArrayValues2(currentConstant, constant)) {
6203
- import_core25.log.info(
6801
+ import_core27.log.info(
6204
6802
  1,
6205
6803
  `setConstantAttributeWebGL(${location}) could have been skipped, value unchanged`
6206
6804
  )();
@@ -6222,8 +6820,8 @@ ${source}`;
6222
6820
  }
6223
6821
  /** Ensure extensions are only requested once */
6224
6822
  getExtension(name) {
6225
- getWebGLExtension(this.gl, name, this._extensions);
6226
- return this._extensions;
6823
+ getWebGLExtension(this.gl, name, this.extensions);
6824
+ return this.extensions;
6227
6825
  }
6228
6826
  // INTERNAL SUPPORT METHODS FOR WEBGL RESOURCES
6229
6827
  /**
@@ -6246,21 +6844,21 @@ ${source}`;
6246
6844
  }
6247
6845
  return Boolean(gl && typeof gl.createVertexArray === "function");
6248
6846
  }
6249
- var import_core26, LOG_LEVEL2, WebGLAdapter, webgl2Adapter;
6847
+ var import_core28, LOG_LEVEL2, WebGLAdapter, webgl2Adapter;
6250
6848
  var init_webgl_adapter = __esm({
6251
6849
  "src/adapter/webgl-adapter.ts"() {
6252
6850
  "use strict";
6253
- import_core26 = __toESM(require_core(), 1);
6851
+ import_core28 = __toESM(require_core(), 1);
6254
6852
  init_polyfill_webgl1_extensions();
6255
6853
  init_spector();
6256
6854
  init_webgl_developer_tools();
6257
6855
  LOG_LEVEL2 = 1;
6258
- WebGLAdapter = class extends import_core26.Adapter {
6856
+ WebGLAdapter = class extends import_core28.Adapter {
6259
6857
  /** type of device's created by this adapter */
6260
6858
  type = "webgl";
6261
6859
  constructor() {
6262
6860
  super();
6263
- import_core26.Device.defaultProps = { ...import_core26.Device.defaultProps, ...DEFAULT_SPECTOR_PROPS };
6861
+ import_core28.Device.defaultProps = { ...import_core28.Device.defaultProps, ...DEFAULT_SPECTOR_PROPS };
6264
6862
  }
6265
6863
  /** Force any created WebGL contexts to be WebGL2 contexts, polyfilled with WebGL1 extensions */
6266
6864
  enforceWebGL2(enable2) {
@@ -6275,7 +6873,7 @@ ${source}`;
6275
6873
  return true;
6276
6874
  }
6277
6875
  if (typeof WebGLRenderingContext !== "undefined" && handle instanceof WebGLRenderingContext) {
6278
- import_core26.log.warn("WebGL1 is not supported", handle)();
6876
+ import_core28.log.warn("WebGL1 is not supported", handle)();
6279
6877
  }
6280
6878
  return false;
6281
6879
  }
@@ -6291,8 +6889,9 @@ ${source}`;
6291
6889
  if (gl instanceof WebGLDevice2) {
6292
6890
  return gl;
6293
6891
  }
6294
- if (gl?.device instanceof WebGLDevice2) {
6295
- return gl.device;
6892
+ const existingDevice = WebGLDevice2.getDeviceFromContext(gl);
6893
+ if (existingDevice) {
6894
+ return existingDevice;
6296
6895
  }
6297
6896
  if (!isWebGL(gl)) {
6298
6897
  throw new Error("Invalid WebGL2RenderingContext");
@@ -6316,19 +6915,19 @@ ${source}`;
6316
6915
  const results = await Promise.allSettled(promises);
6317
6916
  for (const result of results) {
6318
6917
  if (result.status === "rejected") {
6319
- import_core26.log.error(`Failed to initialize debug libraries ${result.reason}`)();
6918
+ import_core28.log.error(`Failed to initialize debug libraries ${result.reason}`)();
6320
6919
  }
6321
6920
  }
6322
6921
  try {
6323
6922
  const device = new WebGLDevice2(props);
6324
- import_core26.log.groupCollapsed(LOG_LEVEL2, `WebGLDevice ${device.id} created`)();
6923
+ import_core28.log.groupCollapsed(LOG_LEVEL2, `WebGLDevice ${device.id} created`)();
6325
6924
  const message2 = `${device._reused ? "Reusing" : "Created"} device with WebGL2 ${device.props.debug ? "debug " : ""}context: ${device.info.vendor}, ${device.info.renderer} for canvas: ${device.canvasContext.id}`;
6326
- import_core26.log.probe(LOG_LEVEL2, message2)();
6327
- import_core26.log.table(LOG_LEVEL2, device.info)();
6925
+ import_core28.log.probe(LOG_LEVEL2, message2)();
6926
+ import_core28.log.table(LOG_LEVEL2, device.info)();
6328
6927
  return device;
6329
6928
  } finally {
6330
- import_core26.log.groupEnd(LOG_LEVEL2)();
6331
- import_core26.log.info(
6929
+ import_core28.log.groupEnd(LOG_LEVEL2)();
6930
+ import_core28.log.info(
6332
6931
  LOG_LEVEL2,
6333
6932
  `%cWebGL call tracing: luma.log.set('debug-webgl') `,
6334
6933
  "color: white; background: blue; padding: 2px 6px; border-radius: 3px;"