@luma.gl/core 9.3.0-alpha.2 → 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/canvas-context.d.ts +6 -181
- package/dist/adapter/canvas-context.d.ts.map +1 -1
- package/dist/adapter/canvas-context.js +5 -450
- package/dist/adapter/canvas-context.js.map +1 -1
- package/dist/adapter/canvas-observer.d.ts +32 -0
- package/dist/adapter/canvas-observer.d.ts.map +1 -0
- package/dist/adapter/canvas-observer.js +90 -0
- package/dist/adapter/canvas-observer.js.map +1 -0
- package/dist/adapter/canvas-surface.d.ts +150 -0
- package/dist/adapter/canvas-surface.d.ts.map +1 -0
- package/dist/adapter/canvas-surface.js +392 -0
- package/dist/adapter/canvas-surface.js.map +1 -0
- package/dist/adapter/device.d.ts +64 -9
- package/dist/adapter/device.d.ts.map +1 -1
- package/dist/adapter/device.js +108 -4
- package/dist/adapter/device.js.map +1 -1
- package/dist/adapter/luma.js +1 -1
- package/dist/adapter/presentation-context.d.ts +11 -0
- package/dist/adapter/presentation-context.d.ts.map +1 -0
- package/dist/adapter/presentation-context.js +12 -0
- package/dist/adapter/presentation-context.js.map +1 -0
- package/dist/adapter/resources/buffer.d.ts +1 -1
- package/dist/adapter/resources/buffer.d.ts.map +1 -1
- package/dist/adapter/resources/buffer.js +14 -6
- package/dist/adapter/resources/buffer.js.map +1 -1
- package/dist/adapter/resources/command-encoder.d.ts +27 -6
- package/dist/adapter/resources/command-encoder.d.ts.map +1 -1
- package/dist/adapter/resources/command-encoder.js +65 -1
- package/dist/adapter/resources/command-encoder.js.map +1 -1
- package/dist/adapter/resources/fence.d.ts +1 -1
- package/dist/adapter/resources/fence.d.ts.map +1 -1
- package/dist/adapter/resources/fence.js +3 -1
- package/dist/adapter/resources/fence.js.map +1 -1
- package/dist/adapter/resources/framebuffer.d.ts.map +1 -1
- package/dist/adapter/resources/framebuffer.js +9 -11
- package/dist/adapter/resources/framebuffer.js.map +1 -1
- package/dist/adapter/resources/query-set.d.ts +17 -1
- package/dist/adapter/resources/query-set.d.ts.map +1 -1
- package/dist/adapter/resources/query-set.js.map +1 -1
- package/dist/adapter/resources/render-pipeline.d.ts +19 -7
- package/dist/adapter/resources/render-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/render-pipeline.js +20 -2
- package/dist/adapter/resources/render-pipeline.js.map +1 -1
- package/dist/adapter/resources/resource.d.ts +8 -0
- package/dist/adapter/resources/resource.d.ts.map +1 -1
- package/dist/adapter/resources/resource.js +240 -14
- package/dist/adapter/resources/resource.js.map +1 -1
- package/dist/adapter/resources/shader.js +27 -25
- package/dist/adapter/resources/shader.js.map +1 -1
- package/dist/adapter/resources/shared-render-pipeline.d.ts +22 -0
- package/dist/adapter/resources/shared-render-pipeline.d.ts.map +1 -0
- package/dist/adapter/resources/shared-render-pipeline.js +25 -0
- package/dist/adapter/resources/shared-render-pipeline.js.map +1 -0
- package/dist/adapter/resources/texture.d.ts +78 -12
- package/dist/adapter/resources/texture.d.ts.map +1 -1
- package/dist/adapter/resources/texture.js +182 -30
- package/dist/adapter/resources/texture.js.map +1 -1
- package/dist/adapter-utils/format-compiler-log.d.ts.map +1 -1
- package/dist/adapter-utils/format-compiler-log.js +23 -15
- package/dist/adapter-utils/format-compiler-log.js.map +1 -1
- package/dist/dist.dev.js +1265 -362
- package/dist/dist.min.js +10 -9
- package/dist/index.cjs +1027 -243
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/shadertypes/data-types/decode-shader-types.d.ts +2 -2
- package/dist/shadertypes/data-types/decode-shader-types.d.ts.map +1 -1
- package/dist/shadertypes/data-types/decode-shader-types.js +11 -2
- package/dist/shadertypes/data-types/decode-shader-types.js.map +1 -1
- package/dist/shadertypes/textures/pixel-utils.js +4 -4
- package/dist/shadertypes/textures/pixel-utils.js.map +1 -1
- package/dist/shadertypes/textures/texture-format-decoder.d.ts.map +1 -1
- package/dist/shadertypes/textures/texture-format-decoder.js +53 -8
- package/dist/shadertypes/textures/texture-format-decoder.js.map +1 -1
- package/dist/shadertypes/textures/texture-format-table.d.ts.map +1 -1
- package/dist/shadertypes/textures/texture-format-table.js +10 -9
- package/dist/shadertypes/textures/texture-format-table.js.map +1 -1
- package/dist/shadertypes/textures/texture-formats.d.ts +5 -2
- package/dist/shadertypes/textures/texture-formats.d.ts.map +1 -1
- package/dist/shadertypes/textures/texture-formats.js.map +1 -1
- package/dist/shadertypes/textures/texture-layout.d.ts +1 -1
- package/dist/utils/array-equal.d.ts +1 -1
- package/dist/utils/array-equal.d.ts.map +1 -1
- package/dist/utils/array-equal.js +15 -9
- package/dist/utils/array-equal.js.map +1 -1
- package/dist/utils/assert.d.ts +5 -0
- package/dist/utils/assert.d.ts.map +1 -0
- package/dist/utils/assert.js +17 -0
- package/dist/utils/assert.js.map +1 -0
- package/dist/utils/stats-manager.d.ts.map +1 -1
- package/dist/utils/stats-manager.js +61 -1
- package/dist/utils/stats-manager.js.map +1 -1
- package/package.json +6 -6
- package/src/adapter/canvas-context.ts +7 -590
- package/src/adapter/canvas-observer.ts +130 -0
- package/src/adapter/canvas-surface.ts +521 -0
- package/src/adapter/device.ts +174 -13
- package/src/adapter/presentation-context.ts +16 -0
- package/src/adapter/resources/buffer.ts +13 -5
- package/src/adapter/resources/command-encoder.ts +96 -7
- package/src/adapter/resources/fence.ts +3 -1
- package/src/adapter/resources/framebuffer.ts +9 -11
- package/src/adapter/resources/query-set.ts +17 -1
- package/src/adapter/resources/render-pipeline.ts +42 -13
- package/src/adapter/resources/resource.ts +284 -14
- package/src/adapter/resources/shader.ts +28 -28
- package/src/adapter/resources/shared-render-pipeline.ts +40 -0
- package/src/adapter/resources/texture.ts +269 -40
- package/src/adapter-utils/format-compiler-log.ts +23 -15
- package/src/index.ts +8 -0
- package/src/shadertypes/data-types/decode-shader-types.ts +13 -4
- package/src/shadertypes/textures/pixel-utils.ts +4 -4
- package/src/shadertypes/textures/texture-format-decoder.ts +73 -8
- package/src/shadertypes/textures/texture-format-table.ts +10 -9
- package/src/shadertypes/textures/texture-formats.ts +6 -1
- package/src/utils/array-equal.ts +21 -9
- package/src/utils/assert.ts +18 -0
- package/src/utils/stats-manager.ts +76 -2
|
@@ -3,8 +3,76 @@
|
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
5
|
import type {Device} from '../device';
|
|
6
|
+
import type {Stat, Stats} from '@probe.gl/stats';
|
|
6
7
|
import {uid} from '../../utils/uid';
|
|
7
8
|
|
|
9
|
+
const CPU_HOTSPOT_PROFILER_MODULE = 'cpu-hotspot-profiler';
|
|
10
|
+
const RESOURCE_COUNTS_STATS = 'GPU Resource Counts';
|
|
11
|
+
const LEGACY_RESOURCE_COUNTS_STATS = 'Resource Counts';
|
|
12
|
+
const GPU_TIME_AND_MEMORY_STATS = 'GPU Time and Memory';
|
|
13
|
+
const BASE_RESOURCE_COUNT_ORDER = [
|
|
14
|
+
'Resources',
|
|
15
|
+
'Buffers',
|
|
16
|
+
'Textures',
|
|
17
|
+
'Samplers',
|
|
18
|
+
'TextureViews',
|
|
19
|
+
'Framebuffers',
|
|
20
|
+
'QuerySets',
|
|
21
|
+
'Shaders',
|
|
22
|
+
'RenderPipelines',
|
|
23
|
+
'ComputePipelines',
|
|
24
|
+
'PipelineLayouts',
|
|
25
|
+
'VertexArrays',
|
|
26
|
+
'RenderPasss',
|
|
27
|
+
'ComputePasss',
|
|
28
|
+
'CommandEncoders',
|
|
29
|
+
'CommandBuffers'
|
|
30
|
+
] as const;
|
|
31
|
+
const WEBGL_RESOURCE_COUNT_ORDER = [
|
|
32
|
+
'Resources',
|
|
33
|
+
'Buffers',
|
|
34
|
+
'Textures',
|
|
35
|
+
'Samplers',
|
|
36
|
+
'TextureViews',
|
|
37
|
+
'Framebuffers',
|
|
38
|
+
'QuerySets',
|
|
39
|
+
'Shaders',
|
|
40
|
+
'RenderPipelines',
|
|
41
|
+
'SharedRenderPipelines',
|
|
42
|
+
'ComputePipelines',
|
|
43
|
+
'PipelineLayouts',
|
|
44
|
+
'VertexArrays',
|
|
45
|
+
'RenderPasss',
|
|
46
|
+
'ComputePasss',
|
|
47
|
+
'CommandEncoders',
|
|
48
|
+
'CommandBuffers'
|
|
49
|
+
] as const;
|
|
50
|
+
const BASE_RESOURCE_COUNT_STAT_ORDER = BASE_RESOURCE_COUNT_ORDER.flatMap(resourceType => [
|
|
51
|
+
`${resourceType} Created`,
|
|
52
|
+
`${resourceType} Active`
|
|
53
|
+
]);
|
|
54
|
+
const WEBGL_RESOURCE_COUNT_STAT_ORDER = WEBGL_RESOURCE_COUNT_ORDER.flatMap(resourceType => [
|
|
55
|
+
`${resourceType} Created`,
|
|
56
|
+
`${resourceType} Active`
|
|
57
|
+
]);
|
|
58
|
+
const ORDERED_STATS_CACHE = new WeakMap<
|
|
59
|
+
Stats,
|
|
60
|
+
{orderedStatNames: readonly string[]; statCount: number}
|
|
61
|
+
>();
|
|
62
|
+
const ORDERED_STAT_NAME_SET_CACHE = new WeakMap<readonly string[], Set<string>>();
|
|
63
|
+
|
|
64
|
+
type CpuHotspotProfiler = {
|
|
65
|
+
enabled?: boolean;
|
|
66
|
+
activeDefaultFramebufferAcquireDepth?: number;
|
|
67
|
+
statsBookkeepingTimeMs?: number;
|
|
68
|
+
statsBookkeepingCalls?: number;
|
|
69
|
+
transientCanvasResourceCreates?: number;
|
|
70
|
+
transientCanvasTextureCreates?: number;
|
|
71
|
+
transientCanvasTextureViewCreates?: number;
|
|
72
|
+
transientCanvasSamplerCreates?: number;
|
|
73
|
+
transientCanvasFramebufferCreates?: number;
|
|
74
|
+
};
|
|
75
|
+
|
|
8
76
|
export type ResourceProps = {
|
|
9
77
|
/** Name of resource, mainly for debugging purposes. A unique name will be assigned if not provided */
|
|
10
78
|
id?: string;
|
|
@@ -48,6 +116,8 @@ export abstract class Resource<Props extends ResourceProps> {
|
|
|
48
116
|
destroyed: boolean = false;
|
|
49
117
|
/** For resources that allocate GPU memory */
|
|
50
118
|
private allocatedBytes: number = 0;
|
|
119
|
+
/** Stats bucket currently holding the tracked allocation */
|
|
120
|
+
private allocatedBytesName: string | null = null;
|
|
51
121
|
/** Attached resources will be destroyed when this resource is destroyed. Tracks auto-created "sub" resources. */
|
|
52
122
|
private _attachedResources = new Set<Resource<ResourceProps>>();
|
|
53
123
|
|
|
@@ -74,6 +144,9 @@ export abstract class Resource<Props extends ResourceProps> {
|
|
|
74
144
|
* destroy can be called on any resource to release it before it is garbage collected.
|
|
75
145
|
*/
|
|
76
146
|
destroy(): void {
|
|
147
|
+
if (this.destroyed) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
77
150
|
this.destroyResource();
|
|
78
151
|
}
|
|
79
152
|
|
|
@@ -119,7 +192,7 @@ export abstract class Resource<Props extends ResourceProps> {
|
|
|
119
192
|
|
|
120
193
|
/** Destroy all owned resources. Make sure the resources are no longer needed before calling. */
|
|
121
194
|
destroyAttachedResources(): void {
|
|
122
|
-
for (const resource of
|
|
195
|
+
for (const resource of this._attachedResources) {
|
|
123
196
|
resource.destroy();
|
|
124
197
|
}
|
|
125
198
|
// don't remove while we are iterating
|
|
@@ -130,6 +203,9 @@ export abstract class Resource<Props extends ResourceProps> {
|
|
|
130
203
|
|
|
131
204
|
/** Perform all destroy steps. Can be called by derived resources when overriding destroy() */
|
|
132
205
|
protected destroyResource(): void {
|
|
206
|
+
if (this.destroyed) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
133
209
|
this.destroyAttachedResources();
|
|
134
210
|
this.removeStats();
|
|
135
211
|
this.destroyed = true;
|
|
@@ -137,34 +213,111 @@ export abstract class Resource<Props extends ResourceProps> {
|
|
|
137
213
|
|
|
138
214
|
/** Called by .destroy() to track object destruction. Subclass must call if overriding destroy() */
|
|
139
215
|
protected removeStats(): void {
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
|
|
216
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
217
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
218
|
+
const statsObjects = [
|
|
219
|
+
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
|
|
220
|
+
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
|
|
221
|
+
];
|
|
222
|
+
const orderedStatNames = getResourceCountStatOrder(this._device);
|
|
223
|
+
for (const stats of statsObjects) {
|
|
224
|
+
initializeStats(stats, orderedStatNames);
|
|
225
|
+
}
|
|
226
|
+
const name = this.getStatsName();
|
|
227
|
+
for (const stats of statsObjects) {
|
|
228
|
+
stats.get('Resources Active').decrementCount();
|
|
229
|
+
stats.get(`${name}s Active`).decrementCount();
|
|
230
|
+
}
|
|
231
|
+
if (profiler) {
|
|
232
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
233
|
+
profiler.statsBookkeepingTimeMs =
|
|
234
|
+
(profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
235
|
+
}
|
|
143
236
|
}
|
|
144
237
|
|
|
145
238
|
/** Called by subclass to track memory allocations */
|
|
146
|
-
protected trackAllocatedMemory(bytes: number, name = this
|
|
147
|
-
const
|
|
239
|
+
protected trackAllocatedMemory(bytes: number, name = this.getStatsName()): void {
|
|
240
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
241
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
242
|
+
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS);
|
|
243
|
+
|
|
244
|
+
if (this.allocatedBytes > 0 && this.allocatedBytesName) {
|
|
245
|
+
stats.get('GPU Memory').subtractCount(this.allocatedBytes);
|
|
246
|
+
stats.get(`${this.allocatedBytesName} Memory`).subtractCount(this.allocatedBytes);
|
|
247
|
+
}
|
|
248
|
+
|
|
148
249
|
stats.get('GPU Memory').addCount(bytes);
|
|
149
250
|
stats.get(`${name} Memory`).addCount(bytes);
|
|
251
|
+
if (profiler) {
|
|
252
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
253
|
+
profiler.statsBookkeepingTimeMs =
|
|
254
|
+
(profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
255
|
+
}
|
|
150
256
|
this.allocatedBytes = bytes;
|
|
257
|
+
this.allocatedBytesName = name;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** Called by subclass to track handle-backed memory allocations separately from owned allocations */
|
|
261
|
+
protected trackReferencedMemory(bytes: number, name = this.getStatsName()): void {
|
|
262
|
+
this.trackAllocatedMemory(bytes, `Referenced ${name}`);
|
|
151
263
|
}
|
|
152
264
|
|
|
153
265
|
/** Called by subclass to track memory deallocations */
|
|
154
|
-
protected trackDeallocatedMemory(name = this
|
|
155
|
-
|
|
266
|
+
protected trackDeallocatedMemory(name = this.getStatsName()): void {
|
|
267
|
+
if (this.allocatedBytes === 0) {
|
|
268
|
+
this.allocatedBytesName = null;
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
273
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
274
|
+
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS);
|
|
156
275
|
stats.get('GPU Memory').subtractCount(this.allocatedBytes);
|
|
157
|
-
stats.get(`${name} Memory`).subtractCount(this.allocatedBytes);
|
|
276
|
+
stats.get(`${this.allocatedBytesName || name} Memory`).subtractCount(this.allocatedBytes);
|
|
277
|
+
if (profiler) {
|
|
278
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
279
|
+
profiler.statsBookkeepingTimeMs =
|
|
280
|
+
(profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
281
|
+
}
|
|
158
282
|
this.allocatedBytes = 0;
|
|
283
|
+
this.allocatedBytesName = null;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/** Called by subclass to deallocate handle-backed memory tracked via trackReferencedMemory() */
|
|
287
|
+
protected trackDeallocatedReferencedMemory(name = this.getStatsName()): void {
|
|
288
|
+
this.trackDeallocatedMemory(`Referenced ${name}`);
|
|
159
289
|
}
|
|
160
290
|
|
|
161
291
|
/** Called by resource constructor to track object creation */
|
|
162
292
|
private addStats(): void {
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
293
|
+
const name = this.getStatsName();
|
|
294
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
295
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
296
|
+
const statsObjects = [
|
|
297
|
+
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
|
|
298
|
+
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
|
|
299
|
+
];
|
|
300
|
+
const orderedStatNames = getResourceCountStatOrder(this._device);
|
|
301
|
+
for (const stats of statsObjects) {
|
|
302
|
+
initializeStats(stats, orderedStatNames);
|
|
303
|
+
}
|
|
304
|
+
for (const stats of statsObjects) {
|
|
305
|
+
stats.get('Resources Created').incrementCount();
|
|
306
|
+
stats.get('Resources Active').incrementCount();
|
|
307
|
+
stats.get(`${name}s Created`).incrementCount();
|
|
308
|
+
stats.get(`${name}s Active`).incrementCount();
|
|
309
|
+
}
|
|
310
|
+
if (profiler) {
|
|
311
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
312
|
+
profiler.statsBookkeepingTimeMs =
|
|
313
|
+
(profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
314
|
+
}
|
|
315
|
+
recordTransientCanvasResourceCreate(this._device, name);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** Canonical resource name used for stats buckets. */
|
|
319
|
+
protected getStatsName(): string {
|
|
320
|
+
return getCanonicalResourceName(this);
|
|
168
321
|
}
|
|
169
322
|
}
|
|
170
323
|
|
|
@@ -183,3 +336,120 @@ function selectivelyMerge<Props>(props: Props, defaultProps: Required<Props>): R
|
|
|
183
336
|
}
|
|
184
337
|
return mergedProps;
|
|
185
338
|
}
|
|
339
|
+
|
|
340
|
+
function initializeStats(stats: Stats, orderedStatNames: readonly string[]): void {
|
|
341
|
+
const statsMap = stats.stats;
|
|
342
|
+
let addedOrderedStat = false;
|
|
343
|
+
for (const statName of orderedStatNames) {
|
|
344
|
+
if (!statsMap[statName]) {
|
|
345
|
+
stats.get(statName);
|
|
346
|
+
addedOrderedStat = true;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const statCount = Object.keys(statsMap).length;
|
|
351
|
+
const cachedStats = ORDERED_STATS_CACHE.get(stats);
|
|
352
|
+
if (
|
|
353
|
+
!addedOrderedStat &&
|
|
354
|
+
cachedStats?.orderedStatNames === orderedStatNames &&
|
|
355
|
+
cachedStats.statCount === statCount
|
|
356
|
+
) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const reorderedStats: Record<string, Stat> = {};
|
|
361
|
+
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE.get(orderedStatNames);
|
|
362
|
+
if (!orderedStatNamesSet) {
|
|
363
|
+
orderedStatNamesSet = new Set(orderedStatNames);
|
|
364
|
+
ORDERED_STAT_NAME_SET_CACHE.set(orderedStatNames, orderedStatNamesSet);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
for (const statName of orderedStatNames) {
|
|
368
|
+
if (statsMap[statName]) {
|
|
369
|
+
reorderedStats[statName] = statsMap[statName];
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
for (const [statName, stat] of Object.entries(statsMap)) {
|
|
374
|
+
if (!orderedStatNamesSet.has(statName)) {
|
|
375
|
+
reorderedStats[statName] = stat;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
for (const statName of Object.keys(statsMap)) {
|
|
380
|
+
delete statsMap[statName];
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
Object.assign(statsMap, reorderedStats);
|
|
384
|
+
ORDERED_STATS_CACHE.set(stats, {orderedStatNames, statCount});
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function getResourceCountStatOrder(device: Device): readonly string[] {
|
|
388
|
+
return device.type === 'webgl' ? WEBGL_RESOURCE_COUNT_STAT_ORDER : BASE_RESOURCE_COUNT_STAT_ORDER;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function getCpuHotspotProfiler(device: Device): CpuHotspotProfiler | null {
|
|
392
|
+
const profiler = device.userData[CPU_HOTSPOT_PROFILER_MODULE] as CpuHotspotProfiler | undefined;
|
|
393
|
+
return profiler?.enabled ? profiler : null;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function getTimestamp(): number {
|
|
397
|
+
return globalThis.performance?.now?.() ?? Date.now();
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function recordTransientCanvasResourceCreate(device: Device, name: string): void {
|
|
401
|
+
const profiler = getCpuHotspotProfiler(device);
|
|
402
|
+
if (!profiler || !profiler.activeDefaultFramebufferAcquireDepth) {
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
profiler.transientCanvasResourceCreates = (profiler.transientCanvasResourceCreates || 0) + 1;
|
|
407
|
+
|
|
408
|
+
switch (name) {
|
|
409
|
+
case 'Texture':
|
|
410
|
+
profiler.transientCanvasTextureCreates = (profiler.transientCanvasTextureCreates || 0) + 1;
|
|
411
|
+
break;
|
|
412
|
+
case 'TextureView':
|
|
413
|
+
profiler.transientCanvasTextureViewCreates =
|
|
414
|
+
(profiler.transientCanvasTextureViewCreates || 0) + 1;
|
|
415
|
+
break;
|
|
416
|
+
case 'Sampler':
|
|
417
|
+
profiler.transientCanvasSamplerCreates = (profiler.transientCanvasSamplerCreates || 0) + 1;
|
|
418
|
+
break;
|
|
419
|
+
case 'Framebuffer':
|
|
420
|
+
profiler.transientCanvasFramebufferCreates =
|
|
421
|
+
(profiler.transientCanvasFramebufferCreates || 0) + 1;
|
|
422
|
+
break;
|
|
423
|
+
default:
|
|
424
|
+
break;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function getCanonicalResourceName(resource: Resource<any>): string {
|
|
429
|
+
let prototype = Object.getPrototypeOf(resource);
|
|
430
|
+
|
|
431
|
+
while (prototype) {
|
|
432
|
+
const parentPrototype = Object.getPrototypeOf(prototype);
|
|
433
|
+
if (!parentPrototype || parentPrototype === Resource.prototype) {
|
|
434
|
+
return (
|
|
435
|
+
getPrototypeToStringTag(prototype) ||
|
|
436
|
+
resource[Symbol.toStringTag] ||
|
|
437
|
+
resource.constructor.name
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
prototype = parentPrototype;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return resource[Symbol.toStringTag] || resource.constructor.name;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function getPrototypeToStringTag(prototype: object): string | null {
|
|
447
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, Symbol.toStringTag);
|
|
448
|
+
if (typeof descriptor?.get === 'function') {
|
|
449
|
+
return descriptor.get.call(prototype);
|
|
450
|
+
}
|
|
451
|
+
if (typeof descriptor?.value === 'string') {
|
|
452
|
+
return descriptor.value;
|
|
453
|
+
}
|
|
454
|
+
return null;
|
|
455
|
+
}
|
|
@@ -106,38 +106,38 @@ export abstract class Shader extends Resource<ShaderProps> {
|
|
|
106
106
|
|
|
107
107
|
const shaderName: string = shaderId; // getShaderName(this.source) || ;
|
|
108
108
|
const shaderTitle: string = `${this.stage} shader "${shaderName}"`;
|
|
109
|
-
|
|
109
|
+
const htmlLog = formatCompilerLog(messages, this.source, {showSourceCode: 'all', html: true});
|
|
110
110
|
// Show translated source if available
|
|
111
111
|
const translatedSource = this.getTranslatedSource();
|
|
112
|
+
|
|
113
|
+
const container = document.createElement('div');
|
|
114
|
+
container.innerHTML = `\
|
|
115
|
+
<h1>Compilation error in ${shaderTitle}</h1>
|
|
116
|
+
<div style="display:flex;position:fixed;top:10px;right:20px;gap:2px;">
|
|
117
|
+
<button id="copy">Copy source</button><br/>
|
|
118
|
+
<button id="close">Close</button>
|
|
119
|
+
</div>
|
|
120
|
+
<code><pre>${htmlLog}</pre></code>`;
|
|
112
121
|
if (translatedSource) {
|
|
113
|
-
|
|
122
|
+
container.innerHTML += `<br /><h1>Translated Source</h1><br /><br /><code><pre>${translatedSource}</pre></code>`;
|
|
114
123
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
button.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
errors[0]?.scrollIntoView();
|
|
132
|
-
|
|
133
|
-
// TODO - add a small embedded copy button (instead of main button)
|
|
134
|
-
button.onclick = () => {
|
|
135
|
-
// const source = this.source.replaceAll('\n', '<br />');
|
|
136
|
-
const dataURI = `data:text/plain,${encodeURIComponent(this.source)}`;
|
|
137
|
-
navigator.clipboard.writeText(dataURI);
|
|
124
|
+
container.style.top = '0';
|
|
125
|
+
container.style.left = '0';
|
|
126
|
+
container.style.background = 'white';
|
|
127
|
+
container.style.position = 'fixed';
|
|
128
|
+
container.style.zIndex = '9999';
|
|
129
|
+
container.style.maxWidth = '100vw';
|
|
130
|
+
container.style.maxHeight = '100vh';
|
|
131
|
+
container.style.overflowY = 'auto';
|
|
132
|
+
document.body.appendChild(container);
|
|
133
|
+
const error = container.querySelector('.luma-compiler-log-error');
|
|
134
|
+
error?.scrollIntoView();
|
|
135
|
+
(container.querySelector('button#close') as HTMLButtonElement).onclick = () => {
|
|
136
|
+
container.remove();
|
|
137
|
+
};
|
|
138
|
+
(container.querySelector('button#copy') as HTMLButtonElement).onclick = () => {
|
|
139
|
+
navigator.clipboard.writeText(this.source);
|
|
138
140
|
};
|
|
139
|
-
|
|
140
|
-
// TODO - add a small embedded close button
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
static override defaultProps: Required<ShaderProps> = {
|
|
@@ -162,5 +162,5 @@ function getShaderIdFromProps(props: ShaderProps): string {
|
|
|
162
162
|
function getShaderName(shader: string, defaultName: string = 'unnamed'): string {
|
|
163
163
|
const SHADER_NAME_REGEXP = /#define[\s*]SHADER_NAME[\s*]([A-Za-z0-9_-]+)[\s*]/;
|
|
164
164
|
const match = SHADER_NAME_REGEXP.exec(shader);
|
|
165
|
-
return match
|
|
165
|
+
return match?.[1] ?? defaultName;
|
|
166
166
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
4
|
+
|
|
5
|
+
import type {Device} from '../device';
|
|
6
|
+
import type {Shader} from './shader';
|
|
7
|
+
import {Resource, type ResourceProps} from './resource';
|
|
8
|
+
|
|
9
|
+
export type SharedRenderPipelineProps = ResourceProps & {
|
|
10
|
+
handle?: unknown;
|
|
11
|
+
vs: Shader;
|
|
12
|
+
fs: Shader;
|
|
13
|
+
varyings?: string[];
|
|
14
|
+
bufferMode?: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Internal base class for backend-specific shared render-pipeline implementations.
|
|
19
|
+
* Backends may use this to share expensive linked/program state across multiple
|
|
20
|
+
* `RenderPipeline` wrappers.
|
|
21
|
+
*/
|
|
22
|
+
export abstract class SharedRenderPipeline extends Resource<SharedRenderPipelineProps> {
|
|
23
|
+
override get [Symbol.toStringTag](): string {
|
|
24
|
+
return 'SharedRenderPipeline';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
abstract override readonly device: Device;
|
|
28
|
+
abstract override readonly handle: unknown;
|
|
29
|
+
|
|
30
|
+
constructor(device: Device, props: SharedRenderPipelineProps) {
|
|
31
|
+
super(device, props, {
|
|
32
|
+
...Resource.defaultProps,
|
|
33
|
+
handle: undefined!,
|
|
34
|
+
vs: undefined!,
|
|
35
|
+
fs: undefined!,
|
|
36
|
+
varyings: undefined!,
|
|
37
|
+
bufferMode: undefined!
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|