@luma.gl/effects 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/dist.dev.js +1265 -362
- package/dist/dist.min.js +10 -9
- package/dist/index.cjs +419 -258
- package/dist/index.cjs.map +2 -2
- package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.d.ts +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.js +5 -4
- package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/denoise.d.ts +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/denoise.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/denoise.js +29 -21
- package/dist/passes/postprocessing/image-adjust-filters/denoise.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/huesaturation.d.ts +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/huesaturation.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/huesaturation.js +26 -32
- package/dist/passes/postprocessing/image-adjust-filters/huesaturation.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/noise.d.ts +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/noise.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/noise.js +8 -7
- package/dist/passes/postprocessing/image-adjust-filters/noise.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/sepia.d.ts +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/sepia.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/sepia.js +10 -9
- package/dist/passes/postprocessing/image-adjust-filters/sepia.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/vibrance.d.ts +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/vibrance.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/vibrance.js +9 -8
- package/dist/passes/postprocessing/image-adjust-filters/vibrance.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/vignette.d.ts +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/vignette.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/vignette.js +9 -13
- package/dist/passes/postprocessing/image-adjust-filters/vignette.js.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/tiltshift.d.ts +2 -2
- package/dist/passes/postprocessing/image-blur-filters/tiltshift.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/tiltshift.js +34 -16
- package/dist/passes/postprocessing/image-blur-filters/tiltshift.js.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/triangleblur.d.ts +2 -2
- package/dist/passes/postprocessing/image-blur-filters/triangleblur.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/triangleblur.js +21 -12
- package/dist/passes/postprocessing/image-blur-filters/triangleblur.js.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/zoomblur.d.ts +2 -2
- package/dist/passes/postprocessing/image-blur-filters/zoomblur.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/zoomblur.js +20 -11
- package/dist/passes/postprocessing/image-blur-filters/zoomblur.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/colorhalftone.d.ts +1 -1
- package/dist/passes/postprocessing/image-fun-filters/colorhalftone.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/colorhalftone.js +18 -16
- package/dist/passes/postprocessing/image-fun-filters/colorhalftone.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/dotscreen.d.ts +1 -1
- package/dist/passes/postprocessing/image-fun-filters/dotscreen.js +11 -11
- package/dist/passes/postprocessing/image-fun-filters/edgework.d.ts +2 -2
- package/dist/passes/postprocessing/image-fun-filters/edgework.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/edgework.js +83 -12
- package/dist/passes/postprocessing/image-fun-filters/edgework.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.d.ts +1 -1
- package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.js +33 -21
- package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/ink.d.ts +1 -1
- package/dist/passes/postprocessing/image-fun-filters/ink.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/ink.js +24 -15
- package/dist/passes/postprocessing/image-fun-filters/ink.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/magnify.d.ts +1 -1
- package/dist/passes/postprocessing/image-fun-filters/magnify.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/magnify.js +16 -11
- package/dist/passes/postprocessing/image-fun-filters/magnify.js.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.d.ts +2 -2
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.js +24 -10
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.js.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/swirl.d.ts +2 -2
- package/dist/passes/postprocessing/image-warp-filters/swirl.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/swirl.js +18 -13
- package/dist/passes/postprocessing/image-warp-filters/swirl.js.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/warp.d.ts +1 -1
- package/dist/passes/postprocessing/image-warp-filters/warp.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/warp.js +9 -4
- package/dist/passes/postprocessing/image-warp-filters/warp.js.map +1 -1
- package/package.json +2 -2
- package/src/passes/postprocessing/image-adjust-filters/brightnesscontrast.ts +5 -4
- package/src/passes/postprocessing/image-adjust-filters/denoise.ts +31 -23
- package/src/passes/postprocessing/image-adjust-filters/huesaturation.ts +28 -34
- package/src/passes/postprocessing/image-adjust-filters/noise.ts +8 -7
- package/src/passes/postprocessing/image-adjust-filters/sepia.ts +10 -9
- package/src/passes/postprocessing/image-adjust-filters/vibrance.ts +9 -8
- package/src/passes/postprocessing/image-adjust-filters/vignette.ts +9 -13
- package/src/passes/postprocessing/image-blur-filters/tiltshift.ts +36 -18
- package/src/passes/postprocessing/image-blur-filters/triangleblur.ts +21 -12
- package/src/passes/postprocessing/image-blur-filters/zoomblur.ts +21 -12
- package/src/passes/postprocessing/image-fun-filters/colorhalftone.ts +18 -16
- package/src/passes/postprocessing/image-fun-filters/dotscreen.ts +11 -11
- package/src/passes/postprocessing/image-fun-filters/edgework.ts +84 -13
- package/src/passes/postprocessing/image-fun-filters/hexagonalpixelate.ts +36 -24
- package/src/passes/postprocessing/image-fun-filters/ink.ts +24 -15
- package/src/passes/postprocessing/image-fun-filters/magnify.ts +16 -11
- package/src/passes/postprocessing/image-warp-filters/bulgepinch.ts +24 -10
- package/src/passes/postprocessing/image-warp-filters/swirl.ts +18 -13
- package/src/passes/postprocessing/image-warp-filters/warp.ts +9 -4
package/dist/dist.dev.js
CHANGED
|
@@ -67,12 +67,14 @@ var __exports__ = (() => {
|
|
|
67
67
|
Fence: () => Fence,
|
|
68
68
|
Framebuffer: () => Framebuffer,
|
|
69
69
|
PipelineLayout: () => PipelineLayout,
|
|
70
|
+
PresentationContext: () => PresentationContext,
|
|
70
71
|
QuerySet: () => QuerySet,
|
|
71
72
|
RenderPass: () => RenderPass,
|
|
72
73
|
RenderPipeline: () => RenderPipeline,
|
|
73
74
|
Resource: () => Resource,
|
|
74
75
|
Sampler: () => Sampler,
|
|
75
76
|
Shader: () => Shader,
|
|
77
|
+
SharedRenderPipeline: () => SharedRenderPipeline,
|
|
76
78
|
Texture: () => Texture,
|
|
77
79
|
TextureFormatDecoder: () => TextureFormatDecoder,
|
|
78
80
|
TextureView: () => TextureView,
|
|
@@ -83,6 +85,8 @@ var __exports__ = (() => {
|
|
|
83
85
|
VertexArray: () => VertexArray,
|
|
84
86
|
_getTextureFormatDefinition: () => getTextureFormatDefinition,
|
|
85
87
|
_getTextureFormatTable: () => getTextureFormatTable,
|
|
88
|
+
assert: () => assert2,
|
|
89
|
+
assertDefined: () => assertDefined,
|
|
86
90
|
getAttributeInfosFromLayouts: () => getAttributeInfosFromLayouts,
|
|
87
91
|
getAttributeShaderTypeInfo: () => getAttributeShaderTypeInfo,
|
|
88
92
|
getDataType: () => getDataType,
|
|
@@ -299,6 +303,24 @@ var __exports__ = (() => {
|
|
|
299
303
|
};
|
|
300
304
|
|
|
301
305
|
// ../core/src/utils/stats-manager.ts
|
|
306
|
+
var GPU_TIME_AND_MEMORY_STATS = "GPU Time and Memory";
|
|
307
|
+
var GPU_TIME_AND_MEMORY_STAT_ORDER = [
|
|
308
|
+
"Adapter",
|
|
309
|
+
"GPU",
|
|
310
|
+
"GPU Type",
|
|
311
|
+
"GPU Backend",
|
|
312
|
+
"Frame Rate",
|
|
313
|
+
"CPU Time",
|
|
314
|
+
"GPU Time",
|
|
315
|
+
"GPU Memory",
|
|
316
|
+
"Buffer Memory",
|
|
317
|
+
"Texture Memory",
|
|
318
|
+
"Referenced Buffer Memory",
|
|
319
|
+
"Referenced Texture Memory",
|
|
320
|
+
"Swap Chain Texture"
|
|
321
|
+
];
|
|
322
|
+
var ORDERED_STATS_CACHE = /* @__PURE__ */ new WeakMap();
|
|
323
|
+
var ORDERED_STAT_NAME_SET_CACHE = /* @__PURE__ */ new WeakMap();
|
|
302
324
|
var StatsManager = class {
|
|
303
325
|
stats = /* @__PURE__ */ new Map();
|
|
304
326
|
getStats(name2) {
|
|
@@ -308,10 +330,50 @@ var __exports__ = (() => {
|
|
|
308
330
|
if (!this.stats.has(name2)) {
|
|
309
331
|
this.stats.set(name2, new Stats({ id: name2 }));
|
|
310
332
|
}
|
|
311
|
-
|
|
333
|
+
const stats = this.stats.get(name2);
|
|
334
|
+
if (name2 === GPU_TIME_AND_MEMORY_STATS) {
|
|
335
|
+
initializeStats(stats, GPU_TIME_AND_MEMORY_STAT_ORDER);
|
|
336
|
+
}
|
|
337
|
+
return stats;
|
|
312
338
|
}
|
|
313
339
|
};
|
|
314
340
|
var lumaStats = new StatsManager();
|
|
341
|
+
function initializeStats(stats, orderedStatNames) {
|
|
342
|
+
const statsMap = stats.stats;
|
|
343
|
+
let addedOrderedStat = false;
|
|
344
|
+
for (const statName of orderedStatNames) {
|
|
345
|
+
if (!statsMap[statName]) {
|
|
346
|
+
stats.get(statName);
|
|
347
|
+
addedOrderedStat = true;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const statCount = Object.keys(statsMap).length;
|
|
351
|
+
const cachedStats = ORDERED_STATS_CACHE.get(stats);
|
|
352
|
+
if (!addedOrderedStat && cachedStats?.orderedStatNames === orderedStatNames && cachedStats.statCount === statCount) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const reorderedStats = {};
|
|
356
|
+
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE.get(orderedStatNames);
|
|
357
|
+
if (!orderedStatNamesSet) {
|
|
358
|
+
orderedStatNamesSet = new Set(orderedStatNames);
|
|
359
|
+
ORDERED_STAT_NAME_SET_CACHE.set(orderedStatNames, orderedStatNamesSet);
|
|
360
|
+
}
|
|
361
|
+
for (const statName of orderedStatNames) {
|
|
362
|
+
if (statsMap[statName]) {
|
|
363
|
+
reorderedStats[statName] = statsMap[statName];
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
for (const [statName, stat] of Object.entries(statsMap)) {
|
|
367
|
+
if (!orderedStatNamesSet.has(statName)) {
|
|
368
|
+
reorderedStats[statName] = stat;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
for (const statName of Object.keys(statsMap)) {
|
|
372
|
+
delete statsMap[statName];
|
|
373
|
+
}
|
|
374
|
+
Object.assign(statsMap, reorderedStats);
|
|
375
|
+
ORDERED_STATS_CACHE.set(stats, { orderedStatNames, statCount });
|
|
376
|
+
}
|
|
315
377
|
|
|
316
378
|
// ../../node_modules/@probe.gl/env/dist/lib/globals.js
|
|
317
379
|
var window_ = globalThis;
|
|
@@ -343,7 +405,139 @@ var __exports__ = (() => {
|
|
|
343
405
|
}
|
|
344
406
|
|
|
345
407
|
// ../../node_modules/@probe.gl/env/dist/index.js
|
|
346
|
-
var VERSION = true ? "4.1.
|
|
408
|
+
var VERSION = true ? "4.1.1" : "untranspiled source";
|
|
409
|
+
|
|
410
|
+
// ../../node_modules/@probe.gl/log/dist/utils/assert.js
|
|
411
|
+
function assert(condition, message) {
|
|
412
|
+
if (!condition) {
|
|
413
|
+
throw new Error(message || "Assertion failed");
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// ../../node_modules/@probe.gl/log/dist/loggers/log-utils.js
|
|
418
|
+
function normalizeLogLevel(logLevel) {
|
|
419
|
+
if (!logLevel) {
|
|
420
|
+
return 0;
|
|
421
|
+
}
|
|
422
|
+
let resolvedLevel;
|
|
423
|
+
switch (typeof logLevel) {
|
|
424
|
+
case "number":
|
|
425
|
+
resolvedLevel = logLevel;
|
|
426
|
+
break;
|
|
427
|
+
case "object":
|
|
428
|
+
resolvedLevel = logLevel.logLevel || logLevel.priority || 0;
|
|
429
|
+
break;
|
|
430
|
+
default:
|
|
431
|
+
return 0;
|
|
432
|
+
}
|
|
433
|
+
assert(Number.isFinite(resolvedLevel) && resolvedLevel >= 0);
|
|
434
|
+
return resolvedLevel;
|
|
435
|
+
}
|
|
436
|
+
function normalizeArguments(opts) {
|
|
437
|
+
const { logLevel, message } = opts;
|
|
438
|
+
opts.logLevel = normalizeLogLevel(logLevel);
|
|
439
|
+
const args = opts.args ? Array.from(opts.args) : [];
|
|
440
|
+
while (args.length && args.shift() !== message) {
|
|
441
|
+
}
|
|
442
|
+
switch (typeof logLevel) {
|
|
443
|
+
case "string":
|
|
444
|
+
case "function":
|
|
445
|
+
if (message !== void 0) {
|
|
446
|
+
args.unshift(message);
|
|
447
|
+
}
|
|
448
|
+
opts.message = logLevel;
|
|
449
|
+
break;
|
|
450
|
+
case "object":
|
|
451
|
+
Object.assign(opts, logLevel);
|
|
452
|
+
break;
|
|
453
|
+
default:
|
|
454
|
+
}
|
|
455
|
+
if (typeof opts.message === "function") {
|
|
456
|
+
opts.message = opts.message();
|
|
457
|
+
}
|
|
458
|
+
const messageType = typeof opts.message;
|
|
459
|
+
assert(messageType === "string" || messageType === "object");
|
|
460
|
+
return Object.assign(opts, { args }, opts.opts);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// ../../node_modules/@probe.gl/log/dist/loggers/base-log.js
|
|
464
|
+
var noop = () => {
|
|
465
|
+
};
|
|
466
|
+
var BaseLog = class {
|
|
467
|
+
constructor({ level = 0 } = {}) {
|
|
468
|
+
this.userData = {};
|
|
469
|
+
this._onceCache = /* @__PURE__ */ new Set();
|
|
470
|
+
this._level = level;
|
|
471
|
+
}
|
|
472
|
+
set level(newLevel) {
|
|
473
|
+
this.setLevel(newLevel);
|
|
474
|
+
}
|
|
475
|
+
get level() {
|
|
476
|
+
return this.getLevel();
|
|
477
|
+
}
|
|
478
|
+
setLevel(level) {
|
|
479
|
+
this._level = level;
|
|
480
|
+
return this;
|
|
481
|
+
}
|
|
482
|
+
getLevel() {
|
|
483
|
+
return this._level;
|
|
484
|
+
}
|
|
485
|
+
// Unconditional logging
|
|
486
|
+
warn(message, ...args) {
|
|
487
|
+
return this._log("warn", 0, message, args, { once: true });
|
|
488
|
+
}
|
|
489
|
+
error(message, ...args) {
|
|
490
|
+
return this._log("error", 0, message, args);
|
|
491
|
+
}
|
|
492
|
+
// Conditional logging
|
|
493
|
+
log(logLevel, message, ...args) {
|
|
494
|
+
return this._log("log", logLevel, message, args);
|
|
495
|
+
}
|
|
496
|
+
info(logLevel, message, ...args) {
|
|
497
|
+
return this._log("info", logLevel, message, args);
|
|
498
|
+
}
|
|
499
|
+
once(logLevel, message, ...args) {
|
|
500
|
+
return this._log("once", logLevel, message, args, { once: true });
|
|
501
|
+
}
|
|
502
|
+
_log(type, logLevel, message, args, options = {}) {
|
|
503
|
+
const normalized = normalizeArguments({
|
|
504
|
+
logLevel,
|
|
505
|
+
message,
|
|
506
|
+
args: this._buildArgs(logLevel, message, args),
|
|
507
|
+
opts: options
|
|
508
|
+
});
|
|
509
|
+
return this._createLogFunction(type, normalized, options);
|
|
510
|
+
}
|
|
511
|
+
_buildArgs(logLevel, message, args) {
|
|
512
|
+
return [logLevel, message, ...args];
|
|
513
|
+
}
|
|
514
|
+
_createLogFunction(type, normalized, options) {
|
|
515
|
+
if (!this._shouldLog(normalized.logLevel)) {
|
|
516
|
+
return noop;
|
|
517
|
+
}
|
|
518
|
+
const tag = this._getOnceTag(options.tag ?? normalized.tag ?? normalized.message);
|
|
519
|
+
if ((options.once || normalized.once) && tag !== void 0) {
|
|
520
|
+
if (this._onceCache.has(tag)) {
|
|
521
|
+
return noop;
|
|
522
|
+
}
|
|
523
|
+
this._onceCache.add(tag);
|
|
524
|
+
}
|
|
525
|
+
return this._emit(type, normalized);
|
|
526
|
+
}
|
|
527
|
+
_shouldLog(logLevel) {
|
|
528
|
+
return this.getLevel() >= normalizeLogLevel(logLevel);
|
|
529
|
+
}
|
|
530
|
+
_getOnceTag(tag) {
|
|
531
|
+
if (tag === void 0) {
|
|
532
|
+
return void 0;
|
|
533
|
+
}
|
|
534
|
+
try {
|
|
535
|
+
return typeof tag === "string" ? tag : String(tag);
|
|
536
|
+
} catch {
|
|
537
|
+
return void 0;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
};
|
|
347
541
|
|
|
348
542
|
// ../../node_modules/@probe.gl/log/dist/utils/local-storage.js
|
|
349
543
|
function getStorage(type) {
|
|
@@ -462,13 +656,6 @@ var __exports__ = (() => {
|
|
|
462
656
|
}
|
|
463
657
|
}
|
|
464
658
|
|
|
465
|
-
// ../../node_modules/@probe.gl/log/dist/utils/assert.js
|
|
466
|
-
function assert(condition, message) {
|
|
467
|
-
if (!condition) {
|
|
468
|
-
throw new Error(message || "Assertion failed");
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
|
|
472
659
|
// ../../node_modules/@probe.gl/log/dist/utils/hi-res-timestamp.js
|
|
473
660
|
function getHiResTimestamp2() {
|
|
474
661
|
let timestamp;
|
|
@@ -483,7 +670,7 @@ var __exports__ = (() => {
|
|
|
483
670
|
return timestamp;
|
|
484
671
|
}
|
|
485
672
|
|
|
486
|
-
// ../../node_modules/@probe.gl/log/dist/log.js
|
|
673
|
+
// ../../node_modules/@probe.gl/log/dist/loggers/probe-log.js
|
|
487
674
|
var originalConsole = {
|
|
488
675
|
debug: isBrowser() ? console.debug || console.log : console.log,
|
|
489
676
|
log: console.log,
|
|
@@ -495,12 +682,9 @@ var __exports__ = (() => {
|
|
|
495
682
|
enabled: true,
|
|
496
683
|
level: 0
|
|
497
684
|
};
|
|
498
|
-
|
|
499
|
-
}
|
|
500
|
-
var cache = {};
|
|
501
|
-
var ONCE = { once: true };
|
|
502
|
-
var Log = class {
|
|
685
|
+
var ProbeLog = class extends BaseLog {
|
|
503
686
|
constructor({ id } = { id: "" }) {
|
|
687
|
+
super({ level: 0 });
|
|
504
688
|
this.VERSION = VERSION;
|
|
505
689
|
this._startTs = getHiResTimestamp2();
|
|
506
690
|
this._deltaTs = getHiResTimestamp2();
|
|
@@ -508,22 +692,16 @@ var __exports__ = (() => {
|
|
|
508
692
|
this.LOG_THROTTLE_TIMEOUT = 0;
|
|
509
693
|
this.id = id;
|
|
510
694
|
this.userData = {};
|
|
511
|
-
this._storage = new LocalStorage(`__probe-${this.id}__`, DEFAULT_LOG_CONFIGURATION);
|
|
695
|
+
this._storage = new LocalStorage(`__probe-${this.id}__`, { [this.id]: DEFAULT_LOG_CONFIGURATION });
|
|
512
696
|
this.timeStamp(`${this.id} started`);
|
|
513
697
|
autobind(this);
|
|
514
698
|
Object.seal(this);
|
|
515
699
|
}
|
|
516
|
-
set level(newLevel) {
|
|
517
|
-
this.setLevel(newLevel);
|
|
518
|
-
}
|
|
519
|
-
get level() {
|
|
520
|
-
return this.getLevel();
|
|
521
|
-
}
|
|
522
700
|
isEnabled() {
|
|
523
|
-
return this.
|
|
701
|
+
return this._getConfiguration().enabled;
|
|
524
702
|
}
|
|
525
703
|
getLevel() {
|
|
526
|
-
return this.
|
|
704
|
+
return this._getConfiguration().level;
|
|
527
705
|
}
|
|
528
706
|
/** @return milliseconds, with fractions */
|
|
529
707
|
getTotal() {
|
|
@@ -547,20 +725,20 @@ var __exports__ = (() => {
|
|
|
547
725
|
}
|
|
548
726
|
// Configure
|
|
549
727
|
enable(enabled = true) {
|
|
550
|
-
this.
|
|
728
|
+
this._updateConfiguration({ enabled });
|
|
551
729
|
return this;
|
|
552
730
|
}
|
|
553
731
|
setLevel(level) {
|
|
554
|
-
this.
|
|
732
|
+
this._updateConfiguration({ level });
|
|
555
733
|
return this;
|
|
556
734
|
}
|
|
557
735
|
/** return the current status of the setting */
|
|
558
736
|
get(setting) {
|
|
559
|
-
return this.
|
|
737
|
+
return this._getConfiguration()[setting];
|
|
560
738
|
}
|
|
561
739
|
// update the status of the setting
|
|
562
740
|
set(setting, value) {
|
|
563
|
-
this.
|
|
741
|
+
this._updateConfiguration({ [setting]: value });
|
|
564
742
|
}
|
|
565
743
|
/** Logs the current settings as a table */
|
|
566
744
|
settings() {
|
|
@@ -576,11 +754,16 @@ var __exports__ = (() => {
|
|
|
576
754
|
throw new Error(message || "Assertion failed");
|
|
577
755
|
}
|
|
578
756
|
}
|
|
579
|
-
warn(message) {
|
|
580
|
-
return this.
|
|
757
|
+
warn(message, ...args) {
|
|
758
|
+
return this._log("warn", 0, message, args, {
|
|
759
|
+
method: originalConsole.warn,
|
|
760
|
+
once: true
|
|
761
|
+
});
|
|
581
762
|
}
|
|
582
|
-
error(message) {
|
|
583
|
-
return this.
|
|
763
|
+
error(message, ...args) {
|
|
764
|
+
return this._log("error", 0, message, args, {
|
|
765
|
+
method: originalConsole.error
|
|
766
|
+
});
|
|
584
767
|
}
|
|
585
768
|
/** Print a deprecation warning */
|
|
586
769
|
deprecated(oldUsage, newUsage) {
|
|
@@ -590,50 +773,63 @@ var __exports__ = (() => {
|
|
|
590
773
|
removed(oldUsage, newUsage) {
|
|
591
774
|
return this.error(`\`${oldUsage}\` has been removed. Use \`${newUsage}\` instead`);
|
|
592
775
|
}
|
|
593
|
-
probe(logLevel, message) {
|
|
594
|
-
return this.
|
|
776
|
+
probe(logLevel, message, ...args) {
|
|
777
|
+
return this._log("log", logLevel, message, args, {
|
|
778
|
+
method: originalConsole.log,
|
|
595
779
|
time: true,
|
|
596
780
|
once: true
|
|
597
781
|
});
|
|
598
782
|
}
|
|
599
|
-
log(logLevel, message) {
|
|
600
|
-
return this.
|
|
783
|
+
log(logLevel, message, ...args) {
|
|
784
|
+
return this._log("log", logLevel, message, args, {
|
|
785
|
+
method: originalConsole.debug
|
|
786
|
+
});
|
|
601
787
|
}
|
|
602
|
-
info(logLevel, message) {
|
|
603
|
-
return this.
|
|
788
|
+
info(logLevel, message, ...args) {
|
|
789
|
+
return this._log("info", logLevel, message, args, { method: console.info });
|
|
604
790
|
}
|
|
605
|
-
once(logLevel, message) {
|
|
606
|
-
return this.
|
|
791
|
+
once(logLevel, message, ...args) {
|
|
792
|
+
return this._log("once", logLevel, message, args, {
|
|
793
|
+
method: originalConsole.debug || originalConsole.info,
|
|
794
|
+
once: true
|
|
795
|
+
});
|
|
607
796
|
}
|
|
608
797
|
/** Logs an object as a table */
|
|
609
798
|
table(logLevel, table, columns) {
|
|
610
799
|
if (table) {
|
|
611
|
-
return this.
|
|
800
|
+
return this._log("table", logLevel, table, columns && [columns] || [], {
|
|
801
|
+
method: console.table || noop,
|
|
612
802
|
tag: getTableHeader(table)
|
|
613
803
|
});
|
|
614
804
|
}
|
|
615
805
|
return noop;
|
|
616
806
|
}
|
|
617
807
|
time(logLevel, message) {
|
|
618
|
-
return this.
|
|
808
|
+
return this._log("time", logLevel, message, [], {
|
|
809
|
+
method: console.time ? console.time : console.info
|
|
810
|
+
});
|
|
619
811
|
}
|
|
620
812
|
timeEnd(logLevel, message) {
|
|
621
|
-
return this.
|
|
813
|
+
return this._log("time", logLevel, message, [], {
|
|
814
|
+
method: console.timeEnd ? console.timeEnd : console.info
|
|
815
|
+
});
|
|
622
816
|
}
|
|
623
817
|
timeStamp(logLevel, message) {
|
|
624
|
-
return this.
|
|
818
|
+
return this._log("time", logLevel, message, [], {
|
|
819
|
+
method: console.timeStamp || noop
|
|
820
|
+
});
|
|
625
821
|
}
|
|
626
822
|
group(logLevel, message, opts = { collapsed: false }) {
|
|
627
|
-
const
|
|
628
|
-
|
|
629
|
-
options.method = (collapsed ? console.groupCollapsed : console.group) || console.info;
|
|
630
|
-
return this._getLogFunction(options);
|
|
823
|
+
const method = (opts.collapsed ? console.groupCollapsed : console.group) || console.info;
|
|
824
|
+
return this._log("group", logLevel, message, [], { method });
|
|
631
825
|
}
|
|
632
826
|
groupCollapsed(logLevel, message, opts = {}) {
|
|
633
827
|
return this.group(logLevel, message, Object.assign({}, opts, { collapsed: true }));
|
|
634
828
|
}
|
|
635
829
|
groupEnd(logLevel) {
|
|
636
|
-
return this.
|
|
830
|
+
return this._log("groupEnd", logLevel, "", [], {
|
|
831
|
+
method: console.groupEnd || noop
|
|
832
|
+
});
|
|
637
833
|
}
|
|
638
834
|
// EXPERIMENTAL
|
|
639
835
|
withGroup(logLevel, message, func) {
|
|
@@ -649,78 +845,34 @@ var __exports__ = (() => {
|
|
|
649
845
|
console.trace();
|
|
650
846
|
}
|
|
651
847
|
}
|
|
652
|
-
// PRIVATE METHODS
|
|
653
|
-
/** Deduces log level from a variety of arguments */
|
|
654
848
|
_shouldLog(logLevel) {
|
|
655
|
-
return this.isEnabled() &&
|
|
656
|
-
}
|
|
657
|
-
_getLogFunction(logLevel, message, method, args, opts) {
|
|
658
|
-
if (this._shouldLog(logLevel)) {
|
|
659
|
-
opts = normalizeArguments({ logLevel, message, args, opts });
|
|
660
|
-
method = method || opts.method;
|
|
661
|
-
assert(method);
|
|
662
|
-
opts.total = this.getTotal();
|
|
663
|
-
opts.delta = this.getDelta();
|
|
664
|
-
this._deltaTs = getHiResTimestamp2();
|
|
665
|
-
const tag = opts.tag || opts.message;
|
|
666
|
-
if (opts.once && tag) {
|
|
667
|
-
if (!cache[tag]) {
|
|
668
|
-
cache[tag] = getHiResTimestamp2();
|
|
669
|
-
} else {
|
|
670
|
-
return noop;
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
message = decorateMessage(this.id, opts.message, opts);
|
|
674
|
-
return method.bind(console, message, ...opts.args);
|
|
675
|
-
}
|
|
676
|
-
return noop;
|
|
677
|
-
}
|
|
678
|
-
};
|
|
679
|
-
Log.VERSION = VERSION;
|
|
680
|
-
function normalizeLogLevel(logLevel) {
|
|
681
|
-
if (!logLevel) {
|
|
682
|
-
return 0;
|
|
849
|
+
return this.isEnabled() && super._shouldLog(logLevel);
|
|
683
850
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
default:
|
|
693
|
-
return 0;
|
|
694
|
-
}
|
|
695
|
-
assert(Number.isFinite(resolvedLevel) && resolvedLevel >= 0);
|
|
696
|
-
return resolvedLevel;
|
|
697
|
-
}
|
|
698
|
-
function normalizeArguments(opts) {
|
|
699
|
-
const { logLevel, message } = opts;
|
|
700
|
-
opts.logLevel = normalizeLogLevel(logLevel);
|
|
701
|
-
const args = opts.args ? Array.from(opts.args) : [];
|
|
702
|
-
while (args.length && args.shift() !== message) {
|
|
851
|
+
_emit(_type, normalized) {
|
|
852
|
+
const method = normalized.method;
|
|
853
|
+
assert(method);
|
|
854
|
+
normalized.total = this.getTotal();
|
|
855
|
+
normalized.delta = this.getDelta();
|
|
856
|
+
this._deltaTs = getHiResTimestamp2();
|
|
857
|
+
const message = decorateMessage(this.id, normalized.message, normalized);
|
|
858
|
+
return method.bind(console, message, ...normalized.args);
|
|
703
859
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
}
|
|
710
|
-
opts.message = logLevel;
|
|
711
|
-
break;
|
|
712
|
-
case "object":
|
|
713
|
-
Object.assign(opts, logLevel);
|
|
714
|
-
break;
|
|
715
|
-
default:
|
|
860
|
+
_getConfiguration() {
|
|
861
|
+
if (!this._storage.config[this.id]) {
|
|
862
|
+
this._updateConfiguration(DEFAULT_LOG_CONFIGURATION);
|
|
863
|
+
}
|
|
864
|
+
return this._storage.config[this.id];
|
|
716
865
|
}
|
|
717
|
-
|
|
718
|
-
|
|
866
|
+
_updateConfiguration(configuration) {
|
|
867
|
+
const currentConfiguration = this._storage.config[this.id] || {
|
|
868
|
+
...DEFAULT_LOG_CONFIGURATION
|
|
869
|
+
};
|
|
870
|
+
this._storage.setConfiguration({
|
|
871
|
+
[this.id]: { ...currentConfiguration, ...configuration }
|
|
872
|
+
});
|
|
719
873
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
return Object.assign(opts, { args }, opts.opts);
|
|
723
|
-
}
|
|
874
|
+
};
|
|
875
|
+
ProbeLog.VERSION = VERSION;
|
|
724
876
|
function decorateMessage(id, message, opts) {
|
|
725
877
|
if (typeof message === "string") {
|
|
726
878
|
const time = opts.time ? leftPad(formatTime(opts.total)) : "";
|
|
@@ -742,10 +894,10 @@ var __exports__ = (() => {
|
|
|
742
894
|
globalThis.probe = {};
|
|
743
895
|
|
|
744
896
|
// ../../node_modules/@probe.gl/log/dist/index.js
|
|
745
|
-
var dist_default = new
|
|
897
|
+
var dist_default = new ProbeLog({ id: "@probe.gl/log" });
|
|
746
898
|
|
|
747
899
|
// ../core/src/utils/log.ts
|
|
748
|
-
var log = new
|
|
900
|
+
var log = new ProbeLog({ id: "luma.gl" });
|
|
749
901
|
|
|
750
902
|
// ../core/src/utils/uid.ts
|
|
751
903
|
var uidCounters = {};
|
|
@@ -756,6 +908,57 @@ var __exports__ = (() => {
|
|
|
756
908
|
}
|
|
757
909
|
|
|
758
910
|
// ../core/src/adapter/resources/resource.ts
|
|
911
|
+
var CPU_HOTSPOT_PROFILER_MODULE = "cpu-hotspot-profiler";
|
|
912
|
+
var RESOURCE_COUNTS_STATS = "GPU Resource Counts";
|
|
913
|
+
var LEGACY_RESOURCE_COUNTS_STATS = "Resource Counts";
|
|
914
|
+
var GPU_TIME_AND_MEMORY_STATS2 = "GPU Time and Memory";
|
|
915
|
+
var BASE_RESOURCE_COUNT_ORDER = [
|
|
916
|
+
"Resources",
|
|
917
|
+
"Buffers",
|
|
918
|
+
"Textures",
|
|
919
|
+
"Samplers",
|
|
920
|
+
"TextureViews",
|
|
921
|
+
"Framebuffers",
|
|
922
|
+
"QuerySets",
|
|
923
|
+
"Shaders",
|
|
924
|
+
"RenderPipelines",
|
|
925
|
+
"ComputePipelines",
|
|
926
|
+
"PipelineLayouts",
|
|
927
|
+
"VertexArrays",
|
|
928
|
+
"RenderPasss",
|
|
929
|
+
"ComputePasss",
|
|
930
|
+
"CommandEncoders",
|
|
931
|
+
"CommandBuffers"
|
|
932
|
+
];
|
|
933
|
+
var WEBGL_RESOURCE_COUNT_ORDER = [
|
|
934
|
+
"Resources",
|
|
935
|
+
"Buffers",
|
|
936
|
+
"Textures",
|
|
937
|
+
"Samplers",
|
|
938
|
+
"TextureViews",
|
|
939
|
+
"Framebuffers",
|
|
940
|
+
"QuerySets",
|
|
941
|
+
"Shaders",
|
|
942
|
+
"RenderPipelines",
|
|
943
|
+
"SharedRenderPipelines",
|
|
944
|
+
"ComputePipelines",
|
|
945
|
+
"PipelineLayouts",
|
|
946
|
+
"VertexArrays",
|
|
947
|
+
"RenderPasss",
|
|
948
|
+
"ComputePasss",
|
|
949
|
+
"CommandEncoders",
|
|
950
|
+
"CommandBuffers"
|
|
951
|
+
];
|
|
952
|
+
var BASE_RESOURCE_COUNT_STAT_ORDER = BASE_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
|
|
953
|
+
`${resourceType} Created`,
|
|
954
|
+
`${resourceType} Active`
|
|
955
|
+
]);
|
|
956
|
+
var WEBGL_RESOURCE_COUNT_STAT_ORDER = WEBGL_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
|
|
957
|
+
`${resourceType} Created`,
|
|
958
|
+
`${resourceType} Active`
|
|
959
|
+
]);
|
|
960
|
+
var ORDERED_STATS_CACHE2 = /* @__PURE__ */ new WeakMap();
|
|
961
|
+
var ORDERED_STAT_NAME_SET_CACHE2 = /* @__PURE__ */ new WeakMap();
|
|
759
962
|
var Resource = class {
|
|
760
963
|
toString() {
|
|
761
964
|
return `${this[Symbol.toStringTag] || this.constructor.name}:"${this.id}"`;
|
|
@@ -772,6 +975,8 @@ var __exports__ = (() => {
|
|
|
772
975
|
destroyed = false;
|
|
773
976
|
/** For resources that allocate GPU memory */
|
|
774
977
|
allocatedBytes = 0;
|
|
978
|
+
/** Stats bucket currently holding the tracked allocation */
|
|
979
|
+
allocatedBytesName = null;
|
|
775
980
|
/** Attached resources will be destroyed when this resource is destroyed. Tracks auto-created "sub" resources. */
|
|
776
981
|
_attachedResources = /* @__PURE__ */ new Set();
|
|
777
982
|
/**
|
|
@@ -793,6 +998,9 @@ var __exports__ = (() => {
|
|
|
793
998
|
* destroy can be called on any resource to release it before it is garbage collected.
|
|
794
999
|
*/
|
|
795
1000
|
destroy() {
|
|
1001
|
+
if (this.destroyed) {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
796
1004
|
this.destroyResource();
|
|
797
1005
|
}
|
|
798
1006
|
/** @deprecated Use destroy() */
|
|
@@ -831,7 +1039,7 @@ var __exports__ = (() => {
|
|
|
831
1039
|
}
|
|
832
1040
|
/** Destroy all owned resources. Make sure the resources are no longer needed before calling. */
|
|
833
1041
|
destroyAttachedResources() {
|
|
834
|
-
for (const resource of
|
|
1042
|
+
for (const resource of this._attachedResources) {
|
|
835
1043
|
resource.destroy();
|
|
836
1044
|
}
|
|
837
1045
|
this._attachedResources = /* @__PURE__ */ new Set();
|
|
@@ -839,37 +1047,107 @@ var __exports__ = (() => {
|
|
|
839
1047
|
// PROTECTED METHODS
|
|
840
1048
|
/** Perform all destroy steps. Can be called by derived resources when overriding destroy() */
|
|
841
1049
|
destroyResource() {
|
|
1050
|
+
if (this.destroyed) {
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
842
1053
|
this.destroyAttachedResources();
|
|
843
1054
|
this.removeStats();
|
|
844
1055
|
this.destroyed = true;
|
|
845
1056
|
}
|
|
846
1057
|
/** Called by .destroy() to track object destruction. Subclass must call if overriding destroy() */
|
|
847
1058
|
removeStats() {
|
|
848
|
-
const
|
|
849
|
-
const
|
|
850
|
-
|
|
1059
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1060
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1061
|
+
const statsObjects = [
|
|
1062
|
+
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
|
|
1063
|
+
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
|
|
1064
|
+
];
|
|
1065
|
+
const orderedStatNames = getResourceCountStatOrder(this._device);
|
|
1066
|
+
for (const stats of statsObjects) {
|
|
1067
|
+
initializeStats2(stats, orderedStatNames);
|
|
1068
|
+
}
|
|
1069
|
+
const name2 = this.getStatsName();
|
|
1070
|
+
for (const stats of statsObjects) {
|
|
1071
|
+
stats.get("Resources Active").decrementCount();
|
|
1072
|
+
stats.get(`${name2}s Active`).decrementCount();
|
|
1073
|
+
}
|
|
1074
|
+
if (profiler) {
|
|
1075
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1076
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1077
|
+
}
|
|
851
1078
|
}
|
|
852
1079
|
/** Called by subclass to track memory allocations */
|
|
853
|
-
trackAllocatedMemory(bytes, name2 = this
|
|
854
|
-
const
|
|
1080
|
+
trackAllocatedMemory(bytes, name2 = this.getStatsName()) {
|
|
1081
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1082
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1083
|
+
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
|
|
1084
|
+
if (this.allocatedBytes > 0 && this.allocatedBytesName) {
|
|
1085
|
+
stats.get("GPU Memory").subtractCount(this.allocatedBytes);
|
|
1086
|
+
stats.get(`${this.allocatedBytesName} Memory`).subtractCount(this.allocatedBytes);
|
|
1087
|
+
}
|
|
855
1088
|
stats.get("GPU Memory").addCount(bytes);
|
|
856
1089
|
stats.get(`${name2} Memory`).addCount(bytes);
|
|
1090
|
+
if (profiler) {
|
|
1091
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1092
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1093
|
+
}
|
|
857
1094
|
this.allocatedBytes = bytes;
|
|
1095
|
+
this.allocatedBytesName = name2;
|
|
1096
|
+
}
|
|
1097
|
+
/** Called by subclass to track handle-backed memory allocations separately from owned allocations */
|
|
1098
|
+
trackReferencedMemory(bytes, name2 = this.getStatsName()) {
|
|
1099
|
+
this.trackAllocatedMemory(bytes, `Referenced ${name2}`);
|
|
858
1100
|
}
|
|
859
1101
|
/** Called by subclass to track memory deallocations */
|
|
860
|
-
trackDeallocatedMemory(name2 = this
|
|
861
|
-
|
|
1102
|
+
trackDeallocatedMemory(name2 = this.getStatsName()) {
|
|
1103
|
+
if (this.allocatedBytes === 0) {
|
|
1104
|
+
this.allocatedBytesName = null;
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1108
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1109
|
+
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
|
|
862
1110
|
stats.get("GPU Memory").subtractCount(this.allocatedBytes);
|
|
863
|
-
stats.get(`${name2} Memory`).subtractCount(this.allocatedBytes);
|
|
1111
|
+
stats.get(`${this.allocatedBytesName || name2} Memory`).subtractCount(this.allocatedBytes);
|
|
1112
|
+
if (profiler) {
|
|
1113
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1114
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1115
|
+
}
|
|
864
1116
|
this.allocatedBytes = 0;
|
|
1117
|
+
this.allocatedBytesName = null;
|
|
1118
|
+
}
|
|
1119
|
+
/** Called by subclass to deallocate handle-backed memory tracked via trackReferencedMemory() */
|
|
1120
|
+
trackDeallocatedReferencedMemory(name2 = this.getStatsName()) {
|
|
1121
|
+
this.trackDeallocatedMemory(`Referenced ${name2}`);
|
|
865
1122
|
}
|
|
866
1123
|
/** Called by resource constructor to track object creation */
|
|
867
1124
|
addStats() {
|
|
868
|
-
const
|
|
869
|
-
const
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
1125
|
+
const name2 = this.getStatsName();
|
|
1126
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1127
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1128
|
+
const statsObjects = [
|
|
1129
|
+
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
|
|
1130
|
+
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
|
|
1131
|
+
];
|
|
1132
|
+
const orderedStatNames = getResourceCountStatOrder(this._device);
|
|
1133
|
+
for (const stats of statsObjects) {
|
|
1134
|
+
initializeStats2(stats, orderedStatNames);
|
|
1135
|
+
}
|
|
1136
|
+
for (const stats of statsObjects) {
|
|
1137
|
+
stats.get("Resources Created").incrementCount();
|
|
1138
|
+
stats.get("Resources Active").incrementCount();
|
|
1139
|
+
stats.get(`${name2}s Created`).incrementCount();
|
|
1140
|
+
stats.get(`${name2}s Active`).incrementCount();
|
|
1141
|
+
}
|
|
1142
|
+
if (profiler) {
|
|
1143
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1144
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1145
|
+
}
|
|
1146
|
+
recordTransientCanvasResourceCreate(this._device, name2);
|
|
1147
|
+
}
|
|
1148
|
+
/** Canonical resource name used for stats buckets. */
|
|
1149
|
+
getStatsName() {
|
|
1150
|
+
return getCanonicalResourceName(this);
|
|
873
1151
|
}
|
|
874
1152
|
};
|
|
875
1153
|
/** Default properties for resource */
|
|
@@ -887,6 +1165,96 @@ var __exports__ = (() => {
|
|
|
887
1165
|
}
|
|
888
1166
|
return mergedProps;
|
|
889
1167
|
}
|
|
1168
|
+
function initializeStats2(stats, orderedStatNames) {
|
|
1169
|
+
const statsMap = stats.stats;
|
|
1170
|
+
let addedOrderedStat = false;
|
|
1171
|
+
for (const statName of orderedStatNames) {
|
|
1172
|
+
if (!statsMap[statName]) {
|
|
1173
|
+
stats.get(statName);
|
|
1174
|
+
addedOrderedStat = true;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
const statCount = Object.keys(statsMap).length;
|
|
1178
|
+
const cachedStats = ORDERED_STATS_CACHE2.get(stats);
|
|
1179
|
+
if (!addedOrderedStat && cachedStats?.orderedStatNames === orderedStatNames && cachedStats.statCount === statCount) {
|
|
1180
|
+
return;
|
|
1181
|
+
}
|
|
1182
|
+
const reorderedStats = {};
|
|
1183
|
+
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE2.get(orderedStatNames);
|
|
1184
|
+
if (!orderedStatNamesSet) {
|
|
1185
|
+
orderedStatNamesSet = new Set(orderedStatNames);
|
|
1186
|
+
ORDERED_STAT_NAME_SET_CACHE2.set(orderedStatNames, orderedStatNamesSet);
|
|
1187
|
+
}
|
|
1188
|
+
for (const statName of orderedStatNames) {
|
|
1189
|
+
if (statsMap[statName]) {
|
|
1190
|
+
reorderedStats[statName] = statsMap[statName];
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
for (const [statName, stat] of Object.entries(statsMap)) {
|
|
1194
|
+
if (!orderedStatNamesSet.has(statName)) {
|
|
1195
|
+
reorderedStats[statName] = stat;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
for (const statName of Object.keys(statsMap)) {
|
|
1199
|
+
delete statsMap[statName];
|
|
1200
|
+
}
|
|
1201
|
+
Object.assign(statsMap, reorderedStats);
|
|
1202
|
+
ORDERED_STATS_CACHE2.set(stats, { orderedStatNames, statCount });
|
|
1203
|
+
}
|
|
1204
|
+
function getResourceCountStatOrder(device) {
|
|
1205
|
+
return device.type === "webgl" ? WEBGL_RESOURCE_COUNT_STAT_ORDER : BASE_RESOURCE_COUNT_STAT_ORDER;
|
|
1206
|
+
}
|
|
1207
|
+
function getCpuHotspotProfiler(device) {
|
|
1208
|
+
const profiler = device.userData[CPU_HOTSPOT_PROFILER_MODULE];
|
|
1209
|
+
return profiler?.enabled ? profiler : null;
|
|
1210
|
+
}
|
|
1211
|
+
function getTimestamp() {
|
|
1212
|
+
return globalThis.performance?.now?.() ?? Date.now();
|
|
1213
|
+
}
|
|
1214
|
+
function recordTransientCanvasResourceCreate(device, name2) {
|
|
1215
|
+
const profiler = getCpuHotspotProfiler(device);
|
|
1216
|
+
if (!profiler || !profiler.activeDefaultFramebufferAcquireDepth) {
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
profiler.transientCanvasResourceCreates = (profiler.transientCanvasResourceCreates || 0) + 1;
|
|
1220
|
+
switch (name2) {
|
|
1221
|
+
case "Texture":
|
|
1222
|
+
profiler.transientCanvasTextureCreates = (profiler.transientCanvasTextureCreates || 0) + 1;
|
|
1223
|
+
break;
|
|
1224
|
+
case "TextureView":
|
|
1225
|
+
profiler.transientCanvasTextureViewCreates = (profiler.transientCanvasTextureViewCreates || 0) + 1;
|
|
1226
|
+
break;
|
|
1227
|
+
case "Sampler":
|
|
1228
|
+
profiler.transientCanvasSamplerCreates = (profiler.transientCanvasSamplerCreates || 0) + 1;
|
|
1229
|
+
break;
|
|
1230
|
+
case "Framebuffer":
|
|
1231
|
+
profiler.transientCanvasFramebufferCreates = (profiler.transientCanvasFramebufferCreates || 0) + 1;
|
|
1232
|
+
break;
|
|
1233
|
+
default:
|
|
1234
|
+
break;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
function getCanonicalResourceName(resource) {
|
|
1238
|
+
let prototype = Object.getPrototypeOf(resource);
|
|
1239
|
+
while (prototype) {
|
|
1240
|
+
const parentPrototype = Object.getPrototypeOf(prototype);
|
|
1241
|
+
if (!parentPrototype || parentPrototype === Resource.prototype) {
|
|
1242
|
+
return getPrototypeToStringTag(prototype) || resource[Symbol.toStringTag] || resource.constructor.name;
|
|
1243
|
+
}
|
|
1244
|
+
prototype = parentPrototype;
|
|
1245
|
+
}
|
|
1246
|
+
return resource[Symbol.toStringTag] || resource.constructor.name;
|
|
1247
|
+
}
|
|
1248
|
+
function getPrototypeToStringTag(prototype) {
|
|
1249
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, Symbol.toStringTag);
|
|
1250
|
+
if (typeof descriptor?.get === "function") {
|
|
1251
|
+
return descriptor.get.call(prototype);
|
|
1252
|
+
}
|
|
1253
|
+
if (typeof descriptor?.value === "string") {
|
|
1254
|
+
return descriptor.value;
|
|
1255
|
+
}
|
|
1256
|
+
return null;
|
|
1257
|
+
}
|
|
890
1258
|
|
|
891
1259
|
// ../core/src/adapter/resources/buffer.ts
|
|
892
1260
|
var _Buffer = class extends Resource {
|
|
@@ -926,18 +1294,26 @@ var __exports__ = (() => {
|
|
|
926
1294
|
/** A partial CPU-side copy of the data in this buffer, for debugging purposes */
|
|
927
1295
|
debugData = new ArrayBuffer(0);
|
|
928
1296
|
/** This doesn't handle partial non-zero offset updates correctly */
|
|
929
|
-
_setDebugData(data,
|
|
930
|
-
|
|
1297
|
+
_setDebugData(data, _byteOffset, byteLength) {
|
|
1298
|
+
let arrayBufferView = null;
|
|
1299
|
+
let arrayBuffer2;
|
|
1300
|
+
if (ArrayBuffer.isView(data)) {
|
|
1301
|
+
arrayBufferView = data;
|
|
1302
|
+
arrayBuffer2 = data.buffer;
|
|
1303
|
+
} else {
|
|
1304
|
+
arrayBuffer2 = data;
|
|
1305
|
+
}
|
|
931
1306
|
const debugDataLength = Math.min(
|
|
932
1307
|
data ? data.byteLength : byteLength,
|
|
933
1308
|
_Buffer.DEBUG_DATA_MAX_LENGTH
|
|
934
1309
|
);
|
|
935
1310
|
if (arrayBuffer2 === null) {
|
|
936
1311
|
this.debugData = new ArrayBuffer(debugDataLength);
|
|
937
|
-
} else if (byteOffset === 0 && byteLength === arrayBuffer2.byteLength) {
|
|
938
|
-
this.debugData = arrayBuffer2.slice(0, debugDataLength);
|
|
939
1312
|
} else {
|
|
940
|
-
|
|
1313
|
+
const sourceByteOffset = Math.min(arrayBufferView?.byteOffset || 0, arrayBuffer2.byteLength);
|
|
1314
|
+
const availableByteLength = Math.max(0, arrayBuffer2.byteLength - sourceByteOffset);
|
|
1315
|
+
const copyByteLength = Math.min(debugDataLength, availableByteLength);
|
|
1316
|
+
this.debugData = new Uint8Array(arrayBuffer2, sourceByteOffset, copyByteLength).slice().buffer;
|
|
941
1317
|
}
|
|
942
1318
|
}
|
|
943
1319
|
};
|
|
@@ -1133,6 +1509,7 @@ var __exports__ = (() => {
|
|
|
1133
1509
|
var float16_renderable = "float16-renderable-webgl";
|
|
1134
1510
|
var rgb9e5ufloat_renderable = "rgb9e5ufloat-renderable-webgl";
|
|
1135
1511
|
var snorm8_renderable = "snorm8-renderable-webgl";
|
|
1512
|
+
var norm16_webgl = "norm16-webgl";
|
|
1136
1513
|
var norm16_renderable = "norm16-renderable-webgl";
|
|
1137
1514
|
var snorm16_renderable = "snorm16-renderable-webgl";
|
|
1138
1515
|
var float32_filterable = "float32-filterable";
|
|
@@ -1166,16 +1543,16 @@ var __exports__ = (() => {
|
|
|
1166
1543
|
"rgba8sint": {},
|
|
1167
1544
|
"bgra8unorm": {},
|
|
1168
1545
|
"bgra8unorm-srgb": {},
|
|
1169
|
-
"r16unorm": { f: norm16_renderable },
|
|
1170
|
-
"rg16unorm": { render: norm16_renderable },
|
|
1171
|
-
"rgb16unorm-webgl": { f:
|
|
1546
|
+
"r16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1547
|
+
"rg16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1548
|
+
"rgb16unorm-webgl": { f: norm16_webgl, render: false },
|
|
1172
1549
|
// rgb not renderable
|
|
1173
|
-
"rgba16unorm": { render: norm16_renderable },
|
|
1174
|
-
"r16snorm": { f: snorm16_renderable },
|
|
1175
|
-
"rg16snorm": { render: snorm16_renderable },
|
|
1176
|
-
"rgb16snorm-webgl": { f:
|
|
1550
|
+
"rgba16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1551
|
+
"r16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1552
|
+
"rg16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1553
|
+
"rgb16snorm-webgl": { f: norm16_webgl, render: false },
|
|
1177
1554
|
// rgb not renderable
|
|
1178
|
-
"rgba16snorm": { render: snorm16_renderable },
|
|
1555
|
+
"rgba16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1179
1556
|
"r16uint": {},
|
|
1180
1557
|
"rg16uint": {},
|
|
1181
1558
|
"rgba16uint": {},
|
|
@@ -1278,7 +1655,7 @@ var __exports__ = (() => {
|
|
|
1278
1655
|
// WEBGL_compressed_texture_pvrtc
|
|
1279
1656
|
"pvrtc-rgb4unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1280
1657
|
"pvrtc-rgba4unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1281
|
-
"pvrtc-
|
|
1658
|
+
"pvrtc-rgb2unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1282
1659
|
"pvrtc-rgba2unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1283
1660
|
// WEBGL_compressed_texture_etc1
|
|
1284
1661
|
"etc1-rbg-unorm-webgl": { f: texture_compression_etc1_webgl },
|
|
@@ -1345,10 +1722,19 @@ var __exports__ = (() => {
|
|
|
1345
1722
|
depth,
|
|
1346
1723
|
byteAlignment
|
|
1347
1724
|
}) {
|
|
1348
|
-
const
|
|
1349
|
-
const
|
|
1725
|
+
const formatInfo = textureFormatDecoder.getInfo(format);
|
|
1726
|
+
const {
|
|
1727
|
+
bytesPerPixel,
|
|
1728
|
+
bytesPerBlock = bytesPerPixel,
|
|
1729
|
+
blockWidth = 1,
|
|
1730
|
+
blockHeight = 1,
|
|
1731
|
+
compressed = false
|
|
1732
|
+
} = formatInfo;
|
|
1733
|
+
const blockColumns = compressed ? Math.ceil(width / blockWidth) : width;
|
|
1734
|
+
const blockRows = compressed ? Math.ceil(height / blockHeight) : height;
|
|
1735
|
+
const unpaddedBytesPerRow = blockColumns * bytesPerBlock;
|
|
1350
1736
|
const bytesPerRow = Math.ceil(unpaddedBytesPerRow / byteAlignment) * byteAlignment;
|
|
1351
|
-
const rowsPerImage =
|
|
1737
|
+
const rowsPerImage = blockRows;
|
|
1352
1738
|
const byteLength = bytesPerRow * rowsPerImage * depth;
|
|
1353
1739
|
return {
|
|
1354
1740
|
bytesPerPixel,
|
|
@@ -1374,7 +1760,8 @@ var __exports__ = (() => {
|
|
|
1374
1760
|
const isSigned = formatInfo?.signed;
|
|
1375
1761
|
const isInteger = formatInfo?.integer;
|
|
1376
1762
|
const isWebGLSpecific = formatInfo?.webgl;
|
|
1377
|
-
|
|
1763
|
+
const isCompressed = Boolean(formatInfo?.compressed);
|
|
1764
|
+
formatCapabilities.render &&= !isDepthStencil && !isCompressed;
|
|
1378
1765
|
formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
|
|
1379
1766
|
return formatCapabilities;
|
|
1380
1767
|
}
|
|
@@ -1386,6 +1773,7 @@ var __exports__ = (() => {
|
|
|
1386
1773
|
formatInfo.bytesPerPixel = 1;
|
|
1387
1774
|
formatInfo.srgb = false;
|
|
1388
1775
|
formatInfo.compressed = true;
|
|
1776
|
+
formatInfo.bytesPerBlock = getCompressedTextureBlockByteLength(format);
|
|
1389
1777
|
const blockSize = getCompressedTextureBlockSize(format);
|
|
1390
1778
|
if (blockSize) {
|
|
1391
1779
|
formatInfo.blockWidth = blockSize.blockWidth;
|
|
@@ -1398,7 +1786,7 @@ var __exports__ = (() => {
|
|
|
1398
1786
|
const dataType = `${type}${length}`;
|
|
1399
1787
|
const decodedType = getDataTypeInfo(dataType);
|
|
1400
1788
|
const bits = decodedType.byteLength * 8;
|
|
1401
|
-
const components = channels
|
|
1789
|
+
const components = channels?.length ?? 1;
|
|
1402
1790
|
const bitsPerChannel = [
|
|
1403
1791
|
bits,
|
|
1404
1792
|
components >= 2 ? bits : 0,
|
|
@@ -1415,7 +1803,7 @@ var __exports__ = (() => {
|
|
|
1415
1803
|
signed: decodedType.signed,
|
|
1416
1804
|
normalized: decodedType.normalized,
|
|
1417
1805
|
bitsPerChannel,
|
|
1418
|
-
bytesPerPixel: decodedType.byteLength *
|
|
1806
|
+
bytesPerPixel: decodedType.byteLength * components,
|
|
1419
1807
|
packed: formatInfo.packed,
|
|
1420
1808
|
srgb: formatInfo.srgb
|
|
1421
1809
|
};
|
|
@@ -1471,8 +1859,29 @@ var __exports__ = (() => {
|
|
|
1471
1859
|
const [, blockWidth, blockHeight] = matches;
|
|
1472
1860
|
return { blockWidth: Number(blockWidth), blockHeight: Number(blockHeight) };
|
|
1473
1861
|
}
|
|
1862
|
+
if (format.startsWith("bc") || format.startsWith("etc1") || format.startsWith("etc2") || format.startsWith("eac") || format.startsWith("atc")) {
|
|
1863
|
+
return { blockWidth: 4, blockHeight: 4 };
|
|
1864
|
+
}
|
|
1865
|
+
if (format.startsWith("pvrtc-rgb4") || format.startsWith("pvrtc-rgba4")) {
|
|
1866
|
+
return { blockWidth: 4, blockHeight: 4 };
|
|
1867
|
+
}
|
|
1868
|
+
if (format.startsWith("pvrtc-rgb2") || format.startsWith("pvrtc-rgba2")) {
|
|
1869
|
+
return { blockWidth: 8, blockHeight: 4 };
|
|
1870
|
+
}
|
|
1474
1871
|
return null;
|
|
1475
1872
|
}
|
|
1873
|
+
function getCompressedTextureBlockByteLength(format) {
|
|
1874
|
+
if (format.startsWith("bc1") || format.startsWith("bc4") || format.startsWith("etc1") || format.startsWith("etc2-rgb8") || format.startsWith("etc2-rgb8a1") || format.startsWith("eac-r11") || format === "atc-rgb-unorm-webgl") {
|
|
1875
|
+
return 8;
|
|
1876
|
+
}
|
|
1877
|
+
if (format.startsWith("bc2") || format.startsWith("bc3") || format.startsWith("bc5") || format.startsWith("bc6h") || format.startsWith("bc7") || format.startsWith("etc2-rgba8") || format.startsWith("eac-rg11") || format.startsWith("astc") || format === "atc-rgba-unorm-webgl" || format === "atc-rgbai-unorm-webgl") {
|
|
1878
|
+
return 16;
|
|
1879
|
+
}
|
|
1880
|
+
if (format.startsWith("pvrtc")) {
|
|
1881
|
+
return 8;
|
|
1882
|
+
}
|
|
1883
|
+
return 16;
|
|
1884
|
+
}
|
|
1476
1885
|
|
|
1477
1886
|
// ../core/src/image-utils/image-types.ts
|
|
1478
1887
|
function isExternalImage(data) {
|
|
@@ -1533,6 +1942,8 @@ var __exports__ = (() => {
|
|
|
1533
1942
|
/** Used by other luma.gl modules to store data on the device */
|
|
1534
1943
|
_moduleData = {};
|
|
1535
1944
|
_textureCaps = {};
|
|
1945
|
+
/** Internal timestamp query set used when GPU timing collection is enabled for this device. */
|
|
1946
|
+
_debugGPUTimeQuery = null;
|
|
1536
1947
|
constructor(props) {
|
|
1537
1948
|
this.props = { ..._Device.defaultProps, ...props };
|
|
1538
1949
|
this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase());
|
|
@@ -1586,6 +1997,16 @@ var __exports__ = (() => {
|
|
|
1586
1997
|
isTextureFormatCompressed(format) {
|
|
1587
1998
|
return textureFormatDecoder.isCompressed(format);
|
|
1588
1999
|
}
|
|
2000
|
+
/** Returns the compressed texture formats that can be created and sampled on this device */
|
|
2001
|
+
getSupportedCompressedTextureFormats() {
|
|
2002
|
+
const supportedFormats = [];
|
|
2003
|
+
for (const format of Object.keys(getTextureFormatTable())) {
|
|
2004
|
+
if (this.isTextureFormatCompressed(format) && this.isTextureFormatSupported(format)) {
|
|
2005
|
+
supportedFormats.push(format);
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
return supportedFormats;
|
|
2009
|
+
}
|
|
1589
2010
|
// DEBUG METHODS
|
|
1590
2011
|
pushDebugGroup(groupLabel) {
|
|
1591
2012
|
this.commandEncoder.pushDebugGroup(groupLabel);
|
|
@@ -1668,6 +2089,70 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1668
2089
|
beginComputePass(props) {
|
|
1669
2090
|
return this.commandEncoder.beginComputePass(props);
|
|
1670
2091
|
}
|
|
2092
|
+
/**
|
|
2093
|
+
* Generate mipmaps for a WebGPU texture.
|
|
2094
|
+
* WebGPU textures must be created up front with the required mip count, usage flags, and a format that supports the chosen generation path.
|
|
2095
|
+
* WebGL uses `Texture.generateMipmapsWebGL()` directly because the backend manages mip generation on the texture object itself.
|
|
2096
|
+
*/
|
|
2097
|
+
generateMipmapsWebGPU(_texture) {
|
|
2098
|
+
throw new Error("not implemented");
|
|
2099
|
+
}
|
|
2100
|
+
/** Internal helper for creating a shareable WebGL render-pipeline implementation. */
|
|
2101
|
+
_createSharedRenderPipelineWebGL(_props) {
|
|
2102
|
+
throw new Error("_createSharedRenderPipelineWebGL() not implemented");
|
|
2103
|
+
}
|
|
2104
|
+
/**
|
|
2105
|
+
* Internal helper that returns `true` when timestamp-query GPU timing should be
|
|
2106
|
+
* collected for this device.
|
|
2107
|
+
*/
|
|
2108
|
+
_supportsDebugGPUTime() {
|
|
2109
|
+
return this.features.has("timestamp-query") && Boolean(this.props.debug || this.props.debugGPUTime);
|
|
2110
|
+
}
|
|
2111
|
+
/**
|
|
2112
|
+
* Internal helper that enables device-managed GPU timing collection on the
|
|
2113
|
+
* default command encoder. Reuses the existing query set if timing is already enabled.
|
|
2114
|
+
*
|
|
2115
|
+
* @param queryCount - Number of timestamp slots reserved for profiled passes.
|
|
2116
|
+
* @returns The device-managed timestamp QuerySet, or `null` when timing is not supported or could not be enabled.
|
|
2117
|
+
*/
|
|
2118
|
+
_enableDebugGPUTime(queryCount = 256) {
|
|
2119
|
+
if (!this._supportsDebugGPUTime()) {
|
|
2120
|
+
return null;
|
|
2121
|
+
}
|
|
2122
|
+
if (this._debugGPUTimeQuery) {
|
|
2123
|
+
return this._debugGPUTimeQuery;
|
|
2124
|
+
}
|
|
2125
|
+
try {
|
|
2126
|
+
this._debugGPUTimeQuery = this.createQuerySet({ type: "timestamp", count: queryCount });
|
|
2127
|
+
this.commandEncoder = this.createCommandEncoder({
|
|
2128
|
+
id: this.commandEncoder.props.id,
|
|
2129
|
+
timeProfilingQuerySet: this._debugGPUTimeQuery
|
|
2130
|
+
});
|
|
2131
|
+
} catch {
|
|
2132
|
+
this._debugGPUTimeQuery = null;
|
|
2133
|
+
}
|
|
2134
|
+
return this._debugGPUTimeQuery;
|
|
2135
|
+
}
|
|
2136
|
+
/**
|
|
2137
|
+
* Internal helper that disables device-managed GPU timing collection and restores
|
|
2138
|
+
* the default command encoder to an unprofiled state.
|
|
2139
|
+
*/
|
|
2140
|
+
_disableDebugGPUTime() {
|
|
2141
|
+
if (!this._debugGPUTimeQuery) {
|
|
2142
|
+
return;
|
|
2143
|
+
}
|
|
2144
|
+
if (this.commandEncoder.getTimeProfilingQuerySet() === this._debugGPUTimeQuery) {
|
|
2145
|
+
this.commandEncoder = this.createCommandEncoder({
|
|
2146
|
+
id: this.commandEncoder.props.id
|
|
2147
|
+
});
|
|
2148
|
+
}
|
|
2149
|
+
this._debugGPUTimeQuery.destroy();
|
|
2150
|
+
this._debugGPUTimeQuery = null;
|
|
2151
|
+
}
|
|
2152
|
+
/** Internal helper that returns `true` when device-managed GPU timing is currently active. */
|
|
2153
|
+
_isDebugGPUTimeEnabled() {
|
|
2154
|
+
return this._debugGPUTimeQuery !== null;
|
|
2155
|
+
}
|
|
1671
2156
|
// DEPRECATED METHODS
|
|
1672
2157
|
/** @deprecated Use getDefaultCanvasContext() */
|
|
1673
2158
|
getCanvasContext() {
|
|
@@ -1775,7 +2260,8 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1775
2260
|
onVisibilityChange: (context) => log.log(1, `${context} Visibility changed ${context.isVisible}`)(),
|
|
1776
2261
|
onDevicePixelRatioChange: (context, info) => log.log(1, `${context} DPR changed ${info.oldRatio} => ${context.devicePixelRatio}`)(),
|
|
1777
2262
|
// Debug flags
|
|
1778
|
-
debug:
|
|
2263
|
+
debug: getDefaultDebugValue(),
|
|
2264
|
+
debugGPUTime: false,
|
|
1779
2265
|
debugShaders: log.get("debug-shaders") || void 0,
|
|
1780
2266
|
debugFramebuffers: Boolean(log.get("debug-framebuffers")),
|
|
1781
2267
|
debugFactories: Boolean(log.get("debug-factories")),
|
|
@@ -1786,9 +2272,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1786
2272
|
// Experimental
|
|
1787
2273
|
_reuseDevices: false,
|
|
1788
2274
|
_requestMaxLimits: true,
|
|
1789
|
-
_cacheShaders:
|
|
1790
|
-
|
|
1791
|
-
|
|
2275
|
+
_cacheShaders: true,
|
|
2276
|
+
_destroyShaders: false,
|
|
2277
|
+
_cachePipelines: true,
|
|
2278
|
+
_sharePipelines: true,
|
|
2279
|
+
_destroyPipelines: false,
|
|
1792
2280
|
// TODO - Change these after confirming things work as expected
|
|
1793
2281
|
_initializeFeatures: true,
|
|
1794
2282
|
_disabledFeatures: {
|
|
@@ -1797,6 +2285,25 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1797
2285
|
// INTERNAL
|
|
1798
2286
|
_handle: void 0
|
|
1799
2287
|
});
|
|
2288
|
+
function _getDefaultDebugValue(logDebugValue, nodeEnv) {
|
|
2289
|
+
if (logDebugValue !== void 0 && logDebugValue !== null) {
|
|
2290
|
+
return Boolean(logDebugValue);
|
|
2291
|
+
}
|
|
2292
|
+
if (nodeEnv !== void 0) {
|
|
2293
|
+
return nodeEnv !== "production";
|
|
2294
|
+
}
|
|
2295
|
+
return false;
|
|
2296
|
+
}
|
|
2297
|
+
function getDefaultDebugValue() {
|
|
2298
|
+
return _getDefaultDebugValue(log.get("debug"), getNodeEnv());
|
|
2299
|
+
}
|
|
2300
|
+
function getNodeEnv() {
|
|
2301
|
+
const processObject = globalThis.process;
|
|
2302
|
+
if (!processObject?.env) {
|
|
2303
|
+
return void 0;
|
|
2304
|
+
}
|
|
2305
|
+
return processObject.env["NODE_ENV"];
|
|
2306
|
+
}
|
|
1800
2307
|
|
|
1801
2308
|
// ../core/src/adapter/luma.ts
|
|
1802
2309
|
var STARTUP_MESSAGE = "set luma.log.level=1 (or higher) to trace rendering";
|
|
@@ -1974,6 +2481,100 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1974
2481
|
return pageLoadPromise;
|
|
1975
2482
|
}
|
|
1976
2483
|
|
|
2484
|
+
// ../core/src/adapter/canvas-observer.ts
|
|
2485
|
+
var CanvasObserver = class {
|
|
2486
|
+
props;
|
|
2487
|
+
_resizeObserver;
|
|
2488
|
+
_intersectionObserver;
|
|
2489
|
+
_observeDevicePixelRatioTimeout = null;
|
|
2490
|
+
_observeDevicePixelRatioMediaQuery = null;
|
|
2491
|
+
_handleDevicePixelRatioChange = () => this._refreshDevicePixelRatio();
|
|
2492
|
+
_trackPositionInterval = null;
|
|
2493
|
+
_started = false;
|
|
2494
|
+
get started() {
|
|
2495
|
+
return this._started;
|
|
2496
|
+
}
|
|
2497
|
+
constructor(props) {
|
|
2498
|
+
this.props = props;
|
|
2499
|
+
}
|
|
2500
|
+
start() {
|
|
2501
|
+
if (this._started || !this.props.canvas) {
|
|
2502
|
+
return;
|
|
2503
|
+
}
|
|
2504
|
+
this._started = true;
|
|
2505
|
+
this._intersectionObserver ||= new IntersectionObserver(
|
|
2506
|
+
(entries) => this.props.onIntersection(entries)
|
|
2507
|
+
);
|
|
2508
|
+
this._resizeObserver ||= new ResizeObserver((entries) => this.props.onResize(entries));
|
|
2509
|
+
this._intersectionObserver.observe(this.props.canvas);
|
|
2510
|
+
try {
|
|
2511
|
+
this._resizeObserver.observe(this.props.canvas, { box: "device-pixel-content-box" });
|
|
2512
|
+
} catch {
|
|
2513
|
+
this._resizeObserver.observe(this.props.canvas, { box: "content-box" });
|
|
2514
|
+
}
|
|
2515
|
+
this._observeDevicePixelRatioTimeout = setTimeout(() => this._refreshDevicePixelRatio(), 0);
|
|
2516
|
+
if (this.props.trackPosition) {
|
|
2517
|
+
this._trackPosition();
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
stop() {
|
|
2521
|
+
if (!this._started) {
|
|
2522
|
+
return;
|
|
2523
|
+
}
|
|
2524
|
+
this._started = false;
|
|
2525
|
+
if (this._observeDevicePixelRatioTimeout) {
|
|
2526
|
+
clearTimeout(this._observeDevicePixelRatioTimeout);
|
|
2527
|
+
this._observeDevicePixelRatioTimeout = null;
|
|
2528
|
+
}
|
|
2529
|
+
if (this._observeDevicePixelRatioMediaQuery) {
|
|
2530
|
+
this._observeDevicePixelRatioMediaQuery.removeEventListener(
|
|
2531
|
+
"change",
|
|
2532
|
+
this._handleDevicePixelRatioChange
|
|
2533
|
+
);
|
|
2534
|
+
this._observeDevicePixelRatioMediaQuery = null;
|
|
2535
|
+
}
|
|
2536
|
+
if (this._trackPositionInterval) {
|
|
2537
|
+
clearInterval(this._trackPositionInterval);
|
|
2538
|
+
this._trackPositionInterval = null;
|
|
2539
|
+
}
|
|
2540
|
+
this._resizeObserver?.disconnect();
|
|
2541
|
+
this._intersectionObserver?.disconnect();
|
|
2542
|
+
}
|
|
2543
|
+
_refreshDevicePixelRatio() {
|
|
2544
|
+
if (!this._started) {
|
|
2545
|
+
return;
|
|
2546
|
+
}
|
|
2547
|
+
this.props.onDevicePixelRatioChange();
|
|
2548
|
+
this._observeDevicePixelRatioMediaQuery?.removeEventListener(
|
|
2549
|
+
"change",
|
|
2550
|
+
this._handleDevicePixelRatioChange
|
|
2551
|
+
);
|
|
2552
|
+
this._observeDevicePixelRatioMediaQuery = matchMedia(
|
|
2553
|
+
`(resolution: ${window.devicePixelRatio}dppx)`
|
|
2554
|
+
);
|
|
2555
|
+
this._observeDevicePixelRatioMediaQuery.addEventListener(
|
|
2556
|
+
"change",
|
|
2557
|
+
this._handleDevicePixelRatioChange,
|
|
2558
|
+
{ once: true }
|
|
2559
|
+
);
|
|
2560
|
+
}
|
|
2561
|
+
_trackPosition(intervalMs = 100) {
|
|
2562
|
+
if (this._trackPositionInterval) {
|
|
2563
|
+
return;
|
|
2564
|
+
}
|
|
2565
|
+
this._trackPositionInterval = setInterval(() => {
|
|
2566
|
+
if (!this._started) {
|
|
2567
|
+
if (this._trackPositionInterval) {
|
|
2568
|
+
clearInterval(this._trackPositionInterval);
|
|
2569
|
+
this._trackPositionInterval = null;
|
|
2570
|
+
}
|
|
2571
|
+
} else {
|
|
2572
|
+
this.props.onPositionChange();
|
|
2573
|
+
}
|
|
2574
|
+
}, intervalMs);
|
|
2575
|
+
}
|
|
2576
|
+
};
|
|
2577
|
+
|
|
1977
2578
|
// ../core/src/utils/promise-utils.ts
|
|
1978
2579
|
function withResolvers() {
|
|
1979
2580
|
let resolve;
|
|
@@ -1985,8 +2586,21 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1985
2586
|
return { promise, resolve, reject };
|
|
1986
2587
|
}
|
|
1987
2588
|
|
|
1988
|
-
// ../core/src/
|
|
1989
|
-
|
|
2589
|
+
// ../core/src/utils/assert.ts
|
|
2590
|
+
function assert2(condition, message) {
|
|
2591
|
+
if (!condition) {
|
|
2592
|
+
const error = new Error(message ?? "luma.gl assertion failed.");
|
|
2593
|
+
Error.captureStackTrace?.(error, assert2);
|
|
2594
|
+
throw error;
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
function assertDefined(value, message) {
|
|
2598
|
+
assert2(value, message);
|
|
2599
|
+
return value;
|
|
2600
|
+
}
|
|
2601
|
+
|
|
2602
|
+
// ../core/src/adapter/canvas-surface.ts
|
|
2603
|
+
var _CanvasSurface = class {
|
|
1990
2604
|
static isHTMLCanvas(canvas) {
|
|
1991
2605
|
return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
|
|
1992
2606
|
}
|
|
@@ -2022,10 +2636,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2022
2636
|
drawingBufferHeight;
|
|
2023
2637
|
/** Resolves when the canvas is initialized, i.e. when the ResizeObserver has updated the pixel size */
|
|
2024
2638
|
_initializedResolvers = withResolvers();
|
|
2025
|
-
|
|
2026
|
-
_resizeObserver;
|
|
2027
|
-
/** IntersectionObserver to track canvas visibility changes */
|
|
2028
|
-
_intersectionObserver;
|
|
2639
|
+
_canvasObserver;
|
|
2029
2640
|
/** Position of the canvas in the document, updated by a timer */
|
|
2030
2641
|
_position = [0, 0];
|
|
2031
2642
|
/** Whether this canvas context has been destroyed */
|
|
@@ -2036,7 +2647,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2036
2647
|
return `${this[Symbol.toStringTag]}(${this.id})`;
|
|
2037
2648
|
}
|
|
2038
2649
|
constructor(props) {
|
|
2039
|
-
this.props = { ...
|
|
2650
|
+
this.props = { ..._CanvasSurface.defaultProps, ...props };
|
|
2040
2651
|
props = this.props;
|
|
2041
2652
|
this.initialized = this._initializedResolvers.promise;
|
|
2042
2653
|
if (!isBrowser()) {
|
|
@@ -2048,11 +2659,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2048
2659
|
} else {
|
|
2049
2660
|
this.canvas = props.canvas;
|
|
2050
2661
|
}
|
|
2051
|
-
if (
|
|
2662
|
+
if (_CanvasSurface.isHTMLCanvas(this.canvas)) {
|
|
2052
2663
|
this.id = props.id || this.canvas.id;
|
|
2053
2664
|
this.type = "html-canvas";
|
|
2054
2665
|
this.htmlCanvas = this.canvas;
|
|
2055
|
-
} else if (
|
|
2666
|
+
} else if (_CanvasSurface.isOffscreenCanvas(this.canvas)) {
|
|
2056
2667
|
this.id = props.id || "offscreen-canvas";
|
|
2057
2668
|
this.type = "offscreen-canvas";
|
|
2058
2669
|
this.offscreenCanvas = this.canvas;
|
|
@@ -2068,25 +2679,21 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2068
2679
|
this.drawingBufferHeight = this.canvas.height;
|
|
2069
2680
|
this.devicePixelRatio = globalThis.devicePixelRatio || 1;
|
|
2070
2681
|
this._position = [0, 0];
|
|
2071
|
-
|
|
2072
|
-
this.
|
|
2073
|
-
|
|
2074
|
-
)
|
|
2075
|
-
this.
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
} catch {
|
|
2080
|
-
this._resizeObserver.observe(this.canvas, { box: "content-box" });
|
|
2081
|
-
}
|
|
2082
|
-
setTimeout(() => this._observeDevicePixelRatio(), 0);
|
|
2083
|
-
if (this.props.trackPosition) {
|
|
2084
|
-
this._trackPosition();
|
|
2085
|
-
}
|
|
2086
|
-
}
|
|
2682
|
+
this._canvasObserver = new CanvasObserver({
|
|
2683
|
+
canvas: this.htmlCanvas,
|
|
2684
|
+
trackPosition: this.props.trackPosition,
|
|
2685
|
+
onResize: (entries) => this._handleResize(entries),
|
|
2686
|
+
onIntersection: (entries) => this._handleIntersection(entries),
|
|
2687
|
+
onDevicePixelRatioChange: () => this._observeDevicePixelRatio(),
|
|
2688
|
+
onPositionChange: () => this.updatePosition()
|
|
2689
|
+
});
|
|
2087
2690
|
}
|
|
2088
2691
|
destroy() {
|
|
2089
|
-
this.destroyed
|
|
2692
|
+
if (!this.destroyed) {
|
|
2693
|
+
this.destroyed = true;
|
|
2694
|
+
this._stopObservers();
|
|
2695
|
+
this.device = null;
|
|
2696
|
+
}
|
|
2090
2697
|
}
|
|
2091
2698
|
setProps(props) {
|
|
2092
2699
|
if ("useDevicePixels" in props) {
|
|
@@ -2100,59 +2707,36 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2100
2707
|
this._resizeDrawingBufferIfNeeded();
|
|
2101
2708
|
return this._getCurrentFramebuffer(options);
|
|
2102
2709
|
}
|
|
2103
|
-
// SIZE METHODS
|
|
2104
|
-
/**
|
|
2105
|
-
* Returns the size covered by the canvas in CSS pixels
|
|
2106
|
-
* @note This can be different from the actual device pixel size of a canvas due to DPR scaling, and rounding to integer pixels
|
|
2107
|
-
* @note This is independent of the canvas' internal drawing buffer size (.width, .height).
|
|
2108
|
-
*/
|
|
2109
2710
|
getCSSSize() {
|
|
2110
2711
|
return [this.cssWidth, this.cssHeight];
|
|
2111
2712
|
}
|
|
2112
2713
|
getPosition() {
|
|
2113
2714
|
return this._position;
|
|
2114
2715
|
}
|
|
2115
|
-
/**
|
|
2116
|
-
* Returns the size covered by the canvas in actual device pixels.
|
|
2117
|
-
* @note This can be different from the 'CSS' size of a canvas due to DPR scaling, and rounding to integer pixels
|
|
2118
|
-
* @note This is independent of the canvas' internal drawing buffer size (.width, .height).
|
|
2119
|
-
*/
|
|
2120
2716
|
getDevicePixelSize() {
|
|
2121
2717
|
return [this.devicePixelWidth, this.devicePixelHeight];
|
|
2122
2718
|
}
|
|
2123
|
-
/** Get the drawing buffer size (number of pixels GPU is rendering into, can be different from CSS size) */
|
|
2124
2719
|
getDrawingBufferSize() {
|
|
2125
2720
|
return [this.drawingBufferWidth, this.drawingBufferHeight];
|
|
2126
2721
|
}
|
|
2127
|
-
/** Returns the biggest allowed framebuffer size. @todo Allow the application to limit this? */
|
|
2128
2722
|
getMaxDrawingBufferSize() {
|
|
2129
2723
|
const maxTextureDimension = this.device.limits.maxTextureDimension2D;
|
|
2130
2724
|
return [maxTextureDimension, maxTextureDimension];
|
|
2131
2725
|
}
|
|
2132
|
-
/**
|
|
2133
|
-
* Update the canvas drawing buffer size.
|
|
2134
|
-
* @note - Called automatically if props.autoResize is true.
|
|
2135
|
-
* @note - Defers update of drawing buffer size until framebuffer is requested to avoid flicker
|
|
2136
|
-
* (resizing clears the drawing buffer)!
|
|
2137
|
-
*/
|
|
2138
2726
|
setDrawingBufferSize(width, height) {
|
|
2139
|
-
|
|
2140
|
-
|
|
2727
|
+
width = Math.floor(width);
|
|
2728
|
+
height = Math.floor(height);
|
|
2729
|
+
if (this.drawingBufferWidth === width && this.drawingBufferHeight === height) {
|
|
2730
|
+
return;
|
|
2731
|
+
}
|
|
2732
|
+
this.drawingBufferWidth = width;
|
|
2733
|
+
this.drawingBufferHeight = height;
|
|
2141
2734
|
this._needsDrawingBufferResize = true;
|
|
2142
2735
|
}
|
|
2143
|
-
/**
|
|
2144
|
-
* Returns the current DPR (number of physical pixels per CSS pixel), if props.useDevicePixels is true
|
|
2145
|
-
* @note This can be a fractional (non-integer) number, e.g. when the user zooms in the browser.
|
|
2146
|
-
* @note This function handles the non-HTML canvas cases
|
|
2147
|
-
*/
|
|
2148
2736
|
getDevicePixelRatio() {
|
|
2149
|
-
const
|
|
2150
|
-
return
|
|
2737
|
+
const devicePixelRatio2 = typeof window !== "undefined" && window.devicePixelRatio;
|
|
2738
|
+
return devicePixelRatio2 || 1;
|
|
2151
2739
|
}
|
|
2152
|
-
// DEPRECATED METHODS
|
|
2153
|
-
/**
|
|
2154
|
-
* Maps CSS pixel position to device pixel position
|
|
2155
|
-
*/
|
|
2156
2740
|
cssToDevicePixels(cssPixel, yInvert = true) {
|
|
2157
2741
|
const ratio = this.cssToDeviceRatio();
|
|
2158
2742
|
const [width, height] = this.getDrawingBufferSize();
|
|
@@ -2162,10 +2746,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2162
2746
|
getPixelSize() {
|
|
2163
2747
|
return this.getDevicePixelSize();
|
|
2164
2748
|
}
|
|
2165
|
-
/** @deprecated
|
|
2749
|
+
/** @deprecated Use the current drawing buffer size for projection setup. */
|
|
2166
2750
|
getAspect() {
|
|
2167
|
-
const [width, height] = this.
|
|
2168
|
-
return width / height;
|
|
2751
|
+
const [width, height] = this.getDrawingBufferSize();
|
|
2752
|
+
return width > 0 && height > 0 ? width / height : 1;
|
|
2169
2753
|
}
|
|
2170
2754
|
/** @deprecated Returns multiplier need to convert CSS size to Device size */
|
|
2171
2755
|
cssToDeviceRatio() {
|
|
@@ -2181,18 +2765,40 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2181
2765
|
resize(size) {
|
|
2182
2766
|
this.setDrawingBufferSize(size.width, size.height);
|
|
2183
2767
|
}
|
|
2184
|
-
// IMPLEMENTATION
|
|
2185
|
-
/**
|
|
2186
|
-
* Allows subclass constructor to override the canvas id for auto created canvases.
|
|
2187
|
-
* This can really help when debugging DOM in apps that create multiple devices
|
|
2188
|
-
*/
|
|
2189
2768
|
_setAutoCreatedCanvasId(id) {
|
|
2190
2769
|
if (this.htmlCanvas?.id === "lumagl-auto-created-canvas") {
|
|
2191
2770
|
this.htmlCanvas.id = id;
|
|
2192
2771
|
}
|
|
2193
2772
|
}
|
|
2194
|
-
/**
|
|
2773
|
+
/**
|
|
2774
|
+
* Starts DOM observation after the derived context and its device are fully initialized.
|
|
2775
|
+
*
|
|
2776
|
+
* `CanvasSurface` construction runs before subclasses can assign `this.device`, and the
|
|
2777
|
+
* default WebGL canvas context is created before `WebGLDevice` has initialized `limits`,
|
|
2778
|
+
* `features`, and the rest of its runtime state. Deferring observer startup avoids early
|
|
2779
|
+
* `ResizeObserver` and DPR callbacks running against a partially initialized device.
|
|
2780
|
+
*/
|
|
2781
|
+
_startObservers() {
|
|
2782
|
+
if (this.destroyed) {
|
|
2783
|
+
return;
|
|
2784
|
+
}
|
|
2785
|
+
this._canvasObserver.start();
|
|
2786
|
+
}
|
|
2787
|
+
/**
|
|
2788
|
+
* Stops all DOM observation and timers associated with a canvas surface.
|
|
2789
|
+
*
|
|
2790
|
+
* This pairs with `_startObservers()` so teardown uses the same lifecycle whether a context is
|
|
2791
|
+
* explicitly destroyed, abandoned during device reuse, or temporarily has not started observing
|
|
2792
|
+
* yet. Centralizing shutdown here keeps resize/DPR/position watchers from surviving past the
|
|
2793
|
+
* lifetime of the owning device.
|
|
2794
|
+
*/
|
|
2795
|
+
_stopObservers() {
|
|
2796
|
+
this._canvasObserver.stop();
|
|
2797
|
+
}
|
|
2195
2798
|
_handleIntersection(entries) {
|
|
2799
|
+
if (this.destroyed) {
|
|
2800
|
+
return;
|
|
2801
|
+
}
|
|
2196
2802
|
const entry = entries.find((entry_) => entry_.target === this.canvas);
|
|
2197
2803
|
if (!entry) {
|
|
2198
2804
|
return;
|
|
@@ -2203,33 +2809,34 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2203
2809
|
this.device.props.onVisibilityChange(this);
|
|
2204
2810
|
}
|
|
2205
2811
|
}
|
|
2206
|
-
/**
|
|
2207
|
-
* Reacts to an observed resize by using the most accurate pixel size information the browser can provide
|
|
2208
|
-
* @see https://web.dev/articles/device-pixel-content-box
|
|
2209
|
-
* @see https://webgpufundamentals.org/webgpu/lessons/webgpu-resizing-the-canvas.html
|
|
2210
|
-
*/
|
|
2211
2812
|
_handleResize(entries) {
|
|
2813
|
+
if (this.destroyed) {
|
|
2814
|
+
return;
|
|
2815
|
+
}
|
|
2212
2816
|
const entry = entries.find((entry_) => entry_.target === this.canvas);
|
|
2213
2817
|
if (!entry) {
|
|
2214
2818
|
return;
|
|
2215
2819
|
}
|
|
2216
|
-
|
|
2217
|
-
this.
|
|
2820
|
+
const contentBoxSize = assertDefined(entry.contentBoxSize?.[0]);
|
|
2821
|
+
this.cssWidth = contentBoxSize.inlineSize;
|
|
2822
|
+
this.cssHeight = contentBoxSize.blockSize;
|
|
2218
2823
|
const oldPixelSize = this.getDevicePixelSize();
|
|
2219
|
-
const devicePixelWidth = entry.devicePixelContentBoxSize?.[0]
|
|
2220
|
-
const devicePixelHeight = entry.devicePixelContentBoxSize?.[0]
|
|
2824
|
+
const devicePixelWidth = entry.devicePixelContentBoxSize?.[0]?.inlineSize || contentBoxSize.inlineSize * devicePixelRatio;
|
|
2825
|
+
const devicePixelHeight = entry.devicePixelContentBoxSize?.[0]?.blockSize || contentBoxSize.blockSize * devicePixelRatio;
|
|
2221
2826
|
const [maxDevicePixelWidth, maxDevicePixelHeight] = this.getMaxDrawingBufferSize();
|
|
2222
2827
|
this.devicePixelWidth = Math.max(1, Math.min(devicePixelWidth, maxDevicePixelWidth));
|
|
2223
2828
|
this.devicePixelHeight = Math.max(1, Math.min(devicePixelHeight, maxDevicePixelHeight));
|
|
2224
2829
|
this._updateDrawingBufferSize();
|
|
2225
2830
|
this.device.props.onResize(this, { oldPixelSize });
|
|
2226
2831
|
}
|
|
2227
|
-
/** Initiate a deferred update for the canvas drawing buffer size */
|
|
2228
2832
|
_updateDrawingBufferSize() {
|
|
2229
2833
|
if (this.props.autoResize) {
|
|
2230
2834
|
if (typeof this.props.useDevicePixels === "number") {
|
|
2231
|
-
const
|
|
2232
|
-
this.setDrawingBufferSize(
|
|
2835
|
+
const devicePixelRatio2 = this.props.useDevicePixels;
|
|
2836
|
+
this.setDrawingBufferSize(
|
|
2837
|
+
this.cssWidth * devicePixelRatio2,
|
|
2838
|
+
this.cssHeight * devicePixelRatio2
|
|
2839
|
+
);
|
|
2233
2840
|
} else if (this.props.useDevicePixels) {
|
|
2234
2841
|
this.setDrawingBufferSize(this.devicePixelWidth, this.devicePixelHeight);
|
|
2235
2842
|
} else {
|
|
@@ -2240,7 +2847,6 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2240
2847
|
this.isInitialized = true;
|
|
2241
2848
|
this.updatePosition();
|
|
2242
2849
|
}
|
|
2243
|
-
/** Perform a deferred resize of the drawing buffer if needed */
|
|
2244
2850
|
_resizeDrawingBufferIfNeeded() {
|
|
2245
2851
|
if (this._needsDrawingBufferResize) {
|
|
2246
2852
|
this._needsDrawingBufferResize = false;
|
|
@@ -2252,34 +2858,21 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2252
2858
|
}
|
|
2253
2859
|
}
|
|
2254
2860
|
}
|
|
2255
|
-
/** Monitor DPR changes */
|
|
2256
2861
|
_observeDevicePixelRatio() {
|
|
2862
|
+
if (this.destroyed || !this._canvasObserver.started) {
|
|
2863
|
+
return;
|
|
2864
|
+
}
|
|
2257
2865
|
const oldRatio = this.devicePixelRatio;
|
|
2258
2866
|
this.devicePixelRatio = window.devicePixelRatio;
|
|
2259
2867
|
this.updatePosition();
|
|
2260
|
-
this.device.props.onDevicePixelRatioChange(this, {
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
() => this._observeDevicePixelRatio(),
|
|
2264
|
-
{ once: true }
|
|
2265
|
-
);
|
|
2266
|
-
}
|
|
2267
|
-
/** Start tracking positions with a timer */
|
|
2268
|
-
_trackPosition(intervalMs = 100) {
|
|
2269
|
-
const intervalId = setInterval(() => {
|
|
2270
|
-
if (this.destroyed) {
|
|
2271
|
-
clearInterval(intervalId);
|
|
2272
|
-
} else {
|
|
2273
|
-
this.updatePosition();
|
|
2274
|
-
}
|
|
2275
|
-
}, intervalMs);
|
|
2868
|
+
this.device.props.onDevicePixelRatioChange?.(this, {
|
|
2869
|
+
oldRatio
|
|
2870
|
+
});
|
|
2276
2871
|
}
|
|
2277
|
-
/**
|
|
2278
|
-
* Calculated the absolute position of the canvas
|
|
2279
|
-
* @note - getBoundingClientRect() is normally cheap but can be expensive
|
|
2280
|
-
* if called before browser has finished a reflow. Should not be the case here.
|
|
2281
|
-
*/
|
|
2282
2872
|
updatePosition() {
|
|
2873
|
+
if (this.destroyed) {
|
|
2874
|
+
return;
|
|
2875
|
+
}
|
|
2283
2876
|
const newRect = this.htmlCanvas?.getBoundingClientRect();
|
|
2284
2877
|
if (newRect) {
|
|
2285
2878
|
const position = [newRect.left, newRect.top];
|
|
@@ -2288,13 +2881,15 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2288
2881
|
if (positionChanged) {
|
|
2289
2882
|
const oldPosition = this._position;
|
|
2290
2883
|
this._position = position;
|
|
2291
|
-
this.device.props.onPositionChange?.(this, {
|
|
2884
|
+
this.device.props.onPositionChange?.(this, {
|
|
2885
|
+
oldPosition
|
|
2886
|
+
});
|
|
2292
2887
|
}
|
|
2293
2888
|
}
|
|
2294
2889
|
}
|
|
2295
2890
|
};
|
|
2296
|
-
var
|
|
2297
|
-
__publicField(
|
|
2891
|
+
var CanvasSurface = _CanvasSurface;
|
|
2892
|
+
__publicField(CanvasSurface, "defaultProps", {
|
|
2298
2893
|
id: void 0,
|
|
2299
2894
|
canvas: null,
|
|
2300
2895
|
width: 800,
|
|
@@ -2322,7 +2917,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2322
2917
|
}
|
|
2323
2918
|
function getCanvasFromDOM(canvasId) {
|
|
2324
2919
|
const canvas = document.getElementById(canvasId);
|
|
2325
|
-
if (!
|
|
2920
|
+
if (!CanvasSurface.isHTMLCanvas(canvas)) {
|
|
2326
2921
|
throw new Error("Object is not a canvas element");
|
|
2327
2922
|
}
|
|
2328
2923
|
return canvas;
|
|
@@ -2346,33 +2941,40 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2346
2941
|
const point = pixel;
|
|
2347
2942
|
const x = scaleX(point[0], ratio, width);
|
|
2348
2943
|
let y = scaleY(point[1], ratio, height, yInvert);
|
|
2349
|
-
let
|
|
2350
|
-
const xHigh =
|
|
2351
|
-
|
|
2944
|
+
let temporary = scaleX(point[0] + 1, ratio, width);
|
|
2945
|
+
const xHigh = temporary === width - 1 ? temporary : temporary - 1;
|
|
2946
|
+
temporary = scaleY(point[1] + 1, ratio, height, yInvert);
|
|
2352
2947
|
let yHigh;
|
|
2353
2948
|
if (yInvert) {
|
|
2354
|
-
|
|
2949
|
+
temporary = temporary === 0 ? temporary : temporary + 1;
|
|
2355
2950
|
yHigh = y;
|
|
2356
|
-
y =
|
|
2951
|
+
y = temporary;
|
|
2357
2952
|
} else {
|
|
2358
|
-
yHigh =
|
|
2953
|
+
yHigh = temporary === height - 1 ? temporary : temporary - 1;
|
|
2359
2954
|
}
|
|
2360
2955
|
return {
|
|
2361
2956
|
x,
|
|
2362
2957
|
y,
|
|
2363
|
-
// when ratio < 1, current css pixel and next css pixel may point to same device pixel, set width/height to 1 in those cases.
|
|
2364
2958
|
width: Math.max(xHigh - x + 1, 1),
|
|
2365
2959
|
height: Math.max(yHigh - y + 1, 1)
|
|
2366
2960
|
};
|
|
2367
2961
|
}
|
|
2368
2962
|
function scaleX(x, ratio, width) {
|
|
2369
|
-
|
|
2370
|
-
return r;
|
|
2963
|
+
return Math.min(Math.round(x * ratio), width - 1);
|
|
2371
2964
|
}
|
|
2372
2965
|
function scaleY(y, ratio, height, yInvert) {
|
|
2373
2966
|
return yInvert ? Math.max(0, height - 1 - Math.round(y * ratio)) : Math.min(Math.round(y * ratio), height - 1);
|
|
2374
2967
|
}
|
|
2375
2968
|
|
|
2969
|
+
// ../core/src/adapter/canvas-context.ts
|
|
2970
|
+
var CanvasContext = class extends CanvasSurface {
|
|
2971
|
+
};
|
|
2972
|
+
__publicField(CanvasContext, "defaultProps", CanvasSurface.defaultProps);
|
|
2973
|
+
|
|
2974
|
+
// ../core/src/adapter/presentation-context.ts
|
|
2975
|
+
var PresentationContext = class extends CanvasSurface {
|
|
2976
|
+
};
|
|
2977
|
+
|
|
2376
2978
|
// ../core/src/adapter/resources/sampler.ts
|
|
2377
2979
|
var _Sampler = class extends Resource {
|
|
2378
2980
|
get [Symbol.toStringTag]() {
|
|
@@ -2427,6 +3029,8 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2427
3029
|
depth;
|
|
2428
3030
|
/** mip levels in this texture */
|
|
2429
3031
|
mipLevels;
|
|
3032
|
+
/** sample count */
|
|
3033
|
+
samples;
|
|
2430
3034
|
/** Rows are multiples of this length, padded with extra bytes if needed */
|
|
2431
3035
|
byteAlignment;
|
|
2432
3036
|
/** The ready promise is always resolved. It is provided for type compatibility with DynamicTexture. */
|
|
@@ -2452,6 +3056,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2452
3056
|
this.height = this.props.height;
|
|
2453
3057
|
this.depth = this.props.depth;
|
|
2454
3058
|
this.mipLevels = this.props.mipLevels;
|
|
3059
|
+
this.samples = this.props.samples || 1;
|
|
2455
3060
|
if (this.dimension === "cube") {
|
|
2456
3061
|
this.depth = 6;
|
|
2457
3062
|
}
|
|
@@ -2485,9 +3090,25 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2485
3090
|
setSampler(sampler) {
|
|
2486
3091
|
this.sampler = sampler instanceof Sampler ? sampler : this.device.createSampler(sampler);
|
|
2487
3092
|
}
|
|
3093
|
+
/**
|
|
3094
|
+
* Copy raw image data (bytes) into the texture.
|
|
3095
|
+
*
|
|
3096
|
+
* @note Deprecated compatibility wrapper over {@link writeData}.
|
|
3097
|
+
* @note Uses the same layout defaults and alignment rules as {@link writeData}.
|
|
3098
|
+
* @note Tightly packed CPU uploads can omit `bytesPerRow` and `rowsPerImage`.
|
|
3099
|
+
* @note If the CPU source rows are padded, pass explicit `bytesPerRow` and `rowsPerImage`.
|
|
3100
|
+
* @deprecated Use writeData()
|
|
3101
|
+
*/
|
|
3102
|
+
copyImageData(options) {
|
|
3103
|
+
const { data, depth, ...writeOptions } = options;
|
|
3104
|
+
this.writeData(data, {
|
|
3105
|
+
...writeOptions,
|
|
3106
|
+
depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
|
|
3107
|
+
});
|
|
3108
|
+
}
|
|
2488
3109
|
/**
|
|
2489
3110
|
* Calculates the memory layout of the texture, required when reading and writing data.
|
|
2490
|
-
* @return the
|
|
3111
|
+
* @return the backend-aligned linear layout, in particular bytesPerRow which includes any required padding for buffer copy/read paths
|
|
2491
3112
|
*/
|
|
2492
3113
|
computeMemoryLayout(options_ = {}) {
|
|
2493
3114
|
const options = this._normalizeTextureReadOptions(options_);
|
|
@@ -2506,9 +3127,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2506
3127
|
* @returns A Buffer containing the texture data.
|
|
2507
3128
|
*
|
|
2508
3129
|
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
2509
|
-
* @note The application can call Texture.computeMemoryLayout() to compute the layout.
|
|
3130
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
|
|
2510
3131
|
* @note The application can call Buffer.readAsync()
|
|
2511
3132
|
* @note If not supplied a buffer will be created and the application needs to call Buffer.destroy
|
|
3133
|
+
* @note On WebGPU this corresponds to a texture-to-buffer copy and uses buffer-copy alignment rules.
|
|
3134
|
+
* @note On WebGL, luma.gl emulates the same logical readback behavior.
|
|
2512
3135
|
*/
|
|
2513
3136
|
readBuffer(options, buffer) {
|
|
2514
3137
|
throw new Error("readBuffer not implemented");
|
|
@@ -2524,10 +3147,14 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2524
3147
|
throw new Error("readBuffer not implemented");
|
|
2525
3148
|
}
|
|
2526
3149
|
/**
|
|
2527
|
-
* Writes
|
|
3150
|
+
* Writes a GPU Buffer into a texture.
|
|
2528
3151
|
*
|
|
3152
|
+
* @param buffer - Source GPU buffer.
|
|
3153
|
+
* @param options - Destination subresource, extent, and source layout options.
|
|
2529
3154
|
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
2530
|
-
* @note The application can call Texture.computeMemoryLayout() to compute the layout.
|
|
3155
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
|
|
3156
|
+
* @note On WebGPU this corresponds to a buffer-to-texture copy and uses buffer-copy alignment rules.
|
|
3157
|
+
* @note On WebGL, luma.gl emulates the same destination and layout semantics.
|
|
2531
3158
|
*/
|
|
2532
3159
|
writeBuffer(buffer, options) {
|
|
2533
3160
|
throw new Error("readBuffer not implemented");
|
|
@@ -2535,8 +3162,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2535
3162
|
/**
|
|
2536
3163
|
* Writes an array buffer into a texture.
|
|
2537
3164
|
*
|
|
2538
|
-
* @
|
|
2539
|
-
* @
|
|
3165
|
+
* @param data - Source texel data.
|
|
3166
|
+
* @param options - Destination subresource, extent, and source layout options.
|
|
3167
|
+
* @note If `bytesPerRow` and `rowsPerImage` are omitted, luma.gl computes a tightly packed CPU-memory layout for the requested region.
|
|
3168
|
+
* @note On WebGPU this corresponds to `GPUQueue.writeTexture()` and does not implicitly pad rows to 256 bytes.
|
|
3169
|
+
* @note On WebGL, padded CPU data is supported via the same `bytesPerRow` and `rowsPerImage` options.
|
|
2540
3170
|
*/
|
|
2541
3171
|
writeData(data, options) {
|
|
2542
3172
|
throw new Error("readBuffer not implemented");
|
|
@@ -2599,37 +3229,166 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2599
3229
|
}
|
|
2600
3230
|
}
|
|
2601
3231
|
_normalizeCopyImageDataOptions(options_) {
|
|
2602
|
-
const {
|
|
2603
|
-
const options = {
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
}
|
|
2608
|
-
options.bytesPerRow = options_.bytesPerRow || width * (info.bytesPerPixel || 4);
|
|
2609
|
-
options.rowsPerImage = options_.rowsPerImage || height;
|
|
2610
|
-
return options;
|
|
3232
|
+
const { data, depth, ...writeOptions } = options_;
|
|
3233
|
+
const options = this._normalizeTextureWriteOptions({
|
|
3234
|
+
...writeOptions,
|
|
3235
|
+
depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
|
|
3236
|
+
});
|
|
3237
|
+
return { data, depth: options.depthOrArrayLayers, ...options };
|
|
2611
3238
|
}
|
|
2612
3239
|
_normalizeCopyExternalImageOptions(options_) {
|
|
3240
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3241
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3242
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
2613
3243
|
const size = this.device.getExternalImageSize(options_.image);
|
|
2614
|
-
const options = {
|
|
2615
|
-
|
|
2616
|
-
|
|
3244
|
+
const options = {
|
|
3245
|
+
..._Texture.defaultCopyExternalImageOptions,
|
|
3246
|
+
...mipLevelSize,
|
|
3247
|
+
...size,
|
|
3248
|
+
...optionsWithoutUndefined
|
|
3249
|
+
};
|
|
3250
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3251
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3252
|
+
options.depth = Math.min(options.depth, mipLevelSize.depthOrArrayLayers - options.z);
|
|
2617
3253
|
return options;
|
|
2618
3254
|
}
|
|
2619
3255
|
_normalizeTextureReadOptions(options_) {
|
|
2620
|
-
const
|
|
2621
|
-
const
|
|
2622
|
-
|
|
2623
|
-
options
|
|
3256
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3257
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3258
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
3259
|
+
const options = {
|
|
3260
|
+
..._Texture.defaultTextureReadOptions,
|
|
3261
|
+
...mipLevelSize,
|
|
3262
|
+
...optionsWithoutUndefined
|
|
3263
|
+
};
|
|
3264
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3265
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3266
|
+
options.depthOrArrayLayers = Math.min(
|
|
3267
|
+
options.depthOrArrayLayers,
|
|
3268
|
+
mipLevelSize.depthOrArrayLayers - options.z
|
|
3269
|
+
);
|
|
2624
3270
|
return options;
|
|
2625
3271
|
}
|
|
3272
|
+
/**
|
|
3273
|
+
* Normalizes a texture read request and validates the color-only readback contract used by the
|
|
3274
|
+
* current texture read APIs. Supported dimensions are `2d`, `cube`, `cube-array`,
|
|
3275
|
+
* `2d-array`, and `3d`.
|
|
3276
|
+
*
|
|
3277
|
+
* @throws if the texture format, aspect, or dimension is not supported by the first-pass
|
|
3278
|
+
* color-read implementation.
|
|
3279
|
+
*/
|
|
3280
|
+
_getSupportedColorReadOptions(options_) {
|
|
3281
|
+
const options = this._normalizeTextureReadOptions(options_);
|
|
3282
|
+
const formatInfo = textureFormatDecoder.getInfo(this.format);
|
|
3283
|
+
this._validateColorReadAspect(options);
|
|
3284
|
+
this._validateColorReadFormat(formatInfo);
|
|
3285
|
+
switch (this.dimension) {
|
|
3286
|
+
case "2d":
|
|
3287
|
+
case "cube":
|
|
3288
|
+
case "cube-array":
|
|
3289
|
+
case "2d-array":
|
|
3290
|
+
case "3d":
|
|
3291
|
+
return options;
|
|
3292
|
+
default:
|
|
3293
|
+
throw new Error(`${this} color readback does not support ${this.dimension} textures`);
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
/** Validates that a read request targets the full color aspect of the texture. */
|
|
3297
|
+
_validateColorReadAspect(options) {
|
|
3298
|
+
if (options.aspect !== "all") {
|
|
3299
|
+
throw new Error(`${this} color readback only supports aspect 'all'`);
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
/** Validates that a read request targets an uncompressed color-renderable texture format. */
|
|
3303
|
+
_validateColorReadFormat(formatInfo) {
|
|
3304
|
+
if (formatInfo.compressed) {
|
|
3305
|
+
throw new Error(
|
|
3306
|
+
`${this} color readback does not support compressed formats (${this.format})`
|
|
3307
|
+
);
|
|
3308
|
+
}
|
|
3309
|
+
switch (formatInfo.attachment) {
|
|
3310
|
+
case "color":
|
|
3311
|
+
return;
|
|
3312
|
+
case "depth":
|
|
3313
|
+
throw new Error(`${this} color readback does not support depth formats (${this.format})`);
|
|
3314
|
+
case "stencil":
|
|
3315
|
+
throw new Error(`${this} color readback does not support stencil formats (${this.format})`);
|
|
3316
|
+
case "depth-stencil":
|
|
3317
|
+
throw new Error(
|
|
3318
|
+
`${this} color readback does not support depth-stencil formats (${this.format})`
|
|
3319
|
+
);
|
|
3320
|
+
default:
|
|
3321
|
+
throw new Error(`${this} color readback does not support format ${this.format}`);
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
2626
3324
|
_normalizeTextureWriteOptions(options_) {
|
|
2627
|
-
const
|
|
2628
|
-
const
|
|
2629
|
-
|
|
2630
|
-
options
|
|
3325
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3326
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3327
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
3328
|
+
const options = {
|
|
3329
|
+
..._Texture.defaultTextureWriteOptions,
|
|
3330
|
+
...mipLevelSize,
|
|
3331
|
+
...optionsWithoutUndefined
|
|
3332
|
+
};
|
|
3333
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3334
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3335
|
+
options.depthOrArrayLayers = Math.min(
|
|
3336
|
+
options.depthOrArrayLayers,
|
|
3337
|
+
mipLevelSize.depthOrArrayLayers - options.z
|
|
3338
|
+
);
|
|
3339
|
+
const layout = textureFormatDecoder.computeMemoryLayout({
|
|
3340
|
+
format: this.format,
|
|
3341
|
+
width: options.width,
|
|
3342
|
+
height: options.height,
|
|
3343
|
+
depth: options.depthOrArrayLayers,
|
|
3344
|
+
byteAlignment: this.byteAlignment
|
|
3345
|
+
});
|
|
3346
|
+
const minimumBytesPerRow = layout.bytesPerPixel * options.width;
|
|
3347
|
+
options.bytesPerRow = optionsWithoutUndefined.bytesPerRow ?? layout.bytesPerRow;
|
|
3348
|
+
options.rowsPerImage = optionsWithoutUndefined.rowsPerImage ?? options.height;
|
|
3349
|
+
if (options.bytesPerRow < minimumBytesPerRow) {
|
|
3350
|
+
throw new Error(
|
|
3351
|
+
`bytesPerRow (${options.bytesPerRow}) must be at least ${minimumBytesPerRow} for ${this.format}`
|
|
3352
|
+
);
|
|
3353
|
+
}
|
|
3354
|
+
if (options.rowsPerImage < options.height) {
|
|
3355
|
+
throw new Error(
|
|
3356
|
+
`rowsPerImage (${options.rowsPerImage}) must be at least ${options.height} for ${this.format}`
|
|
3357
|
+
);
|
|
3358
|
+
}
|
|
3359
|
+
const bytesPerPixel = this.device.getTextureFormatInfo(this.format).bytesPerPixel;
|
|
3360
|
+
if (bytesPerPixel && options.bytesPerRow % bytesPerPixel !== 0) {
|
|
3361
|
+
throw new Error(
|
|
3362
|
+
`bytesPerRow (${options.bytesPerRow}) must be a multiple of bytesPerPixel (${bytesPerPixel}) for ${this.format}`
|
|
3363
|
+
);
|
|
3364
|
+
}
|
|
2631
3365
|
return options;
|
|
2632
3366
|
}
|
|
3367
|
+
_getMipLevelSize(mipLevel) {
|
|
3368
|
+
const width = Math.max(1, this.width >> mipLevel);
|
|
3369
|
+
const height = this.baseDimension === "1d" ? 1 : Math.max(1, this.height >> mipLevel);
|
|
3370
|
+
const depthOrArrayLayers = this.dimension === "3d" ? Math.max(1, this.depth >> mipLevel) : this.depth;
|
|
3371
|
+
return { width, height, depthOrArrayLayers };
|
|
3372
|
+
}
|
|
3373
|
+
getAllocatedByteLength() {
|
|
3374
|
+
let allocatedByteLength = 0;
|
|
3375
|
+
for (let mipLevel = 0; mipLevel < this.mipLevels; mipLevel++) {
|
|
3376
|
+
const { width, height, depthOrArrayLayers } = this._getMipLevelSize(mipLevel);
|
|
3377
|
+
allocatedByteLength += textureFormatDecoder.computeMemoryLayout({
|
|
3378
|
+
format: this.format,
|
|
3379
|
+
width,
|
|
3380
|
+
height,
|
|
3381
|
+
depth: depthOrArrayLayers,
|
|
3382
|
+
byteAlignment: 1
|
|
3383
|
+
}).byteLength;
|
|
3384
|
+
}
|
|
3385
|
+
return allocatedByteLength * this.samples;
|
|
3386
|
+
}
|
|
3387
|
+
static _omitUndefined(options) {
|
|
3388
|
+
return Object.fromEntries(
|
|
3389
|
+
Object.entries(options).filter(([, value]) => value !== void 0)
|
|
3390
|
+
);
|
|
3391
|
+
}
|
|
2633
3392
|
};
|
|
2634
3393
|
var Texture = _Texture;
|
|
2635
3394
|
/** The texture can be bound for use as a sampled texture in a shader */
|
|
@@ -2665,6 +3424,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2665
3424
|
byteOffset: 0,
|
|
2666
3425
|
bytesPerRow: void 0,
|
|
2667
3426
|
rowsPerImage: void 0,
|
|
3427
|
+
width: void 0,
|
|
3428
|
+
height: void 0,
|
|
3429
|
+
depthOrArrayLayers: void 0,
|
|
3430
|
+
depth: 1,
|
|
2668
3431
|
mipLevel: 0,
|
|
2669
3432
|
x: 0,
|
|
2670
3433
|
y: 0,
|
|
@@ -2698,6 +3461,19 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2698
3461
|
mipLevel: 0,
|
|
2699
3462
|
aspect: "all"
|
|
2700
3463
|
});
|
|
3464
|
+
__publicField(Texture, "defaultTextureWriteOptions", {
|
|
3465
|
+
byteOffset: 0,
|
|
3466
|
+
bytesPerRow: void 0,
|
|
3467
|
+
rowsPerImage: void 0,
|
|
3468
|
+
x: 0,
|
|
3469
|
+
y: 0,
|
|
3470
|
+
z: 0,
|
|
3471
|
+
width: void 0,
|
|
3472
|
+
height: void 0,
|
|
3473
|
+
depthOrArrayLayers: 1,
|
|
3474
|
+
mipLevel: 0,
|
|
3475
|
+
aspect: "all"
|
|
3476
|
+
});
|
|
2701
3477
|
|
|
2702
3478
|
// ../core/src/adapter/resources/texture-view.ts
|
|
2703
3479
|
var _TextureView = class extends Resource {
|
|
@@ -2744,24 +3520,32 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2744
3520
|
const log2 = shaderLog.slice().sort((a, b) => a.lineNum - b.lineNum);
|
|
2745
3521
|
switch (options?.showSourceCode || "no") {
|
|
2746
3522
|
case "all":
|
|
2747
|
-
let
|
|
3523
|
+
let currentMessageIndex = 0;
|
|
2748
3524
|
for (let lineNum = 1; lineNum <= lines.length; lineNum++) {
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
formattedLog +=
|
|
3525
|
+
const line = lines[lineNum - 1];
|
|
3526
|
+
const currentMessage = log2[currentMessageIndex];
|
|
3527
|
+
if (line && currentMessage) {
|
|
3528
|
+
formattedLog += getNumberedLine(line, lineNum, options);
|
|
3529
|
+
}
|
|
3530
|
+
while (log2.length > currentMessageIndex && currentMessage.lineNum === lineNum) {
|
|
3531
|
+
const message = log2[currentMessageIndex++];
|
|
3532
|
+
if (message) {
|
|
3533
|
+
formattedLog += formatCompilerMessage(message, lines, message.lineNum, {
|
|
3534
|
+
...options,
|
|
3535
|
+
inlineSource: false
|
|
3536
|
+
});
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
}
|
|
3540
|
+
while (log2.length > currentMessageIndex) {
|
|
3541
|
+
const message = log2[currentMessageIndex++];
|
|
3542
|
+
if (message) {
|
|
3543
|
+
formattedLog += formatCompilerMessage(message, [], 0, {
|
|
2753
3544
|
...options,
|
|
2754
3545
|
inlineSource: false
|
|
2755
3546
|
});
|
|
2756
3547
|
}
|
|
2757
3548
|
}
|
|
2758
|
-
while (log2.length > currentMessage) {
|
|
2759
|
-
const message = log2[currentMessage++];
|
|
2760
|
-
formattedLog += formatCompilerMessage(message, [], 0, {
|
|
2761
|
-
...options,
|
|
2762
|
-
inlineSource: false
|
|
2763
|
-
});
|
|
2764
|
-
}
|
|
2765
3549
|
return formattedLog;
|
|
2766
3550
|
case "issues":
|
|
2767
3551
|
case "no":
|
|
@@ -2783,8 +3567,8 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
2783
3567
|
|
|
2784
3568
|
`;
|
|
2785
3569
|
}
|
|
2786
|
-
const color = message.type === "error" ? "red" : "
|
|
2787
|
-
return options?.html ? `<div class='luma-compiler-log
|
|
3570
|
+
const color = message.type === "error" ? "red" : "orange";
|
|
3571
|
+
return options?.html ? `<div class='luma-compiler-log-${message.type}' style="color:${color};"><b> ${message.type.toUpperCase()}: ${message.message}</b></div>` : `${message.type.toUpperCase()}: ${message.message}`;
|
|
2788
3572
|
}
|
|
2789
3573
|
function getNumberedLines(lines, lineNum, options) {
|
|
2790
3574
|
let numberedLines = "";
|
|
@@ -2870,29 +3654,34 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
2870
3654
|
}
|
|
2871
3655
|
const shaderName = shaderId;
|
|
2872
3656
|
const shaderTitle = `${this.stage} shader "${shaderName}"`;
|
|
2873
|
-
|
|
3657
|
+
const htmlLog = formatCompilerLog(messages, this.source, { showSourceCode: "all", html: true });
|
|
2874
3658
|
const translatedSource = this.getTranslatedSource();
|
|
3659
|
+
const container = document.createElement("div");
|
|
3660
|
+
container.innerHTML = `<h1>Compilation error in ${shaderTitle}</h1>
|
|
3661
|
+
<div style="display:flex;position:fixed;top:10px;right:20px;gap:2px;">
|
|
3662
|
+
<button id="copy">Copy source</button><br/>
|
|
3663
|
+
<button id="close">Close</button>
|
|
3664
|
+
</div>
|
|
3665
|
+
<code><pre>${htmlLog}</pre></code>`;
|
|
2875
3666
|
if (translatedSource) {
|
|
2876
|
-
|
|
2877
|
-
}
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
button.
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
const dataURI = `data:text/plain,${encodeURIComponent(this.source)}`;
|
|
2895
|
-
navigator.clipboard.writeText(dataURI);
|
|
3667
|
+
container.innerHTML += `<br /><h1>Translated Source</h1><br /><br /><code><pre>${translatedSource}</pre></code>`;
|
|
3668
|
+
}
|
|
3669
|
+
container.style.top = "0";
|
|
3670
|
+
container.style.left = "0";
|
|
3671
|
+
container.style.background = "white";
|
|
3672
|
+
container.style.position = "fixed";
|
|
3673
|
+
container.style.zIndex = "9999";
|
|
3674
|
+
container.style.maxWidth = "100vw";
|
|
3675
|
+
container.style.maxHeight = "100vh";
|
|
3676
|
+
container.style.overflowY = "auto";
|
|
3677
|
+
document.body.appendChild(container);
|
|
3678
|
+
const error = container.querySelector(".luma-compiler-log-error");
|
|
3679
|
+
error?.scrollIntoView();
|
|
3680
|
+
container.querySelector("button#close").onclick = () => {
|
|
3681
|
+
container.remove();
|
|
3682
|
+
};
|
|
3683
|
+
container.querySelector("button#copy").onclick = () => {
|
|
3684
|
+
navigator.clipboard.writeText(this.source);
|
|
2896
3685
|
};
|
|
2897
3686
|
}
|
|
2898
3687
|
};
|
|
@@ -2912,7 +3701,7 @@ ${htmlLog}
|
|
|
2912
3701
|
function getShaderName(shader, defaultName = "unnamed") {
|
|
2913
3702
|
const SHADER_NAME_REGEXP = /#define[\s*]SHADER_NAME[\s*]([A-Za-z0-9_-]+)[\s*]/;
|
|
2914
3703
|
const match = SHADER_NAME_REGEXP.exec(shader);
|
|
2915
|
-
return match
|
|
3704
|
+
return match?.[1] ?? defaultName;
|
|
2916
3705
|
}
|
|
2917
3706
|
|
|
2918
3707
|
// ../core/src/adapter/resources/framebuffer.ts
|
|
@@ -3018,17 +3807,15 @@ ${htmlLog}
|
|
|
3018
3807
|
* and destroys existing textures if owned
|
|
3019
3808
|
*/
|
|
3020
3809
|
resizeAttachments(width, height) {
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
}
|
|
3031
|
-
}
|
|
3810
|
+
this.colorAttachments.forEach((colorAttachment, i) => {
|
|
3811
|
+
const resizedTexture = colorAttachment.texture.clone({
|
|
3812
|
+
width,
|
|
3813
|
+
height
|
|
3814
|
+
});
|
|
3815
|
+
this.destroyAttachedResource(colorAttachment);
|
|
3816
|
+
this.colorAttachments[i] = resizedTexture.view;
|
|
3817
|
+
this.attachResource(resizedTexture.view);
|
|
3818
|
+
});
|
|
3032
3819
|
if (this.depthStencilAttachment) {
|
|
3033
3820
|
const resizedTexture = this.depthStencilAttachment.texture.clone({
|
|
3034
3821
|
width,
|
|
@@ -3065,10 +3852,21 @@ ${htmlLog}
|
|
|
3065
3852
|
linkStatus = "pending";
|
|
3066
3853
|
/** The hash of the pipeline */
|
|
3067
3854
|
hash = "";
|
|
3855
|
+
/** Optional shared backend implementation */
|
|
3856
|
+
sharedRenderPipeline = null;
|
|
3857
|
+
/** Whether shader or pipeline compilation/linking is still in progress */
|
|
3858
|
+
get isPending() {
|
|
3859
|
+
return this.linkStatus === "pending" || this.vs.compilationStatus === "pending" || this.fs?.compilationStatus === "pending";
|
|
3860
|
+
}
|
|
3861
|
+
/** Whether shader or pipeline compilation/linking has failed */
|
|
3862
|
+
get isErrored() {
|
|
3863
|
+
return this.linkStatus === "error" || this.vs.compilationStatus === "error" || this.fs?.compilationStatus === "error";
|
|
3864
|
+
}
|
|
3068
3865
|
constructor(device, props) {
|
|
3069
3866
|
super(device, props, _RenderPipeline.defaultProps);
|
|
3070
3867
|
this.shaderLayout = this.props.shaderLayout;
|
|
3071
3868
|
this.bufferLayout = this.props.bufferLayout || [];
|
|
3869
|
+
this.sharedRenderPipeline = this.props._sharedRenderPipeline || null;
|
|
3072
3870
|
}
|
|
3073
3871
|
};
|
|
3074
3872
|
var RenderPipeline = _RenderPipeline;
|
|
@@ -3086,10 +3884,30 @@ ${htmlLog}
|
|
|
3086
3884
|
colorAttachmentFormats: void 0,
|
|
3087
3885
|
depthStencilAttachmentFormat: void 0,
|
|
3088
3886
|
parameters: {},
|
|
3089
|
-
|
|
3090
|
-
|
|
3887
|
+
varyings: void 0,
|
|
3888
|
+
bufferMode: void 0,
|
|
3889
|
+
disableWarnings: false,
|
|
3890
|
+
_sharedRenderPipeline: void 0,
|
|
3891
|
+
bindings: void 0
|
|
3091
3892
|
});
|
|
3092
3893
|
|
|
3894
|
+
// ../core/src/adapter/resources/shared-render-pipeline.ts
|
|
3895
|
+
var SharedRenderPipeline = class extends Resource {
|
|
3896
|
+
get [Symbol.toStringTag]() {
|
|
3897
|
+
return "SharedRenderPipeline";
|
|
3898
|
+
}
|
|
3899
|
+
constructor(device, props) {
|
|
3900
|
+
super(device, props, {
|
|
3901
|
+
...Resource.defaultProps,
|
|
3902
|
+
handle: void 0,
|
|
3903
|
+
vs: void 0,
|
|
3904
|
+
fs: void 0,
|
|
3905
|
+
varyings: void 0,
|
|
3906
|
+
bufferMode: void 0
|
|
3907
|
+
});
|
|
3908
|
+
}
|
|
3909
|
+
};
|
|
3910
|
+
|
|
3093
3911
|
// ../core/src/adapter/resources/render-pass.ts
|
|
3094
3912
|
var _RenderPass = class extends Resource {
|
|
3095
3913
|
get [Symbol.toStringTag]() {
|
|
@@ -3172,8 +3990,69 @@ ${htmlLog}
|
|
|
3172
3990
|
get [Symbol.toStringTag]() {
|
|
3173
3991
|
return "CommandEncoder";
|
|
3174
3992
|
}
|
|
3993
|
+
_timeProfilingQuerySet = null;
|
|
3994
|
+
_timeProfilingSlotCount = 0;
|
|
3995
|
+
_gpuTimeMs;
|
|
3175
3996
|
constructor(device, props) {
|
|
3176
3997
|
super(device, props, _CommandEncoder.defaultProps);
|
|
3998
|
+
this._timeProfilingQuerySet = props.timeProfilingQuerySet ?? null;
|
|
3999
|
+
this._timeProfilingSlotCount = 0;
|
|
4000
|
+
this._gpuTimeMs = void 0;
|
|
4001
|
+
}
|
|
4002
|
+
/**
|
|
4003
|
+
* Reads all resolved timestamp pairs on the current profiler query set and caches the sum
|
|
4004
|
+
* as milliseconds on this encoder.
|
|
4005
|
+
*/
|
|
4006
|
+
async resolveTimeProfilingQuerySet() {
|
|
4007
|
+
this._gpuTimeMs = void 0;
|
|
4008
|
+
if (!this._timeProfilingQuerySet) {
|
|
4009
|
+
return;
|
|
4010
|
+
}
|
|
4011
|
+
const pairCount = Math.floor(this._timeProfilingSlotCount / 2);
|
|
4012
|
+
if (pairCount <= 0) {
|
|
4013
|
+
return;
|
|
4014
|
+
}
|
|
4015
|
+
const queryCount = pairCount * 2;
|
|
4016
|
+
const results = await this._timeProfilingQuerySet.readResults({
|
|
4017
|
+
firstQuery: 0,
|
|
4018
|
+
queryCount
|
|
4019
|
+
});
|
|
4020
|
+
let totalDurationNanoseconds = 0n;
|
|
4021
|
+
for (let queryIndex = 0; queryIndex < queryCount; queryIndex += 2) {
|
|
4022
|
+
totalDurationNanoseconds += results[queryIndex + 1] - results[queryIndex];
|
|
4023
|
+
}
|
|
4024
|
+
this._gpuTimeMs = Number(totalDurationNanoseconds) / 1e6;
|
|
4025
|
+
}
|
|
4026
|
+
/** Returns the number of query slots consumed by automatic pass profiling on this encoder. */
|
|
4027
|
+
getTimeProfilingSlotCount() {
|
|
4028
|
+
return this._timeProfilingSlotCount;
|
|
4029
|
+
}
|
|
4030
|
+
getTimeProfilingQuerySet() {
|
|
4031
|
+
return this._timeProfilingQuerySet;
|
|
4032
|
+
}
|
|
4033
|
+
/** Internal helper for auto-assigning timestamp slots to render/compute passes on this encoder. */
|
|
4034
|
+
_applyTimeProfilingToPassProps(props) {
|
|
4035
|
+
const passProps = props || {};
|
|
4036
|
+
if (!this._supportsTimestampQueries() || !this._timeProfilingQuerySet) {
|
|
4037
|
+
return passProps;
|
|
4038
|
+
}
|
|
4039
|
+
if (passProps.timestampQuerySet !== void 0 || passProps.beginTimestampIndex !== void 0 || passProps.endTimestampIndex !== void 0) {
|
|
4040
|
+
return passProps;
|
|
4041
|
+
}
|
|
4042
|
+
const beginTimestampIndex = this._timeProfilingSlotCount;
|
|
4043
|
+
if (beginTimestampIndex + 1 >= this._timeProfilingQuerySet.props.count) {
|
|
4044
|
+
return passProps;
|
|
4045
|
+
}
|
|
4046
|
+
this._timeProfilingSlotCount += 2;
|
|
4047
|
+
return {
|
|
4048
|
+
...passProps,
|
|
4049
|
+
timestampQuerySet: this._timeProfilingQuerySet,
|
|
4050
|
+
beginTimestampIndex,
|
|
4051
|
+
endTimestampIndex: beginTimestampIndex + 1
|
|
4052
|
+
};
|
|
4053
|
+
}
|
|
4054
|
+
_supportsTimestampQueries() {
|
|
4055
|
+
return this.device.features.has("timestamp-query");
|
|
3177
4056
|
}
|
|
3178
4057
|
};
|
|
3179
4058
|
var CommandEncoder = _CommandEncoder;
|
|
@@ -3182,7 +4061,8 @@ ${htmlLog}
|
|
|
3182
4061
|
// beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
|
|
3183
4062
|
__publicField(CommandEncoder, "defaultProps", {
|
|
3184
4063
|
...Resource.defaultProps,
|
|
3185
|
-
measureExecutionTime: void 0
|
|
4064
|
+
measureExecutionTime: void 0,
|
|
4065
|
+
timeProfilingQuerySet: void 0
|
|
3186
4066
|
});
|
|
3187
4067
|
|
|
3188
4068
|
// ../core/src/adapter/resources/command-buffer.ts
|
|
@@ -3201,11 +4081,20 @@ ${htmlLog}
|
|
|
3201
4081
|
|
|
3202
4082
|
// ../core/src/shadertypes/data-types/decode-shader-types.ts
|
|
3203
4083
|
function getVariableShaderTypeInfo(format) {
|
|
3204
|
-
const
|
|
4084
|
+
const resolvedFormat = resolveVariableShaderTypeAlias(format);
|
|
4085
|
+
const decoded = UNIFORM_FORMATS[resolvedFormat];
|
|
4086
|
+
if (!decoded) {
|
|
4087
|
+
throw new Error(`Unsupported variable shader type: ${format}`);
|
|
4088
|
+
}
|
|
3205
4089
|
return decoded;
|
|
3206
4090
|
}
|
|
3207
4091
|
function getAttributeShaderTypeInfo(attributeType) {
|
|
3208
|
-
const
|
|
4092
|
+
const resolvedAttributeType = resolveAttributeShaderTypeAlias(attributeType);
|
|
4093
|
+
const decoded = TYPE_INFO[resolvedAttributeType];
|
|
4094
|
+
if (!decoded) {
|
|
4095
|
+
throw new Error(`Unsupported attribute shader type: ${attributeType}`);
|
|
4096
|
+
}
|
|
4097
|
+
const [primitiveType, components] = decoded;
|
|
3209
4098
|
const integer = primitiveType === "i32" || primitiveType === "u32";
|
|
3210
4099
|
const signed = primitiveType !== "u32";
|
|
3211
4100
|
const byteLength = PRIMITIVE_TYPE_SIZES[primitiveType] * components;
|
|
@@ -3217,6 +4106,12 @@ ${htmlLog}
|
|
|
3217
4106
|
signed
|
|
3218
4107
|
};
|
|
3219
4108
|
}
|
|
4109
|
+
function resolveAttributeShaderTypeAlias(alias) {
|
|
4110
|
+
return WGSL_ATTRIBUTE_TYPE_ALIAS_MAP[alias] || alias;
|
|
4111
|
+
}
|
|
4112
|
+
function resolveVariableShaderTypeAlias(alias) {
|
|
4113
|
+
return WGSL_VARIABLE_TYPE_ALIAS_MAP[alias] || alias;
|
|
4114
|
+
}
|
|
3220
4115
|
var PRIMITIVE_TYPE_SIZES = {
|
|
3221
4116
|
f32: 4,
|
|
3222
4117
|
f16: 2,
|
|
@@ -3541,7 +4436,9 @@ ${htmlLog}
|
|
|
3541
4436
|
|
|
3542
4437
|
// ../core/src/adapter/resources/fence.ts
|
|
3543
4438
|
var _Fence = class extends Resource {
|
|
3544
|
-
[Symbol.toStringTag]
|
|
4439
|
+
get [Symbol.toStringTag]() {
|
|
4440
|
+
return "Fence";
|
|
4441
|
+
}
|
|
3545
4442
|
constructor(device, props = {}) {
|
|
3546
4443
|
super(device, props, _Fence.defaultProps);
|
|
3547
4444
|
}
|
|
@@ -3701,20 +4598,26 @@ ${htmlLog}
|
|
|
3701
4598
|
}
|
|
3702
4599
|
|
|
3703
4600
|
// ../core/src/utils/array-equal.ts
|
|
4601
|
+
var MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH = 128;
|
|
3704
4602
|
function arrayEqual(a, b, limit = 16) {
|
|
3705
|
-
if (a
|
|
3706
|
-
return
|
|
4603
|
+
if (a === b) {
|
|
4604
|
+
return true;
|
|
3707
4605
|
}
|
|
3708
4606
|
const arrayA = a;
|
|
3709
4607
|
const arrayB = b;
|
|
3710
|
-
if (!isNumberArray(arrayA)) {
|
|
4608
|
+
if (!isNumberArray(arrayA) || !isNumberArray(arrayB)) {
|
|
3711
4609
|
return false;
|
|
3712
4610
|
}
|
|
3713
|
-
if (
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
4611
|
+
if (arrayA.length !== arrayB.length) {
|
|
4612
|
+
return false;
|
|
4613
|
+
}
|
|
4614
|
+
const maxCompareLength = Math.min(limit, MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH);
|
|
4615
|
+
if (arrayA.length > maxCompareLength) {
|
|
4616
|
+
return false;
|
|
4617
|
+
}
|
|
4618
|
+
for (let i = 0; i < arrayA.length; ++i) {
|
|
4619
|
+
if (arrayB[i] !== arrayA[i]) {
|
|
4620
|
+
return false;
|
|
3718
4621
|
}
|
|
3719
4622
|
}
|
|
3720
4623
|
return true;
|
|
@@ -3939,7 +4842,7 @@ ${htmlLog}
|
|
|
3939
4842
|
let bitOffsetWithinPixel = 0;
|
|
3940
4843
|
const channels = [];
|
|
3941
4844
|
for (let i = 0; i < 4; i++) {
|
|
3942
|
-
const bits = bitsPerChannel[i];
|
|
4845
|
+
const bits = bitsPerChannel[i] ?? 0;
|
|
3943
4846
|
if (bits <= 0) {
|
|
3944
4847
|
channels.push(0);
|
|
3945
4848
|
} else {
|
|
@@ -3948,14 +4851,14 @@ ${htmlLog}
|
|
|
3948
4851
|
bitOffsetWithinPixel += bits;
|
|
3949
4852
|
}
|
|
3950
4853
|
}
|
|
3951
|
-
return [channels[0], channels[1], channels[2], channels[3]];
|
|
4854
|
+
return [channels[0] ?? 0, channels[1] ?? 0, channels[2] ?? 0, channels[3] ?? 0];
|
|
3952
4855
|
}
|
|
3953
4856
|
function writePixel(dataView, bitOffset, bitsPerChannel, pixel) {
|
|
3954
4857
|
let currentBitOffset = bitOffset;
|
|
3955
4858
|
for (let channel = 0; channel < 4; channel++) {
|
|
3956
|
-
const bits = bitsPerChannel[channel];
|
|
4859
|
+
const bits = bitsPerChannel[channel] ?? 0;
|
|
3957
4860
|
const maxValue = (1 << bits) - 1;
|
|
3958
|
-
const channelValue = pixel[channel] & maxValue;
|
|
4861
|
+
const channelValue = (pixel[channel] ?? 0) & maxValue;
|
|
3959
4862
|
writeBitsToDataView(dataView, currentBitOffset, bits, channelValue);
|
|
3960
4863
|
currentBitOffset += bits;
|
|
3961
4864
|
}
|