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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/dist/adapter/converters/webgl-texture-table.d.ts +7 -1
  2. package/dist/adapter/converters/webgl-texture-table.d.ts.map +1 -1
  3. package/dist/adapter/converters/webgl-texture-table.js +121 -43
  4. package/dist/adapter/converters/webgl-texture-table.js.map +1 -1
  5. package/dist/adapter/device-helpers/webgl-device-features.d.ts.map +1 -1
  6. package/dist/adapter/device-helpers/webgl-device-features.js +1 -2
  7. package/dist/adapter/device-helpers/webgl-device-features.js.map +1 -1
  8. package/dist/adapter/device-helpers/webgl-device-info.js +5 -0
  9. package/dist/adapter/device-helpers/webgl-device-info.js.map +1 -1
  10. package/dist/adapter/helpers/get-shader-layout-from-glsl.js +23 -21
  11. package/dist/adapter/helpers/get-shader-layout-from-glsl.js.map +1 -1
  12. package/dist/adapter/helpers/parse-shader-compiler-log.d.ts +1 -1
  13. package/dist/adapter/helpers/parse-shader-compiler-log.d.ts.map +1 -1
  14. package/dist/adapter/helpers/parse-shader-compiler-log.js +20 -0
  15. package/dist/adapter/helpers/parse-shader-compiler-log.js.map +1 -1
  16. package/dist/adapter/resources/webgl-buffer.d.ts.map +1 -1
  17. package/dist/adapter/resources/webgl-buffer.js +19 -4
  18. package/dist/adapter/resources/webgl-buffer.js.map +1 -1
  19. package/dist/adapter/resources/webgl-command-buffer.d.ts +3 -4
  20. package/dist/adapter/resources/webgl-command-buffer.d.ts.map +1 -1
  21. package/dist/adapter/resources/webgl-command-buffer.js +11 -7
  22. package/dist/adapter/resources/webgl-command-buffer.js.map +1 -1
  23. package/dist/adapter/resources/webgl-command-encoder.d.ts +5 -4
  24. package/dist/adapter/resources/webgl-command-encoder.d.ts.map +1 -1
  25. package/dist/adapter/resources/webgl-command-encoder.js +20 -7
  26. package/dist/adapter/resources/webgl-command-encoder.js.map +1 -1
  27. package/dist/adapter/resources/webgl-query-set.d.ts +29 -31
  28. package/dist/adapter/resources/webgl-query-set.d.ts.map +1 -1
  29. package/dist/adapter/resources/webgl-query-set.js +193 -97
  30. package/dist/adapter/resources/webgl-query-set.js.map +1 -1
  31. package/dist/adapter/resources/webgl-render-pass.d.ts.map +1 -1
  32. package/dist/adapter/resources/webgl-render-pass.js +17 -0
  33. package/dist/adapter/resources/webgl-render-pass.js.map +1 -1
  34. package/dist/adapter/resources/webgl-render-pipeline.d.ts +13 -19
  35. package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
  36. package/dist/adapter/resources/webgl-render-pipeline.js +36 -154
  37. package/dist/adapter/resources/webgl-render-pipeline.js.map +1 -1
  38. package/dist/adapter/resources/webgl-shared-render-pipeline.d.ts +24 -0
  39. package/dist/adapter/resources/webgl-shared-render-pipeline.d.ts.map +1 -0
  40. package/dist/adapter/resources/webgl-shared-render-pipeline.js +152 -0
  41. package/dist/adapter/resources/webgl-shared-render-pipeline.js.map +1 -0
  42. package/dist/adapter/resources/webgl-texture.d.ts +23 -4
  43. package/dist/adapter/resources/webgl-texture.d.ts.map +1 -1
  44. package/dist/adapter/resources/webgl-texture.js +203 -100
  45. package/dist/adapter/resources/webgl-texture.js.map +1 -1
  46. package/dist/adapter/resources/webgl-transform-feedback.js +5 -5
  47. package/dist/adapter/resources/webgl-transform-feedback.js.map +1 -1
  48. package/dist/adapter/webgl-adapter.d.ts.map +1 -1
  49. package/dist/adapter/webgl-adapter.js +3 -4
  50. package/dist/adapter/webgl-adapter.js.map +1 -1
  51. package/dist/adapter/webgl-device.d.ts +6 -3
  52. package/dist/adapter/webgl-device.d.ts.map +1 -1
  53. package/dist/adapter/webgl-device.js +56 -14
  54. package/dist/adapter/webgl-device.js.map +1 -1
  55. package/dist/adapter/webgl-presentation-context.d.ts +21 -0
  56. package/dist/adapter/webgl-presentation-context.d.ts.map +1 -0
  57. package/dist/adapter/webgl-presentation-context.js +64 -0
  58. package/dist/adapter/webgl-presentation-context.js.map +1 -0
  59. package/dist/context/debug/spector.d.ts.map +1 -1
  60. package/dist/context/debug/spector.js +4 -4
  61. package/dist/context/debug/spector.js.map +1 -1
  62. package/dist/context/debug/webgl-developer-tools.js +2 -0
  63. package/dist/context/debug/webgl-developer-tools.js.map +1 -1
  64. package/dist/context/helpers/create-browser-context.d.ts.map +1 -1
  65. package/dist/context/helpers/create-browser-context.js +6 -8
  66. package/dist/context/helpers/create-browser-context.js.map +1 -1
  67. package/dist/context/helpers/webgl-context-data.d.ts +5 -1
  68. package/dist/context/helpers/webgl-context-data.d.ts.map +1 -1
  69. package/dist/context/helpers/webgl-context-data.js +9 -10
  70. package/dist/context/helpers/webgl-context-data.js.map +1 -1
  71. package/dist/context/parameters/unified-parameter-api.d.ts +1 -1
  72. package/dist/context/parameters/unified-parameter-api.js +2 -2
  73. package/dist/context/parameters/unified-parameter-api.js.map +1 -1
  74. package/dist/context/state-tracker/webgl-state-tracker.js +2 -2
  75. package/dist/context/state-tracker/webgl-state-tracker.js.map +1 -1
  76. package/dist/dist.dev.js +1427 -828
  77. package/dist/dist.min.js +2 -2
  78. package/dist/index.cjs +1325 -811
  79. package/dist/index.cjs.map +4 -4
  80. package/dist/utils/fill-array.js +1 -1
  81. package/dist/utils/fill-array.js.map +1 -1
  82. package/package.json +4 -4
  83. package/src/adapter/converters/webgl-texture-table.ts +159 -47
  84. package/src/adapter/device-helpers/webgl-device-features.ts +1 -2
  85. package/src/adapter/device-helpers/webgl-device-info.ts +6 -0
  86. package/src/adapter/helpers/get-shader-layout-from-glsl.ts +25 -24
  87. package/src/adapter/helpers/parse-shader-compiler-log.ts +23 -1
  88. package/src/adapter/resources/webgl-buffer.ts +16 -4
  89. package/src/adapter/resources/webgl-command-buffer.ts +21 -24
  90. package/src/adapter/resources/webgl-command-encoder.ts +22 -7
  91. package/src/adapter/resources/webgl-query-set.ts +229 -102
  92. package/src/adapter/resources/webgl-render-pass.ts +19 -0
  93. package/src/adapter/resources/webgl-render-pipeline.ts +46 -181
  94. package/src/adapter/resources/webgl-shared-render-pipeline.ts +208 -0
  95. package/src/adapter/resources/webgl-texture.ts +326 -121
  96. package/src/adapter/resources/webgl-transform-feedback.ts +5 -5
  97. package/src/adapter/webgl-adapter.ts +3 -4
  98. package/src/adapter/webgl-device.ts +66 -19
  99. package/src/adapter/webgl-presentation-context.ts +93 -0
  100. package/src/context/debug/spector.ts +4 -4
  101. package/src/context/debug/webgl-developer-tools.ts +2 -0
  102. package/src/context/helpers/create-browser-context.ts +8 -8
  103. package/src/context/helpers/webgl-context-data.ts +17 -11
  104. package/src/context/parameters/unified-parameter-api.ts +2 -2
  105. package/src/context/state-tracker/webgl-state-tracker.ts +2 -2
  106. package/src/utils/fill-array.ts +1 -1
@@ -8,6 +8,8 @@ import type {
8
8
  DeviceInfo,
9
9
  DeviceTextureFormatCapabilities,
10
10
  CanvasContextProps,
11
+ PresentationContextProps,
12
+ PresentationContext,
11
13
  Buffer,
12
14
  Texture,
13
15
  Framebuffer,
@@ -23,6 +25,7 @@ import type {
23
25
  FramebufferProps,
24
26
  // RenderPipeline,
25
27
  RenderPipelineProps,
28
+ SharedRenderPipeline,
26
29
  ComputePipeline,
27
30
  ComputePipelineProps,
28
31
  // CommandEncoder,
@@ -36,10 +39,12 @@ import {Device, CanvasContext, log} from '@luma.gl/core';
36
39
  import type {GLExtensions} from '@luma.gl/constants';
37
40
  import {WebGLStateTracker} from '../context/state-tracker/webgl-state-tracker';
38
41
  import {createBrowserContext} from '../context/helpers/create-browser-context';
42
+ import {getWebGLContextData} from '../context/helpers/webgl-context-data';
39
43
  import {getDeviceInfo} from './device-helpers/webgl-device-info';
40
44
  import {WebGLDeviceFeatures} from './device-helpers/webgl-device-features';
41
45
  import {WebGLDeviceLimits} from './device-helpers/webgl-device-limits';
42
46
  import {WebGLCanvasContext} from './webgl-canvas-context';
47
+ import {WebGLPresentationContext} from './webgl-presentation-context';
43
48
  import type {Spector} from '../context/debug/spector-types';
44
49
  import {initializeSpectorJS} from '../context/debug/spector';
45
50
  import {makeDebugContext} from '../context/debug/webgl-developer-tools';
@@ -52,6 +57,7 @@ import {WEBGLSampler} from './resources/webgl-sampler';
52
57
  import {WEBGLTexture} from './resources/webgl-texture';
53
58
  import {WEBGLFramebuffer} from './resources/webgl-framebuffer';
54
59
  import {WEBGLRenderPipeline} from './resources/webgl-render-pipeline';
60
+ import {WEBGLSharedRenderPipeline} from './resources/webgl-shared-render-pipeline';
55
61
  import {WEBGLCommandEncoder} from './resources/webgl-command-encoder';
56
62
  import {WEBGLCommandBuffer} from './resources/webgl-command-buffer';
57
63
  import {WEBGLVertexArray} from './resources/webgl-vertex-array';
@@ -70,6 +76,13 @@ import {getWebGLExtension} from '../context/helpers/webgl-extensions';
70
76
 
71
77
  /** WebGPU style Device API for a WebGL context */
72
78
  export class WebGLDevice extends Device {
79
+ static getDeviceFromContext(gl: WebGL2RenderingContext | null): WebGLDevice | null {
80
+ if (!gl) {
81
+ return null;
82
+ }
83
+ // @ts-expect-error Ingore WebGL2RenderingContext type
84
+ return gl.luma?.device ?? null;
85
+ }
73
86
  // Public `Device` API
74
87
 
75
88
  /** type of this device */
@@ -100,7 +113,7 @@ export class WebGLDevice extends Device {
100
113
  _constants: (TypedArray | null)[];
101
114
 
102
115
  /** State used by luma.gl classes - TODO - not used? */
103
- readonly _extensions: GLExtensions = {};
116
+ readonly extensions!: GLExtensions;
104
117
  _polyfilled: boolean = false;
105
118
 
106
119
  /** Instance of Spector.js (if initialized) */
@@ -141,7 +154,8 @@ export class WebGLDevice extends Device {
141
154
  // Note that this can be avoided in webgl2adapter.create() if
142
155
  // DeviceProps._reuseDevices is set.
143
156
  // @ts-expect-error device is attached to context
144
- let device: WebGLDevice | undefined = canvasContextProps.canvas?.gl?.device;
157
+ const existingContext = canvasContextProps.canvas?.gl ?? null;
158
+ let device: WebGLDevice | null = WebGLDevice.getDeviceFromContext(existingContext);
145
159
  if (device) {
146
160
  throw new Error(`WebGL context already attached to device ${device.id}`);
147
161
  }
@@ -190,8 +204,7 @@ export class WebGLDevice extends Device {
190
204
 
191
205
  // Note that the browser will only create one WebGL context per canvas.
192
206
  // This means that a newly created gl context may already have a device attached to it.
193
- // @ts-expect-error luma.gl stores a device reference on the context.
194
- device = gl.device;
207
+ device = WebGLDevice.getDeviceFromContext(gl);
195
208
  if (device) {
196
209
  if (props._reuseDevices) {
197
210
  log.log(
@@ -199,6 +212,9 @@ export class WebGLDevice extends Device {
199
212
  `Not creating a new Device, instead returning a reference to Device ${device.id} already attached to WebGL context`,
200
213
  device
201
214
  )();
215
+ // Destroy the orphaned canvas context that was created above (line 149)
216
+ // to prevent its ResizeObserver from firing callbacks with undefined device
217
+ this.canvasContext.destroy();
202
218
  device._reused = true;
203
219
  return device;
204
220
  }
@@ -214,16 +230,15 @@ export class WebGLDevice extends Device {
214
230
  this.spectorJS = initializeSpectorJS({...this.props, gl: this.handle});
215
231
 
216
232
  // Instrument context
217
- (this.gl as any).device = this; // Update GL context: Link webgl context back to device
233
+ const contextData = getWebGLContextData(this.handle);
234
+ contextData.device = this; // Update GL context: Link webgl context back to device
235
+
236
+ this.extensions = contextData.extensions || (contextData.extensions = {});
218
237
 
219
238
  // initialize luma Device fields
220
- this.info = getDeviceInfo(this.gl, this._extensions);
239
+ this.info = getDeviceInfo(this.gl, this.extensions);
221
240
  this.limits = new WebGLDeviceLimits(this.gl);
222
- this.features = new WebGLDeviceFeatures(
223
- this.gl,
224
- this._extensions,
225
- this.props._disabledFeatures
226
- );
241
+ this.features = new WebGLDeviceFeatures(this.gl, this.extensions, this.props._disabledFeatures);
227
242
  if (this.props._initializeFeatures) {
228
243
  this.features.initializeFeatures();
229
244
  }
@@ -245,6 +260,7 @@ export class WebGLDevice extends Device {
245
260
  }
246
261
 
247
262
  this.commandEncoder = new WEBGLCommandEncoder(this, {id: `${this}-command-encoder`});
263
+ this.canvasContext._startObservers();
248
264
  }
249
265
 
250
266
  /**
@@ -258,6 +274,7 @@ export class WebGLDevice extends Device {
258
274
  * browser API for destroying WebGL contexts.
259
275
  */
260
276
  destroy(): void {
277
+ this.commandEncoder?.destroy();
261
278
  // Note that deck.gl (especially in React strict mode) depends on being able
262
279
  // to asynchronously create a Device against the same canvas (i.e. WebGL context)
263
280
  // multiple times and getting the same device back. Since deck.gl is not aware
@@ -265,7 +282,8 @@ export class WebGLDevice extends Device {
265
282
  // Therefore we must do nothing in destroy() if props._reuseDevices is true
266
283
  if (!this.props._reuseDevices && !this._reused) {
267
284
  // Delete the reference to the device that we store on the WebGL context
268
- delete (this.gl as any).device;
285
+ const contextData = getWebGLContextData(this.handle);
286
+ contextData.device = null;
269
287
  }
270
288
  }
271
289
 
@@ -279,6 +297,10 @@ export class WebGLDevice extends Device {
279
297
  throw new Error('WebGL only supports a single canvas');
280
298
  }
281
299
 
300
+ createPresentationContext(props?: PresentationContextProps): PresentationContext {
301
+ return new WebGLPresentationContext(this, props || {});
302
+ }
303
+
282
304
  createBuffer(props: BufferProps | ArrayBuffer | ArrayBufferView): WEBGLBuffer {
283
305
  const newProps = this._normalizeBufferProps(props);
284
306
  return new WEBGLBuffer(this, newProps);
@@ -324,6 +346,13 @@ export class WebGLDevice extends Device {
324
346
  return new WEBGLRenderPipeline(this, props);
325
347
  }
326
348
 
349
+ override _createSharedRenderPipelineWebGL(props: RenderPipelineProps): SharedRenderPipeline {
350
+ return new WEBGLSharedRenderPipeline(
351
+ this,
352
+ props as RenderPipelineProps & {vs: WEBGLShader; fs: WEBGLShader}
353
+ );
354
+ }
355
+
327
356
  createComputePipeline(props?: ComputePipelineProps): ComputePipeline {
328
357
  throw new Error('ComputePipeline not supported in WebGL');
329
358
  }
@@ -337,14 +366,32 @@ export class WebGLDevice extends Device {
337
366
  * https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext/commit
338
367
  * Chrome's offscreen canvas does not require gl.commit
339
368
  */
340
- submit(commandBuffer: WEBGLCommandBuffer): void {
369
+ submit(commandBuffer?: WEBGLCommandBuffer): void {
370
+ let submittedCommandEncoder: WEBGLCommandEncoder | null = null;
341
371
  if (!commandBuffer) {
342
- commandBuffer = this.commandEncoder.finish();
372
+ submittedCommandEncoder = this.commandEncoder;
373
+ commandBuffer = submittedCommandEncoder.finish();
343
374
  this.commandEncoder.destroy();
344
- this.commandEncoder = this.createCommandEncoder({id: `${this.id}-default-encoder`});
375
+ this.commandEncoder = this.createCommandEncoder({
376
+ id: submittedCommandEncoder.props.id,
377
+ timeProfilingQuerySet: submittedCommandEncoder.getTimeProfilingQuerySet()
378
+ });
345
379
  }
346
380
 
347
- commandBuffer._executeCommands();
381
+ try {
382
+ commandBuffer._executeCommands();
383
+
384
+ if (submittedCommandEncoder) {
385
+ submittedCommandEncoder
386
+ .resolveTimeProfilingQuerySet()
387
+ .then(() => {
388
+ this.commandEncoder._gpuTimeMs = submittedCommandEncoder._gpuTimeMs;
389
+ })
390
+ .catch(() => {});
391
+ }
392
+ } finally {
393
+ commandBuffer.destroy();
394
+ }
348
395
  }
349
396
 
350
397
  //
@@ -407,7 +454,7 @@ export class WebGLDevice extends Device {
407
454
  override _getDeviceSpecificTextureFormatCapabilities(
408
455
  capabilities: DeviceTextureFormatCapabilities
409
456
  ): DeviceTextureFormatCapabilities {
410
- return getTextureFormatCapabilitiesWebGL(this.gl, capabilities, this._extensions);
457
+ return getTextureFormatCapabilitiesWebGL(this.gl, capabilities, this.extensions);
411
458
  }
412
459
 
413
460
  //
@@ -510,8 +557,8 @@ export class WebGLDevice extends Device {
510
557
 
511
558
  /** Ensure extensions are only requested once */
512
559
  getExtension(name: keyof GLExtensions): GLExtensions {
513
- getWebGLExtension(this.gl, name, this._extensions);
514
- return this._extensions;
560
+ getWebGLExtension(this.gl, name, this.extensions);
561
+ return this.extensions;
515
562
  }
516
563
 
517
564
  // INTERNAL SUPPORT METHODS FOR WEBGL RESOURCES
@@ -0,0 +1,93 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import type {PresentationContextProps, TextureFormatDepthStencil, Framebuffer} from '@luma.gl/core';
6
+ import {PresentationContext} from '@luma.gl/core';
7
+ import type {WebGLDevice} from './webgl-device';
8
+
9
+ type PresentationCanvasRenderingContext2D =
10
+ | CanvasRenderingContext2D
11
+ | OffscreenCanvasRenderingContext2D;
12
+
13
+ /**
14
+ * Tracks a non-WebGL destination canvas while rendering into the device's default canvas context.
15
+ */
16
+ export class WebGLPresentationContext extends PresentationContext {
17
+ readonly device: WebGLDevice;
18
+ readonly handle = null;
19
+ readonly context2d: PresentationCanvasRenderingContext2D;
20
+
21
+ get [Symbol.toStringTag](): string {
22
+ return 'WebGLPresentationContext';
23
+ }
24
+
25
+ constructor(device: WebGLDevice, props: PresentationContextProps = {}) {
26
+ super(props);
27
+ this.device = device;
28
+ const contextLabel = `${this[Symbol.toStringTag]}(${this.id})`;
29
+
30
+ const defaultCanvasContext = this.device.getDefaultCanvasContext();
31
+ if (!defaultCanvasContext.offscreenCanvas) {
32
+ throw new Error(
33
+ `${contextLabel}: WebGL PresentationContext requires the default CanvasContext canvas to be an OffscreenCanvas`
34
+ );
35
+ }
36
+
37
+ const context2d = this.canvas.getContext('2d');
38
+ if (!context2d) {
39
+ throw new Error(`${contextLabel}: Failed to create 2d presentation context`);
40
+ }
41
+ this.context2d = context2d;
42
+
43
+ this._setAutoCreatedCanvasId(`${this.device.id}-presentation-canvas`);
44
+ this._configureDevice();
45
+ this._startObservers();
46
+ }
47
+
48
+ present(): void {
49
+ this._resizeDrawingBufferIfNeeded();
50
+ this.device.submit();
51
+
52
+ const defaultCanvasContext = this.device.getDefaultCanvasContext();
53
+ const [sourceWidth, sourceHeight] = defaultCanvasContext.getDrawingBufferSize();
54
+
55
+ // Responsive layouts can transiently collapse presentation canvases to 0x0 during reflow.
56
+ // In that case WebGL has nothing meaningful to present, and drawImage() would throw when the
57
+ // offscreen source canvas has zero width or height.
58
+ if (
59
+ this.drawingBufferWidth === 0 ||
60
+ this.drawingBufferHeight === 0 ||
61
+ sourceWidth === 0 ||
62
+ sourceHeight === 0 ||
63
+ defaultCanvasContext.canvas.width === 0 ||
64
+ defaultCanvasContext.canvas.height === 0
65
+ ) {
66
+ return;
67
+ }
68
+
69
+ if (
70
+ sourceWidth !== this.drawingBufferWidth ||
71
+ sourceHeight !== this.drawingBufferHeight ||
72
+ defaultCanvasContext.canvas.width !== this.drawingBufferWidth ||
73
+ defaultCanvasContext.canvas.height !== this.drawingBufferHeight
74
+ ) {
75
+ throw new Error(
76
+ `${this[Symbol.toStringTag]}(${this.id}): Default canvas context size ${sourceWidth}x${sourceHeight} does not match presentation size ${this.drawingBufferWidth}x${this.drawingBufferHeight}`
77
+ );
78
+ }
79
+
80
+ this.context2d.clearRect(0, 0, this.drawingBufferWidth, this.drawingBufferHeight);
81
+ this.context2d.drawImage(defaultCanvasContext.canvas, 0, 0);
82
+ }
83
+
84
+ protected override _configureDevice(): void {}
85
+
86
+ protected override _getCurrentFramebuffer(options?: {
87
+ depthStencilFormat?: TextureFormatDepthStencil | false;
88
+ }): Framebuffer {
89
+ const defaultCanvasContext = this.device.getDefaultCanvasContext();
90
+ defaultCanvasContext.setDrawingBufferSize(this.drawingBufferWidth, this.drawingBufferHeight);
91
+ return defaultCanvasContext.getCurrentFramebuffer(options);
92
+ }
93
+ }
@@ -4,6 +4,7 @@
4
4
 
5
5
  import {log} from '@luma.gl/core';
6
6
  import {loadScript} from '../../utils/load-script';
7
+ import {getWebGLContextData} from '../helpers/webgl-context-data';
7
8
 
8
9
  import type {Spector} from './spector-types';
9
10
 
@@ -91,11 +92,10 @@ export function initializeSpectorJS(props: SpectorProps): Spector | null {
91
92
  if (props.gl) {
92
93
  // capture startup
93
94
  const gl = props.gl;
94
- // @ts-expect-error
95
- const device = gl.device;
95
+ const contextData = getWebGLContextData(gl);
96
+ const device = contextData.device;
96
97
  spector?.startCapture(props.gl, 500); // 500 commands
97
- // @ts-expect-error
98
- gl.device = device;
98
+ contextData.device = device;
99
99
 
100
100
  new Promise(resolve => setTimeout(resolve, 2000)).then(_ => {
101
101
  log.info('Spector capture stopped after 2 seconds')();
@@ -104,6 +104,8 @@ function getDebugContext(
104
104
  // Store the debug context
105
105
  data.realContext = gl;
106
106
  data.debugContext = debugContext;
107
+ // Share the context metadata object with the debug context so lookups stay consistent.
108
+ (debugContext as {luma?: unknown}).luma = data;
107
109
  debugContext.debug = true;
108
110
 
109
111
  // Return it
@@ -2,6 +2,8 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
+ import {getWebGLContextData} from './webgl-context-data';
6
+
5
7
  /**
6
8
  * ContextProps
7
9
  * @param onContextLost
@@ -55,15 +57,11 @@ export function createBrowserContext(
55
57
  }
56
58
 
57
59
  // Creation failed with failIfMajorPerformanceCaveat - Try a Software GPU
60
+ let softwareRenderer = false;
58
61
  if (!gl && allowSoftwareRenderer) {
59
62
  webglProps.failIfMajorPerformanceCaveat = false;
60
63
  gl = canvas.getContext('webgl2', webglProps);
61
- if (gl) {
62
- // @ts-expect-error
63
- gl.luma ||= {};
64
- // @ts-expect-error
65
- gl.luma.softwareRenderer = true;
66
- }
64
+ softwareRenderer = true;
67
65
  }
68
66
 
69
67
  if (!gl) {
@@ -79,6 +77,10 @@ export function createBrowserContext(
79
77
  throw new Error(`Failed to create WebGL context: ${errorMessage}`);
80
78
  }
81
79
 
80
+ // Initialize luma.gl specific context data
81
+ const luma = getWebGLContextData(gl);
82
+ luma.softwareRenderer = softwareRenderer;
83
+
82
84
  // Carefully extract and wrap callbacks to prevent addEventListener from rebinding them.
83
85
  const {onContextLost, onContextRestored} = props;
84
86
  canvas.addEventListener('webglcontextlost', (event: Event) => onContextLost(event), false);
@@ -88,8 +90,6 @@ export function createBrowserContext(
88
90
  false
89
91
  );
90
92
 
91
- // @ts-expect-error
92
- gl.luma ||= {};
93
93
  return gl;
94
94
  } finally {
95
95
  canvas.removeEventListener('webglcontextcreationerror', onCreateError, false);
@@ -2,12 +2,17 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
+ import type {GLExtensions} from '@luma.gl/constants';
6
+
5
7
  /**
6
8
  * Stores luma.gl specific state associated with a context
7
9
  */
8
10
  export interface WebGLContextData {
11
+ /** This type is used by lower level code that is not aware of the Device type */
12
+ device?: unknown;
9
13
  _polyfilled: boolean;
10
- _extensions: Record<string, any>;
14
+ extensions: GLExtensions;
15
+ softwareRenderer?: boolean;
11
16
  }
12
17
 
13
18
  /**
@@ -16,16 +21,17 @@ export interface WebGLContextData {
16
21
  */
17
22
  export function getWebGLContextData(gl: WebGL2RenderingContext): WebGLContextData {
18
23
  // @ts-expect-error
19
- const luma = gl.luma as WebGLContextData | null;
20
- if (!luma) {
21
- const contextState: WebGLContextData = {
22
- _polyfilled: false,
23
- _extensions: {}
24
- };
25
- // @ts-expect-error
26
- gl.luma = contextState;
27
- }
24
+ const contextData = (gl.luma as WebGLContextData | null) || {
25
+ _polyfilled: false,
26
+ extensions: {},
27
+ softwareRenderer: false
28
+ };
29
+
30
+ contextData._polyfilled ??= false;
31
+ contextData.extensions ||= {};
28
32
 
29
33
  // @ts-expect-error
30
- return gl.luma;
34
+ gl.luma = contextData;
35
+
36
+ return contextData;
31
37
  }
@@ -18,7 +18,7 @@ export type {GLParameters};
18
18
  /**
19
19
  * Sets any GL parameter regardless of function (gl.blendMode, ...)
20
20
  *
21
- * @note requires a `cache` object to be set on the context (gl.state.cache)
21
+ * @note requires a `cache` object to be set on the context (lumaState.cache)
22
22
  * This object is used to fill in any missing values for composite setter functions
23
23
  */
24
24
  export function setGLParameters(gl: WebGL2RenderingContext, parameters: GLParameters): void {
@@ -58,7 +58,7 @@ export function setGLParameters(gl: WebGL2RenderingContext, parameters: GLParame
58
58
  // But it is too inconvenient to always require a cache parameter here.
59
59
  // This is the ONLY external dependency in this module/
60
60
  // @ts-expect-error
61
- const cache = gl.state && gl.state.cache;
61
+ const cache = gl.lumaState?.cache;
62
62
  if (cache) {
63
63
  for (const key in compositeSetters) {
64
64
  // TODO - avoid calling composite setters if values have not changed.
@@ -21,7 +21,7 @@ import {
21
21
  export class WebGLStateTracker {
22
22
  static get(gl: WebGL2RenderingContext): WebGLStateTracker {
23
23
  // @ts-expect-error
24
- return gl.state as WebGLStateTracker;
24
+ return gl.lumaState as WebGLStateTracker;
25
25
  }
26
26
 
27
27
  gl: WebGL2RenderingContext;
@@ -78,7 +78,7 @@ export class WebGLStateTracker {
78
78
  this.initialized = true;
79
79
 
80
80
  // @ts-expect-error
81
- this.gl.state = this;
81
+ this.gl.lumaState = this;
82
82
 
83
83
  installProgramSpy(gl);
84
84
 
@@ -16,7 +16,7 @@ export function fillArray(options: {
16
16
  const total = count * length;
17
17
  let copied = 0;
18
18
  for (let i = start; copied < length; copied++) {
19
- target[i++] = source[copied];
19
+ target[i++] = source[copied] ?? 0;
20
20
  }
21
21
 
22
22
  while (copied < total) {