@luma.gl/webgpu 9.1.4 → 9.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luma.gl/webgpu",
3
- "version": "9.1.4",
3
+ "version": "9.1.6",
4
4
  "description": "WebGPU adapter for the luma.gl core API",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -43,5 +43,5 @@
43
43
  "@probe.gl/env": "^4.0.8",
44
44
  "@webgpu/types": "^0.1.34"
45
45
  },
46
- "gitHead": "553efa111ddb2709b2278d1e3f6c83cb66a36052"
46
+ "gitHead": "a0c83f5e6bdd9cdf59917ecf01ef958432c42b86"
47
47
  }
@@ -46,7 +46,8 @@ export function getShaderLayoutBinding(
46
46
  ): BindingDeclaration | null {
47
47
  const bindingLayout = shaderLayout.bindings.find(
48
48
  binding =>
49
- binding.name === bindingName || `${binding.name}uniforms` === bindingName.toLocaleLowerCase()
49
+ binding.name === bindingName ||
50
+ `${binding.name.toLocaleLowerCase()}uniforms` === bindingName.toLocaleLowerCase()
50
51
  );
51
52
  if (!bindingLayout) {
52
53
  log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();
@@ -0,0 +1,125 @@
1
+ import {
2
+ PipelineLayout,
3
+ PipelineLayoutProps,
4
+ StorageBufferBindingLayout,
5
+ StorageTextureBindingLayout
6
+ } from '@luma.gl/core';
7
+ import {WebGPUDevice} from '../webgpu-device';
8
+
9
+ const VISIBILITY_ALL = GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE;
10
+
11
+ export class WebGPUPipelineLayout extends PipelineLayout {
12
+ device: WebGPUDevice;
13
+ handle: GPUPipelineLayout;
14
+
15
+ constructor(device: WebGPUDevice, props: PipelineLayoutProps) {
16
+ super(device, props);
17
+
18
+ this.device = device;
19
+
20
+ const bindGroupEntries = this.mapShaderLayoutToBindGroupEntries();
21
+
22
+ this.handle = this.device.handle.createPipelineLayout({
23
+ label: props?.id ?? 'unnamed-pipeline-layout',
24
+ bindGroupLayouts: [
25
+ // TODO (kaapp): We can cache these to re-use them across
26
+ // layers, particularly if using a separate group for injected
27
+ // bindings (e.g. project/lighting)
28
+ this.device.handle.createBindGroupLayout({
29
+ label: 'bind-group-layout',
30
+ entries: bindGroupEntries
31
+ })
32
+ ]
33
+ });
34
+ }
35
+
36
+ override destroy(): void {
37
+ // WebGPUPipelineLayout has no destroy method.
38
+ // @ts-expect-error
39
+ this.handle = null;
40
+ }
41
+
42
+ protected mapShaderLayoutToBindGroupEntries(): GPUBindGroupLayoutEntry[] {
43
+ // Set up the pipeline layout
44
+ // TODO (kaapp): This only supports the first group, but so does the rest of the code
45
+ const bindGroupEntries: GPUBindGroupLayoutEntry[] = [];
46
+
47
+ for (let i = 0; i < this.props.shaderLayout.bindings.length; i++) {
48
+ const binding = this.props.shaderLayout.bindings[i];
49
+ const bindingTypeInfo: Omit<GPUBindGroupLayoutEntry, 'binding' | 'visibility'> = {};
50
+
51
+ switch (binding.type) {
52
+ case 'uniform': {
53
+ bindingTypeInfo.buffer = {
54
+ type: 'uniform',
55
+ hasDynamicOffset: binding.hasDynamicOffset,
56
+ minBindingSize: binding.minBindingSize
57
+ };
58
+ break;
59
+ }
60
+
61
+ case 'read-only-storage': {
62
+ bindingTypeInfo.buffer = {
63
+ type: 'read-only-storage',
64
+ hasDynamicOffset: binding.hasDynamicOffset,
65
+ minBindingSize: binding.minBindingSize
66
+ };
67
+ break;
68
+ }
69
+
70
+ case 'sampler': {
71
+ bindingTypeInfo.sampler = {
72
+ type: binding.samplerType
73
+ };
74
+ break;
75
+ }
76
+
77
+ case 'storage': {
78
+ if (isStorageTextureBindingLayout(binding)) {
79
+ bindingTypeInfo.storageTexture = {
80
+ // TODO (kaapp): Not all formats in the binding layout are supported
81
+ // by WebGPU, but at least it will provide a clear error for now.
82
+ format: binding.format as GPUTextureFormat,
83
+ access: binding.access,
84
+ viewDimension: binding.viewDimension
85
+ };
86
+ } else {
87
+ bindingTypeInfo.buffer = {
88
+ type: 'storage',
89
+ hasDynamicOffset: binding.hasDynamicOffset,
90
+ minBindingSize: binding.minBindingSize
91
+ };
92
+ }
93
+ break;
94
+ }
95
+
96
+ case 'texture': {
97
+ bindingTypeInfo.texture = {
98
+ multisampled: binding.multisampled,
99
+ sampleType: binding.sampleType,
100
+ viewDimension: binding.viewDimension
101
+ };
102
+ break;
103
+ }
104
+
105
+ default: {
106
+ console.warn('unhandled binding type when creating pipeline descriptor');
107
+ }
108
+ }
109
+
110
+ bindGroupEntries.push({
111
+ binding: binding.location,
112
+ visibility: binding.visibility || VISIBILITY_ALL,
113
+ ...bindingTypeInfo
114
+ });
115
+ }
116
+
117
+ return bindGroupEntries;
118
+ }
119
+ }
120
+
121
+ const isStorageTextureBindingLayout = (
122
+ maybe: StorageBufferBindingLayout | StorageTextureBindingLayout
123
+ ): maybe is StorageTextureBindingLayout => {
124
+ return (maybe as StorageTextureBindingLayout).format !== undefined;
125
+ };
@@ -168,6 +168,10 @@ export class WebGPURenderPipeline extends RenderPipeline {
168
168
  ]
169
169
  };
170
170
 
171
+ const layout = this.device.createPipelineLayout({
172
+ shaderLayout: this.shaderLayout
173
+ });
174
+
171
175
  // Create a partially populated descriptor
172
176
  const descriptor: GPURenderPipelineDescriptor = {
173
177
  vertex,
@@ -175,7 +179,7 @@ export class WebGPURenderPipeline extends RenderPipeline {
175
179
  primitive: {
176
180
  topology: this.props.topology
177
181
  },
178
- layout: 'auto'
182
+ layout: layout.handle
179
183
  };
180
184
 
181
185
  if (this.props.parameters.depthWriteEnabled && this.props.parameters.depthCompare) {
@@ -28,7 +28,8 @@ import type {
28
28
  TransformFeedbackProps,
29
29
  QuerySet,
30
30
  QuerySetProps,
31
- DeviceProps
31
+ DeviceProps,
32
+ PipelineLayoutProps,
32
33
  } from '@luma.gl/core';
33
34
  import {Device, DeviceFeatures} from '@luma.gl/core';
34
35
  import {WebGPUBuffer} from './resources/webgpu-buffer';
@@ -46,6 +47,7 @@ import {WebGPUVertexArray} from './resources/webgpu-vertex-array';
46
47
 
47
48
  import {WebGPUCanvasContext} from './webgpu-canvas-context';
48
49
  import {WebGPUQuerySet} from './resources/webgpu-query-set';
50
+ import {WebGPUPipelineLayout} from './resources/webgpu-pipeline-layout';
49
51
 
50
52
  /** WebGPU Device implementation */
51
53
  export class WebGPUDevice extends Device {
@@ -194,6 +196,10 @@ export class WebGPUDevice extends Device {
194
196
  return new WebGPUCanvasContext(this, this.adapter, props);
195
197
  }
196
198
 
199
+ createPipelineLayout(props: PipelineLayoutProps): WebGPUPipelineLayout {
200
+ return new WebGPUPipelineLayout(this, props);
201
+ }
202
+
197
203
  submit(): void {
198
204
  const commandBuffer = this.commandEncoder?.finish();
199
205
  if (commandBuffer) {
@@ -205,7 +211,6 @@ export class WebGPUDevice extends Device {
205
211
  }
206
212
  });
207
213
  }
208
- this.commandEncoder = null;
209
214
  }
210
215
 
211
216
  // PRIVATE METHODS