@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.
Files changed (73) hide show
  1. package/dist/adapter/converters/device-parameters.d.ts +9 -0
  2. package/dist/adapter/converters/device-parameters.d.ts.map +1 -1
  3. package/dist/adapter/converters/device-parameters.js +15 -2
  4. package/dist/adapter/converters/device-parameters.js.map +1 -1
  5. package/dist/adapter/resources/webgl-command-buffer.js +0 -1
  6. package/dist/adapter/resources/webgl-command-buffer.js.map +1 -1
  7. package/dist/adapter/resources/webgl-render-pass.d.ts +2 -2
  8. package/dist/adapter/resources/webgl-render-pass.d.ts.map +1 -1
  9. package/dist/adapter/resources/webgl-render-pass.js +5 -3
  10. package/dist/adapter/resources/webgl-render-pass.js.map +1 -1
  11. package/dist/adapter/resources/webgl-render-pipeline.d.ts +23 -28
  12. package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
  13. package/dist/adapter/resources/webgl-render-pipeline.js +41 -110
  14. package/dist/adapter/resources/webgl-render-pipeline.js.map +1 -1
  15. package/dist/adapter/resources/webgl-sampler.js.map +1 -1
  16. package/dist/adapter/resources/webgl-shader.js +3 -1
  17. package/dist/adapter/resources/webgl-shader.js.map +1 -1
  18. package/dist/adapter/resources/webgl-texture.js +5 -5
  19. package/dist/adapter/resources/webgl-texture.js.map +1 -1
  20. package/dist/adapter/resources/webgl-vertex-array.d.ts +67 -0
  21. package/dist/adapter/resources/webgl-vertex-array.d.ts.map +1 -0
  22. package/dist/adapter/resources/webgl-vertex-array.js +166 -0
  23. package/dist/adapter/resources/webgl-vertex-array.js.map +1 -0
  24. package/dist/adapter/webgl-device.d.ts +11 -1
  25. package/dist/adapter/webgl-device.d.ts.map +1 -1
  26. package/dist/adapter/webgl-device.js +66 -1
  27. package/dist/adapter/webgl-device.js.map +1 -1
  28. package/dist/classic/clear.js +3 -3
  29. package/dist/classic/clear.js.map +1 -1
  30. package/dist/classic/copy-and-blit.d.ts.map +1 -1
  31. package/dist/classic/copy-and-blit.js +7 -9
  32. package/dist/classic/copy-and-blit.js.map +1 -1
  33. package/dist/context/context/create-browser-context.d.ts.map +1 -1
  34. package/dist/context/context/create-browser-context.js.map +1 -1
  35. package/dist/context/parameters/unified-parameter-api.d.ts +3 -3
  36. package/dist/context/parameters/unified-parameter-api.d.ts.map +1 -1
  37. package/dist/context/parameters/unified-parameter-api.js +4 -4
  38. package/dist/context/parameters/unified-parameter-api.js.map +1 -1
  39. package/dist/context/state-tracker/track-context-state.js +3 -3
  40. package/dist/context/state-tracker/track-context-state.js.map +1 -1
  41. package/dist/context/state-tracker/with-parameters.d.ts +1 -1
  42. package/dist/context/state-tracker/with-parameters.d.ts.map +1 -1
  43. package/dist/context/state-tracker/with-parameters.js +3 -3
  44. package/dist/context/state-tracker/with-parameters.js.map +1 -1
  45. package/dist/dist.dev.js +1273 -1179
  46. package/dist/index.cjs +1026 -972
  47. package/dist/index.d.ts +5 -5
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +5 -5
  50. package/dist/index.js.map +1 -1
  51. package/dist.min.js +22 -22
  52. package/package.json +5 -5
  53. package/src/adapter/converters/device-parameters.ts +34 -2
  54. package/src/adapter/resources/webgl-command-buffer.ts +2 -2
  55. package/src/adapter/resources/webgl-render-pass.ts +8 -6
  56. package/src/adapter/resources/webgl-render-pipeline.ts +141 -174
  57. package/src/adapter/resources/webgl-sampler.ts +1 -1
  58. package/src/adapter/resources/webgl-shader.ts +1 -1
  59. package/src/adapter/resources/webgl-texture.ts +5 -5
  60. package/src/adapter/resources/webgl-vertex-array.ts +278 -0
  61. package/src/adapter/webgl-device.ts +137 -11
  62. package/src/classic/clear.ts +3 -3
  63. package/src/classic/copy-and-blit.ts +19 -15
  64. package/src/context/context/create-browser-context.ts +12 -0
  65. package/src/context/parameters/unified-parameter-api.ts +4 -4
  66. package/src/context/state-tracker/track-context-state.ts +3 -3
  67. package/src/context/state-tracker/with-parameters.ts +3 -3
  68. package/src/index.ts +38 -16
  69. package/dist/adapter/objects/webgl-vertex-array-object.d.ts +0 -55
  70. package/dist/adapter/objects/webgl-vertex-array-object.d.ts.map +0 -1
  71. package/dist/adapter/objects/webgl-vertex-array-object.js +0 -173
  72. package/dist/adapter/objects/webgl-vertex-array-object.js.map +0 -1
  73. 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 {popContextState, pushContextState, trackContextState} from '../context/state-tracker/track-context-state';
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}>((resolve) => {
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() ? createBrowserContext(this.canvasContext.canvas, {...props, onContextLost}) : null);
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() : 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
+ }
@@ -1,6 +1,6 @@
1
1
  import {Device, Framebuffer, assert} from '@luma.gl/core';
2
2
  import {WebGLDevice} from '../adapter/webgl-device';
3
- import {withParameters} from '../context/state-tracker/with-parameters';
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
- withParameters(device.gl, parameters, () => {
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
- withParameters(device.gl2, {framebuffer}, () => {
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} from '../adapter/resources/webgl-texture';
6
+ import {WEBGLTexture} from '../adapter/resources/webgl-texture';
7
7
  import {WEBGLFramebuffer} from '../adapter/resources/webgl-framebuffer';
8
- import {withParameters} from '../context/state-tracker/with-parameters';
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 {sourceX = 0, sourceY = 0, sourceFormat = GL.RGBA} = options || {};
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
- sourceAttachment = GL.FRONT;
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 = sourceType || (framebuffer.colorAttachments[attachment] as WEBGLTexture).type;
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
- withParameters(gl2, {framebuffer}, () => {
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
- texture
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 setParameters(
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 getParameters(
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 resetParameters(device: Device | WebGLRenderingContext): void {
124
- setParameters(device, GL_PARAMETER_DEFAULTS);
123
+ export function resetGLParameters(device: Device | WebGLRenderingContext): void {
124
+ setGLParameters(device, GL_PARAMETER_DEFAULTS);
125
125
  }
126
126
 
127
127
  // Helpers