@luma.gl/webgl 9.1.0-alpha.15 → 9.1.0-alpha.16

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 (43) hide show
  1. package/dist/adapter/converters/device-parameters.d.ts +3 -3
  2. package/dist/adapter/converters/device-parameters.d.ts.map +1 -1
  3. package/dist/adapter/helpers/webgl-texture-utils.d.ts +24 -22
  4. package/dist/adapter/helpers/webgl-texture-utils.d.ts.map +1 -1
  5. package/dist/adapter/helpers/webgl-texture-utils.js +6 -224
  6. package/dist/adapter/resources/webgl-command-buffer.js +15 -15
  7. package/dist/adapter/resources/webgl-render-pipeline.d.ts +1 -1
  8. package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
  9. package/dist/adapter/resources/webgl-render-pipeline.js +24 -11
  10. package/dist/adapter/resources/webgl-shader.d.ts +1 -0
  11. package/dist/adapter/resources/webgl-shader.d.ts.map +1 -1
  12. package/dist/adapter/resources/webgl-shader.js +6 -4
  13. package/dist/adapter/webgl-adapter.d.ts.map +1 -1
  14. package/dist/adapter/webgl-adapter.js +4 -10
  15. package/dist/adapter/webgl-device.d.ts +1 -2
  16. package/dist/adapter/webgl-device.d.ts.map +1 -1
  17. package/dist/adapter/webgl-device.js +33 -14
  18. package/dist/context/debug/spector-types.js +1 -1
  19. package/dist/context/debug/spector.d.ts +5 -5
  20. package/dist/context/debug/spector.d.ts.map +1 -1
  21. package/dist/context/debug/spector.js +6 -6
  22. package/dist/context/debug/webgl-developer-tools.d.ts +1 -3
  23. package/dist/context/debug/webgl-developer-tools.d.ts.map +1 -1
  24. package/dist/context/debug/webgl-developer-tools.js +4 -19
  25. package/dist/context/helpers/create-browser-context.d.ts +6 -22
  26. package/dist/context/helpers/create-browser-context.d.ts.map +1 -1
  27. package/dist/context/helpers/create-browser-context.js +26 -32
  28. package/dist/dist.dev.js +147 -135
  29. package/dist/dist.min.js +2 -2
  30. package/dist/index.cjs +129 -123
  31. package/dist/index.cjs.map +3 -3
  32. package/package.json +3 -3
  33. package/src/adapter/converters/device-parameters.ts +3 -3
  34. package/src/adapter/helpers/webgl-texture-utils.ts +33 -30
  35. package/src/adapter/resources/webgl-command-buffer.ts +16 -16
  36. package/src/adapter/resources/webgl-render-pipeline.ts +26 -11
  37. package/src/adapter/resources/webgl-shader.ts +7 -5
  38. package/src/adapter/webgl-adapter.ts +4 -12
  39. package/src/adapter/webgl-device.ts +67 -40
  40. package/src/context/debug/spector-types.ts +1 -1
  41. package/src/context/debug/spector.ts +11 -11
  42. package/src/context/debug/webgl-developer-tools.ts +5 -31
  43. package/src/context/helpers/create-browser-context.ts +39 -64
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luma.gl/webgl",
3
- "version": "9.1.0-alpha.15",
3
+ "version": "9.1.0-alpha.16",
4
4
  "description": "WebGL2 adapter for the luma.gl core API",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -43,9 +43,9 @@
43
43
  "@luma.gl/core": "9.1.0-alpha.14"
44
44
  },
45
45
  "dependencies": {
46
- "@luma.gl/constants": "9.1.0-alpha.15",
46
+ "@luma.gl/constants": "9.1.0-alpha.16",
47
47
  "@math.gl/types": "4.1.0-alpha.3",
48
48
  "@probe.gl/env": "^4.0.8"
49
49
  },
50
- "gitHead": "41af576ca655cb749a5567cf903f9e9242793c77"
50
+ "gitHead": "39eec40d12c826548b636c057fdb8572adfe611f"
51
51
  }
@@ -31,7 +31,7 @@ export function withDeviceAndGLParameters<T = unknown>(
31
31
  device: Device,
32
32
  parameters: Parameters,
33
33
  glParameters: GLParameters,
34
- func: (device?: Device) => T
34
+ func: (_?: Device) => T
35
35
  ): T {
36
36
  if (isObjectEmpty(parameters)) {
37
37
  // Avoid setting state if no parameters provided. Just call and return
@@ -62,7 +62,7 @@ export function withDeviceAndGLParameters<T = unknown>(
62
62
  export function withGLParameters<T = unknown>(
63
63
  device: Device,
64
64
  parameters: GLParameters,
65
- func: (device?: Device) => T
65
+ func: (_?: Device) => T
66
66
  ): T {
67
67
  if (isObjectEmpty(parameters)) {
68
68
  // Avoid setting state if no parameters provided. Just call and return
@@ -91,7 +91,7 @@ export function withGLParameters<T = unknown>(
91
91
  export function withDeviceParameters<T = unknown>(
92
92
  device: Device,
93
93
  parameters: Parameters,
94
- func: (device?: Device) => T
94
+ func: (_?: Device) => T
95
95
  ): T {
96
96
  if (isObjectEmpty(parameters)) {
97
97
  // Avoid setting state if no parameters provided. Just call and return
@@ -490,6 +490,30 @@ export function setMipLevelFromGPUBuffer(
490
490
  gl.bindBuffer(GL.PIXEL_UNPACK_BUFFER, null);
491
491
  }
492
492
  */
493
+ export type ReadPixelsToArrayOptions = {
494
+ sourceX?: number;
495
+ sourceY?: number;
496
+ sourceFormat?: number;
497
+ sourceAttachment?: number;
498
+ target?: Uint8Array | Uint16Array | Float32Array;
499
+ // following parameters are auto deduced if not provided
500
+ sourceWidth?: number;
501
+ sourceHeight?: number;
502
+ sourceDepth?: number;
503
+ sourceType?: number;
504
+ };
505
+
506
+ export type ReadPixelsToBufferOptions = {
507
+ sourceX?: number;
508
+ sourceY?: number;
509
+ sourceFormat?: number;
510
+ target?: Buffer; // A new Buffer object is created when not provided.
511
+ targetByteOffset?: number; // byte offset in buffer object
512
+ // following parameters are auto deduced if not provided
513
+ sourceWidth?: number;
514
+ sourceHeight?: number;
515
+ sourceType?: number;
516
+ };
493
517
 
494
518
  /**
495
519
  * Copies data from a type or a Texture object into ArrayBuffer object.
@@ -504,18 +528,7 @@ export function setMipLevelFromGPUBuffer(
504
528
  */
505
529
  export function readPixelsToArray(
506
530
  source: Framebuffer | Texture,
507
- options?: {
508
- sourceX?: number;
509
- sourceY?: number;
510
- sourceFormat?: number;
511
- sourceAttachment?: number;
512
- target?: Uint8Array | Uint16Array | Float32Array;
513
- // following parameters are auto deduced if not provided
514
- sourceWidth?: number;
515
- sourceHeight?: number;
516
- sourceDepth?: number;
517
- sourceType?: number;
518
- }
531
+ options?: ReadPixelsToArrayOptions
519
532
  ): Uint8Array | Uint16Array | Float32Array {
520
533
  const {
521
534
  sourceX = 0,
@@ -576,17 +589,7 @@ export function readPixelsToArray(
576
589
  */
577
590
  export function readPixelsToBuffer(
578
591
  source: Framebuffer | Texture,
579
- options?: {
580
- sourceX?: number;
581
- sourceY?: number;
582
- sourceFormat?: number;
583
- target?: Buffer; // A new Buffer object is created when not provided.
584
- targetByteOffset?: number; // byte offset in buffer object
585
- // following parameters are auto deduced if not provided
586
- sourceWidth?: number;
587
- sourceHeight?: number;
588
- sourceType?: number;
589
- }
592
+ options?: ReadPixelsToBufferOptions
590
593
  ): WEBGLBuffer {
591
594
  const {
592
595
  target,
@@ -620,11 +623,11 @@ export function readPixelsToBuffer(
620
623
  // TODO(donmccurdy): Do we have tests to confirm this is working?
621
624
  const commandEncoder = source.device.createCommandEncoder();
622
625
  commandEncoder.copyTextureToBuffer({
623
- source: source as Texture,
626
+ sourceTexture: source as Texture,
624
627
  width: sourceWidth,
625
628
  height: sourceHeight,
626
629
  origin: [sourceX, sourceY],
627
- destination: webglBufferTarget,
630
+ destinationBuffer: webglBufferTarget,
628
631
  byteOffset: targetByteOffset
629
632
  });
630
633
  commandEncoder.destroy();
@@ -642,8 +645,8 @@ export function readPixelsToBuffer(
642
645
  */
643
646
  // eslint-disable-next-line complexity, max-statements
644
647
  export function copyToTexture(
645
- source: Framebuffer | Texture,
646
- target: Texture | GL,
648
+ sourceTexture: Framebuffer | Texture,
649
+ destinationTexture: Texture | GL,
647
650
  options?: {
648
651
  sourceX?: number;
649
652
  sourceY?: number;
@@ -673,7 +676,7 @@ export function copyToTexture(
673
676
  height // defaults to target height
674
677
  } = options || {};
675
678
 
676
- const {framebuffer, deleteFramebuffer} = getFramebuffer(source);
679
+ const {framebuffer, deleteFramebuffer} = getFramebuffer(sourceTexture);
677
680
  // assert(framebuffer);
678
681
  const webglFramebuffer = framebuffer;
679
682
  const {device, handle} = webglFramebuffer;
@@ -690,8 +693,8 @@ export function copyToTexture(
690
693
  // assert(target);
691
694
  let texture: WEBGLTexture | null = null;
692
695
  let textureTarget: GL;
693
- if (target instanceof WEBGLTexture) {
694
- texture = target;
696
+ if (destinationTexture instanceof WEBGLTexture) {
697
+ texture = destinationTexture;
695
698
  width = Number.isFinite(width) ? width : texture.width;
696
699
  height = Number.isFinite(height) ? height : texture.height;
697
700
  texture?.bind(0);
@@ -73,8 +73,8 @@ export class WEBGLCommandBuffer extends CommandBuffer {
73
73
  }
74
74
 
75
75
  function _copyBufferToBuffer(device: WebGLDevice, options: CopyBufferToBufferOptions): void {
76
- const source = options.source as WEBGLBuffer;
77
- const destination = options.destination as WEBGLBuffer;
76
+ const source = options.sourceBuffer as WEBGLBuffer;
77
+ const destination = options.destinationBuffer as WEBGLBuffer;
78
78
 
79
79
  // {In WebGL2 we can p}erform the copy on the GPU
80
80
  // Use GL.COPY_READ_BUFFER+GL.COPY_WRITE_BUFFER avoid disturbing other targets and locking type
@@ -106,22 +106,22 @@ function _copyBufferToTexture(device: WebGLDevice, options: CopyBufferToTextureO
106
106
  function _copyTextureToBuffer(device: WebGLDevice, options: CopyTextureToBufferOptions): void {
107
107
  const {
108
108
  /** Texture to copy to/from. */
109
- source,
109
+ sourceTexture,
110
110
  /** Mip-map level of the texture to copy to/from. (Default 0) */
111
111
  mipLevel = 0,
112
112
  /** Defines which aspects of the texture to copy to/from. */
113
113
  aspect = 'all',
114
114
 
115
115
  /** Width to copy */
116
- width = options.source.width,
116
+ width = options.sourceTexture.width,
117
117
  /** Height to copy */
118
- height = options.source.height,
118
+ height = options.sourceTexture.height,
119
119
  depthOrArrayLayers = 0,
120
120
  /** Defines the origin of the copy - the minimum corner of the texture sub-region to copy to/from. */
121
121
  origin = [0, 0],
122
122
 
123
123
  /** Destination buffer */
124
- destination,
124
+ destinationBuffer,
125
125
  /** Offset, in bytes, from the beginning of the buffer to the start of the image data (default 0) */
126
126
  byteOffset = 0,
127
127
  /**
@@ -139,7 +139,7 @@ function _copyTextureToBuffer(device: WebGLDevice, options: CopyTextureToBufferO
139
139
 
140
140
  // TODO - Not possible to read just stencil or depth part in WebGL?
141
141
  if (aspect !== 'all') {
142
- throw new Error('not supported');
142
+ throw new Error('aspect not supported in WebGL');
143
143
  }
144
144
 
145
145
  // TODO - mipLevels are set when attaching texture to framebuffer
@@ -148,10 +148,10 @@ function _copyTextureToBuffer(device: WebGLDevice, options: CopyTextureToBufferO
148
148
  }
149
149
 
150
150
  // Asynchronous read (PIXEL_PACK_BUFFER) is WebGL2 only feature
151
- const {framebuffer, destroyFramebuffer} = getFramebuffer(source);
151
+ const {framebuffer, destroyFramebuffer} = getFramebuffer(sourceTexture);
152
152
  let prevHandle: WebGLFramebuffer | null | undefined;
153
153
  try {
154
- const webglBuffer = destination as WEBGLBuffer;
154
+ const webglBuffer = destinationBuffer as WEBGLBuffer;
155
155
  const sourceWidth = width || framebuffer.width;
156
156
  const sourceHeight = height || framebuffer.height;
157
157
  const sourceParams = getTextureFormatWebGL(
@@ -220,7 +220,7 @@ export function readPixelsToBuffer(
220
220
  function _copyTextureToTexture(device: WebGLDevice, options: CopyTextureToTextureOptions): void {
221
221
  const {
222
222
  /** Texture to copy to/from. */
223
- source,
223
+ sourceTexture,
224
224
  /** Mip-map level of the texture to copy to (Default 0) */
225
225
  destinationMipLevel = 0,
226
226
  /** Defines which aspects of the texture to copy to/from. */
@@ -232,7 +232,7 @@ function _copyTextureToTexture(device: WebGLDevice, options: CopyTextureToTextur
232
232
  destinationOrigin = [0, 0],
233
233
 
234
234
  /** Texture to copy to/from. */
235
- destination
235
+ destinationTexture
236
236
  /** Mip-map level of the texture to copy to/from. (Default 0) */
237
237
  // destinationMipLevel = options.mipLevel,
238
238
  /** Defines the origin of the copy - the minimum corner of the texture sub-region to copy to/from. */
@@ -242,12 +242,12 @@ function _copyTextureToTexture(device: WebGLDevice, options: CopyTextureToTextur
242
242
  } = options;
243
243
 
244
244
  let {
245
- width = options.destination.width,
246
- height = options.destination.height
245
+ width = options.destinationTexture.width,
246
+ height = options.destinationTexture.height
247
247
  // depthOrArrayLayers = 0
248
248
  } = options;
249
249
 
250
- const {framebuffer, destroyFramebuffer} = getFramebuffer(source);
250
+ const {framebuffer, destroyFramebuffer} = getFramebuffer(sourceTexture);
251
251
  const [sourceX, sourceY] = origin;
252
252
  const [destinationX, destinationY, destinationZ] = destinationOrigin;
253
253
 
@@ -261,8 +261,8 @@ function _copyTextureToTexture(device: WebGLDevice, options: CopyTextureToTextur
261
261
 
262
262
  let texture: WEBGLTexture = null;
263
263
  let textureTarget: GL;
264
- if (destination instanceof WEBGLTexture) {
265
- texture = destination;
264
+ if (destinationTexture instanceof WEBGLTexture) {
265
+ texture = destinationTexture;
266
266
  width = Number.isFinite(width) ? width : texture.width;
267
267
  height = Number.isFinite(height) ? height : texture.height;
268
268
  texture.bind(0);
@@ -110,12 +110,12 @@ export class WEBGLRenderPipeline extends RenderPipeline {
110
110
  // and reference them as `app` from both GLSL and JS.
111
111
  // TODO - this is rather hacky - we could also remap the name directly in the shader layout.
112
112
  const binding =
113
- this.shaderLayout.bindings.find(binding => binding.name === name) ||
114
- this.shaderLayout.bindings.find(binding => binding.name === `${name}Uniforms`);
113
+ this.shaderLayout.bindings.find(binding_ => binding_.name === name) ||
114
+ this.shaderLayout.bindings.find(binding_ => binding_.name === `${name}Uniforms`);
115
115
 
116
116
  if (!binding) {
117
117
  const validBindings = this.shaderLayout.bindings
118
- .map(binding => `"${binding.name}"`)
118
+ .map(binding_ => `"${binding_.name}"`)
119
119
  .join(', ');
120
120
  if (!options?.disableWarnings) {
121
121
  log.warn(
@@ -317,22 +317,37 @@ export class WEBGLRenderPipeline extends RenderPipeline {
317
317
  }
318
318
 
319
319
  /** Report link status. First, check for shader compilation failures if linking fails */
320
- _reportLinkStatus(status: 'success' | 'linking' | 'validation') {
320
+ async _reportLinkStatus(status: 'success' | 'linking' | 'validation'): Promise<void> {
321
321
  switch (status) {
322
322
  case 'success':
323
323
  return;
324
324
 
325
325
  default:
326
326
  // First check for shader compilation failures if linking fails
327
- if (this.vs.compilationStatus === 'error') {
328
- this.vs.debugShader();
329
- throw new Error(`Error during compilation of shader ${this.vs.id}`);
327
+ switch (this.vs.compilationStatus) {
328
+ case 'error':
329
+ this.vs.debugShader();
330
+ throw new Error(`Error during compilation of shader ${this.vs.id}`);
331
+ case 'pending':
332
+ this.vs.asyncCompilationStatus.then(() => this.vs.debugShader());
333
+ break;
334
+ case 'success':
335
+ break;
330
336
  }
331
- if (this.fs?.compilationStatus === 'error') {
332
- this.fs.debugShader();
333
- throw new Error(`Error during compilation of shader ${this.fs.id}`);
337
+
338
+ switch (this.fs?.compilationStatus) {
339
+ case 'error':
340
+ this.fs.debugShader();
341
+ throw new Error(`Error during compilation of shader ${this.fs.id}`);
342
+ case 'pending':
343
+ this.fs.asyncCompilationStatus.then(() => this.fs.debugShader());
344
+ break;
345
+ case 'success':
346
+ break;
334
347
  }
335
- throw new Error(`Error during ${status}: ${this.device.gl.getProgramInfoLog(this.handle)}`);
348
+
349
+ const linkErrorLog = this.device.gl.getProgramInfoLog(this.handle);
350
+ throw new Error(`Error during ${status}: ${linkErrorLog}`);
336
351
  }
337
352
  }
338
353
 
@@ -39,14 +39,18 @@ export class WEBGLShader extends Shader {
39
39
  }
40
40
  }
41
41
 
42
+ get asyncCompilationStatus(): Promise<'pending' | 'success' | 'error'> {
43
+ return this._waitForCompilationComplete().then(() => this.compilationStatus);
44
+ }
45
+
42
46
  override async getCompilationInfo(): Promise<readonly CompilerMessage[]> {
43
47
  await this._waitForCompilationComplete();
44
48
  return this.getCompilationInfoSync();
45
49
  }
46
50
 
47
51
  override getCompilationInfoSync(): readonly CompilerMessage[] {
48
- const log = this.device.gl.getShaderInfoLog(this.handle);
49
- return log ? parseShaderCompilerLog(log) : [];
52
+ const shaderLog = this.device.gl.getShaderInfoLog(this.handle);
53
+ return shaderLog ? parseShaderCompilerLog(shaderLog) : [];
50
54
  }
51
55
 
52
56
  override getTranslatedSource(): string | null {
@@ -59,9 +63,7 @@ export class WEBGLShader extends Shader {
59
63
 
60
64
  /** Compile a shader and get compilation status */
61
65
  protected async _compile(source: string): Promise<void> {
62
- const addGLSLVersion = (source: string) =>
63
- source.startsWith('#version ') ? source : `#version 300 es\n${source}`;
64
- source = addGLSLVersion(source);
66
+ source = source.startsWith('#version ') ? source : `#version 300 es\n${source}`;
65
67
 
66
68
  const {gl} = this.device;
67
69
  gl.shaderSource(this.handle, source);
@@ -2,7 +2,7 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {Adapter, Device, DeviceProps, CanvasContext, log} from '@luma.gl/core';
5
+ import {Adapter, Device, DeviceProps, log} from '@luma.gl/core';
6
6
  import {WebGLDevice} from './webgl-device';
7
7
  import {enforceWebGL2} from '../context/polyfills/polyfill-webgl1-extensions';
8
8
  import {loadSpectorJS, DEFAULT_SPECTOR_PROPS} from '../context/debug/spector';
@@ -52,7 +52,7 @@ export class WebGLAdapter extends Adapter {
52
52
  if (!isWebGL(gl)) {
53
53
  throw new Error('Invalid WebGL2RenderingContext');
54
54
  }
55
- return new WebGLDevice({gl: gl as WebGL2RenderingContext});
55
+ return new WebGLDevice({_handle: gl as WebGL2RenderingContext});
56
56
  }
57
57
 
58
58
  async create(props: DeviceProps = {}): Promise<WebGLDevice> {
@@ -61,20 +61,14 @@ export class WebGLAdapter extends Adapter {
61
61
  const promises: Promise<unknown>[] = [];
62
62
 
63
63
  // Load webgl and spector debug scripts from CDN if requested
64
- if (props.debug) {
64
+ if (props.debugWebGL) {
65
65
  promises.push(loadWebGLDeveloperTools());
66
66
  }
67
67
 
68
- if (props.debugWithSpectorJS) {
68
+ if (props.debugSpectorJS) {
69
69
  promises.push(loadSpectorJS(props));
70
70
  }
71
71
 
72
- // Wait for page to load: if canvas is a string we need to query the DOM for the canvas element.
73
- // We only wait when props.canvas is string to avoids setting the global page onload callback unless necessary.
74
- if (typeof props.canvas === 'string') {
75
- promises.push(CanvasContext.pageLoaded);
76
- }
77
-
78
72
  // Wait for all the loads to settle before creating the context.
79
73
  // The Device.create() functions are async, so in contrast to the constructor, we can `await` here.
80
74
  const results = await Promise.allSettled(promises);
@@ -84,8 +78,6 @@ export class WebGLAdapter extends Adapter {
84
78
  }
85
79
  }
86
80
 
87
- log.probe(LOG_LEVEL + 1, 'DOM is loaded')();
88
-
89
81
  const device = new WebGLDevice(props);
90
82
 
91
83
  // Log some debug info about the newly created context
@@ -12,28 +12,7 @@ import type {
12
12
  Texture,
13
13
  Framebuffer,
14
14
  VertexArray,
15
- VertexArrayProps
16
- } from '@luma.gl/core';
17
- import {Device, CanvasContext, log} from '@luma.gl/core';
18
- import type {GLExtensions} from '@luma.gl/constants';
19
- import {WebGLStateTracker} from '../context/state-tracker/webgl-state-tracker';
20
- import {createBrowserContext} from '../context/helpers/create-browser-context';
21
- import {getDeviceInfo} from './device-helpers/webgl-device-info';
22
- import {WebGLDeviceFeatures} from './device-helpers/webgl-device-features';
23
- import {WebGLDeviceLimits} from './device-helpers/webgl-device-limits';
24
- import {WebGLCanvasContext} from './webgl-canvas-context';
25
- import type {Spector} from '../context/debug/spector-types';
26
- import {initializeSpectorJS} from '../context/debug/spector';
27
- import {makeDebugContext} from '../context/debug/webgl-developer-tools';
28
- import {
29
- isTextureFormatSupported,
30
- isTextureFormatRenderable,
31
- isTextureFormatFilterable
32
- } from './converters/texture-formats';
33
- import {uid} from '../utils/uid';
34
-
35
- // WebGL classes
36
- import type {
15
+ VertexArrayProps,
37
16
  BufferProps,
38
17
  ShaderProps,
39
18
  // Sampler,
@@ -55,6 +34,23 @@ import type {
55
34
  TransformFeedbackProps,
56
35
  QuerySetProps
57
36
  } from '@luma.gl/core';
37
+ import {Device, CanvasContext, log} from '@luma.gl/core';
38
+ import type {GLExtensions} from '@luma.gl/constants';
39
+ import {WebGLStateTracker} from '../context/state-tracker/webgl-state-tracker';
40
+ import {createBrowserContext} from '../context/helpers/create-browser-context';
41
+ import {getDeviceInfo} from './device-helpers/webgl-device-info';
42
+ import {WebGLDeviceFeatures} from './device-helpers/webgl-device-features';
43
+ import {WebGLDeviceLimits} from './device-helpers/webgl-device-limits';
44
+ import {WebGLCanvasContext} from './webgl-canvas-context';
45
+ import type {Spector} from '../context/debug/spector-types';
46
+ import {initializeSpectorJS} from '../context/debug/spector';
47
+ import {makeDebugContext} from '../context/debug/webgl-developer-tools';
48
+ import {
49
+ isTextureFormatSupported,
50
+ isTextureFormatRenderable,
51
+ isTextureFormatFilterable
52
+ } from './converters/texture-formats';
53
+ import {uid} from '../utils/uid';
58
54
 
59
55
  import {WEBGLBuffer} from './resources/webgl-buffer';
60
56
  import {WEBGLShader} from './resources/webgl-shader';
@@ -120,35 +116,62 @@ export class WebGLDevice extends Device {
120
116
  constructor(props: DeviceProps) {
121
117
  super({...props, id: props.id || uid('webgl-device')});
122
118
 
119
+ // WebGL requires a canvas to be created before creating the context
120
+ if (!props.createCanvasContext) {
121
+ throw new Error('WebGLDevice requires props.createCanvasContext to be set');
122
+ }
123
+ const canvasContextProps = props.createCanvasContext === true ? {} : props.createCanvasContext;
124
+
123
125
  // If attaching to an already attached context, return the attached device
124
126
  // @ts-expect-error device is attached to context
125
- const device: WebGLDevice | undefined = props.gl?.device;
127
+ let device: WebGLDevice | undefined = canvasContextProps.canvas?.gl?.device;
126
128
  if (device) {
127
129
  throw new Error(`WebGL context already attached to device ${device.id}`);
128
130
  }
129
131
 
130
132
  // Create and instrument context
131
- const canvas = props.gl?.canvas || props.canvas;
132
- this.canvasContext = new WebGLCanvasContext(this, {...props, canvas});
133
+ this.canvasContext = new WebGLCanvasContext(this, canvasContextProps);
133
134
 
134
135
  this.lost = new Promise<{reason: 'destroyed'; message: string}>(resolve => {
135
136
  this._resolveContextLost = resolve;
136
137
  });
137
138
 
138
- this.handle = createBrowserContext(this.canvasContext.canvas, {
139
- ...props,
140
- onContextLost: (event: Event) =>
141
- this._resolveContextLost?.({
142
- reason: 'destroyed',
143
- message: 'Entered sleep mode, or too many apps or browser tabs are using the GPU.'
144
- })
145
- });
146
- this.gl = this.handle;
139
+ const webglContextAttributes: WebGLContextAttributes = {...props.webgl};
140
+ // Copy props from CanvasContextProps
141
+ if (canvasContextProps.alphaMode === 'premultiplied') {
142
+ webglContextAttributes.premultipliedAlpha = true;
143
+ }
144
+ if (props.powerPreference !== undefined) {
145
+ webglContextAttributes.powerPreference = props.powerPreference;
146
+ }
147
147
 
148
- if (!this.handle) {
148
+ const gl = createBrowserContext(
149
+ this.canvasContext.canvas,
150
+ {
151
+ onContextLost: (event: Event) =>
152
+ this._resolveContextLost?.({
153
+ reason: 'destroyed',
154
+ message: 'Entered sleep mode, or too many apps or browser tabs are using the GPU.'
155
+ }),
156
+ // eslint-disable-next-line no-console
157
+ onContextRestored: (event: Event) => console.log('WebGL context restored')
158
+ },
159
+ webglContextAttributes
160
+ );
161
+
162
+ if (!gl) {
149
163
  throw new Error('WebGL context creation failed');
150
164
  }
151
165
 
166
+ // @ts-expect-error device is attached to context
167
+ device = gl.device;
168
+ if (device) {
169
+ throw new Error(`WebGL context already attached to device ${device.id}`);
170
+ }
171
+
172
+ this.handle = gl;
173
+ this.gl = gl;
174
+
152
175
  // Add spector debug instrumentation to context
153
176
  // We need to trust spector integration to decide if spector should be initialized
154
177
  // We also run spector instrumentation first, otherwise spector can clobber luma instrumentation.
@@ -161,8 +184,12 @@ export class WebGLDevice extends Device {
161
184
  // initialize luma Device fields
162
185
  this.info = getDeviceInfo(this.gl, this._extensions);
163
186
  this.limits = new WebGLDeviceLimits(this.gl);
164
- this.features = new WebGLDeviceFeatures(this.gl, this._extensions, this.props.disabledFeatures);
165
- if (this.props.initalizeFeatures) {
187
+ this.features = new WebGLDeviceFeatures(
188
+ this.gl,
189
+ this._extensions,
190
+ this.props._disabledFeatures
191
+ );
192
+ if (this.props._initializeFeatures) {
166
193
  this.features.initializeFeatures();
167
194
  }
168
195
 
@@ -175,8 +202,8 @@ export class WebGLDevice extends Device {
175
202
  glState.trackState(this.gl, {copyState: false});
176
203
 
177
204
  // DEBUG contexts: Add luma debug instrumentation to the context, force log level to at least 1
178
- if (props.debug) {
179
- this.gl = makeDebugContext(this.gl, {...props, throwOnError: true});
205
+ if (props.debugWebGL) {
206
+ this.gl = makeDebugContext(this.gl, {...props});
180
207
  this.debug = true;
181
208
  log.level = Math.max(log.level, 1);
182
209
  log.warn('WebGL debug mode activated. Performance reduced.')();
@@ -212,7 +239,7 @@ export class WebGLDevice extends Device {
212
239
  }
213
240
 
214
241
  createBuffer(props: BufferProps | ArrayBuffer | ArrayBufferView): WEBGLBuffer {
215
- const newProps = this._getBufferProps(props);
242
+ const newProps = this._normalizeBufferProps(props);
216
243
  return new WEBGLBuffer(this, newProps);
217
244
  }
218
245
 
@@ -1,5 +1,5 @@
1
1
  // Forked from https://github.com/BabylonJS/Spector.js/blob/master/dist/spector.d.ts
2
- /* eslint-disable camelcase */
2
+ /* eslint-disable camelcase, no-shadow */
3
3
 
4
4
  interface IEvent<T> {
5
5
  add(callback: (element: T) => void, context?: any): number;
@@ -5,14 +5,14 @@
5
5
  import {log} from '@luma.gl/core';
6
6
  import {loadScript} from '../../utils/load-script';
7
7
 
8
- import {Spector} from './spector-types';
8
+ import type {Spector} from './spector-types';
9
9
 
10
10
  /** Spector debug initialization options */
11
11
  type SpectorProps = {
12
- /** Whether spector is enabled */
13
- debugWithSpectorJS?: boolean;
12
+ /** Whether spector.js is enabled */
13
+ debugSpectorJS?: boolean;
14
14
  /** URL to load spector script from. Typically a CDN URL */
15
- spectorUrl?: string;
15
+ debugSpectorJSUrl?: string;
16
16
  /** Canvas to monitor */
17
17
  gl?: WebGL2RenderingContext;
18
18
  };
@@ -29,19 +29,19 @@ declare global {
29
29
  }
30
30
 
31
31
  export const DEFAULT_SPECTOR_PROPS: Required<SpectorProps> = {
32
- debugWithSpectorJS: log.get('spector') || log.get('spectorjs'),
32
+ debugSpectorJS: log.get('debug-spectorjs'),
33
33
  // https://github.com/BabylonJS/Spector.js#basic-usage
34
34
  // https://forum.babylonjs.com/t/spectorcdn-is-temporarily-off/48241
35
35
  // spectorUrl: 'https://spectorcdn.babylonjs.com/spector.bundle.js';
36
- spectorUrl: 'https://cdn.jsdelivr.net/npm/spectorjs@0.9.30/dist/spector.bundle.js',
36
+ debugSpectorJSUrl: 'https://cdn.jsdelivr.net/npm/spectorjs@0.9.30/dist/spector.bundle.js',
37
37
  gl: undefined!
38
38
  };
39
39
 
40
40
  /** Loads spector from CDN if not already installed */
41
- export async function loadSpectorJS(props: {spectorUrl?: string}): Promise<void> {
41
+ export async function loadSpectorJS(props: {debugSpectorJSUrl?: string}): Promise<void> {
42
42
  if (!globalThis.SPECTOR) {
43
43
  try {
44
- await loadScript(props.spectorUrl || DEFAULT_SPECTOR_PROPS.spectorUrl);
44
+ await loadScript(props.debugSpectorJSUrl || DEFAULT_SPECTOR_PROPS.debugSpectorJSUrl);
45
45
  } catch (error) {
46
46
  log.warn(String(error));
47
47
  }
@@ -50,14 +50,14 @@ export async function loadSpectorJS(props: {spectorUrl?: string}): Promise<void>
50
50
 
51
51
  export function initializeSpectorJS(props: SpectorProps): Spector | null {
52
52
  props = {...DEFAULT_SPECTOR_PROPS, ...props};
53
- if (!props.debugWithSpectorJS) {
53
+ if (!props.debugSpectorJS) {
54
54
  return null;
55
55
  }
56
56
 
57
57
  if (!spector && globalThis.SPECTOR && !globalThis.luma?.spector) {
58
58
  log.probe(LOG_LEVEL, 'SPECTOR found and initialized. Start with `luma.spector.displayUI()`')();
59
- const {Spector} = globalThis.SPECTOR as any;
60
- spector = new Spector();
59
+ const {Spector: SpectorJS} = globalThis.SPECTOR as any;
60
+ spector = new SpectorJS();
61
61
  if (globalThis.luma) {
62
62
  (globalThis.luma as any).spector = spector;
63
63
  }