@luma.gl/core
Version:
The luma.gl core Device API
1,321 lines (1,309 loc) • 184 kB
JavaScript
"use strict";
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;
};
// dist/index.js
var dist_exports = {};
__export(dist_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: () => assert,
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
});
module.exports = __toCommonJS(dist_exports);
// dist/utils/stats-manager.js
var import_stats = require("@probe.gl/stats");
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 import_stats.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 == null ? void 0 : 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 });
}
// dist/utils/log.js
var import_log = require("@probe.gl/log");
var log = new import_log.Log({ id: "luma.gl" });
// dist/utils/uid.js
var uidCounters = {};
function uid(id = "id") {
uidCounters[id] = uidCounters[id] || 1;
const count = uidCounters[id]++;
return `${id}-${count}`;
}
// dist/adapter/resources/resource.js
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 == null ? void 0 : 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 == null ? void 0 : profiler.enabled) ? profiler : null;
}
function getTimestamp() {
var _a, _b;
return ((_b = (_a = globalThis.performance) == null ? void 0 : _a.now) == null ? void 0 : _b.call(_a)) ?? 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 == null ? void 0 : descriptor.get) === "function") {
return descriptor.get.call(prototype);
}
if (typeof (descriptor == null ? void 0 : descriptor.value) === "string") {
return descriptor.value;
}
return null;
}
// dist/adapter/resources/buffer.js
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 == null ? void 0 : 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
});
// dist/shadertypes/data-types/data-type-decoder.js
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]
};
// dist/shadertypes/vertex-types/vertex-format-decoder.js
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 "unorm16x3-webgl";
}
return `${dataType}x${components}`;
case "snorm16":
if (components === 1) {
return "snorm16";
}
if (components === 3) {
return "snorm16x3-webgl";
}
return `${dataType}x${components}`;
case "float16":
if (components === 1 || components === 3) {
throw new Error(`size: ${components}`);
}
return `${dataType}x${components}`;
default:
return components === 1 ? dataType : `${dataType}x${components}`;
}
}
/** Get the vertex format for an attribute with TypedArray and size */
getVertexFormatFromAttribute(typedArray, size, normalized) {
if (!size || size > 4) {
throw new Error(`size ${size}`);
}
const components = size;
const signedDataType = dataTypeDecoder.getDataType(typedArray);
return this.makeVertexFormat(signedDataType, components, normalized);
}
/**
* Return a "default" vertex format for a certain shader data type
* The simplest vertex format that matches the shader attribute's data type
*/
getCompatibleVertexFormat(opts) {
let vertexType;
switch (opts.primitiveType) {
case "f32":
vertexType = "float32";
break;
case "i32":
vertexType = "sint32";
break;
case "u32":
vertexType = "uint32";
break;
case "f16":
return opts.components <= 2 ? "float16x2" : "float16x4";
}
if (opts.components === 1) {
return vertexType;
}
return `${vertexType}x${opts.components}`;
}
};
var vertexFormatDecoder = new VertexFormatDecoder();
// dist/shadertypes/texture-types/texture-format-table.js
var texture_compression_bc = "texture-compression-bc";
var texture_compression_astc = "texture-compression-astc";
var texture_compression_etc2 = "texture-compression-etc2";
var texture_compression_etc1_webgl = "texture-compression-etc1-webgl";
var texture_compression_pvrtc_webgl = "texture-compression-pvrtc-webgl";
var texture_compression_atc_webgl = "texture-compression-atc-webgl";
var float32_renderable = "float32-renderable-webgl";
var float16_renderable = "float16-renderable-webgl";
var rgb9e5ufloat_renderable = "rgb9e5ufloat-renderable-webgl";
var snorm8_renderable = "snorm8-renderable-webgl";
var norm16_webgl = "norm16-webgl";
var norm16_renderable = "norm16-renderable-webgl";
var snorm16_renderable = "snorm16-renderable-webgl";
var float32_filterable = "float32-filterable";
var float16_filterable = "float16-filterable-webgl";
function getTextureFormatDefinition(format) {
const info = TEXTURE_FORMAT_TABLE[format];
if (!info) {
throw new Error(`Unsupported texture format ${format}`);
}
return info;
}
function getTextureFormatTable() {
return TEXTURE_FORMAT_TABLE;
}
var TEXTURE_FORMAT_COLOR_DEPTH_TABLE = {
// 8-bit formats
"r8unorm": {},
"rg8unorm": {},
"rgb8unorm-webgl": {},
"rgba8unorm": {},
"rgba8unorm-srgb": {},
"r8snorm": { render: snorm8_renderable },
"rg8snorm": { render: snorm8_renderable },
"rgb8snorm-webgl": {},
"rgba8snorm": { render: snorm8_renderable },
"r8uint": {},
"rg8uint": {},
"rgba8uint": {},
"r8sint": {},
"rg8sint": {},
"rgba8sint": {},
"bgra8unorm": {},
"bgra8unorm-srgb": {},
"r16unorm": { f: norm16_webgl, render: norm16_renderable },
"rg16unorm": { f: norm16_webgl, render: norm16_renderable },
"rgb16unorm-webgl": { f: norm16_webgl, render: false },
// rgb not renderable
"rgba16unorm": { f: norm16_webgl, render: norm16_renderable },
"r16snorm": { f: norm16_webgl, render: snorm16_renderable },
"rg16snorm": { f: norm16_webgl, render: snorm16_renderable },
"rgb16snorm-webgl": { f: norm16_webgl, render: false },
// rgb not renderable
"rgba16snorm": { f: norm16_webgl, render: snorm16_renderable },
"r16uint": {},
"rg16uint": {},
"rgba16uint": {},
"r16sint": {},
"rg16sint": {},
"rgba16sint": {},
"r16float": { render: float16_renderable, filter: "float16-filterable-webgl" },
"rg16float": { render: float16_renderable, filter: float16_filterable },
"rgba16float": { render: float16_renderable, filter: float16_filterable },
"r32uint": {},
"rg32uint": {},
"rgba32uint": {},
"r32sint": {},
"rg32sint": {},
"rgba32sint": {},
"r32float": { render: float32_renderable, filter: float32_filterable },
"rg32float": { render: false, filter: float32_filterable },
"rgb32float-webgl": { render: float32_renderable, filter: float32_filterable },
"rgba32float": { render: float32_renderable, filter: float32_filterable },
// Packed 16-bit formats
"rgba4unorm-webgl": { channels: "rgba", bitsPerChannel: [4, 4, 4, 4], packed: true },
"rgb565unorm-webgl": { channels: "rgb", bitsPerChannel: [5, 6, 5, 0], packed: true },
"rgb5a1unorm-webgl": { channels: "rgba", bitsPerChannel: [5, 5, 5, 1], packed: true },
// Packed 32 bit formats
"rgb9e5ufloat": { channels: "rgb", packed: true, render: rgb9e5ufloat_renderable },
// , filter: true},
"rg11b10ufloat": { channels: "rgb", bitsPerChannel: [11, 11, 10, 0], packed: true, p: 1, render: float32_renderable },
"rgb10a2unorm": { channels: "rgba", bitsPerChannel: [10, 10, 10, 2], packed: true, p: 1 },
"rgb10a2uint": { channels: "rgba", bitsPerChannel: [10, 10, 10, 2], packed: true, p: 1 },
// Depth/stencil Formats
// Depth and stencil formats
stencil8: { attachment: "stencil", bitsPerChannel: [8, 0, 0, 0], dataType: "uint8" },
"depth16unorm": { attachment: "depth", bitsPerChannel: [16, 0, 0, 0], dataType: "uint16" },
"depth24plus": { attachment: "depth", bitsPerChannel: [24, 0, 0, 0], dataType: "uint32" },
"depth32float": { attachment: "depth", bitsPerChannel: [32, 0, 0, 0], dataType: "float32" },
// The depth component of the "depth24plus" and "depth24plus-stencil8" formats may be implemented as either a 24-bit depth value or a "depth32float" value.
"depth24plus-stencil8": { attachment: "depth-stencil", bitsPerChannel: [24, 8, 0, 0], packed: true },
// "depth32float-stencil8" feature
"depth32float-stencil8": { attachment: "depth-stencil", bitsPerChannel: [32, 8, 0, 0], packed: true }
};
var TEXTURE_FORMAT_COMPRESSED_TABLE = {
// BC compressed formats: check device.features.has("texture-compression-bc");
"bc1-rgb-unorm-webgl": { f: texture_compression_bc },
"bc1-rgb-unorm-srgb-webgl": { f: texture_compression_bc },
"bc1-rgba-unorm": { f: texture_compression_bc },
"bc1-rgba-unorm-srgb": { f: texture_compression_bc },
"bc2-rgba-unorm": { f: texture_compression_bc },
"bc2-rgba-unorm-srgb": { f: texture_compression_bc },
"bc3-rgba-unorm": { f: texture_compression_bc },
"bc3-rgba-unorm-srgb": { f: texture_compression_bc },
"bc4-r-unorm": { f: texture_compression_bc },
"bc4-r-snorm": { f: texture_compression_bc },
"bc5-rg-unorm": { f: texture_compression_bc },
"bc5-rg-snorm": { f: texture_compression_bc },
"bc6h-rgb-ufloat": { f: texture_compression_bc },
"bc6h-rgb-float": { f: texture_compression_bc },
"bc7-rgba-unorm": { f: texture_compression_bc },
"bc7-rgba-unorm-srgb": { f: texture_compression_bc },
// WEBGL_compressed_texture_etc: device.features.has("texture-compression-etc2")
// Note: Supposedly guaranteed availability compressed formats in WebGL2, but through CPU decompression
"etc2-rgb8unorm": { f: texture_compression_etc2 },
"etc2-rgb8unorm-srgb": { f: texture_compression_etc2 },
"etc2-rgb8a1unorm": { f: texture_compression_etc2 },
"etc2-rgb8a1unorm-srgb": { f: texture_compression_etc2 },
"etc2-rgba8unorm": { f: texture_compression_etc2 },
"etc2-rgba8unorm-srgb": { f: texture_compression_etc2 },
"eac-r11unorm": { f: texture_compression_etc2 },
"eac-r11snorm": { f: texture_compression_etc2 },
"eac-rg11unorm": { f: texture_compression_etc2 },
"eac-rg11snorm": { f: texture_compression_etc2 },
// X_ASTC compressed formats: device.features.has("texture-compression-astc")
"astc-4x4-unorm": { f: texture_compression_astc },
"astc-4x4-unorm-srgb": { f: texture_compression_astc },
"astc-5x4-unorm": { f: texture_compression_astc },
"astc-5x4-unorm-srgb": { f: texture_compression_astc },
"astc-5x5-unorm": { f: texture_compression_astc },
"astc-5x5-unorm-srgb": { f: texture_compression_astc },
"astc-6x5-unorm": { f: texture_compression_astc },
"astc-6x5-unorm-srgb": { f: texture_compression_astc },
"astc-6x6-unorm": { f: texture_compression_astc },
"astc-6x6-unorm-srgb": { f: texture_compression_astc },
"astc-8x5-unorm": { f: texture_compression_astc },
"astc-8x5-unorm-srgb": { f: texture_compression_astc },
"astc-8x6-unorm": { f: texture_compression_astc },
"astc-8x6-unorm-srgb": { f: texture_compression_astc },
"astc-8x8-unorm": { f: texture_compression_astc },
"astc-8x8-unorm-srgb": { f: texture_compression_astc },
"astc-10x5-unorm": { f: texture_compression_astc },
"astc-10x5-unorm-srgb": { f: texture_compression_astc },
"astc-10x6-unorm": { f: texture_compression_astc },
"astc-10x6-unorm-srgb": { f: texture_compression_astc },
"astc-10x8-unorm": { f: texture_compression_astc },
"astc-10x8-unorm-srgb": { f: texture_compression_astc },
"astc-10x10-unorm": { f: texture_compression_astc },
"astc-10x10-unorm-srgb": { f: texture_compression_astc },
"astc-12x10-unorm": { f: texture_compression_astc },
"astc-12x10-unorm-srgb": { f: texture_compression_astc },
"astc-12x12-unorm": { f: texture_compression_astc },
"astc-12x12-unorm-srgb": { f: texture_compression_astc },
// WEBGL_compressed_texture_pvrtc
"pvrtc-rgb4unorm-webgl": { f: texture_compression_pvrtc_webgl },
"pvrtc-rgba4unorm-webgl": { f: texture_compression_pvrtc_webgl },
"pvrtc-rgb2unorm-webgl": { f: texture_compression_pvrtc_webgl },
"pvrtc-rgba2unorm-webgl": { f: texture_compression_pvrtc_webgl },
// WEBGL_compressed_texture_etc1
"etc1-rbg-unorm-webgl": { f: texture_compression_etc1_webgl },
// WEBGL_compressed_texture_atc
"atc-rgb-unorm-webgl": { f: texture_compression_atc_webgl },
"atc-rgba-unorm-webgl": { f: texture_compression_atc_webgl },
"atc-rgbai-unorm-webgl": { f: texture_compression_atc_webgl }
};
var TEXTURE_FORMAT_TABLE = {
...TEXTURE_FORMAT_COLOR_DEPTH_TABLE,
...TEXTURE_FORMAT_COMPRESSED_TABLE
};
// dist/shadertypes/texture-types/texture-format-decoder.js
var RGB_FORMAT_REGEX = /^(r|rg|rgb|rgba|bgra)([0-9]*)([a-z]*)(-srgb)?(-webgl)?$/;
var COLOR_FORMAT_PREFIXES = ["rgb", "rgba", "bgra"];
var DEPTH_FORMAT_PREFIXES = ["depth", "stencil"];
var COMPRESSED_TEXTURE_FORMAT_PREFIXES = [
"bc1",
"bc2",
"bc3",
"bc4",
"bc5",
"bc6",
"bc7",
"etc1",
"etc2",
"eac",
"atc",
"astc",
"pvrtc"
];
var TextureFormatDecoder = class {
/** Checks if a texture format is color */
isColor(format) {
return COLOR_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
}
/** Checks if a texture format is depth or stencil */
isDepthStencil(format) {
return DEPTH_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
}
/** Checks if a texture format is compressed */
isCompressed(format) {
return COMPRESSED_TEXTURE_FORMAT_PREFIXES.some((prefix) => format.startsWith(prefix));
}
/** Returns information about a texture format, e.g. attachment type, components, byte length and flags (integer, signed, normalized) */
getInfo(format) {
return getTextureFormatInfo(format);
}
/** "static" capabilities of a texture format. @note Needs to be adjusted against current device */
getCapabilities(format) {
return getTextureFormatCapabilities(format);
}
/** Computes the memory layout for a texture, in particular including row byte alignment */
computeMemoryLayout(opts) {
return computeTextureMemoryLayout(opts);
}
};
var textureFormatDecoder = new TextureFormatDecoder();
function computeTextureMemoryLayout({ format, width, height, depth, byteAlignment }) {
const formatInfo = textureFormatDecoder.getInfo(format);
const { bytesPerPixel, bytesPerBlock = bytesPerPixel, blockWidth = 1, blockHeight = 1, compressed = false } = formatInfo;
const blockColumns = compressed ? Math.ceil(width / blockWidth) : width;
const blockRows = compressed ? Math.ceil(height / blockHeight) : height;
const unpaddedBytesPerRow = blockColumns * bytesPerBlock;
const bytesPerRow = Math.ceil(unpaddedBytesPerRow / byteAlignment) * byteAlignment;
const rowsPerImage = blockRows;
const byteLength = bytesPerRow * rowsPerImage * depth;
return {
bytesPerPixel,
bytesPerRow,
rowsPerImage,
depthOrArrayLayers: depth,
bytesPerImage: bytesPerRow * rowsPerImage,
byteLength
};
}
function getTextureFormatCapabilities(format) {
const info = getTextureFormatDefinition(format);
const formatCapabilities = {
format,
create: info.f ?? true,
render: info.render ?? true,
filter: info.filter ?? true,
blend: info.blend ?? true,
store: info.store ?? true
};
const formatInfo = getTextureFormatInfo(format);
const isDepthStencil = format.startsWith("depth") || format.startsWith("stencil");
const isSigned = formatInfo == null ? void 0 : formatInfo.signed;
const isInteger = formatInfo == null ? void 0 : formatInfo.integer;
const isWebGLSpecific = formatInfo == null ? void 0 : formatInfo.webgl;
const isCompressed = Boolean(formatInfo == null ? void 0 : formatInfo.compressed);
formatCapabilities.render &&= !isDepthStencil && !isCompressed;
formatCapabilities.filter &&= !isDepthStencil && !isSigned && !isInteger && !isWebGLSpecific;
return formatCapabilities;
}
function getTextureFormatInfo(format) {
let formatInfo = getTextureFormatInfoUsingTable(format);
if (textureFormatDecoder.isCompressed(format)) {
formatInfo.channels = "rgb";
formatInfo.components = 3;
formatInfo.bytesPerPixel = 1;
formatInfo.srgb = false;
formatInfo.compressed = true;
formatInfo.bytesPerBlock = getCompressedTextureBlockByteLength(format);
const blockSize = getCompressedTextureBlockSize(format);
if (blockSize) {
formatInfo.blockWidth = blockSize.blockWidth;
formatInfo.blockHeight = blockSize.blockHeight;
}
}
const matches = !formatInfo.packed ? RGB_FORMAT_REGEX.exec(format) : null;
if (matches) {
const [, channels, length, type, srgb, suffix] = matches;
const dataType = `${type}${length}`;
const decodedType = dataTypeDecoder.getDataTypeInfo(dataType);
const bits = decodedType.byteLength * 8;
const components = (channels == null ? void 0 : channels.length) ?? 1;
const bitsPerChannel = [
bits,
components >= 2 ? bits : 0,
components >= 3 ? bits : 0,
components >= 4 ? bits : 0
];
formatInfo = {
format,
attachment: formatInfo.attachment,
dataType: decodedType.signedType,
components,
channels,
integer: decodedType.integer,
signed: decodedType.signed,
normalized: decodedType.normalized,
bitsPerChannel,
bytesPerPixel: decodedType.byteLength * components,
packed: formatInfo.packed,
srgb: formatInfo.srgb
};
if (suffix === "-webgl") {
formatInfo.webgl = true;
}
if (srgb === "-srgb") {
formatInfo.srgb = true;
}
}
if (format.endsWith("-webgl")) {
formatInfo.webgl = true;
}
if (format.endsWith("-srgb")) {
formatInfo.srgb = true;
}
return formatInfo;
}
function getTextureFormatInfoUsingTable(format) {
var _a;
const info = getTextureFormatDefinition(format);
const bytesPerPixel = info.bytesPerPixel || 1;
const bitsPerChannel = info.bitsPerChannel || [8, 8, 8, 8];
delete info.bitsPerChannel;
delete info.bytesPerPixel;
delete info.f;
delete info.render;
delete info.filter;
delete info.blend;
delete info.store;
const formatInfo = {
...info,
format,
attachment: info.attachment || "color",
channels: info.channels || "r",
components: info.components || ((_a = info.channels) == null ? void 0 : _a.length) || 1,
bytesPerPixel,
bitsPerChannel,
dataType: info.dataType || "uint8",
srgb: info.srgb ?? false,
packed: info.packed ?? false,
webgl: info.webgl ?? false,
integer: info.integer ?? false,
signed: info.signed ?? false,
normalized: info.normalized ?? false,
compressed: info.compressed ?? false
};
return formatInfo;
}
function getCompressedTextureBlockSize(format) {
const REGEX = /.*-(\d+)x(\d+)-.*/;
const matches = REGEX.exec(format);
if (matches) {
const [, blockWidth, blockHeight] = matches;
return { blockWidth: Number(blockWidth), blockHeight: Number(blockHeight) };
}
if (format.startsWith("bc") || format.startsWith("etc1") || format.startsWith("etc2") || format.startsWith("eac") || format.startsWith("atc")) {
return { blockWidth: 4, blockHeight: 4 };
}
if (format.startsWith("pvrtc-rgb4") || format.startsWith("pvrtc-rgba4")) {
return { blockWidth: 4, blockHeight: 4 };
}
if (format.startsWith("pvrtc-rgb2") || format.startsWith("pvrtc-rgba2")) {
return { blockWidth: 8, blockHeight: 4 };
}
return null;
}
function getCompressedTextureBlockByteLength(format) {
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") {
return 8;
}
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") {
return 16;
}
if (format.startsWith("pvrtc")) {
return 8;
}
return 16;
}
// dist/shadertypes/image-types/image-types.js
function isExternalImage(data) {
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;
}
function getExternalImageSize(data) {
if (typeof ImageData !== "undefined" && data instanceof ImageData || typeof ImageBitmap !== "undefined" && data instanceof ImageBitmap || typeof HTMLCanvasElement !== "undefined" && data instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && data instanceof OffscreenCanvas) {
return { width: data.width, height: data.height };
}
if (typeof HTMLImageElement !== "undefined" && data instanceof HTMLImageElement) {
return { width: data.naturalWidth, height: data.naturalHeight };
}
if (typeof HTMLVideoElement !== "undefined" && data instanceof HTMLVideoElement) {
return { width: data.videoWidth, height: data.videoHeight };
}
if (typeof VideoFrame !== "undefined" && data instanceof VideoFrame) {
return { width: data.displayWidth, height: data.displayHeight };
}
throw new Error("Unknown image type");
}
// dist/adapter/device.js
var DeviceLimits = class {
};
function formatErrorLogArguments(context, args) {
const formattedContext = formatErrorLogValue(context);
const formattedArgs = args.map(formatErrorLogValue).filter((arg) => arg !== void 0);
return [formattedContext, ...formattedArgs].filter((arg) => arg !== void 0);
}
function formatErrorLogValue(value) {
var _a;
if (value === void 0) {
return void 0;
}
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
return value;
}
if (value instanceof Error) {
return value.message;
}
if (Array.isArray(value)) {
return value.map(formatErrorLogValue);
}
if (typeof value === "object") {
if (hasCustomToString(value)) {
const stringValue = String(value);
if (stringValue !== "[object Object]") {
return stringValue;
}
}
if (looksLikeGPUCompilationMessage(value)) {
return formatGPUCompilationMessage(value);
}
return ((_a = value.constructor) == null ? void 0 : _a.name) || "Object";
}
return String(value);
}
function hasCustomToString(value) {
return "toString" in value && typeof value.toString === "function" && value.toString !== Object.prototype.toString;
}
function looksLikeGPUCompilationMessage(value) {
return "message" in value && "type" in value;
}
function formatGPUCompilationMessage(value) {
const type = typeof value.type === "string" ? value.type : "message";
const message = typeof value.message === "string" ? value.message : "";
const lineNum = typeof value.lineNum === "number" ? value.lineNum : null;
const linePos = typeof value.linePos === "number" ? value.linePos : null;
const location = lineNum !== null && linePos !== null ? ` @ ${lineNum}:${linePos}` : lineNum !== null ? ` @ ${lineNum}` : "";
return `${type}${location}: ${message}`.trim();
}
var DeviceFeatures = class {
features;
disabledFeatures;
constructor(features = [], disabledFeatures) {
this.features = new Set(features);
this.disabledFeatures = disabledFeatures || {};
}
*[Symbol.iterator]() {
yield* this.features;
}
has(feature) {
var _a;
return !((_a = this.disabledFeatures) == null ? void 0 : _a[feature]) && this.features.has(feature);
}
};
var _Device = class {
get [Symbol.toStringTag]() {
return "Device";
}
toString() {
return `Device(${this.id})`;
}
/** id of this device, primarily for debugging */
id;
/** A copy of the device props */
props;
/** Available for the application to store data on the device */
userData = {};
/** stats */
statsManager = lumaStats;
/** Internal per-device factory storage */
_factories = {};
/** An abstract timestamp used for change tracking */
timestamp = 0;
/** True if this device has been reused during device creation (app has multiple references) */
_reused = false;
/** Used by other luma.gl modules to store data on the device */
_moduleData = {};
_textureCaps = {};
/** Internal timestamp query set used when GPU timing collection is enabled for this device. */
_debugGPUTimeQuery = null;
constructor(props) {
this.props = { ..._Device.defaultProps, ...props };
this.id = this.props.id || uid(this[Symbol.toStringTag].toLowerCase());
}
// TODO - just expose the shadertypes decoders?
getVertexFormatInfo(format) {
return vertexFormatDecoder.getVertexFormatInfo(format);
}
isVertexFormatSupported(format) {
return true;
}
/** R