@luma.gl/webgpu 9.2.5 → 9.3.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.
- 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 +39 -32
- 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 +7 -0
- package/dist/adapter/resources/webgpu-buffer.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-buffer.js +58 -15
- 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 +13 -0
- package/dist/adapter/resources/webgpu-fence.d.ts.map +1 -0
- package/dist/adapter/resources/webgpu-fence.js +33 -0
- package/dist/adapter/resources/webgpu-fence.js.map +1 -0
- 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 +11 -18
- 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 +25 -3
- package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-texture.js +211 -43
- 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-adapter.d.ts.map +1 -1
- package/dist/adapter/webgpu-adapter.js +34 -34
- package/dist/adapter/webgpu-adapter.js.map +1 -1
- package/dist/adapter/webgpu-canvas-context.d.ts +6 -3
- package/dist/adapter/webgpu-canvas-context.d.ts.map +1 -1
- package/dist/adapter/webgpu-canvas-context.js +90 -30
- package/dist/adapter/webgpu-canvas-context.js.map +1 -1
- package/dist/adapter/webgpu-device.d.ts +12 -2
- package/dist/adapter/webgpu-device.d.ts.map +1 -1
- package/dist/adapter/webgpu-device.js +173 -16
- 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 +8070 -547
- package/dist/dist.min.js +169 -6
- package/dist/index.cjs +1929 -410
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/wgsl/get-shader-layout-wgsl.d.ts +8 -0
- package/dist/wgsl/get-shader-layout-wgsl.d.ts.map +1 -0
- package/dist/wgsl/get-shader-layout-wgsl.js +144 -0
- package/dist/wgsl/get-shader-layout-wgsl.js.map +1 -0
- package/package.json +6 -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 +52 -46
- 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 +61 -15
- 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 +38 -0
- package/src/adapter/resources/webgpu-framebuffer.ts +21 -0
- package/src/adapter/resources/webgpu-pipeline-layout.ts +18 -17
- 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 +281 -101
- package/src/adapter/resources/webgpu-vertex-array.ts +1 -1
- package/src/adapter/webgpu-adapter.ts +40 -42
- package/src/adapter/webgpu-canvas-context.ts +107 -40
- package/src/adapter/webgpu-device.ts +231 -21
- package/src/adapter/webgpu-presentation-context.ts +180 -0
- package/src/index.ts +3 -0
- package/src/wgsl/get-shader-layout-wgsl.ts +165 -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
|
@@ -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
|
}
|
|
@@ -1,30 +1,43 @@
|
|
|
1
1
|
// luma.gl, MIT license
|
|
2
|
-
import
|
|
3
|
-
TextureProps,
|
|
4
|
-
TextureViewProps,
|
|
5
|
-
CopyExternalImageOptions,
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
import {
|
|
3
|
+
type TextureProps,
|
|
4
|
+
type TextureViewProps,
|
|
5
|
+
type CopyExternalImageOptions,
|
|
6
|
+
type TextureReadOptions,
|
|
7
|
+
type TextureWriteOptions,
|
|
8
|
+
type SamplerProps,
|
|
9
|
+
Buffer,
|
|
10
|
+
Texture,
|
|
11
|
+
log,
|
|
12
|
+
textureFormatDecoder
|
|
8
13
|
} from '@luma.gl/core';
|
|
9
|
-
import {Texture, log} from '@luma.gl/core';
|
|
10
14
|
|
|
11
15
|
import {getWebGPUTextureFormat} from '../helpers/convert-texture-format';
|
|
12
16
|
import type {WebGPUDevice} from '../webgpu-device';
|
|
13
17
|
import {WebGPUSampler} from './webgpu-sampler';
|
|
14
18
|
import {WebGPUTextureView} from './webgpu-texture-view';
|
|
19
|
+
import {WebGPUBuffer} from './webgpu-buffer';
|
|
15
20
|
|
|
21
|
+
/** WebGPU implementation of the luma.gl core Texture resource */
|
|
16
22
|
export class WebGPUTexture extends Texture {
|
|
17
23
|
readonly device: WebGPUDevice;
|
|
18
24
|
readonly handle: GPUTexture;
|
|
19
25
|
sampler: WebGPUSampler;
|
|
20
26
|
view: WebGPUTextureView;
|
|
27
|
+
private _allocatedByteLength: number = 0;
|
|
21
28
|
|
|
22
29
|
constructor(device: WebGPUDevice, props: TextureProps) {
|
|
23
|
-
|
|
30
|
+
// WebGPU buffer copies use 256-byte row alignment. queue.writeTexture() can use tightly packed rows.
|
|
31
|
+
super(device, props, {byteAlignment: 256});
|
|
24
32
|
this.device = device;
|
|
25
33
|
|
|
26
|
-
if (
|
|
27
|
-
this.
|
|
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);
|
|
28
41
|
}
|
|
29
42
|
|
|
30
43
|
this.device.pushErrorScope('out-of-memory');
|
|
@@ -54,19 +67,14 @@ export class WebGPUTexture extends Texture {
|
|
|
54
67
|
this.device.debug();
|
|
55
68
|
});
|
|
56
69
|
|
|
57
|
-
// Update props if external handle was supplied - used mainly by CanvasContext.getDefaultFramebuffer()
|
|
58
|
-
// TODO - Read all properties directly from the supplied handle?
|
|
59
70
|
if (this.props.handle) {
|
|
60
71
|
this.handle.label ||= this.id;
|
|
72
|
+
// @ts-expect-error readonly
|
|
61
73
|
this.width = this.handle.width;
|
|
74
|
+
// @ts-expect-error readonly
|
|
62
75
|
this.height = this.handle.height;
|
|
63
76
|
}
|
|
64
77
|
|
|
65
|
-
this.sampler =
|
|
66
|
-
props.sampler instanceof WebGPUSampler
|
|
67
|
-
? props.sampler
|
|
68
|
-
: new WebGPUSampler(this.device, (props.sampler as SamplerProps) || {});
|
|
69
|
-
|
|
70
78
|
this.view = new WebGPUTextureView(this.device, {
|
|
71
79
|
...this.props,
|
|
72
80
|
texture: this,
|
|
@@ -74,14 +82,34 @@ export class WebGPUTexture extends Texture {
|
|
|
74
82
|
// Note: arrayLayerCount controls the view of array textures, but does not apply to 3d texture depths
|
|
75
83
|
arrayLayerCount: this.dimension !== '3d' ? this.depth : 1
|
|
76
84
|
});
|
|
85
|
+
this.attachResource(this.view);
|
|
77
86
|
|
|
78
87
|
// Set initial data
|
|
79
88
|
// Texture base class strips out the data prop from this.props, so we need to handle it here
|
|
80
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
|
+
}
|
|
81
98
|
}
|
|
82
99
|
|
|
83
100
|
override destroy(): void {
|
|
84
|
-
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();
|
|
85
113
|
// @ts-expect-error readonly
|
|
86
114
|
this.handle = null;
|
|
87
115
|
}
|
|
@@ -90,37 +118,6 @@ export class WebGPUTexture extends Texture {
|
|
|
90
118
|
return new WebGPUTextureView(this.device, {...props, texture: this});
|
|
91
119
|
}
|
|
92
120
|
|
|
93
|
-
copyImageData(options_: CopyImageDataOptions): void {
|
|
94
|
-
const {width, height, depth} = this;
|
|
95
|
-
const options = this._normalizeCopyImageDataOptions(options_);
|
|
96
|
-
this.device.pushErrorScope('validation');
|
|
97
|
-
this.device.handle.queue.writeTexture(
|
|
98
|
-
// destination: GPUImageCopyTexture
|
|
99
|
-
{
|
|
100
|
-
// texture subresource
|
|
101
|
-
texture: this.handle,
|
|
102
|
-
mipLevel: options.mipLevel,
|
|
103
|
-
aspect: options.aspect,
|
|
104
|
-
// origin to write to
|
|
105
|
-
origin: [options.x, options.y, options.z]
|
|
106
|
-
},
|
|
107
|
-
// data
|
|
108
|
-
options.data,
|
|
109
|
-
// dataLayout: GPUImageDataLayout
|
|
110
|
-
{
|
|
111
|
-
offset: options.byteOffset,
|
|
112
|
-
bytesPerRow: options.bytesPerRow,
|
|
113
|
-
rowsPerImage: options.rowsPerImage
|
|
114
|
-
},
|
|
115
|
-
// size: GPUExtent3D - extents of the content to write
|
|
116
|
-
[width, height, depth]
|
|
117
|
-
);
|
|
118
|
-
this.device.popErrorScope((error: GPUError) => {
|
|
119
|
-
this.device.reportError(new Error(`copyImageData: ${error.message}`), this)();
|
|
120
|
-
this.device.debug();
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
121
|
copyExternalImage(options_: CopyExternalImageOptions): {width: number; height: number} {
|
|
125
122
|
const options = this._normalizeCopyExternalImageOptions(options_);
|
|
126
123
|
|
|
@@ -130,19 +127,19 @@ export class WebGPUTexture extends Texture {
|
|
|
130
127
|
{
|
|
131
128
|
source: options.image,
|
|
132
129
|
origin: [options.sourceX, options.sourceY],
|
|
133
|
-
flipY: options.flipY
|
|
130
|
+
flipY: false // options.flipY
|
|
134
131
|
},
|
|
135
132
|
// destination: GPUImageCopyTextureTagged
|
|
136
133
|
{
|
|
137
134
|
texture: this.handle,
|
|
138
|
-
origin: [options.x, options.y,
|
|
135
|
+
origin: [options.x, options.y, options.z],
|
|
139
136
|
mipLevel: options.mipLevel,
|
|
140
137
|
aspect: options.aspect,
|
|
141
138
|
colorSpace: options.colorSpace,
|
|
142
139
|
premultipliedAlpha: options.premultipliedAlpha
|
|
143
140
|
},
|
|
144
141
|
// copySize: GPUExtent3D
|
|
145
|
-
[options.width, options.height, 1
|
|
142
|
+
[options.width, options.height, options.depth] // depth is always 1 for 2D textures
|
|
146
143
|
);
|
|
147
144
|
this.device.popErrorScope((error: GPUError) => {
|
|
148
145
|
this.device.reportError(new Error(`copyExternalImage: ${error.message}`), this)();
|
|
@@ -157,72 +154,255 @@ export class WebGPUTexture extends Texture {
|
|
|
157
154
|
log.warn(`${this}: generateMipmaps not supported in WebGPU`)();
|
|
158
155
|
}
|
|
159
156
|
|
|
160
|
-
|
|
157
|
+
getImageDataLayout(options: TextureReadOptions): {
|
|
158
|
+
byteLength: number;
|
|
159
|
+
bytesPerRow: number;
|
|
160
|
+
rowsPerImage: number;
|
|
161
|
+
} {
|
|
162
|
+
return {
|
|
163
|
+
byteLength: 0,
|
|
164
|
+
bytesPerRow: 0,
|
|
165
|
+
rowsPerImage: 0
|
|
166
|
+
};
|
|
167
|
+
}
|
|
161
168
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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;
|
|
179
|
+
|
|
180
|
+
const layout = this.computeMemoryLayout({width, height, depthOrArrayLayers, mipLevel});
|
|
181
|
+
|
|
182
|
+
const {byteLength} = layout;
|
|
168
183
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
184
|
+
if (buffer.byteLength < byteOffset + byteLength) {
|
|
185
|
+
throw new Error(
|
|
186
|
+
`${this} readBuffer target is too small (${buffer.byteLength} < ${byteOffset + byteLength})`
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const gpuDevice = this.device.handle;
|
|
191
|
+
this.device.pushErrorScope('validation');
|
|
192
|
+
const commandEncoder = gpuDevice.createCommandEncoder();
|
|
193
|
+
this.copyToBuffer(
|
|
194
|
+
commandEncoder,
|
|
195
|
+
{x, y, z, width, height, depthOrArrayLayers, mipLevel, aspect, byteOffset},
|
|
196
|
+
buffer
|
|
175
197
|
);
|
|
176
|
-
device.submit([encoder.finish()]);
|
|
177
198
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
+
});
|
|
183
205
|
|
|
184
|
-
|
|
185
|
-
|
|
206
|
+
return buffer;
|
|
207
|
+
}
|
|
186
208
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
data = new Uint8Array(bytesPerRow * img.height);
|
|
192
|
-
let imagePixelIndex = 0;
|
|
193
|
-
for (let y = 0; y < img.height; ++y) {
|
|
194
|
-
for (let x = 0; x < img.width; ++x) {
|
|
195
|
-
const i = x * 4 + y * bytesPerRow;
|
|
196
|
-
data[i] = imageData.data[imagePixelIndex];
|
|
197
|
-
data[i + 1] = imageData.data[imagePixelIndex + 1];
|
|
198
|
-
data[i + 2] = imageData.data[imagePixelIndex + 2];
|
|
199
|
-
data[i + 3] = imageData.data[imagePixelIndex + 3];
|
|
200
|
-
imagePixelIndex += 4;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
return this;
|
|
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
|
+
);
|
|
205
213
|
}
|
|
206
214
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
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
|
+
|
|
237
|
+
commandEncoder.copyTextureToBuffer(
|
|
210
238
|
{
|
|
211
|
-
|
|
212
|
-
|
|
239
|
+
texture: this.handle,
|
|
240
|
+
origin: {x, y, z},
|
|
241
|
+
mipLevel,
|
|
242
|
+
aspect
|
|
213
243
|
},
|
|
214
244
|
{
|
|
215
|
-
|
|
245
|
+
buffer: webgpuBuffer.handle,
|
|
246
|
+
offset: byteOffset,
|
|
247
|
+
bytesPerRow: effectiveBytesPerRow,
|
|
248
|
+
rowsPerImage: effectiveRowsPerImage
|
|
216
249
|
},
|
|
217
250
|
{
|
|
218
251
|
width,
|
|
219
252
|
height,
|
|
220
|
-
|
|
253
|
+
depthOrArrayLayers
|
|
221
254
|
}
|
|
222
255
|
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
override writeBuffer(buffer: Buffer, options_: TextureWriteOptions = {}) {
|
|
259
|
+
const options = this._normalizeTextureWriteOptions(options_);
|
|
260
|
+
const {
|
|
261
|
+
x,
|
|
262
|
+
y,
|
|
263
|
+
z,
|
|
264
|
+
width,
|
|
265
|
+
height,
|
|
266
|
+
depthOrArrayLayers,
|
|
267
|
+
mipLevel,
|
|
268
|
+
aspect,
|
|
269
|
+
byteOffset,
|
|
270
|
+
bytesPerRow,
|
|
271
|
+
rowsPerImage
|
|
272
|
+
} = options;
|
|
223
273
|
|
|
224
|
-
this.device.handle
|
|
225
|
-
|
|
274
|
+
const gpuDevice = this.device.handle;
|
|
275
|
+
|
|
276
|
+
this.device.pushErrorScope('validation');
|
|
277
|
+
const commandEncoder = gpuDevice.createCommandEncoder();
|
|
278
|
+
commandEncoder.copyBufferToTexture(
|
|
279
|
+
{
|
|
280
|
+
buffer: buffer.handle as GPUBuffer,
|
|
281
|
+
offset: byteOffset,
|
|
282
|
+
bytesPerRow,
|
|
283
|
+
rowsPerImage
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
texture: this.handle,
|
|
287
|
+
origin: {x, y, z},
|
|
288
|
+
mipLevel,
|
|
289
|
+
aspect
|
|
290
|
+
},
|
|
291
|
+
{width, height, depthOrArrayLayers}
|
|
292
|
+
);
|
|
293
|
+
const commandBuffer = commandEncoder.finish();
|
|
294
|
+
this.device.handle.queue.submit([commandBuffer]);
|
|
295
|
+
this.device.popErrorScope((error: GPUError) => {
|
|
296
|
+
this.device.reportError(new Error(`${this} writeBuffer: ${error.message}`), this)();
|
|
297
|
+
this.device.debug();
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
override writeData(
|
|
302
|
+
data: ArrayBuffer | SharedArrayBuffer | ArrayBufferView,
|
|
303
|
+
options_: TextureWriteOptions = {}
|
|
304
|
+
): void {
|
|
305
|
+
const device = this.device;
|
|
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
|
+
format: this.format,
|
|
313
|
+
width,
|
|
314
|
+
height,
|
|
315
|
+
depth: depthOrArrayLayers,
|
|
316
|
+
byteAlignment: 1
|
|
317
|
+
});
|
|
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
|
+
}
|
|
329
|
+
|
|
330
|
+
this.device.pushErrorScope('validation');
|
|
331
|
+
device.handle.queue.writeTexture(
|
|
332
|
+
{
|
|
333
|
+
texture: this.handle,
|
|
334
|
+
mipLevel,
|
|
335
|
+
aspect,
|
|
336
|
+
origin: {x, y, z}
|
|
337
|
+
},
|
|
338
|
+
source,
|
|
339
|
+
{
|
|
340
|
+
offset: byteOffset,
|
|
341
|
+
bytesPerRow,
|
|
342
|
+
rowsPerImage
|
|
343
|
+
},
|
|
344
|
+
{width: copyWidth, height: copyHeight, depthOrArrayLayers}
|
|
345
|
+
);
|
|
346
|
+
this.device.popErrorScope((error: GPUError) => {
|
|
347
|
+
this.device.reportError(new Error(`${this} writeData: ${error.message}`), this)();
|
|
348
|
+
this.device.debug();
|
|
349
|
+
});
|
|
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);
|
|
226
407
|
}
|
|
227
|
-
*/
|
|
228
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;
|
|
@@ -35,62 +35,60 @@ export class WebGPUAdapter extends Adapter {
|
|
|
35
35
|
throw new Error('WebGPU not available. Recent Chrome browsers should work.');
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
// forceSoftware: false
|
|
43
|
-
});
|
|
38
|
+
const adapter = await navigator.gpu.requestAdapter({
|
|
39
|
+
powerPreference: 'high-performance'
|
|
40
|
+
// forceSoftware: false
|
|
41
|
+
});
|
|
44
42
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
if (!adapter) {
|
|
44
|
+
throw new Error('Failed to request WebGPU adapter');
|
|
45
|
+
}
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
47
|
+
// Note: adapter.requestAdapterInfo() has been replaced with adapter.info. Fall back in case adapter.info is not available
|
|
48
|
+
const adapterInfo =
|
|
49
|
+
adapter.info ||
|
|
50
|
+
// @ts-ignore
|
|
51
|
+
(await adapter.requestAdapterInfo?.());
|
|
52
|
+
// log.probe(2, 'Adapter available', adapterInfo)();
|
|
53
|
+
|
|
54
|
+
const requiredFeatures: GPUFeatureName[] = [];
|
|
55
|
+
const requiredLimits: Record<string, number> = {};
|
|
56
|
+
|
|
57
|
+
if (props._requestMaxLimits) {
|
|
58
|
+
// Require all features
|
|
59
|
+
requiredFeatures.push(...(Array.from(adapter.features) as GPUFeatureName[]));
|
|
60
|
+
|
|
61
|
+
// Require all limits
|
|
62
|
+
// Filter out chrome specific keys (avoid crash)
|
|
63
|
+
const limits = Object.keys(adapter.limits).filter(
|
|
64
|
+
key => !['minSubgroupSize', 'maxSubgroupSize'].includes(key)
|
|
65
|
+
);
|
|
66
|
+
for (const key of limits) {
|
|
67
|
+
const limit = key as keyof GPUSupportedLimits;
|
|
68
|
+
const value = adapter.limits[limit];
|
|
69
|
+
if (typeof value === 'number') {
|
|
70
|
+
requiredLimits[limit] = value;
|
|
74
71
|
}
|
|
75
72
|
}
|
|
73
|
+
}
|
|
76
74
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
const gpuDevice = await adapter.requestDevice({
|
|
76
|
+
requiredFeatures,
|
|
77
|
+
requiredLimits
|
|
78
|
+
});
|
|
81
79
|
|
|
82
|
-
|
|
80
|
+
// log.probe(1, 'GPUDevice available')();
|
|
83
81
|
|
|
84
|
-
|
|
82
|
+
const {WebGPUDevice} = await import('./webgpu-device');
|
|
85
83
|
|
|
84
|
+
log.groupCollapsed(1, 'WebGPUDevice created')();
|
|
85
|
+
try {
|
|
86
86
|
const device = new WebGPUDevice(props, gpuDevice, adapter, adapterInfo);
|
|
87
|
-
|
|
88
87
|
log.probe(
|
|
89
88
|
1,
|
|
90
89
|
'Device created. For more info, set chrome://flags/#enable-webgpu-developer-features'
|
|
91
90
|
)();
|
|
92
91
|
log.table(1, device.info)();
|
|
93
|
-
|
|
94
92
|
return device;
|
|
95
93
|
} finally {
|
|
96
94
|
log.groupEnd(1)();
|