wesl-debug
Version:
Utilities for testing WESL/WGSL shaders in Node.js environments.
206 lines (205 loc) • 10.4 kB
TypeScript
import { LinkParams, VirtualLibraryFn } from "wesl";
import { WgslElementType, WgslElementType as WgslElementType$1 } from "thimbleberry";
import { ImageData, ImageData as ImageData$1 } from "vitest-image-snapshot";
//#region src/CompileShader.d.ts
interface CompileShaderParams {
/** The project directory, used for resolving dependencies. */
projectDir: string;
/** The GPUDevice to use for shader compilation. */
device: GPUDevice;
/** The WGSL/WESL shader source code. */
src: string;
/** Optional conditions for shader compilation. */
conditions?: LinkParams["conditions"];
/** Optional constants for shader compilation. */
constants?: LinkParams["constants"];
/** Optional virtual libraries to include in the shader. */
virtualLibs?: LinkParams["virtualLibs"];
}
/**
* Compiles a single WESL shader source string into a GPUShaderModule for testing
* with automatic package detection.
*
* Parses the shader source to find references to wesl packages, and
* then searches installed npm packages to find the appropriate npm package
* bundle to include in the link.
*/
declare function compileShader(params: CompileShaderParams): Promise<GPUShaderModule>;
//#endregion
//#region src/ErrorScopes.d.ts
/**
* Runs a function with WebGPU error scopes, automatically handling push/pop/check.
* Throws if any validation, out-of-memory, or internal errors occur.
*/
declare function withErrorScopes<T>(device: GPUDevice, fn: () => T | Promise<T>): Promise<T>;
//#endregion
//#region src/ExampleTextures.d.ts
interface SamplerOptions {
addressMode?: "clamp-to-edge" | "repeat" | "mirror-repeat";
filterMode?: "nearest" | "linear";
}
/** Create texture filled with solid color. Internally cached. */
declare function solidTexture(device: GPUDevice, color: [r: number, g: number, b: number, a: number], width: number, height: number): GPUTexture;
/** Create gradient texture. Direction: 'horizontal' (default) or 'vertical'. */
declare function gradientTexture(device: GPUDevice, width: number, height: number, direction?: "horizontal" | "vertical"): GPUTexture;
/** Create checkerboard pattern. cellSize: pixels per cell (default: width/4). */
declare function checkerboardTexture(device: GPUDevice, width: number, height: number, cellSize?: number): GPUTexture;
/** Create sampler. Default: linear filtering with clamp-to-edge. Internally cached. */
declare function createSampler(device: GPUDevice, options?: SamplerOptions): GPUSampler;
/** Create radial gradient texture (white center to black edge). */
declare function radialGradientTexture(device: GPUDevice, size: number): GPUTexture;
/** Create edge pattern texture with sharp vertical, horizontal, and diagonal lines. */
declare function edgePatternTexture(device: GPUDevice, size: number): GPUTexture;
/** Create color bars texture (RGB primaries and secondaries). */
declare function colorBarsTexture(device: GPUDevice, size: number): GPUTexture;
/** Create seeded noise pattern (deterministic). */
declare function noiseTexture(device: GPUDevice, size: number, seed?: number): GPUTexture;
//#endregion
//#region src/ImageHelpers.d.ts
/** Load PNG file and create GPU texture. */
declare function pngToTexture(device: GPUDevice, imagePath: string): Promise<GPUTexture>;
//#endregion
//#region src/RenderUniforms.d.ts
/** User provided uniform values */
interface RenderUniforms {
/** Elapsed time in seconds (default: 0.0) */
time?: number;
/** Mouse position in [0,1] normalized coords (default: [0.0, 0.0]) */
mouse?: [number, number];
}
/**
* Creates a standard uniform buffer for running test fragment shaders.
*
* @param outputSize - Output texture dimensions (becomes uniforms.resolution)
* @param uniforms - User-provided uniform values (time, mouse)
* @returns GPUBuffer containing uniform data
*/
declare function renderUniformBuffer(device: GPUDevice, outputSize: [number, number], uniforms?: RenderUniforms): GPUBuffer;
/**
* return the WGSL struct for use in shaders as test::Uniforms.
*
* @returns virtual library object for passing to compileShader()
*/
declare function createUniformsVirtualLib(): Record<string, VirtualLibraryFn>;
//#endregion
//#region src/TestComputeShader.d.ts
interface ComputeTestParams {
/** WESL/WGSL source code for a compute shader to test*/
src: string;
/** directory in your project. Used so that the test library
* can find installed npm shader libraries.
* That way your fragment shader can use import statements
* from shader npm libraries.
* (typically use import.meta.url) */
projectDir: string;
/** gpu device for running the tests.
* (typically use getGPUDevice() from wesl-debug) */
device: GPUDevice;
/** format of result buffer
* default: "u32" */
resultFormat?: WgslElementType$1;
/** size of result buffer in bytes
* default: 16 */
size?: number;
/** flags for conditional compilation for testing shader specialization.
* useful to test `@if` statements in the shader. */
conditions?: LinkParams["conditions"];
/** constants for shader compilation.
* useful to inject host-provided values via the `constants::` namespace. */
constants?: LinkParams["constants"];
}
/**
* Transpiles and runs a simple compute shader on the GPU for testing.
*
* A storage buffer is available for the shader to write test results.
* `test::results[0]` is the first element of the buffer in wesl.
* After execution the storage buffer is copied back to the CPU and returned
* for test validation.
*
* Shader libraries mentioned in the shader source are attached automatically
* if they are in node_modules.
*
* @returns storage result array (typically four numbers if the buffer format is u32 or f32)
*/
declare function testComputeShader(params: ComputeTestParams): Promise<number[]>;
/**
* Transpiles and runs a simple compute shader on the GPU for testing.
*
* a storage buffer is available for the shader at `@group(0) @binding(0)`.
* Compute shaders can write test results into the buffer.
* After execution the storage buffer is copied back to the CPU and returned
* for test validation.
*
* Shader libraries mentioned in the shader source are attached automatically
* if they are in node_modules.
*
* @param module - The compiled GPUShaderModule containing the compute shader.
* The shader is invoked once.
* @param resultFormat - format for interpreting the result buffer data. (default u32)
* @param size - size of result buffer in bytes (default 16)
* @returns storage result array
*/
declare function runCompute(device: GPUDevice, module: GPUShaderModule, resultFormat?: WgslElementType$1, size?: number): Promise<number[]>;
//#endregion
//#region src/TestFragmentShader.d.ts
declare const fullscreenTriangleVertex = "\n @vertex\n fn vs_main(@builtin(vertex_index) idx: u32) -> @builtin(position) vec4f {\n // Fullscreen triangle: covers viewport with 3 vertices, no vertex buffer needed\n var pos: vec2f;\n if (idx == 0u) {\n pos = vec2f(-1.0, -1.0); // Vertex 0: bottom-left (-1, -1)\n } else if (idx == 1u) {\n pos = vec2f(3.0, -1.0); // Vertex 1: bottom-right beyond viewport (3, -1)\n } else {\n pos = vec2f(-1.0, 3.0); // Vertex 2: top-left beyond viewport (-1, 3)\n }\n return vec4f(pos, 0.0, 1.0);\n }";
interface FragmentTestParams {
/** WESL/WGSL source code for a fragment shader to test*/
src: string;
/** directory in your project. Used so that the test library
* can find installed npm shader libraries.
* That way your fragment shader can use import statements
* from shader npm libraries.
* (typically use import.meta.url) */
projectDir: string;
/** gpu device for running the tests.
* (typically use getGPUDevice() from wesl-debug) */
device: GPUDevice;
/** optionally select the texture format for the output texture
* default: "rgba32float" */
textureFormat?: GPUTextureFormat;
/** optionally specify the size of the output texture.
* default: [1, 1] for simple color tests.
* Use [2, 2] for derivative tests (forms a complete 2x2 quad for dpdx/dpdy) */
size?: [width: number, height: number];
/** flags for conditional compilation for testing shader specialization.
* useful to test `@if` statements in the shader. */
conditions?: LinkParams["conditions"];
/** constants for shader compilation.
* useful to inject host-provided values via the `constants::` namespace. */
constants?: LinkParams["constants"];
/** uniform values for the shader (time, mouse).
* resolution is auto-populated from size parameter.
* Creates test::Uniforms struct available in shader. */
uniforms?: RenderUniforms;
/** input textures + samplers for the shader.
* binds sequentially: [1]=texture, [2]=sampler, [3]=texture, [4]=sampler, ...
* (binding 0 is reserved for uniforms) */
inputTextures?: Array<{
texture: GPUTexture;
sampler: GPUSampler;
}>;
}
/** Run a fragment shader and returns pixel (0,0) for validation. */
declare function testFragmentShader(params: FragmentTestParams): Promise<number[]>;
/** Run a fragment shader and return the rendered image. */
declare function testFragmentShaderImage(params: FragmentTestParams): Promise<ImageData$1>;
/**
* Tests an animated shader at multiple time points.
* Useful for validating that shaders change over time.
*
* @param params - Same as testFragmentShader, plus timePoints array
* @returns Array of image arrays, one per time point
*/
declare function testAnimatedShader(params: FragmentTestParams & {
timePoints: number[];
}): Promise<number[][]>;
//#endregion
//#region src/WebGPUTestSetup.d.ts
/** get or create shared GPU device for testing */
declare function getGPUDevice(): Promise<GPUDevice>;
/** destroy globally shared GPU test device */
declare function destroySharedDevice(): void;
//#endregion
export { CompileShaderParams, ComputeTestParams, FragmentTestParams, type ImageData, RenderUniforms, SamplerOptions, type WgslElementType, checkerboardTexture, colorBarsTexture, compileShader, createSampler, createUniformsVirtualLib, destroySharedDevice, edgePatternTexture, fullscreenTriangleVertex, getGPUDevice, gradientTexture, noiseTexture, pngToTexture, radialGradientTexture, renderUniformBuffer, runCompute, solidTexture, testAnimatedShader, testComputeShader, testFragmentShader, testFragmentShaderImage, withErrorScopes };
//# sourceMappingURL=index.d.ts.map