typegpu
Version:
A thin layer between JS and WebGPU/WGSL that improves development experience and allows for faster iteration.
65 lines (64 loc) • 2.61 kB
JavaScript
import { getName, setName } from "../../shared/meta.js";
import { $getNameForward, $internal, $resolve } from "../../shared/symbols.js";
import { shaderStageSlot } from "../slot/internalSlots.js";
import { createFnCore } from "./fnCore.js";
import { createIoSchema, separateAllAsPositional } from "./ioSchema.js";
import { stripTemplate } from "./templateUtils.js";
/**
* Creates a shell of a typed entry function for the vertex shader stage. Any function
* that implements this shell can run for each vertex, allowing the inner code to process
* attributes and determine the final position of the vertex.
*
* @param options.in
* Vertex attributes and builtins to be made available to functions that implement this shell.
* @param options.out
* A record containing the final position of the vertex, and any information
* passed onto the fragment shader stage.
*/
export function vertexFn(options) {
if (Object.keys(options.out).length === 0) {
throw new Error(`A vertexFn output cannot be empty since it must include the 'position' builtin.`);
}
const shell = {
in: options.in,
out: options.out,
argTypes: options.in && Object.keys(options.in).length !== 0 ? [createIoSchema(options.in)] : [],
entryPoint: 'vertex',
};
const call = (arg, ...values) => createVertexFn(shell, stripTemplate(arg, ...values));
return Object.assign(call, shell);
}
export function isTgpuVertexFn(value) {
return value?.shell?.entryPoint === 'vertex';
}
// --------------
// Implementation
// --------------
function createVertexFn(shell, implementation) {
const core = createFnCore(implementation, 'vertex');
const entryInput = separateAllAsPositional(shell.in ?? {});
const result = {
shell,
$uses(newExternals) {
core.setExternals('userProvided', newExternals);
return this;
},
[$internal]: true,
[$getNameForward]: core,
$name(newLabel) {
setName(this, newLabel);
return this;
},
[$resolve](ctx) {
const outputWithLocation = createIoSchema(shell.out, ctx.varyingLocations).$name(`${getName(this) ?? ''}_Output`);
if (typeof implementation === 'string') {
core.setExternals('out', { Out: outputWithLocation });
}
return ctx.withSlots([[shaderStageSlot, 'vertex']], () => core.resolve(ctx, [], outputWithLocation, entryInput));
},
toString() {
return `vertexFn:${getName(core) ?? '<unnamed>'}`;
},
};
return result;
}