From b707690162deea82428682f16a91f0e9ab03f01a Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Thu, 12 Mar 2026 13:02:09 +0100 Subject: [PATCH 1/5] feat: More convenient TgpuVertexFn.AutoIn and TgpuVertexFn.AutoOut types --- packages/typegpu/src/core/function/autoIO.ts | 9 +++++++++ packages/typegpu/src/core/function/tgpuFragmentFn.ts | 3 +++ packages/typegpu/src/core/function/tgpuVertexFn.ts | 3 +++ packages/typegpu/src/indexNamedExports.ts | 6 +++++- 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/typegpu/src/core/function/autoIO.ts b/packages/typegpu/src/core/function/autoIO.ts index 53cb34136..5b359c2e1 100644 --- a/packages/typegpu/src/core/function/autoIO.ts +++ b/packages/typegpu/src/core/function/autoIO.ts @@ -2,10 +2,13 @@ import { builtin, type OmitBuiltins } from '../../builtin.ts'; import { AutoStruct } from '../../data/autoStruct.ts'; import type { ResolvedSnippet } from '../../data/snippet.ts'; import { vec4f } from '../../data/vector.ts'; +import { FormatToWGSLType } from '../../data/vertexFormatData.ts'; import type { BaseData, v4f } from '../../data/wgslTypes.ts'; import { getName, setName } from '../../shared/meta.ts'; import type { InferGPU, InferGPURecord, InferRecord } from '../../shared/repr.ts'; import { $internal, $resolve } from '../../shared/symbols.ts'; +import { Assume } from '../../shared/utilityTypes.ts'; +import { TgpuVertexAttrib } from '../../shared/vertexFormat.ts'; import type { ResolutionCtx, SelfResolvable } from '../../types.ts'; import { shaderStageSlot } from '../slot/internalSlots.ts'; import { createFnCore, type FnCore } from './fnCore.ts'; @@ -20,6 +23,12 @@ const builtinVertexIn = { export type AutoVertexIn = T & InferRecord; +export type _AutoVertexIn = AutoVertexIn<{ + [Key in keyof T]: T[Key] extends TgpuVertexAttrib + ? InferGPU> + : Assume>; +}>; + const builtinVertexOut = { $clipDistances: builtin.clipDistances, $position: builtin.position, diff --git a/packages/typegpu/src/core/function/tgpuFragmentFn.ts b/packages/typegpu/src/core/function/tgpuFragmentFn.ts index 5a06b3c2c..6d3fa5054 100644 --- a/packages/typegpu/src/core/function/tgpuFragmentFn.ts +++ b/packages/typegpu/src/core/function/tgpuFragmentFn.ts @@ -22,6 +22,7 @@ import type { Prettify } from '../../shared/utilityTypes.ts'; import type { ResolutionCtx, SelfResolvable } from '../../types.ts'; import { addReturnTypeToExternals } from '../resolve/externals.ts'; import { shaderStageSlot } from '../slot/internalSlots.ts'; +import { AnyAutoCustoms, AutoFragmentIn, AutoFragmentOut } from './autoIO.ts'; import { createFnCore, type FnCore } from './fnCore.ts'; import type { BaseIOData, Implementation, InferIO, IOLayout, IORecord } from './fnTypes.ts'; import { createIoSchema, type IOLayoutToSchema } from './ioSchema.ts'; @@ -118,6 +119,8 @@ export declare namespace TgpuFragmentFn { // readable, and refactoring to use a builtin argument is too much hassle. type In = Record; type Out = Record | BaseData; + type AutoIn = AutoFragmentIn; + type AutoOut = AutoFragmentOut; } export function fragmentFn(options: { diff --git a/packages/typegpu/src/core/function/tgpuVertexFn.ts b/packages/typegpu/src/core/function/tgpuVertexFn.ts index 9ee0c4b93..0f68b8431 100644 --- a/packages/typegpu/src/core/function/tgpuVertexFn.ts +++ b/packages/typegpu/src/core/function/tgpuVertexFn.ts @@ -7,6 +7,7 @@ import { $getNameForward, $internal, $resolve } from '../../shared/symbols.ts'; import type { Prettify } from '../../shared/utilityTypes.ts'; import type { ResolutionCtx, SelfResolvable } from '../../types.ts'; import { shaderStageSlot } from '../slot/internalSlots.ts'; +import { _AutoVertexIn, AnyAutoCustoms, AutoVertexOut } from './autoIO.ts'; import { createFnCore, type FnCore } from './fnCore.ts'; import type { BaseIOData, Implementation, InferIO, IORecord } from './fnTypes.ts'; import { createIoSchema, type IOLayoutToSchema } from './ioSchema.ts'; @@ -77,6 +78,8 @@ export interface TgpuVertexFn< export declare namespace TgpuVertexFn { type In = BaseData | Record; type Out = Record; + type AutoIn = _AutoVertexIn; + type AutoOut = AutoVertexOut; } export function vertexFn(options: { diff --git a/packages/typegpu/src/indexNamedExports.ts b/packages/typegpu/src/indexNamedExports.ts index 013c23f46..f21cff1bf 100644 --- a/packages/typegpu/src/indexNamedExports.ts +++ b/packages/typegpu/src/indexNamedExports.ts @@ -110,9 +110,13 @@ export type { TgpuVertexFn, TgpuVertexFnShell } from './core/function/tgpuVertex export type { TgpuFragmentFn, TgpuFragmentFnShell } from './core/function/tgpuFragmentFn.ts'; export type { TgpuComputeFn, TgpuComputeFnShell } from './core/function/tgpuComputeFn.ts'; export type { + /** @deprecated use TgpuFragmentFn.AutoIn */ AutoFragmentIn, + /** @deprecated use TgpuFragmentFn.AutoOut */ AutoFragmentOut, - AutoVertexIn, + /** @deprecated use TgpuVertexFn.AutoIn */ + _AutoVertexIn as AutoVertexIn, + /** @deprecated use TgpuVertexFn.AutoOut */ AutoVertexOut, } from './core/function/autoIO.ts'; export type { TgpuDeclare } from './core/declare/tgpuDeclare.ts'; From f1680f4dd29525df590047826d79ad60bae88344 Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Thu, 12 Mar 2026 17:59:21 +0100 Subject: [PATCH 2/5] Update packages/typegpu/src/core/function/autoIO.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/typegpu/src/core/function/autoIO.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/typegpu/src/core/function/autoIO.ts b/packages/typegpu/src/core/function/autoIO.ts index 5b359c2e1..d4ba229b2 100644 --- a/packages/typegpu/src/core/function/autoIO.ts +++ b/packages/typegpu/src/core/function/autoIO.ts @@ -2,13 +2,13 @@ import { builtin, type OmitBuiltins } from '../../builtin.ts'; import { AutoStruct } from '../../data/autoStruct.ts'; import type { ResolvedSnippet } from '../../data/snippet.ts'; import { vec4f } from '../../data/vector.ts'; -import { FormatToWGSLType } from '../../data/vertexFormatData.ts'; +import type { FormatToWGSLType } from '../../data/vertexFormatData.ts'; import type { BaseData, v4f } from '../../data/wgslTypes.ts'; import { getName, setName } from '../../shared/meta.ts'; import type { InferGPU, InferGPURecord, InferRecord } from '../../shared/repr.ts'; import { $internal, $resolve } from '../../shared/symbols.ts'; -import { Assume } from '../../shared/utilityTypes.ts'; -import { TgpuVertexAttrib } from '../../shared/vertexFormat.ts'; +import type { Assume } from '../../shared/utilityTypes.ts'; +import type { TgpuVertexAttrib } from '../../shared/vertexFormat.ts'; import type { ResolutionCtx, SelfResolvable } from '../../types.ts'; import { shaderStageSlot } from '../slot/internalSlots.ts'; import { createFnCore, type FnCore } from './fnCore.ts'; From cc8e01dcfad58aea00120debc5256bb3c18d6a99 Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Thu, 12 Mar 2026 17:59:32 +0100 Subject: [PATCH 3/5] Update packages/typegpu/src/core/function/tgpuVertexFn.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/typegpu/src/core/function/tgpuVertexFn.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/typegpu/src/core/function/tgpuVertexFn.ts b/packages/typegpu/src/core/function/tgpuVertexFn.ts index 0f68b8431..e3946da04 100644 --- a/packages/typegpu/src/core/function/tgpuVertexFn.ts +++ b/packages/typegpu/src/core/function/tgpuVertexFn.ts @@ -7,7 +7,7 @@ import { $getNameForward, $internal, $resolve } from '../../shared/symbols.ts'; import type { Prettify } from '../../shared/utilityTypes.ts'; import type { ResolutionCtx, SelfResolvable } from '../../types.ts'; import { shaderStageSlot } from '../slot/internalSlots.ts'; -import { _AutoVertexIn, AnyAutoCustoms, AutoVertexOut } from './autoIO.ts'; +import type { _AutoVertexIn, AnyAutoCustoms, AutoVertexOut } from './autoIO.ts'; import { createFnCore, type FnCore } from './fnCore.ts'; import type { BaseIOData, Implementation, InferIO, IORecord } from './fnTypes.ts'; import { createIoSchema, type IOLayoutToSchema } from './ioSchema.ts'; From 78d7d76d17f7839f5ff821e6b938f4d8da703805 Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Thu, 12 Mar 2026 17:59:42 +0100 Subject: [PATCH 4/5] Update packages/typegpu/src/core/function/tgpuFragmentFn.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- packages/typegpu/src/core/function/tgpuFragmentFn.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/typegpu/src/core/function/tgpuFragmentFn.ts b/packages/typegpu/src/core/function/tgpuFragmentFn.ts index 6d3fa5054..2b8ee51bd 100644 --- a/packages/typegpu/src/core/function/tgpuFragmentFn.ts +++ b/packages/typegpu/src/core/function/tgpuFragmentFn.ts @@ -22,7 +22,7 @@ import type { Prettify } from '../../shared/utilityTypes.ts'; import type { ResolutionCtx, SelfResolvable } from '../../types.ts'; import { addReturnTypeToExternals } from '../resolve/externals.ts'; import { shaderStageSlot } from '../slot/internalSlots.ts'; -import { AnyAutoCustoms, AutoFragmentIn, AutoFragmentOut } from './autoIO.ts'; +import type { AnyAutoCustoms, AutoFragmentIn, AutoFragmentOut } from './autoIO.ts'; import { createFnCore, type FnCore } from './fnCore.ts'; import type { BaseIOData, Implementation, InferIO, IOLayout, IORecord } from './fnTypes.ts'; import { createIoSchema, type IOLayoutToSchema } from './ioSchema.ts'; From e08e02a0df10543465584dc46aeef6fd4fb8fcf6 Mon Sep 17 00:00:00 2001 From: Iwo Plaza Date: Mon, 16 Mar 2026 16:36:14 +0100 Subject: [PATCH 5/5] Update examples --- .../algorithms/jump-flood-voronoi/index.ts | 14 ++--- .../background-segmentation/shaders.ts | 5 +- .../rendering/box-raytracing/index.ts | 62 +++++++++---------- 3 files changed, 36 insertions(+), 45 deletions(-) diff --git a/apps/typegpu-docs/src/examples/algorithms/jump-flood-voronoi/index.ts b/apps/typegpu-docs/src/examples/algorithms/jump-flood-voronoi/index.ts index b9534724b..060bd38c5 100644 --- a/apps/typegpu-docs/src/examples/algorithms/jump-flood-voronoi/index.ts +++ b/apps/typegpu-docs/src/examples/algorithms/jump-flood-voronoi/index.ts @@ -6,7 +6,6 @@ import { defineControls } from '../../common/defineControls.ts'; const root = await tgpu.init(); const canvas = document.querySelector('canvas') as HTMLCanvasElement; -const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); const context = root.configureContext({ canvas }); @@ -176,17 +175,12 @@ const jumpFlood = root.createGuardedComputePipeline((x, y) => { std.textureStore(pingPongLayout.$.writeView, d.vec2i(x, y), 1, d.vec4f(bestSample.coord, 0, 0)); }); -const voronoiFrag = tgpu.fragmentFn({ - in: { uv: d.vec2f }, - out: d.vec4f, -})(({ uv }) => - std.textureSample(colorSampleLayout.$.floodTexture, colorSampleLayout.$.sampler, uv), -); - const voronoiPipeline = root.createRenderPipeline({ vertex: common.fullScreenTriangle, - fragment: voronoiFrag, - targets: { format: presentationFormat }, + fragment: ({ uv }) => { + 'use gpu'; + return std.textureSample(colorSampleLayout.$.floodTexture, colorSampleLayout.$.sampler, uv); + }, }); const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/apps/typegpu-docs/src/examples/image-processing/background-segmentation/shaders.ts b/apps/typegpu-docs/src/examples/image-processing/background-segmentation/shaders.ts index 0d2e52e15..6a0d672c8 100644 --- a/apps/typegpu-docs/src/examples/image-processing/background-segmentation/shaders.ts +++ b/apps/typegpu-docs/src/examples/image-processing/background-segmentation/shaders.ts @@ -1,4 +1,4 @@ -import tgpu, { d, std } from 'typegpu'; +import tgpu, { d, std, type TgpuFragmentFn } from 'typegpu'; import { MODEL_HEIGHT, MODEL_WIDTH } from './model.ts'; import { blockDim, @@ -94,9 +94,8 @@ export const computeFn = tgpu.computeFn({ } }); -export const fragmentFn = (input: { uv: d.v2f }) => { +export const fragmentFn = ({ uv }: TgpuFragmentFn.AutoIn<{ uv: d.v2f }>) => { 'use gpu'; - const uv = input.uv; const originalColor = std.textureSampleBaseClampToEdge( drawWithMaskLayout.$.inputTexture, drawWithMaskLayout.$.sampler, diff --git a/apps/typegpu-docs/src/examples/rendering/box-raytracing/index.ts b/apps/typegpu-docs/src/examples/rendering/box-raytracing/index.ts index ee3ed4cf0..35cd5ca48 100644 --- a/apps/typegpu-docs/src/examples/rendering/box-raytracing/index.ts +++ b/apps/typegpu-docs/src/examples/rendering/box-raytracing/index.ts @@ -1,5 +1,5 @@ import { linearToSrgb, srgbToLinear } from '@typegpu/color'; -import tgpu, { d } from 'typegpu'; +import tgpu, { d, type TgpuFragmentFn, type TgpuVertexFn } from 'typegpu'; import { add, discard, div, max, min, mul, normalize, pow, sub } from 'typegpu/std'; import { mat4 } from 'wgpu-matrix'; import { defineControls } from '../../common/defineControls.ts'; @@ -133,41 +133,39 @@ const getBoxIntersection = tgpu }`) .$uses({ IntersectionStruct }); -const Varying = { - rayWorldOrigin: d.vec3f, -}; - -const mainVertex = tgpu.vertexFn({ - in: { vertexIndex: d.builtin.vertexIndex }, - out: { pos: d.builtin.position, ...Varying }, -})((input) => { +const mainVertex = ({ $vertexIndex: vid }: TgpuVertexFn.AutoIn<{}>) => { + 'use gpu'; const pos = [d.vec2f(-1, -1), d.vec2f(3, -1), d.vec2f(-1, 3)]; - const rayWorldOrigin = mul(uniforms.$.invViewMatrix, d.vec4f(0, 0, 0, 1)).xyz; + const rayWorldOrigin = (uniforms.$.invViewMatrix * d.vec4f(0, 0, 0, 1)).xyz; - return { pos: d.vec4f(pos[input.vertexIndex], 0.0, 1.0), rayWorldOrigin }; -}); + return { + $position: d.vec4f(pos[vid], 0, 1), + rayWorldOrigin, + } satisfies TgpuVertexFn.AutoOut; +}; -const fragmentFunction = tgpu.fragmentFn({ - in: { position: d.builtin.position, ...Varying }, - out: d.vec4f, -})((input) => { - const boxSize3 = d.vec3f(d.f32(uniforms.$.boxSize)); - const halfBoxSize3 = mul(0.5, boxSize3); - const halfCanvasDims = mul(0.5, uniforms.$.canvasDims); +const fragmentFunction = ({ + $position, + rayWorldOrigin, +}: TgpuFragmentFn.AutoIn<{ rayWorldOrigin: d.v3f }>) => { + 'use gpu'; + const boxSize3 = d.vec3f(uniforms.$.boxSize); + const halfBoxSize3 = 0.5 * boxSize3; + const halfCanvasDims = 0.5 * uniforms.$.canvasDims; const minDim = min(uniforms.$.canvasDims.x, uniforms.$.canvasDims.y); - const viewCoords = div(sub(input.position.xy, halfCanvasDims), minDim); + const viewCoords = ($position.xy - halfCanvasDims) / minDim; const ray = Ray({ - origin: input.rayWorldOrigin, - direction: mul(uniforms.$.invViewMatrix, d.vec4f(normalize(d.vec3f(viewCoords, 1)), 0)).xyz, + origin: rayWorldOrigin, + direction: (uniforms.$.invViewMatrix * d.vec4f(normalize(d.vec3f(viewCoords, 1)), 0)).xyz, }); const bigBoxIntersection = getBoxIntersection( AxisAlignedBounds({ - min: mul(-1, halfBoxSize3), - max: add(cubeSize, halfBoxSize3), + min: -1 * halfBoxSize3, + max: cubeSize + halfBoxSize3, }), ray, ); @@ -188,12 +186,12 @@ const fragmentFunction = tgpu.fragmentFn({ continue; } - const ijkScaled = d.vec3f(d.f32(i), d.f32(j), d.f32(k)); + const ijkScaled = d.vec3f(i, j, k); const intersection = getBoxIntersection( AxisAlignedBounds({ - min: sub(ijkScaled, halfBoxSize3), - max: add(ijkScaled, halfBoxSize3), + min: ijkScaled - halfBoxSize3, + max: ijkScaled + halfBoxSize3, }), ray, ); @@ -202,25 +200,25 @@ const fragmentFunction = tgpu.fragmentFn({ const boxDensity = max(0, intersection.tMax - intersection.tMin) * pow(uniforms.$.materialDensity, 2); density += boxDensity; - invColor = add(invColor, mul(boxDensity, div(d.vec3f(1), boxMatrix.$[i][j][k].albedo))); + invColor += boxDensity * (1 / boxMatrix.$[i][j][k].albedo); intersectionFound = true; } } } } - const linear = div(d.vec3f(1), invColor); + const linear = 1 / invColor; const srgb = linearToSrgb(linear); const gamma = 2.2; - const corrected = pow(srgb, d.vec3f(1.0 / gamma)); + const corrected = pow(srgb, d.vec3f(1 / gamma)); if (intersectionFound) { - return mul(min(density, 1), d.vec4f(min(corrected, d.vec3f(1)), 1)); + return min(density, 1) * d.vec4f(min(corrected, d.vec3f(1)), 1); } discard(); return d.vec4f(); -}); +}; // pipeline