@luma.gl/webgl 9.0.0-alpha.7 → 9.0.0-alpha.8

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 (52) hide show
  1. package/dist/adapter/resources/webgl-render-pipeline.js +12 -0
  2. package/dist/adapter/resources/webgl-render-pipeline.js.map +1 -1
  3. package/dist/adapter/webgl-device.d.ts +13 -7
  4. package/dist/adapter/webgl-device.d.ts.map +1 -1
  5. package/dist/adapter/webgl-device.js +65 -17
  6. package/dist/adapter/webgl-device.js.map +1 -1
  7. package/dist/classic/accessor.d.ts.map +1 -1
  8. package/dist/classic/accessor.js.map +1 -1
  9. package/dist/context/context/create-browser-context.d.ts.map +1 -1
  10. package/dist/context/context/create-browser-context.js +8 -2
  11. package/dist/context/context/create-browser-context.js.map +1 -1
  12. package/dist/context/debug/webgl-developer-tools.d.ts +1 -1
  13. package/dist/context/debug/webgl-developer-tools.d.ts.map +1 -1
  14. package/dist/context/debug/webgl-developer-tools.js +1 -1
  15. package/dist/context/debug/webgl-developer-tools.js.map +1 -1
  16. package/dist/context/polyfill/polyfill-context.js +0 -1
  17. package/dist/context/polyfill/polyfill-context.js.map +1 -1
  18. package/dist/es5/adapter/resources/webgl-render-pipeline.js +12 -0
  19. package/dist/es5/adapter/resources/webgl-render-pipeline.js.map +1 -1
  20. package/dist/es5/adapter/webgl-device.js +79 -25
  21. package/dist/es5/adapter/webgl-device.js.map +1 -1
  22. package/dist/es5/classic/accessor.js.map +1 -1
  23. package/dist/es5/context/context/create-browser-context.js +10 -2
  24. package/dist/es5/context/context/create-browser-context.js.map +1 -1
  25. package/dist/es5/context/debug/webgl-developer-tools.js +1 -1
  26. package/dist/es5/context/debug/webgl-developer-tools.js.map +1 -1
  27. package/dist/es5/context/polyfill/polyfill-context.js +0 -1
  28. package/dist/es5/context/polyfill/polyfill-context.js.map +1 -1
  29. package/dist/es5/index.js.map +1 -1
  30. package/dist/esm/adapter/resources/webgl-render-pipeline.js +12 -0
  31. package/dist/esm/adapter/resources/webgl-render-pipeline.js.map +1 -1
  32. package/dist/esm/adapter/webgl-device.js +65 -17
  33. package/dist/esm/adapter/webgl-device.js.map +1 -1
  34. package/dist/esm/classic/accessor.js.map +1 -1
  35. package/dist/esm/context/context/create-browser-context.js +8 -2
  36. package/dist/esm/context/context/create-browser-context.js.map +1 -1
  37. package/dist/esm/context/debug/webgl-developer-tools.js +1 -1
  38. package/dist/esm/context/debug/webgl-developer-tools.js.map +1 -1
  39. package/dist/esm/context/polyfill/polyfill-context.js +0 -1
  40. package/dist/esm/context/polyfill/polyfill-context.js.map +1 -1
  41. package/dist/esm/index.js.map +1 -1
  42. package/dist/index.d.ts +1 -0
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js.map +1 -1
  45. package/package.json +4 -4
  46. package/src/adapter/resources/webgl-render-pipeline.ts +5 -1
  47. package/src/adapter/webgl-device.ts +79 -27
  48. package/src/classic/accessor.ts +0 -13
  49. package/src/context/context/create-browser-context.ts +6 -2
  50. package/src/context/debug/webgl-developer-tools.ts +2 -2
  51. package/src/context/polyfill/polyfill-context.ts +0 -2
  52. package/src/index.ts +1 -0
@@ -369,14 +369,16 @@ export default class WEBGLRenderPipeline extends RenderPipeline {
369
369
  /** Get the primitive type for transform feedback */
370
370
  function getDrawMode(
371
371
  topology: PrimitiveTopology
372
- ): GL.POINTS | GL.LINES | GL.LINE_STRIP | GL.TRIANGLES | GL.TRIANGLE_STRIP {
372
+ ): GL.POINTS | GL.LINES | GL.LINE_STRIP | GL.LINE_LOOP | GL.TRIANGLES | GL.TRIANGLE_STRIP | GL.TRIANGLE_FAN {
373
373
  // prettier-ignore
374
374
  switch (topology) {
375
375
  case 'point-list': return GL.POINTS;
376
376
  case 'line-list': return GL.LINES;
377
377
  case 'line-strip': return GL.LINE_STRIP;
378
+ case 'line-loop': return GL.LINE_LOOP;
378
379
  case 'triangle-list': return GL.TRIANGLES;
379
380
  case 'triangle-strip': return GL.TRIANGLE_STRIP;
381
+ case 'triangle-fan': return GL.TRIANGLE_FAN;
380
382
  default: throw new Error(topology);
381
383
  }
382
384
  }
@@ -388,8 +390,10 @@ function getGLPrimitive(topology: PrimitiveTopology): GL.POINTS | GL.LINES | GL.
388
390
  case 'point-list': return GL.POINTS;
389
391
  case 'line-list': return GL.LINES;
390
392
  case 'line-strip': return GL.LINES;
393
+ case 'line-loop': return GL.LINES;
391
394
  case 'triangle-list': return GL.TRIANGLES;
392
395
  case 'triangle-strip': return GL.TRIANGLES;
396
+ case 'triangle-fan': return GL.TRIANGLES;
393
397
  default: throw new Error(topology);
394
398
  }
395
399
  }
@@ -13,7 +13,10 @@ import {polyfillContext} from '../context/polyfill/polyfill-context';
13
13
  import {trackContextState} from '../context/state-tracker/track-context-state';
14
14
  import {ContextState} from '../context/context/context-state';
15
15
  import {createBrowserContext} from '../context/context/create-browser-context';
16
- import {createHeadlessContext, isHeadlessGLRegistered} from '../context/context/create-headless-context';
16
+ import {
17
+ createHeadlessContext,
18
+ isHeadlessGLRegistered
19
+ } from '../context/context/create-headless-context';
17
20
  import {getDeviceInfo} from './device-helpers/get-device-info';
18
21
  import {getDeviceFeatures} from './device-helpers/device-features';
19
22
  import {getDeviceLimits, getWebGLLimits, WebGLLimits} from './device-helpers/device-limits';
@@ -61,7 +64,9 @@ let counter = 0;
61
64
 
62
65
  /** WebGPU style Device API for a WebGL context */
63
66
  export default class WebGLDevice extends Device implements ContextState {
64
- // Public API
67
+ //
68
+ // Public `Device` API
69
+ //
65
70
 
66
71
  static type: string = 'webgl';
67
72
 
@@ -71,7 +76,7 @@ export default class WebGLDevice extends Device implements ContextState {
71
76
 
72
77
  readonly info: DeviceInfo;
73
78
  readonly canvasContext: WebGLCanvasContext;
74
- readonly lost: Promise<{reason: 'destroyed'; message: string}>;
79
+
75
80
  readonly handle: WebGLRenderingContext;
76
81
 
77
82
  get features(): Set<DeviceFeature> {
@@ -84,12 +89,20 @@ export default class WebGLDevice extends Device implements ContextState {
84
89
  return this._limits;
85
90
  }
86
91
 
87
- // WebGL specific API
92
+ readonly lost: Promise<{reason: 'destroyed'; message: string}>;
93
+
94
+ private _resolveContextLost?: (value: {reason: 'destroyed'; message: string}) => void;
95
+ private _features?: Set<DeviceFeature>;
96
+ private _limits?: DeviceLimits;
97
+
98
+ //
99
+ // WebGL-only API (not part of `Device` API)
100
+ //
88
101
 
89
102
  /** WebGL1 typed context. Can always be used. */
90
103
  readonly gl: WebGLRenderingContext;
91
104
  /** WebGL2 typed context. Need to check isWebGL2 or isWebGL1 before using. */
92
- readonly gl2: WebGL2RenderingContext;
105
+ readonly gl2: WebGL2RenderingContext | null = null;
93
106
  readonly debug: boolean = false;
94
107
 
95
108
  /** `true` if this is a WebGL1 context. @note `false` if WebGL2 */
@@ -102,9 +115,7 @@ export default class WebGLDevice extends Device implements ContextState {
102
115
  return this._webglLimits;
103
116
  }
104
117
 
105
- private _features: Set<DeviceFeature>;
106
- private _limits: DeviceLimits;
107
- private _webglLimits: WebGLLimits;
118
+ private _webglLimits?: WebGLLimits;
108
119
 
109
120
  /** State used by luma.gl classes: TODO - move to canvasContext*/
110
121
  readonly _canvasSizeInfo = {clientWidth: 0, clientHeight: 0, devicePixelRatio: 1};
@@ -115,6 +126,10 @@ export default class WebGLDevice extends Device implements ContextState {
115
126
  /** Instance of Spector.js (if initialized) */
116
127
  spector;
117
128
 
129
+ //
130
+ // Static methods, expected to be present by `luma.createDevice()`
131
+ //
132
+
118
133
  /**
119
134
  * Get a device instance from a GL context
120
135
  * Creates and instruments the device if not already created
@@ -136,7 +151,7 @@ export default class WebGLDevice extends Device implements ContextState {
136
151
  return new WebGLDevice({gl: gl as WebGLRenderingContext});
137
152
  }
138
153
 
139
- static async create(props?: DeviceProps): Promise<WebGLDevice> {
154
+ static async create(props: DeviceProps = {}): Promise<WebGLDevice> {
140
155
  log.groupCollapsed(LOG_LEVEL, 'WebGLDevice created');
141
156
 
142
157
  // Wait for page to load. Only wait when props. canvas is string
@@ -154,10 +169,20 @@ export default class WebGLDevice extends Device implements ContextState {
154
169
  await loadSpectorJS();
155
170
  }
156
171
 
157
- log.probe(LOG_LEVEL, 'DOM is loaded')();
172
+ log.probe(LOG_LEVEL + 1, 'DOM is loaded')();
173
+
174
+ // @ts-expect-error
175
+ if (props.gl && props.gl.device) {
176
+ return WebGLDevice.attach(props.gl);
177
+ }
178
+
158
179
  return new WebGLDevice(props);
159
180
  }
160
181
 
182
+ //
183
+ // Public API
184
+ //
185
+
161
186
  constructor(props: DeviceProps) {
162
187
  super(props);
163
188
 
@@ -165,16 +190,31 @@ export default class WebGLDevice extends Device implements ContextState {
165
190
  // @ts-expect-error device is attached to context
166
191
  const device: WebGLDevice | undefined = props.gl?.device;
167
192
  if (device) {
168
- log.warn(`WebGL context already attached to device ${device.id}`);
169
- return device;
193
+ throw new Error(`WebGL context already attached to device ${device.id}`);
170
194
  }
171
195
 
172
196
  // Create and instrument context
173
197
  this.canvasContext = new WebGLCanvasContext(this, props);
174
198
 
175
- let gl = props.gl;
176
- gl = gl || (isBrowser() && createBrowserContext(this.canvasContext.canvas, props));
177
- gl = gl || (!isBrowser() && createHeadlessContext(props));
199
+ this.lost = new Promise<{reason: 'destroyed'; message: string}>((resolve) => {
200
+ this._resolveContextLost = resolve;
201
+ });
202
+
203
+ const onContextLost = (event: Event) =>
204
+ this._resolveContextLost?.({
205
+ reason: 'destroyed',
206
+ message: 'Computer entered sleep mode, or too many apps or browser tabs are using the GPU.'
207
+ });
208
+
209
+ let gl: WebGLRenderingContext | WebGL2RenderingContext | null = props.gl;
210
+ gl =
211
+ gl ||
212
+ (isBrowser() ? createBrowserContext(this.canvasContext.canvas, {...props, onContextLost}) : null);
213
+ gl = gl || (!isBrowser() ? createHeadlessContext({...props, onContextLost}) : null);
214
+
215
+ if (!gl) {
216
+ throw new Error('WebGL context creation failed');
217
+ }
178
218
 
179
219
  this.handle = gl;
180
220
  this.gl = this.handle;
@@ -187,7 +227,7 @@ export default class WebGLDevice extends Device implements ContextState {
187
227
 
188
228
  // @ts-expect-error Link webgl context back to device
189
229
  this.gl.device = this;
190
- // @ts-expect-error Annotate webgl context to handle
230
+ // @ts-expect-error Annotate webgl context to handle
191
231
  this.gl._version = this.isWebGL2 ? 2 : 1;
192
232
 
193
233
  // Add subset of WebGL2 methods to WebGL1 context
@@ -198,7 +238,7 @@ export default class WebGLDevice extends Device implements ContextState {
198
238
  const {enable = true, copyState = false} = props;
199
239
  trackContextState(this.gl, {
200
240
  enable,
201
- copyState,
241
+ copyState,
202
242
  log: (...args: any[]) => log.log(1, ...args)()
203
243
  });
204
244
 
@@ -231,15 +271,26 @@ ${this.info.vendor}, ${this.info.renderer} for canvas: ${this.canvasContext.id}`
231
271
  * @note Has no effect for browser contexts, there is no browser API for destroying contexts
232
272
  */
233
273
  destroy() {
234
- let ext = this.gl.getExtension('STACKGL_destroy_context');
274
+ const ext = this.gl.getExtension('STACKGL_destroy_context');
235
275
  if (ext) {
236
276
  ext.destroy();
237
277
  }
238
- // ext = this.gl.getExtension('WEBGL_lose_context');
239
- // if (ext) {
240
- // // TODO - disconnect context lost callbacks?
241
- // ext.loseContext();
242
- // }
278
+ }
279
+
280
+ /**
281
+ * Loses the context
282
+ * @note Triggers context loss, mainly for testing
283
+ */
284
+ loseDevice() {
285
+ const ext = this.gl.getExtension('WEBGL_lose_context');
286
+ if (ext) {
287
+ ext.loseContext();
288
+ }
289
+ // loseContext should trigger context loss callback but
290
+ this._resolveContextLost?.({
291
+ reason: 'destroyed',
292
+ message: 'Application triggered context loss'
293
+ });
243
294
  }
244
295
 
245
296
  get isLost(): boolean {
@@ -266,7 +317,9 @@ ${this.info.vendor}, ${this.info.renderer} for canvas: ${this.canvasContext.id}`
266
317
 
267
318
  /** Returns a WebGL2RenderingContext or throws an error */
268
319
  assertWebGL2(): WebGL2RenderingContext {
269
- assert(this.isWebGL2, 'Requires WebGL2');
320
+ if (!this.gl2) {
321
+ throw new Error('Requires WebGL2');
322
+ }
270
323
  return this.gl2;
271
324
  }
272
325
 
@@ -316,7 +369,7 @@ ${this.info.vendor}, ${this.info.renderer} for canvas: ${this.canvasContext.id}`
316
369
  throw new Error('compute shaders not supported in WebGL');
317
370
  }
318
371
 
319
- private renderPass: WEBGLRenderPass;
372
+ private renderPass: WEBGLRenderPass | null = null;
320
373
 
321
374
  getDefaultRenderPass(): WEBGLRenderPass {
322
375
  this.renderPass =
@@ -333,7 +386,7 @@ ${this.info.vendor}, ${this.info.renderer} for canvas: ${this.canvasContext.id}`
333
386
  * Chrome's offscreen canvas does not require gl.commit
334
387
  */
335
388
  submit(): void {
336
- this.renderPass.endPass();
389
+ this.renderPass?.endPass();
337
390
  this.renderPass = null;
338
391
  // this.canvasContext.commit();
339
392
  }
@@ -351,7 +404,6 @@ function isWebGL(gl: any): boolean {
351
404
  return Boolean(gl && Number.isFinite(gl._version));
352
405
  }
353
406
 
354
-
355
407
  /** Check if supplied parameter is a WebGL2RenderingContext */
356
408
  function isWebGL2(gl: any): boolean {
357
409
  if (typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext) {
@@ -2,19 +2,6 @@ import {assert, checkProps, Buffer, AccessorObject} from '@luma.gl/api';
2
2
  import GL from '@luma.gl/constants';
3
3
  import {getTypedArrayFromGLType} from './typed-array-utils';
4
4
 
5
- // export interface AccessorObject {
6
- // offset?: number;
7
- // stride?: number;
8
- // type?: number;
9
- // size?: number;
10
- // divisor?: number;
11
- // normalized?: boolean;
12
- // integer?: boolean;
13
-
14
- // buffer?: Buffer;
15
- // index?: number;
16
- // }
17
-
18
5
  const DEFAULT_ACCESSOR_VALUES = {
19
6
  offset: 0,
20
7
  stride: 0,
@@ -84,10 +84,14 @@ const DEFAULT_CONTEXT_PROPS: ContextProps = {
84
84
  }
85
85
 
86
86
  if (props.onContextLost) {
87
- canvas.addEventListener('webglcontextlost', props.onContextLost, false);
87
+ // Carefully extract and wrap callbacks to prevent addEventListener from rebinding them.
88
+ const {onContextLost} = props;
89
+ canvas.addEventListener('webglcontextlost',(event: Event) => onContextLost(event), false);
88
90
  }
89
91
  if (props.onContextRestored) {
90
- canvas.addEventListener('webglcontextrestored', props.onContextRestored, false);
92
+ // Carefully extract and wrap callbacks to prevent addEventListener from rebinding them.
93
+ const {onContextRestored} = props;
94
+ canvas.addEventListener('webglcontextrestored', (event: Event) => onContextRestored(event), false);
91
95
  }
92
96
 
93
97
  return gl;
@@ -46,7 +46,7 @@ export async function loadWebGLDeveloperTools(): Promise<void> {
46
46
 
47
47
  // Returns (a potentially new) context with debug instrumentation turned off or on.
48
48
  // Note that this actually returns a new context
49
- export function makeDebugContext(gl: WebGLRenderingContext, props: DebugContextProps = {}): WebGLRenderingContext {
49
+ export function makeDebugContext(gl: WebGLRenderingContext, props: DebugContextProps = {}): WebGLRenderingContext | null {
50
50
  // Return null to ensure we don't try to create a context in this case (TODO what case is that?)
51
51
  if (!gl) {
52
52
  return null;
@@ -133,7 +133,7 @@ function onGLError(props: DebugContextProps, err, functionName: string, args: an
133
133
 
134
134
  // Don't generate function string until it is needed
135
135
  function onValidateGLFunc(props: DebugContextProps, functionName: string, functionArgs: any[]): void {
136
- let functionString: string;
136
+ let functionString: string = '';
137
137
  if (log.level >= 1) {
138
138
  functionString = getFunctionString(functionName, functionArgs);
139
139
  log.log(1, functionString)();
@@ -38,8 +38,6 @@ function initializeExtensions(gl: WebGLRenderingContext): void {
38
38
  for (const extensionName of EXTENSIONS) {
39
39
  const extension = gl.getExtension(extensionName);
40
40
  contextState._extensions[extensionName] = extension;
41
- // TODO - this looks like a mistake?
42
- contextState[extensionName] = extension;
43
41
  }
44
42
  }
45
43
 
package/src/index.ts CHANGED
@@ -39,6 +39,7 @@ export {default as WEBGLVertexArrayObject} from './adapter/objects/webgl-vertex-
39
39
 
40
40
  // WebGL adapter classes (Legacy, will be moved to gltools)
41
41
  export {default as Accessor} from './classic/accessor';
42
+ export type {AccessorObject} from './types';
42
43
  export type {ClassicBufferProps, ClassicBufferProps as BufferProps} from './classic/buffer';
43
44
  export {default as ClassicBuffer, default as Buffer} from './classic/buffer';
44
45