@luma.gl/webgpu 9.3.0-alpha.4 → 9.3.0-alpha.8
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/dist/adapter/helpers/cpu-hotspot-profiler.d.ts +54 -0
- package/dist/adapter/helpers/cpu-hotspot-profiler.d.ts.map +1 -0
- package/dist/adapter/helpers/cpu-hotspot-profiler.js +26 -0
- package/dist/adapter/helpers/cpu-hotspot-profiler.js.map +1 -0
- package/dist/adapter/helpers/generate-mipmaps-webgpu.d.ts +7 -0
- package/dist/adapter/helpers/generate-mipmaps-webgpu.d.ts.map +1 -0
- package/dist/adapter/helpers/generate-mipmaps-webgpu.js +490 -0
- package/dist/adapter/helpers/generate-mipmaps-webgpu.js.map +1 -0
- package/dist/adapter/helpers/get-bind-group.d.ts +4 -6
- package/dist/adapter/helpers/get-bind-group.d.ts.map +1 -1
- package/dist/adapter/helpers/get-bind-group.js +31 -30
- package/dist/adapter/helpers/get-bind-group.js.map +1 -1
- package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts +3 -1
- package/dist/adapter/helpers/get-vertex-buffer-layout.d.ts.map +1 -1
- package/dist/adapter/helpers/get-vertex-buffer-layout.js +17 -12
- package/dist/adapter/helpers/get-vertex-buffer-layout.js.map +1 -1
- package/dist/adapter/helpers/webgpu-parameters.d.ts.map +1 -1
- package/dist/adapter/helpers/webgpu-parameters.js +1 -0
- package/dist/adapter/helpers/webgpu-parameters.js.map +1 -1
- package/dist/adapter/resources/webgpu-buffer.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-buffer.js +19 -3
- package/dist/adapter/resources/webgpu-buffer.js.map +1 -1
- package/dist/adapter/resources/webgpu-command-buffer.js +1 -1
- package/dist/adapter/resources/webgpu-command-buffer.js.map +1 -1
- package/dist/adapter/resources/webgpu-command-encoder.d.ts +7 -16
- package/dist/adapter/resources/webgpu-command-encoder.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-command-encoder.js +89 -32
- package/dist/adapter/resources/webgpu-command-encoder.js.map +1 -1
- package/dist/adapter/resources/webgpu-compute-pass.d.ts +3 -3
- package/dist/adapter/resources/webgpu-compute-pass.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-compute-pass.js +30 -12
- package/dist/adapter/resources/webgpu-compute-pass.js.map +1 -1
- package/dist/adapter/resources/webgpu-compute-pipeline.d.ts +7 -9
- package/dist/adapter/resources/webgpu-compute-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-compute-pipeline.js +30 -17
- package/dist/adapter/resources/webgpu-compute-pipeline.js.map +1 -1
- package/dist/adapter/resources/webgpu-fence.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-fence.js +9 -1
- package/dist/adapter/resources/webgpu-fence.js.map +1 -1
- package/dist/adapter/resources/webgpu-framebuffer.d.ts +6 -0
- package/dist/adapter/resources/webgpu-framebuffer.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-framebuffer.js +16 -0
- package/dist/adapter/resources/webgpu-framebuffer.js.map +1 -1
- package/dist/adapter/resources/webgpu-pipeline-layout.d.ts +1 -1
- package/dist/adapter/resources/webgpu-pipeline-layout.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-pipeline-layout.js +10 -16
- package/dist/adapter/resources/webgpu-pipeline-layout.js.map +1 -1
- package/dist/adapter/resources/webgpu-query-set.d.ts +33 -4
- package/dist/adapter/resources/webgpu-query-set.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-query-set.js +145 -4
- package/dist/adapter/resources/webgpu-query-set.js.map +1 -1
- package/dist/adapter/resources/webgpu-render-pass.d.ts +6 -3
- package/dist/adapter/resources/webgpu-render-pass.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-render-pass.js +78 -34
- package/dist/adapter/resources/webgpu-render-pass.js.map +1 -1
- package/dist/adapter/resources/webgpu-render-pipeline.d.ts +14 -10
- package/dist/adapter/resources/webgpu-render-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-render-pipeline.js +56 -35
- package/dist/adapter/resources/webgpu-render-pipeline.js.map +1 -1
- package/dist/adapter/resources/webgpu-sampler.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-sampler.js +4 -0
- package/dist/adapter/resources/webgpu-sampler.js.map +1 -1
- package/dist/adapter/resources/webgpu-shader.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-shader.js +17 -1
- package/dist/adapter/resources/webgpu-shader.js.map +1 -1
- package/dist/adapter/resources/webgpu-texture-view.d.ts +6 -0
- package/dist/adapter/resources/webgpu-texture-view.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-texture-view.js +47 -11
- package/dist/adapter/resources/webgpu-texture-view.js.map +1 -1
- package/dist/adapter/resources/webgpu-texture.d.ts +18 -5
- package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-texture.js +148 -97
- package/dist/adapter/resources/webgpu-texture.js.map +1 -1
- package/dist/adapter/resources/webgpu-vertex-array.js +1 -1
- package/dist/adapter/resources/webgpu-vertex-array.js.map +1 -1
- package/dist/adapter/webgpu-canvas-context.d.ts +2 -0
- package/dist/adapter/webgpu-canvas-context.d.ts.map +1 -1
- package/dist/adapter/webgpu-canvas-context.js +78 -19
- package/dist/adapter/webgpu-canvas-context.js.map +1 -1
- package/dist/adapter/webgpu-device.d.ts +10 -2
- package/dist/adapter/webgpu-device.d.ts.map +1 -1
- package/dist/adapter/webgpu-device.js +159 -13
- package/dist/adapter/webgpu-device.js.map +1 -1
- package/dist/adapter/webgpu-presentation-context.d.ts +25 -0
- package/dist/adapter/webgpu-presentation-context.d.ts.map +1 -0
- package/dist/adapter/webgpu-presentation-context.js +144 -0
- package/dist/adapter/webgpu-presentation-context.js.map +1 -0
- package/dist/dist.dev.js +3180 -1849
- package/dist/dist.min.js +168 -9
- package/dist/index.cjs +1640 -405
- package/dist/index.cjs.map +4 -4
- package/dist/wgsl/get-shader-layout-wgsl.d.ts.map +1 -1
- package/dist/wgsl/get-shader-layout-wgsl.js +8 -0
- package/dist/wgsl/get-shader-layout-wgsl.js.map +1 -1
- package/package.json +5 -5
- package/src/adapter/helpers/cpu-hotspot-profiler.ts +70 -0
- package/src/adapter/helpers/generate-mipmaps-webgpu.ts +583 -0
- package/src/adapter/helpers/get-bind-group.ts +42 -49
- package/src/adapter/helpers/get-vertex-buffer-layout.ts +31 -12
- package/src/adapter/helpers/webgpu-parameters.ts +2 -0
- package/src/adapter/resources/webgpu-buffer.ts +18 -3
- package/src/adapter/resources/webgpu-command-buffer.ts +1 -1
- package/src/adapter/resources/webgpu-command-encoder.ts +129 -50
- package/src/adapter/resources/webgpu-compute-pass.ts +48 -13
- package/src/adapter/resources/webgpu-compute-pipeline.ts +49 -18
- package/src/adapter/resources/webgpu-fence.ts +11 -3
- package/src/adapter/resources/webgpu-framebuffer.ts +21 -0
- package/src/adapter/resources/webgpu-pipeline-layout.ts +16 -14
- package/src/adapter/resources/webgpu-query-set.ts +185 -9
- package/src/adapter/resources/webgpu-render-pass.ts +92 -40
- package/src/adapter/resources/webgpu-render-pipeline.ts +83 -44
- package/src/adapter/resources/webgpu-sampler.ts +5 -0
- package/src/adapter/resources/webgpu-shader.ts +16 -1
- package/src/adapter/resources/webgpu-texture-view.ts +51 -11
- package/src/adapter/resources/webgpu-texture.ts +198 -132
- package/src/adapter/resources/webgpu-vertex-array.ts +1 -1
- package/src/adapter/webgpu-canvas-context.ts +91 -26
- package/src/adapter/webgpu-device.ts +212 -17
- package/src/adapter/webgpu-presentation-context.ts +180 -0
- package/src/wgsl/get-shader-layout-wgsl.ts +9 -0
- package/dist/adapter/helpers/accessor-to-format.d.ts +0 -1
- package/dist/adapter/helpers/accessor-to-format.d.ts.map +0 -1
- package/dist/adapter/helpers/accessor-to-format.js +0 -105
- package/dist/adapter/helpers/accessor-to-format.js.map +0 -1
- package/src/adapter/helpers/accessor-to-format.ts +0 -104
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
import type {ShaderLayout, BufferLayout, AttributeDeclaration, VertexFormat} from '@luma.gl/core';
|
|
6
|
-
import {log,
|
|
6
|
+
import {log, vertexFormatDecoder} from '@luma.gl/core';
|
|
7
7
|
// import {getAttributeInfosFromLayouts} from '@luma.gl/core';
|
|
8
8
|
|
|
9
9
|
/** Throw error on any WebGL-only vertex formats */
|
|
@@ -23,10 +23,12 @@ function getWebGPUVertexFormat(format: VertexFormat): GPUVertexFormat {
|
|
|
23
23
|
*/
|
|
24
24
|
export function getVertexBufferLayout(
|
|
25
25
|
shaderLayout: ShaderLayout,
|
|
26
|
-
bufferLayout: BufferLayout[]
|
|
26
|
+
bufferLayout: BufferLayout[],
|
|
27
|
+
options?: {pipelineId?: string}
|
|
27
28
|
): GPUVertexBufferLayout[] {
|
|
28
29
|
const vertexBufferLayouts: GPUVertexBufferLayout[] = [];
|
|
29
30
|
const usedAttributes = new Set<string>();
|
|
31
|
+
const shaderAttributes = shaderLayout.attributes || [];
|
|
30
32
|
|
|
31
33
|
// First handle any buffers mentioned in `bufferLayout`
|
|
32
34
|
for (const mapping of bufferLayout) {
|
|
@@ -44,7 +46,12 @@ export function getVertexBufferLayout(
|
|
|
44
46
|
// const arrayStride = mapping.byteStride; TODO
|
|
45
47
|
for (const attributeMapping of mapping.attributes) {
|
|
46
48
|
const attributeName = attributeMapping.attribute;
|
|
47
|
-
const attributeLayout = findAttributeLayout(
|
|
49
|
+
const attributeLayout = findAttributeLayout(
|
|
50
|
+
shaderLayout,
|
|
51
|
+
attributeName,
|
|
52
|
+
usedAttributes,
|
|
53
|
+
options
|
|
54
|
+
);
|
|
48
55
|
|
|
49
56
|
// @ts-ignore
|
|
50
57
|
const location: number = attributeLayout?.location;
|
|
@@ -59,15 +66,20 @@ export function getVertexBufferLayout(
|
|
|
59
66
|
shaderLocation: location
|
|
60
67
|
});
|
|
61
68
|
|
|
62
|
-
byteStride += getVertexFormatInfo(format).byteLength;
|
|
69
|
+
byteStride += vertexFormatDecoder.getVertexFormatInfo(format).byteLength;
|
|
63
70
|
}
|
|
64
71
|
// non-interleaved mapping (just set offset and stride)
|
|
65
72
|
} else {
|
|
66
|
-
const attributeLayout = findAttributeLayout(
|
|
73
|
+
const attributeLayout = findAttributeLayout(
|
|
74
|
+
shaderLayout,
|
|
75
|
+
mapping.name,
|
|
76
|
+
usedAttributes,
|
|
77
|
+
options
|
|
78
|
+
);
|
|
67
79
|
if (!attributeLayout) {
|
|
68
80
|
continue; // eslint-disable-line no-continue
|
|
69
81
|
}
|
|
70
|
-
byteStride = getVertexFormatInfo(format).byteLength;
|
|
82
|
+
byteStride = vertexFormatDecoder.getVertexFormatInfo(format).byteLength;
|
|
71
83
|
|
|
72
84
|
stepMode =
|
|
73
85
|
attributeLayout.stepMode ||
|
|
@@ -89,10 +101,10 @@ export function getVertexBufferLayout(
|
|
|
89
101
|
}
|
|
90
102
|
|
|
91
103
|
// Add any non-mapped attributes - TODO - avoid hardcoded types
|
|
92
|
-
for (const attribute of
|
|
104
|
+
for (const attribute of shaderAttributes) {
|
|
93
105
|
if (!usedAttributes.has(attribute.name)) {
|
|
94
106
|
vertexBufferLayouts.push({
|
|
95
|
-
arrayStride: getVertexFormatInfo('float32x3').byteLength,
|
|
107
|
+
arrayStride: vertexFormatDecoder.getVertexFormatInfo('float32x3').byteLength,
|
|
96
108
|
stepMode:
|
|
97
109
|
attribute.stepMode || (attribute.name.startsWith('instance') ? 'instance' : 'vertex'),
|
|
98
110
|
attributes: [
|
|
@@ -124,6 +136,7 @@ export function getBufferSlots(
|
|
|
124
136
|
bufferLayout: BufferLayout[]
|
|
125
137
|
): Record<string, number> {
|
|
126
138
|
const usedAttributes = new Set<string>();
|
|
139
|
+
const shaderAttributes = shaderLayout.attributes || [];
|
|
127
140
|
let bufferSlot = 0;
|
|
128
141
|
const bufferSlots: Record<string, number> = {};
|
|
129
142
|
|
|
@@ -142,7 +155,7 @@ export function getBufferSlots(
|
|
|
142
155
|
}
|
|
143
156
|
|
|
144
157
|
// Add any non-mapped attributes
|
|
145
|
-
for (const attribute of
|
|
158
|
+
for (const attribute of shaderAttributes) {
|
|
146
159
|
if (!usedAttributes.has(attribute.name)) {
|
|
147
160
|
bufferSlots[attribute.name] = bufferSlot++;
|
|
148
161
|
}
|
|
@@ -159,11 +172,17 @@ export function getBufferSlots(
|
|
|
159
172
|
function findAttributeLayout(
|
|
160
173
|
shaderLayout: ShaderLayout,
|
|
161
174
|
name: string,
|
|
162
|
-
attributeNames?: Set<string
|
|
175
|
+
attributeNames?: Set<string>,
|
|
176
|
+
options?: {pipelineId?: string}
|
|
163
177
|
): AttributeDeclaration | null {
|
|
164
|
-
const attribute = shaderLayout.attributes
|
|
178
|
+
const attribute = shaderLayout.attributes?.find(attribute_ => attribute_.name === name);
|
|
165
179
|
if (!attribute) {
|
|
166
|
-
|
|
180
|
+
const pipelineContext = options?.pipelineId
|
|
181
|
+
? `RenderPipeline(${options.pipelineId})`
|
|
182
|
+
: 'RenderPipeline';
|
|
183
|
+
log.warn(
|
|
184
|
+
`${pipelineContext}: Ignoring "${name}" attribute, since it is not present in shader layout.`
|
|
185
|
+
)();
|
|
167
186
|
return null;
|
|
168
187
|
}
|
|
169
188
|
if (attributeNames) {
|
|
@@ -65,6 +65,8 @@ export const PARAMETER_TABLE: Record<keyof Parameters, Function> = {
|
|
|
65
65
|
depthStencil.format = value;
|
|
66
66
|
},
|
|
67
67
|
|
|
68
|
+
clearDepth: notSupported,
|
|
69
|
+
|
|
68
70
|
depthBias: (_: keyof Parameters, value: any, descriptor: GPURenderPipelineDescriptor) => {
|
|
69
71
|
const depthStencil = addDepthStencil(descriptor);
|
|
70
72
|
depthStencil.depthBias = value;
|
|
@@ -67,12 +67,27 @@ export class WebGPUBuffer extends Buffer {
|
|
|
67
67
|
this.device.reportError(new Error(`${this} creation failed ${error.message}`), this)();
|
|
68
68
|
this.device.debug();
|
|
69
69
|
});
|
|
70
|
+
|
|
71
|
+
if (!this.props.handle) {
|
|
72
|
+
this.trackAllocatedMemory(size);
|
|
73
|
+
} else {
|
|
74
|
+
this.trackReferencedMemory(size, 'Buffer');
|
|
75
|
+
}
|
|
70
76
|
}
|
|
71
77
|
|
|
72
78
|
override destroy(): void {
|
|
73
|
-
this.handle
|
|
74
|
-
|
|
75
|
-
|
|
79
|
+
if (!this.destroyed && this.handle) {
|
|
80
|
+
this.removeStats();
|
|
81
|
+
if (!this.props.handle) {
|
|
82
|
+
this.trackDeallocatedMemory();
|
|
83
|
+
this.handle.destroy();
|
|
84
|
+
} else {
|
|
85
|
+
this.trackDeallocatedReferencedMemory('Buffer');
|
|
86
|
+
}
|
|
87
|
+
this.destroyed = true;
|
|
88
|
+
// @ts-expect-error readonly
|
|
89
|
+
this.handle = null;
|
|
90
|
+
}
|
|
76
91
|
}
|
|
77
92
|
|
|
78
93
|
write(data: ArrayBufferLike | ArrayBufferView | SharedArrayBuffer, byteOffset = 0) {
|
|
@@ -13,7 +13,7 @@ export class WebGPUCommandBuffer extends CommandBuffer {
|
|
|
13
13
|
readonly handle: GPUCommandBuffer;
|
|
14
14
|
|
|
15
15
|
constructor(commandEncoder: WebGPUCommandEncoder, props: CommandBufferProps) {
|
|
16
|
-
super(commandEncoder.device,
|
|
16
|
+
super(commandEncoder.device, props);
|
|
17
17
|
this.device = commandEncoder.device;
|
|
18
18
|
this.handle =
|
|
19
19
|
this.props.handle ||
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
import type {
|
|
6
|
+
CommandBufferProps,
|
|
6
7
|
RenderPassProps,
|
|
7
8
|
ComputePassProps,
|
|
9
|
+
CopyBufferToTextureOptions,
|
|
8
10
|
CopyTextureToTextureOptions,
|
|
9
11
|
CopyTextureToBufferOptions
|
|
10
12
|
} from '@luma.gl/core';
|
|
11
|
-
import {CommandEncoder, CommandEncoderProps, Buffer
|
|
13
|
+
import {CommandEncoder, CommandEncoderProps, Buffer} from '@luma.gl/core';
|
|
12
14
|
import {WebGPUDevice} from '../webgpu-device';
|
|
13
15
|
import {WebGPUCommandBuffer} from './webgpu-command-buffer';
|
|
14
16
|
import {WebGPUBuffer} from './webgpu-buffer';
|
|
@@ -34,9 +36,11 @@ export class WebGPUCommandEncoder extends CommandEncoder {
|
|
|
34
36
|
this.handle.label = this.props.id;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
override destroy(): void {
|
|
39
|
+
override destroy(): void {
|
|
40
|
+
this.destroyResource();
|
|
41
|
+
}
|
|
38
42
|
|
|
39
|
-
finish(props?:
|
|
43
|
+
finish(props?: CommandBufferProps): WebGPUCommandBuffer {
|
|
40
44
|
this.device.pushErrorScope('validation');
|
|
41
45
|
const commandBuffer = new WebGPUCommandBuffer(this, {
|
|
42
46
|
id: props?.id || 'unnamed-command-buffer'
|
|
@@ -46,6 +50,7 @@ export class WebGPUCommandEncoder extends CommandEncoder {
|
|
|
46
50
|
this.device.reportError(new Error(message), this)();
|
|
47
51
|
this.device.debug();
|
|
48
52
|
});
|
|
53
|
+
this.destroy();
|
|
49
54
|
return commandBuffer;
|
|
50
55
|
}
|
|
51
56
|
|
|
@@ -53,19 +58,26 @@ export class WebGPUCommandEncoder extends CommandEncoder {
|
|
|
53
58
|
* Allows a render pass to begin against a canvas context
|
|
54
59
|
* @todo need to support a "Framebuffer" equivalent (aka preconfigured RenderPassDescriptors?).
|
|
55
60
|
*/
|
|
56
|
-
beginRenderPass(props: RenderPassProps): WebGPURenderPass {
|
|
57
|
-
return new WebGPURenderPass(
|
|
61
|
+
beginRenderPass(props: RenderPassProps = {}): WebGPURenderPass {
|
|
62
|
+
return new WebGPURenderPass(
|
|
63
|
+
this.device,
|
|
64
|
+
this._applyTimeProfilingToPassProps(props),
|
|
65
|
+
this.handle
|
|
66
|
+
);
|
|
58
67
|
}
|
|
59
68
|
|
|
60
|
-
beginComputePass(props: ComputePassProps): WebGPUComputePass {
|
|
61
|
-
return new WebGPUComputePass(
|
|
69
|
+
beginComputePass(props: ComputePassProps = {}): WebGPUComputePass {
|
|
70
|
+
return new WebGPUComputePass(
|
|
71
|
+
this.device,
|
|
72
|
+
this._applyTimeProfilingToPassProps(props),
|
|
73
|
+
this.handle
|
|
74
|
+
);
|
|
62
75
|
}
|
|
63
76
|
|
|
64
77
|
// beginRenderPass(GPURenderPassDescriptor descriptor): GPURenderPassEncoder;
|
|
65
78
|
// beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
|
|
66
79
|
|
|
67
|
-
copyBufferToBuffer(options:
|
|
68
|
-
{
|
|
80
|
+
copyBufferToBuffer(options: {
|
|
69
81
|
sourceBuffer: Buffer;
|
|
70
82
|
sourceOffset?: number;
|
|
71
83
|
destinationBuffer: Buffer;
|
|
@@ -73,74 +85,119 @@ export class WebGPUCommandEncoder extends CommandEncoder {
|
|
|
73
85
|
size?: number;
|
|
74
86
|
}): void {
|
|
75
87
|
const webgpuSourceBuffer = options.sourceBuffer as WebGPUBuffer;
|
|
76
|
-
const
|
|
88
|
+
const webgpuDestinationBuffer = options.destinationBuffer as WebGPUBuffer;
|
|
77
89
|
this.handle.copyBufferToBuffer(
|
|
78
90
|
webgpuSourceBuffer.handle,
|
|
79
91
|
options.sourceOffset ?? 0,
|
|
80
|
-
|
|
92
|
+
webgpuDestinationBuffer.handle,
|
|
81
93
|
options.destinationOffset ?? 0,
|
|
82
94
|
options.size ?? 0
|
|
83
95
|
);
|
|
84
96
|
}
|
|
85
97
|
|
|
86
|
-
copyBufferToTexture(options:
|
|
87
|
-
{
|
|
88
|
-
sourceBuffer: Buffer;
|
|
89
|
-
offset?: number;
|
|
90
|
-
bytesPerRow: number;
|
|
91
|
-
rowsPerImage: number;
|
|
92
|
-
|
|
93
|
-
destinationTexture: Texture;
|
|
94
|
-
mipLevel?: number;
|
|
95
|
-
aspect?: 'all' | 'stencil-only' | 'depth-only';
|
|
96
|
-
|
|
97
|
-
origin?: number[] | [number, number, number];
|
|
98
|
-
extent?: number[] | [number, number, number];
|
|
99
|
-
}): void {
|
|
98
|
+
copyBufferToTexture(options: CopyBufferToTextureOptions): void {
|
|
100
99
|
const webgpuSourceBuffer = options.sourceBuffer as WebGPUBuffer;
|
|
101
|
-
const
|
|
100
|
+
const webgpuDestinationTexture = options.destinationTexture as WebGPUTexture;
|
|
101
|
+
const copyOrigin = options.origin ?? [0, 0, 0];
|
|
102
|
+
const copySize = options.size;
|
|
102
103
|
this.handle.copyBufferToTexture(
|
|
103
104
|
{
|
|
104
105
|
buffer: webgpuSourceBuffer.handle,
|
|
105
|
-
offset: options.
|
|
106
|
+
offset: options.byteOffset ?? 0,
|
|
106
107
|
bytesPerRow: options.bytesPerRow,
|
|
107
108
|
rowsPerImage: options.rowsPerImage
|
|
108
109
|
},
|
|
109
110
|
{
|
|
110
|
-
texture:
|
|
111
|
+
texture: webgpuDestinationTexture.handle,
|
|
111
112
|
mipLevel: options.mipLevel ?? 0,
|
|
112
|
-
origin:
|
|
113
|
-
|
|
113
|
+
origin: {
|
|
114
|
+
x: copyOrigin[0] ?? 0,
|
|
115
|
+
y: copyOrigin[1] ?? 0,
|
|
116
|
+
z: copyOrigin[2] ?? 0
|
|
117
|
+
},
|
|
118
|
+
aspect: options.aspect
|
|
114
119
|
},
|
|
115
120
|
{
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
depthOrArrayLayers: options.extent?.[2]
|
|
121
|
+
width: copySize[0],
|
|
122
|
+
height: copySize[1],
|
|
123
|
+
depthOrArrayLayers: copySize[2]
|
|
120
124
|
}
|
|
121
125
|
);
|
|
122
126
|
}
|
|
123
127
|
|
|
124
128
|
copyTextureToBuffer(options: CopyTextureToBufferOptions): void {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
129
|
+
const {
|
|
130
|
+
sourceTexture,
|
|
131
|
+
destinationBuffer,
|
|
132
|
+
origin = [0, 0, 0],
|
|
133
|
+
byteOffset = 0,
|
|
134
|
+
width,
|
|
135
|
+
height,
|
|
136
|
+
depthOrArrayLayers,
|
|
137
|
+
mipLevel,
|
|
138
|
+
aspect
|
|
139
|
+
} = options;
|
|
140
|
+
const webgpuSourceTexture = sourceTexture as WebGPUTexture;
|
|
141
|
+
webgpuSourceTexture.copyToBuffer(
|
|
142
|
+
this.handle,
|
|
143
|
+
{
|
|
144
|
+
x: origin[0] ?? 0,
|
|
145
|
+
y: origin[1] ?? 0,
|
|
146
|
+
z: origin[2] ?? 0,
|
|
147
|
+
width,
|
|
148
|
+
height,
|
|
149
|
+
depthOrArrayLayers,
|
|
150
|
+
mipLevel,
|
|
151
|
+
aspect,
|
|
152
|
+
byteOffset,
|
|
153
|
+
bytesPerRow: options.bytesPerRow,
|
|
154
|
+
rowsPerImage: options.rowsPerImage
|
|
155
|
+
},
|
|
156
|
+
destinationBuffer
|
|
157
|
+
);
|
|
133
158
|
}
|
|
134
159
|
|
|
135
160
|
copyTextureToTexture(options: CopyTextureToTextureOptions): void {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
161
|
+
const webgpuSourceTexture = options.sourceTexture as WebGPUTexture;
|
|
162
|
+
const webgpuDestinationTexture = options.destinationTexture as WebGPUTexture;
|
|
163
|
+
const sourceRegion = webgpuSourceTexture._normalizeTextureReadOptions({
|
|
164
|
+
x: options.origin?.[0] ?? 0,
|
|
165
|
+
y: options.origin?.[1] ?? 0,
|
|
166
|
+
z: options.origin?.[2] ?? 0,
|
|
167
|
+
width: options.width,
|
|
168
|
+
height: options.height,
|
|
169
|
+
depthOrArrayLayers: options.depthOrArrayLayers,
|
|
170
|
+
mipLevel: options.mipLevel ?? 0,
|
|
171
|
+
aspect: options.aspect ?? 'all'
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
this.handle.copyTextureToTexture(
|
|
175
|
+
{
|
|
176
|
+
texture: webgpuSourceTexture.handle,
|
|
177
|
+
mipLevel: sourceRegion.mipLevel,
|
|
178
|
+
origin: {
|
|
179
|
+
x: sourceRegion.x,
|
|
180
|
+
y: sourceRegion.y,
|
|
181
|
+
z: sourceRegion.z
|
|
182
|
+
},
|
|
183
|
+
aspect: sourceRegion.aspect
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
texture: webgpuDestinationTexture.handle,
|
|
187
|
+
mipLevel: options.destinationMipLevel ?? 0,
|
|
188
|
+
origin: {
|
|
189
|
+
x: options.destinationOrigin?.[0] ?? 0,
|
|
190
|
+
y: options.destinationOrigin?.[1] ?? 0,
|
|
191
|
+
z: options.destinationOrigin?.[2] ?? 0
|
|
192
|
+
},
|
|
193
|
+
aspect: options.destinationAspect ?? sourceRegion.aspect
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
width: sourceRegion.width,
|
|
197
|
+
height: sourceRegion.height,
|
|
198
|
+
depthOrArrayLayers: sourceRegion.depthOrArrayLayers
|
|
199
|
+
}
|
|
200
|
+
);
|
|
144
201
|
}
|
|
145
202
|
|
|
146
203
|
override pushDebugGroup(groupLabel: string): void {
|
|
@@ -174,6 +231,28 @@ export class WebGPUCommandEncoder extends CommandEncoder {
|
|
|
174
231
|
options?.destinationOffset || 0
|
|
175
232
|
);
|
|
176
233
|
}
|
|
234
|
+
|
|
235
|
+
writeTimestamp(querySet: WebGPUQuerySet, queryIndex: number): void {
|
|
236
|
+
querySet._invalidateResults();
|
|
237
|
+
const writeTimestamp = (
|
|
238
|
+
this.handle as GPUCommandEncoder & {
|
|
239
|
+
writeTimestamp?: (querySet: GPUQuerySet, queryIndex: number) => void;
|
|
240
|
+
}
|
|
241
|
+
).writeTimestamp;
|
|
242
|
+
|
|
243
|
+
if (writeTimestamp) {
|
|
244
|
+
writeTimestamp.call(this.handle, querySet.handle, queryIndex);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const computePass = this.handle.beginComputePass({
|
|
249
|
+
timestampWrites: {
|
|
250
|
+
querySet: querySet.handle,
|
|
251
|
+
beginningOfPassWriteIndex: queryIndex
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
computePass.end();
|
|
255
|
+
}
|
|
177
256
|
}
|
|
178
257
|
|
|
179
258
|
/*
|
|
@@ -2,7 +2,15 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
ComputePass,
|
|
7
|
+
ComputePassProps,
|
|
8
|
+
ComputePipeline,
|
|
9
|
+
Buffer,
|
|
10
|
+
Bindings,
|
|
11
|
+
BindingsByGroup,
|
|
12
|
+
_getDefaultBindGroupFactory
|
|
13
|
+
} from '@luma.gl/core';
|
|
6
14
|
import {WebGPUDevice} from '../webgpu-device';
|
|
7
15
|
import {WebGPUBuffer} from './webgpu-buffer';
|
|
8
16
|
import {WebGPUComputePipeline} from './webgpu-compute-pipeline';
|
|
@@ -14,53 +22,80 @@ export class WebGPUComputePass extends ComputePass {
|
|
|
14
22
|
|
|
15
23
|
_webgpuPipeline: WebGPUComputePipeline | null = null;
|
|
16
24
|
|
|
17
|
-
constructor(
|
|
25
|
+
constructor(
|
|
26
|
+
device: WebGPUDevice,
|
|
27
|
+
props: ComputePassProps = {},
|
|
28
|
+
commandEncoder: GPUCommandEncoder = device.commandEncoder.handle
|
|
29
|
+
) {
|
|
18
30
|
super(device, props);
|
|
19
31
|
this.device = device;
|
|
32
|
+
const {props: computePassProps} = this;
|
|
20
33
|
|
|
21
34
|
// Set up queries
|
|
22
35
|
let timestampWrites: GPUComputePassTimestampWrites | undefined;
|
|
23
|
-
if (
|
|
24
|
-
const webgpuQuerySet =
|
|
36
|
+
if (computePassProps.timestampQuerySet) {
|
|
37
|
+
const webgpuQuerySet = computePassProps.timestampQuerySet as WebGPUQuerySet;
|
|
25
38
|
if (webgpuQuerySet) {
|
|
39
|
+
webgpuQuerySet._invalidateResults();
|
|
26
40
|
timestampWrites = {
|
|
27
41
|
querySet: webgpuQuerySet.handle,
|
|
28
|
-
beginningOfPassWriteIndex:
|
|
29
|
-
endOfPassWriteIndex:
|
|
42
|
+
beginningOfPassWriteIndex: computePassProps.beginTimestampIndex,
|
|
43
|
+
endOfPassWriteIndex: computePassProps.endTimestampIndex
|
|
30
44
|
};
|
|
31
45
|
}
|
|
32
46
|
}
|
|
33
47
|
|
|
34
48
|
this.handle =
|
|
35
49
|
this.props.handle ||
|
|
36
|
-
|
|
50
|
+
commandEncoder.beginComputePass({
|
|
37
51
|
label: this.props.id,
|
|
38
52
|
timestampWrites
|
|
39
53
|
});
|
|
40
54
|
}
|
|
41
55
|
|
|
42
56
|
/** @note no WebGPU destroy method, just gc */
|
|
43
|
-
override destroy(): void {
|
|
57
|
+
override destroy(): void {
|
|
58
|
+
this.destroyResource();
|
|
59
|
+
}
|
|
44
60
|
|
|
45
61
|
end(): void {
|
|
62
|
+
if (this.destroyed) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
46
65
|
this.handle.end();
|
|
66
|
+
this.destroy();
|
|
47
67
|
}
|
|
48
68
|
|
|
49
69
|
setPipeline(pipeline: ComputePipeline): void {
|
|
50
70
|
const wgpuPipeline = pipeline as WebGPUComputePipeline;
|
|
51
71
|
this.handle.setPipeline(wgpuPipeline.handle);
|
|
52
72
|
this._webgpuPipeline = wgpuPipeline;
|
|
53
|
-
this.
|
|
73
|
+
const bindGroups = _getDefaultBindGroupFactory(this.device).getBindGroups(
|
|
74
|
+
this._webgpuPipeline,
|
|
75
|
+
this._webgpuPipeline._getBindingsByGroupWebGPU(),
|
|
76
|
+
this._webgpuPipeline._getBindGroupCacheKeysWebGPU()
|
|
77
|
+
);
|
|
78
|
+
for (const [group, bindGroup] of Object.entries(bindGroups)) {
|
|
79
|
+
if (bindGroup) {
|
|
80
|
+
this.handle.setBindGroup(Number(group), bindGroup as GPUBindGroup);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
54
83
|
}
|
|
55
84
|
|
|
56
85
|
/**
|
|
57
86
|
* Sets an array of bindings (uniform buffers, samplers, textures, ...)
|
|
58
87
|
* TODO - still some API confusion - does this method go here or on the pipeline?
|
|
59
88
|
*/
|
|
60
|
-
setBindings(bindings:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
89
|
+
setBindings(bindings: Bindings | BindingsByGroup): void {
|
|
90
|
+
const bindGroups =
|
|
91
|
+
(this._webgpuPipeline &&
|
|
92
|
+
_getDefaultBindGroupFactory(this.device).getBindGroups(this._webgpuPipeline, bindings)) ||
|
|
93
|
+
{};
|
|
94
|
+
for (const [group, bindGroup] of Object.entries(bindGroups)) {
|
|
95
|
+
if (bindGroup) {
|
|
96
|
+
this.handle.setBindGroup(Number(group), bindGroup as GPUBindGroup);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
64
99
|
}
|
|
65
100
|
|
|
66
101
|
/**
|
|
@@ -2,11 +2,19 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
ComputePipeline,
|
|
7
|
+
ComputePipelineProps,
|
|
8
|
+
Bindings,
|
|
9
|
+
BindingsByGroup,
|
|
10
|
+
_getDefaultBindGroupFactory,
|
|
11
|
+
normalizeBindingsByGroup
|
|
12
|
+
} from '@luma.gl/core';
|
|
7
13
|
import {WebGPUDevice} from '../webgpu-device';
|
|
8
14
|
import {WebGPUShader} from './webgpu-shader';
|
|
9
15
|
|
|
16
|
+
const EMPTY_BIND_GROUPS: BindingsByGroup = {};
|
|
17
|
+
|
|
10
18
|
// COMPUTE PIPELINE
|
|
11
19
|
|
|
12
20
|
/** Creates a new compute pipeline when parameters change */
|
|
@@ -14,11 +22,8 @@ export class WebGPUComputePipeline extends ComputePipeline {
|
|
|
14
22
|
readonly device: WebGPUDevice;
|
|
15
23
|
readonly handle: GPUComputePipeline;
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
private
|
|
19
|
-
private _bindGroup: GPUBindGroup | null = null;
|
|
20
|
-
/** For internal use to create BindGroups */
|
|
21
|
-
private _bindings: Record<string, Binding> = {};
|
|
25
|
+
private _bindingsByGroup: BindingsByGroup;
|
|
26
|
+
private _bindGroupCacheKeysByGroup: Partial<Record<number, object>>;
|
|
22
27
|
|
|
23
28
|
constructor(device: WebGPUDevice, props: ComputePipelineProps) {
|
|
24
29
|
super(device, props);
|
|
@@ -37,26 +42,52 @@ export class WebGPUComputePipeline extends ComputePipeline {
|
|
|
37
42
|
},
|
|
38
43
|
layout: 'auto'
|
|
39
44
|
});
|
|
45
|
+
|
|
46
|
+
this._bindingsByGroup = EMPTY_BIND_GROUPS;
|
|
47
|
+
this._bindGroupCacheKeysByGroup = {};
|
|
40
48
|
}
|
|
41
49
|
|
|
42
50
|
/**
|
|
43
51
|
* @todo Use renderpass.setBindings() ?
|
|
44
52
|
* @todo Do we want to expose BindGroups in the API and remove this?
|
|
45
53
|
*/
|
|
46
|
-
setBindings(bindings:
|
|
47
|
-
|
|
54
|
+
setBindings(bindings: Bindings | BindingsByGroup): void {
|
|
55
|
+
const nextBindingsByGroup = normalizeBindingsByGroup(this.shaderLayout, bindings);
|
|
56
|
+
for (const [groupKey, groupBindings] of Object.entries(nextBindingsByGroup)) {
|
|
57
|
+
const group = Number(groupKey);
|
|
58
|
+
for (const [name, binding] of Object.entries(groupBindings || {})) {
|
|
59
|
+
const currentGroupBindings = this._bindingsByGroup[group] || {};
|
|
60
|
+
if (currentGroupBindings[name] !== binding) {
|
|
61
|
+
if (
|
|
62
|
+
!this._bindingsByGroup[group] ||
|
|
63
|
+
this._bindingsByGroup[group] === currentGroupBindings
|
|
64
|
+
) {
|
|
65
|
+
this._bindingsByGroup[group] = {...currentGroupBindings};
|
|
66
|
+
}
|
|
67
|
+
this._bindingsByGroup[group][name] = binding;
|
|
68
|
+
this._bindGroupCacheKeysByGroup[group] = {};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
48
72
|
}
|
|
49
73
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
74
|
+
_getBindGroups(
|
|
75
|
+
bindings?: Bindings | BindingsByGroup,
|
|
76
|
+
bindGroupCacheKeys?: Partial<Record<number, object>>
|
|
77
|
+
): Partial<Record<number, unknown>> {
|
|
78
|
+
const hasExplicitBindings = Boolean(bindings);
|
|
79
|
+
return _getDefaultBindGroupFactory(this.device).getBindGroups(
|
|
80
|
+
this,
|
|
81
|
+
hasExplicitBindings ? bindings : this._bindingsByGroup,
|
|
82
|
+
hasExplicitBindings ? bindGroupCacheKeys : this._bindGroupCacheKeysByGroup
|
|
83
|
+
);
|
|
84
|
+
}
|
|
54
85
|
|
|
55
|
-
|
|
56
|
-
this.
|
|
57
|
-
|
|
58
|
-
getBindGroup(this.device.handle, this._bindGroupLayout, this.shaderLayout, this._bindings);
|
|
86
|
+
_getBindingsByGroupWebGPU(): BindingsByGroup {
|
|
87
|
+
return this._bindingsByGroup;
|
|
88
|
+
}
|
|
59
89
|
|
|
60
|
-
|
|
90
|
+
_getBindGroupCacheKeysWebGPU(): Partial<Record<number, object>> {
|
|
91
|
+
return this._bindGroupCacheKeysByGroup;
|
|
61
92
|
}
|
|
62
93
|
}
|
|
@@ -15,9 +15,17 @@ export class WebGPUFence extends Fence {
|
|
|
15
15
|
constructor(device: WebGPUDevice, props: FenceProps = {}) {
|
|
16
16
|
super(device, {});
|
|
17
17
|
this.device = device;
|
|
18
|
-
this.signaled = device.handle.queue
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
this.signaled = device.handle.queue
|
|
19
|
+
.onSubmittedWorkDone()
|
|
20
|
+
.then(() => {
|
|
21
|
+
this._signaled = true;
|
|
22
|
+
})
|
|
23
|
+
.catch(error => {
|
|
24
|
+
if (this.device.shouldIgnoreDroppedInstanceError(error)) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
throw error;
|
|
28
|
+
});
|
|
21
29
|
}
|
|
22
30
|
|
|
23
31
|
isSignaled(): boolean {
|
|
@@ -29,4 +29,25 @@ export class WebGPUFramebuffer extends Framebuffer {
|
|
|
29
29
|
protected updateAttachments(): void {
|
|
30
30
|
// WebGPU framebuffers are JS only objects, nothing to update
|
|
31
31
|
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Internal-only hook for the cached CanvasContext/PresentationContext swapchain path.
|
|
35
|
+
* Rebinds the long-lived default framebuffer wrapper to the current per-frame color view
|
|
36
|
+
* and optional depth attachment without allocating a new luma.gl Framebuffer object.
|
|
37
|
+
*/
|
|
38
|
+
_reinitialize(
|
|
39
|
+
colorAttachment: WebGPUTextureView,
|
|
40
|
+
depthStencilAttachment: WebGPUTextureView | null
|
|
41
|
+
): void {
|
|
42
|
+
this.colorAttachments[0] = colorAttachment;
|
|
43
|
+
// @ts-expect-error Internal-only canvas wrapper reuse mutates this otherwise-readonly attachment.
|
|
44
|
+
this.depthStencilAttachment = depthStencilAttachment;
|
|
45
|
+
this.width = colorAttachment.texture.width;
|
|
46
|
+
this.height = colorAttachment.texture.height;
|
|
47
|
+
|
|
48
|
+
this.props.width = this.width;
|
|
49
|
+
this.props.height = this.height;
|
|
50
|
+
this.props.colorAttachments = [colorAttachment.texture];
|
|
51
|
+
this.props.depthStencilAttachment = depthStencilAttachment?.texture || null;
|
|
52
|
+
}
|
|
32
53
|
}
|