Skip to content

fix: TypeGPU functions using TGSL dependencies declaration order #1522

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 58 additions & 30 deletions packages/typegpu/tests/tgslFn.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -574,36 +574,6 @@ describe('TGSL tgpu.fn function', () => {
);
});

it('(when using plugin) can be invoked for a constant with "kernel" directive', () => {
const addKernelJs = (x: number, y: number) => {
'kernel';
return x + y;
};

const add = tgpu.fn([d.u32, d.u32])(addKernelJs);

expect(addKernelJs(2, 3)).toBe(5);
expect(add(2, 3)).toBe(5);
expect(parseResolved({ add })).toBe(
parse(`fn add(x: u32, y: u32){
return (x + y);
}`),
);
});

it('(when using plugin) can be invoked for inline function with no directive', () => {
const add = tgpu.fn([d.u32, d.u32])(
(x, y) => x + y,
);

expect(add(2, 3)).toBe(5);
expect(parseResolved({ add })).toBe(
parse(`fn add(x: u32, y: u32){
return (x + y);
}`),
);
});

it('resolves a function with a pointer parameter', () => {
const addOnes = tgpu.fn([d.ptrStorage(d.vec3f, 'read-write')])((ptr) => {
ptr.x += 1;
Expand Down Expand Up @@ -879,3 +849,61 @@ describe('tgpu.fn arguments', () => {
expect(vec).toStrictEqual(d.vec3f());
});
});

describe('tgsl fn when using plugin', () => {
it('can be invoked for a constant with "kernel" directive', () => {
const addKernelJs = (x: number, y: number) => {
'kernel';
return x + y;
};

const add = tgpu.fn([d.u32, d.u32])(addKernelJs);

expect(addKernelJs(2, 3)).toBe(5);
expect(add(2, 3)).toBe(5);
expect(parseResolved({ add })).toBe(
parse(`fn add(x: u32, y: u32){
return (x + y);
}`),
);
});

it('can be invoked for inline function with no directive', () => {
const add = tgpu.fn([d.u32, d.u32])(
(x, y) => x + y,
);

expect(add(2, 3)).toBe(5);
expect(parseResolved({ add })).toBe(
parse(`fn add(x: u32, y: u32){
return (x + y);
}`),
);
});

it('can reference function defined below', () => {
const bar = tgpu.fn([], d.f32)(() => foo() + 2);
const foo = tgpu.fn([], d.f32)(() => 1);

expect(parseResolved({ bar })).toBe(
parse(`
fn foo() -> f32 {
return 1;
}

fn bar() -> f32 {
return (foo() + 2);
}`),
);
});

// TODO: throw an error when cyclic dependency is detected
// it('throws when it detects a cyclic dependency', () => {
// let bar: TgpuFn;
// let foo: TgpuFn;
// bar = tgpu.fn([], d.f32)(() => foo() + 2);
// foo = tgpu.fn([], d.f32)(() => bar() - 2);

// expect(() => parseResolved({ bar })).toThrowErrorMatchingInlineSnapshot(``);
// });
});
16 changes: 11 additions & 5 deletions packages/unplugin-typegpu/src/babel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,19 @@ function functionToTranspiled(
i('ast'),
template.expression`${embedJSON({ params, body, externalNames })}`(),
),
types.objectProperty(
types.objectMethod(
'get',
i('externals'),
types.objectExpression(
externalNames.map((name) =>
types.objectProperty(i(name), i(name), false, true)
[],
types.blockStatement([
types.returnStatement(
types.objectExpression(
externalNames.map((name) =>
types.objectProperty(i(name), i(name), false, true)
),
),
),
),
]),
),
]);

Expand Down
2 changes: 1 addition & 1 deletion packages/unplugin-typegpu/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ const typegpu: UnpluginInstance<Options, false> = createUnplugin(
const metadata = `{
v: ${FORMAT_VERSION},
ast: ${embedJSON({ params, body, externalNames })},
externals: {${externalNames.join(', ')}},
get externals() { return {${externalNames.join(', ')}}; },
}`;

assignMetadata(magicString, def, metadata);
Expand Down
18 changes: 12 additions & 6 deletions packages/unplugin-typegpu/test/aliasing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ describe('[BABEL] tgpu alias gathering', () => {
}, {
v: 1,
ast: {"params":[],"body":[0,[[13,"x",[1,[5,"2"],"+",[5,"2"]]]]],"externalNames":[]},
externals: {}
get externals() {
return {};
}
}) && $.f)({}));"
`);
});
Expand All @@ -39,7 +41,9 @@ describe('[BABEL] tgpu alias gathering', () => {
}, {
v: 1,
ast: {"params":[],"body":[0,[[13,"x",[1,[5,"2"],"+",[5,"2"]]]]],"externalNames":[]},
externals: {}
get externals() {
return {};
}
}) && $.f)({}));"
`);
});
Expand All @@ -60,7 +64,9 @@ describe('[BABEL] tgpu alias gathering', () => {
}, {
v: 1,
ast: {"params":[],"body":[0,[[13,"x",[1,[5,"2"],"+",[5,"2"]]]]],"externalNames":[]},
externals: {}
get externals() {
return {};
}
}) && $.f)({}));"
`);
});
Expand All @@ -82,7 +88,7 @@ describe('[ROLLUP] tgpu alias gathering', () => {
}), {
v: 1,
ast: {"params":[],"body":[0,[]],"externalNames":[]},
externals: {},
get externals() { return {}; },
}) && $.f)({})));
"
`);
Expand All @@ -104,7 +110,7 @@ describe('[ROLLUP] tgpu alias gathering', () => {
}), {
v: 1,
ast: {"params":[],"body":[0,[]],"externalNames":[]},
externals: {},
get externals() { return {}; },
}) && $.f)({})));
"
`);
Expand All @@ -126,7 +132,7 @@ describe('[ROLLUP] tgpu alias gathering', () => {
}), {
v: 1,
ast: {"params":[],"body":[0,[]],"externalNames":[]},
externals: {},
get externals() { return {}; },
}) && $.f)({})));
"
`);
Expand Down
32 changes: 21 additions & 11 deletions packages/unplugin-typegpu/test/auto-naming.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ describe('[BABEL] auto naming', () => {
var fn = (globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu.fn([])(($ => (globalThis.__TYPEGPU_META__ ??= new WeakMap()).set($.f = () => {}, {
v: 1,
ast: {"params":[],"body":[0,[]],"externalNames":[]},
externals: {}
get externals() {
return {};
}
}) && $.f)({})), "fn");
let shell = (globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu.fn([]), "shell");
console.log(bindGroupLayout, vertexLayout);"
Expand Down Expand Up @@ -126,14 +128,18 @@ describe('[BABEL] auto naming', () => {
const myFunction = (globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu.fn([])(($ => (globalThis.__TYPEGPU_META__ ??= new WeakMap()).set($.f = () => 0, {
v: 1,
ast: {"params":[],"body":[0,[[10,[5,"0"]]]],"externalNames":[]},
externals: {}
get externals() {
return {};
}
}) && $.f)({})), "myFunction");
const myComputeFn = (globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu['~unstable'].computeFn({
workgroupSize: [1]
})(($ => (globalThis.__TYPEGPU_META__ ??= new WeakMap()).set($.f = () => {}, {
v: 1,
ast: {"params":[],"body":[0,[]],"externalNames":[]},
externals: {}
get externals() {
return {};
}
}) && $.f)({})), "myComputeFn");
const myVertexFn = (globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu['~unstable'].vertexFn({
out: {
Expand All @@ -144,7 +150,9 @@ describe('[BABEL] auto naming', () => {
}), {
v: 1,
ast: {"params":[],"body":[0,[[10,[104,{"ret":[5,"0"]}]]]],"externalNames":[]},
externals: {}
get externals() {
return {};
}
}) && $.f)({})), "myVertexFn");
const myFragmentFn = (globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu['~unstable'].fragmentFn({
in: {
Expand All @@ -154,8 +162,10 @@ describe('[BABEL] auto naming', () => {
})(($ => (globalThis.__TYPEGPU_META__ ??= new WeakMap()).set($.f = () => d.vec4f(), {
v: 1,
ast: {"params":[],"body":[0,[[10,[6,[7,"d","vec4f"],[]]]]],"externalNames":["d"]},
externals: {
d
get externals() {
return {
d
};
}
}) && $.f)({})), "myFragmentFn");"
`);
Expand Down Expand Up @@ -304,7 +314,7 @@ describe('[ROLLUP] auto naming', () => {
((globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu.fn([])((($ => (globalThis.__TYPEGPU_META__ ??= new WeakMap()).set($.f = (() => {}), {
v: 1,
ast: {"params":[],"body":[0,[]],"externalNames":[]},
externals: {},
get externals() { return {}; },
}) && $.f)({}))), "fn"));

console.log(bindGroupLayout, vertexLayout);
Expand Down Expand Up @@ -412,20 +422,20 @@ describe('[ROLLUP] auto naming', () => {
((globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu.fn([])((($ => (globalThis.__TYPEGPU_META__ ??= new WeakMap()).set($.f = (() => 0), {
v: 1,
ast: {"params":[],"body":[0,[[10,[5,"0"]]]],"externalNames":[]},
externals: {},
get externals() { return {}; },
}) && $.f)({}))), "myFunction"));
((globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu['~unstable'].computeFn({ workgroupSize: [1] })(
(($ => (globalThis.__TYPEGPU_META__ ??= new WeakMap()).set($.f = (() => {}), {
v: 1,
ast: {"params":[],"body":[0,[]],"externalNames":[]},
externals: {},
get externals() { return {}; },
}) && $.f)({})),
), "myComputeFn"));
((globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu['~unstable'].vertexFn({ out: { ret: d.i32 } })(
(($ => (globalThis.__TYPEGPU_META__ ??= new WeakMap()).set($.f = (() => ({ ret: 0 })), {
v: 1,
ast: {"params":[],"body":[0,[[10,[104,{"ret":[5,"0"]}]]]],"externalNames":[]},
externals: {},
get externals() { return {}; },
}) && $.f)({})),
), "myVertexFn"));
((globalThis.__TYPEGPU_AUTONAME__ ?? (a => a))(tgpu['~unstable'].fragmentFn({
Expand All @@ -435,7 +445,7 @@ describe('[ROLLUP] auto naming', () => {
(($ => (globalThis.__TYPEGPU_META__ ??= new WeakMap()).set($.f = (() => d.vec4f()), {
v: 1,
ast: {"params":[],"body":[0,[[10,[6,[7,"d","vec4f"],[]]]]],"externalNames":["d"]},
externals: {d},
get externals() { return {d}; },
}) && $.f)({})),
), "myFragmentFn"));
"
Expand Down
Loading