@luma.gl/webgpu 9.0.0-beta.1 → 9.0.0-beta.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 (129) hide show
  1. package/dist/adapter/helpers/accessor-to-format.js +102 -1
  2. package/dist/adapter/helpers/convert-texture-format.d.ts.map +1 -1
  3. package/dist/adapter/helpers/convert-texture-format.js +8 -5
  4. package/dist/adapter/helpers/get-bind-group.d.ts +3 -3
  5. package/dist/adapter/helpers/get-bind-group.d.ts.map +1 -1
  6. package/dist/adapter/helpers/get-bind-group.js +57 -41
  7. package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts.map +1 -1
  8. package/dist/adapter/helpers/get-vertex-buffer-layout.js +117 -80
  9. package/dist/adapter/helpers/webgpu-parameters.d.ts.map +1 -1
  10. package/dist/adapter/helpers/webgpu-parameters.js +185 -125
  11. package/dist/adapter/resources/webgpu-buffer.d.ts +1 -1
  12. package/dist/adapter/resources/webgpu-buffer.d.ts.map +1 -1
  13. package/dist/adapter/resources/webgpu-buffer.js +119 -62
  14. package/dist/adapter/resources/webgpu-command-encoder.d.ts +7 -1
  15. package/dist/adapter/resources/webgpu-command-encoder.d.ts.map +1 -1
  16. package/dist/adapter/resources/webgpu-command-encoder.js +81 -49
  17. package/dist/adapter/resources/webgpu-compute-pass.d.ts +15 -9
  18. package/dist/adapter/resources/webgpu-compute-pass.d.ts.map +1 -1
  19. package/dist/adapter/resources/webgpu-compute-pass.js +76 -41
  20. package/dist/adapter/resources/webgpu-compute-pipeline.d.ts +14 -4
  21. package/dist/adapter/resources/webgpu-compute-pipeline.d.ts.map +1 -1
  22. package/dist/adapter/resources/webgpu-compute-pipeline.js +46 -19
  23. package/dist/adapter/resources/webgpu-external-texture.d.ts +2 -2
  24. package/dist/adapter/resources/webgpu-external-texture.d.ts.map +1 -1
  25. package/dist/adapter/resources/webgpu-external-texture.js +35 -18
  26. package/dist/adapter/resources/webgpu-framebuffer.d.ts +1 -1
  27. package/dist/adapter/resources/webgpu-framebuffer.d.ts.map +1 -1
  28. package/dist/adapter/resources/webgpu-framebuffer.js +14 -7
  29. package/dist/adapter/resources/webgpu-query-set.d.ts +17 -0
  30. package/dist/adapter/resources/webgpu-query-set.d.ts.map +1 -0
  31. package/dist/adapter/resources/webgpu-query-set.js +27 -0
  32. package/dist/adapter/resources/webgpu-render-pass.d.ts +4 -2
  33. package/dist/adapter/resources/webgpu-render-pass.d.ts.map +1 -1
  34. package/dist/adapter/resources/webgpu-render-pass.js +133 -105
  35. package/dist/adapter/resources/webgpu-render-pipeline.d.ts +52 -5
  36. package/dist/adapter/resources/webgpu-render-pipeline.d.ts.map +1 -1
  37. package/dist/adapter/resources/webgpu-render-pipeline.js +151 -78
  38. package/dist/adapter/resources/webgpu-sampler.d.ts +1 -1
  39. package/dist/adapter/resources/webgpu-sampler.d.ts.map +1 -1
  40. package/dist/adapter/resources/webgpu-sampler.js +21 -15
  41. package/dist/adapter/resources/webgpu-shader.d.ts +2 -5
  42. package/dist/adapter/resources/webgpu-shader.d.ts.map +1 -1
  43. package/dist/adapter/resources/webgpu-shader.js +45 -44
  44. package/dist/adapter/resources/webgpu-texture-view.d.ts +20 -0
  45. package/dist/adapter/resources/webgpu-texture-view.d.ts.map +1 -0
  46. package/dist/adapter/resources/webgpu-texture-view.js +35 -0
  47. package/dist/adapter/resources/webgpu-texture.d.ts +8 -8
  48. package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -1
  49. package/dist/adapter/resources/webgpu-texture.js +130 -107
  50. package/dist/adapter/resources/webgpu-vertex-array.d.ts +9 -8
  51. package/dist/adapter/resources/webgpu-vertex-array.d.ts.map +1 -1
  52. package/dist/adapter/resources/webgpu-vertex-array.js +60 -39
  53. package/dist/adapter/webgpu-canvas-context.d.ts +3 -3
  54. package/dist/adapter/webgpu-canvas-context.d.ts.map +1 -1
  55. package/dist/adapter/webgpu-canvas-context.js +101 -67
  56. package/dist/adapter/webgpu-device.d.ts +26 -28
  57. package/dist/adapter/webgpu-device.d.ts.map +1 -1
  58. package/dist/adapter/webgpu-device.js +254 -220
  59. package/dist/dist.dev.js +804 -2270
  60. package/dist/dist.min.js +9 -0
  61. package/dist/index.cjs +366 -485
  62. package/dist/index.cjs.map +7 -0
  63. package/dist/index.d.ts +5 -5
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +5 -1
  66. package/dist.min.js +1 -22
  67. package/package.json +9 -7
  68. package/src/adapter/helpers/accessor-to-format.ts +5 -1
  69. package/src/adapter/helpers/convert-texture-format.ts +4 -1
  70. package/src/adapter/helpers/get-bind-group.ts +12 -6
  71. package/src/adapter/helpers/get-vertex-buffer-layout.ts +13 -5
  72. package/src/adapter/helpers/webgpu-parameters.ts +79 -15
  73. package/src/adapter/resources/webgpu-buffer.ts +24 -11
  74. package/src/adapter/resources/webgpu-command-encoder.ts +24 -9
  75. package/src/adapter/resources/webgpu-compute-pass.ts +45 -22
  76. package/src/adapter/resources/webgpu-compute-pipeline.ts +48 -16
  77. package/src/adapter/resources/webgpu-external-texture.ts +14 -6
  78. package/src/adapter/resources/webgpu-framebuffer.ts +4 -0
  79. package/src/adapter/resources/webgpu-query-set.ts +37 -0
  80. package/src/adapter/resources/webgpu-render-pass.ts +37 -14
  81. package/src/adapter/resources/webgpu-render-pipeline.ts +80 -119
  82. package/src/adapter/resources/webgpu-sampler.ts +4 -1
  83. package/src/adapter/resources/webgpu-shader.ts +14 -25
  84. package/src/adapter/resources/webgpu-texture-view.ts +46 -0
  85. package/src/adapter/resources/webgpu-texture.ts +33 -28
  86. package/src/adapter/resources/webgpu-vertex-array.ts +28 -20
  87. package/src/adapter/webgpu-canvas-context.ts +10 -4
  88. package/src/adapter/webgpu-device.ts +109 -106
  89. package/src/index.ts +2 -1
  90. package/dist/adapter/helpers/accessor-to-format.js.map +0 -1
  91. package/dist/adapter/helpers/convert-texture-format.js.map +0 -1
  92. package/dist/adapter/helpers/generate-mipmaps.d.ts +0 -10
  93. package/dist/adapter/helpers/generate-mipmaps.d.ts.map +0 -1
  94. package/dist/adapter/helpers/generate-mipmaps.js +0 -100
  95. package/dist/adapter/helpers/generate-mipmaps.js.map +0 -1
  96. package/dist/adapter/helpers/get-bind-group.js.map +0 -1
  97. package/dist/adapter/helpers/get-vertex-buffer-layout.js.map +0 -1
  98. package/dist/adapter/helpers/webgpu-parameters.js.map +0 -1
  99. package/dist/adapter/resources/webgpu-buffer.js.map +0 -1
  100. package/dist/adapter/resources/webgpu-command-encoder.js.map +0 -1
  101. package/dist/adapter/resources/webgpu-compute-pass.js.map +0 -1
  102. package/dist/adapter/resources/webgpu-compute-pipeline.js.map +0 -1
  103. package/dist/adapter/resources/webgpu-external-texture.js.map +0 -1
  104. package/dist/adapter/resources/webgpu-framebuffer.js.map +0 -1
  105. package/dist/adapter/resources/webgpu-query.d.ts +0 -1
  106. package/dist/adapter/resources/webgpu-query.d.ts.map +0 -1
  107. package/dist/adapter/resources/webgpu-query.js +0 -2
  108. package/dist/adapter/resources/webgpu-query.js.map +0 -1
  109. package/dist/adapter/resources/webgpu-render-pass.js.map +0 -1
  110. package/dist/adapter/resources/webgpu-render-pipeline.js.map +0 -1
  111. package/dist/adapter/resources/webgpu-sampler.js.map +0 -1
  112. package/dist/adapter/resources/webgpu-shader.js.map +0 -1
  113. package/dist/adapter/resources/webgpu-texture.js.map +0 -1
  114. package/dist/adapter/resources/webgpu-vertex-array.js.map +0 -1
  115. package/dist/adapter/webgpu-canvas-context.js.map +0 -1
  116. package/dist/adapter/webgpu-device.js.map +0 -1
  117. package/dist/adapter/webgpu-types.d.ts +0 -1
  118. package/dist/adapter/webgpu-types.d.ts.map +0 -1
  119. package/dist/adapter/webgpu-types.js +0 -2
  120. package/dist/adapter/webgpu-types.js.map +0 -1
  121. package/dist/glsl/glsllang.d.ts +0 -3
  122. package/dist/glsl/glsllang.d.ts.map +0 -1
  123. package/dist/glsl/glsllang.js +0 -9
  124. package/dist/glsl/glsllang.js.map +0 -1
  125. package/dist/index.js.map +0 -1
  126. package/src/adapter/helpers/generate-mipmaps.ts +0 -107
  127. package/src/adapter/resources/webgpu-query.ts +0 -43
  128. package/src/adapter/webgpu-types.ts +0 -0
  129. package/src/glsl/glsllang.ts +0 -14
@@ -1,10 +1,15 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
1
5
  import type {RenderPassProps, RenderPassParameters, Binding, Framebuffer} from '@luma.gl/core';
2
6
  import {Buffer, RenderPass, RenderPipeline, cast, log} from '@luma.gl/core';
3
7
  import {WebGPUDevice} from '../webgpu-device';
4
8
  import {WebGPUBuffer} from './webgpu-buffer';
5
- import {WebGPUTexture} from './webgpu-texture';
9
+ import {WebGPUTextureView} from './webgpu-texture-view';
6
10
  // import {WebGPUCommandEncoder} from './webgpu-command-encoder';
7
11
  import {WebGPURenderPipeline} from './webgpu-render-pipeline';
12
+ import {WebGPUQuerySet} from './webgpu-query-set';
8
13
 
9
14
  export class WebGPURenderPass extends RenderPass {
10
15
  readonly device: WebGPUDevice;
@@ -16,13 +21,30 @@ export class WebGPURenderPass extends RenderPass {
16
21
  constructor(device: WebGPUDevice, props: RenderPassProps = {}) {
17
22
  super(device, props);
18
23
  this.device = device;
19
- const framebuffer = props.framebuffer || device.canvasContext.getCurrentFramebuffer() ;
24
+ const framebuffer = props.framebuffer || device.canvasContext.getCurrentFramebuffer();
20
25
  const renderPassDescriptor = this.getRenderPassDescriptor(framebuffer);
26
+
27
+ const webgpuQuerySet = props.timestampQuerySet as WebGPUQuerySet;
28
+ if (webgpuQuerySet) {
29
+ renderPassDescriptor.occlusionQuerySet = webgpuQuerySet.handle;
30
+ }
31
+
32
+ if (device.features.has('timestamp-query')) {
33
+ const webgpuQuerySet = props.timestampQuerySet as WebGPUQuerySet;
34
+ renderPassDescriptor.timestampWrites = webgpuQuerySet
35
+ ? ({
36
+ querySet: webgpuQuerySet.handle,
37
+ beginningOfPassWriteIndex: props.beginTimestampIndex,
38
+ endOfPassWriteIndex: props.endTimestampIndex
39
+ } as GPUComputePassTimestampWrites)
40
+ : undefined;
41
+ }
42
+
43
+ this.handle = this.props.handle || device.commandEncoder.beginRenderPass(renderPassDescriptor);
44
+ this.handle.label = this.props.id;
21
45
  log.groupCollapsed(3, `new WebGPURenderPass(${this.id})`)();
22
46
  log.probe(3, JSON.stringify(renderPassDescriptor, null, 2))();
23
47
  log.groupEnd(3)();
24
- this.handle = this.props.handle || device.commandEncoder.beginRenderPass(renderPassDescriptor);
25
- this.handle.label = this.props.id;
26
48
  }
27
49
 
28
50
  override destroy(): void {}
@@ -124,19 +146,20 @@ export class WebGPURenderPass extends RenderPass {
124
146
  this.handle.insertDebugMarker(markerLabel);
125
147
  }
126
148
 
127
- // writeTimestamp(querySet: GPUQuerySet, queryIndex: number): void;
128
- // beginOcclusionQuery(queryIndex: number): void;
129
- // endOcclusionQuery(): void;
130
- // beginPipelineStatisticsQuery(querySet: GPUQuerySet, queryIndex: number): void;
131
- // endPipelineStatisticsQuery(querySet: GPUQuerySet, queryIndex: number): void;
149
+ beginOcclusionQuery(queryIndex: number): void {
150
+ this.handle.beginOcclusionQuery(queryIndex);
151
+ }
152
+ endOcclusionQuery(): void {
153
+ this.handle.endOcclusionQuery();
154
+ }
132
155
 
133
156
  // executeBundles(bundles: Iterable<GPURenderBundle>): void;
134
157
 
135
158
  // INTERNAL
136
159
 
137
- /**
160
+ /**
138
161
  * Partial render pass descriptor. Used by WebGPURenderPass.
139
- * @returns attachments fields of a renderpass descriptor.
162
+ * @returns attachments fields of a renderpass descriptor.
140
163
  */
141
164
  protected getRenderPassDescriptor(framebuffer: Framebuffer): GPURenderPassDescriptor {
142
165
  const renderPassDescriptor: GPURenderPassDescriptor = {
@@ -147,14 +170,14 @@ export class WebGPURenderPass extends RenderPass {
147
170
  // clear values
148
171
  loadOp: this.props.clearColor !== false ? 'clear' : 'load',
149
172
  colorClearValue: this.props.clearColor || [0, 0, 0, 0],
150
- storeOp: this.props.discard? 'discard': 'store',
173
+ storeOp: this.props.discard ? 'discard' : 'store',
151
174
  // ...colorAttachment,
152
- view: (colorAttachment as WebGPUTexture).createView()
175
+ view: (colorAttachment as WebGPUTextureView).handle
153
176
  }));
154
177
 
155
178
  if (framebuffer.depthStencilAttachment) {
156
179
  renderPassDescriptor.depthStencilAttachment = {
157
- view: (framebuffer.depthStencilAttachment as WebGPUTexture).createView()
180
+ view: (framebuffer.depthStencilAttachment as WebGPUTextureView).handle
158
181
  };
159
182
  const {depthStencilAttachment} = renderPassDescriptor;
160
183
 
@@ -1,7 +1,7 @@
1
1
  // luma.gl MIT license
2
2
 
3
- import type {Binding, UniformValue, RenderPass, VertexArray} from '@luma.gl/core';
4
- import {RenderPipeline, RenderPipelineProps, cast, log, isObjectEmpty} from '@luma.gl/core';
3
+ import type {Binding, RenderPass, VertexArray} from '@luma.gl/core';
4
+ import {RenderPipeline, RenderPipelineProps, cast, log} from '@luma.gl/core';
5
5
  import {applyParametersToRenderPipelineDescriptor} from '../helpers/webgpu-parameters';
6
6
  import {getWebGPUTextureFormat} from '../helpers/convert-texture-format';
7
7
  import {getBindGroup} from '../helpers/get-bind-group';
@@ -25,12 +25,8 @@ export class WebGPURenderPipeline extends RenderPipeline {
25
25
  vs: WebGPUShader;
26
26
  fs: WebGPUShader | null = null;
27
27
 
28
- // private _bufferSlots: Record<string, number>;
29
- // private _buffers: Buffer[];
30
- // private _firstIndex: number;
31
- // private _lastIndex: number;
32
-
33
28
  /** For internal use to create BindGroups */
29
+ private _bindings: Record<string, Binding>;
34
30
  private _bindGroupLayout: GPUBindGroupLayout | null = null;
35
31
  private _bindGroup: GPUBindGroup | null = null;
36
32
 
@@ -43,74 +39,30 @@ export class WebGPURenderPipeline extends RenderPipeline {
43
39
  log.groupCollapsed(1, `new WebGPURenderPipeline(${this.id})`)();
44
40
  log.probe(1, JSON.stringify(descriptor, null, 2))();
45
41
  log.groupEnd(1)();
46
- this.handle = this.device.handle.createRenderPipeline(descriptor);
42
+ this.handle = this.device.handle.createRenderPipeline(descriptor);
47
43
  }
48
44
  this.handle.label = this.props.id;
49
45
 
50
46
  this.vs = cast<WebGPUShader>(props.vs);
51
47
  this.fs = cast<WebGPUShader>(props.fs);
52
48
 
53
- // this._bufferSlots = getBufferSlots(this.props.shaderLayout, this.props.bufferLayout);
54
- // this._buffers = new Array<Buffer>(Object.keys(this._bufferSlots).length).fill(null);
49
+ this._bindings = {...this.props.bindings};
55
50
  }
56
51
 
57
52
  override destroy(): void {
58
53
  // WebGPURenderPipeline has no destroy method.
54
+ this.handle = null;
59
55
  }
60
56
 
61
- // setIndexBuffer(indexBuffer: Buffer): void {
62
- // this._indexBuffer = cast<WebGPUBuffer>(indexBuffer);
63
- // }
64
-
65
- /*
66
- setAttributes(attributes: Record<string, Buffer>): void {
67
- for (const [name, buffer] of Object.entries(attributes)) {
68
- const bufferIndex = this._bufferSlots[name];
69
- if (bufferIndex >= 0) {
70
- this._buffers[bufferIndex] = buffer;
71
- } else {
72
- throw new Error(
73
- `Setting attribute '${name}' not listed in shader layout for program ${this.id}`
74
- );
75
- }
76
- }
77
- // for (let i = 0; i < this._bufferSlots.length; ++i) {
78
- // const bufferName = this._bufferSlots[i];
79
- // if (attributes[bufferName]) {
80
- // this.handle
81
- // }
82
- // }
83
- }
84
- */
85
-
86
- // setConstantAttributes(attributes: Record<string, TypedArray>): void {
87
- // throw new Error('not implemented');
88
- // }
89
-
57
+ /**
58
+ * @todo Use renderpass.setBindings() ?
59
+ * @todo Do we want to expose BindGroups in the API and remove this?
60
+ */
90
61
  setBindings(bindings: Record<string, Binding>): void {
91
- if (!isObjectEmpty(this.props.bindings)) {
92
- // Do we want to save things on CPU side?
93
- Object.assign(this.props.bindings, bindings);
94
-
95
- // Get hold of the bind group layout. We don't want to do this unless we know there is at least one bind group
96
- this._bindGroupLayout = this._bindGroupLayout || this.handle.getBindGroupLayout(0);
97
-
98
- // Set up the bindings
99
- this._bindGroup = getBindGroup(
100
- this.device.handle,
101
- this._bindGroupLayout,
102
- this.props.shaderLayout,
103
- this.props.bindings
104
- );
105
- }
106
- }
107
-
108
- setUniforms(uniforms: Record<string, UniformValue>): void {
109
- if (!isObjectEmpty(uniforms)) {
110
- throw new Error('WebGPU does not support uniforms');
111
- }
62
+ Object.assign(this._bindings, bindings);
112
63
  }
113
64
 
65
+ /** @todo - should this be moved to renderpass? */
114
66
  draw(options: {
115
67
  renderPass: RenderPass;
116
68
  vertexArray: VertexArray;
@@ -121,9 +73,8 @@ export class WebGPURenderPipeline extends RenderPipeline {
121
73
  firstIndex?: number;
122
74
  firstInstance?: number;
123
75
  baseVertex?: number;
124
- }): void {
125
- const webgpuRenderPass: WebGPURenderPass =
126
- cast<WebGPURenderPass>(options.renderPass) || this.device.getDefaultRenderPass();
76
+ }): boolean {
77
+ const webgpuRenderPass = options.renderPass as WebGPURenderPass;
127
78
 
128
79
  // Set pipeline
129
80
  webgpuRenderPass.handle.setPipeline(this.handle);
@@ -134,7 +85,6 @@ export class WebGPURenderPipeline extends RenderPipeline {
134
85
  webgpuRenderPass.handle.setBindGroup(0, bindGroup);
135
86
  }
136
87
 
137
-
138
88
  // Set attributes
139
89
  // Note: Rebinds constant attributes before each draw call
140
90
  options.vertexArray.bindBeforeRender(options.renderPass);
@@ -158,43 +108,55 @@ export class WebGPURenderPipeline extends RenderPipeline {
158
108
 
159
109
  // Note: Rebinds constant attributes before each draw call
160
110
  options.vertexArray.unbindAfterRender(options.renderPass);
161
- }
162
111
 
163
- // _getBuffers() {
164
- // return this._buffers;
165
- // }
112
+ return true;
113
+ }
166
114
 
167
115
  /** Return a bind group created by setBindings */
168
116
  _getBindGroup() {
169
- // assert(this._bindGroup);
117
+ if (this.props.shaderLayout.bindings.length === 0) {
118
+ return null;
119
+ }
120
+
121
+ // Get hold of the bind group layout. We don't want to do this unless we know there is at least one bind group
122
+ this._bindGroupLayout = this._bindGroupLayout || this.handle.getBindGroupLayout(0);
123
+
124
+ // Set up the bindings
125
+ // TODO what if bindings change? We need to rebuild the bind group!
126
+ this._bindGroup =
127
+ this._bindGroup ||
128
+ getBindGroup(
129
+ this.device.handle,
130
+ this._bindGroupLayout,
131
+ this.props.shaderLayout,
132
+ this._bindings
133
+ );
134
+
170
135
  return this._bindGroup;
171
136
  }
172
137
 
173
- /**
174
- * Populate the complex WebGPU GPURenderPipelineDescriptor
138
+ /**
139
+ * Populate the complex WebGPU GPURenderPipelineDescriptor
175
140
  */
176
141
  protected _getRenderPipelineDescriptor() {
177
142
  // Set up the vertex stage
178
143
  const vertex: GPUVertexState = {
179
144
  module: cast<WebGPUShader>(this.props.vs).handle,
180
- entryPoint: this.props.vsEntryPoint || 'main',
145
+ entryPoint: this.props.vertexEntryPoint || 'main',
181
146
  buffers: getVertexBufferLayout(this.props.shaderLayout, this.props.bufferLayout)
182
147
  };
183
148
 
184
149
  // Set up the fragment stage
185
- let fragment: GPUFragmentState | undefined;
186
- if (this.props.fs) {
187
- fragment = {
188
- module: cast<WebGPUShader>(this.props.fs).handle,
189
- entryPoint: this.props.fsEntryPoint || 'main',
190
- targets: [
191
- {
192
- // TODO exclamation mark hack!
193
- format: getWebGPUTextureFormat(this.device?.canvasContext?.format)
194
- }
195
- ]
196
- };
197
- }
150
+ const fragment: GPUFragmentState = {
151
+ module: cast<WebGPUShader>(this.props.fs).handle,
152
+ entryPoint: this.props.fragmentEntryPoint || 'main',
153
+ targets: [
154
+ {
155
+ // TODO exclamation mark hack!
156
+ format: getWebGPUTextureFormat(this.device?.canvasContext?.format)
157
+ }
158
+ ]
159
+ };
198
160
 
199
161
  // WebGPU has more restrictive topology support than WebGL
200
162
  switch (this.props.topology) {
@@ -219,47 +181,46 @@ export class WebGPURenderPipeline extends RenderPipeline {
219
181
 
220
182
  return descriptor;
221
183
  }
184
+ }
185
+ /**
186
+ _setAttributeBuffers(webgpuRenderPass: WebGPURenderPass) {
187
+ if (this._indexBuffer) {
188
+ webgpuRenderPass.handle.setIndexBuffer(this._indexBuffer.handle, this._indexBuffer.props.indexType);
189
+ }
222
190
 
223
- /**
224
- _setAttributeBuffers(webgpuRenderPass: WebGPURenderPass) {
225
- if (this._indexBuffer) {
226
- webgpuRenderPass.handle.setIndexBuffer(this._indexBuffer.handle, this._indexBuffer.props.indexType);
191
+ const buffers = this._getBuffers();
192
+ for (let i = 0; i < buffers.length; ++i) {
193
+ const buffer = cast<WebGPUBuffer>(buffers[i]);
194
+ if (!buffer) {
195
+ const attribute = this.props.shaderLayout.attributes.find(
196
+ (attribute) => attribute.location === i
197
+ );
198
+ throw new Error(
199
+ `No buffer provided for attribute '${attribute?.name || ''}' in Model '${this.props.id}'`
200
+ );
227
201
  }
202
+ webgpuRenderPass.handle.setVertexBuffer(i, buffer.handle);
203
+ }
228
204
 
229
- const buffers = this._getBuffers();
230
- for (let i = 0; i < buffers.length; ++i) {
231
- const buffer = cast<WebGPUBuffer>(buffers[i]);
232
- if (!buffer) {
233
- const attribute = this.props.shaderLayout.attributes.find(
234
- (attribute) => attribute.location === i
235
- );
236
- throw new Error(
237
- `No buffer provided for attribute '${attribute?.name || ''}' in Model '${this.props.id}'`
238
- );
239
- }
240
- webgpuRenderPass.handle.setVertexBuffer(i, buffer.handle);
205
+ // TODO - HANDLE buffer maps
206
+ /*
207
+ for (const [bufferName, attributeMapping] of Object.entries(this.props.bufferLayout)) {
208
+ const buffer = cast<WebGPUBuffer>(this.props.attributes[bufferName]);
209
+ if (!buffer) {
210
+ log.warn(`Missing buffer for buffer map ${bufferName}`)();
211
+ continue;
241
212
  }
242
213
 
243
- // TODO - HANDLE buffer maps
244
- /*
245
- for (const [bufferName, attributeMapping] of Object.entries(this.props.bufferLayout)) {
246
- const buffer = cast<WebGPUBuffer>(this.props.attributes[bufferName]);
247
- if (!buffer) {
248
- log.warn(`Missing buffer for buffer map ${bufferName}`)();
249
- continue;
250
- }
251
-
252
- if ('location' in attributeMapping) {
214
+ if ('location' in attributeMapping) {
215
+ // @ts-expect-error TODO model must not depend on webgpu
216
+ renderPass.handle.setVertexBuffer(layout.location, buffer.handle);
217
+ } else {
218
+ for (const [bufferName, mapping] of Object.entries(attributeMapping)) {
253
219
  // @ts-expect-error TODO model must not depend on webgpu
254
- renderPass.handle.setVertexBuffer(layout.location, buffer.handle);
255
- } else {
256
- for (const [bufferName, mapping] of Object.entries(attributeMapping)) {
257
- // @ts-expect-error TODO model must not depend on webgpu
258
- renderPass.handle.setVertexBuffer(field.location, buffer.handle);
259
- }
220
+ renderPass.handle.setVertexBuffer(field.location, buffer.handle);
260
221
  }
261
222
  }
262
- *
263
223
  }
264
- */
224
+ *
265
225
  }
226
+ */
@@ -3,7 +3,7 @@ import type {WebGPUDevice} from '../webgpu-device';
3
3
 
4
4
  export type WebGPUSamplerProps = SamplerProps & {
5
5
  handle?: GPUSampler;
6
- }
6
+ };
7
7
 
8
8
  /**
9
9
  *
@@ -27,6 +27,9 @@ export class WebGPUSampler extends Sampler {
27
27
  }
28
28
 
29
29
  override destroy(): void {
30
+ // GPUSampler does not have a destroy method
30
31
  // this.handle.destroy();
32
+ // @ts-expect-error readonly
33
+ this.handle = null;
31
34
  }
32
35
  }
@@ -1,14 +1,11 @@
1
- // luma.gl, MIT license
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
2
3
  // Copyright (c) vis.gl contributors
3
4
 
4
5
  import type {ShaderProps, CompilerMessage} from '@luma.gl/core';
5
6
  import {Shader, log} from '@luma.gl/core';
6
7
  import type {WebGPUDevice} from '../webgpu-device';
7
8
 
8
- export type WebGPUShaderProps = ShaderProps & {
9
- handle?: GPUShaderModule;
10
- };
11
-
12
9
  /**
13
10
  * Immutable shader
14
11
  */
@@ -16,7 +13,7 @@ export class WebGPUShader extends Shader {
16
13
  readonly device: WebGPUDevice;
17
14
  readonly handle: GPUShaderModule;
18
15
 
19
- constructor(device: WebGPUDevice, props: WebGPUShaderProps) {
16
+ constructor(device: WebGPUDevice, props: ShaderProps) {
20
17
  super(device, props);
21
18
  this.device = device;
22
19
 
@@ -29,8 +26,11 @@ export class WebGPUShader extends Shader {
29
26
  }
30
27
 
31
28
  async _checkCompilationError(errorScope: Promise<GPUError | null>): Promise<void> {
32
- const error = await errorScope as GPUValidationError;
29
+ const error = (await errorScope) as GPUValidationError;
33
30
  if (error) {
31
+ // The `Shader` base class will determine if debug window should be opened based on props
32
+ this.debugShader();
33
+
34
34
  const shaderLog = await this.getCompilationInfo();
35
35
  log.error(`Shader compilation error: ${error.message}`, shaderLog)();
36
36
  // Note: Even though this error is asynchronous and thrown after the constructor completes,
@@ -42,6 +42,8 @@ export class WebGPUShader extends Shader {
42
42
  override destroy(): void {
43
43
  // Note: WebGPU does not offer a method to destroy shaders
44
44
  // this.handle.destroy();
45
+ // @ts-expect-error readonly
46
+ this.handle = null;
45
47
  }
46
48
 
47
49
  /** Returns compilation info for this shader */
@@ -53,26 +55,13 @@ export class WebGPUShader extends Shader {
53
55
  // PRIVATE METHODS
54
56
 
55
57
  protected createHandle(): GPUShaderModule {
56
- const {source, stage} = this.props;
58
+ const {source} = this.props;
57
59
 
58
- let language = this.props.language;
59
- // Compile from src
60
- if (language === 'auto') {
61
- // wgsl uses C++ "auto" style arrow notation
62
- language = source.includes('->') ? 'wgsl' : 'glsl';
60
+ const isGLSL = source.includes('#version');
61
+ if (this.props.language === 'glsl' || isGLSL) {
62
+ throw new Error('GLSL shaders are not supported in WebGPU');
63
63
  }
64
64
 
65
- switch(language) {
66
- case 'wgsl':
67
- return this.device.handle.createShaderModule({code: source});
68
- case 'glsl':
69
- return this.device.handle.createShaderModule({
70
- code: source,
71
- // @ts-expect-error
72
- transform: (glsl) => this.device.glslang.compileGLSL(glsl, stage)
73
- });
74
- default:
75
- throw new Error(language);
76
- }
65
+ return this.device.handle.createShaderModule({code: source});
77
66
  }
78
67
  }
@@ -0,0 +1,46 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {TextureView, TextureViewProps} from '@luma.gl/core';
6
+ import type {WebGPUDevice} from '../webgpu-device';
7
+ import type {WebGPUTexture} from './webgpu-texture';
8
+
9
+ export type WebGPUTextureViewProps = TextureViewProps & {
10
+ handle?: GPUTextureView;
11
+ };
12
+
13
+ /**
14
+ *
15
+ */
16
+ export class WebGPUTextureView extends TextureView {
17
+ readonly device: WebGPUDevice;
18
+ readonly handle: GPUTextureView;
19
+ readonly texture: WebGPUTexture;
20
+
21
+ constructor(device: WebGPUDevice, props: WebGPUTextureViewProps & {texture: WebGPUTexture}) {
22
+ super(device, props);
23
+ this.device = device;
24
+ this.texture = props.texture;
25
+
26
+ this.handle =
27
+ this.handle ||
28
+ this.texture.handle.createView({
29
+ format: (props.format || this.texture.format) as GPUTextureFormat,
30
+ dimension: props.dimension || this.texture.dimension,
31
+ aspect: props.aspect,
32
+ baseMipLevel: props.baseMipLevel,
33
+ mipLevelCount: props.mipLevelCount, // GPUIntegerCoordinate;
34
+ baseArrayLayer: props.baseArrayLayer, // GPUIntegerCoordinate;
35
+ arrayLayerCount: props.arrayLayerCount // GPUIntegerCoordinate;
36
+ });
37
+ this.handle.label = this.props.id;
38
+ }
39
+
40
+ override destroy(): void {
41
+ // GPUTextureView does not have a destroy method
42
+ // this.handle.destroy();
43
+ // @ts-expect-error readonly
44
+ this.handle = null;
45
+ }
46
+ }
@@ -1,14 +1,18 @@
1
- // luma.gl, MIT license
2
- import {Texture, TextureProps, Sampler, SamplerProps} from '@luma.gl/core';
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {Texture, TextureProps, TextureViewProps, Sampler, SamplerProps} from '@luma.gl/core';
3
6
  import {getWebGPUTextureFormat} from '../helpers/convert-texture-format';
4
7
  import type {WebGPUDevice} from '../webgpu-device';
5
8
  import {WebGPUSampler} from './webgpu-sampler';
9
+ import {WebGPUTextureView} from './webgpu-texture-view';
6
10
 
7
11
  const BASE_DIMENSIONS: Record<string, '1d' | '2d' | '3d'> = {
8
12
  '1d': '1d',
9
13
  '2d': '2d',
10
14
  '2d-array': '2d',
11
- 'cube': '2d',
15
+ cube: '2d',
12
16
  'cube-array': '2d',
13
17
  '3d': '3d'
14
18
  };
@@ -16,12 +20,13 @@ const BASE_DIMENSIONS: Record<string, '1d' | '2d' | '3d'> = {
16
20
  export class WebGPUTexture extends Texture {
17
21
  readonly device: WebGPUDevice;
18
22
  readonly handle: GPUTexture;
19
- readonly view: GPUTextureView;
20
- sampler: WebGPUSampler;
21
23
 
22
24
  override height: number = 1;
23
25
  override width: number = 1;
24
26
 
27
+ sampler: WebGPUSampler;
28
+ view: WebGPUTextureView;
29
+
25
30
  // static async createFromImageURL(src, usage = 0) {
26
31
  // const img = document.createElement('img');
27
32
  // img.src = src;
@@ -46,6 +51,16 @@ export class WebGPUTexture extends Texture {
46
51
  this.initialize(props);
47
52
  }
48
53
 
54
+ override destroy(): void {
55
+ this.handle?.destroy();
56
+ // @ts-expect-error readonly
57
+ this.handle = null;
58
+ }
59
+
60
+ createView(props: TextureViewProps): WebGPUTextureView {
61
+ return new WebGPUTextureView(this.device, {...props, texture: this});
62
+ }
63
+
49
64
  protected initialize(props: TextureProps): void {
50
65
  // @ts-expect-error
51
66
  this.handle = this.props.handle || this.createHandle();
@@ -67,12 +82,16 @@ export class WebGPUTexture extends Texture {
67
82
 
68
83
  // Create a default sampler. This mimics the WebGL1 API where sampler props are stored on the texture
69
84
  // this.setSampler(props.sampler);
70
- this.sampler = props.sampler instanceof WebGPUSampler ? props.sampler : new WebGPUSampler(this.device, props.sampler);
85
+ this.sampler =
86
+ props.sampler instanceof WebGPUSampler
87
+ ? props.sampler
88
+ : new WebGPUSampler(this.device, props.sampler);
71
89
 
72
90
  // TODO - To support texture arrays we need to create custom views...
73
91
  // But we are not ready to expose TextureViews to the public API.
74
92
  // @ts-expect-error
75
- this.view = this.createView();
93
+
94
+ this.view = new WebGPUTextureView(this.device, {...this.props, texture: this});
76
95
  // format: this.props.format,
77
96
  // dimension: this.props.dimension,
78
97
  // aspect = "all";
@@ -104,22 +123,17 @@ export class WebGPUTexture extends Texture {
104
123
  });
105
124
  }
106
125
 
107
- override destroy(): void {
108
- this.handle.destroy();
109
- }
110
-
111
126
  /**
112
127
  * Set default sampler
113
128
  * Accept a sampler instance or set of props;
114
129
  */
115
130
  setSampler(sampler: Sampler | SamplerProps): this {
116
- this.sampler = sampler instanceof WebGPUSampler ? sampler : new WebGPUSampler(this.device, sampler);
131
+ this.sampler =
132
+ sampler instanceof WebGPUSampler ? sampler : new WebGPUSampler(this.device, sampler);
117
133
  return this;
118
134
  }
119
135
 
120
- setData(options: {
121
- data: any;
122
- }) {
136
+ setData(options: {data: any}) {
123
137
  return this.setImage({source: options.data});
124
138
  }
125
139
 
@@ -138,7 +152,7 @@ export class WebGPUTexture extends Texture {
138
152
  aspect?: 'all' | 'stencil-only' | 'depth-only';
139
153
  colorSpace?: 'srgb';
140
154
  premultipliedAlpha?: boolean;
141
- }): {width: number, height: number} {
155
+ }): {width: number; height: number} {
142
156
  const {
143
157
  source,
144
158
  width = options.source.width,
@@ -173,22 +187,13 @@ export class WebGPUTexture extends Texture {
173
187
  premultipliedAlpha
174
188
  },
175
189
  // copySize: GPUExtent3D
176
- [
177
- width,
178
- height,
179
- depth
180
- ]
190
+ [width, height, depth]
181
191
  );
182
192
  return {width, height};
183
193
  }
184
194
 
185
- // WebGPU specific
186
-
187
- /** TODO - intention is to expose TextureViews in the public API */
188
- createView(): GPUTextureView {
189
- return this.handle.createView({label: this.id});
190
- }
191
-
195
+ // WebGPU specific
196
+
192
197
  /*
193
198
  async readPixels() {
194
199
  const readbackBuffer = device.createBuffer({