@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,229 @@
1
+ import {Parameters} from '@luma.gl/api';
2
+
3
+ function addDepthStencil(descriptor: GPURenderPipelineDescriptor): GPUDepthStencilState {
4
+ descriptor.depthStencil = descriptor.depthStencil || {
5
+ // required, set something
6
+ format: 'depth24plus',
7
+ stencilFront: {},
8
+ stencilBack: {}
9
+ };
10
+ return descriptor.depthStencil;
11
+ }
12
+
13
+ /**
14
+ * Supports for luma.gl's flat parameter space
15
+ * Populates the corresponding sub-objects in a GPURenderPipelineDescriptor
16
+ */
17
+ // @ts-expect-error
18
+ export const PARAMETER_TABLE: Record<keyof Parameters, Function> = {
19
+ // RASTERIZATION PARAMETERS
20
+
21
+ cullMode: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
22
+ descriptor.primitive = descriptor.primitive || {};
23
+ descriptor.primitive.cullMode = value;
24
+ },
25
+
26
+ frontFace: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
27
+ descriptor.primitive = descriptor.primitive || {};
28
+ descriptor.primitive.frontFace = value;
29
+ },
30
+
31
+ // DEPTH
32
+
33
+ depthWriteEnabled: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
34
+ const depthStencil = addDepthStencil(descriptor);
35
+ depthStencil.depthWriteEnabled = value;
36
+ },
37
+
38
+ depthCompare: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
39
+ const depthStencil = addDepthStencil(descriptor);
40
+ depthStencil.depthCompare = value;
41
+ },
42
+
43
+ depthFormat: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
44
+ const depthStencil = addDepthStencil(descriptor);
45
+ depthStencil.format = value;
46
+ },
47
+
48
+ depthBias: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
49
+ const depthStencil = addDepthStencil(descriptor);
50
+ depthStencil.depthBias = value;
51
+ },
52
+
53
+ depthBiasSlopeScale: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
54
+ const depthStencil = addDepthStencil(descriptor);
55
+ depthStencil.depthBiasSlopeScale = value;
56
+ },
57
+
58
+ depthBiasClamp: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
59
+ const depthStencil = addDepthStencil(descriptor);
60
+ depthStencil.depthBiasClamp = value;
61
+ },
62
+
63
+ // STENCIL
64
+
65
+ stencilReadMask: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
66
+ const depthStencil = addDepthStencil(descriptor);
67
+ depthStencil.stencilReadMask = value;
68
+ },
69
+
70
+ stencilWriteMask: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
71
+ const depthStencil = addDepthStencil(descriptor);
72
+ depthStencil.stencilWriteMask = value;
73
+ },
74
+
75
+ stencilCompare: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
76
+ const depthStencil = addDepthStencil(descriptor);
77
+ depthStencil.stencilFront!.compare = value;
78
+ depthStencil.stencilBack!.compare = value;
79
+ },
80
+
81
+ stencilPassOperation: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
82
+ const depthStencil = addDepthStencil(descriptor);
83
+ depthStencil.stencilFront!.passOp = value;
84
+ depthStencil.stencilBack!.passOp = value;
85
+ },
86
+
87
+ stencilFailOperation: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
88
+ const depthStencil = addDepthStencil(descriptor);
89
+ depthStencil.stencilFront!.failOp = value;
90
+ depthStencil.stencilBack!.failOp = value;
91
+ },
92
+
93
+ stencilDepthFailOperation: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
94
+ const depthStencil = addDepthStencil(descriptor);
95
+ depthStencil.stencilFront!.depthFailOp = value;
96
+ depthStencil.stencilBack!.depthFailOp = value;
97
+ },
98
+
99
+ // MULTISAMPLE
100
+
101
+ sampleCount: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
102
+ descriptor.multisample = descriptor.multisample || {};
103
+ descriptor.multisample.count = value;
104
+ },
105
+
106
+ sampleMask: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
107
+ descriptor.multisample = descriptor.multisample || {};
108
+ descriptor.multisample.mask = value;
109
+ },
110
+
111
+ sampleAlphaToCoverageEnabled: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
112
+ descriptor.multisample = descriptor.multisample || {};
113
+ descriptor.multisample.alphaToCoverageEnabled = value;
114
+ },
115
+
116
+ // COLOR
117
+
118
+ colorMask: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
119
+ const targets = addColorState(descriptor);
120
+ targets[0].writeMask = value;
121
+ },
122
+
123
+ blendColorOperation: (parameter: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
124
+ const targets = addColorState(descriptor);
125
+ const target = targets[0];
126
+ // const blend: GPUBlendState = target.blend || {color: {alpha: 0}};
127
+ // blend.color = blend.color || {};
128
+ // target.blend.color.operation = value;
129
+ }
130
+
131
+ /*
132
+ blendColorSrcTarget: (parameter, value, descriptor: GPURenderPipelineDescriptor) => {
133
+ addColorState(descriptor);
134
+ targets[0].blend = targets[0].blend || {};
135
+ targets[0].blend.color = targets[0].blend.color || {};
136
+ targets[0].blend.color.srcTarget = value;
137
+ },
138
+
139
+ blendColorDstTarget: (parameter, value, descriptor: GPURenderPipelineDescriptor) => {
140
+ addColorState(descriptor);
141
+ targets[0].blend = targets[0].blend || {};
142
+ targets[0].blend.color = targets[0].blend.color || {};
143
+ targets[0].blend.color.dstTarget = value;
144
+ },
145
+
146
+ blendAlphaOperation: (parameter, value, descriptor: GPURenderPipelineDescriptor) => {
147
+ addColorState(descriptor);
148
+ targets[0].blend = targets[0].blend || {};
149
+ targets[0].blend.alpha = targets[0].blend.alpha || {};
150
+ targets[0].blend.alpha.operation = value;
151
+ },
152
+
153
+ blendAlphaSrcTarget: (parameter, value, descriptor: GPURenderPipelineDescriptor) => {
154
+ addColorState(descriptor);
155
+ targets[0].blend = targets[0].blend || {};
156
+ targets[0].blend.alpha = targets[0].blend.alpha || {};
157
+ targets[0].blend.alpha.srcTarget = value;
158
+ },
159
+
160
+ blendAlphaDstTarget: (parameter, value, descriptor: GPURenderPipelineDescriptor) => {
161
+ addColorState(descriptor);
162
+ targets[0].blend = targets[0].blend || {};
163
+ targets[0].blend.alpha = targets[0].blend.alpha || {};
164
+ targets[0].blend.alpha.dstTarget = value;
165
+ },
166
+ */
167
+ };
168
+
169
+ const DEFAULT_PIPELINE_DESCRIPTOR: GPURenderPipelineDescriptor = {
170
+ // depthStencil: {
171
+ // stencilFront: {},
172
+ // stencilBack: {},
173
+ // // depthWriteEnabled: true,
174
+ // // depthCompare: 'less',
175
+ // // format: 'depth24plus-stencil8',
176
+ // },
177
+
178
+ primitive: {
179
+ cullMode: 'back',
180
+ topology: 'triangle-list'
181
+ },
182
+
183
+ vertex: {
184
+ module: undefined!,
185
+ entryPoint: 'main'
186
+ },
187
+
188
+ fragment: {
189
+ module: undefined!,
190
+ entryPoint: 'main',
191
+ targets: [
192
+ // { format: props.color0Format || 'bgra8unorm' }
193
+ ]
194
+ }
195
+ };
196
+
197
+ export function applyParametersToRenderPipelineDescriptor(
198
+ pipelineDescriptor: GPURenderPipelineDescriptor,
199
+ parameters: Parameters = {}
200
+ ): void {
201
+ // Apply defaults
202
+ Object.assign(pipelineDescriptor, {...DEFAULT_PIPELINE_DESCRIPTOR, ...pipelineDescriptor});
203
+ setParameters(pipelineDescriptor, parameters);
204
+ }
205
+
206
+ // Apply any supplied parameters
207
+ function setParameters(
208
+ pipelineDescriptor: GPURenderPipelineDescriptor,
209
+ parameters: Parameters
210
+ ): void {
211
+ for (const [key, value] of Object.entries(parameters)) {
212
+ const setterFunction = PARAMETER_TABLE[key as keyof Parameters];
213
+ if (!setterFunction) {
214
+ throw new Error(`Illegal parameter ${key}`);
215
+ }
216
+ setterFunction(key, value, pipelineDescriptor);
217
+ }
218
+ }
219
+
220
+ function addColorState(descriptor: GPURenderPipelineDescriptor): GPUColorTargetState[] {
221
+ descriptor.fragment!.targets = descriptor.fragment?.targets || [];
222
+ if (!Array.isArray(descriptor.fragment?.targets)) {
223
+ throw new Error('colorstate');
224
+ }
225
+ if (descriptor.fragment?.targets?.length === 0) {
226
+ descriptor.fragment.targets?.push({});
227
+ }
228
+ return descriptor.fragment?.targets as GPUColorTargetState[];
229
+ }
@@ -0,0 +1,92 @@
1
+ // WEBGPU Buffer implementation
2
+ import {Buffer, BufferProps, assert} from '@luma.gl/api';
3
+ import type WebGPUDevice from '../webgpu-device';
4
+
5
+ function getByteLength(props: BufferProps): number {
6
+ return props.byteLength || props.data?.byteLength || 0;
7
+ }
8
+
9
+ export default class WebGPUBuffer extends Buffer {
10
+ readonly device: WebGPUDevice;
11
+ readonly handle: GPUBuffer;
12
+ readonly byteLength: number;
13
+
14
+ constructor(device: WebGPUDevice, props: BufferProps) {
15
+ super(device, props);
16
+ this.device = device;
17
+
18
+ this.byteLength = getByteLength(props);
19
+ const mapBuffer = Boolean(props.data);
20
+
21
+ this.handle = this.props.handle || this.device.handle.createBuffer({
22
+ size: this.byteLength,
23
+ // usage defaults to vertex
24
+ usage: this.props.usage || (GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST),
25
+ mappedAtCreation: this.props.mappedAtCreation || mapBuffer,
26
+ label: this.props.id
27
+ });
28
+
29
+ if (props.data) {
30
+ this._writeMapped(props.data);
31
+ // this.handle.writeAsync({data: props.data, map: false, unmap: false});
32
+ }
33
+
34
+ if (mapBuffer && !props.mappedAtCreation) {
35
+ this.handle.unmap();
36
+ }
37
+ }
38
+
39
+ destroy(): void {
40
+ this.handle.destroy();
41
+ }
42
+
43
+ // WebGPU provides multiple ways to write a buffer...
44
+ write(data: ArrayBufferView, byteOffset = 0) {
45
+ this.device.handle.queue.writeBuffer(
46
+ this.handle,
47
+ byteOffset,
48
+ data.buffer,
49
+ data.byteOffset,
50
+ data.byteLength
51
+ );
52
+ }
53
+
54
+ async readAsync(byteOffset: number = 0, byteLength: number = this.byteLength): Promise<ArrayBuffer> {
55
+ // We need MAP_READ flag, but only COPY_DST buffers can have MAP_READ flag, so we need to create a temp buffer
56
+ const tempBuffer = new WebGPUBuffer(this.device, {usage: Buffer.MAP_READ | Buffer.COPY_DST, byteLength});
57
+
58
+ // Now do a GPU-side copy into the temp buffer we can actually read.
59
+ // TODO - we are spinning up an independent command queue here, what does this mean
60
+ const commandEncoder = this.device.handle.createCommandEncoder();
61
+ commandEncoder.copyBufferToBuffer(this.handle, byteOffset, tempBuffer.handle, 0, byteLength);
62
+ this.device.handle.queue.submit([commandEncoder.finish()]);
63
+
64
+ // Map the temp buffer and read the data.
65
+ await tempBuffer.handle.mapAsync(GPUMapMode.READ, byteOffset, byteLength);
66
+ const arrayBuffer = tempBuffer.handle.getMappedRange().slice(0);
67
+ tempBuffer.handle.unmap();
68
+ tempBuffer.destroy();
69
+
70
+ return arrayBuffer;
71
+ }
72
+
73
+ _writeMapped<TypedArray>(typedArray: TypedArray): void {
74
+ const arrayBuffer = this.handle.getMappedRange();
75
+ // @ts-expect-error
76
+ new typedArray.constructor(arrayBuffer).set(typedArray);
77
+ }
78
+
79
+ // WEBGPU API
80
+
81
+ mapAsync(mode: number, offset: number = 0, size?: number): Promise<void> {
82
+ return this.handle.mapAsync(mode, offset, size);
83
+ }
84
+
85
+ getMappedRange(offset: number = 0, size?: number): ArrayBuffer {
86
+ return this.handle.getMappedRange(offset, size);
87
+ }
88
+
89
+ unmap(): void {
90
+ this.handle.unmap();
91
+ }
92
+ }
@@ -0,0 +1,112 @@
1
+ import {CommandEncoder, CommandEncoderProps, RenderPipeline, Buffer, Texture, cast} from '@luma.gl/api';
2
+ import WebGPUDevice from '../webgpu-device';
3
+ import WEBGPUBuffer from './webgpu-buffer';
4
+ import WebGPUTexture from './webgpu-texture';
5
+
6
+ export default class WebGPUCommandEncoder extends CommandEncoder {
7
+ readonly device: WebGPUDevice;
8
+ readonly handle: GPUCommandEncoder;
9
+
10
+ constructor(device: WebGPUDevice, props: CommandEncoderProps) {
11
+ super(props);
12
+ this.device = device;
13
+ this.handle = props.handle || this.device.handle.createCommandEncoder({
14
+ measureExecutionTime: this.props.measureExecutionTime
15
+ });
16
+ this.handle.label = this.props.id;
17
+ }
18
+
19
+ destroy() {}
20
+
21
+ finish(options?: {id?: string}): GPUCommandBuffer {
22
+ return this.finish(options);
23
+ }
24
+
25
+ // beginRenderPass(GPURenderPassDescriptor descriptor): GPURenderPassEncoder;
26
+ // beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
27
+
28
+ copyBufferToBuffer(options: {
29
+ source: Buffer,
30
+ sourceOffset?: number,
31
+ destination: Buffer,
32
+ destinationOffset?: number,
33
+ size?: number
34
+ }): void {
35
+ this.handle.copyBufferToBuffer(
36
+ cast<WEBGPUBuffer>(options.source).handle,
37
+ options.sourceOffset ?? 0,
38
+ cast<WEBGPUBuffer>(options.destination).handle,
39
+ options.destinationOffset ?? 0,
40
+ options.size ?? 0
41
+ );
42
+ }
43
+
44
+ copyBufferToTexture(options: {
45
+ source: Buffer,
46
+ offset?: number,
47
+ bytesPerRow: number,
48
+ rowsPerImage: number,
49
+
50
+ destination: Texture,
51
+ mipLevel?: number;
52
+ aspect?: 'all' | 'stencil-only' | 'depth-only',
53
+
54
+ origin?: number[] | [number, number, number],
55
+ extent?: number[] | [number, number, number]
56
+ }): void {
57
+ this.handle.copyBufferToTexture(
58
+ {
59
+ buffer: cast<WEBGPUBuffer>(options.source).handle,
60
+ offset: options.offset ?? 0,
61
+ bytesPerRow: options.bytesPerRow,
62
+ rowsPerImage: options.rowsPerImage,
63
+ },
64
+ {
65
+ texture: cast<WebGPUTexture>(options.destination).handle,
66
+ mipLevel: options.mipLevel ?? 0,
67
+ origin: options.origin ?? {},
68
+ // aspect: options.aspect
69
+ },
70
+ {
71
+ // TODO exclamation mark hack
72
+ width: options.extent![0],
73
+ height: options.extent![1],
74
+ depthOrArrayLayers: options.extent![2]
75
+ }
76
+ );
77
+ }
78
+
79
+ copyTextureToBuffer(options: {
80
+ source: GPUImageCopyTexture,
81
+ destination: GPUImageCopyBuffer,
82
+ copySize: GPUExtent3D
83
+ }): void {}
84
+
85
+ copyTextureToTexture(options: {
86
+ source: GPUImageCopyTexture ,
87
+ destination: GPUImageCopyTexture,
88
+ copySize: GPUExtent3D
89
+ }): void {}
90
+
91
+ pushDebugGroup(groupLabel: string): void {
92
+ this.handle.pushDebugGroup(groupLabel);
93
+ }
94
+
95
+ popDebugGroup(): void {
96
+ this.handle.popDebugGroup();
97
+ }
98
+
99
+ insertDebugMarker(markerLabel: string): void {
100
+ this.handle.insertDebugMarker(markerLabel);
101
+ }
102
+
103
+ // writeTimestamp(querySet: Query, queryIndex: number): void {}
104
+
105
+ // resolveQuerySet(options: {
106
+ // querySet: GPUQuerySet,
107
+ // firstQuery: number,
108
+ // queryCount: number,
109
+ // destination: Buffer,
110
+ // destinationOffset?: number;
111
+ // }): void;
112
+ }
@@ -0,0 +1,74 @@
1
+ import {ComputePass, ComputePassProps, ComputePipeline, Buffer, Binding, cast} from '@luma.gl/api';
2
+ import WebGPUDevice from '../webgpu-device';
3
+ import WebGPUBuffer from './webgpu-buffer';
4
+ // import WebGPUCommandEncoder from './webgpu-command-encoder';
5
+ import WebGPUComputePipeline from './webgpu-compute-pipeline';
6
+
7
+ export default class WebGPUComputePass extends ComputePass {
8
+ readonly device: WebGPUDevice;
9
+ readonly handle: GPUComputePassEncoder;
10
+ _bindGroupLayout: GPUBindGroupLayout | null = null;
11
+
12
+ constructor(device: WebGPUDevice, props: ComputePassProps) {
13
+ super(device, props);
14
+ this.device = device;
15
+
16
+ this.handle = this.props.handle || device.commandEncoder?.beginComputePass({
17
+ label: this.props.id,
18
+ // timestampWrites?: GPUComputePassTimestampWrites;
19
+ });
20
+ }
21
+
22
+ /** @note no WebGPU destroy method, just gc */
23
+ destroy() {}
24
+
25
+ endPass(): void {
26
+ this.handle.endPass();
27
+ }
28
+
29
+ setPipeline(pipeline: ComputePipeline): void {
30
+ const wgpuPipeline = cast<WebGPUComputePipeline>(pipeline);
31
+ this.handle.setPipeline(wgpuPipeline.handle);
32
+ this._bindGroupLayout = wgpuPipeline._getBindGroupLayout();
33
+ }
34
+
35
+ /** Sets an array of bindings (uniform buffers, samplers, textures, ...) */
36
+ setBindings(bindings: Binding[]): void {
37
+ throw new Error('fix me');
38
+ // const bindGroup = getBindGroup(this.device.handle, this._bindGroupLayout, this.props.bindings);
39
+ // this.handle.setBindGroup(0, bindGroup);
40
+ }
41
+
42
+ /**
43
+ * Dispatch work to be performed with the current ComputePipeline.
44
+ * @param x X dimension of the grid of workgroups to dispatch.
45
+ * @param y Y dimension of the grid of workgroups to dispatch.
46
+ * @param z Z dimension of the grid of workgroups to dispatch.
47
+ */
48
+ dispatch(x: number, y?: number, z?: number): void {
49
+ this.handle.dispatch(x, y, z);
50
+ }
51
+
52
+ /**
53
+ * Dispatch work to be performed with the current ComputePipeline.
54
+ * @param indirectBuffer buffer must be a tightly packed block of three 32-bit unsigned integer values (12 bytes total), given in the same order as the arguments for dispatch()
55
+ * @param indirectOffset
56
+ */
57
+ dispatchIndirect(indirectBuffer: Buffer, indirectOffset: number = 0): void {
58
+ this.handle.dispatchIndirect(cast<WebGPUBuffer>(indirectBuffer).handle, indirectOffset);
59
+ }
60
+
61
+ pushDebugGroup(groupLabel: string): void {
62
+ this.handle.pushDebugGroup(groupLabel);
63
+ }
64
+ popDebugGroup(): void {
65
+ this.handle.popDebugGroup();
66
+ }
67
+ insertDebugMarker(markerLabel: string): void {
68
+ this.handle.insertDebugMarker(markerLabel);
69
+ }
70
+
71
+ // writeTimestamp(querySet: GPUQuerySet, queryIndex: number): void;
72
+ // beginPipelineStatisticsQuery(querySet: GPUQuerySet, queryIndex: number): void;
73
+ // endPipelineStatisticsQuery(querySet: GPUQuerySet, queryIndex: number): void;
74
+ }
@@ -0,0 +1,34 @@
1
+ // prettier-ignore
2
+ import {ComputePipeline, ComputePipelineProps, cast} from '@luma.gl/api';
3
+
4
+ import WebGPUDevice from '../webgpu-device';
5
+ import WebGPUShader from './webgpu-shader';
6
+
7
+ // COMPUTE PIPELINE
8
+
9
+ /** Creates a new compute pipeline when parameters change */
10
+ export default class WebGPUComputePipeline extends ComputePipeline {
11
+ device: WebGPUDevice;
12
+ handle: GPUComputePipeline;
13
+
14
+ constructor(device: WebGPUDevice, props: ComputePipelineProps) {
15
+ super(device, props);
16
+ this.device = device;
17
+
18
+ const module = cast<WebGPUShader>(this.props.cs).handle;
19
+ this.handle = this.props.handle || this.device.handle.createComputePipeline({
20
+ label: this.props.id,
21
+ compute: {
22
+ module,
23
+ entryPoint: this.props.csEntryPoint,
24
+ // constants: this.props.csConstants
25
+ }
26
+ });
27
+ }
28
+
29
+ /** For internal use in render passes */
30
+ _getBindGroupLayout() {
31
+ // TODO: Cache?
32
+ return this.handle.getBindGroupLayout(0);
33
+ }
34
+ }
@@ -0,0 +1,37 @@
1
+ // luma.gl, MIT license
2
+ import {ExternalTexture, ExternalTextureProps, Sampler, SamplerProps} from '@luma.gl/api';
3
+ import type WebGPUDevice from '../webgpu-device';
4
+ import WebGPUSampler from './webgpu-sampler';
5
+
6
+ /**
7
+ * Cheap, temporary texture view for videos
8
+ * Only valid within same callback, destroyed automatically as a microtask.
9
+ */
10
+ export default class WebGPUExternalTexture extends ExternalTexture {
11
+ readonly device: WebGPUDevice;
12
+ readonly handle: GPUExternalTexture;
13
+ sampler: WebGPUSampler;
14
+
15
+ constructor(device: WebGPUDevice, props: ExternalTextureProps) {
16
+ super(device, props);
17
+ this.device = device;
18
+ this.handle = this.props.handle || this.device.handle.importExternalTexture({
19
+ source: props.source,
20
+ colorSpace: props.colorSpace
21
+ });
22
+ this.sampler = null;
23
+ }
24
+
25
+ destroy(): void {
26
+ // External textures are destroyed automatically,
27
+ // as a microtask, instead of manually or upon garbage collection like other resources.
28
+ // this.handle.destroy();
29
+ }
30
+
31
+ /** Set default sampler */
32
+ setSampler(sampler: Sampler | SamplerProps): this {
33
+ // We can accept a sampler instance or set of props;
34
+ this.sampler = sampler instanceof WebGPUSampler ? sampler : new WebGPUSampler(this.device, sampler);
35
+ return this;
36
+ }
37
+ }
@@ -0,0 +1,120 @@
1
+ import type {FramebufferProps, ColorTextureFormat} from '@luma.gl/api';
2
+ import {Framebuffer, Texture} from '@luma.gl/api';
3
+ import WebGPUDevice from '../webgpu-device';
4
+ // import WebGPUCanvasContext from '../webgpu-canvas-context';
5
+ import WEBGPUTexture from './webgpu-texture';
6
+ import WebGPUTexture from './webgpu-texture';
7
+
8
+ // const DEFAULT_DEPTH_STENCIL_FORMAT: DepthStencilTextureFormat = 'depth24plus';
9
+
10
+ const MAX_COLOR_ATTACHMENTS = 8;
11
+
12
+ /**
13
+ * Create new textures with correct size for all attachments.
14
+ * @note resize() destroys existing textures (if size has changed).
15
+ */
16
+ export default class WebGPUFramebuffer extends Framebuffer {
17
+ readonly device: WebGPUDevice;
18
+
19
+ colorAttachments: WebGPUTexture[] = [];
20
+ depthStencilAttachment: WebGPUTexture | null = null;
21
+
22
+ /** Partial render pass descriptor. Used by WebGPURenderPass */
23
+ renderPassDescriptor: {
24
+ colorAttachments: GPURenderPassColorAttachment[];
25
+ depthStencilAttachment?: GPURenderPassDepthStencilAttachment;
26
+ } = {
27
+ colorAttachments: []
28
+ };
29
+
30
+ constructor(device: WebGPUDevice, props: FramebufferProps) {
31
+ super(device, props);
32
+ this.device = device;
33
+
34
+ if (props.depthStencilAttachment) {
35
+ this.depthStencilAttachment = this.createDepthStencilTexture(props);
36
+ }
37
+
38
+ if (props.colorAttachments) {
39
+ this.colorAttachments = props.colorAttachments.map(colorAttachment => this.createColorTexture(this.props, colorAttachment));
40
+ }
41
+
42
+ if (this.depthStencilAttachment) {
43
+ this.renderPassDescriptor.depthStencilAttachment = {
44
+ view: this.depthStencilAttachment.handle.createView(),
45
+ // Add default clear values
46
+ depthLoadValue: 1.0,
47
+ depthStoreOp: 'store',
48
+ stencilLoadValue: 0,
49
+ stencilStoreOp: 'store',
50
+ }
51
+ }
52
+
53
+ if (this.colorAttachments.length > 0) {
54
+ this.renderPassDescriptor.colorAttachments = this.colorAttachments.map(colorAttachment => ({
55
+ view: colorAttachment.handle.createView(),
56
+ loadValue: [0.0, 0.0, 0.0, 0.0],
57
+ storeOp: 'store'
58
+ }));
59
+ }
60
+ }
61
+
62
+ /** Create depth stencil texture */
63
+ private createDepthStencilTexture(props: FramebufferProps): WEBGPUTexture {
64
+ if (props.depthStencilAttachment instanceof WEBGPUTexture) {
65
+ return props.depthStencilAttachment;
66
+ }
67
+
68
+ if (typeof props.depthStencilAttachment === 'string') {
69
+ return this.device._createTexture({
70
+ id: 'depth-stencil-attachment',
71
+ format: props.depthStencilAttachment,
72
+ width: props.width,
73
+ height: props.height,
74
+ usage: Texture.RENDER_ATTACHMENT
75
+ });
76
+ }
77
+
78
+ throw new Error('type');
79
+ }
80
+
81
+ private createColorTexture(props: FramebufferProps, texture: Texture | ColorTextureFormat): WEBGPUTexture {
82
+ if (texture instanceof WEBGPUTexture) {
83
+ return texture;
84
+ }
85
+
86
+ if (typeof texture === 'string') {
87
+ return this.device._createTexture({
88
+ id: 'color-attachment',
89
+ format: texture,
90
+ width: props.width,
91
+ height: props.height,
92
+ usage: Texture.RENDER_ATTACHMENT
93
+ });
94
+ }
95
+
96
+ throw new Error('type');
97
+ }
98
+
99
+ /**
100
+ * Create new textures with correct size for all attachments.
101
+ * @note destroys existing textures.
102
+ */
103
+ protected _resizeAttachments(width: number, height: number): void {
104
+ for (let i = 0; i < this.colorAttachments.length; ++i) {
105
+ if (this.colorAttachments[i]) {
106
+ const resizedTexture = this.device._createTexture({...this.colorAttachments[i].props, width, height})
107
+ this.colorAttachments[i].destroy();
108
+ this.colorAttachments[i] = resizedTexture;
109
+ this.renderPassDescriptor.colorAttachments[i].view = resizedTexture.handle.createView();
110
+ }
111
+ }
112
+
113
+ if (this.depthStencilAttachment) {
114
+ const resizedTexture = this.device._createTexture({...this.depthStencilAttachment.props, width, height})
115
+ this.depthStencilAttachment.destroy();
116
+ this.depthStencilAttachment = resizedTexture;
117
+ this.renderPassDescriptor.depthStencilAttachment.view = resizedTexture.handle.createView();
118
+ }
119
+ }
120
+ }