@luma.gl/webgl 9.3.0-alpha.4 → 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 (68) 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 +16 -17
  11. package/dist/adapter/helpers/get-shader-layout-from-glsl.js.map +1 -1
  12. package/dist/adapter/resources/webgl-buffer.d.ts.map +1 -1
  13. package/dist/adapter/resources/webgl-buffer.js +19 -4
  14. package/dist/adapter/resources/webgl-buffer.js.map +1 -1
  15. package/dist/adapter/resources/webgl-command-buffer.d.ts +2 -2
  16. package/dist/adapter/resources/webgl-command-buffer.d.ts.map +1 -1
  17. package/dist/adapter/resources/webgl-command-buffer.js +2 -2
  18. package/dist/adapter/resources/webgl-command-buffer.js.map +1 -1
  19. package/dist/adapter/resources/webgl-command-encoder.d.ts +5 -4
  20. package/dist/adapter/resources/webgl-command-encoder.d.ts.map +1 -1
  21. package/dist/adapter/resources/webgl-command-encoder.js +20 -7
  22. package/dist/adapter/resources/webgl-command-encoder.js.map +1 -1
  23. package/dist/adapter/resources/webgl-query-set.d.ts +29 -31
  24. package/dist/adapter/resources/webgl-query-set.d.ts.map +1 -1
  25. package/dist/adapter/resources/webgl-query-set.js +193 -97
  26. package/dist/adapter/resources/webgl-query-set.js.map +1 -1
  27. package/dist/adapter/resources/webgl-render-pass.d.ts.map +1 -1
  28. package/dist/adapter/resources/webgl-render-pass.js +12 -0
  29. package/dist/adapter/resources/webgl-render-pass.js.map +1 -1
  30. package/dist/adapter/resources/webgl-render-pipeline.d.ts +13 -19
  31. package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
  32. package/dist/adapter/resources/webgl-render-pipeline.js +35 -152
  33. package/dist/adapter/resources/webgl-render-pipeline.js.map +1 -1
  34. package/dist/adapter/resources/webgl-shared-render-pipeline.d.ts +24 -0
  35. package/dist/adapter/resources/webgl-shared-render-pipeline.d.ts.map +1 -0
  36. package/dist/adapter/resources/webgl-shared-render-pipeline.js +152 -0
  37. package/dist/adapter/resources/webgl-shared-render-pipeline.js.map +1 -0
  38. package/dist/adapter/resources/webgl-texture.d.ts +23 -4
  39. package/dist/adapter/resources/webgl-texture.d.ts.map +1 -1
  40. package/dist/adapter/resources/webgl-texture.js +203 -100
  41. package/dist/adapter/resources/webgl-texture.js.map +1 -1
  42. package/dist/adapter/webgl-device.d.ts +4 -2
  43. package/dist/adapter/webgl-device.d.ts.map +1 -1
  44. package/dist/adapter/webgl-device.js +31 -3
  45. package/dist/adapter/webgl-device.js.map +1 -1
  46. package/dist/adapter/webgl-presentation-context.d.ts +21 -0
  47. package/dist/adapter/webgl-presentation-context.d.ts.map +1 -0
  48. package/dist/adapter/webgl-presentation-context.js +64 -0
  49. package/dist/adapter/webgl-presentation-context.js.map +1 -0
  50. package/dist/dist.dev.js +1332 -788
  51. package/dist/dist.min.js +2 -2
  52. package/dist/index.cjs +1247 -797
  53. package/dist/index.cjs.map +4 -4
  54. package/package.json +3 -3
  55. package/src/adapter/converters/webgl-texture-table.ts +159 -47
  56. package/src/adapter/device-helpers/webgl-device-features.ts +1 -2
  57. package/src/adapter/device-helpers/webgl-device-info.ts +6 -0
  58. package/src/adapter/helpers/get-shader-layout-from-glsl.ts +18 -19
  59. package/src/adapter/resources/webgl-buffer.ts +16 -4
  60. package/src/adapter/resources/webgl-command-buffer.ts +3 -2
  61. package/src/adapter/resources/webgl-command-encoder.ts +22 -7
  62. package/src/adapter/resources/webgl-query-set.ts +229 -102
  63. package/src/adapter/resources/webgl-render-pass.ts +13 -0
  64. package/src/adapter/resources/webgl-render-pipeline.ts +45 -179
  65. package/src/adapter/resources/webgl-shared-render-pipeline.ts +208 -0
  66. package/src/adapter/resources/webgl-texture.ts +326 -121
  67. package/src/adapter/webgl-device.ts +40 -4
  68. package/src/adapter/webgl-presentation-context.ts +93 -0
package/dist/dist.dev.js CHANGED
@@ -1983,6 +1983,8 @@ var __exports__ = (() => {
1983
1983
  }
1984
1984
  const gpuVendor = identifyGPUVendor(vendor, renderer);
1985
1985
  switch (gpuVendor) {
1986
+ case "apple":
1987
+ return isAppleSiliconGPU(vendor, renderer) ? "integrated" : "unknown";
1986
1988
  case "intel":
1987
1989
  return "integrated";
1988
1990
  case "software":
@@ -1993,6 +1995,9 @@ var __exports__ = (() => {
1993
1995
  return "discrete";
1994
1996
  }
1995
1997
  }
1998
+ function isAppleSiliconGPU(vendor, renderer) {
1999
+ return /Apple (M\d|A\d|GPU)/i.test(`${vendor} ${renderer}`);
2000
+ }
1996
2001
  var init_webgl_device_info = __esm({
1997
2002
  "src/adapter/device-helpers/webgl-device-info.ts"() {
1998
2003
  "use strict";
@@ -2041,8 +2046,27 @@ var __exports__ = (() => {
2041
2046
  return feature in TEXTURE_FEATURES;
2042
2047
  }
2043
2048
  function checkTextureFeature(gl, feature, extensions) {
2044
- const textureExtensions = TEXTURE_FEATURES[feature] || [];
2045
- 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
+ );
2046
2070
  }
2047
2071
  function getTextureFormatCapabilitiesWebGL(gl, formatSupport, extensions) {
2048
2072
  let supported = formatSupport.create;
@@ -2053,12 +2077,17 @@ var __exports__ = (() => {
2053
2077
  if (webglFormatInfo?.x) {
2054
2078
  supported = supported && Boolean(getWebGLExtension(gl, webglFormatInfo.x, extensions));
2055
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);
2056
2085
  return {
2057
2086
  format: formatSupport.format,
2058
2087
  // @ts-ignore
2059
2088
  create: supported && formatSupport.create,
2060
2089
  // @ts-ignore
2061
- render: supported && formatSupport.render,
2090
+ render: renderable,
2062
2091
  // @ts-ignore
2063
2092
  filter: supported && formatSupport.filter,
2064
2093
  // @ts-ignore
@@ -2067,6 +2096,45 @@ var __exports__ = (() => {
2067
2096
  store: supported && formatSupport.store
2068
2097
  };
2069
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
+ }
2070
2138
  function getTextureFormatWebGL(format) {
2071
2139
  const formatData = WEBGL_TEXTURE_FORMATS[format];
2072
2140
  const webglFormat = convertTextureFormatToGL(format);
@@ -2122,7 +2190,7 @@ var __exports__ = (() => {
2122
2190
  }
2123
2191
  return webglFormat;
2124
2192
  }
2125
- 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;
2126
2194
  var init_webgl_texture_table = __esm({
2127
2195
  "src/adapter/converters/webgl-texture-table.ts"() {
2128
2196
  "use strict";
@@ -2141,44 +2209,51 @@ var __exports__ = (() => {
2141
2209
  EXT_texture_norm16 = "EXT_texture_norm16";
2142
2210
  EXT_render_snorm = "EXT_render_snorm";
2143
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";
2144
2218
  TEXTURE_FEATURES = {
2145
- "float32-renderable-webgl": ["EXT_color_buffer_float"],
2146
- "float16-renderable-webgl": ["EXT_color_buffer_half_float"],
2147
- "rgb9e5ufloat-renderable-webgl": ["WEBGL_render_shared_exponent"],
2148
- "snorm8-renderable-webgl": [EXT_render_snorm],
2149
- "norm16-renderable-webgl": [EXT_texture_norm16],
2150
- "snorm16-renderable-webgl": [EXT_texture_norm16, EXT_render_snorm],
2151
- "float32-filterable": ["OES_texture_float_linear"],
2152
- "float16-filterable-webgl": ["OES_texture_half_float_linear"],
2153
- "texture-filterable-anisotropic-webgl": ["EXT_texture_filter_anisotropic"],
2154
- "texture-blend-float-webgl": ["EXT_float_blend"],
2155
- "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] },
2156
2231
  // 'texture-compression-bc3-srgb-webgl': [X_S3TC_SRGB],
2157
2232
  // 'texture-compression-bc3-webgl': [X_S3TC],
2158
- "texture-compression-bc5-webgl": [X_RGTC],
2159
- "texture-compression-bc7-webgl": [X_BPTC],
2160
- "texture-compression-etc2": [X_ETC2],
2161
- "texture-compression-astc": [X_ASTC],
2162
- "texture-compression-etc1-webgl": [X_ETC1],
2163
- "texture-compression-pvrtc-webgl": [X_PVRTC],
2164
- "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] }
2165
2240
  };
2166
2241
  WEBGL_TEXTURE_FORMATS = {
2167
2242
  // 8-bit formats
2168
2243
  "r8unorm": { gl: 33321 /* R8 */, rb: true },
2169
- "r8snorm": { gl: 36756 /* R8_SNORM */ },
2244
+ "r8snorm": { gl: 36756 /* R8_SNORM */, r: SNORM8_COLOR_RENDERABLE },
2170
2245
  "r8uint": { gl: 33330 /* R8UI */, rb: true },
2171
2246
  "r8sint": { gl: 33329 /* R8I */, rb: true },
2172
2247
  // 16-bit formats
2173
2248
  "rg8unorm": { gl: 33323 /* RG8 */, rb: true },
2174
- "rg8snorm": { gl: 36757 /* RG8_SNORM */ },
2249
+ "rg8snorm": { gl: 36757 /* RG8_SNORM */, r: SNORM8_COLOR_RENDERABLE },
2175
2250
  "rg8uint": { gl: 33336 /* RG8UI */, rb: true },
2176
2251
  "rg8sint": { gl: 33335 /* RG8I */, rb: true },
2177
2252
  "r16uint": { gl: 33332 /* R16UI */, rb: true },
2178
2253
  "r16sint": { gl: 33331 /* R16I */, rb: true },
2179
- "r16float": { gl: 33325 /* R16F */, rb: true },
2180
- "r16unorm": { gl: 33322 /* R16_EXT */, rb: true },
2181
- "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 },
2182
2257
  // Packed 16-bit formats
2183
2258
  "rgba4unorm-webgl": { gl: 32854 /* RGBA4 */, rb: true },
2184
2259
  "rgb565unorm-webgl": { gl: 36194 /* RGB565 */, rb: true },
@@ -2189,7 +2264,7 @@ var __exports__ = (() => {
2189
2264
  // 32-bit formats
2190
2265
  "rgba8unorm": { gl: 32856 /* RGBA8 */ },
2191
2266
  "rgba8unorm-srgb": { gl: 35907 /* SRGB8_ALPHA8 */ },
2192
- "rgba8snorm": { gl: 36759 /* RGBA8_SNORM */ },
2267
+ "rgba8snorm": { gl: 36759 /* RGBA8_SNORM */, r: SNORM8_COLOR_RENDERABLE },
2193
2268
  "rgba8uint": { gl: 36220 /* RGBA8UI */ },
2194
2269
  "rgba8sint": { gl: 36238 /* RGBA8I */ },
2195
2270
  // reverse colors, webgpu only
@@ -2197,38 +2272,38 @@ var __exports__ = (() => {
2197
2272
  "bgra8unorm-srgb": {},
2198
2273
  "rg16uint": { gl: 33338 /* RG16UI */ },
2199
2274
  "rg16sint": { gl: 33337 /* RG16I */ },
2200
- "rg16float": { gl: 33327 /* RG16F */, rb: true },
2201
- "rg16unorm": { gl: 33324 /* RG16_EXT */ },
2202
- "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 },
2203
2278
  "r32uint": { gl: 33334 /* R32UI */, rb: true },
2204
2279
  "r32sint": { gl: 33333 /* R32I */, rb: true },
2205
- "r32float": { gl: 33326 /* R32F */ },
2280
+ "r32float": { gl: 33326 /* R32F */, r: FLOAT32_COLOR_RENDERABLE },
2206
2281
  // Packed 32-bit formats
2207
- "rgb9e5ufloat": { gl: 35901 /* RGB9_E5 */ },
2282
+ "rgb9e5ufloat": { gl: 35901 /* RGB9_E5 */, r: RGB9E5UFLOAT_COLOR_RENDERABLE },
2208
2283
  // , filter: true},
2209
2284
  "rg11b10ufloat": { gl: 35898 /* R11F_G11F_B10F */, rb: true },
2210
2285
  "rgb10a2unorm": { gl: 32857 /* RGB10_A2 */, rb: true },
2211
2286
  "rgb10a2uint": { gl: 36975 /* RGB10_A2UI */, rb: true },
2212
2287
  // 48-bit formats
2213
- "rgb16unorm-webgl": { gl: 32852 /* RGB16_EXT */ },
2288
+ "rgb16unorm-webgl": { gl: 32852 /* RGB16_EXT */, r: false },
2214
2289
  // rgb not renderable
2215
- "rgb16snorm-webgl": { gl: 36762 /* RGB16_SNORM_EXT */ },
2290
+ "rgb16snorm-webgl": { gl: 36762 /* RGB16_SNORM_EXT */, r: false },
2216
2291
  // rgb not renderable
2217
2292
  // 64-bit formats
2218
2293
  "rg32uint": { gl: 33340 /* RG32UI */, rb: true },
2219
2294
  "rg32sint": { gl: 33339 /* RG32I */, rb: true },
2220
- "rg32float": { gl: 33328 /* RG32F */, rb: true },
2295
+ "rg32float": { gl: 33328 /* RG32F */, rb: true, r: FLOAT32_COLOR_RENDERABLE },
2221
2296
  "rgba16uint": { gl: 36214 /* RGBA16UI */, rb: true },
2222
2297
  "rgba16sint": { gl: 36232 /* RGBA16I */, rb: true },
2223
- "rgba16float": { gl: 34842 /* RGBA16F */ },
2224
- "rgba16unorm": { gl: 32859 /* RGBA16_EXT */, rb: true },
2225
- "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 },
2226
2301
  // 96-bit formats (deprecated!)
2227
- "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 */] },
2228
2303
  // 128-bit formats
2229
2304
  "rgba32uint": { gl: 36208 /* RGBA32UI */, rb: true },
2230
2305
  "rgba32sint": { gl: 36226 /* RGBA32I */, rb: true },
2231
- "rgba32float": { gl: 34836 /* RGBA32F */, rb: true },
2306
+ "rgba32float": { gl: 34836 /* RGBA32F */, rb: true, r: FLOAT32_COLOR_RENDERABLE },
2232
2307
  // Depth and stencil formats
2233
2308
  "stencil8": { gl: 36168 /* STENCIL_INDEX8 */, rb: true },
2234
2309
  // 8 stencil bits
@@ -2286,8 +2361,8 @@ var __exports__ = (() => {
2286
2361
  "astc-8x6-unorm-srgb": { gl: 37846 /* COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR */ },
2287
2362
  "astc-8x8-unorm": { gl: 37815 /* COMPRESSED_RGBA_ASTC_8x8_KHR */ },
2288
2363
  "astc-8x8-unorm-srgb": { gl: 37847 /* COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR */ },
2289
- "astc-10x5-unorm": { gl: 37819 /* COMPRESSED_RGBA_ASTC_10x10_KHR */ },
2290
- "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 */ },
2291
2366
  "astc-10x6-unorm": { gl: 37817 /* COMPRESSED_RGBA_ASTC_10x6_KHR */ },
2292
2367
  "astc-10x6-unorm-srgb": { gl: 37849 /* COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR */ },
2293
2368
  "astc-10x8-unorm": { gl: 37818 /* COMPRESSED_RGBA_ASTC_10x8_KHR */ },
@@ -2301,7 +2376,7 @@ var __exports__ = (() => {
2301
2376
  // WEBGL_compressed_texture_pvrtc
2302
2377
  "pvrtc-rgb4unorm-webgl": { gl: 35840 /* COMPRESSED_RGB_PVRTC_4BPPV1_IMG */ },
2303
2378
  "pvrtc-rgba4unorm-webgl": { gl: 35842 /* COMPRESSED_RGBA_PVRTC_4BPPV1_IMG */ },
2304
- "pvrtc-rbg2unorm-webgl": { gl: 35841 /* COMPRESSED_RGB_PVRTC_2BPPV1_IMG */ },
2379
+ "pvrtc-rgb2unorm-webgl": { gl: 35841 /* COMPRESSED_RGB_PVRTC_2BPPV1_IMG */ },
2305
2380
  "pvrtc-rgba2unorm-webgl": { gl: 35843 /* COMPRESSED_RGBA_PVRTC_2BPPV1_IMG */ },
2306
2381
  // WEBGL_compressed_texture_etc1
2307
2382
  "etc1-rbg-unorm-webgl": { gl: 36196 /* COMPRESSED_RGB_ETC1_WEBGL */ },
@@ -2325,12 +2400,11 @@ var __exports__ = (() => {
2325
2400
  // optional WebGPU features
2326
2401
  "depth-clip-control": "EXT_depth_clamp",
2327
2402
  // TODO these seem subtly different
2328
- // 'timestamp-query' // GPUQueryType "timestamp-query"
2403
+ "timestamp-query": "EXT_disjoint_timer_query_webgl2",
2329
2404
  // "indirect-first-instance"
2330
2405
  // Textures are handled by getTextureFeatures()
2331
2406
  // 'depth32float-stencil8' // GPUTextureFormat 'depth32float-stencil8'
2332
2407
  // optional WebGL features
2333
- "timer-query-webgl": "EXT_disjoint_timer_query_webgl2",
2334
2408
  "compilation-status-async-webgl": "KHR_parallel_shader_compile",
2335
2409
  "polygon-mode-webgl": "WEBGL_polygon_mode",
2336
2410
  "provoking-vertex-webgl": "WEBGL_provoking_vertex",
@@ -2675,6 +2749,65 @@ var __exports__ = (() => {
2675
2749
  }
2676
2750
  });
2677
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
+
2678
2811
  // src/utils/uid.ts
2679
2812
  function uid(id = "id") {
2680
2813
  uidCounters[id] = uidCounters[id] || 1;
@@ -2691,35 +2824,35 @@ var __exports__ = (() => {
2691
2824
 
2692
2825
  // src/adapter/resources/webgl-buffer.ts
2693
2826
  function getWebGLTarget(usage) {
2694
- if (usage & import_core8.Buffer.INDEX) {
2827
+ if (usage & import_core9.Buffer.INDEX) {
2695
2828
  return 34963 /* ELEMENT_ARRAY_BUFFER */;
2696
2829
  }
2697
- if (usage & import_core8.Buffer.VERTEX) {
2830
+ if (usage & import_core9.Buffer.VERTEX) {
2698
2831
  return 34962 /* ARRAY_BUFFER */;
2699
2832
  }
2700
- if (usage & import_core8.Buffer.UNIFORM) {
2833
+ if (usage & import_core9.Buffer.UNIFORM) {
2701
2834
  return 35345 /* UNIFORM_BUFFER */;
2702
2835
  }
2703
2836
  return 34962 /* ARRAY_BUFFER */;
2704
2837
  }
2705
2838
  function getWebGLUsage(usage) {
2706
- if (usage & import_core8.Buffer.INDEX) {
2839
+ if (usage & import_core9.Buffer.INDEX) {
2707
2840
  return 35044 /* STATIC_DRAW */;
2708
2841
  }
2709
- if (usage & import_core8.Buffer.VERTEX) {
2842
+ if (usage & import_core9.Buffer.VERTEX) {
2710
2843
  return 35044 /* STATIC_DRAW */;
2711
2844
  }
2712
- if (usage & import_core8.Buffer.UNIFORM) {
2845
+ if (usage & import_core9.Buffer.UNIFORM) {
2713
2846
  return 35048 /* DYNAMIC_DRAW */;
2714
2847
  }
2715
2848
  return 35044 /* STATIC_DRAW */;
2716
2849
  }
2717
- var import_core8, WEBGLBuffer;
2850
+ var import_core9, WEBGLBuffer;
2718
2851
  var init_webgl_buffer = __esm({
2719
2852
  "src/adapter/resources/webgl-buffer.ts"() {
2720
2853
  "use strict";
2721
- import_core8 = __toESM(require_core(), 1);
2722
- WEBGLBuffer = class extends import_core8.Buffer {
2854
+ import_core9 = __toESM(require_core(), 1);
2855
+ WEBGLBuffer = class extends import_core9.Buffer {
2723
2856
  device;
2724
2857
  gl;
2725
2858
  handle;
@@ -2754,8 +2887,12 @@ var __exports__ = (() => {
2754
2887
  destroy() {
2755
2888
  if (!this.destroyed && this.handle) {
2756
2889
  this.removeStats();
2757
- this.trackDeallocatedMemory();
2758
- 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
+ }
2759
2896
  this.destroyed = true;
2760
2897
  this.handle = null;
2761
2898
  }
@@ -2770,7 +2907,11 @@ var __exports__ = (() => {
2770
2907
  this.bytesUsed = byteLength;
2771
2908
  this.byteLength = byteLength;
2772
2909
  this._setDebugData(data, byteOffset, byteLength);
2773
- this.trackAllocatedMemory(byteLength);
2910
+ if (!this.props.handle) {
2911
+ this.trackAllocatedMemory(byteLength);
2912
+ } else {
2913
+ this.trackReferencedMemory(byteLength, "Buffer");
2914
+ }
2774
2915
  }
2775
2916
  // Allocate a GPU buffer of specified size.
2776
2917
  _initWithByteLength(byteLength) {
@@ -2785,7 +2926,11 @@ var __exports__ = (() => {
2785
2926
  this.bytesUsed = byteLength;
2786
2927
  this.byteLength = byteLength;
2787
2928
  this._setDebugData(null, 0, byteLength);
2788
- this.trackAllocatedMemory(byteLength);
2929
+ if (!this.props.handle) {
2930
+ this.trackAllocatedMemory(byteLength);
2931
+ } else {
2932
+ this.trackReferencedMemory(byteLength, "Buffer");
2933
+ }
2789
2934
  return this;
2790
2935
  }
2791
2936
  write(data, byteOffset = 0) {
@@ -2898,13 +3043,13 @@ var __exports__ = (() => {
2898
3043
  });
2899
3044
 
2900
3045
  // src/adapter/resources/webgl-shader.ts
2901
- var import_core9, WEBGLShader;
3046
+ var import_core10, WEBGLShader;
2902
3047
  var init_webgl_shader = __esm({
2903
3048
  "src/adapter/resources/webgl-shader.ts"() {
2904
3049
  "use strict";
2905
- import_core9 = __toESM(require_core(), 1);
3050
+ import_core10 = __toESM(require_core(), 1);
2906
3051
  init_parse_shader_compiler_log();
2907
- WEBGLShader = class extends import_core9.Shader {
3052
+ WEBGLShader = class extends import_core10.Shader {
2908
3053
  device;
2909
3054
  handle;
2910
3055
  constructor(device, props) {
@@ -2970,9 +3115,9 @@ ${source}`;
2970
3115
  }
2971
3116
  return;
2972
3117
  }
2973
- import_core9.log.once(1, "Shader compilation is asynchronous")();
3118
+ import_core10.log.once(1, "Shader compilation is asynchronous")();
2974
3119
  await this._waitForCompilationComplete();
2975
- 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}`)();
2976
3121
  this._getCompilationStatus();
2977
3122
  this.debugShader();
2978
3123
  }
@@ -3139,7 +3284,7 @@ ${source}`;
3139
3284
  gl.stencilMaskSeparate(1029 /* BACK */, mask);
3140
3285
  }
3141
3286
  if (parameters.stencilReadMask) {
3142
- import_core10.log.warn("stencilReadMask not supported under WebGL");
3287
+ import_core11.log.warn("stencilReadMask not supported under WebGL");
3143
3288
  }
3144
3289
  if (parameters.stencilCompare) {
3145
3290
  const mask = parameters.stencilReadMask || 4294967295;
@@ -3273,11 +3418,11 @@ ${source}`;
3273
3418
  }
3274
3419
  return isEmpty;
3275
3420
  }
3276
- var import_core10;
3421
+ var import_core11;
3277
3422
  var init_device_parameters = __esm({
3278
3423
  "src/adapter/converters/device-parameters.ts"() {
3279
3424
  "use strict";
3280
- import_core10 = __toESM(require_core(), 1);
3425
+ import_core11 = __toESM(require_core(), 1);
3281
3426
  init_unified_parameter_api();
3282
3427
  }
3283
3428
  });
@@ -3370,13 +3515,13 @@ ${source}`;
3370
3515
  });
3371
3516
 
3372
3517
  // src/adapter/resources/webgl-sampler.ts
3373
- var import_core11, WEBGLSampler;
3518
+ var import_core12, WEBGLSampler;
3374
3519
  var init_webgl_sampler = __esm({
3375
3520
  "src/adapter/resources/webgl-sampler.ts"() {
3376
3521
  "use strict";
3377
- import_core11 = __toESM(require_core(), 1);
3522
+ import_core12 = __toESM(require_core(), 1);
3378
3523
  init_sampler_parameters();
3379
- WEBGLSampler = class extends import_core11.Sampler {
3524
+ WEBGLSampler = class extends import_core12.Sampler {
3380
3525
  device;
3381
3526
  handle;
3382
3527
  parameters;
@@ -3452,19 +3597,19 @@ ${source}`;
3452
3597
  });
3453
3598
 
3454
3599
  // src/adapter/resources/webgl-texture-view.ts
3455
- var import_core12, WEBGLTextureView;
3600
+ var import_core13, WEBGLTextureView;
3456
3601
  var init_webgl_texture_view = __esm({
3457
3602
  "src/adapter/resources/webgl-texture-view.ts"() {
3458
3603
  "use strict";
3459
- import_core12 = __toESM(require_core(), 1);
3460
- WEBGLTextureView = class extends import_core12.TextureView {
3604
+ import_core13 = __toESM(require_core(), 1);
3605
+ WEBGLTextureView = class extends import_core13.TextureView {
3461
3606
  device;
3462
3607
  gl;
3463
3608
  handle;
3464
3609
  // Does not have a WebGL representation
3465
3610
  texture;
3466
3611
  constructor(device, props) {
3467
- super(device, { ...import_core12.Texture.defaultProps, ...props });
3612
+ super(device, { ...import_core13.Texture.defaultProps, ...props });
3468
3613
  this.device = device;
3469
3614
  this.gl = this.device.gl;
3470
3615
  this.handle = null;
@@ -3474,98 +3619,6 @@ ${source}`;
3474
3619
  }
3475
3620
  });
3476
3621
 
3477
- // src/adapter/converters/webgl-shadertypes.ts
3478
- function convertDataTypeToGLDataType(normalizedType) {
3479
- return NORMALIZED_SHADER_TYPE_TO_WEBGL[normalizedType];
3480
- }
3481
- function convertGLUniformTypeToShaderVariableType(glUniformType) {
3482
- return WEBGL_SHADER_TYPES[glUniformType];
3483
- }
3484
- function isGLSamplerType(type) {
3485
- return Boolean(WEBGL_SAMPLER_TO_TEXTURE_BINDINGS[type]);
3486
- }
3487
- function getTextureBindingFromGLSamplerType(glSamplerType) {
3488
- return WEBGL_SAMPLER_TO_TEXTURE_BINDINGS[glSamplerType];
3489
- }
3490
- var WEBGL_SHADER_TYPES, WEBGL_SAMPLER_TO_TEXTURE_BINDINGS, NORMALIZED_SHADER_TYPE_TO_WEBGL, WEBGL_TO_NORMALIZED_DATA_TYPE;
3491
- var init_webgl_shadertypes = __esm({
3492
- "src/adapter/converters/webgl-shadertypes.ts"() {
3493
- "use strict";
3494
- WEBGL_SHADER_TYPES = {
3495
- [5126 /* FLOAT */]: "f32",
3496
- [35664 /* FLOAT_VEC2 */]: "vec2<f32>",
3497
- [35665 /* FLOAT_VEC3 */]: "vec3<f32>",
3498
- [35666 /* FLOAT_VEC4 */]: "vec4<f32>",
3499
- [5124 /* INT */]: "i32",
3500
- [35667 /* INT_VEC2 */]: "vec2<i32>",
3501
- [35668 /* INT_VEC3 */]: "vec3<i32>",
3502
- [35669 /* INT_VEC4 */]: "vec4<i32>",
3503
- [5125 /* UNSIGNED_INT */]: "u32",
3504
- [36294 /* UNSIGNED_INT_VEC2 */]: "vec2<u32>",
3505
- [36295 /* UNSIGNED_INT_VEC3 */]: "vec3<u32>",
3506
- [36296 /* UNSIGNED_INT_VEC4 */]: "vec4<u32>",
3507
- [35670 /* BOOL */]: "f32",
3508
- [35671 /* BOOL_VEC2 */]: "vec2<f32>",
3509
- [35672 /* BOOL_VEC3 */]: "vec3<f32>",
3510
- [35673 /* BOOL_VEC4 */]: "vec4<f32>",
3511
- // TODO - are sizes/components below correct?
3512
- [35674 /* FLOAT_MAT2 */]: "mat2x2<f32>",
3513
- [35685 /* FLOAT_MAT2x3 */]: "mat2x3<f32>",
3514
- [35686 /* FLOAT_MAT2x4 */]: "mat2x4<f32>",
3515
- [35687 /* FLOAT_MAT3x2 */]: "mat3x2<f32>",
3516
- [35675 /* FLOAT_MAT3 */]: "mat3x3<f32>",
3517
- [35688 /* FLOAT_MAT3x4 */]: "mat3x4<f32>",
3518
- [35689 /* FLOAT_MAT4x2 */]: "mat4x2<f32>",
3519
- [35690 /* FLOAT_MAT4x3 */]: "mat4x3<f32>",
3520
- [35676 /* FLOAT_MAT4 */]: "mat4x4<f32>"
3521
- };
3522
- WEBGL_SAMPLER_TO_TEXTURE_BINDINGS = {
3523
- [35678 /* SAMPLER_2D */]: { viewDimension: "2d", sampleType: "float" },
3524
- [35680 /* SAMPLER_CUBE */]: { viewDimension: "cube", sampleType: "float" },
3525
- [35679 /* SAMPLER_3D */]: { viewDimension: "3d", sampleType: "float" },
3526
- [35682 /* SAMPLER_2D_SHADOW */]: { viewDimension: "3d", sampleType: "depth" },
3527
- [36289 /* SAMPLER_2D_ARRAY */]: { viewDimension: "2d-array", sampleType: "float" },
3528
- [36292 /* SAMPLER_2D_ARRAY_SHADOW */]: { viewDimension: "2d-array", sampleType: "depth" },
3529
- [36293 /* SAMPLER_CUBE_SHADOW */]: { viewDimension: "cube", sampleType: "float" },
3530
- [36298 /* INT_SAMPLER_2D */]: { viewDimension: "2d", sampleType: "sint" },
3531
- [36299 /* INT_SAMPLER_3D */]: { viewDimension: "3d", sampleType: "sint" },
3532
- [36300 /* INT_SAMPLER_CUBE */]: { viewDimension: "cube", sampleType: "sint" },
3533
- [36303 /* INT_SAMPLER_2D_ARRAY */]: { viewDimension: "2d-array", sampleType: "uint" },
3534
- [36306 /* UNSIGNED_INT_SAMPLER_2D */]: { viewDimension: "2d", sampleType: "uint" },
3535
- [36307 /* UNSIGNED_INT_SAMPLER_3D */]: { viewDimension: "3d", sampleType: "uint" },
3536
- [36308 /* UNSIGNED_INT_SAMPLER_CUBE */]: { viewDimension: "cube", sampleType: "uint" },
3537
- [36311 /* UNSIGNED_INT_SAMPLER_2D_ARRAY */]: { viewDimension: "2d-array", sampleType: "uint" }
3538
- };
3539
- NORMALIZED_SHADER_TYPE_TO_WEBGL = {
3540
- uint8: 5121 /* UNSIGNED_BYTE */,
3541
- sint8: 5120 /* BYTE */,
3542
- unorm8: 5121 /* UNSIGNED_BYTE */,
3543
- snorm8: 5120 /* BYTE */,
3544
- uint16: 5123 /* UNSIGNED_SHORT */,
3545
- sint16: 5122 /* SHORT */,
3546
- unorm16: 5123 /* UNSIGNED_SHORT */,
3547
- snorm16: 5122 /* SHORT */,
3548
- uint32: 5125 /* UNSIGNED_INT */,
3549
- sint32: 5124 /* INT */,
3550
- // WebGPU does not support normalized 32 bit integer attributes
3551
- // 'unorm32': GL.UNSIGNED_INT,
3552
- // 'snorm32': GL.INT,
3553
- float16: 5131 /* HALF_FLOAT */,
3554
- float32: 5126 /* FLOAT */
3555
- };
3556
- WEBGL_TO_NORMALIZED_DATA_TYPE = {
3557
- [5120 /* BYTE */]: ["sint8", "snorm16"],
3558
- [5121 /* UNSIGNED_BYTE */]: ["uint8", "unorm8"],
3559
- [5122 /* SHORT */]: ["sint16", "unorm16"],
3560
- [5123 /* UNSIGNED_SHORT */]: ["uint16", "unorm16"],
3561
- [5124 /* INT */]: ["sint32", "sint32"],
3562
- [5125 /* UNSIGNED_INT */]: ["uint32", "uint32"],
3563
- [5126 /* FLOAT */]: ["float32", "float32"],
3564
- [5131 /* HALF_FLOAT */]: ["float16", "float16"]
3565
- };
3566
- }
3567
- });
3568
-
3569
3622
  // src/adapter/converters/shader-formats.ts
3570
3623
  function convertGLDataTypeToDataType(type) {
3571
3624
  return GL_DATA_TYPE_MAP[type];
@@ -3596,6 +3649,24 @@ ${source}`;
3596
3649
  });
3597
3650
 
3598
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
+ }
3599
3670
  function getWebGLTextureTarget(dimension) {
3600
3671
  switch (dimension) {
3601
3672
  case "1d":
@@ -3616,19 +3687,18 @@ ${source}`;
3616
3687
  function getWebGLCubeFaceTarget(glTarget, dimension, level) {
3617
3688
  return dimension === "cube" ? 34069 /* TEXTURE_CUBE_MAP_POSITIVE_X */ + level : glTarget;
3618
3689
  }
3619
- var import_core13, import_core14, WEBGLTexture;
3690
+ var import_core14, import_core15, WEBGLTexture;
3620
3691
  var init_webgl_texture = __esm({
3621
3692
  "src/adapter/resources/webgl-texture.ts"() {
3622
3693
  "use strict";
3623
- import_core13 = __toESM(require_core(), 1);
3694
+ import_core14 = __toESM(require_core(), 1);
3624
3695
  init_webgl_texture_table();
3625
3696
  init_sampler_parameters();
3626
3697
  init_with_parameters();
3627
3698
  init_webgl_texture_view();
3628
- init_webgl_shadertypes();
3629
3699
  init_shader_formats();
3630
- import_core14 = __toESM(require_core(), 1);
3631
- WEBGLTexture = class extends import_core13.Texture {
3700
+ import_core15 = __toESM(require_core(), 1);
3701
+ WEBGLTexture = class extends import_core14.Texture {
3632
3702
  // readonly MAX_ATTRIBUTES: number;
3633
3703
  device;
3634
3704
  gl;
@@ -3657,8 +3727,10 @@ ${source}`;
3657
3727
  // state
3658
3728
  /** Texture binding slot - TODO - move to texture view? */
3659
3729
  _textureUnit = 0;
3660
- /** Chached framebuffer */
3730
+ /** Cached framebuffer reused for color texture readback. */
3661
3731
  _framebuffer = null;
3732
+ /** Cache key for the currently attached readback subresource `${mipLevel}:${layer}`. */
3733
+ _framebufferAttachmentKey = null;
3662
3734
  constructor(device, props) {
3663
3735
  super(device, props, { byteAlignment: 1 });
3664
3736
  this.device = device;
@@ -3673,20 +3745,27 @@ ${source}`;
3673
3745
  this.device._setWebGLDebugMetadata(this.handle, this, { spector: this.props });
3674
3746
  this.gl.bindTexture(this.glTarget, this.handle);
3675
3747
  const { dimension, width, height, depth, mipLevels, glTarget, glInternalFormat } = this;
3676
- switch (dimension) {
3677
- case "2d":
3678
- case "cube":
3679
- this.gl.texStorage2D(glTarget, mipLevels, glInternalFormat, width, height);
3680
- break;
3681
- case "2d-array":
3682
- case "3d":
3683
- this.gl.texStorage3D(glTarget, mipLevels, glInternalFormat, width, height, depth);
3684
- break;
3685
- default:
3686
- 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
+ }
3687
3761
  }
3688
3762
  this.gl.bindTexture(this.glTarget, null);
3689
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
+ }
3690
3769
  this.setSampler(this.props.sampler);
3691
3770
  this.view = new WEBGLTextureView(this.device, { ...this.props, texture: this });
3692
3771
  Object.seal(this);
@@ -3695,9 +3774,14 @@ ${source}`;
3695
3774
  if (this.handle) {
3696
3775
  this._framebuffer?.destroy();
3697
3776
  this._framebuffer = null;
3698
- this.gl.deleteTexture(this.handle);
3777
+ this._framebufferAttachmentKey = null;
3699
3778
  this.removeStats();
3700
- 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
+ }
3701
3785
  this.destroyed = true;
3702
3786
  }
3703
3787
  }
@@ -3736,99 +3820,180 @@ ${source}`;
3736
3820
  return { width: options.width, height: options.height };
3737
3821
  }
3738
3822
  copyImageData(options_) {
3739
- const options = this._normalizeCopyImageDataOptions(options_);
3740
- const typedArray = options.data;
3741
- const { width, height, depth, z = 0 } = options;
3742
- 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;
3743
3871
  const { glFormat, glType, compressed } = this;
3744
3872
  const glTarget = getWebGLCubeFaceTarget(this.glTarget, this.dimension, z);
3745
- let unpackRowLength;
3746
- if (!this.compressed) {
3747
- const { bytesPerPixel } = this.device.getTextureFormatInfo(this.format);
3748
- if (bytesPerPixel) {
3749
- if (options.bytesPerRow % bytesPerPixel !== 0) {
3750
- throw new Error(
3751
- `bytesPerRow (${options.bytesPerRow}) must be a multiple of bytesPerPixel (${bytesPerPixel}) for ${this.format}`
3752
- );
3753
- }
3754
- unpackRowLength = options.bytesPerRow / bytesPerPixel;
3755
- }
3873
+ if (compressed) {
3874
+ throw new Error("writeBuffer for compressed textures is not implemented in WebGL");
3756
3875
  }
3757
- const glParameters = !this.compressed ? {
3876
+ const { bytesPerPixel } = this.device.getTextureFormatInfo(this.format);
3877
+ const unpackRowLength = bytesPerPixel ? options.bytesPerRow / bytesPerPixel : void 0;
3878
+ const glParameters = {
3758
3879
  [3317 /* UNPACK_ALIGNMENT */]: this.byteAlignment,
3759
3880
  ...unpackRowLength !== void 0 ? { [3314 /* UNPACK_ROW_LENGTH */]: unpackRowLength } : {},
3760
3881
  [32878 /* UNPACK_IMAGE_HEIGHT */]: options.rowsPerImage
3761
- } : {};
3882
+ };
3762
3883
  this.gl.bindTexture(this.glTarget, this.handle);
3884
+ this.gl.bindBuffer(35052 /* PIXEL_UNPACK_BUFFER */, buffer.handle);
3763
3885
  withGLParameters(this.gl, glParameters, () => {
3764
3886
  switch (this.dimension) {
3765
3887
  case "2d":
3766
3888
  case "cube":
3767
- if (compressed) {
3768
- this.gl.compressedTexSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, typedArray, byteOffset);
3769
- } else {
3770
- this.gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, typedArray, byteOffset);
3771
- }
3889
+ this.gl.texSubImage2D(
3890
+ glTarget,
3891
+ mipLevel,
3892
+ x,
3893
+ y,
3894
+ width,
3895
+ height,
3896
+ glFormat,
3897
+ glType,
3898
+ byteOffset
3899
+ );
3772
3900
  break;
3773
3901
  case "2d-array":
3774
3902
  case "3d":
3775
- if (compressed) {
3776
- this.gl.compressedTexSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, typedArray, byteOffset);
3777
- } else {
3778
- this.gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, typedArray, byteOffset);
3779
- }
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
+ );
3780
3916
  break;
3781
3917
  default:
3782
3918
  }
3783
3919
  });
3920
+ this.gl.bindBuffer(35052 /* PIXEL_UNPACK_BUFFER */, null);
3784
3921
  this.gl.bindTexture(this.glTarget, null);
3785
3922
  }
3786
- readBuffer(options = {}, buffer) {
3787
- throw new Error("readBuffer not implemented");
3788
- }
3789
- async readDataAsync(options = {}) {
3790
- return this.readDataSyncWebGL(options);
3791
- }
3792
- writeBuffer(buffer, options_ = {}) {
3793
- }
3794
3923
  writeData(data, options_ = {}) {
3795
3924
  const options = this._normalizeTextureWriteOptions(options_);
3796
3925
  const typedArray = ArrayBuffer.isView(data) ? data : new Uint8Array(data);
3797
- const {} = this;
3798
- const { width, height, mipLevel, x, y, z } = options;
3926
+ const { width, height, depthOrArrayLayers, mipLevel, x, y, z, byteOffset } = options;
3799
3927
  const { glFormat, glType, compressed } = this;
3800
- const depth = 0;
3801
- const glTarget = getWebGLCubeFaceTarget(this.glTarget, this.dimension, depth);
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
+ }
3802
3936
  const glParameters = !this.compressed ? {
3803
- // WebGL does not require byte alignment, but allows it to be specified
3804
- [3317 /* UNPACK_ALIGNMENT */]: this.byteAlignment
3805
- // [GL.UNPACK_ROW_LENGTH]: bytesPerRow,
3806
- // [GL.UNPACK_IMAGE_HEIGHT]: rowsPerImage
3937
+ [3317 /* UNPACK_ALIGNMENT */]: this.byteAlignment,
3938
+ ...unpackRowLength !== void 0 ? { [3314 /* UNPACK_ROW_LENGTH */]: unpackRowLength } : {},
3939
+ [32878 /* UNPACK_IMAGE_HEIGHT */]: options.rowsPerImage
3807
3940
  } : {};
3808
- this.gl.bindTexture(glTarget, this.handle);
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);
3809
3946
  this.gl.bindBuffer(35052 /* PIXEL_UNPACK_BUFFER */, null);
3810
3947
  withGLParameters(this.gl, glParameters, () => {
3811
3948
  switch (this.dimension) {
3812
3949
  case "2d":
3813
3950
  case "cube":
3814
3951
  if (compressed) {
3815
- 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
+ }
3816
3957
  } else {
3817
- 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);
3818
3959
  }
3819
3960
  break;
3820
3961
  case "2d-array":
3821
3962
  case "3d":
3822
3963
  if (compressed) {
3823
- 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
+ }
3824
3989
  } else {
3825
- 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);
3826
3991
  }
3827
3992
  break;
3828
3993
  default:
3829
3994
  }
3830
3995
  });
3831
- this.gl.bindTexture(glTarget, null);
3996
+ this.gl.bindTexture(this.glTarget, null);
3832
3997
  }
3833
3998
  // IMPLEMENTATION SPECIFIC
3834
3999
  /** @todo - for now we always use 1 for maximum compatibility, we can fine tune later */
@@ -3850,30 +4015,107 @@ ${source}`;
3850
4015
  }
3851
4016
  // WEBGL SPECIFIC
3852
4017
  readDataSyncWebGL(options_ = {}) {
3853
- const options = this._normalizeTextureReadOptions(options_);
4018
+ const options = this._getSupportedColorReadOptions(options_);
3854
4019
  const memoryLayout = this.computeMemoryLayout(options);
3855
4020
  const shaderType = convertGLDataTypeToDataType(this.glType);
3856
- const ArrayType = (0, import_core14.getTypedArrayConstructor)(shaderType);
3857
- const targetArray = new ArrayType(memoryLayout.byteLength);
3858
- const signedType = (0, import_core14.getDataType)(targetArray);
3859
- 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) {
3860
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 */);
3861
4053
  const prevHandle = this.gl.bindFramebuffer(
3862
4054
  36160 /* FRAMEBUFFER */,
3863
4055
  framebuffer.handle
3864
4056
  );
3865
- this.gl.readBuffer(36064 /* COLOR_ATTACHMENT0 */);
3866
- this.gl.readPixels(
3867
- options.x,
3868
- options.y,
3869
- options.width,
3870
- options.height,
3871
- this.glFormat,
3872
- sourceType,
3873
- targetArray
3874
- );
3875
- this.gl.bindFramebuffer(36160 /* FRAMEBUFFER */, prevHandle || null);
3876
- 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;
3877
4119
  }
3878
4120
  /**
3879
4121
  * @note - this is used by the DynamicTexture class to generate mipmaps on WebGL
@@ -3881,7 +4123,7 @@ ${source}`;
3881
4123
  generateMipmapsWebGL(options) {
3882
4124
  const isFilterableAndRenderable = this.device.isTextureFormatRenderable(this.props.format) && this.device.isTextureFormatFilterable(this.props.format);
3883
4125
  if (!isFilterableAndRenderable) {
3884
- 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`)();
3885
4127
  if (!options?.force) {
3886
4128
  return;
3887
4129
  }
@@ -3890,7 +4132,7 @@ ${source}`;
3890
4132
  this.gl.bindTexture(this.glTarget, this.handle);
3891
4133
  this.gl.generateMipmap(this.glTarget);
3892
4134
  } catch (error) {
3893
- import_core13.log.warn(`Error generating mipmap for ${this}: ${error.message}`)();
4135
+ import_core14.log.warn(`Error generating mipmap for ${this}: ${error.message}`)();
3894
4136
  } finally {
3895
4137
  this.gl.bindTexture(this.glTarget, null);
3896
4138
  }
@@ -3900,7 +4142,7 @@ ${source}`;
3900
4142
  * Sets sampler parameters on texture
3901
4143
  */
3902
4144
  _setSamplerParameters(parameters) {
3903
- 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))();
3904
4146
  this.gl.bindTexture(this.glTarget, this.handle);
3905
4147
  for (const [pname, pvalue] of Object.entries(parameters)) {
3906
4148
  const param = Number(pname);
@@ -3957,210 +4199,6 @@ ${source}`;
3957
4199
  }
3958
4200
  });
3959
4201
 
3960
- // src/adapter/helpers/get-shader-layout-from-glsl.ts
3961
- function getShaderLayoutFromGLSL(gl, program) {
3962
- const shaderLayout = {
3963
- attributes: [],
3964
- bindings: []
3965
- };
3966
- shaderLayout.attributes = readAttributeDeclarations(gl, program);
3967
- const uniformBlocks = readUniformBlocks(gl, program);
3968
- for (const uniformBlock of uniformBlocks) {
3969
- const uniforms2 = uniformBlock.uniforms.map((uniform) => ({
3970
- name: uniform.name,
3971
- format: uniform.format,
3972
- byteOffset: uniform.byteOffset,
3973
- byteStride: uniform.byteStride,
3974
- arrayLength: uniform.arrayLength
3975
- }));
3976
- shaderLayout.bindings.push({
3977
- type: "uniform",
3978
- name: uniformBlock.name,
3979
- group: 0,
3980
- location: uniformBlock.location,
3981
- visibility: (uniformBlock.vertex ? 1 : 0) & (uniformBlock.fragment ? 2 : 0),
3982
- minBindingSize: uniformBlock.byteLength,
3983
- uniforms: uniforms2
3984
- });
3985
- }
3986
- const uniforms = readUniformBindings(gl, program);
3987
- let textureUnit = 0;
3988
- for (const uniform of uniforms) {
3989
- if (isGLSamplerType(uniform.type)) {
3990
- const { viewDimension, sampleType } = getTextureBindingFromGLSamplerType(uniform.type);
3991
- shaderLayout.bindings.push({
3992
- type: "texture",
3993
- name: uniform.name,
3994
- group: 0,
3995
- location: textureUnit,
3996
- viewDimension,
3997
- sampleType
3998
- });
3999
- uniform.textureUnit = textureUnit;
4000
- textureUnit += 1;
4001
- }
4002
- }
4003
- if (uniforms.length) {
4004
- shaderLayout.uniforms = uniforms;
4005
- }
4006
- const varyings = readVaryings(gl, program);
4007
- if (varyings?.length) {
4008
- shaderLayout.varyings = varyings;
4009
- }
4010
- return shaderLayout;
4011
- }
4012
- function readAttributeDeclarations(gl, program) {
4013
- const attributes = [];
4014
- const count = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
4015
- for (let index = 0; index < count; index++) {
4016
- const activeInfo = gl.getActiveAttrib(program, index);
4017
- if (!activeInfo) {
4018
- throw new Error("activeInfo");
4019
- }
4020
- const {
4021
- name,
4022
- type: compositeType
4023
- /* , size*/
4024
- } = activeInfo;
4025
- const location = gl.getAttribLocation(program, name);
4026
- if (location >= 0) {
4027
- const attributeType = convertGLUniformTypeToShaderVariableType(compositeType);
4028
- const stepMode = /instance/i.test(name) ? "instance" : "vertex";
4029
- attributes.push({
4030
- name,
4031
- location,
4032
- stepMode,
4033
- type: attributeType
4034
- // size - for arrays, size is the number of elements in the array
4035
- });
4036
- }
4037
- }
4038
- attributes.sort((a, b) => a.location - b.location);
4039
- return attributes;
4040
- }
4041
- function readVaryings(gl, program) {
4042
- const varyings = [];
4043
- const count = gl.getProgramParameter(program, 35971 /* TRANSFORM_FEEDBACK_VARYINGS */);
4044
- for (let location = 0; location < count; location++) {
4045
- const activeInfo = gl.getTransformFeedbackVarying(program, location);
4046
- if (!activeInfo) {
4047
- throw new Error("activeInfo");
4048
- }
4049
- const { name, type: glUniformType, size } = activeInfo;
4050
- const uniformType = convertGLUniformTypeToShaderVariableType(glUniformType);
4051
- const { type, components } = (0, import_core15.getVariableShaderTypeInfo)(uniformType);
4052
- varyings.push({ location, name, type, size: size * components });
4053
- }
4054
- varyings.sort((a, b) => a.location - b.location);
4055
- return varyings;
4056
- }
4057
- function readUniformBindings(gl, program) {
4058
- const uniforms = [];
4059
- const uniformCount = gl.getProgramParameter(program, 35718 /* ACTIVE_UNIFORMS */);
4060
- for (let i = 0; i < uniformCount; i++) {
4061
- const activeInfo = gl.getActiveUniform(program, i);
4062
- if (!activeInfo) {
4063
- throw new Error("activeInfo");
4064
- }
4065
- const { name: rawName, size, type } = activeInfo;
4066
- const { name, isArray: isArray3 } = parseUniformName(rawName);
4067
- let webglLocation = gl.getUniformLocation(program, name);
4068
- const uniformInfo = {
4069
- // WebGL locations are uniquely typed but just numbers
4070
- location: webglLocation,
4071
- name,
4072
- size,
4073
- type,
4074
- isArray: isArray3
4075
- };
4076
- uniforms.push(uniformInfo);
4077
- if (uniformInfo.size > 1) {
4078
- for (let j = 0; j < uniformInfo.size; j++) {
4079
- const elementName = `${name}[${j}]`;
4080
- webglLocation = gl.getUniformLocation(program, elementName);
4081
- const arrayElementUniformInfo = {
4082
- ...uniformInfo,
4083
- name: elementName,
4084
- location: webglLocation
4085
- };
4086
- uniforms.push(arrayElementUniformInfo);
4087
- }
4088
- }
4089
- }
4090
- return uniforms;
4091
- }
4092
- function readUniformBlocks(gl, program) {
4093
- const getBlockParameter = (blockIndex, pname) => gl.getActiveUniformBlockParameter(program, blockIndex, pname);
4094
- const uniformBlocks = [];
4095
- const blockCount = gl.getProgramParameter(program, 35382 /* ACTIVE_UNIFORM_BLOCKS */);
4096
- for (let blockIndex = 0; blockIndex < blockCount; blockIndex++) {
4097
- const blockInfo = {
4098
- name: gl.getActiveUniformBlockName(program, blockIndex) || "",
4099
- location: getBlockParameter(blockIndex, 35391 /* UNIFORM_BLOCK_BINDING */),
4100
- byteLength: getBlockParameter(blockIndex, 35392 /* UNIFORM_BLOCK_DATA_SIZE */),
4101
- vertex: getBlockParameter(blockIndex, 35396 /* UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER */),
4102
- fragment: getBlockParameter(blockIndex, 35398 /* UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER */),
4103
- uniformCount: getBlockParameter(blockIndex, 35394 /* UNIFORM_BLOCK_ACTIVE_UNIFORMS */),
4104
- uniforms: []
4105
- };
4106
- const uniformIndices = getBlockParameter(blockIndex, 35395 /* UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES */) || [];
4107
- const uniformType = gl.getActiveUniforms(program, uniformIndices, 35383 /* UNIFORM_TYPE */);
4108
- const uniformArrayLength = gl.getActiveUniforms(program, uniformIndices, 35384 /* UNIFORM_SIZE */);
4109
- const uniformOffset = gl.getActiveUniforms(program, uniformIndices, 35387 /* UNIFORM_OFFSET */);
4110
- const uniformStride = gl.getActiveUniforms(program, uniformIndices, 35388 /* UNIFORM_ARRAY_STRIDE */);
4111
- for (let i = 0; i < blockInfo.uniformCount; ++i) {
4112
- const uniformIndex = uniformIndices[i];
4113
- if (uniformIndex === void 0) {
4114
- continue;
4115
- }
4116
- const activeInfo = gl.getActiveUniform(program, uniformIndex);
4117
- if (!activeInfo) {
4118
- throw new Error("activeInfo");
4119
- }
4120
- const format = convertGLUniformTypeToShaderVariableType(uniformType[i]);
4121
- blockInfo.uniforms.push({
4122
- name: activeInfo.name,
4123
- format,
4124
- type: uniformType[i],
4125
- arrayLength: uniformArrayLength[i],
4126
- byteOffset: uniformOffset[i],
4127
- byteStride: uniformStride[i]
4128
- // matrixStride: uniformStride[i],
4129
- // rowMajor: uniformRowMajor[i]
4130
- });
4131
- }
4132
- uniformBlocks.push(blockInfo);
4133
- }
4134
- uniformBlocks.sort((a, b) => a.location - b.location);
4135
- return uniformBlocks;
4136
- }
4137
- function parseUniformName(name) {
4138
- if (name[name.length - 1] !== "]") {
4139
- return {
4140
- name,
4141
- length: 1,
4142
- isArray: false
4143
- };
4144
- }
4145
- const UNIFORM_NAME_REGEXP = /([^[]*)(\[[0-9]+\])?/;
4146
- const matches = UNIFORM_NAME_REGEXP.exec(name);
4147
- const uniformName = (0, import_core15.assertDefined)(matches?.[1], `Failed to parse GLSL uniform name ${name}`);
4148
- return {
4149
- name: uniformName,
4150
- // TODO - is this a bug, shouldn't we return the value?
4151
- length: matches?.[2] ? 1 : 0,
4152
- isArray: Boolean(matches?.[2])
4153
- };
4154
- }
4155
- var import_core15;
4156
- var init_get_shader_layout_from_glsl = __esm({
4157
- "src/adapter/helpers/get-shader-layout-from-glsl.ts"() {
4158
- "use strict";
4159
- import_core15 = __toESM(require_core(), 1);
4160
- init_webgl_shadertypes();
4161
- }
4162
- });
4163
-
4164
4202
  // src/adapter/helpers/set-uniform.ts
4165
4203
  function setUniform(gl, location, type, value) {
4166
4204
  const gl2 = gl;
@@ -4307,12 +4345,11 @@ ${source}`;
4307
4345
  }
4308
4346
  return mergedLayout;
4309
4347
  }
4310
- var import_core16, LOG_PROGRAM_PERF_PRIORITY, WEBGLRenderPipeline;
4348
+ var import_core16, WEBGLRenderPipeline;
4311
4349
  var init_webgl_render_pipeline = __esm({
4312
4350
  "src/adapter/resources/webgl-render-pipeline.ts"() {
4313
4351
  "use strict";
4314
4352
  import_core16 = __toESM(require_core(), 1);
4315
- init_get_shader_layout_from_glsl();
4316
4353
  init_device_parameters();
4317
4354
  init_set_uniform();
4318
4355
  init_webgl_buffer();
@@ -4320,7 +4357,6 @@ ${source}`;
4320
4357
  init_webgl_texture();
4321
4358
  init_webgl_texture_view();
4322
4359
  init_webgl_topology_utils();
4323
- LOG_PROGRAM_PERF_PRIORITY = 4;
4324
4360
  WEBGLRenderPipeline = class extends import_core16.RenderPipeline {
4325
4361
  /** The WebGL device that created this render pipeline */
4326
4362
  device;
@@ -4332,10 +4368,10 @@ ${source}`;
4332
4368
  fs;
4333
4369
  /** The layout extracted from shader by WebGL introspection APIs */
4334
4370
  introspectedLayout;
4335
- /** Uniforms set on this model */
4336
- uniforms = {};
4337
- /** Bindings set on this model */
4371
+ /** Compatibility path for direct pipeline.setBindings() usage */
4338
4372
  bindings = {};
4373
+ /** Compatibility path for direct pipeline.uniforms usage */
4374
+ uniforms = {};
4339
4375
  /** WebGL varyings */
4340
4376
  varyings = null;
4341
4377
  _uniformCount = 0;
@@ -4347,33 +4383,28 @@ ${source}`;
4347
4383
  constructor(device, props) {
4348
4384
  super(device, props);
4349
4385
  this.device = device;
4350
- 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;
4351
4393
  this.device._setWebGLDebugMetadata(this.handle, this, { spector: { id: this.props.id } });
4352
- this.vs = props.vs;
4353
- this.fs = props.fs;
4354
- const { varyings, bufferMode = 35981 /* SEPARATE_ATTRIBS */ } = props;
4355
- if (varyings && varyings.length > 0) {
4356
- this.varyings = varyings;
4357
- this.device.gl.transformFeedbackVaryings(this.handle, varyings, bufferMode);
4358
- }
4359
- this._linkShaders();
4360
- import_core16.log.time(3, `RenderPipeline ${this.id} - shaderLayout introspection`)();
4361
- this.introspectedLayout = getShaderLayoutFromGLSL(this.device.gl, this.handle);
4362
- import_core16.log.timeEnd(3, `RenderPipeline ${this.id} - shaderLayout introspection`)();
4363
4394
  this.shaderLayout = props.shaderLayout ? mergeShaderLayout(this.introspectedLayout, props.shaderLayout) : this.introspectedLayout;
4364
4395
  }
4365
4396
  destroy() {
4366
- if (this.handle) {
4367
- this.device.gl.useProgram(null);
4368
- this.device.gl.deleteProgram(this.handle);
4369
- this.destroyed = true;
4370
- this.handle.destroyed = true;
4371
- this.handle = null;
4397
+ if (this.destroyed) {
4398
+ return;
4399
+ }
4400
+ if (this.sharedRenderPipeline && !this.props._sharedRenderPipeline) {
4401
+ this.sharedRenderPipeline.destroy();
4372
4402
  }
4403
+ this.destroyResource();
4373
4404
  }
4374
4405
  /**
4375
- * Bindings include: textures, samplers and uniform buffers
4376
- * @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.
4377
4408
  */
4378
4409
  setBindings(bindings, options) {
4379
4410
  for (const [name, value] of Object.entries(bindings)) {
@@ -4416,6 +4447,7 @@ ${source}`;
4416
4447
  * This function unifies those ways into a single call using common parameters with sane defaults
4417
4448
  */
4418
4449
  draw(options) {
4450
+ this._syncLinkStatus();
4419
4451
  const {
4420
4452
  renderPass,
4421
4453
  parameters = this.props.parameters,
@@ -4429,7 +4461,9 @@ ${source}`;
4429
4461
  // firstIndex,
4430
4462
  // firstInstance,
4431
4463
  // baseVertex,
4432
- transformFeedback
4464
+ transformFeedback,
4465
+ bindings = this.bindings,
4466
+ uniforms = this.uniforms
4433
4467
  } = options;
4434
4468
  const glDrawMode = getGLDrawMode(topology);
4435
4469
  const isIndexed = Boolean(vertexArray.indexBuffer);
@@ -4438,71 +4472,506 @@ ${source}`;
4438
4472
  import_core16.log.info(2, `RenderPipeline:${this.id}.draw() aborted - waiting for shader linking`)();
4439
4473
  return false;
4440
4474
  }
4441
- if (!this._areTexturesRenderable()) {
4475
+ if (!this._areTexturesRenderable(bindings)) {
4442
4476
  import_core16.log.info(2, `RenderPipeline:${this.id}.draw() aborted - textures not yet loaded`)();
4443
4477
  return false;
4444
4478
  }
4445
- this.device.gl.useProgram(this.handle);
4446
- vertexArray.bindBeforeRender(renderPass);
4447
- if (transformFeedback) {
4448
- 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;
4449
4951
  }
4450
- this._applyBindings();
4451
- this._applyUniforms();
4452
- const webglRenderPass = renderPass;
4453
- withDeviceAndGLParameters(this.device, parameters, webglRenderPass.glParameters, () => {
4454
- if (isIndexed && isInstanced) {
4455
- this.device.gl.drawElementsInstanced(
4456
- glDrawMode,
4457
- vertexCount || 0,
4458
- // indexCount?
4459
- glIndexType,
4460
- firstVertex,
4461
- instanceCount || 0
4462
- );
4463
- } else if (isIndexed) {
4464
- this.device.gl.drawElements(glDrawMode, vertexCount || 0, glIndexType, firstVertex);
4465
- } else if (isInstanced) {
4466
- this.device.gl.drawArraysInstanced(
4467
- glDrawMode,
4468
- firstVertex,
4469
- vertexCount || 0,
4470
- instanceCount || 0
4471
- );
4472
- } else {
4473
- this.device.gl.drawArrays(glDrawMode, firstVertex, vertexCount || 0);
4474
- }
4475
- if (transformFeedback) {
4476
- transformFeedback.end();
4477
- }
4478
- });
4479
- vertexArray.unbindAfterRender(renderPass);
4480
- return true;
4952
+ this.device.gl.useProgram(null);
4953
+ this.device.gl.deleteProgram(this.handle);
4954
+ this.handle.destroyed = true;
4955
+ this.destroyResource();
4481
4956
  }
4482
- // PRIVATE METHODS
4483
- // setAttributes(attributes: Record<string, Buffer>): void {}
4484
- // setBindings(bindings: Record<string, Binding>): void {}
4485
4957
  async _linkShaders() {
4486
4958
  const { gl } = this.device;
4487
4959
  gl.attachShader(this.handle, this.vs.handle);
4488
4960
  gl.attachShader(this.handle, this.fs.handle);
4489
- 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}`)();
4490
4962
  gl.linkProgram(this.handle);
4491
- import_core16.log.timeEnd(LOG_PROGRAM_PERF_PRIORITY, `linkProgram for ${this.id}`)();
4492
- if (import_core16.log.level === 0) {
4493
- }
4963
+ import_core18.log.timeEnd(LOG_PROGRAM_PERF_PRIORITY, `linkProgram for ${this.id}`)();
4494
4964
  if (!this.device.features.has("compilation-status-async-webgl")) {
4495
4965
  const status2 = this._getLinkStatus();
4496
4966
  this._reportLinkStatus(status2);
4497
4967
  return;
4498
4968
  }
4499
- import_core16.log.once(1, "RenderPipeline linking is asynchronous")();
4969
+ import_core18.log.once(1, "RenderPipeline linking is asynchronous")();
4500
4970
  await this._waitForLinkComplete();
4501
- 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}`)();
4502
4972
  const status = this._getLinkStatus();
4503
4973
  this._reportLinkStatus(status);
4504
4974
  }
4505
- /** Report link status. First, check for shader compilation failures if linking fails */
4506
4975
  async _reportLinkStatus(status) {
4507
4976
  switch (status) {
4508
4977
  case "success":
@@ -4539,11 +5008,6 @@ ${source}`;
4539
5008
  this.device.debug();
4540
5009
  }
4541
5010
  }
4542
- /**
4543
- * Get the shader compilation status
4544
- * TODO - Load log even when no error reported, to catch warnings?
4545
- * https://gamedev.stackexchange.com/questions/30429/how-to-detect-glsl-warnings
4546
- */
4547
5011
  _getLinkStatus() {
4548
5012
  const { gl } = this.device;
4549
5013
  const linked = gl.getProgramParameter(this.handle, 35714 /* LINK_STATUS */);
@@ -4551,6 +5015,7 @@ ${source}`;
4551
5015
  this.linkStatus = "error";
4552
5016
  return "link-error";
4553
5017
  }
5018
+ this._initializeSamplerUniforms();
4554
5019
  gl.validateProgram(this.handle);
4555
5020
  const validated = gl.getProgramParameter(this.handle, 35715 /* VALIDATE_STATUS */);
4556
5021
  if (!validated) {
@@ -4560,7 +5025,36 @@ ${source}`;
4560
5025
  this.linkStatus = "success";
4561
5026
  return "success";
4562
5027
  }
4563
- /** 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
+ }
4564
5058
  async _waitForLinkComplete() {
4565
5059
  const waitMs = async (ms) => await new Promise((resolve) => setTimeout(resolve, ms));
4566
5060
  const DELAY_MS = 10;
@@ -4577,101 +5071,6 @@ ${source}`;
4577
5071
  await waitMs(DELAY_MS);
4578
5072
  }
4579
5073
  }
4580
- /**
4581
- * Checks if all texture-values uniforms are renderable (i.e. loaded)
4582
- * Update a texture if needed (e.g. from video)
4583
- * Note: This is currently done before every draw call
4584
- */
4585
- _areTexturesRenderable() {
4586
- let texturesRenderable = true;
4587
- for (const bindingInfo of this.shaderLayout.bindings) {
4588
- if (!this.bindings[bindingInfo.name] && !this.bindings[bindingInfo.name.replace(/Uniforms$/, "")]) {
4589
- import_core16.log.warn(`Binding ${bindingInfo.name} not found in ${this.id}`)();
4590
- texturesRenderable = false;
4591
- }
4592
- }
4593
- return texturesRenderable;
4594
- }
4595
- /** Apply any bindings (before each draw call) */
4596
- _applyBindings() {
4597
- if (this.linkStatus !== "success") {
4598
- return;
4599
- }
4600
- const { gl } = this.device;
4601
- gl.useProgram(this.handle);
4602
- let textureUnit = 0;
4603
- let uniformBufferIndex = 0;
4604
- for (const binding of this.shaderLayout.bindings) {
4605
- const value = this.bindings[binding.name] || this.bindings[binding.name.replace(/Uniforms$/, "")];
4606
- if (!value) {
4607
- throw new Error(`No value for binding ${binding.name} in ${this.id}`);
4608
- }
4609
- switch (binding.type) {
4610
- case "uniform":
4611
- const { name } = binding;
4612
- const location = gl.getUniformBlockIndex(this.handle, name);
4613
- if (location === 4294967295 /* INVALID_INDEX */) {
4614
- throw new Error(`Invalid uniform block name ${name}`);
4615
- }
4616
- gl.uniformBlockBinding(this.handle, location, uniformBufferIndex);
4617
- if (value instanceof WEBGLBuffer) {
4618
- gl.bindBufferBase(35345 /* UNIFORM_BUFFER */, uniformBufferIndex, value.handle);
4619
- } else {
4620
- gl.bindBufferRange(
4621
- 35345 /* UNIFORM_BUFFER */,
4622
- uniformBufferIndex,
4623
- // @ts-expect-error
4624
- value.buffer.handle,
4625
- // @ts-expect-error
4626
- value.offset || 0,
4627
- // @ts-expect-error
4628
- value.size || value.buffer.byteLength - value.offset
4629
- );
4630
- }
4631
- uniformBufferIndex += 1;
4632
- break;
4633
- case "texture":
4634
- if (!(value instanceof WEBGLTextureView || value instanceof WEBGLTexture || value instanceof WEBGLFramebuffer)) {
4635
- throw new Error("texture");
4636
- }
4637
- let texture;
4638
- if (value instanceof WEBGLTextureView) {
4639
- texture = value.texture;
4640
- } else if (value instanceof WEBGLTexture) {
4641
- texture = value;
4642
- } else if (value instanceof WEBGLFramebuffer && value.colorAttachments[0] instanceof WEBGLTextureView) {
4643
- import_core16.log.warn(
4644
- "Passing framebuffer in texture binding may be deprecated. Use fbo.colorAttachments[0] instead"
4645
- )();
4646
- texture = value.colorAttachments[0].texture;
4647
- } else {
4648
- throw new Error("No texture");
4649
- }
4650
- gl.activeTexture(33984 /* TEXTURE0 */ + textureUnit);
4651
- gl.bindTexture(texture.glTarget, texture.handle);
4652
- textureUnit += 1;
4653
- break;
4654
- case "sampler":
4655
- break;
4656
- case "storage":
4657
- case "read-only-storage":
4658
- throw new Error(`binding type '${binding.type}' not supported in WebGL`);
4659
- }
4660
- }
4661
- }
4662
- /**
4663
- * Due to program sharing, uniforms need to be reset before every draw call
4664
- * (though caching will avoid redundant WebGL calls)
4665
- */
4666
- _applyUniforms() {
4667
- for (const uniformLayout of this.shaderLayout.uniforms || []) {
4668
- const { name, location, type, textureUnit } = uniformLayout;
4669
- const value = this.uniforms[name] ?? textureUnit;
4670
- if (value !== void 0) {
4671
- setUniform(this.device.gl, location, type, value);
4672
- }
4673
- }
4674
- }
4675
5074
  };
4676
5075
  }
4677
5076
  });
@@ -4738,7 +5137,7 @@ ${source}`;
4738
5137
  const webglBuffer = destinationBuffer;
4739
5138
  const sourceWidth = width || framebuffer.width;
4740
5139
  const sourceHeight = height || framebuffer.height;
4741
- const colorAttachment0 = (0, import_core17.assertDefined)(framebuffer.colorAttachments[0]);
5140
+ const colorAttachment0 = (0, import_core19.assertDefined)(framebuffer.colorAttachments[0]);
4742
5141
  const sourceParams = getTextureFormatWebGL(colorAttachment0.texture.props.format);
4743
5142
  const sourceFormat = sourceParams.format;
4744
5143
  const sourceType = sourceParams.type;
@@ -4846,7 +5245,7 @@ ${source}`;
4846
5245
  }
4847
5246
  }
4848
5247
  function getFramebuffer(source) {
4849
- if (source instanceof import_core17.Texture) {
5248
+ if (source instanceof import_core19.Texture) {
4850
5249
  const { width, height, id } = source;
4851
5250
  const framebuffer = source.device.createFramebuffer({
4852
5251
  id: `framebuffer-for-${id}`,
@@ -4858,19 +5257,19 @@ ${source}`;
4858
5257
  }
4859
5258
  return { framebuffer: source, destroyFramebuffer: false };
4860
5259
  }
4861
- var import_core17, WEBGLCommandBuffer;
5260
+ var import_core19, WEBGLCommandBuffer;
4862
5261
  var init_webgl_command_buffer = __esm({
4863
5262
  "src/adapter/resources/webgl-command-buffer.ts"() {
4864
5263
  "use strict";
4865
- import_core17 = __toESM(require_core(), 1);
5264
+ import_core19 = __toESM(require_core(), 1);
4866
5265
  init_webgl_texture();
4867
5266
  init_webgl_texture_table();
4868
- WEBGLCommandBuffer = class extends import_core17.CommandBuffer {
5267
+ WEBGLCommandBuffer = class extends import_core19.CommandBuffer {
4869
5268
  device;
4870
5269
  handle = null;
4871
5270
  commands = [];
4872
- constructor(device) {
4873
- super(device, {});
5271
+ constructor(device, props = {}) {
5272
+ super(device, props);
4874
5273
  this.device = device;
4875
5274
  }
4876
5275
  _executeCommands(commands = this.commands) {
@@ -4898,15 +5297,15 @@ ${source}`;
4898
5297
  });
4899
5298
 
4900
5299
  // src/adapter/resources/webgl-render-pass.ts
4901
- var import_core18, COLOR_CHANNELS, WEBGLRenderPass;
5300
+ var import_core20, COLOR_CHANNELS, WEBGLRenderPass;
4902
5301
  var init_webgl_render_pass = __esm({
4903
5302
  "src/adapter/resources/webgl-render-pass.ts"() {
4904
5303
  "use strict";
4905
- import_core18 = __toESM(require_core(), 1);
5304
+ import_core20 = __toESM(require_core(), 1);
4906
5305
  init_with_parameters();
4907
5306
  init_unified_parameter_api();
4908
5307
  COLOR_CHANNELS = [1, 2, 4, 8];
4909
- WEBGLRenderPass = class extends import_core18.RenderPass {
5308
+ WEBGLRenderPass = class extends import_core20.RenderPass {
4910
5309
  device;
4911
5310
  handle = null;
4912
5311
  /** Parameters that should be applied before each draw call */
@@ -4939,9 +5338,21 @@ ${source}`;
4939
5338
  this.device.gl.drawBuffers([1029 /* BACK */]);
4940
5339
  }
4941
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
+ }
4942
5345
  }
4943
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
+ }
4944
5354
  this.device.popState();
5355
+ this.destroy();
4945
5356
  }
4946
5357
  pushDebugGroup(groupLabel) {
4947
5358
  }
@@ -5083,31 +5494,39 @@ ${source}`;
5083
5494
  });
5084
5495
 
5085
5496
  // src/adapter/resources/webgl-command-encoder.ts
5086
- var import_core19, WEBGLCommandEncoder;
5497
+ var import_core21, WEBGLCommandEncoder;
5087
5498
  var init_webgl_command_encoder = __esm({
5088
5499
  "src/adapter/resources/webgl-command-encoder.ts"() {
5089
5500
  "use strict";
5090
- import_core19 = __toESM(require_core(), 1);
5501
+ import_core21 = __toESM(require_core(), 1);
5091
5502
  init_webgl_command_buffer();
5092
5503
  init_webgl_render_pass();
5093
- WEBGLCommandEncoder = class extends import_core19.CommandEncoder {
5504
+ WEBGLCommandEncoder = class extends import_core21.CommandEncoder {
5094
5505
  device;
5095
5506
  handle = null;
5096
5507
  commandBuffer;
5097
5508
  constructor(device, props) {
5098
5509
  super(device, props);
5099
5510
  this.device = device;
5100
- this.commandBuffer = new WEBGLCommandBuffer(device);
5511
+ this.commandBuffer = new WEBGLCommandBuffer(device, {
5512
+ id: `${this.props.id}-command-buffer`
5513
+ });
5101
5514
  }
5102
5515
  destroy() {
5516
+ this.destroyResource();
5103
5517
  }
5104
- 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();
5105
5524
  return this.commandBuffer;
5106
5525
  }
5107
- beginRenderPass(props) {
5108
- return new WEBGLRenderPass(this.device, props);
5526
+ beginRenderPass(props = {}) {
5527
+ return new WEBGLRenderPass(this.device, this._applyTimeProfilingToPassProps(props));
5109
5528
  }
5110
- beginComputePass(props) {
5529
+ beginComputePass(props = {}) {
5111
5530
  throw new Error("ComputePass not supported in WebGL");
5112
5531
  }
5113
5532
  copyBufferToBuffer(options) {
@@ -5133,6 +5552,10 @@ ${source}`;
5133
5552
  }
5134
5553
  resolveQuerySet(querySet, destination, options) {
5135
5554
  }
5555
+ writeTimestamp(querySet, queryIndex) {
5556
+ const webglQuerySet = querySet;
5557
+ webglQuerySet.writeTimestamp(queryIndex);
5558
+ }
5136
5559
  };
5137
5560
  }
5138
5561
  });
@@ -5181,15 +5604,15 @@ ${source}`;
5181
5604
  }
5182
5605
  return true;
5183
5606
  }
5184
- var import_core20, WEBGLVertexArray;
5607
+ var import_core22, WEBGLVertexArray;
5185
5608
  var init_webgl_vertex_array = __esm({
5186
5609
  "src/adapter/resources/webgl-vertex-array.ts"() {
5187
5610
  "use strict";
5188
- import_core20 = __toESM(require_core(), 1);
5611
+ import_core22 = __toESM(require_core(), 1);
5189
5612
  init_dist();
5190
5613
  init_webgl_vertex_formats();
5191
5614
  init_fill_array();
5192
- WEBGLVertexArray = class extends import_core20.VertexArray {
5615
+ WEBGLVertexArray = class extends import_core22.VertexArray {
5193
5616
  get [Symbol.toStringTag]() {
5194
5617
  return "VertexArray";
5195
5618
  }
@@ -5357,7 +5780,7 @@ ${source}`;
5357
5780
  this.buffer = this.buffer || this.device.createBuffer({ byteLength });
5358
5781
  updateNeeded ||= !compareConstantArrayValues(constantValue, this.bufferValue);
5359
5782
  if (updateNeeded) {
5360
- const typedArray = (0, import_core20.getScratchArray)(value.constructor, length);
5783
+ const typedArray = (0, import_core22.getScratchArray)(value.constructor, length);
5361
5784
  fillArray({ target: typedArray, source: constantValue, start: 0, count: length });
5362
5785
  this.buffer.write(typedArray);
5363
5786
  this.bufferValue = value;
@@ -5375,14 +5798,14 @@ ${source}`;
5375
5798
  }
5376
5799
  return /^\d+$/.test(value);
5377
5800
  }
5378
- var import_core21, WEBGLTransformFeedback;
5801
+ var import_core23, WEBGLTransformFeedback;
5379
5802
  var init_webgl_transform_feedback = __esm({
5380
5803
  "src/adapter/resources/webgl-transform-feedback.ts"() {
5381
5804
  "use strict";
5382
- import_core21 = __toESM(require_core(), 1);
5805
+ import_core23 = __toESM(require_core(), 1);
5383
5806
  init_src2();
5384
5807
  init_webgl_topology_utils();
5385
- WEBGLTransformFeedback = class extends import_core21.TransformFeedback {
5808
+ WEBGLTransformFeedback = class extends import_core23.TransformFeedback {
5386
5809
  device;
5387
5810
  gl;
5388
5811
  handle;
@@ -5445,7 +5868,7 @@ ${source}`;
5445
5868
  const { buffer, byteLength, byteOffset } = this._getBufferRange(bufferOrRange);
5446
5869
  if (location < 0) {
5447
5870
  this.unusedBuffers[locationOrName] = buffer;
5448
- import_core21.log.warn(`${this.id} unusedBuffers varying buffer ${locationOrName}`)();
5871
+ import_core23.log.warn(`${this.id} unusedBuffers varying buffer ${locationOrName}`)();
5449
5872
  return;
5450
5873
  }
5451
5874
  this.buffers[location] = { buffer, byteLength, byteOffset };
@@ -5528,156 +5951,249 @@ ${source}`;
5528
5951
  });
5529
5952
 
5530
5953
  // src/adapter/resources/webgl-query-set.ts
5531
- var import_core22, WEBGLQuerySet;
5954
+ var import_core24, WEBGLQuerySet;
5532
5955
  var init_webgl_query_set = __esm({
5533
5956
  "src/adapter/resources/webgl-query-set.ts"() {
5534
5957
  "use strict";
5535
- import_core22 = __toESM(require_core(), 1);
5536
- WEBGLQuerySet = class extends import_core22.QuerySet {
5958
+ import_core24 = __toESM(require_core(), 1);
5959
+ WEBGLQuerySet = class extends import_core24.QuerySet {
5537
5960
  device;
5538
5961
  handle;
5539
- target = null;
5540
- _queryPending = false;
5541
- _pollingPromise = null;
5962
+ _timestampPairs = [];
5963
+ _occlusionQuery = null;
5964
+ _occlusionActive = false;
5542
5965
  get [Symbol.toStringTag]() {
5543
- return "Query";
5966
+ return "QuerySet";
5544
5967
  }
5545
- // Create a query class
5546
5968
  constructor(device, props) {
5547
5969
  super(device, props);
5548
5970
  this.device = device;
5549
- if (props.count > 1) {
5550
- throw new Error("WebGL QuerySet can only have one value");
5551
- }
5552
- const handle = this.device.gl.createQuery();
5553
- if (!handle) {
5554
- 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;
5555
5986
  }
5556
- this.handle = handle;
5557
5987
  Object.seal(this);
5558
5988
  }
5559
5989
  destroy() {
5560
- 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();
5561
6008
  }
5562
- // FOR RENDER PASS AND COMMAND ENCODER
5563
- /**
5564
- * Shortcut for timer query (dependent on extension in both WebGL1 and 2)
5565
- * Measures GPU time delta between this call and a matching `end` call in the
5566
- * GPU instruction stream.
5567
- */
5568
- beginTimestampQuery() {
5569
- 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)];
5570
6048
  }
5571
- endTimestampQuery() {
5572
- 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;
5573
6061
  }
5574
- // Shortcut for occlusion queries
5575
- beginOcclusionQuery(options) {
5576
- return this._begin(
5577
- options?.conservative ? 36202 /* ANY_SAMPLES_PASSED_CONSERVATIVE */ : 35887 /* ANY_SAMPLES_PASSED */
5578
- );
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;
5579
6080
  }
5580
6081
  endOcclusionQuery() {
5581
- this._end();
5582
- }
5583
- // Shortcut for transformFeedbackQuery
5584
- beginTransformFeedbackQuery() {
5585
- return this._begin(35976 /* TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN */);
5586
- }
5587
- endTransformFeedbackQuery() {
5588
- this._end();
5589
- }
5590
- async resolveQuery() {
5591
- const value = await this.pollQuery();
5592
- 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;
5593
6087
  }
5594
- // PRIVATE METHODS
5595
- /**
5596
- * Due to OpenGL API limitations, after calling `begin()` on one Query
5597
- * instance, `end()` must be called on that same instance before
5598
- * calling `begin()` on another query. While there can be multiple
5599
- * outstanding queries representing disjoint `begin()`/`end()` intervals.
5600
- * It is not possible to interleave or overlap `begin` and `end` calls.
5601
- */
5602
- _begin(target2) {
5603
- 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;
5604
6110
  return;
5605
6111
  }
5606
- this.target = target2;
5607
- this.device.gl.beginQuery(this.target, this.handle);
5608
- 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;
5609
6118
  }
5610
- // ends the current query
5611
- _end() {
5612
- if (this._queryPending) {
5613
- 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");
5614
6122
  }
5615
- if (this.target) {
5616
- this.device.gl.endQuery(this.target);
5617
- this.target = null;
5618
- 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");
5619
6127
  }
5620
- return;
6128
+ return Math.floor(queryIndex / 2);
5621
6129
  }
5622
- // Returns true if the query result is available
5623
- isResultAvailable() {
5624
- if (!this._queryPending) {
6130
+ _isTimestampPairAvailable(pairIndex) {
6131
+ const pair = this._timestampPairs[pairIndex];
6132
+ if (!pair || pair.completedQueries.length === 0) {
5625
6133
  return false;
5626
6134
  }
6135
+ return this._pollQueryAvailability(pair.completedQueries[0]);
6136
+ }
6137
+ _pollQueryAvailability(query) {
6138
+ if (query.result !== null || query.disjoint) {
6139
+ return true;
6140
+ }
5627
6141
  const resultAvailable = this.device.gl.getQueryParameter(
5628
- this.handle,
6142
+ query.handle,
5629
6143
  34919 /* QUERY_RESULT_AVAILABLE */
5630
6144
  );
5631
- if (resultAvailable) {
5632
- this._queryPending = false;
6145
+ if (!resultAvailable) {
6146
+ return false;
5633
6147
  }
5634
- return resultAvailable;
5635
- }
5636
- // Timing query is disjoint, i.e. results are invalid
5637
- isTimerDisjoint() {
5638
- return this.device.gl.getParameter(36795 /* GPU_DISJOINT_EXT */);
5639
- }
5640
- // Returns query result.
5641
- getResult() {
5642
- 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;
5643
6152
  }
5644
- // Returns the query result, converted to milliseconds to match JavaScript conventions.
5645
- getTimerMilliseconds() {
5646
- 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
+ }
5647
6164
  }
5648
- // Polls the query
5649
- pollQuery(limit = Number.POSITIVE_INFINITY) {
5650
- if (this._pollingPromise) {
5651
- return this._pollingPromise;
6165
+ _consumeQueryResult(query) {
6166
+ if (query.promise) {
6167
+ return query.promise;
5652
6168
  }
5653
- let counter = 0;
5654
- this._pollingPromise = new Promise((resolve, reject) => {
6169
+ query.promise = new Promise((resolve, reject) => {
5655
6170
  const poll = () => {
5656
- if (this.isResultAvailable()) {
5657
- resolve(this.getResult());
5658
- this._pollingPromise = null;
5659
- } else if (counter++ > limit) {
5660
- reject("Timed out");
5661
- this._pollingPromise = null;
5662
- } else {
6171
+ if (!this._pollQueryAvailability(query)) {
5663
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);
5664
6180
  }
5665
6181
  };
5666
- requestAnimationFrame(poll);
6182
+ poll();
5667
6183
  });
5668
- return this._pollingPromise;
6184
+ return query.promise;
5669
6185
  }
5670
6186
  };
5671
6187
  }
5672
6188
  });
5673
6189
 
5674
6190
  // src/adapter/resources/webgl-fence.ts
5675
- var import_core23, WEBGLFence;
6191
+ var import_core25, WEBGLFence;
5676
6192
  var init_webgl_fence = __esm({
5677
6193
  "src/adapter/resources/webgl-fence.ts"() {
5678
6194
  "use strict";
5679
- import_core23 = __toESM(require_core(), 1);
5680
- WEBGLFence = class extends import_core23.Fence {
6195
+ import_core25 = __toESM(require_core(), 1);
6196
+ WEBGLFence = class extends import_core25.Fence {
5681
6197
  device;
5682
6198
  gl;
5683
6199
  handle;
@@ -5797,7 +6313,7 @@ ${source}`;
5797
6313
  sourceFormat ||= texture?.glFormat || 6408 /* RGBA */;
5798
6314
  sourceType ||= texture?.glType || 5121 /* UNSIGNED_BYTE */;
5799
6315
  target2 = getPixelArray(target2, sourceType, sourceFormat, sourceWidth, sourceHeight, sourceDepth);
5800
- const signedType = (0, import_core24.getDataType)(target2);
6316
+ const signedType = (0, import_core26.getDataType)(target2);
5801
6317
  sourceType = sourceType || convertDataTypeToGLDataType(signedType);
5802
6318
  const prevHandle = gl.bindFramebuffer(
5803
6319
  36160 /* FRAMEBUFFER */,
@@ -5849,7 +6365,7 @@ ${source}`;
5849
6365
  return webglBufferTarget;
5850
6366
  }
5851
6367
  function getFramebuffer2(source) {
5852
- if (!(source instanceof import_core24.Framebuffer)) {
6368
+ if (!(source instanceof import_core26.Framebuffer)) {
5853
6369
  return { framebuffer: toFramebuffer(source), deleteFramebuffer: true };
5854
6370
  }
5855
6371
  return { framebuffer: source, deleteFramebuffer: false };
@@ -5871,15 +6387,15 @@ ${source}`;
5871
6387
  }
5872
6388
  glType ||= 5121 /* UNSIGNED_BYTE */;
5873
6389
  const shaderType = convertGLDataTypeToDataType(glType);
5874
- const ArrayType = (0, import_core24.getTypedArrayConstructor)(shaderType);
6390
+ const ArrayType = (0, import_core26.getTypedArrayConstructor)(shaderType);
5875
6391
  const components = glFormatToComponents(glFormat);
5876
6392
  return new ArrayType(width * height * components);
5877
6393
  }
5878
- var import_core24;
6394
+ var import_core26;
5879
6395
  var init_webgl_texture_utils = __esm({
5880
6396
  "src/adapter/helpers/webgl-texture-utils.ts"() {
5881
6397
  "use strict";
5882
- import_core24 = __toESM(require_core(), 1);
6398
+ import_core26 = __toESM(require_core(), 1);
5883
6399
  init_webgl_shadertypes();
5884
6400
  init_format_utils();
5885
6401
  init_shader_formats();
@@ -5925,11 +6441,11 @@ ${source}`;
5925
6441
  }
5926
6442
  return true;
5927
6443
  }
5928
- var import_core25, WebGLDevice;
6444
+ var import_core27, WebGLDevice;
5929
6445
  var init_webgl_device = __esm({
5930
6446
  "src/adapter/webgl-device.ts"() {
5931
6447
  "use strict";
5932
- import_core25 = __toESM(require_core(), 1);
6448
+ import_core27 = __toESM(require_core(), 1);
5933
6449
  init_webgl_state_tracker();
5934
6450
  init_create_browser_context();
5935
6451
  init_webgl_context_data();
@@ -5937,6 +6453,7 @@ ${source}`;
5937
6453
  init_webgl_device_features();
5938
6454
  init_webgl_device_limits();
5939
6455
  init_webgl_canvas_context();
6456
+ init_webgl_presentation_context();
5940
6457
  init_spector();
5941
6458
  init_webgl_developer_tools();
5942
6459
  init_webgl_texture_table();
@@ -5947,6 +6464,7 @@ ${source}`;
5947
6464
  init_webgl_texture();
5948
6465
  init_webgl_framebuffer();
5949
6466
  init_webgl_render_pipeline();
6467
+ init_webgl_shared_render_pipeline();
5950
6468
  init_webgl_command_encoder();
5951
6469
  init_webgl_vertex_array();
5952
6470
  init_webgl_transform_feedback();
@@ -5956,7 +6474,7 @@ ${source}`;
5956
6474
  init_unified_parameter_api();
5957
6475
  init_with_parameters();
5958
6476
  init_webgl_extensions();
5959
- WebGLDevice = class extends import_core25.Device {
6477
+ WebGLDevice = class extends import_core27.Device {
5960
6478
  static getDeviceFromContext(gl) {
5961
6479
  if (!gl) {
5962
6480
  return null;
@@ -6007,7 +6525,7 @@ ${source}`;
6007
6525
  }
6008
6526
  constructor(props) {
6009
6527
  super({ ...props, id: props.id || uid("webgl-device") });
6010
- const canvasContextProps = import_core25.Device._getCanvasContextProps(props);
6528
+ const canvasContextProps = import_core27.Device._getCanvasContextProps(props);
6011
6529
  if (!canvasContextProps) {
6012
6530
  throw new Error("WebGLDevice requires props.createCanvasContext to be set");
6013
6531
  }
@@ -6049,7 +6567,7 @@ ${source}`;
6049
6567
  device = WebGLDevice.getDeviceFromContext(gl);
6050
6568
  if (device) {
6051
6569
  if (props._reuseDevices) {
6052
- import_core25.log.log(
6570
+ import_core27.log.log(
6053
6571
  1,
6054
6572
  `Not creating a new Device, instead returning a reference to Device ${device.id} already attached to WebGL context`,
6055
6573
  device
@@ -6073,17 +6591,18 @@ ${source}`;
6073
6591
  this.features.initializeFeatures();
6074
6592
  }
6075
6593
  const glState = new WebGLStateTracker(this.gl, {
6076
- log: (...args) => import_core25.log.log(1, ...args)()
6594
+ log: (...args) => import_core27.log.log(1, ...args)()
6077
6595
  });
6078
6596
  glState.trackState(this.gl, { copyState: false });
6079
6597
  if (props.debug || props.debugWebGL) {
6080
6598
  this.gl = makeDebugContext(this.gl, { debugWebGL: true, traceWebGL: props.debugWebGL });
6081
- import_core25.log.warn("WebGL debug mode activated. Performance reduced.")();
6599
+ import_core27.log.warn("WebGL debug mode activated. Performance reduced.")();
6082
6600
  }
6083
6601
  if (props.debugWebGL) {
6084
- import_core25.log.level = Math.max(import_core25.log.level, 1);
6602
+ import_core27.log.level = Math.max(import_core27.log.level, 1);
6085
6603
  }
6086
6604
  this.commandEncoder = new WEBGLCommandEncoder(this, { id: `${this}-command-encoder` });
6605
+ this.canvasContext._startObservers();
6087
6606
  }
6088
6607
  /**
6089
6608
  * Destroys the device
@@ -6096,6 +6615,7 @@ ${source}`;
6096
6615
  * browser API for destroying WebGL contexts.
6097
6616
  */
6098
6617
  destroy() {
6618
+ this.commandEncoder?.destroy();
6099
6619
  if (!this.props._reuseDevices && !this._reused) {
6100
6620
  const contextData = getWebGLContextData(this.handle);
6101
6621
  contextData.device = null;
@@ -6108,6 +6628,9 @@ ${source}`;
6108
6628
  createCanvasContext(props) {
6109
6629
  throw new Error("WebGL only supports a single canvas");
6110
6630
  }
6631
+ createPresentationContext(props) {
6632
+ return new WebGLPresentationContext(this, props || {});
6633
+ }
6111
6634
  createBuffer(props) {
6112
6635
  const newProps = this._normalizeBufferProps(props);
6113
6636
  return new WEBGLBuffer(this, newProps);
@@ -6142,6 +6665,12 @@ ${source}`;
6142
6665
  createRenderPipeline(props) {
6143
6666
  return new WEBGLRenderPipeline(this, props);
6144
6667
  }
6668
+ _createSharedRenderPipelineWebGL(props) {
6669
+ return new WEBGLSharedRenderPipeline(
6670
+ this,
6671
+ props
6672
+ );
6673
+ }
6145
6674
  createComputePipeline(props) {
6146
6675
  throw new Error("ComputePipeline not supported in WebGL");
6147
6676
  }
@@ -6154,12 +6683,27 @@ ${source}`;
6154
6683
  * Chrome's offscreen canvas does not require gl.commit
6155
6684
  */
6156
6685
  submit(commandBuffer) {
6686
+ let submittedCommandEncoder = null;
6157
6687
  if (!commandBuffer) {
6158
- commandBuffer = this.commandEncoder.finish();
6688
+ submittedCommandEncoder = this.commandEncoder;
6689
+ commandBuffer = submittedCommandEncoder.finish();
6159
6690
  this.commandEncoder.destroy();
6160
- 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();
6161
6706
  }
6162
- commandBuffer._executeCommands();
6163
6707
  }
6164
6708
  //
6165
6709
  // TEMPORARY HACKS - will be removed in v9.1
@@ -6182,7 +6726,7 @@ ${source}`;
6182
6726
  return withGLParameters(this.gl, parameters, func);
6183
6727
  }
6184
6728
  resetWebGL() {
6185
- 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")();
6186
6730
  resetGLParameters(this.gl);
6187
6731
  }
6188
6732
  _getDeviceSpecificTextureFormatCapabilities(capabilities) {
@@ -6254,7 +6798,7 @@ ${source}`;
6254
6798
  this._constants = this._constants || new Array(maxVertexAttributes).fill(null);
6255
6799
  const currentConstant = this._constants[location];
6256
6800
  if (currentConstant && compareConstantArrayValues2(currentConstant, constant)) {
6257
- import_core25.log.info(
6801
+ import_core27.log.info(
6258
6802
  1,
6259
6803
  `setConstantAttributeWebGL(${location}) could have been skipped, value unchanged`
6260
6804
  )();
@@ -6300,21 +6844,21 @@ ${source}`;
6300
6844
  }
6301
6845
  return Boolean(gl && typeof gl.createVertexArray === "function");
6302
6846
  }
6303
- var import_core26, LOG_LEVEL2, WebGLAdapter, webgl2Adapter;
6847
+ var import_core28, LOG_LEVEL2, WebGLAdapter, webgl2Adapter;
6304
6848
  var init_webgl_adapter = __esm({
6305
6849
  "src/adapter/webgl-adapter.ts"() {
6306
6850
  "use strict";
6307
- import_core26 = __toESM(require_core(), 1);
6851
+ import_core28 = __toESM(require_core(), 1);
6308
6852
  init_polyfill_webgl1_extensions();
6309
6853
  init_spector();
6310
6854
  init_webgl_developer_tools();
6311
6855
  LOG_LEVEL2 = 1;
6312
- WebGLAdapter = class extends import_core26.Adapter {
6856
+ WebGLAdapter = class extends import_core28.Adapter {
6313
6857
  /** type of device's created by this adapter */
6314
6858
  type = "webgl";
6315
6859
  constructor() {
6316
6860
  super();
6317
- import_core26.Device.defaultProps = { ...import_core26.Device.defaultProps, ...DEFAULT_SPECTOR_PROPS };
6861
+ import_core28.Device.defaultProps = { ...import_core28.Device.defaultProps, ...DEFAULT_SPECTOR_PROPS };
6318
6862
  }
6319
6863
  /** Force any created WebGL contexts to be WebGL2 contexts, polyfilled with WebGL1 extensions */
6320
6864
  enforceWebGL2(enable2) {
@@ -6329,7 +6873,7 @@ ${source}`;
6329
6873
  return true;
6330
6874
  }
6331
6875
  if (typeof WebGLRenderingContext !== "undefined" && handle instanceof WebGLRenderingContext) {
6332
- import_core26.log.warn("WebGL1 is not supported", handle)();
6876
+ import_core28.log.warn("WebGL1 is not supported", handle)();
6333
6877
  }
6334
6878
  return false;
6335
6879
  }
@@ -6371,19 +6915,19 @@ ${source}`;
6371
6915
  const results = await Promise.allSettled(promises);
6372
6916
  for (const result of results) {
6373
6917
  if (result.status === "rejected") {
6374
- import_core26.log.error(`Failed to initialize debug libraries ${result.reason}`)();
6918
+ import_core28.log.error(`Failed to initialize debug libraries ${result.reason}`)();
6375
6919
  }
6376
6920
  }
6377
6921
  try {
6378
6922
  const device = new WebGLDevice2(props);
6379
- import_core26.log.groupCollapsed(LOG_LEVEL2, `WebGLDevice ${device.id} created`)();
6923
+ import_core28.log.groupCollapsed(LOG_LEVEL2, `WebGLDevice ${device.id} created`)();
6380
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}`;
6381
- import_core26.log.probe(LOG_LEVEL2, message2)();
6382
- 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)();
6383
6927
  return device;
6384
6928
  } finally {
6385
- import_core26.log.groupEnd(LOG_LEVEL2)();
6386
- import_core26.log.info(
6929
+ import_core28.log.groupEnd(LOG_LEVEL2)();
6930
+ import_core28.log.info(
6387
6931
  LOG_LEVEL2,
6388
6932
  `%cWebGL call tracing: luma.log.set('debug-webgl') `,
6389
6933
  "color: white; background: blue; padding: 2px 6px; border-radius: 3px;"