typegpu
Version:
A thin layer between JS and WebGPU/WGSL that improves development experience and allows for faster iteration.
104 lines (103 loc) • 3.13 kB
JavaScript
import { safeStringify } from "../shared/stringify.js";
import { getCustomAlignment, isDisarray, isLooseDecorated, isUnstruct, } from "./dataTypes.js";
import { packedFormats } from "./vertexFormatData.js";
import { isDecorated, isWgslArray, isWgslStruct } from "./wgslTypes.js";
const knownAlignmentMap = {
f32: 4,
f16: 2,
i32: 4,
u32: 4,
bool: 4,
u16: 2,
vec2f: 8,
vec2h: 4,
vec2i: 8,
vec2u: 8,
'vec2<bool>': 8,
vec3f: 16,
vec3h: 8,
vec3i: 16,
vec3u: 16,
'vec3<bool>': 16,
vec4f: 16,
vec4h: 8,
vec4i: 16,
vec4u: 16,
'vec4<bool>': 16,
mat2x2f: 8,
mat3x3f: 16,
mat4x4f: 16,
atomic: 4,
};
function computeAlignment(data) {
const dataType = data?.type;
const knownAlignment = knownAlignmentMap[dataType];
if (knownAlignment !== undefined) {
return knownAlignment;
}
if (isWgslStruct(data)) {
return Object.values(data.propTypes)
.map(alignmentOf)
.reduce((a, b) => (a > b ? a : b));
}
if (isWgslArray(data)) {
return alignmentOf(data.elementType);
}
if (isUnstruct(data)) {
// A loose struct is aligned to its first property.
const firstProp = Object.values(data.propTypes)[0];
return firstProp ? (getCustomAlignment(firstProp) ?? 1) : 1;
}
if (isDisarray(data)) {
return getCustomAlignment(data.elementType) ?? 1;
}
if (isDecorated(data) || isLooseDecorated(data)) {
return getCustomAlignment(data) ?? alignmentOf(data.inner);
}
if (packedFormats.has(dataType)) {
return 1;
}
throw new Error(`Cannot determine alignment of data: ${safeStringify(data)}`);
}
function computeCustomAlignment(data) {
if (isUnstruct(data)) {
// A loose struct is aligned to its first property.
const firstProp = Object.values(data.propTypes)[0];
return firstProp ? customAlignmentOf(firstProp) : 1;
}
if (isDisarray(data)) {
return customAlignmentOf(data.elementType);
}
if (isLooseDecorated(data)) {
return getCustomAlignment(data) ?? customAlignmentOf(data.inner);
}
return getCustomAlignment(data) ?? 1;
}
/**
* Since alignments can be inferred from data types, they are not stored on them.
* Instead, this weak map acts as an extended property of those data types.
*/
const cachedAlignments = new WeakMap();
const cachedCustomAlignments = new WeakMap();
export function alignmentOf(data) {
let alignment = cachedAlignments.get(data);
if (alignment === undefined) {
alignment = computeAlignment(data);
cachedAlignments.set(data, alignment);
}
return alignment;
}
export function customAlignmentOf(data) {
let alignment = cachedCustomAlignments.get(data);
if (alignment === undefined) {
alignment = computeCustomAlignment(data);
cachedCustomAlignments.set(data, alignment);
}
return alignment;
}
/**
* Returns the alignment (in bytes) of data represented by the `schema`.
*/
export function PUBLIC_alignmentOf(schema) {
return alignmentOf(schema);
}