@luma.gl/webgl 9.2.5 → 9.3.0-alpha.2
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/resources/webgl-buffer.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-buffer.js +1 -0
- package/dist/adapter/resources/webgl-buffer.js.map +1 -1
- package/dist/adapter/resources/webgl-fence.d.ts +14 -0
- package/dist/adapter/resources/webgl-fence.d.ts.map +1 -0
- package/dist/adapter/resources/webgl-fence.js +49 -0
- package/dist/adapter/resources/webgl-fence.js.map +1 -0
- package/dist/adapter/resources/webgl-render-pass.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-render-pass.js +4 -6
- package/dist/adapter/resources/webgl-render-pass.js.map +1 -1
- package/dist/adapter/resources/webgl-texture.d.ts +21 -4
- package/dist/adapter/resources/webgl-texture.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-texture.js +148 -22
- package/dist/adapter/resources/webgl-texture.js.map +1 -1
- package/dist/adapter/webgl-adapter.d.ts.map +1 -1
- package/dist/adapter/webgl-adapter.js +19 -19
- package/dist/adapter/webgl-adapter.js.map +1 -1
- package/dist/adapter/webgl-canvas-context.d.ts +2 -2
- package/dist/adapter/webgl-canvas-context.d.ts.map +1 -1
- package/dist/adapter/webgl-canvas-context.js +16 -6
- package/dist/adapter/webgl-canvas-context.js.map +1 -1
- package/dist/adapter/webgl-device.d.ts +2 -1
- package/dist/adapter/webgl-device.d.ts.map +1 -1
- package/dist/adapter/webgl-device.js +14 -13
- package/dist/adapter/webgl-device.js.map +1 -1
- package/dist/context/debug/webgl-developer-tools.js +4 -6
- package/dist/context/debug/webgl-developer-tools.js.map +1 -1
- package/dist/context/helpers/create-browser-context.d.ts.map +1 -1
- package/dist/context/helpers/create-browser-context.js +47 -35
- package/dist/context/helpers/create-browser-context.js.map +1 -1
- package/dist/dist.dev.js +468 -274
- package/dist/dist.min.js +2 -2
- package/dist/index.cjs +447 -275
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/adapter/resources/webgl-buffer.ts +1 -0
- package/src/adapter/resources/webgl-fence.ts +55 -0
- package/src/adapter/resources/webgl-render-pass.ts +4 -6
- package/src/adapter/resources/webgl-texture.ts +209 -37
- package/src/adapter/webgl-adapter.ts +23 -20
- package/src/adapter/webgl-canvas-context.ts +19 -8
- package/src/adapter/webgl-device.ts +15 -14
- package/src/context/debug/webgl-developer-tools.ts +13 -6
- package/src/context/helpers/create-browser-context.ts +54 -43
- package/src/index.ts +1 -0
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export { WEBGLTexture } from "./adapter/resources/webgl-texture.js";
|
|
|
8
8
|
export { WEBGLShader } from "./adapter/resources/webgl-shader.js";
|
|
9
9
|
export { WEBGLSampler } from "./adapter/resources/webgl-sampler.js";
|
|
10
10
|
export { WEBGLFramebuffer } from "./adapter/resources/webgl-framebuffer.js";
|
|
11
|
+
export { WEBGLFence } from "./adapter/resources/webgl-fence.js";
|
|
11
12
|
export { WEBGLRenderPipeline } from "./adapter/resources/webgl-render-pipeline.js";
|
|
12
13
|
export { WEBGLCommandEncoder } from "./adapter/resources/webgl-command-encoder.js";
|
|
13
14
|
export { WEBGLRenderPass } from "./adapter/resources/webgl-render-pass.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,YAAY,EAAC,iBAAiB,EAAC,wDAAqD;AAGpF,OAAO,EAAC,aAAa,EAAC,mCAAgC;AACtD,YAAY,EAAC,YAAY,EAAC,mCAAgC;AAG1D,OAAO,EAAC,WAAW,EAAC,kCAA+B;AACnD,OAAO,EAAC,kBAAkB,EAAC,0CAAuC;AAGlE,OAAO,EAAC,WAAW,EAAC,4CAAyC;AAC7D,OAAO,EAAC,YAAY,EAAC,6CAA0C;AAE/D,OAAO,EAAC,WAAW,EAAC,4CAAyC;AAC7D,OAAO,EAAC,YAAY,EAAC,6CAA0C;AAC/D,OAAO,EAAC,gBAAgB,EAAC,iDAA8C;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,YAAY,EAAC,iBAAiB,EAAC,wDAAqD;AAGpF,OAAO,EAAC,aAAa,EAAC,mCAAgC;AACtD,YAAY,EAAC,YAAY,EAAC,mCAAgC;AAG1D,OAAO,EAAC,WAAW,EAAC,kCAA+B;AACnD,OAAO,EAAC,kBAAkB,EAAC,0CAAuC;AAGlE,OAAO,EAAC,WAAW,EAAC,4CAAyC;AAC7D,OAAO,EAAC,YAAY,EAAC,6CAA0C;AAE/D,OAAO,EAAC,WAAW,EAAC,4CAAyC;AAC7D,OAAO,EAAC,YAAY,EAAC,6CAA0C;AAC/D,OAAO,EAAC,gBAAgB,EAAC,iDAA8C;AACvE,OAAO,EAAC,UAAU,EAAC,2CAAwC;AAE3D,OAAO,EAAC,mBAAmB,EAAC,qDAAkD;AAE9E,OAAO,EAAC,mBAAmB,EAAC,qDAAkD;AAC9E,OAAO,EAAC,eAAe,EAAC,iDAA8C;AAEtE,OAAO,EAAC,gBAAgB,EAAC,kDAA+C;AAGxE,OAAO,EAAC,sBAAsB,EAAC,wDAAqD;AAIpF,OAAO,EAAC,mBAAmB,EAAE,oBAAoB,EAAC,kDAA+C;AAGjG,OAAO,EAAC,uBAAuB,EAAC,yDAAsD;AACtF,OAAO,EAAC,iBAAiB,EAAC,uDAAoD;AAG9E,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,eAAe,EAChB,sDAAmD;AAEpD,OAAO,EAAC,gBAAgB,EAAC,mDAAgD"}
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ export { WEBGLTexture } from "./adapter/resources/webgl-texture.js";
|
|
|
13
13
|
export { WEBGLShader } from "./adapter/resources/webgl-shader.js";
|
|
14
14
|
export { WEBGLSampler } from "./adapter/resources/webgl-sampler.js";
|
|
15
15
|
export { WEBGLFramebuffer } from "./adapter/resources/webgl-framebuffer.js";
|
|
16
|
+
export { WEBGLFence } from "./adapter/resources/webgl-fence.js";
|
|
16
17
|
export { WEBGLRenderPipeline } from "./adapter/resources/webgl-render-pipeline.js";
|
|
17
18
|
// export {WEBGLComputePipeline} from './adapter/resources/webgl-compute-pipeline';
|
|
18
19
|
export { WEBGLCommandEncoder } from "./adapter/resources/webgl-command-encoder.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,+BAA+B;AAC/B,oCAAoC;AAWpC,wBAAwB;AACxB,OAAO,EAAC,aAAa,EAAC,mCAAgC;AAGtD,uBAAuB;AACvB,OAAO,EAAC,WAAW,EAAC,kCAA+B;AACnD,OAAO,EAAC,kBAAkB,EAAC,0CAAuC;AAElE,yBAAyB;AACzB,OAAO,EAAC,WAAW,EAAC,4CAAyC;AAC7D,OAAO,EAAC,YAAY,EAAC,6CAA0C;AAC/D,mFAAmF;AACnF,OAAO,EAAC,WAAW,EAAC,4CAAyC;AAC7D,OAAO,EAAC,YAAY,EAAC,6CAA0C;AAC/D,OAAO,EAAC,gBAAgB,EAAC,iDAA8C;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,UAAU;AACV,+BAA+B;AAC/B,oCAAoC;AAWpC,wBAAwB;AACxB,OAAO,EAAC,aAAa,EAAC,mCAAgC;AAGtD,uBAAuB;AACvB,OAAO,EAAC,WAAW,EAAC,kCAA+B;AACnD,OAAO,EAAC,kBAAkB,EAAC,0CAAuC;AAElE,yBAAyB;AACzB,OAAO,EAAC,WAAW,EAAC,4CAAyC;AAC7D,OAAO,EAAC,YAAY,EAAC,6CAA0C;AAC/D,mFAAmF;AACnF,OAAO,EAAC,WAAW,EAAC,4CAAyC;AAC7D,OAAO,EAAC,YAAY,EAAC,6CAA0C;AAC/D,OAAO,EAAC,gBAAgB,EAAC,iDAA8C;AACvE,OAAO,EAAC,UAAU,EAAC,2CAAwC;AAE3D,OAAO,EAAC,mBAAmB,EAAC,qDAAkD;AAC9E,mFAAmF;AACnF,OAAO,EAAC,mBAAmB,EAAC,qDAAkD;AAC9E,OAAO,EAAC,eAAe,EAAC,iDAA8C;AACtE,2EAA2E;AAC3E,OAAO,EAAC,gBAAgB,EAAC,kDAA+C;AAExE,wBAAwB;AACxB,OAAO,EAAC,sBAAsB,EAAC,wDAAqD;AAEpF,wBAAwB;AAExB,OAAO,EAAC,mBAAmB,EAAE,oBAAoB,EAAC,kDAA+C;AAEjG,yBAAyB;AACzB,OAAO,EAAC,uBAAuB,EAAC,yDAAsD;AACtF,OAAO,EAAC,iBAAiB,EAAC,uDAAoD;AAE9E,0BAA0B;AAC1B,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,eAAe,EAChB,sDAAmD;AAEpD,OAAO,EAAC,gBAAgB,EAAC,mDAAgD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luma.gl/webgl",
|
|
3
|
-
"version": "9.2
|
|
3
|
+
"version": "9.3.0-alpha.2",
|
|
4
4
|
"description": "WebGL2 adapter for the luma.gl core API",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,12 +40,12 @@
|
|
|
40
40
|
"prepublishOnly": "npm run build-minified-bundle && npm run build-dev-bundle"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"@luma.gl/core": "
|
|
43
|
+
"@luma.gl/core": "9.2.0-alpha.6"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@luma.gl/constants": "9.2
|
|
46
|
+
"@luma.gl/constants": "9.3.0-alpha.2",
|
|
47
47
|
"@math.gl/types": "^4.1.0",
|
|
48
48
|
"@probe.gl/env": "^4.0.8"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "7fedf8d8902f58490a4ffca9a873daee3c732f24"
|
|
51
51
|
}
|
|
@@ -42,6 +42,7 @@ export class WEBGLBuffer extends Buffer {
|
|
|
42
42
|
// - In WebGL2, we can use GL.COPY_READ_BUFFER which avoids locking the type here
|
|
43
43
|
this.glTarget = getWebGLTarget(this.props.usage);
|
|
44
44
|
this.glUsage = getWebGLUsage(this.props.usage);
|
|
45
|
+
// Note: uint8 indices are converted to uint16 during device normalization for WebGPU compatibility
|
|
45
46
|
this.glIndexType = this.props.indexType === 'uint32' ? GL.UNSIGNED_INT : GL.UNSIGNED_SHORT;
|
|
46
47
|
|
|
47
48
|
// Set data: (re)initializes the buffer
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import {Fence, type FenceProps} from '@luma.gl/core';
|
|
6
|
+
import {WebGLDevice} from '../webgl-device';
|
|
7
|
+
|
|
8
|
+
/** WebGL fence implemented with gl.fenceSync */
|
|
9
|
+
export class WEBGLFence extends Fence {
|
|
10
|
+
readonly device: WebGLDevice;
|
|
11
|
+
readonly gl: WebGL2RenderingContext;
|
|
12
|
+
readonly handle: WebGLSync;
|
|
13
|
+
readonly signaled: Promise<void>;
|
|
14
|
+
private _signaled = false;
|
|
15
|
+
|
|
16
|
+
constructor(device: WebGLDevice, props: FenceProps = {}) {
|
|
17
|
+
super(device, {});
|
|
18
|
+
this.device = device;
|
|
19
|
+
this.gl = device.gl;
|
|
20
|
+
|
|
21
|
+
const sync = this.props.handle || this.gl.fenceSync(this.gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
|
|
22
|
+
if (!sync) {
|
|
23
|
+
throw new Error('Failed to create WebGL fence');
|
|
24
|
+
}
|
|
25
|
+
this.handle = sync;
|
|
26
|
+
|
|
27
|
+
this.signaled = new Promise(resolve => {
|
|
28
|
+
const poll = () => {
|
|
29
|
+
const status = this.gl.clientWaitSync(this.handle, 0, 0);
|
|
30
|
+
if (status === this.gl.ALREADY_SIGNALED || status === this.gl.CONDITION_SATISFIED) {
|
|
31
|
+
this._signaled = true;
|
|
32
|
+
resolve();
|
|
33
|
+
} else {
|
|
34
|
+
setTimeout(poll, 1);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
poll();
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
isSignaled(): boolean {
|
|
42
|
+
if (this._signaled) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
const status = this.gl.getSyncParameter(this.handle, this.gl.SYNC_STATUS);
|
|
46
|
+
this._signaled = status === this.gl.SIGNALED;
|
|
47
|
+
return this._signaled;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
destroy(): void {
|
|
51
|
+
if (!this.destroyed) {
|
|
52
|
+
this.gl.deleteSync(this.handle);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -50,7 +50,8 @@ export class WEBGLRenderPass extends RenderPass {
|
|
|
50
50
|
(_, i) => GL.COLOR_ATTACHMENT0 + i
|
|
51
51
|
);
|
|
52
52
|
this.device.gl.drawBuffers(drawBuffers);
|
|
53
|
-
} else {
|
|
53
|
+
} else if (!this.props.framebuffer) {
|
|
54
|
+
// Default framebuffer only supports GL.BACK/GL.NONE draw buffers
|
|
54
55
|
this.device.gl.drawBuffers([GL.BACK]);
|
|
55
56
|
}
|
|
56
57
|
|
|
@@ -110,12 +111,9 @@ export class WEBGLRenderPass extends RenderPass {
|
|
|
110
111
|
if (parameters.blendConstant) {
|
|
111
112
|
glParameters.blendColor = parameters.blendConstant;
|
|
112
113
|
}
|
|
113
|
-
if (parameters.stencilReference) {
|
|
114
|
-
// eslint-disable-next-line no-console
|
|
115
|
-
console.warn('RenderPassParameters.stencilReference not yet implemented in WebGL');
|
|
116
|
-
// parameters.stencilFunc = [func, ref, mask];
|
|
117
|
-
// Does this work?
|
|
114
|
+
if (parameters.stencilReference !== undefined) {
|
|
118
115
|
glParameters[GL.STENCIL_REF] = parameters.stencilReference;
|
|
116
|
+
glParameters[GL.STENCIL_BACK_REF] = parameters.stencilReference;
|
|
119
117
|
}
|
|
120
118
|
|
|
121
119
|
if ('colorMask' in parameters) {
|
|
@@ -2,33 +2,45 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
// @ts-nocheck
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
type Device,
|
|
9
|
+
type TextureProps,
|
|
10
|
+
type TextureViewProps,
|
|
11
|
+
type Sampler,
|
|
12
|
+
type SamplerProps,
|
|
13
|
+
type CopyExternalImageOptions,
|
|
14
|
+
type CopyImageDataOptions,
|
|
15
|
+
type TextureReadOptions,
|
|
16
|
+
type TextureWriteOptions,
|
|
17
|
+
type TextureFormat,
|
|
18
|
+
type TypedArray,
|
|
19
|
+
Buffer,
|
|
20
|
+
Texture,
|
|
21
|
+
log
|
|
14
22
|
} from '@luma.gl/core';
|
|
15
|
-
|
|
23
|
+
|
|
16
24
|
import {
|
|
25
|
+
GLSamplerParameters,
|
|
26
|
+
GLValueParameters,
|
|
17
27
|
GL,
|
|
18
28
|
GLTextureTarget,
|
|
19
29
|
GLTextureCubeMapTarget,
|
|
20
30
|
GLTexelDataFormat,
|
|
21
|
-
GLPixelType
|
|
22
|
-
// GLDataType,
|
|
23
|
-
GLSamplerParameters,
|
|
24
|
-
GLValueParameters
|
|
31
|
+
GLPixelType
|
|
25
32
|
} from '@luma.gl/constants';
|
|
33
|
+
|
|
26
34
|
import {getTextureFormatWebGL} from '../converters/webgl-texture-table';
|
|
27
35
|
import {convertSamplerParametersToWebGL} from '../converters/sampler-parameters';
|
|
28
36
|
import {withGLParameters} from '../../context/state-tracker/with-parameters';
|
|
29
37
|
import {WebGLDevice} from '../webgl-device';
|
|
38
|
+
import {WEBGLFramebuffer} from './webgl-framebuffer';
|
|
30
39
|
import {WEBGLSampler} from './webgl-sampler';
|
|
31
40
|
import {WEBGLTextureView} from './webgl-texture-view';
|
|
41
|
+
import {convertDataTypeToGLDataType} from '../converters/webgl-shadertypes';
|
|
42
|
+
import {convertGLDataTypeToDataType} from '../converters/shader-formats';
|
|
43
|
+
import {getTypedArrayConstructor, getDataType} from '@luma.gl/core';
|
|
32
44
|
|
|
33
45
|
/**
|
|
34
46
|
* WebGL... the texture API from hell... hopefully made simpler
|
|
@@ -65,9 +77,12 @@ export class WEBGLTexture extends Texture {
|
|
|
65
77
|
// state
|
|
66
78
|
/** Texture binding slot - TODO - move to texture view? */
|
|
67
79
|
_textureUnit: number = 0;
|
|
80
|
+
/** Chached framebuffer */
|
|
81
|
+
_framebuffer: WEBGLFramebuffer | null = null;
|
|
68
82
|
|
|
69
83
|
constructor(device: Device, props: TextureProps) {
|
|
70
|
-
|
|
84
|
+
// const byteAlignment = this._getRowByteAlignment(props.format, props.width);
|
|
85
|
+
super(device, props, {byteAlignment: 1});
|
|
71
86
|
|
|
72
87
|
this.device = device as WebGLDevice;
|
|
73
88
|
this.gl = this.device.gl;
|
|
@@ -119,6 +134,10 @@ export class WEBGLTexture extends Texture {
|
|
|
119
134
|
|
|
120
135
|
override destroy(): void {
|
|
121
136
|
if (this.handle) {
|
|
137
|
+
// Destroy any cached framebuffer
|
|
138
|
+
this._framebuffer?.destroy();
|
|
139
|
+
this._framebuffer = null;
|
|
140
|
+
|
|
122
141
|
this.gl.deleteTexture(this.handle);
|
|
123
142
|
this.removeStats();
|
|
124
143
|
this.trackDeallocatedMemory('Texture');
|
|
@@ -138,12 +157,51 @@ export class WEBGLTexture extends Texture {
|
|
|
138
157
|
this._setSamplerParameters(parameters);
|
|
139
158
|
}
|
|
140
159
|
|
|
160
|
+
copyExternalImage(options_: CopyExternalImageOptions): {width: number; height: number} {
|
|
161
|
+
const options = this._normalizeCopyExternalImageOptions(options_);
|
|
162
|
+
|
|
163
|
+
if (options.sourceX || options.sourceY) {
|
|
164
|
+
// requires copyTexSubImage2D from a framebuffer'
|
|
165
|
+
throw new Error('WebGL does not support sourceX/sourceY)');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const {glFormat, glType} = this;
|
|
169
|
+
const {image, depth, mipLevel, x, y, z, width, height} = options;
|
|
170
|
+
|
|
171
|
+
// WebGL cube maps specify faces by overriding target instead of using the z parameter
|
|
172
|
+
const glTarget = getWebGLCubeFaceTarget(this.glTarget, this.dimension, z);
|
|
173
|
+
const glParameters: GLValueParameters = options.flipY ? {[GL.UNPACK_FLIP_Y_WEBGL]: true} : {};
|
|
174
|
+
|
|
175
|
+
this.gl.bindTexture(this.glTarget, this.handle);
|
|
176
|
+
|
|
177
|
+
withGLParameters(this.gl, glParameters, () => {
|
|
178
|
+
switch (this.dimension) {
|
|
179
|
+
case '2d':
|
|
180
|
+
case 'cube':
|
|
181
|
+
// prettier-ignore
|
|
182
|
+
this.gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, image);
|
|
183
|
+
break;
|
|
184
|
+
case '2d-array':
|
|
185
|
+
case '3d':
|
|
186
|
+
// prettier-ignore
|
|
187
|
+
this.gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, image);
|
|
188
|
+
break;
|
|
189
|
+
default:
|
|
190
|
+
// Can never happen in WebGL
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
this.gl.bindTexture(this.glTarget, null);
|
|
195
|
+
|
|
196
|
+
return {width: options.width, height: options.height};
|
|
197
|
+
}
|
|
198
|
+
|
|
141
199
|
copyImageData(options_: CopyImageDataOptions): void {
|
|
142
200
|
const options = this._normalizeCopyImageDataOptions(options_);
|
|
143
201
|
|
|
144
202
|
const typedArray = options.data as TypedArray;
|
|
145
|
-
const {width, height, depth} =
|
|
146
|
-
const {mipLevel = 0, byteOffset = 0, x = 0, y = 0
|
|
203
|
+
const {width, height, depth, z = 0} = options;
|
|
204
|
+
const {mipLevel = 0, byteOffset = 0, x = 0, y = 0} = options;
|
|
147
205
|
const {glFormat, glType, compressed} = this;
|
|
148
206
|
|
|
149
207
|
// Target used for face updates, but not for binding
|
|
@@ -164,12 +222,13 @@ export class WEBGLTexture extends Texture {
|
|
|
164
222
|
|
|
165
223
|
const glParameters: GLValueParameters = !this.compressed
|
|
166
224
|
? {
|
|
225
|
+
[GL.UNPACK_ALIGNMENT]: this.byteAlignment,
|
|
167
226
|
...(unpackRowLength !== undefined ? {[GL.UNPACK_ROW_LENGTH]: unpackRowLength} : {}),
|
|
168
227
|
[GL.UNPACK_IMAGE_HEIGHT]: options.rowsPerImage
|
|
169
228
|
}
|
|
170
229
|
: {};
|
|
171
230
|
|
|
172
|
-
this.gl.bindTexture(glTarget, this.handle);
|
|
231
|
+
this.gl.bindTexture(this.glTarget, this.handle);
|
|
173
232
|
|
|
174
233
|
withGLParameters(this.gl, glParameters, () => {
|
|
175
234
|
switch (this.dimension) {
|
|
@@ -198,51 +257,163 @@ export class WEBGLTexture extends Texture {
|
|
|
198
257
|
}
|
|
199
258
|
});
|
|
200
259
|
|
|
201
|
-
this.gl.bindTexture(glTarget, null);
|
|
260
|
+
this.gl.bindTexture(this.glTarget, null);
|
|
202
261
|
}
|
|
203
262
|
|
|
204
|
-
|
|
205
|
-
|
|
263
|
+
readBuffer(options: TextureReadOptions = {}, buffer?: Buffer): Buffer {
|
|
264
|
+
throw new Error('readBuffer not implemented');
|
|
265
|
+
}
|
|
206
266
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
267
|
+
async readDataAsync(options: TextureReadOptions = {}): Promise<ArrayBuffer> {
|
|
268
|
+
return this.readDataSyncWebGL(options);
|
|
269
|
+
}
|
|
211
270
|
|
|
212
|
-
|
|
213
|
-
const {image, depth, mipLevel, x, y, z, width, height} = options;
|
|
271
|
+
writeBuffer(buffer: Buffer, options_: TextureWriteOptions = {}) {}
|
|
214
272
|
|
|
215
|
-
|
|
273
|
+
writeData(data: ArrayBuffer | ArrayBufferView, options_: TextureWriteOptions = {}): void {
|
|
274
|
+
const options = this._normalizeTextureWriteOptions(options_);
|
|
275
|
+
|
|
276
|
+
const typedArray = ArrayBuffer.isView(data) ? data : new Uint8Array(data);
|
|
277
|
+
const {} = this;
|
|
278
|
+
const {width, height, mipLevel, x, y, z} = options;
|
|
279
|
+
const {glFormat, glType, compressed} = this;
|
|
280
|
+
const depth = 0; // TODO - fix
|
|
216
281
|
const glTarget = getWebGLCubeFaceTarget(this.glTarget, this.dimension, depth);
|
|
217
|
-
const glParameters: GLValueParameters = options.flipY ? {[GL.UNPACK_FLIP_Y_WEBGL]: true} : {};
|
|
218
282
|
|
|
219
|
-
|
|
283
|
+
// const byteOffset = 0;
|
|
284
|
+
// const {bytesPerRow, rowsPerImage} = this.computeMemoryLayout(options);
|
|
285
|
+
|
|
286
|
+
const glParameters: GLValueParameters = !this.compressed
|
|
287
|
+
? {
|
|
288
|
+
// WebGL does not require byte alignment, but allows it to be specified
|
|
289
|
+
[GL.UNPACK_ALIGNMENT]: this.byteAlignment
|
|
290
|
+
// [GL.UNPACK_ROW_LENGTH]: bytesPerRow,
|
|
291
|
+
// [GL.UNPACK_IMAGE_HEIGHT]: rowsPerImage
|
|
292
|
+
}
|
|
293
|
+
: {};
|
|
294
|
+
|
|
295
|
+
this.gl.bindTexture(glTarget, this.handle);
|
|
296
|
+
this.gl.bindBuffer(GL.PIXEL_UNPACK_BUFFER, null);
|
|
220
297
|
|
|
221
298
|
withGLParameters(this.gl, glParameters, () => {
|
|
222
299
|
switch (this.dimension) {
|
|
223
300
|
case '2d':
|
|
224
301
|
case 'cube':
|
|
225
|
-
|
|
226
|
-
|
|
302
|
+
if (compressed) {
|
|
303
|
+
// prettier-ignore
|
|
304
|
+
this.gl.compressedTexSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, typedArray);
|
|
305
|
+
} else {
|
|
306
|
+
// prettier-ignore
|
|
307
|
+
this.gl.texSubImage2D(glTarget, mipLevel, x, y, width, height, glFormat, glType, typedArray);
|
|
308
|
+
}
|
|
227
309
|
break;
|
|
228
310
|
case '2d-array':
|
|
229
311
|
case '3d':
|
|
230
|
-
|
|
231
|
-
|
|
312
|
+
if (compressed) {
|
|
313
|
+
// prettier-ignore
|
|
314
|
+
this.gl.compressedTexSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, typedArray);
|
|
315
|
+
} else {
|
|
316
|
+
// prettier-ignore
|
|
317
|
+
this.gl.texSubImage3D(glTarget, mipLevel, x, y, z, width, height, depth, glFormat, glType, typedArray);
|
|
318
|
+
}
|
|
232
319
|
break;
|
|
233
320
|
default:
|
|
234
321
|
// Can never happen in WebGL
|
|
235
322
|
}
|
|
236
323
|
});
|
|
237
324
|
|
|
238
|
-
this.gl.bindTexture(
|
|
325
|
+
this.gl.bindTexture(glTarget, null);
|
|
326
|
+
}
|
|
239
327
|
|
|
240
|
-
|
|
328
|
+
// IMPLEMENTATION SPECIFIC
|
|
329
|
+
|
|
330
|
+
/** @todo - for now we always use 1 for maximum compatibility, we can fine tune later */
|
|
331
|
+
private _getRowByteAlignment(format: TextureFormat, width: number): 1 | 2 | 4 | 8 {
|
|
332
|
+
// For best texture data read/write performance, calculate the biggest pack/unpack alignment
|
|
333
|
+
// that fits with the provided texture row byte length
|
|
334
|
+
// Note: Any RGBA or 32 bit type will be at least 4 bytes, which should result in good performance.
|
|
335
|
+
// const info = this.device.getTextureFormatInfo(format);
|
|
336
|
+
// const rowByteLength = width * info.bytesPerPixel;
|
|
337
|
+
// if (rowByteLength % 8 === 0) return 8;
|
|
338
|
+
// if (rowByteLength % 4 === 0) return 4;
|
|
339
|
+
// if (rowByteLength % 2 === 0) return 2;
|
|
340
|
+
return 1;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Wraps a given texture into a framebuffer object, that can be further used
|
|
345
|
+
* to read data from the texture object.
|
|
346
|
+
*/
|
|
347
|
+
_getFramebuffer() {
|
|
348
|
+
this._framebuffer ||= this.device.createFramebuffer({
|
|
349
|
+
id: `framebuffer-for-${this.id}`,
|
|
350
|
+
width: this.width,
|
|
351
|
+
height: this.height,
|
|
352
|
+
colorAttachments: [this]
|
|
353
|
+
});
|
|
354
|
+
return this._framebuffer;
|
|
241
355
|
}
|
|
242
356
|
|
|
243
357
|
// WEBGL SPECIFIC
|
|
244
358
|
|
|
245
|
-
|
|
359
|
+
override readDataSyncWebGL(options_: TextureReadOptions = {}): ArrayBuffer {
|
|
360
|
+
const options = this._normalizeTextureReadOptions(options_);
|
|
361
|
+
|
|
362
|
+
const memoryLayout = this.computeMemoryLayout(options);
|
|
363
|
+
|
|
364
|
+
// const formatInfo = getTextureFormatInfo(format);
|
|
365
|
+
// Allocate pixel array if not already available, using supplied type
|
|
366
|
+
const shaderType = convertGLDataTypeToDataType(this.glType);
|
|
367
|
+
|
|
368
|
+
const ArrayType = getTypedArrayConstructor(shaderType);
|
|
369
|
+
// const components = glFormatToComponents(this.glFormat);
|
|
370
|
+
// TODO - check for composite type (components = 1).
|
|
371
|
+
|
|
372
|
+
const targetArray = new ArrayType(memoryLayout.byteLength) as
|
|
373
|
+
| Uint8Array
|
|
374
|
+
| Uint16Array
|
|
375
|
+
| Float32Array;
|
|
376
|
+
|
|
377
|
+
// Pixel array available, if necessary, deduce type from it.
|
|
378
|
+
const signedType = getDataType(targetArray);
|
|
379
|
+
const sourceType = convertDataTypeToGLDataType(signedType);
|
|
380
|
+
|
|
381
|
+
// There is a lot of hedging in the WebGL2 spec about what formats are guaranteed to be readable
|
|
382
|
+
// (It should always be possible to read RGBA/UNSIGNED_BYTE, but most other combinations are not guaranteed)
|
|
383
|
+
// Querying is possible but expensive:
|
|
384
|
+
// const {device} = framebuffer;
|
|
385
|
+
// texture.glReadFormat ||= gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
|
|
386
|
+
// texture.glReadType ||= gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
|
|
387
|
+
// console.log('params', device.getGLKey(texture.glReadFormat), device.getGLKey(texture.glReadType));
|
|
388
|
+
|
|
389
|
+
const framebuffer = this._getFramebuffer();
|
|
390
|
+
|
|
391
|
+
// Note: luma.gl overrides bindFramebuffer so that we can reliably restore the previous framebuffer (this is the only function for which we do that)
|
|
392
|
+
const prevHandle = this.gl.bindFramebuffer(
|
|
393
|
+
GL.FRAMEBUFFER,
|
|
394
|
+
framebuffer.handle
|
|
395
|
+
) as unknown as WebGLFramebuffer | null;
|
|
396
|
+
|
|
397
|
+
// Select the color attachment to read from
|
|
398
|
+
this.gl.readBuffer(GL.COLOR_ATTACHMENT0);
|
|
399
|
+
this.gl.readPixels(
|
|
400
|
+
options.x,
|
|
401
|
+
options.y,
|
|
402
|
+
options.width,
|
|
403
|
+
options.height,
|
|
404
|
+
this.glFormat,
|
|
405
|
+
sourceType,
|
|
406
|
+
targetArray
|
|
407
|
+
);
|
|
408
|
+
this.gl.bindFramebuffer(GL.FRAMEBUFFER, prevHandle || null);
|
|
409
|
+
|
|
410
|
+
return targetArray.buffer as ArrayBuffer;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* @note - this is used by the DynamicTexture class to generate mipmaps on WebGL
|
|
415
|
+
*/
|
|
416
|
+
override generateMipmapsWebGL(options?: {force?: boolean}): void {
|
|
246
417
|
const isFilterableAndRenderable =
|
|
247
418
|
this.device.isTextureFormatRenderable(this.props.format) &&
|
|
248
419
|
this.device.isTextureFormatFilterable(this.props.format);
|
|
@@ -312,6 +483,7 @@ export class WEBGLTexture extends Texture {
|
|
|
312
483
|
|
|
313
484
|
this.gl.bindTexture(this.glTarget, null);
|
|
314
485
|
}
|
|
486
|
+
|
|
315
487
|
_getActiveUnit(): number {
|
|
316
488
|
return this.gl.getParameter(GL.ACTIVE_TEXTURE) - GL.TEXTURE0;
|
|
317
489
|
}
|
|
@@ -78,40 +78,44 @@ export class WebGLAdapter extends Adapter {
|
|
|
78
78
|
async create(props: DeviceProps = {}): Promise<WebGLDevice> {
|
|
79
79
|
const {WebGLDevice} = await import('./webgl-device');
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
const promises: Promise<unknown>[] = [];
|
|
81
|
+
const promises: Promise<unknown>[] = [];
|
|
84
82
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
83
|
+
// Load webgl and spector debug scripts from CDN if requested
|
|
84
|
+
if (props.debugWebGL || props.debug) {
|
|
85
|
+
promises.push(loadWebGLDeveloperTools());
|
|
86
|
+
}
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
if (props.debugSpectorJS) {
|
|
89
|
+
promises.push(loadSpectorJS(props));
|
|
90
|
+
}
|
|
93
91
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
92
|
+
// Wait for all the loads to settle before creating the context.
|
|
93
|
+
// The Device.create() functions are async, so in contrast to the constructor, we can `await` here.
|
|
94
|
+
const results = await Promise.allSettled(promises);
|
|
95
|
+
for (const result of results) {
|
|
96
|
+
if (result.status === 'rejected') {
|
|
97
|
+
log.error(`Failed to initialize debug libraries ${result.reason}`)();
|
|
101
98
|
}
|
|
99
|
+
}
|
|
102
100
|
|
|
101
|
+
try {
|
|
103
102
|
const device = new WebGLDevice(props);
|
|
104
103
|
|
|
104
|
+
log.groupCollapsed(LOG_LEVEL, `WebGLDevice ${device.id} created`)();
|
|
105
105
|
// Log some debug info about the newly created context
|
|
106
106
|
const message = `\
|
|
107
107
|
${device._reused ? 'Reusing' : 'Created'} device with WebGL2 ${device.props.debug ? 'debug ' : ''}context: \
|
|
108
108
|
${device.info.vendor}, ${device.info.renderer} for canvas: ${device.canvasContext.id}`;
|
|
109
109
|
log.probe(LOG_LEVEL, message)();
|
|
110
110
|
log.table(LOG_LEVEL, device.info)();
|
|
111
|
-
|
|
112
111
|
return device;
|
|
113
112
|
} finally {
|
|
114
113
|
log.groupEnd(LOG_LEVEL)();
|
|
114
|
+
log.info(
|
|
115
|
+
LOG_LEVEL,
|
|
116
|
+
`%cWebGL call tracing: luma.log.set('debug-webgl') `,
|
|
117
|
+
'color: white; background: blue; padding: 2px 6px; border-radius: 3px;'
|
|
118
|
+
)();
|
|
115
119
|
}
|
|
116
120
|
}
|
|
117
121
|
}
|
|
@@ -121,8 +125,7 @@ function isWebGL(gl: any): gl is WebGL2RenderingContext {
|
|
|
121
125
|
if (typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext) {
|
|
122
126
|
return true;
|
|
123
127
|
}
|
|
124
|
-
|
|
125
|
-
return Boolean(gl && Number.isFinite(gl._version));
|
|
128
|
+
return Boolean(gl && typeof gl.createVertexArray === 'function');
|
|
126
129
|
}
|
|
127
130
|
|
|
128
131
|
export const webgl2Adapter = new WebGLAdapter();
|
|
@@ -27,16 +27,27 @@ export class WebGLCanvasContext extends CanvasContext {
|
|
|
27
27
|
|
|
28
28
|
// Base class constructor cannot access derived methods/fields, so we need to call these functions in the subclass constructor
|
|
29
29
|
this._setAutoCreatedCanvasId(`${this.device.id}-canvas`);
|
|
30
|
-
this.
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
getCurrentFramebuffer(): WEBGLFramebuffer {
|
|
34
|
-
// Setting handle to null returns a reference to the default framebuffer
|
|
35
|
-
this._framebuffer = this._framebuffer || new WEBGLFramebuffer(this.device, {handle: null});
|
|
36
|
-
return this._framebuffer;
|
|
30
|
+
this._configureDevice();
|
|
37
31
|
}
|
|
38
32
|
|
|
39
33
|
// IMPLEMENTATION OF ABSTRACT METHODS
|
|
40
34
|
|
|
41
|
-
|
|
35
|
+
_configureDevice(): void {
|
|
36
|
+
const shouldResize =
|
|
37
|
+
this.drawingBufferWidth !== this._framebuffer?.width ||
|
|
38
|
+
this.drawingBufferHeight !== this._framebuffer?.height;
|
|
39
|
+
if (shouldResize) {
|
|
40
|
+
this._framebuffer?.resize([this.drawingBufferWidth, this.drawingBufferHeight]);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
_getCurrentFramebuffer(): WEBGLFramebuffer {
|
|
45
|
+
this._framebuffer ||= new WEBGLFramebuffer(this.device, {
|
|
46
|
+
id: 'canvas-context-framebuffer',
|
|
47
|
+
handle: null, // Setting handle to null returns a reference to the default WebGL framebuffer
|
|
48
|
+
width: this.drawingBufferWidth,
|
|
49
|
+
height: this.drawingBufferHeight
|
|
50
|
+
});
|
|
51
|
+
return this._framebuffer;
|
|
52
|
+
}
|
|
42
53
|
}
|