@luma.gl/effects 9.2.6 → 9.3.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dist.dev.js +2686 -644
- package/dist/dist.min.js +10 -9
- package/dist/index.cjs +753 -302
- package/dist/index.cjs.map +3 -3
- package/dist/passes/postprocessing/fxaa/fxaa.d.ts +1 -0
- package/dist/passes/postprocessing/fxaa/fxaa.d.ts.map +1 -1
- package/dist/passes/postprocessing/fxaa/fxaa.js +287 -0
- package/dist/passes/postprocessing/fxaa/fxaa.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.d.ts +2 -2
- package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.js +6 -7
- package/dist/passes/postprocessing/image-adjust-filters/brightnesscontrast.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/denoise.d.ts +2 -2
- package/dist/passes/postprocessing/image-adjust-filters/denoise.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/denoise.js +32 -24
- package/dist/passes/postprocessing/image-adjust-filters/denoise.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/huesaturation.d.ts +2 -2
- package/dist/passes/postprocessing/image-adjust-filters/huesaturation.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/huesaturation.js +26 -33
- package/dist/passes/postprocessing/image-adjust-filters/huesaturation.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/noise.d.ts +2 -2
- package/dist/passes/postprocessing/image-adjust-filters/noise.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/noise.js +10 -9
- package/dist/passes/postprocessing/image-adjust-filters/noise.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/sepia.d.ts +2 -2
- package/dist/passes/postprocessing/image-adjust-filters/sepia.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/sepia.js +12 -11
- package/dist/passes/postprocessing/image-adjust-filters/sepia.js.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/vibrance.d.ts +2 -2
- package/dist/passes/postprocessing/image-adjust-filters/vibrance.js +10 -10
- package/dist/passes/postprocessing/image-adjust-filters/vignette.d.ts +2 -2
- package/dist/passes/postprocessing/image-adjust-filters/vignette.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-adjust-filters/vignette.js +11 -15
- package/dist/passes/postprocessing/image-adjust-filters/vignette.js.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/tiltshift.d.ts +3 -3
- package/dist/passes/postprocessing/image-blur-filters/tiltshift.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/tiltshift.js +36 -18
- package/dist/passes/postprocessing/image-blur-filters/tiltshift.js.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/triangleblur.d.ts +3 -3
- package/dist/passes/postprocessing/image-blur-filters/triangleblur.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/triangleblur.js +27 -18
- package/dist/passes/postprocessing/image-blur-filters/triangleblur.js.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/zoomblur.d.ts +3 -3
- package/dist/passes/postprocessing/image-blur-filters/zoomblur.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-blur-filters/zoomblur.js +22 -13
- package/dist/passes/postprocessing/image-blur-filters/zoomblur.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/colorhalftone.d.ts +2 -2
- package/dist/passes/postprocessing/image-fun-filters/colorhalftone.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/colorhalftone.js +20 -18
- package/dist/passes/postprocessing/image-fun-filters/colorhalftone.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/dotscreen.d.ts +2 -2
- package/dist/passes/postprocessing/image-fun-filters/dotscreen.js +12 -12
- package/dist/passes/postprocessing/image-fun-filters/edgework.d.ts +3 -3
- package/dist/passes/postprocessing/image-fun-filters/edgework.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/edgework.js +85 -14
- package/dist/passes/postprocessing/image-fun-filters/edgework.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.d.ts +2 -2
- package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.js +35 -23
- package/dist/passes/postprocessing/image-fun-filters/hexagonalpixelate.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/ink.d.ts +2 -2
- package/dist/passes/postprocessing/image-fun-filters/ink.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/ink.js +26 -17
- package/dist/passes/postprocessing/image-fun-filters/ink.js.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/magnify.d.ts +2 -2
- package/dist/passes/postprocessing/image-fun-filters/magnify.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-fun-filters/magnify.js +23 -13
- package/dist/passes/postprocessing/image-fun-filters/magnify.js.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.d.ts +3 -3
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.js +28 -14
- package/dist/passes/postprocessing/image-warp-filters/bulgepinch.js.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/swirl.d.ts +3 -3
- package/dist/passes/postprocessing/image-warp-filters/swirl.d.ts.map +1 -1
- package/dist/passes/postprocessing/image-warp-filters/swirl.js +21 -16
- 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 +4 -5
- package/src/passes/postprocessing/fxaa/fxaa.ts +288 -0
- package/src/passes/postprocessing/image-adjust-filters/brightnesscontrast.ts +6 -7
- package/src/passes/postprocessing/image-adjust-filters/denoise.ts +34 -26
- package/src/passes/postprocessing/image-adjust-filters/huesaturation.ts +28 -35
- package/src/passes/postprocessing/image-adjust-filters/noise.ts +10 -9
- package/src/passes/postprocessing/image-adjust-filters/sepia.ts +12 -11
- package/src/passes/postprocessing/image-adjust-filters/vibrance.ts +10 -10
- package/src/passes/postprocessing/image-adjust-filters/vignette.ts +11 -15
- package/src/passes/postprocessing/image-blur-filters/tiltshift.ts +38 -20
- package/src/passes/postprocessing/image-blur-filters/triangleblur.ts +27 -18
- package/src/passes/postprocessing/image-blur-filters/zoomblur.ts +23 -14
- package/src/passes/postprocessing/image-fun-filters/colorhalftone.ts +20 -18
- package/src/passes/postprocessing/image-fun-filters/dotscreen.ts +12 -12
- package/src/passes/postprocessing/image-fun-filters/edgework.ts +86 -15
- package/src/passes/postprocessing/image-fun-filters/hexagonalpixelate.ts +39 -27
- package/src/passes/postprocessing/image-fun-filters/ink.ts +26 -17
- package/src/passes/postprocessing/image-fun-filters/magnify.ts +23 -13
- package/src/passes/postprocessing/image-warp-filters/bulgepinch.ts +28 -14
- package/src/passes/postprocessing/image-warp-filters/swirl.ts +21 -16
- package/src/passes/postprocessing/image-warp-filters/warp.ts +9 -4
package/dist/dist.dev.js
CHANGED
|
@@ -64,39 +64,51 @@ var __exports__ = (() => {
|
|
|
64
64
|
DeviceFeatures: () => DeviceFeatures,
|
|
65
65
|
DeviceLimits: () => DeviceLimits,
|
|
66
66
|
ExternalTexture: () => ExternalTexture,
|
|
67
|
+
Fence: () => Fence,
|
|
67
68
|
Framebuffer: () => Framebuffer,
|
|
69
|
+
PipelineFactory: () => PipelineFactory,
|
|
68
70
|
PipelineLayout: () => PipelineLayout,
|
|
71
|
+
PresentationContext: () => PresentationContext,
|
|
69
72
|
QuerySet: () => QuerySet,
|
|
70
73
|
RenderPass: () => RenderPass,
|
|
71
74
|
RenderPipeline: () => RenderPipeline,
|
|
72
75
|
Resource: () => Resource,
|
|
73
76
|
Sampler: () => Sampler,
|
|
74
77
|
Shader: () => Shader,
|
|
78
|
+
ShaderBlockWriter: () => ShaderBlockWriter,
|
|
79
|
+
ShaderFactory: () => ShaderFactory,
|
|
80
|
+
SharedRenderPipeline: () => SharedRenderPipeline,
|
|
75
81
|
Texture: () => Texture,
|
|
76
|
-
TextureFormatDecoder: () => TextureFormatDecoder,
|
|
77
82
|
TextureView: () => TextureView,
|
|
78
83
|
TransformFeedback: () => TransformFeedback,
|
|
79
84
|
UniformBlock: () => UniformBlock,
|
|
80
|
-
UniformBufferLayout: () => UniformBufferLayout,
|
|
81
85
|
UniformStore: () => UniformStore,
|
|
82
86
|
VertexArray: () => VertexArray,
|
|
87
|
+
_getDefaultBindGroupFactory: () => _getDefaultBindGroupFactory,
|
|
83
88
|
_getTextureFormatDefinition: () => getTextureFormatDefinition,
|
|
84
89
|
_getTextureFormatTable: () => getTextureFormatTable,
|
|
90
|
+
assert: () => assert2,
|
|
91
|
+
assertDefined: () => assertDefined,
|
|
92
|
+
dataTypeDecoder: () => dataTypeDecoder,
|
|
93
|
+
flattenBindingsByGroup: () => flattenBindingsByGroup,
|
|
85
94
|
getAttributeInfosFromLayouts: () => getAttributeInfosFromLayouts,
|
|
86
95
|
getAttributeShaderTypeInfo: () => getAttributeShaderTypeInfo,
|
|
87
|
-
|
|
88
|
-
getDataTypeInfo: () => getDataTypeInfo,
|
|
89
|
-
getNormalizedDataType: () => getNormalizedDataType,
|
|
96
|
+
getExternalImageSize: () => getExternalImageSize,
|
|
90
97
|
getScratchArray: () => getScratchArray,
|
|
98
|
+
getShaderLayoutBinding: () => getShaderLayoutBinding,
|
|
99
|
+
getTextureImageView: () => getTextureImageView,
|
|
91
100
|
getTypedArrayConstructor: () => getTypedArrayConstructor,
|
|
92
101
|
getVariableShaderTypeInfo: () => getVariableShaderTypeInfo,
|
|
93
|
-
|
|
94
|
-
getVertexFormatInfo: () => getVertexFormatInfo,
|
|
102
|
+
isExternalImage: () => isExternalImage,
|
|
95
103
|
log: () => log,
|
|
96
104
|
luma: () => luma,
|
|
97
|
-
|
|
105
|
+
makeShaderBlockLayout: () => makeShaderBlockLayout,
|
|
106
|
+
normalizeBindingsByGroup: () => normalizeBindingsByGroup,
|
|
98
107
|
readPixel: () => readPixel,
|
|
108
|
+
setTextureImageData: () => setTextureImageData,
|
|
109
|
+
shaderTypeDecoder: () => shaderTypeDecoder,
|
|
99
110
|
textureFormatDecoder: () => textureFormatDecoder,
|
|
111
|
+
vertexFormatDecoder: () => vertexFormatDecoder,
|
|
100
112
|
writePixel: () => writePixel
|
|
101
113
|
});
|
|
102
114
|
|
|
@@ -294,6 +306,24 @@ var __exports__ = (() => {
|
|
|
294
306
|
};
|
|
295
307
|
|
|
296
308
|
// ../core/src/utils/stats-manager.ts
|
|
309
|
+
var GPU_TIME_AND_MEMORY_STATS = "GPU Time and Memory";
|
|
310
|
+
var GPU_TIME_AND_MEMORY_STAT_ORDER = [
|
|
311
|
+
"Adapter",
|
|
312
|
+
"GPU",
|
|
313
|
+
"GPU Type",
|
|
314
|
+
"GPU Backend",
|
|
315
|
+
"Frame Rate",
|
|
316
|
+
"CPU Time",
|
|
317
|
+
"GPU Time",
|
|
318
|
+
"GPU Memory",
|
|
319
|
+
"Buffer Memory",
|
|
320
|
+
"Texture Memory",
|
|
321
|
+
"Referenced Buffer Memory",
|
|
322
|
+
"Referenced Texture Memory",
|
|
323
|
+
"Swap Chain Texture"
|
|
324
|
+
];
|
|
325
|
+
var ORDERED_STATS_CACHE = /* @__PURE__ */ new WeakMap();
|
|
326
|
+
var ORDERED_STAT_NAME_SET_CACHE = /* @__PURE__ */ new WeakMap();
|
|
297
327
|
var StatsManager = class {
|
|
298
328
|
stats = /* @__PURE__ */ new Map();
|
|
299
329
|
getStats(name2) {
|
|
@@ -303,10 +333,50 @@ var __exports__ = (() => {
|
|
|
303
333
|
if (!this.stats.has(name2)) {
|
|
304
334
|
this.stats.set(name2, new Stats({ id: name2 }));
|
|
305
335
|
}
|
|
306
|
-
|
|
336
|
+
const stats = this.stats.get(name2);
|
|
337
|
+
if (name2 === GPU_TIME_AND_MEMORY_STATS) {
|
|
338
|
+
initializeStats(stats, GPU_TIME_AND_MEMORY_STAT_ORDER);
|
|
339
|
+
}
|
|
340
|
+
return stats;
|
|
307
341
|
}
|
|
308
342
|
};
|
|
309
343
|
var lumaStats = new StatsManager();
|
|
344
|
+
function initializeStats(stats, orderedStatNames) {
|
|
345
|
+
const statsMap = stats.stats;
|
|
346
|
+
let addedOrderedStat = false;
|
|
347
|
+
for (const statName of orderedStatNames) {
|
|
348
|
+
if (!statsMap[statName]) {
|
|
349
|
+
stats.get(statName);
|
|
350
|
+
addedOrderedStat = true;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
const statCount = Object.keys(statsMap).length;
|
|
354
|
+
const cachedStats = ORDERED_STATS_CACHE.get(stats);
|
|
355
|
+
if (!addedOrderedStat && cachedStats?.orderedStatNames === orderedStatNames && cachedStats.statCount === statCount) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const reorderedStats = {};
|
|
359
|
+
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE.get(orderedStatNames);
|
|
360
|
+
if (!orderedStatNamesSet) {
|
|
361
|
+
orderedStatNamesSet = new Set(orderedStatNames);
|
|
362
|
+
ORDERED_STAT_NAME_SET_CACHE.set(orderedStatNames, orderedStatNamesSet);
|
|
363
|
+
}
|
|
364
|
+
for (const statName of orderedStatNames) {
|
|
365
|
+
if (statsMap[statName]) {
|
|
366
|
+
reorderedStats[statName] = statsMap[statName];
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
for (const [statName, stat] of Object.entries(statsMap)) {
|
|
370
|
+
if (!orderedStatNamesSet.has(statName)) {
|
|
371
|
+
reorderedStats[statName] = stat;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
for (const statName of Object.keys(statsMap)) {
|
|
375
|
+
delete statsMap[statName];
|
|
376
|
+
}
|
|
377
|
+
Object.assign(statsMap, reorderedStats);
|
|
378
|
+
ORDERED_STATS_CACHE.set(stats, { orderedStatNames, statCount });
|
|
379
|
+
}
|
|
310
380
|
|
|
311
381
|
// ../../node_modules/@probe.gl/env/dist/lib/globals.js
|
|
312
382
|
var window_ = globalThis;
|
|
@@ -338,7 +408,139 @@ var __exports__ = (() => {
|
|
|
338
408
|
}
|
|
339
409
|
|
|
340
410
|
// ../../node_modules/@probe.gl/env/dist/index.js
|
|
341
|
-
var VERSION = true ? "4.1.
|
|
411
|
+
var VERSION = true ? "4.1.1" : "untranspiled source";
|
|
412
|
+
|
|
413
|
+
// ../../node_modules/@probe.gl/log/dist/utils/assert.js
|
|
414
|
+
function assert(condition, message) {
|
|
415
|
+
if (!condition) {
|
|
416
|
+
throw new Error(message || "Assertion failed");
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// ../../node_modules/@probe.gl/log/dist/loggers/log-utils.js
|
|
421
|
+
function normalizeLogLevel(logLevel) {
|
|
422
|
+
if (!logLevel) {
|
|
423
|
+
return 0;
|
|
424
|
+
}
|
|
425
|
+
let resolvedLevel;
|
|
426
|
+
switch (typeof logLevel) {
|
|
427
|
+
case "number":
|
|
428
|
+
resolvedLevel = logLevel;
|
|
429
|
+
break;
|
|
430
|
+
case "object":
|
|
431
|
+
resolvedLevel = logLevel.logLevel || logLevel.priority || 0;
|
|
432
|
+
break;
|
|
433
|
+
default:
|
|
434
|
+
return 0;
|
|
435
|
+
}
|
|
436
|
+
assert(Number.isFinite(resolvedLevel) && resolvedLevel >= 0);
|
|
437
|
+
return resolvedLevel;
|
|
438
|
+
}
|
|
439
|
+
function normalizeArguments(opts) {
|
|
440
|
+
const { logLevel, message } = opts;
|
|
441
|
+
opts.logLevel = normalizeLogLevel(logLevel);
|
|
442
|
+
const args = opts.args ? Array.from(opts.args) : [];
|
|
443
|
+
while (args.length && args.shift() !== message) {
|
|
444
|
+
}
|
|
445
|
+
switch (typeof logLevel) {
|
|
446
|
+
case "string":
|
|
447
|
+
case "function":
|
|
448
|
+
if (message !== void 0) {
|
|
449
|
+
args.unshift(message);
|
|
450
|
+
}
|
|
451
|
+
opts.message = logLevel;
|
|
452
|
+
break;
|
|
453
|
+
case "object":
|
|
454
|
+
Object.assign(opts, logLevel);
|
|
455
|
+
break;
|
|
456
|
+
default:
|
|
457
|
+
}
|
|
458
|
+
if (typeof opts.message === "function") {
|
|
459
|
+
opts.message = opts.message();
|
|
460
|
+
}
|
|
461
|
+
const messageType = typeof opts.message;
|
|
462
|
+
assert(messageType === "string" || messageType === "object");
|
|
463
|
+
return Object.assign(opts, { args }, opts.opts);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// ../../node_modules/@probe.gl/log/dist/loggers/base-log.js
|
|
467
|
+
var noop = () => {
|
|
468
|
+
};
|
|
469
|
+
var BaseLog = class {
|
|
470
|
+
constructor({ level = 0 } = {}) {
|
|
471
|
+
this.userData = {};
|
|
472
|
+
this._onceCache = /* @__PURE__ */ new Set();
|
|
473
|
+
this._level = level;
|
|
474
|
+
}
|
|
475
|
+
set level(newLevel) {
|
|
476
|
+
this.setLevel(newLevel);
|
|
477
|
+
}
|
|
478
|
+
get level() {
|
|
479
|
+
return this.getLevel();
|
|
480
|
+
}
|
|
481
|
+
setLevel(level) {
|
|
482
|
+
this._level = level;
|
|
483
|
+
return this;
|
|
484
|
+
}
|
|
485
|
+
getLevel() {
|
|
486
|
+
return this._level;
|
|
487
|
+
}
|
|
488
|
+
// Unconditional logging
|
|
489
|
+
warn(message, ...args) {
|
|
490
|
+
return this._log("warn", 0, message, args, { once: true });
|
|
491
|
+
}
|
|
492
|
+
error(message, ...args) {
|
|
493
|
+
return this._log("error", 0, message, args);
|
|
494
|
+
}
|
|
495
|
+
// Conditional logging
|
|
496
|
+
log(logLevel, message, ...args) {
|
|
497
|
+
return this._log("log", logLevel, message, args);
|
|
498
|
+
}
|
|
499
|
+
info(logLevel, message, ...args) {
|
|
500
|
+
return this._log("info", logLevel, message, args);
|
|
501
|
+
}
|
|
502
|
+
once(logLevel, message, ...args) {
|
|
503
|
+
return this._log("once", logLevel, message, args, { once: true });
|
|
504
|
+
}
|
|
505
|
+
_log(type, logLevel, message, args, options = {}) {
|
|
506
|
+
const normalized = normalizeArguments({
|
|
507
|
+
logLevel,
|
|
508
|
+
message,
|
|
509
|
+
args: this._buildArgs(logLevel, message, args),
|
|
510
|
+
opts: options
|
|
511
|
+
});
|
|
512
|
+
return this._createLogFunction(type, normalized, options);
|
|
513
|
+
}
|
|
514
|
+
_buildArgs(logLevel, message, args) {
|
|
515
|
+
return [logLevel, message, ...args];
|
|
516
|
+
}
|
|
517
|
+
_createLogFunction(type, normalized, options) {
|
|
518
|
+
if (!this._shouldLog(normalized.logLevel)) {
|
|
519
|
+
return noop;
|
|
520
|
+
}
|
|
521
|
+
const tag = this._getOnceTag(options.tag ?? normalized.tag ?? normalized.message);
|
|
522
|
+
if ((options.once || normalized.once) && tag !== void 0) {
|
|
523
|
+
if (this._onceCache.has(tag)) {
|
|
524
|
+
return noop;
|
|
525
|
+
}
|
|
526
|
+
this._onceCache.add(tag);
|
|
527
|
+
}
|
|
528
|
+
return this._emit(type, normalized);
|
|
529
|
+
}
|
|
530
|
+
_shouldLog(logLevel) {
|
|
531
|
+
return this.getLevel() >= normalizeLogLevel(logLevel);
|
|
532
|
+
}
|
|
533
|
+
_getOnceTag(tag) {
|
|
534
|
+
if (tag === void 0) {
|
|
535
|
+
return void 0;
|
|
536
|
+
}
|
|
537
|
+
try {
|
|
538
|
+
return typeof tag === "string" ? tag : String(tag);
|
|
539
|
+
} catch {
|
|
540
|
+
return void 0;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
};
|
|
342
544
|
|
|
343
545
|
// ../../node_modules/@probe.gl/log/dist/utils/local-storage.js
|
|
344
546
|
function getStorage(type) {
|
|
@@ -457,13 +659,6 @@ var __exports__ = (() => {
|
|
|
457
659
|
}
|
|
458
660
|
}
|
|
459
661
|
|
|
460
|
-
// ../../node_modules/@probe.gl/log/dist/utils/assert.js
|
|
461
|
-
function assert(condition, message) {
|
|
462
|
-
if (!condition) {
|
|
463
|
-
throw new Error(message || "Assertion failed");
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
|
|
467
662
|
// ../../node_modules/@probe.gl/log/dist/utils/hi-res-timestamp.js
|
|
468
663
|
function getHiResTimestamp2() {
|
|
469
664
|
let timestamp;
|
|
@@ -478,7 +673,7 @@ var __exports__ = (() => {
|
|
|
478
673
|
return timestamp;
|
|
479
674
|
}
|
|
480
675
|
|
|
481
|
-
// ../../node_modules/@probe.gl/log/dist/log.js
|
|
676
|
+
// ../../node_modules/@probe.gl/log/dist/loggers/probe-log.js
|
|
482
677
|
var originalConsole = {
|
|
483
678
|
debug: isBrowser() ? console.debug || console.log : console.log,
|
|
484
679
|
log: console.log,
|
|
@@ -490,12 +685,9 @@ var __exports__ = (() => {
|
|
|
490
685
|
enabled: true,
|
|
491
686
|
level: 0
|
|
492
687
|
};
|
|
493
|
-
|
|
494
|
-
}
|
|
495
|
-
var cache = {};
|
|
496
|
-
var ONCE = { once: true };
|
|
497
|
-
var Log = class {
|
|
688
|
+
var ProbeLog = class extends BaseLog {
|
|
498
689
|
constructor({ id } = { id: "" }) {
|
|
690
|
+
super({ level: 0 });
|
|
499
691
|
this.VERSION = VERSION;
|
|
500
692
|
this._startTs = getHiResTimestamp2();
|
|
501
693
|
this._deltaTs = getHiResTimestamp2();
|
|
@@ -503,22 +695,16 @@ var __exports__ = (() => {
|
|
|
503
695
|
this.LOG_THROTTLE_TIMEOUT = 0;
|
|
504
696
|
this.id = id;
|
|
505
697
|
this.userData = {};
|
|
506
|
-
this._storage = new LocalStorage(`__probe-${this.id}__`, DEFAULT_LOG_CONFIGURATION);
|
|
698
|
+
this._storage = new LocalStorage(`__probe-${this.id}__`, { [this.id]: DEFAULT_LOG_CONFIGURATION });
|
|
507
699
|
this.timeStamp(`${this.id} started`);
|
|
508
700
|
autobind(this);
|
|
509
701
|
Object.seal(this);
|
|
510
702
|
}
|
|
511
|
-
set level(newLevel) {
|
|
512
|
-
this.setLevel(newLevel);
|
|
513
|
-
}
|
|
514
|
-
get level() {
|
|
515
|
-
return this.getLevel();
|
|
516
|
-
}
|
|
517
703
|
isEnabled() {
|
|
518
|
-
return this.
|
|
704
|
+
return this._getConfiguration().enabled;
|
|
519
705
|
}
|
|
520
706
|
getLevel() {
|
|
521
|
-
return this.
|
|
707
|
+
return this._getConfiguration().level;
|
|
522
708
|
}
|
|
523
709
|
/** @return milliseconds, with fractions */
|
|
524
710
|
getTotal() {
|
|
@@ -542,20 +728,20 @@ var __exports__ = (() => {
|
|
|
542
728
|
}
|
|
543
729
|
// Configure
|
|
544
730
|
enable(enabled = true) {
|
|
545
|
-
this.
|
|
731
|
+
this._updateConfiguration({ enabled });
|
|
546
732
|
return this;
|
|
547
733
|
}
|
|
548
734
|
setLevel(level) {
|
|
549
|
-
this.
|
|
735
|
+
this._updateConfiguration({ level });
|
|
550
736
|
return this;
|
|
551
737
|
}
|
|
552
738
|
/** return the current status of the setting */
|
|
553
739
|
get(setting) {
|
|
554
|
-
return this.
|
|
740
|
+
return this._getConfiguration()[setting];
|
|
555
741
|
}
|
|
556
742
|
// update the status of the setting
|
|
557
743
|
set(setting, value) {
|
|
558
|
-
this.
|
|
744
|
+
this._updateConfiguration({ [setting]: value });
|
|
559
745
|
}
|
|
560
746
|
/** Logs the current settings as a table */
|
|
561
747
|
settings() {
|
|
@@ -571,11 +757,16 @@ var __exports__ = (() => {
|
|
|
571
757
|
throw new Error(message || "Assertion failed");
|
|
572
758
|
}
|
|
573
759
|
}
|
|
574
|
-
warn(message) {
|
|
575
|
-
return this.
|
|
760
|
+
warn(message, ...args) {
|
|
761
|
+
return this._log("warn", 0, message, args, {
|
|
762
|
+
method: originalConsole.warn,
|
|
763
|
+
once: true
|
|
764
|
+
});
|
|
576
765
|
}
|
|
577
|
-
error(message) {
|
|
578
|
-
return this.
|
|
766
|
+
error(message, ...args) {
|
|
767
|
+
return this._log("error", 0, message, args, {
|
|
768
|
+
method: originalConsole.error
|
|
769
|
+
});
|
|
579
770
|
}
|
|
580
771
|
/** Print a deprecation warning */
|
|
581
772
|
deprecated(oldUsage, newUsage) {
|
|
@@ -585,50 +776,63 @@ var __exports__ = (() => {
|
|
|
585
776
|
removed(oldUsage, newUsage) {
|
|
586
777
|
return this.error(`\`${oldUsage}\` has been removed. Use \`${newUsage}\` instead`);
|
|
587
778
|
}
|
|
588
|
-
probe(logLevel, message) {
|
|
589
|
-
return this.
|
|
779
|
+
probe(logLevel, message, ...args) {
|
|
780
|
+
return this._log("log", logLevel, message, args, {
|
|
781
|
+
method: originalConsole.log,
|
|
590
782
|
time: true,
|
|
591
783
|
once: true
|
|
592
784
|
});
|
|
593
785
|
}
|
|
594
|
-
log(logLevel, message) {
|
|
595
|
-
return this.
|
|
786
|
+
log(logLevel, message, ...args) {
|
|
787
|
+
return this._log("log", logLevel, message, args, {
|
|
788
|
+
method: originalConsole.debug
|
|
789
|
+
});
|
|
596
790
|
}
|
|
597
|
-
info(logLevel, message) {
|
|
598
|
-
return this.
|
|
791
|
+
info(logLevel, message, ...args) {
|
|
792
|
+
return this._log("info", logLevel, message, args, { method: console.info });
|
|
599
793
|
}
|
|
600
|
-
once(logLevel, message) {
|
|
601
|
-
return this.
|
|
794
|
+
once(logLevel, message, ...args) {
|
|
795
|
+
return this._log("once", logLevel, message, args, {
|
|
796
|
+
method: originalConsole.debug || originalConsole.info,
|
|
797
|
+
once: true
|
|
798
|
+
});
|
|
602
799
|
}
|
|
603
800
|
/** Logs an object as a table */
|
|
604
801
|
table(logLevel, table, columns) {
|
|
605
802
|
if (table) {
|
|
606
|
-
return this.
|
|
803
|
+
return this._log("table", logLevel, table, columns && [columns] || [], {
|
|
804
|
+
method: console.table || noop,
|
|
607
805
|
tag: getTableHeader(table)
|
|
608
806
|
});
|
|
609
807
|
}
|
|
610
808
|
return noop;
|
|
611
809
|
}
|
|
612
810
|
time(logLevel, message) {
|
|
613
|
-
return this.
|
|
811
|
+
return this._log("time", logLevel, message, [], {
|
|
812
|
+
method: console.time ? console.time : console.info
|
|
813
|
+
});
|
|
614
814
|
}
|
|
615
815
|
timeEnd(logLevel, message) {
|
|
616
|
-
return this.
|
|
816
|
+
return this._log("time", logLevel, message, [], {
|
|
817
|
+
method: console.timeEnd ? console.timeEnd : console.info
|
|
818
|
+
});
|
|
617
819
|
}
|
|
618
820
|
timeStamp(logLevel, message) {
|
|
619
|
-
return this.
|
|
821
|
+
return this._log("time", logLevel, message, [], {
|
|
822
|
+
method: console.timeStamp || noop
|
|
823
|
+
});
|
|
620
824
|
}
|
|
621
825
|
group(logLevel, message, opts = { collapsed: false }) {
|
|
622
|
-
const
|
|
623
|
-
|
|
624
|
-
options.method = (collapsed ? console.groupCollapsed : console.group) || console.info;
|
|
625
|
-
return this._getLogFunction(options);
|
|
826
|
+
const method = (opts.collapsed ? console.groupCollapsed : console.group) || console.info;
|
|
827
|
+
return this._log("group", logLevel, message, [], { method });
|
|
626
828
|
}
|
|
627
829
|
groupCollapsed(logLevel, message, opts = {}) {
|
|
628
830
|
return this.group(logLevel, message, Object.assign({}, opts, { collapsed: true }));
|
|
629
831
|
}
|
|
630
832
|
groupEnd(logLevel) {
|
|
631
|
-
return this.
|
|
833
|
+
return this._log("groupEnd", logLevel, "", [], {
|
|
834
|
+
method: console.groupEnd || noop
|
|
835
|
+
});
|
|
632
836
|
}
|
|
633
837
|
// EXPERIMENTAL
|
|
634
838
|
withGroup(logLevel, message, func) {
|
|
@@ -644,78 +848,34 @@ var __exports__ = (() => {
|
|
|
644
848
|
console.trace();
|
|
645
849
|
}
|
|
646
850
|
}
|
|
647
|
-
// PRIVATE METHODS
|
|
648
|
-
/** Deduces log level from a variety of arguments */
|
|
649
851
|
_shouldLog(logLevel) {
|
|
650
|
-
return this.isEnabled() &&
|
|
651
|
-
}
|
|
652
|
-
_getLogFunction(logLevel, message, method, args, opts) {
|
|
653
|
-
if (this._shouldLog(logLevel)) {
|
|
654
|
-
opts = normalizeArguments({ logLevel, message, args, opts });
|
|
655
|
-
method = method || opts.method;
|
|
656
|
-
assert(method);
|
|
657
|
-
opts.total = this.getTotal();
|
|
658
|
-
opts.delta = this.getDelta();
|
|
659
|
-
this._deltaTs = getHiResTimestamp2();
|
|
660
|
-
const tag = opts.tag || opts.message;
|
|
661
|
-
if (opts.once && tag) {
|
|
662
|
-
if (!cache[tag]) {
|
|
663
|
-
cache[tag] = getHiResTimestamp2();
|
|
664
|
-
} else {
|
|
665
|
-
return noop;
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
message = decorateMessage(this.id, opts.message, opts);
|
|
669
|
-
return method.bind(console, message, ...opts.args);
|
|
670
|
-
}
|
|
671
|
-
return noop;
|
|
852
|
+
return this.isEnabled() && super._shouldLog(logLevel);
|
|
672
853
|
}
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
case "number":
|
|
682
|
-
resolvedLevel = logLevel;
|
|
683
|
-
break;
|
|
684
|
-
case "object":
|
|
685
|
-
resolvedLevel = logLevel.logLevel || logLevel.priority || 0;
|
|
686
|
-
break;
|
|
687
|
-
default:
|
|
688
|
-
return 0;
|
|
689
|
-
}
|
|
690
|
-
assert(Number.isFinite(resolvedLevel) && resolvedLevel >= 0);
|
|
691
|
-
return resolvedLevel;
|
|
692
|
-
}
|
|
693
|
-
function normalizeArguments(opts) {
|
|
694
|
-
const { logLevel, message } = opts;
|
|
695
|
-
opts.logLevel = normalizeLogLevel(logLevel);
|
|
696
|
-
const args = opts.args ? Array.from(opts.args) : [];
|
|
697
|
-
while (args.length && args.shift() !== message) {
|
|
854
|
+
_emit(_type, normalized) {
|
|
855
|
+
const method = normalized.method;
|
|
856
|
+
assert(method);
|
|
857
|
+
normalized.total = this.getTotal();
|
|
858
|
+
normalized.delta = this.getDelta();
|
|
859
|
+
this._deltaTs = getHiResTimestamp2();
|
|
860
|
+
const message = decorateMessage(this.id, normalized.message, normalized);
|
|
861
|
+
return method.bind(console, message, ...normalized.args);
|
|
698
862
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
}
|
|
705
|
-
opts.message = logLevel;
|
|
706
|
-
break;
|
|
707
|
-
case "object":
|
|
708
|
-
Object.assign(opts, logLevel);
|
|
709
|
-
break;
|
|
710
|
-
default:
|
|
863
|
+
_getConfiguration() {
|
|
864
|
+
if (!this._storage.config[this.id]) {
|
|
865
|
+
this._updateConfiguration(DEFAULT_LOG_CONFIGURATION);
|
|
866
|
+
}
|
|
867
|
+
return this._storage.config[this.id];
|
|
711
868
|
}
|
|
712
|
-
|
|
713
|
-
|
|
869
|
+
_updateConfiguration(configuration) {
|
|
870
|
+
const currentConfiguration = this._storage.config[this.id] || {
|
|
871
|
+
...DEFAULT_LOG_CONFIGURATION
|
|
872
|
+
};
|
|
873
|
+
this._storage.setConfiguration({
|
|
874
|
+
[this.id]: { ...currentConfiguration, ...configuration }
|
|
875
|
+
});
|
|
714
876
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
return Object.assign(opts, { args }, opts.opts);
|
|
718
|
-
}
|
|
877
|
+
};
|
|
878
|
+
ProbeLog.VERSION = VERSION;
|
|
719
879
|
function decorateMessage(id, message, opts) {
|
|
720
880
|
if (typeof message === "string") {
|
|
721
881
|
const time = opts.time ? leftPad(formatTime(opts.total)) : "";
|
|
@@ -737,10 +897,10 @@ var __exports__ = (() => {
|
|
|
737
897
|
globalThis.probe = {};
|
|
738
898
|
|
|
739
899
|
// ../../node_modules/@probe.gl/log/dist/index.js
|
|
740
|
-
var dist_default = new
|
|
900
|
+
var dist_default = new ProbeLog({ id: "@probe.gl/log" });
|
|
741
901
|
|
|
742
902
|
// ../core/src/utils/log.ts
|
|
743
|
-
var log = new
|
|
903
|
+
var log = new ProbeLog({ id: "luma.gl" });
|
|
744
904
|
|
|
745
905
|
// ../core/src/utils/uid.ts
|
|
746
906
|
var uidCounters = {};
|
|
@@ -751,19 +911,75 @@ var __exports__ = (() => {
|
|
|
751
911
|
}
|
|
752
912
|
|
|
753
913
|
// ../core/src/adapter/resources/resource.ts
|
|
914
|
+
var CPU_HOTSPOT_PROFILER_MODULE = "cpu-hotspot-profiler";
|
|
915
|
+
var RESOURCE_COUNTS_STATS = "GPU Resource Counts";
|
|
916
|
+
var LEGACY_RESOURCE_COUNTS_STATS = "Resource Counts";
|
|
917
|
+
var GPU_TIME_AND_MEMORY_STATS2 = "GPU Time and Memory";
|
|
918
|
+
var BASE_RESOURCE_COUNT_ORDER = [
|
|
919
|
+
"Resources",
|
|
920
|
+
"Buffers",
|
|
921
|
+
"Textures",
|
|
922
|
+
"Samplers",
|
|
923
|
+
"TextureViews",
|
|
924
|
+
"Framebuffers",
|
|
925
|
+
"QuerySets",
|
|
926
|
+
"Shaders",
|
|
927
|
+
"RenderPipelines",
|
|
928
|
+
"ComputePipelines",
|
|
929
|
+
"PipelineLayouts",
|
|
930
|
+
"VertexArrays",
|
|
931
|
+
"RenderPasss",
|
|
932
|
+
"ComputePasss",
|
|
933
|
+
"CommandEncoders",
|
|
934
|
+
"CommandBuffers"
|
|
935
|
+
];
|
|
936
|
+
var WEBGL_RESOURCE_COUNT_ORDER = [
|
|
937
|
+
"Resources",
|
|
938
|
+
"Buffers",
|
|
939
|
+
"Textures",
|
|
940
|
+
"Samplers",
|
|
941
|
+
"TextureViews",
|
|
942
|
+
"Framebuffers",
|
|
943
|
+
"QuerySets",
|
|
944
|
+
"Shaders",
|
|
945
|
+
"RenderPipelines",
|
|
946
|
+
"SharedRenderPipelines",
|
|
947
|
+
"ComputePipelines",
|
|
948
|
+
"PipelineLayouts",
|
|
949
|
+
"VertexArrays",
|
|
950
|
+
"RenderPasss",
|
|
951
|
+
"ComputePasss",
|
|
952
|
+
"CommandEncoders",
|
|
953
|
+
"CommandBuffers"
|
|
954
|
+
];
|
|
955
|
+
var BASE_RESOURCE_COUNT_STAT_ORDER = BASE_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
|
|
956
|
+
`${resourceType} Created`,
|
|
957
|
+
`${resourceType} Active`
|
|
958
|
+
]);
|
|
959
|
+
var WEBGL_RESOURCE_COUNT_STAT_ORDER = WEBGL_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
|
|
960
|
+
`${resourceType} Created`,
|
|
961
|
+
`${resourceType} Active`
|
|
962
|
+
]);
|
|
963
|
+
var ORDERED_STATS_CACHE2 = /* @__PURE__ */ new WeakMap();
|
|
964
|
+
var ORDERED_STAT_NAME_SET_CACHE2 = /* @__PURE__ */ new WeakMap();
|
|
754
965
|
var Resource = class {
|
|
755
966
|
toString() {
|
|
756
967
|
return `${this[Symbol.toStringTag] || this.constructor.name}:"${this.id}"`;
|
|
757
968
|
}
|
|
758
969
|
/** props.id, for debugging. */
|
|
759
970
|
id;
|
|
971
|
+
/** The props that this resource was created with */
|
|
760
972
|
props;
|
|
973
|
+
/** User data object, reserved for the application */
|
|
761
974
|
userData = {};
|
|
975
|
+
/** The device that this resource is associated with - TODO can we remove this dup? */
|
|
762
976
|
_device;
|
|
763
977
|
/** Whether this resource has been destroyed */
|
|
764
978
|
destroyed = false;
|
|
765
979
|
/** For resources that allocate GPU memory */
|
|
766
980
|
allocatedBytes = 0;
|
|
981
|
+
/** Stats bucket currently holding the tracked allocation */
|
|
982
|
+
allocatedBytesName = null;
|
|
767
983
|
/** Attached resources will be destroyed when this resource is destroyed. Tracks auto-created "sub" resources. */
|
|
768
984
|
_attachedResources = /* @__PURE__ */ new Set();
|
|
769
985
|
/**
|
|
@@ -785,6 +1001,9 @@ var __exports__ = (() => {
|
|
|
785
1001
|
* destroy can be called on any resource to release it before it is garbage collected.
|
|
786
1002
|
*/
|
|
787
1003
|
destroy() {
|
|
1004
|
+
if (this.destroyed) {
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
788
1007
|
this.destroyResource();
|
|
789
1008
|
}
|
|
790
1009
|
/** @deprecated Use destroy() */
|
|
@@ -823,7 +1042,7 @@ var __exports__ = (() => {
|
|
|
823
1042
|
}
|
|
824
1043
|
/** Destroy all owned resources. Make sure the resources are no longer needed before calling. */
|
|
825
1044
|
destroyAttachedResources() {
|
|
826
|
-
for (const resource of
|
|
1045
|
+
for (const resource of this._attachedResources) {
|
|
827
1046
|
resource.destroy();
|
|
828
1047
|
}
|
|
829
1048
|
this._attachedResources = /* @__PURE__ */ new Set();
|
|
@@ -831,37 +1050,107 @@ var __exports__ = (() => {
|
|
|
831
1050
|
// PROTECTED METHODS
|
|
832
1051
|
/** Perform all destroy steps. Can be called by derived resources when overriding destroy() */
|
|
833
1052
|
destroyResource() {
|
|
1053
|
+
if (this.destroyed) {
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
834
1056
|
this.destroyAttachedResources();
|
|
835
1057
|
this.removeStats();
|
|
836
1058
|
this.destroyed = true;
|
|
837
1059
|
}
|
|
838
1060
|
/** Called by .destroy() to track object destruction. Subclass must call if overriding destroy() */
|
|
839
1061
|
removeStats() {
|
|
840
|
-
const
|
|
841
|
-
const
|
|
842
|
-
|
|
1062
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1063
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1064
|
+
const statsObjects = [
|
|
1065
|
+
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
|
|
1066
|
+
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
|
|
1067
|
+
];
|
|
1068
|
+
const orderedStatNames = getResourceCountStatOrder(this._device);
|
|
1069
|
+
for (const stats of statsObjects) {
|
|
1070
|
+
initializeStats2(stats, orderedStatNames);
|
|
1071
|
+
}
|
|
1072
|
+
const name2 = this.getStatsName();
|
|
1073
|
+
for (const stats of statsObjects) {
|
|
1074
|
+
stats.get("Resources Active").decrementCount();
|
|
1075
|
+
stats.get(`${name2}s Active`).decrementCount();
|
|
1076
|
+
}
|
|
1077
|
+
if (profiler) {
|
|
1078
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1079
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1080
|
+
}
|
|
843
1081
|
}
|
|
844
1082
|
/** Called by subclass to track memory allocations */
|
|
845
|
-
trackAllocatedMemory(bytes, name2 = this
|
|
846
|
-
const
|
|
1083
|
+
trackAllocatedMemory(bytes, name2 = this.getStatsName()) {
|
|
1084
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1085
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1086
|
+
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
|
|
1087
|
+
if (this.allocatedBytes > 0 && this.allocatedBytesName) {
|
|
1088
|
+
stats.get("GPU Memory").subtractCount(this.allocatedBytes);
|
|
1089
|
+
stats.get(`${this.allocatedBytesName} Memory`).subtractCount(this.allocatedBytes);
|
|
1090
|
+
}
|
|
847
1091
|
stats.get("GPU Memory").addCount(bytes);
|
|
848
1092
|
stats.get(`${name2} Memory`).addCount(bytes);
|
|
1093
|
+
if (profiler) {
|
|
1094
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1095
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1096
|
+
}
|
|
849
1097
|
this.allocatedBytes = bytes;
|
|
1098
|
+
this.allocatedBytesName = name2;
|
|
1099
|
+
}
|
|
1100
|
+
/** Called by subclass to track handle-backed memory allocations separately from owned allocations */
|
|
1101
|
+
trackReferencedMemory(bytes, name2 = this.getStatsName()) {
|
|
1102
|
+
this.trackAllocatedMemory(bytes, `Referenced ${name2}`);
|
|
850
1103
|
}
|
|
851
1104
|
/** Called by subclass to track memory deallocations */
|
|
852
|
-
trackDeallocatedMemory(name2 = this
|
|
853
|
-
|
|
1105
|
+
trackDeallocatedMemory(name2 = this.getStatsName()) {
|
|
1106
|
+
if (this.allocatedBytes === 0) {
|
|
1107
|
+
this.allocatedBytesName = null;
|
|
1108
|
+
return;
|
|
1109
|
+
}
|
|
1110
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1111
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1112
|
+
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
|
|
854
1113
|
stats.get("GPU Memory").subtractCount(this.allocatedBytes);
|
|
855
|
-
stats.get(`${name2} Memory`).subtractCount(this.allocatedBytes);
|
|
1114
|
+
stats.get(`${this.allocatedBytesName || name2} Memory`).subtractCount(this.allocatedBytes);
|
|
1115
|
+
if (profiler) {
|
|
1116
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1117
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1118
|
+
}
|
|
856
1119
|
this.allocatedBytes = 0;
|
|
1120
|
+
this.allocatedBytesName = null;
|
|
1121
|
+
}
|
|
1122
|
+
/** Called by subclass to deallocate handle-backed memory tracked via trackReferencedMemory() */
|
|
1123
|
+
trackDeallocatedReferencedMemory(name2 = this.getStatsName()) {
|
|
1124
|
+
this.trackDeallocatedMemory(`Referenced ${name2}`);
|
|
857
1125
|
}
|
|
858
1126
|
/** Called by resource constructor to track object creation */
|
|
859
1127
|
addStats() {
|
|
860
|
-
const
|
|
861
|
-
const
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
1128
|
+
const name2 = this.getStatsName();
|
|
1129
|
+
const profiler = getCpuHotspotProfiler(this._device);
|
|
1130
|
+
const startTime = profiler ? getTimestamp() : 0;
|
|
1131
|
+
const statsObjects = [
|
|
1132
|
+
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
|
|
1133
|
+
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
|
|
1134
|
+
];
|
|
1135
|
+
const orderedStatNames = getResourceCountStatOrder(this._device);
|
|
1136
|
+
for (const stats of statsObjects) {
|
|
1137
|
+
initializeStats2(stats, orderedStatNames);
|
|
1138
|
+
}
|
|
1139
|
+
for (const stats of statsObjects) {
|
|
1140
|
+
stats.get("Resources Created").incrementCount();
|
|
1141
|
+
stats.get("Resources Active").incrementCount();
|
|
1142
|
+
stats.get(`${name2}s Created`).incrementCount();
|
|
1143
|
+
stats.get(`${name2}s Active`).incrementCount();
|
|
1144
|
+
}
|
|
1145
|
+
if (profiler) {
|
|
1146
|
+
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
|
|
1147
|
+
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
|
|
1148
|
+
}
|
|
1149
|
+
recordTransientCanvasResourceCreate(this._device, name2);
|
|
1150
|
+
}
|
|
1151
|
+
/** Canonical resource name used for stats buckets. */
|
|
1152
|
+
getStatsName() {
|
|
1153
|
+
return getCanonicalResourceName(this);
|
|
865
1154
|
}
|
|
866
1155
|
};
|
|
867
1156
|
/** Default properties for resource */
|
|
@@ -879,6 +1168,96 @@ var __exports__ = (() => {
|
|
|
879
1168
|
}
|
|
880
1169
|
return mergedProps;
|
|
881
1170
|
}
|
|
1171
|
+
function initializeStats2(stats, orderedStatNames) {
|
|
1172
|
+
const statsMap = stats.stats;
|
|
1173
|
+
let addedOrderedStat = false;
|
|
1174
|
+
for (const statName of orderedStatNames) {
|
|
1175
|
+
if (!statsMap[statName]) {
|
|
1176
|
+
stats.get(statName);
|
|
1177
|
+
addedOrderedStat = true;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
const statCount = Object.keys(statsMap).length;
|
|
1181
|
+
const cachedStats = ORDERED_STATS_CACHE2.get(stats);
|
|
1182
|
+
if (!addedOrderedStat && cachedStats?.orderedStatNames === orderedStatNames && cachedStats.statCount === statCount) {
|
|
1183
|
+
return;
|
|
1184
|
+
}
|
|
1185
|
+
const reorderedStats = {};
|
|
1186
|
+
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE2.get(orderedStatNames);
|
|
1187
|
+
if (!orderedStatNamesSet) {
|
|
1188
|
+
orderedStatNamesSet = new Set(orderedStatNames);
|
|
1189
|
+
ORDERED_STAT_NAME_SET_CACHE2.set(orderedStatNames, orderedStatNamesSet);
|
|
1190
|
+
}
|
|
1191
|
+
for (const statName of orderedStatNames) {
|
|
1192
|
+
if (statsMap[statName]) {
|
|
1193
|
+
reorderedStats[statName] = statsMap[statName];
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
for (const [statName, stat] of Object.entries(statsMap)) {
|
|
1197
|
+
if (!orderedStatNamesSet.has(statName)) {
|
|
1198
|
+
reorderedStats[statName] = stat;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
for (const statName of Object.keys(statsMap)) {
|
|
1202
|
+
delete statsMap[statName];
|
|
1203
|
+
}
|
|
1204
|
+
Object.assign(statsMap, reorderedStats);
|
|
1205
|
+
ORDERED_STATS_CACHE2.set(stats, { orderedStatNames, statCount });
|
|
1206
|
+
}
|
|
1207
|
+
function getResourceCountStatOrder(device) {
|
|
1208
|
+
return device.type === "webgl" ? WEBGL_RESOURCE_COUNT_STAT_ORDER : BASE_RESOURCE_COUNT_STAT_ORDER;
|
|
1209
|
+
}
|
|
1210
|
+
function getCpuHotspotProfiler(device) {
|
|
1211
|
+
const profiler = device.userData[CPU_HOTSPOT_PROFILER_MODULE];
|
|
1212
|
+
return profiler?.enabled ? profiler : null;
|
|
1213
|
+
}
|
|
1214
|
+
function getTimestamp() {
|
|
1215
|
+
return globalThis.performance?.now?.() ?? Date.now();
|
|
1216
|
+
}
|
|
1217
|
+
function recordTransientCanvasResourceCreate(device, name2) {
|
|
1218
|
+
const profiler = getCpuHotspotProfiler(device);
|
|
1219
|
+
if (!profiler || !profiler.activeDefaultFramebufferAcquireDepth) {
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1222
|
+
profiler.transientCanvasResourceCreates = (profiler.transientCanvasResourceCreates || 0) + 1;
|
|
1223
|
+
switch (name2) {
|
|
1224
|
+
case "Texture":
|
|
1225
|
+
profiler.transientCanvasTextureCreates = (profiler.transientCanvasTextureCreates || 0) + 1;
|
|
1226
|
+
break;
|
|
1227
|
+
case "TextureView":
|
|
1228
|
+
profiler.transientCanvasTextureViewCreates = (profiler.transientCanvasTextureViewCreates || 0) + 1;
|
|
1229
|
+
break;
|
|
1230
|
+
case "Sampler":
|
|
1231
|
+
profiler.transientCanvasSamplerCreates = (profiler.transientCanvasSamplerCreates || 0) + 1;
|
|
1232
|
+
break;
|
|
1233
|
+
case "Framebuffer":
|
|
1234
|
+
profiler.transientCanvasFramebufferCreates = (profiler.transientCanvasFramebufferCreates || 0) + 1;
|
|
1235
|
+
break;
|
|
1236
|
+
default:
|
|
1237
|
+
break;
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
1240
|
+
function getCanonicalResourceName(resource) {
|
|
1241
|
+
let prototype = Object.getPrototypeOf(resource);
|
|
1242
|
+
while (prototype) {
|
|
1243
|
+
const parentPrototype = Object.getPrototypeOf(prototype);
|
|
1244
|
+
if (!parentPrototype || parentPrototype === Resource.prototype) {
|
|
1245
|
+
return getPrototypeToStringTag(prototype) || resource[Symbol.toStringTag] || resource.constructor.name;
|
|
1246
|
+
}
|
|
1247
|
+
prototype = parentPrototype;
|
|
1248
|
+
}
|
|
1249
|
+
return resource[Symbol.toStringTag] || resource.constructor.name;
|
|
1250
|
+
}
|
|
1251
|
+
function getPrototypeToStringTag(prototype) {
|
|
1252
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, Symbol.toStringTag);
|
|
1253
|
+
if (typeof descriptor?.get === "function") {
|
|
1254
|
+
return descriptor.get.call(prototype);
|
|
1255
|
+
}
|
|
1256
|
+
if (typeof descriptor?.value === "string") {
|
|
1257
|
+
return descriptor.value;
|
|
1258
|
+
}
|
|
1259
|
+
return null;
|
|
1260
|
+
}
|
|
882
1261
|
|
|
883
1262
|
// ../core/src/adapter/resources/buffer.ts
|
|
884
1263
|
var _Buffer = class extends Resource {
|
|
@@ -918,18 +1297,26 @@ var __exports__ = (() => {
|
|
|
918
1297
|
/** A partial CPU-side copy of the data in this buffer, for debugging purposes */
|
|
919
1298
|
debugData = new ArrayBuffer(0);
|
|
920
1299
|
/** This doesn't handle partial non-zero offset updates correctly */
|
|
921
|
-
_setDebugData(data,
|
|
922
|
-
|
|
1300
|
+
_setDebugData(data, _byteOffset, byteLength) {
|
|
1301
|
+
let arrayBufferView = null;
|
|
1302
|
+
let arrayBuffer2;
|
|
1303
|
+
if (ArrayBuffer.isView(data)) {
|
|
1304
|
+
arrayBufferView = data;
|
|
1305
|
+
arrayBuffer2 = data.buffer;
|
|
1306
|
+
} else {
|
|
1307
|
+
arrayBuffer2 = data;
|
|
1308
|
+
}
|
|
923
1309
|
const debugDataLength = Math.min(
|
|
924
1310
|
data ? data.byteLength : byteLength,
|
|
925
1311
|
_Buffer.DEBUG_DATA_MAX_LENGTH
|
|
926
1312
|
);
|
|
927
1313
|
if (arrayBuffer2 === null) {
|
|
928
1314
|
this.debugData = new ArrayBuffer(debugDataLength);
|
|
929
|
-
} else if (byteOffset === 0 && byteLength === arrayBuffer2.byteLength) {
|
|
930
|
-
this.debugData = arrayBuffer2.slice(0, debugDataLength);
|
|
931
1315
|
} else {
|
|
932
|
-
|
|
1316
|
+
const sourceByteOffset = Math.min(arrayBufferView?.byteOffset || 0, arrayBuffer2.byteLength);
|
|
1317
|
+
const availableByteLength = Math.max(0, arrayBuffer2.byteLength - sourceByteOffset);
|
|
1318
|
+
const copyByteLength = Math.min(debugDataLength, availableByteLength);
|
|
1319
|
+
this.debugData = new Uint8Array(arrayBuffer2, sourceByteOffset, copyByteLength).slice().buffer;
|
|
933
1320
|
}
|
|
934
1321
|
}
|
|
935
1322
|
};
|
|
@@ -963,61 +1350,73 @@ var __exports__ = (() => {
|
|
|
963
1350
|
onMapped: void 0
|
|
964
1351
|
});
|
|
965
1352
|
|
|
966
|
-
// ../core/src/shadertypes/data-types/
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
signedType,
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
case "sint8":
|
|
987
|
-
return "snorm8";
|
|
988
|
-
case "uint16":
|
|
989
|
-
return "unorm16";
|
|
990
|
-
case "sint16":
|
|
991
|
-
return "snorm16";
|
|
992
|
-
default:
|
|
993
|
-
return dataType;
|
|
1353
|
+
// ../core/src/shadertypes/data-types/data-type-decoder.ts
|
|
1354
|
+
var DataTypeDecoder = class {
|
|
1355
|
+
/**
|
|
1356
|
+
* Gets info about a data type constant (signed or normalized)
|
|
1357
|
+
* @returns underlying primitive / signed types, byte length, normalization, integer, signed flags
|
|
1358
|
+
*/
|
|
1359
|
+
getDataTypeInfo(type) {
|
|
1360
|
+
const [signedType, primitiveType, byteLength] = NORMALIZED_TYPE_MAP[type];
|
|
1361
|
+
const normalized = type.includes("norm");
|
|
1362
|
+
const integer = !normalized && !type.startsWith("float");
|
|
1363
|
+
const signed = type.startsWith("s");
|
|
1364
|
+
return {
|
|
1365
|
+
signedType,
|
|
1366
|
+
primitiveType,
|
|
1367
|
+
byteLength,
|
|
1368
|
+
normalized,
|
|
1369
|
+
integer,
|
|
1370
|
+
signed
|
|
1371
|
+
// TODO - add webglOnly flag
|
|
1372
|
+
};
|
|
994
1373
|
}
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1374
|
+
/** Build a vertex format from a signed data type and a component */
|
|
1375
|
+
getNormalizedDataType(signedDataType) {
|
|
1376
|
+
const dataType = signedDataType;
|
|
1377
|
+
switch (dataType) {
|
|
1378
|
+
case "uint8":
|
|
1379
|
+
return "unorm8";
|
|
1380
|
+
case "sint8":
|
|
1381
|
+
return "snorm8";
|
|
1382
|
+
case "uint16":
|
|
1383
|
+
return "unorm16";
|
|
1384
|
+
case "sint16":
|
|
1385
|
+
return "snorm16";
|
|
1386
|
+
default:
|
|
1387
|
+
return dataType;
|
|
1388
|
+
}
|
|
1004
1389
|
}
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1390
|
+
/** Align offset to 1, 2 or 4 elements (4, 8 or 16 bytes) */
|
|
1391
|
+
alignTo(size, count) {
|
|
1392
|
+
switch (count) {
|
|
1393
|
+
case 1:
|
|
1394
|
+
return size;
|
|
1395
|
+
case 2:
|
|
1396
|
+
return size + size % 2;
|
|
1397
|
+
default:
|
|
1398
|
+
return size + (4 - size % 4) % 4;
|
|
1399
|
+
}
|
|
1010
1400
|
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1401
|
+
/** Returns the VariableShaderType that corresponds to a typed array */
|
|
1402
|
+
getDataType(arrayOrType) {
|
|
1403
|
+
const Constructor = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType;
|
|
1404
|
+
if (Constructor === Uint8ClampedArray) {
|
|
1405
|
+
return "uint8";
|
|
1406
|
+
}
|
|
1407
|
+
const info = Object.values(NORMALIZED_TYPE_MAP).find((entry) => Constructor === entry[4]);
|
|
1408
|
+
if (!info) {
|
|
1409
|
+
throw new Error(Constructor.name);
|
|
1410
|
+
}
|
|
1411
|
+
return info[0];
|
|
1014
1412
|
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
}
|
|
1413
|
+
/** Returns the TypedArray that corresponds to a shader data type */
|
|
1414
|
+
getTypedArrayConstructor(type) {
|
|
1415
|
+
const [, , , , Constructor] = NORMALIZED_TYPE_MAP[type];
|
|
1416
|
+
return Constructor;
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1419
|
+
var dataTypeDecoder = new DataTypeDecoder();
|
|
1021
1420
|
var NORMALIZED_TYPE_MAP = {
|
|
1022
1421
|
uint8: ["uint8", "u32", 1, false, Uint8Array],
|
|
1023
1422
|
sint8: ["sint8", "i32", 1, false, Int8Array],
|
|
@@ -1033,87 +1432,99 @@ var __exports__ = (() => {
|
|
|
1033
1432
|
sint32: ["sint32", "i32", 4, false, Int32Array]
|
|
1034
1433
|
};
|
|
1035
1434
|
|
|
1036
|
-
// ../core/src/shadertypes/vertex-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
type
|
|
1049
|
-
components
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
case "unorm8":
|
|
1064
|
-
if (components === 1) {
|
|
1065
|
-
return "unorm8";
|
|
1066
|
-
}
|
|
1067
|
-
if (components === 3) {
|
|
1068
|
-
return "unorm8x3-webgl";
|
|
1069
|
-
}
|
|
1070
|
-
return `${dataType}x${components}`;
|
|
1071
|
-
case "snorm8":
|
|
1072
|
-
case "uint8":
|
|
1073
|
-
case "sint8":
|
|
1074
|
-
case "uint16":
|
|
1075
|
-
case "sint16":
|
|
1076
|
-
case "unorm16":
|
|
1077
|
-
case "snorm16":
|
|
1078
|
-
case "float16":
|
|
1079
|
-
if (components === 1 || components === 3) {
|
|
1080
|
-
throw new Error(`size: ${components}`);
|
|
1081
|
-
}
|
|
1082
|
-
return `${dataType}x${components}`;
|
|
1083
|
-
default:
|
|
1084
|
-
return components === 1 ? dataType : `${dataType}x${components}`;
|
|
1435
|
+
// ../core/src/shadertypes/vertex-types/vertex-format-decoder.ts
|
|
1436
|
+
var VertexFormatDecoder = class {
|
|
1437
|
+
/**
|
|
1438
|
+
* Decodes a vertex format, returning type, components, byte length and flags (integer, signed, normalized)
|
|
1439
|
+
*/
|
|
1440
|
+
getVertexFormatInfo(format) {
|
|
1441
|
+
let webglOnly;
|
|
1442
|
+
if (format.endsWith("-webgl")) {
|
|
1443
|
+
format.replace("-webgl", "");
|
|
1444
|
+
webglOnly = true;
|
|
1445
|
+
}
|
|
1446
|
+
const [type_, count] = format.split("x");
|
|
1447
|
+
const type = type_;
|
|
1448
|
+
const components = count ? parseInt(count) : 1;
|
|
1449
|
+
const decodedType = dataTypeDecoder.getDataTypeInfo(type);
|
|
1450
|
+
const result = {
|
|
1451
|
+
type,
|
|
1452
|
+
components,
|
|
1453
|
+
byteLength: decodedType.byteLength * components,
|
|
1454
|
+
integer: decodedType.integer,
|
|
1455
|
+
signed: decodedType.signed,
|
|
1456
|
+
normalized: decodedType.normalized
|
|
1457
|
+
};
|
|
1458
|
+
if (webglOnly) {
|
|
1459
|
+
result.webglOnly = true;
|
|
1460
|
+
}
|
|
1461
|
+
return result;
|
|
1085
1462
|
}
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1463
|
+
/** Build a vertex format from a signed data type and a component */
|
|
1464
|
+
makeVertexFormat(signedDataType, components, normalized) {
|
|
1465
|
+
const dataType = normalized ? dataTypeDecoder.getNormalizedDataType(signedDataType) : signedDataType;
|
|
1466
|
+
switch (dataType) {
|
|
1467
|
+
case "unorm8":
|
|
1468
|
+
if (components === 1) {
|
|
1469
|
+
return "unorm8";
|
|
1470
|
+
}
|
|
1471
|
+
if (components === 3) {
|
|
1472
|
+
return "unorm8x3-webgl";
|
|
1473
|
+
}
|
|
1474
|
+
return `${dataType}x${components}`;
|
|
1475
|
+
case "snorm8":
|
|
1476
|
+
case "uint8":
|
|
1477
|
+
case "sint8":
|
|
1478
|
+
case "uint16":
|
|
1479
|
+
case "sint16":
|
|
1480
|
+
case "unorm16":
|
|
1481
|
+
case "snorm16":
|
|
1482
|
+
case "float16":
|
|
1483
|
+
if (components === 1 || components === 3) {
|
|
1484
|
+
throw new Error(`size: ${components}`);
|
|
1485
|
+
}
|
|
1486
|
+
return `${dataType}x${components}`;
|
|
1487
|
+
default:
|
|
1488
|
+
return components === 1 ? dataType : `${dataType}x${components}`;
|
|
1489
|
+
}
|
|
1090
1490
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
vertexType = "float32";
|
|
1100
|
-
break;
|
|
1101
|
-
case "i32":
|
|
1102
|
-
vertexType = "sint32";
|
|
1103
|
-
break;
|
|
1104
|
-
case "u32":
|
|
1105
|
-
vertexType = "uint32";
|
|
1106
|
-
break;
|
|
1107
|
-
case "f16":
|
|
1108
|
-
return opts.components <= 2 ? "float16x2" : "float16x4";
|
|
1491
|
+
/** Get the vertex format for an attribute with TypedArray and size */
|
|
1492
|
+
getVertexFormatFromAttribute(typedArray, size, normalized) {
|
|
1493
|
+
if (!size || size > 4) {
|
|
1494
|
+
throw new Error(`size ${size}`);
|
|
1495
|
+
}
|
|
1496
|
+
const components = size;
|
|
1497
|
+
const signedDataType = dataTypeDecoder.getDataType(typedArray);
|
|
1498
|
+
return this.makeVertexFormat(signedDataType, components, normalized);
|
|
1109
1499
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1500
|
+
/**
|
|
1501
|
+
* Return a "default" vertex format for a certain shader data type
|
|
1502
|
+
* The simplest vertex format that matches the shader attribute's data type
|
|
1503
|
+
*/
|
|
1504
|
+
getCompatibleVertexFormat(opts) {
|
|
1505
|
+
let vertexType;
|
|
1506
|
+
switch (opts.primitiveType) {
|
|
1507
|
+
case "f32":
|
|
1508
|
+
vertexType = "float32";
|
|
1509
|
+
break;
|
|
1510
|
+
case "i32":
|
|
1511
|
+
vertexType = "sint32";
|
|
1512
|
+
break;
|
|
1513
|
+
case "u32":
|
|
1514
|
+
vertexType = "uint32";
|
|
1515
|
+
break;
|
|
1516
|
+
case "f16":
|
|
1517
|
+
return opts.components <= 2 ? "float16x2" : "float16x4";
|
|
1518
|
+
}
|
|
1519
|
+
if (opts.components === 1) {
|
|
1520
|
+
return vertexType;
|
|
1521
|
+
}
|
|
1522
|
+
return `${vertexType}x${opts.components}`;
|
|
1112
1523
|
}
|
|
1113
|
-
|
|
1114
|
-
|
|
1524
|
+
};
|
|
1525
|
+
var vertexFormatDecoder = new VertexFormatDecoder();
|
|
1115
1526
|
|
|
1116
|
-
// ../core/src/shadertypes/
|
|
1527
|
+
// ../core/src/shadertypes/texture-types/texture-format-table.ts
|
|
1117
1528
|
var texture_compression_bc = "texture-compression-bc";
|
|
1118
1529
|
var texture_compression_astc = "texture-compression-astc";
|
|
1119
1530
|
var texture_compression_etc2 = "texture-compression-etc2";
|
|
@@ -1124,6 +1535,7 @@ var __exports__ = (() => {
|
|
|
1124
1535
|
var float16_renderable = "float16-renderable-webgl";
|
|
1125
1536
|
var rgb9e5ufloat_renderable = "rgb9e5ufloat-renderable-webgl";
|
|
1126
1537
|
var snorm8_renderable = "snorm8-renderable-webgl";
|
|
1538
|
+
var norm16_webgl = "norm16-webgl";
|
|
1127
1539
|
var norm16_renderable = "norm16-renderable-webgl";
|
|
1128
1540
|
var snorm16_renderable = "snorm16-renderable-webgl";
|
|
1129
1541
|
var float32_filterable = "float32-filterable";
|
|
@@ -1157,16 +1569,16 @@ var __exports__ = (() => {
|
|
|
1157
1569
|
"rgba8sint": {},
|
|
1158
1570
|
"bgra8unorm": {},
|
|
1159
1571
|
"bgra8unorm-srgb": {},
|
|
1160
|
-
"r16unorm": { f: norm16_renderable },
|
|
1161
|
-
"rg16unorm": { render: norm16_renderable },
|
|
1162
|
-
"rgb16unorm-webgl": { f:
|
|
1572
|
+
"r16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1573
|
+
"rg16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1574
|
+
"rgb16unorm-webgl": { f: norm16_webgl, render: false },
|
|
1163
1575
|
// rgb not renderable
|
|
1164
|
-
"rgba16unorm": { render: norm16_renderable },
|
|
1165
|
-
"r16snorm": { f: snorm16_renderable },
|
|
1166
|
-
"rg16snorm": { render: snorm16_renderable },
|
|
1167
|
-
"rgb16snorm-webgl": { f:
|
|
1576
|
+
"rgba16unorm": { f: norm16_webgl, render: norm16_renderable },
|
|
1577
|
+
"r16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1578
|
+
"rg16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1579
|
+
"rgb16snorm-webgl": { f: norm16_webgl, render: false },
|
|
1168
1580
|
// rgb not renderable
|
|
1169
|
-
"rgba16snorm": { render: snorm16_renderable },
|
|
1581
|
+
"rgba16snorm": { f: norm16_webgl, render: snorm16_renderable },
|
|
1170
1582
|
"r16uint": {},
|
|
1171
1583
|
"rg16uint": {},
|
|
1172
1584
|
"rgba16uint": {},
|
|
@@ -1269,7 +1681,7 @@ var __exports__ = (() => {
|
|
|
1269
1681
|
// WEBGL_compressed_texture_pvrtc
|
|
1270
1682
|
"pvrtc-rgb4unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1271
1683
|
"pvrtc-rgba4unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1272
|
-
"pvrtc-
|
|
1684
|
+
"pvrtc-rgb2unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1273
1685
|
"pvrtc-rgba2unorm-webgl": { f: texture_compression_pvrtc_webgl },
|
|
1274
1686
|
// WEBGL_compressed_texture_etc1
|
|
1275
1687
|
"etc1-rbg-unorm-webgl": { f: texture_compression_etc1_webgl },
|
|
@@ -1283,7 +1695,10 @@ var __exports__ = (() => {
|
|
|
1283
1695
|
...TEXTURE_FORMAT_COMPRESSED_TABLE
|
|
1284
1696
|
};
|
|
1285
1697
|
|
|
1286
|
-
// ../core/src/shadertypes/
|
|
1698
|
+
// ../core/src/shadertypes/texture-types/texture-format-decoder.ts
|
|
1699
|
+
var RGB_FORMAT_REGEX = /^(r|rg|rgb|rgba|bgra)([0-9]*)([a-z]*)(-srgb)?(-webgl)?$/;
|
|
1700
|
+
var COLOR_FORMAT_PREFIXES = ["rgb", "rgba", "bgra"];
|
|
1701
|
+
var DEPTH_FORMAT_PREFIXES = ["depth", "stencil"];
|
|
1287
1702
|
var COMPRESSED_TEXTURE_FORMAT_PREFIXES = [
|
|
1288
1703
|
"bc1",
|
|
1289
1704
|
"bc2",
|
|
@@ -1299,49 +1714,83 @@ var __exports__ = (() => {
|
|
|
1299
1714
|
"astc",
|
|
1300
1715
|
"pvrtc"
|
|
1301
1716
|
];
|
|
1302
|
-
var RGB_FORMAT_REGEX = /^(r|rg|rgb|rgba|bgra)([0-9]*)([a-z]*)(-srgb)?(-webgl)?$/;
|
|
1303
1717
|
var TextureFormatDecoder = class {
|
|
1304
|
-
/** Returns information about a texture format, e.g. attatchment type, components, byte length and flags (integer, signed, normalized) */
|
|
1305
|
-
getInfo(format) {
|
|
1306
|
-
return getTextureFormatInfo(format);
|
|
1307
|
-
}
|
|
1308
1718
|
/** Checks if a texture format is color */
|
|
1309
1719
|
isColor(format) {
|
|
1310
|
-
return
|
|
1720
|
+
return COLOR_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
|
|
1311
1721
|
}
|
|
1312
1722
|
/** Checks if a texture format is depth or stencil */
|
|
1313
1723
|
isDepthStencil(format) {
|
|
1314
|
-
return
|
|
1724
|
+
return DEPTH_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
|
|
1315
1725
|
}
|
|
1316
1726
|
/** Checks if a texture format is compressed */
|
|
1317
1727
|
isCompressed(format) {
|
|
1318
1728
|
return COMPRESSED_TEXTURE_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
|
|
1319
1729
|
}
|
|
1320
|
-
/**
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1730
|
+
/** Returns information about a texture format, e.g. attachment type, components, byte length and flags (integer, signed, normalized) */
|
|
1731
|
+
getInfo(format) {
|
|
1732
|
+
return getTextureFormatInfo(format);
|
|
1733
|
+
}
|
|
1734
|
+
/** "static" capabilities of a texture format. @note Needs to be adjusted against current device */
|
|
1324
1735
|
getCapabilities(format) {
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
filter: info.filter ?? true,
|
|
1331
|
-
blend: info.blend ?? true,
|
|
1332
|
-
store: info.store ?? true
|
|
1333
|
-
};
|
|
1334
|
-
const formatInfo = getTextureFormatInfo(format);
|
|
1335
|
-
const isDepthStencil = format.startsWith("depth") || format.startsWith("stencil");
|
|
1336
|
-
const isSigned = formatInfo?.signed;
|
|
1337
|
-
const isInteger = formatInfo?.integer;
|
|
1338
|
-
const isWebGLSpecific = formatInfo?.webgl;
|
|
1339
|
-
formatCapabilities.render &&= !isSigned;
|
|
1340
|
-
formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
|
|
1341
|
-
return formatCapabilities;
|
|
1736
|
+
return getTextureFormatCapabilities(format);
|
|
1737
|
+
}
|
|
1738
|
+
/** Computes the memory layout for a texture, in particular including row byte alignment */
|
|
1739
|
+
computeMemoryLayout(opts) {
|
|
1740
|
+
return computeTextureMemoryLayout(opts);
|
|
1342
1741
|
}
|
|
1343
1742
|
};
|
|
1344
1743
|
var textureFormatDecoder = new TextureFormatDecoder();
|
|
1744
|
+
function computeTextureMemoryLayout({
|
|
1745
|
+
format,
|
|
1746
|
+
width,
|
|
1747
|
+
height,
|
|
1748
|
+
depth,
|
|
1749
|
+
byteAlignment
|
|
1750
|
+
}) {
|
|
1751
|
+
const formatInfo = textureFormatDecoder.getInfo(format);
|
|
1752
|
+
const {
|
|
1753
|
+
bytesPerPixel,
|
|
1754
|
+
bytesPerBlock = bytesPerPixel,
|
|
1755
|
+
blockWidth = 1,
|
|
1756
|
+
blockHeight = 1,
|
|
1757
|
+
compressed = false
|
|
1758
|
+
} = formatInfo;
|
|
1759
|
+
const blockColumns = compressed ? Math.ceil(width / blockWidth) : width;
|
|
1760
|
+
const blockRows = compressed ? Math.ceil(height / blockHeight) : height;
|
|
1761
|
+
const unpaddedBytesPerRow = blockColumns * bytesPerBlock;
|
|
1762
|
+
const bytesPerRow = Math.ceil(unpaddedBytesPerRow / byteAlignment) * byteAlignment;
|
|
1763
|
+
const rowsPerImage = blockRows;
|
|
1764
|
+
const byteLength = bytesPerRow * rowsPerImage * depth;
|
|
1765
|
+
return {
|
|
1766
|
+
bytesPerPixel,
|
|
1767
|
+
bytesPerRow,
|
|
1768
|
+
rowsPerImage,
|
|
1769
|
+
depthOrArrayLayers: depth,
|
|
1770
|
+
bytesPerImage: bytesPerRow * rowsPerImage,
|
|
1771
|
+
byteLength
|
|
1772
|
+
};
|
|
1773
|
+
}
|
|
1774
|
+
function getTextureFormatCapabilities(format) {
|
|
1775
|
+
const info = getTextureFormatDefinition(format);
|
|
1776
|
+
const formatCapabilities = {
|
|
1777
|
+
format,
|
|
1778
|
+
create: info.f ?? true,
|
|
1779
|
+
render: info.render ?? true,
|
|
1780
|
+
filter: info.filter ?? true,
|
|
1781
|
+
blend: info.blend ?? true,
|
|
1782
|
+
store: info.store ?? true
|
|
1783
|
+
};
|
|
1784
|
+
const formatInfo = getTextureFormatInfo(format);
|
|
1785
|
+
const isDepthStencil = format.startsWith("depth") || format.startsWith("stencil");
|
|
1786
|
+
const isSigned = formatInfo?.signed;
|
|
1787
|
+
const isInteger = formatInfo?.integer;
|
|
1788
|
+
const isWebGLSpecific = formatInfo?.webgl;
|
|
1789
|
+
const isCompressed = Boolean(formatInfo?.compressed);
|
|
1790
|
+
formatCapabilities.render &&= !isDepthStencil && !isCompressed;
|
|
1791
|
+
formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
|
|
1792
|
+
return formatCapabilities;
|
|
1793
|
+
}
|
|
1345
1794
|
function getTextureFormatInfo(format) {
|
|
1346
1795
|
let formatInfo = getTextureFormatInfoUsingTable(format);
|
|
1347
1796
|
if (textureFormatDecoder.isCompressed(format)) {
|
|
@@ -1350,19 +1799,20 @@ var __exports__ = (() => {
|
|
|
1350
1799
|
formatInfo.bytesPerPixel = 1;
|
|
1351
1800
|
formatInfo.srgb = false;
|
|
1352
1801
|
formatInfo.compressed = true;
|
|
1802
|
+
formatInfo.bytesPerBlock = getCompressedTextureBlockByteLength(format);
|
|
1353
1803
|
const blockSize = getCompressedTextureBlockSize(format);
|
|
1354
1804
|
if (blockSize) {
|
|
1355
1805
|
formatInfo.blockWidth = blockSize.blockWidth;
|
|
1356
1806
|
formatInfo.blockHeight = blockSize.blockHeight;
|
|
1357
1807
|
}
|
|
1358
1808
|
}
|
|
1359
|
-
const matches = RGB_FORMAT_REGEX.exec(format);
|
|
1809
|
+
const matches = !formatInfo.packed ? RGB_FORMAT_REGEX.exec(format) : null;
|
|
1360
1810
|
if (matches) {
|
|
1361
1811
|
const [, channels, length, type, srgb, suffix] = matches;
|
|
1362
1812
|
const dataType = `${type}${length}`;
|
|
1363
|
-
const decodedType = getDataTypeInfo(dataType);
|
|
1813
|
+
const decodedType = dataTypeDecoder.getDataTypeInfo(dataType);
|
|
1364
1814
|
const bits = decodedType.byteLength * 8;
|
|
1365
|
-
const components = channels
|
|
1815
|
+
const components = channels?.length ?? 1;
|
|
1366
1816
|
const bitsPerChannel = [
|
|
1367
1817
|
bits,
|
|
1368
1818
|
components >= 2 ? bits : 0,
|
|
@@ -1379,7 +1829,7 @@ var __exports__ = (() => {
|
|
|
1379
1829
|
signed: decodedType.signed,
|
|
1380
1830
|
normalized: decodedType.normalized,
|
|
1381
1831
|
bitsPerChannel,
|
|
1382
|
-
bytesPerPixel: decodedType.byteLength *
|
|
1832
|
+
bytesPerPixel: decodedType.byteLength * components,
|
|
1383
1833
|
packed: formatInfo.packed,
|
|
1384
1834
|
srgb: formatInfo.srgb
|
|
1385
1835
|
};
|
|
@@ -1435,10 +1885,31 @@ var __exports__ = (() => {
|
|
|
1435
1885
|
const [, blockWidth, blockHeight] = matches;
|
|
1436
1886
|
return { blockWidth: Number(blockWidth), blockHeight: Number(blockHeight) };
|
|
1437
1887
|
}
|
|
1888
|
+
if (format.startsWith("bc") || format.startsWith("etc1") || format.startsWith("etc2") || format.startsWith("eac") || format.startsWith("atc")) {
|
|
1889
|
+
return { blockWidth: 4, blockHeight: 4 };
|
|
1890
|
+
}
|
|
1891
|
+
if (format.startsWith("pvrtc-rgb4") || format.startsWith("pvrtc-rgba4")) {
|
|
1892
|
+
return { blockWidth: 4, blockHeight: 4 };
|
|
1893
|
+
}
|
|
1894
|
+
if (format.startsWith("pvrtc-rgb2") || format.startsWith("pvrtc-rgba2")) {
|
|
1895
|
+
return { blockWidth: 8, blockHeight: 4 };
|
|
1896
|
+
}
|
|
1438
1897
|
return null;
|
|
1439
1898
|
}
|
|
1899
|
+
function getCompressedTextureBlockByteLength(format) {
|
|
1900
|
+
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") {
|
|
1901
|
+
return 8;
|
|
1902
|
+
}
|
|
1903
|
+
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") {
|
|
1904
|
+
return 16;
|
|
1905
|
+
}
|
|
1906
|
+
if (format.startsWith("pvrtc")) {
|
|
1907
|
+
return 8;
|
|
1908
|
+
}
|
|
1909
|
+
return 16;
|
|
1910
|
+
}
|
|
1440
1911
|
|
|
1441
|
-
// ../core/src/image-
|
|
1912
|
+
// ../core/src/shadertypes/image-types/image-types.ts
|
|
1442
1913
|
function isExternalImage(data) {
|
|
1443
1914
|
return typeof ImageData !== "undefined" && data instanceof ImageData || typeof ImageBitmap !== "undefined" && data instanceof ImageBitmap || typeof HTMLImageElement !== "undefined" && data instanceof HTMLImageElement || typeof HTMLVideoElement !== "undefined" && data instanceof HTMLVideoElement || typeof VideoFrame !== "undefined" && data instanceof VideoFrame || typeof HTMLCanvasElement !== "undefined" && data instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && data instanceof OffscreenCanvas;
|
|
1444
1915
|
}
|
|
@@ -1461,6 +1932,52 @@ var __exports__ = (() => {
|
|
|
1461
1932
|
// ../core/src/adapter/device.ts
|
|
1462
1933
|
var DeviceLimits = class {
|
|
1463
1934
|
};
|
|
1935
|
+
function formatErrorLogArguments(context, args) {
|
|
1936
|
+
const formattedContext = formatErrorLogValue(context);
|
|
1937
|
+
const formattedArgs = args.map(formatErrorLogValue).filter((arg) => arg !== void 0);
|
|
1938
|
+
return [formattedContext, ...formattedArgs].filter((arg) => arg !== void 0);
|
|
1939
|
+
}
|
|
1940
|
+
function formatErrorLogValue(value) {
|
|
1941
|
+
if (value === void 0) {
|
|
1942
|
+
return void 0;
|
|
1943
|
+
}
|
|
1944
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
1945
|
+
return value;
|
|
1946
|
+
}
|
|
1947
|
+
if (value instanceof Error) {
|
|
1948
|
+
return value.message;
|
|
1949
|
+
}
|
|
1950
|
+
if (Array.isArray(value)) {
|
|
1951
|
+
return value.map(formatErrorLogValue);
|
|
1952
|
+
}
|
|
1953
|
+
if (typeof value === "object") {
|
|
1954
|
+
if (hasCustomToString(value)) {
|
|
1955
|
+
const stringValue = String(value);
|
|
1956
|
+
if (stringValue !== "[object Object]") {
|
|
1957
|
+
return stringValue;
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
if (looksLikeGPUCompilationMessage(value)) {
|
|
1961
|
+
return formatGPUCompilationMessage(value);
|
|
1962
|
+
}
|
|
1963
|
+
return value.constructor?.name || "Object";
|
|
1964
|
+
}
|
|
1965
|
+
return String(value);
|
|
1966
|
+
}
|
|
1967
|
+
function hasCustomToString(value) {
|
|
1968
|
+
return "toString" in value && typeof value.toString === "function" && value.toString !== Object.prototype.toString;
|
|
1969
|
+
}
|
|
1970
|
+
function looksLikeGPUCompilationMessage(value) {
|
|
1971
|
+
return "message" in value && "type" in value;
|
|
1972
|
+
}
|
|
1973
|
+
function formatGPUCompilationMessage(value) {
|
|
1974
|
+
const type = typeof value.type === "string" ? value.type : "message";
|
|
1975
|
+
const message = typeof value.message === "string" ? value.message : "";
|
|
1976
|
+
const lineNum = typeof value.lineNum === "number" ? value.lineNum : null;
|
|
1977
|
+
const linePos = typeof value.linePos === "number" ? value.linePos : null;
|
|
1978
|
+
const location = lineNum !== null && linePos !== null ? ` @ ${lineNum}:${linePos}` : lineNum !== null ? ` @ ${lineNum}` : "";
|
|
1979
|
+
return `${type}${location}: ${message}`.trim();
|
|
1980
|
+
}
|
|
1464
1981
|
var DeviceFeatures = class {
|
|
1465
1982
|
features;
|
|
1466
1983
|
disabledFeatures;
|
|
@@ -1490,19 +2007,24 @@ var __exports__ = (() => {
|
|
|
1490
2007
|
userData = {};
|
|
1491
2008
|
/** stats */
|
|
1492
2009
|
statsManager = lumaStats;
|
|
2010
|
+
/** Internal per-device factory storage */
|
|
2011
|
+
_factories = {};
|
|
1493
2012
|
/** An abstract timestamp used for change tracking */
|
|
1494
2013
|
timestamp = 0;
|
|
1495
2014
|
/** True if this device has been reused during device creation (app has multiple references) */
|
|
1496
2015
|
_reused = false;
|
|
1497
2016
|
/** Used by other luma.gl modules to store data on the device */
|
|
1498
|
-
|
|
2017
|
+
_moduleData = {};
|
|
1499
2018
|
_textureCaps = {};
|
|
2019
|
+
/** Internal timestamp query set used when GPU timing collection is enabled for this device. */
|
|
2020
|
+
_debugGPUTimeQuery = null;
|
|
1500
2021
|
constructor(props) {
|
|
1501
2022
|
this.props = { ..._Device.defaultProps, ...props };
|
|
1502
2023
|
this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase());
|
|
1503
2024
|
}
|
|
2025
|
+
// TODO - just expose the shadertypes decoders?
|
|
1504
2026
|
getVertexFormatInfo(format) {
|
|
1505
|
-
return getVertexFormatInfo(format);
|
|
2027
|
+
return vertexFormatDecoder.getVertexFormatInfo(format);
|
|
1506
2028
|
}
|
|
1507
2029
|
isVertexFormatSupported(format) {
|
|
1508
2030
|
return true;
|
|
@@ -1550,6 +2072,16 @@ var __exports__ = (() => {
|
|
|
1550
2072
|
isTextureFormatCompressed(format) {
|
|
1551
2073
|
return textureFormatDecoder.isCompressed(format);
|
|
1552
2074
|
}
|
|
2075
|
+
/** Returns the compressed texture formats that can be created and sampled on this device */
|
|
2076
|
+
getSupportedCompressedTextureFormats() {
|
|
2077
|
+
const supportedFormats = [];
|
|
2078
|
+
for (const format of Object.keys(getTextureFormatTable())) {
|
|
2079
|
+
if (this.isTextureFormatCompressed(format) && this.isTextureFormatSupported(format)) {
|
|
2080
|
+
supportedFormats.push(format);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
return supportedFormats;
|
|
2084
|
+
}
|
|
1553
2085
|
// DEBUG METHODS
|
|
1554
2086
|
pushDebugGroup(groupLabel) {
|
|
1555
2087
|
this.commandEncoder.pushDebugGroup(groupLabel);
|
|
@@ -1592,7 +2124,13 @@ var __exports__ = (() => {
|
|
|
1592
2124
|
reportError(error, context, ...args) {
|
|
1593
2125
|
const isHandled = this.props.onError(error, context);
|
|
1594
2126
|
if (!isHandled) {
|
|
1595
|
-
|
|
2127
|
+
const logArguments = formatErrorLogArguments(context, args);
|
|
2128
|
+
return log.error(
|
|
2129
|
+
this.type === "webgl" ? "%cWebGL" : "%cWebGPU",
|
|
2130
|
+
"color: white; background: red; padding: 2px 6px; border-radius: 3px;",
|
|
2131
|
+
error.message,
|
|
2132
|
+
...logArguments
|
|
2133
|
+
);
|
|
1596
2134
|
}
|
|
1597
2135
|
return () => {
|
|
1598
2136
|
};
|
|
@@ -1614,6 +2152,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1614
2152
|
}
|
|
1615
2153
|
return this.canvasContext;
|
|
1616
2154
|
}
|
|
2155
|
+
/** Create a fence sync object */
|
|
2156
|
+
createFence() {
|
|
2157
|
+
throw new Error("createFence() not implemented");
|
|
2158
|
+
}
|
|
1617
2159
|
/** Create a RenderPass using the default CommandEncoder */
|
|
1618
2160
|
beginRenderPass(props) {
|
|
1619
2161
|
return this.commandEncoder.beginRenderPass(props);
|
|
@@ -1622,6 +2164,78 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1622
2164
|
beginComputePass(props) {
|
|
1623
2165
|
return this.commandEncoder.beginComputePass(props);
|
|
1624
2166
|
}
|
|
2167
|
+
/**
|
|
2168
|
+
* Generate mipmaps for a WebGPU texture.
|
|
2169
|
+
* WebGPU textures must be created up front with the required mip count, usage flags, and a format that supports the chosen generation path.
|
|
2170
|
+
* WebGL uses `Texture.generateMipmapsWebGL()` directly because the backend manages mip generation on the texture object itself.
|
|
2171
|
+
*/
|
|
2172
|
+
generateMipmapsWebGPU(_texture) {
|
|
2173
|
+
throw new Error("not implemented");
|
|
2174
|
+
}
|
|
2175
|
+
/** Internal helper for creating a shareable WebGL render-pipeline implementation. */
|
|
2176
|
+
_createSharedRenderPipelineWebGL(_props) {
|
|
2177
|
+
throw new Error("_createSharedRenderPipelineWebGL() not implemented");
|
|
2178
|
+
}
|
|
2179
|
+
/** Internal WebGPU-only helper for retrieving the native bind-group layout for a pipeline group. */
|
|
2180
|
+
_createBindGroupLayoutWebGPU(_pipeline, _group) {
|
|
2181
|
+
throw new Error("_createBindGroupLayoutWebGPU() not implemented");
|
|
2182
|
+
}
|
|
2183
|
+
/** Internal WebGPU-only helper for creating a native bind group. */
|
|
2184
|
+
_createBindGroupWebGPU(_bindGroupLayout, _shaderLayout, _bindings, _group) {
|
|
2185
|
+
throw new Error("_createBindGroupWebGPU() not implemented");
|
|
2186
|
+
}
|
|
2187
|
+
/**
|
|
2188
|
+
* Internal helper that returns `true` when timestamp-query GPU timing should be
|
|
2189
|
+
* collected for this device.
|
|
2190
|
+
*/
|
|
2191
|
+
_supportsDebugGPUTime() {
|
|
2192
|
+
return this.features.has("timestamp-query") && Boolean(this.props.debug || this.props.debugGPUTime);
|
|
2193
|
+
}
|
|
2194
|
+
/**
|
|
2195
|
+
* Internal helper that enables device-managed GPU timing collection on the
|
|
2196
|
+
* default command encoder. Reuses the existing query set if timing is already enabled.
|
|
2197
|
+
*
|
|
2198
|
+
* @param queryCount - Number of timestamp slots reserved for profiled passes.
|
|
2199
|
+
* @returns The device-managed timestamp QuerySet, or `null` when timing is not supported or could not be enabled.
|
|
2200
|
+
*/
|
|
2201
|
+
_enableDebugGPUTime(queryCount = 256) {
|
|
2202
|
+
if (!this._supportsDebugGPUTime()) {
|
|
2203
|
+
return null;
|
|
2204
|
+
}
|
|
2205
|
+
if (this._debugGPUTimeQuery) {
|
|
2206
|
+
return this._debugGPUTimeQuery;
|
|
2207
|
+
}
|
|
2208
|
+
try {
|
|
2209
|
+
this._debugGPUTimeQuery = this.createQuerySet({ type: "timestamp", count: queryCount });
|
|
2210
|
+
this.commandEncoder = this.createCommandEncoder({
|
|
2211
|
+
id: this.commandEncoder.props.id,
|
|
2212
|
+
timeProfilingQuerySet: this._debugGPUTimeQuery
|
|
2213
|
+
});
|
|
2214
|
+
} catch {
|
|
2215
|
+
this._debugGPUTimeQuery = null;
|
|
2216
|
+
}
|
|
2217
|
+
return this._debugGPUTimeQuery;
|
|
2218
|
+
}
|
|
2219
|
+
/**
|
|
2220
|
+
* Internal helper that disables device-managed GPU timing collection and restores
|
|
2221
|
+
* the default command encoder to an unprofiled state.
|
|
2222
|
+
*/
|
|
2223
|
+
_disableDebugGPUTime() {
|
|
2224
|
+
if (!this._debugGPUTimeQuery) {
|
|
2225
|
+
return;
|
|
2226
|
+
}
|
|
2227
|
+
if (this.commandEncoder.getTimeProfilingQuerySet() === this._debugGPUTimeQuery) {
|
|
2228
|
+
this.commandEncoder = this.createCommandEncoder({
|
|
2229
|
+
id: this.commandEncoder.props.id
|
|
2230
|
+
});
|
|
2231
|
+
}
|
|
2232
|
+
this._debugGPUTimeQuery.destroy();
|
|
2233
|
+
this._debugGPUTimeQuery = null;
|
|
2234
|
+
}
|
|
2235
|
+
/** Internal helper that returns `true` when device-managed GPU timing is currently active. */
|
|
2236
|
+
_isDebugGPUTimeEnabled() {
|
|
2237
|
+
return this._debugGPUTimeQuery !== null;
|
|
2238
|
+
}
|
|
1625
2239
|
// DEPRECATED METHODS
|
|
1626
2240
|
/** @deprecated Use getDefaultCanvasContext() */
|
|
1627
2241
|
getCanvasContext() {
|
|
@@ -1657,6 +2271,12 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1657
2271
|
resetWebGL() {
|
|
1658
2272
|
throw new Error("not implemented");
|
|
1659
2273
|
}
|
|
2274
|
+
// INTERNAL LUMA.GL METHODS
|
|
2275
|
+
getModuleData(moduleName) {
|
|
2276
|
+
this._moduleData[moduleName] ||= {};
|
|
2277
|
+
return this._moduleData[moduleName];
|
|
2278
|
+
}
|
|
2279
|
+
// INTERNAL HELPERS
|
|
1660
2280
|
// IMPLEMENTATION
|
|
1661
2281
|
/** Helper to get the canvas context props */
|
|
1662
2282
|
static _getCanvasContextProps(props) {
|
|
@@ -1723,7 +2343,8 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1723
2343
|
onVisibilityChange: (context) => log.log(1, `${context} Visibility changed ${context.isVisible}`)(),
|
|
1724
2344
|
onDevicePixelRatioChange: (context, info) => log.log(1, `${context} DPR changed ${info.oldRatio} => ${context.devicePixelRatio}`)(),
|
|
1725
2345
|
// Debug flags
|
|
1726
|
-
debug:
|
|
2346
|
+
debug: getDefaultDebugValue(),
|
|
2347
|
+
debugGPUTime: false,
|
|
1727
2348
|
debugShaders: log.get("debug-shaders") || void 0,
|
|
1728
2349
|
debugFramebuffers: Boolean(log.get("debug-framebuffers")),
|
|
1729
2350
|
debugFactories: Boolean(log.get("debug-factories")),
|
|
@@ -1734,9 +2355,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1734
2355
|
// Experimental
|
|
1735
2356
|
_reuseDevices: false,
|
|
1736
2357
|
_requestMaxLimits: true,
|
|
1737
|
-
_cacheShaders:
|
|
1738
|
-
|
|
1739
|
-
|
|
2358
|
+
_cacheShaders: true,
|
|
2359
|
+
_destroyShaders: false,
|
|
2360
|
+
_cachePipelines: true,
|
|
2361
|
+
_sharePipelines: true,
|
|
2362
|
+
_destroyPipelines: false,
|
|
1740
2363
|
// TODO - Change these after confirming things work as expected
|
|
1741
2364
|
_initializeFeatures: true,
|
|
1742
2365
|
_disabledFeatures: {
|
|
@@ -1745,6 +2368,25 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1745
2368
|
// INTERNAL
|
|
1746
2369
|
_handle: void 0
|
|
1747
2370
|
});
|
|
2371
|
+
function _getDefaultDebugValue(logDebugValue, nodeEnv) {
|
|
2372
|
+
if (logDebugValue !== void 0 && logDebugValue !== null) {
|
|
2373
|
+
return Boolean(logDebugValue);
|
|
2374
|
+
}
|
|
2375
|
+
if (nodeEnv !== void 0) {
|
|
2376
|
+
return nodeEnv !== "production";
|
|
2377
|
+
}
|
|
2378
|
+
return false;
|
|
2379
|
+
}
|
|
2380
|
+
function getDefaultDebugValue() {
|
|
2381
|
+
return _getDefaultDebugValue(log.get("debug"), getNodeEnv());
|
|
2382
|
+
}
|
|
2383
|
+
function getNodeEnv() {
|
|
2384
|
+
const processObject = globalThis.process;
|
|
2385
|
+
if (!processObject?.env) {
|
|
2386
|
+
return void 0;
|
|
2387
|
+
}
|
|
2388
|
+
return processObject.env["NODE_ENV"];
|
|
2389
|
+
}
|
|
1748
2390
|
|
|
1749
2391
|
// ../core/src/adapter/luma.ts
|
|
1750
2392
|
var STARTUP_MESSAGE = "set luma.log.level=1 (or higher) to trace rendering";
|
|
@@ -1922,6 +2564,100 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1922
2564
|
return pageLoadPromise;
|
|
1923
2565
|
}
|
|
1924
2566
|
|
|
2567
|
+
// ../core/src/adapter/canvas-observer.ts
|
|
2568
|
+
var CanvasObserver = class {
|
|
2569
|
+
props;
|
|
2570
|
+
_resizeObserver;
|
|
2571
|
+
_intersectionObserver;
|
|
2572
|
+
_observeDevicePixelRatioTimeout = null;
|
|
2573
|
+
_observeDevicePixelRatioMediaQuery = null;
|
|
2574
|
+
_handleDevicePixelRatioChange = () => this._refreshDevicePixelRatio();
|
|
2575
|
+
_trackPositionInterval = null;
|
|
2576
|
+
_started = false;
|
|
2577
|
+
get started() {
|
|
2578
|
+
return this._started;
|
|
2579
|
+
}
|
|
2580
|
+
constructor(props) {
|
|
2581
|
+
this.props = props;
|
|
2582
|
+
}
|
|
2583
|
+
start() {
|
|
2584
|
+
if (this._started || !this.props.canvas) {
|
|
2585
|
+
return;
|
|
2586
|
+
}
|
|
2587
|
+
this._started = true;
|
|
2588
|
+
this._intersectionObserver ||= new IntersectionObserver(
|
|
2589
|
+
(entries) => this.props.onIntersection(entries)
|
|
2590
|
+
);
|
|
2591
|
+
this._resizeObserver ||= new ResizeObserver((entries) => this.props.onResize(entries));
|
|
2592
|
+
this._intersectionObserver.observe(this.props.canvas);
|
|
2593
|
+
try {
|
|
2594
|
+
this._resizeObserver.observe(this.props.canvas, { box: "device-pixel-content-box" });
|
|
2595
|
+
} catch {
|
|
2596
|
+
this._resizeObserver.observe(this.props.canvas, { box: "content-box" });
|
|
2597
|
+
}
|
|
2598
|
+
this._observeDevicePixelRatioTimeout = setTimeout(() => this._refreshDevicePixelRatio(), 0);
|
|
2599
|
+
if (this.props.trackPosition) {
|
|
2600
|
+
this._trackPosition();
|
|
2601
|
+
}
|
|
2602
|
+
}
|
|
2603
|
+
stop() {
|
|
2604
|
+
if (!this._started) {
|
|
2605
|
+
return;
|
|
2606
|
+
}
|
|
2607
|
+
this._started = false;
|
|
2608
|
+
if (this._observeDevicePixelRatioTimeout) {
|
|
2609
|
+
clearTimeout(this._observeDevicePixelRatioTimeout);
|
|
2610
|
+
this._observeDevicePixelRatioTimeout = null;
|
|
2611
|
+
}
|
|
2612
|
+
if (this._observeDevicePixelRatioMediaQuery) {
|
|
2613
|
+
this._observeDevicePixelRatioMediaQuery.removeEventListener(
|
|
2614
|
+
"change",
|
|
2615
|
+
this._handleDevicePixelRatioChange
|
|
2616
|
+
);
|
|
2617
|
+
this._observeDevicePixelRatioMediaQuery = null;
|
|
2618
|
+
}
|
|
2619
|
+
if (this._trackPositionInterval) {
|
|
2620
|
+
clearInterval(this._trackPositionInterval);
|
|
2621
|
+
this._trackPositionInterval = null;
|
|
2622
|
+
}
|
|
2623
|
+
this._resizeObserver?.disconnect();
|
|
2624
|
+
this._intersectionObserver?.disconnect();
|
|
2625
|
+
}
|
|
2626
|
+
_refreshDevicePixelRatio() {
|
|
2627
|
+
if (!this._started) {
|
|
2628
|
+
return;
|
|
2629
|
+
}
|
|
2630
|
+
this.props.onDevicePixelRatioChange();
|
|
2631
|
+
this._observeDevicePixelRatioMediaQuery?.removeEventListener(
|
|
2632
|
+
"change",
|
|
2633
|
+
this._handleDevicePixelRatioChange
|
|
2634
|
+
);
|
|
2635
|
+
this._observeDevicePixelRatioMediaQuery = matchMedia(
|
|
2636
|
+
`(resolution: ${window.devicePixelRatio}dppx)`
|
|
2637
|
+
);
|
|
2638
|
+
this._observeDevicePixelRatioMediaQuery.addEventListener(
|
|
2639
|
+
"change",
|
|
2640
|
+
this._handleDevicePixelRatioChange,
|
|
2641
|
+
{ once: true }
|
|
2642
|
+
);
|
|
2643
|
+
}
|
|
2644
|
+
_trackPosition(intervalMs = 100) {
|
|
2645
|
+
if (this._trackPositionInterval) {
|
|
2646
|
+
return;
|
|
2647
|
+
}
|
|
2648
|
+
this._trackPositionInterval = setInterval(() => {
|
|
2649
|
+
if (!this._started) {
|
|
2650
|
+
if (this._trackPositionInterval) {
|
|
2651
|
+
clearInterval(this._trackPositionInterval);
|
|
2652
|
+
this._trackPositionInterval = null;
|
|
2653
|
+
}
|
|
2654
|
+
} else {
|
|
2655
|
+
this.props.onPositionChange();
|
|
2656
|
+
}
|
|
2657
|
+
}, intervalMs);
|
|
2658
|
+
}
|
|
2659
|
+
};
|
|
2660
|
+
|
|
1925
2661
|
// ../core/src/utils/promise-utils.ts
|
|
1926
2662
|
function withResolvers() {
|
|
1927
2663
|
let resolve;
|
|
@@ -1933,8 +2669,21 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1933
2669
|
return { promise, resolve, reject };
|
|
1934
2670
|
}
|
|
1935
2671
|
|
|
1936
|
-
// ../core/src/
|
|
1937
|
-
|
|
2672
|
+
// ../core/src/utils/assert.ts
|
|
2673
|
+
function assert2(condition, message) {
|
|
2674
|
+
if (!condition) {
|
|
2675
|
+
const error = new Error(message ?? "luma.gl assertion failed.");
|
|
2676
|
+
Error.captureStackTrace?.(error, assert2);
|
|
2677
|
+
throw error;
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
function assertDefined(value, message) {
|
|
2681
|
+
assert2(value, message);
|
|
2682
|
+
return value;
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
// ../core/src/adapter/canvas-surface.ts
|
|
2686
|
+
var _CanvasSurface = class {
|
|
1938
2687
|
static isHTMLCanvas(canvas) {
|
|
1939
2688
|
return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
|
|
1940
2689
|
}
|
|
@@ -1968,16 +2717,20 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1968
2717
|
drawingBufferWidth;
|
|
1969
2718
|
/** Height of drawing buffer: automatically tracks this.pixelHeight if props.autoResize is true */
|
|
1970
2719
|
drawingBufferHeight;
|
|
2720
|
+
/** Resolves when the canvas is initialized, i.e. when the ResizeObserver has updated the pixel size */
|
|
1971
2721
|
_initializedResolvers = withResolvers();
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
_position;
|
|
2722
|
+
_canvasObserver;
|
|
2723
|
+
/** Position of the canvas in the document, updated by a timer */
|
|
2724
|
+
_position = [0, 0];
|
|
2725
|
+
/** Whether this canvas context has been destroyed */
|
|
1975
2726
|
destroyed = false;
|
|
2727
|
+
/** Whether the drawing buffer size needs to be resized (deferred resizing to avoid flicker) */
|
|
2728
|
+
_needsDrawingBufferResize = true;
|
|
1976
2729
|
toString() {
|
|
1977
2730
|
return `${this[Symbol.toStringTag]}(${this.id})`;
|
|
1978
2731
|
}
|
|
1979
2732
|
constructor(props) {
|
|
1980
|
-
this.props = { ...
|
|
2733
|
+
this.props = { ..._CanvasSurface.defaultProps, ...props };
|
|
1981
2734
|
props = this.props;
|
|
1982
2735
|
this.initialized = this._initializedResolvers.promise;
|
|
1983
2736
|
if (!isBrowser()) {
|
|
@@ -1989,11 +2742,11 @@ or create a device with the 'debug: true' prop.`;
|
|
|
1989
2742
|
} else {
|
|
1990
2743
|
this.canvas = props.canvas;
|
|
1991
2744
|
}
|
|
1992
|
-
if (
|
|
2745
|
+
if (_CanvasSurface.isHTMLCanvas(this.canvas)) {
|
|
1993
2746
|
this.id = props.id || this.canvas.id;
|
|
1994
2747
|
this.type = "html-canvas";
|
|
1995
2748
|
this.htmlCanvas = this.canvas;
|
|
1996
|
-
} else if (
|
|
2749
|
+
} else if (_CanvasSurface.isOffscreenCanvas(this.canvas)) {
|
|
1997
2750
|
this.id = props.id || "offscreen-canvas";
|
|
1998
2751
|
this.type = "offscreen-canvas";
|
|
1999
2752
|
this.offscreenCanvas = this.canvas;
|
|
@@ -2009,25 +2762,21 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2009
2762
|
this.drawingBufferHeight = this.canvas.height;
|
|
2010
2763
|
this.devicePixelRatio = globalThis.devicePixelRatio || 1;
|
|
2011
2764
|
this._position = [0, 0];
|
|
2012
|
-
|
|
2013
|
-
this.
|
|
2014
|
-
|
|
2015
|
-
)
|
|
2016
|
-
this.
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
} catch {
|
|
2021
|
-
this._resizeObserver.observe(this.canvas, { box: "content-box" });
|
|
2022
|
-
}
|
|
2023
|
-
setTimeout(() => this._observeDevicePixelRatio(), 0);
|
|
2024
|
-
if (this.props.trackPosition) {
|
|
2025
|
-
this._trackPosition();
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2765
|
+
this._canvasObserver = new CanvasObserver({
|
|
2766
|
+
canvas: this.htmlCanvas,
|
|
2767
|
+
trackPosition: this.props.trackPosition,
|
|
2768
|
+
onResize: (entries) => this._handleResize(entries),
|
|
2769
|
+
onIntersection: (entries) => this._handleIntersection(entries),
|
|
2770
|
+
onDevicePixelRatioChange: () => this._observeDevicePixelRatio(),
|
|
2771
|
+
onPositionChange: () => this.updatePosition()
|
|
2772
|
+
});
|
|
2028
2773
|
}
|
|
2029
2774
|
destroy() {
|
|
2030
|
-
this.destroyed
|
|
2775
|
+
if (!this.destroyed) {
|
|
2776
|
+
this.destroyed = true;
|
|
2777
|
+
this._stopObservers();
|
|
2778
|
+
this.device = null;
|
|
2779
|
+
}
|
|
2031
2780
|
}
|
|
2032
2781
|
setProps(props) {
|
|
2033
2782
|
if ("useDevicePixels" in props) {
|
|
@@ -2036,55 +2785,41 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2036
2785
|
}
|
|
2037
2786
|
return this;
|
|
2038
2787
|
}
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
*/
|
|
2788
|
+
/** Returns a framebuffer with properly resized current 'swap chain' textures */
|
|
2789
|
+
getCurrentFramebuffer(options) {
|
|
2790
|
+
this._resizeDrawingBufferIfNeeded();
|
|
2791
|
+
return this._getCurrentFramebuffer(options);
|
|
2792
|
+
}
|
|
2045
2793
|
getCSSSize() {
|
|
2046
2794
|
return [this.cssWidth, this.cssHeight];
|
|
2047
2795
|
}
|
|
2048
2796
|
getPosition() {
|
|
2049
2797
|
return this._position;
|
|
2050
2798
|
}
|
|
2051
|
-
/**
|
|
2052
|
-
* Returns the size covered by the canvas in actual device pixels.
|
|
2053
|
-
* @note This can be different from the 'CSS' size of a canvas due to DPR scaling, and rounding to integer pixels
|
|
2054
|
-
* @note This is independent of the canvas' internal drawing buffer size (.width, .height).
|
|
2055
|
-
*/
|
|
2056
2799
|
getDevicePixelSize() {
|
|
2057
2800
|
return [this.devicePixelWidth, this.devicePixelHeight];
|
|
2058
2801
|
}
|
|
2059
|
-
/** Get the drawing buffer size (number of pixels GPU is rendering into, can be different from CSS size) */
|
|
2060
2802
|
getDrawingBufferSize() {
|
|
2061
2803
|
return [this.drawingBufferWidth, this.drawingBufferHeight];
|
|
2062
2804
|
}
|
|
2063
|
-
/** Returns the biggest allowed framebuffer size. @todo Allow the application to limit this? */
|
|
2064
2805
|
getMaxDrawingBufferSize() {
|
|
2065
2806
|
const maxTextureDimension = this.device.limits.maxTextureDimension2D;
|
|
2066
2807
|
return [maxTextureDimension, maxTextureDimension];
|
|
2067
2808
|
}
|
|
2068
|
-
/** Update the canvas drawing buffer size. Called automatically if props.autoResize is true. */
|
|
2069
2809
|
setDrawingBufferSize(width, height) {
|
|
2070
|
-
|
|
2071
|
-
|
|
2810
|
+
width = Math.floor(width);
|
|
2811
|
+
height = Math.floor(height);
|
|
2812
|
+
if (this.drawingBufferWidth === width && this.drawingBufferHeight === height) {
|
|
2813
|
+
return;
|
|
2814
|
+
}
|
|
2072
2815
|
this.drawingBufferWidth = width;
|
|
2073
2816
|
this.drawingBufferHeight = height;
|
|
2817
|
+
this._needsDrawingBufferResize = true;
|
|
2074
2818
|
}
|
|
2075
|
-
/**
|
|
2076
|
-
* Returns the current DPR (number of physical pixels per CSS pixel), if props.useDevicePixels is true
|
|
2077
|
-
* @note This can be a fractional (non-integer) number, e.g. when the user zooms in the browser.
|
|
2078
|
-
* @note This function handles the non-HTML canvas cases
|
|
2079
|
-
*/
|
|
2080
2819
|
getDevicePixelRatio() {
|
|
2081
|
-
const
|
|
2082
|
-
return
|
|
2820
|
+
const devicePixelRatio2 = typeof window !== "undefined" && window.devicePixelRatio;
|
|
2821
|
+
return devicePixelRatio2 || 1;
|
|
2083
2822
|
}
|
|
2084
|
-
// DEPRECATED METHODS
|
|
2085
|
-
/**
|
|
2086
|
-
* Maps CSS pixel position to device pixel position
|
|
2087
|
-
*/
|
|
2088
2823
|
cssToDevicePixels(cssPixel, yInvert = true) {
|
|
2089
2824
|
const ratio = this.cssToDeviceRatio();
|
|
2090
2825
|
const [width, height] = this.getDrawingBufferSize();
|
|
@@ -2094,10 +2829,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2094
2829
|
getPixelSize() {
|
|
2095
2830
|
return this.getDevicePixelSize();
|
|
2096
2831
|
}
|
|
2097
|
-
/** @deprecated
|
|
2832
|
+
/** @deprecated Use the current drawing buffer size for projection setup. */
|
|
2098
2833
|
getAspect() {
|
|
2099
|
-
const [width, height] = this.
|
|
2100
|
-
return width / height;
|
|
2834
|
+
const [width, height] = this.getDrawingBufferSize();
|
|
2835
|
+
return width > 0 && height > 0 ? width / height : 1;
|
|
2101
2836
|
}
|
|
2102
2837
|
/** @deprecated Returns multiplier need to convert CSS size to Device size */
|
|
2103
2838
|
cssToDeviceRatio() {
|
|
@@ -2113,18 +2848,40 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2113
2848
|
resize(size) {
|
|
2114
2849
|
this.setDrawingBufferSize(size.width, size.height);
|
|
2115
2850
|
}
|
|
2116
|
-
// IMPLEMENTATION
|
|
2117
|
-
/**
|
|
2118
|
-
* Allows subclass constructor to override the canvas id for auto created canvases.
|
|
2119
|
-
* This can really help when debugging DOM in apps that create multiple devices
|
|
2120
|
-
*/
|
|
2121
2851
|
_setAutoCreatedCanvasId(id) {
|
|
2122
2852
|
if (this.htmlCanvas?.id === "lumagl-auto-created-canvas") {
|
|
2123
2853
|
this.htmlCanvas.id = id;
|
|
2124
2854
|
}
|
|
2125
2855
|
}
|
|
2126
|
-
/**
|
|
2856
|
+
/**
|
|
2857
|
+
* Starts DOM observation after the derived context and its device are fully initialized.
|
|
2858
|
+
*
|
|
2859
|
+
* `CanvasSurface` construction runs before subclasses can assign `this.device`, and the
|
|
2860
|
+
* default WebGL canvas context is created before `WebGLDevice` has initialized `limits`,
|
|
2861
|
+
* `features`, and the rest of its runtime state. Deferring observer startup avoids early
|
|
2862
|
+
* `ResizeObserver` and DPR callbacks running against a partially initialized device.
|
|
2863
|
+
*/
|
|
2864
|
+
_startObservers() {
|
|
2865
|
+
if (this.destroyed) {
|
|
2866
|
+
return;
|
|
2867
|
+
}
|
|
2868
|
+
this._canvasObserver.start();
|
|
2869
|
+
}
|
|
2870
|
+
/**
|
|
2871
|
+
* Stops all DOM observation and timers associated with a canvas surface.
|
|
2872
|
+
*
|
|
2873
|
+
* This pairs with `_startObservers()` so teardown uses the same lifecycle whether a context is
|
|
2874
|
+
* explicitly destroyed, abandoned during device reuse, or temporarily has not started observing
|
|
2875
|
+
* yet. Centralizing shutdown here keeps resize/DPR/position watchers from surviving past the
|
|
2876
|
+
* lifetime of the owning device.
|
|
2877
|
+
*/
|
|
2878
|
+
_stopObservers() {
|
|
2879
|
+
this._canvasObserver.stop();
|
|
2880
|
+
}
|
|
2127
2881
|
_handleIntersection(entries) {
|
|
2882
|
+
if (this.destroyed) {
|
|
2883
|
+
return;
|
|
2884
|
+
}
|
|
2128
2885
|
const entry = entries.find((entry_) => entry_.target === this.canvas);
|
|
2129
2886
|
if (!entry) {
|
|
2130
2887
|
return;
|
|
@@ -2135,21 +2892,20 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2135
2892
|
this.device.props.onVisibilityChange(this);
|
|
2136
2893
|
}
|
|
2137
2894
|
}
|
|
2138
|
-
/**
|
|
2139
|
-
* Reacts to an observed resize by using the most accurate pixel size information the browser can provide
|
|
2140
|
-
* @see https://web.dev/articles/device-pixel-content-box
|
|
2141
|
-
* @see https://webgpufundamentals.org/webgpu/lessons/webgpu-resizing-the-canvas.html
|
|
2142
|
-
*/
|
|
2143
2895
|
_handleResize(entries) {
|
|
2896
|
+
if (this.destroyed) {
|
|
2897
|
+
return;
|
|
2898
|
+
}
|
|
2144
2899
|
const entry = entries.find((entry_) => entry_.target === this.canvas);
|
|
2145
2900
|
if (!entry) {
|
|
2146
2901
|
return;
|
|
2147
2902
|
}
|
|
2148
|
-
|
|
2149
|
-
this.
|
|
2903
|
+
const contentBoxSize = assertDefined(entry.contentBoxSize?.[0]);
|
|
2904
|
+
this.cssWidth = contentBoxSize.inlineSize;
|
|
2905
|
+
this.cssHeight = contentBoxSize.blockSize;
|
|
2150
2906
|
const oldPixelSize = this.getDevicePixelSize();
|
|
2151
|
-
const devicePixelWidth = entry.devicePixelContentBoxSize?.[0]
|
|
2152
|
-
const devicePixelHeight = entry.devicePixelContentBoxSize?.[0]
|
|
2907
|
+
const devicePixelWidth = entry.devicePixelContentBoxSize?.[0]?.inlineSize || contentBoxSize.inlineSize * devicePixelRatio;
|
|
2908
|
+
const devicePixelHeight = entry.devicePixelContentBoxSize?.[0]?.blockSize || contentBoxSize.blockSize * devicePixelRatio;
|
|
2153
2909
|
const [maxDevicePixelWidth, maxDevicePixelHeight] = this.getMaxDrawingBufferSize();
|
|
2154
2910
|
this.devicePixelWidth = Math.max(1, Math.min(devicePixelWidth, maxDevicePixelWidth));
|
|
2155
2911
|
this.devicePixelHeight = Math.max(1, Math.min(devicePixelHeight, maxDevicePixelHeight));
|
|
@@ -2159,47 +2915,47 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2159
2915
|
_updateDrawingBufferSize() {
|
|
2160
2916
|
if (this.props.autoResize) {
|
|
2161
2917
|
if (typeof this.props.useDevicePixels === "number") {
|
|
2162
|
-
const
|
|
2163
|
-
this.setDrawingBufferSize(
|
|
2918
|
+
const devicePixelRatio2 = this.props.useDevicePixels;
|
|
2919
|
+
this.setDrawingBufferSize(
|
|
2920
|
+
this.cssWidth * devicePixelRatio2,
|
|
2921
|
+
this.cssHeight * devicePixelRatio2
|
|
2922
|
+
);
|
|
2164
2923
|
} else if (this.props.useDevicePixels) {
|
|
2165
2924
|
this.setDrawingBufferSize(this.devicePixelWidth, this.devicePixelHeight);
|
|
2166
2925
|
} else {
|
|
2167
2926
|
this.setDrawingBufferSize(this.cssWidth, this.cssHeight);
|
|
2168
2927
|
}
|
|
2169
|
-
this._updateDevice();
|
|
2170
2928
|
}
|
|
2171
2929
|
this._initializedResolvers.resolve();
|
|
2172
2930
|
this.isInitialized = true;
|
|
2173
2931
|
this.updatePosition();
|
|
2174
2932
|
}
|
|
2175
|
-
|
|
2933
|
+
_resizeDrawingBufferIfNeeded() {
|
|
2934
|
+
if (this._needsDrawingBufferResize) {
|
|
2935
|
+
this._needsDrawingBufferResize = false;
|
|
2936
|
+
const sizeChanged = this.drawingBufferWidth !== this.canvas.width || this.drawingBufferHeight !== this.canvas.height;
|
|
2937
|
+
if (sizeChanged) {
|
|
2938
|
+
this.canvas.width = this.drawingBufferWidth;
|
|
2939
|
+
this.canvas.height = this.drawingBufferHeight;
|
|
2940
|
+
this._configureDevice();
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2176
2944
|
_observeDevicePixelRatio() {
|
|
2945
|
+
if (this.destroyed || !this._canvasObserver.started) {
|
|
2946
|
+
return;
|
|
2947
|
+
}
|
|
2177
2948
|
const oldRatio = this.devicePixelRatio;
|
|
2178
2949
|
this.devicePixelRatio = window.devicePixelRatio;
|
|
2179
2950
|
this.updatePosition();
|
|
2180
|
-
this.device.props.onDevicePixelRatioChange(this, {
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
() => this._observeDevicePixelRatio(),
|
|
2184
|
-
{ once: true }
|
|
2185
|
-
);
|
|
2186
|
-
}
|
|
2187
|
-
/** Start tracking positions with a timer */
|
|
2188
|
-
_trackPosition(intervalMs = 100) {
|
|
2189
|
-
const intervalId = setInterval(() => {
|
|
2190
|
-
if (this.destroyed) {
|
|
2191
|
-
clearInterval(intervalId);
|
|
2192
|
-
} else {
|
|
2193
|
-
this.updatePosition();
|
|
2194
|
-
}
|
|
2195
|
-
}, intervalMs);
|
|
2951
|
+
this.device.props.onDevicePixelRatioChange?.(this, {
|
|
2952
|
+
oldRatio
|
|
2953
|
+
});
|
|
2196
2954
|
}
|
|
2197
|
-
/**
|
|
2198
|
-
* Calculated the absolute position of the canvas
|
|
2199
|
-
* @note - getBoundingClientRect() is normally cheap but can be expensive
|
|
2200
|
-
* if called before browser has finished a reflow. Should not be the case here.
|
|
2201
|
-
*/
|
|
2202
2955
|
updatePosition() {
|
|
2956
|
+
if (this.destroyed) {
|
|
2957
|
+
return;
|
|
2958
|
+
}
|
|
2203
2959
|
const newRect = this.htmlCanvas?.getBoundingClientRect();
|
|
2204
2960
|
if (newRect) {
|
|
2205
2961
|
const position = [newRect.left, newRect.top];
|
|
@@ -2208,13 +2964,15 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2208
2964
|
if (positionChanged) {
|
|
2209
2965
|
const oldPosition = this._position;
|
|
2210
2966
|
this._position = position;
|
|
2211
|
-
this.device.props.onPositionChange?.(this, {
|
|
2967
|
+
this.device.props.onPositionChange?.(this, {
|
|
2968
|
+
oldPosition
|
|
2969
|
+
});
|
|
2212
2970
|
}
|
|
2213
2971
|
}
|
|
2214
2972
|
}
|
|
2215
2973
|
};
|
|
2216
|
-
var
|
|
2217
|
-
__publicField(
|
|
2974
|
+
var CanvasSurface = _CanvasSurface;
|
|
2975
|
+
__publicField(CanvasSurface, "defaultProps", {
|
|
2218
2976
|
id: void 0,
|
|
2219
2977
|
canvas: null,
|
|
2220
2978
|
width: 800,
|
|
@@ -2242,7 +3000,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2242
3000
|
}
|
|
2243
3001
|
function getCanvasFromDOM(canvasId) {
|
|
2244
3002
|
const canvas = document.getElementById(canvasId);
|
|
2245
|
-
if (!
|
|
3003
|
+
if (!CanvasSurface.isHTMLCanvas(canvas)) {
|
|
2246
3004
|
throw new Error("Object is not a canvas element");
|
|
2247
3005
|
}
|
|
2248
3006
|
return canvas;
|
|
@@ -2266,33 +3024,40 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2266
3024
|
const point = pixel;
|
|
2267
3025
|
const x = scaleX(point[0], ratio, width);
|
|
2268
3026
|
let y = scaleY(point[1], ratio, height, yInvert);
|
|
2269
|
-
let
|
|
2270
|
-
const xHigh =
|
|
2271
|
-
|
|
3027
|
+
let temporary = scaleX(point[0] + 1, ratio, width);
|
|
3028
|
+
const xHigh = temporary === width - 1 ? temporary : temporary - 1;
|
|
3029
|
+
temporary = scaleY(point[1] + 1, ratio, height, yInvert);
|
|
2272
3030
|
let yHigh;
|
|
2273
3031
|
if (yInvert) {
|
|
2274
|
-
|
|
3032
|
+
temporary = temporary === 0 ? temporary : temporary + 1;
|
|
2275
3033
|
yHigh = y;
|
|
2276
|
-
y =
|
|
3034
|
+
y = temporary;
|
|
2277
3035
|
} else {
|
|
2278
|
-
yHigh =
|
|
3036
|
+
yHigh = temporary === height - 1 ? temporary : temporary - 1;
|
|
2279
3037
|
}
|
|
2280
3038
|
return {
|
|
2281
3039
|
x,
|
|
2282
3040
|
y,
|
|
2283
|
-
// when ratio < 1, current css pixel and next css pixel may point to same device pixel, set width/height to 1 in those cases.
|
|
2284
3041
|
width: Math.max(xHigh - x + 1, 1),
|
|
2285
3042
|
height: Math.max(yHigh - y + 1, 1)
|
|
2286
3043
|
};
|
|
2287
3044
|
}
|
|
2288
3045
|
function scaleX(x, ratio, width) {
|
|
2289
|
-
|
|
2290
|
-
return r;
|
|
3046
|
+
return Math.min(Math.round(x * ratio), width - 1);
|
|
2291
3047
|
}
|
|
2292
3048
|
function scaleY(y, ratio, height, yInvert) {
|
|
2293
3049
|
return yInvert ? Math.max(0, height - 1 - Math.round(y * ratio)) : Math.min(Math.round(y * ratio), height - 1);
|
|
2294
3050
|
}
|
|
2295
3051
|
|
|
3052
|
+
// ../core/src/adapter/canvas-context.ts
|
|
3053
|
+
var CanvasContext = class extends CanvasSurface {
|
|
3054
|
+
};
|
|
3055
|
+
__publicField(CanvasContext, "defaultProps", CanvasSurface.defaultProps);
|
|
3056
|
+
|
|
3057
|
+
// ../core/src/adapter/presentation-context.ts
|
|
3058
|
+
var PresentationContext = class extends CanvasSurface {
|
|
3059
|
+
};
|
|
3060
|
+
|
|
2296
3061
|
// ../core/src/adapter/resources/sampler.ts
|
|
2297
3062
|
var _Sampler = class extends Resource {
|
|
2298
3063
|
get [Symbol.toStringTag]() {
|
|
@@ -2347,7 +3112,15 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2347
3112
|
depth;
|
|
2348
3113
|
/** mip levels in this texture */
|
|
2349
3114
|
mipLevels;
|
|
2350
|
-
/**
|
|
3115
|
+
/** sample count */
|
|
3116
|
+
samples;
|
|
3117
|
+
/** Rows are multiples of this length, padded with extra bytes if needed */
|
|
3118
|
+
byteAlignment;
|
|
3119
|
+
/** The ready promise is always resolved. It is provided for type compatibility with DynamicTexture. */
|
|
3120
|
+
ready = Promise.resolve(this);
|
|
3121
|
+
/** isReady is always true. It is provided for type compatibility with DynamicTexture. */
|
|
3122
|
+
isReady = true;
|
|
3123
|
+
/** "Time" of last update. Monotonically increasing timestamp. TODO move to DynamicTexture? */
|
|
2351
3124
|
updateTimestamp;
|
|
2352
3125
|
get [Symbol.toStringTag]() {
|
|
2353
3126
|
return "Texture";
|
|
@@ -2356,7 +3129,7 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2356
3129
|
return `Texture(${this.id},${this.format},${this.width}x${this.height})`;
|
|
2357
3130
|
}
|
|
2358
3131
|
/** Do not use directly. Create with device.createTexture() */
|
|
2359
|
-
constructor(device, props) {
|
|
3132
|
+
constructor(device, props, backendProps) {
|
|
2360
3133
|
props = _Texture.normalizeProps(device, props);
|
|
2361
3134
|
super(device, props, _Texture.defaultProps);
|
|
2362
3135
|
this.dimension = this.props.dimension;
|
|
@@ -2366,6 +3139,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2366
3139
|
this.height = this.props.height;
|
|
2367
3140
|
this.depth = this.props.depth;
|
|
2368
3141
|
this.mipLevels = this.props.mipLevels;
|
|
3142
|
+
this.samples = this.props.samples || 1;
|
|
3143
|
+
if (this.dimension === "cube") {
|
|
3144
|
+
this.depth = 6;
|
|
3145
|
+
}
|
|
2369
3146
|
if (this.props.width === void 0 || this.props.height === void 0) {
|
|
2370
3147
|
if (device.isExternalImage(props.data)) {
|
|
2371
3148
|
const size = device.getExternalImageSize(props.data);
|
|
@@ -2376,17 +3153,14 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2376
3153
|
this.height = 1;
|
|
2377
3154
|
if (this.props.width === void 0 || this.props.height === void 0) {
|
|
2378
3155
|
log.warn(
|
|
2379
|
-
`${this} created with undefined width or height. This is deprecated. Use
|
|
3156
|
+
`${this} created with undefined width or height. This is deprecated. Use DynamicTexture instead.`
|
|
2380
3157
|
)();
|
|
2381
3158
|
}
|
|
2382
3159
|
}
|
|
2383
3160
|
}
|
|
3161
|
+
this.byteAlignment = backendProps?.byteAlignment || 1;
|
|
2384
3162
|
this.updateTimestamp = device.incrementTimestamp();
|
|
2385
3163
|
}
|
|
2386
|
-
/** Set sampler props associated with this texture */
|
|
2387
|
-
setSampler(sampler) {
|
|
2388
|
-
this.sampler = sampler instanceof Sampler ? sampler : this.device.createSampler(sampler);
|
|
2389
|
-
}
|
|
2390
3164
|
/**
|
|
2391
3165
|
* Create a new texture with the same parameters and optionally a different size
|
|
2392
3166
|
* @note Textures are immutable and cannot be resized after creation, but we can create a similar texture with the same parameters but a new size.
|
|
@@ -2395,6 +3169,105 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2395
3169
|
clone(size) {
|
|
2396
3170
|
return this.device.createTexture({ ...this.props, ...size });
|
|
2397
3171
|
}
|
|
3172
|
+
/** Set sampler props associated with this texture */
|
|
3173
|
+
setSampler(sampler) {
|
|
3174
|
+
this.sampler = sampler instanceof Sampler ? sampler : this.device.createSampler(sampler);
|
|
3175
|
+
}
|
|
3176
|
+
/**
|
|
3177
|
+
* Copy raw image data (bytes) into the texture.
|
|
3178
|
+
*
|
|
3179
|
+
* @note Deprecated compatibility wrapper over {@link writeData}.
|
|
3180
|
+
* @note Uses the same layout defaults and alignment rules as {@link writeData}.
|
|
3181
|
+
* @note Tightly packed CPU uploads can omit `bytesPerRow` and `rowsPerImage`.
|
|
3182
|
+
* @note If the CPU source rows are padded, pass explicit `bytesPerRow` and `rowsPerImage`.
|
|
3183
|
+
* @deprecated Use writeData()
|
|
3184
|
+
*/
|
|
3185
|
+
copyImageData(options) {
|
|
3186
|
+
const { data, depth, ...writeOptions } = options;
|
|
3187
|
+
this.writeData(data, {
|
|
3188
|
+
...writeOptions,
|
|
3189
|
+
depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
|
|
3190
|
+
});
|
|
3191
|
+
}
|
|
3192
|
+
/**
|
|
3193
|
+
* Calculates the memory layout of the texture, required when reading and writing data.
|
|
3194
|
+
* @return the backend-aligned linear layout, in particular bytesPerRow which includes any required padding for buffer copy/read paths
|
|
3195
|
+
*/
|
|
3196
|
+
computeMemoryLayout(options_ = {}) {
|
|
3197
|
+
const options = this._normalizeTextureReadOptions(options_);
|
|
3198
|
+
const { width = this.width, height = this.height, depthOrArrayLayers = this.depth } = options;
|
|
3199
|
+
const { format, byteAlignment } = this;
|
|
3200
|
+
return textureFormatDecoder.computeMemoryLayout({
|
|
3201
|
+
format,
|
|
3202
|
+
width,
|
|
3203
|
+
height,
|
|
3204
|
+
depth: depthOrArrayLayers,
|
|
3205
|
+
byteAlignment
|
|
3206
|
+
});
|
|
3207
|
+
}
|
|
3208
|
+
/**
|
|
3209
|
+
* Read the contents of a texture into a GPU Buffer.
|
|
3210
|
+
* @returns A Buffer containing the texture data.
|
|
3211
|
+
*
|
|
3212
|
+
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
3213
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
|
|
3214
|
+
* @note The application can call Buffer.readAsync() to read the returned buffer on the CPU.
|
|
3215
|
+
* @note The destination buffer must be supplied by the caller and must be large enough for the requested region.
|
|
3216
|
+
* @note On WebGPU this corresponds to a texture-to-buffer copy and uses buffer-copy alignment rules.
|
|
3217
|
+
* @note On WebGL, luma.gl emulates the same logical readback behavior.
|
|
3218
|
+
*/
|
|
3219
|
+
readBuffer(options, buffer) {
|
|
3220
|
+
throw new Error("readBuffer not implemented");
|
|
3221
|
+
}
|
|
3222
|
+
/**
|
|
3223
|
+
* Reads data from a texture into an ArrayBuffer.
|
|
3224
|
+
* @returns An ArrayBuffer containing the texture data.
|
|
3225
|
+
*
|
|
3226
|
+
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
3227
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the layout.
|
|
3228
|
+
* @deprecated Use Texture.readBuffer() with an explicit destination buffer, or DynamicTexture.readAsync() for convenience readback.
|
|
3229
|
+
*/
|
|
3230
|
+
readDataAsync(options) {
|
|
3231
|
+
throw new Error("readBuffer not implemented");
|
|
3232
|
+
}
|
|
3233
|
+
/**
|
|
3234
|
+
* Writes a GPU Buffer into a texture.
|
|
3235
|
+
*
|
|
3236
|
+
* @param buffer - Source GPU buffer.
|
|
3237
|
+
* @param options - Destination subresource, extent, and source layout options.
|
|
3238
|
+
* @note The memory layout of the texture data is determined by the texture format and dimensions.
|
|
3239
|
+
* @note The application can call Texture.computeMemoryLayout() to compute the backend-aligned layout.
|
|
3240
|
+
* @note On WebGPU this corresponds to a buffer-to-texture copy and uses buffer-copy alignment rules.
|
|
3241
|
+
* @note On WebGL, luma.gl emulates the same destination and layout semantics.
|
|
3242
|
+
*/
|
|
3243
|
+
writeBuffer(buffer, options) {
|
|
3244
|
+
throw new Error("readBuffer not implemented");
|
|
3245
|
+
}
|
|
3246
|
+
/**
|
|
3247
|
+
* Writes an array buffer into a texture.
|
|
3248
|
+
*
|
|
3249
|
+
* @param data - Source texel data.
|
|
3250
|
+
* @param options - Destination subresource, extent, and source layout options.
|
|
3251
|
+
* @note If `bytesPerRow` and `rowsPerImage` are omitted, luma.gl computes a tightly packed CPU-memory layout for the requested region.
|
|
3252
|
+
* @note On WebGPU this corresponds to `GPUQueue.writeTexture()` and does not implicitly pad rows to 256 bytes.
|
|
3253
|
+
* @note On WebGL, padded CPU data is supported via the same `bytesPerRow` and `rowsPerImage` options.
|
|
3254
|
+
*/
|
|
3255
|
+
writeData(data, options) {
|
|
3256
|
+
throw new Error("readBuffer not implemented");
|
|
3257
|
+
}
|
|
3258
|
+
// IMPLEMENTATION SPECIFIC
|
|
3259
|
+
/**
|
|
3260
|
+
* WebGL can read data synchronously.
|
|
3261
|
+
* @note While it is convenient, the performance penalty is very significant
|
|
3262
|
+
*/
|
|
3263
|
+
readDataSyncWebGL(options) {
|
|
3264
|
+
throw new Error("readDataSyncWebGL not available");
|
|
3265
|
+
}
|
|
3266
|
+
/** Generate mipmaps (WebGL only) */
|
|
3267
|
+
generateMipmapsWebGL() {
|
|
3268
|
+
throw new Error("generateMipmapsWebGL not available");
|
|
3269
|
+
}
|
|
3270
|
+
// HELPERS
|
|
2398
3271
|
/** Ensure we have integer coordinates */
|
|
2399
3272
|
static normalizeProps(device, props) {
|
|
2400
3273
|
const newProps = { ...props };
|
|
@@ -2407,7 +3280,6 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2407
3280
|
}
|
|
2408
3281
|
return newProps;
|
|
2409
3282
|
}
|
|
2410
|
-
// HELPERS
|
|
2411
3283
|
/** Initialize texture with supplied props */
|
|
2412
3284
|
// eslint-disable-next-line max-statements
|
|
2413
3285
|
_initializeData(data) {
|
|
@@ -2441,23 +3313,166 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2441
3313
|
}
|
|
2442
3314
|
}
|
|
2443
3315
|
_normalizeCopyImageDataOptions(options_) {
|
|
2444
|
-
const {
|
|
2445
|
-
const options = {
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
}
|
|
2450
|
-
options.bytesPerRow = options_.bytesPerRow || width * (info.bytesPerPixel || 4);
|
|
2451
|
-
options.rowsPerImage = options_.rowsPerImage || height;
|
|
2452
|
-
return options;
|
|
3316
|
+
const { data, depth, ...writeOptions } = options_;
|
|
3317
|
+
const options = this._normalizeTextureWriteOptions({
|
|
3318
|
+
...writeOptions,
|
|
3319
|
+
depthOrArrayLayers: writeOptions.depthOrArrayLayers ?? depth
|
|
3320
|
+
});
|
|
3321
|
+
return { data, depth: options.depthOrArrayLayers, ...options };
|
|
2453
3322
|
}
|
|
2454
3323
|
_normalizeCopyExternalImageOptions(options_) {
|
|
3324
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3325
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3326
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
2455
3327
|
const size = this.device.getExternalImageSize(options_.image);
|
|
2456
|
-
const options = {
|
|
2457
|
-
|
|
2458
|
-
|
|
3328
|
+
const options = {
|
|
3329
|
+
..._Texture.defaultCopyExternalImageOptions,
|
|
3330
|
+
...mipLevelSize,
|
|
3331
|
+
...size,
|
|
3332
|
+
...optionsWithoutUndefined
|
|
3333
|
+
};
|
|
3334
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3335
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3336
|
+
options.depth = Math.min(options.depth, mipLevelSize.depthOrArrayLayers - options.z);
|
|
3337
|
+
return options;
|
|
3338
|
+
}
|
|
3339
|
+
_normalizeTextureReadOptions(options_) {
|
|
3340
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3341
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3342
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
3343
|
+
const options = {
|
|
3344
|
+
..._Texture.defaultTextureReadOptions,
|
|
3345
|
+
...mipLevelSize,
|
|
3346
|
+
...optionsWithoutUndefined
|
|
3347
|
+
};
|
|
3348
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3349
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3350
|
+
options.depthOrArrayLayers = Math.min(
|
|
3351
|
+
options.depthOrArrayLayers,
|
|
3352
|
+
mipLevelSize.depthOrArrayLayers - options.z
|
|
3353
|
+
);
|
|
2459
3354
|
return options;
|
|
2460
3355
|
}
|
|
3356
|
+
/**
|
|
3357
|
+
* Normalizes a texture read request and validates the color-only readback contract used by the
|
|
3358
|
+
* current texture read APIs. Supported dimensions are `2d`, `cube`, `cube-array`,
|
|
3359
|
+
* `2d-array`, and `3d`.
|
|
3360
|
+
*
|
|
3361
|
+
* @throws if the texture format, aspect, or dimension is not supported by the first-pass
|
|
3362
|
+
* color-read implementation.
|
|
3363
|
+
*/
|
|
3364
|
+
_getSupportedColorReadOptions(options_) {
|
|
3365
|
+
const options = this._normalizeTextureReadOptions(options_);
|
|
3366
|
+
const formatInfo = textureFormatDecoder.getInfo(this.format);
|
|
3367
|
+
this._validateColorReadAspect(options);
|
|
3368
|
+
this._validateColorReadFormat(formatInfo);
|
|
3369
|
+
switch (this.dimension) {
|
|
3370
|
+
case "2d":
|
|
3371
|
+
case "cube":
|
|
3372
|
+
case "cube-array":
|
|
3373
|
+
case "2d-array":
|
|
3374
|
+
case "3d":
|
|
3375
|
+
return options;
|
|
3376
|
+
default:
|
|
3377
|
+
throw new Error(`${this} color readback does not support ${this.dimension} textures`);
|
|
3378
|
+
}
|
|
3379
|
+
}
|
|
3380
|
+
/** Validates that a read request targets the full color aspect of the texture. */
|
|
3381
|
+
_validateColorReadAspect(options) {
|
|
3382
|
+
if (options.aspect !== "all") {
|
|
3383
|
+
throw new Error(`${this} color readback only supports aspect 'all'`);
|
|
3384
|
+
}
|
|
3385
|
+
}
|
|
3386
|
+
/** Validates that a read request targets an uncompressed color-renderable texture format. */
|
|
3387
|
+
_validateColorReadFormat(formatInfo) {
|
|
3388
|
+
if (formatInfo.compressed) {
|
|
3389
|
+
throw new Error(
|
|
3390
|
+
`${this} color readback does not support compressed formats (${this.format})`
|
|
3391
|
+
);
|
|
3392
|
+
}
|
|
3393
|
+
switch (formatInfo.attachment) {
|
|
3394
|
+
case "color":
|
|
3395
|
+
return;
|
|
3396
|
+
case "depth":
|
|
3397
|
+
throw new Error(`${this} color readback does not support depth formats (${this.format})`);
|
|
3398
|
+
case "stencil":
|
|
3399
|
+
throw new Error(`${this} color readback does not support stencil formats (${this.format})`);
|
|
3400
|
+
case "depth-stencil":
|
|
3401
|
+
throw new Error(
|
|
3402
|
+
`${this} color readback does not support depth-stencil formats (${this.format})`
|
|
3403
|
+
);
|
|
3404
|
+
default:
|
|
3405
|
+
throw new Error(`${this} color readback does not support format ${this.format}`);
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
_normalizeTextureWriteOptions(options_) {
|
|
3409
|
+
const optionsWithoutUndefined = _Texture._omitUndefined(options_);
|
|
3410
|
+
const mipLevel = optionsWithoutUndefined.mipLevel ?? 0;
|
|
3411
|
+
const mipLevelSize = this._getMipLevelSize(mipLevel);
|
|
3412
|
+
const options = {
|
|
3413
|
+
..._Texture.defaultTextureWriteOptions,
|
|
3414
|
+
...mipLevelSize,
|
|
3415
|
+
...optionsWithoutUndefined
|
|
3416
|
+
};
|
|
3417
|
+
options.width = Math.min(options.width, mipLevelSize.width - options.x);
|
|
3418
|
+
options.height = Math.min(options.height, mipLevelSize.height - options.y);
|
|
3419
|
+
options.depthOrArrayLayers = Math.min(
|
|
3420
|
+
options.depthOrArrayLayers,
|
|
3421
|
+
mipLevelSize.depthOrArrayLayers - options.z
|
|
3422
|
+
);
|
|
3423
|
+
const layout = textureFormatDecoder.computeMemoryLayout({
|
|
3424
|
+
format: this.format,
|
|
3425
|
+
width: options.width,
|
|
3426
|
+
height: options.height,
|
|
3427
|
+
depth: options.depthOrArrayLayers,
|
|
3428
|
+
byteAlignment: this.byteAlignment
|
|
3429
|
+
});
|
|
3430
|
+
const minimumBytesPerRow = layout.bytesPerPixel * options.width;
|
|
3431
|
+
options.bytesPerRow = optionsWithoutUndefined.bytesPerRow ?? layout.bytesPerRow;
|
|
3432
|
+
options.rowsPerImage = optionsWithoutUndefined.rowsPerImage ?? options.height;
|
|
3433
|
+
if (options.bytesPerRow < minimumBytesPerRow) {
|
|
3434
|
+
throw new Error(
|
|
3435
|
+
`bytesPerRow (${options.bytesPerRow}) must be at least ${minimumBytesPerRow} for ${this.format}`
|
|
3436
|
+
);
|
|
3437
|
+
}
|
|
3438
|
+
if (options.rowsPerImage < options.height) {
|
|
3439
|
+
throw new Error(
|
|
3440
|
+
`rowsPerImage (${options.rowsPerImage}) must be at least ${options.height} for ${this.format}`
|
|
3441
|
+
);
|
|
3442
|
+
}
|
|
3443
|
+
const bytesPerPixel = this.device.getTextureFormatInfo(this.format).bytesPerPixel;
|
|
3444
|
+
if (bytesPerPixel && options.bytesPerRow % bytesPerPixel !== 0) {
|
|
3445
|
+
throw new Error(
|
|
3446
|
+
`bytesPerRow (${options.bytesPerRow}) must be a multiple of bytesPerPixel (${bytesPerPixel}) for ${this.format}`
|
|
3447
|
+
);
|
|
3448
|
+
}
|
|
3449
|
+
return options;
|
|
3450
|
+
}
|
|
3451
|
+
_getMipLevelSize(mipLevel) {
|
|
3452
|
+
const width = Math.max(1, this.width >> mipLevel);
|
|
3453
|
+
const height = this.baseDimension === "1d" ? 1 : Math.max(1, this.height >> mipLevel);
|
|
3454
|
+
const depthOrArrayLayers = this.dimension === "3d" ? Math.max(1, this.depth >> mipLevel) : this.depth;
|
|
3455
|
+
return { width, height, depthOrArrayLayers };
|
|
3456
|
+
}
|
|
3457
|
+
getAllocatedByteLength() {
|
|
3458
|
+
let allocatedByteLength = 0;
|
|
3459
|
+
for (let mipLevel = 0; mipLevel < this.mipLevels; mipLevel++) {
|
|
3460
|
+
const { width, height, depthOrArrayLayers } = this._getMipLevelSize(mipLevel);
|
|
3461
|
+
allocatedByteLength += textureFormatDecoder.computeMemoryLayout({
|
|
3462
|
+
format: this.format,
|
|
3463
|
+
width,
|
|
3464
|
+
height,
|
|
3465
|
+
depth: depthOrArrayLayers,
|
|
3466
|
+
byteAlignment: 1
|
|
3467
|
+
}).byteLength;
|
|
3468
|
+
}
|
|
3469
|
+
return allocatedByteLength * this.samples;
|
|
3470
|
+
}
|
|
3471
|
+
static _omitUndefined(options) {
|
|
3472
|
+
return Object.fromEntries(
|
|
3473
|
+
Object.entries(options).filter(([, value]) => value !== void 0)
|
|
3474
|
+
);
|
|
3475
|
+
}
|
|
2461
3476
|
};
|
|
2462
3477
|
var Texture = _Texture;
|
|
2463
3478
|
/** The texture can be bound for use as a sampled texture in a shader */
|
|
@@ -2474,13 +3489,12 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2474
3489
|
__publicField(Texture, "TEXTURE", 4);
|
|
2475
3490
|
/** @deprecated Use Texture.RENDER */
|
|
2476
3491
|
__publicField(Texture, "RENDER_ATTACHMENT", 16);
|
|
2477
|
-
/** Default options */
|
|
2478
3492
|
__publicField(Texture, "defaultProps", {
|
|
2479
3493
|
...Resource.defaultProps,
|
|
2480
3494
|
data: null,
|
|
2481
3495
|
dimension: "2d",
|
|
2482
3496
|
format: "rgba8unorm",
|
|
2483
|
-
usage: _Texture.
|
|
3497
|
+
usage: _Texture.SAMPLE | _Texture.RENDER | _Texture.COPY_DST,
|
|
2484
3498
|
width: void 0,
|
|
2485
3499
|
height: void 0,
|
|
2486
3500
|
depth: 1,
|
|
@@ -2494,6 +3508,10 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2494
3508
|
byteOffset: 0,
|
|
2495
3509
|
bytesPerRow: void 0,
|
|
2496
3510
|
rowsPerImage: void 0,
|
|
3511
|
+
width: void 0,
|
|
3512
|
+
height: void 0,
|
|
3513
|
+
depthOrArrayLayers: void 0,
|
|
3514
|
+
depth: 1,
|
|
2497
3515
|
mipLevel: 0,
|
|
2498
3516
|
x: 0,
|
|
2499
3517
|
y: 0,
|
|
@@ -2517,6 +3535,29 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2517
3535
|
premultipliedAlpha: false,
|
|
2518
3536
|
flipY: false
|
|
2519
3537
|
});
|
|
3538
|
+
__publicField(Texture, "defaultTextureReadOptions", {
|
|
3539
|
+
x: 0,
|
|
3540
|
+
y: 0,
|
|
3541
|
+
z: 0,
|
|
3542
|
+
width: void 0,
|
|
3543
|
+
height: void 0,
|
|
3544
|
+
depthOrArrayLayers: 1,
|
|
3545
|
+
mipLevel: 0,
|
|
3546
|
+
aspect: "all"
|
|
3547
|
+
});
|
|
3548
|
+
__publicField(Texture, "defaultTextureWriteOptions", {
|
|
3549
|
+
byteOffset: 0,
|
|
3550
|
+
bytesPerRow: void 0,
|
|
3551
|
+
rowsPerImage: void 0,
|
|
3552
|
+
x: 0,
|
|
3553
|
+
y: 0,
|
|
3554
|
+
z: 0,
|
|
3555
|
+
width: void 0,
|
|
3556
|
+
height: void 0,
|
|
3557
|
+
depthOrArrayLayers: 1,
|
|
3558
|
+
mipLevel: 0,
|
|
3559
|
+
aspect: "all"
|
|
3560
|
+
});
|
|
2520
3561
|
|
|
2521
3562
|
// ../core/src/adapter/resources/texture-view.ts
|
|
2522
3563
|
var _TextureView = class extends Resource {
|
|
@@ -2563,24 +3604,32 @@ or create a device with the 'debug: true' prop.`;
|
|
|
2563
3604
|
const log2 = shaderLog.slice().sort((a, b) => a.lineNum - b.lineNum);
|
|
2564
3605
|
switch (options?.showSourceCode || "no") {
|
|
2565
3606
|
case "all":
|
|
2566
|
-
let
|
|
3607
|
+
let currentMessageIndex = 0;
|
|
2567
3608
|
for (let lineNum = 1; lineNum <= lines.length; lineNum++) {
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
formattedLog +=
|
|
3609
|
+
const line = lines[lineNum - 1];
|
|
3610
|
+
const currentMessage = log2[currentMessageIndex];
|
|
3611
|
+
if (line && currentMessage) {
|
|
3612
|
+
formattedLog += getNumberedLine(line, lineNum, options);
|
|
3613
|
+
}
|
|
3614
|
+
while (log2.length > currentMessageIndex && currentMessage.lineNum === lineNum) {
|
|
3615
|
+
const message = log2[currentMessageIndex++];
|
|
3616
|
+
if (message) {
|
|
3617
|
+
formattedLog += formatCompilerMessage(message, lines, message.lineNum, {
|
|
3618
|
+
...options,
|
|
3619
|
+
inlineSource: false
|
|
3620
|
+
});
|
|
3621
|
+
}
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
while (log2.length > currentMessageIndex) {
|
|
3625
|
+
const message = log2[currentMessageIndex++];
|
|
3626
|
+
if (message) {
|
|
3627
|
+
formattedLog += formatCompilerMessage(message, [], 0, {
|
|
2572
3628
|
...options,
|
|
2573
3629
|
inlineSource: false
|
|
2574
3630
|
});
|
|
2575
3631
|
}
|
|
2576
3632
|
}
|
|
2577
|
-
while (log2.length > currentMessage) {
|
|
2578
|
-
const message = log2[currentMessage++];
|
|
2579
|
-
formattedLog += formatCompilerMessage(message, [], 0, {
|
|
2580
|
-
...options,
|
|
2581
|
-
inlineSource: false
|
|
2582
|
-
});
|
|
2583
|
-
}
|
|
2584
3633
|
return formattedLog;
|
|
2585
3634
|
case "issues":
|
|
2586
3635
|
case "no":
|
|
@@ -2602,8 +3651,8 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
2602
3651
|
|
|
2603
3652
|
`;
|
|
2604
3653
|
}
|
|
2605
|
-
const color = message.type === "error" ? "red" : "
|
|
2606
|
-
return options?.html ? `<div class='luma-compiler-log
|
|
3654
|
+
const color = message.type === "error" ? "red" : "orange";
|
|
3655
|
+
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}`;
|
|
2607
3656
|
}
|
|
2608
3657
|
function getNumberedLines(lines, lineNum, options) {
|
|
2609
3658
|
let numberedLines = "";
|
|
@@ -2689,29 +3738,34 @@ ${numberedLines}${positionIndicator}${message.type.toUpperCase()}: ${message.mes
|
|
|
2689
3738
|
}
|
|
2690
3739
|
const shaderName = shaderId;
|
|
2691
3740
|
const shaderTitle = `${this.stage} shader "${shaderName}"`;
|
|
2692
|
-
|
|
3741
|
+
const htmlLog = formatCompilerLog(messages, this.source, { showSourceCode: "all", html: true });
|
|
2693
3742
|
const translatedSource = this.getTranslatedSource();
|
|
3743
|
+
const container = document.createElement("div");
|
|
3744
|
+
container.innerHTML = `<h1>Compilation error in ${shaderTitle}</h1>
|
|
3745
|
+
<div style="display:flex;position:fixed;top:10px;right:20px;gap:2px;">
|
|
3746
|
+
<button id="copy">Copy source</button><br/>
|
|
3747
|
+
<button id="close">Close</button>
|
|
3748
|
+
</div>
|
|
3749
|
+
<code><pre>${htmlLog}</pre></code>`;
|
|
2694
3750
|
if (translatedSource) {
|
|
2695
|
-
|
|
2696
|
-
}
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
button.
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
const dataURI = `data:text/plain,${encodeURIComponent(this.source)}`;
|
|
2714
|
-
navigator.clipboard.writeText(dataURI);
|
|
3751
|
+
container.innerHTML += `<br /><h1>Translated Source</h1><br /><br /><code><pre>${translatedSource}</pre></code>`;
|
|
3752
|
+
}
|
|
3753
|
+
container.style.top = "0";
|
|
3754
|
+
container.style.left = "0";
|
|
3755
|
+
container.style.background = "white";
|
|
3756
|
+
container.style.position = "fixed";
|
|
3757
|
+
container.style.zIndex = "9999";
|
|
3758
|
+
container.style.maxWidth = "100vw";
|
|
3759
|
+
container.style.maxHeight = "100vh";
|
|
3760
|
+
container.style.overflowY = "auto";
|
|
3761
|
+
document.body.appendChild(container);
|
|
3762
|
+
const error = container.querySelector(".luma-compiler-log-error");
|
|
3763
|
+
error?.scrollIntoView();
|
|
3764
|
+
container.querySelector("button#close").onclick = () => {
|
|
3765
|
+
container.remove();
|
|
3766
|
+
};
|
|
3767
|
+
container.querySelector("button#copy").onclick = () => {
|
|
3768
|
+
navigator.clipboard.writeText(this.source);
|
|
2715
3769
|
};
|
|
2716
3770
|
}
|
|
2717
3771
|
};
|
|
@@ -2731,7 +3785,7 @@ ${htmlLog}
|
|
|
2731
3785
|
function getShaderName(shader, defaultName = "unnamed") {
|
|
2732
3786
|
const SHADER_NAME_REGEXP = /#define[\s*]SHADER_NAME[\s*]([A-Za-z0-9_-]+)[\s*]/;
|
|
2733
3787
|
const match = SHADER_NAME_REGEXP.exec(shader);
|
|
2734
|
-
return match
|
|
3788
|
+
return match?.[1] ?? defaultName;
|
|
2735
3789
|
}
|
|
2736
3790
|
|
|
2737
3791
|
// ../core/src/adapter/resources/framebuffer.ts
|
|
@@ -2757,7 +3811,12 @@ ${htmlLog}
|
|
|
2757
3811
|
(colorAttachment) => colorAttachment.texture.clone(size)
|
|
2758
3812
|
);
|
|
2759
3813
|
const depthStencilAttachment = this.depthStencilAttachment && this.depthStencilAttachment.texture.clone(size);
|
|
2760
|
-
return this.device.createFramebuffer({
|
|
3814
|
+
return this.device.createFramebuffer({
|
|
3815
|
+
...this.props,
|
|
3816
|
+
...size,
|
|
3817
|
+
colorAttachments,
|
|
3818
|
+
depthStencilAttachment
|
|
3819
|
+
});
|
|
2761
3820
|
}
|
|
2762
3821
|
resize(size) {
|
|
2763
3822
|
let updateSize = !size;
|
|
@@ -2832,17 +3891,15 @@ ${htmlLog}
|
|
|
2832
3891
|
* and destroys existing textures if owned
|
|
2833
3892
|
*/
|
|
2834
3893
|
resizeAttachments(width, height) {
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
}
|
|
2845
|
-
}
|
|
3894
|
+
this.colorAttachments.forEach((colorAttachment, i) => {
|
|
3895
|
+
const resizedTexture = colorAttachment.texture.clone({
|
|
3896
|
+
width,
|
|
3897
|
+
height
|
|
3898
|
+
});
|
|
3899
|
+
this.destroyAttachedResource(colorAttachment);
|
|
3900
|
+
this.colorAttachments[i] = resizedTexture.view;
|
|
3901
|
+
this.attachResource(resizedTexture.view);
|
|
3902
|
+
});
|
|
2846
3903
|
if (this.depthStencilAttachment) {
|
|
2847
3904
|
const resizedTexture = this.depthStencilAttachment.texture.clone({
|
|
2848
3905
|
width,
|
|
@@ -2879,30 +3936,538 @@ ${htmlLog}
|
|
|
2879
3936
|
linkStatus = "pending";
|
|
2880
3937
|
/** The hash of the pipeline */
|
|
2881
3938
|
hash = "";
|
|
3939
|
+
/** Optional shared backend implementation */
|
|
3940
|
+
sharedRenderPipeline = null;
|
|
3941
|
+
/** Whether shader or pipeline compilation/linking is still in progress */
|
|
3942
|
+
get isPending() {
|
|
3943
|
+
return this.linkStatus === "pending" || this.vs.compilationStatus === "pending" || this.fs?.compilationStatus === "pending";
|
|
3944
|
+
}
|
|
3945
|
+
/** Whether shader or pipeline compilation/linking has failed */
|
|
3946
|
+
get isErrored() {
|
|
3947
|
+
return this.linkStatus === "error" || this.vs.compilationStatus === "error" || this.fs?.compilationStatus === "error";
|
|
3948
|
+
}
|
|
2882
3949
|
constructor(device, props) {
|
|
2883
3950
|
super(device, props, _RenderPipeline.defaultProps);
|
|
2884
3951
|
this.shaderLayout = this.props.shaderLayout;
|
|
2885
3952
|
this.bufferLayout = this.props.bufferLayout || [];
|
|
3953
|
+
this.sharedRenderPipeline = this.props._sharedRenderPipeline || null;
|
|
3954
|
+
}
|
|
3955
|
+
};
|
|
3956
|
+
var RenderPipeline = _RenderPipeline;
|
|
3957
|
+
__publicField(RenderPipeline, "defaultProps", {
|
|
3958
|
+
...Resource.defaultProps,
|
|
3959
|
+
vs: null,
|
|
3960
|
+
vertexEntryPoint: "vertexMain",
|
|
3961
|
+
vsConstants: {},
|
|
3962
|
+
fs: null,
|
|
3963
|
+
fragmentEntryPoint: "fragmentMain",
|
|
3964
|
+
fsConstants: {},
|
|
3965
|
+
shaderLayout: null,
|
|
3966
|
+
bufferLayout: [],
|
|
3967
|
+
topology: "triangle-list",
|
|
3968
|
+
colorAttachmentFormats: void 0,
|
|
3969
|
+
depthStencilAttachmentFormat: void 0,
|
|
3970
|
+
parameters: {},
|
|
3971
|
+
varyings: void 0,
|
|
3972
|
+
bufferMode: void 0,
|
|
3973
|
+
disableWarnings: false,
|
|
3974
|
+
_sharedRenderPipeline: void 0,
|
|
3975
|
+
bindings: void 0,
|
|
3976
|
+
bindGroups: void 0
|
|
3977
|
+
});
|
|
3978
|
+
|
|
3979
|
+
// ../core/src/adapter/resources/shared-render-pipeline.ts
|
|
3980
|
+
var SharedRenderPipeline = class extends Resource {
|
|
3981
|
+
get [Symbol.toStringTag]() {
|
|
3982
|
+
return "SharedRenderPipeline";
|
|
3983
|
+
}
|
|
3984
|
+
constructor(device, props) {
|
|
3985
|
+
super(device, props, {
|
|
3986
|
+
...Resource.defaultProps,
|
|
3987
|
+
handle: void 0,
|
|
3988
|
+
vs: void 0,
|
|
3989
|
+
fs: void 0,
|
|
3990
|
+
varyings: void 0,
|
|
3991
|
+
bufferMode: void 0
|
|
3992
|
+
});
|
|
3993
|
+
}
|
|
3994
|
+
};
|
|
3995
|
+
|
|
3996
|
+
// ../core/src/adapter/resources/compute-pipeline.ts
|
|
3997
|
+
var _ComputePipeline = class extends Resource {
|
|
3998
|
+
get [Symbol.toStringTag]() {
|
|
3999
|
+
return "ComputePipeline";
|
|
4000
|
+
}
|
|
4001
|
+
hash = "";
|
|
4002
|
+
/** The merged shader layout */
|
|
4003
|
+
shaderLayout;
|
|
4004
|
+
constructor(device, props) {
|
|
4005
|
+
super(device, props, _ComputePipeline.defaultProps);
|
|
4006
|
+
this.shaderLayout = props.shaderLayout;
|
|
4007
|
+
}
|
|
4008
|
+
};
|
|
4009
|
+
var ComputePipeline = _ComputePipeline;
|
|
4010
|
+
__publicField(ComputePipeline, "defaultProps", {
|
|
4011
|
+
...Resource.defaultProps,
|
|
4012
|
+
shader: void 0,
|
|
4013
|
+
entryPoint: void 0,
|
|
4014
|
+
constants: {},
|
|
4015
|
+
shaderLayout: void 0
|
|
4016
|
+
});
|
|
4017
|
+
|
|
4018
|
+
// ../core/src/factories/pipeline-factory.ts
|
|
4019
|
+
var _PipelineFactory = class {
|
|
4020
|
+
/** Get the singleton default pipeline factory for the specified device */
|
|
4021
|
+
static getDefaultPipelineFactory(device) {
|
|
4022
|
+
const moduleData = device.getModuleData("@luma.gl/core");
|
|
4023
|
+
moduleData.defaultPipelineFactory ||= new _PipelineFactory(device);
|
|
4024
|
+
return moduleData.defaultPipelineFactory;
|
|
4025
|
+
}
|
|
4026
|
+
device;
|
|
4027
|
+
_hashCounter = 0;
|
|
4028
|
+
_hashes = {};
|
|
4029
|
+
_renderPipelineCache = {};
|
|
4030
|
+
_computePipelineCache = {};
|
|
4031
|
+
_sharedRenderPipelineCache = {};
|
|
4032
|
+
get [Symbol.toStringTag]() {
|
|
4033
|
+
return "PipelineFactory";
|
|
4034
|
+
}
|
|
4035
|
+
toString() {
|
|
4036
|
+
return `PipelineFactory(${this.device.id})`;
|
|
4037
|
+
}
|
|
4038
|
+
constructor(device) {
|
|
4039
|
+
this.device = device;
|
|
4040
|
+
}
|
|
4041
|
+
/**
|
|
4042
|
+
* WebGL has two cache layers with different priorities:
|
|
4043
|
+
* - `_sharedRenderPipelineCache` owns `WEBGLSharedRenderPipeline` / `WebGLProgram` reuse.
|
|
4044
|
+
* - `_renderPipelineCache` owns `RenderPipeline` wrapper reuse.
|
|
4045
|
+
*
|
|
4046
|
+
* Shared WebGL program reuse is the hard requirement. Wrapper reuse is beneficial,
|
|
4047
|
+
* but wrapper cache misses are acceptable if that keeps the cache logic simple and
|
|
4048
|
+
* prevents incorrect cache hits.
|
|
4049
|
+
*
|
|
4050
|
+
* In particular, wrapper hash logic must never force program creation or linked-program
|
|
4051
|
+
* introspection just to decide whether a shared WebGL program can be reused.
|
|
4052
|
+
*/
|
|
4053
|
+
/** Return a RenderPipeline matching supplied props. Reuses an equivalent pipeline if already created. */
|
|
4054
|
+
createRenderPipeline(props) {
|
|
4055
|
+
if (!this.device.props._cachePipelines) {
|
|
4056
|
+
return this.device.createRenderPipeline(props);
|
|
4057
|
+
}
|
|
4058
|
+
const allProps = { ...RenderPipeline.defaultProps, ...props };
|
|
4059
|
+
const cache = this._renderPipelineCache;
|
|
4060
|
+
const hash = this._hashRenderPipeline(allProps);
|
|
4061
|
+
let pipeline = cache[hash]?.resource;
|
|
4062
|
+
if (!pipeline) {
|
|
4063
|
+
const sharedRenderPipeline = this.device.type === "webgl" && this.device.props._sharePipelines ? this.createSharedRenderPipeline(allProps) : void 0;
|
|
4064
|
+
pipeline = this.device.createRenderPipeline({
|
|
4065
|
+
...allProps,
|
|
4066
|
+
id: allProps.id ? `${allProps.id}-cached` : uid("unnamed-cached"),
|
|
4067
|
+
_sharedRenderPipeline: sharedRenderPipeline
|
|
4068
|
+
});
|
|
4069
|
+
pipeline.hash = hash;
|
|
4070
|
+
cache[hash] = { resource: pipeline, useCount: 1 };
|
|
4071
|
+
if (this.device.props.debugFactories) {
|
|
4072
|
+
log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
|
|
4073
|
+
}
|
|
4074
|
+
} else {
|
|
4075
|
+
cache[hash].useCount++;
|
|
4076
|
+
if (this.device.props.debugFactories) {
|
|
4077
|
+
log.log(
|
|
4078
|
+
3,
|
|
4079
|
+
`${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`
|
|
4080
|
+
)();
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
return pipeline;
|
|
4084
|
+
}
|
|
4085
|
+
/** Return a ComputePipeline matching supplied props. Reuses an equivalent pipeline if already created. */
|
|
4086
|
+
createComputePipeline(props) {
|
|
4087
|
+
if (!this.device.props._cachePipelines) {
|
|
4088
|
+
return this.device.createComputePipeline(props);
|
|
4089
|
+
}
|
|
4090
|
+
const allProps = { ...ComputePipeline.defaultProps, ...props };
|
|
4091
|
+
const cache = this._computePipelineCache;
|
|
4092
|
+
const hash = this._hashComputePipeline(allProps);
|
|
4093
|
+
let pipeline = cache[hash]?.resource;
|
|
4094
|
+
if (!pipeline) {
|
|
4095
|
+
pipeline = this.device.createComputePipeline({
|
|
4096
|
+
...allProps,
|
|
4097
|
+
id: allProps.id ? `${allProps.id}-cached` : void 0
|
|
4098
|
+
});
|
|
4099
|
+
pipeline.hash = hash;
|
|
4100
|
+
cache[hash] = { resource: pipeline, useCount: 1 };
|
|
4101
|
+
if (this.device.props.debugFactories) {
|
|
4102
|
+
log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
|
|
4103
|
+
}
|
|
4104
|
+
} else {
|
|
4105
|
+
cache[hash].useCount++;
|
|
4106
|
+
if (this.device.props.debugFactories) {
|
|
4107
|
+
log.log(
|
|
4108
|
+
3,
|
|
4109
|
+
`${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`
|
|
4110
|
+
)();
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4113
|
+
return pipeline;
|
|
4114
|
+
}
|
|
4115
|
+
release(pipeline) {
|
|
4116
|
+
if (!this.device.props._cachePipelines) {
|
|
4117
|
+
pipeline.destroy();
|
|
4118
|
+
return;
|
|
4119
|
+
}
|
|
4120
|
+
const cache = this._getCache(pipeline);
|
|
4121
|
+
const hash = pipeline.hash;
|
|
4122
|
+
cache[hash].useCount--;
|
|
4123
|
+
if (cache[hash].useCount === 0) {
|
|
4124
|
+
this._destroyPipeline(pipeline);
|
|
4125
|
+
if (this.device.props.debugFactories) {
|
|
4126
|
+
log.log(3, `${this}: ${pipeline} released and destroyed`)();
|
|
4127
|
+
}
|
|
4128
|
+
} else if (cache[hash].useCount < 0) {
|
|
4129
|
+
log.error(`${this}: ${pipeline} released, useCount < 0, resetting`)();
|
|
4130
|
+
cache[hash].useCount = 0;
|
|
4131
|
+
} else if (this.device.props.debugFactories) {
|
|
4132
|
+
log.log(3, `${this}: ${pipeline} released, count=${cache[hash].useCount}`)();
|
|
4133
|
+
}
|
|
4134
|
+
}
|
|
4135
|
+
createSharedRenderPipeline(props) {
|
|
4136
|
+
const sharedPipelineHash = this._hashSharedRenderPipeline(props);
|
|
4137
|
+
let sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
4138
|
+
if (!sharedCacheItem) {
|
|
4139
|
+
const sharedRenderPipeline = this.device._createSharedRenderPipelineWebGL(props);
|
|
4140
|
+
sharedCacheItem = { resource: sharedRenderPipeline, useCount: 0 };
|
|
4141
|
+
this._sharedRenderPipelineCache[sharedPipelineHash] = sharedCacheItem;
|
|
4142
|
+
}
|
|
4143
|
+
sharedCacheItem.useCount++;
|
|
4144
|
+
return sharedCacheItem.resource;
|
|
4145
|
+
}
|
|
4146
|
+
releaseSharedRenderPipeline(pipeline) {
|
|
4147
|
+
if (!pipeline.sharedRenderPipeline) {
|
|
4148
|
+
return;
|
|
4149
|
+
}
|
|
4150
|
+
const sharedPipelineHash = this._hashSharedRenderPipeline(pipeline.sharedRenderPipeline.props);
|
|
4151
|
+
const sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
4152
|
+
if (!sharedCacheItem) {
|
|
4153
|
+
return;
|
|
4154
|
+
}
|
|
4155
|
+
sharedCacheItem.useCount--;
|
|
4156
|
+
if (sharedCacheItem.useCount === 0) {
|
|
4157
|
+
sharedCacheItem.resource.destroy();
|
|
4158
|
+
delete this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
4159
|
+
}
|
|
4160
|
+
}
|
|
4161
|
+
// PRIVATE
|
|
4162
|
+
/** Destroy a cached pipeline, removing it from the cache if configured to do so. */
|
|
4163
|
+
_destroyPipeline(pipeline) {
|
|
4164
|
+
const cache = this._getCache(pipeline);
|
|
4165
|
+
if (!this.device.props._destroyPipelines) {
|
|
4166
|
+
return false;
|
|
4167
|
+
}
|
|
4168
|
+
delete cache[pipeline.hash];
|
|
4169
|
+
pipeline.destroy();
|
|
4170
|
+
if (pipeline instanceof RenderPipeline) {
|
|
4171
|
+
this.releaseSharedRenderPipeline(pipeline);
|
|
4172
|
+
}
|
|
4173
|
+
return true;
|
|
4174
|
+
}
|
|
4175
|
+
/** Get the appropriate cache for the type of pipeline */
|
|
4176
|
+
_getCache(pipeline) {
|
|
4177
|
+
let cache;
|
|
4178
|
+
if (pipeline instanceof ComputePipeline) {
|
|
4179
|
+
cache = this._computePipelineCache;
|
|
4180
|
+
}
|
|
4181
|
+
if (pipeline instanceof RenderPipeline) {
|
|
4182
|
+
cache = this._renderPipelineCache;
|
|
4183
|
+
}
|
|
4184
|
+
if (!cache) {
|
|
4185
|
+
throw new Error(`${this}`);
|
|
4186
|
+
}
|
|
4187
|
+
if (!cache[pipeline.hash]) {
|
|
4188
|
+
throw new Error(`${this}: ${pipeline} matched incorrect entry`);
|
|
4189
|
+
}
|
|
4190
|
+
return cache;
|
|
4191
|
+
}
|
|
4192
|
+
/** Calculate a hash based on all the inputs for a compute pipeline */
|
|
4193
|
+
_hashComputePipeline(props) {
|
|
4194
|
+
const { type } = this.device;
|
|
4195
|
+
const shaderHash = this._getHash(props.shader.source);
|
|
4196
|
+
const shaderLayoutHash = this._getHash(JSON.stringify(props.shaderLayout));
|
|
4197
|
+
return `${type}/C/${shaderHash}SL${shaderLayoutHash}`;
|
|
4198
|
+
}
|
|
4199
|
+
/** Calculate a hash based on all the inputs for a render pipeline */
|
|
4200
|
+
_hashRenderPipeline(props) {
|
|
4201
|
+
const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
|
|
4202
|
+
const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
|
|
4203
|
+
const varyingHash = this._getWebGLVaryingHash(props);
|
|
4204
|
+
const shaderLayoutHash = this._getHash(JSON.stringify(props.shaderLayout));
|
|
4205
|
+
const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
|
|
4206
|
+
const { type } = this.device;
|
|
4207
|
+
switch (type) {
|
|
4208
|
+
case "webgl":
|
|
4209
|
+
const webglParameterHash = this._getHash(JSON.stringify(props.parameters));
|
|
4210
|
+
return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${webglParameterHash}SL${shaderLayoutHash}BL${bufferLayoutHash}`;
|
|
4211
|
+
case "webgpu":
|
|
4212
|
+
default:
|
|
4213
|
+
const entryPointHash = this._getHash(
|
|
4214
|
+
JSON.stringify({
|
|
4215
|
+
vertexEntryPoint: props.vertexEntryPoint,
|
|
4216
|
+
fragmentEntryPoint: props.fragmentEntryPoint
|
|
4217
|
+
})
|
|
4218
|
+
);
|
|
4219
|
+
const parameterHash = this._getHash(JSON.stringify(props.parameters));
|
|
4220
|
+
const attachmentHash = this._getWebGPUAttachmentHash(props);
|
|
4221
|
+
return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}EP${entryPointHash}P${parameterHash}SL${shaderLayoutHash}BL${bufferLayoutHash}A${attachmentHash}`;
|
|
4222
|
+
}
|
|
4223
|
+
}
|
|
4224
|
+
// This is the only gate for shared `WebGLProgram` reuse.
|
|
4225
|
+
// Only include inputs that affect program linking or transform-feedback linkage.
|
|
4226
|
+
// Wrapper-only concerns such as topology, parameters, attachment formats and layout
|
|
4227
|
+
// overrides must not be added here.
|
|
4228
|
+
_hashSharedRenderPipeline(props) {
|
|
4229
|
+
const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
|
|
4230
|
+
const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
|
|
4231
|
+
const varyingHash = this._getWebGLVaryingHash(props);
|
|
4232
|
+
return `webgl/S/${vsHash}/${fsHash}V${varyingHash}`;
|
|
4233
|
+
}
|
|
4234
|
+
_getHash(key) {
|
|
4235
|
+
if (this._hashes[key] === void 0) {
|
|
4236
|
+
this._hashes[key] = this._hashCounter++;
|
|
4237
|
+
}
|
|
4238
|
+
return this._hashes[key];
|
|
4239
|
+
}
|
|
4240
|
+
_getWebGLVaryingHash(props) {
|
|
4241
|
+
const { varyings = [], bufferMode = null } = props;
|
|
4242
|
+
return this._getHash(JSON.stringify({ varyings, bufferMode }));
|
|
4243
|
+
}
|
|
4244
|
+
_getWebGPUAttachmentHash(props) {
|
|
4245
|
+
const colorAttachmentFormats = props.colorAttachmentFormats ?? [
|
|
4246
|
+
this.device.preferredColorFormat
|
|
4247
|
+
];
|
|
4248
|
+
const depthStencilAttachmentFormat = props.parameters?.depthWriteEnabled ? props.depthStencilAttachmentFormat || this.device.preferredDepthFormat : null;
|
|
4249
|
+
return this._getHash(
|
|
4250
|
+
JSON.stringify({
|
|
4251
|
+
colorAttachmentFormats,
|
|
4252
|
+
depthStencilAttachmentFormat
|
|
4253
|
+
})
|
|
4254
|
+
);
|
|
4255
|
+
}
|
|
4256
|
+
};
|
|
4257
|
+
var PipelineFactory = _PipelineFactory;
|
|
4258
|
+
__publicField(PipelineFactory, "defaultProps", { ...RenderPipeline.defaultProps });
|
|
4259
|
+
|
|
4260
|
+
// ../core/src/factories/shader-factory.ts
|
|
4261
|
+
var _ShaderFactory = class {
|
|
4262
|
+
/** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
|
|
4263
|
+
static getDefaultShaderFactory(device) {
|
|
4264
|
+
const moduleData = device.getModuleData("@luma.gl/core");
|
|
4265
|
+
moduleData.defaultShaderFactory ||= new _ShaderFactory(device);
|
|
4266
|
+
return moduleData.defaultShaderFactory;
|
|
4267
|
+
}
|
|
4268
|
+
device;
|
|
4269
|
+
_cache = {};
|
|
4270
|
+
get [Symbol.toStringTag]() {
|
|
4271
|
+
return "ShaderFactory";
|
|
4272
|
+
}
|
|
4273
|
+
toString() {
|
|
4274
|
+
return `${this[Symbol.toStringTag]}(${this.device.id})`;
|
|
4275
|
+
}
|
|
4276
|
+
/** @internal */
|
|
4277
|
+
constructor(device) {
|
|
4278
|
+
this.device = device;
|
|
4279
|
+
}
|
|
4280
|
+
/** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
|
|
4281
|
+
createShader(props) {
|
|
4282
|
+
if (!this.device.props._cacheShaders) {
|
|
4283
|
+
return this.device.createShader(props);
|
|
4284
|
+
}
|
|
4285
|
+
const key = this._hashShader(props);
|
|
4286
|
+
let cacheEntry = this._cache[key];
|
|
4287
|
+
if (!cacheEntry) {
|
|
4288
|
+
const resource = this.device.createShader({
|
|
4289
|
+
...props,
|
|
4290
|
+
id: props.id ? `${props.id}-cached` : void 0
|
|
4291
|
+
});
|
|
4292
|
+
this._cache[key] = cacheEntry = { resource, useCount: 1 };
|
|
4293
|
+
if (this.device.props.debugFactories) {
|
|
4294
|
+
log.log(3, `${this}: Created new shader ${resource.id}`)();
|
|
4295
|
+
}
|
|
4296
|
+
} else {
|
|
4297
|
+
cacheEntry.useCount++;
|
|
4298
|
+
if (this.device.props.debugFactories) {
|
|
4299
|
+
log.log(
|
|
4300
|
+
3,
|
|
4301
|
+
`${this}: Reusing shader ${cacheEntry.resource.id} count=${cacheEntry.useCount}`
|
|
4302
|
+
)();
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4305
|
+
return cacheEntry.resource;
|
|
4306
|
+
}
|
|
4307
|
+
/** Releases a previously-requested {@link Shader}, destroying it if no users remain. */
|
|
4308
|
+
release(shader) {
|
|
4309
|
+
if (!this.device.props._cacheShaders) {
|
|
4310
|
+
shader.destroy();
|
|
4311
|
+
return;
|
|
4312
|
+
}
|
|
4313
|
+
const key = this._hashShader(shader);
|
|
4314
|
+
const cacheEntry = this._cache[key];
|
|
4315
|
+
if (cacheEntry) {
|
|
4316
|
+
cacheEntry.useCount--;
|
|
4317
|
+
if (cacheEntry.useCount === 0) {
|
|
4318
|
+
if (this.device.props._destroyShaders) {
|
|
4319
|
+
delete this._cache[key];
|
|
4320
|
+
cacheEntry.resource.destroy();
|
|
4321
|
+
if (this.device.props.debugFactories) {
|
|
4322
|
+
log.log(3, `${this}: Releasing shader ${shader.id}, destroyed`)();
|
|
4323
|
+
}
|
|
4324
|
+
}
|
|
4325
|
+
} else if (cacheEntry.useCount < 0) {
|
|
4326
|
+
throw new Error(`ShaderFactory: Shader ${shader.id} released too many times`);
|
|
4327
|
+
} else if (this.device.props.debugFactories) {
|
|
4328
|
+
log.log(3, `${this}: Releasing shader ${shader.id} count=${cacheEntry.useCount}`)();
|
|
4329
|
+
}
|
|
4330
|
+
}
|
|
4331
|
+
}
|
|
4332
|
+
// PRIVATE
|
|
4333
|
+
_hashShader(value) {
|
|
4334
|
+
return `${value.stage}:${value.source}`;
|
|
4335
|
+
}
|
|
4336
|
+
};
|
|
4337
|
+
var ShaderFactory = _ShaderFactory;
|
|
4338
|
+
__publicField(ShaderFactory, "defaultProps", { ...Shader.defaultProps });
|
|
4339
|
+
|
|
4340
|
+
// ../core/src/adapter-utils/bind-groups.ts
|
|
4341
|
+
function getShaderLayoutBinding(shaderLayout, bindingName, options) {
|
|
4342
|
+
const bindingLayout = shaderLayout.bindings.find(
|
|
4343
|
+
(binding) => binding.name === bindingName || `${binding.name.toLocaleLowerCase()}uniforms` === bindingName.toLocaleLowerCase()
|
|
4344
|
+
);
|
|
4345
|
+
if (!bindingLayout && !options?.ignoreWarnings) {
|
|
4346
|
+
log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();
|
|
4347
|
+
}
|
|
4348
|
+
return bindingLayout || null;
|
|
4349
|
+
}
|
|
4350
|
+
function normalizeBindingsByGroup(shaderLayout, bindingsOrBindGroups) {
|
|
4351
|
+
if (!bindingsOrBindGroups) {
|
|
4352
|
+
return {};
|
|
4353
|
+
}
|
|
4354
|
+
if (areBindingsGrouped(bindingsOrBindGroups)) {
|
|
4355
|
+
const bindGroups2 = bindingsOrBindGroups;
|
|
4356
|
+
return Object.fromEntries(
|
|
4357
|
+
Object.entries(bindGroups2).map(([group, bindings]) => [Number(group), { ...bindings }])
|
|
4358
|
+
);
|
|
4359
|
+
}
|
|
4360
|
+
const bindGroups = {};
|
|
4361
|
+
for (const [bindingName, binding] of Object.entries(bindingsOrBindGroups)) {
|
|
4362
|
+
const bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
|
|
4363
|
+
const group = bindingLayout?.group ?? 0;
|
|
4364
|
+
bindGroups[group] ||= {};
|
|
4365
|
+
bindGroups[group][bindingName] = binding;
|
|
4366
|
+
}
|
|
4367
|
+
return bindGroups;
|
|
4368
|
+
}
|
|
4369
|
+
function flattenBindingsByGroup(bindGroups) {
|
|
4370
|
+
const bindings = {};
|
|
4371
|
+
for (const groupBindings of Object.values(bindGroups)) {
|
|
4372
|
+
Object.assign(bindings, groupBindings);
|
|
4373
|
+
}
|
|
4374
|
+
return bindings;
|
|
4375
|
+
}
|
|
4376
|
+
function areBindingsGrouped(bindingsOrBindGroups) {
|
|
4377
|
+
const keys = Object.keys(bindingsOrBindGroups);
|
|
4378
|
+
return keys.length > 0 && keys.every((key) => /^\d+$/.test(key));
|
|
4379
|
+
}
|
|
4380
|
+
|
|
4381
|
+
// ../core/src/factories/bind-group-factory.ts
|
|
4382
|
+
var BindGroupFactory = class {
|
|
4383
|
+
device;
|
|
4384
|
+
_layoutCacheByPipeline = /* @__PURE__ */ new WeakMap();
|
|
4385
|
+
_bindGroupCacheByLayout = /* @__PURE__ */ new WeakMap();
|
|
4386
|
+
constructor(device) {
|
|
4387
|
+
this.device = device;
|
|
4388
|
+
}
|
|
4389
|
+
getBindGroups(pipeline, bindings, bindGroupCacheKeys) {
|
|
4390
|
+
if (this.device.type !== "webgpu" || pipeline.shaderLayout.bindings.length === 0) {
|
|
4391
|
+
return {};
|
|
4392
|
+
}
|
|
4393
|
+
const bindingsByGroup = normalizeBindingsByGroup(pipeline.shaderLayout, bindings);
|
|
4394
|
+
const resolvedBindGroups = {};
|
|
4395
|
+
for (const group of getBindGroupIndicesUpToMax(pipeline.shaderLayout.bindings)) {
|
|
4396
|
+
const groupBindings = bindingsByGroup[group];
|
|
4397
|
+
const bindGroupLayout = this._getBindGroupLayout(pipeline, group);
|
|
4398
|
+
if (!groupBindings || Object.keys(groupBindings).length === 0) {
|
|
4399
|
+
if (!hasBindingsInGroup(pipeline.shaderLayout.bindings, group)) {
|
|
4400
|
+
resolvedBindGroups[group] = this._getEmptyBindGroup(
|
|
4401
|
+
bindGroupLayout,
|
|
4402
|
+
pipeline.shaderLayout,
|
|
4403
|
+
group
|
|
4404
|
+
);
|
|
4405
|
+
}
|
|
4406
|
+
continue;
|
|
4407
|
+
}
|
|
4408
|
+
const bindGroupCacheKey = bindGroupCacheKeys?.[group];
|
|
4409
|
+
if (bindGroupCacheKey) {
|
|
4410
|
+
const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
|
|
4411
|
+
if (layoutCache.bindGroupsBySource.has(bindGroupCacheKey)) {
|
|
4412
|
+
resolvedBindGroups[group] = layoutCache.bindGroupsBySource.get(bindGroupCacheKey) || null;
|
|
4413
|
+
continue;
|
|
4414
|
+
}
|
|
4415
|
+
const bindGroup = this.device._createBindGroupWebGPU(
|
|
4416
|
+
bindGroupLayout,
|
|
4417
|
+
pipeline.shaderLayout,
|
|
4418
|
+
groupBindings,
|
|
4419
|
+
group
|
|
4420
|
+
);
|
|
4421
|
+
layoutCache.bindGroupsBySource.set(bindGroupCacheKey, bindGroup);
|
|
4422
|
+
resolvedBindGroups[group] = bindGroup;
|
|
4423
|
+
} else {
|
|
4424
|
+
resolvedBindGroups[group] = this.device._createBindGroupWebGPU(
|
|
4425
|
+
bindGroupLayout,
|
|
4426
|
+
pipeline.shaderLayout,
|
|
4427
|
+
groupBindings,
|
|
4428
|
+
group
|
|
4429
|
+
);
|
|
4430
|
+
}
|
|
4431
|
+
}
|
|
4432
|
+
return resolvedBindGroups;
|
|
4433
|
+
}
|
|
4434
|
+
_getBindGroupLayout(pipeline, group) {
|
|
4435
|
+
let layoutCache = this._layoutCacheByPipeline.get(pipeline);
|
|
4436
|
+
if (!layoutCache) {
|
|
4437
|
+
layoutCache = {};
|
|
4438
|
+
this._layoutCacheByPipeline.set(pipeline, layoutCache);
|
|
4439
|
+
}
|
|
4440
|
+
layoutCache[group] ||= this.device._createBindGroupLayoutWebGPU(pipeline, group);
|
|
4441
|
+
return layoutCache[group];
|
|
4442
|
+
}
|
|
4443
|
+
_getEmptyBindGroup(bindGroupLayout, shaderLayout, group) {
|
|
4444
|
+
const layoutCache = this._getLayoutBindGroupCache(bindGroupLayout);
|
|
4445
|
+
layoutCache.emptyBindGroup ||= this.device._createBindGroupWebGPU(bindGroupLayout, shaderLayout, {}, group) || null;
|
|
4446
|
+
return layoutCache.emptyBindGroup;
|
|
4447
|
+
}
|
|
4448
|
+
_getLayoutBindGroupCache(bindGroupLayout) {
|
|
4449
|
+
let layoutCache = this._bindGroupCacheByLayout.get(bindGroupLayout);
|
|
4450
|
+
if (!layoutCache) {
|
|
4451
|
+
layoutCache = { bindGroupsBySource: /* @__PURE__ */ new WeakMap() };
|
|
4452
|
+
this._bindGroupCacheByLayout.set(bindGroupLayout, layoutCache);
|
|
4453
|
+
}
|
|
4454
|
+
return layoutCache;
|
|
2886
4455
|
}
|
|
2887
4456
|
};
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
parameters: {},
|
|
2903
|
-
bindings: {},
|
|
2904
|
-
uniforms: {}
|
|
2905
|
-
});
|
|
4457
|
+
function _getDefaultBindGroupFactory(device) {
|
|
4458
|
+
device._factories.bindGroupFactory ||= new BindGroupFactory(device);
|
|
4459
|
+
return device._factories.bindGroupFactory;
|
|
4460
|
+
}
|
|
4461
|
+
function getBindGroupIndicesUpToMax(bindings) {
|
|
4462
|
+
const maxGroup = bindings.reduce(
|
|
4463
|
+
(highestGroup, binding) => Math.max(highestGroup, binding.group),
|
|
4464
|
+
-1
|
|
4465
|
+
);
|
|
4466
|
+
return Array.from({ length: maxGroup + 1 }, (_, group) => group);
|
|
4467
|
+
}
|
|
4468
|
+
function hasBindingsInGroup(bindings, group) {
|
|
4469
|
+
return bindings.some((binding) => binding.group === group);
|
|
4470
|
+
}
|
|
2906
4471
|
|
|
2907
4472
|
// ../core/src/adapter/resources/render-pass.ts
|
|
2908
4473
|
var _RenderPass = class extends Resource {
|
|
@@ -2942,28 +4507,6 @@ ${htmlLog}
|
|
|
2942
4507
|
endTimestampIndex: void 0
|
|
2943
4508
|
});
|
|
2944
4509
|
|
|
2945
|
-
// ../core/src/adapter/resources/compute-pipeline.ts
|
|
2946
|
-
var _ComputePipeline = class extends Resource {
|
|
2947
|
-
get [Symbol.toStringTag]() {
|
|
2948
|
-
return "ComputePipeline";
|
|
2949
|
-
}
|
|
2950
|
-
hash = "";
|
|
2951
|
-
/** The merged shader layout */
|
|
2952
|
-
shaderLayout;
|
|
2953
|
-
constructor(device, props) {
|
|
2954
|
-
super(device, props, _ComputePipeline.defaultProps);
|
|
2955
|
-
this.shaderLayout = props.shaderLayout;
|
|
2956
|
-
}
|
|
2957
|
-
};
|
|
2958
|
-
var ComputePipeline = _ComputePipeline;
|
|
2959
|
-
__publicField(ComputePipeline, "defaultProps", {
|
|
2960
|
-
...Resource.defaultProps,
|
|
2961
|
-
shader: void 0,
|
|
2962
|
-
entryPoint: void 0,
|
|
2963
|
-
constants: {},
|
|
2964
|
-
shaderLayout: void 0
|
|
2965
|
-
});
|
|
2966
|
-
|
|
2967
4510
|
// ../core/src/adapter/resources/compute-pass.ts
|
|
2968
4511
|
var _ComputePass = class extends Resource {
|
|
2969
4512
|
constructor(device, props) {
|
|
@@ -2986,8 +4529,69 @@ ${htmlLog}
|
|
|
2986
4529
|
get [Symbol.toStringTag]() {
|
|
2987
4530
|
return "CommandEncoder";
|
|
2988
4531
|
}
|
|
4532
|
+
_timeProfilingQuerySet = null;
|
|
4533
|
+
_timeProfilingSlotCount = 0;
|
|
4534
|
+
_gpuTimeMs;
|
|
2989
4535
|
constructor(device, props) {
|
|
2990
4536
|
super(device, props, _CommandEncoder.defaultProps);
|
|
4537
|
+
this._timeProfilingQuerySet = props.timeProfilingQuerySet ?? null;
|
|
4538
|
+
this._timeProfilingSlotCount = 0;
|
|
4539
|
+
this._gpuTimeMs = void 0;
|
|
4540
|
+
}
|
|
4541
|
+
/**
|
|
4542
|
+
* Reads all resolved timestamp pairs on the current profiler query set and caches the sum
|
|
4543
|
+
* as milliseconds on this encoder.
|
|
4544
|
+
*/
|
|
4545
|
+
async resolveTimeProfilingQuerySet() {
|
|
4546
|
+
this._gpuTimeMs = void 0;
|
|
4547
|
+
if (!this._timeProfilingQuerySet) {
|
|
4548
|
+
return;
|
|
4549
|
+
}
|
|
4550
|
+
const pairCount = Math.floor(this._timeProfilingSlotCount / 2);
|
|
4551
|
+
if (pairCount <= 0) {
|
|
4552
|
+
return;
|
|
4553
|
+
}
|
|
4554
|
+
const queryCount = pairCount * 2;
|
|
4555
|
+
const results = await this._timeProfilingQuerySet.readResults({
|
|
4556
|
+
firstQuery: 0,
|
|
4557
|
+
queryCount
|
|
4558
|
+
});
|
|
4559
|
+
let totalDurationNanoseconds = 0n;
|
|
4560
|
+
for (let queryIndex = 0; queryIndex < queryCount; queryIndex += 2) {
|
|
4561
|
+
totalDurationNanoseconds += results[queryIndex + 1] - results[queryIndex];
|
|
4562
|
+
}
|
|
4563
|
+
this._gpuTimeMs = Number(totalDurationNanoseconds) / 1e6;
|
|
4564
|
+
}
|
|
4565
|
+
/** Returns the number of query slots consumed by automatic pass profiling on this encoder. */
|
|
4566
|
+
getTimeProfilingSlotCount() {
|
|
4567
|
+
return this._timeProfilingSlotCount;
|
|
4568
|
+
}
|
|
4569
|
+
getTimeProfilingQuerySet() {
|
|
4570
|
+
return this._timeProfilingQuerySet;
|
|
4571
|
+
}
|
|
4572
|
+
/** Internal helper for auto-assigning timestamp slots to render/compute passes on this encoder. */
|
|
4573
|
+
_applyTimeProfilingToPassProps(props) {
|
|
4574
|
+
const passProps = props || {};
|
|
4575
|
+
if (!this._supportsTimestampQueries() || !this._timeProfilingQuerySet) {
|
|
4576
|
+
return passProps;
|
|
4577
|
+
}
|
|
4578
|
+
if (passProps.timestampQuerySet !== void 0 || passProps.beginTimestampIndex !== void 0 || passProps.endTimestampIndex !== void 0) {
|
|
4579
|
+
return passProps;
|
|
4580
|
+
}
|
|
4581
|
+
const beginTimestampIndex = this._timeProfilingSlotCount;
|
|
4582
|
+
if (beginTimestampIndex + 1 >= this._timeProfilingQuerySet.props.count) {
|
|
4583
|
+
return passProps;
|
|
4584
|
+
}
|
|
4585
|
+
this._timeProfilingSlotCount += 2;
|
|
4586
|
+
return {
|
|
4587
|
+
...passProps,
|
|
4588
|
+
timestampQuerySet: this._timeProfilingQuerySet,
|
|
4589
|
+
beginTimestampIndex,
|
|
4590
|
+
endTimestampIndex: beginTimestampIndex + 1
|
|
4591
|
+
};
|
|
4592
|
+
}
|
|
4593
|
+
_supportsTimestampQueries() {
|
|
4594
|
+
return this.device.features.has("timestamp-query");
|
|
2991
4595
|
}
|
|
2992
4596
|
};
|
|
2993
4597
|
var CommandEncoder = _CommandEncoder;
|
|
@@ -2996,7 +4600,8 @@ ${htmlLog}
|
|
|
2996
4600
|
// beginComputePass(optional GPUComputePassDescriptor descriptor = {}): GPUComputePassEncoder;
|
|
2997
4601
|
__publicField(CommandEncoder, "defaultProps", {
|
|
2998
4602
|
...Resource.defaultProps,
|
|
2999
|
-
measureExecutionTime: void 0
|
|
4603
|
+
measureExecutionTime: void 0,
|
|
4604
|
+
timeProfilingQuerySet: void 0
|
|
3000
4605
|
});
|
|
3001
4606
|
|
|
3002
4607
|
// ../core/src/adapter/resources/command-buffer.ts
|
|
@@ -3013,13 +4618,22 @@ ${htmlLog}
|
|
|
3013
4618
|
...Resource.defaultProps
|
|
3014
4619
|
});
|
|
3015
4620
|
|
|
3016
|
-
// ../core/src/shadertypes/
|
|
4621
|
+
// ../core/src/shadertypes/shader-types/shader-type-decoder.ts
|
|
3017
4622
|
function getVariableShaderTypeInfo(format) {
|
|
3018
|
-
const
|
|
4623
|
+
const resolvedFormat = resolveVariableShaderTypeAlias(format);
|
|
4624
|
+
const decoded = UNIFORM_FORMATS[resolvedFormat];
|
|
4625
|
+
if (!decoded) {
|
|
4626
|
+
throw new Error(`Unsupported variable shader type: ${format}`);
|
|
4627
|
+
}
|
|
3019
4628
|
return decoded;
|
|
3020
4629
|
}
|
|
3021
4630
|
function getAttributeShaderTypeInfo(attributeType) {
|
|
3022
|
-
const
|
|
4631
|
+
const resolvedAttributeType = resolveAttributeShaderTypeAlias(attributeType);
|
|
4632
|
+
const decoded = TYPE_INFO[resolvedAttributeType];
|
|
4633
|
+
if (!decoded) {
|
|
4634
|
+
throw new Error(`Unsupported attribute shader type: ${attributeType}`);
|
|
4635
|
+
}
|
|
4636
|
+
const [primitiveType, components] = decoded;
|
|
3023
4637
|
const integer = primitiveType === "i32" || primitiveType === "u32";
|
|
3024
4638
|
const signed = primitiveType !== "u32";
|
|
3025
4639
|
const byteLength = PRIMITIVE_TYPE_SIZES[primitiveType] * components;
|
|
@@ -3031,6 +4645,33 @@ ${htmlLog}
|
|
|
3031
4645
|
signed
|
|
3032
4646
|
};
|
|
3033
4647
|
}
|
|
4648
|
+
var ShaderTypeDecoder = class {
|
|
4649
|
+
getVariableShaderTypeInfo(format) {
|
|
4650
|
+
return getVariableShaderTypeInfo(format);
|
|
4651
|
+
}
|
|
4652
|
+
getAttributeShaderTypeInfo(attributeType) {
|
|
4653
|
+
return getAttributeShaderTypeInfo(attributeType);
|
|
4654
|
+
}
|
|
4655
|
+
makeShaderAttributeType(primitiveType, components) {
|
|
4656
|
+
return makeShaderAttributeType(primitiveType, components);
|
|
4657
|
+
}
|
|
4658
|
+
resolveAttributeShaderTypeAlias(alias) {
|
|
4659
|
+
return resolveAttributeShaderTypeAlias(alias);
|
|
4660
|
+
}
|
|
4661
|
+
resolveVariableShaderTypeAlias(alias) {
|
|
4662
|
+
return resolveVariableShaderTypeAlias(alias);
|
|
4663
|
+
}
|
|
4664
|
+
};
|
|
4665
|
+
function makeShaderAttributeType(primitiveType, components) {
|
|
4666
|
+
return components === 1 ? primitiveType : `vec${components}<${primitiveType}>`;
|
|
4667
|
+
}
|
|
4668
|
+
function resolveAttributeShaderTypeAlias(alias) {
|
|
4669
|
+
return WGSL_ATTRIBUTE_TYPE_ALIAS_MAP[alias] || alias;
|
|
4670
|
+
}
|
|
4671
|
+
function resolveVariableShaderTypeAlias(alias) {
|
|
4672
|
+
return WGSL_VARIABLE_TYPE_ALIAS_MAP[alias] || alias;
|
|
4673
|
+
}
|
|
4674
|
+
var shaderTypeDecoder = new ShaderTypeDecoder();
|
|
3034
4675
|
var PRIMITIVE_TYPE_SIZES = {
|
|
3035
4676
|
f32: 4,
|
|
3036
4677
|
f16: 2,
|
|
@@ -3127,7 +4768,18 @@ ${htmlLog}
|
|
|
3127
4768
|
vec4h: "vec4<f16>"
|
|
3128
4769
|
};
|
|
3129
4770
|
var WGSL_VARIABLE_TYPE_ALIAS_MAP = {
|
|
3130
|
-
|
|
4771
|
+
vec2i: "vec2<i32>",
|
|
4772
|
+
vec3i: "vec3<i32>",
|
|
4773
|
+
vec4i: "vec4<i32>",
|
|
4774
|
+
vec2u: "vec2<u32>",
|
|
4775
|
+
vec3u: "vec3<u32>",
|
|
4776
|
+
vec4u: "vec4<u32>",
|
|
4777
|
+
vec2f: "vec2<f32>",
|
|
4778
|
+
vec3f: "vec3<f32>",
|
|
4779
|
+
vec4f: "vec4<f32>",
|
|
4780
|
+
vec2h: "vec2<f16>",
|
|
4781
|
+
vec3h: "vec3<f16>",
|
|
4782
|
+
vec4h: "vec4<f16>",
|
|
3131
4783
|
mat2x2f: "mat2x2<f32>",
|
|
3132
4784
|
mat2x3f: "mat2x3<f32>",
|
|
3133
4785
|
mat2x4f: "mat2x4<f32>",
|
|
@@ -3194,10 +4846,10 @@ ${htmlLog}
|
|
|
3194
4846
|
if (!shaderDeclaration) {
|
|
3195
4847
|
return null;
|
|
3196
4848
|
}
|
|
3197
|
-
const attributeTypeInfo = getAttributeShaderTypeInfo(shaderDeclaration.type);
|
|
3198
|
-
const defaultVertexFormat = getCompatibleVertexFormat(attributeTypeInfo);
|
|
4849
|
+
const attributeTypeInfo = shaderTypeDecoder.getAttributeShaderTypeInfo(shaderDeclaration.type);
|
|
4850
|
+
const defaultVertexFormat = vertexFormatDecoder.getCompatibleVertexFormat(attributeTypeInfo);
|
|
3199
4851
|
const vertexFormat = bufferMapping?.vertexFormat || defaultVertexFormat;
|
|
3200
|
-
const vertexFormatInfo = getVertexFormatInfo(vertexFormat);
|
|
4852
|
+
const vertexFormatInfo = vertexFormatDecoder.getVertexFormatInfo(vertexFormat);
|
|
3201
4853
|
return {
|
|
3202
4854
|
attributeName: bufferMapping?.attributeName || shaderDeclaration.name,
|
|
3203
4855
|
bufferName: bufferMapping?.bufferName || shaderDeclaration.name,
|
|
@@ -3265,7 +4917,7 @@ ${htmlLog}
|
|
|
3265
4917
|
let byteStride = bufferLayout.byteStride;
|
|
3266
4918
|
if (typeof bufferLayout.byteStride !== "number") {
|
|
3267
4919
|
for (const attributeMapping2 of bufferLayout.attributes || []) {
|
|
3268
|
-
const info = getVertexFormatInfo(attributeMapping2.format);
|
|
4920
|
+
const info = vertexFormatDecoder.getVertexFormatInfo(attributeMapping2.format);
|
|
3269
4921
|
byteStride += info.byteLength;
|
|
3270
4922
|
}
|
|
3271
4923
|
}
|
|
@@ -3353,6 +5005,20 @@ ${htmlLog}
|
|
|
3353
5005
|
count: void 0
|
|
3354
5006
|
});
|
|
3355
5007
|
|
|
5008
|
+
// ../core/src/adapter/resources/fence.ts
|
|
5009
|
+
var _Fence = class extends Resource {
|
|
5010
|
+
get [Symbol.toStringTag]() {
|
|
5011
|
+
return "Fence";
|
|
5012
|
+
}
|
|
5013
|
+
constructor(device, props = {}) {
|
|
5014
|
+
super(device, props, _Fence.defaultProps);
|
|
5015
|
+
}
|
|
5016
|
+
};
|
|
5017
|
+
var Fence = _Fence;
|
|
5018
|
+
__publicField(Fence, "defaultProps", {
|
|
5019
|
+
...Resource.defaultProps
|
|
5020
|
+
});
|
|
5021
|
+
|
|
3356
5022
|
// ../core/src/adapter/resources/pipeline-layout.ts
|
|
3357
5023
|
var _PipelineLayout = class extends Resource {
|
|
3358
5024
|
get [Symbol.toStringTag]() {
|
|
@@ -3371,6 +5037,200 @@ ${htmlLog}
|
|
|
3371
5037
|
}
|
|
3372
5038
|
});
|
|
3373
5039
|
|
|
5040
|
+
// ../core/src/shadertypes/data-types/decode-data-types.ts
|
|
5041
|
+
function alignTo(size, count) {
|
|
5042
|
+
switch (count) {
|
|
5043
|
+
case 1:
|
|
5044
|
+
return size;
|
|
5045
|
+
case 2:
|
|
5046
|
+
return size + size % 2;
|
|
5047
|
+
default:
|
|
5048
|
+
return size + (4 - size % 4) % 4;
|
|
5049
|
+
}
|
|
5050
|
+
}
|
|
5051
|
+
function getTypedArrayConstructor(type) {
|
|
5052
|
+
const [, , , , Constructor] = NORMALIZED_TYPE_MAP2[type];
|
|
5053
|
+
return Constructor;
|
|
5054
|
+
}
|
|
5055
|
+
var NORMALIZED_TYPE_MAP2 = {
|
|
5056
|
+
uint8: ["uint8", "u32", 1, false, Uint8Array],
|
|
5057
|
+
sint8: ["sint8", "i32", 1, false, Int8Array],
|
|
5058
|
+
unorm8: ["uint8", "f32", 1, true, Uint8Array],
|
|
5059
|
+
snorm8: ["sint8", "f32", 1, true, Int8Array],
|
|
5060
|
+
uint16: ["uint16", "u32", 2, false, Uint16Array],
|
|
5061
|
+
sint16: ["sint16", "i32", 2, false, Int16Array],
|
|
5062
|
+
unorm16: ["uint16", "u32", 2, true, Uint16Array],
|
|
5063
|
+
snorm16: ["sint16", "i32", 2, true, Int16Array],
|
|
5064
|
+
float16: ["float16", "f16", 2, false, Uint16Array],
|
|
5065
|
+
float32: ["float32", "f32", 4, false, Float32Array],
|
|
5066
|
+
uint32: ["uint32", "u32", 4, false, Uint32Array],
|
|
5067
|
+
sint32: ["sint32", "i32", 4, false, Int32Array]
|
|
5068
|
+
};
|
|
5069
|
+
|
|
5070
|
+
// ../core/src/shadertypes/shader-types/shader-block-layout.ts
|
|
5071
|
+
function makeShaderBlockLayout(uniformTypes, options = {}) {
|
|
5072
|
+
const copiedUniformTypes = { ...uniformTypes };
|
|
5073
|
+
const layout = options.layout ?? "std140";
|
|
5074
|
+
const fields = {};
|
|
5075
|
+
let size = 0;
|
|
5076
|
+
for (const [key, uniformType] of Object.entries(copiedUniformTypes)) {
|
|
5077
|
+
size = addToLayout(fields, key, uniformType, size, layout);
|
|
5078
|
+
}
|
|
5079
|
+
size = alignTo(size, getTypeAlignment(copiedUniformTypes, layout));
|
|
5080
|
+
return {
|
|
5081
|
+
layout,
|
|
5082
|
+
byteLength: size * 4,
|
|
5083
|
+
uniformTypes: copiedUniformTypes,
|
|
5084
|
+
fields
|
|
5085
|
+
};
|
|
5086
|
+
}
|
|
5087
|
+
function getLeafLayoutInfo(type, layout) {
|
|
5088
|
+
const resolvedType = resolveVariableShaderTypeAlias(type);
|
|
5089
|
+
const decodedType = getVariableShaderTypeInfo(resolvedType);
|
|
5090
|
+
const matrixMatch = /^mat(\d)x(\d)<.+>$/.exec(resolvedType);
|
|
5091
|
+
if (matrixMatch) {
|
|
5092
|
+
const columns = Number(matrixMatch[1]);
|
|
5093
|
+
const rows = Number(matrixMatch[2]);
|
|
5094
|
+
const columnInfo = getVectorLayoutInfo(
|
|
5095
|
+
rows,
|
|
5096
|
+
resolvedType,
|
|
5097
|
+
decodedType.type,
|
|
5098
|
+
layout
|
|
5099
|
+
);
|
|
5100
|
+
const columnStride = getMatrixColumnStride(columnInfo.size, columnInfo.alignment, layout);
|
|
5101
|
+
return {
|
|
5102
|
+
alignment: columnInfo.alignment,
|
|
5103
|
+
size: columns * columnStride,
|
|
5104
|
+
components: columns * rows,
|
|
5105
|
+
columns,
|
|
5106
|
+
rows,
|
|
5107
|
+
columnStride,
|
|
5108
|
+
shaderType: resolvedType,
|
|
5109
|
+
type: decodedType.type
|
|
5110
|
+
};
|
|
5111
|
+
}
|
|
5112
|
+
const vectorMatch = /^vec(\d)<.+>$/.exec(resolvedType);
|
|
5113
|
+
if (vectorMatch) {
|
|
5114
|
+
return getVectorLayoutInfo(
|
|
5115
|
+
Number(vectorMatch[1]),
|
|
5116
|
+
resolvedType,
|
|
5117
|
+
decodedType.type,
|
|
5118
|
+
layout
|
|
5119
|
+
);
|
|
5120
|
+
}
|
|
5121
|
+
return {
|
|
5122
|
+
alignment: 1,
|
|
5123
|
+
size: 1,
|
|
5124
|
+
components: 1,
|
|
5125
|
+
columns: 1,
|
|
5126
|
+
rows: 1,
|
|
5127
|
+
columnStride: 1,
|
|
5128
|
+
shaderType: resolvedType,
|
|
5129
|
+
type: decodedType.type
|
|
5130
|
+
};
|
|
5131
|
+
}
|
|
5132
|
+
function isCompositeShaderTypeStruct(value) {
|
|
5133
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
5134
|
+
}
|
|
5135
|
+
function addToLayout(fields, name2, type, offset, layout) {
|
|
5136
|
+
if (typeof type === "string") {
|
|
5137
|
+
const info = getLeafLayoutInfo(type, layout);
|
|
5138
|
+
const alignedOffset = alignTo(offset, info.alignment);
|
|
5139
|
+
fields[name2] = {
|
|
5140
|
+
offset: alignedOffset,
|
|
5141
|
+
...info
|
|
5142
|
+
};
|
|
5143
|
+
return alignedOffset + info.size;
|
|
5144
|
+
}
|
|
5145
|
+
if (Array.isArray(type)) {
|
|
5146
|
+
if (Array.isArray(type[0])) {
|
|
5147
|
+
throw new Error(`Nested arrays are not supported for ${name2}`);
|
|
5148
|
+
}
|
|
5149
|
+
const elementType = type[0];
|
|
5150
|
+
const length = type[1];
|
|
5151
|
+
const stride = getArrayStride(elementType, layout);
|
|
5152
|
+
const arrayOffset = alignTo(offset, getTypeAlignment(type, layout));
|
|
5153
|
+
for (let i = 0; i < length; i++) {
|
|
5154
|
+
addToLayout(fields, `${name2}[${i}]`, elementType, arrayOffset + i * stride, layout);
|
|
5155
|
+
}
|
|
5156
|
+
return arrayOffset + stride * length;
|
|
5157
|
+
}
|
|
5158
|
+
if (isCompositeShaderTypeStruct(type)) {
|
|
5159
|
+
const structAlignment = getTypeAlignment(type, layout);
|
|
5160
|
+
let structOffset = alignTo(offset, structAlignment);
|
|
5161
|
+
for (const [memberName, memberType] of Object.entries(type)) {
|
|
5162
|
+
structOffset = addToLayout(fields, `${name2}.${memberName}`, memberType, structOffset, layout);
|
|
5163
|
+
}
|
|
5164
|
+
return alignTo(structOffset, structAlignment);
|
|
5165
|
+
}
|
|
5166
|
+
throw new Error(`Unsupported CompositeShaderType for ${name2}`);
|
|
5167
|
+
}
|
|
5168
|
+
function getTypeSize(type, layout) {
|
|
5169
|
+
if (typeof type === "string") {
|
|
5170
|
+
return getLeafLayoutInfo(type, layout).size;
|
|
5171
|
+
}
|
|
5172
|
+
if (Array.isArray(type)) {
|
|
5173
|
+
const elementType = type[0];
|
|
5174
|
+
const length = type[1];
|
|
5175
|
+
if (Array.isArray(elementType)) {
|
|
5176
|
+
throw new Error("Nested arrays are not supported");
|
|
5177
|
+
}
|
|
5178
|
+
return getArrayStride(elementType, layout) * length;
|
|
5179
|
+
}
|
|
5180
|
+
let size = 0;
|
|
5181
|
+
for (const memberType of Object.values(type)) {
|
|
5182
|
+
const compositeMemberType = memberType;
|
|
5183
|
+
size = alignTo(size, getTypeAlignment(compositeMemberType, layout));
|
|
5184
|
+
size += getTypeSize(compositeMemberType, layout);
|
|
5185
|
+
}
|
|
5186
|
+
return alignTo(size, getTypeAlignment(type, layout));
|
|
5187
|
+
}
|
|
5188
|
+
function getTypeAlignment(type, layout) {
|
|
5189
|
+
if (typeof type === "string") {
|
|
5190
|
+
return getLeafLayoutInfo(type, layout).alignment;
|
|
5191
|
+
}
|
|
5192
|
+
if (Array.isArray(type)) {
|
|
5193
|
+
const elementType = type[0];
|
|
5194
|
+
const elementAlignment = getTypeAlignment(elementType, layout);
|
|
5195
|
+
return uses16ByteArrayAlignment(layout) ? Math.max(elementAlignment, 4) : elementAlignment;
|
|
5196
|
+
}
|
|
5197
|
+
let maxAlignment = 1;
|
|
5198
|
+
for (const memberType of Object.values(type)) {
|
|
5199
|
+
const memberAlignment = getTypeAlignment(memberType, layout);
|
|
5200
|
+
maxAlignment = Math.max(maxAlignment, memberAlignment);
|
|
5201
|
+
}
|
|
5202
|
+
return uses16ByteStructAlignment(layout) ? Math.max(maxAlignment, 4) : maxAlignment;
|
|
5203
|
+
}
|
|
5204
|
+
function getVectorLayoutInfo(components, shaderType, type, layout) {
|
|
5205
|
+
return {
|
|
5206
|
+
alignment: components === 2 ? 2 : 4,
|
|
5207
|
+
size: components === 3 ? 3 : components,
|
|
5208
|
+
components,
|
|
5209
|
+
columns: 1,
|
|
5210
|
+
rows: components,
|
|
5211
|
+
columnStride: components === 3 ? 3 : components,
|
|
5212
|
+
shaderType,
|
|
5213
|
+
type
|
|
5214
|
+
};
|
|
5215
|
+
}
|
|
5216
|
+
function getArrayStride(elementType, layout) {
|
|
5217
|
+
const elementSize = getTypeSize(elementType, layout);
|
|
5218
|
+
const elementAlignment = getTypeAlignment(elementType, layout);
|
|
5219
|
+
return getArrayLikeStride(elementSize, elementAlignment, layout);
|
|
5220
|
+
}
|
|
5221
|
+
function getArrayLikeStride(size, alignment, layout) {
|
|
5222
|
+
return alignTo(size, uses16ByteArrayAlignment(layout) ? 4 : alignment);
|
|
5223
|
+
}
|
|
5224
|
+
function getMatrixColumnStride(size, alignment, layout) {
|
|
5225
|
+
return layout === "std140" ? 4 : alignTo(size, alignment);
|
|
5226
|
+
}
|
|
5227
|
+
function uses16ByteArrayAlignment(layout) {
|
|
5228
|
+
return layout === "std140" || layout === "wgsl-uniform";
|
|
5229
|
+
}
|
|
5230
|
+
function uses16ByteStructAlignment(layout) {
|
|
5231
|
+
return layout === "std140" || layout === "wgsl-uniform";
|
|
5232
|
+
}
|
|
5233
|
+
|
|
3374
5234
|
// ../core/src/utils/array-utils-flat.ts
|
|
3375
5235
|
var arrayBuffer;
|
|
3376
5236
|
function getScratchArrayBuffer(byteLength) {
|
|
@@ -3395,92 +5255,201 @@ ${htmlLog}
|
|
|
3395
5255
|
return isTypedArray(value);
|
|
3396
5256
|
}
|
|
3397
5257
|
|
|
3398
|
-
// ../core/src/portable/
|
|
3399
|
-
var
|
|
3400
|
-
|
|
3401
|
-
layout
|
|
3402
|
-
/**
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
constructor(
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
5258
|
+
// ../core/src/portable/shader-block-writer.ts
|
|
5259
|
+
var ShaderBlockWriter = class {
|
|
5260
|
+
/** Layout metadata used to flatten and serialize values. */
|
|
5261
|
+
layout;
|
|
5262
|
+
/**
|
|
5263
|
+
* Creates a writer for a precomputed shader-block layout.
|
|
5264
|
+
*/
|
|
5265
|
+
constructor(layout) {
|
|
5266
|
+
this.layout = layout;
|
|
5267
|
+
}
|
|
5268
|
+
/**
|
|
5269
|
+
* Returns `true` if the flattened layout contains the given field.
|
|
5270
|
+
*/
|
|
5271
|
+
has(name2) {
|
|
5272
|
+
return Boolean(this.layout.fields[name2]);
|
|
5273
|
+
}
|
|
5274
|
+
/**
|
|
5275
|
+
* Returns offset and size metadata for a flattened field.
|
|
5276
|
+
*/
|
|
5277
|
+
get(name2) {
|
|
5278
|
+
const entry = this.layout.fields[name2];
|
|
5279
|
+
return entry ? { offset: entry.offset, size: entry.size } : void 0;
|
|
5280
|
+
}
|
|
5281
|
+
/**
|
|
5282
|
+
* Flattens nested composite values into leaf-path values understood by {@link UniformBlock}.
|
|
5283
|
+
*
|
|
5284
|
+
* Top-level values may be supplied either in nested object form matching the
|
|
5285
|
+
* declared composite shader types or as already-flattened leaf-path values.
|
|
5286
|
+
*/
|
|
5287
|
+
getFlatUniformValues(uniformValues) {
|
|
5288
|
+
const flattenedUniformValues = {};
|
|
5289
|
+
for (const [name2, value] of Object.entries(uniformValues)) {
|
|
5290
|
+
const uniformType = this.layout.uniformTypes[name2];
|
|
5291
|
+
if (uniformType) {
|
|
5292
|
+
this._flattenCompositeValue(flattenedUniformValues, name2, uniformType, value);
|
|
5293
|
+
} else if (this.layout.fields[name2]) {
|
|
5294
|
+
flattenedUniformValues[name2] = value;
|
|
5295
|
+
}
|
|
5296
|
+
}
|
|
5297
|
+
return flattenedUniformValues;
|
|
5298
|
+
}
|
|
5299
|
+
/**
|
|
5300
|
+
* Serializes the supplied values into buffer-backed binary data.
|
|
5301
|
+
*
|
|
5302
|
+
* The returned view length matches {@link ShaderBlockLayout.byteLength}, which
|
|
5303
|
+
* is the exact packed size of the block.
|
|
5304
|
+
*/
|
|
3421
5305
|
getData(uniformValues) {
|
|
3422
|
-
const
|
|
5306
|
+
const buffer = getScratchArrayBuffer(this.layout.byteLength);
|
|
5307
|
+
new Uint8Array(buffer, 0, this.layout.byteLength).fill(0);
|
|
3423
5308
|
const typedArrays = {
|
|
3424
|
-
i32: new Int32Array(
|
|
3425
|
-
u32: new Uint32Array(
|
|
3426
|
-
f32: new Float32Array(
|
|
3427
|
-
|
|
3428
|
-
f16: new Uint16Array(arrayBuffer2)
|
|
5309
|
+
i32: new Int32Array(buffer),
|
|
5310
|
+
u32: new Uint32Array(buffer),
|
|
5311
|
+
f32: new Float32Array(buffer),
|
|
5312
|
+
f16: new Uint16Array(buffer)
|
|
3429
5313
|
};
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
5314
|
+
const flattenedUniformValues = this.getFlatUniformValues(uniformValues);
|
|
5315
|
+
for (const [name2, value] of Object.entries(flattenedUniformValues)) {
|
|
5316
|
+
this._writeLeafValue(typedArrays, name2, value);
|
|
5317
|
+
}
|
|
5318
|
+
return new Uint8Array(buffer, 0, this.layout.byteLength);
|
|
5319
|
+
}
|
|
5320
|
+
/**
|
|
5321
|
+
* Recursively flattens nested values using the declared composite shader type.
|
|
5322
|
+
*/
|
|
5323
|
+
_flattenCompositeValue(flattenedUniformValues, baseName, uniformType, value) {
|
|
5324
|
+
if (value === void 0) {
|
|
5325
|
+
return;
|
|
5326
|
+
}
|
|
5327
|
+
if (typeof uniformType === "string" || this.layout.fields[baseName]) {
|
|
5328
|
+
flattenedUniformValues[baseName] = value;
|
|
5329
|
+
return;
|
|
5330
|
+
}
|
|
5331
|
+
if (Array.isArray(uniformType)) {
|
|
5332
|
+
const elementType = uniformType[0];
|
|
5333
|
+
const length = uniformType[1];
|
|
5334
|
+
if (Array.isArray(elementType)) {
|
|
5335
|
+
throw new Error(`Nested arrays are not supported for ${baseName}`);
|
|
3435
5336
|
}
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
5337
|
+
if (typeof elementType === "string" && isNumberArray(value)) {
|
|
5338
|
+
this._flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value);
|
|
5339
|
+
return;
|
|
5340
|
+
}
|
|
5341
|
+
if (!Array.isArray(value)) {
|
|
5342
|
+
log.warn(`Unsupported uniform array value for ${baseName}:`, value)();
|
|
5343
|
+
return;
|
|
5344
|
+
}
|
|
5345
|
+
for (let index = 0; index < Math.min(value.length, length); index++) {
|
|
5346
|
+
const elementValue = value[index];
|
|
5347
|
+
if (elementValue === void 0) {
|
|
3443
5348
|
continue;
|
|
3444
5349
|
}
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
5350
|
+
this._flattenCompositeValue(
|
|
5351
|
+
flattenedUniformValues,
|
|
5352
|
+
`${baseName}[${index}]`,
|
|
5353
|
+
elementType,
|
|
5354
|
+
elementValue
|
|
5355
|
+
);
|
|
5356
|
+
}
|
|
5357
|
+
return;
|
|
5358
|
+
}
|
|
5359
|
+
if (isCompositeShaderTypeStruct(uniformType) && isCompositeUniformObject(value)) {
|
|
5360
|
+
for (const [key, subValue] of Object.entries(value)) {
|
|
5361
|
+
if (subValue === void 0) {
|
|
3451
5362
|
continue;
|
|
3452
5363
|
}
|
|
3453
|
-
|
|
5364
|
+
const nestedName = `${baseName}.${key}`;
|
|
5365
|
+
this._flattenCompositeValue(flattenedUniformValues, nestedName, uniformType[key], subValue);
|
|
3454
5366
|
}
|
|
5367
|
+
return;
|
|
3455
5368
|
}
|
|
3456
|
-
|
|
5369
|
+
log.warn(`Unsupported uniform value for ${baseName}:`, value)();
|
|
3457
5370
|
}
|
|
3458
|
-
/**
|
|
3459
|
-
|
|
3460
|
-
|
|
5371
|
+
/**
|
|
5372
|
+
* Expands tightly packed numeric arrays into per-element leaf fields.
|
|
5373
|
+
*/
|
|
5374
|
+
_flattenPackedArray(flattenedUniformValues, baseName, elementType, length, value) {
|
|
5375
|
+
const numericValue = value;
|
|
5376
|
+
const elementLayout = getLeafLayoutInfo(elementType, this.layout.layout);
|
|
5377
|
+
const packedElementLength = elementLayout.components;
|
|
5378
|
+
for (let index = 0; index < length; index++) {
|
|
5379
|
+
const start = index * packedElementLength;
|
|
5380
|
+
if (start >= numericValue.length) {
|
|
5381
|
+
break;
|
|
5382
|
+
}
|
|
5383
|
+
if (packedElementLength === 1) {
|
|
5384
|
+
flattenedUniformValues[`${baseName}[${index}]`] = Number(numericValue[start]);
|
|
5385
|
+
} else {
|
|
5386
|
+
flattenedUniformValues[`${baseName}[${index}]`] = sliceNumericArray(
|
|
5387
|
+
value,
|
|
5388
|
+
start,
|
|
5389
|
+
start + packedElementLength
|
|
5390
|
+
);
|
|
5391
|
+
}
|
|
5392
|
+
}
|
|
3461
5393
|
}
|
|
3462
|
-
/**
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
5394
|
+
/**
|
|
5395
|
+
* Writes one flattened leaf value into its typed-array view.
|
|
5396
|
+
*/
|
|
5397
|
+
_writeLeafValue(typedArrays, name2, value) {
|
|
5398
|
+
const entry = this.layout.fields[name2];
|
|
5399
|
+
if (!entry) {
|
|
5400
|
+
log.warn(`Uniform ${name2} not found in layout`)();
|
|
5401
|
+
return;
|
|
5402
|
+
}
|
|
5403
|
+
const { type, components, columns, rows, offset, columnStride } = entry;
|
|
5404
|
+
const array = typedArrays[type];
|
|
5405
|
+
if (components === 1) {
|
|
5406
|
+
array[offset] = Number(value);
|
|
5407
|
+
return;
|
|
5408
|
+
}
|
|
5409
|
+
const sourceValue = value;
|
|
5410
|
+
if (columns === 1) {
|
|
5411
|
+
for (let componentIndex = 0; componentIndex < components; componentIndex++) {
|
|
5412
|
+
array[offset + componentIndex] = Number(sourceValue[componentIndex] ?? 0);
|
|
5413
|
+
}
|
|
5414
|
+
return;
|
|
5415
|
+
}
|
|
5416
|
+
let sourceIndex = 0;
|
|
5417
|
+
for (let columnIndex = 0; columnIndex < columns; columnIndex++) {
|
|
5418
|
+
const columnOffset = offset + columnIndex * columnStride;
|
|
5419
|
+
for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
|
|
5420
|
+
array[columnOffset + rowIndex] = Number(sourceValue[sourceIndex++] ?? 0);
|
|
5421
|
+
}
|
|
5422
|
+
}
|
|
3466
5423
|
}
|
|
3467
5424
|
};
|
|
5425
|
+
function isCompositeUniformObject(value) {
|
|
5426
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value) && !ArrayBuffer.isView(value);
|
|
5427
|
+
}
|
|
5428
|
+
function sliceNumericArray(value, start, end) {
|
|
5429
|
+
return Array.prototype.slice.call(value, start, end);
|
|
5430
|
+
}
|
|
3468
5431
|
|
|
3469
5432
|
// ../core/src/utils/array-equal.ts
|
|
5433
|
+
var MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH = 128;
|
|
3470
5434
|
function arrayEqual(a, b, limit = 16) {
|
|
3471
|
-
if (a
|
|
3472
|
-
return
|
|
5435
|
+
if (a === b) {
|
|
5436
|
+
return true;
|
|
3473
5437
|
}
|
|
3474
5438
|
const arrayA = a;
|
|
3475
5439
|
const arrayB = b;
|
|
3476
|
-
if (!isNumberArray(arrayA)) {
|
|
5440
|
+
if (!isNumberArray(arrayA) || !isNumberArray(arrayB)) {
|
|
3477
5441
|
return false;
|
|
3478
5442
|
}
|
|
3479
|
-
if (
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
5443
|
+
if (arrayA.length !== arrayB.length) {
|
|
5444
|
+
return false;
|
|
5445
|
+
}
|
|
5446
|
+
const maxCompareLength = Math.min(limit, MAX_ELEMENTWISE_ARRAY_COMPARE_LENGTH);
|
|
5447
|
+
if (arrayA.length > maxCompareLength) {
|
|
5448
|
+
return false;
|
|
5449
|
+
}
|
|
5450
|
+
for (let i = 0; i < arrayA.length; ++i) {
|
|
5451
|
+
if (arrayB[i] !== arrayA[i]) {
|
|
5452
|
+
return false;
|
|
3484
5453
|
}
|
|
3485
5454
|
}
|
|
3486
5455
|
return true;
|
|
@@ -3545,27 +5514,33 @@ ${htmlLog}
|
|
|
3545
5514
|
};
|
|
3546
5515
|
|
|
3547
5516
|
// ../core/src/portable/uniform-store.ts
|
|
5517
|
+
var minUniformBufferSize = 1024;
|
|
3548
5518
|
var UniformStore = class {
|
|
5519
|
+
/** Device used to infer layout and allocate buffers. */
|
|
5520
|
+
device;
|
|
3549
5521
|
/** Stores the uniform values for each uniform block */
|
|
3550
5522
|
uniformBlocks = /* @__PURE__ */ new Map();
|
|
3551
|
-
/**
|
|
3552
|
-
|
|
5523
|
+
/** Flattened layout metadata for each block. */
|
|
5524
|
+
shaderBlockLayouts = /* @__PURE__ */ new Map();
|
|
5525
|
+
/** Serializers for block-backed uniform data. */
|
|
5526
|
+
shaderBlockWriters = /* @__PURE__ */ new Map();
|
|
3553
5527
|
/** Actual buffer for the blocks */
|
|
3554
5528
|
uniformBuffers = /* @__PURE__ */ new Map();
|
|
3555
5529
|
/**
|
|
3556
|
-
*
|
|
3557
|
-
* @param blocks
|
|
5530
|
+
* Creates a new {@link UniformStore} for the supplied device and block definitions.
|
|
3558
5531
|
*/
|
|
3559
|
-
constructor(blocks) {
|
|
5532
|
+
constructor(device, blocks) {
|
|
5533
|
+
this.device = device;
|
|
3560
5534
|
for (const [bufferName, block] of Object.entries(blocks)) {
|
|
3561
5535
|
const uniformBufferName = bufferName;
|
|
3562
|
-
const
|
|
3563
|
-
block.
|
|
3564
|
-
|
|
3565
|
-
);
|
|
3566
|
-
this.
|
|
5536
|
+
const shaderBlockLayout = makeShaderBlockLayout(block.uniformTypes ?? {}, {
|
|
5537
|
+
layout: block.layout ?? getDefaultUniformBufferLayout(device)
|
|
5538
|
+
});
|
|
5539
|
+
const shaderBlockWriter = new ShaderBlockWriter(shaderBlockLayout);
|
|
5540
|
+
this.shaderBlockLayouts.set(uniformBufferName, shaderBlockLayout);
|
|
5541
|
+
this.shaderBlockWriters.set(uniformBufferName, shaderBlockWriter);
|
|
3567
5542
|
const uniformBlock = new UniformBlock({ name: bufferName });
|
|
3568
|
-
uniformBlock.setUniforms(block.defaultUniforms || {});
|
|
5543
|
+
uniformBlock.setUniforms(shaderBlockWriter.getFlatUniformValues(block.defaultUniforms || {}));
|
|
3569
5544
|
this.uniformBlocks.set(uniformBufferName, uniformBlock);
|
|
3570
5545
|
}
|
|
3571
5546
|
}
|
|
@@ -3577,33 +5552,51 @@ ${htmlLog}
|
|
|
3577
5552
|
}
|
|
3578
5553
|
/**
|
|
3579
5554
|
* Set uniforms
|
|
3580
|
-
*
|
|
5555
|
+
*
|
|
5556
|
+
* Makes all group properties partial and eagerly propagates changes to any
|
|
5557
|
+
* managed GPU buffers.
|
|
3581
5558
|
*/
|
|
3582
5559
|
setUniforms(uniforms) {
|
|
3583
5560
|
for (const [blockName, uniformValues] of Object.entries(uniforms)) {
|
|
3584
|
-
|
|
5561
|
+
const uniformBufferName = blockName;
|
|
5562
|
+
const shaderBlockWriter = this.shaderBlockWriters.get(uniformBufferName);
|
|
5563
|
+
const flattenedUniforms = shaderBlockWriter?.getFlatUniformValues(
|
|
5564
|
+
uniformValues || {}
|
|
5565
|
+
);
|
|
5566
|
+
this.uniformBlocks.get(uniformBufferName)?.setUniforms(flattenedUniforms || {});
|
|
3585
5567
|
}
|
|
3586
5568
|
this.updateUniformBuffers();
|
|
3587
5569
|
}
|
|
3588
|
-
/**
|
|
5570
|
+
/**
|
|
5571
|
+
* Returns the allocation size for the named uniform buffer.
|
|
5572
|
+
*
|
|
5573
|
+
* This may exceed the packed layout size because minimum buffer-size policy is
|
|
5574
|
+
* applied at the store layer.
|
|
5575
|
+
*/
|
|
3589
5576
|
getUniformBufferByteLength(uniformBufferName) {
|
|
3590
|
-
|
|
5577
|
+
const packedByteLength = this.shaderBlockLayouts.get(uniformBufferName)?.byteLength || 0;
|
|
5578
|
+
return Math.max(packedByteLength, minUniformBufferSize);
|
|
3591
5579
|
}
|
|
3592
|
-
/**
|
|
5580
|
+
/**
|
|
5581
|
+
* Returns packed binary data that can be uploaded to the named uniform buffer.
|
|
5582
|
+
*
|
|
5583
|
+
* The returned view length matches the packed block size and is not padded to
|
|
5584
|
+
* the store's minimum allocation size.
|
|
5585
|
+
*/
|
|
3593
5586
|
getUniformBufferData(uniformBufferName) {
|
|
3594
5587
|
const uniformValues = this.uniformBlocks.get(uniformBufferName)?.getAllUniforms() || {};
|
|
3595
|
-
|
|
5588
|
+
const shaderBlockWriter = this.shaderBlockWriters.get(uniformBufferName);
|
|
5589
|
+
return shaderBlockWriter?.getData(uniformValues) || new Uint8Array(0);
|
|
3596
5590
|
}
|
|
3597
5591
|
/**
|
|
3598
|
-
* Creates an unmanaged uniform buffer
|
|
3599
|
-
* The new buffer is initialized with current / supplied values
|
|
5592
|
+
* Creates an unmanaged uniform buffer initialized with the current or supplied values.
|
|
3600
5593
|
*/
|
|
3601
|
-
createUniformBuffer(
|
|
5594
|
+
createUniformBuffer(uniformBufferName, uniforms) {
|
|
3602
5595
|
if (uniforms) {
|
|
3603
5596
|
this.setUniforms(uniforms);
|
|
3604
5597
|
}
|
|
3605
5598
|
const byteLength = this.getUniformBufferByteLength(uniformBufferName);
|
|
3606
|
-
const uniformBuffer = device.createBuffer({
|
|
5599
|
+
const uniformBuffer = this.device.createBuffer({
|
|
3607
5600
|
usage: Buffer2.UNIFORM | Buffer2.COPY_DST,
|
|
3608
5601
|
byteLength
|
|
3609
5602
|
});
|
|
@@ -3611,11 +5604,11 @@ ${htmlLog}
|
|
|
3611
5604
|
uniformBuffer.write(uniformBufferData);
|
|
3612
5605
|
return uniformBuffer;
|
|
3613
5606
|
}
|
|
3614
|
-
/**
|
|
3615
|
-
getManagedUniformBuffer(
|
|
5607
|
+
/** Returns the managed uniform buffer for the named block. */
|
|
5608
|
+
getManagedUniformBuffer(uniformBufferName) {
|
|
3616
5609
|
if (!this.uniformBuffers.get(uniformBufferName)) {
|
|
3617
5610
|
const byteLength = this.getUniformBufferByteLength(uniformBufferName);
|
|
3618
|
-
const uniformBuffer = device.createBuffer({
|
|
5611
|
+
const uniformBuffer = this.device.createBuffer({
|
|
3619
5612
|
usage: Buffer2.UNIFORM | Buffer2.COPY_DST,
|
|
3620
5613
|
byteLength
|
|
3621
5614
|
});
|
|
@@ -3623,7 +5616,11 @@ ${htmlLog}
|
|
|
3623
5616
|
}
|
|
3624
5617
|
return this.uniformBuffers.get(uniformBufferName);
|
|
3625
5618
|
}
|
|
3626
|
-
/**
|
|
5619
|
+
/**
|
|
5620
|
+
* Updates every managed uniform buffer whose source uniforms have changed.
|
|
5621
|
+
*
|
|
5622
|
+
* @returns The first redraw reason encountered, or `false` if nothing changed.
|
|
5623
|
+
*/
|
|
3627
5624
|
updateUniformBuffers() {
|
|
3628
5625
|
let reason = false;
|
|
3629
5626
|
for (const uniformBufferName of this.uniformBlocks.keys()) {
|
|
@@ -3635,7 +5632,11 @@ ${htmlLog}
|
|
|
3635
5632
|
}
|
|
3636
5633
|
return reason;
|
|
3637
5634
|
}
|
|
3638
|
-
/**
|
|
5635
|
+
/**
|
|
5636
|
+
* Updates one managed uniform buffer if its corresponding block is dirty.
|
|
5637
|
+
*
|
|
5638
|
+
* @returns The redraw reason for the update, or `false` if no write occurred.
|
|
5639
|
+
*/
|
|
3639
5640
|
updateUniformBuffer(uniformBufferName) {
|
|
3640
5641
|
const uniformBlock = this.uniformBlocks.get(uniformBufferName);
|
|
3641
5642
|
let uniformBuffer = this.uniformBuffers.get(uniformBufferName);
|
|
@@ -3656,8 +5657,49 @@ ${htmlLog}
|
|
|
3656
5657
|
return reason;
|
|
3657
5658
|
}
|
|
3658
5659
|
};
|
|
5660
|
+
function getDefaultUniformBufferLayout(device) {
|
|
5661
|
+
return device.type === "webgpu" ? "wgsl-uniform" : "std140";
|
|
5662
|
+
}
|
|
5663
|
+
|
|
5664
|
+
// ../core/src/shadertypes/texture-types/texture-layout.ts
|
|
5665
|
+
function getTextureImageView(arrayBuffer2, memoryLayout, format, image = 0) {
|
|
5666
|
+
const formatInfo = textureFormatDecoder.getInfo(format);
|
|
5667
|
+
const bytesPerComponent = formatInfo.bytesPerPixel / formatInfo.components;
|
|
5668
|
+
const { bytesPerImage } = memoryLayout;
|
|
5669
|
+
const offset = bytesPerImage * image;
|
|
5670
|
+
const totalPixels = memoryLayout.bytesPerImage / bytesPerComponent;
|
|
5671
|
+
switch (format) {
|
|
5672
|
+
case "rgba8unorm":
|
|
5673
|
+
case "bgra8unorm":
|
|
5674
|
+
case "rgba8uint":
|
|
5675
|
+
return new Uint8Array(arrayBuffer2, offset, totalPixels);
|
|
5676
|
+
case "r8unorm":
|
|
5677
|
+
return new Uint8Array(arrayBuffer2, offset, totalPixels);
|
|
5678
|
+
case "r16uint":
|
|
5679
|
+
case "rgba16uint":
|
|
5680
|
+
return new Uint16Array(arrayBuffer2, offset, totalPixels);
|
|
5681
|
+
case "r32uint":
|
|
5682
|
+
case "rgba32uint":
|
|
5683
|
+
return new Uint32Array(arrayBuffer2, offset, totalPixels);
|
|
5684
|
+
case "r32float":
|
|
5685
|
+
return new Float32Array(arrayBuffer2, offset, totalPixels);
|
|
5686
|
+
case "rgba16float":
|
|
5687
|
+
return new Uint16Array(arrayBuffer2, offset, totalPixels);
|
|
5688
|
+
case "rgba32float":
|
|
5689
|
+
return new Float32Array(arrayBuffer2, offset, totalPixels);
|
|
5690
|
+
default:
|
|
5691
|
+
throw new Error(`Unsupported format: ${format}`);
|
|
5692
|
+
}
|
|
5693
|
+
}
|
|
5694
|
+
function setTextureImageData(arrayBuffer2, memoryLayout, format, data, image = 0) {
|
|
5695
|
+
const offset = 0;
|
|
5696
|
+
const totalPixels = memoryLayout.bytesPerImage / memoryLayout.bytesPerPixel;
|
|
5697
|
+
const subArray = data.subarray(0, totalPixels);
|
|
5698
|
+
const typedArray = getTextureImageView(arrayBuffer2, memoryLayout, format, image);
|
|
5699
|
+
typedArray.set(subArray, offset);
|
|
5700
|
+
}
|
|
3659
5701
|
|
|
3660
|
-
// ../core/src/shadertypes/
|
|
5702
|
+
// ../core/src/shadertypes/texture-types/pixel-utils.ts
|
|
3661
5703
|
function readPixel(pixelData, x, y, bitsPerChannel) {
|
|
3662
5704
|
if (x < 0 || x >= pixelData.width || y < 0 || y >= pixelData.height) {
|
|
3663
5705
|
throw new Error("Coordinates out of bounds.");
|
|
@@ -3667,7 +5709,7 @@ ${htmlLog}
|
|
|
3667
5709
|
let bitOffsetWithinPixel = 0;
|
|
3668
5710
|
const channels = [];
|
|
3669
5711
|
for (let i = 0; i < 4; i++) {
|
|
3670
|
-
const bits = bitsPerChannel[i];
|
|
5712
|
+
const bits = bitsPerChannel[i] ?? 0;
|
|
3671
5713
|
if (bits <= 0) {
|
|
3672
5714
|
channels.push(0);
|
|
3673
5715
|
} else {
|
|
@@ -3676,14 +5718,14 @@ ${htmlLog}
|
|
|
3676
5718
|
bitOffsetWithinPixel += bits;
|
|
3677
5719
|
}
|
|
3678
5720
|
}
|
|
3679
|
-
return [channels[0], channels[1], channels[2], channels[3]];
|
|
5721
|
+
return [channels[0] ?? 0, channels[1] ?? 0, channels[2] ?? 0, channels[3] ?? 0];
|
|
3680
5722
|
}
|
|
3681
5723
|
function writePixel(dataView, bitOffset, bitsPerChannel, pixel) {
|
|
3682
5724
|
let currentBitOffset = bitOffset;
|
|
3683
5725
|
for (let channel = 0; channel < 4; channel++) {
|
|
3684
|
-
const bits = bitsPerChannel[channel];
|
|
5726
|
+
const bits = bitsPerChannel[channel] ?? 0;
|
|
3685
5727
|
const maxValue = (1 << bits) - 1;
|
|
3686
|
-
const channelValue = pixel[channel] & maxValue;
|
|
5728
|
+
const channelValue = (pixel[channel] ?? 0) & maxValue;
|
|
3687
5729
|
writeBitsToDataView(dataView, currentBitOffset, bits, channelValue);
|
|
3688
5730
|
currentBitOffset += bits;
|
|
3689
5731
|
}
|