@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
|
@@ -40,6 +40,11 @@ export class WebGPUSampler extends Sampler {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
override destroy(): void {
|
|
43
|
+
if (this.destroyed) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
this.destroyResource();
|
|
43
48
|
// GPUSampler does not have a destroy method
|
|
44
49
|
// this.handle.destroy();
|
|
45
50
|
// @ts-expect-error readonly
|
|
@@ -64,7 +64,22 @@ export class WebGPUShader extends Shader {
|
|
|
64
64
|
|
|
65
65
|
/** Returns compilation info for this shader */
|
|
66
66
|
async getCompilationInfo(): Promise<readonly CompilerMessage[]> {
|
|
67
|
-
|
|
67
|
+
// `_checkCompilationError()` runs asynchronously after construction, so the shader can be
|
|
68
|
+
// destroyed before we await compilation info. Snapshot the handle and treat a destroyed shader
|
|
69
|
+
// as having no compiler messages instead of dereferencing `null`.
|
|
70
|
+
const handle = this.handle;
|
|
71
|
+
if (!handle) {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
let compilationInfo;
|
|
75
|
+
try {
|
|
76
|
+
compilationInfo = await handle.getCompilationInfo();
|
|
77
|
+
} catch (error) {
|
|
78
|
+
if (this.device.shouldIgnoreDroppedInstanceError(error, 'getCompilationInfo')) {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
68
83
|
return compilationInfo.messages;
|
|
69
84
|
}
|
|
70
85
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import {TextureView, TextureViewProps} from '@luma.gl/core';
|
|
6
6
|
import type {WebGPUDevice} from '../webgpu-device';
|
|
7
7
|
import type {WebGPUTexture} from './webgpu-texture';
|
|
8
|
+
import {getCpuHotspotProfiler, getTimestamp} from '../helpers/cpu-hotspot-profiler';
|
|
8
9
|
|
|
9
10
|
/*
|
|
10
11
|
// type = sampler
|
|
@@ -39,17 +40,15 @@ export class WebGPUTextureView extends TextureView {
|
|
|
39
40
|
this.texture = props.texture;
|
|
40
41
|
|
|
41
42
|
this.device.pushErrorScope('validation');
|
|
42
|
-
this.handle =
|
|
43
|
-
|
|
44
|
-
this.texture.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
arrayLayerCount: this.props.arrayLayerCount
|
|
52
|
-
});
|
|
43
|
+
this.handle = this.texture.handle.createView({
|
|
44
|
+
format: (this.props.format || this.texture.format) as GPUTextureFormat,
|
|
45
|
+
dimension: this.props.dimension || this.texture.dimension,
|
|
46
|
+
aspect: this.props.aspect,
|
|
47
|
+
baseMipLevel: this.props.baseMipLevel,
|
|
48
|
+
mipLevelCount: this.props.mipLevelCount,
|
|
49
|
+
baseArrayLayer: this.props.baseArrayLayer,
|
|
50
|
+
arrayLayerCount: this.props.arrayLayerCount
|
|
51
|
+
});
|
|
53
52
|
this.device.popErrorScope((error: GPUError) => {
|
|
54
53
|
this.device.reportError(new Error(`TextureView constructor: ${error.message}`), this)();
|
|
55
54
|
this.device.debug();
|
|
@@ -59,9 +58,50 @@ export class WebGPUTextureView extends TextureView {
|
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
override destroy(): void {
|
|
61
|
+
if (this.destroyed) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this.destroyResource();
|
|
62
66
|
// GPUTextureView does not have a destroy method
|
|
63
67
|
// this.handle.destroy();
|
|
64
68
|
// @ts-expect-error readonly
|
|
65
69
|
this.handle = null;
|
|
66
70
|
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Internal-only hook for the cached CanvasContext/PresentationContext swapchain path.
|
|
74
|
+
* Rebuilds the default view when the per-frame canvas texture handle changes, without
|
|
75
|
+
* replacing the long-lived luma.gl wrapper object.
|
|
76
|
+
*/
|
|
77
|
+
_reinitialize(texture: WebGPUTexture): void {
|
|
78
|
+
// @ts-expect-error readonly
|
|
79
|
+
this.texture = texture;
|
|
80
|
+
|
|
81
|
+
const profiler = getCpuHotspotProfiler(this.device);
|
|
82
|
+
this.device.pushErrorScope('validation');
|
|
83
|
+
const createViewStartTime = profiler ? getTimestamp() : 0;
|
|
84
|
+
const handle = this.texture.handle.createView({
|
|
85
|
+
format: (this.props.format || this.texture.format) as GPUTextureFormat,
|
|
86
|
+
dimension: this.props.dimension || this.texture.dimension,
|
|
87
|
+
aspect: this.props.aspect,
|
|
88
|
+
baseMipLevel: this.props.baseMipLevel,
|
|
89
|
+
mipLevelCount: this.props.mipLevelCount,
|
|
90
|
+
baseArrayLayer: this.props.baseArrayLayer,
|
|
91
|
+
arrayLayerCount: this.props.arrayLayerCount
|
|
92
|
+
});
|
|
93
|
+
if (profiler) {
|
|
94
|
+
profiler.textureViewReinitializeCount = (profiler.textureViewReinitializeCount || 0) + 1;
|
|
95
|
+
profiler.textureViewReinitializeTimeMs =
|
|
96
|
+
(profiler.textureViewReinitializeTimeMs || 0) + (getTimestamp() - createViewStartTime);
|
|
97
|
+
}
|
|
98
|
+
this.device.popErrorScope((error: GPUError) => {
|
|
99
|
+
this.device.reportError(new Error(`TextureView constructor: ${error.message}`), this)();
|
|
100
|
+
this.device.debug();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
handle.label = this.props.id;
|
|
104
|
+
// @ts-expect-error readonly
|
|
105
|
+
this.handle = handle;
|
|
106
|
+
}
|
|
67
107
|
}
|
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
type TextureProps,
|
|
4
4
|
type TextureViewProps,
|
|
5
5
|
type CopyExternalImageOptions,
|
|
6
|
-
type CopyImageDataOptions,
|
|
7
6
|
type TextureReadOptions,
|
|
8
7
|
type TextureWriteOptions,
|
|
9
8
|
type SamplerProps,
|
|
@@ -17,6 +16,7 @@ import {getWebGPUTextureFormat} from '../helpers/convert-texture-format';
|
|
|
17
16
|
import type {WebGPUDevice} from '../webgpu-device';
|
|
18
17
|
import {WebGPUSampler} from './webgpu-sampler';
|
|
19
18
|
import {WebGPUTextureView} from './webgpu-texture-view';
|
|
19
|
+
import {WebGPUBuffer} from './webgpu-buffer';
|
|
20
20
|
|
|
21
21
|
/** WebGPU implementation of the luma.gl core Texture resource */
|
|
22
22
|
export class WebGPUTexture extends Texture {
|
|
@@ -24,11 +24,22 @@ export class WebGPUTexture extends Texture {
|
|
|
24
24
|
readonly handle: GPUTexture;
|
|
25
25
|
sampler: WebGPUSampler;
|
|
26
26
|
view: WebGPUTextureView;
|
|
27
|
+
private _allocatedByteLength: number = 0;
|
|
27
28
|
|
|
28
29
|
constructor(device: WebGPUDevice, props: TextureProps) {
|
|
29
|
-
|
|
30
|
+
// WebGPU buffer copies use 256-byte row alignment. queue.writeTexture() can use tightly packed rows.
|
|
31
|
+
super(device, props, {byteAlignment: 256});
|
|
30
32
|
this.device = device;
|
|
31
33
|
|
|
34
|
+
if (props.sampler instanceof WebGPUSampler) {
|
|
35
|
+
this.sampler = props.sampler;
|
|
36
|
+
} else if (props.sampler === undefined) {
|
|
37
|
+
this.sampler = this.device.getDefaultSampler();
|
|
38
|
+
} else {
|
|
39
|
+
this.sampler = new WebGPUSampler(this.device, (props.sampler as SamplerProps) || {});
|
|
40
|
+
this.attachResource(this.sampler);
|
|
41
|
+
}
|
|
42
|
+
|
|
32
43
|
this.device.pushErrorScope('out-of-memory');
|
|
33
44
|
this.device.pushErrorScope('validation');
|
|
34
45
|
|
|
@@ -56,8 +67,6 @@ export class WebGPUTexture extends Texture {
|
|
|
56
67
|
this.device.debug();
|
|
57
68
|
});
|
|
58
69
|
|
|
59
|
-
// Update props if external handle was supplied - used mainly by CanvasContext.getDefaultFramebuffer()
|
|
60
|
-
// TODO - Read all properties directly from the supplied handle?
|
|
61
70
|
if (this.props.handle) {
|
|
62
71
|
this.handle.label ||= this.id;
|
|
63
72
|
// @ts-expect-error readonly
|
|
@@ -66,11 +75,6 @@ export class WebGPUTexture extends Texture {
|
|
|
66
75
|
this.height = this.handle.height;
|
|
67
76
|
}
|
|
68
77
|
|
|
69
|
-
this.sampler =
|
|
70
|
-
props.sampler instanceof WebGPUSampler
|
|
71
|
-
? props.sampler
|
|
72
|
-
: new WebGPUSampler(this.device, (props.sampler as SamplerProps) || {});
|
|
73
|
-
|
|
74
78
|
this.view = new WebGPUTextureView(this.device, {
|
|
75
79
|
...this.props,
|
|
76
80
|
texture: this,
|
|
@@ -78,14 +82,34 @@ export class WebGPUTexture extends Texture {
|
|
|
78
82
|
// Note: arrayLayerCount controls the view of array textures, but does not apply to 3d texture depths
|
|
79
83
|
arrayLayerCount: this.dimension !== '3d' ? this.depth : 1
|
|
80
84
|
});
|
|
85
|
+
this.attachResource(this.view);
|
|
81
86
|
|
|
82
87
|
// Set initial data
|
|
83
88
|
// Texture base class strips out the data prop from this.props, so we need to handle it here
|
|
84
89
|
this._initializeData(props.data);
|
|
90
|
+
|
|
91
|
+
this._allocatedByteLength = this.getAllocatedByteLength();
|
|
92
|
+
|
|
93
|
+
if (!this.props.handle) {
|
|
94
|
+
this.trackAllocatedMemory(this._allocatedByteLength, 'Texture');
|
|
95
|
+
} else {
|
|
96
|
+
this.trackReferencedMemory(this._allocatedByteLength, 'Texture');
|
|
97
|
+
}
|
|
85
98
|
}
|
|
86
99
|
|
|
87
100
|
override destroy(): void {
|
|
88
|
-
this.
|
|
101
|
+
if (this.destroyed) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!this.props.handle && this.handle) {
|
|
106
|
+
this.trackDeallocatedMemory('Texture');
|
|
107
|
+
this.handle.destroy();
|
|
108
|
+
} else if (this.handle) {
|
|
109
|
+
this.trackDeallocatedReferencedMemory('Texture');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
this.destroyResource();
|
|
89
113
|
// @ts-expect-error readonly
|
|
90
114
|
this.handle = null;
|
|
91
115
|
}
|
|
@@ -126,38 +150,6 @@ export class WebGPUTexture extends Texture {
|
|
|
126
150
|
return {width: options.width, height: options.height};
|
|
127
151
|
}
|
|
128
152
|
|
|
129
|
-
copyImageData(options_: CopyImageDataOptions): void {
|
|
130
|
-
const {width, height, depth} = this;
|
|
131
|
-
const options = this._normalizeCopyImageDataOptions(options_);
|
|
132
|
-
this.device.pushErrorScope('validation');
|
|
133
|
-
|
|
134
|
-
this.device.handle.queue.writeTexture(
|
|
135
|
-
// destination: GPUImageCopyTexture
|
|
136
|
-
{
|
|
137
|
-
// texture subresource
|
|
138
|
-
texture: this.handle,
|
|
139
|
-
mipLevel: options.mipLevel,
|
|
140
|
-
aspect: options.aspect,
|
|
141
|
-
// origin to write to
|
|
142
|
-
origin: [options.x, options.y, options.z]
|
|
143
|
-
},
|
|
144
|
-
// data
|
|
145
|
-
options.data,
|
|
146
|
-
// dataLayout: GPUImageDataLayout
|
|
147
|
-
{
|
|
148
|
-
offset: options.byteOffset,
|
|
149
|
-
bytesPerRow: options.bytesPerRow,
|
|
150
|
-
rowsPerImage: options.rowsPerImage
|
|
151
|
-
},
|
|
152
|
-
// size: GPUExtent3D - extents of the content to write
|
|
153
|
-
[width, height, depth]
|
|
154
|
-
);
|
|
155
|
-
this.device.popErrorScope((error: GPUError) => {
|
|
156
|
-
this.device.reportError(new Error(`copyImageData: ${error.message}`), this)();
|
|
157
|
-
this.device.debug();
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
153
|
override generateMipmapsWebGL(): void {
|
|
162
154
|
log.warn(`${this}: generateMipmaps not supported in WebGPU`)();
|
|
163
155
|
}
|
|
@@ -174,99 +166,111 @@ export class WebGPUTexture extends Texture {
|
|
|
174
166
|
};
|
|
175
167
|
}
|
|
176
168
|
|
|
177
|
-
override readBuffer(
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
} = options;
|
|
169
|
+
override readBuffer(
|
|
170
|
+
options: TextureReadOptions & {byteOffset?: number} = {},
|
|
171
|
+
buffer?: Buffer
|
|
172
|
+
): Buffer {
|
|
173
|
+
if (!buffer) {
|
|
174
|
+
throw new Error(`${this} readBuffer requires a destination buffer`);
|
|
175
|
+
}
|
|
176
|
+
const {x, y, z, width, height, depthOrArrayLayers, mipLevel, aspect} =
|
|
177
|
+
this._getSupportedColorReadOptions(options);
|
|
178
|
+
const byteOffset = options.byteOffset ?? 0;
|
|
188
179
|
|
|
189
|
-
const layout = this.computeMemoryLayout(
|
|
180
|
+
const layout = this.computeMemoryLayout({width, height, depthOrArrayLayers, mipLevel});
|
|
190
181
|
|
|
191
|
-
const {
|
|
182
|
+
const {byteLength} = layout;
|
|
192
183
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
usage: Buffer.COPY_DST | Buffer.MAP_READ
|
|
199
|
-
});
|
|
200
|
-
const gpuReadBuffer = readBuffer.handle as GPUBuffer;
|
|
184
|
+
if (buffer.byteLength < byteOffset + byteLength) {
|
|
185
|
+
throw new Error(
|
|
186
|
+
`${this} readBuffer target is too small (${buffer.byteLength} < ${byteOffset + byteLength})`
|
|
187
|
+
);
|
|
188
|
+
}
|
|
201
189
|
|
|
202
|
-
// Record commands to copy from the texture to the buffer.
|
|
203
190
|
const gpuDevice = this.device.handle;
|
|
204
|
-
|
|
205
191
|
this.device.pushErrorScope('validation');
|
|
206
192
|
const commandEncoder = gpuDevice.createCommandEncoder();
|
|
193
|
+
this.copyToBuffer(
|
|
194
|
+
commandEncoder,
|
|
195
|
+
{x, y, z, width, height, depthOrArrayLayers, mipLevel, aspect, byteOffset},
|
|
196
|
+
buffer
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const commandBuffer = commandEncoder.finish();
|
|
200
|
+
this.device.handle.queue.submit([commandBuffer]);
|
|
201
|
+
this.device.popErrorScope((error: GPUError) => {
|
|
202
|
+
this.device.reportError(new Error(`${this} readBuffer: ${error.message}`), this)();
|
|
203
|
+
this.device.debug();
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
return buffer;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
override async readDataAsync(options: TextureReadOptions = {}): Promise<ArrayBuffer> {
|
|
210
|
+
throw new Error(
|
|
211
|
+
`${this} readDataAsync is deprecated; use readBuffer() with an explicit destination buffer or DynamicTexture.readAsync()`
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
copyToBuffer(
|
|
216
|
+
commandEncoder: GPUCommandEncoder,
|
|
217
|
+
options: TextureReadOptions & {
|
|
218
|
+
byteOffset?: number;
|
|
219
|
+
bytesPerRow?: number;
|
|
220
|
+
rowsPerImage?: number;
|
|
221
|
+
} = {},
|
|
222
|
+
buffer: Buffer
|
|
223
|
+
): void {
|
|
224
|
+
const {
|
|
225
|
+
byteOffset = 0,
|
|
226
|
+
bytesPerRow: requestedBytesPerRow,
|
|
227
|
+
rowsPerImage: requestedRowsPerImage,
|
|
228
|
+
...textureReadOptions
|
|
229
|
+
} = options;
|
|
230
|
+
const {x, y, z, width, height, depthOrArrayLayers, mipLevel, aspect} =
|
|
231
|
+
this._getSupportedColorReadOptions(textureReadOptions);
|
|
232
|
+
const layout = this.computeMemoryLayout({width, height, depthOrArrayLayers, mipLevel});
|
|
233
|
+
const effectiveBytesPerRow = requestedBytesPerRow ?? layout.bytesPerRow;
|
|
234
|
+
const effectiveRowsPerImage = requestedRowsPerImage ?? layout.rowsPerImage;
|
|
235
|
+
const webgpuBuffer = buffer as WebGPUBuffer;
|
|
236
|
+
|
|
207
237
|
commandEncoder.copyTextureToBuffer(
|
|
208
|
-
// source
|
|
209
238
|
{
|
|
210
239
|
texture: this.handle,
|
|
211
240
|
origin: {x, y, z},
|
|
212
|
-
// origin: [options.x, options.y, 0], // options.depth],
|
|
213
241
|
mipLevel,
|
|
214
242
|
aspect
|
|
215
|
-
// colorSpace: options.colorSpace,
|
|
216
|
-
// premultipliedAlpha: options.premultipliedAlpha
|
|
217
243
|
},
|
|
218
|
-
// destination
|
|
219
244
|
{
|
|
220
|
-
buffer:
|
|
221
|
-
offset:
|
|
222
|
-
bytesPerRow,
|
|
223
|
-
rowsPerImage
|
|
245
|
+
buffer: webgpuBuffer.handle,
|
|
246
|
+
offset: byteOffset,
|
|
247
|
+
bytesPerRow: effectiveBytesPerRow,
|
|
248
|
+
rowsPerImage: effectiveRowsPerImage
|
|
224
249
|
},
|
|
225
|
-
// copy size
|
|
226
250
|
{
|
|
227
251
|
width,
|
|
228
252
|
height,
|
|
229
253
|
depthOrArrayLayers
|
|
230
254
|
}
|
|
231
255
|
);
|
|
232
|
-
|
|
233
|
-
// Submit the command.
|
|
234
|
-
const commandBuffer = commandEncoder.finish();
|
|
235
|
-
this.device.handle.queue.submit([commandBuffer]);
|
|
236
|
-
this.device.popErrorScope((error: GPUError) => {
|
|
237
|
-
this.device.reportError(new Error(`${this} readBuffer: ${error.message}`), this)();
|
|
238
|
-
this.device.debug();
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
return readBuffer;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
override async readDataAsync(options: TextureReadOptions = {}): Promise<ArrayBuffer> {
|
|
245
|
-
const buffer = this.readBuffer(options);
|
|
246
|
-
const data = await buffer.readAsync();
|
|
247
|
-
buffer.destroy();
|
|
248
|
-
return data.buffer as ArrayBuffer;
|
|
249
256
|
}
|
|
250
257
|
|
|
251
|
-
override writeBuffer(buffer: Buffer,
|
|
258
|
+
override writeBuffer(buffer: Buffer, options_: TextureWriteOptions = {}) {
|
|
259
|
+
const options = this._normalizeTextureWriteOptions(options_);
|
|
252
260
|
const {
|
|
253
|
-
x
|
|
254
|
-
y
|
|
255
|
-
z
|
|
256
|
-
width
|
|
257
|
-
height
|
|
258
|
-
depthOrArrayLayers
|
|
259
|
-
mipLevel
|
|
260
|
-
aspect
|
|
261
|
+
x,
|
|
262
|
+
y,
|
|
263
|
+
z,
|
|
264
|
+
width,
|
|
265
|
+
height,
|
|
266
|
+
depthOrArrayLayers,
|
|
267
|
+
mipLevel,
|
|
268
|
+
aspect,
|
|
269
|
+
byteOffset,
|
|
270
|
+
bytesPerRow,
|
|
271
|
+
rowsPerImage
|
|
261
272
|
} = options;
|
|
262
273
|
|
|
263
|
-
const layout = this.computeMemoryLayout(options);
|
|
264
|
-
|
|
265
|
-
// Get the data on the CPU.
|
|
266
|
-
// await buffer.mapAndReadAsync();
|
|
267
|
-
|
|
268
|
-
const {bytesPerRow, rowsPerImage} = layout;
|
|
269
|
-
|
|
270
274
|
const gpuDevice = this.device.handle;
|
|
271
275
|
|
|
272
276
|
this.device.pushErrorScope('validation');
|
|
@@ -274,7 +278,7 @@ export class WebGPUTexture extends Texture {
|
|
|
274
278
|
commandEncoder.copyBufferToTexture(
|
|
275
279
|
{
|
|
276
280
|
buffer: buffer.handle as GPUBuffer,
|
|
277
|
-
offset:
|
|
281
|
+
offset: byteOffset,
|
|
278
282
|
bytesPerRow,
|
|
279
283
|
rowsPerImage
|
|
280
284
|
},
|
|
@@ -294,29 +298,34 @@ export class WebGPUTexture extends Texture {
|
|
|
294
298
|
});
|
|
295
299
|
}
|
|
296
300
|
|
|
297
|
-
override writeData(
|
|
301
|
+
override writeData(
|
|
302
|
+
data: ArrayBuffer | SharedArrayBuffer | ArrayBufferView,
|
|
303
|
+
options_: TextureWriteOptions = {}
|
|
304
|
+
): void {
|
|
298
305
|
const device = this.device;
|
|
299
|
-
|
|
300
|
-
const {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
height = this.height,
|
|
306
|
-
depthOrArrayLayers = this.depth,
|
|
307
|
-
mipLevel = 0,
|
|
308
|
-
aspect = 'all'
|
|
309
|
-
} = options;
|
|
310
|
-
|
|
311
|
-
const layout = textureFormatDecoder.computeMemoryLayout({
|
|
306
|
+
const options = this._normalizeTextureWriteOptions(options_);
|
|
307
|
+
const {x, y, z, width, height, depthOrArrayLayers, mipLevel, aspect, byteOffset} = options;
|
|
308
|
+
const source = data as GPUAllowSharedBufferSource;
|
|
309
|
+
const formatInfo = this.device.getTextureFormatInfo(this.format);
|
|
310
|
+
// queue.writeTexture() defaults to tightly packed rows, unlike WebGPU buffer copy paths.
|
|
311
|
+
const packedSourceLayout = textureFormatDecoder.computeMemoryLayout({
|
|
312
312
|
format: this.format,
|
|
313
|
-
width
|
|
314
|
-
height
|
|
315
|
-
depth:
|
|
316
|
-
byteAlignment:
|
|
313
|
+
width,
|
|
314
|
+
height,
|
|
315
|
+
depth: depthOrArrayLayers,
|
|
316
|
+
byteAlignment: 1
|
|
317
317
|
});
|
|
318
|
-
|
|
319
|
-
const
|
|
318
|
+
const bytesPerRow = options_.bytesPerRow ?? packedSourceLayout.bytesPerRow;
|
|
319
|
+
const rowsPerImage = options_.rowsPerImage ?? packedSourceLayout.rowsPerImage;
|
|
320
|
+
let copyWidth = width;
|
|
321
|
+
let copyHeight = height;
|
|
322
|
+
|
|
323
|
+
if (formatInfo.compressed) {
|
|
324
|
+
const blockWidth = formatInfo.blockWidth || 1;
|
|
325
|
+
const blockHeight = formatInfo.blockHeight || 1;
|
|
326
|
+
copyWidth = Math.ceil(width / blockWidth) * blockWidth;
|
|
327
|
+
copyHeight = Math.ceil(height / blockHeight) * blockHeight;
|
|
328
|
+
}
|
|
320
329
|
|
|
321
330
|
this.device.pushErrorScope('validation');
|
|
322
331
|
device.handle.queue.writeTexture(
|
|
@@ -326,17 +335,74 @@ export class WebGPUTexture extends Texture {
|
|
|
326
335
|
aspect,
|
|
327
336
|
origin: {x, y, z}
|
|
328
337
|
},
|
|
329
|
-
|
|
338
|
+
source,
|
|
330
339
|
{
|
|
331
|
-
offset:
|
|
340
|
+
offset: byteOffset,
|
|
332
341
|
bytesPerRow,
|
|
333
342
|
rowsPerImage
|
|
334
343
|
},
|
|
335
|
-
{width, height, depthOrArrayLayers}
|
|
344
|
+
{width: copyWidth, height: copyHeight, depthOrArrayLayers}
|
|
336
345
|
);
|
|
337
346
|
this.device.popErrorScope((error: GPUError) => {
|
|
338
347
|
this.device.reportError(new Error(`${this} writeData: ${error.message}`), this)();
|
|
339
348
|
this.device.debug();
|
|
340
349
|
});
|
|
341
350
|
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Internal-only hook for the cached CanvasContext/PresentationContext swapchain path.
|
|
354
|
+
* Rebinds this handle-backed texture wrapper to the current per-frame canvas texture
|
|
355
|
+
* without allocating a new luma.gl Texture or TextureView wrapper.
|
|
356
|
+
*/
|
|
357
|
+
_reinitialize(handle: GPUTexture, props?: Partial<TextureProps>): void {
|
|
358
|
+
const nextWidth = props?.width ?? handle.width ?? this.width;
|
|
359
|
+
const nextHeight = props?.height ?? handle.height ?? this.height;
|
|
360
|
+
const nextDepth = props?.depth ?? this.depth;
|
|
361
|
+
const nextFormat = props?.format ?? this.format;
|
|
362
|
+
const allocationMayHaveChanged =
|
|
363
|
+
nextWidth !== this.width ||
|
|
364
|
+
nextHeight !== this.height ||
|
|
365
|
+
nextDepth !== this.depth ||
|
|
366
|
+
nextFormat !== this.format;
|
|
367
|
+
handle.label ||= this.id;
|
|
368
|
+
|
|
369
|
+
// @ts-expect-error readonly
|
|
370
|
+
this.handle = handle;
|
|
371
|
+
// @ts-expect-error readonly
|
|
372
|
+
this.width = nextWidth;
|
|
373
|
+
// @ts-expect-error readonly
|
|
374
|
+
this.height = nextHeight;
|
|
375
|
+
|
|
376
|
+
if (props?.depth !== undefined) {
|
|
377
|
+
// @ts-expect-error readonly
|
|
378
|
+
this.depth = nextDepth;
|
|
379
|
+
}
|
|
380
|
+
if (props?.format !== undefined) {
|
|
381
|
+
// @ts-expect-error readonly
|
|
382
|
+
this.format = nextFormat;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
this.props.handle = handle;
|
|
386
|
+
if (props?.width !== undefined) {
|
|
387
|
+
this.props.width = props.width;
|
|
388
|
+
}
|
|
389
|
+
if (props?.height !== undefined) {
|
|
390
|
+
this.props.height = props.height;
|
|
391
|
+
}
|
|
392
|
+
if (props?.depth !== undefined) {
|
|
393
|
+
this.props.depth = props.depth;
|
|
394
|
+
}
|
|
395
|
+
if (props?.format !== undefined) {
|
|
396
|
+
this.props.format = props.format;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (allocationMayHaveChanged) {
|
|
400
|
+
const nextAllocation = this.getAllocatedByteLength();
|
|
401
|
+
if (nextAllocation !== this._allocatedByteLength) {
|
|
402
|
+
this._allocatedByteLength = nextAllocation;
|
|
403
|
+
this.trackReferencedMemory(nextAllocation, 'Texture');
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
this.view._reinitialize(this);
|
|
407
|
+
}
|
|
342
408
|
}
|
|
@@ -14,7 +14,7 @@ import {WebGPURenderPass} from './webgpu-render-pass';
|
|
|
14
14
|
/** VertexArrayObject wrapper */
|
|
15
15
|
export class WebGPUVertexArray extends VertexArray {
|
|
16
16
|
override get [Symbol.toStringTag](): string {
|
|
17
|
-
return '
|
|
17
|
+
return 'VertexArray';
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
readonly device: WebGPUDevice;
|