typegpu
Version:
A thin layer between JS and WebGPU/WGSL that improves development experience and allows for faster iteration.
247 lines (246 loc) • 7.55 kB
JavaScript
// We import tsover-runtime, then use Symbol.* types, because tsdown strips the imported `Operator`
// type no matter what. Seems like a bug in tsdown.
// oxlint-disable-next-line no-unassigned-import
import 'tsover-runtime';
import { $internal, isMarkedInternal } from "../shared/symbols.js";
export const Void = {
[$internal]: {},
type: 'void',
toString() {
return 'void';
},
};
export const wgslTypeLiterals = [
'bool',
'f32',
'f16',
'i32',
'u32',
'u16',
'vec2f',
'vec2h',
'vec2i',
'vec2u',
'vec2<bool>',
'vec3f',
'vec3h',
'vec3i',
'vec3u',
'vec3<bool>',
'vec4f',
'vec4h',
'vec4i',
'vec4u',
'vec4<bool>',
'mat2x2f',
'mat3x3f',
'mat4x4f',
'struct',
'array',
'ptr',
'atomic',
'decorated',
'abstractInt',
'abstractFloat',
'void',
'texture_1d',
'texture_storage_1d',
'texture_2d',
'texture_storage_2d',
'texture_multisampled_2d',
'texture_depth_2d',
'texture_depth_multisampled_2d',
'texture_2d_array',
'texture_storage_2d_array',
'texture_depth_2d_array',
'texture_cube',
'texture_depth_cube',
'texture_cube_array',
'texture_depth_cube_array',
'texture_3d',
'texture_storage_3d',
'texture_external',
'sampler',
'sampler_comparison',
];
// #endregion
export function isVecInstance(value) {
const v = value;
return isMarkedInternal(v) && typeof v.kind === 'string' && v.kind.startsWith('vec');
}
export function isVecBoolInstance(value) {
return isVecInstance(value) && value.kind.includes('b');
}
export function isVec2(value) {
const v = value;
return isMarkedInternal(v) && typeof v.type === 'string' && v.type.startsWith('vec2');
}
export function isVec3(value) {
const v = value;
return isMarkedInternal(v) && typeof v.type === 'string' && v.type.startsWith('vec3');
}
export function isVec4(value) {
const v = value;
return isMarkedInternal(v) && typeof v.type === 'string' && v.type.startsWith('vec4');
}
export function isVec(value) {
return isVec2(value) || isVec3(value) || isVec4(value);
}
export function isVecBool(value) {
return isVec(value) && value.type.includes('b');
}
export function isMatInstance(value) {
const v = value;
return (isMarkedInternal(v) && typeof v.kind?.startsWith === 'function' && v.kind.startsWith('mat'));
}
export function isMat2x2f(value) {
return isMarkedInternal(value) && value?.type === 'mat2x2f';
}
export function isMat3x3f(value) {
return isMarkedInternal(value) && value?.type === 'mat3x3f';
}
export function isMat4x4f(value) {
return isMarkedInternal(value) && value?.type === 'mat4x4f';
}
export function isMat(value) {
return isMat2x2f(value) || isMat3x3f(value) || isMat4x4f(value);
}
export function isInteger(value) {
return (isMarkedInternal(value) && ['abstractInt', 'i32', 'u32'].includes(value?.type));
}
export function isIntegerVec(value) {
return isVec(value) && isInteger(value.primitive);
}
export function isFloat32VecInstance(element) {
return isVecInstance(element) && ['vec2f', 'vec3f', 'vec4f'].includes(element.kind);
}
export function isInteger32VecInstance(value) {
return isVecInstance(value) && /[iu]$/.test(value.kind);
}
export function isUint32VecInstance(value) {
return isVecInstance(value) && /[u]$/.test(value.kind);
}
export function isWgslData(value) {
return isMarkedInternal(value) && wgslTypeLiterals.includes(value?.type);
}
/**
* Checks whether passed in value is an array schema,
* as opposed to, e.g., a disarray schema.
*
* Array schemas can be used to describe uniform and storage buffers,
* whereas disarray schemas cannot.
*
* @example
* isWgslArray(d.arrayOf(d.u32, 4)) // true
* isWgslArray(d.disarray(d.u32, 4)) // false
* isWgslArray(d.vec3f) // false
*/
export function isWgslArray(schema) {
return isMarkedInternal(schema) && schema?.type === 'array';
}
/**
* Checks whether passed in value is a struct schema,
* as opposed to, e.g., an unstruct schema.
*
* Struct schemas can be used to describe uniform and storage buffers,
* whereas unstruct schemas cannot.
*
* @example
* isWgslStruct(d.struct({ a: d.u32 })) // true
* isWgslStruct(d.unstruct({ a: d.u32 })) // false
* isWgslStruct(d.vec3f) // false
*/
export function isWgslStruct(schema) {
return isMarkedInternal(schema) && schema?.type === 'struct';
}
/**
* Checks whether passed in value is a pointer schema.
*
* @example
* isPtr(d.ptrFn(d.f32)) // true
* isPtr(d.ptrPrivate(d.f32)) // true
* isPtr(d.f32) // false
*/
export function isPtr(schema) {
return isMarkedInternal(schema) && schema?.type === 'ptr';
}
/**
* Checks whether the passed in value is an atomic schema.
*
* @example
* isAtomic(d.atomic(d.u32)) // true
* isAtomic(d.u32) // false
*/
export function isAtomic(schema) {
return isMarkedInternal(schema) && schema?.type === 'atomic';
}
export function isAlignAttrib(value) {
return isMarkedInternal(value) && value?.type === '@align';
}
export function isSizeAttrib(value) {
return isMarkedInternal(value) && value?.type === '@size';
}
export function isLocationAttrib(value) {
return isMarkedInternal(value) && value?.type === '@location';
}
export function isInterpolateAttrib(value) {
return isMarkedInternal(value) && value?.type === '@interpolate';
}
export function isBuiltinAttrib(value) {
return isMarkedInternal(value) && value?.type === '@builtin';
}
export function isInvariantAttrib(value) {
return isMarkedInternal(value) && value?.type === '@invariant';
}
export function isDecorated(value) {
return isMarkedInternal(value) && value?.type === 'decorated';
}
export function isAbstractFloat(value) {
return isMarkedInternal(value) && value.type === 'abstractFloat';
}
export function isAbstractInt(value) {
return isMarkedInternal(value) && value.type === 'abstractInt';
}
export function isAbstract(value) {
return isAbstractFloat(value) || isAbstractInt(value);
}
export function isConcrete(value) {
return !isAbstract(value);
}
export function isVoid(value) {
return isMarkedInternal(value) && value.type === 'void';
}
export function isBool(value) {
return isMarkedInternal(value) && value.type === 'bool';
}
export function isNumericSchema(schema) {
const type = schema?.type;
return (isMarkedInternal(schema) &&
(type === 'abstractInt' ||
type === 'abstractFloat' ||
type === 'f32' ||
type === 'f16' ||
type === 'i32' ||
type === 'u32'));
}
export function isHalfPrecisionSchema(schema) {
const type = schema?.type;
return (isMarkedInternal(schema) &&
(type === 'f16' || type === 'vec2h' || type === 'vec3h' || type === 'vec4h'));
}
const ephemeralTypes = ['abstractInt', 'abstractFloat', 'f32', 'f16', 'i32', 'u32', 'bool'];
/**
* Returns true for schemas that are not naturally referential in JS (primitives).
* @param schema
* @returns
*/
export function isNaturallyEphemeral(schema) {
return !isMarkedInternal(schema) || ephemeralTypes.includes(schema?.type);
}
export function WORKAROUND_getSchema(vec) {
// TODO: Remove workaround
// it's a workaround for circular dependencies caused by us using schemas in the shader generator
// these schema properties are assigned on the prototype of vector and matrix instances
// oxlint-disable-next-line typescript/no-explicit-any -- explained above
return vec.schema;
}