Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c82ea68
Add an error
Dec 16, 2025
77c5132
Refactor
Dec 16, 2025
8417be7
Remove public currentStage
Dec 16, 2025
84c0399
Keep entrypoint info on functions
Dec 16, 2025
9c108c0
Remove remaining isEntry
Dec 16, 2025
ed3d0ae
Remove does from entrypoints
Dec 16, 2025
10e27ab
Remove `resolveStage`
Dec 16, 2025
675697a
Rename Stage to ShaderStage
Dec 16, 2025
e3e24a5
Add more tests
Dec 16, 2025
a1060a9
Fix circular dep
Dec 16, 2025
2f31c53
smol
Dec 16, 2025
45bf547
Merge remote-tracking branch 'origin/main' into fix/better-error-when…
Dec 16, 2025
3428f04
Review fixes
Dec 18, 2025
14e6b7a
Merge remote-tracking branch 'origin/main' into fix/better-error-when…
Dec 18, 2025
1310713
Add a test
Dec 18, 2025
c820cd0
Merge branch 'main' into fix/better-error-when-logging-from-vertex
aleksanderkatan Dec 18, 2025
2ea9223
Merge branch 'main' into fix/better-error-when-logging-from-vertex
aleksanderkatan Dec 22, 2025
e42761a
Merge remote-tracking branch 'origin/main' into fix/better-error-when…
Jan 15, 2026
50c7f27
Merge fixes
Jan 15, 2026
23083d3
Add shaderStageSlot
Jan 15, 2026
3054814
Remove _currentStage
Jan 15, 2026
fd0f6a9
Update tests
Jan 15, 2026
f326bdf
Export type guards
Jan 15, 2026
7dc5e64
Update log test example
Jan 15, 2026
c51df35
smol
Jan 15, 2026
7579e3a
Update test
Jan 15, 2026
2e551d2
Update apps/typegpu-docs/src/examples/tests/log-test/index.ts
aleksanderkatan Jan 15, 2026
07c81be
Remove duplicated test
Jan 15, 2026
e41cc9f
Merge branch 'main' into fix/better-error-when-logging-from-vertex
aleksanderkatan Jan 20, 2026
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
52 changes: 46 additions & 6 deletions apps/typegpu-docs/src/examples/tests/log-test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,16 +215,56 @@ export const controls = {
},
'Render pipeline': {
onButtonClick: () => {
const context = canvas.getContext('webgpu') as GPUCanvasContext;
const pipeline = root['~unstable']
.withVertex(mainVertex)
.withFragment(mainFragment, { format: presentationFormat })
.createPipeline();

context.configure({
device: root.device,
format: presentationFormat,
alphaMode: 'premultiplied',
pipeline
.withColorAttachment({
view: context.getCurrentTexture().createView(),
clearValue: [0, 0, 0, 0],
loadOp: 'clear',
storeOp: 'store',
})
.draw(3);
},
},
'Render pipeline helper': {
onButtonClick: () => {
const helper = tgpu.fn([])(() => {
'use gpu';
console.log('A log made from a helper used during both stages.');
});

const mainVertex = tgpu['~unstable'].vertexFn({
in: { vertexIndex: d.builtin.vertexIndex },
out: { pos: d.builtin.position },
})((input) => {
console.log('A log made from vertex stage.');
helper();

const positions = [
d.vec2f(0, 0.5),
d.vec2f(-0.5, -0.5),
d.vec2f(0.5, -0.5),
];

return { pos: d.vec4f(positions[input.vertexIndex], 0, 1) };
});

const mainFragment = tgpu['~unstable'].fragmentFn({
in: { pos: d.builtin.position },
out: d.vec4f,
})(() => {
console.log('A log made from fragment stage.');
helper();

return d.vec4f(0.769, 0.392, 1.0, 1);
});

const pipeline = root['~unstable']
.withVertex(mainVertex, {})
.withVertex(mainVertex)
.withFragment(mainFragment, { format: presentationFormat })
.createPipeline();

Expand Down
22 changes: 15 additions & 7 deletions packages/typegpu/src/core/function/tgpuComputeFn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '../../shared/meta.ts';
import { $getNameForward, $internal, $resolve } from '../../shared/symbols.ts';
import type { ResolutionCtx, SelfResolvable } from '../../types.ts';
import { shaderStageSlot } from '../slot/internalSlots.ts';
import { createFnCore, type FnCore } from './fnCore.ts';
import type { Implementation, InferIO, IORecord } from './fnTypes.ts';
import { createIoSchema, type IOLayoutToSchema } from './ioSchema.ts';
Expand All @@ -27,7 +28,7 @@ type TgpuComputeFnShellHeader<
readonly argTypes: [IOLayoutToSchema<ComputeIn>] | [];
readonly returnType: Void;
readonly workgroupSize: [number, number, number];
readonly isEntry: true;
readonly entryPoint: 'compute';
};

/**
Expand Down Expand Up @@ -107,7 +108,7 @@ export function computeFn<
options.workgroupSize[1] ?? 1,
options.workgroupSize[2] ?? 1,
],
isEntry: true,
entryPoint: 'compute',
};

const call = (
Expand All @@ -123,6 +124,12 @@ export function computeFn<
return Object.assign(call, shell);
}

export function isTgpuComputeFn<ComputeIn extends IORecord<AnyComputeBuiltin>>(
value: unknown | TgpuComputeFn<ComputeIn>,
): value is TgpuComputeFn<ComputeIn> {
return (value as TgpuComputeFn<ComputeIn>)?.shell?.entryPoint === 'compute';
}

// --------------
// Implementation
// --------------
Expand Down Expand Up @@ -162,11 +169,12 @@ function createComputeFn<ComputeIn extends IORecord<AnyComputeBuiltin>>(
},

[$resolve](ctx: ResolutionCtx): ResolvedSnippet {
return core.resolve(
ctx,
shell.argTypes,
shell.returnType,
);
return ctx.withSlots([[shaderStageSlot, 'compute']], () =>
core.resolve(
ctx,
shell.argTypes,
shell.returnType,
));
},

toString() {
Expand Down
2 changes: 0 additions & 2 deletions packages/typegpu/src/core/function/tgpuFn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ type TgpuFnShellHeader<
readonly [$internal]: true;
readonly argTypes: Args;
readonly returnType: Return;
readonly isEntry: false;
};

/**
Expand Down Expand Up @@ -132,7 +131,6 @@ export function fn<
[$internal]: true,
argTypes,
returnType: returnType ?? Void as Return,
isEntry: false,
};

const call = (
Expand Down
27 changes: 20 additions & 7 deletions packages/typegpu/src/core/function/tgpuFragmentFn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import { $getNameForward, $internal, $resolve } from '../../shared/symbols.ts';
import type { ResolutionCtx, SelfResolvable } from '../../types.ts';
import { addReturnTypeToExternals } from '../resolve/externals.ts';
import { shaderStageSlot } from '../slot/internalSlots.ts';
import { createFnCore, type FnCore } from './fnCore.ts';
import type {
BaseIOData,
Expand Down Expand Up @@ -61,7 +62,7 @@ type TgpuFragmentFnShellHeader<
readonly in: FragmentIn | undefined;
readonly out: FragmentOut;
readonly returnType: IOLayoutToSchema<FragmentOut>;
readonly isEntry: true;
readonly entryPoint: 'fragment';
};

/**
Expand Down Expand Up @@ -145,7 +146,7 @@ export function fragmentFn<
in: options.in,
out: options.out,
returnType: createIoSchema(options.out),
isEntry: true,
entryPoint: 'fragment',
};

const call = (
Expand All @@ -159,6 +160,17 @@ export function fragmentFn<
>;
}

export function isTgpuFragmentFn<
FragmentIn extends FragmentInConstrained,
FragmentOut extends FragmentOutConstrained,
>(
value: unknown | TgpuFragmentFn<FragmentIn, FragmentOut>,
): value is TgpuFragmentFn<FragmentIn, FragmentOut> {
return (value as TgpuFragmentFn<FragmentIn, FragmentOut>)?.shell
?.entryPoint ===
'fragment';
}

// --------------
// Implementation
// --------------
Expand Down Expand Up @@ -215,11 +227,12 @@ function createFragmentFn(
}
core.applyExternals({ Out: outputType });

return core.resolve(
ctx,
inputWithLocation ? [inputWithLocation] : [],
shell.returnType,
);
return ctx.withSlots([[shaderStageSlot, 'fragment']], () =>
core.resolve(
ctx,
inputWithLocation ? [inputWithLocation] : [],
shell.returnType,
));
},

toString() {
Expand Down
26 changes: 19 additions & 7 deletions packages/typegpu/src/core/function/tgpuVertexFn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from '../../shared/meta.ts';
import { $getNameForward, $internal, $resolve } from '../../shared/symbols.ts';
import type { ResolutionCtx, SelfResolvable } from '../../types.ts';
import { shaderStageSlot } from '../slot/internalSlots.ts';
import { createFnCore, type FnCore } from './fnCore.ts';
import type {
BaseIOData,
Expand Down Expand Up @@ -52,7 +53,7 @@ type TgpuVertexFnShellHeader<
readonly in: VertexIn | undefined;
readonly out: VertexOut;
readonly argTypes: [IOLayoutToSchema<VertexIn>] | [];
readonly isEntry: true;
readonly entryPoint: 'vertex';
};

/**
Expand Down Expand Up @@ -134,7 +135,7 @@ export function vertexFn<
argTypes: options.in && Object.keys(options.in).length !== 0
? [createIoSchema(options.in)]
: [],
isEntry: true,
entryPoint: 'vertex',
};

const call = (
Expand All @@ -145,6 +146,16 @@ export function vertexFn<
return Object.assign(call, shell) as TgpuVertexFnShell<VertexIn, VertexOut>;
}

export function isTgpuVertexFn<
VertexIn extends VertexInConstrained,
VertexOut extends VertexOutConstrained,
>(
value: unknown | TgpuVertexFn<VertexIn, VertexOut>,
): value is TgpuVertexFn<VertexIn, VertexOut> {
return (value as TgpuVertexFn<VertexIn, VertexOut>)?.shell?.entryPoint ===
'vertex';
}

// --------------
// Implementation
// --------------
Expand Down Expand Up @@ -195,11 +206,12 @@ function createVertexFn(
core.applyExternals({ Out: outputWithLocation });
}

return core.resolve(
ctx,
shell.argTypes,
outputWithLocation,
);
return ctx.withSlots([[shaderStageSlot, 'vertex']], () =>
core.resolve(
ctx,
shell.argTypes,
outputWithLocation,
));
},

toString() {
Expand Down
4 changes: 4 additions & 0 deletions packages/typegpu/src/core/slot/internalSlots.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import type { ShaderStage } from '../../types.ts';
import { slot } from './slot.ts';

export const shaderStageSlot = slot<ShaderStage>(undefined);
3 changes: 3 additions & 0 deletions packages/typegpu/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ export { isUsableAsStorage } from './extension.ts';
export { isUsableAsUniform } from './core/buffer/bufferUsage.ts';
export { isBufferShorthand } from './core/buffer/bufferShorthand.ts';
export { isTgpuFn } from './core/function/tgpuFn.ts';
export { isTgpuFragmentFn } from './core/function/tgpuFragmentFn.ts';
export { isTgpuVertexFn } from './core/function/tgpuVertexFn.ts';
export { isTgpuComputeFn } from './core/function/tgpuComputeFn.ts';
export { isVariable } from './core/variable/tgpuVariable.ts';

// types
Expand Down
8 changes: 7 additions & 1 deletion packages/typegpu/src/tgsl/consoleLog/logGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { TgpuMutable } from '../../core/buffer/bufferShorthand.ts';
import { stitch } from '../../core/resolve/stitch.ts';
import type { TgpuRoot } from '../../core/root/rootTypes.ts';
import { shaderStageSlot } from '../../core/slot/internalSlots.ts';
import { arrayOf } from '../../data/array.ts';
import { atomic } from '../../data/atomic.ts';
import { UnknownData } from '../../data/dataTypes.ts';
Expand Down Expand Up @@ -89,8 +90,13 @@ export class LogGeneratorImpl implements LogGenerator {
op: string,
args: Snippet[],
): Snippet {
if (shaderStageSlot.$ === 'vertex') {
console.warn(`'console.${op}' is not supported in vertex shaders.`);
return fallbackSnippet;
}

if (!supportedLogOps.includes(op as SupportedLogOps)) {
console.warn(`Unsupported log method '${op}' was used in TGSL.`);
console.warn(`Unsupported log method '${op}'.`);
return fallbackSnippet;
}

Expand Down
6 changes: 6 additions & 0 deletions packages/typegpu/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,12 @@ export type ExecState =
| CodegenState
| SimulationState;

export type ShaderStage =
| 'vertex'
| 'fragment'
| 'compute'
| undefined;

/**
* Passed into each resolvable item. All items in a tree share a resolution ctx,
* but there can be layers added and removed from the item stack when going down
Expand Down
Loading