@luma.gl/webgl 9.1.0-alpha.1 → 9.1.0-alpha.12
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.
- package/dist/adapter/converters/device-parameters.d.ts.map +1 -1
- package/dist/adapter/converters/device-parameters.js +18 -11
- package/dist/adapter/converters/texture-formats.d.ts +1 -1
- package/dist/adapter/converters/texture-formats.d.ts.map +1 -1
- package/dist/adapter/converters/texture-formats.js +9 -16
- package/dist/adapter/device-helpers/webgl-device-features.d.ts.map +1 -1
- package/dist/adapter/device-helpers/webgl-device-features.js +1 -3
- package/dist/adapter/helpers/format-utils.d.ts.map +1 -0
- package/dist/adapter/helpers/get-shader-layout.d.ts.map +1 -1
- package/dist/adapter/helpers/get-shader-layout.js +1 -3
- package/dist/adapter/helpers/typed-array-utils.d.ts.map +1 -0
- package/dist/adapter/helpers/webgl-texture-utils.d.ts +89 -22
- package/dist/adapter/helpers/webgl-texture-utils.d.ts.map +1 -1
- package/dist/adapter/helpers/webgl-texture-utils.js +220 -26
- package/dist/adapter/resources/webgl-framebuffer.js +1 -1
- package/dist/adapter/resources/webgl-render-pass.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-render-pass.js +17 -4
- package/dist/adapter/resources/webgl-render-pipeline.d.ts +1 -3
- package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-render-pipeline.js +1 -1
- package/dist/adapter/resources/webgl-shader.js +1 -1
- package/dist/adapter/resources/webgl-texture.d.ts +21 -3
- package/dist/adapter/resources/webgl-texture.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-texture.js +49 -30
- package/dist/adapter/resources/webgl-transform-feedback.js +1 -1
- package/dist/adapter/resources/webgl-vertex-array.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-vertex-array.js +3 -0
- package/dist/adapter/webgl-adapter.d.ts +21 -0
- package/dist/adapter/webgl-adapter.d.ts.map +1 -0
- package/dist/adapter/webgl-adapter.js +91 -0
- package/dist/adapter/webgl-device.d.ts +16 -29
- package/dist/adapter/webgl-device.d.ts.map +1 -1
- package/dist/adapter/webgl-device.js +34 -114
- package/dist/context/debug/spector-types.d.ts +1108 -0
- package/dist/context/debug/spector-types.d.ts.map +1 -0
- package/dist/context/debug/spector-types.js +697 -0
- package/dist/context/debug/spector.d.ts +12 -8
- package/dist/context/debug/spector.d.ts.map +1 -1
- package/dist/context/debug/spector.js +23 -17
- package/dist/context/polyfills/polyfill-webgl1-extensions.d.ts +9 -0
- package/dist/context/polyfills/polyfill-webgl1-extensions.d.ts.map +1 -0
- package/dist/context/polyfills/polyfill-webgl1-extensions.js +181 -0
- package/dist/context/state-tracker/webgl-state-tracker.d.ts +43 -0
- package/dist/context/state-tracker/webgl-state-tracker.d.ts.map +1 -0
- package/dist/context/state-tracker/{track-context-state.js → webgl-state-tracker.js} +44 -74
- package/dist/context/state-tracker/with-parameters.d.ts.map +1 -1
- package/dist/context/state-tracker/with-parameters.js +5 -4
- package/dist/deprecated/accessor.d.ts.map +1 -0
- package/dist/{classic → deprecated}/accessor.js +36 -1
- package/dist/deprecated/clear.d.ts.map +1 -0
- package/dist/{classic → deprecated}/clear.js +2 -0
- package/dist/dist.dev.js +816 -642
- package/dist/dist.min.js +2 -2
- package/dist/index.cjs +815 -648
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/utils/fill-array.d.ts +4 -4
- package/dist/utils/fill-array.d.ts.map +1 -1
- package/dist/utils/split-uniforms-and-bindings.d.ts +1 -1
- package/dist/utils/split-uniforms-and-bindings.d.ts.map +1 -1
- package/dist/utils/uid.d.ts +7 -0
- package/dist/utils/uid.d.ts.map +1 -0
- package/dist/utils/uid.js +14 -0
- package/package.json +5 -5
- package/src/adapter/converters/device-parameters.ts +18 -12
- package/src/adapter/converters/texture-formats.ts +12 -20
- package/src/adapter/device-helpers/webgl-device-features.ts +5 -3
- package/src/adapter/helpers/get-shader-layout.ts +1 -3
- package/src/adapter/helpers/webgl-texture-utils.ts +366 -44
- package/src/adapter/resources/webgl-framebuffer.ts +1 -1
- package/src/adapter/resources/webgl-render-pass.ts +20 -7
- package/src/adapter/resources/webgl-render-pipeline.ts +12 -4
- package/src/adapter/resources/webgl-shader.ts +1 -1
- package/src/adapter/resources/webgl-texture.ts +76 -30
- package/src/adapter/resources/webgl-transform-feedback.ts +1 -1
- package/src/adapter/resources/webgl-vertex-array.ts +3 -0
- package/src/adapter/webgl-adapter.ts +113 -0
- package/src/adapter/webgl-device.ts +45 -139
- package/src/context/debug/spector-types.ts +1154 -0
- package/src/context/debug/spector.ts +38 -29
- package/src/context/polyfills/polyfill-webgl1-extensions.ts +202 -0
- package/src/context/state-tracker/{track-context-state.ts → webgl-state-tracker.ts} +55 -94
- package/src/context/state-tracker/with-parameters.ts +5 -4
- package/src/{classic → deprecated}/accessor.ts +44 -3
- package/src/{classic → deprecated}/clear.ts +3 -1
- package/src/index.ts +6 -8
- package/src/utils/fill-array.ts +4 -4
- package/src/utils/split-uniforms-and-bindings.ts +3 -3
- package/src/utils/uid.ts +16 -0
- package/dist/classic/accessor.d.ts.map +0 -1
- package/dist/classic/clear.d.ts.map +0 -1
- package/dist/classic/copy-and-blit.d.ts +0 -63
- package/dist/classic/copy-and-blit.d.ts.map +0 -1
- package/dist/classic/copy-and-blit.js +0 -193
- package/dist/classic/format-utils.d.ts.map +0 -1
- package/dist/classic/typed-array-utils.d.ts.map +0 -1
- package/dist/context/state-tracker/track-context-state.d.ts +0 -22
- package/dist/context/state-tracker/track-context-state.d.ts.map +0 -1
- package/src/classic/copy-and-blit.ts +0 -318
- /package/dist/{classic → adapter/helpers}/format-utils.d.ts +0 -0
- /package/dist/{classic → adapter/helpers}/format-utils.js +0 -0
- /package/dist/{classic → adapter/helpers}/typed-array-utils.d.ts +0 -0
- /package/dist/{classic → adapter/helpers}/typed-array-utils.js +0 -0
- /package/dist/{classic → deprecated}/accessor.d.ts +0 -0
- /package/dist/{classic → deprecated}/clear.d.ts +0 -0
- /package/src/{classic → adapter/helpers}/format-utils.ts +0 -0
- /package/src/{classic → adapter/helpers}/typed-array-utils.ts +0 -0
|
@@ -52,7 +52,7 @@ import {WEBGLTextureView} from './webgl-texture-view';
|
|
|
52
52
|
import {
|
|
53
53
|
initializeTextureStorage,
|
|
54
54
|
// clearMipLevel,
|
|
55
|
-
|
|
55
|
+
copyExternalImageToMipLevel,
|
|
56
56
|
copyCPUDataToMipLevel,
|
|
57
57
|
// copyGPUBufferToMipLevel,
|
|
58
58
|
getWebGLTextureTarget
|
|
@@ -192,7 +192,7 @@ export class WEBGLTexture extends Texture {
|
|
|
192
192
|
let {width, height} = props;
|
|
193
193
|
|
|
194
194
|
if (!width || !height) {
|
|
195
|
-
const textureSize =
|
|
195
|
+
const textureSize = Texture.getTextureDataSize(data);
|
|
196
196
|
width = textureSize?.width || 1;
|
|
197
197
|
height = textureSize?.height || 1;
|
|
198
198
|
}
|
|
@@ -333,13 +333,64 @@ export class WEBGLTexture extends Texture {
|
|
|
333
333
|
}
|
|
334
334
|
|
|
335
335
|
// Image Data Setters
|
|
336
|
+
copyExternalImage(options: {
|
|
337
|
+
image: ExternalImage;
|
|
338
|
+
sourceX?: number;
|
|
339
|
+
sourceY?: number;
|
|
340
|
+
width?: number;
|
|
341
|
+
height?: number;
|
|
342
|
+
depth?: number;
|
|
343
|
+
mipLevel?: number;
|
|
344
|
+
x?: number;
|
|
345
|
+
y?: number;
|
|
346
|
+
z?: number;
|
|
347
|
+
aspect?: 'all' | 'stencil-only' | 'depth-only';
|
|
348
|
+
colorSpace?: 'srgb';
|
|
349
|
+
premultipliedAlpha?: boolean;
|
|
350
|
+
}): {width: number; height: number} {
|
|
351
|
+
const size = Texture.getExternalImageSize(options.image);
|
|
352
|
+
const opts = {...Texture.defaultCopyExternalImageOptions, ...size, ...options};
|
|
353
|
+
|
|
354
|
+
const {image, depth, mipLevel, x, y, z} = opts;
|
|
355
|
+
let {width, height} = opts;
|
|
356
|
+
const {dimension, glTarget, glFormat, glInternalFormat, glType} = this;
|
|
357
|
+
|
|
358
|
+
// WebGL will error if we try to copy outside the bounds of the texture
|
|
359
|
+
width = Math.min(width, size.width - x);
|
|
360
|
+
height = Math.min(height, size.height - y);
|
|
361
|
+
|
|
362
|
+
// WebGL does not yet support sourceX/sourceY in copyExternalImage; requires copyTexSubImage2D from a framebuffer'
|
|
363
|
+
|
|
364
|
+
if (options.sourceX || options.sourceY) {
|
|
365
|
+
throw new Error(
|
|
366
|
+
'WebGL does not yet support sourceX/sourceY in copyExternalImage; requires copyTexSubImage2D from a framebuffer'
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
copyExternalImageToMipLevel(this.device.gl, this.handle, image, {
|
|
371
|
+
dimension,
|
|
372
|
+
mipLevel,
|
|
373
|
+
x,
|
|
374
|
+
y,
|
|
375
|
+
z,
|
|
376
|
+
width,
|
|
377
|
+
height,
|
|
378
|
+
depth,
|
|
379
|
+
glFormat,
|
|
380
|
+
glInternalFormat,
|
|
381
|
+
glType,
|
|
382
|
+
glTarget
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
return {width: opts.width, height: opts.height};
|
|
386
|
+
}
|
|
336
387
|
|
|
337
388
|
setTexture1DData(data: Texture1DData): void {
|
|
338
389
|
throw new Error('setTexture1DData not supported in WebGL.');
|
|
339
390
|
}
|
|
340
391
|
|
|
341
392
|
/** Set a simple texture */
|
|
342
|
-
setTexture2DData(lodData: Texture2DData, depth = 0
|
|
393
|
+
setTexture2DData(lodData: Texture2DData, depth = 0): void {
|
|
343
394
|
this.bind();
|
|
344
395
|
|
|
345
396
|
const lodArray = normalizeTextureData(lodData, this);
|
|
@@ -367,7 +418,9 @@ export class WEBGLTexture extends Texture {
|
|
|
367
418
|
throw new Error(this.id);
|
|
368
419
|
}
|
|
369
420
|
if (ArrayBuffer.isView(data)) {
|
|
421
|
+
this.bind();
|
|
370
422
|
copyCPUDataToMipLevel(this.device.gl, data, this);
|
|
423
|
+
this.unbind();
|
|
371
424
|
}
|
|
372
425
|
}
|
|
373
426
|
|
|
@@ -381,9 +434,9 @@ export class WEBGLTexture extends Texture {
|
|
|
381
434
|
if (this.props.dimension !== 'cube') {
|
|
382
435
|
throw new Error(this.id);
|
|
383
436
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
437
|
+
for (const face of Texture.CubeFaces) {
|
|
438
|
+
this.setTextureCubeFaceData(data[face], face);
|
|
439
|
+
}
|
|
387
440
|
}
|
|
388
441
|
|
|
389
442
|
/**
|
|
@@ -414,27 +467,9 @@ export class WEBGLTexture extends Texture {
|
|
|
414
467
|
log.warn(`${this.id} has mipmap and multiple LODs.`)();
|
|
415
468
|
}
|
|
416
469
|
|
|
417
|
-
|
|
418
|
-
// const glType = GL.UNSIGNED_BYTE;
|
|
419
|
-
// const {width, height, format = GL.RGBA, type = GL.UNSIGNED_BYTE} = this;
|
|
420
|
-
// const {width, height, format = GL.RGBA, type = GL.UNSIGNED_BYTE} = this;
|
|
470
|
+
const faceDepth = Texture.CubeFaces.indexOf(face);
|
|
421
471
|
|
|
422
|
-
this.
|
|
423
|
-
// for (let lodLevel = 0; lodLevel < lodData.length; lodLevel++) {
|
|
424
|
-
// const imageData = lodData[lodLevel];
|
|
425
|
-
// if (imageData instanceof ArrayBuffer) {
|
|
426
|
-
// // const imageData = image instanceof ArrayBuffer ? new ImageData(new Uint8ClampedArray(image), this.width) : image;
|
|
427
|
-
// this.device.gl.texImage2D?.(
|
|
428
|
-
// glFace,
|
|
429
|
-
// lodLevel,
|
|
430
|
-
// this.glInternalFormat,
|
|
431
|
-
// this.glInternalFormat,
|
|
432
|
-
// glType,
|
|
433
|
-
// imageData
|
|
434
|
-
// );
|
|
435
|
-
// }
|
|
436
|
-
// }
|
|
437
|
-
this.unbind();
|
|
472
|
+
this.setTexture2DData(lodData, faceDepth);
|
|
438
473
|
}
|
|
439
474
|
|
|
440
475
|
// INTERNAL METHODS
|
|
@@ -592,23 +627,34 @@ export class WEBGLTexture extends Texture {
|
|
|
592
627
|
* Copy a region of data from a CPU memory buffer into this texture.
|
|
593
628
|
* @todo - GLUnpackParameters parameters
|
|
594
629
|
*/
|
|
595
|
-
protected _setMipLevel(
|
|
630
|
+
protected _setMipLevel(
|
|
631
|
+
depth: number,
|
|
632
|
+
mipLevel: number,
|
|
633
|
+
textureData: Texture2DData,
|
|
634
|
+
glTarget: GL = this.glTarget
|
|
635
|
+
) {
|
|
596
636
|
// if (!textureData) {
|
|
597
637
|
// clearMipLevel(this.device.gl, {...this, depth, level});
|
|
598
638
|
// return;
|
|
599
639
|
// }
|
|
600
640
|
|
|
601
641
|
if (Texture.isExternalImage(textureData)) {
|
|
602
|
-
|
|
642
|
+
copyExternalImageToMipLevel(this.device.gl, this.handle, textureData, {
|
|
643
|
+
...this,
|
|
644
|
+
depth,
|
|
645
|
+
mipLevel,
|
|
646
|
+
glTarget
|
|
647
|
+
});
|
|
603
648
|
return;
|
|
604
649
|
}
|
|
605
650
|
|
|
606
651
|
// @ts-expect-error
|
|
607
|
-
if (
|
|
652
|
+
if (Texture.isTextureLevelData(textureData)) {
|
|
608
653
|
copyCPUDataToMipLevel(this.device.gl, textureData.data, {
|
|
609
654
|
...this,
|
|
610
655
|
depth,
|
|
611
|
-
|
|
656
|
+
mipLevel,
|
|
657
|
+
glTarget
|
|
612
658
|
});
|
|
613
659
|
return;
|
|
614
660
|
}
|
|
@@ -56,7 +56,7 @@ export class WEBGLTransformFeedback extends TransformFeedback {
|
|
|
56
56
|
|
|
57
57
|
end(): void {
|
|
58
58
|
this.gl.endTransformFeedback();
|
|
59
|
-
if (
|
|
59
|
+
if (this.bindOnUse) {
|
|
60
60
|
this._unbindBuffers();
|
|
61
61
|
}
|
|
62
62
|
this.gl.bindTransformFeedback(GL.TRANSFORM_FEEDBACK, null);
|
|
@@ -97,6 +97,9 @@ export class WEBGLVertexArray extends VertexArray {
|
|
|
97
97
|
// Attaches ARRAY_BUFFER with specified buffer format to location
|
|
98
98
|
this.device.gl.vertexAttribPointer(location, size, type, normalized, stride, offset);
|
|
99
99
|
}
|
|
100
|
+
// Clear binding - keeping it may cause [.WebGL-0x12804417100]
|
|
101
|
+
// GL_INVALID_OPERATION: A transform feedback buffer that would be written to is also bound to a non-transform-feedback target
|
|
102
|
+
this.device.gl.bindBuffer(GL.ARRAY_BUFFER, null);
|
|
100
103
|
|
|
101
104
|
// Mark as non-constant
|
|
102
105
|
this.device.gl.enableVertexAttribArray(location);
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {Adapter, Device, DeviceProps, CanvasContext, log} from '@luma.gl/core';
|
|
6
|
+
import {WebGLDevice} from './webgl-device';
|
|
7
|
+
import {enforceWebGL2} from '../context/polyfills/polyfill-webgl1-extensions';
|
|
8
|
+
import {loadSpectorJS, DEFAULT_SPECTOR_PROPS} from '../context/debug/spector';
|
|
9
|
+
import {loadWebGLDeveloperTools} from '../context/debug/webgl-developer-tools';
|
|
10
|
+
|
|
11
|
+
const LOG_LEVEL = 1;
|
|
12
|
+
|
|
13
|
+
export class WebGLAdapter extends Adapter {
|
|
14
|
+
/** type of device's created by this adapter */
|
|
15
|
+
readonly type: Device['type'] = 'webgl';
|
|
16
|
+
|
|
17
|
+
constructor() {
|
|
18
|
+
super();
|
|
19
|
+
|
|
20
|
+
// Add spector default props to device default props, so that runtime settings are observed
|
|
21
|
+
Device.defaultProps = {...Device.defaultProps, ...DEFAULT_SPECTOR_PROPS};
|
|
22
|
+
|
|
23
|
+
// @ts-ignore DEPRECATED For backwards compatibility luma.registerDevices
|
|
24
|
+
WebGLDevice.adapter = this;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Check if WebGL 2 is available */
|
|
28
|
+
isSupported(): boolean {
|
|
29
|
+
return typeof WebGL2RenderingContext !== 'undefined';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Force any created WebGL contexts to be WebGL2 contexts, polyfilled with WebGL1 extensions */
|
|
33
|
+
enforceWebGL2(enable: boolean): void {
|
|
34
|
+
enforceWebGL2(enable);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get a device instance from a GL context
|
|
39
|
+
* Creates and instruments the device if not already created
|
|
40
|
+
* @param gl
|
|
41
|
+
* @returns
|
|
42
|
+
*/
|
|
43
|
+
async attach(gl: Device | WebGL2RenderingContext): Promise<WebGLDevice> {
|
|
44
|
+
if (gl instanceof WebGLDevice) {
|
|
45
|
+
return gl;
|
|
46
|
+
}
|
|
47
|
+
// @ts-expect-error
|
|
48
|
+
if (gl?.device instanceof Device) {
|
|
49
|
+
// @ts-expect-error
|
|
50
|
+
return gl.device as WebGLDevice;
|
|
51
|
+
}
|
|
52
|
+
if (!isWebGL(gl)) {
|
|
53
|
+
throw new Error('Invalid WebGL2RenderingContext');
|
|
54
|
+
}
|
|
55
|
+
return new WebGLDevice({gl: gl as WebGL2RenderingContext});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async create(props: DeviceProps = {}): Promise<WebGLDevice> {
|
|
59
|
+
log.groupCollapsed(LOG_LEVEL, 'WebGLDevice created')();
|
|
60
|
+
|
|
61
|
+
const promises: Promise<unknown>[] = [];
|
|
62
|
+
|
|
63
|
+
// Load webgl and spector debug scripts from CDN if requested
|
|
64
|
+
if (props.debug) {
|
|
65
|
+
promises.push(loadWebGLDeveloperTools());
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (props.debugWithSpectorJS) {
|
|
69
|
+
promises.push(loadSpectorJS(props));
|
|
70
|
+
}
|
|
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
|
+
// Wait for all the loads to settle before creating the context.
|
|
79
|
+
// The Device.create() functions are async, so in contrast to the constructor, we can `await` here.
|
|
80
|
+
const results = await Promise.allSettled(promises);
|
|
81
|
+
for (const result of results) {
|
|
82
|
+
if (result.status === 'rejected') {
|
|
83
|
+
log.error(`Failed to initialize debug libraries ${result.reason}`)();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
log.probe(LOG_LEVEL + 1, 'DOM is loaded')();
|
|
88
|
+
|
|
89
|
+
const device = new WebGLDevice(props);
|
|
90
|
+
|
|
91
|
+
// Log some debug info about the newly created context
|
|
92
|
+
const message = `\
|
|
93
|
+
Created ${device.type}${device.debug ? ' debug' : ''} context: \
|
|
94
|
+
${device.info.vendor}, ${device.info.renderer} for canvas: ${device.canvasContext.id}`;
|
|
95
|
+
log.probe(LOG_LEVEL, message)();
|
|
96
|
+
log.table(LOG_LEVEL, device.info)();
|
|
97
|
+
|
|
98
|
+
log.groupEnd(LOG_LEVEL)();
|
|
99
|
+
|
|
100
|
+
return device;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Check if supplied parameter is a WebGL2RenderingContext */
|
|
105
|
+
function isWebGL(gl: any): boolean {
|
|
106
|
+
if (typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
// Look for debug contexts, headless gl etc
|
|
110
|
+
return Boolean(gl && Number.isFinite(gl._version));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export const webgl2Adapter = new WebGLAdapter();
|
|
@@ -3,27 +3,34 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
import type {TypedArray} from '@math.gl/types';
|
|
6
|
-
import type {
|
|
7
|
-
|
|
6
|
+
import type {
|
|
7
|
+
DeviceProps,
|
|
8
|
+
DeviceInfo,
|
|
9
|
+
CanvasContextProps,
|
|
10
|
+
TextureFormat,
|
|
11
|
+
Buffer,
|
|
12
|
+
Texture,
|
|
13
|
+
Framebuffer,
|
|
14
|
+
VertexArray,
|
|
15
|
+
VertexArrayProps
|
|
16
|
+
} from '@luma.gl/core';
|
|
8
17
|
import {Device, CanvasContext, log} from '@luma.gl/core';
|
|
9
18
|
import type {GLExtensions} from '@luma.gl/constants';
|
|
10
|
-
import {
|
|
11
|
-
popContextState,
|
|
12
|
-
pushContextState,
|
|
13
|
-
trackContextState
|
|
14
|
-
} from '../context/state-tracker/track-context-state';
|
|
19
|
+
import {WebGLStateTracker} from '../context/state-tracker/webgl-state-tracker';
|
|
15
20
|
import {createBrowserContext} from '../context/helpers/create-browser-context';
|
|
16
21
|
import {getDeviceInfo} from './device-helpers/webgl-device-info';
|
|
17
22
|
import {WebGLDeviceFeatures} from './device-helpers/webgl-device-features';
|
|
18
23
|
import {WebGLDeviceLimits} from './device-helpers/webgl-device-limits';
|
|
19
24
|
import {WebGLCanvasContext} from './webgl-canvas-context';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
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';
|
|
22
28
|
import {
|
|
23
29
|
isTextureFormatSupported,
|
|
24
30
|
isTextureFormatRenderable,
|
|
25
31
|
isTextureFormatFilterable
|
|
26
32
|
} from './converters/texture-formats';
|
|
33
|
+
import {uid} from '../utils/uid';
|
|
27
34
|
|
|
28
35
|
// WebGL classes
|
|
29
36
|
import type {
|
|
@@ -61,27 +68,22 @@ import {WEBGLVertexArray} from './resources/webgl-vertex-array';
|
|
|
61
68
|
import {WEBGLTransformFeedback} from './resources/webgl-transform-feedback';
|
|
62
69
|
import {WEBGLQuerySet} from './resources/webgl-query-set';
|
|
63
70
|
|
|
64
|
-
import {readPixelsToArray, readPixelsToBuffer} from '
|
|
71
|
+
import {readPixelsToArray, readPixelsToBuffer} from './helpers/webgl-texture-utils';
|
|
65
72
|
import {
|
|
66
73
|
setGLParameters,
|
|
67
74
|
getGLParameters,
|
|
68
75
|
resetGLParameters
|
|
69
76
|
} from '../context/parameters/unified-parameter-api';
|
|
70
77
|
import {withGLParameters} from '../context/state-tracker/with-parameters';
|
|
71
|
-
import {clear} from '../
|
|
78
|
+
import {clear} from '../deprecated/clear';
|
|
72
79
|
import {getWebGLExtension} from '../context/helpers/webgl-extensions';
|
|
73
80
|
|
|
74
|
-
const LOG_LEVEL = 1;
|
|
75
|
-
|
|
76
81
|
/** WebGPU style Device API for a WebGL context */
|
|
77
82
|
export class WebGLDevice extends Device {
|
|
78
83
|
//
|
|
79
84
|
// Public `Device` API
|
|
80
85
|
//
|
|
81
86
|
|
|
82
|
-
/** type of this device */
|
|
83
|
-
static readonly type: string = 'webgl';
|
|
84
|
-
|
|
85
87
|
/** type of this device */
|
|
86
88
|
readonly type = 'webgl';
|
|
87
89
|
|
|
@@ -97,93 +99,26 @@ export class WebGLDevice extends Device {
|
|
|
97
99
|
|
|
98
100
|
private _resolveContextLost?: (value: {reason: 'destroyed'; message: string}) => void;
|
|
99
101
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
/** Check if WebGL 2 is available */
|
|
105
|
-
static isSupported(): boolean {
|
|
106
|
-
return typeof WebGL2RenderingContext !== 'undefined';
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Get a device instance from a GL context
|
|
111
|
-
* Creates and instruments the device if not already created
|
|
112
|
-
* @param gl
|
|
113
|
-
* @returns
|
|
114
|
-
*/
|
|
115
|
-
static attach(gl: Device | WebGL2RenderingContext): WebGLDevice {
|
|
116
|
-
if (gl instanceof WebGLDevice) {
|
|
117
|
-
return gl;
|
|
118
|
-
}
|
|
119
|
-
// @ts-expect-error
|
|
120
|
-
if (gl?.device instanceof Device) {
|
|
121
|
-
// @ts-expect-error
|
|
122
|
-
return gl.device as WebGLDevice;
|
|
123
|
-
}
|
|
124
|
-
if (!isWebGL(gl)) {
|
|
125
|
-
throw new Error('Invalid WebGL2RenderingContext');
|
|
126
|
-
}
|
|
127
|
-
return new WebGLDevice({gl: gl as WebGL2RenderingContext});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
static async create(props: DeviceProps = {}): Promise<WebGLDevice> {
|
|
131
|
-
log.groupCollapsed(LOG_LEVEL, 'WebGLDevice created')();
|
|
132
|
-
|
|
133
|
-
const promises: Promise<unknown>[] = [];
|
|
134
|
-
|
|
135
|
-
// Load webgl and spector debug scripts from CDN if requested
|
|
136
|
-
if (props.debug) {
|
|
137
|
-
promises.push(loadWebGLDeveloperTools());
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (props.spector) {
|
|
141
|
-
promises.push(loadSpectorJS());
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Wait for page to load: if canvas is a string we need to query the DOM for the canvas element.
|
|
145
|
-
// We only wait when props.canvas is string to avoids setting the global page onload callback unless necessary.
|
|
146
|
-
if (typeof props.canvas === 'string') {
|
|
147
|
-
promises.push(CanvasContext.pageLoaded);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Wait for all the loads to settle before creating the context.
|
|
151
|
-
// The Device.create() functions are async, so in contrast to the constructor, we can `await` here.
|
|
152
|
-
const results = await Promise.allSettled(promises);
|
|
153
|
-
for (const result of results) {
|
|
154
|
-
if (result.status === 'rejected') {
|
|
155
|
-
log.error(`Failed to initialize debug libraries ${result.reason}`)();
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
log.probe(LOG_LEVEL + 1, 'DOM is loaded')();
|
|
160
|
-
|
|
161
|
-
// @ts-expect-error
|
|
162
|
-
if (props.gl?.device) {
|
|
163
|
-
log.warn('reattaching existing device')();
|
|
164
|
-
return WebGLDevice.attach(props.gl);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const device = new WebGLDevice(props);
|
|
102
|
+
/** WebGL2 context. */
|
|
103
|
+
readonly gl: WebGL2RenderingContext;
|
|
104
|
+
readonly debug: boolean = false;
|
|
168
105
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
Created ${device.type}${device.debug ? ' debug' : ''} context: \
|
|
172
|
-
${device.info.vendor}, ${device.info.renderer} for canvas: ${device.canvasContext.id}`;
|
|
173
|
-
log.probe(LOG_LEVEL, message)();
|
|
174
|
-
log.table(LOG_LEVEL, device.info)();
|
|
106
|
+
/** State used by luma.gl classes: TODO - move to canvasContext*/
|
|
107
|
+
readonly _canvasSizeInfo = {clientWidth: 0, clientHeight: 0, devicePixelRatio: 1};
|
|
175
108
|
|
|
176
|
-
|
|
109
|
+
/** State used by luma.gl classes - TODO - not used? */
|
|
110
|
+
readonly _extensions: GLExtensions = {};
|
|
111
|
+
_polyfilled: boolean = false;
|
|
177
112
|
|
|
178
|
-
|
|
179
|
-
|
|
113
|
+
/** Instance of Spector.js (if initialized) */
|
|
114
|
+
spectorJS: Spector;
|
|
180
115
|
|
|
181
116
|
//
|
|
182
117
|
// Public API
|
|
183
118
|
//
|
|
184
119
|
|
|
185
120
|
constructor(props: DeviceProps) {
|
|
186
|
-
super({...props, id: props.id || 'webgl-device'});
|
|
121
|
+
super({...props, id: props.id || uid('webgl-device')});
|
|
187
122
|
|
|
188
123
|
// If attaching to an already attached context, return the attached device
|
|
189
124
|
// @ts-expect-error device is attached to context
|
|
@@ -200,8 +135,7 @@ ${device.info.vendor}, ${device.info.renderer} for canvas: ${device.canvasContex
|
|
|
200
135
|
this._resolveContextLost = resolve;
|
|
201
136
|
});
|
|
202
137
|
|
|
203
|
-
|
|
204
|
-
gl ||= createBrowserContext(this.canvasContext.canvas, {
|
|
138
|
+
this.handle = createBrowserContext(this.canvasContext.canvas, {
|
|
205
139
|
...props,
|
|
206
140
|
onContextLost: (event: Event) =>
|
|
207
141
|
this._resolveContextLost?.({
|
|
@@ -209,18 +143,22 @@ ${device.info.vendor}, ${device.info.renderer} for canvas: ${device.canvasContex
|
|
|
209
143
|
message: 'Entered sleep mode, or too many apps or browser tabs are using the GPU.'
|
|
210
144
|
})
|
|
211
145
|
});
|
|
146
|
+
this.gl = this.handle;
|
|
212
147
|
|
|
213
|
-
if (!
|
|
148
|
+
if (!this.handle) {
|
|
214
149
|
throw new Error('WebGL context creation failed');
|
|
215
150
|
}
|
|
216
151
|
|
|
217
|
-
|
|
218
|
-
|
|
152
|
+
// Add spector debug instrumentation to context
|
|
153
|
+
// We need to trust spector integration to decide if spector should be initialized
|
|
154
|
+
// We also run spector instrumentation first, otherwise spector can clobber luma instrumentation.
|
|
155
|
+
this.spectorJS = initializeSpectorJS({...this.props, gl: this.handle});
|
|
219
156
|
|
|
157
|
+
// Instrument context
|
|
220
158
|
(this.gl as any).device = this; // Update GL context: Link webgl context back to device
|
|
221
159
|
(this.gl as any)._version = 2; // Update GL context: Store WebGL version field on gl context (HACK to identify debug contexts)
|
|
222
160
|
|
|
223
|
-
// luma Device fields
|
|
161
|
+
// initialize luma Device fields
|
|
224
162
|
this.info = getDeviceInfo(this.gl, this._extensions);
|
|
225
163
|
this.limits = new WebGLDeviceLimits(this.gl);
|
|
226
164
|
this.features = new WebGLDeviceFeatures(this.gl, this._extensions, this.props.disabledFeatures);
|
|
@@ -231,25 +169,18 @@ ${device.info.vendor}, ${device.info.renderer} for canvas: ${device.canvasContex
|
|
|
231
169
|
this.canvasContext.resize();
|
|
232
170
|
|
|
233
171
|
// Install context state tracking
|
|
234
|
-
|
|
235
|
-
const {enable = true, copyState = false} = props;
|
|
236
|
-
trackContextState(this.gl, {
|
|
237
|
-
enable,
|
|
238
|
-
copyState,
|
|
172
|
+
const glState = new WebGLStateTracker(this.gl, {
|
|
239
173
|
log: (...args: any[]) => log.log(1, ...args)()
|
|
240
174
|
});
|
|
175
|
+
glState.trackState(this.gl, {copyState: false});
|
|
241
176
|
|
|
242
|
-
// DEBUG contexts: Add debug instrumentation to the context, force log level to at least 1
|
|
177
|
+
// DEBUG contexts: Add luma debug instrumentation to the context, force log level to at least 1
|
|
243
178
|
if (props.debug) {
|
|
244
179
|
this.gl = makeDebugContext(this.gl, {...props, throwOnError: true});
|
|
245
180
|
this.debug = true;
|
|
246
181
|
log.level = Math.max(log.level, 1);
|
|
247
182
|
log.warn('WebGL debug mode activated. Performance reduced.')();
|
|
248
183
|
}
|
|
249
|
-
|
|
250
|
-
if (props.spector) {
|
|
251
|
-
this.spectorJS = initializeSpectorJS({...this.props, canvas: this.handle.canvas});
|
|
252
|
-
}
|
|
253
184
|
}
|
|
254
185
|
|
|
255
186
|
/**
|
|
@@ -262,10 +193,6 @@ ${device.info.vendor}, ${device.info.renderer} for canvas: ${device.canvasContex
|
|
|
262
193
|
return this.gl.isContextLost();
|
|
263
194
|
}
|
|
264
195
|
|
|
265
|
-
getSize(): [number, number] {
|
|
266
|
-
return [this.gl.drawingBufferWidth, this.gl.drawingBufferHeight];
|
|
267
|
-
}
|
|
268
|
-
|
|
269
196
|
isTextureFormatSupported(format: TextureFormat): boolean {
|
|
270
197
|
return isTextureFormatSupported(this.gl, format, this._extensions);
|
|
271
198
|
}
|
|
@@ -425,20 +352,6 @@ ${device.info.vendor}, ${device.info.renderer} for canvas: ${device.canvasContex
|
|
|
425
352
|
// WebGL-only API (not part of `Device` API)
|
|
426
353
|
//
|
|
427
354
|
|
|
428
|
-
/** WebGL2 context. */
|
|
429
|
-
readonly gl: WebGL2RenderingContext;
|
|
430
|
-
readonly debug: boolean = false;
|
|
431
|
-
|
|
432
|
-
/** State used by luma.gl classes: TODO - move to canvasContext*/
|
|
433
|
-
readonly _canvasSizeInfo = {clientWidth: 0, clientHeight: 0, devicePixelRatio: 1};
|
|
434
|
-
|
|
435
|
-
/** State used by luma.gl classes - TODO - not used? */
|
|
436
|
-
readonly _extensions: GLExtensions = {};
|
|
437
|
-
_polyfilled: boolean = false;
|
|
438
|
-
|
|
439
|
-
/** Instance of Spector.js (if initialized) */
|
|
440
|
-
spectorJS: unknown;
|
|
441
|
-
|
|
442
355
|
/**
|
|
443
356
|
* Triggers device (or WebGL context) loss.
|
|
444
357
|
* @note primarily intended for testing how application reacts to device loss
|
|
@@ -461,12 +374,14 @@ ${device.info.vendor}, ${device.info.renderer} for canvas: ${device.canvasContex
|
|
|
461
374
|
|
|
462
375
|
/** Save current WebGL context state onto an internal stack */
|
|
463
376
|
pushState(): void {
|
|
464
|
-
|
|
377
|
+
const webglState = WebGLStateTracker.get(this.gl);
|
|
378
|
+
webglState.push();
|
|
465
379
|
}
|
|
466
380
|
|
|
467
381
|
/** Restores previously saved context state */
|
|
468
382
|
popState(): void {
|
|
469
|
-
|
|
383
|
+
const webglState = WebGLStateTracker.get(this.gl);
|
|
384
|
+
webglState.pop();
|
|
470
385
|
}
|
|
471
386
|
|
|
472
387
|
/**
|
|
@@ -541,15 +456,6 @@ ${device.info.vendor}, ${device.info.renderer} for canvas: ${device.canvasContex
|
|
|
541
456
|
}
|
|
542
457
|
}
|
|
543
458
|
|
|
544
|
-
/** Check if supplied parameter is a WebGL2RenderingContext */
|
|
545
|
-
function isWebGL(gl: any): boolean {
|
|
546
|
-
if (typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext) {
|
|
547
|
-
return true;
|
|
548
|
-
}
|
|
549
|
-
// Look for debug contexts, headless gl etc
|
|
550
|
-
return Boolean(gl && Number.isFinite(gl._version));
|
|
551
|
-
}
|
|
552
|
-
|
|
553
459
|
/** Set constant float array attribute */
|
|
554
460
|
function setConstantFloatArray(device: WebGLDevice, location: number, array: Float32Array): void {
|
|
555
461
|
switch (array.length) {
|