@luma.gl/webgpu 9.0.0-beta.4 → 9.0.0-beta.5

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 (60) hide show
  1. package/dist/adapter/helpers/accessor-to-format.js +99 -1
  2. package/dist/adapter/helpers/convert-texture-format.js +5 -5
  3. package/dist/adapter/helpers/generate-mipmaps.js +76 -82
  4. package/dist/adapter/helpers/get-bind-group.js +54 -41
  5. package/dist/adapter/helpers/get-vertex-buffer-layout.js +110 -80
  6. package/dist/adapter/helpers/webgpu-parameters.js +182 -125
  7. package/dist/adapter/resources/webgpu-buffer.js +110 -62
  8. package/dist/adapter/resources/webgpu-command-encoder.js +73 -49
  9. package/dist/adapter/resources/webgpu-compute-pass.js +54 -41
  10. package/dist/adapter/resources/webgpu-compute-pipeline.js +24 -19
  11. package/dist/adapter/resources/webgpu-external-texture.js +29 -19
  12. package/dist/adapter/resources/webgpu-framebuffer.js +11 -7
  13. package/dist/adapter/resources/webgpu-query.js +42 -1
  14. package/dist/adapter/resources/webgpu-render-pass.js +115 -105
  15. package/dist/adapter/resources/webgpu-render-pipeline.js +148 -83
  16. package/dist/adapter/resources/webgpu-sampler.js +18 -15
  17. package/dist/adapter/resources/webgpu-shader.js +55 -45
  18. package/dist/adapter/resources/webgpu-texture.js +129 -109
  19. package/dist/adapter/resources/webgpu-vertex-array.d.ts +4 -1
  20. package/dist/adapter/resources/webgpu-vertex-array.d.ts.map +1 -1
  21. package/dist/adapter/resources/webgpu-vertex-array.js +64 -41
  22. package/dist/adapter/webgpu-canvas-context.d.ts.map +1 -1
  23. package/dist/adapter/webgpu-canvas-context.js +100 -69
  24. package/dist/adapter/webgpu-device.d.ts.map +1 -1
  25. package/dist/adapter/webgpu-device.js +257 -230
  26. package/dist/adapter/webgpu-types.js +0 -2
  27. package/dist/dist.dev.js +661 -2178
  28. package/dist/glsl/glsllang.js +9 -6
  29. package/dist/index.cjs +58 -239
  30. package/dist/index.cjs.map +7 -0
  31. package/dist/index.js +9 -6
  32. package/dist.min.js +1 -22
  33. package/package.json +9 -7
  34. package/src/adapter/resources/webgpu-vertex-array.ts +5 -2
  35. package/src/adapter/webgpu-canvas-context.ts +1 -0
  36. package/src/adapter/webgpu-device.ts +16 -36
  37. package/dist/adapter/helpers/accessor-to-format.js.map +0 -1
  38. package/dist/adapter/helpers/convert-texture-format.js.map +0 -1
  39. package/dist/adapter/helpers/generate-mipmaps.js.map +0 -1
  40. package/dist/adapter/helpers/get-bind-group.js.map +0 -1
  41. package/dist/adapter/helpers/get-vertex-buffer-layout.js.map +0 -1
  42. package/dist/adapter/helpers/webgpu-parameters.js.map +0 -1
  43. package/dist/adapter/resources/webgpu-buffer.js.map +0 -1
  44. package/dist/adapter/resources/webgpu-command-encoder.js.map +0 -1
  45. package/dist/adapter/resources/webgpu-compute-pass.js.map +0 -1
  46. package/dist/adapter/resources/webgpu-compute-pipeline.js.map +0 -1
  47. package/dist/adapter/resources/webgpu-external-texture.js.map +0 -1
  48. package/dist/adapter/resources/webgpu-framebuffer.js.map +0 -1
  49. package/dist/adapter/resources/webgpu-query.js.map +0 -1
  50. package/dist/adapter/resources/webgpu-render-pass.js.map +0 -1
  51. package/dist/adapter/resources/webgpu-render-pipeline.js.map +0 -1
  52. package/dist/adapter/resources/webgpu-sampler.js.map +0 -1
  53. package/dist/adapter/resources/webgpu-shader.js.map +0 -1
  54. package/dist/adapter/resources/webgpu-texture.js.map +0 -1
  55. package/dist/adapter/resources/webgpu-vertex-array.js.map +0 -1
  56. package/dist/adapter/webgpu-canvas-context.js.map +0 -1
  57. package/dist/adapter/webgpu-device.js.map +0 -1
  58. package/dist/adapter/webgpu-types.js.map +0 -1
  59. package/dist/glsl/glsllang.js.map +0 -1
  60. package/dist/index.js.map +0 -1
@@ -1,2 +1,100 @@
1
+ /*
2
+ import {assert} from '@luma.gl/core';
1
3
 
2
- //# sourceMappingURL=accessor-to-format.js.map
4
+ type Accessor = Record<string, any>;
5
+
6
+ const FORMAT_TO_ACCESSOR: Record<GPUVertexFormat, Accessor> = {
7
+ uchar2: {type: 'uchar', size: 2},
8
+ uchar4: {type: 'uchar', size: 4},
9
+ char2: {type: 'char', size: 2},
10
+ char4: {type: 'char', size: 4},
11
+ uchar2norm: {type: 'uchar', size: 2, normalized: true},
12
+ uchar4norm: {type: 'uchar', size: 4, normalized: true},
13
+ char2norm: {type: 'char', size: 2, normalized: true},
14
+ char4norm: {type: 'char', size: 4, normalized: true},
15
+ ushort2: {type: 'ushort', size: 2},
16
+ ushort4: {type: 'ushort', size: 4},
17
+ short2: {type: 'short', size: 2},
18
+ short4: {type: 'short', size: 4},
19
+ ushort2norm: {type: 'ushort', size: 2, normalized: true},
20
+ ushort4norm: {type: 'ushort', size: 4, normalized: true},
21
+ short2norm: {type: 'short', size: 1, normalized: true},
22
+ short4norm: {type: 'short', size: 1, normalized: true},
23
+ half2: {type: 'half', size: 2},
24
+ half4: {type: 'half', size: 4},
25
+ float: {type: 'float', size: 1},
26
+ float2: {type: 'float', size: 2},
27
+ float3: {type: 'float', size: 3},
28
+ float4: {type: 'float', size: 4},
29
+ uint: {type: 'uint', size: 1, integer: true},
30
+ uint2: {type: 'uint', size: 2, integer: true},
31
+ uint3: {type: 'uint', size: 3, integer: true},
32
+ uint4: {type: 'uint', size: 4, integer: true},
33
+ int: {type: 'int', size: 1, integer: true},
34
+ int2: {type: 'int', size: 2, integer: true},
35
+ int3: {type: 'int', size: 3, integer: true},
36
+ int4: {type: 'int', size: 4, integer: true}
37
+ };
38
+
39
+ /**
40
+ * Convert from WebGPU attribute format strings to accessor {type, size, normalized, integer}
41
+ * @param {*} format
42
+ *
43
+ export function mapWebGPUFormatToAccessor(format) {
44
+ const accessorDefinition = FORMAT_TO_ACCESSOR[format];
45
+ assert(accessorDefinition, 'invalid attribute format');
46
+ return Object.freeze(accessorDefinition);
47
+ }
48
+
49
+ /**
50
+ * Convert from accessor {type, size, normalized, integer} to WebGPU attribute format strings
51
+ * @param {*} format
52
+ *
53
+ export function mapAccessorToWebGPUFormat(accessor) {
54
+ const {type = GL.FLOAT, size = 1, normalized = false, integer = false} = accessor;
55
+ assert(size >=1 && size <=4);
56
+ // `norm` suffix (uchar4norm)
57
+ const norm = normalized ? 'norm' : '';
58
+ // size 1 is ommitted in format names (float vs float2)
59
+ const count = size === 1 ? '' : size;
60
+ switch (type) {
61
+ case GL.UNSIGNED_BYTE:
62
+ switch (size) {
63
+ case 2:
64
+ case 4:
65
+ return `uchar${count}${norm}`;
66
+ }
67
+ case GL.BYTE:
68
+ switch (size) {
69
+ case 2:
70
+ case 4:
71
+ return `char${count}${norm}`;
72
+ }
73
+ case GL.UNSIGNED_SHORT:
74
+ switch (size) {
75
+ case 2:
76
+ case 4:
77
+ return `ushort${count}${norm}`;
78
+ }
79
+ case GL.SHORT:
80
+ switch (size) {
81
+ case 2:
82
+ case 4:
83
+ return `short${count}${norm}`;
84
+ }
85
+ case GL.HALF_FLOAT:
86
+ switch (size) {
87
+ case 2:
88
+ case 4:
89
+ return `half${count}`;
90
+ }
91
+ case GL.FLOAT:
92
+ return `float${count}`;
93
+ case GL.UNSIGNED_INT:
94
+ return `uint${count}`;
95
+ case GL.INT:
96
+ return `int${count}`;
97
+ }
98
+ throw new Error('illegal accessor');
99
+ }
100
+ */
@@ -1,7 +1,7 @@
1
+ /** Ensure a texture format is WebGPU compatible */
1
2
  export function getWebGPUTextureFormat(format) {
2
- if (format.includes('webgl')) {
3
- throw new Error('webgl-only format');
4
- }
5
- return format;
3
+ if (format.includes('webgl')) {
4
+ throw new Error('webgl-only format');
5
+ }
6
+ return format;
6
7
  }
7
- //# sourceMappingURL=convert-texture-format.js.map
@@ -1,3 +1,7 @@
1
+ // luma.gl, MIT license
2
+ // Forked from Kangz/mipmapper.js under MIT license Copyright 2020 Brandon Jones
3
+ // https://gist.github.com/Kangz/782d5f1ae502daf53910a13f55db2f83
4
+ // @ts-nocheck this is written against outdated WebGPU API, needs an update pass
1
5
  const VS_GEN_MIPMAP = `\#version 450
2
6
  const vec2 pos[4] = vec2[4](vec2(-1.0f, 1.0f), vec2(1.0f, 1.0f), vec2(-1.0f, -1.0f), vec2(1.0f, -1.0f));
3
7
  layout(location = 0) out vec2 vTex;
@@ -13,88 +17,78 @@ layout(location = 0) out vec4 outColor;
13
17
  void main() {
14
18
  outColor = texture(sampler2D(img, imgSampler), vTex);
15
19
  }`;
20
+ /** WebGPU does not have built-in mipmap creation */
16
21
  export class WebGPUMipmapGenerator {
17
- constructor(device, glslang) {
18
- this.device = void 0;
19
- this.mipmapSampler = void 0;
20
- this.mipmapPipeline = void 0;
21
- this.device = device;
22
- this.mipmapSampler = device.createSampler({
23
- minFilter: 'linear'
24
- });
25
- this.mipmapPipeline = device.createRenderPipeline({
26
- vertexStage: {
27
- module: device.createShaderModule({
28
- code: glslang.compileGLSL(VS_GEN_MIPMAP, 'vertex')
29
- }),
30
- entryPoint: 'main'
31
- },
32
- fragmentStage: {
33
- module: device.createShaderModule({
34
- code: glslang.compileGLSL(FS_GEN_MIPMAP, 'fragment')
35
- }),
36
- entryPoint: 'main'
37
- },
38
- primitiveTopology: 'triangle-strip',
39
- colorStates: [{
40
- format: 'rgba8unorm'
41
- }]
42
- });
43
- }
44
- generateMipmappedTexture(imageBitmap) {
45
- const textureSize = {
46
- width: imageBitmap.width,
47
- height: imageBitmap.height,
48
- depth: 1
49
- };
50
- const mipLevelCount = Math.floor(Math.log2(Math.max(imageBitmap.width, imageBitmap.height))) + 1;
51
- const texture = this.device.createTexture({
52
- size: textureSize,
53
- format: 'rgba8unorm',
54
- usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.SAMPLED | GPUTextureUsage.OUTPUT_ATTACHMENT,
55
- mipLevelCount
56
- });
57
- this.device.queue.copyImageBitmapToTexture({
58
- imageBitmap
59
- }, {
60
- texture
61
- }, textureSize);
62
- const commandEncoder = this.device.createCommandEncoder({});
63
- for (let i = 1; i < mipLevelCount; ++i) {
64
- const passEncoder = commandEncoder.beginRenderPass({
65
- colorAttachments: [{
66
- attachment: texture.createView({
67
- baseMipLevel: i,
68
- mipLevelCount: 1
69
- }),
70
- loadValue: {
71
- r: 1.0,
72
- g: 0.0,
73
- b: 0.0,
74
- a: 0.0
75
- }
76
- }]
77
- });
78
- const bindGroup = this.device.createBindGroup({
79
- layout: this.mipmapPipeline.getBindGroupLayout(0),
80
- bindings: [{
81
- binding: 0,
82
- resource: this.mipmapSampler
83
- }, {
84
- binding: 1,
85
- resource: texture.createView({
86
- baseMipLevel: i - 1,
87
- mipLevelCount: 1
88
- })
89
- }]
90
- });
91
- passEncoder.setPipeline(this.mipmapPipeline);
92
- passEncoder.setBindGroup(0, bindGroup);
93
- passEncoder.draw(4);
94
- passEncoder.endPass();
22
+ device;
23
+ mipmapSampler;
24
+ mipmapPipeline;
25
+ constructor(device, glslang) {
26
+ this.device = device;
27
+ this.mipmapSampler = device.createSampler({ minFilter: 'linear' });
28
+ this.mipmapPipeline = device.createRenderPipeline({
29
+ vertexStage: {
30
+ module: device.createShaderModule({
31
+ code: glslang.compileGLSL(VS_GEN_MIPMAP, 'vertex')
32
+ }),
33
+ entryPoint: 'main'
34
+ },
35
+ fragmentStage: {
36
+ module: device.createShaderModule({
37
+ code: glslang.compileGLSL(FS_GEN_MIPMAP, 'fragment')
38
+ }),
39
+ entryPoint: 'main'
40
+ },
41
+ primitiveTopology: 'triangle-strip',
42
+ colorStates: [{
43
+ format: 'rgba8unorm',
44
+ }]
45
+ });
46
+ }
47
+ generateMipmappedTexture(imageBitmap) {
48
+ const textureSize = {
49
+ width: imageBitmap.width,
50
+ height: imageBitmap.height,
51
+ depth: 1,
52
+ };
53
+ const mipLevelCount = Math.floor(Math.log2(Math.max(imageBitmap.width, imageBitmap.height))) + 1;
54
+ // Populate the top level of the srcTexture with the imageBitmap.
55
+ const texture = this.device.createTexture({
56
+ size: textureSize,
57
+ format: 'rgba8unorm',
58
+ usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.SAMPLED | GPUTextureUsage.OUTPUT_ATTACHMENT,
59
+ mipLevelCount
60
+ });
61
+ this.device.queue.copyImageBitmapToTexture({ imageBitmap }, { texture }, textureSize);
62
+ const commandEncoder = this.device.createCommandEncoder({});
63
+ for (let i = 1; i < mipLevelCount; ++i) {
64
+ const passEncoder = commandEncoder.beginRenderPass({
65
+ colorAttachments: [{
66
+ attachment: texture.createView({
67
+ baseMipLevel: i,
68
+ mipLevelCount: 1
69
+ }),
70
+ loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 0.0 },
71
+ }],
72
+ });
73
+ const bindGroup = this.device.createBindGroup({
74
+ layout: this.mipmapPipeline.getBindGroupLayout(0),
75
+ bindings: [{
76
+ binding: 0,
77
+ resource: this.mipmapSampler,
78
+ }, {
79
+ binding: 1,
80
+ resource: texture.createView({
81
+ baseMipLevel: i - 1,
82
+ mipLevelCount: 1
83
+ }),
84
+ }],
85
+ });
86
+ passEncoder.setPipeline(this.mipmapPipeline);
87
+ passEncoder.setBindGroup(0, bindGroup);
88
+ passEncoder.draw(4);
89
+ passEncoder.endPass();
90
+ }
91
+ this.device.queue.submit([commandEncoder.finish()]);
92
+ return texture;
95
93
  }
96
- this.device.queue.submit([commandEncoder.finish()]);
97
- return texture;
98
- }
99
94
  }
100
- //# sourceMappingURL=generate-mipmaps.js.map
@@ -1,53 +1,66 @@
1
1
  import { Buffer, Sampler, Texture, log, cast } from '@luma.gl/core';
2
+ /**
3
+ * Create a WebGPU "bind group layout" from an array of luma.gl bindings
4
+ * @note bind groups can be automatically generated by WebGPU.
5
+ */
2
6
  export function makeBindGroupLayout(device, layout, bindings) {
3
- throw new Error('not implemented');
7
+ throw new Error('not implemented');
8
+ // return device.createBindGroupLayout({
9
+ // layout,
10
+ // entries: getBindGroupEntries(bindings)
11
+ // })
4
12
  }
13
+ /**
14
+ * Create a WebGPU "bind group" from an array of luma.gl bindings
15
+ */
5
16
  export function getBindGroup(device, bindGroupLayout, shaderLayout, bindings) {
6
- const entries = getBindGroupEntries(bindings, shaderLayout);
7
- return device.createBindGroup({
8
- layout: bindGroupLayout,
9
- entries
10
- });
17
+ const entries = getBindGroupEntries(bindings, shaderLayout);
18
+ return device.createBindGroup({
19
+ layout: bindGroupLayout,
20
+ entries
21
+ });
11
22
  }
12
23
  export function getShaderLayoutBinding(shaderLayout, bindingName) {
13
- const bindingLayout = shaderLayout.bindings.find(binding => binding.name === bindingName || `${binding.name}uniforms` === bindingName.toLocaleLowerCase());
14
- if (!bindingLayout) {
15
- log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();
16
- }
17
- return bindingLayout;
24
+ const bindingLayout = shaderLayout.bindings.find(binding => binding.name === bindingName || `${binding.name}uniforms` === bindingName.toLocaleLowerCase());
25
+ if (!bindingLayout) {
26
+ log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();
27
+ }
28
+ return bindingLayout;
18
29
  }
30
+ /**
31
+ * @param bindings
32
+ * @returns
33
+ */
19
34
  function getBindGroupEntries(bindings, shaderLayout) {
20
- const entries = [];
21
- for (const [bindingName, value] of Object.entries(bindings)) {
22
- const bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
23
- if (bindingLayout) {
24
- entries.push(getBindGroupEntry(value, bindingLayout.location));
35
+ const entries = [];
36
+ for (const [bindingName, value] of Object.entries(bindings)) {
37
+ const bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
38
+ if (bindingLayout) {
39
+ entries.push(getBindGroupEntry(value, bindingLayout.location));
40
+ }
25
41
  }
26
- }
27
- return entries;
42
+ return entries;
28
43
  }
29
44
  function getBindGroupEntry(binding, index) {
30
- if (binding instanceof Buffer) {
31
- return {
32
- binding: index,
33
- resource: {
34
- buffer: cast(binding).handle
35
- }
36
- };
37
- }
38
- if (binding instanceof Sampler) {
39
- return {
40
- binding: index,
41
- resource: cast(binding).handle
42
- };
43
- } else if (binding instanceof Texture) {
44
- return {
45
- binding: index,
46
- resource: cast(binding).handle.createView({
47
- label: 'bind-group-auto-created'
48
- })
49
- };
50
- }
51
- throw new Error('invalid binding');
45
+ if (binding instanceof Buffer) {
46
+ return {
47
+ binding: index,
48
+ resource: {
49
+ buffer: cast(binding).handle
50
+ }
51
+ };
52
+ }
53
+ if (binding instanceof Sampler) {
54
+ return {
55
+ binding: index,
56
+ resource: cast(binding).handle
57
+ };
58
+ }
59
+ else if (binding instanceof Texture) {
60
+ return {
61
+ binding: index,
62
+ resource: cast(binding).handle.createView({ label: 'bind-group-auto-created' })
63
+ };
64
+ }
65
+ throw new Error('invalid binding');
52
66
  }
53
- //# sourceMappingURL=get-bind-group.js.map
@@ -1,94 +1,124 @@
1
1
  import { log, decodeVertexFormat } from '@luma.gl/core';
2
+ // import {getAttributeInfosFromLayouts} from '@luma.gl/core';
3
+ /** Throw error on any WebGL-only vertex formats */
2
4
  function getWebGPUVertexFormat(format) {
3
- if (format.endsWith('-webgl')) {
4
- throw new Error(`WebGPU does not support vertex format ${format}`);
5
- }
6
- return format;
5
+ if (format.endsWith('-webgl')) {
6
+ throw new Error(`WebGPU does not support vertex format ${format}`);
7
+ }
8
+ return format;
7
9
  }
10
+ /**
11
+ * Build a WebGPU vertex buffer layout intended for use in a GPURenderPassDescriptor.
12
+ * Converts luma.gl attribute definitions to a WebGPU GPUVertexBufferLayout[] array
13
+ * @param layout
14
+ * @param bufferLayout The buffer map is optional
15
+ * @returns WebGPU layout intended for a GPURenderPassDescriptor.
16
+ */
8
17
  export function getVertexBufferLayout(shaderLayout, bufferLayout) {
9
- const vertexBufferLayouts = [];
10
- const usedAttributes = new Set();
11
- for (const mapping of bufferLayout) {
12
- const vertexAttributes = [];
13
- let stepMode = 'vertex';
14
- let byteStride = 0;
15
- if (mapping.attributes) {
16
- for (const attributeMapping of mapping.attributes) {
17
- const attributeName = attributeMapping.attribute;
18
- const attributeLayout = findAttributeLayout(shaderLayout, attributeName, usedAttributes);
19
- stepMode = attributeLayout.stepMode || (attributeLayout.name.startsWith('instance') ? 'instance' : 'vertex');
20
- vertexAttributes.push({
21
- format: getWebGPUVertexFormat(attributeMapping.format || mapping.format),
22
- offset: attributeMapping.byteOffset,
23
- shaderLocation: attributeLayout.location
18
+ const vertexBufferLayouts = [];
19
+ const usedAttributes = new Set();
20
+ // First handle any buffers mentioned in `bufferLayout`
21
+ for (const mapping of bufferLayout) {
22
+ // Build vertex attributes for one buffer
23
+ const vertexAttributes = [];
24
+ // TODO verify that all stepModes for one buffer are the same
25
+ let stepMode = 'vertex';
26
+ let byteStride = 0;
27
+ // interleaved mapping {..., attributes: [{...}, ...]}
28
+ if (mapping.attributes) {
29
+ // const arrayStride = mapping.byteStride; TODO
30
+ for (const attributeMapping of mapping.attributes) {
31
+ const attributeName = attributeMapping.attribute;
32
+ const attributeLayout = findAttributeLayout(shaderLayout, attributeName, usedAttributes);
33
+ stepMode = attributeLayout.stepMode || (attributeLayout.name.startsWith('instance') ? 'instance' : 'vertex');
34
+ vertexAttributes.push({
35
+ format: getWebGPUVertexFormat(attributeMapping.format || mapping.format),
36
+ offset: attributeMapping.byteOffset,
37
+ shaderLocation: attributeLayout.location
38
+ });
39
+ byteStride += decodeVertexFormat(mapping.format).byteLength;
40
+ }
41
+ // non-interleaved mapping (just set offset and stride)
42
+ }
43
+ else {
44
+ const attributeLayout = findAttributeLayout(shaderLayout, mapping.name, usedAttributes);
45
+ if (!attributeLayout) {
46
+ continue; // eslint-disable-line no-continue
47
+ }
48
+ byteStride = decodeVertexFormat(mapping.format).byteLength;
49
+ stepMode = attributeLayout.stepMode || (attributeLayout.name.startsWith('instance') ? 'instance' : 'vertex');
50
+ vertexAttributes.push({
51
+ format: getWebGPUVertexFormat(mapping.format),
52
+ // We only support 0 offset for non-interleaved buffer layouts
53
+ offset: 0,
54
+ shaderLocation: attributeLayout.location
55
+ });
56
+ }
57
+ // Store all the attribute bindings for one buffer
58
+ vertexBufferLayouts.push({
59
+ arrayStride: mapping.byteStride || byteStride,
60
+ stepMode,
61
+ attributes: vertexAttributes
24
62
  });
25
- byteStride += decodeVertexFormat(mapping.format).byteLength;
26
- }
27
- } else {
28
- const attributeLayout = findAttributeLayout(shaderLayout, mapping.name, usedAttributes);
29
- if (!attributeLayout) {
30
- continue;
31
- }
32
- byteStride = decodeVertexFormat(mapping.format).byteLength;
33
- stepMode = attributeLayout.stepMode || (attributeLayout.name.startsWith('instance') ? 'instance' : 'vertex');
34
- vertexAttributes.push({
35
- format: getWebGPUVertexFormat(mapping.format),
36
- offset: 0,
37
- shaderLocation: attributeLayout.location
38
- });
39
63
  }
40
- vertexBufferLayouts.push({
41
- arrayStride: mapping.byteStride || byteStride,
42
- stepMode,
43
- attributes: vertexAttributes
44
- });
45
- }
46
- for (const attribute of shaderLayout.attributes) {
47
- if (!usedAttributes.has(attribute.name)) {
48
- vertexBufferLayouts.push({
49
- arrayStride: decodeVertexFormat('float32x3').byteLength,
50
- stepMode: attribute.stepMode || (attribute.name.startsWith('instance') ? 'instance' : 'vertex'),
51
- attributes: [{
52
- format: getWebGPUVertexFormat('float32x3'),
53
- offset: 0,
54
- shaderLocation: attribute.location
55
- }]
56
- });
64
+ // Add any non-mapped attributes - TODO - avoid hardcoded types
65
+ for (const attribute of shaderLayout.attributes) {
66
+ if (!usedAttributes.has(attribute.name)) {
67
+ vertexBufferLayouts.push({
68
+ arrayStride: decodeVertexFormat('float32x3').byteLength,
69
+ stepMode: attribute.stepMode || (attribute.name.startsWith('instance') ? 'instance' : 'vertex'),
70
+ attributes: [
71
+ {
72
+ format: getWebGPUVertexFormat('float32x3'),
73
+ offset: 0,
74
+ shaderLocation: attribute.location
75
+ }
76
+ ]
77
+ });
78
+ }
57
79
  }
58
- }
59
- return vertexBufferLayouts;
80
+ return vertexBufferLayouts;
60
81
  }
61
82
  export function getBufferSlots(shaderLayout, bufferLayout) {
62
- const usedAttributes = new Set();
63
- let bufferSlot = 0;
64
- const bufferSlots = {};
65
- for (const mapping of bufferLayout) {
66
- if ('attributes' in mapping) {
67
- for (const interleaved of mapping.attributes) {
68
- usedAttributes.add(interleaved.attribute);
69
- }
70
- } else {
71
- usedAttributes.add(mapping.name);
83
+ const usedAttributes = new Set();
84
+ let bufferSlot = 0;
85
+ const bufferSlots = {};
86
+ // First handle any buffers mentioned in `bufferLayout`
87
+ for (const mapping of bufferLayout) {
88
+ // interleaved mapping {..., attributes: [{...}, ...]}
89
+ if ('attributes' in mapping) {
90
+ for (const interleaved of mapping.attributes) {
91
+ usedAttributes.add(interleaved.attribute);
92
+ }
93
+ // non-interleaved mapping (just set offset and stride)
94
+ }
95
+ else {
96
+ usedAttributes.add(mapping.name);
97
+ }
98
+ bufferSlots[mapping.name] = bufferSlot++;
72
99
  }
73
- bufferSlots[mapping.name] = bufferSlot++;
74
- }
75
- for (const attribute of shaderLayout.attributes) {
76
- if (!usedAttributes.has(attribute.name)) {
77
- bufferSlots[attribute.name] = bufferSlot++;
100
+ // Add any non-mapped attributes
101
+ for (const attribute of shaderLayout.attributes) {
102
+ if (!usedAttributes.has(attribute.name)) {
103
+ bufferSlots[attribute.name] = bufferSlot++;
104
+ }
78
105
  }
79
- }
80
- return bufferSlots;
106
+ return bufferSlots;
81
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
+ */
82
113
  function findAttributeLayout(shaderLayout, name, attributeNames) {
83
- const attribute = shaderLayout.attributes.find(attribute => attribute.name === name);
84
- if (!attribute) {
85
- log.warn(`Unknown attribute ${name}`)();
86
- return null;
87
- }
88
- if (attributeNames.has(name)) {
89
- throw new Error(`Duplicate attribute ${name}`);
90
- }
91
- attributeNames.add(name);
92
- return attribute;
114
+ const attribute = shaderLayout.attributes.find(attribute => attribute.name === name);
115
+ if (!attribute) {
116
+ log.warn(`Unknown attribute ${name}`)();
117
+ return null;
118
+ }
119
+ if (attributeNames.has(name)) {
120
+ throw new Error(`Duplicate attribute ${name}`);
121
+ }
122
+ attributeNames.add(name);
123
+ return attribute;
93
124
  }
94
- //# sourceMappingURL=get-vertex-buffer-layout.js.map