@luma.gl/core
Version:
The luma.gl core Device API
1,489 lines (1,463 loc) • 213 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if (typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if (typeof define === 'function' && define.amd) define([], factory);
else if (typeof exports === 'object') exports['luma'] = factory();
else root['luma'] = factory();})(globalThis, function () {
"use strict";
var __exports__ = (() => {
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __export = (target, all) => {
for (var name2 in all)
__defProp(target, name2, { get: all[name2], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
// bundle.ts
var bundle_exports = {};
__export(bundle_exports, {
Adapter: () => Adapter,
Buffer: () => Buffer2,
CanvasContext: () => CanvasContext,
CommandBuffer: () => CommandBuffer,
CommandEncoder: () => CommandEncoder,
ComputePass: () => ComputePass,
ComputePipeline: () => ComputePipeline,
Device: () => Device,
DeviceFeatures: () => DeviceFeatures,
DeviceLimits: () => DeviceLimits,
ExternalTexture: () => ExternalTexture,
Fence: () => Fence,
Framebuffer: () => Framebuffer,
PipelineFactory: () => PipelineFactory,
PipelineLayout: () => PipelineLayout,
PresentationContext: () => PresentationContext,
QuerySet: () => QuerySet,
RenderPass: () => RenderPass,
RenderPipeline: () => RenderPipeline,
Resource: () => Resource,
Sampler: () => Sampler,
Shader: () => Shader,
ShaderBlockWriter: () => ShaderBlockWriter,
ShaderFactory: () => ShaderFactory,
SharedRenderPipeline: () => SharedRenderPipeline,
Texture: () => Texture,
TextureView: () => TextureView,
TransformFeedback: () => TransformFeedback,
UniformBlock: () => UniformBlock,
UniformStore: () => UniformStore,
VertexArray: () => VertexArray,
_getDefaultBindGroupFactory: () => _getDefaultBindGroupFactory,
_getTextureFormatDefinition: () => getTextureFormatDefinition,
_getTextureFormatTable: () => getTextureFormatTable,
assert: () => assert2,
assertDefined: () => assertDefined,
dataTypeDecoder: () => dataTypeDecoder,
flattenBindingsByGroup: () => flattenBindingsByGroup,
getAttributeInfosFromLayouts: () => getAttributeInfosFromLayouts,
getAttributeShaderTypeInfo: () => getAttributeShaderTypeInfo,
getExternalImageSize: () => getExternalImageSize,
getScratchArray: () => getScratchArray,
getShaderLayoutBinding: () => getShaderLayoutBinding,
getTextureImageView: () => getTextureImageView,
getTypedArrayConstructor: () => getTypedArrayConstructor,
getVariableShaderTypeInfo: () => getVariableShaderTypeInfo,
isExternalImage: () => isExternalImage,
log: () => log,
luma: () => luma,
makeShaderBlockLayout: () => makeShaderBlockLayout,
normalizeBindingsByGroup: () => normalizeBindingsByGroup,
readPixel: () => readPixel,
setTextureImageData: () => setTextureImageData,
shaderTypeDecoder: () => shaderTypeDecoder,
textureFormatDecoder: () => textureFormatDecoder,
vertexFormatDecoder: () => vertexFormatDecoder,
writePixel: () => writePixel
});
// ../../node_modules/@probe.gl/stats/dist/utils/hi-res-timestamp.js
function getHiResTimestamp() {
let timestamp;
if (typeof window !== "undefined" && window.performance) {
timestamp = window.performance.now();
} else if (typeof process !== "undefined" && process.hrtime) {
const timeParts = process.hrtime();
timestamp = timeParts[0] * 1e3 + timeParts[1] / 1e6;
} else {
timestamp = Date.now();
}
return timestamp;
}
// ../../node_modules/@probe.gl/stats/dist/lib/stat.js
var Stat = class {
constructor(name2, type) {
this.sampleSize = 1;
this.time = 0;
this.count = 0;
this.samples = 0;
this.lastTiming = 0;
this.lastSampleTime = 0;
this.lastSampleCount = 0;
this._count = 0;
this._time = 0;
this._samples = 0;
this._startTime = 0;
this._timerPending = false;
this.name = name2;
this.type = type;
this.reset();
}
reset() {
this.time = 0;
this.count = 0;
this.samples = 0;
this.lastTiming = 0;
this.lastSampleTime = 0;
this.lastSampleCount = 0;
this._count = 0;
this._time = 0;
this._samples = 0;
this._startTime = 0;
this._timerPending = false;
return this;
}
setSampleSize(samples) {
this.sampleSize = samples;
return this;
}
/** Call to increment count (+1) */
incrementCount() {
this.addCount(1);
return this;
}
/** Call to decrement count (-1) */
decrementCount() {
this.subtractCount(1);
return this;
}
/** Increase count */
addCount(value) {
this._count += value;
this._samples++;
this._checkSampling();
return this;
}
/** Decrease count */
subtractCount(value) {
this._count -= value;
this._samples++;
this._checkSampling();
return this;
}
/** Add an arbitrary timing and bump the count */
addTime(time) {
this._time += time;
this.lastTiming = time;
this._samples++;
this._checkSampling();
return this;
}
/** Start a timer */
timeStart() {
this._startTime = getHiResTimestamp();
this._timerPending = true;
return this;
}
/** End a timer. Adds to time and bumps the timing count. */
timeEnd() {
if (!this._timerPending) {
return this;
}
this.addTime(getHiResTimestamp() - this._startTime);
this._timerPending = false;
this._checkSampling();
return this;
}
getSampleAverageCount() {
return this.sampleSize > 0 ? this.lastSampleCount / this.sampleSize : 0;
}
/** Calculate average time / count for the previous window */
getSampleAverageTime() {
return this.sampleSize > 0 ? this.lastSampleTime / this.sampleSize : 0;
}
/** Calculate counts per second for the previous window */
getSampleHz() {
return this.lastSampleTime > 0 ? this.sampleSize / (this.lastSampleTime / 1e3) : 0;
}
getAverageCount() {
return this.samples > 0 ? this.count / this.samples : 0;
}
/** Calculate average time / count */
getAverageTime() {
return this.samples > 0 ? this.time / this.samples : 0;
}
/** Calculate counts per second */
getHz() {
return this.time > 0 ? this.samples / (this.time / 1e3) : 0;
}
_checkSampling() {
if (this._samples === this.sampleSize) {
this.lastSampleTime = this._time;
this.lastSampleCount = this._count;
this.count += this._count;
this.time += this._time;
this.samples += this._samples;
this._time = 0;
this._count = 0;
this._samples = 0;
}
}
};
// ../../node_modules/@probe.gl/stats/dist/lib/stats.js
var Stats = class {
constructor(options) {
this.stats = {};
this.id = options.id;
this.stats = {};
this._initializeStats(options.stats);
Object.seal(this);
}
/** Acquire a stat. Create if it doesn't exist. */
get(name2, type = "count") {
return this._getOrCreate({ name: name2, type });
}
get size() {
return Object.keys(this.stats).length;
}
/** Reset all stats */
reset() {
for (const stat of Object.values(this.stats)) {
stat.reset();
}
return this;
}
forEach(fn) {
for (const stat of Object.values(this.stats)) {
fn(stat);
}
}
getTable() {
const table = {};
this.forEach((stat) => {
table[stat.name] = {
time: stat.time || 0,
count: stat.count || 0,
average: stat.getAverageTime() || 0,
hz: stat.getHz() || 0
};
});
return table;
}
_initializeStats(stats = []) {
stats.forEach((stat) => this._getOrCreate(stat));
}
_getOrCreate(stat) {
const { name: name2, type } = stat;
let result = this.stats[name2];
if (!result) {
if (stat instanceof Stat) {
result = stat;
} else {
result = new Stat(name2, type);
}
this.stats[name2] = result;
}
return result;
}
};
// src/utils/stats-manager.ts
var GPU_TIME_AND_MEMORY_STATS = "GPU Time and Memory";
var GPU_TIME_AND_MEMORY_STAT_ORDER = [
"Adapter",
"GPU",
"GPU Type",
"GPU Backend",
"Frame Rate",
"CPU Time",
"GPU Time",
"GPU Memory",
"Buffer Memory",
"Texture Memory",
"Referenced Buffer Memory",
"Referenced Texture Memory",
"Swap Chain Texture"
];
var ORDERED_STATS_CACHE = /* @__PURE__ */ new WeakMap();
var ORDERED_STAT_NAME_SET_CACHE = /* @__PURE__ */ new WeakMap();
var StatsManager = class {
stats = /* @__PURE__ */ new Map();
getStats(name2) {
return this.get(name2);
}
get(name2) {
if (!this.stats.has(name2)) {
this.stats.set(name2, new Stats({ id: name2 }));
}
const stats = this.stats.get(name2);
if (name2 === GPU_TIME_AND_MEMORY_STATS) {
initializeStats(stats, GPU_TIME_AND_MEMORY_STAT_ORDER);
}
return stats;
}
};
var lumaStats = new StatsManager();
function initializeStats(stats, orderedStatNames) {
const statsMap = stats.stats;
let addedOrderedStat = false;
for (const statName of orderedStatNames) {
if (!statsMap[statName]) {
stats.get(statName);
addedOrderedStat = true;
}
}
const statCount = Object.keys(statsMap).length;
const cachedStats = ORDERED_STATS_CACHE.get(stats);
if (!addedOrderedStat && cachedStats?.orderedStatNames === orderedStatNames && cachedStats.statCount === statCount) {
return;
}
const reorderedStats = {};
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE.get(orderedStatNames);
if (!orderedStatNamesSet) {
orderedStatNamesSet = new Set(orderedStatNames);
ORDERED_STAT_NAME_SET_CACHE.set(orderedStatNames, orderedStatNamesSet);
}
for (const statName of orderedStatNames) {
if (statsMap[statName]) {
reorderedStats[statName] = statsMap[statName];
}
}
for (const [statName, stat] of Object.entries(statsMap)) {
if (!orderedStatNamesSet.has(statName)) {
reorderedStats[statName] = stat;
}
}
for (const statName of Object.keys(statsMap)) {
delete statsMap[statName];
}
Object.assign(statsMap, reorderedStats);
ORDERED_STATS_CACHE.set(stats, { orderedStatNames, statCount });
}
// ../../node_modules/@probe.gl/env/dist/lib/globals.js
var window_ = globalThis;
var document_ = globalThis.document || {};
var process_ = globalThis.process || {};
var console_ = globalThis.console;
var navigator_ = globalThis.navigator || {};
// ../../node_modules/@probe.gl/env/dist/lib/is-electron.js
function isElectron(mockUserAgent) {
if (typeof window !== "undefined" && window.process?.type === "renderer") {
return true;
}
if (typeof process !== "undefined" && Boolean(process.versions?.["electron"])) {
return true;
}
const realUserAgent = typeof navigator !== "undefined" && navigator.userAgent;
const userAgent = mockUserAgent || realUserAgent;
return Boolean(userAgent && userAgent.indexOf("Electron") >= 0);
}
// ../../node_modules/@probe.gl/env/dist/lib/is-browser.js
function isBrowser() {
const isNode = (
// @ts-expect-error
typeof process === "object" && String(process) === "[object process]" && !process?.browser
);
return !isNode || isElectron();
}
// ../../node_modules/@probe.gl/env/dist/index.js
var VERSION = true ? "4.1.1" : "untranspiled source";
// ../../node_modules/@probe.gl/log/dist/utils/assert.js
function assert(condition, message) {
if (!condition) {
throw new Error(message || "Assertion failed");
}
}
// ../../node_modules/@probe.gl/log/dist/loggers/log-utils.js
function normalizeLogLevel(logLevel) {
if (!logLevel) {
return 0;
}
let resolvedLevel;
switch (typeof logLevel) {
case "number":
resolvedLevel = logLevel;
break;
case "object":
resolvedLevel = logLevel.logLevel || logLevel.priority || 0;
break;
default:
return 0;
}
assert(Number.isFinite(resolvedLevel) && resolvedLevel >= 0);
return resolvedLevel;
}
function normalizeArguments(opts) {
const { logLevel, message } = opts;
opts.logLevel = normalizeLogLevel(logLevel);
const args = opts.args ? Array.from(opts.args) : [];
while (args.length && args.shift() !== message) {
}
switch (typeof logLevel) {
case "string":
case "function":
if (message !== void 0) {
args.unshift(message);
}
opts.message = logLevel;
break;
case "object":
Object.assign(opts, logLevel);
break;
default:
}
if (typeof opts.message === "function") {
opts.message = opts.message();
}
const messageType = typeof opts.message;
assert(messageType === "string" || messageType === "object");
return Object.assign(opts, { args }, opts.opts);
}
// ../../node_modules/@probe.gl/log/dist/loggers/base-log.js
var noop = () => {
};
var BaseLog = class {
constructor({ level = 0 } = {}) {
this.userData = {};
this._onceCache = /* @__PURE__ */ new Set();
this._level = level;
}
set level(newLevel) {
this.setLevel(newLevel);
}
get level() {
return this.getLevel();
}
setLevel(level) {
this._level = level;
return this;
}
getLevel() {
return this._level;
}
// Unconditional logging
warn(message, ...args) {
return this._log("warn", 0, message, args, { once: true });
}
error(message, ...args) {
return this._log("error", 0, message, args);
}
// Conditional logging
log(logLevel, message, ...args) {
return this._log("log", logLevel, message, args);
}
info(logLevel, message, ...args) {
return this._log("info", logLevel, message, args);
}
once(logLevel, message, ...args) {
return this._log("once", logLevel, message, args, { once: true });
}
_log(type, logLevel, message, args, options = {}) {
const normalized = normalizeArguments({
logLevel,
message,
args: this._buildArgs(logLevel, message, args),
opts: options
});
return this._createLogFunction(type, normalized, options);
}
_buildArgs(logLevel, message, args) {
return [logLevel, message, ...args];
}
_createLogFunction(type, normalized, options) {
if (!this._shouldLog(normalized.logLevel)) {
return noop;
}
const tag = this._getOnceTag(options.tag ?? normalized.tag ?? normalized.message);
if ((options.once || normalized.once) && tag !== void 0) {
if (this._onceCache.has(tag)) {
return noop;
}
this._onceCache.add(tag);
}
return this._emit(type, normalized);
}
_shouldLog(logLevel) {
return this.getLevel() >= normalizeLogLevel(logLevel);
}
_getOnceTag(tag) {
if (tag === void 0) {
return void 0;
}
try {
return typeof tag === "string" ? tag : String(tag);
} catch {
return void 0;
}
}
};
// ../../node_modules/@probe.gl/log/dist/utils/local-storage.js
function getStorage(type) {
try {
const storage = window[type];
const x = "__storage_test__";
storage.setItem(x, x);
storage.removeItem(x);
return storage;
} catch (e) {
return null;
}
}
var LocalStorage = class {
constructor(id, defaultConfig, type = "sessionStorage") {
this.storage = getStorage(type);
this.id = id;
this.config = defaultConfig;
this._loadConfiguration();
}
getConfiguration() {
return this.config;
}
setConfiguration(configuration) {
Object.assign(this.config, configuration);
if (this.storage) {
const serialized = JSON.stringify(this.config);
this.storage.setItem(this.id, serialized);
}
}
// Get config from persistent store, if available
_loadConfiguration() {
let configuration = {};
if (this.storage) {
const serializedConfiguration = this.storage.getItem(this.id);
configuration = serializedConfiguration ? JSON.parse(serializedConfiguration) : {};
}
Object.assign(this.config, configuration);
return this;
}
};
// ../../node_modules/@probe.gl/log/dist/utils/formatters.js
function formatTime(ms) {
let formatted;
if (ms < 10) {
formatted = `${ms.toFixed(2)}ms`;
} else if (ms < 100) {
formatted = `${ms.toFixed(1)}ms`;
} else if (ms < 1e3) {
formatted = `${ms.toFixed(0)}ms`;
} else {
formatted = `${(ms / 1e3).toFixed(2)}s`;
}
return formatted;
}
function leftPad(string, length = 8) {
const padLength = Math.max(length - string.length, 0);
return `${" ".repeat(padLength)}${string}`;
}
// ../../node_modules/@probe.gl/log/dist/utils/color.js
var COLOR;
(function(COLOR2) {
COLOR2[COLOR2["BLACK"] = 30] = "BLACK";
COLOR2[COLOR2["RED"] = 31] = "RED";
COLOR2[COLOR2["GREEN"] = 32] = "GREEN";
COLOR2[COLOR2["YELLOW"] = 33] = "YELLOW";
COLOR2[COLOR2["BLUE"] = 34] = "BLUE";
COLOR2[COLOR2["MAGENTA"] = 35] = "MAGENTA";
COLOR2[COLOR2["CYAN"] = 36] = "CYAN";
COLOR2[COLOR2["WHITE"] = 37] = "WHITE";
COLOR2[COLOR2["BRIGHT_BLACK"] = 90] = "BRIGHT_BLACK";
COLOR2[COLOR2["BRIGHT_RED"] = 91] = "BRIGHT_RED";
COLOR2[COLOR2["BRIGHT_GREEN"] = 92] = "BRIGHT_GREEN";
COLOR2[COLOR2["BRIGHT_YELLOW"] = 93] = "BRIGHT_YELLOW";
COLOR2[COLOR2["BRIGHT_BLUE"] = 94] = "BRIGHT_BLUE";
COLOR2[COLOR2["BRIGHT_MAGENTA"] = 95] = "BRIGHT_MAGENTA";
COLOR2[COLOR2["BRIGHT_CYAN"] = 96] = "BRIGHT_CYAN";
COLOR2[COLOR2["BRIGHT_WHITE"] = 97] = "BRIGHT_WHITE";
})(COLOR || (COLOR = {}));
var BACKGROUND_INCREMENT = 10;
function getColor(color) {
if (typeof color !== "string") {
return color;
}
color = color.toUpperCase();
return COLOR[color] || COLOR.WHITE;
}
function addColor(string, color, background) {
if (!isBrowser && typeof string === "string") {
if (color) {
const colorCode = getColor(color);
string = `\x1B[${colorCode}m${string}\x1B[39m`;
}
if (background) {
const colorCode = getColor(background);
string = `\x1B[${colorCode + BACKGROUND_INCREMENT}m${string}\x1B[49m`;
}
}
return string;
}
// ../../node_modules/@probe.gl/log/dist/utils/autobind.js
function autobind(obj, predefined = ["constructor"]) {
const proto = Object.getPrototypeOf(obj);
const propNames = Object.getOwnPropertyNames(proto);
const object = obj;
for (const key of propNames) {
const value = object[key];
if (typeof value === "function") {
if (!predefined.find((name2) => key === name2)) {
object[key] = value.bind(obj);
}
}
}
}
// ../../node_modules/@probe.gl/log/dist/utils/hi-res-timestamp.js
function getHiResTimestamp2() {
let timestamp;
if (isBrowser() && window_.performance) {
timestamp = window_?.performance?.now?.();
} else if ("hrtime" in process_) {
const timeParts = process_?.hrtime?.();
timestamp = timeParts[0] * 1e3 + timeParts[1] / 1e6;
} else {
timestamp = Date.now();
}
return timestamp;
}
// ../../node_modules/@probe.gl/log/dist/loggers/probe-log.js
var originalConsole = {
debug: isBrowser() ? console.debug || console.log : console.log,
log: console.log,
info: console.info,
warn: console.warn,
error: console.error
};
var DEFAULT_LOG_CONFIGURATION = {
enabled: true,
level: 0
};
var ProbeLog = class extends BaseLog {
constructor({ id } = { id: "" }) {
super({ level: 0 });
this.VERSION = VERSION;
this._startTs = getHiResTimestamp2();
this._deltaTs = getHiResTimestamp2();
this.userData = {};
this.LOG_THROTTLE_TIMEOUT = 0;
this.id = id;
this.userData = {};
this._storage = new LocalStorage(`__probe-${this.id}__`, { [this.id]: DEFAULT_LOG_CONFIGURATION });
this.timeStamp(`${this.id} started`);
autobind(this);
Object.seal(this);
}
isEnabled() {
return this._getConfiguration().enabled;
}
getLevel() {
return this._getConfiguration().level;
}
/** @return milliseconds, with fractions */
getTotal() {
return Number((getHiResTimestamp2() - this._startTs).toPrecision(10));
}
/** @return milliseconds, with fractions */
getDelta() {
return Number((getHiResTimestamp2() - this._deltaTs).toPrecision(10));
}
/** @deprecated use logLevel */
set priority(newPriority) {
this.level = newPriority;
}
/** @deprecated use logLevel */
get priority() {
return this.level;
}
/** @deprecated use logLevel */
getPriority() {
return this.level;
}
// Configure
enable(enabled = true) {
this._updateConfiguration({ enabled });
return this;
}
setLevel(level) {
this._updateConfiguration({ level });
return this;
}
/** return the current status of the setting */
get(setting) {
return this._getConfiguration()[setting];
}
// update the status of the setting
set(setting, value) {
this._updateConfiguration({ [setting]: value });
}
/** Logs the current settings as a table */
settings() {
if (console.table) {
console.table(this._storage.config);
} else {
console.log(this._storage.config);
}
}
// Unconditional logging
assert(condition, message) {
if (!condition) {
throw new Error(message || "Assertion failed");
}
}
warn(message, ...args) {
return this._log("warn", 0, message, args, {
method: originalConsole.warn,
once: true
});
}
error(message, ...args) {
return this._log("error", 0, message, args, {
method: originalConsole.error
});
}
/** Print a deprecation warning */
deprecated(oldUsage, newUsage) {
return this.warn(`\`${oldUsage}\` is deprecated and will be removed in a later version. Use \`${newUsage}\` instead`);
}
/** Print a removal warning */
removed(oldUsage, newUsage) {
return this.error(`\`${oldUsage}\` has been removed. Use \`${newUsage}\` instead`);
}
probe(logLevel, message, ...args) {
return this._log("log", logLevel, message, args, {
method: originalConsole.log,
time: true,
once: true
});
}
log(logLevel, message, ...args) {
return this._log("log", logLevel, message, args, {
method: originalConsole.debug
});
}
info(logLevel, message, ...args) {
return this._log("info", logLevel, message, args, { method: console.info });
}
once(logLevel, message, ...args) {
return this._log("once", logLevel, message, args, {
method: originalConsole.debug || originalConsole.info,
once: true
});
}
/** Logs an object as a table */
table(logLevel, table, columns) {
if (table) {
return this._log("table", logLevel, table, columns && [columns] || [], {
method: console.table || noop,
tag: getTableHeader(table)
});
}
return noop;
}
time(logLevel, message) {
return this._log("time", logLevel, message, [], {
method: console.time ? console.time : console.info
});
}
timeEnd(logLevel, message) {
return this._log("time", logLevel, message, [], {
method: console.timeEnd ? console.timeEnd : console.info
});
}
timeStamp(logLevel, message) {
return this._log("time", logLevel, message, [], {
method: console.timeStamp || noop
});
}
group(logLevel, message, opts = { collapsed: false }) {
const method = (opts.collapsed ? console.groupCollapsed : console.group) || console.info;
return this._log("group", logLevel, message, [], { method });
}
groupCollapsed(logLevel, message, opts = {}) {
return this.group(logLevel, message, Object.assign({}, opts, { collapsed: true }));
}
groupEnd(logLevel) {
return this._log("groupEnd", logLevel, "", [], {
method: console.groupEnd || noop
});
}
// EXPERIMENTAL
withGroup(logLevel, message, func) {
this.group(logLevel, message)();
try {
func();
} finally {
this.groupEnd(logLevel)();
}
}
trace() {
if (console.trace) {
console.trace();
}
}
_shouldLog(logLevel) {
return this.isEnabled() && super._shouldLog(logLevel);
}
_emit(_type, normalized) {
const method = normalized.method;
assert(method);
normalized.total = this.getTotal();
normalized.delta = this.getDelta();
this._deltaTs = getHiResTimestamp2();
const message = decorateMessage(this.id, normalized.message, normalized);
return method.bind(console, message, ...normalized.args);
}
_getConfiguration() {
if (!this._storage.config[this.id]) {
this._updateConfiguration(DEFAULT_LOG_CONFIGURATION);
}
return this._storage.config[this.id];
}
_updateConfiguration(configuration) {
const currentConfiguration = this._storage.config[this.id] || {
...DEFAULT_LOG_CONFIGURATION
};
this._storage.setConfiguration({
[this.id]: { ...currentConfiguration, ...configuration }
});
}
};
ProbeLog.VERSION = VERSION;
function decorateMessage(id, message, opts) {
if (typeof message === "string") {
const time = opts.time ? leftPad(formatTime(opts.total)) : "";
message = opts.time ? `${id}: ${time} ${message}` : `${id}: ${message}`;
message = addColor(message, opts.color, opts.background);
}
return message;
}
function getTableHeader(table) {
for (const key in table) {
for (const title in table[key]) {
return title || "untitled";
}
}
return "empty";
}
// ../../node_modules/@probe.gl/log/dist/init.js
globalThis.probe = {};
// ../../node_modules/@probe.gl/log/dist/index.js
var dist_default = new ProbeLog({ id: "@probe.gl/log" });
// src/utils/log.ts
var log = new ProbeLog({ id: "luma.gl" });
// src/utils/uid.ts
var uidCounters = {};
function uid(id = "id") {
uidCounters[id] = uidCounters[id] || 1;
const count = uidCounters[id]++;
return `${id}-${count}`;
}
// src/adapter/resources/resource.ts
var CPU_HOTSPOT_PROFILER_MODULE = "cpu-hotspot-profiler";
var RESOURCE_COUNTS_STATS = "GPU Resource Counts";
var LEGACY_RESOURCE_COUNTS_STATS = "Resource Counts";
var GPU_TIME_AND_MEMORY_STATS2 = "GPU Time and Memory";
var BASE_RESOURCE_COUNT_ORDER = [
"Resources",
"Buffers",
"Textures",
"Samplers",
"TextureViews",
"Framebuffers",
"QuerySets",
"Shaders",
"RenderPipelines",
"ComputePipelines",
"PipelineLayouts",
"VertexArrays",
"RenderPasss",
"ComputePasss",
"CommandEncoders",
"CommandBuffers"
];
var WEBGL_RESOURCE_COUNT_ORDER = [
"Resources",
"Buffers",
"Textures",
"Samplers",
"TextureViews",
"Framebuffers",
"QuerySets",
"Shaders",
"RenderPipelines",
"SharedRenderPipelines",
"ComputePipelines",
"PipelineLayouts",
"VertexArrays",
"RenderPasss",
"ComputePasss",
"CommandEncoders",
"CommandBuffers"
];
var BASE_RESOURCE_COUNT_STAT_ORDER = BASE_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
`${resourceType} Created`,
`${resourceType} Active`
]);
var WEBGL_RESOURCE_COUNT_STAT_ORDER = WEBGL_RESOURCE_COUNT_ORDER.flatMap((resourceType) => [
`${resourceType} Created`,
`${resourceType} Active`
]);
var ORDERED_STATS_CACHE2 = /* @__PURE__ */ new WeakMap();
var ORDERED_STAT_NAME_SET_CACHE2 = /* @__PURE__ */ new WeakMap();
var Resource = class {
toString() {
return `${this[Symbol.toStringTag] || this.constructor.name}:"${this.id}"`;
}
/** props.id, for debugging. */
id;
/** The props that this resource was created with */
props;
/** User data object, reserved for the application */
userData = {};
/** The device that this resource is associated with - TODO can we remove this dup? */
_device;
/** Whether this resource has been destroyed */
destroyed = false;
/** For resources that allocate GPU memory */
allocatedBytes = 0;
/** Stats bucket currently holding the tracked allocation */
allocatedBytesName = null;
/** Attached resources will be destroyed when this resource is destroyed. Tracks auto-created "sub" resources. */
_attachedResources = /* @__PURE__ */ new Set();
/**
* Create a new Resource. Called from Subclass
*/
constructor(device, props, defaultProps) {
if (!device) {
throw new Error("no device");
}
this._device = device;
this.props = selectivelyMerge(props, defaultProps);
const id = this.props.id !== "undefined" ? this.props.id : uid(this[Symbol.toStringTag]);
this.props.id = id;
this.id = id;
this.userData = this.props.userData || {};
this.addStats();
}
/**
* destroy can be called on any resource to release it before it is garbage collected.
*/
destroy() {
if (this.destroyed) {
return;
}
this.destroyResource();
}
/** @deprecated Use destroy() */
delete() {
this.destroy();
return this;
}
/**
* Combines a map of user props and default props, only including props from defaultProps
* @returns returns a map of overridden default props
*/
getProps() {
return this.props;
}
// ATTACHED RESOURCES
/**
* Attaches a resource. Attached resources are auto destroyed when this resource is destroyed
* Called automatically when sub resources are auto created but can be called by application
*/
attachResource(resource) {
this._attachedResources.add(resource);
}
/**
* Detach an attached resource. The resource will no longer be auto-destroyed when this resource is destroyed.
*/
detachResource(resource) {
this._attachedResources.delete(resource);
}
/**
* Destroys a resource (only if owned), and removes from the owned (auto-destroy) list for this resource.
*/
destroyAttachedResource(resource) {
if (this._attachedResources.delete(resource)) {
resource.destroy();
}
}
/** Destroy all owned resources. Make sure the resources are no longer needed before calling. */
destroyAttachedResources() {
for (const resource of this._attachedResources) {
resource.destroy();
}
this._attachedResources = /* @__PURE__ */ new Set();
}
// PROTECTED METHODS
/** Perform all destroy steps. Can be called by derived resources when overriding destroy() */
destroyResource() {
if (this.destroyed) {
return;
}
this.destroyAttachedResources();
this.removeStats();
this.destroyed = true;
}
/** Called by .destroy() to track object destruction. Subclass must call if overriding destroy() */
removeStats() {
const profiler = getCpuHotspotProfiler(this._device);
const startTime = profiler ? getTimestamp() : 0;
const statsObjects = [
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
];
const orderedStatNames = getResourceCountStatOrder(this._device);
for (const stats of statsObjects) {
initializeStats2(stats, orderedStatNames);
}
const name2 = this.getStatsName();
for (const stats of statsObjects) {
stats.get("Resources Active").decrementCount();
stats.get(`${name2}s Active`).decrementCount();
}
if (profiler) {
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
}
}
/** Called by subclass to track memory allocations */
trackAllocatedMemory(bytes, name2 = this.getStatsName()) {
const profiler = getCpuHotspotProfiler(this._device);
const startTime = profiler ? getTimestamp() : 0;
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
if (this.allocatedBytes > 0 && this.allocatedBytesName) {
stats.get("GPU Memory").subtractCount(this.allocatedBytes);
stats.get(`${this.allocatedBytesName} Memory`).subtractCount(this.allocatedBytes);
}
stats.get("GPU Memory").addCount(bytes);
stats.get(`${name2} Memory`).addCount(bytes);
if (profiler) {
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
}
this.allocatedBytes = bytes;
this.allocatedBytesName = name2;
}
/** Called by subclass to track handle-backed memory allocations separately from owned allocations */
trackReferencedMemory(bytes, name2 = this.getStatsName()) {
this.trackAllocatedMemory(bytes, `Referenced ${name2}`);
}
/** Called by subclass to track memory deallocations */
trackDeallocatedMemory(name2 = this.getStatsName()) {
if (this.allocatedBytes === 0) {
this.allocatedBytesName = null;
return;
}
const profiler = getCpuHotspotProfiler(this._device);
const startTime = profiler ? getTimestamp() : 0;
const stats = this._device.statsManager.getStats(GPU_TIME_AND_MEMORY_STATS2);
stats.get("GPU Memory").subtractCount(this.allocatedBytes);
stats.get(`${this.allocatedBytesName || name2} Memory`).subtractCount(this.allocatedBytes);
if (profiler) {
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
}
this.allocatedBytes = 0;
this.allocatedBytesName = null;
}
/** Called by subclass to deallocate handle-backed memory tracked via trackReferencedMemory() */
trackDeallocatedReferencedMemory(name2 = this.getStatsName()) {
this.trackDeallocatedMemory(`Referenced ${name2}`);
}
/** Called by resource constructor to track object creation */
addStats() {
const name2 = this.getStatsName();
const profiler = getCpuHotspotProfiler(this._device);
const startTime = profiler ? getTimestamp() : 0;
const statsObjects = [
this._device.statsManager.getStats(RESOURCE_COUNTS_STATS),
this._device.statsManager.getStats(LEGACY_RESOURCE_COUNTS_STATS)
];
const orderedStatNames = getResourceCountStatOrder(this._device);
for (const stats of statsObjects) {
initializeStats2(stats, orderedStatNames);
}
for (const stats of statsObjects) {
stats.get("Resources Created").incrementCount();
stats.get("Resources Active").incrementCount();
stats.get(`${name2}s Created`).incrementCount();
stats.get(`${name2}s Active`).incrementCount();
}
if (profiler) {
profiler.statsBookkeepingCalls = (profiler.statsBookkeepingCalls || 0) + 1;
profiler.statsBookkeepingTimeMs = (profiler.statsBookkeepingTimeMs || 0) + (getTimestamp() - startTime);
}
recordTransientCanvasResourceCreate(this._device, name2);
}
/** Canonical resource name used for stats buckets. */
getStatsName() {
return getCanonicalResourceName(this);
}
};
/** Default properties for resource */
__publicField(Resource, "defaultProps", {
id: "undefined",
handle: void 0,
userData: void 0
});
function selectivelyMerge(props, defaultProps) {
const mergedProps = { ...defaultProps };
for (const key in props) {
if (props[key] !== void 0) {
mergedProps[key] = props[key];
}
}
return mergedProps;
}
function initializeStats2(stats, orderedStatNames) {
const statsMap = stats.stats;
let addedOrderedStat = false;
for (const statName of orderedStatNames) {
if (!statsMap[statName]) {
stats.get(statName);
addedOrderedStat = true;
}
}
const statCount = Object.keys(statsMap).length;
const cachedStats = ORDERED_STATS_CACHE2.get(stats);
if (!addedOrderedStat && cachedStats?.orderedStatNames === orderedStatNames && cachedStats.statCount === statCount) {
return;
}
const reorderedStats = {};
let orderedStatNamesSet = ORDERED_STAT_NAME_SET_CACHE2.get(orderedStatNames);
if (!orderedStatNamesSet) {
orderedStatNamesSet = new Set(orderedStatNames);
ORDERED_STAT_NAME_SET_CACHE2.set(orderedStatNames, orderedStatNamesSet);
}
for (const statName of orderedStatNames) {
if (statsMap[statName]) {
reorderedStats[statName] = statsMap[statName];
}
}
for (const [statName, stat] of Object.entries(statsMap)) {
if (!orderedStatNamesSet.has(statName)) {
reorderedStats[statName] = stat;
}
}
for (const statName of Object.keys(statsMap)) {
delete statsMap[statName];
}
Object.assign(statsMap, reorderedStats);
ORDERED_STATS_CACHE2.set(stats, { orderedStatNames, statCount });
}
function getResourceCountStatOrder(device) {
return device.type === "webgl" ? WEBGL_RESOURCE_COUNT_STAT_ORDER : BASE_RESOURCE_COUNT_STAT_ORDER;
}
function getCpuHotspotProfiler(device) {
const profiler = device.userData[CPU_HOTSPOT_PROFILER_MODULE];
return profiler?.enabled ? profiler : null;
}
function getTimestamp() {
return globalThis.performance?.now?.() ?? Date.now();
}
function recordTransientCanvasResourceCreate(device, name2) {
const profiler = getCpuHotspotProfiler(device);
if (!profiler || !profiler.activeDefaultFramebufferAcquireDepth) {
return;
}
profiler.transientCanvasResourceCreates = (profiler.transientCanvasResourceCreates || 0) + 1;
switch (name2) {
case "Texture":
profiler.transientCanvasTextureCreates = (profiler.transientCanvasTextureCreates || 0) + 1;
break;
case "TextureView":
profiler.transientCanvasTextureViewCreates = (profiler.transientCanvasTextureViewCreates || 0) + 1;
break;
case "Sampler":
profiler.transientCanvasSamplerCreates = (profiler.transientCanvasSamplerCreates || 0) + 1;
break;
case "Framebuffer":
profiler.transientCanvasFramebufferCreates = (profiler.transientCanvasFramebufferCreates || 0) + 1;
break;
default:
break;
}
}
function getCanonicalResourceName(resource) {
let prototype = Object.getPrototypeOf(resource);
while (prototype) {
const parentPrototype = Object.getPrototypeOf(prototype);
if (!parentPrototype || parentPrototype === Resource.prototype) {
return getPrototypeToStringTag(prototype) || resource[Symbol.toStringTag] || resource.constructor.name;
}
prototype = parentPrototype;
}
return resource[Symbol.toStringTag] || resource.constructor.name;
}
function getPrototypeToStringTag(prototype) {
const descriptor = Object.getOwnPropertyDescriptor(prototype, Symbol.toStringTag);
if (typeof descriptor?.get === "function") {
return descriptor.get.call(prototype);
}
if (typeof descriptor?.value === "string") {
return descriptor.value;
}
return null;
}
// src/adapter/resources/buffer.ts
var _Buffer = class extends Resource {
get [Symbol.toStringTag]() {
return "Buffer";
}
/** The usage with which this buffer was created */
usage;
/** For index buffers, whether indices are 8, 16 or 32 bit. Note: uint8 indices are automatically converted to uint16 for WebGPU compatibility */
indexType;
/** "Time" of last update, can be used to check if redraw is needed */
updateTimestamp;
constructor(device, props) {
const deducedProps = { ...props };
if ((props.usage || 0) & _Buffer.INDEX && !props.indexType) {
if (props.data instanceof Uint32Array) {
deducedProps.indexType = "uint32";
} else if (props.data instanceof Uint16Array) {
deducedProps.indexType = "uint16";
} else if (props.data instanceof Uint8Array) {
deducedProps.indexType = "uint8";
}
}
delete deducedProps.data;
super(device, deducedProps, _Buffer.defaultProps);
this.usage = deducedProps.usage || 0;
this.indexType = deducedProps.indexType;
this.updateTimestamp = device.incrementTimestamp();
}
/**
* Create a copy of this Buffer with new byteLength, with same props but of the specified size.
* @note Does not copy contents of the cloned Buffer.
*/
clone(props) {
return this.device.createBuffer({ ...this.props, ...props });
}
/** A partial CPU-side copy of the data in this buffer, for debugging purposes */
debugData = new ArrayBuffer(0);
/** This doesn't handle partial non-zero offset updates correctly */
_setDebugData(data, _byteOffset, byteLength) {
let arrayBufferView = null;
let arrayBuffer2;
if (ArrayBuffer.isView(data)) {
arrayBufferView = data;
arrayBuffer2 = data.buffer;
} else {
arrayBuffer2 = data;
}
const debugDataLength = Math.min(
data ? data.byteLength : byteLength,
_Buffer.DEBUG_DATA_MAX_LENGTH
);
if (arrayBuffer2 === null) {
this.debugData = new ArrayBuffer(debugDataLength);
} else {
const sourceByteOffset = Math.min(arrayBufferView?.byteOffset || 0, arrayBuffer2.byteLength);
const availableByteLength = Math.max(0, arrayBuffer2.byteLength - sourceByteOffset);
const copyByteLength = Math.min(debugDataLength, availableByteLength);
this.debugData = new Uint8Array(arrayBuffer2, sourceByteOffset, copyByteLength).slice().buffer;
}
}
};
var Buffer2 = _Buffer;
/** Index buffer */
__publicField(Buffer2, "INDEX", 16);
/** Vertex buffer */
__publicField(Buffer2, "VERTEX", 32);
/** Uniform buffer */
__publicField(Buffer2, "UNIFORM", 64);
/** Storage buffer */
__publicField(Buffer2, "STORAGE", 128);
__publicField(Buffer2, "INDIRECT", 256);
__publicField(Buffer2, "QUERY_RESOLVE", 512);
// Usage Flags
__publicField(Buffer2, "MAP_READ", 1);
__publicField(Buffer2, "MAP_WRITE", 2);
__publicField(Buffer2, "COPY_SRC", 4);
__publicField(Buffer2, "COPY_DST", 8);
// PROTECTED METHODS (INTENDED FOR USE BY OTHER FRAMEWORK CODE ONLY)
/** Max amount of debug data saved. Two vec4's */
__publicField(Buffer2, "DEBUG_DATA_MAX_LENGTH", 32);
__publicField(Buffer2, "defaultProps", {
...Resource.defaultProps,
usage: 0,
// Buffer.COPY_DST | Buffer.COPY_SRC
byteLength: 0,
byteOffset: 0,
data: null,
indexType: "uint16",
onMapped: void 0
});
// src/shadertypes/data-types/data-type-decoder.ts
var DataTypeDecoder = class {
/**
* Gets info about a data type constant (signed or normalized)
* @returns underlying primitive / signed types, byte length, normalization, integer, signed flags
*/
getDataTypeInfo(type) {
const [signedType, primitiveType, byteLength] = NORMALIZED_TYPE_MAP[type];
const normalized = type.includes("norm");
const integer = !normalized && !type.startsWith("float");
const signed = type.startsWith("s");
return {
signedType,
primitiveType,
byteLength,
normalized,
integer,
signed
// TODO - add webglOnly flag
};
}
/** Build a vertex format from a signed data type and a component */
getNormalizedDataType(signedDataType) {
const dataType = signedDataType;
switch (dataType) {
case "uint8":
return "unorm8";
case "sint8":
return "snorm8";
case "uint16":
return "unorm16";
case "sint16":
return "snorm16";
default:
return dataType;
}
}
/** Align offset to 1, 2 or 4 elements (4, 8 or 16 bytes) */
alignTo(size, count) {
switch (count) {
case 1:
return size;
case 2:
return size + size % 2;
default:
return size + (4 - size % 4) % 4;
}
}
/** Returns the VariableShaderType that corresponds to a typed array */
getDataType(arrayOrType) {
const Constructor = ArrayBuffer.isView(arrayOrType) ? arrayOrType.constructor : arrayOrType;
if (Constructor === Uint8ClampedArray) {
return "uint8";
}
const info = Object.values(NORMALIZED_TYPE_MAP).find((entry) => Constructor === entry[4]);
if (!info) {
throw new Error(Constructor.name);
}
return info[0];
}
/** Returns the TypedArray that corresponds to a shader data type */
getTypedArrayConstructor(type) {
const [, , , , Constructor] = NORMALIZED_TYPE_MAP[type];
return Constructor;
}
};
var dataTypeDecoder = new DataTypeDecoder();
var NORMALIZED_TYPE_MAP = {
uint8: ["uint8", "u32", 1, false, Uint8Array],
sint8: ["sint8", "i32", 1, false, Int8Array],
unorm8: ["uint8", "f32", 1, true, Uint8Array],
snorm8: ["sint8", "f32", 1, true, Int8Array],
uint16: ["uint16", "u32", 2, false, Uint16Array],
sint16: ["sint16", "i32", 2, false, Int16Array],
unorm16: ["uint16", "u32", 2, true, Uint16Array],
snorm16: ["sint16", "i32", 2, true, Int16Array],
float16: ["float16", "f16", 2, false, Uint16Array],
float32: ["float32", "f32", 4, false, Float32Array],
uint32: ["uint32", "u32", 4, false, Uint32Array],
sint32: ["sint32", "i32", 4, false, Int32Array]
};
// src/shadertypes/vertex-types/vertex-format-decoder.ts
var VertexFormatDecoder = class {
/**
* Decodes a vertex format, returning type, components, byte length and flags (integer, signed, normalized)
*/
getVertexFormatInfo(format) {
let webglOnly;
if (format.endsWith("-webgl")) {
format.replace("-webgl", "");
webglOnly = true;
}
const [type_, count] = format.split("x");
const type = type_;
const components = count ? parseInt(count) : 1;
const decodedType = dataTypeDecoder.getDataTypeInfo(type);
const result = {
type,
components,
byteLength: decodedType.byteLength * components,
integer: decodedType.integer,
signed: decodedType.signed,
normalized: decodedType.normalized
};
if (webglOnly) {
result.webglOnly = true;
}
return result;
}
/** Build a vertex format from a signed data type and a component */
makeVertexFormat(signedDataType, components, normalized) {
const dataType = normalized ? dataTypeDecoder.getNormalizedDataType(signedDataType) : signedDataType;
switch (dataType) {
case "unorm8":
if (components === 1) {
return "unorm8";
}
if (components === 3) {
return "unorm8x3-webgl";
}
return `${dataType}x${components}`;
case "snorm8":
if (components === 1) {
return "snorm8";
}
if (components === 3) {
return "snorm8x3-webgl";
}
return `${dataType}x${components}`;
case "uint8":
case "sint8":
if (components === 1 || components === 3) {
throw new Error(`size: ${components}`);
}
return `${dataType}x${components}`;
case "uint16":
if (components === 1) {
return "uint16";
}
if (components === 3) {
return "uint16x3-webgl";
}
return `${dataType}x${components}`;
case "sint16":
if (components === 1) {
return "sint16";
}
if (components === 3) {
return "sint16x3-webgl";
}
return `${dataType}x${components}`;
case "unorm16":
if (components === 1) {
return "unorm16";
}
if (components === 3) {
return "unorm16