@luma.gl/webgl 9.0.0-alpha.27 → 9.0.0-alpha.29
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/helpers/get-shader-layout.d.ts +8 -5
- package/dist/adapter/helpers/get-shader-layout.d.ts.map +1 -1
- package/dist/adapter/helpers/get-shader-layout.js +59 -16
- package/dist/adapter/helpers/get-shader-layout.js.map +1 -1
- package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts +12 -0
- package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts.map +1 -0
- package/dist/adapter/helpers/get-vertex-buffer-layout.js +84 -0
- package/dist/adapter/helpers/get-vertex-buffer-layout.js.map +1 -0
- package/dist/adapter/objects/webgl-vertex-array-object.js +2 -2
- package/dist/adapter/objects/webgl-vertex-array-object.js.map +1 -1
- package/dist/adapter/resources/webgl-buffer.d.ts +13 -4
- package/dist/adapter/resources/webgl-buffer.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-buffer.js +23 -21
- package/dist/adapter/resources/webgl-buffer.js.map +1 -1
- package/dist/adapter/resources/webgl-external-texture.js.map +1 -1
- package/dist/adapter/resources/webgl-render-pipeline.d.ts +27 -4
- package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-render-pipeline.js +25 -7
- package/dist/adapter/resources/webgl-render-pipeline.js.map +1 -1
- package/dist/adapter/webgl-device.d.ts.map +1 -1
- package/dist/adapter/webgl-device.js +5 -2
- package/dist/adapter/webgl-device.js.map +1 -1
- package/dist/classic/buffer-with-accessor.d.ts +5 -15
- package/dist/classic/buffer-with-accessor.d.ts.map +1 -1
- package/dist/classic/buffer-with-accessor.js +25 -30
- package/dist/classic/buffer-with-accessor.js.map +1 -1
- package/dist/classic/copy-and-blit.d.ts.map +1 -1
- package/dist/classic/copy-and-blit.js +2 -2
- package/dist/classic/copy-and-blit.js.map +1 -1
- package/dist/context/debug/webgl-developer-tools.d.ts.map +1 -1
- package/dist/context/debug/webgl-developer-tools.js +2 -1
- package/dist/context/debug/webgl-developer-tools.js.map +1 -1
- package/dist/context/parameters/webgl-parameter-tables.js +2 -2
- package/dist/context/parameters/webgl-parameter-tables.js.map +1 -1
- package/dist/dist.dev.js +164 -83
- package/dist/index.cjs +207 -146
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist.min.js +22 -22
- package/package.json +5 -5
- package/src/adapter/helpers/get-shader-layout.ts +93 -33
- package/src/adapter/helpers/get-vertex-buffer-layout.ts +123 -0
- package/src/adapter/objects/webgl-vertex-array-object.ts +2 -2
- package/src/adapter/resources/webgl-buffer.ts +40 -41
- package/src/adapter/resources/webgl-external-texture.ts +1 -1
- package/src/adapter/resources/webgl-render-pipeline.ts +51 -35
- package/src/adapter/webgl-device.ts +4 -2
- package/src/classic/buffer-with-accessor.ts +42 -43
- package/src/classic/copy-and-blit.ts +2 -3
- package/src/context/debug/webgl-developer-tools.ts +8 -2
- package/src/context/parameters/webgl-parameter-tables.ts +2 -2
- package/src/index.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@luma.gl/webgl",
|
|
3
|
-
"version": "9.0.0-alpha.
|
|
3
|
+
"version": "9.0.0-alpha.29",
|
|
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.
|
|
48
|
-
"@luma.gl/constants": "9.0.0-alpha.
|
|
47
|
+
"@luma.gl/api": "9.0.0-alpha.29",
|
|
48
|
+
"@luma.gl/constants": "9.0.0-alpha.29",
|
|
49
49
|
"@probe.gl/env": "^4.0.2"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@luma.gl/test-utils": "9.0.0-alpha.
|
|
52
|
+
"@luma.gl/test-utils": "9.0.0-alpha.29"
|
|
53
53
|
},
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "1aee1ad82fd09d441172f5ef490ebc083a7fa239"
|
|
55
55
|
}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
// luma.gl, MIT license
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import type {
|
|
4
4
|
ShaderLayout,
|
|
5
|
-
|
|
5
|
+
AttributeLayout,
|
|
6
6
|
UniformBinding,
|
|
7
7
|
UniformBlockBinding,
|
|
8
|
-
ProgramBindings,
|
|
9
8
|
AttributeBinding,
|
|
10
9
|
VaryingBinding,
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
AccessorObject,
|
|
11
|
+
BufferMapping,
|
|
12
|
+
VertexFormat
|
|
13
13
|
} from '@luma.gl/api';
|
|
14
|
+
import {log} from '@luma.gl/api';
|
|
14
15
|
import {GL} from '@luma.gl/constants';
|
|
15
16
|
import {isWebGL2} from '../../context/context/webgl-checks';
|
|
16
17
|
import {Accessor} from '../../classic/accessor'; // TODO - should NOT depend on classic API
|
|
@@ -24,14 +25,13 @@ import {isSamplerUniform} from './uniforms';
|
|
|
24
25
|
* (although linking does not need to have been successful).
|
|
25
26
|
*/
|
|
26
27
|
export function getShaderLayout(gl: WebGLRenderingContext, program: WebGLProgram): ShaderLayout {
|
|
27
|
-
const programBindings = getProgramBindings(gl, program);
|
|
28
|
-
|
|
29
28
|
const shaderLayout: ShaderLayout = {
|
|
30
29
|
attributes: [],
|
|
31
30
|
bindings: []
|
|
32
31
|
};
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
const attributes: AttributeBinding[] = readAttributeBindings(gl, program);
|
|
34
|
+
for (const attribute of attributes) {
|
|
35
35
|
// TODO - multicolumn attributes like a matrix4 can be up to 16 elts...
|
|
36
36
|
const size = Math.min(attribute.accessor.size, 4);
|
|
37
37
|
const format =
|
|
@@ -46,8 +46,9 @@ export function getShaderLayout(gl: WebGLRenderingContext, program: WebGLProgram
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
// Uniform blocks
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
const uniformBlocks: UniformBlockBinding[] = readUniformBlocks(gl, program);
|
|
50
|
+
for (const uniformBlock of uniformBlocks) {
|
|
51
|
+
const uniforms = uniformBlock.uniforms.map(uniform => ({
|
|
51
52
|
name: uniform.name,
|
|
52
53
|
format: uniform.format,
|
|
53
54
|
byteOffset: uniform.byteOffset,
|
|
@@ -64,8 +65,9 @@ export function getShaderLayout(gl: WebGLRenderingContext, program: WebGLProgram
|
|
|
64
65
|
});
|
|
65
66
|
}
|
|
66
67
|
|
|
68
|
+
const uniforms: UniformBinding[] = readUniformBindings(gl, program);
|
|
67
69
|
let textureUnit = 0;
|
|
68
|
-
for (const uniform of
|
|
70
|
+
for (const uniform of uniforms) {
|
|
69
71
|
if (isSamplerUniform(uniform.type)) {
|
|
70
72
|
const {viewDimension, sampleType} = getSamplerInfo(uniform.type);
|
|
71
73
|
shaderLayout.bindings.push({
|
|
@@ -82,38 +84,95 @@ export function getShaderLayout(gl: WebGLRenderingContext, program: WebGLProgram
|
|
|
82
84
|
}
|
|
83
85
|
}
|
|
84
86
|
|
|
85
|
-
const uniforms = programBindings.uniforms?.filter((uniform) => uniform.location !== null) || [];
|
|
86
87
|
if (uniforms.length) {
|
|
87
88
|
shaderLayout.uniforms = uniforms;
|
|
88
89
|
}
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
|
|
91
|
+
// Varyings
|
|
92
|
+
const varyings: VaryingBinding[] = readVaryings(gl, program);
|
|
93
|
+
// Note - samplers are always in unform bindings, even if uniform blocks are used
|
|
94
|
+
if (varyings?.length) {
|
|
95
|
+
shaderLayout.varyings = varyings;
|
|
91
96
|
}
|
|
92
97
|
|
|
93
98
|
return shaderLayout;
|
|
94
99
|
}
|
|
95
100
|
|
|
96
101
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
102
|
+
* Merges an provided shader layout into a base shader layout
|
|
103
|
+
* In WebGL, this allows the auto generated shader layout to be overridden by the application
|
|
104
|
+
* Typically to change the format of the vertex attributes (from float32x4 to uint8x4 etc).
|
|
105
|
+
* @todo Drop this? This could also be done more clearly with bufferMapping
|
|
100
106
|
*/
|
|
101
|
-
export function
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
):
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
export function mergeShaderLayout(
|
|
108
|
+
baseLayout: ShaderLayout,
|
|
109
|
+
overrideLayout: ShaderLayout
|
|
110
|
+
): ShaderLayout {
|
|
111
|
+
// Deep clone the base layout
|
|
112
|
+
const mergedLayout: ShaderLayout = {
|
|
113
|
+
...baseLayout,
|
|
114
|
+
attributes: baseLayout.attributes.map(attribute => ({...attribute}))
|
|
115
|
+
};
|
|
116
|
+
// Merge the attributes
|
|
117
|
+
for (const attribute of overrideLayout?.attributes || []) {
|
|
118
|
+
const baseAttribute = mergedLayout.attributes.find(attr => attr.name === attribute.name);
|
|
119
|
+
if (!baseAttribute) {
|
|
120
|
+
log.warn(`shader layout attribute ${attribute.name} not present in shader`);
|
|
121
|
+
} else {
|
|
122
|
+
baseAttribute.format = attribute.format || baseAttribute.format;
|
|
123
|
+
baseAttribute.stepMode = attribute.stepMode || baseAttribute.stepMode;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return mergedLayout;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function mergeBufferMap(baseLayout: ShaderLayout, bufferMap: BufferMapping[]): ShaderLayout {
|
|
130
|
+
// Deep clone the base layout
|
|
131
|
+
const mergedLayout: ShaderLayout = {
|
|
132
|
+
...baseLayout,
|
|
133
|
+
attributes: baseLayout.attributes.map(attribute => ({...attribute}))
|
|
110
134
|
};
|
|
135
|
+
for (const bufferMapping of bufferMap) {
|
|
136
|
+
// Handle interleave
|
|
137
|
+
switch (bufferMapping.type) {
|
|
138
|
+
case 'interleave':
|
|
139
|
+
// Handle interleaved buffer mapping
|
|
140
|
+
for (const attributeOverride of bufferMapping.attributes) {
|
|
141
|
+
overrideShaderLayoutAttribute(mergedLayout, attributeOverride);
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
|
|
145
|
+
default:
|
|
146
|
+
// Handle simple attribute overrides
|
|
147
|
+
overrideShaderLayoutAttribute(mergedLayout, bufferMapping);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return mergedLayout;
|
|
151
|
+
}
|
|
111
152
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
153
|
+
function overrideShaderLayoutAttribute(
|
|
154
|
+
layout: ShaderLayout,
|
|
155
|
+
attributeOverride: {name: string; format?: VertexFormat}
|
|
156
|
+
): void {
|
|
157
|
+
const attribute = getAttributeFromLayout(layout, attributeOverride.name);
|
|
158
|
+
if (attribute && attributeOverride.format) {
|
|
159
|
+
attribute.format = attributeOverride.format;
|
|
160
|
+
}
|
|
115
161
|
}
|
|
116
162
|
|
|
163
|
+
export function getAttributeFromLayout(
|
|
164
|
+
shaderLayout: ShaderLayout,
|
|
165
|
+
name: string
|
|
166
|
+
): AttributeLayout | null {
|
|
167
|
+
const attribute = shaderLayout.attributes.find(attr => attr.name === name);
|
|
168
|
+
if (!attribute) {
|
|
169
|
+
log.warn(`shader layout attribute "${name}" not present in shader`);
|
|
170
|
+
}
|
|
171
|
+
return attribute || null;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// HELPERS
|
|
175
|
+
|
|
117
176
|
/**
|
|
118
177
|
* Extract info about all transform feedback varyings
|
|
119
178
|
*
|
|
@@ -261,7 +320,8 @@ function readUniformBlocks(
|
|
|
261
320
|
uniforms: [] as any[]
|
|
262
321
|
};
|
|
263
322
|
|
|
264
|
-
const uniformIndices =
|
|
323
|
+
const uniformIndices =
|
|
324
|
+
(getBlockParameter(blockIndex, GL.UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES) as number[]) || [];
|
|
265
325
|
|
|
266
326
|
const uniformType = gl2.getActiveUniforms(program, uniformIndices, GL.UNIFORM_TYPE); // Array of GLenum indicating the types of the uniforms.
|
|
267
327
|
const uniformArrayLength = gl2.getActiveUniforms(program, uniformIndices, GL.UNIFORM_SIZE); // Array of GLuint indicating the sizes of the uniforms.
|
|
@@ -283,14 +343,14 @@ function readUniformBlocks(
|
|
|
283
343
|
if (!activeInfo) {
|
|
284
344
|
throw new Error('activeInfo');
|
|
285
345
|
}
|
|
286
|
-
|
|
346
|
+
|
|
287
347
|
blockInfo.uniforms.push({
|
|
288
348
|
name: activeInfo.name,
|
|
289
349
|
format: decodeUniformType(uniformType[i]).format,
|
|
290
350
|
type: uniformType[i],
|
|
291
351
|
arrayLength: uniformArrayLength[i],
|
|
292
352
|
byteOffset: uniformOffset[i],
|
|
293
|
-
byteStride: uniformStride[i]
|
|
353
|
+
byteStride: uniformStride[i]
|
|
294
354
|
// matrixStride: uniformStride[i],
|
|
295
355
|
// rowMajor: uniformRowMajor[i]
|
|
296
356
|
});
|
|
@@ -327,7 +387,7 @@ const SAMPLER_UNIFORMS_GL_TO_GPU: Record<
|
|
|
327
387
|
[GL.UNSIGNED_INT_SAMPLER_2D_ARRAY]: ['2d-array', 'uint']
|
|
328
388
|
};
|
|
329
389
|
|
|
330
|
-
type SamplerInfo =
|
|
390
|
+
type SamplerInfo = {
|
|
331
391
|
viewDimension: '1d' | '2d' | '2d-array' | 'cube' | 'cube-array' | '3d';
|
|
332
392
|
sampleType: 'float' | 'unfilterable-float' | 'depth' | 'sint' | 'uint';
|
|
333
393
|
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type {ShaderLayout, BufferMapping, AttributeLayout} from '@luma.gl/api';
|
|
2
|
+
import {decodeVertexFormat} from '@luma.gl/api';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build a WebGPU vertex buffer layout intended for use in a GPURenderPassDescriptor.
|
|
6
|
+
* Converts luma.gl attribute definitions to a WebGPU GPUVertexBufferLayout[] array
|
|
7
|
+
* @param layout
|
|
8
|
+
* @param bufferMap The buffer map is optional
|
|
9
|
+
* @returns WebGPU layout intended for a GPURenderPassDescriptor.
|
|
10
|
+
*/
|
|
11
|
+
export function getVertexBufferLayout(layout: ShaderLayout, bufferMap: BufferMapping[]): GPUVertexBufferLayout[] {
|
|
12
|
+
const vertexBufferLayouts: GPUVertexBufferLayout[] = [];
|
|
13
|
+
const usedAttributes = new Set<string>();
|
|
14
|
+
|
|
15
|
+
// First handle any buffers mentioned in `bufferMapping`
|
|
16
|
+
for (const mapping of bufferMap) {
|
|
17
|
+
// Build vertex attributes for one buffer
|
|
18
|
+
const vertexAttributes: GPUVertexAttribute[] = [];
|
|
19
|
+
|
|
20
|
+
// TODO verify that all stepModes for one buffer are the same
|
|
21
|
+
let stepMode: 'vertex' | 'instance' = 'vertex';
|
|
22
|
+
let byteStride = 0;
|
|
23
|
+
const byteOffset = mapping.byteOffset || 0;
|
|
24
|
+
|
|
25
|
+
// interleaved mapping {..., attributes: [{...}, ...]}
|
|
26
|
+
if ('attributes' in mapping) {
|
|
27
|
+
// const arrayStride = mapping.byteStride; TODO
|
|
28
|
+
for (const interleaved of mapping.attributes) {
|
|
29
|
+
const attributeLayout = findAttributeLayout(layout, interleaved.name, usedAttributes);
|
|
30
|
+
|
|
31
|
+
stepMode = attributeLayout.stepMode || 'vertex';
|
|
32
|
+
vertexAttributes.push({
|
|
33
|
+
format: attributeLayout.format,
|
|
34
|
+
offset: byteOffset + byteStride,
|
|
35
|
+
shaderLocation: attributeLayout.location
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
byteStride += decodeVertexFormat(attributeLayout.format).byteLength;
|
|
39
|
+
}
|
|
40
|
+
// non-interleaved mapping (just set offset and stride)
|
|
41
|
+
} else {
|
|
42
|
+
const attributeLayout = findAttributeLayout(layout, mapping.name, usedAttributes);
|
|
43
|
+
byteStride = decodeVertexFormat(attributeLayout.format).byteLength;
|
|
44
|
+
|
|
45
|
+
stepMode = attributeLayout.stepMode || 'vertex';
|
|
46
|
+
vertexAttributes.push({
|
|
47
|
+
format: attributeLayout.format,
|
|
48
|
+
offset: byteOffset,
|
|
49
|
+
shaderLocation: attributeLayout.location
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Store all the attribute bindings for one buffer
|
|
54
|
+
vertexBufferLayouts.push({
|
|
55
|
+
arrayStride: mapping.byteStride || byteStride,
|
|
56
|
+
stepMode: stepMode || 'vertex',
|
|
57
|
+
attributes: vertexAttributes
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Add any non-mapped attributes
|
|
62
|
+
for (const attribute of layout.attributes) {
|
|
63
|
+
if (!usedAttributes.has(attribute.name)) {
|
|
64
|
+
vertexBufferLayouts.push({
|
|
65
|
+
arrayStride: decodeVertexFormat(attribute.format).byteLength,
|
|
66
|
+
stepMode: attribute.stepMode || 'vertex',
|
|
67
|
+
attributes: [{
|
|
68
|
+
format: attribute.format,
|
|
69
|
+
offset: 0,
|
|
70
|
+
shaderLocation: attribute.location
|
|
71
|
+
}]
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return vertexBufferLayouts;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function getBufferSlots(layout: ShaderLayout, bufferMap: BufferMapping[]): Record<string, number> {
|
|
80
|
+
const usedAttributes = new Set<string>();
|
|
81
|
+
let bufferSlot = 0;
|
|
82
|
+
const bufferSlots: Record<string, number> = {};
|
|
83
|
+
|
|
84
|
+
// First handle any buffers mentioned in `bufferMapping`
|
|
85
|
+
for (const mapping of bufferMap) {
|
|
86
|
+
// interleaved mapping {..., attributes: [{...}, ...]}
|
|
87
|
+
if ('attributes' in mapping) {
|
|
88
|
+
for (const interleaved of mapping.attributes) {
|
|
89
|
+
usedAttributes.add(interleaved.name);
|
|
90
|
+
}
|
|
91
|
+
// non-interleaved mapping (just set offset and stride)
|
|
92
|
+
} else {
|
|
93
|
+
usedAttributes.add(mapping.name);
|
|
94
|
+
}
|
|
95
|
+
bufferSlots[mapping.name] = bufferSlot++;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Add any non-mapped attributes
|
|
99
|
+
for (const attribute of layout.attributes) {
|
|
100
|
+
if (!usedAttributes.has(attribute.name)) {
|
|
101
|
+
bufferSlots[attribute.name] = bufferSlot++;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return bufferSlots;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Looks up an attribute in the ShaderLayout.
|
|
110
|
+
* @throws if name is not in ShaderLayout
|
|
111
|
+
* @throws if name has already been referenced
|
|
112
|
+
*/
|
|
113
|
+
function findAttributeLayout(layout: ShaderLayout, name: string, attributeNames: Set<string>): AttributeLayout {
|
|
114
|
+
const attribute = layout.attributes.find(attribute => attribute.name === name);
|
|
115
|
+
if (!attribute) {
|
|
116
|
+
throw new Error(`Unknown attribute ${name}`);
|
|
117
|
+
}
|
|
118
|
+
if (attributeNames.has(name)) {
|
|
119
|
+
throw new Error(`Duplicate attribute ${name}`);
|
|
120
|
+
}
|
|
121
|
+
attributeNames.add(name);
|
|
122
|
+
return attribute;
|
|
123
|
+
}
|
|
@@ -84,7 +84,7 @@ export class WEBGLVertexArrayObject extends WebGLResource<VertexArrayObjectProps
|
|
|
84
84
|
// Set (bind) an elements buffer, for indexed rendering.
|
|
85
85
|
// Must be a Buffer bound to GL.ELEMENT_ARRAY_BUFFER. Constants not supported
|
|
86
86
|
setElementBuffer(elementBuffer: WEBGLBuffer | null = null, opts = {}) {
|
|
87
|
-
assert(!elementBuffer || elementBuffer.
|
|
87
|
+
assert(!elementBuffer || elementBuffer.glTarget === GL.ELEMENT_ARRAY_BUFFER, ERR_ELEMENTS);
|
|
88
88
|
|
|
89
89
|
// The GL.ELEMENT_ARRAY_BUFFER_BINDING is stored on the VertexArrayObject...
|
|
90
90
|
this.bind(() => {
|
|
@@ -95,7 +95,7 @@ export class WEBGLVertexArrayObject extends WebGLResource<VertexArrayObjectProps
|
|
|
95
95
|
/** Set a location in vertex attributes array to a buffer, enables the location, sets divisor */
|
|
96
96
|
setBuffer(location: number, buffer: WEBGLBuffer, accessor: any): void {
|
|
97
97
|
// Check target
|
|
98
|
-
if (buffer.
|
|
98
|
+
if (buffer.glTarget === GL.ELEMENT_ARRAY_BUFFER) {
|
|
99
99
|
this.setElementBuffer(buffer, accessor);
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
@@ -11,17 +11,21 @@ export class WEBGLBuffer extends Buffer {
|
|
|
11
11
|
readonly gl: WebGLRenderingContext;
|
|
12
12
|
readonly gl2: WebGL2RenderingContext | null;
|
|
13
13
|
readonly handle: WebGLBuffer;
|
|
14
|
-
readonly target: number;
|
|
15
14
|
|
|
15
|
+
/** Target in OpenGL defines the type of buffer */
|
|
16
|
+
readonly glTarget: GL.ARRAY_BUFFER | GL.ELEMENT_ARRAY_BUFFER | GL.UNIFORM_BUFFER;
|
|
17
|
+
/** Usage is a hint on how frequently the buffer will be updates */
|
|
18
|
+
readonly glUsage: GL.STATIC_DRAW | GL.DYNAMIC_DRAW;
|
|
19
|
+
/** Index type is needed when issuing draw calls, so we pre-compute it */
|
|
20
|
+
readonly glIndexType: GL.UNSIGNED_SHORT | GL.UNSIGNED_INT = GL.UNSIGNED_SHORT;
|
|
21
|
+
|
|
22
|
+
/** Number of bytes allocated on the GPU for this buffer */
|
|
16
23
|
byteLength: number;
|
|
24
|
+
/** Number of bytes used */
|
|
17
25
|
bytesUsed: number;
|
|
26
|
+
/** A partial CPU-side copy of the data in this buffer, for debugging purposes */
|
|
18
27
|
debugData: ArrayBuffer | null = null;
|
|
19
28
|
|
|
20
|
-
webglUsage: number;
|
|
21
|
-
|
|
22
|
-
// accessor: {};
|
|
23
|
-
|
|
24
|
-
|
|
25
29
|
constructor(device: WebGLDevice, props: BufferProps = {}) {
|
|
26
30
|
super(device, props);
|
|
27
31
|
|
|
@@ -33,13 +37,13 @@ export class WEBGLBuffer extends Buffer {
|
|
|
33
37
|
this.handle = handle || this.gl.createBuffer();
|
|
34
38
|
device.setSpectorMetadata(this.handle, {...this.props, data: typeof this.props.data});
|
|
35
39
|
|
|
36
|
-
// In WebGL1, need to make sure we use GL.ELEMENT_ARRAY_BUFFER when initializing element buffers
|
|
37
|
-
//
|
|
38
|
-
// In WebGL2, we can use GL.COPY_READ_BUFFER which avoids locking the type here
|
|
39
|
-
|
|
40
|
-
this.
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
// - In WebGL1, need to make sure we use GL.ELEMENT_ARRAY_BUFFER when initializing element buffers
|
|
41
|
+
// otherwise buffer type will lock to generic (non-element) buffer
|
|
42
|
+
// - In WebGL2, we can use GL.COPY_READ_BUFFER which avoids locking the type here
|
|
43
|
+
this.glTarget = getWebGLTarget(this.props.usage);
|
|
44
|
+
this.glUsage = getWebGLUsage(this.props.usage);
|
|
45
|
+
this.glIndexType = this.props.indexType === 'uint32' ? GL.UNSIGNED_INT : GL.UNSIGNED_SHORT;
|
|
46
|
+
|
|
43
47
|
this.debugData = null;
|
|
44
48
|
|
|
45
49
|
// Set data: (re)initializes the buffer
|
|
@@ -48,25 +52,19 @@ export class WEBGLBuffer extends Buffer {
|
|
|
48
52
|
} else {
|
|
49
53
|
this._initWithByteLength(props.byteLength || 0);
|
|
50
54
|
}
|
|
51
|
-
|
|
52
|
-
// Deprecated: Merge main props and accessor
|
|
53
|
-
// this.accessor = {...props.accessor};
|
|
54
|
-
|
|
55
|
-
// Object.seal(this);
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
// PRIVATE METHODS
|
|
59
58
|
|
|
60
|
-
|
|
59
|
+
/** Allocate a new buffer and initialize to contents of typed array */
|
|
61
60
|
_initWithData(data, byteOffset: number = 0, byteLength: number = data.byteLength + byteOffset): this {
|
|
62
61
|
assert(ArrayBuffer.isView(data));
|
|
63
62
|
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
this.gl.
|
|
67
|
-
this.gl.
|
|
68
|
-
this.gl.
|
|
69
|
-
this.gl.bindBuffer(target, null);
|
|
63
|
+
const glTarget = this._getWriteTarget();
|
|
64
|
+
this.gl.bindBuffer(glTarget, this.handle);
|
|
65
|
+
this.gl.bufferData(glTarget, byteLength, this.glUsage);
|
|
66
|
+
this.gl.bufferSubData(glTarget, byteOffset, data);
|
|
67
|
+
this.gl.bindBuffer(glTarget, null);
|
|
70
68
|
|
|
71
69
|
this.debugData = data.slice(0, DEBUG_DATA_LENGTH);
|
|
72
70
|
this.bytesUsed = byteLength;
|
|
@@ -88,11 +86,11 @@ export class WEBGLBuffer extends Buffer {
|
|
|
88
86
|
data = new Float32Array(0);
|
|
89
87
|
}
|
|
90
88
|
|
|
91
|
-
const
|
|
89
|
+
const glTarget = this._getWriteTarget();
|
|
92
90
|
|
|
93
|
-
this.gl.bindBuffer(
|
|
94
|
-
this.gl.bufferData(
|
|
95
|
-
this.gl.bindBuffer(
|
|
91
|
+
this.gl.bindBuffer(glTarget, this.handle);
|
|
92
|
+
this.gl.bufferData(glTarget, data, this.glUsage);
|
|
93
|
+
this.gl.bindBuffer(glTarget, null);
|
|
96
94
|
|
|
97
95
|
this.debugData = null;
|
|
98
96
|
this.bytesUsed = byteLength;
|
|
@@ -118,16 +116,16 @@ export class WEBGLBuffer extends Buffer {
|
|
|
118
116
|
|
|
119
117
|
// Create the buffer - binding it here for the first time locks the type
|
|
120
118
|
// In WebGL2, use GL.COPY_WRITE_BUFFER to avoid locking the type
|
|
121
|
-
const
|
|
122
|
-
this.gl.bindBuffer(
|
|
119
|
+
const glTarget = this.device.isWebGL2 ? GL.COPY_WRITE_BUFFER : this.glTarget;
|
|
120
|
+
this.gl.bindBuffer(glTarget, this.handle);
|
|
123
121
|
// WebGL2: subData supports additional srcOffset and length parameters
|
|
124
122
|
if (srcOffset !== 0 || byteLength !== undefined) {
|
|
125
123
|
this.device.assertWebGL2();
|
|
126
|
-
this.gl2.bufferSubData(
|
|
124
|
+
this.gl2.bufferSubData(glTarget, byteOffset, data, srcOffset, byteLength);
|
|
127
125
|
} else {
|
|
128
|
-
this.gl.bufferSubData(
|
|
126
|
+
this.gl.bufferSubData(glTarget, byteOffset, data);
|
|
129
127
|
}
|
|
130
|
-
this.gl.bindBuffer(
|
|
128
|
+
this.gl.bindBuffer(glTarget, null);
|
|
131
129
|
|
|
132
130
|
// TODO - update local `data` if offsets are right
|
|
133
131
|
// this.debugData = data.slice(byteOffset, 40);
|
|
@@ -161,13 +159,13 @@ export class WEBGLBuffer extends Buffer {
|
|
|
161
159
|
}
|
|
162
160
|
|
|
163
161
|
_getWriteTarget() {
|
|
164
|
-
return this.
|
|
165
|
-
// return this.device.isWebGL2 ? GL.COPY_WRITE_BUFFER : this.
|
|
162
|
+
return this.glTarget;
|
|
163
|
+
// return this.device.isWebGL2 ? GL.COPY_WRITE_BUFFER : this.glTarget;
|
|
166
164
|
}
|
|
167
165
|
|
|
168
166
|
_getReadTarget() {
|
|
169
|
-
return this.
|
|
170
|
-
// return this.device.isWebGL2 ? GL.COPY_READ_BUFFER : this.
|
|
167
|
+
return this.glTarget;
|
|
168
|
+
// return this.device.isWebGL2 ? GL.COPY_READ_BUFFER : this.glTarget;
|
|
171
169
|
}
|
|
172
170
|
}
|
|
173
171
|
|
|
@@ -182,7 +180,7 @@ export class WEBGLBuffer extends Buffer {
|
|
|
182
180
|
// static INDIRECT = 0x0100;
|
|
183
181
|
// static QUERY_RESOLVE = 0x0200;
|
|
184
182
|
|
|
185
|
-
function getWebGLTarget(usage: number): GL {
|
|
183
|
+
function getWebGLTarget(usage: number): GL.ARRAY_BUFFER | GL.ELEMENT_ARRAY_BUFFER | GL.UNIFORM_BUFFER {
|
|
186
184
|
if (usage & Buffer.INDEX) {
|
|
187
185
|
return GL.ELEMENT_ARRAY_BUFFER;
|
|
188
186
|
}
|
|
@@ -204,7 +202,8 @@ function getWebGLTarget(usage: number): GL {
|
|
|
204
202
|
return GL.ARRAY_BUFFER;
|
|
205
203
|
}
|
|
206
204
|
|
|
207
|
-
|
|
205
|
+
/** @todo usage is not passed correctly */
|
|
206
|
+
function getWebGLUsage(usage: number): GL.STATIC_DRAW | GL.DYNAMIC_DRAW {
|
|
208
207
|
if (usage & Buffer.INDEX) {
|
|
209
208
|
return GL.STATIC_DRAW;
|
|
210
209
|
}
|
|
@@ -214,5 +213,5 @@ function getWebGLUsage(usage: number): GL {
|
|
|
214
213
|
if (usage & Buffer.UNIFORM) {
|
|
215
214
|
return GL.DYNAMIC_DRAW;
|
|
216
215
|
}
|
|
217
|
-
return GL.
|
|
216
|
+
return GL.STATIC_DRAW;
|
|
218
217
|
}
|
|
@@ -53,7 +53,7 @@ export class WEBGLExternalTexture extends WEBGLTexture {
|
|
|
53
53
|
constructor(device: Device | WebGLRenderingContext, props: TextureProps) {
|
|
54
54
|
super(WebGLDevice.attach(device), {id: uid('texture'), ...props});
|
|
55
55
|
|
|
56
|
-
this.
|
|
56
|
+
this.glTarget = getWebGLTextureTarget(props);
|
|
57
57
|
|
|
58
58
|
this.device = WebGLDevice.attach(device);
|
|
59
59
|
this.gl = this.device.gl;
|