@luma.gl/webgl 9.0.0-alpha.35 → 9.0.0-alpha.36
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 +9 -0
- package/dist/adapter/converters/device-parameters.d.ts.map +1 -1
- package/dist/adapter/converters/device-parameters.js +15 -2
- package/dist/adapter/converters/device-parameters.js.map +1 -1
- package/dist/adapter/resources/webgl-command-buffer.js +0 -1
- package/dist/adapter/resources/webgl-command-buffer.js.map +1 -1
- package/dist/adapter/resources/webgl-render-pass.d.ts +2 -2
- package/dist/adapter/resources/webgl-render-pass.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-render-pass.js +5 -3
- package/dist/adapter/resources/webgl-render-pass.js.map +1 -1
- package/dist/adapter/resources/webgl-render-pipeline.d.ts +23 -28
- package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-render-pipeline.js +41 -110
- package/dist/adapter/resources/webgl-render-pipeline.js.map +1 -1
- package/dist/adapter/resources/webgl-sampler.js.map +1 -1
- package/dist/adapter/resources/webgl-shader.js +3 -1
- package/dist/adapter/resources/webgl-shader.js.map +1 -1
- package/dist/adapter/resources/webgl-texture.js +5 -5
- package/dist/adapter/resources/webgl-texture.js.map +1 -1
- package/dist/adapter/resources/webgl-vertex-array.d.ts +67 -0
- package/dist/adapter/resources/webgl-vertex-array.d.ts.map +1 -0
- package/dist/adapter/resources/webgl-vertex-array.js +166 -0
- package/dist/adapter/resources/webgl-vertex-array.js.map +1 -0
- package/dist/adapter/webgl-device.d.ts +11 -1
- package/dist/adapter/webgl-device.d.ts.map +1 -1
- package/dist/adapter/webgl-device.js +66 -1
- package/dist/adapter/webgl-device.js.map +1 -1
- package/dist/classic/clear.js +3 -3
- package/dist/classic/clear.js.map +1 -1
- package/dist/classic/copy-and-blit.d.ts.map +1 -1
- package/dist/classic/copy-and-blit.js +7 -9
- package/dist/classic/copy-and-blit.js.map +1 -1
- package/dist/context/context/create-browser-context.d.ts.map +1 -1
- package/dist/context/context/create-browser-context.js.map +1 -1
- package/dist/context/parameters/unified-parameter-api.d.ts +3 -3
- package/dist/context/parameters/unified-parameter-api.d.ts.map +1 -1
- package/dist/context/parameters/unified-parameter-api.js +4 -4
- package/dist/context/parameters/unified-parameter-api.js.map +1 -1
- package/dist/context/state-tracker/track-context-state.js +3 -3
- package/dist/context/state-tracker/track-context-state.js.map +1 -1
- package/dist/context/state-tracker/with-parameters.d.ts +1 -1
- package/dist/context/state-tracker/with-parameters.d.ts.map +1 -1
- package/dist/context/state-tracker/with-parameters.js +3 -3
- package/dist/context/state-tracker/with-parameters.js.map +1 -1
- package/dist/dist.dev.js +1273 -1179
- package/dist/index.cjs +1026 -972
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist.min.js +22 -22
- package/package.json +5 -5
- package/src/adapter/converters/device-parameters.ts +34 -2
- package/src/adapter/resources/webgl-command-buffer.ts +2 -2
- package/src/adapter/resources/webgl-render-pass.ts +8 -6
- package/src/adapter/resources/webgl-render-pipeline.ts +141 -174
- package/src/adapter/resources/webgl-sampler.ts +1 -1
- package/src/adapter/resources/webgl-shader.ts +1 -1
- package/src/adapter/resources/webgl-texture.ts +5 -5
- package/src/adapter/resources/webgl-vertex-array.ts +278 -0
- package/src/adapter/webgl-device.ts +137 -11
- package/src/classic/clear.ts +3 -3
- package/src/classic/copy-and-blit.ts +19 -15
- package/src/context/context/create-browser-context.ts +12 -0
- package/src/context/parameters/unified-parameter-api.ts +4 -4
- package/src/context/state-tracker/track-context-state.ts +3 -3
- package/src/context/state-tracker/with-parameters.ts +3 -3
- package/src/index.ts +38 -16
- package/dist/adapter/objects/webgl-vertex-array-object.d.ts +0 -55
- package/dist/adapter/objects/webgl-vertex-array-object.d.ts.map +0 -1
- package/dist/adapter/objects/webgl-vertex-array-object.js +0 -173
- package/dist/adapter/objects/webgl-vertex-array-object.js.map +0 -1
- package/src/adapter/objects/webgl-vertex-array-object.ts +0 -276
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
// luma.gl, MIT license
|
|
2
|
+
|
|
3
|
+
import type {Device, Buffer, VertexArrayProps, TypedArray, NumberArray} from '@luma.gl/core';
|
|
4
|
+
import {VertexArray, getScratchArray, fillArray} from '@luma.gl/core';
|
|
5
|
+
import {GL} from '@luma.gl/constants';
|
|
6
|
+
import {getBrowser} from '@probe.gl/env';
|
|
7
|
+
|
|
8
|
+
import {WebGLDevice} from '../webgl-device';
|
|
9
|
+
import {WEBGLBuffer} from '../resources/webgl-buffer';
|
|
10
|
+
|
|
11
|
+
import {BufferWithAccessor} from '../../classic/buffer-with-accessor';
|
|
12
|
+
import {getGLFromVertexType} from '../converters/vertex-formats';
|
|
13
|
+
// import {AccessorObject} from '../..';
|
|
14
|
+
// import {getGLFromVertexType} from '../converters/vertex-formats';
|
|
15
|
+
|
|
16
|
+
/** VertexArrayObject wrapper */
|
|
17
|
+
export class WEBGLVertexArray extends VertexArray {
|
|
18
|
+
override get [Symbol.toStringTag](): string {
|
|
19
|
+
return 'VertexArray';
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
readonly device: WebGLDevice;
|
|
23
|
+
readonly handle: WebGLVertexArrayObject;
|
|
24
|
+
|
|
25
|
+
/** Attribute 0 buffer constant */
|
|
26
|
+
private buffer: BufferWithAccessor | null = null;
|
|
27
|
+
private bufferValue = null;
|
|
28
|
+
|
|
29
|
+
/** * Attribute 0 can not be disable on most desktop OpenGL based browsers */
|
|
30
|
+
static isConstantAttributeZeroSupported(device: Device): boolean {
|
|
31
|
+
return device.info.type === 'webgl2' || getBrowser() === 'Chrome';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Create a VertexArray
|
|
35
|
+
constructor(device: WebGLDevice, props?: VertexArrayProps) {
|
|
36
|
+
super(device, props);
|
|
37
|
+
this.device = device;
|
|
38
|
+
this.handle = this.device.gl2.createVertexArray();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
override destroy(): void {
|
|
42
|
+
super.destroy();
|
|
43
|
+
if (this.buffer) {
|
|
44
|
+
this.buffer?.destroy();
|
|
45
|
+
}
|
|
46
|
+
if (this.handle) {
|
|
47
|
+
this.device.gl2.deleteVertexArray(this.handle);
|
|
48
|
+
// @ts-expect-error read-only/undefined
|
|
49
|
+
this.handle = undefined!;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Auto-delete elements?
|
|
53
|
+
// return [this.elements];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
// Set (bind) an elements buffer, for indexed rendering.
|
|
58
|
+
// Must be a Buffer bound to GL.ELEMENT_ARRAY_BUFFER. Constants not supported
|
|
59
|
+
*
|
|
60
|
+
* @param elementBuffer
|
|
61
|
+
*/
|
|
62
|
+
setIndexBuffer(indexBuffer: Buffer | null): void {
|
|
63
|
+
const buffer = indexBuffer as WEBGLBuffer;
|
|
64
|
+
if (buffer && (buffer.glTarget !== GL.ELEMENT_ARRAY_BUFFER)) {
|
|
65
|
+
throw new Error('Use .setBuffer()');
|
|
66
|
+
}
|
|
67
|
+
// In WebGL The GL.ELEMENT_ARRAY_BUFFER_BINDING is stored on the VertexArrayObject
|
|
68
|
+
this.device.gl2.bindVertexArray(this.handle);
|
|
69
|
+
// TODO - this initial binding does not seem to take effect? see bindBeforeRender()
|
|
70
|
+
this.device.gl2.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, buffer ? buffer.handle : null);
|
|
71
|
+
// log.log(1, 'VertexArray.setIndexBuffer', indexBuffer)();
|
|
72
|
+
// log.log(1, `Binding vertex array ${this.id}`, buffer?.id)();
|
|
73
|
+
|
|
74
|
+
this.indexBuffer = buffer;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Set a location in vertex attributes array to a buffer, enables the location, sets divisor */
|
|
78
|
+
setBuffer(location: number, attributeBuffer: Buffer): void {
|
|
79
|
+
const buffer = attributeBuffer as WEBGLBuffer;
|
|
80
|
+
// Sanity check target
|
|
81
|
+
if (buffer.glTarget === GL.ELEMENT_ARRAY_BUFFER) {
|
|
82
|
+
throw new Error('Use .setIndexBuffer()');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const {size, type, stride, offset, normalized, integer, divisor} = this._getAccessor(location);
|
|
86
|
+
|
|
87
|
+
this.device.gl2.bindVertexArray(this.handle);
|
|
88
|
+
// A non-zero buffer object must be bound to the GL_ARRAY_BUFFER target
|
|
89
|
+
this.device.gl.bindBuffer(GL.ARRAY_BUFFER, buffer.handle);
|
|
90
|
+
|
|
91
|
+
// WebGL2 supports *integer* data formats, i.e. GPU will see integer values
|
|
92
|
+
if (integer) {
|
|
93
|
+
this.device.assertWebGL2();
|
|
94
|
+
this.device.gl2.vertexAttribIPointer(location, size, type, stride, offset);
|
|
95
|
+
} else {
|
|
96
|
+
// Attaches ARRAY_BUFFER with specified buffer format to location
|
|
97
|
+
this.device.gl.vertexAttribPointer(location, size, type, normalized, stride, offset);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Mark as non-constant
|
|
101
|
+
this.device.gl.enableVertexAttribArray(location);
|
|
102
|
+
// Set the step mode 0=vertex, 1=instance
|
|
103
|
+
this.device.gl2.vertexAttribDivisor(location, divisor || 0);
|
|
104
|
+
|
|
105
|
+
this.attributes[location] = buffer;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Set a location in vertex attributes array to a constant value, disables the location */
|
|
109
|
+
override setConstant(location: number, value: TypedArray): void {
|
|
110
|
+
this._enable(location, false);
|
|
111
|
+
this.attributes[location] = value;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
init = false;
|
|
115
|
+
|
|
116
|
+
override bindBeforeRender(): void {
|
|
117
|
+
this.device.gl2.bindVertexArray(this.handle);
|
|
118
|
+
// TODO - the initial bind does not seem to take effect.
|
|
119
|
+
if (!this.init) {
|
|
120
|
+
// log.log(1, `Binding vertex array ${this.id}`, this.indexBuffer?.id)();
|
|
121
|
+
const webglBuffer = this.indexBuffer as WEBGLBuffer;
|
|
122
|
+
this.device.gl2.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, webglBuffer?.handle || null);
|
|
123
|
+
this.init = true;
|
|
124
|
+
}
|
|
125
|
+
this._applyConstantAttributes();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
override unbindAfterRender(): void {
|
|
129
|
+
// log.log(1, `Unbinding vertex array ${this.id}`)();
|
|
130
|
+
// TODO technically this is not necessary, but we might be interfacing
|
|
131
|
+
// with code that does not use vertex array objects
|
|
132
|
+
this.device.gl2.bindVertexArray(null);
|
|
133
|
+
// this.device.gl2.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, null);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Internal methods
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Constant attributes need to be reset before every draw call
|
|
140
|
+
* Any attribute that is disabled in the current vertex array object
|
|
141
|
+
* is read from the context's global constant value for that attribute location.
|
|
142
|
+
* @note Constant attributes are only supported in WebGL, not in WebGPU
|
|
143
|
+
*/
|
|
144
|
+
protected _applyConstantAttributes(): void {
|
|
145
|
+
for (let location = 0; location < this.maxVertexAttributes; ++location) {
|
|
146
|
+
const constant = this.attributes[location];
|
|
147
|
+
// A typed array means this is a constant
|
|
148
|
+
if (ArrayBuffer.isView(constant)) {
|
|
149
|
+
this.device.setConstantAttribute(location, constant);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Set a location in vertex attributes array to a buffer, enables the location, sets divisor
|
|
156
|
+
* @note requires vertex array to be bound
|
|
157
|
+
*/
|
|
158
|
+
// protected _setAttributeLayout(location: number): void {
|
|
159
|
+
// const {size, type, stride, offset, normalized, integer, divisor} = this._getAccessor(location);
|
|
160
|
+
|
|
161
|
+
// // WebGL2 supports *integer* data formats, i.e. GPU will see integer values
|
|
162
|
+
// if (integer) {
|
|
163
|
+
// this.device.assertWebGL2();
|
|
164
|
+
// this.device.gl2.vertexAttribIPointer(location, size, type, stride, offset);
|
|
165
|
+
// } else {
|
|
166
|
+
// // Attaches ARRAY_BUFFER with specified buffer format to location
|
|
167
|
+
// this.device.gl.vertexAttribPointer(location, size, type, normalized, stride, offset);
|
|
168
|
+
// }
|
|
169
|
+
// this.device.gl2.vertexAttribDivisor(location, divisor || 0);
|
|
170
|
+
// }
|
|
171
|
+
|
|
172
|
+
/** Get an accessor from the */
|
|
173
|
+
protected _getAccessor(location: number) {
|
|
174
|
+
const attributeInfo = this.attributeInfos[location];
|
|
175
|
+
if (!attributeInfo) {
|
|
176
|
+
throw new Error(`Unknown attribute location ${location}`);
|
|
177
|
+
}
|
|
178
|
+
const glType = getGLFromVertexType(attributeInfo.bufferDataType);
|
|
179
|
+
return {
|
|
180
|
+
size: attributeInfo.bufferComponents,
|
|
181
|
+
type: glType,
|
|
182
|
+
stride: attributeInfo.byteStride,
|
|
183
|
+
offset: attributeInfo.byteOffset,
|
|
184
|
+
normalized: attributeInfo.normalized,
|
|
185
|
+
// it is the shader attribute declaration, not the vertex memory format,
|
|
186
|
+
// that determines if the data in the buffer will be treated as integers.
|
|
187
|
+
//
|
|
188
|
+
// Also note that WebGL supports assigning non-normalized integer data to floating point attributes,
|
|
189
|
+
// but as far as we can tell, WebGPU does not.
|
|
190
|
+
integer: attributeInfo.integer,
|
|
191
|
+
divisor: attributeInfo.stepMode === 'instance' ? 1 : 0
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Enabling an attribute location makes it reference the currently bound buffer
|
|
197
|
+
* Disabling an attribute location makes it reference the global constant value
|
|
198
|
+
* TODO - handle single values for size 1 attributes?
|
|
199
|
+
* TODO - convert classic arrays based on known type?
|
|
200
|
+
*/
|
|
201
|
+
protected _enable(location: number, enable = true): void {
|
|
202
|
+
// Attribute 0 cannot be disabled in most desktop OpenGL based browsers...
|
|
203
|
+
const canDisableAttributeZero = WEBGLVertexArray.isConstantAttributeZeroSupported(this.device);
|
|
204
|
+
const canDisableAttribute = canDisableAttributeZero || location !== 0;
|
|
205
|
+
|
|
206
|
+
if (enable || canDisableAttribute) {
|
|
207
|
+
location = Number(location);
|
|
208
|
+
this.device.gl2.bindVertexArray(this.handle);
|
|
209
|
+
if (enable) {
|
|
210
|
+
this.device.gl.enableVertexAttribArray(location);
|
|
211
|
+
} else {
|
|
212
|
+
this.device.gl.disableVertexAttribArray(location);
|
|
213
|
+
}
|
|
214
|
+
this.device.gl2.bindVertexArray(null);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Provide a means to create a buffer that is equivalent to a constant.
|
|
220
|
+
* NOTE: Desktop OpenGL cannot disable attribute 0.
|
|
221
|
+
* https://stackoverflow.com/questions/20305231/webgl-warning-attribute-0-is-disabled-
|
|
222
|
+
* this-has-significant-performance-penalty
|
|
223
|
+
*/
|
|
224
|
+
getConstantBuffer(elementCount: number, value: TypedArray): Buffer {
|
|
225
|
+
// Create buffer only when needed, and reuse it (avoids inflating buffer creation statistics)
|
|
226
|
+
|
|
227
|
+
const constantValue = normalizeConstantArrayValue(value);
|
|
228
|
+
|
|
229
|
+
const byteLength = constantValue.byteLength * elementCount;
|
|
230
|
+
const length = constantValue.length * elementCount;
|
|
231
|
+
|
|
232
|
+
let updateNeeded = !this.buffer;
|
|
233
|
+
|
|
234
|
+
this.buffer = this.buffer || (this.device.createBuffer({byteLength}) as BufferWithAccessor);
|
|
235
|
+
updateNeeded = updateNeeded || this.buffer.reallocate(byteLength);
|
|
236
|
+
|
|
237
|
+
// Reallocate and update contents if needed
|
|
238
|
+
updateNeeded = updateNeeded || !compareConstantArrayValues(constantValue, this.bufferValue);
|
|
239
|
+
|
|
240
|
+
if (updateNeeded) {
|
|
241
|
+
// Create a typed array that is big enough, and fill it with the required data
|
|
242
|
+
const typedArray = getScratchArray(value.constructor, length);
|
|
243
|
+
fillArray({target: typedArray, source: constantValue, start: 0, count: length});
|
|
244
|
+
this.buffer.subData(typedArray);
|
|
245
|
+
this.bufferValue = value;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return this.buffer;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// HELPER FUNCTIONS
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* TODO - convert Arrays based on known type? (read type from accessor, don't assume Float32Array)
|
|
256
|
+
* TODO - handle single values for size 1 attributes?
|
|
257
|
+
*/
|
|
258
|
+
function normalizeConstantArrayValue(arrayValue: NumberArray) {
|
|
259
|
+
if (Array.isArray(arrayValue)) {
|
|
260
|
+
return new Float32Array(arrayValue);
|
|
261
|
+
}
|
|
262
|
+
return arrayValue;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
*
|
|
267
|
+
*/
|
|
268
|
+
function compareConstantArrayValues(v1: NumberArray, v2: NumberArray): boolean {
|
|
269
|
+
if (!v1 || !v2 || v1.length !== v2.length || v1.constructor !== v2.constructor) {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
for (let i = 0; i < v1.length; ++i) {
|
|
273
|
+
if (v1[i] !== v2[i]) {
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
@@ -5,12 +5,19 @@ import type {
|
|
|
5
5
|
DeviceLimits,
|
|
6
6
|
DeviceFeature,
|
|
7
7
|
CanvasContextProps,
|
|
8
|
-
TextureFormat
|
|
8
|
+
TextureFormat,
|
|
9
|
+
VertexArray,
|
|
10
|
+
VertexArrayProps,
|
|
11
|
+
TypedArray
|
|
9
12
|
} from '@luma.gl/core';
|
|
10
|
-
import {Device, CanvasContext, log, uid} from '@luma.gl/core';
|
|
13
|
+
import {Device, CanvasContext, log, uid, assert} from '@luma.gl/core';
|
|
11
14
|
import {isBrowser} from '@probe.gl/env';
|
|
12
15
|
import {polyfillContext} from '../context/polyfill/polyfill-context';
|
|
13
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
popContextState,
|
|
18
|
+
pushContextState,
|
|
19
|
+
trackContextState
|
|
20
|
+
} from '../context/state-tracker/track-context-state';
|
|
14
21
|
import {createBrowserContext} from '../context/context/create-browser-context';
|
|
15
22
|
import {
|
|
16
23
|
createHeadlessContext,
|
|
@@ -59,6 +66,7 @@ import {WEBGLFramebuffer} from './resources/webgl-framebuffer';
|
|
|
59
66
|
import {WEBGLRenderPass} from './resources/webgl-render-pass';
|
|
60
67
|
import {WEBGLRenderPipeline} from './resources/webgl-render-pipeline';
|
|
61
68
|
import {WEBGLCommandEncoder} from './resources/webgl-command-encoder';
|
|
69
|
+
import {WEBGLVertexArray} from './resources/webgl-vertex-array';
|
|
62
70
|
|
|
63
71
|
const LOG_LEVEL = 1;
|
|
64
72
|
|
|
@@ -133,7 +141,7 @@ export class WebGLDevice extends Device {
|
|
|
133
141
|
if (log.get('debug') || props.debug) {
|
|
134
142
|
await loadWebGLDeveloperTools();
|
|
135
143
|
}
|
|
136
|
-
|
|
144
|
+
|
|
137
145
|
// @ts-expect-error spector not on props
|
|
138
146
|
const {spector} = props;
|
|
139
147
|
if (log.get('spector') || spector) {
|
|
@@ -167,7 +175,7 @@ export class WebGLDevice extends Device {
|
|
|
167
175
|
// Create and instrument context
|
|
168
176
|
this.canvasContext = new WebGLCanvasContext(this, props);
|
|
169
177
|
|
|
170
|
-
this.lost = new Promise<{reason: 'destroyed'; message: string}>(
|
|
178
|
+
this.lost = new Promise<{reason: 'destroyed'; message: string}>(resolve => {
|
|
171
179
|
this._resolveContextLost = resolve;
|
|
172
180
|
});
|
|
173
181
|
|
|
@@ -180,7 +188,9 @@ export class WebGLDevice extends Device {
|
|
|
180
188
|
let gl: WebGLRenderingContext | WebGL2RenderingContext | null = props.gl || null;
|
|
181
189
|
gl =
|
|
182
190
|
gl ||
|
|
183
|
-
(isBrowser()
|
|
191
|
+
(isBrowser()
|
|
192
|
+
? createBrowserContext(this.canvasContext.canvas, {...props, onContextLost})
|
|
193
|
+
: null);
|
|
184
194
|
gl = gl || (!isBrowser() ? createHeadlessContext({...props, onContextLost}) : null);
|
|
185
195
|
|
|
186
196
|
if (!gl) {
|
|
@@ -313,6 +323,10 @@ ${this.info.vendor}, ${this.info.renderer} for canvas: ${this.canvasContext.id}`
|
|
|
313
323
|
return new WEBGLRenderPipeline(this, props);
|
|
314
324
|
}
|
|
315
325
|
|
|
326
|
+
override createVertexArray(props: VertexArrayProps): VertexArray {
|
|
327
|
+
return new WEBGLVertexArray(this, props);
|
|
328
|
+
}
|
|
329
|
+
|
|
316
330
|
beginRenderPass(props: RenderPassProps): WEBGLRenderPass {
|
|
317
331
|
return new WEBGLRenderPass(this, props);
|
|
318
332
|
}
|
|
@@ -379,7 +393,7 @@ ${this.info.vendor}, ${this.info.renderer} for canvas: ${this.canvasContext.id}`
|
|
|
379
393
|
private _webglLimits?: WebGLLimits;
|
|
380
394
|
|
|
381
395
|
/** Return WebGL specific limits */
|
|
382
|
-
get webglLimits()
|
|
396
|
+
get webglLimits(): WebGLLimits {
|
|
383
397
|
this._webglLimits = this._webglLimits || getWebGLLimits(this.gl);
|
|
384
398
|
return this._webglLimits;
|
|
385
399
|
}
|
|
@@ -413,8 +427,8 @@ ${this.info.vendor}, ${this.info.renderer} for canvas: ${this.canvasContext.id}`
|
|
|
413
427
|
popContextState(this.gl);
|
|
414
428
|
}
|
|
415
429
|
|
|
416
|
-
/**
|
|
417
|
-
* Storing data on a special field on WebGLObjects makes that data visible in SPECTOR chrome debug extension
|
|
430
|
+
/**
|
|
431
|
+
* Storing data on a special field on WebGLObjects makes that data visible in SPECTOR chrome debug extension
|
|
418
432
|
* luma.gl ids and props can be inspected
|
|
419
433
|
*/
|
|
420
434
|
setSpectorMetadata(handle: unknown, props: Record<string, unknown>) {
|
|
@@ -423,13 +437,13 @@ ${this.info.vendor}, ${this.info.renderer} for canvas: ${this.canvasContext.id}`
|
|
|
423
437
|
handle.__SPECTOR_Metadata = props;
|
|
424
438
|
}
|
|
425
439
|
|
|
426
|
-
/**
|
|
440
|
+
/**
|
|
427
441
|
* Returns the GL.<KEY> constant that corresponds to a numeric value of a GL constant
|
|
428
442
|
* Be aware that there are some duplicates especially for constants that are 0,
|
|
429
443
|
* so this isn't guaranteed to return the right key in all cases.
|
|
430
444
|
*/
|
|
431
445
|
getGLKey(value: unknown, gl?: WebGLRenderingContext): string {
|
|
432
|
-
// @ts-ignore expect-error depends on settings
|
|
446
|
+
// @ts-ignore expect-error depends on settings
|
|
433
447
|
gl = gl || this.gl2 || this.gl;
|
|
434
448
|
const number = Number(value);
|
|
435
449
|
for (const key in gl) {
|
|
@@ -441,6 +455,38 @@ ${this.info.vendor}, ${this.info.renderer} for canvas: ${this.canvasContext.id}`
|
|
|
441
455
|
// No constant found. Stringify the value and return it.
|
|
442
456
|
return String(value);
|
|
443
457
|
}
|
|
458
|
+
|
|
459
|
+
/** Store constants */
|
|
460
|
+
_constants: (TypedArray | null)[];
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Set a constant value for a location. Disabled attributes at that location will read from this value
|
|
464
|
+
* @note WebGL constants are stored globally on the WebGL context, not the VertexArray
|
|
465
|
+
* so they need to be updated before every render
|
|
466
|
+
* @todo - remember/cache values to avoid setting them unnecessarily?
|
|
467
|
+
*/
|
|
468
|
+
setConstantAttribute(location: number, constant: TypedArray): void {
|
|
469
|
+
this._constants = this._constants || new Array(this.limits.maxVertexAttributes).fill(null);
|
|
470
|
+
const currentConstant = this._constants[location];
|
|
471
|
+
if (currentConstant && compareConstantArrayValues(currentConstant, constant)) {
|
|
472
|
+
log.info(1, `setConstantAttribute(${location}) could have been skipped, value unchanged`)();
|
|
473
|
+
}
|
|
474
|
+
this._constants[location] = constant;
|
|
475
|
+
|
|
476
|
+
switch (constant.constructor) {
|
|
477
|
+
case Float32Array:
|
|
478
|
+
setConstantFloatArray(this, location, constant as Float32Array);
|
|
479
|
+
break;
|
|
480
|
+
case Int32Array:
|
|
481
|
+
setConstantIntArray(this, location, constant as Int32Array);
|
|
482
|
+
break;
|
|
483
|
+
case Uint32Array:
|
|
484
|
+
setConstantUintArray(this, location, constant as Uint32Array);
|
|
485
|
+
break;
|
|
486
|
+
default:
|
|
487
|
+
assert(false);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
444
490
|
}
|
|
445
491
|
|
|
446
492
|
/** Check if supplied parameter is a WebGLRenderingContext */
|
|
@@ -463,3 +509,83 @@ function isWebGL2(gl: any): boolean {
|
|
|
463
509
|
// Look for debug contexts, headless gl etc
|
|
464
510
|
return Boolean(gl && gl._version === 2);
|
|
465
511
|
}
|
|
512
|
+
|
|
513
|
+
/** Set constant float array attribute */
|
|
514
|
+
function setConstantFloatArray(device: WebGLDevice, location: number, array: Float32Array): void {
|
|
515
|
+
switch (array.length) {
|
|
516
|
+
case 1:
|
|
517
|
+
device.gl.vertexAttrib1fv(location, array);
|
|
518
|
+
break;
|
|
519
|
+
case 2:
|
|
520
|
+
device.gl.vertexAttrib2fv(location, array);
|
|
521
|
+
break;
|
|
522
|
+
case 3:
|
|
523
|
+
device.gl.vertexAttrib3fv(location, array);
|
|
524
|
+
break;
|
|
525
|
+
case 4:
|
|
526
|
+
device.gl.vertexAttrib4fv(location, array);
|
|
527
|
+
break;
|
|
528
|
+
default:
|
|
529
|
+
assert(false);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/** Set constant signed int array attribute */
|
|
534
|
+
function setConstantIntArray(device: WebGLDevice, location: number, array: Int32Array): void {
|
|
535
|
+
device.assertWebGL2();
|
|
536
|
+
device.gl2?.vertexAttribI4iv(location, array);
|
|
537
|
+
// TODO - not clear if we need to use the special forms, more testing needed
|
|
538
|
+
// switch (array.length) {
|
|
539
|
+
// case 1:
|
|
540
|
+
// gl.vertexAttribI1iv(location, array);
|
|
541
|
+
// break;
|
|
542
|
+
// case 2:
|
|
543
|
+
// gl.vertexAttribI2iv(location, array);
|
|
544
|
+
// break;
|
|
545
|
+
// case 3:
|
|
546
|
+
// gl.vertexAttribI3iv(location, array);
|
|
547
|
+
// break;
|
|
548
|
+
// case 4:
|
|
549
|
+
// break;
|
|
550
|
+
// default:
|
|
551
|
+
// assert(false);
|
|
552
|
+
// }
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/** Set constant unsigned int array attribute */
|
|
556
|
+
function setConstantUintArray(device: WebGLDevice, location: number, array: Uint32Array) {
|
|
557
|
+
device.assertWebGL2();
|
|
558
|
+
device.gl2?.vertexAttribI4uiv(location, array);
|
|
559
|
+
// TODO - not clear if we need to use the special forms, more testing needed
|
|
560
|
+
// switch (array.length) {
|
|
561
|
+
// case 1:
|
|
562
|
+
// gl.vertexAttribI1uiv(location, array);
|
|
563
|
+
// break;
|
|
564
|
+
// case 2:
|
|
565
|
+
// gl.vertexAttribI2uiv(location, array);
|
|
566
|
+
// break;
|
|
567
|
+
// case 3:
|
|
568
|
+
// gl.vertexAttribI3uiv(location, array);
|
|
569
|
+
// break;
|
|
570
|
+
// case 4:
|
|
571
|
+
// gl.vertexAttribI4uiv(location, array);
|
|
572
|
+
// break;
|
|
573
|
+
// default:
|
|
574
|
+
// assert(false);
|
|
575
|
+
// }
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
*
|
|
580
|
+
*/
|
|
581
|
+
function compareConstantArrayValues(v1: TypedArray, v2: TypedArray): boolean {
|
|
582
|
+
if (!v1 || !v2 || v1.length !== v2.length || v1.constructor !== v2.constructor) {
|
|
583
|
+
return false;
|
|
584
|
+
}
|
|
585
|
+
for (let i = 0; i < v1.length; ++i) {
|
|
586
|
+
if (v1[i] !== v2[i]) {
|
|
587
|
+
return false;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
return true;
|
|
591
|
+
}
|
package/src/classic/clear.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {Device, Framebuffer, assert} from '@luma.gl/core';
|
|
2
2
|
import {WebGLDevice} from '../adapter/webgl-device';
|
|
3
|
-
import {
|
|
3
|
+
import {withGLParameters} from '../context/state-tracker/with-parameters';
|
|
4
4
|
|
|
5
5
|
// Should collapse during minification
|
|
6
6
|
const GL_DEPTH_BUFFER_BIT = 0x00000100;
|
|
@@ -57,7 +57,7 @@ export function clear(
|
|
|
57
57
|
assert(clearFlags !== 0, ERR_ARGUMENTS);
|
|
58
58
|
|
|
59
59
|
// Temporarily set any clear "colors" and call clear
|
|
60
|
-
|
|
60
|
+
withGLParameters(device.gl, parameters, () => {
|
|
61
61
|
device.gl.clear(clearFlags);
|
|
62
62
|
});
|
|
63
63
|
}
|
|
@@ -73,7 +73,7 @@ export function clearBuffer(
|
|
|
73
73
|
const device = WebGLDevice.attach(gl);
|
|
74
74
|
|
|
75
75
|
const {framebuffer = null, buffer = GL_COLOR, drawBuffer = 0, value = [0, 0, 0, 0]} = options || {};
|
|
76
|
-
|
|
76
|
+
withGLParameters(device.gl2, {framebuffer}, () => {
|
|
77
77
|
// Method selection per OpenGL ES 3 docs
|
|
78
78
|
switch (buffer) {
|
|
79
79
|
case GL_COLOR:
|
|
@@ -3,9 +3,9 @@ import {assert, Texture, Framebuffer, FramebufferProps} from '@luma.gl/core';
|
|
|
3
3
|
import {GL} from '@luma.gl/constants';
|
|
4
4
|
|
|
5
5
|
import {BufferWithAccessor as Buffer} from './buffer-with-accessor';
|
|
6
|
-
import {WEBGLTexture}
|
|
6
|
+
import {WEBGLTexture} from '../adapter/resources/webgl-texture';
|
|
7
7
|
import {WEBGLFramebuffer} from '../adapter/resources/webgl-framebuffer';
|
|
8
|
-
import {
|
|
8
|
+
import {withGLParameters} from '../context/state-tracker/with-parameters';
|
|
9
9
|
import {getGLTypeFromTypedArray, getTypedArrayFromGLType} from './typed-array-utils';
|
|
10
10
|
import {glFormatToComponents, glTypeToBytes} from './format-utils';
|
|
11
11
|
|
|
@@ -34,9 +34,13 @@ export function readPixelsToArray(
|
|
|
34
34
|
sourceType?: number;
|
|
35
35
|
}
|
|
36
36
|
): Uint8Array | Uint16Array | Float32Array {
|
|
37
|
-
const {
|
|
37
|
+
const {
|
|
38
|
+
sourceX = 0,
|
|
39
|
+
sourceY = 0,
|
|
40
|
+
sourceFormat = GL.RGBA,
|
|
41
|
+
sourceAttachment = GL.COLOR_ATTACHMENT0 // TODO - support gl.readBuffer
|
|
42
|
+
} = options || {};
|
|
38
43
|
let {
|
|
39
|
-
sourceAttachment = GL.COLOR_ATTACHMENT0, // TODO - support gl.readBuffer
|
|
40
44
|
target = null,
|
|
41
45
|
// following parameters are auto deduced if not provided
|
|
42
46
|
sourceWidth,
|
|
@@ -51,15 +55,18 @@ export function readPixelsToArray(
|
|
|
51
55
|
sourceHeight = sourceHeight || framebuffer.height;
|
|
52
56
|
|
|
53
57
|
// TODO - Set and unset gl.readBuffer
|
|
54
|
-
if (sourceAttachment === GL.COLOR_ATTACHMENT0 && handle === null) {
|
|
55
|
-
|
|
56
|
-
}
|
|
58
|
+
// if (sourceAttachment === GL.COLOR_ATTACHMENT0 && handle === null) {
|
|
59
|
+
// sourceAttachment = GL.FRONT;
|
|
60
|
+
// }
|
|
57
61
|
|
|
58
62
|
const attachment = sourceAttachment - GL.COLOR_ATTACHMENT0;
|
|
59
63
|
// assert(attachments[sourceAttachment]);
|
|
60
64
|
|
|
61
65
|
// Deduce the type from color attachment if not provided.
|
|
62
|
-
sourceType =
|
|
66
|
+
sourceType =
|
|
67
|
+
sourceType ||
|
|
68
|
+
(framebuffer.colorAttachments[attachment] as WEBGLTexture)?.type ||
|
|
69
|
+
GL.UNSIGNED_BYTE;
|
|
63
70
|
|
|
64
71
|
// Deduce type and allocated pixelArray if needed
|
|
65
72
|
target = getPixelArray(target, sourceType, sourceFormat, sourceWidth, sourceHeight);
|
|
@@ -122,7 +129,7 @@ export function readPixelsToBuffer(
|
|
|
122
129
|
}
|
|
123
130
|
|
|
124
131
|
target.bind({glTarget: GL.PIXEL_PACK_BUFFER});
|
|
125
|
-
|
|
132
|
+
withGLParameters(gl2, {framebuffer}, () => {
|
|
126
133
|
gl2.readPixels(
|
|
127
134
|
sourceX,
|
|
128
135
|
sourceY,
|
|
@@ -253,7 +260,7 @@ export function copyToTexture(
|
|
|
253
260
|
texture.unbind();
|
|
254
261
|
}
|
|
255
262
|
// @ts-expect-error
|
|
256
|
-
gl.bindFramebuffer(GL.FRAMEBUFFER, prevHandle || null);
|
|
263
|
+
device.gl.bindFramebuffer(GL.FRAMEBUFFER, prevHandle || null);
|
|
257
264
|
if (deleteFramebuffer) {
|
|
258
265
|
framebuffer.destroy();
|
|
259
266
|
}
|
|
@@ -281,11 +288,8 @@ export function toFramebuffer(texture: Texture, props?: FramebufferProps): Frame
|
|
|
281
288
|
id: `framebuffer-for-${id}`,
|
|
282
289
|
width,
|
|
283
290
|
height,
|
|
284
|
-
colorAttachments: [
|
|
285
|
-
|
|
286
|
-
]
|
|
287
|
-
}
|
|
288
|
-
);
|
|
291
|
+
colorAttachments: [texture]
|
|
292
|
+
});
|
|
289
293
|
return framebuffer;
|
|
290
294
|
}
|
|
291
295
|
|
|
@@ -69,6 +69,8 @@ export function createBrowserContext(
|
|
|
69
69
|
props = {...props, webgl2: false};
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
// props.failIfMajorPerformanceCaveat = true;
|
|
73
|
+
|
|
72
74
|
// Prefer webgl2 over webgl1 if both are acceptable
|
|
73
75
|
if (!gl && props.webgl2) {
|
|
74
76
|
gl = canvas.getContext('webgl2', props) as WebGL2RenderingContext;
|
|
@@ -77,6 +79,16 @@ export function createBrowserContext(
|
|
|
77
79
|
gl = canvas.getContext('webgl', props) as WebGLRenderingContext;
|
|
78
80
|
}
|
|
79
81
|
|
|
82
|
+
// Software GPU
|
|
83
|
+
|
|
84
|
+
// props.failIfMajorPerformanceCaveat = false;
|
|
85
|
+
// if (!gl && props.webgl2) {
|
|
86
|
+
// gl = canvas.getContext('webgl2', props);
|
|
87
|
+
// }
|
|
88
|
+
// if (!gl && props.webgl1) {
|
|
89
|
+
// gl = canvas.getContext('webgl', props);
|
|
90
|
+
// }
|
|
91
|
+
|
|
80
92
|
// TODO are we removing this listener before giving it a chance to fire?
|
|
81
93
|
canvas.removeEventListener('webglcontextcreationerror', onCreateError, false);
|
|
82
94
|
|
|
@@ -20,7 +20,7 @@ export type {GLParameters};
|
|
|
20
20
|
* @note requires a `cache` object to be set on the context (gl.state.cache)
|
|
21
21
|
* This object is used to fill in any missing values for composite setter functions
|
|
22
22
|
*/
|
|
23
|
-
export function
|
|
23
|
+
export function setGLParameters(
|
|
24
24
|
device: Device | WebGLRenderingContext,
|
|
25
25
|
parameters: GLParameters
|
|
26
26
|
): void {
|
|
@@ -88,7 +88,7 @@ export function setParameters(
|
|
|
88
88
|
* considered a very slow operation, to be used only if/when a context already manipulated
|
|
89
89
|
* by external code needs to be synchronized for the first time
|
|
90
90
|
*/
|
|
91
|
-
export function
|
|
91
|
+
export function getGLParameters(
|
|
92
92
|
device: Device | WebGLRenderingContext,
|
|
93
93
|
parameters: keyof GLParameters | (keyof GLParameters)[] | GLParameters = GL_PARAMETER_DEFAULTS
|
|
94
94
|
): GLParameters {
|
|
@@ -120,8 +120,8 @@ export function getParameters(
|
|
|
120
120
|
* NOT the canvas size dimensions, so they will have to be properly set after
|
|
121
121
|
* calling this function.
|
|
122
122
|
*/
|
|
123
|
-
export function
|
|
124
|
-
|
|
123
|
+
export function resetGLParameters(device: Device | WebGLRenderingContext): void {
|
|
124
|
+
setGLParameters(device, GL_PARAMETER_DEFAULTS);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
// Helpers
|