New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@luma.gl/webgpu

Package Overview
Dependencies
Maintainers
0
Versions
111
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@luma.gl/webgpu - npm Package Compare versions

Comparing version 9.1.0-alpha.19 to 9.1.0-beta.1

dist/adapter/helpers/accessor-to-format.js.map

1

dist/adapter/helpers/accessor-to-format.js

@@ -104,1 +104,2 @@ // luma.gl

*/
//# sourceMappingURL=accessor-to-format.js.map

@@ -11,1 +11,2 @@ // luma.gl

}
//# sourceMappingURL=convert-texture-format.js.map

4

dist/adapter/helpers/get-bind-group.d.ts

@@ -11,3 +11,5 @@ import type { ComputeShaderLayout, BindingDeclaration, Binding } from '@luma.gl/core';

export declare function getBindGroup(device: GPUDevice, bindGroupLayout: GPUBindGroupLayout, shaderLayout: ComputeShaderLayout, bindings: Record<string, Binding>): GPUBindGroup;
export declare function getShaderLayoutBinding(shaderLayout: ComputeShaderLayout, bindingName: string): BindingDeclaration | null;
export declare function getShaderLayoutBinding(shaderLayout: ComputeShaderLayout, bindingName: string, options?: {
ignoreWarnings?: boolean;
}): BindingDeclaration | null;
//# sourceMappingURL=get-bind-group.d.ts.map

@@ -26,5 +26,5 @@ // luma.gl

}
export function getShaderLayoutBinding(shaderLayout, bindingName) {
export function getShaderLayoutBinding(shaderLayout, bindingName, options) {
const bindingLayout = shaderLayout.bindings.find(binding => binding.name === bindingName || `${binding.name}uniforms` === bindingName.toLocaleLowerCase());
if (!bindingLayout) {
if (!bindingLayout && !options?.ignoreWarnings) {
log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();

@@ -41,10 +41,17 @@ }

for (const [bindingName, value] of Object.entries(bindings)) {
const bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
let bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
if (bindingLayout) {
entries.push(getBindGroupEntry(value, bindingLayout.location));
}
// TODO - hack to automatically bind samplers to supplied texture default samplers
bindingLayout = getShaderLayoutBinding(shaderLayout, `${bindingName}Sampler`, {
ignoreWarnings: true
});
if (bindingLayout) {
entries.push(getBindGroupEntry(value, bindingLayout.location, { sampler: true }));
}
}
return entries;
}
function getBindGroupEntry(binding, index) {
function getBindGroupEntry(binding, index, options) {
if (binding instanceof Buffer) {

@@ -65,2 +72,8 @@ return {

else if (binding instanceof Texture) {
if (options?.sampler) {
return {
binding: index,
resource: binding.sampler.handle
};
}
return {

@@ -73,1 +86,2 @@ binding: index,

}
//# sourceMappingURL=get-bind-group.js.map

@@ -127,7 +127,7 @@ // luma.gl

if (!attribute) {
log.warn(`Unknown attribute ${name}`)();
log.warn(`Supplied attribute not present in shader layout: ${name}`)();
return null;
}
if (attributeNames.has(name)) {
throw new Error(`Duplicate attribute ${name}`);
throw new Error(`Found multiple entries for attribute: ${name}`);
}

@@ -137,1 +137,2 @@ attributeNames.add(name);

}
//# sourceMappingURL=get-vertex-buffer-layout.js.map

@@ -213,1 +213,2 @@ // luma.gl

}
//# sourceMappingURL=webgpu-parameters.js.map

@@ -128,1 +128,2 @@ // luma.gl

*/
//# sourceMappingURL=webgpu-buffer.js.map

@@ -102,1 +102,2 @@ // luma.gl

*/
//# sourceMappingURL=webgpu-command-encoder.js.map

@@ -81,1 +81,2 @@ // luma.gl

}
//# sourceMappingURL=webgpu-compute-pass.js.map

@@ -50,1 +50,2 @@ // luma.gl

}
//# sourceMappingURL=webgpu-compute-pipeline.js.map

@@ -41,1 +41,2 @@ // luma.gl

}
//# sourceMappingURL=webgpu-external-texture.js.map

@@ -23,1 +23,2 @@ // luma.gl

}
//# sourceMappingURL=webgpu-framebuffer.js.map

@@ -28,1 +28,2 @@ // luma.gl

}
//# sourceMappingURL=webgpu-query-set.js.map

@@ -32,3 +32,9 @@ // luma.gl

}
this.device.handle.pushErrorScope('validation');
this.handle = this.props.handle || device.commandEncoder.beginRenderPass(renderPassDescriptor);
this.device.handle.popErrorScope().then((error) => {
if (error) {
log.error(`${this} creation failed:\n"${error.message}"`, this)();
}
});
this.handle.label = this.props.id;

@@ -154,1 +160,2 @@ log.groupCollapsed(3, `new WebGPURenderPass(${this.id})`)();

}
//# sourceMappingURL=webgpu-render-pass.js.map

@@ -15,2 +15,3 @@ import type { Binding, RenderPass, VertexArray } from '@luma.gl/core';

private _bindGroup;
get [Symbol.toStringTag](): string;
constructor(device: WebGPUDevice, props: RenderPipelineProps);

@@ -17,0 +18,0 @@ destroy(): void;

@@ -18,2 +18,5 @@ // luma.gl MIT license

_bindGroup = null;
get [Symbol.toStringTag]() {
return 'WebGPURenderPipeline';
}
constructor(device, props) {

@@ -28,5 +31,12 @@ super(device, props);

log.groupEnd(1)();
this.device.handle.pushErrorScope('validation');
this.handle = this.device.handle.createRenderPipeline(descriptor);
this.device.handle.popErrorScope().then((error) => {
if (error) {
log.error(`${this} creation failed:\n"${error.message}"`, this, this.props.vs?.source)();
}
});
}
this.handle.label = this.props.id;
// Note: Often the same shader in WebGPU
this.vs = props.vs;

@@ -46,2 +56,8 @@ this.fs = props.fs;

setBindings(bindings) {
// Invalidate the cached bind group if any value has changed
for (const [name, binding] of Object.entries(bindings)) {
if (this._bindings[name] !== binding) {
this._bindGroup = null;
}
}
Object.assign(this._bindings, bindings);

@@ -53,3 +69,9 @@ }

// Set pipeline
this.device.handle.pushErrorScope('validation');
webgpuRenderPass.handle.setPipeline(this.handle);
this.device.handle.popErrorScope().then((error) => {
if (error) {
log.error(`${this} setPipeline failed:\n"${error.message}"`, this)();
}
});
// Set bindings (uniform buffers, textures etc)

@@ -99,2 +121,13 @@ const bindGroup = this._getBindGroup();

};
// Populate color targets
// TODO - at the moment blend and write mask are only set on the first target
const targets = [];
if (this.props.colorAttachmentFormats) {
for (const format of this.props.colorAttachmentFormats) {
targets.push(format ? { format: getWebGPUTextureFormat(format) } : null);
}
}
else {
targets.push({ format: getWebGPUTextureFormat(this.device.preferredColorFormat) });
}
// Set up the fragment stage

@@ -104,8 +137,3 @@ const fragment = {

entryPoint: this.props.fragmentEntryPoint || 'main',
targets: [
{
// TODO exclamation mark hack!
format: getWebGPUTextureFormat(this.device.getCanvasContext().format)
}
]
targets
};

@@ -121,2 +149,9 @@ // Create a partially populated descriptor

};
// Set depth format if required, defaulting to the preferred depth format
const depthFormat = this.props.depthStencilAttachmentFormat || this.device.preferredDepthFormat;
if (this.props.parameters.depthWriteEnabled) {
descriptor.depthStencil = {
format: getWebGPUTextureFormat(depthFormat)
};
}
// Set parameters on the descriptor

@@ -169,1 +204,2 @@ applyParametersToRenderPipelineDescriptor(descriptor, this.props.parameters);

*/
//# sourceMappingURL=webgpu-render-pipeline.js.map

@@ -36,1 +36,2 @@ // luma.gl, MIT license

}
//# sourceMappingURL=webgpu-sampler.js.map

@@ -12,8 +12,7 @@ import type { ShaderProps, CompilerMessage } from '@luma.gl/core';

get asyncCompilationStatus(): Promise<any>;
_checkCompilationError(errorScope: Promise<GPUError | null>): Promise<void>;
_checkCompilationError(): Promise<void>;
destroy(): void;
/** Returns compilation info for this shader */
getCompilationInfo(): Promise<readonly CompilerMessage[]>;
protected createHandle(): GPUShaderModule;
}
//# sourceMappingURL=webgpu-shader.d.ts.map

@@ -14,6 +14,15 @@ // luma.gl

this.device = device;
const isGLSL = props.source.includes('#version');
if (this.props.language === 'glsl' || isGLSL) {
throw new Error('GLSL shaders are not supported in WebGPU');
}
this.device.handle.pushErrorScope('validation');
this.handle = this.props.handle || this.createHandle();
this.handle = this.props.handle || this.device.handle.createShaderModule({ code: props.source });
this.device.handle.popErrorScope().then((error) => {
if (error) {
log.error(`${this} creation failed:\n"${error.message}"`, this, this.props.source)();
}
});
this.handle.label = this.props.id;
this._checkCompilationError(this.device.handle.popErrorScope());
this._checkCompilationError();
}

@@ -23,12 +32,12 @@ get asyncCompilationStatus() {

}
async _checkCompilationError(errorScope) {
const error = (await errorScope);
if (error) {
// The `Shader` base class will determine if debug window should be opened based on props
this.debugShader();
const shaderLog = await this.getCompilationInfo();
log.error(`Shader compilation error: ${error.message}`, shaderLog)();
async _checkCompilationError() {
const shaderLog = await this.getCompilationInfo();
const hasErrors = Boolean(shaderLog.find(msg => msg.type === 'error'));
this.compilationStatus = hasErrors ? 'error' : 'success';
this.debugShader();
if (this.compilationStatus === 'error') {
log.error(`Shader compilation error`, shaderLog)();
// Note: Even though this error is asynchronous and thrown after the constructor completes,
// it will result in a useful stack trace leading back to the constructor
throw new Error(`Shader compilation error: ${error.message}`);
// throw new Error(`Shader compilation error`);
}

@@ -47,11 +56,3 @@ }

}
// PRIVATE METHODS
createHandle() {
const { source } = this.props;
const isGLSL = source.includes('#version');
if (this.props.language === 'glsl' || isGLSL) {
throw new Error('GLSL shaders are not supported in WebGPU');
}
return this.device.handle.createShaderModule({ code: source });
}
}
//# sourceMappingURL=webgpu-shader.js.map

@@ -36,1 +36,2 @@ // luma.gl

}
//# sourceMappingURL=webgpu-texture-view.js.map

@@ -161,1 +161,2 @@ import { Texture } from '@luma.gl/core';

}
//# sourceMappingURL=webgpu-texture.js.map

@@ -41,3 +41,3 @@ // luma.gl

// Note we can't unset an index buffer
log.warn('setting index buffer', webgpuIndexBuffer?.handle, webgpuIndexBuffer?.indexType)();
log.info(3, 'setting index buffer', webgpuIndexBuffer?.handle, webgpuIndexBuffer?.indexType)();
webgpuRenderPass.handle.setIndexBuffer(webgpuIndexBuffer?.handle,

@@ -50,3 +50,3 @@ // @ts-expect-error TODO - we must enforce type

if (webgpuBuffer?.handle) {
log.warn(`setting vertex buffer ${location}`, webgpuBuffer?.handle)();
log.info(3, `setting vertex buffer ${location}`, webgpuBuffer?.handle)();
webgpuRenderPass.handle.setVertexBuffer(location, webgpuBuffer?.handle);

@@ -71,1 +71,2 @@ }

}
//# sourceMappingURL=webgpu-vertex-array.js.map

@@ -65,1 +65,2 @@ // luma.gl

export const webgpuAdapter = new WebGPUAdapter();
//# sourceMappingURL=webgpu-adapter.js.map

@@ -1,2 +0,2 @@

import type { Texture, TextureFormat, CanvasContextProps } from '@luma.gl/core';
import type { DepthStencilTextureFormat, CanvasContextProps } from '@luma.gl/core';
import { CanvasContext } from '@luma.gl/core';

@@ -13,8 +13,5 @@ import { WebGPUDevice } from "./webgpu-device.js";

readonly device: WebGPUDevice;
readonly gpuCanvasContext: GPUCanvasContext;
/** Format of returned textures: "bgra8unorm", "rgba8unorm", "rgba16float". */
readonly format: TextureFormat;
/** Default stencil format for depth textures */
readonly depthStencilFormat: TextureFormat;
readonly handle: GPUCanvasContext;
private depthStencilAttachment;
get [Symbol.toStringTag](): string;
constructor(device: WebGPUDevice, adapter: GPUAdapter, props: CanvasContextProps);

@@ -24,5 +21,7 @@ /** Destroy any textures produced while configured and remove the context configuration. */

/** Update framebuffer with properly resized "swap chain" texture views */
getCurrentFramebuffer(): WebGPUFramebuffer;
getCurrentFramebuffer(options?: {
depthStencilFormat?: DepthStencilTextureFormat | false;
}): WebGPUFramebuffer;
/** Resizes and updates render targets if necessary */
update(): void;
updateSize(size: [newWidth: number, newHeight: number]): void;
resize(options?: {

@@ -36,4 +35,4 @@ width?: number;

/** We build render targets on demand (i.e. not when size changes but when about to render) */
_createDepthStencilAttachment(): Texture;
_createDepthStencilAttachment(depthStencilFormat: DepthStencilTextureFormat): WebGPUTexture;
}
//# sourceMappingURL=webgpu-canvas-context.d.ts.map
// luma.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors
import { CanvasContext, log } from '@luma.gl/core';
import { getWebGPUTextureFormat } from "./helpers/convert-texture-format.js";
import { CanvasContext, Texture, log } from '@luma.gl/core';
import { WebGPUFramebuffer } from "./resources/webgpu-framebuffer.js";

@@ -14,43 +13,36 @@ /**

device;
gpuCanvasContext;
/** Format of returned textures: "bgra8unorm", "rgba8unorm", "rgba16float". */
format = navigator.gpu.getPreferredCanvasFormat();
/** Default stencil format for depth textures */
depthStencilFormat = 'depth24plus';
handle;
depthStencilAttachment = null;
get [Symbol.toStringTag]() {
return 'WebGPUCanvasContext';
}
constructor(device, adapter, props) {
super(props);
this.device = device;
// TODO - hack to trigger resize?
this.width = -1;
this.height = -1;
// Base class constructor cannot access derived methods/fields, so we need to call these functions in the subclass constructor
this._setAutoCreatedCanvasId(`${this.device.id}-canvas`);
// @ts-ignore TODO - we don't handle OffscreenRenderingContext.
this.gpuCanvasContext = this.canvas.getContext('webgpu');
// TODO this has been replaced
// this.format = this.gpuCanvasContext.getPreferredFormat(adapter);
this.format = 'bgra8unorm';
this.updateSize([this.drawingBufferWidth, this.drawingBufferHeight]);
}
/** Destroy any textures produced while configured and remove the context configuration. */
destroy() {
this.gpuCanvasContext.unconfigure();
this.handle.unconfigure();
}
/** Update framebuffer with properly resized "swap chain" texture views */
getCurrentFramebuffer() {
// Ensure the canvas context size is updated
this.update();
getCurrentFramebuffer(options = {
depthStencilFormat: 'depth24plus'
}) {
// Wrap the current canvas context texture in a luma.gl texture
// const currentColorAttachment = this.device.createTexture({
// id: 'default-render-target',
// handle: this.gpuCanvasContext.getCurrentTexture(),
// format: this.format,
// width: this.width,
// height: this.height
// });
// Wrap the current canvas context texture in a luma.gl texture
const currentColorAttachment = this.getCurrentTexture();
this.width = currentColorAttachment.width;
this.height = currentColorAttachment.height;
// TODO - temporary debug code
if (currentColorAttachment.width !== this.drawingBufferWidth ||
currentColorAttachment.height !== this.drawingBufferHeight) {
const [oldWidth, oldHeight] = this.getDrawingBufferSize();
this.drawingBufferWidth = currentColorAttachment.width;
this.drawingBufferHeight = currentColorAttachment.height;
log.log(1, `${this}: Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`)();
}
// Resize the depth stencil attachment
this._createDepthStencilAttachment();
if (options?.depthStencilFormat) {
this._createDepthStencilAttachment(options?.depthStencilFormat);
}
return new WebGPUFramebuffer(this.device, {

@@ -62,33 +54,28 @@ colorAttachments: [currentColorAttachment],

/** Resizes and updates render targets if necessary */
update() {
const [width, height] = this.getPixelSize();
const sizeChanged = width !== this.width || height !== this.height;
if (sizeChanged) {
this.width = width;
this.height = height;
if (this.depthStencilAttachment) {
this.depthStencilAttachment.destroy();
this.depthStencilAttachment = null;
}
// Reconfigure the canvas size.
// https://www.w3.org/TR/webgpu/#canvas-configuration
this.gpuCanvasContext.configure({
device: this.device.handle,
format: getWebGPUTextureFormat(this.format),
// Can be used to define e.g. -srgb views
// viewFormats: [...]
colorSpace: this.props.colorSpace,
alphaMode: this.props.alphaMode
});
log.log(1, `Resized to ${this.width}x${this.height}px`)();
updateSize(size) {
if (this.depthStencilAttachment) {
this.depthStencilAttachment.destroy();
this.depthStencilAttachment = null;
}
// Reconfigure the canvas size.
// https://www.w3.org/TR/webgpu/#canvas-configuration
this.handle.configure({
device: this.device.handle,
format: this.device.preferredColorFormat,
// Can be used to define e.g. -srgb views
// viewFormats: [...]
colorSpace: this.props.colorSpace,
alphaMode: this.props.alphaMode
});
}
resize(options) {
this.update();
if (!this.device.handle)
return;
if (this.props.autoResize) {
return;
}
// Resize browser context .
if (this.canvas) {
const devicePixelRatio = this.getDevicePixelRatio(options?.useDevicePixels);
this.setDevicePixelRatio(devicePixelRatio, options);
this._setDevicePixelRatio(devicePixelRatio, options);
return;

@@ -101,15 +88,15 @@ }

id: `${this.id}#color-texture`,
handle: this.gpuCanvasContext.getCurrentTexture(),
format: this.format
handle: this.handle.getCurrentTexture(),
format: this.device.preferredColorFormat
});
}
/** We build render targets on demand (i.e. not when size changes but when about to render) */
_createDepthStencilAttachment() {
_createDepthStencilAttachment(depthStencilFormat) {
if (!this.depthStencilAttachment) {
this.depthStencilAttachment = this.device.createTexture({
id: `${this.id}#depth-stencil-texture`,
format: this.depthStencilFormat,
width: this.width,
height: this.height,
usage: GPUTextureUsage.RENDER_ATTACHMENT
usage: Texture.RENDER_ATTACHMENT,
format: depthStencilFormat,
width: this.drawingBufferWidth,
height: this.drawingBufferHeight
});

@@ -120,1 +107,2 @@ }

}
//# sourceMappingURL=webgpu-canvas-context.js.map

@@ -1,2 +0,2 @@

import type { DeviceInfo, DeviceLimits, CanvasContextProps, BufferProps, SamplerProps, ShaderProps, Texture, TextureProps, TextureFormat, ExternalTextureProps, FramebufferProps, RenderPipelineProps, ComputePipelineProps, RenderPassProps, ComputePassProps, VertexArrayProps, TransformFeedback, TransformFeedbackProps, QuerySet, QuerySetProps, DeviceProps } from '@luma.gl/core';
import type { DeviceInfo, DeviceLimits, DeviceTextureFormatCapabilities, CanvasContextProps, BufferProps, SamplerProps, ShaderProps, Texture, TextureProps, ExternalTextureProps, FramebufferProps, RenderPipelineProps, ComputePipelineProps, RenderPassProps, ComputePassProps, VertexArrayProps, TransformFeedback, TransformFeedbackProps, QuerySet, QuerySetProps, DeviceProps } from '@luma.gl/core';
import { Device, DeviceFeatures } from '@luma.gl/core';

@@ -17,8 +17,8 @@ import { WebGPUBuffer } from "./resources/webgpu-buffer.js";

export declare class WebGPUDevice extends Device {
/** The underlying WebGPU device */
readonly handle: GPUDevice;
/** type of this device */
readonly type = "webgpu";
/** The underlying WebGPU device */
readonly handle: GPUDevice;
readonly adapter: GPUAdapter;
readonly adapterInfo: GPUAdapterInfo;
readonly preferredColorFormat: "rgba8unorm" | "bgra8unorm";
readonly preferredDepthFormat = "depth24plus";
readonly features: DeviceFeatures;

@@ -31,13 +31,10 @@ readonly info: DeviceInfo;

}>;
renderPass: WebGPURenderPass | null;
canvasContext: WebGPUCanvasContext | null;
private _isLost;
commandEncoder: GPUCommandEncoder | null;
renderPass: WebGPURenderPass | null;
readonly adapter: GPUAdapter;
readonly adapterInfo: GPUAdapterInfo;
constructor(props: DeviceProps, device: GPUDevice, adapter: GPUAdapter, adapterInfo: GPUAdapterInfo);
destroy(): void;
isTextureFormatSupported(format: TextureFormat): boolean;
/** @todo implement proper check? */
isTextureFormatFilterable(format: TextureFormat): boolean;
/** @todo implement proper check? */
isTextureFormatRenderable(format: TextureFormat): boolean;
get isLost(): boolean;

@@ -65,2 +62,3 @@ createBuffer(props: BufferProps | ArrayBuffer | ArrayBufferView): WebGPUBuffer;

protected _getFeatures(): DeviceFeatures;
_getDeviceSpecificTextureFormatCapabilities(capabilities: DeviceTextureFormatCapabilities): DeviceTextureFormatCapabilities;
copyExternalImageToTexture(options: {

@@ -67,0 +65,0 @@ texture: Texture;

@@ -21,10 +21,8 @@ // luma.gl

export class WebGPUDevice extends Device {
/** The underlying WebGPU device */
handle;
/** type of this device */
type = 'webgpu';
/** The underlying WebGPU device */
handle;
/* The underlying WebGPU adapter */
adapter;
/* The underlying WebGPU adapter's info */
adapterInfo;
preferredColorFormat = navigator.gpu.getPreferredCanvasFormat();
preferredDepthFormat = 'depth24plus';
features;

@@ -34,6 +32,11 @@ info;

lost;
canvasContext = null;
renderPass = null;
canvasContext;
_isLost = false;
// canvasContext: WebGPUCanvasContext | null = null;
commandEncoder = null;
renderPass = null;
/* The underlying WebGPU adapter */
adapter;
/* The underlying WebGPU adapter's info */
adapterInfo;
constructor(props, device, adapter, adapterInfo) {

@@ -50,4 +53,9 @@ super({ ...props, id: props.id || 'webgpu-device' });

// TODO is this the right way to make sure the error is an Error instance?
const errorMessage = event instanceof GPUUncapturedErrorEvent ? event.error.message : 'Unknown error';
this.error(new Error(errorMessage));
const errorMessage = event instanceof GPUUncapturedErrorEvent ? event.error.message : 'Unknown WebGPU error';
this.reportError(new Error(errorMessage));
if (this.props.debug) {
// eslint-disable-next-line no-debugger
debugger;
}
event.preventDefault();
});

@@ -73,15 +81,2 @@ // "Context" loss handling

}
isTextureFormatSupported(format) {
return !format.includes('webgl');
}
/** @todo implement proper check? */
isTextureFormatFilterable(format) {
return (this.isTextureFormatSupported(format) &&
!format.startsWith('depth') &&
!format.startsWith('stencil'));
}
/** @todo implement proper check? */
isTextureFormatRenderable(format) {
return this.isTextureFormatSupported(format);
}
get isLost() {

@@ -144,9 +139,13 @@ return this._isLost;

submit() {
// this.renderPass?.end();
const commandBuffer = this.commandEncoder?.finish();
if (commandBuffer) {
this.handle.pushErrorScope('validation');
this.handle.queue.submit([commandBuffer]);
this.handle.popErrorScope().then((error) => {
if (error) {
this.reportError(new Error(`WebGPU command submission failed: ${error.message}`));
}
});
}
this.commandEncoder = null;
// this.renderPass = null;
}

@@ -205,2 +204,11 @@ // PRIVATE METHODS

}
_getDeviceSpecificTextureFormatCapabilities(capabilities) {
const { format } = capabilities;
if (format.includes('webgl')) {
return { format, create: false, render: false, filter: false, blend: false, store: false };
}
return capabilities;
}
// DEPRECATED METHODS
// @deprecated
copyExternalImageToTexture(options) {

@@ -232,1 +240,2 @@ const { source, sourceX = 0, sourceY = 0, texture, mipLevel = 0, aspect = 'all', colorSpace = 'display-p3', premultipliedAlpha = false,

}
//# sourceMappingURL=webgpu-device.js.map

@@ -446,6 +446,16 @@ (function webpackUniversalModuleDefinition(root, factory) {

this.device = device;
const isGLSL = props.source.includes("#version");
if (this.props.language === "glsl" || isGLSL) {
throw new Error("GLSL shaders are not supported in WebGPU");
}
this.device.handle.pushErrorScope("validation");
this.handle = this.props.handle || this.createHandle();
this.handle = this.props.handle || this.device.handle.createShaderModule({ code: props.source });
this.device.handle.popErrorScope().then((error) => {
if (error) {
import_core6.log.error(`${this} creation failed:
"${error.message}"`, this, this.props.source)();
}
});
this.handle.label = this.props.id;
this._checkCompilationError(this.device.handle.popErrorScope());
this._checkCompilationError();
}

@@ -455,9 +465,9 @@ get asyncCompilationStatus() {

}
async _checkCompilationError(errorScope) {
const error = await errorScope;
if (error) {
this.debugShader();
const shaderLog = await this.getCompilationInfo();
import_core6.log.error(`Shader compilation error: ${error.message}`, shaderLog)();
throw new Error(`Shader compilation error: ${error.message}`);
async _checkCompilationError() {
const shaderLog = await this.getCompilationInfo();
const hasErrors = Boolean(shaderLog.find((msg) => msg.type === "error"));
this.compilationStatus = hasErrors ? "error" : "success";
this.debugShader();
if (this.compilationStatus === "error") {
import_core6.log.error(`Shader compilation error`, shaderLog)();
}

@@ -473,11 +483,2 @@ }

}
// PRIVATE METHODS
createHandle() {
const { source } = this.props;
const isGLSL = source.includes("#version");
if (this.props.language === "glsl" || isGLSL) {
throw new Error("GLSL shaders are not supported in WebGPU");
}
return this.device.handle.createShaderModule({ code: source });
}
};

@@ -693,7 +694,7 @@

}
function getShaderLayoutBinding(shaderLayout, bindingName) {
function getShaderLayoutBinding(shaderLayout, bindingName, options) {
const bindingLayout = shaderLayout.bindings.find(
(binding) => binding.name === bindingName || `${binding.name}uniforms` === bindingName.toLocaleLowerCase()
);
if (!bindingLayout) {
if (!bindingLayout && !options?.ignoreWarnings) {
import_core7.log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();

@@ -706,10 +707,16 @@ }

for (const [bindingName, value] of Object.entries(bindings)) {
const bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
let bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
if (bindingLayout) {
entries.push(getBindGroupEntry(value, bindingLayout.location));
}
bindingLayout = getShaderLayoutBinding(shaderLayout, `${bindingName}Sampler`, {
ignoreWarnings: true
});
if (bindingLayout) {
entries.push(getBindGroupEntry(value, bindingLayout.location, { sampler: true }));
}
}
return entries;
}
function getBindGroupEntry(binding, index) {
function getBindGroupEntry(binding, index, options) {
if (binding instanceof import_core7.Buffer) {

@@ -729,2 +736,8 @@ return {

} else if (binding instanceof import_core7.Texture) {
if (options?.sampler) {
return {
binding: index,
resource: binding.sampler.handle
};
}
return {

@@ -807,7 +820,7 @@ binding: index,

if (!attribute) {
import_core8.log.warn(`Unknown attribute ${name}`)();
import_core8.log.warn(`Supplied attribute not present in shader layout: ${name}`)();
return null;
}
if (attributeNames.has(name)) {
throw new Error(`Duplicate attribute ${name}`);
throw new Error(`Found multiple entries for attribute: ${name}`);
}

@@ -828,2 +841,5 @@ attributeNames.add(name);

_bindGroup = null;
get [Symbol.toStringTag]() {
return "WebGPURenderPipeline";
}
constructor(device, props) {

@@ -838,3 +854,10 @@ super(device, props);

import_core9.log.groupEnd(1)();
this.device.handle.pushErrorScope("validation");
this.handle = this.device.handle.createRenderPipeline(descriptor);
this.device.handle.popErrorScope().then((error) => {
if (error) {
import_core9.log.error(`${this} creation failed:
"${error.message}"`, this, this.props.vs?.source)();
}
});
}

@@ -854,2 +877,7 @@ this.handle.label = this.props.id;

setBindings(bindings) {
for (const [name, binding] of Object.entries(bindings)) {
if (this._bindings[name] !== binding) {
this._bindGroup = null;
}
}
Object.assign(this._bindings, bindings);

@@ -860,3 +888,10 @@ }

const webgpuRenderPass = options.renderPass;
this.device.handle.pushErrorScope("validation");
webgpuRenderPass.handle.setPipeline(this.handle);
this.device.handle.popErrorScope().then((error) => {
if (error) {
import_core9.log.error(`${this} setPipeline failed:
"${error.message}"`, this)();
}
});
const bindGroup = this._getBindGroup();

@@ -904,11 +939,14 @@ if (bindGroup) {

};
const targets = [];
if (this.props.colorAttachmentFormats) {
for (const format of this.props.colorAttachmentFormats) {
targets.push(format ? { format: getWebGPUTextureFormat(format) } : null);
}
} else {
targets.push({ format: getWebGPUTextureFormat(this.device.preferredColorFormat) });
}
const fragment = {
module: this.props.fs.handle,
entryPoint: this.props.fragmentEntryPoint || "main",
targets: [
{
// TODO exclamation mark hack!
format: getWebGPUTextureFormat(this.device.getCanvasContext().format)
}
]
targets
};

@@ -923,2 +961,8 @@ const descriptor = {

};
const depthFormat = this.props.depthStencilAttachmentFormat || this.device.preferredDepthFormat;
if (this.props.parameters.depthWriteEnabled) {
descriptor.depthStencil = {
format: getWebGPUTextureFormat(depthFormat)
};
}
applyParametersToRenderPipelineDescriptor(descriptor, this.props.parameters);

@@ -1010,3 +1054,10 @@ return descriptor;

}
this.device.handle.pushErrorScope("validation");
this.handle = this.props.handle || device.commandEncoder.beginRenderPass(renderPassDescriptor);
this.device.handle.popErrorScope().then((error) => {
if (error) {
import_core12.log.error(`${this} creation failed:
"${error.message}"`, this)();
}
});
this.handle.label = this.props.id;

@@ -1304,3 +1355,8 @@ import_core12.log.groupCollapsed(3, `new WebGPURenderPass(${this.id})`)();

if (webgpuIndexBuffer?.handle) {
import_core14.log.warn("setting index buffer", webgpuIndexBuffer?.handle, webgpuIndexBuffer?.indexType)();
import_core14.log.info(
3,
"setting index buffer",
webgpuIndexBuffer?.handle,
webgpuIndexBuffer?.indexType
)();
webgpuRenderPass.handle.setIndexBuffer(

@@ -1315,3 +1371,3 @@ webgpuIndexBuffer?.handle,

if (webgpuBuffer?.handle) {
import_core14.log.warn(`setting vertex buffer ${location}`, webgpuBuffer?.handle)();
import_core14.log.info(3, `setting vertex buffer ${location}`, webgpuBuffer?.handle)();
webgpuRenderPass.handle.setVertexBuffer(location, webgpuBuffer?.handle);

@@ -1337,28 +1393,34 @@ }

device;
gpuCanvasContext;
/** Format of returned textures: "bgra8unorm", "rgba8unorm", "rgba16float". */
format = navigator.gpu.getPreferredCanvasFormat();
/** Default stencil format for depth textures */
depthStencilFormat = "depth24plus";
handle;
depthStencilAttachment = null;
get [Symbol.toStringTag]() {
return "WebGPUCanvasContext";
}
constructor(device, adapter, props) {
super(props);
this.device = device;
this.width = -1;
this.height = -1;
this._setAutoCreatedCanvasId(`${this.device.id}-canvas`);
this.gpuCanvasContext = this.canvas.getContext("webgpu");
this.format = "bgra8unorm";
this.updateSize([this.drawingBufferWidth, this.drawingBufferHeight]);
}
/** Destroy any textures produced while configured and remove the context configuration. */
destroy() {
this.gpuCanvasContext.unconfigure();
this.handle.unconfigure();
}
/** Update framebuffer with properly resized "swap chain" texture views */
getCurrentFramebuffer() {
this.update();
getCurrentFramebuffer(options = {
depthStencilFormat: "depth24plus"
}) {
const currentColorAttachment = this.getCurrentTexture();
this.width = currentColorAttachment.width;
this.height = currentColorAttachment.height;
this._createDepthStencilAttachment();
if (currentColorAttachment.width !== this.drawingBufferWidth || currentColorAttachment.height !== this.drawingBufferHeight) {
const [oldWidth, oldHeight] = this.getDrawingBufferSize();
this.drawingBufferWidth = currentColorAttachment.width;
this.drawingBufferHeight = currentColorAttachment.height;
import_core15.log.log(
1,
`${this}: Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`
)();
}
if (options?.depthStencilFormat) {
this._createDepthStencilAttachment(options?.depthStencilFormat);
}
return new WebGPUFramebuffer(this.device, {

@@ -1370,30 +1432,25 @@ colorAttachments: [currentColorAttachment],

/** Resizes and updates render targets if necessary */
update() {
const [width, height] = this.getPixelSize();
const sizeChanged = width !== this.width || height !== this.height;
if (sizeChanged) {
this.width = width;
this.height = height;
if (this.depthStencilAttachment) {
this.depthStencilAttachment.destroy();
this.depthStencilAttachment = null;
}
this.gpuCanvasContext.configure({
device: this.device.handle,
format: getWebGPUTextureFormat(this.format),
// Can be used to define e.g. -srgb views
// viewFormats: [...]
colorSpace: this.props.colorSpace,
alphaMode: this.props.alphaMode
});
import_core15.log.log(1, `Resized to ${this.width}x${this.height}px`)();
updateSize(size) {
if (this.depthStencilAttachment) {
this.depthStencilAttachment.destroy();
this.depthStencilAttachment = null;
}
this.handle.configure({
device: this.device.handle,
format: this.device.preferredColorFormat,
// Can be used to define e.g. -srgb views
// viewFormats: [...]
colorSpace: this.props.colorSpace,
alphaMode: this.props.alphaMode
});
}
resize(options) {
this.update();
if (!this.device.handle)
return;
if (this.props.autoResize) {
return;
}
if (this.canvas) {
const devicePixelRatio = this.getDevicePixelRatio(options?.useDevicePixels);
this.setDevicePixelRatio(devicePixelRatio, options);
this._setDevicePixelRatio(devicePixelRatio, options);
return;

@@ -1406,15 +1463,15 @@ }

id: `${this.id}#color-texture`,
handle: this.gpuCanvasContext.getCurrentTexture(),
format: this.format
handle: this.handle.getCurrentTexture(),
format: this.device.preferredColorFormat
});
}
/** We build render targets on demand (i.e. not when size changes but when about to render) */
_createDepthStencilAttachment() {
_createDepthStencilAttachment(depthStencilFormat) {
if (!this.depthStencilAttachment) {
this.depthStencilAttachment = this.device.createTexture({
id: `${this.id}#depth-stencil-texture`,
format: this.depthStencilFormat,
width: this.width,
height: this.height,
usage: GPUTextureUsage.RENDER_ATTACHMENT
usage: import_core15.Texture.RENDER_ATTACHMENT,
format: depthStencilFormat,
width: this.drawingBufferWidth,
height: this.drawingBufferHeight
});

@@ -1448,10 +1505,8 @@ }

var WebGPUDevice = class extends import_core17.Device {
/** The underlying WebGPU device */
handle;
/** type of this device */
type = "webgpu";
/** The underlying WebGPU device */
handle;
/* The underlying WebGPU adapter */
adapter;
/* The underlying WebGPU adapter's info */
adapterInfo;
preferredColorFormat = navigator.gpu.getPreferredCanvasFormat();
preferredDepthFormat = "depth24plus";
features;

@@ -1461,6 +1516,11 @@ info;

lost;
canvasContext = null;
renderPass = null;
canvasContext;
_isLost = false;
// canvasContext: WebGPUCanvasContext | null = null;
commandEncoder = null;
renderPass = null;
/* The underlying WebGPU adapter */
adapter;
/* The underlying WebGPU adapter's info */
adapterInfo;
constructor(props, device, adapter, adapterInfo) {

@@ -1475,4 +1535,8 @@ super({ ...props, id: props.id || "webgpu-device" });

device.addEventListener("uncapturederror", (event) => {
const errorMessage = event instanceof GPUUncapturedErrorEvent ? event.error.message : "Unknown error";
this.error(new Error(errorMessage));
const errorMessage = event instanceof GPUUncapturedErrorEvent ? event.error.message : "Unknown WebGPU error";
this.reportError(new Error(errorMessage));
if (this.props.debug) {
debugger;
}
event.preventDefault();
});

@@ -1496,13 +1560,2 @@ this.lost = new Promise(async (resolve) => {

}
isTextureFormatSupported(format) {
return !format.includes("webgl");
}
/** @todo implement proper check? */
isTextureFormatFilterable(format) {
return this.isTextureFormatSupported(format) && !format.startsWith("depth") && !format.startsWith("stencil");
}
/** @todo implement proper check? */
isTextureFormatRenderable(format) {
return this.isTextureFormatSupported(format);
}
get isLost() {

@@ -1567,3 +1620,9 @@ return this._isLost;

if (commandBuffer) {
this.handle.pushErrorScope("validation");
this.handle.queue.submit([commandBuffer]);
this.handle.popErrorScope().then((error) => {
if (error) {
this.reportError(new Error(`WebGPU command submission failed: ${error.message}`));
}
});
}

@@ -1618,2 +1677,11 @@ this.commandEncoder = null;

}
_getDeviceSpecificTextureFormatCapabilities(capabilities) {
const { format } = capabilities;
if (format.includes("webgl")) {
return { format, create: false, render: false, filter: false, blend: false, store: false };
}
return capabilities;
}
// DEPRECATED METHODS
// @deprecated
copyExternalImageToTexture(options) {

@@ -1620,0 +1688,0 @@ const {

@@ -7,4 +7,8 @@ (function webpackUniversalModuleDefinition(root, factory) {

else root['luma'] = factory();})(globalThis, function () {
var __exports__=(()=>{var ye=Object.create;var F=Object.defineProperty;var ve=Object.getOwnPropertyDescriptor;var Se=Object.getOwnPropertyNames;var Ce=Object.getPrototypeOf,Pe=Object.prototype.hasOwnProperty;var Ee=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports),Be=(n,e)=>{for(var t in e)F(n,t,{get:e[t],enumerable:!0})},I=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Se(e))!Pe.call(n,i)&&i!==t&&F(n,i,{get:()=>e[i],enumerable:!(r=ve(e,i))||r.enumerable});return n},R=(n,e,t)=>(I(n,e,"default"),t&&I(t,e,"default")),h=(n,e,t)=>(t=n!=null?ye(Ce(n)):{},I(e||!n||!n.__esModule?F(t,"default",{value:n,enumerable:!0}):t,n)),Ae=n=>I(F({},"__esModule",{value:!0}),n);var o=Ee((We,te)=>{te.exports=globalThis.luma});var D={};Be(D,{WebGPUBuffer:()=>b,WebGPUDevice:()=>v,WebGPUSampler:()=>p,WebGPUShader:()=>P,WebGPUTexture:()=>C,webgpuAdapter:()=>fe});R(D,h(o(),1));var f=h(o(),1);var X=h(o(),1);var O=h(o(),1);function Te(n){return n.byteLength||n.data?.byteLength||0}var b=class extends O.Buffer{device;handle;byteLength;constructor(e,t){super(e,t),this.device=e,this.byteLength=Te(t);let r=Boolean(t.data),i=Math.ceil(this.byteLength/4)*4;this.handle=this.props.handle||this.device.handle.createBuffer({size:i,usage:this.props.usage||GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST,mappedAtCreation:this.props.mappedAtCreation||r,label:this.props.id}),t.data&&this._writeMapped(t.data),r&&!t.mappedAtCreation&&this.handle.unmap()}destroy(){this.handle?.destroy(),this.handle=null}write(e,t=0){this.device.handle.queue.writeBuffer(this.handle,t,e.buffer,e.byteOffset,e.byteLength)}async readAsync(e=0,t=this.byteLength){let r=new b(this.device,{usage:O.Buffer.MAP_READ|O.Buffer.COPY_DST,byteLength:t}),i=this.device.handle.createCommandEncoder();i.copyBufferToBuffer(this.handle,e,r.handle,0,t),this.device.handle.queue.submit([i.finish()]),await r.handle.mapAsync(GPUMapMode.READ,e,t);let s=r.handle.getMappedRange().slice(0);return r.handle.unmap(),r.destroy(),new Uint8Array(s)}_writeMapped(e){let t=this.handle.getMappedRange();new e.constructor(t).set(e)}mapAsync(e,t=0,r){return this.handle.mapAsync(e,t,r)}getMappedRange(e=0,t){return this.handle.getMappedRange(e,t)}unmap(){this.handle.unmap()}};var w=h(o(),1);function S(n){if(n.includes("webgl"))throw new Error("webgl-only format");return n}var re=h(o(),1),p=class extends re.Sampler{device;handle;constructor(e,t){super(e,t),this.device=e;let r={...this.props,mipmapFilter:void 0};t.type!=="comparison-sampler"&&delete r.compare,t.mipmapFilter&&t.mipmapFilter!=="none"&&(r.mipmapFilter=t.mipmapFilter),this.handle=this.handle||this.device.handle.createSampler(r),this.handle.label=this.props.id}destroy(){this.handle=null}};var ne=h(o(),1),G=class extends ne.TextureView{device;handle;texture;constructor(e,t){super(e,t),this.device=e,this.texture=t.texture,this.handle=this.handle||this.texture.handle.createView({format:t.format||this.texture.format,dimension:t.dimension||this.texture.dimension,aspect:t.aspect,baseMipLevel:t.baseMipLevel,mipLevelCount:t.mipLevelCount,baseArrayLayer:t.baseArrayLayer,arrayLayerCount:t.arrayLayerCount}),this.handle.label=this.props.id}destroy(){this.handle=null}};var Ge={"1d":"1d","2d":"2d","2d-array":"2d",cube:"2d","cube-array":"2d","3d":"3d"},C=class extends w.Texture{device;handle;sampler;view;constructor(e,t){super(e,t),this.device=e;let r={...this.props};t.data&&(r.data=t.data),this.initialize(r)}destroy(){this.handle?.destroy(),this.handle=null}createView(e){return new G(this.device,{...e,texture:this})}initialize(e){this.handle=this.props.handle||this.createHandle(),this.handle.label||=this.id,this.props.data&&(w.Texture.isExternalImage(this.props.data)?this.copyExternalImage({image:this.props.data}):this.setData({data:this.props.data})),this.width=this.handle.width,this.height=this.handle.height,this.sampler=e.sampler instanceof p?e.sampler:new p(this.device,e.sampler||{}),this.view=new G(this.device,{...this.props,texture:this})}createHandle(){let e=this.props.width||this.props.data?.width||1,t=this.props.height||this.props.data?.height||1;return this.device.handle.createTexture({label:this.id,size:{width:e,height:t,depthOrArrayLayers:this.depth},usage:this.props.usage||w.Texture.TEXTURE|w.Texture.COPY_DST,dimension:Ge[this.dimension],format:S(this.format),mipLevelCount:this.mipLevels,sampleCount:this.props.samples})}createGPUTextureView(){return this.handle.createView({label:this.id})}setSampler(e){return this.sampler=e instanceof p?e:new p(this.device,e),this}setTexture1DData(e){throw new Error("not implemented")}setTexture2DData(e,t,r){throw new Error("not implemented")}setTexture3DData(e,t,r){throw new Error("not implemented")}setTextureCubeData(e,t){throw new Error("not implemented")}setTextureArrayData(e){throw new Error("not implemented")}setTextureCubeArrayData(e){throw new Error("not implemented")}setData(e){if(ArrayBuffer.isView(e.data)){let t=new Uint8ClampedArray(e.data.buffer),r=new ImageData(t,this.width,this.height);return this.copyExternalImage({image:r})}throw new Error("Texture.setData: Use CommandEncoder to upload data to texture in WebGPU")}copyExternalImage(e){let t=w.Texture.getExternalImageSize(e.image),r={...w.Texture.defaultCopyExternalImageOptions,...t,...e},{image:i,sourceX:s,sourceY:a,width:l,height:u,depth:d,mipLevel:g,x:c,y:T,z:J,aspect:ge,colorSpace:be,premultipliedAlpha:xe,flipY:we}=r;return this.device.handle.queue.copyExternalImageToTexture({source:i,origin:[s,a],flipY:we},{texture:this.handle,origin:[c,T,J],mipLevel:g,aspect:ge,colorSpace:be,premultipliedAlpha:xe},[l,u,d]),{width:l,height:u}}};var ie=h(o(),1);var W=class extends ie.ExternalTexture{device;handle;sampler;constructor(e,t){super(e,t),this.device=e,this.handle=this.props.handle||this.device.handle.importExternalTexture({source:t.source,colorSpace:t.colorSpace}),this.sampler=null}destroy(){this.handle=null}setSampler(e){return this.sampler=e instanceof p?e:new p(this.device,e),this}};var M=h(o(),1),P=class extends M.Shader{device;handle;constructor(e,t){super(e,t),this.device=e,this.device.handle.pushErrorScope("validation"),this.handle=this.props.handle||this.createHandle(),this.handle.label=this.props.id,this._checkCompilationError(this.device.handle.popErrorScope())}get asyncCompilationStatus(){return this.getCompilationInfo().then(()=>this.compilationStatus)}async _checkCompilationError(e){let t=await e;if(t){this.debugShader();let r=await this.getCompilationInfo();throw M.log.error(`Shader compilation error: ${t.message}`,r)(),new Error(`Shader compilation error: ${t.message}`)}}destroy(){this.handle=null}async getCompilationInfo(){return(await this.handle.getCompilationInfo()).messages}createHandle(){let{source:e}=this.props,t=e.includes("#version");if(this.props.language==="glsl"||t)throw new Error("GLSL shaders are not supported in WebGPU");return this.device.handle.createShaderModule({code:e})}};var B=h(o(),1);function m(n){return n.depthStencil=n.depthStencil||{format:"depth24plus",stencilFront:{},stencilBack:{},depthWriteEnabled:!1,depthCompare:"less-equal"},n.depthStencil}function U(n){return m(n).stencilFront}function k(n){return m(n).stencilBack}var Le={cullMode:(n,e,t)=>{t.primitive=t.primitive||{},t.primitive.cullMode=e},frontFace:(n,e,t)=>{t.primitive=t.primitive||{},t.primitive.frontFace=e},depthWriteEnabled:(n,e,t)=>{let r=m(t);r.depthWriteEnabled=e},depthCompare:(n,e,t)=>{let r=m(t);r.depthCompare=e},depthFormat:(n,e,t)=>{let r=m(t);r.format=e},depthBias:(n,e,t)=>{let r=m(t);r.depthBias=e},depthBiasSlopeScale:(n,e,t)=>{let r=m(t);r.depthBiasSlopeScale=e},depthBiasClamp:(n,e,t)=>{let r=m(t);r.depthBiasClamp=e},stencilReadMask:(n,e,t)=>{let r=m(t);r.stencilReadMask=e},stencilWriteMask:(n,e,t)=>{let r=m(t);r.stencilWriteMask=e},stencilCompare:(n,e,t)=>{let r=U(t),i=k(t);r.compare=e,i.compare=e},stencilPassOperation:(n,e,t)=>{let r=U(t),i=k(t);r.passOp=e,i.passOp=e},stencilFailOperation:(n,e,t)=>{let r=U(t),i=k(t);r.failOp=e,i.failOp=e},stencilDepthFailOperation:(n,e,t)=>{let r=U(t),i=k(t);r.depthFailOp=e,i.depthFailOp=e},sampleCount:(n,e,t)=>{t.multisample=t.multisample||{},t.multisample.count=e},sampleMask:(n,e,t)=>{t.multisample=t.multisample||{},t.multisample.mask=e},sampleAlphaToCoverageEnabled:(n,e,t)=>{t.multisample=t.multisample||{},t.multisample.alphaToCoverageEnabled=e},colorMask:(n,e,t)=>{let r=se(t);r[0].writeMask=e},blendColorOperation:(n,e,t)=>{se(t)}},_e={primitive:{cullMode:"back",topology:"triangle-list"},vertex:{module:void 0,entryPoint:"main"},fragment:{module:void 0,entryPoint:"main",targets:[]},layout:"auto"};function ae(n,e={}){Object.assign(n,{..._e,...n}),De(n,e)}function De(n,e){for(let[t,r]of Object.entries(e)){let i=Le[t];if(!i)throw new Error(`Illegal parameter ${t}`);i(t,r,n)}}function se(n){if(n.fragment.targets=n.fragment?.targets||[],!Array.isArray(n.fragment?.targets))throw new Error("colorstate");return n.fragment?.targets?.length===0&&n.fragment.targets?.push({}),n.fragment?.targets}var x=h(o(),1);function V(n,e,t,r){let i=Fe(r,t);return n.createBindGroup({layout:e,entries:i})}function Ie(n,e){let t=n.bindings.find(r=>r.name===e||`${r.name}uniforms`===e.toLocaleLowerCase());return t||x.log.warn(`Binding ${e} not set: Not found in shader layout.`)(),t||null}function Fe(n,e){let t=[];for(let[r,i]of Object.entries(n)){let s=Ie(e,r);s&&t.push(Re(i,s.location))}return t}function Re(n,e){if(n instanceof x.Buffer)return{binding:e,resource:{buffer:n.handle}};if(n instanceof x.Sampler)return{binding:e,resource:n.handle};if(n instanceof x.Texture)return{binding:e,resource:n.handle.createView({label:"bind-group-auto-created"})};throw new Error("invalid binding")}var E=h(o(),1);function Z(n){if(n.endsWith("-webgl"))throw new Error(`WebGPU does not support vertex format ${n}`);return n}function he(n,e){let t=[],r=new Set;for(let i of e){let s=[],a="vertex",l=0,u=i.format;if(i.attributes)for(let d of i.attributes){let g=d.attribute,c=oe(n,g,r),T=c?.location;a=c?.stepMode||(c?.name.startsWith("instance")?"instance":"vertex"),s.push({format:Z(d.format||i.format),offset:d.byteOffset,shaderLocation:T}),l+=(0,E.decodeVertexFormat)(u).byteLength}else{let d=oe(n,i.name,r);if(!d)continue;l=(0,E.decodeVertexFormat)(u).byteLength,a=d.stepMode||(d.name.startsWith("instance")?"instance":"vertex"),s.push({format:Z(u),offset:0,shaderLocation:d.location})}t.push({arrayStride:i.byteStride||l,stepMode:a,attributes:s})}for(let i of n.attributes)r.has(i.name)||t.push({arrayStride:(0,E.decodeVertexFormat)("float32x3").byteLength,stepMode:i.stepMode||(i.name.startsWith("instance")?"instance":"vertex"),attributes:[{format:Z("float32x3"),offset:0,shaderLocation:i.location}]});return t}function oe(n,e,t){let r=n.attributes.find(i=>i.name===e);if(!r)return E.log.warn(`Unknown attribute ${e}`)(),null;if(t.has(e))throw new Error(`Duplicate attribute ${e}`);return t.add(e),r}var q=class extends B.RenderPipeline{device;handle;vs;fs=null;_bindings;_bindGroupLayout=null;_bindGroup=null;constructor(e,t){if(super(e,t),this.device=e,this.handle=this.props.handle,!this.handle){let r=this._getRenderPipelineDescriptor();B.log.groupCollapsed(1,`new WebGPURenderPipeline(${this.id})`)(),B.log.probe(1,JSON.stringify(r,null,2))(),B.log.groupEnd(1)(),this.handle=this.device.handle.createRenderPipeline(r)}this.handle.label=this.props.id,this.vs=t.vs,this.fs=t.fs,this._bindings={...this.props.bindings}}destroy(){this.handle=null}setBindings(e){Object.assign(this._bindings,e)}draw(e){let t=e.renderPass;t.handle.setPipeline(this.handle);let r=this._getBindGroup();return r&&t.handle.setBindGroup(0,r),e.vertexArray.bindBeforeRender(e.renderPass),e.indexCount?t.handle.drawIndexed(e.indexCount,e.instanceCount,e.firstIndex,e.baseVertex,e.firstInstance):t.handle.draw(e.vertexCount||0,e.instanceCount||1,e.firstInstance),e.vertexArray.unbindAfterRender(e.renderPass),!0}_getBindGroup(){return this.shaderLayout.bindings.length===0?null:(this._bindGroupLayout=this._bindGroupLayout||this.handle.getBindGroupLayout(0),this._bindGroup=this._bindGroup||V(this.device.handle,this._bindGroupLayout,this.shaderLayout,this._bindings),this._bindGroup)}_getRenderPipelineDescriptor(){let e={module:this.props.vs.handle,entryPoint:this.props.vertexEntryPoint||"main",buffers:he(this.shaderLayout,this.props.bufferLayout)},t={module:this.props.fs.handle,entryPoint:this.props.fragmentEntryPoint||"main",targets:[{format:S(this.device.getCanvasContext().format)}]},r={vertex:e,fragment:t,primitive:{topology:this.props.topology},layout:"auto"};return ae(r,this.props.parameters),r}};var de=h(o(),1),A=class extends de.Framebuffer{device;colorAttachments=[];depthStencilAttachment=null;constructor(e,t){super(e,t),this.device=e,this.autoCreateAttachmentTextures()}updateAttachments(){}};var le=h(o(),1);var z=class extends le.ComputePipeline{device;handle;_bindGroupLayout=null;_bindGroup=null;_bindings={};constructor(e,t){super(e,t),this.device=e;let r=this.props.shader;this.handle=this.props.handle||this.device.handle.createComputePipeline({label:this.props.id,compute:{module:r.handle,entryPoint:this.props.entryPoint,constants:this.props.constants},layout:"auto"})}setBindings(e){Object.assign(this._bindings,e)}_getBindGroup(){return this._bindGroupLayout=this._bindGroupLayout||this.handle.getBindGroupLayout(0),this._bindGroup=this._bindGroup||V(this.device.handle,this._bindGroupLayout,this.shaderLayout,this._bindings),this._bindGroup}};var y=h(o(),1),$=class extends y.RenderPass{device;handle;pipeline=null;constructor(e,t={}){super(e,t),this.device=e;let r=t.framebuffer||e.getCanvasContext().getCurrentFramebuffer(),i=this.getRenderPassDescriptor(r),s=t.timestampQuerySet;if(s&&(i.occlusionQuerySet=s.handle),e.features.has("timestamp-query")){let a=t.timestampQuerySet;i.timestampWrites=a?{querySet:a.handle,beginningOfPassWriteIndex:t.beginTimestampIndex,endOfPassWriteIndex:t.endTimestampIndex}:void 0}if(!e.commandEncoder)throw new Error("commandEncoder not available");this.handle=this.props.handle||e.commandEncoder.beginRenderPass(i),this.handle.label=this.props.id,y.log.groupCollapsed(3,`new WebGPURenderPass(${this.id})`)(),y.log.probe(3,JSON.stringify(i,null,2))(),y.log.groupEnd(3)()}destroy(){}end(){this.handle.end()}setPipeline(e){this.pipeline=e,this.handle.setPipeline(this.pipeline.handle)}setBindings(e){this.pipeline?.setBindings(e);let t=this.pipeline?._getBindGroup();t&&this.handle.setBindGroup(0,t)}setIndexBuffer(e,t,r=0,i){this.handle.setIndexBuffer(e.handle,t,r,i)}setVertexBuffer(e,t,r=0){this.handle.setVertexBuffer(e,t.handle,r)}draw(e){e.indexCount?this.handle.drawIndexed(e.indexCount,e.instanceCount,e.firstIndex,e.baseVertex,e.firstInstance):this.handle.draw(e.vertexCount||0,e.instanceCount||1,e.firstIndex,e.firstInstance)}drawIndirect(){}setParameters(e){let{blendConstant:t,stencilReference:r,scissorRect:i,viewport:s}=e;t&&this.handle.setBlendConstant(t),r&&this.handle.setStencilReference(r),i&&this.handle.setScissorRect(i[0],i[1],i[2],i[3]),s&&this.handle.setViewport(s[0],s[1],s[2],s[3],s[4],s[5])}pushDebugGroup(e){this.handle.pushDebugGroup(e)}popDebugGroup(){this.handle.popDebugGroup()}insertDebugMarker(e){this.handle.insertDebugMarker(e)}beginOcclusionQuery(e){this.handle.beginOcclusionQuery(e)}endOcclusionQuery(){this.handle.endOcclusionQuery()}getRenderPassDescriptor(e){let t={colorAttachments:[]};if(t.colorAttachments=e.colorAttachments.map((r,i)=>({loadOp:this.props.clearColor!==!1?"clear":"load",colorClearValue:this.props.clearColors?.[i]||this.props.clearColor||y.RenderPass.defaultClearColor,storeOp:this.props.discard?"discard":"store",view:r.handle})),e.depthStencilAttachment){t.depthStencilAttachment={view:e.depthStencilAttachment.handle};let{depthStencilAttachment:r}=t;this.props.depthReadOnly&&(r.depthReadOnly=!0),this.props.clearDepth!==!1&&(r.depthClearValue=this.props.clearDepth),!0&&(r.depthLoadOp=this.props.clearDepth!==!1?"clear":"load",r.depthStoreOp="store"),!1&&(r.stencilLoadOp=this.props.clearStencil!==!1?"clear":"load",r.stencilStoreOp="store")}return t}};var pe=h(o(),1),Q=class extends pe.ComputePass{device;handle;_webgpuPipeline=null;constructor(e,t){super(e,t),this.device=e;let r;if(e.features.has("timestamp-query")){let i=t.timestampQuerySet;i&&(r={querySet:i.handle,beginningOfPassWriteIndex:t.beginTimestampIndex,endOfPassWriteIndex:t.endTimestampIndex})}this.handle=this.props.handle||e.commandEncoder?.beginComputePass({label:this.props.id,timestampWrites:r})}destroy(){}end(){this.handle.end()}setPipeline(e){let t=e;this.handle.setPipeline(t.handle),this._webgpuPipeline=t,this.setBindings([])}setBindings(e){let t=this._webgpuPipeline._getBindGroup();this.handle.setBindGroup(0,t)}dispatch(e,t,r){this.handle.dispatchWorkgroups(e,t,r)}dispatchIndirect(e,t=0){let r=e;this.handle.dispatchWorkgroupsIndirect(r.handle,t)}pushDebugGroup(e){this.handle.pushDebugGroup(e)}popDebugGroup(){this.handle.popDebugGroup()}insertDebugMarker(e){this.handle.insertDebugMarker(e)}};var L=h(o(),1);var ht=globalThis.document||{},dt=globalThis.process||{},lt=globalThis.console,ue=globalThis.navigator||{};function N(n){if(typeof window<"u"&&window.process?.type==="renderer"||typeof process<"u"&&Boolean(process.versions?.electron))return!0;let e=typeof navigator<"u"&&navigator.userAgent,t=n||e;return Boolean(t&&t.indexOf("Electron")>=0)}function ce(){return!(typeof process=="object"&&String(process)==="[object process]"&&!process?.browser)||N()}function K(n){return!n&&!ce()?"Node":N(n)?"Electron":(n||ue.userAgent||"").indexOf("Edge")>-1?"Edge":globalThis.chrome?"Chrome":globalThis.safari?"Safari":globalThis.mozInnerScreenX?"Firefox":"Unknown"}var j=class extends L.VertexArray{get[Symbol.toStringTag](){return"WebGPUVertexArray"}device;handle;constructor(e,t){super(e,t),this.device=e}destroy(){}setIndexBuffer(e){this.indexBuffer=e}setBuffer(e,t){this.attributes[e]=t}bindBeforeRender(e,t,r){let i=e,s=this.indexBuffer;s?.handle&&(L.log.warn("setting index buffer",s?.handle,s?.indexType)(),i.handle.setIndexBuffer(s?.handle,s?.indexType));for(let a=0;a<this.maxVertexAttributes;a++){let l=this.attributes[a];l?.handle&&(L.log.warn(`setting vertex buffer ${a}`,l?.handle)(),i.handle.setVertexBuffer(a,l?.handle))}}unbindAfterRender(e){}static isConstantAttributeZeroSupported(e){return K()==="Chrome"}};var Y=h(o(),1);var _=class extends Y.CanvasContext{device;gpuCanvasContext;format=navigator.gpu.getPreferredCanvasFormat();depthStencilFormat="depth24plus";depthStencilAttachment=null;constructor(e,t,r){super(r),this.device=e,this.width=-1,this.height=-1,this._setAutoCreatedCanvasId(`${this.device.id}-canvas`),this.gpuCanvasContext=this.canvas.getContext("webgpu"),this.format="bgra8unorm"}destroy(){this.gpuCanvasContext.unconfigure()}getCurrentFramebuffer(){this.update();let e=this.getCurrentTexture();return this.width=e.width,this.height=e.height,this._createDepthStencilAttachment(),new A(this.device,{colorAttachments:[e],depthStencilAttachment:this.depthStencilAttachment})}update(){let[e,t]=this.getPixelSize();(e!==this.width||t!==this.height)&&(this.width=e,this.height=t,this.depthStencilAttachment&&(this.depthStencilAttachment.destroy(),this.depthStencilAttachment=null),this.gpuCanvasContext.configure({device:this.device.handle,format:S(this.format),colorSpace:this.props.colorSpace,alphaMode:this.props.alphaMode}),Y.log.log(1,`Resized to ${this.width}x${this.height}px`)())}resize(e){if(this.update(),!!this.device.handle&&this.canvas){let t=this.getDevicePixelRatio(e?.useDevicePixels);this.setDevicePixelRatio(t,e);return}}getCurrentTexture(){return this.device.createTexture({id:`${this.id}#color-texture`,handle:this.gpuCanvasContext.getCurrentTexture(),format:this.format})}_createDepthStencilAttachment(){return this.depthStencilAttachment||(this.depthStencilAttachment=this.device.createTexture({id:`${this.id}#depth-stencil-texture`,format:this.depthStencilFormat,width:this.width,height:this.height,usage:GPUTextureUsage.RENDER_ATTACHMENT})),this.depthStencilAttachment}};var me=h(o(),1),H=class extends me.QuerySet{device;handle;constructor(e,t){super(e,t),this.device=e,this.handle=this.props.handle||this.device.handle.createQuerySet({type:this.props.type,count:this.props.count}),this.handle.label=this.props.id}destroy(){this.handle?.destroy(),this.handle=null}};var v=class extends X.Device{type="webgpu";handle;adapter;adapterInfo;features;info;limits;lost;canvasContext=null;_isLost=!1;commandEncoder=null;renderPass=null;constructor(e,t,r,i){if(super({...e,id:e.id||"webgpu-device"}),this.handle=t,this.adapter=r,this.adapterInfo=i,this.info=this._getInfo(),this.features=this._getFeatures(),this.limits=this.handle.limits,t.addEventListener("uncapturederror",s=>{let a=s instanceof GPUUncapturedErrorEvent?s.error.message:"Unknown error";this.error(new Error(a))}),this.lost=new Promise(async s=>{let a=await this.handle.lost;this._isLost=!0,s({reason:"destroyed",message:a.message})}),e.createCanvasContext){let s=e.createCanvasContext===!0?{}:e.createCanvasContext;this.canvasContext=new _(this,this.adapter,s)}}destroy(){this.handle.destroy()}isTextureFormatSupported(e){return!e.includes("webgl")}isTextureFormatFilterable(e){return this.isTextureFormatSupported(e)&&!e.startsWith("depth")&&!e.startsWith("stencil")}isTextureFormatRenderable(e){return this.isTextureFormatSupported(e)}get isLost(){return this._isLost}createBuffer(e){let t=this._normalizeBufferProps(e);return new b(this,t)}createTexture(e){return new C(this,e)}createExternalTexture(e){return new W(this,e)}createShader(e){return new P(this,e)}createSampler(e){return new p(this,e)}createRenderPipeline(e){return new q(this,e)}createFramebuffer(e){return new A(this,e)}createComputePipeline(e){return new z(this,e)}createVertexArray(e){return new j(this,e)}beginRenderPass(e){return this.commandEncoder=this.commandEncoder||this.handle.createCommandEncoder(),new $(this,e)}beginComputePass(e){return this.commandEncoder=this.commandEncoder||this.handle.createCommandEncoder(),new Q(this,e)}createTransformFeedback(e){throw new Error("Transform feedback not supported in WebGPU")}createQuerySet(e){return new H(this,e)}createCanvasContext(e){return new _(this,this.adapter,e)}submit(){let e=this.commandEncoder?.finish();e&&this.handle.queue.submit([e]),this.commandEncoder=null}_getInfo(){let[e,t]=(this.adapterInfo.driver||"").split(" Version "),r=this.adapterInfo.vendor||this.adapter.__brand||"unknown",i=e||"",s=t||"",a=r==="apple"?"apple":"unknown",l=this.adapterInfo.architecture||"unknown",u=this.adapterInfo.backend||"unknown",d=(this.adapterInfo.type||"").split(" ")[0].toLowerCase()||"unknown";return{type:"webgpu",vendor:r,renderer:i,version:s,gpu:a,gpuType:d,gpuBackend:u,gpuArchitecture:l,shadingLanguage:"wgsl",shadingLanguageVersion:100}}_getFeatures(){let e=new Set(this.handle.features);e.has("depth-clamping")&&(e.delete("depth-clamping"),e.add("depth-clip-control")),e.has("texture-compression-bc")&&e.add("texture-compression-bc5-webgl");let t=["timer-query-webgl","compilation-status-async-webgl","float32-renderable-webgl","float16-renderable-webgl","norm16-renderable-webgl","texture-filterable-anisotropic-webgl","shader-noperspective-interpolation-webgl"];for(let r of t)e.add(r);return new X.DeviceFeatures(Array.from(e),this.props._disabledFeatures)}copyExternalImageToTexture(e){let{source:t,sourceX:r=0,sourceY:i=0,texture:s,mipLevel:a=0,aspect:l="all",colorSpace:u="display-p3",premultipliedAlpha:d=!1,width:g=s.width,height:c=s.height,depth:T=1}=e,J=s;this.handle?.queue.copyExternalImageToTexture({source:t,origin:[r,i]},{texture:J.handle,origin:[0,0,0],mipLevel:a,aspect:l,colorSpace:u,premultipliedAlpha:d},[g,c,T])}};var ee=class extends f.Adapter{type="webgpu";constructor(){super(),v.adapter=this}isSupported(){return Boolean(typeof navigator<"u"&&navigator.gpu)}async create(e){if(!navigator.gpu)throw new Error("WebGPU not available. Open in Chrome Canary and turn on chrome://flags/#enable-unsafe-webgpu");f.log.groupCollapsed(1,"WebGPUDevice created")();let t=await navigator.gpu.requestAdapter({powerPreference:"high-performance"});if(!t)throw new Error("Failed to request WebGPU adapter");let r=await t.requestAdapterInfo();f.log.probe(2,"Adapter available",r)();let i=[],s={};if(e._requestMaxLimits){i.push(...Array.from(t.features));let u=Object.keys(t.limits).filter(d=>!["minSubgroupSize","maxSubgroupSize"].includes(d));for(let d of u){let g=d,c=t.limits[g];typeof c=="number"&&(s[g]=c)}}let a=await t.requestDevice({requiredFeatures:i,requiredLimits:s});f.log.probe(1,"GPUDevice available")();let l=new v(e,a,t,r);return f.log.probe(1,"Device created. For more info, set chrome://flags/#enable-webgpu-developer-features")(),f.log.table(1,l.info)(),f.log.groupEnd(1)(),l}async attach(e){throw new Error("WebGPUAdapter.attach() not implemented")}},fe=new ee;return Ae(D);})();
var __exports__=(()=>{var Se=Object.create;var R=Object.defineProperty;var Ee=Object.getOwnPropertyDescriptor;var Ce=Object.getOwnPropertyNames;var Pe=Object.getPrototypeOf,Be=Object.prototype.hasOwnProperty;var Ae=(n,e)=>()=>(e||n((e={exports:{}}).exports,e),e.exports),Ge=(n,e)=>{for(var t in e)R(n,t,{get:e[t],enumerable:!0})},W=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Ce(e))!Be.call(n,i)&&i!==t&&R(n,i,{get:()=>e[i],enumerable:!(r=Ee(e,i))||r.enumerable});return n},O=(n,e,t)=>(W(n,e,"default"),t&&W(t,e,"default")),d=(n,e,t)=>(t=n!=null?Se(Pe(n)):{},W(e||!n||!n.__esModule?R(t,"default",{value:n,enumerable:!0}):t,n)),Te=n=>W(R({},"__esModule",{value:!0}),n);var o=Ae((Oe,te)=>{te.exports=globalThis.luma});var F={};Ge(F,{WebGPUBuffer:()=>b,WebGPUDevice:()=>S,WebGPUSampler:()=>p,WebGPUShader:()=>P,WebGPUTexture:()=>C,webgpuAdapter:()=>be});O(F,d(o(),1));var f=d(o(),1);var X=d(o(),1);var M=d(o(),1);function _e(n){return n.byteLength||n.data?.byteLength||0}var b=class extends M.Buffer{device;handle;byteLength;constructor(e,t){super(e,t),this.device=e,this.byteLength=_e(t);let r=Boolean(t.data),i=Math.ceil(this.byteLength/4)*4;this.handle=this.props.handle||this.device.handle.createBuffer({size:i,usage:this.props.usage||GPUBufferUsage.VERTEX|GPUBufferUsage.COPY_DST,mappedAtCreation:this.props.mappedAtCreation||r,label:this.props.id}),t.data&&this._writeMapped(t.data),r&&!t.mappedAtCreation&&this.handle.unmap()}destroy(){this.handle?.destroy(),this.handle=null}write(e,t=0){this.device.handle.queue.writeBuffer(this.handle,t,e.buffer,e.byteOffset,e.byteLength)}async readAsync(e=0,t=this.byteLength){let r=new b(this.device,{usage:M.Buffer.MAP_READ|M.Buffer.COPY_DST,byteLength:t}),i=this.device.handle.createCommandEncoder();i.copyBufferToBuffer(this.handle,e,r.handle,0,t),this.device.handle.queue.submit([i.finish()]),await r.handle.mapAsync(GPUMapMode.READ,e,t);let s=r.handle.getMappedRange().slice(0);return r.handle.unmap(),r.destroy(),new Uint8Array(s)}_writeMapped(e){let t=this.handle.getMappedRange();new e.constructor(t).set(e)}mapAsync(e,t=0,r){return this.handle.mapAsync(e,t,r)}getMappedRange(e=0,t){return this.handle.getMappedRange(e,t)}unmap(){this.handle.unmap()}};var v=d(o(),1);function E(n){if(n.includes("webgl"))throw new Error("webgl-only format");return n}var re=d(o(),1),p=class extends re.Sampler{device;handle;constructor(e,t){super(e,t),this.device=e;let r={...this.props,mipmapFilter:void 0};t.type!=="comparison-sampler"&&delete r.compare,t.mipmapFilter&&t.mipmapFilter!=="none"&&(r.mipmapFilter=t.mipmapFilter),this.handle=this.handle||this.device.handle.createSampler(r),this.handle.label=this.props.id}destroy(){this.handle=null}};var ne=d(o(),1),_=class extends ne.TextureView{device;handle;texture;constructor(e,t){super(e,t),this.device=e,this.texture=t.texture,this.handle=this.handle||this.texture.handle.createView({format:t.format||this.texture.format,dimension:t.dimension||this.texture.dimension,aspect:t.aspect,baseMipLevel:t.baseMipLevel,mipLevelCount:t.mipLevelCount,baseArrayLayer:t.baseArrayLayer,arrayLayerCount:t.arrayLayerCount}),this.handle.label=this.props.id}destroy(){this.handle=null}};var De={"1d":"1d","2d":"2d","2d-array":"2d",cube:"2d","cube-array":"2d","3d":"3d"},C=class extends v.Texture{device;handle;sampler;view;constructor(e,t){super(e,t),this.device=e;let r={...this.props};t.data&&(r.data=t.data),this.initialize(r)}destroy(){this.handle?.destroy(),this.handle=null}createView(e){return new _(this.device,{...e,texture:this})}initialize(e){this.handle=this.props.handle||this.createHandle(),this.handle.label||=this.id,this.props.data&&(v.Texture.isExternalImage(this.props.data)?this.copyExternalImage({image:this.props.data}):this.setData({data:this.props.data})),this.width=this.handle.width,this.height=this.handle.height,this.sampler=e.sampler instanceof p?e.sampler:new p(this.device,e.sampler||{}),this.view=new _(this.device,{...this.props,texture:this})}createHandle(){let e=this.props.width||this.props.data?.width||1,t=this.props.height||this.props.data?.height||1;return this.device.handle.createTexture({label:this.id,size:{width:e,height:t,depthOrArrayLayers:this.depth},usage:this.props.usage||v.Texture.TEXTURE|v.Texture.COPY_DST,dimension:De[this.dimension],format:E(this.format),mipLevelCount:this.mipLevels,sampleCount:this.props.samples})}createGPUTextureView(){return this.handle.createView({label:this.id})}setSampler(e){return this.sampler=e instanceof p?e:new p(this.device,e),this}setTexture1DData(e){throw new Error("not implemented")}setTexture2DData(e,t,r){throw new Error("not implemented")}setTexture3DData(e,t,r){throw new Error("not implemented")}setTextureCubeData(e,t){throw new Error("not implemented")}setTextureArrayData(e){throw new Error("not implemented")}setTextureCubeArrayData(e){throw new Error("not implemented")}setData(e){if(ArrayBuffer.isView(e.data)){let t=new Uint8ClampedArray(e.data.buffer),r=new ImageData(t,this.width,this.height);return this.copyExternalImage({image:r})}throw new Error("Texture.setData: Use CommandEncoder to upload data to texture in WebGPU")}copyExternalImage(e){let t=v.Texture.getExternalImageSize(e.image),r={...v.Texture.defaultCopyExternalImageOptions,...t,...e},{image:i,sourceX:s,sourceY:a,width:l,height:c,depth:h,mipLevel:g,x:u,y:T,z:J,aspect:xe,colorSpace:we,premultipliedAlpha:ye,flipY:ve}=r;return this.device.handle.queue.copyExternalImageToTexture({source:i,origin:[s,a],flipY:ve},{texture:this.handle,origin:[u,T,J],mipLevel:g,aspect:xe,colorSpace:we,premultipliedAlpha:ye},[l,c,h]),{width:l,height:c}}};var ie=d(o(),1);var U=class extends ie.ExternalTexture{device;handle;sampler;constructor(e,t){super(e,t),this.device=e,this.handle=this.props.handle||this.device.handle.importExternalTexture({source:t.source,colorSpace:t.colorSpace}),this.sampler=null}destroy(){this.handle=null}setSampler(e){return this.sampler=e instanceof p?e:new p(this.device,e),this}};var D=d(o(),1),P=class extends D.Shader{device;handle;constructor(e,t){super(e,t),this.device=e;let r=t.source.includes("#version");if(this.props.language==="glsl"||r)throw new Error("GLSL shaders are not supported in WebGPU");this.device.handle.pushErrorScope("validation"),this.handle=this.props.handle||this.device.handle.createShaderModule({code:t.source}),this.device.handle.popErrorScope().then(i=>{i&&D.log.error(`${this} creation failed:
"${i.message}"`,this,this.props.source)()}),this.handle.label=this.props.id,this._checkCompilationError()}get asyncCompilationStatus(){return this.getCompilationInfo().then(()=>this.compilationStatus)}async _checkCompilationError(){let e=await this.getCompilationInfo(),t=Boolean(e.find(r=>r.type==="error"));this.compilationStatus=t?"error":"success",this.debugShader(),this.compilationStatus==="error"&&D.log.error("Shader compilation error",e)()}destroy(){this.handle=null}async getCompilationInfo(){return(await this.handle.getCompilationInfo()).messages}};var w=d(o(),1);function m(n){return n.depthStencil=n.depthStencil||{format:"depth24plus",stencilFront:{},stencilBack:{},depthWriteEnabled:!1,depthCompare:"less-equal"},n.depthStencil}function k(n){return m(n).stencilFront}function V(n){return m(n).stencilBack}var Le={cullMode:(n,e,t)=>{t.primitive=t.primitive||{},t.primitive.cullMode=e},frontFace:(n,e,t)=>{t.primitive=t.primitive||{},t.primitive.frontFace=e},depthWriteEnabled:(n,e,t)=>{let r=m(t);r.depthWriteEnabled=e},depthCompare:(n,e,t)=>{let r=m(t);r.depthCompare=e},depthFormat:(n,e,t)=>{let r=m(t);r.format=e},depthBias:(n,e,t)=>{let r=m(t);r.depthBias=e},depthBiasSlopeScale:(n,e,t)=>{let r=m(t);r.depthBiasSlopeScale=e},depthBiasClamp:(n,e,t)=>{let r=m(t);r.depthBiasClamp=e},stencilReadMask:(n,e,t)=>{let r=m(t);r.stencilReadMask=e},stencilWriteMask:(n,e,t)=>{let r=m(t);r.stencilWriteMask=e},stencilCompare:(n,e,t)=>{let r=k(t),i=V(t);r.compare=e,i.compare=e},stencilPassOperation:(n,e,t)=>{let r=k(t),i=V(t);r.passOp=e,i.passOp=e},stencilFailOperation:(n,e,t)=>{let r=k(t),i=V(t);r.failOp=e,i.failOp=e},stencilDepthFailOperation:(n,e,t)=>{let r=k(t),i=V(t);r.depthFailOp=e,i.depthFailOp=e},sampleCount:(n,e,t)=>{t.multisample=t.multisample||{},t.multisample.count=e},sampleMask:(n,e,t)=>{t.multisample=t.multisample||{},t.multisample.mask=e},sampleAlphaToCoverageEnabled:(n,e,t)=>{t.multisample=t.multisample||{},t.multisample.alphaToCoverageEnabled=e},colorMask:(n,e,t)=>{let r=se(t);r[0].writeMask=e},blendColorOperation:(n,e,t)=>{se(t)}},Ie={primitive:{cullMode:"back",topology:"triangle-list"},vertex:{module:void 0,entryPoint:"main"},fragment:{module:void 0,entryPoint:"main",targets:[]},layout:"auto"};function ae(n,e={}){Object.assign(n,{...Ie,...n}),Fe(n,e)}function Fe(n,e){for(let[t,r]of Object.entries(e)){let i=Le[t];if(!i)throw new Error(`Illegal parameter ${t}`);i(t,r,n)}}function se(n){if(n.fragment.targets=n.fragment?.targets||[],!Array.isArray(n.fragment?.targets))throw new Error("colorstate");return n.fragment?.targets?.length===0&&n.fragment.targets?.push({}),n.fragment?.targets}var x=d(o(),1);function $(n,e,t,r){let i=We(r,t);return n.createBindGroup({layout:e,entries:i})}function oe(n,e,t){let r=n.bindings.find(i=>i.name===e||`${i.name}uniforms`===e.toLocaleLowerCase());return!r&&!t?.ignoreWarnings&&x.log.warn(`Binding ${e} not set: Not found in shader layout.`)(),r||null}function We(n,e){let t=[];for(let[r,i]of Object.entries(n)){let s=oe(e,r);s&&t.push(de(i,s.location)),s=oe(e,`${r}Sampler`,{ignoreWarnings:!0}),s&&t.push(de(i,s.location,{sampler:!0}))}return t}function de(n,e,t){if(n instanceof x.Buffer)return{binding:e,resource:{buffer:n.handle}};if(n instanceof x.Sampler)return{binding:e,resource:n.handle};if(n instanceof x.Texture)return t?.sampler?{binding:e,resource:n.sampler.handle}:{binding:e,resource:n.handle.createView({label:"bind-group-auto-created"})};throw new Error("invalid binding")}var B=d(o(),1);function Z(n){if(n.endsWith("-webgl"))throw new Error(`WebGPU does not support vertex format ${n}`);return n}function le(n,e){let t=[],r=new Set;for(let i of e){let s=[],a="vertex",l=0,c=i.format;if(i.attributes)for(let h of i.attributes){let g=h.attribute,u=he(n,g,r),T=u?.location;a=u?.stepMode||(u?.name.startsWith("instance")?"instance":"vertex"),s.push({format:Z(h.format||i.format),offset:h.byteOffset,shaderLocation:T}),l+=(0,B.decodeVertexFormat)(c).byteLength}else{let h=he(n,i.name,r);if(!h)continue;l=(0,B.decodeVertexFormat)(c).byteLength,a=h.stepMode||(h.name.startsWith("instance")?"instance":"vertex"),s.push({format:Z(c),offset:0,shaderLocation:h.location})}t.push({arrayStride:i.byteStride||l,stepMode:a,attributes:s})}for(let i of n.attributes)r.has(i.name)||t.push({arrayStride:(0,B.decodeVertexFormat)("float32x3").byteLength,stepMode:i.stepMode||(i.name.startsWith("instance")?"instance":"vertex"),attributes:[{format:Z("float32x3"),offset:0,shaderLocation:i.location}]});return t}function he(n,e,t){let r=n.attributes.find(i=>i.name===e);if(!r)return B.log.warn(`Supplied attribute not present in shader layout: ${e}`)(),null;if(t.has(e))throw new Error(`Found multiple entries for attribute: ${e}`);return t.add(e),r}var z=class extends w.RenderPipeline{device;handle;vs;fs=null;_bindings;_bindGroupLayout=null;_bindGroup=null;get[Symbol.toStringTag](){return"WebGPURenderPipeline"}constructor(e,t){if(super(e,t),this.device=e,this.handle=this.props.handle,!this.handle){let r=this._getRenderPipelineDescriptor();w.log.groupCollapsed(1,`new WebGPURenderPipeline(${this.id})`)(),w.log.probe(1,JSON.stringify(r,null,2))(),w.log.groupEnd(1)(),this.device.handle.pushErrorScope("validation"),this.handle=this.device.handle.createRenderPipeline(r),this.device.handle.popErrorScope().then(i=>{i&&w.log.error(`${this} creation failed:
"${i.message}"`,this,this.props.vs?.source)()})}this.handle.label=this.props.id,this.vs=t.vs,this.fs=t.fs,this._bindings={...this.props.bindings}}destroy(){this.handle=null}setBindings(e){for(let[t,r]of Object.entries(e))this._bindings[t]!==r&&(this._bindGroup=null);Object.assign(this._bindings,e)}draw(e){let t=e.renderPass;this.device.handle.pushErrorScope("validation"),t.handle.setPipeline(this.handle),this.device.handle.popErrorScope().then(i=>{i&&w.log.error(`${this} setPipeline failed:
"${i.message}"`,this)()});let r=this._getBindGroup();return r&&t.handle.setBindGroup(0,r),e.vertexArray.bindBeforeRender(e.renderPass),e.indexCount?t.handle.drawIndexed(e.indexCount,e.instanceCount,e.firstIndex,e.baseVertex,e.firstInstance):t.handle.draw(e.vertexCount||0,e.instanceCount||1,e.firstInstance),e.vertexArray.unbindAfterRender(e.renderPass),!0}_getBindGroup(){return this.shaderLayout.bindings.length===0?null:(this._bindGroupLayout=this._bindGroupLayout||this.handle.getBindGroupLayout(0),this._bindGroup=this._bindGroup||$(this.device.handle,this._bindGroupLayout,this.shaderLayout,this._bindings),this._bindGroup)}_getRenderPipelineDescriptor(){let e={module:this.props.vs.handle,entryPoint:this.props.vertexEntryPoint||"main",buffers:le(this.shaderLayout,this.props.bufferLayout)},t=[];if(this.props.colorAttachmentFormats)for(let a of this.props.colorAttachmentFormats)t.push(a?{format:E(a)}:null);else t.push({format:E(this.device.preferredColorFormat)});let r={module:this.props.fs.handle,entryPoint:this.props.fragmentEntryPoint||"main",targets:t},i={vertex:e,fragment:r,primitive:{topology:this.props.topology},layout:"auto"},s=this.props.depthStencilAttachmentFormat||this.device.preferredDepthFormat;return this.props.parameters.depthWriteEnabled&&(i.depthStencil={format:E(s)}),ae(i,this.props.parameters),i}};var pe=d(o(),1),A=class extends pe.Framebuffer{device;colorAttachments=[];depthStencilAttachment=null;constructor(e,t){super(e,t),this.device=e,this.autoCreateAttachmentTextures()}updateAttachments(){}};var ce=d(o(),1);var q=class extends ce.ComputePipeline{device;handle;_bindGroupLayout=null;_bindGroup=null;_bindings={};constructor(e,t){super(e,t),this.device=e;let r=this.props.shader;this.handle=this.props.handle||this.device.handle.createComputePipeline({label:this.props.id,compute:{module:r.handle,entryPoint:this.props.entryPoint,constants:this.props.constants},layout:"auto"})}setBindings(e){Object.assign(this._bindings,e)}_getBindGroup(){return this._bindGroupLayout=this._bindGroupLayout||this.handle.getBindGroupLayout(0),this._bindGroup=this._bindGroup||$(this.device.handle,this._bindGroupLayout,this.shaderLayout,this._bindings),this._bindGroup}};var y=d(o(),1),Q=class extends y.RenderPass{device;handle;pipeline=null;constructor(e,t={}){super(e,t),this.device=e;let r=t.framebuffer||e.getCanvasContext().getCurrentFramebuffer(),i=this.getRenderPassDescriptor(r),s=t.timestampQuerySet;if(s&&(i.occlusionQuerySet=s.handle),e.features.has("timestamp-query")){let a=t.timestampQuerySet;i.timestampWrites=a?{querySet:a.handle,beginningOfPassWriteIndex:t.beginTimestampIndex,endOfPassWriteIndex:t.endTimestampIndex}:void 0}if(!e.commandEncoder)throw new Error("commandEncoder not available");this.device.handle.pushErrorScope("validation"),this.handle=this.props.handle||e.commandEncoder.beginRenderPass(i),this.device.handle.popErrorScope().then(a=>{a&&y.log.error(`${this} creation failed:
"${a.message}"`,this)()}),this.handle.label=this.props.id,y.log.groupCollapsed(3,`new WebGPURenderPass(${this.id})`)(),y.log.probe(3,JSON.stringify(i,null,2))(),y.log.groupEnd(3)()}destroy(){}end(){this.handle.end()}setPipeline(e){this.pipeline=e,this.handle.setPipeline(this.pipeline.handle)}setBindings(e){this.pipeline?.setBindings(e);let t=this.pipeline?._getBindGroup();t&&this.handle.setBindGroup(0,t)}setIndexBuffer(e,t,r=0,i){this.handle.setIndexBuffer(e.handle,t,r,i)}setVertexBuffer(e,t,r=0){this.handle.setVertexBuffer(e,t.handle,r)}draw(e){e.indexCount?this.handle.drawIndexed(e.indexCount,e.instanceCount,e.firstIndex,e.baseVertex,e.firstInstance):this.handle.draw(e.vertexCount||0,e.instanceCount||1,e.firstIndex,e.firstInstance)}drawIndirect(){}setParameters(e){let{blendConstant:t,stencilReference:r,scissorRect:i,viewport:s}=e;t&&this.handle.setBlendConstant(t),r&&this.handle.setStencilReference(r),i&&this.handle.setScissorRect(i[0],i[1],i[2],i[3]),s&&this.handle.setViewport(s[0],s[1],s[2],s[3],s[4],s[5])}pushDebugGroup(e){this.handle.pushDebugGroup(e)}popDebugGroup(){this.handle.popDebugGroup()}insertDebugMarker(e){this.handle.insertDebugMarker(e)}beginOcclusionQuery(e){this.handle.beginOcclusionQuery(e)}endOcclusionQuery(){this.handle.endOcclusionQuery()}getRenderPassDescriptor(e){let t={colorAttachments:[]};if(t.colorAttachments=e.colorAttachments.map((r,i)=>({loadOp:this.props.clearColor!==!1?"clear":"load",colorClearValue:this.props.clearColors?.[i]||this.props.clearColor||y.RenderPass.defaultClearColor,storeOp:this.props.discard?"discard":"store",view:r.handle})),e.depthStencilAttachment){t.depthStencilAttachment={view:e.depthStencilAttachment.handle};let{depthStencilAttachment:r}=t;this.props.depthReadOnly&&(r.depthReadOnly=!0),this.props.clearDepth!==!1&&(r.depthClearValue=this.props.clearDepth),!0&&(r.depthLoadOp=this.props.clearDepth!==!1?"clear":"load",r.depthStoreOp="store"),!1&&(r.stencilLoadOp=this.props.clearStencil!==!1?"clear":"load",r.stencilStoreOp="store")}return t}};var ue=d(o(),1),N=class extends ue.ComputePass{device;handle;_webgpuPipeline=null;constructor(e,t){super(e,t),this.device=e;let r;if(e.features.has("timestamp-query")){let i=t.timestampQuerySet;i&&(r={querySet:i.handle,beginningOfPassWriteIndex:t.beginTimestampIndex,endOfPassWriteIndex:t.endTimestampIndex})}this.handle=this.props.handle||e.commandEncoder?.beginComputePass({label:this.props.id,timestampWrites:r})}destroy(){}end(){this.handle.end()}setPipeline(e){let t=e;this.handle.setPipeline(t.handle),this._webgpuPipeline=t,this.setBindings([])}setBindings(e){let t=this._webgpuPipeline._getBindGroup();this.handle.setBindGroup(0,t)}dispatch(e,t,r){this.handle.dispatchWorkgroups(e,t,r)}dispatchIndirect(e,t=0){let r=e;this.handle.dispatchWorkgroupsIndirect(r.handle,t)}pushDebugGroup(e){this.handle.pushDebugGroup(e)}popDebugGroup(){this.handle.popDebugGroup()}insertDebugMarker(e){this.handle.insertDebugMarker(e)}};var L=d(o(),1);var dt=globalThis.document||{},ht=globalThis.process||{},lt=globalThis.console,me=globalThis.navigator||{};function j(n){if(typeof window<"u"&&window.process?.type==="renderer"||typeof process<"u"&&Boolean(process.versions?.electron))return!0;let e=typeof navigator<"u"&&navigator.userAgent,t=n||e;return Boolean(t&&t.indexOf("Electron")>=0)}function fe(){return!(typeof process=="object"&&String(process)==="[object process]"&&!process?.browser)||j()}function K(n){return!n&&!fe()?"Node":j(n)?"Electron":(n||me.userAgent||"").indexOf("Edge")>-1?"Edge":globalThis.chrome?"Chrome":globalThis.safari?"Safari":globalThis.mozInnerScreenX?"Firefox":"Unknown"}var H=class extends L.VertexArray{get[Symbol.toStringTag](){return"WebGPUVertexArray"}device;handle;constructor(e,t){super(e,t),this.device=e}destroy(){}setIndexBuffer(e){this.indexBuffer=e}setBuffer(e,t){this.attributes[e]=t}bindBeforeRender(e,t,r){let i=e,s=this.indexBuffer;s?.handle&&(L.log.info(3,"setting index buffer",s?.handle,s?.indexType)(),i.handle.setIndexBuffer(s?.handle,s?.indexType));for(let a=0;a<this.maxVertexAttributes;a++){let l=this.attributes[a];l?.handle&&(L.log.info(3,`setting vertex buffer ${a}`,l?.handle)(),i.handle.setVertexBuffer(a,l?.handle))}}unbindAfterRender(e){}static isConstantAttributeZeroSupported(e){return K()==="Chrome"}};var G=d(o(),1);var I=class extends G.CanvasContext{device;handle;depthStencilAttachment=null;get[Symbol.toStringTag](){return"WebGPUCanvasContext"}constructor(e,t,r){super(r),this.device=e,this._setAutoCreatedCanvasId(`${this.device.id}-canvas`),this.updateSize([this.drawingBufferWidth,this.drawingBufferHeight])}destroy(){this.handle.unconfigure()}getCurrentFramebuffer(e={depthStencilFormat:"depth24plus"}){let t=this.getCurrentTexture();if(t.width!==this.drawingBufferWidth||t.height!==this.drawingBufferHeight){let[r,i]=this.getDrawingBufferSize();this.drawingBufferWidth=t.width,this.drawingBufferHeight=t.height,G.log.log(1,`${this}: Resized to compensate for initial canvas size mismatch ${r}x${i} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`)()}return e?.depthStencilFormat&&this._createDepthStencilAttachment(e?.depthStencilFormat),new A(this.device,{colorAttachments:[t],depthStencilAttachment:this.depthStencilAttachment})}updateSize(e){this.depthStencilAttachment&&(this.depthStencilAttachment.destroy(),this.depthStencilAttachment=null),this.handle.configure({device:this.device.handle,format:this.device.preferredColorFormat,colorSpace:this.props.colorSpace,alphaMode:this.props.alphaMode})}resize(e){if(this.device.handle&&!this.props.autoResize&&this.canvas){let t=this.getDevicePixelRatio(e?.useDevicePixels);this._setDevicePixelRatio(t,e);return}}getCurrentTexture(){return this.device.createTexture({id:`${this.id}#color-texture`,handle:this.handle.getCurrentTexture(),format:this.device.preferredColorFormat})}_createDepthStencilAttachment(e){return this.depthStencilAttachment||(this.depthStencilAttachment=this.device.createTexture({id:`${this.id}#depth-stencil-texture`,usage:G.Texture.RENDER_ATTACHMENT,format:e,width:this.drawingBufferWidth,height:this.drawingBufferHeight})),this.depthStencilAttachment}};var ge=d(o(),1),Y=class extends ge.QuerySet{device;handle;constructor(e,t){super(e,t),this.device=e,this.handle=this.props.handle||this.device.handle.createQuerySet({type:this.props.type,count:this.props.count}),this.handle.label=this.props.id}destroy(){this.handle?.destroy(),this.handle=null}};var S=class extends X.Device{handle;type="webgpu";preferredColorFormat=navigator.gpu.getPreferredCanvasFormat();preferredDepthFormat="depth24plus";features;info;limits;lost;renderPass=null;canvasContext;_isLost=!1;commandEncoder=null;adapter;adapterInfo;constructor(e,t,r,i){if(super({...e,id:e.id||"webgpu-device"}),this.handle=t,this.adapter=r,this.adapterInfo=i,this.info=this._getInfo(),this.features=this._getFeatures(),this.limits=this.handle.limits,t.addEventListener("uncapturederror",s=>{let a=s instanceof GPUUncapturedErrorEvent?s.error.message:"Unknown WebGPU error";if(this.reportError(new Error(a)),this.props.debug)debugger;s.preventDefault()}),this.lost=new Promise(async s=>{let a=await this.handle.lost;this._isLost=!0,s({reason:"destroyed",message:a.message})}),e.createCanvasContext){let s=e.createCanvasContext===!0?{}:e.createCanvasContext;this.canvasContext=new I(this,this.adapter,s)}}destroy(){this.handle.destroy()}get isLost(){return this._isLost}createBuffer(e){let t=this._normalizeBufferProps(e);return new b(this,t)}createTexture(e){return new C(this,e)}createExternalTexture(e){return new U(this,e)}createShader(e){return new P(this,e)}createSampler(e){return new p(this,e)}createRenderPipeline(e){return new z(this,e)}createFramebuffer(e){return new A(this,e)}createComputePipeline(e){return new q(this,e)}createVertexArray(e){return new H(this,e)}beginRenderPass(e){return this.commandEncoder=this.commandEncoder||this.handle.createCommandEncoder(),new Q(this,e)}beginComputePass(e){return this.commandEncoder=this.commandEncoder||this.handle.createCommandEncoder(),new N(this,e)}createTransformFeedback(e){throw new Error("Transform feedback not supported in WebGPU")}createQuerySet(e){return new Y(this,e)}createCanvasContext(e){return new I(this,this.adapter,e)}submit(){let e=this.commandEncoder?.finish();e&&(this.handle.pushErrorScope("validation"),this.handle.queue.submit([e]),this.handle.popErrorScope().then(t=>{t&&this.reportError(new Error(`WebGPU command submission failed: ${t.message}`))})),this.commandEncoder=null}_getInfo(){let[e,t]=(this.adapterInfo.driver||"").split(" Version "),r=this.adapterInfo.vendor||this.adapter.__brand||"unknown",i=e||"",s=t||"",a=r==="apple"?"apple":"unknown",l=this.adapterInfo.architecture||"unknown",c=this.adapterInfo.backend||"unknown",h=(this.adapterInfo.type||"").split(" ")[0].toLowerCase()||"unknown";return{type:"webgpu",vendor:r,renderer:i,version:s,gpu:a,gpuType:h,gpuBackend:c,gpuArchitecture:l,shadingLanguage:"wgsl",shadingLanguageVersion:100}}_getFeatures(){let e=new Set(this.handle.features);e.has("depth-clamping")&&(e.delete("depth-clamping"),e.add("depth-clip-control")),e.has("texture-compression-bc")&&e.add("texture-compression-bc5-webgl");let t=["timer-query-webgl","compilation-status-async-webgl","float32-renderable-webgl","float16-renderable-webgl","norm16-renderable-webgl","texture-filterable-anisotropic-webgl","shader-noperspective-interpolation-webgl"];for(let r of t)e.add(r);return new X.DeviceFeatures(Array.from(e),this.props._disabledFeatures)}_getDeviceSpecificTextureFormatCapabilities(e){let{format:t}=e;return t.includes("webgl")?{format:t,create:!1,render:!1,filter:!1,blend:!1,store:!1}:e}copyExternalImageToTexture(e){let{source:t,sourceX:r=0,sourceY:i=0,texture:s,mipLevel:a=0,aspect:l="all",colorSpace:c="display-p3",premultipliedAlpha:h=!1,width:g=s.width,height:u=s.height,depth:T=1}=e,J=s;this.handle?.queue.copyExternalImageToTexture({source:t,origin:[r,i]},{texture:J.handle,origin:[0,0,0],mipLevel:a,aspect:l,colorSpace:c,premultipliedAlpha:h},[g,u,T])}};var ee=class extends f.Adapter{type="webgpu";constructor(){super(),S.adapter=this}isSupported(){return Boolean(typeof navigator<"u"&&navigator.gpu)}async create(e){if(!navigator.gpu)throw new Error("WebGPU not available. Open in Chrome Canary and turn on chrome://flags/#enable-unsafe-webgpu");f.log.groupCollapsed(1,"WebGPUDevice created")();let t=await navigator.gpu.requestAdapter({powerPreference:"high-performance"});if(!t)throw new Error("Failed to request WebGPU adapter");let r=await t.requestAdapterInfo();f.log.probe(2,"Adapter available",r)();let i=[],s={};if(e._requestMaxLimits){i.push(...Array.from(t.features));let c=Object.keys(t.limits).filter(h=>!["minSubgroupSize","maxSubgroupSize"].includes(h));for(let h of c){let g=h,u=t.limits[g];typeof u=="number"&&(s[g]=u)}}let a=await t.requestDevice({requiredFeatures:i,requiredLimits:s});f.log.probe(1,"GPUDevice available")();let l=new S(e,a,t,r);return f.log.probe(1,"Device created. For more info, set chrome://flags/#enable-webgpu-developer-features")(),f.log.table(1,l.info)(),f.log.groupEnd(1)(),l}async attach(e){throw new Error("WebGPUAdapter.attach() not implemented")}},be=new ee;return Te(F);})();
return __exports__;
});

@@ -11,1 +11,2 @@ // luma.gl

export { WebGPUShader } from "./adapter/resources/webgpu-shader.js";
//# sourceMappingURL=index.js.map
{
"name": "@luma.gl/webgpu",
"version": "9.1.0-alpha.19",
"version": "9.1.0-beta.1",
"description": "WebGPU adapter for the luma.gl core API",

@@ -40,3 +40,3 @@ "type": "module",

"peerDependencies": {
"@luma.gl/core": "9.1.0-alpha.17"
"@luma.gl/core": "9.1.0-alpha.19"
},

@@ -47,3 +47,3 @@ "dependencies": {

},
"gitHead": "c836c09a5105e2515a036abff4a1b926d245a152"
"gitHead": "e04bfb138f96d690992f0e0a67b358cbe23bd59f"
}

@@ -45,3 +45,4 @@ // luma.gl

shaderLayout: ComputeShaderLayout,
bindingName: string
bindingName: string,
options?: {ignoreWarnings?: boolean}
): BindingDeclaration | null {

@@ -52,3 +53,3 @@ const bindingLayout = shaderLayout.bindings.find(

);
if (!bindingLayout) {
if (!bindingLayout && !options?.ignoreWarnings) {
log.warn(`Binding ${bindingName} not set: Not found in shader layout.`)();

@@ -70,6 +71,14 @@ }

for (const [bindingName, value] of Object.entries(bindings)) {
const bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
let bindingLayout = getShaderLayoutBinding(shaderLayout, bindingName);
if (bindingLayout) {
entries.push(getBindGroupEntry(value, bindingLayout.location));
}
// TODO - hack to automatically bind samplers to supplied texture default samplers
bindingLayout = getShaderLayoutBinding(shaderLayout, `${bindingName}Sampler`, {
ignoreWarnings: true
});
if (bindingLayout) {
entries.push(getBindGroupEntry(value, bindingLayout.location, {sampler: true}));
}
}

@@ -80,3 +89,7 @@

function getBindGroupEntry(binding: Binding, index: number): GPUBindGroupEntry {
function getBindGroupEntry(
binding: Binding,
index: number,
options?: {sampler?: boolean}
): GPUBindGroupEntry {
if (binding instanceof Buffer) {

@@ -96,2 +109,8 @@ return {

} else if (binding instanceof Texture) {
if (options?.sampler) {
return {
binding: index,
resource: (binding as WebGPUTexture).sampler.handle
};
}
return {

@@ -98,0 +117,0 @@ binding: index,

@@ -155,7 +155,7 @@ // luma.gl

if (!attribute) {
log.warn(`Unknown attribute ${name}`)();
log.warn(`Supplied attribute not present in shader layout: ${name}`)();
return null;
}
if (attributeNames.has(name)) {
throw new Error(`Duplicate attribute ${name}`);
throw new Error(`Found multiple entries for attribute: ${name}`);
}

@@ -162,0 +162,0 @@ attributeNames.add(name);

@@ -49,3 +49,9 @@ // luma.gl

this.device.handle.pushErrorScope('validation');
this.handle = this.props.handle || device.commandEncoder.beginRenderPass(renderPassDescriptor);
this.device.handle.popErrorScope().then((error: GPUError | null) => {
if (error) {
log.error(`${this} creation failed:\n"${error.message}"`, this)();
}
});
this.handle.label = this.props.id;

@@ -52,0 +58,0 @@ log.groupCollapsed(3, `new WebGPURenderPass(${this.id})`)();

@@ -33,2 +33,6 @@ // luma.gl MIT license

override get [Symbol.toStringTag]() {
return 'WebGPURenderPipeline';
}
constructor(device: WebGPUDevice, props: RenderPipelineProps) {

@@ -43,6 +47,14 @@ super(device, props);

log.groupEnd(1)();
this.device.handle.pushErrorScope('validation');
this.handle = this.device.handle.createRenderPipeline(descriptor);
this.device.handle.popErrorScope().then((error: GPUError | null) => {
if (error) {
log.error(`${this} creation failed:\n"${error.message}"`, this, this.props.vs?.source)();
}
});
}
this.handle.label = this.props.id;
// Note: Often the same shader in WebGPU
this.vs = props.vs as WebGPUShader;

@@ -65,2 +77,8 @@ this.fs = props.fs as WebGPUShader;

setBindings(bindings: Record<string, Binding>): void {
// Invalidate the cached bind group if any value has changed
for (const [name, binding] of Object.entries(bindings)) {
if (this._bindings[name] !== binding) {
this._bindGroup = null;
}
}
Object.assign(this._bindings, bindings);

@@ -84,3 +102,9 @@ }

// Set pipeline
this.device.handle.pushErrorScope('validation');
webgpuRenderPass.handle.setPipeline(this.handle);
this.device.handle.popErrorScope().then((error: GPUError | null) => {
if (error) {
log.error(`${this} setPipeline failed:\n"${error.message}"`, this)();
}
});

@@ -149,2 +173,13 @@ // Set bindings (uniform buffers, textures etc)

// Populate color targets
// TODO - at the moment blend and write mask are only set on the first target
const targets: (GPUColorTargetState | null)[] = [];
if (this.props.colorAttachmentFormats) {
for (const format of this.props.colorAttachmentFormats) {
targets.push(format ? {format: getWebGPUTextureFormat(format)} : null);
}
} else {
targets.push({format: getWebGPUTextureFormat(this.device.preferredColorFormat)});
}
// Set up the fragment stage

@@ -154,8 +189,3 @@ const fragment: GPUFragmentState = {

entryPoint: this.props.fragmentEntryPoint || 'main',
targets: [
{
// TODO exclamation mark hack!
format: getWebGPUTextureFormat(this.device.getCanvasContext().format)
}
]
targets
};

@@ -173,2 +203,11 @@

// Set depth format if required, defaulting to the preferred depth format
const depthFormat = this.props.depthStencilAttachmentFormat || this.device.preferredDepthFormat;
if (this.props.parameters.depthWriteEnabled) {
descriptor.depthStencil = {
format: getWebGPUTextureFormat(depthFormat)
};
}
// Set parameters on the descriptor

@@ -175,0 +214,0 @@ applyParametersToRenderPipelineDescriptor(descriptor, this.props.parameters);

@@ -20,8 +20,17 @@ // luma.gl

const isGLSL = props.source.includes('#version');
if (this.props.language === 'glsl' || isGLSL) {
throw new Error('GLSL shaders are not supported in WebGPU');
}
this.device.handle.pushErrorScope('validation');
this.handle = this.props.handle || this.device.handle.createShaderModule({code: props.source});
this.device.handle.popErrorScope().then((error: GPUError | null) => {
if (error) {
log.error(`${this} creation failed:\n"${error.message}"`, this, this.props.source)();
}
});
this.handle = this.props.handle || this.createHandle();
this.handle.label = this.props.id;
this._checkCompilationError(this.device.handle.popErrorScope());
this._checkCompilationError();
}

@@ -33,13 +42,13 @@

async _checkCompilationError(errorScope: Promise<GPUError | null>): Promise<void> {
const error = (await errorScope) as GPUValidationError;
if (error) {
// The `Shader` base class will determine if debug window should be opened based on props
this.debugShader();
async _checkCompilationError(): Promise<void> {
const shaderLog = await this.getCompilationInfo();
const hasErrors = Boolean(shaderLog.find(msg => msg.type === 'error'));
this.compilationStatus = hasErrors ? 'error' : 'success';
this.debugShader();
const shaderLog = await this.getCompilationInfo();
log.error(`Shader compilation error: ${error.message}`, shaderLog)();
if (this.compilationStatus === 'error') {
log.error(`Shader compilation error`, shaderLog)();
// Note: Even though this error is asynchronous and thrown after the constructor completes,
// it will result in a useful stack trace leading back to the constructor
throw new Error(`Shader compilation error: ${error.message}`);
// throw new Error(`Shader compilation error`);
}

@@ -60,15 +69,2 @@ }

}
// PRIVATE METHODS
protected createHandle(): GPUShaderModule {
const {source} = this.props;
const isGLSL = source.includes('#version');
if (this.props.language === 'glsl' || isGLSL) {
throw new Error('GLSL shaders are not supported in WebGPU');
}
return this.device.handle.createShaderModule({code: source});
}
}

@@ -60,3 +60,8 @@ // luma.gl

// Note we can't unset an index buffer
log.warn('setting index buffer', webgpuIndexBuffer?.handle, webgpuIndexBuffer?.indexType)();
log.info(
3,
'setting index buffer',
webgpuIndexBuffer?.handle,
webgpuIndexBuffer?.indexType
)();
webgpuRenderPass.handle.setIndexBuffer(

@@ -71,3 +76,3 @@ webgpuIndexBuffer?.handle,

if (webgpuBuffer?.handle) {
log.warn(`setting vertex buffer ${location}`, webgpuBuffer?.handle)();
log.info(3, `setting vertex buffer ${location}`, webgpuBuffer?.handle)();
webgpuRenderPass.handle.setVertexBuffer(location, webgpuBuffer?.handle);

@@ -74,0 +79,0 @@ }

@@ -7,5 +7,4 @@ // luma.gl

import type {Texture, TextureFormat, CanvasContextProps} from '@luma.gl/core';
import {CanvasContext, log} from '@luma.gl/core';
import {getWebGPUTextureFormat} from './helpers/convert-texture-format';
import type {DepthStencilTextureFormat, CanvasContextProps} from '@luma.gl/core';
import {CanvasContext, Texture, log} from '@luma.gl/core';
import {WebGPUDevice} from './webgpu-device';

@@ -22,23 +21,17 @@ import {WebGPUFramebuffer} from './resources/webgpu-framebuffer';

readonly device: WebGPUDevice;
readonly gpuCanvasContext: GPUCanvasContext;
/** Format of returned textures: "bgra8unorm", "rgba8unorm", "rgba16float". */
readonly format: TextureFormat = navigator.gpu.getPreferredCanvasFormat() as TextureFormat;
/** Default stencil format for depth textures */
readonly depthStencilFormat: TextureFormat = 'depth24plus';
readonly handle: GPUCanvasContext;
private depthStencilAttachment: Texture | null = null;
private depthStencilAttachment: WebGPUTexture | null = null;
get [Symbol.toStringTag](): string {
return 'WebGPUCanvasContext';
}
constructor(device: WebGPUDevice, adapter: GPUAdapter, props: CanvasContextProps) {
super(props);
this.device = device;
// TODO - hack to trigger resize?
this.width = -1;
this.height = -1;
// Base class constructor cannot access derived methods/fields, so we need to call these functions in the subclass constructor
this._setAutoCreatedCanvasId(`${this.device.id}-canvas`);
// @ts-ignore TODO - we don't handle OffscreenRenderingContext.
this.gpuCanvasContext = this.canvas.getContext('webgpu');
// TODO this has been replaced
// this.format = this.gpuCanvasContext.getPreferredFormat(adapter);
this.format = 'bgra8unorm';
this.updateSize([this.drawingBufferWidth, this.drawingBufferHeight]);
}

@@ -48,26 +41,31 @@

destroy(): void {
this.gpuCanvasContext.unconfigure();
this.handle.unconfigure();
}
/** Update framebuffer with properly resized "swap chain" texture views */
getCurrentFramebuffer(): WebGPUFramebuffer {
// Ensure the canvas context size is updated
this.update();
getCurrentFramebuffer(
options: {depthStencilFormat?: DepthStencilTextureFormat | false} = {
depthStencilFormat: 'depth24plus'
}
): WebGPUFramebuffer {
// Wrap the current canvas context texture in a luma.gl texture
// const currentColorAttachment = this.device.createTexture({
// id: 'default-render-target',
// handle: this.gpuCanvasContext.getCurrentTexture(),
// format: this.format,
// width: this.width,
// height: this.height
// });
// Wrap the current canvas context texture in a luma.gl texture
const currentColorAttachment = this.getCurrentTexture();
this.width = currentColorAttachment.width;
this.height = currentColorAttachment.height;
// TODO - temporary debug code
if (
currentColorAttachment.width !== this.drawingBufferWidth ||
currentColorAttachment.height !== this.drawingBufferHeight
) {
const [oldWidth, oldHeight] = this.getDrawingBufferSize();
this.drawingBufferWidth = currentColorAttachment.width;
this.drawingBufferHeight = currentColorAttachment.height;
log.log(
1,
`${this}: Resized to compensate for initial canvas size mismatch ${oldWidth}x${oldHeight} => ${this.drawingBufferWidth}x${this.drawingBufferHeight}px`
)();
}
// Resize the depth stencil attachment
this._createDepthStencilAttachment();
if (options?.depthStencilFormat) {
this._createDepthStencilAttachment(options?.depthStencilFormat);
}

@@ -81,40 +79,31 @@ return new WebGPUFramebuffer(this.device, {

/** Resizes and updates render targets if necessary */
update() {
const [width, height] = this.getPixelSize();
updateSize(size: [newWidth: number, newHeight: number]): void {
if (this.depthStencilAttachment) {
this.depthStencilAttachment.destroy();
this.depthStencilAttachment = null;
}
const sizeChanged = width !== this.width || height !== this.height;
if (sizeChanged) {
this.width = width;
this.height = height;
if (this.depthStencilAttachment) {
this.depthStencilAttachment.destroy();
this.depthStencilAttachment = null;
}
// Reconfigure the canvas size.
// https://www.w3.org/TR/webgpu/#canvas-configuration
this.gpuCanvasContext.configure({
device: this.device.handle,
format: getWebGPUTextureFormat(this.format),
// Can be used to define e.g. -srgb views
// viewFormats: [...]
colorSpace: this.props.colorSpace,
alphaMode: this.props.alphaMode
});
log.log(1, `Resized to ${this.width}x${this.height}px`)();
}
// Reconfigure the canvas size.
// https://www.w3.org/TR/webgpu/#canvas-configuration
this.handle.configure({
device: this.device.handle,
format: this.device.preferredColorFormat,
// Can be used to define e.g. -srgb views
// viewFormats: [...]
colorSpace: this.props.colorSpace,
alphaMode: this.props.alphaMode
});
}
resize(options?: {width?: number; height?: number; useDevicePixels?: boolean | number}): void {
this.update();
if (!this.device.handle) return;
if (this.props.autoResize) {
return;
}
// Resize browser context .
if (this.canvas) {
const devicePixelRatio = this.getDevicePixelRatio(options?.useDevicePixels);
this.setDevicePixelRatio(devicePixelRatio, options);
this._setDevicePixelRatio(devicePixelRatio, options);
return;

@@ -128,4 +117,4 @@ }

id: `${this.id}#color-texture`,
handle: this.gpuCanvasContext.getCurrentTexture(),
format: this.format
handle: this.handle.getCurrentTexture(),
format: this.device.preferredColorFormat
});

@@ -135,10 +124,10 @@ }

/** We build render targets on demand (i.e. not when size changes but when about to render) */
_createDepthStencilAttachment() {
_createDepthStencilAttachment(depthStencilFormat: DepthStencilTextureFormat): WebGPUTexture {
if (!this.depthStencilAttachment) {
this.depthStencilAttachment = this.device.createTexture({
id: `${this.id}#depth-stencil-texture`,
format: this.depthStencilFormat,
width: this.width,
height: this.height,
usage: GPUTextureUsage.RENDER_ATTACHMENT
usage: Texture.RENDER_ATTACHMENT,
format: depthStencilFormat,
width: this.drawingBufferWidth,
height: this.drawingBufferHeight
});

@@ -145,0 +134,0 @@ }

@@ -12,2 +12,3 @@ // luma.gl

DeviceFeature,
DeviceTextureFormatCapabilities,
CanvasContextProps,

@@ -19,3 +20,2 @@ BufferProps,

TextureProps,
TextureFormat,
ExternalTextureProps,

@@ -33,3 +33,3 @@ FramebufferProps,

QuerySetProps,
DeviceProps
DeviceProps,
} from '@luma.gl/core';

@@ -55,11 +55,11 @@ import {Device, DeviceFeatures} from '@luma.gl/core';

export class WebGPUDevice extends Device {
/** The underlying WebGPU device */
readonly handle: GPUDevice;
/** type of this device */
readonly type = 'webgpu';
/** The underlying WebGPU device */
readonly handle: GPUDevice;
/* The underlying WebGPU adapter */
readonly adapter: GPUAdapter;
/* The underlying WebGPU adapter's info */
readonly adapterInfo: GPUAdapterInfo;
readonly preferredColorFormat = navigator.gpu.getPreferredCanvasFormat() as
| 'rgba8unorm'
| 'bgra8unorm';
readonly preferredDepthFormat = 'depth24plus';

@@ -71,7 +71,13 @@ readonly features: DeviceFeatures;

readonly lost: Promise<{reason: 'destroyed'; message: string}>;
canvasContext: WebGPUCanvasContext | null = null;
renderPass: WebGPURenderPass | null = null;
override canvasContext: WebGPUCanvasContext | null;
private _isLost: boolean = false;
// canvasContext: WebGPUCanvasContext | null = null;
commandEncoder: GPUCommandEncoder | null = null;
renderPass: WebGPURenderPass | null = null;
/* The underlying WebGPU adapter */
readonly adapter: GPUAdapter;
/* The underlying WebGPU adapter's info */
readonly adapterInfo: GPUAdapterInfo;

@@ -97,4 +103,9 @@ constructor(

const errorMessage =
event instanceof GPUUncapturedErrorEvent ? event.error.message : 'Unknown error';
this.error(new Error(errorMessage));
event instanceof GPUUncapturedErrorEvent ? event.error.message : 'Unknown WebGPU error';
this.reportError(new Error(errorMessage));
if (this.props.debug) {
// eslint-disable-next-line no-debugger
debugger;
}
event.preventDefault();
});

@@ -126,20 +137,2 @@

isTextureFormatSupported(format: TextureFormat): boolean {
return !format.includes('webgl');
}
/** @todo implement proper check? */
isTextureFormatFilterable(format: TextureFormat): boolean {
return (
this.isTextureFormatSupported(format) &&
!format.startsWith('depth') &&
!format.startsWith('stencil')
);
}
/** @todo implement proper check? */
isTextureFormatRenderable(format: TextureFormat): boolean {
return this.isTextureFormatSupported(format);
}
get isLost(): boolean {

@@ -219,9 +212,13 @@ return this._isLost;

submit(): void {
// this.renderPass?.end();
const commandBuffer = this.commandEncoder?.finish();
if (commandBuffer) {
this.handle.pushErrorScope('validation');
this.handle.queue.submit([commandBuffer]);
this.handle.popErrorScope().then((error: GPUError | null) => {
if (error) {
this.reportError(new Error(`WebGPU command submission failed: ${error.message}`));
}
});
}
this.commandEncoder = null;
// this.renderPass = null;
}

@@ -291,2 +288,15 @@

override _getDeviceSpecificTextureFormatCapabilities(
capabilities: DeviceTextureFormatCapabilities
): DeviceTextureFormatCapabilities {
const {format} = capabilities;
if (format.includes('webgl')) {
return {format, create: false, render: false, filter: false, blend: false, store: false};
}
return capabilities;
}
// DEPRECATED METHODS
// @deprecated
copyExternalImageToTexture(options: {

@@ -293,0 +303,0 @@ texture: Texture;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc