@luma.gl/webgpu 9.0.0-alpha.10

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 (128) hide show
  1. package/LICENSE +32 -0
  2. package/README.md +1 -0
  3. package/dist/adapter/helpers/accessor-to-format.d.ts +1 -0
  4. package/dist/adapter/helpers/accessor-to-format.d.ts.map +1 -0
  5. package/dist/adapter/helpers/accessor-to-format.js +2 -0
  6. package/dist/adapter/helpers/accessor-to-format.js.map +1 -0
  7. package/dist/adapter/helpers/convert-texture-format.d.ts +5 -0
  8. package/dist/adapter/helpers/convert-texture-format.d.ts.map +1 -0
  9. package/dist/adapter/helpers/convert-texture-format.js +8 -0
  10. package/dist/adapter/helpers/convert-texture-format.js.map +1 -0
  11. package/dist/adapter/helpers/generate-mipmaps.d.ts +10 -0
  12. package/dist/adapter/helpers/generate-mipmaps.d.ts.map +1 -0
  13. package/dist/adapter/helpers/generate-mipmaps.js +95 -0
  14. package/dist/adapter/helpers/generate-mipmaps.js.map +1 -0
  15. package/dist/adapter/helpers/get-bind-group.d.ts +13 -0
  16. package/dist/adapter/helpers/get-bind-group.d.ts.map +1 -0
  17. package/dist/adapter/helpers/get-bind-group.js +60 -0
  18. package/dist/adapter/helpers/get-bind-group.js.map +1 -0
  19. package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts +12 -0
  20. package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts.map +1 -0
  21. package/dist/adapter/helpers/get-vertex-buffer-layout.js +98 -0
  22. package/dist/adapter/helpers/get-vertex-buffer-layout.js.map +1 -0
  23. package/dist/adapter/helpers/webgpu-parameters.d.ts +9 -0
  24. package/dist/adapter/helpers/webgpu-parameters.d.ts.map +1 -0
  25. package/dist/adapter/helpers/webgpu-parameters.js +143 -0
  26. package/dist/adapter/helpers/webgpu-parameters.js.map +1 -0
  27. package/dist/adapter/resources/webgpu-buffer.d.ts +17 -0
  28. package/dist/adapter/resources/webgpu-buffer.d.ts.map +1 -0
  29. package/dist/adapter/resources/webgpu-buffer.js +80 -0
  30. package/dist/adapter/resources/webgpu-buffer.js.map +1 -0
  31. package/dist/adapter/resources/webgpu-command-encoder.d.ts +44 -0
  32. package/dist/adapter/resources/webgpu-command-encoder.d.ts.map +1 -0
  33. package/dist/adapter/resources/webgpu-command-encoder.js +66 -0
  34. package/dist/adapter/resources/webgpu-command-encoder.js.map +1 -0
  35. package/dist/adapter/resources/webgpu-compute-pass.d.ts +32 -0
  36. package/dist/adapter/resources/webgpu-compute-pass.d.ts.map +1 -0
  37. package/dist/adapter/resources/webgpu-compute-pass.js +58 -0
  38. package/dist/adapter/resources/webgpu-compute-pass.js.map +1 -0
  39. package/dist/adapter/resources/webgpu-compute-pipeline.d.ts +12 -0
  40. package/dist/adapter/resources/webgpu-compute-pipeline.d.ts.map +1 -0
  41. package/dist/adapter/resources/webgpu-compute-pipeline.js +27 -0
  42. package/dist/adapter/resources/webgpu-compute-pipeline.js.map +1 -0
  43. package/dist/adapter/resources/webgpu-external-texture.d.ts +18 -0
  44. package/dist/adapter/resources/webgpu-external-texture.d.ts.map +1 -0
  45. package/dist/adapter/resources/webgpu-external-texture.js +30 -0
  46. package/dist/adapter/resources/webgpu-external-texture.js.map +1 -0
  47. package/dist/adapter/resources/webgpu-framebuffer.d.ts +29 -0
  48. package/dist/adapter/resources/webgpu-framebuffer.d.ts.map +1 -0
  49. package/dist/adapter/resources/webgpu-framebuffer.js +111 -0
  50. package/dist/adapter/resources/webgpu-framebuffer.js.map +1 -0
  51. package/dist/adapter/resources/webgpu-query.d.ts +1 -0
  52. package/dist/adapter/resources/webgpu-query.d.ts.map +1 -0
  53. package/dist/adapter/resources/webgpu-query.js +2 -0
  54. package/dist/adapter/resources/webgpu-query.js.map +1 -0
  55. package/dist/adapter/resources/webgpu-render-pass.d.ts +34 -0
  56. package/dist/adapter/resources/webgpu-render-pass.d.ts.map +1 -0
  57. package/dist/adapter/resources/webgpu-render-pass.js +98 -0
  58. package/dist/adapter/resources/webgpu-render-pass.js.map +1 -0
  59. package/dist/adapter/resources/webgpu-render-pipeline.d.ts +44 -0
  60. package/dist/adapter/resources/webgpu-render-pipeline.d.ts.map +1 -0
  61. package/dist/adapter/resources/webgpu-render-pipeline.js +164 -0
  62. package/dist/adapter/resources/webgpu-render-pipeline.js.map +1 -0
  63. package/dist/adapter/resources/webgpu-sampler.d.ts +16 -0
  64. package/dist/adapter/resources/webgpu-sampler.d.ts.map +1 -0
  65. package/dist/adapter/resources/webgpu-sampler.js +25 -0
  66. package/dist/adapter/resources/webgpu-sampler.js.map +1 -0
  67. package/dist/adapter/resources/webgpu-shader.d.ts +21 -0
  68. package/dist/adapter/resources/webgpu-shader.d.ts.map +1 -0
  69. package/dist/adapter/resources/webgpu-shader.js +64 -0
  70. package/dist/adapter/resources/webgpu-shader.js.map +1 -0
  71. package/dist/adapter/resources/webgpu-texture.d.ts +39 -0
  72. package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -0
  73. package/dist/adapter/resources/webgpu-texture.js +111 -0
  74. package/dist/adapter/resources/webgpu-texture.js.map +1 -0
  75. package/dist/adapter/webgpu-canvas-context.d.ts +32 -0
  76. package/dist/adapter/webgpu-canvas-context.d.ts.map +1 -0
  77. package/dist/adapter/webgpu-canvas-context.js +95 -0
  78. package/dist/adapter/webgpu-canvas-context.js.map +1 -0
  79. package/dist/adapter/webgpu-device.d.ts +67 -0
  80. package/dist/adapter/webgpu-device.d.ts.map +1 -0
  81. package/dist/adapter/webgpu-device.js +242 -0
  82. package/dist/adapter/webgpu-device.js.map +1 -0
  83. package/dist/adapter/webgpu-types.d.ts +1 -0
  84. package/dist/adapter/webgpu-types.d.ts.map +1 -0
  85. package/dist/adapter/webgpu-types.js +2 -0
  86. package/dist/adapter/webgpu-types.js.map +1 -0
  87. package/dist/bundle.d.ts +2 -0
  88. package/dist/bundle.d.ts.map +1 -0
  89. package/dist/bundle.js +5 -0
  90. package/dist/bundle.js.map +1 -0
  91. package/dist/glsl/glsllang.d.ts +3 -0
  92. package/dist/glsl/glsllang.d.ts.map +1 -0
  93. package/dist/glsl/glsllang.js +10 -0
  94. package/dist/glsl/glsllang.js.map +1 -0
  95. package/dist/index.d.ts +8 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +8 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/init.d.ts +2 -0
  100. package/dist/init.d.ts.map +1 -0
  101. package/dist/init.js +4 -0
  102. package/dist/init.js.map +1 -0
  103. package/package.json +36 -0
  104. package/src/adapter/helpers/accessor-to-format.ts +101 -0
  105. package/src/adapter/helpers/convert-texture-format.ts +10 -0
  106. package/src/adapter/helpers/generate-mipmaps.ts +107 -0
  107. package/src/adapter/helpers/get-bind-group.ts +82 -0
  108. package/src/adapter/helpers/get-vertex-buffer-layout.ts +123 -0
  109. package/src/adapter/helpers/webgpu-parameters.ts +229 -0
  110. package/src/adapter/resources/webgpu-buffer.ts +92 -0
  111. package/src/adapter/resources/webgpu-command-encoder.ts +112 -0
  112. package/src/adapter/resources/webgpu-compute-pass.ts +74 -0
  113. package/src/adapter/resources/webgpu-compute-pipeline.ts +34 -0
  114. package/src/adapter/resources/webgpu-external-texture.ts +37 -0
  115. package/src/adapter/resources/webgpu-framebuffer.ts +120 -0
  116. package/src/adapter/resources/webgpu-query.ts +43 -0
  117. package/src/adapter/resources/webgpu-render-pass.ts +131 -0
  118. package/src/adapter/resources/webgpu-render-pipeline.ts +246 -0
  119. package/src/adapter/resources/webgpu-sampler.ts +32 -0
  120. package/src/adapter/resources/webgpu-shader.ts +72 -0
  121. package/src/adapter/resources/webgpu-texture.ts +244 -0
  122. package/src/adapter/webgpu-canvas-context.ts +102 -0
  123. package/src/adapter/webgpu-device.ts +294 -0
  124. package/src/adapter/webgpu-types.ts +0 -0
  125. package/src/bundle.ts +4 -0
  126. package/src/glsl/glsllang.ts +14 -0
  127. package/src/index.ts +13 -0
  128. package/src/init.ts +4 -0
@@ -0,0 +1,43 @@
1
+ /*
2
+ import {Resource, Query, QueryProps} from '@luma.gl/api';
3
+ import WebGPUDevice from '../webgpu-device';
4
+
5
+ export type WebGPUQueryProps = QueryProps & {
6
+ handle?: any;
7
+ };
8
+
9
+ const DEFAULT_QUERY_PROPS: Required<WebGPUQueryProps> = {
10
+ id: undefined,
11
+ handle: undefined,
12
+ userData: undefined,
13
+ type: 'timestamp',
14
+ count: 1,
15
+ pipelineStatistics: []
16
+ };
17
+
18
+ /**
19
+ * Immutable
20
+ *
21
+ class WebGPUQuery extends Resource<WebGPUQueryProps> implements Query {
22
+ readonly device: WebGPUDevice;
23
+ readonly handle: GPUQuerySet;
24
+
25
+ constructor(device: WebGPUDevice, props: WebGPUQueryProps) {
26
+ super(device, props, DEFAULT_QUERY_PROPS);
27
+ this.handle = this.props.handle as GPUQuerySet || this.createHandle();
28
+ this.handle.label = this.props.id;
29
+ }
30
+
31
+ protected createHandle() {
32
+ return this.device.handle.createQuerySet({
33
+ type: this.props.type,
34
+ count: this.props.count,
35
+ pipelineStatistics: this.props.pipelineStatistics
36
+ });
37
+ }
38
+
39
+ destroy() {
40
+ this.handle.destroy();
41
+ }
42
+ }
43
+ */
@@ -0,0 +1,131 @@
1
+ import type {RenderPassProps, RenderPassParameters, Binding} from '@luma.gl/api';
2
+ import {Buffer, RenderPass, RenderPipeline, cast, log} from '@luma.gl/api';
3
+ import WebGPUDevice from '../webgpu-device';
4
+ import WebGPUBuffer from './webgpu-buffer';
5
+ // import WebGPUCommandEncoder from './webgpu-command-encoder';
6
+ import WebGPURenderPipeline from './webgpu-render-pipeline';
7
+
8
+ export default class WebGPURenderPass extends RenderPass {
9
+ readonly device: WebGPUDevice;
10
+ readonly handle: GPURenderPassEncoder;
11
+
12
+ /** Active pipeline */
13
+ pipeline: WebGPURenderPipeline | null = null;
14
+
15
+ constructor(device: WebGPUDevice, props: RenderPassProps = {}) {
16
+ super(device, props);
17
+ this.device = device;
18
+ const framebuffer = props.framebuffer || device.canvasContext.getCurrentFramebuffer();
19
+ // @ts-expect-error
20
+ const renderPassDescriptor = framebuffer.renderPassDescriptor;
21
+ this.handle = this.props.handle || device.commandEncoder.beginRenderPass(renderPassDescriptor);
22
+ this.handle.label = this.props.id;
23
+ }
24
+
25
+ destroy() {}
26
+
27
+ endPass(): void {
28
+ this.handle.endPass();
29
+ }
30
+
31
+ setPipeline(pipeline: RenderPipeline): void {
32
+ this.pipeline = cast<WebGPURenderPipeline>(pipeline);
33
+ this.handle.setPipeline(this.pipeline.handle);
34
+ }
35
+
36
+ /** Sets an array of bindings (uniform buffers, samplers, textures, ...) */
37
+ setBindings(bindings: Record<string, Binding>): void {
38
+ this.pipeline?.setBindings(bindings);
39
+ const bindGroup = this.pipeline?._getBindGroup();
40
+ if (bindGroup) {
41
+ this.handle.setBindGroup(0, bindGroup);
42
+ }
43
+ }
44
+
45
+ setIndexBuffer(
46
+ buffer: Buffer,
47
+ indexFormat: GPUIndexFormat,
48
+ offset: number = 0,
49
+ size?: number
50
+ ): void {
51
+ this.handle.setIndexBuffer(cast<WebGPUBuffer>(buffer).handle, indexFormat, offset, size);
52
+ }
53
+
54
+ setVertexBuffer(slot: number, buffer: Buffer, offset: number = 0): void {
55
+ this.handle.setVertexBuffer(slot, cast<WebGPUBuffer>(buffer).handle, offset);
56
+ }
57
+
58
+ draw(options: {
59
+ vertexCount?: number;
60
+ indexCount?: number;
61
+ instanceCount?: number;
62
+ firstVertex?: number;
63
+ firstIndex?: number;
64
+ firstInstance?: number;
65
+ baseVertex?: number;
66
+ }): void {
67
+ if (options.indexCount) {
68
+ this.handle.drawIndexed(
69
+ options.indexCount,
70
+ options.instanceCount,
71
+ options.firstIndex,
72
+ options.baseVertex,
73
+ options.firstInstance
74
+ );
75
+ } else {
76
+ this.handle.draw(
77
+ options.vertexCount || 0,
78
+ options.instanceCount,
79
+ options.firstIndex,
80
+ options.firstInstance
81
+ );
82
+ }
83
+ }
84
+
85
+ drawIndirect(): void {
86
+ // drawIndirect(indirectBuffer: GPUBuffer, indirectOffset: number): void;
87
+ // drawIndexedIndirect(indirectBuffer: GPUBuffer, indirectOffset: number): void;
88
+ }
89
+
90
+ setParameters(parameters: RenderPassParameters): void {
91
+ const {blendConstant, stencilReference, scissorRect, viewport} = parameters;
92
+ if (blendConstant) {
93
+ this.handle.setBlendConstant(blendConstant);
94
+ }
95
+ if (stencilReference) {
96
+ this.handle.setStencilReference(stencilReference);
97
+ }
98
+ if (scissorRect) {
99
+ this.handle.setScissorRect(scissorRect[0], scissorRect[1], scissorRect[2], scissorRect[3]);
100
+ }
101
+ // TODO - explain how 3 dimensions vs 2 in WebGL works.
102
+ if (viewport) {
103
+ this.handle.setViewport(
104
+ viewport[0],
105
+ viewport[1],
106
+ viewport[2],
107
+ viewport[3],
108
+ viewport[4],
109
+ viewport[5]
110
+ );
111
+ }
112
+ }
113
+
114
+ pushDebugGroup(groupLabel: string): void {
115
+ this.handle.pushDebugGroup(groupLabel);
116
+ }
117
+ popDebugGroup(): void {
118
+ this.handle.popDebugGroup();
119
+ }
120
+ insertDebugMarker(markerLabel: string): void {
121
+ this.handle.insertDebugMarker(markerLabel);
122
+ }
123
+
124
+ // writeTimestamp(querySet: GPUQuerySet, queryIndex: number): void;
125
+ // beginOcclusionQuery(queryIndex: number): void;
126
+ // endOcclusionQuery(): void;
127
+ // beginPipelineStatisticsQuery(querySet: GPUQuerySet, queryIndex: number): void;
128
+ // endPipelineStatisticsQuery(querySet: GPUQuerySet, queryIndex: number): void;
129
+
130
+ // executeBundles(bundles: Iterable<GPURenderBundle>): void;
131
+ }
@@ -0,0 +1,246 @@
1
+ import type {Binding, RenderPass, Shader} from '@luma.gl/api';
2
+ import {Buffer, RenderPipeline, RenderPipelineProps, cast, log, isObjectEmpty} from '@luma.gl/api';
3
+ import {applyParametersToRenderPipelineDescriptor} from '../helpers/webgpu-parameters';
4
+ import {getWebGPUTextureFormat} from '../helpers/convert-texture-format';
5
+ import {getBindGroup} from '../helpers/get-bind-group';
6
+ import {getVertexBufferLayout, getBufferSlots} from '../helpers/get-vertex-buffer-layout';
7
+ // import {convertAttributesVertexBufferToLayout} from '../helpers/get-vertex-buffer-layout';
8
+ // import {mapAccessorToWebGPUFormat} from './helpers/accessor-to-format';
9
+ // import type {BufferAccessors} from './webgpu-pipeline';
10
+
11
+ import type WebGPUDevice from '../webgpu-device';
12
+ import type WebGPUBuffer from './webgpu-buffer';
13
+ import type WebGPUShader from './webgpu-shader';
14
+ import type WebGPURenderPass from './webgpu-render-pass';
15
+
16
+ // RENDER PIPELINE
17
+
18
+ /** Creates a new render pipeline when parameters change */
19
+ export default class WebGPURenderPipeline extends RenderPipeline {
20
+ device: WebGPUDevice;
21
+ handle: GPURenderPipeline;
22
+
23
+ vs: WebGPUShader;
24
+ fs: WebGPUShader | null = null;
25
+
26
+ private _bufferSlots: Record<string, number>;
27
+ private _buffers: Buffer[];
28
+ private _indexBuffer: WebGPUBuffer | null = null;
29
+ // private _firstIndex: number;
30
+ // private _lastIndex: number;
31
+
32
+ /** For internal use to create BindGroups */
33
+ private _bindGroupLayout: GPUBindGroupLayout;
34
+ private _bindGroup: GPUBindGroup | null = null;
35
+
36
+ constructor(device: WebGPUDevice, props: RenderPipelineProps) {
37
+ super(device, props);
38
+ this.device = device;
39
+ this.handle = (this.props.handle as GPURenderPipeline) || this.createHandle();
40
+ this.handle.label = this.props.id;
41
+
42
+ this.vs = cast<WebGPUShader>(props.vs);
43
+ this.fs = cast<WebGPUShader>(props.fs);
44
+
45
+ this._bufferSlots = getBufferSlots(this.props.layout, this.props.bufferMap);
46
+ this._buffers = new Array<Buffer>(Object.keys(this._bufferSlots).length).fill(null);
47
+ this._bindGroupLayout = this.handle.getBindGroupLayout(0);
48
+ }
49
+
50
+ protected createHandle(): GPURenderPipeline {
51
+ const descriptor = this._getRenderPipelineDescriptor();
52
+ const renderPipeline = this.device.handle.createRenderPipeline(descriptor);
53
+ log.groupCollapsed(1, `new WebGPRenderPipeline(${this.id})`)();
54
+ log.log(1, JSON.stringify(descriptor, null, 2))();
55
+ log.groupEnd(1)();
56
+ return renderPipeline;
57
+ }
58
+
59
+ destroy() {
60
+ // WebGPURenderPipeline has no destroy method.
61
+ }
62
+
63
+ setIndexBuffer(indexBuffer: Buffer): void {
64
+ this._indexBuffer = cast<WebGPUBuffer>(indexBuffer);
65
+ }
66
+
67
+ setAttributes(attributes: Record<string, Buffer>): void {
68
+ for (const [name, buffer] of Object.entries(attributes)) {
69
+ const bufferIndex = this._bufferSlots[name];
70
+ if (bufferIndex >= 0) {
71
+ this._buffers[bufferIndex] = buffer;
72
+ } else {
73
+ throw new Error(
74
+ `Setting attribute '${name}' not listed in shader layout for program ${this.id}`
75
+ );
76
+ }
77
+ }
78
+ // for (let i = 0; i < this._bufferSlots.length; ++i) {
79
+ // const bufferName = this._bufferSlots[i];
80
+ // if (attributes[bufferName]) {
81
+ // this.handle
82
+ // }
83
+ // }
84
+ }
85
+
86
+ /** Set the bindings */
87
+ setBindings(bindings: Record<string, Binding>): void {
88
+ if (!isObjectEmpty(this.props.bindings)) {
89
+ Object.assign(this.props.bindings, bindings);
90
+ // Set up the bindings
91
+ this._bindGroup = getBindGroup(
92
+ this.device.handle,
93
+ this._bindGroupLayout,
94
+ this.props.layout,
95
+ this.props.bindings
96
+ );
97
+ }
98
+ }
99
+
100
+ setUniforms(uniforms: Record<string, any>): void {
101
+ if (!isObjectEmpty(uniforms)) {
102
+ throw new Error('WebGPU does not support uniforms');
103
+ }
104
+ }
105
+
106
+ _getBuffers() {
107
+ return this._buffers;
108
+ }
109
+
110
+ /** Return a bind group created by setBindings */
111
+ _getBindGroup() {
112
+ // assert(this._bindGroup);
113
+ return this._bindGroup;
114
+ }
115
+
116
+ /** Populate the complex WebGPU GPURenderPipelineDescriptor */
117
+ protected _getRenderPipelineDescriptor() {
118
+ // Set up the vertex stage
119
+ const vertex: GPUVertexState = {
120
+ module: cast<WebGPUShader>(this.props.vs).handle,
121
+ entryPoint: this.props.vsEntryPoint || 'main',
122
+ buffers: getVertexBufferLayout(this.props.layout, this.props.bufferMap)
123
+ };
124
+
125
+ // Set up the fragment stage
126
+ let fragment: GPUFragmentState | undefined;
127
+ if (this.props.fs) {
128
+ fragment = {
129
+ module: cast<WebGPUShader>(this.props.fs).handle,
130
+ entryPoint: this.props.fsEntryPoint || 'main',
131
+ targets: [
132
+ {
133
+ // TODO exclamation mark hack!
134
+ format: getWebGPUTextureFormat(this.device?.canvasContext?.format!)
135
+ }
136
+ ]
137
+ };
138
+ }
139
+
140
+ // WebGPU has more restrictive topology support than WebGL
141
+ switch (this.props.topology) {
142
+ case 'triangle-fan':
143
+ case 'line-loop':
144
+ throw new Error(`WebGPU does not support primitive topology ${this.props.topology}`);
145
+ default:
146
+ }
147
+
148
+ // Create a partially populated descriptor
149
+ let descriptor: GPURenderPipelineDescriptor = {
150
+ vertex,
151
+ fragment,
152
+ primitive: {
153
+ topology: this.props.topology
154
+ }
155
+ };
156
+
157
+ // Set parameters on the descriptor
158
+ applyParametersToRenderPipelineDescriptor(descriptor, this.props.parameters);
159
+
160
+ return descriptor;
161
+ }
162
+
163
+ draw(options: {
164
+ renderPass?: RenderPass;
165
+ vertexCount?: number;
166
+ indexCount?: number;
167
+ instanceCount?: number;
168
+ firstVertex?: number;
169
+ firstIndex?: number;
170
+ firstInstance?: number;
171
+ baseVertex?: number;
172
+ }): void {
173
+ const webgpuRenderPass =
174
+ cast<WebGPURenderPass>(options.renderPass) || this.device.getDefaultRenderPass();
175
+
176
+ // Set pipeline
177
+ webgpuRenderPass.handle.setPipeline(this.handle);
178
+
179
+ // Set bindings (uniform buffers, textures etc)
180
+ if (this._getBindGroup()) {
181
+ webgpuRenderPass.handle.setBindGroup(0, this._getBindGroup());
182
+ }
183
+
184
+ // Set attributes
185
+ this._setAttributeBuffers(webgpuRenderPass);
186
+
187
+ // Draw
188
+ if (options.indexCount) {
189
+ webgpuRenderPass.handle.drawIndexed(
190
+ options.indexCount,
191
+ options.instanceCount,
192
+ options.firstIndex,
193
+ options.baseVertex,
194
+ options.firstInstance
195
+ );
196
+ } else {
197
+ webgpuRenderPass.handle.draw(
198
+ options.vertexCount || 0,
199
+ options.instanceCount,
200
+ options.firstIndex,
201
+ options.firstInstance
202
+ );
203
+ }
204
+ }
205
+
206
+ _setAttributeBuffers(webgpuRenderPass: WebGPURenderPass) {
207
+ if (this._indexBuffer) {
208
+ webgpuRenderPass.handle.setIndexBuffer(this._indexBuffer.handle, this._indexBuffer.props.indexType);
209
+ }
210
+
211
+ const buffers = this._getBuffers();
212
+ for (let i = 0; i < buffers.length; ++i) {
213
+ const buffer = cast<WebGPUBuffer>(buffers[i]);
214
+ if (!buffer) {
215
+ const attribute = this.props.layout.attributes.find(
216
+ (attribute) => attribute.location === i
217
+ );
218
+ throw new Error(
219
+ `No buffer provided for attribute '${attribute?.name || ''}' in Model '${this.props.id}'`
220
+ );
221
+ }
222
+ webgpuRenderPass.handle.setVertexBuffer(i, buffer.handle);
223
+ }
224
+
225
+ // TODO - HANDLE buffer maps
226
+ /*
227
+ for (const [bufferName, attributeMapping] of Object.entries(this.props.bufferMap)) {
228
+ const buffer = cast<WebGPUBuffer>(this.props.attributes[bufferName]);
229
+ if (!buffer) {
230
+ log.warn(`Missing buffer for buffer map ${bufferName}`)();
231
+ continue;
232
+ }
233
+
234
+ if ('location' in attributeMapping) {
235
+ // @ts-expect-error TODO model must not depend on webgpu
236
+ renderPass.handle.setVertexBuffer(layout.location, buffer.handle);
237
+ } else {
238
+ for (const [bufferName, mapping] of Object.entries(attributeMapping)) {
239
+ // @ts-expect-error TODO model must not depend on webgpu
240
+ renderPass.handle.setVertexBuffer(field.location, buffer.handle);
241
+ }
242
+ }
243
+ }
244
+ */
245
+ }
246
+ }
@@ -0,0 +1,32 @@
1
+ import {Sampler, SamplerProps} from '@luma.gl/api';
2
+ import type WebGPUDevice from '../webgpu-device';
3
+
4
+ export type WebGPUSamplerProps = SamplerProps & {
5
+ handle?: GPUSampler;
6
+ }
7
+
8
+ /**
9
+ *
10
+ */
11
+ export default class WebGPUSampler extends Sampler {
12
+ readonly device: WebGPUDevice;
13
+ readonly handle: GPUSampler;
14
+
15
+ constructor(device: WebGPUDevice, props: WebGPUSamplerProps) {
16
+ super(device, props);
17
+ this.device = device;
18
+
19
+ // Prepare sampler props
20
+ const samplerProps = this.props;
21
+ if (samplerProps.type !== 'comparison-sampler') {
22
+ delete samplerProps.compare;
23
+ }
24
+
25
+ this.handle = this.handle || this.device.handle.createSampler(this.props);
26
+ this.handle.label = this.props.id;
27
+ }
28
+
29
+ destroy(): void {
30
+ // this.handle.destroy();
31
+ }
32
+ }
@@ -0,0 +1,72 @@
1
+ import type {ShaderProps, CompilerMessage} from '@luma.gl/api';
2
+ import {Shader, log} from '@luma.gl/api';
3
+ import type WebGPUDevice from '../webgpu-device';
4
+
5
+ export type WebGPUShaderProps = ShaderProps & {
6
+ handle?: GPUShaderModule;
7
+ };
8
+
9
+ /**
10
+ * Immutable shader
11
+ */
12
+ export default class WebGPUShader extends Shader {
13
+ readonly device: WebGPUDevice;
14
+ readonly handle: GPUShaderModule;
15
+
16
+ constructor(device: WebGPUDevice, props: WebGPUShaderProps) {
17
+ super(device, props);
18
+ this.device = device;
19
+
20
+ this.device.handle.pushErrorScope('validation');
21
+
22
+ this.handle = this.props.handle || this.createHandle();
23
+ this.handle.label = this.props.id;
24
+
25
+ this._checkCompilationError(this.device.handle.popErrorScope());
26
+ }
27
+
28
+ async _checkCompilationError(errorScope: Promise<GPUError>): Promise<void> {
29
+ const error = await errorScope as GPUValidationError;
30
+ if (error) {
31
+ const shaderLog = await this.compilationInfo();
32
+ log.error(`Shader compilation error: ${error.message}`, shaderLog)();
33
+ // Note: Even though this error is asynchronous and thrown after the constructor completes,
34
+ // it will result in a useful stack trace leading back to the constructor
35
+ throw new Error(`Shader compilation error: ${error.message}`);
36
+ }
37
+ }
38
+
39
+ destroy() {
40
+ // this.handle.destroy();
41
+ }
42
+
43
+ protected createHandle(): GPUShaderModule {
44
+ const {source} = this.props;
45
+
46
+ let language = this.props.language;
47
+ // Compile from src
48
+ if (!language) {
49
+ // wgsl uses C++ "auto" style arrow notation
50
+ language = source.includes('->') ? 'wgsl' : 'glsl';
51
+ }
52
+
53
+ switch(language) {
54
+ case 'wgsl':
55
+ return this.device.handle.createShaderModule({code: source});
56
+ case 'glsl':
57
+ return this.device.handle.createShaderModule({
58
+ code: source,
59
+ // @ts-expect-error
60
+ transform: (glsl) => this.device.glslang.compileGLSL(glsl, type)
61
+ });
62
+ default:
63
+ throw new Error(language);
64
+ }
65
+ }
66
+
67
+ /** Returns compilation info for this shader */
68
+ async compilationInfo(): Promise<readonly CompilerMessage[]> {
69
+ const compilationInfo = await this.handle.compilationInfo();
70
+ return compilationInfo.messages;
71
+ }
72
+ }