typegpu
Version:
A thin layer between JS and WebGPU/WGSL that improves development experience and allows for faster iteration.
89 lines (88 loc) • 2.99 kB
JavaScript
import { undecorate } from "./dataTypes.js";
import { DEV } from "../shared/env.js";
import { isNumericSchema } from "./wgslTypes.js";
/**
* What happens to a snippet's origin when it's deep copied in JS, and left as is in WGSL?
* e.g. `vec3f(vec3f(0, 1, 2))`
*/
export function fallthroughCopyOrigin(origin) {
if (origin === 'runtime' || // runtime values stay runtime
origin === 'constant' // constant values stay constant
) {
// The origin is kept as-is
return origin;
}
// All other origins become runtime
return 'runtime';
}
/**
* Whether a snippet aliases a value that lives outside the current expression.
*
* @example
* ```ts
* function foo(a: number) {
* const color = d.vec3f(1, 2, 3);
* return color * a;
* }
*
* // References:
* // - color
* // - a
* //
* // Not references:
* // - d.vec3f(1, 2, 3)
* // - color * a
* ```
*/
export function isAlias(snippet) {
return !(snippet.origin === 'runtime' || snippet.origin === 'constant');
}
export const originToPtrParams = {
uniform: { space: 'uniform', access: 'read' },
readonly: { space: 'storage', access: 'read' },
mutable: { space: 'storage', access: 'read-write' },
workgroup: { space: 'workgroup', access: 'read-write' },
private: { space: 'private', access: 'read-write' },
function: { space: 'function', access: 'read-write' },
// Local declarations are also in the `function` address space
'local-def': { space: 'function', access: 'read-write' },
};
class SnippetImpl {
value;
dataType;
origin;
possibleSideEffects;
constructor(value, dataType, origin, possibleSideEffects) {
this.value = value;
this.dataType = dataType;
this.origin = origin;
this.possibleSideEffects = possibleSideEffects;
}
}
export function isSnippet(value) {
return value instanceof SnippetImpl;
}
export function isSnippetNumeric(snippet) {
return isNumericSchema(snippet.dataType);
}
export function snip(value, dataType, origin, possibleSideEffects = true) {
if (DEV && isSnippet(value)) {
// An early error, but not worth checking every time in production
throw new Error('Cannot nest snippets');
}
return new SnippetImpl(value,
// We don't care about attributes in snippet land, so we discard that information.
undecorate(dataType), origin, possibleSideEffects);
}
export function withDataType(dataType, snippet) {
return new SnippetImpl(snippet.value, dataType, snippet.origin, snippet.possibleSideEffects);
}
export function withValue(value, snippet) {
return new SnippetImpl(value, snippet.dataType, snippet.origin, snippet.possibleSideEffects);
}
export function withSideEffects(possibleSideEffects, snippet) {
return new SnippetImpl(snippet.value, snippet.dataType, snippet.origin, possibleSideEffects);
}
export function noSideEffects(snippet) {
return withSideEffects(/* possibleSideEffects */ false, snippet);
}