@luma.gl/webgl 9.0.0-alpha.26 → 9.0.0-alpha.27

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luma.gl/webgl",
3
- "version": "9.0.0-alpha.26",
3
+ "version": "9.0.0-alpha.27",
4
4
  "description": "WebGL2 adapter for the luma.gl API",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -44,12 +44,12 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@babel/runtime": "^7.0.0",
47
- "@luma.gl/api": "9.0.0-alpha.26",
48
- "@luma.gl/constants": "9.0.0-alpha.26",
47
+ "@luma.gl/api": "9.0.0-alpha.27",
48
+ "@luma.gl/constants": "9.0.0-alpha.27",
49
49
  "@probe.gl/env": "^4.0.2"
50
50
  },
51
51
  "devDependencies": {
52
- "@luma.gl/test-utils": "9.0.0-alpha.26"
52
+ "@luma.gl/test-utils": "9.0.0-alpha.27"
53
53
  },
54
- "gitHead": "e255f78c1c0a4555808c6e9282bcecb6accd147b"
54
+ "gitHead": "4052244031cb80c27fa0e3fd4c3d5514daa08b78"
55
55
  }
@@ -1,18 +1,23 @@
1
- import {assert, ResourceProps} from '@luma.gl/api';
1
+ import type {Device, Buffer, ResourceProps, TypedArray, NumericArray} from '@luma.gl/api';
2
+ import {Resource, assert, getScratchArray, fillArray} from '@luma.gl/api';
2
3
  import {GL} from '@luma.gl/constants';
3
4
  import {getBrowser} from '@probe.gl/env';
4
5
 
5
6
  import {WebGLDevice} from '../webgl-device';
6
7
  import {WebGLResource} from './webgl-resource';
7
-
8
8
  import {WEBGLBuffer} from '../resources/webgl-buffer';
9
9
 
10
+ import {BufferWithAccessor} from '../../classic/buffer-with-accessor';
11
+
10
12
  const ERR_ELEMENTS = 'elements must be GL.ELEMENT_ARRAY_BUFFER';
11
13
 
12
14
  /**
13
15
  * VertexArrayObject properties
16
+ * @param constantAttributeZero Attribute 0 can not be disable on most desktop OpenGL based browsers
17
+ * and on iOS Safari browser.
14
18
  */
15
19
  export type VertexArrayObjectProps = ResourceProps & {
20
+ constantAttributeZero?: boolean;
16
21
  };
17
22
 
18
23
  /** VertexArrayObject wrapper */
@@ -21,11 +26,26 @@ export class WEBGLVertexArrayObject extends WebGLResource<VertexArrayObjectProps
21
26
  return 'BaseVertexArrayObject';
22
27
  }
23
28
 
24
- constructor(device: WebGLDevice, props?: VertexArrayObjectProps) {
25
- // @ts-expect-error
26
- super(device, props, {});
29
+ /** Buffer constant */
30
+ private buffer: BufferWithAccessor | null = null;
31
+ private bufferValue = null;
32
+
33
+ static isConstantAttributeZeroSupported(device: Device): boolean {
34
+ return device.info.type === 'webgl2' || getBrowser() === 'Chrome';
27
35
  }
28
36
 
37
+ // Create a VertexArray
38
+ constructor(device: Device, props?: VertexArrayObjectProps) {
39
+ super(device, props, {...Resource.defaultProps, constantAttributeZero: false});
40
+ Object.seal(this);
41
+ }
42
+
43
+ override destroy(): void {
44
+ super.destroy();
45
+ if (this.buffer) {
46
+ this.buffer?.destroy();
47
+ } }
48
+
29
49
  override _createHandle() {
30
50
  return this.gl2.createVertexArray();
31
51
  }
@@ -41,6 +61,26 @@ export class WEBGLVertexArrayObject extends WebGLResource<VertexArrayObjectProps
41
61
  this.gl2.bindVertexArray(handle);
42
62
  }
43
63
 
64
+ /**
65
+ * Enabling an attribute location makes it reference the currently bound buffer
66
+ * Disabling an attribute location makes it reference the global constant value
67
+ * TODO - handle single values for size 1 attributes?
68
+ * TODO - convert classic arrays based on known type?
69
+ */
70
+ enable(location: number, enable = true): void {
71
+ // Attribute 0 cannot be disabled in most desktop OpenGL based browsers...
72
+ const canDisableAttributeZero = this.device.isWebGL2 || getBrowser() === 'Chrome';
73
+ const canDisableAttribute = canDisableAttributeZero || location !== 0;
74
+
75
+ if (enable || canDisableAttribute) {
76
+ location = Number(location);
77
+ this.bind(() =>
78
+ enable
79
+ ? this.gl.enableVertexAttribArray(location)
80
+ : this.gl.disableVertexAttribArray(location)
81
+ );
82
+ } }
83
+
44
84
  // Set (bind) an elements buffer, for indexed rendering.
45
85
  // Must be a Buffer bound to GL.ELEMENT_ARRAY_BUFFER. Constants not supported
46
86
  setElementBuffer(elementBuffer: WEBGLBuffer | null = null, opts = {}) {
@@ -50,15 +90,14 @@ export class WEBGLVertexArrayObject extends WebGLResource<VertexArrayObjectProps
50
90
  this.bind(() => {
51
91
  this.gl.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, elementBuffer ? elementBuffer.handle : null);
52
92
  });
53
-
54
- return this;
55
93
  }
56
94
 
57
95
  /** Set a location in vertex attributes array to a buffer, enables the location, sets divisor */
58
- setBuffer(location: number, buffer: WEBGLBuffer, accessor: any): this {
96
+ setBuffer(location: number, buffer: WEBGLBuffer, accessor: any): void {
59
97
  // Check target
60
98
  if (buffer.target === GL.ELEMENT_ARRAY_BUFFER) {
61
- return this.setElementBuffer(buffer, accessor);
99
+ this.setElementBuffer(buffer, accessor);
100
+ return;
62
101
  }
63
102
 
64
103
  const {size, type, stride, offset, normalized, integer, divisor} = accessor;
@@ -83,29 +122,154 @@ export class WEBGLVertexArrayObject extends WebGLResource<VertexArrayObjectProps
83
122
 
84
123
  // NOTE We don't unbind buffer here, typically another buffer will be bound just after
85
124
  });
125
+ }
86
126
 
87
- return this;
127
+ /**
128
+ * Set an attribute to a constant value
129
+ * @param device
130
+ * @param location
131
+ * @param array
132
+ *
133
+ * @note Constants are stored globally on the WebGL context, not the VAO
134
+ * so they need to be updated before every render
135
+ * @todo - use known type (in configuration or passed in) to allow non-typed arrays?
136
+ * @todo - remember/cache values to avoid setting them unnecessarily?
137
+ */
138
+ setConstant(location: any, array: TypedArray): void {
139
+ switch (array.constructor) {
140
+ case Float32Array:
141
+ setConstantFloatArray(this.device, location, array as Float32Array);
142
+ break;
143
+ case Int32Array:
144
+ setConstantIntArray(this.device, location, array as Int32Array);
145
+ break;
146
+ case Uint32Array:
147
+ setConstantUintArray(this.device, location, array as Uint32Array);
148
+ break;
149
+ default:
150
+ assert(false);
151
+ }
88
152
  }
89
153
 
90
154
  /**
91
- * Enabling an attribute location makes it reference the currently bound buffer
92
- * Disabling an attribute location makes it reference the global constant value
93
- * TODO - handle single values for size 1 attributes?
94
- * TODO - convert classic arrays based on known type?
155
+ * Provide a means to create a buffer that is equivalent to a constant.
156
+ * NOTE: Desktop OpenGL cannot disable attribute 0.
157
+ * https://stackoverflow.com/questions/20305231/webgl-warning-attribute-0-is-disabled-
158
+ * this-has-significant-performance-penalty
95
159
  */
96
- enable(location: number, enable = true): this {
97
- // Attribute 0 cannot be disabled in most desktop OpenGL based browsers...
98
- const canDisableAttributeZero = this.device.isWebGL2 || getBrowser() === 'Chrome';
99
- const canDisableAttribute = canDisableAttributeZero || location !== 0;
160
+ getConstantBuffer(elementCount: number, value): Buffer {
161
+ // Create buffer only when needed, and reuse it (avoids inflating buffer creation statistics)
100
162
 
101
- if (enable || canDisableAttribute) {
102
- location = Number(location);
103
- this.bind(() =>
104
- enable
105
- ? this.gl.enableVertexAttribArray(location)
106
- : this.gl.disableVertexAttribArray(location)
107
- );
163
+ const constantValue = normalizeConstantArrayValue(value);
164
+
165
+ const byteLength = constantValue.byteLength * elementCount;
166
+ const length = constantValue.length * elementCount;
167
+
168
+ let updateNeeded = !this.buffer;
169
+
170
+ this.buffer = this.buffer || this.device.createBuffer({byteLength}) as BufferWithAccessor;
171
+ updateNeeded = updateNeeded || this.buffer.reallocate(byteLength);
172
+
173
+ // Reallocate and update contents if needed
174
+ updateNeeded =
175
+ updateNeeded || !compareConstantArrayValues(constantValue, this.bufferValue);
176
+
177
+ if (updateNeeded) {
178
+ // Create a typed array that is big enough, and fill it with the required data
179
+ const typedArray = getScratchArray(value.constructor, length);
180
+ fillArray({target: typedArray, source: constantValue, start: 0, count: length});
181
+ this.buffer.subData(typedArray);
182
+ this.bufferValue = value;
183
+ }
184
+
185
+ return this.buffer;
186
+ }
187
+ }
188
+
189
+ function setConstantFloatArray(device: WebGLDevice, location: number, array: Float32Array): void {
190
+ switch (array.length) {
191
+ case 1:
192
+ device.gl.vertexAttrib1fv(location, array);
193
+ break;
194
+ case 2:
195
+ device.gl.vertexAttrib2fv(location, array);
196
+ break;
197
+ case 3:
198
+ device.gl.vertexAttrib3fv(location, array);
199
+ break;
200
+ case 4:
201
+ device.gl.vertexAttrib4fv(location, array);
202
+ break;
203
+ default:
204
+ assert(false);
205
+ }
206
+ }
207
+
208
+ function setConstantIntArray(device: WebGLDevice, location: number, array: Int32Array): void {
209
+ device.assertWebGL2();
210
+ device.gl2?.vertexAttribI4iv(location, array);
211
+ // switch (array.length) {
212
+ // case 1:
213
+ // gl.vertexAttribI1iv(location, array);
214
+ // break;
215
+ // case 2:
216
+ // gl.vertexAttribI2iv(location, array);
217
+ // break;
218
+ // case 3:
219
+ // gl.vertexAttribI3iv(location, array);
220
+ // break;
221
+ // case 4:
222
+ // break;
223
+ // default:
224
+ // assert(false);
225
+ // }
226
+ }
227
+
228
+ function setConstantUintArray(device: WebGLDevice, location: number, array: Uint32Array) {
229
+ device.assertWebGL2();
230
+ device.gl2?.vertexAttribI4uiv(location, array);
231
+ // switch (array.length) {
232
+ // case 1:
233
+ // gl.vertexAttribI1uiv(location, array);
234
+ // break;
235
+ // case 2:
236
+ // gl.vertexAttribI2uiv(location, array);
237
+ // break;
238
+ // case 3:
239
+ // gl.vertexAttribI3uiv(location, array);
240
+ // break;
241
+ // case 4:
242
+ // gl.vertexAttribI4uiv(location, array);
243
+ // break;
244
+ // default:
245
+ // assert(false);
246
+ // }
247
+ }
248
+
249
+ // HELPERS
250
+
251
+ /**
252
+ * TODO - convert Arrays based on known type? (read type from accessor, don't assume Float32Array)
253
+ * TODO - handle single values for size 1 attributes?
254
+ */
255
+ function normalizeConstantArrayValue(arrayValue: NumericArray) {
256
+ if (Array.isArray(arrayValue)) {
257
+ return new Float32Array(arrayValue);
258
+ }
259
+ return arrayValue;
260
+ }
261
+
262
+ /**
263
+ *
264
+ */
265
+ function compareConstantArrayValues(v1: NumericArray, v2: NumericArray): boolean {
266
+ if (!v1 || !v2 || v1.length !== v2.length || v1.constructor !== v2.constructor) {
267
+ return false;
268
+ }
269
+ for (let i = 0; i < v1.length; ++i) {
270
+ if (v1[i] !== v2[i]) {
271
+ return false;
108
272
  }
109
- return this;
110
273
  }
274
+ return true;
111
275
  }
@@ -6,7 +6,8 @@ import type {
6
6
  ShaderLayout,
7
7
  PrimitiveTopology,
8
8
  // BindingLayout,
9
- AttributeLayout
9
+ AttributeLayout,
10
+ TypedArray
10
11
  } from '@luma.gl/api';
11
12
  import {RenderPipeline, cast, log, decodeVertexFormat} from '@luma.gl/api';
12
13
  import {GL} from '@luma.gl/constants';
@@ -112,7 +113,27 @@ export class WEBGLRenderPipeline extends RenderPipeline {
112
113
  }
113
114
  }
114
115
 
115
- /** @todo needed for portable model */
116
+ /**
117
+ * Constant attributes are only supported in WebGL, not in WebGPU
118
+ * Any attribute that is disabled in the current vertex array object
119
+ * is read from the context's global constant value for that attribute location.
120
+ * @param attributes
121
+ */
122
+ setConstantAttributes(attributes: Record<string, TypedArray>): void {
123
+ for (const [name, value] of Object.entries(attributes)) {
124
+ const attribute = getAttributeLayout(this.layout, name);
125
+ if (!attribute) {
126
+ log.warn(`Ignoring constant value supplied for unknown attribute "${name}" in pipeline "${this.id}"`)();
127
+ continue; // eslint-disable-line no-continue
128
+ }
129
+ this.vertexArrayObject.setConstant(attribute.location, value);
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Bindings include: textures, samplers and uniform buffers
135
+ * @todo needed for portable model
136
+ */
116
137
  setBindings(bindings: Record<string, Binding>): void {
117
138
  // if (log.priority >= 2) {
118
139
  // checkUniformValues(uniforms, this.id, this._uniformSetters);