@luma.gl/webgl 9.0.0-alpha.44 → 9.0.0-alpha.46

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 (56) hide show
  1. package/dist/adapter/device-helpers/device-features.js +1 -0
  2. package/dist/adapter/device-helpers/device-features.js.map +1 -1
  3. package/dist/adapter/helpers/webgl-topology-utils.d.ts +6 -1
  4. package/dist/adapter/helpers/webgl-topology-utils.d.ts.map +1 -1
  5. package/dist/adapter/helpers/webgl-topology-utils.js +40 -0
  6. package/dist/adapter/helpers/webgl-topology-utils.js.map +1 -1
  7. package/dist/adapter/resources/webgl-buffer.d.ts +1 -1
  8. package/dist/adapter/resources/webgl-buffer.d.ts.map +1 -1
  9. package/dist/adapter/resources/webgl-buffer.js +2 -0
  10. package/dist/adapter/resources/webgl-buffer.js.map +1 -1
  11. package/dist/adapter/resources/webgl-command-buffer.d.ts.map +1 -1
  12. package/dist/adapter/resources/webgl-command-buffer.js +6 -4
  13. package/dist/adapter/resources/webgl-command-buffer.js.map +1 -1
  14. package/dist/adapter/resources/webgl-render-pipeline.d.ts +2 -0
  15. package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
  16. package/dist/adapter/resources/webgl-render-pipeline.js +4 -44
  17. package/dist/adapter/resources/webgl-render-pipeline.js.map +1 -1
  18. package/dist/adapter/resources/webgl-transform-feedback.d.ts +53 -0
  19. package/dist/adapter/resources/webgl-transform-feedback.d.ts.map +1 -0
  20. package/dist/adapter/resources/webgl-transform-feedback.js +161 -0
  21. package/dist/adapter/resources/webgl-transform-feedback.js.map +1 -0
  22. package/dist/adapter/resources/webgl-vertex-array.d.ts.map +1 -1
  23. package/dist/adapter/resources/webgl-vertex-array.js +5 -3
  24. package/dist/adapter/resources/webgl-vertex-array.js.map +1 -1
  25. package/dist/adapter/webgl-device.d.ts +4 -2
  26. package/dist/adapter/webgl-device.d.ts.map +1 -1
  27. package/dist/adapter/webgl-device.js +7 -3
  28. package/dist/adapter/webgl-device.js.map +1 -1
  29. package/dist/classic/copy-and-blit.d.ts +3 -3
  30. package/dist/classic/copy-and-blit.d.ts.map +1 -1
  31. package/dist/classic/copy-and-blit.js +12 -20
  32. package/dist/classic/copy-and-blit.js.map +1 -1
  33. package/dist/dist.dev.js +2140 -2302
  34. package/dist/index.cjs +645 -806
  35. package/dist/index.d.ts +1 -2
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +1 -1
  38. package/dist/index.js.map +1 -1
  39. package/dist.min.js +23 -22
  40. package/package.json +5 -5
  41. package/src/adapter/device-helpers/device-features.ts +1 -0
  42. package/src/adapter/helpers/webgl-topology-utils.ts +40 -0
  43. package/src/adapter/resources/webgl-buffer.ts +12 -8
  44. package/src/adapter/resources/webgl-command-buffer.ts +7 -13
  45. package/src/adapter/resources/webgl-render-pipeline.ts +11 -47
  46. package/src/adapter/resources/webgl-transform-feedback.ts +205 -0
  47. package/src/adapter/resources/webgl-vertex-array.ts +11 -8
  48. package/src/adapter/webgl-device.ts +10 -5
  49. package/src/classic/copy-and-blit.ts +16 -19
  50. package/src/index.ts +5 -4
  51. package/LICENSE +0 -34
  52. package/dist/classic/buffer-with-accessor.d.ts +0 -82
  53. package/dist/classic/buffer-with-accessor.d.ts.map +0 -1
  54. package/dist/classic/buffer-with-accessor.js +0 -314
  55. package/dist/classic/buffer-with-accessor.js.map +0 -1
  56. package/src/classic/buffer-with-accessor.ts +0 -466
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luma.gl/webgl",
3
- "version": "9.0.0-alpha.44",
3
+ "version": "9.0.0-alpha.46",
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/constants": "9.0.0-alpha.44",
48
- "@luma.gl/core": "9.0.0-alpha.44",
47
+ "@luma.gl/constants": "9.0.0-alpha.46",
48
+ "@luma.gl/core": "9.0.0-alpha.46",
49
49
  "@probe.gl/env": "^4.0.2"
50
50
  },
51
51
  "devDependencies": {
52
- "@luma.gl/test-utils": "9.0.0-alpha.44"
52
+ "@luma.gl/test-utils": "9.0.0-alpha.46"
53
53
  },
54
- "gitHead": "195bed39c8587a68686cf28c0ae0e8dbd9c963f5"
54
+ "gitHead": "c1e0602fd739f8d08e6532034a02e8cf658e188a"
55
55
  }
@@ -126,6 +126,7 @@ const WEBGL_FEATURES: Partial<Record<DeviceFeature, [boolean | string, boolean |
126
126
  'webgl2': [false, true],
127
127
 
128
128
  'timer-query-webgl': ['EXT_disjoint_timer_query', 'EXT_disjoint_timer_query_webgl2'],
129
+ 'transform-feedback-webgl2': [false, true],
129
130
 
130
131
  // WEBGL1 SUPPORT
131
132
  'vertex-array-object-webgl1': ['OES_vertex_array_object', true],
@@ -2,6 +2,7 @@
2
2
  // Copyright (c) vis.gl contributors
3
3
 
4
4
  import {GL, GLPrimitiveTopology, GLPrimitive} from '@luma.gl/constants';
5
+ import {PrimitiveTopology} from '@luma.gl/core';
5
6
 
6
7
  // Counts the number of complete primitives given a number of vertices and a drawMode
7
8
  export function getPrimitiveDrawMode(drawMode: GLPrimitiveTopology): GLPrimitive {
@@ -61,3 +62,42 @@ export function getVertexCount(options: {drawMode: GLPrimitiveTopology, vertexCo
61
62
  throw new Error('drawMode');
62
63
  }
63
64
  }
65
+
66
+ /** Get the primitive type for draw */
67
+ export function getGLDrawMode(
68
+ topology: PrimitiveTopology
69
+ ):
70
+ | GL.POINTS
71
+ | GL.LINES
72
+ | GL.LINE_STRIP
73
+ | GL.LINE_LOOP
74
+ | GL.TRIANGLES
75
+ | GL.TRIANGLE_STRIP
76
+ | GL.TRIANGLE_FAN {
77
+ // prettier-ignore
78
+ switch (topology) {
79
+ case 'point-list': return GL.POINTS;
80
+ case 'line-list': return GL.LINES;
81
+ case 'line-strip': return GL.LINE_STRIP;
82
+ case 'line-loop-webgl': return GL.LINE_LOOP;
83
+ case 'triangle-list': return GL.TRIANGLES;
84
+ case 'triangle-strip': return GL.TRIANGLE_STRIP;
85
+ case 'triangle-fan-webgl': return GL.TRIANGLE_FAN;
86
+ default: throw new Error(topology);
87
+ }
88
+ }
89
+
90
+ /** Get the primitive type for transform feedback */
91
+ export function getGLPrimitive(topology: PrimitiveTopology): GL.POINTS | GL.LINES | GL.TRIANGLES {
92
+ // prettier-ignore
93
+ switch (topology) {
94
+ case 'point-list': return GL.POINTS;
95
+ case 'line-list': return GL.LINES;
96
+ case 'line-strip': return GL.LINES;
97
+ case 'line-loop-webgl': return GL.LINES;
98
+ case 'triangle-list': return GL.TRIANGLES;
99
+ case 'triangle-strip': return GL.TRIANGLES;
100
+ case 'triangle-fan-webgl': return GL.TRIANGLES;
101
+ default: throw new Error(topology);
102
+ }
103
+ }
@@ -36,7 +36,7 @@ export class WEBGLBuffer extends Buffer {
36
36
  this.gl = this.device.gl;
37
37
  this.gl2 = this.device.gl2;
38
38
 
39
- const handle = typeof props === 'object' ? (props ).handle : undefined;
39
+ const handle = typeof props === 'object' ? props.handle : undefined;
40
40
  this.handle = handle || this.gl.createBuffer();
41
41
  device.setSpectorMetadata(this.handle, {...this.props, data: typeof this.props.data});
42
42
 
@@ -45,7 +45,7 @@ export class WEBGLBuffer extends Buffer {
45
45
  // - In WebGL2, we can use GL.COPY_READ_BUFFER which avoids locking the type here
46
46
  this.glTarget = getWebGLTarget(this.props.usage);
47
47
  this.glUsage = getWebGLUsage(this.props.usage);
48
- this.glIndexType = this.props.indexType === 'uint32' ? GL.UNSIGNED_INT : GL.UNSIGNED_SHORT;
48
+ this.glIndexType = this.props.indexType === 'uint32' ? GL.UNSIGNED_INT : GL.UNSIGNED_SHORT;
49
49
 
50
50
  this.debugData = null;
51
51
 
@@ -60,7 +60,11 @@ export class WEBGLBuffer extends Buffer {
60
60
  // PRIVATE METHODS
61
61
 
62
62
  /** Allocate a new buffer and initialize to contents of typed array */
63
- _initWithData(data, byteOffset: number = 0, byteLength: number = data.byteLength + byteOffset): this {
63
+ _initWithData(
64
+ data,
65
+ byteOffset: number = 0,
66
+ byteLength: number = data.byteLength + byteOffset
67
+ ): this {
64
68
  assert(ArrayBuffer.isView(data));
65
69
 
66
70
  const glTarget = this._getWriteTarget();
@@ -135,12 +139,10 @@ export class WEBGLBuffer extends Buffer {
135
139
  }
136
140
 
137
141
  /** Read data from the buffer */
138
- override async readAsync(
139
- byteOffset: number = 0,
140
- byteLength?: number
141
- ): Promise<ArrayBuffer> {
142
+ override async readAsync(byteOffset = 0, byteLength?: number): Promise<Uint8Array> {
142
143
  this.device.assertWebGL2();
143
144
 
145
+ byteLength = byteLength ?? this.byteLength;
144
146
  const data = new Uint8Array(byteLength);
145
147
  const dstOffset = 0;
146
148
 
@@ -183,7 +185,9 @@ export class WEBGLBuffer extends Buffer {
183
185
  // static INDIRECT = 0x0100;
184
186
  // static QUERY_RESOLVE = 0x0200;
185
187
 
186
- function getWebGLTarget(usage: number): GL.ARRAY_BUFFER | GL.ELEMENT_ARRAY_BUFFER | GL.UNIFORM_BUFFER {
188
+ function getWebGLTarget(
189
+ usage: number
190
+ ): GL.ARRAY_BUFFER | GL.ELEMENT_ARRAY_BUFFER | GL.UNIFORM_BUFFER {
187
191
  if (usage & Buffer.INDEX) {
188
192
  return GL.ELEMENT_ARRAY_BUFFER;
189
193
  }
@@ -7,19 +7,14 @@ import type {
7
7
  CopyTextureToBufferOptions,
8
8
  CopyTextureToTextureOptions
9
9
  } from '@luma.gl/core';
10
- import {
11
- CommandBuffer,
12
- Texture,
13
- // Buffer,
14
- Framebuffer
15
- } from '@luma.gl/core';
10
+ import {CommandBuffer, Texture, Framebuffer} from '@luma.gl/core';
16
11
  import {GL} from '@luma.gl/constants';
17
12
 
18
- // import {getTypedArrayFromGLType, getGLTypeFromTypedArray} from '../../classic/typed-array-utils';
19
13
  import {WebGLDevice} from '../webgl-device';
20
14
  import {WEBGLBuffer} from './webgl-buffer';
21
15
  import {WEBGLTexture} from './webgl-texture';
22
16
  import {WEBGLFramebuffer} from './webgl-framebuffer';
17
+ import {getWebGLTextureParameters} from '../converters/texture-formats';
23
18
 
24
19
  function cast<T>(value: unknown): T {
25
20
  return value as T;
@@ -56,7 +51,7 @@ export class WEBGLCommandBuffer extends CommandBuffer {
56
51
  commands: Command[] = [];
57
52
 
58
53
  constructor(device: WebGLDevice) {
59
- super({});
54
+ super(device, {});
60
55
  this.device = device;
61
56
  }
62
57
 
@@ -158,7 +153,7 @@ function _copyTextureToBuffer(device: WebGLDevice, options: CopyTextureToBufferO
158
153
  }
159
154
 
160
155
  // TODO - mipLevels are set when attaching texture to framebuffer
161
- if (mipLevel !== 0 || depthOrArrayLayers !== undefined || bytesPerRow || rowsPerImage) {
156
+ if (mipLevel !== 0 || depthOrArrayLayers !== 0 || bytesPerRow || rowsPerImage) {
162
157
  throw new Error('not implemented');
163
158
  }
164
159
 
@@ -170,10 +165,9 @@ function _copyTextureToBuffer(device: WebGLDevice, options: CopyTextureToBufferO
170
165
  const webglBuffer = destination as WEBGLBuffer;
171
166
  const sourceWidth = width || framebuffer.width;
172
167
  const sourceHeight = height || framebuffer.height;
173
-
174
- // TODO - hack - should be deduced
175
- const sourceFormat = GL.RGBA;
176
- const sourceType = GL.UNSIGNED_BYTE;
168
+ const sourceParams = getWebGLTextureParameters(framebuffer.texture.format, true);
169
+ const sourceFormat = sourceParams.dataFormat;
170
+ const sourceType = sourceParams.type;
177
171
 
178
172
  // if (!target) {
179
173
  // // Create new buffer with enough size
@@ -2,7 +2,7 @@
2
2
  // Copyright (c) vis.gl contributors
3
3
 
4
4
  import type {UniformValue, RenderPipelineProps, Binding} from '@luma.gl/core';
5
- import type {ShaderLayout, PrimitiveTopology} from '@luma.gl/core';
5
+ import type {ShaderLayout} from '@luma.gl/core';
6
6
  import type {RenderPass, VertexArray} from '@luma.gl/core';
7
7
  import {RenderPipeline, cast, splitUniformsAndBindings, log} from '@luma.gl/core';
8
8
  import {mergeShaderLayout} from '@luma.gl/core';
@@ -21,6 +21,8 @@ import {WEBGLFramebuffer} from './webgl-framebuffer';
21
21
  import {WEBGLTexture} from './webgl-texture';
22
22
  // import {WEBGLVertexArray} from './webgl-vertex-array';
23
23
  import {WEBGLRenderPass} from './webgl-render-pass';
24
+ import {WEBGLTransformFeedback} from './webgl-transform-feedback';
25
+ import {getGLDrawMode} from '../helpers/webgl-topology-utils';
24
26
 
25
27
  const LOG_PROGRAM_PERF_PRIORITY = 4;
26
28
 
@@ -133,7 +135,7 @@ export class WEBGLRenderPipeline extends RenderPipeline {
133
135
  // This convention allows shaders to name uniform blocks as `uniform appUniforms {} app;`
134
136
  // and reference them as `app` from both GLSL and JS.
135
137
  // TODO - this is rather hacky - we could also remap the name directly in the shader layout.
136
- const binding =
138
+ const binding =
137
139
  this.shaderLayout.bindings.find(binding => binding.name === name) ||
138
140
  this.shaderLayout.bindings.find(binding => binding.name === `${name}Uniforms`);
139
141
 
@@ -198,6 +200,7 @@ export class WEBGLRenderPipeline extends RenderPipeline {
198
200
  firstIndex?: number;
199
201
  firstInstance?: number;
200
202
  baseVertex?: number;
203
+ transformFeedback?: WEBGLTransformFeedback;
201
204
  }): boolean {
202
205
  const {
203
206
  renderPass,
@@ -205,10 +208,11 @@ export class WEBGLRenderPipeline extends RenderPipeline {
205
208
  vertexCount,
206
209
  // indexCount,
207
210
  instanceCount,
208
- firstVertex = 0
211
+ firstVertex = 0,
209
212
  // firstIndex,
210
213
  // firstInstance,
211
- // baseVertex
214
+ // baseVertex,
215
+ transformFeedback
212
216
  } = options;
213
217
 
214
218
  const glDrawMode = getGLDrawMode(this.props.topology);
@@ -230,10 +234,8 @@ export class WEBGLRenderPipeline extends RenderPipeline {
230
234
  // Note: Rebinds constant attributes before each draw call
231
235
  vertexArray.bindBeforeRender(renderPass);
232
236
 
233
- const primitiveMode = getGLPrimitive(this.props.topology);
234
- const transformFeedback: any = null;
235
237
  if (transformFeedback) {
236
- transformFeedback.begin(primitiveMode);
238
+ transformFeedback.begin(this.props.topology);
237
239
  }
238
240
 
239
241
  // We have to apply bindings before every draw call since other draw calls will overwrite
@@ -391,7 +393,8 @@ export class WEBGLRenderPipeline extends RenderPipeline {
391
393
  let uniformBufferIndex = 0;
392
394
  for (const binding of this.shaderLayout.bindings) {
393
395
  // Accept both `xyz` and `xyzUniforms` as valid names for `xyzUniforms` uniform block
394
- const value = this.bindings[binding.name] || this.bindings[binding.name.replace(/Uniforms$/, '')];
396
+ const value =
397
+ this.bindings[binding.name] || this.bindings[binding.name.replace(/Uniforms$/, '')];
395
398
  if (!value) {
396
399
  throw new Error(`No value for binding ${binding.name} in ${this.id}`);
397
400
  }
@@ -472,42 +475,3 @@ export class WEBGLRenderPipeline extends RenderPipeline {
472
475
  }
473
476
  }
474
477
  }
475
-
476
- /** Get the primitive type for draw */
477
- function getGLDrawMode(
478
- topology: PrimitiveTopology
479
- ):
480
- | GL.POINTS
481
- | GL.LINES
482
- | GL.LINE_STRIP
483
- | GL.LINE_LOOP
484
- | GL.TRIANGLES
485
- | GL.TRIANGLE_STRIP
486
- | GL.TRIANGLE_FAN {
487
- // prettier-ignore
488
- switch (topology) {
489
- case 'point-list': return GL.POINTS;
490
- case 'line-list': return GL.LINES;
491
- case 'line-strip': return GL.LINE_STRIP;
492
- case 'line-loop-webgl': return GL.LINE_LOOP;
493
- case 'triangle-list': return GL.TRIANGLES;
494
- case 'triangle-strip': return GL.TRIANGLE_STRIP;
495
- case 'triangle-fan-webgl': return GL.TRIANGLE_FAN;
496
- default: throw new Error(topology);
497
- }
498
- }
499
-
500
- /** Get the primitive type for transform feedback */
501
- function getGLPrimitive(topology: PrimitiveTopology): GL.POINTS | GL.LINES | GL.TRIANGLES {
502
- // prettier-ignore
503
- switch (topology) {
504
- case 'point-list': return GL.POINTS;
505
- case 'line-list': return GL.LINES;
506
- case 'line-strip': return GL.LINES;
507
- case 'line-loop-webgl': return GL.LINES;
508
- case 'triangle-list': return GL.TRIANGLES;
509
- case 'triangle-strip': return GL.TRIANGLES;
510
- case 'triangle-fan-webgl': return GL.TRIANGLES;
511
- default: throw new Error(topology);
512
- }
513
- }
@@ -0,0 +1,205 @@
1
+ import type {PrimitiveTopology, ShaderLayout, TransformFeedbackProps} from '@luma.gl/core';
2
+ import {log, TransformFeedback, Buffer} from '@luma.gl/core';
3
+ import {GL} from '@luma.gl/constants';
4
+ import {WebGLDevice} from '../webgl-device';
5
+ import {WEBGLBuffer} from '../..';
6
+ import {getGLPrimitive} from '../helpers/webgl-topology-utils';
7
+
8
+ /** For bindRange */
9
+ type BufferRange = {
10
+ buffer: Buffer;
11
+ byteOffset?: number;
12
+ byteLength?: number;
13
+ };
14
+
15
+ export class WEBGLTransformFeedback extends TransformFeedback {
16
+ readonly device: WebGLDevice;
17
+ readonly gl2: WebGL2RenderingContext;
18
+ readonly handle: WebGLTransformFeedback;
19
+
20
+ /**
21
+ * NOTE: The Model already has this information while drawing, but
22
+ * TransformFeedback currently needs it internally, to look up
23
+ * varying information outside of a draw() call.
24
+ */
25
+ readonly layout: ShaderLayout;
26
+ buffers: Record<string, BufferRange> = {};
27
+ unusedBuffers: Record<string, Buffer> = {};
28
+ /**
29
+ * Allows us to avoid a Chrome bug where a buffer that is already bound to a
30
+ * different target cannot be bound to 'TRANSFORM_FEEDBACK_BUFFER' target.
31
+ * This a major workaround, see: https://github.com/KhronosGroup/WebGL/issues/2346
32
+ */
33
+ bindOnUse = true;
34
+ private _bound: boolean = false;
35
+
36
+ constructor(device: WebGLDevice, props: TransformFeedbackProps) {
37
+ super(device, props);
38
+
39
+ device.assertWebGL2();
40
+ this.device = device;
41
+ this.gl2 = device.gl2;
42
+ this.handle = this.props.handle || this.gl2.createTransformFeedback();
43
+ this.layout = this.props.layout;
44
+
45
+ if (props.buffers) {
46
+ this.setBuffers(props.buffers);
47
+ }
48
+
49
+ Object.seal(this);
50
+ }
51
+
52
+ override destroy(): void {
53
+ this.gl2.deleteTransformFeedback(this.handle);
54
+ super.destroy();
55
+ }
56
+
57
+ begin(topology: PrimitiveTopology = 'point-list'): void {
58
+ this.gl2.bindTransformFeedback(GL.TRANSFORM_FEEDBACK, this.handle);
59
+ if (this.bindOnUse) {
60
+ this._bindBuffers();
61
+ }
62
+ this.gl2.beginTransformFeedback(getGLPrimitive(topology));
63
+ }
64
+
65
+ end(): void {
66
+ this.gl2.endTransformFeedback();
67
+ if (!this.bindOnUse) {
68
+ this._unbindBuffers();
69
+ }
70
+ this.gl2.bindTransformFeedback(GL.TRANSFORM_FEEDBACK, null);
71
+ }
72
+
73
+ // SUBCLASS
74
+
75
+ setBuffers(buffers: Record<string, Buffer | BufferRange>) {
76
+ this.buffers = {};
77
+ this.unusedBuffers = {};
78
+
79
+ this.bind(() => {
80
+ for (const bufferName in buffers) {
81
+ this.setBuffer(bufferName, buffers[bufferName]);
82
+ }
83
+ });
84
+ return this;
85
+ }
86
+
87
+ setBuffer(locationOrName: string | number, bufferOrRange: Buffer | BufferRange) {
88
+ const location = this._getVaryingIndex(locationOrName);
89
+ const {buffer, byteLength, byteOffset} = this._getBufferRange(bufferOrRange);
90
+
91
+ if (location < 0) {
92
+ this.unusedBuffers[locationOrName] = buffer;
93
+ log.warn(`${this.id} unusedBuffers varying buffer ${locationOrName}`)();
94
+ return this;
95
+ }
96
+
97
+ this.buffers[location] = {buffer, byteLength, byteOffset};
98
+
99
+ // Need to avoid chrome bug where buffer that is already bound to a different target
100
+ // cannot be bound to 'TRANSFORM_FEEDBACK_BUFFER' target.
101
+ if (!this.bindOnUse) {
102
+ this._bindBuffer(location, buffer, byteOffset, byteLength);
103
+ }
104
+
105
+ return this;
106
+ }
107
+
108
+ bind(funcOrHandle = this.handle) {
109
+ if (typeof funcOrHandle !== 'function') {
110
+ this.gl2.bindTransformFeedback(GL.TRANSFORM_FEEDBACK, funcOrHandle);
111
+ return this;
112
+ }
113
+
114
+ let value: unknown;
115
+
116
+ if (!this._bound) {
117
+ this.gl2.bindTransformFeedback(GL.TRANSFORM_FEEDBACK, this.handle);
118
+ this._bound = true;
119
+ value = funcOrHandle();
120
+ this._bound = false;
121
+ this.gl2.bindTransformFeedback(GL.TRANSFORM_FEEDBACK, null);
122
+ } else {
123
+ value = funcOrHandle();
124
+ }
125
+
126
+ return value;
127
+ }
128
+
129
+ unbind() {
130
+ this.bind(null);
131
+ }
132
+
133
+ // PRIVATE METHODS
134
+
135
+ /** Extract offsets for bindBufferRange */
136
+ protected _getBufferRange(
137
+ bufferOrRange: Buffer | {buffer: Buffer; byteOffset?: number; byteLength?: number}
138
+ ): Required<BufferRange> {
139
+ if (bufferOrRange instanceof WEBGLBuffer) {
140
+ return {buffer: bufferOrRange, byteOffset: 0, byteLength: bufferOrRange.byteLength};
141
+ }
142
+
143
+ // To use bindBufferRange either offset or size must be specified.
144
+ // @ts-expect-error Must be a BufferRange.
145
+ const {buffer, byteOffset = 0, byteLength = bufferOrRange.buffer.byteLength} = bufferOrRange;
146
+ return {buffer, byteOffset, byteLength};
147
+ }
148
+
149
+ protected _getVaryingIndex(locationOrName: string | number) {
150
+ if (isIndex(locationOrName)) {
151
+ return Number(locationOrName);
152
+ }
153
+
154
+ for (const varying of this.layout.varyings) {
155
+ if (locationOrName === varying.name) {
156
+ return varying.location;
157
+ }
158
+ }
159
+
160
+ return -1;
161
+ }
162
+
163
+ /**
164
+ * Need to avoid chrome bug where buffer that is already bound to a different target
165
+ * cannot be bound to 'TRANSFORM_FEEDBACK_BUFFER' target.
166
+ */
167
+ protected _bindBuffers(): void {
168
+ for (const bufferIndex in this.buffers) {
169
+ const {buffer, byteLength, byteOffset} = this._getBufferRange(this.buffers[bufferIndex]);
170
+ this._bindBuffer(Number(bufferIndex), buffer, byteOffset, byteLength);
171
+ }
172
+ }
173
+
174
+ protected _unbindBuffers(): void {
175
+ for (const bufferIndex in this.buffers) {
176
+ this.gl2.bindBufferBase(GL.TRANSFORM_FEEDBACK_BUFFER, Number(bufferIndex), null);
177
+ }
178
+ }
179
+
180
+ protected _bindBuffer(
181
+ index: number,
182
+ buffer: Buffer,
183
+ byteOffset = 0,
184
+ byteLength?: number
185
+ ): this {
186
+ const handle = buffer && (buffer as WEBGLBuffer).handle;
187
+ if (!handle || byteLength === undefined) {
188
+ this.gl2.bindBufferBase(GL.TRANSFORM_FEEDBACK_BUFFER, index, handle);
189
+ } else {
190
+ this.gl2.bindBufferRange(GL.TRANSFORM_FEEDBACK_BUFFER, index, handle, byteOffset, byteLength);
191
+ }
192
+ return this;
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Returns true if the given value is an integer, or a string that
198
+ * trivially converts to an integer (only numeric characters).
199
+ */
200
+ function isIndex(value: string | number): boolean {
201
+ if (typeof value === 'number') {
202
+ return Number.isInteger(value);
203
+ }
204
+ return /^\d+$/.test(value);
205
+ }
@@ -9,7 +9,6 @@ import {getBrowser} from '@probe.gl/env';
9
9
  import {WebGLDevice} from '../webgl-device';
10
10
  import {WEBGLBuffer} from '../resources/webgl-buffer';
11
11
 
12
- import {BufferWithAccessor} from '../../classic/buffer-with-accessor';
13
12
  import {getGLFromVertexType} from '../converters/vertex-formats';
14
13
  // import {AccessorObject} from '../..';
15
14
  // import {getGLFromVertexType} from '../converters/vertex-formats';
@@ -24,7 +23,7 @@ export class WEBGLVertexArray extends VertexArray {
24
23
  readonly handle: WebGLVertexArrayObject;
25
24
 
26
25
  /** Attribute 0 buffer constant */
27
- private buffer: BufferWithAccessor | null = null;
26
+ private buffer: WEBGLBuffer | null = null;
28
27
  private bufferValue = null;
29
28
 
30
29
  /** * Attribute 0 can not be disable on most desktop OpenGL based browsers */
@@ -62,7 +61,7 @@ export class WEBGLVertexArray extends VertexArray {
62
61
  */
63
62
  setIndexBuffer(indexBuffer: Buffer | null): void {
64
63
  const buffer = indexBuffer as WEBGLBuffer;
65
- if (buffer && (buffer.glTarget !== GL.ELEMENT_ARRAY_BUFFER)) {
64
+ if (buffer?.glTarget !== GL.ELEMENT_ARRAY_BUFFER) {
66
65
  throw new Error('Use .setBuffer()');
67
66
  }
68
67
  // In WebGL The GL.ELEMENT_ARRAY_BUFFER_BINDING is stored on the VertexArrayObject
@@ -116,7 +115,7 @@ export class WEBGLVertexArray extends VertexArray {
116
115
 
117
116
  override bindBeforeRender(): void {
118
117
  this.device.gl2.bindVertexArray(this.handle);
119
- // TODO - the initial bind does not seem to take effect.
118
+ // TODO - the initial bind does not seem to take effect.
120
119
  if (!this.init) {
121
120
  // log.log(1, `Binding vertex array ${this.id}`, this.indexBuffer?.id)();
122
121
  const webglBuffer = this.indexBuffer as WEBGLBuffer;
@@ -128,7 +127,7 @@ export class WEBGLVertexArray extends VertexArray {
128
127
 
129
128
  override unbindAfterRender(): void {
130
129
  // log.log(1, `Unbinding vertex array ${this.id}`)();
131
- // TODO technically this is not necessary, but we might be interfacing
130
+ // TODO technically this is not necessary, but we might be interfacing
132
131
  // with code that does not use vertex array objects
133
132
  this.device.gl2.bindVertexArray(null);
134
133
  // this.device.gl2.bindBuffer(GL.ELEMENT_ARRAY_BUFFER, null);
@@ -230,10 +229,14 @@ export class WEBGLVertexArray extends VertexArray {
230
229
  const byteLength = constantValue.byteLength * elementCount;
231
230
  const length = constantValue.length * elementCount;
232
231
 
232
+ if (this.buffer && byteLength !== this.buffer.byteLength) {
233
+ throw new Error(
234
+ `Buffer size is immutable, byte length ${byteLength} !== ${this.buffer.byteLength}.`
235
+ );
236
+ }
233
237
  let updateNeeded = !this.buffer;
234
238
 
235
- this.buffer = this.buffer || (this.device.createBuffer({byteLength}) as BufferWithAccessor);
236
- updateNeeded = updateNeeded || this.buffer.reallocate(byteLength);
239
+ this.buffer = this.buffer || this.device.createBuffer({byteLength});
237
240
 
238
241
  // Reallocate and update contents if needed
239
242
  updateNeeded = updateNeeded || !compareConstantArrayValues(constantValue, this.bufferValue);
@@ -242,7 +245,7 @@ export class WEBGLVertexArray extends VertexArray {
242
245
  // Create a typed array that is big enough, and fill it with the required data
243
246
  const typedArray = getScratchArray(value.constructor, length);
244
247
  fillArray({target: typedArray, source: constantValue, start: 0, count: length});
245
- this.buffer.subData(typedArray);
248
+ this.buffer.write(typedArray);
246
249
  this.bufferValue = value;
247
250
  }
248
251
 
@@ -56,10 +56,10 @@ import type {
56
56
  ComputePass,
57
57
  ComputePassProps,
58
58
  // CommandEncoder,
59
- CommandEncoderProps
59
+ CommandEncoderProps,
60
+ TransformFeedbackProps
60
61
  } from '@luma.gl/core';
61
62
 
62
- import {BufferWithAccessor} from '../classic/buffer-with-accessor';
63
63
  import {WEBGLBuffer} from './resources/webgl-buffer';
64
64
  import {WEBGLShader} from './resources/webgl-shader';
65
65
  import {WEBGLSampler} from './resources/webgl-sampler';
@@ -69,6 +69,7 @@ import {WEBGLRenderPass} from './resources/webgl-render-pass';
69
69
  import {WEBGLRenderPipeline} from './resources/webgl-render-pipeline';
70
70
  import {WEBGLCommandEncoder} from './resources/webgl-command-encoder';
71
71
  import {WEBGLVertexArray} from './resources/webgl-vertex-array';
72
+ import {WEBGLTransformFeedback} from './resources/webgl-transform-feedback';
72
73
 
73
74
  const LOG_LEVEL = 1;
74
75
 
@@ -298,7 +299,7 @@ ${this.info.vendor}, ${this.info.renderer} for canvas: ${this.canvasContext.id}`
298
299
 
299
300
  createBuffer(props: BufferProps | ArrayBuffer | ArrayBufferView): WEBGLBuffer {
300
301
  const newProps = this._getBufferProps(props);
301
- return new BufferWithAccessor(this, newProps);
302
+ return new WEBGLBuffer(this, newProps);
302
303
  }
303
304
 
304
305
  _createTexture(props: TextureProps): WEBGLTexture {
@@ -338,7 +339,11 @@ ${this.info.vendor}, ${this.info.renderer} for canvas: ${this.canvasContext.id}`
338
339
  }
339
340
 
340
341
  beginComputePass(props: ComputePassProps): ComputePass {
341
- throw new Error('compute shaders not supported in WebGL');
342
+ throw new Error('ComputePass not supported in WebGL');
343
+ }
344
+
345
+ createTransformFeedback(props: TransformFeedbackProps): WEBGLTransformFeedback {
346
+ return new WEBGLTransformFeedback(this, props);
342
347
  }
343
348
 
344
349
  private renderPass: WEBGLRenderPass | null = null;
@@ -352,7 +357,7 @@ ${this.info.vendor}, ${this.info.renderer} for canvas: ${this.canvasContext.id}`
352
357
  return this.renderPass;
353
358
  }
354
359
 
355
- override createCommandEncoder(props: CommandEncoderProps): WEBGLCommandEncoder {
360
+ override createCommandEncoder(props?: CommandEncoderProps): WEBGLCommandEncoder {
356
361
  return new WEBGLCommandEncoder(this, props);
357
362
  }
358
363