@luma.gl/webgpu 9.3.0-alpha.4 → 9.3.0-alpha.6
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 +2 -1
- package/dist/adapter/helpers/get-bind-group.d.ts.map +1 -1
- package/dist/adapter/helpers/get-bind-group.js +22 -18
- package/dist/adapter/helpers/get-bind-group.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 +5 -4
- package/dist/adapter/resources/webgpu-command-encoder.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-command-encoder.js +23 -5
- package/dist/adapter/resources/webgpu-command-encoder.js.map +1 -1
- package/dist/adapter/resources/webgpu-compute-pass.d.ts +1 -1
- package/dist/adapter/resources/webgpu-compute-pass.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-compute-pass.js +14 -6
- package/dist/adapter/resources/webgpu-compute-pass.js.map +1 -1
- package/dist/adapter/resources/webgpu-compute-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-compute-pipeline.js +19 -3
- package/dist/adapter/resources/webgpu-compute-pipeline.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-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 +3 -0
- package/dist/adapter/resources/webgpu-render-pass.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-render-pass.js +74 -30
- package/dist/adapter/resources/webgpu-render-pass.js.map +1 -1
- package/dist/adapter/resources/webgpu-render-pipeline.d.ts +7 -4
- package/dist/adapter/resources/webgpu-render-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-render-pipeline.js +26 -15
- 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-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 +10 -4
- package/dist/adapter/resources/webgpu-texture.d.ts.map +1 -1
- package/dist/adapter/resources/webgpu-texture.js +116 -57
- 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 +5 -1
- package/dist/adapter/webgpu-device.d.ts.map +1 -1
- package/dist/adapter/webgpu-device.js +113 -9
- 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 +2815 -1681
- package/dist/dist.min.js +167 -8
- package/dist/index.cjs +1314 -199
- package/dist/index.cjs.map +4 -4
- package/package.json +4 -4
- 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 +26 -24
- 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 +32 -6
- package/src/adapter/resources/webgpu-compute-pass.ts +14 -6
- package/src/adapter/resources/webgpu-compute-pipeline.ts +21 -3
- package/src/adapter/resources/webgpu-framebuffer.ts +21 -0
- package/src/adapter/resources/webgpu-query-set.ts +185 -9
- package/src/adapter/resources/webgpu-render-pass.ts +82 -34
- package/src/adapter/resources/webgpu-render-pipeline.ts +36 -19
- package/src/adapter/resources/webgpu-sampler.ts +5 -0
- package/src/adapter/resources/webgpu-texture-view.ts +51 -11
- package/src/adapter/resources/webgpu-texture.ts +142 -93
- 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 +128 -9
- package/src/adapter/webgpu-presentation-context.ts +180 -0
|
@@ -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,
|
|
@@ -24,11 +23,22 @@ export class WebGPUTexture extends Texture {
|
|
|
24
23
|
readonly handle: GPUTexture;
|
|
25
24
|
sampler: WebGPUSampler;
|
|
26
25
|
view: WebGPUTextureView;
|
|
26
|
+
private _allocatedByteLength: number = 0;
|
|
27
27
|
|
|
28
28
|
constructor(device: WebGPUDevice, props: TextureProps) {
|
|
29
|
-
|
|
29
|
+
// WebGPU buffer copies use 256-byte row alignment. queue.writeTexture() can use tightly packed rows.
|
|
30
|
+
super(device, props, {byteAlignment: 256});
|
|
30
31
|
this.device = device;
|
|
31
32
|
|
|
33
|
+
if (props.sampler instanceof WebGPUSampler) {
|
|
34
|
+
this.sampler = props.sampler;
|
|
35
|
+
} else if (props.sampler === undefined) {
|
|
36
|
+
this.sampler = this.device.getDefaultSampler();
|
|
37
|
+
} else {
|
|
38
|
+
this.sampler = new WebGPUSampler(this.device, (props.sampler as SamplerProps) || {});
|
|
39
|
+
this.attachResource(this.sampler);
|
|
40
|
+
}
|
|
41
|
+
|
|
32
42
|
this.device.pushErrorScope('out-of-memory');
|
|
33
43
|
this.device.pushErrorScope('validation');
|
|
34
44
|
|
|
@@ -56,8 +66,6 @@ export class WebGPUTexture extends Texture {
|
|
|
56
66
|
this.device.debug();
|
|
57
67
|
});
|
|
58
68
|
|
|
59
|
-
// Update props if external handle was supplied - used mainly by CanvasContext.getDefaultFramebuffer()
|
|
60
|
-
// TODO - Read all properties directly from the supplied handle?
|
|
61
69
|
if (this.props.handle) {
|
|
62
70
|
this.handle.label ||= this.id;
|
|
63
71
|
// @ts-expect-error readonly
|
|
@@ -66,11 +74,6 @@ export class WebGPUTexture extends Texture {
|
|
|
66
74
|
this.height = this.handle.height;
|
|
67
75
|
}
|
|
68
76
|
|
|
69
|
-
this.sampler =
|
|
70
|
-
props.sampler instanceof WebGPUSampler
|
|
71
|
-
? props.sampler
|
|
72
|
-
: new WebGPUSampler(this.device, (props.sampler as SamplerProps) || {});
|
|
73
|
-
|
|
74
77
|
this.view = new WebGPUTextureView(this.device, {
|
|
75
78
|
...this.props,
|
|
76
79
|
texture: this,
|
|
@@ -78,14 +81,34 @@ export class WebGPUTexture extends Texture {
|
|
|
78
81
|
// Note: arrayLayerCount controls the view of array textures, but does not apply to 3d texture depths
|
|
79
82
|
arrayLayerCount: this.dimension !== '3d' ? this.depth : 1
|
|
80
83
|
});
|
|
84
|
+
this.attachResource(this.view);
|
|
81
85
|
|
|
82
86
|
// Set initial data
|
|
83
87
|
// Texture base class strips out the data prop from this.props, so we need to handle it here
|
|
84
88
|
this._initializeData(props.data);
|
|
89
|
+
|
|
90
|
+
this._allocatedByteLength = this.getAllocatedByteLength();
|
|
91
|
+
|
|
92
|
+
if (!this.props.handle) {
|
|
93
|
+
this.trackAllocatedMemory(this._allocatedByteLength, 'Texture');
|
|
94
|
+
} else {
|
|
95
|
+
this.trackReferencedMemory(this._allocatedByteLength, 'Texture');
|
|
96
|
+
}
|
|
85
97
|
}
|
|
86
98
|
|
|
87
99
|
override destroy(): void {
|
|
88
|
-
this.
|
|
100
|
+
if (this.destroyed) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (!this.props.handle && this.handle) {
|
|
105
|
+
this.trackDeallocatedMemory('Texture');
|
|
106
|
+
this.handle.destroy();
|
|
107
|
+
} else if (this.handle) {
|
|
108
|
+
this.trackDeallocatedReferencedMemory('Texture');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this.destroyResource();
|
|
89
112
|
// @ts-expect-error readonly
|
|
90
113
|
this.handle = null;
|
|
91
114
|
}
|
|
@@ -126,38 +149,6 @@ export class WebGPUTexture extends Texture {
|
|
|
126
149
|
return {width: options.width, height: options.height};
|
|
127
150
|
}
|
|
128
151
|
|
|
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
152
|
override generateMipmapsWebGL(): void {
|
|
162
153
|
log.warn(`${this}: generateMipmaps not supported in WebGPU`)();
|
|
163
154
|
}
|
|
@@ -175,18 +166,10 @@ export class WebGPUTexture extends Texture {
|
|
|
175
166
|
}
|
|
176
167
|
|
|
177
168
|
override readBuffer(options: TextureReadOptions = {}, buffer?: Buffer): Buffer {
|
|
178
|
-
const {
|
|
179
|
-
|
|
180
|
-
y = 0,
|
|
181
|
-
z = 0,
|
|
182
|
-
width = this.width,
|
|
183
|
-
height = this.height,
|
|
184
|
-
depthOrArrayLayers = this.depth,
|
|
185
|
-
mipLevel = 0,
|
|
186
|
-
aspect = 'all'
|
|
187
|
-
} = options;
|
|
169
|
+
const {x, y, z, width, height, depthOrArrayLayers, mipLevel, aspect} =
|
|
170
|
+
this._getSupportedColorReadOptions(options);
|
|
188
171
|
|
|
189
|
-
const layout = this.computeMemoryLayout(
|
|
172
|
+
const layout = this.computeMemoryLayout({x, y, z, width, height, depthOrArrayLayers, mipLevel});
|
|
190
173
|
|
|
191
174
|
const {bytesPerRow, rowsPerImage, byteLength} = layout;
|
|
192
175
|
|
|
@@ -197,6 +180,13 @@ export class WebGPUTexture extends Texture {
|
|
|
197
180
|
byteLength,
|
|
198
181
|
usage: Buffer.COPY_DST | Buffer.MAP_READ
|
|
199
182
|
});
|
|
183
|
+
|
|
184
|
+
if (readBuffer.byteLength < byteLength) {
|
|
185
|
+
throw new Error(
|
|
186
|
+
`${this} readBuffer target is too small (${readBuffer.byteLength} < ${byteLength})`
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
200
190
|
const gpuReadBuffer = readBuffer.handle as GPUBuffer;
|
|
201
191
|
|
|
202
192
|
// Record commands to copy from the texture to the buffer.
|
|
@@ -248,25 +238,22 @@ export class WebGPUTexture extends Texture {
|
|
|
248
238
|
return data.buffer as ArrayBuffer;
|
|
249
239
|
}
|
|
250
240
|
|
|
251
|
-
override writeBuffer(buffer: Buffer,
|
|
241
|
+
override writeBuffer(buffer: Buffer, options_: TextureWriteOptions = {}) {
|
|
242
|
+
const options = this._normalizeTextureWriteOptions(options_);
|
|
252
243
|
const {
|
|
253
|
-
x
|
|
254
|
-
y
|
|
255
|
-
z
|
|
256
|
-
width
|
|
257
|
-
height
|
|
258
|
-
depthOrArrayLayers
|
|
259
|
-
mipLevel
|
|
260
|
-
aspect
|
|
244
|
+
x,
|
|
245
|
+
y,
|
|
246
|
+
z,
|
|
247
|
+
width,
|
|
248
|
+
height,
|
|
249
|
+
depthOrArrayLayers,
|
|
250
|
+
mipLevel,
|
|
251
|
+
aspect,
|
|
252
|
+
byteOffset,
|
|
253
|
+
bytesPerRow,
|
|
254
|
+
rowsPerImage
|
|
261
255
|
} = options;
|
|
262
256
|
|
|
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
257
|
const gpuDevice = this.device.handle;
|
|
271
258
|
|
|
272
259
|
this.device.pushErrorScope('validation');
|
|
@@ -274,7 +261,7 @@ export class WebGPUTexture extends Texture {
|
|
|
274
261
|
commandEncoder.copyBufferToTexture(
|
|
275
262
|
{
|
|
276
263
|
buffer: buffer.handle as GPUBuffer,
|
|
277
|
-
offset:
|
|
264
|
+
offset: byteOffset,
|
|
278
265
|
bytesPerRow,
|
|
279
266
|
rowsPerImage
|
|
280
267
|
},
|
|
@@ -294,29 +281,34 @@ export class WebGPUTexture extends Texture {
|
|
|
294
281
|
});
|
|
295
282
|
}
|
|
296
283
|
|
|
297
|
-
override writeData(
|
|
284
|
+
override writeData(
|
|
285
|
+
data: ArrayBuffer | SharedArrayBuffer | ArrayBufferView,
|
|
286
|
+
options_: TextureWriteOptions = {}
|
|
287
|
+
): void {
|
|
298
288
|
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({
|
|
289
|
+
const options = this._normalizeTextureWriteOptions(options_);
|
|
290
|
+
const {x, y, z, width, height, depthOrArrayLayers, mipLevel, aspect, byteOffset} = options;
|
|
291
|
+
const source = data as GPUAllowSharedBufferSource;
|
|
292
|
+
const formatInfo = this.device.getTextureFormatInfo(this.format);
|
|
293
|
+
// queue.writeTexture() defaults to tightly packed rows, unlike WebGPU buffer copy paths.
|
|
294
|
+
const packedSourceLayout = textureFormatDecoder.computeMemoryLayout({
|
|
312
295
|
format: this.format,
|
|
313
|
-
width
|
|
314
|
-
height
|
|
315
|
-
depth:
|
|
316
|
-
byteAlignment:
|
|
296
|
+
width,
|
|
297
|
+
height,
|
|
298
|
+
depth: depthOrArrayLayers,
|
|
299
|
+
byteAlignment: 1
|
|
317
300
|
});
|
|
318
|
-
|
|
319
|
-
const
|
|
301
|
+
const bytesPerRow = options_.bytesPerRow ?? packedSourceLayout.bytesPerRow;
|
|
302
|
+
const rowsPerImage = options_.rowsPerImage ?? packedSourceLayout.rowsPerImage;
|
|
303
|
+
let copyWidth = width;
|
|
304
|
+
let copyHeight = height;
|
|
305
|
+
|
|
306
|
+
if (formatInfo.compressed) {
|
|
307
|
+
const blockWidth = formatInfo.blockWidth || 1;
|
|
308
|
+
const blockHeight = formatInfo.blockHeight || 1;
|
|
309
|
+
copyWidth = Math.ceil(width / blockWidth) * blockWidth;
|
|
310
|
+
copyHeight = Math.ceil(height / blockHeight) * blockHeight;
|
|
311
|
+
}
|
|
320
312
|
|
|
321
313
|
this.device.pushErrorScope('validation');
|
|
322
314
|
device.handle.queue.writeTexture(
|
|
@@ -326,17 +318,74 @@ export class WebGPUTexture extends Texture {
|
|
|
326
318
|
aspect,
|
|
327
319
|
origin: {x, y, z}
|
|
328
320
|
},
|
|
329
|
-
|
|
321
|
+
source,
|
|
330
322
|
{
|
|
331
|
-
offset:
|
|
323
|
+
offset: byteOffset,
|
|
332
324
|
bytesPerRow,
|
|
333
325
|
rowsPerImage
|
|
334
326
|
},
|
|
335
|
-
{width, height, depthOrArrayLayers}
|
|
327
|
+
{width: copyWidth, height: copyHeight, depthOrArrayLayers}
|
|
336
328
|
);
|
|
337
329
|
this.device.popErrorScope((error: GPUError) => {
|
|
338
330
|
this.device.reportError(new Error(`${this} writeData: ${error.message}`), this)();
|
|
339
331
|
this.device.debug();
|
|
340
332
|
});
|
|
341
333
|
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Internal-only hook for the cached CanvasContext/PresentationContext swapchain path.
|
|
337
|
+
* Rebinds this handle-backed texture wrapper to the current per-frame canvas texture
|
|
338
|
+
* without allocating a new luma.gl Texture or TextureView wrapper.
|
|
339
|
+
*/
|
|
340
|
+
_reinitialize(handle: GPUTexture, props?: Partial<TextureProps>): void {
|
|
341
|
+
const nextWidth = props?.width ?? handle.width ?? this.width;
|
|
342
|
+
const nextHeight = props?.height ?? handle.height ?? this.height;
|
|
343
|
+
const nextDepth = props?.depth ?? this.depth;
|
|
344
|
+
const nextFormat = props?.format ?? this.format;
|
|
345
|
+
const allocationMayHaveChanged =
|
|
346
|
+
nextWidth !== this.width ||
|
|
347
|
+
nextHeight !== this.height ||
|
|
348
|
+
nextDepth !== this.depth ||
|
|
349
|
+
nextFormat !== this.format;
|
|
350
|
+
handle.label ||= this.id;
|
|
351
|
+
|
|
352
|
+
// @ts-expect-error readonly
|
|
353
|
+
this.handle = handle;
|
|
354
|
+
// @ts-expect-error readonly
|
|
355
|
+
this.width = nextWidth;
|
|
356
|
+
// @ts-expect-error readonly
|
|
357
|
+
this.height = nextHeight;
|
|
358
|
+
|
|
359
|
+
if (props?.depth !== undefined) {
|
|
360
|
+
// @ts-expect-error readonly
|
|
361
|
+
this.depth = nextDepth;
|
|
362
|
+
}
|
|
363
|
+
if (props?.format !== undefined) {
|
|
364
|
+
// @ts-expect-error readonly
|
|
365
|
+
this.format = nextFormat;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
this.props.handle = handle;
|
|
369
|
+
if (props?.width !== undefined) {
|
|
370
|
+
this.props.width = props.width;
|
|
371
|
+
}
|
|
372
|
+
if (props?.height !== undefined) {
|
|
373
|
+
this.props.height = props.height;
|
|
374
|
+
}
|
|
375
|
+
if (props?.depth !== undefined) {
|
|
376
|
+
this.props.depth = props.depth;
|
|
377
|
+
}
|
|
378
|
+
if (props?.format !== undefined) {
|
|
379
|
+
this.props.format = props.format;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (allocationMayHaveChanged) {
|
|
383
|
+
const nextAllocation = this.getAllocatedByteLength();
|
|
384
|
+
if (nextAllocation !== this._allocatedByteLength) {
|
|
385
|
+
this._allocatedByteLength = nextAllocation;
|
|
386
|
+
this.trackReferencedMemory(nextAllocation, 'Texture');
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
this.view._reinitialize(this);
|
|
390
|
+
}
|
|
342
391
|
}
|
|
@@ -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;
|
|
@@ -10,6 +10,7 @@ import {CanvasContext, Texture, log} from '@luma.gl/core';
|
|
|
10
10
|
import {WebGPUDevice} from './webgpu-device';
|
|
11
11
|
import {WebGPUFramebuffer} from './resources/webgpu-framebuffer';
|
|
12
12
|
import {WebGPUTexture} from './resources/webgpu-texture';
|
|
13
|
+
import {getCpuHotspotProfiler, getTimestamp} from './helpers/cpu-hotspot-profiler';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Holds a WebGPU Canvas Context
|
|
@@ -20,7 +21,9 @@ export class WebGPUCanvasContext extends CanvasContext {
|
|
|
20
21
|
readonly device: WebGPUDevice;
|
|
21
22
|
readonly handle: GPUCanvasContext;
|
|
22
23
|
|
|
24
|
+
private colorAttachment: WebGPUTexture | null = null;
|
|
23
25
|
private depthStencilAttachment: WebGPUTexture | null = null;
|
|
26
|
+
private framebuffer: WebGPUFramebuffer | null = null;
|
|
24
27
|
|
|
25
28
|
get [Symbol.toStringTag](): string {
|
|
26
29
|
return 'WebGPUCanvasContext';
|
|
@@ -39,10 +42,23 @@ export class WebGPUCanvasContext extends CanvasContext {
|
|
|
39
42
|
// Base class constructor cannot access derived methods/fields, so we need to call these functions in the subclass constructor
|
|
40
43
|
this._setAutoCreatedCanvasId(`${this.device.id}-canvas`);
|
|
41
44
|
this._configureDevice();
|
|
45
|
+
this._startObservers();
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
/** Destroy any textures produced while configured and remove the context configuration. */
|
|
45
49
|
override destroy(): void {
|
|
50
|
+
if (this.framebuffer) {
|
|
51
|
+
this.framebuffer.destroy();
|
|
52
|
+
this.framebuffer = null;
|
|
53
|
+
}
|
|
54
|
+
if (this.colorAttachment) {
|
|
55
|
+
this.colorAttachment.destroy();
|
|
56
|
+
this.colorAttachment = null;
|
|
57
|
+
}
|
|
58
|
+
if (this.depthStencilAttachment) {
|
|
59
|
+
this.depthStencilAttachment.destroy();
|
|
60
|
+
this.depthStencilAttachment = null;
|
|
61
|
+
}
|
|
46
62
|
this.handle.unconfigure();
|
|
47
63
|
super.destroy();
|
|
48
64
|
}
|
|
@@ -65,6 +81,8 @@ export class WebGPUCanvasContext extends CanvasContext {
|
|
|
65
81
|
colorSpace: this.props.colorSpace,
|
|
66
82
|
alphaMode: this.props.alphaMode
|
|
67
83
|
});
|
|
84
|
+
|
|
85
|
+
this._createDepthStencilAttachment(this.device.preferredDepthFormat);
|
|
68
86
|
}
|
|
69
87
|
|
|
70
88
|
/** Update framebuffer with properly resized "swap chain" texture views */
|
|
@@ -73,50 +91,97 @@ export class WebGPUCanvasContext extends CanvasContext {
|
|
|
73
91
|
depthStencilFormat: 'depth24plus'
|
|
74
92
|
}
|
|
75
93
|
): WebGPUFramebuffer {
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
) {
|
|
83
|
-
const [oldWidth, oldHeight] = this.getDrawingBufferSize();
|
|
84
|
-
this.drawingBufferWidth = currentColorAttachment.width;
|
|
85
|
-
this.drawingBufferHeight = currentColorAttachment.height;
|
|
86
|
-
log.log(
|
|
87
|
-
1,
|
|
88
|
-
`${this}: Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`
|
|
89
|
-
)();
|
|
94
|
+
const profiler = getCpuHotspotProfiler(this.device);
|
|
95
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
96
|
+
if (profiler) {
|
|
97
|
+
profiler.framebufferAcquireCount = (profiler.framebufferAcquireCount || 0) + 1;
|
|
98
|
+
profiler.activeDefaultFramebufferAcquireDepth =
|
|
99
|
+
(profiler.activeDefaultFramebufferAcquireDepth || 0) + 1;
|
|
90
100
|
}
|
|
91
101
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
this.
|
|
102
|
+
try {
|
|
103
|
+
// Wrap the current canvas context texture in a luma.gl texture
|
|
104
|
+
const currentColorAttachment = this._getCurrentTexture();
|
|
105
|
+
// TODO - temporary debug code
|
|
106
|
+
if (
|
|
107
|
+
currentColorAttachment.width !== this.drawingBufferWidth ||
|
|
108
|
+
currentColorAttachment.height !== this.drawingBufferHeight
|
|
109
|
+
) {
|
|
110
|
+
const [oldWidth, oldHeight] = this.getDrawingBufferSize();
|
|
111
|
+
this.drawingBufferWidth = currentColorAttachment.width;
|
|
112
|
+
this.drawingBufferHeight = currentColorAttachment.height;
|
|
113
|
+
log.log(
|
|
114
|
+
1,
|
|
115
|
+
`${this}: Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`
|
|
116
|
+
)();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Resize the depth stencil attachment
|
|
120
|
+
if (options?.depthStencilFormat) {
|
|
121
|
+
this._createDepthStencilAttachment(options?.depthStencilFormat);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.framebuffer ||= new WebGPUFramebuffer(this.device, {
|
|
125
|
+
id: `${this.id}#framebuffer`,
|
|
126
|
+
colorAttachments: [currentColorAttachment],
|
|
127
|
+
depthStencilAttachment: null
|
|
128
|
+
});
|
|
129
|
+
this.framebuffer._reinitialize(
|
|
130
|
+
currentColorAttachment.view,
|
|
131
|
+
options?.depthStencilFormat ? this.depthStencilAttachment?.view || null : null
|
|
132
|
+
);
|
|
133
|
+
return this.framebuffer;
|
|
134
|
+
} finally {
|
|
135
|
+
if (profiler) {
|
|
136
|
+
profiler.activeDefaultFramebufferAcquireDepth =
|
|
137
|
+
(profiler.activeDefaultFramebufferAcquireDepth || 1) - 1;
|
|
138
|
+
profiler.framebufferAcquireTimeMs =
|
|
139
|
+
(profiler.framebufferAcquireTimeMs || 0) + (getTimestamp() - startTime);
|
|
140
|
+
}
|
|
95
141
|
}
|
|
96
|
-
|
|
97
|
-
return new WebGPUFramebuffer(this.device, {
|
|
98
|
-
colorAttachments: [currentColorAttachment],
|
|
99
|
-
depthStencilAttachment: this.depthStencilAttachment
|
|
100
|
-
});
|
|
101
142
|
}
|
|
102
143
|
|
|
103
144
|
// PRIMARY METHODS
|
|
104
145
|
|
|
105
146
|
/** Wrap the current canvas context texture in a luma.gl texture */
|
|
106
147
|
_getCurrentTexture(): WebGPUTexture {
|
|
148
|
+
const profiler = getCpuHotspotProfiler(this.device);
|
|
149
|
+
const currentTextureStartTime = profiler ? getTimestamp() : 0;
|
|
107
150
|
const handle = this.handle.getCurrentTexture();
|
|
108
|
-
|
|
109
|
-
|
|
151
|
+
if (profiler) {
|
|
152
|
+
profiler.currentTextureAcquireCount = (profiler.currentTextureAcquireCount || 0) + 1;
|
|
153
|
+
profiler.currentTextureAcquireTimeMs =
|
|
154
|
+
(profiler.currentTextureAcquireTimeMs || 0) + (getTimestamp() - currentTextureStartTime);
|
|
155
|
+
}
|
|
156
|
+
if (!this.colorAttachment) {
|
|
157
|
+
this.colorAttachment = this.device.createTexture({
|
|
158
|
+
id: `${this.id}#color-texture`,
|
|
159
|
+
handle,
|
|
160
|
+
format: this.device.preferredColorFormat,
|
|
161
|
+
width: handle.width,
|
|
162
|
+
height: handle.height
|
|
163
|
+
});
|
|
164
|
+
return this.colorAttachment;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
this.colorAttachment._reinitialize(handle, {
|
|
110
168
|
handle,
|
|
111
169
|
format: this.device.preferredColorFormat,
|
|
112
170
|
width: handle.width,
|
|
113
171
|
height: handle.height
|
|
114
172
|
});
|
|
173
|
+
return this.colorAttachment;
|
|
115
174
|
}
|
|
116
175
|
|
|
117
176
|
/** We build render targets on demand (i.e. not when size changes but when about to render) */
|
|
118
177
|
_createDepthStencilAttachment(depthStencilFormat: TextureFormatDepthStencil): WebGPUTexture {
|
|
119
|
-
|
|
178
|
+
const needsNewDepthStencilAttachment =
|
|
179
|
+
!this.depthStencilAttachment ||
|
|
180
|
+
this.depthStencilAttachment.width !== this.drawingBufferWidth ||
|
|
181
|
+
this.depthStencilAttachment.height !== this.drawingBufferHeight ||
|
|
182
|
+
this.depthStencilAttachment.format !== depthStencilFormat;
|
|
183
|
+
if (needsNewDepthStencilAttachment) {
|
|
184
|
+
this.depthStencilAttachment?.destroy();
|
|
120
185
|
this.depthStencilAttachment = this.device.createTexture({
|
|
121
186
|
id: `${this.id}#depth-stencil-texture`,
|
|
122
187
|
usage: Texture.RENDER_ATTACHMENT,
|
|
@@ -125,6 +190,6 @@ export class WebGPUCanvasContext extends CanvasContext {
|
|
|
125
190
|
height: this.drawingBufferHeight
|
|
126
191
|
});
|
|
127
192
|
}
|
|
128
|
-
return this.depthStencilAttachment
|
|
193
|
+
return this.depthStencilAttachment!;
|
|
129
194
|
}
|
|
130
195
|
}
|