typegpu 0.11.2 → 0.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,7 +37,7 @@ var AutoFragmentFn = class {
37
37
  autoOut;
38
38
  constructor(impl, varyings, locations) {
39
39
  if (!getName(impl)) setName(impl, "fragmentFn");
40
- this.#core = createFnCore(impl, "@fragment ");
40
+ this.#core = createFnCore(impl, "fragment");
41
41
  this.autoIn = new AutoStruct({
42
42
  ...builtinFragmentIn,
43
43
  ...varyings
@@ -64,7 +64,7 @@ var AutoVertexFn = class {
64
64
  autoOut;
65
65
  constructor(impl, attribs, locations) {
66
66
  if (!getName(impl)) setName(impl, "vertexFn");
67
- this.#core = createFnCore(impl, "@vertex ");
67
+ this.#core = createFnCore(impl, "vertex");
68
68
  this.autoIn = new AutoStruct({
69
69
  ...builtinVertexIn,
70
70
  ...attribs
@@ -1,7 +1,5 @@
1
1
  import { $internal } from "../../shared/symbols.js";
2
2
  import { isWgslStruct } from "../../data/wgslTypes.js";
3
- import { undecorate } from "../../data/dataTypes.js";
4
- import { snip } from "../../data/snippet.js";
5
3
 
6
4
  //#region src/core/function/entryInputRouter.ts
7
5
  /**
@@ -12,28 +10,24 @@ import { snip } from "../../data/snippet.js";
12
10
  var EntryInputRouter = class {
13
11
  [$internal] = {};
14
12
  type = "entry-input-router";
15
- structArgName;
16
- dataSchema;
13
+ structArg;
17
14
  /** Maps schemaKey → { WGSL arg name, type } */
18
15
  positionalArgsMap;
19
- constructor(structArgName, dataSchema, positionalArgs) {
20
- this.structArgName = structArgName;
21
- this.dataSchema = dataSchema;
22
- this.positionalArgsMap = new Map(positionalArgs.map((a) => [a.schemaKey, {
23
- argName: a.argName,
24
- type: a.type
25
- }]));
16
+ constructor(structArg, positionalArgs) {
17
+ this.structArg = structArg;
18
+ this.positionalArgsMap = new Map(positionalArgs.map((a) => [a.schemaKey, a.arg]));
26
19
  }
27
20
  toString() {
28
21
  return "entry-input-router";
29
22
  }
30
23
  accessProp(propName) {
31
24
  const positionalEntry = this.positionalArgsMap.get(propName);
32
- if (positionalEntry) return snip(positionalEntry.argName, positionalEntry.type, "argument");
33
- if (this.dataSchema && isWgslStruct(this.dataSchema)) {
34
- const propType = this.dataSchema.propTypes[propName];
35
- if (propType) return snip(`${this.structArgName}.${propName}`, undecorate(propType), "argument");
36
- }
25
+ if (positionalEntry) return positionalEntry();
26
+ const structSnippet = this.structArg?.();
27
+ if (structSnippet && isWgslStruct(structSnippet.dataType)) return {
28
+ target: structSnippet,
29
+ prop: propName
30
+ };
37
31
  }
38
32
  };
39
33
 
@@ -9,7 +9,7 @@ import { applyExternals, replaceExternalsInWgsl } from "../resolve/externals.js"
9
9
  import { extractArgs } from "./extractArgs.js";
10
10
 
11
11
  //#region src/core/function/fnCore.ts
12
- function createFnCore(implementation, fnAttribute = "") {
12
+ function createFnCore(implementation, functionType, workgroupSize) {
13
13
  /**
14
14
  * External application has to be deferred until resolution because
15
15
  * some externals can reference the owner function which has not been
@@ -24,6 +24,10 @@ function createFnCore(implementation, fnAttribute = "") {
24
24
  },
25
25
  resolve(ctx, argTypes, returnType, entryInput) {
26
26
  const externalMap = {};
27
+ let attributes = "";
28
+ if (functionType === "compute") attributes = `@compute @workgroup_size(${workgroupSize?.join(", ")}) `;
29
+ else if (functionType === "vertex") attributes = `@vertex `;
30
+ else if (functionType === "fragment") attributes = `@fragment `;
27
31
  for (const externals of externalsToApply) applyExternals(externalMap, externals);
28
32
  const id = ctx.getUniqueName(this);
29
33
  if (typeof implementation === "string") {
@@ -32,8 +36,8 @@ function createFnCore(implementation, fnAttribute = "") {
32
36
  if (validArgNames && Object.keys(validArgNames).length > 0) applyExternals(externalMap, { in: validArgNames });
33
37
  const replacedImpl = replaceExternalsInWgsl(ctx, externalMap, implementation);
34
38
  let header = "";
35
- let body$1 = "";
36
- if (fnAttribute !== "" && entryInput && validArgNames) {
39
+ let body = "";
40
+ if (functionType !== "normal" && entryInput && validArgNames) {
37
41
  const { dataSchema, positionalArgs } = entryInput;
38
42
  const parts = [];
39
43
  if (dataSchema && isArgUsedInBody("in", replacedImpl)) parts.push(`in: ${ctx.resolve(dataSchema).value}`);
@@ -42,16 +46,16 @@ function createFnCore(implementation, fnAttribute = "") {
42
46
  if (argName !== "" && isArgUsedInBody(argName, replacedImpl)) parts.push(`${getAttributesString(a.type)}${argName}: ${ctx.resolve(a.type).value}`);
43
47
  }
44
48
  const input = `(${parts.join(", ")})`;
45
- const attributes = isWgslData(returnType) ? getAttributesString(returnType) : "";
46
- header = `${input}${returnType !== Void ? isWgslStruct(returnType) ? ` -> ${ctx.resolve(returnType).value} ` : ` -> ${attributes !== "" ? attributes : "@location(0)"} ${ctx.resolve(returnType).value} ` : " "}`;
47
- body$1 = replacedImpl;
49
+ const attributes$1 = isWgslData(returnType) ? getAttributesString(returnType) : "";
50
+ header = `${input}${returnType !== Void ? isWgslStruct(returnType) ? ` -> ${ctx.resolve(returnType).value} ` : ` -> ${attributes$1 !== "" ? attributes$1 : "@location(0)"} ${ctx.resolve(returnType).value} ` : " "}`;
51
+ body = replacedImpl;
48
52
  } else {
49
53
  const providedArgs = extractArgs(replacedImpl);
50
54
  if (providedArgs.args.length !== argTypes.length) throw new Error(`WGSL implementation has ${providedArgs.args.length} arguments, while the shell has ${argTypes.length} arguments.`);
51
55
  header = `(${providedArgs.args.map((argInfo, i) => `${argInfo.identifier}: ${checkAndReturnType(ctx, `parameter ${argInfo.identifier}`, argInfo.type, argTypes[i])}`).join(", ")})${returnType === Void ? " " : ` -> ${checkAndReturnType(ctx, "return type", providedArgs.ret?.type, returnType)} `}`;
52
- body$1 = replacedImpl.slice(providedArgs.range.end);
56
+ body = replacedImpl.slice(providedArgs.range.end);
53
57
  }
54
- ctx.addDeclaration(`${fnAttribute}fn ${id}${header}${body$1}`);
58
+ ctx.addDeclaration(`${attributes}fn ${id}${header}${body}`);
55
59
  return snip(id, returnType, "runtime");
56
60
  }
57
61
  const pluginData = getMetaData(implementation);
@@ -62,9 +66,9 @@ function createFnCore(implementation, fnAttribute = "") {
62
66
  const missingExternals = ast.externalNames.filter((name) => !(name in externalMap));
63
67
  if (missingExternals.length > 0) throw new MissingLinksError(getName(this), missingExternals);
64
68
  const maybeSecondArg = ast.params[1];
65
- if (maybeSecondArg && maybeSecondArg.type === "i" && fnAttribute !== "") applyExternals(externalMap, { [maybeSecondArg.name]: undecorate(returnType) });
66
- const { head, body, returnType: actualReturnType } = ctx.fnToWgsl({
67
- functionType: fnAttribute.includes("@compute") ? "compute" : fnAttribute.includes("@vertex") ? "vertex" : fnAttribute.includes("@fragment") ? "fragment" : "normal",
69
+ if (maybeSecondArg && maybeSecondArg.type === "i" && functionType !== "normal") applyExternals(externalMap, { [maybeSecondArg.name]: undecorate(returnType) });
70
+ const { code, returnType: actualReturnType } = ctx.fnToWgsl({
71
+ functionType,
68
72
  argTypes,
69
73
  entryInput,
70
74
  params: ast.params,
@@ -72,7 +76,7 @@ function createFnCore(implementation, fnAttribute = "") {
72
76
  body: ast.body,
73
77
  externalMap
74
78
  });
75
- ctx.addDeclaration(`${fnAttribute}fn ${id}${ctx.resolve(head).value}${ctx.resolve(body).value}`);
79
+ ctx.addDeclaration(`${attributes}fn ${id}${code}`);
76
80
  return snip(id, actualReturnType, "runtime");
77
81
  }
78
82
  };
@@ -4,7 +4,7 @@ import { createFnCore } from "./fnCore.js";
4
4
 
5
5
  //#region src/core/function/shelllessImpl.ts
6
6
  function createShelllessImpl(argTypes, implementation) {
7
- const core = createFnCore(implementation, "");
7
+ const core = createFnCore(implementation, "normal");
8
8
  return {
9
9
  [$internal]: true,
10
10
  [$getNameForward]: core,
@@ -31,7 +31,7 @@ function isTgpuComputeFn(value) {
31
31
  return value?.shell?.entryPoint === "compute";
32
32
  }
33
33
  function createComputeFn(shell, workgroupSize, implementation, entryInput) {
34
- const core = createFnCore(implementation, `@compute @workgroup_size(${workgroupSize.join(", ")}) `);
34
+ const core = createFnCore(implementation, "compute", workgroupSize);
35
35
  return {
36
36
  shell,
37
37
  $uses(newExternals) {
@@ -40,7 +40,7 @@ function createFn(shell, _implementation) {
40
40
  pairs = _implementation[$providing]?.pairs ?? [];
41
41
  implementation = _implementation[$internal].inner;
42
42
  } else implementation = _implementation;
43
- const core = createFnCore(implementation, "");
43
+ const core = createFnCore(implementation, "normal");
44
44
  const fnBase = {
45
45
  shell,
46
46
  resourceType: "function",
@@ -32,7 +32,7 @@ function isTgpuFragmentFn(value) {
32
32
  return value?.shell?.entryPoint === "fragment";
33
33
  }
34
34
  function createFragmentFn(shell, implementation) {
35
- const core = createFnCore(implementation, "@fragment ");
35
+ const core = createFnCore(implementation, "fragment");
36
36
  const outputType = shell.returnType;
37
37
  if (typeof implementation === "string") addReturnTypeToExternals(implementation, outputType, (externals) => core.applyExternals(externals));
38
38
  return {
@@ -32,7 +32,7 @@ function isTgpuVertexFn(value) {
32
32
  return value?.shell?.entryPoint === "vertex";
33
33
  }
34
34
  function createVertexFn(shell, implementation) {
35
- const core = createFnCore(implementation, "@vertex ");
35
+ const core = createFnCore(implementation, "vertex");
36
36
  const entryInput = separateAllAsPositional(shell.in ?? {});
37
37
  return {
38
38
  shell,
package/data/index.d.ts CHANGED
@@ -4,7 +4,7 @@ import { AnyAttribute, HasCustomLocation, IsBuiltin, align, interpolate, invaria
4
4
  import { memoryLayoutOf } from "./offsetUtils.js";
5
5
  import { FormatToAcceptedData, FormatToWGSLType, PackedData, TgpuVertexFormatData, float16, float16x2, float16x4, float32, float32x2, float32x3, float32x4, formatToWGSLType, isPackedData, packedFormats, sint16, sint16x2, sint16x4, sint32, sint32x2, sint32x3, sint32x4, sint8, sint8x2, sint8x4, snorm16, snorm16x2, snorm16x4, snorm8, snorm8x2, snorm8x4, uint16, uint16x2, uint16x4, uint32, uint32x2, uint32x3, uint32x4, uint8, uint8x2, uint8x4, unorm10_10_10_2, unorm16, unorm16x2, unorm16x4, unorm8, unorm8x2, unorm8x4, unorm8x4_bgra } from "./vertexFormatData.js";
6
6
  import { _ref } from "./ref.js";
7
- import { Align, AnyVecInstance, AnyWgslData, AnyWgslStruct, Atomic, BaseData, Bool, Builtin, Decorated, F16, F32, I32, Interpolate, Location, Mat2x2f, Mat3x3f, Mat4x4f, Ptr, Size, StorableData, U16, U32, Vec2b, Vec2f, Vec2h, Vec2i, Vec2u, Vec3b, Vec3f, Vec3h, Vec3i, Vec3u, Vec4b, Vec4f, Vec4h, Vec4i, Vec4u, Void, WgslArray, WgslStruct, atomicI32, atomicU32, isAlignAttrib, isAtomic, isBuiltinAttrib, isDecorated, isInterpolateAttrib, isLocationAttrib, isPtr, isSizeAttrib, isWgslArray, isWgslData, isWgslStruct, m2x2f, m3x3f, m4x4f, matBase, v2b, v2f, v2i, v2u, v3b, v3f, v3i, v3u, v4b, v4f, v4i, v4u, vecBase } from "./wgslTypes.js";
7
+ import { Align, AnyVecInstance, AnyWgslData, AnyWgslStruct, Atomic, BaseData, Bool, Builtin, Decorated, F16, F32, I32, Interpolate, Location, Mat2x2f, Mat3x3f, Mat4x4f, Ptr, Size, StorableData, U16, U32, Vec2b, Vec2f, Vec2h, Vec2i, Vec2u, Vec3b, Vec3f, Vec3h, Vec3i, Vec3u, Vec4b, Vec4f, Vec4h, Vec4i, Vec4u, Void, WgslArray, WgslStruct, atomicI32, atomicU32, isAlignAttrib, isAtomic, isBuiltinAttrib, isDecorated, isInterpolateAttrib, isLocationAttrib, isPtr, isSizeAttrib, isWgslArray, isWgslData, isWgslStruct, m2x2f, m3x3f, m4x4f, matBase, v2b, v2f, v2h, v2i, v2u, v3b, v3f, v3h, v3i, v3u, v4b, v4f, v4h, v4i, v4u, vecBase } from "./wgslTypes.js";
8
8
  import { WgslExternalTexture, WgslStorageTexture, WgslStorageTexture1d, WgslStorageTexture2d, WgslStorageTexture2dArray, WgslStorageTexture3d, WgslStorageTextureProps, WgslTexture, WgslTexture1d, WgslTexture2d, WgslTexture2dArray, WgslTexture3d, WgslTextureCube, WgslTextureCubeArray, WgslTextureDepth2d, WgslTextureDepth2dArray, WgslTextureDepthCube, WgslTextureDepthCubeArray, WgslTextureDepthMultisampled2d, WgslTextureMultisampled2d, texture1d, texture2d, texture2dArray, texture3d, textureCube, textureCubeArray, textureDepth2d, textureDepth2dArray, textureDepthCube, textureDepthCubeArray, textureDepthMultisampled2d, textureExternal, textureMultisampled2d, textureStorage1d, textureStorage2d, textureStorage2dArray, textureStorage3d } from "./texture.js";
9
9
  import { Infer, InferGPU, InferInput, InferPartial, InferPatch } from "../shared/repr.js";
10
10
  import { AnyData, AnyLooseData, Disarray, LooseDecorated, Unstruct, isData, isDisarray, isLooseData, isLooseDecorated, isUnstruct } from "./dataTypes.js";
@@ -25,7 +25,7 @@ import { deepEqual } from "./deepEqual.js";
25
25
 
26
26
  //#region src/data/index.d.ts
27
27
  declare namespace index_d_exports {
28
- export { Align, AnyAttribute, AnyBuiltin, AnyData, AnyLooseData, AnyVecInstance, AnyWgslData, AnyWgslStruct, Atomic, BaseData, BaseData as BaseWgslData, Bool, Builtin, BuiltinClipDistances, BuiltinFragDepth, BuiltinFrontFacing, BuiltinGlobalInvocationId, BuiltinInstanceIndex, BuiltinLocalInvocationId, BuiltinLocalInvocationIndex, BuiltinNumWorkgroups, BuiltinPosition, BuiltinSampleIndex, BuiltinSampleMask, BuiltinVertexIndex, BuiltinWorkgroupId, Decorated, Disarray, F16, F32, FormatToAcceptedData, FormatToWGSLType, HasCustomLocation, I32, Infer, InferGPU, InferInput, InferPartial, InferPatch, Interpolate, IsBuiltin, Location, LooseDecorated, Mat2x2f, Mat3x3f, Mat4x4f, PackedData, Ptr, Size, StorableData, TgpuVertexFormatData, U16, U32, Unstruct, Vec2b, Vec2f, Vec2h, Vec2i, Vec2u, Vec3b, Vec3f, Vec3h, Vec3i, Vec3u, Vec4b, Vec4f, Vec4h, Vec4i, Vec4u, Void, WgslArray, WgslComparisonSampler, WgslExternalTexture, WgslSampler, WgslStorageTexture, WgslStorageTexture1d, WgslStorageTexture2d, WgslStorageTexture2dArray, WgslStorageTexture3d, WgslStorageTextureProps, WgslStruct, WgslTexture, WgslTexture1d, WgslTexture2d, WgslTexture2dArray, WgslTexture3d, WgslTextureCube, WgslTextureCubeArray, WgslTextureDepth2d, WgslTextureDepth2dArray, WgslTextureDepthCube, WgslTextureDepthCubeArray, WgslTextureDepthMultisampled2d, WgslTextureMultisampled2d, align, PUBLIC_alignmentOf as alignmentOf, arrayOf, atomic, atomicI32, atomicU32, bool, builtin, comparisonSampler, deepEqual, disarrayOf, f16, f32, float16, float16x2, float16x4, float32, float32x2, float32x3, float32x4, formatToWGSLType, PUBLIC_getLongestContiguousPrefix as getLongestContiguousPrefix, i32, interpolate, invariant, isAlignAttrib, isAtomic, isBuiltin, isBuiltinAttrib, PUBLIC_isContiguous as isContiguous, isData, isDecorated, isDisarray, isInterpolateAttrib, isLocationAttrib, isLooseData, isLooseDecorated, isPackedData, isPtr, isSizeAttrib, isUnstruct, isWgslArray, isWgslData, isWgslStruct, location, m2x2f, m3x3f, m4x4f, mat2x2f, mat3x3f, mat4x4f, matBase, matToArray, memoryLayoutOf, packedFormats, ptrFn, ptrHandle, ptrPrivate, ptrStorage, ptrUniform, ptrWorkgroup, _ref as ref, sampler, sint16, sint16x2, sint16x4, sint32, sint32x2, sint32x3, sint32x4, sint8, sint8x2, sint8x4, size, PUBLIC_sizeOf as sizeOf, snorm16, snorm16x2, snorm16x4, snorm8, snorm8x2, snorm8x4, struct, texture1d, texture2d, texture2dArray, texture3d, textureCube, textureCubeArray, textureDepth2d, textureDepth2dArray, textureDepthCube, textureDepthCubeArray, textureDepthMultisampled2d, textureExternal, textureMultisampled2d, textureStorage1d, textureStorage2d, textureStorage2dArray, textureStorage3d, u16, u32, uint16, uint16x2, uint16x4, uint32, uint32x2, uint32x3, uint32x4, uint8, uint8x2, uint8x4, unorm10_10_10_2, unorm16, unorm16x2, unorm16x4, unorm8, unorm8x2, unorm8x4, unorm8x4_bgra, unstruct, v2b, v2f, v2i, v2u, v3b, v3f, v3i, v3u, v4b, v4f, v4i, v4u, vec2b, vec2f, vec2h, vec2i, vec2u, vec3b, vec3f, vec3h, vec3i, vec3u, vec4b, vec4f, vec4h, vec4i, vec4u, vecBase };
28
+ export { Align, AnyAttribute, AnyBuiltin, AnyData, AnyLooseData, AnyVecInstance, AnyWgslData, AnyWgslStruct, Atomic, BaseData, BaseData as BaseWgslData, Bool, Builtin, BuiltinClipDistances, BuiltinFragDepth, BuiltinFrontFacing, BuiltinGlobalInvocationId, BuiltinInstanceIndex, BuiltinLocalInvocationId, BuiltinLocalInvocationIndex, BuiltinNumWorkgroups, BuiltinPosition, BuiltinSampleIndex, BuiltinSampleMask, BuiltinVertexIndex, BuiltinWorkgroupId, Decorated, Disarray, F16, F32, FormatToAcceptedData, FormatToWGSLType, HasCustomLocation, I32, Infer, InferGPU, InferInput, InferPartial, InferPatch, Interpolate, IsBuiltin, Location, LooseDecorated, Mat2x2f, Mat3x3f, Mat4x4f, PackedData, Ptr, Size, StorableData, TgpuVertexFormatData, U16, U32, Unstruct, Vec2b, Vec2f, Vec2h, Vec2i, Vec2u, Vec3b, Vec3f, Vec3h, Vec3i, Vec3u, Vec4b, Vec4f, Vec4h, Vec4i, Vec4u, Void, WgslArray, WgslComparisonSampler, WgslExternalTexture, WgslSampler, WgslStorageTexture, WgslStorageTexture1d, WgslStorageTexture2d, WgslStorageTexture2dArray, WgslStorageTexture3d, WgslStorageTextureProps, WgslStruct, WgslTexture, WgslTexture1d, WgslTexture2d, WgslTexture2dArray, WgslTexture3d, WgslTextureCube, WgslTextureCubeArray, WgslTextureDepth2d, WgslTextureDepth2dArray, WgslTextureDepthCube, WgslTextureDepthCubeArray, WgslTextureDepthMultisampled2d, WgslTextureMultisampled2d, align, PUBLIC_alignmentOf as alignmentOf, arrayOf, atomic, atomicI32, atomicU32, bool, builtin, comparisonSampler, deepEqual, disarrayOf, f16, f32, float16, float16x2, float16x4, float32, float32x2, float32x3, float32x4, formatToWGSLType, PUBLIC_getLongestContiguousPrefix as getLongestContiguousPrefix, i32, interpolate, invariant, isAlignAttrib, isAtomic, isBuiltin, isBuiltinAttrib, PUBLIC_isContiguous as isContiguous, isData, isDecorated, isDisarray, isInterpolateAttrib, isLocationAttrib, isLooseData, isLooseDecorated, isPackedData, isPtr, isSizeAttrib, isUnstruct, isWgslArray, isWgslData, isWgslStruct, location, m2x2f, m3x3f, m4x4f, mat2x2f, mat3x3f, mat4x4f, matBase, matToArray, memoryLayoutOf, packedFormats, ptrFn, ptrHandle, ptrPrivate, ptrStorage, ptrUniform, ptrWorkgroup, _ref as ref, sampler, sint16, sint16x2, sint16x4, sint32, sint32x2, sint32x3, sint32x4, sint8, sint8x2, sint8x4, size, PUBLIC_sizeOf as sizeOf, snorm16, snorm16x2, snorm16x4, snorm8, snorm8x2, snorm8x4, struct, texture1d, texture2d, texture2dArray, texture3d, textureCube, textureCubeArray, textureDepth2d, textureDepth2dArray, textureDepthCube, textureDepthCubeArray, textureDepthMultisampled2d, textureExternal, textureMultisampled2d, textureStorage1d, textureStorage2d, textureStorage2dArray, textureStorage3d, u16, u32, uint16, uint16x2, uint16x4, uint32, uint32x2, uint32x3, uint32x4, uint8, uint8x2, uint8x4, unorm10_10_10_2, unorm16, unorm16x2, unorm16x4, unorm8, unorm8x2, unorm8x4, unorm8x4_bgra, unstruct, v2b, v2f, v2h, v2i, v2u, v3b, v3f, v3h, v3i, v3u, v4b, v4f, v4h, v4i, v4u, vec2b, vec2f, vec2h, vec2i, vec2u, vec3b, vec3f, vec3h, vec3i, vec3u, vec4b, vec4f, vec4h, vec4i, vec4u, vecBase };
29
29
  }
30
30
  //#endregion
31
- export { type Align, type AnyAttribute, type AnyBuiltin, type AnyData, type AnyLooseData, type AnyVecInstance, type AnyWgslData, type AnyWgslStruct, type Atomic, type BaseData, type BaseData as BaseWgslData, type Bool, type Builtin, type BuiltinClipDistances, type BuiltinFragDepth, type BuiltinFrontFacing, type BuiltinGlobalInvocationId, type BuiltinInstanceIndex, type BuiltinLocalInvocationId, type BuiltinLocalInvocationIndex, type BuiltinNumWorkgroups, type BuiltinPosition, type BuiltinSampleIndex, type BuiltinSampleMask, type BuiltinVertexIndex, type BuiltinWorkgroupId, type Decorated, type Disarray, type F16, type F32, FormatToAcceptedData, FormatToWGSLType, type HasCustomLocation, type I32, type Infer, type InferGPU, type InferInput, type InferPartial, type InferPatch, type Interpolate, type IsBuiltin, type Location, type LooseDecorated, type Mat2x2f, type Mat3x3f, type Mat4x4f, PackedData, type Ptr, type Size, type StorableData, TgpuVertexFormatData, type U16, type U32, type Unstruct, type Vec2b, type Vec2f, type Vec2h, type Vec2i, type Vec2u, type Vec3b, type Vec3f, type Vec3h, type Vec3i, type Vec3u, type Vec4b, type Vec4f, type Vec4h, type Vec4i, type Vec4u, Void, type WgslArray, type WgslComparisonSampler, type WgslExternalTexture, type WgslSampler, type WgslStorageTexture, type WgslStorageTexture1d, type WgslStorageTexture2d, type WgslStorageTexture2dArray, type WgslStorageTexture3d, type WgslStorageTextureProps, type WgslStruct, type WgslTexture, type WgslTexture1d, type WgslTexture2d, type WgslTexture2dArray, type WgslTexture3d, type WgslTextureCube, type WgslTextureCubeArray, type WgslTextureDepth2d, type WgslTextureDepth2dArray, type WgslTextureDepthCube, type WgslTextureDepthCubeArray, type WgslTextureDepthMultisampled2d, type WgslTextureMultisampled2d, align, PUBLIC_alignmentOf as alignmentOf, arrayOf, atomic, type atomicI32, type atomicU32, bool, builtin, comparisonSampler, deepEqual, disarrayOf, f16, f32, float16, float16x2, float16x4, float32, float32x2, float32x3, float32x4, formatToWGSLType, PUBLIC_getLongestContiguousPrefix as getLongestContiguousPrefix, i32, index_d_exports, interpolate, invariant, isAlignAttrib, isAtomic, isBuiltin, isBuiltinAttrib, PUBLIC_isContiguous as isContiguous, isData, isDecorated, isDisarray, isInterpolateAttrib, isLocationAttrib, isLooseData, isLooseDecorated, isPackedData, isPtr, isSizeAttrib, isUnstruct, isWgslArray, isWgslData, isWgslStruct, location, type m2x2f, type m3x3f, type m4x4f, mat2x2f, mat3x3f, mat4x4f, type matBase, matToArray, memoryLayoutOf, packedFormats, ptrFn, ptrHandle, ptrPrivate, ptrStorage, ptrUniform, ptrWorkgroup, _ref as ref, sampler, sint16, sint16x2, sint16x4, sint32, sint32x2, sint32x3, sint32x4, sint8, sint8x2, sint8x4, size, PUBLIC_sizeOf as sizeOf, snorm16, snorm16x2, snorm16x4, snorm8, snorm8x2, snorm8x4, struct, texture1d, texture2d, texture2dArray, texture3d, textureCube, textureCubeArray, textureDepth2d, textureDepth2dArray, textureDepthCube, textureDepthCubeArray, textureDepthMultisampled2d, textureExternal, textureMultisampled2d, textureStorage1d, textureStorage2d, textureStorage2dArray, textureStorage3d, u16, u32, uint16, uint16x2, uint16x4, uint32, uint32x2, uint32x3, uint32x4, uint8, uint8x2, uint8x4, unorm10_10_10_2, unorm16, unorm16x2, unorm16x4, unorm8, unorm8x2, unorm8x4, unorm8x4_bgra, unstruct, type v2b, type v2f, type v2i, type v2u, type v3b, type v3f, type v3i, type v3u, type v4b, type v4f, type v4i, type v4u, vec2b, vec2f, vec2h, vec2i, vec2u, vec3b, vec3f, vec3h, vec3i, vec3u, vec4b, vec4f, vec4h, vec4i, vec4u, type vecBase };
31
+ export { type Align, type AnyAttribute, type AnyBuiltin, type AnyData, type AnyLooseData, type AnyVecInstance, type AnyWgslData, type AnyWgslStruct, type Atomic, type BaseData, type BaseData as BaseWgslData, type Bool, type Builtin, type BuiltinClipDistances, type BuiltinFragDepth, type BuiltinFrontFacing, type BuiltinGlobalInvocationId, type BuiltinInstanceIndex, type BuiltinLocalInvocationId, type BuiltinLocalInvocationIndex, type BuiltinNumWorkgroups, type BuiltinPosition, type BuiltinSampleIndex, type BuiltinSampleMask, type BuiltinVertexIndex, type BuiltinWorkgroupId, type Decorated, type Disarray, type F16, type F32, FormatToAcceptedData, FormatToWGSLType, type HasCustomLocation, type I32, type Infer, type InferGPU, type InferInput, type InferPartial, type InferPatch, type Interpolate, type IsBuiltin, type Location, type LooseDecorated, type Mat2x2f, type Mat3x3f, type Mat4x4f, PackedData, type Ptr, type Size, type StorableData, TgpuVertexFormatData, type U16, type U32, type Unstruct, type Vec2b, type Vec2f, type Vec2h, type Vec2i, type Vec2u, type Vec3b, type Vec3f, type Vec3h, type Vec3i, type Vec3u, type Vec4b, type Vec4f, type Vec4h, type Vec4i, type Vec4u, Void, type WgslArray, type WgslComparisonSampler, type WgslExternalTexture, type WgslSampler, type WgslStorageTexture, type WgslStorageTexture1d, type WgslStorageTexture2d, type WgslStorageTexture2dArray, type WgslStorageTexture3d, type WgslStorageTextureProps, type WgslStruct, type WgslTexture, type WgslTexture1d, type WgslTexture2d, type WgslTexture2dArray, type WgslTexture3d, type WgslTextureCube, type WgslTextureCubeArray, type WgslTextureDepth2d, type WgslTextureDepth2dArray, type WgslTextureDepthCube, type WgslTextureDepthCubeArray, type WgslTextureDepthMultisampled2d, type WgslTextureMultisampled2d, align, PUBLIC_alignmentOf as alignmentOf, arrayOf, atomic, type atomicI32, type atomicU32, bool, builtin, comparisonSampler, deepEqual, disarrayOf, f16, f32, float16, float16x2, float16x4, float32, float32x2, float32x3, float32x4, formatToWGSLType, PUBLIC_getLongestContiguousPrefix as getLongestContiguousPrefix, i32, index_d_exports, interpolate, invariant, isAlignAttrib, isAtomic, isBuiltin, isBuiltinAttrib, PUBLIC_isContiguous as isContiguous, isData, isDecorated, isDisarray, isInterpolateAttrib, isLocationAttrib, isLooseData, isLooseDecorated, isPackedData, isPtr, isSizeAttrib, isUnstruct, isWgslArray, isWgslData, isWgslStruct, location, type m2x2f, type m3x3f, type m4x4f, mat2x2f, mat3x3f, mat4x4f, type matBase, matToArray, memoryLayoutOf, packedFormats, ptrFn, ptrHandle, ptrPrivate, ptrStorage, ptrUniform, ptrWorkgroup, _ref as ref, sampler, sint16, sint16x2, sint16x4, sint32, sint32x2, sint32x3, sint32x4, sint8, sint8x2, sint8x4, size, PUBLIC_sizeOf as sizeOf, snorm16, snorm16x2, snorm16x4, snorm8, snorm8x2, snorm8x4, struct, texture1d, texture2d, texture2dArray, texture3d, textureCube, textureCubeArray, textureDepth2d, textureDepth2dArray, textureDepthCube, textureDepthCubeArray, textureDepthMultisampled2d, textureExternal, textureMultisampled2d, textureStorage1d, textureStorage2d, textureStorage2dArray, textureStorage3d, u16, u32, uint16, uint16x2, uint16x4, uint32, uint32x2, uint32x3, uint32x4, uint8, uint8x2, uint8x4, unorm10_10_10_2, unorm16, unorm16x2, unorm16x4, unorm8, unorm8x2, unorm8x4, unorm8x4_bgra, unstruct, type v2b, type v2f, type v2h, type v2i, type v2u, type v3b, type v3f, type v3h, type v3i, type v3u, type v4b, type v4f, type v4h, type v4i, type v4u, vec2b, vec2f, vec2h, vec2i, vec2u, vec3b, vec3f, vec3h, vec3i, vec3u, vec4b, vec4f, vec4h, vec4i, vec4u, type vecBase };
package/data/numeric.js CHANGED
@@ -2,20 +2,6 @@ import { $internal } from "../shared/symbols.js";
2
2
  import { callableSchema } from "../core/function/createCallableSchema.js";
3
3
 
4
4
  //#region src/data/numeric.ts
5
- const abstractInt = {
6
- [$internal]: {},
7
- type: "abstractInt",
8
- toString() {
9
- return "abstractInt";
10
- }
11
- };
12
- const abstractFloat = {
13
- [$internal]: {},
14
- type: "abstractFloat",
15
- toString() {
16
- return "abstractFloat";
17
- }
18
- };
19
5
  const boolCast = callableSchema({
20
6
  name: "bool",
21
7
  schema: () => bool,
@@ -218,6 +204,22 @@ const f16 = Object.assign(f16Cast, {
218
204
  [$internal]: {},
219
205
  type: "f16"
220
206
  });
207
+ const abstractInt = {
208
+ [$internal]: {},
209
+ type: "abstractInt",
210
+ toString() {
211
+ return "abstractInt";
212
+ },
213
+ concretized: i32
214
+ };
215
+ const abstractFloat = {
216
+ [$internal]: {},
217
+ type: "abstractFloat",
218
+ toString() {
219
+ return "abstractFloat";
220
+ },
221
+ concretized: f32
222
+ };
221
223
 
222
224
  //#endregion
223
225
  export { abstractFloat, abstractInt, bool, f16, f32, i32, u16, u32 };
package/data/snippet.d.ts CHANGED
@@ -12,14 +12,9 @@ interface Snippet {
12
12
  readonly dataType: BaseData | UnknownData;
13
13
  readonly origin: Origin;
14
14
  }
15
- interface ResolvedSnippet {
15
+ interface ResolvedSnippet extends Snippet {
16
16
  readonly value: string;
17
- /**
18
- * The type that `value` is assignable to (not necessary exactly inferred as).
19
- * E.g. `1.1` is assignable to `f32`, but `1.1` itself is an abstract float
20
- */
21
17
  readonly dataType: BaseData;
22
- readonly origin: Origin;
23
18
  }
24
19
  type MapValueToSnippet<T> = { [K in keyof T]: Snippet };
25
20
  //#endregion
@@ -72,6 +72,7 @@ interface matInfixNotation<T extends matBase> {
72
72
  */
73
73
  interface AbstractInt extends BaseData {
74
74
  readonly type: 'abstractInt';
75
+ readonly concretized: I32;
75
76
  readonly [$repr]: number;
76
77
  readonly [$invalidSchemaReason]: 'Abstract numerics are not host-shareable';
77
78
  }
@@ -80,6 +81,7 @@ interface AbstractInt extends BaseData {
80
81
  */
81
82
  interface AbstractFloat extends BaseData {
82
83
  readonly type: 'abstractFloat';
84
+ readonly concretized: F32;
83
85
  readonly [$repr]: number;
84
86
  readonly [$invalidSchemaReason]: 'Abstract numerics are not host-shareable';
85
87
  }
package/package.js CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
- var version = "0.11.2";
2
+ var version = "0.11.3";
3
3
 
4
4
  //#endregion
5
5
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typegpu",
3
- "version": "0.11.2",
3
+ "version": "0.11.3",
4
4
  "description": "A thin layer between JS and WebGPU/WGSL that improves development experience and allows for faster iteration.",
5
5
  "keywords": [
6
6
  "compute",
package/resolutionCtx.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { $internal, $providing, $resolve, isMarkedInternal } from "./shared/symbols.js";
2
2
  import { getName, hasTinyestMetadata, setName } from "./shared/meta.js";
3
3
  import { Void, isPtr, isWgslArray, isWgslStruct } from "./data/wgslTypes.js";
4
- import { UnknownData, isData, undecorate } from "./data/dataTypes.js";
4
+ import { UnknownData, isData } from "./data/dataTypes.js";
5
5
  import { snip } from "./data/snippet.js";
6
6
  import { MissingSlotValueError, ResolutionError, WgslTypeError, invariant } from "./errors.js";
7
7
  import { isLazy, isProviding, isSlot } from "./core/slot/slotTypes.js";
@@ -12,7 +12,6 @@ import { safeStringify } from "./shared/stringify.js";
12
12
  import { getBestConversion } from "./tgsl/conversion.js";
13
13
  import { bool } from "./data/numeric.js";
14
14
  import { coerceToSnippet, concretize, numericLiteralToSnippet } from "./tgsl/generationHelpers.js";
15
- import { getAttributesString } from "./data/attributes.js";
16
15
  import { createIoSchema } from "./core/function/ioSchema.js";
17
16
  import { AutoStruct } from "./data/autoStruct.js";
18
17
  import { EntryInputRouter } from "./core/function/entryInputRouter.js";
@@ -64,12 +63,11 @@ var ItemStateStackImpl = class {
64
63
  bindingMap: new WeakMap(pairs)
65
64
  });
66
65
  }
67
- pushFunctionScope(functionType, args, argAliases, returnType, externalMap) {
66
+ pushFunctionScope(functionType, argAccess, returnType, externalMap) {
68
67
  const scope = {
69
68
  type: "functionScope",
70
69
  functionType,
71
- args,
72
- argAliases,
70
+ argAccess,
73
71
  returnType,
74
72
  externalMap,
75
73
  reportedReturnTypes: /* @__PURE__ */ new Set()
@@ -106,9 +104,8 @@ var ItemStateStackImpl = class {
106
104
  for (let i = this._stack.length - 1; i >= 0; --i) {
107
105
  const layer = this._stack[i];
108
106
  if (layer?.type === "functionScope") {
109
- const arg = layer.args.find((a) => a.value === id);
110
- if (arg !== void 0) return arg;
111
- if (layer.argAliases[id]) return layer.argAliases[id];
107
+ const access = layer.argAccess[id];
108
+ if (access) return access();
112
109
  const external = layer.externalMap[id];
113
110
  if (external !== void 0 && external !== null) return coerceToSnippet(external);
114
111
  return;
@@ -189,6 +186,27 @@ var IndentController = class {
189
186
  }
190
187
  }
191
188
  };
189
+ function createArgument(name, type, origin = "argument") {
190
+ let used = false;
191
+ return {
192
+ name,
193
+ access: () => {
194
+ used = true;
195
+ return snip(name, type, origin);
196
+ },
197
+ decoratedType: type,
198
+ get used() {
199
+ return used;
200
+ }
201
+ };
202
+ }
203
+ function createArgumentPropAccess(argAccess, prop) {
204
+ return () => {
205
+ const argSnippet = argAccess();
206
+ if (!argSnippet) return;
207
+ return accessProp(argSnippet, prop);
208
+ };
209
+ }
192
210
  var ResolutionCtxImpl = class {
193
211
  #namespaceInternal;
194
212
  _indentController = new IndentController();
@@ -287,107 +305,93 @@ var ResolutionCtxImpl = class {
287
305
  try {
288
306
  this.#namespaceInternal.nameRegistry.pushFunctionScope();
289
307
  const args = [];
290
- const argAliases = [];
291
- const pendingHeaderEntries = [];
308
+ const argAccess = {};
292
309
  if (options.entryInput) {
293
310
  const { dataSchema, positionalArgs } = options.entryInput;
294
311
  const firstParam = options.params[0];
295
- const structArgName = this.makeNameValid("_arg_0");
296
- const structArg = dataSchema ? snip(structArgName, dataSchema, "argument") : void 0;
297
- if (structArg) {
298
- args.push(structArg);
299
- pendingHeaderEntries.push({
300
- argName: structArgName,
301
- header: `${structArgName}: ${this.resolve(dataSchema).value}`
302
- });
303
- }
312
+ const structArg = dataSchema ? createArgument(this.makeNameValid("_arg_0"), dataSchema) : void 0;
313
+ if (structArg) args.push(structArg);
304
314
  if (firstParam?.type === FuncParameterType.destructuredObject) for (const { name, alias } of firstParam.props) {
305
315
  const argInfo = positionalArgs.find((a) => a.schemaKey === name);
306
316
  if (argInfo) {
307
- const argName = this.makeNameValid(alias);
308
- const argSnippet = snip(argName, argInfo.type, "argument");
309
- args.push(argSnippet);
310
- argAliases.push([alias, argSnippet]);
311
- pendingHeaderEntries.push({
312
- argName,
313
- header: `${getAttributesString(argInfo.type)}${argName}: ${this.resolve(undecorate(argInfo.type)).value}`
314
- });
315
- } else if (structArg) {
316
- const propSnippet = accessProp(structArg, name);
317
- if (propSnippet) argAliases.push([alias, propSnippet]);
318
- }
317
+ const arg = createArgument(this.makeNameValid(alias), argInfo.type);
318
+ args.push(arg);
319
+ argAccess[alias] = arg.access;
320
+ } else if (structArg) argAccess[alias] = createArgumentPropAccess(structArg.access, name);
319
321
  }
320
322
  else if (firstParam?.type === FuncParameterType.identifier) {
321
323
  const proxyEntries = [];
322
324
  for (const a of positionalArgs) {
323
- const argName = this.makeNameValid(`_arg_${a.schemaKey}`);
324
- const s = snip(argName, a.type, "argument");
325
- args.push(s);
325
+ const arg = createArgument(this.makeNameValid(`_arg_${a.schemaKey}`), a.type);
326
+ args.push(arg);
326
327
  proxyEntries.push({
327
328
  schemaKey: a.schemaKey,
328
- argName,
329
- type: a.type
330
- });
331
- pendingHeaderEntries.push({
332
- argName,
333
- header: `${getAttributesString(a.type)}${argName}: ${this.resolve(undecorate(a.type)).value}`
329
+ arg: arg.access
334
330
  });
335
331
  }
336
- const router = new EntryInputRouter(structArgName, dataSchema, proxyEntries);
337
- argAliases.push([firstParam.name, snip(firstParam.name, router, "argument")]);
332
+ const router = new EntryInputRouter(structArg?.access, proxyEntries);
333
+ argAccess[firstParam.name] = () => snip("N/A", router, "argument");
338
334
  } else for (const a of positionalArgs) {
339
335
  const argName = this.makeNameValid(`_arg_${a.schemaKey}`);
340
- args.push(snip(argName, a.type, "argument"));
341
- pendingHeaderEntries.push({
342
- argName,
343
- header: `${getAttributesString(a.type)}${argName}: ${this.resolve(undecorate(a.type)).value}`
344
- });
336
+ const arg = createArgument(argName, a.type);
337
+ args.push(arg);
338
+ argAccess[argName] = arg.access;
345
339
  }
346
340
  } else for (const [i, argType] of options.argTypes.entries()) {
347
341
  const astParam = options.params[i];
348
342
  const origin = isPtr(argType) ? argType.addressSpace === "storage" ? argType.access === "read" ? "readonly" : "mutable" : argType.addressSpace : "argument";
349
343
  switch (astParam?.type) {
350
344
  case FuncParameterType.identifier: {
351
- const rawName = astParam.name;
352
- const snippet = snip(this.makeNameValid(rawName), argType, origin);
353
- args.push(snippet);
354
- if (snippet.value !== rawName) argAliases.push([rawName, snippet]);
345
+ const arg = createArgument(this.makeNameValid(astParam.name), argType, origin);
346
+ args.push(arg);
347
+ argAccess[astParam.name] = arg.access;
355
348
  break;
356
349
  }
357
350
  case FuncParameterType.destructuredObject: {
358
- const objSnippet = snip(`_arg_${i}`, argType, origin);
359
- args.push(objSnippet);
360
- argAliases.push(...astParam.props.map(({ name, alias }) => [alias, accessProp(objSnippet, name)]));
351
+ const objArg = createArgument(this.makeNameValid(`_arg_${i}`), argType, origin);
352
+ args.push(objArg);
353
+ for (const { name, alias } of astParam.props) argAccess[alias] = createArgumentPropAccess(objArg.access, name);
361
354
  break;
362
355
  }
363
- case void 0: if (!(argType instanceof AutoStruct)) args.push(snip(`_arg_${i}`, argType, origin));
356
+ case void 0: if (!(argType instanceof AutoStruct)) args.push({
357
+ name: this.makeNameValid(`_arg_${i}`),
358
+ access: () => {
359
+ throw new Error(`Unreachable: Accessing an argument that wasn't named in the function signature`);
360
+ },
361
+ decoratedType: argType,
362
+ used: false
363
+ });
364
364
  }
365
365
  }
366
- const scope = this._itemStateStack.pushFunctionScope(options.functionType, args, Object.fromEntries(argAliases), options.returnType, options.externalMap);
366
+ const scope = this._itemStateStack.pushFunctionScope(options.functionType, argAccess, options.returnType, options.externalMap);
367
367
  fnScopePushed = true;
368
- const body = this.gen.functionDefinition(options.body);
369
- let returnType = options.returnType;
370
- if (returnType instanceof AutoStruct) if (isWgslStruct(scope.reportedReturnTypes.values().next().value)) returnType = returnType.completeStruct;
371
- else returnType = void 0;
372
- if (!returnType) {
373
- const returnTypes = [...scope.reportedReturnTypes];
374
- if (returnTypes.length === 0) returnType = Void;
375
- else {
376
- const conversion = getBestConversion(returnTypes);
377
- if (conversion && !conversion.hasImplicitConversions) returnType = conversion.targetType;
368
+ let returnType;
369
+ const code = this.gen.functionDefinition({
370
+ functionType: options.functionType,
371
+ args,
372
+ body: options.body,
373
+ determineReturnType: () => {
374
+ if (returnType) return returnType;
375
+ returnType = options.returnType;
376
+ if (returnType instanceof AutoStruct) if (isWgslStruct(scope.reportedReturnTypes.values().next().value)) returnType = returnType.completeStruct;
377
+ else returnType = void 0;
378
+ if (!returnType) {
379
+ const returnTypes = [...scope.reportedReturnTypes];
380
+ if (returnTypes.length === 0) returnType = Void;
381
+ else {
382
+ const conversion = getBestConversion(returnTypes);
383
+ if (conversion && !conversion.hasImplicitConversions) returnType = conversion.targetType;
384
+ }
385
+ if (!returnType) throw new Error(`Expected function to have a single return type, got [${returnTypes.join(", ")}]. Cast explicitly to the desired type.`);
386
+ returnType = concretize(returnType);
387
+ if (options.functionType === "vertex" || options.functionType === "fragment") returnType = createIoSchema(returnType);
388
+ }
389
+ return returnType;
378
390
  }
379
- if (!returnType) throw new Error(`Expected function to have a single return type, got [${returnTypes.join(", ")}]. Cast explicitly to the desired type.`);
380
- returnType = concretize(returnType);
381
- if (options.functionType === "vertex" || options.functionType === "fragment") returnType = createIoSchema(returnType);
382
- }
383
- if (options.entryInput) return {
384
- head: `(${pendingHeaderEntries.filter(({ argName }) => isArgUsedInBody(argName, body)).map(({ header }) => header).join(", ")}) ${returnType.type !== "void" ? `-> ${getAttributesString(returnType)}${this.resolve(returnType).value} ` : ""}`,
385
- body,
386
- returnType
387
- };
391
+ });
392
+ if (!returnType) throw new Error(`Failed to determine return type`);
388
393
  return {
389
- head: resolveFunctionHeader(this, args, returnType),
390
- body,
394
+ code,
391
395
  returnType
392
396
  };
393
397
  } finally {
@@ -602,13 +606,6 @@ function resolve(item, options) {
602
606
  logResources: ctx.logResources
603
607
  };
604
608
  }
605
- function isArgUsedInBody(argName, body) {
606
- return (/* @__PURE__ */ new RegExp(`\\b${argName}\\b`)).test(body);
607
- }
608
- function resolveFunctionHeader(ctx, args, returnType) {
609
- const argList = args.map((arg) => `${arg.value}: ${ctx.resolve(arg.dataType).value}`).join(", ");
610
- return returnType.type !== "void" ? `(${argList}) -> ${getAttributesString(returnType)}${ctx.resolve(returnType).value} ` : `(${argList}) `;
611
- }
612
609
 
613
610
  //#endregion
614
611
  export { ResolutionCtxImpl, resolve };
@@ -1,5 +1,5 @@
1
1
  import { isNaturallyEphemeral, isPtr, isVec, isWgslArray, isWgslStruct } from "../data/wgslTypes.js";
2
- import { MatrixColumnsAccess, UnknownData, isDisarray } from "../data/dataTypes.js";
2
+ import { MatrixColumnsAccess, isDisarray } from "../data/dataTypes.js";
3
3
  import { isEphemeralSnippet, snip } from "../data/snippet.js";
4
4
  import { isKnownAtComptime } from "../types.js";
5
5
  import { stitch } from "../core/resolve/stitch.js";
@@ -37,7 +37,7 @@ function accessIndex(target, indexArg) {
37
37
  return snip(stitch`${target.value.matrix}[${index}]`, propType, target.origin);
38
38
  }
39
39
  if (target.dataType.type in indexableTypeToResult) throw new Error("The only way of accessing matrix elements in TypeGPU functions is through the 'columns' property.");
40
- if (isKnownAtComptime(target) && isKnownAtComptime(index) || target.dataType === UnknownData) return coerceToSnippet(target.value[index.value]);
40
+ if (isKnownAtComptime(target) && isKnownAtComptime(index)) return coerceToSnippet(target.value[index.value]);
41
41
  if (isWgslStruct(target.dataType) && isKnownAtComptime(index) && typeof index.value === "string") return accessProp(target, index.value);
42
42
  }
43
43
 
@@ -1,7 +1,7 @@
1
1
  import { $gpuCallable } from "../shared/symbols.js";
2
2
  import { isMat, isNaturallyEphemeral, isPtr, isVec, isWgslArray, isWgslStruct } from "../data/wgslTypes.js";
3
3
  import { InfixDispatch, MatrixColumnsAccess, UnknownData, isUnstruct, undecorate } from "../data/dataTypes.js";
4
- import { isEphemeralSnippet, snip } from "../data/snippet.js";
4
+ import { isEphemeralSnippet, isSnippet, snip } from "../data/snippet.js";
5
5
  import { isKnownAtComptime } from "../types.js";
6
6
  import { stitch } from "../core/resolve/stitch.js";
7
7
  import { derefSnippet } from "../data/ref.js";
@@ -92,7 +92,12 @@ function accessProp(target, propName) {
92
92
  if (!result) return;
93
93
  return snip(stitch`${target}.${result.prop}`, result.type, "argument");
94
94
  }
95
- if (target.dataType instanceof EntryInputRouter) return target.dataType.accessProp(propName);
95
+ if (target.dataType instanceof EntryInputRouter) {
96
+ const result = target.dataType.accessProp(propName);
97
+ if (isSnippet(result)) return result;
98
+ if (result) return accessProp(result.target, result.prop);
99
+ return;
100
+ }
96
101
  if (isPtr(target.dataType)) {
97
102
  const derefed = derefSnippet(target);
98
103
  if (propName === "$") return derefed;
@@ -1,10 +1,12 @@
1
1
  import { $internal } from "../../shared/symbols.js";
2
2
  import { Void } from "../../data/wgslTypes.js";
3
- import { UnknownData } from "../../data/dataTypes.js";
3
+ import { UnknownData, unptr } from "../../data/dataTypes.js";
4
4
  import { snip } from "../../data/snippet.js";
5
+ import { invariant } from "../../errors.js";
5
6
  import { stitch } from "../../core/resolve/stitch.js";
7
+ import { convertToCommonType } from "../conversion.js";
6
8
  import { u32 } from "../../data/numeric.js";
7
- import { concretizeSnippets } from "../generationHelpers.js";
9
+ import { concretizeSnippet } from "../generationHelpers.js";
8
10
  import { struct } from "../../data/struct.js";
9
11
  import { shaderStageSlot } from "../../core/slot/internalSlots.js";
10
12
  import { arrayOf } from "../../data/array.js";
@@ -61,16 +63,21 @@ var LogGeneratorImpl = class {
61
63
  console.warn(`Unsupported log method '${op}'.`);
62
64
  return fallbackSnippet;
63
65
  }
64
- const concreteArgs = concretizeSnippets(args);
65
66
  const id = this.#firstUnusedId++;
66
- const nonStringArgs = concreteArgs.filter((e) => e.dataType !== UnknownData);
67
- const logFn = createLoggingFunction(id, nonStringArgs.map((e) => e.dataType), this.#dataBuffer, this.#indexBuffer, this.#options);
68
- const argTypes = concreteArgs.map((e) => e.dataType === UnknownData ? e.value : e.dataType);
67
+ const concreteArgsWithStrings = args.map((arg) => {
68
+ if (arg.dataType === UnknownData) return arg;
69
+ const converted = convertToCommonType(ctx, [arg], [unptr(arg.dataType)])?.[0];
70
+ invariant(converted, `Internal error. Expected type ${arg.dataType} to be convertible to ${unptr(arg.dataType)}`);
71
+ return converted;
72
+ }).map(concretizeSnippet);
73
+ const concreteArgs = concreteArgsWithStrings.filter((arg) => arg.dataType !== UnknownData);
74
+ const logFn = createLoggingFunction(id, concreteArgs.map((e) => e.dataType), this.#dataBuffer, this.#indexBuffer, this.#options);
75
+ const functionSnippet = snip(stitch`${ctx.resolve(logFn).value}(${concreteArgs})`, Void, "runtime");
69
76
  this.#logIdToMeta.set(id, {
70
77
  op,
71
- argTypes
78
+ argTypes: concreteArgsWithStrings.map((e) => e?.dataType === UnknownData ? e?.value : e?.dataType)
72
79
  });
73
- return snip(stitch`${ctx.resolve(logFn).value}(${nonStringArgs})`, Void, "runtime");
80
+ return functionSnippet;
74
81
  }
75
82
  get logResources() {
76
83
  return this.#firstUnusedId === 1 ? void 0 : {
@@ -90,14 +90,19 @@ function getImplicitConversionRank(src, dest) {
90
90
  };
91
91
  }
92
92
  }
93
+ if ((trueSrc.type === "u32" || trueSrc.type === "i32") && trueDst.type === "abstractFloat") return {
94
+ rank: 1,
95
+ action: "cast",
96
+ targetType: trueDst.concretized
97
+ };
93
98
  if (trueSrc.type === "abstractFloat") {
94
- if (trueDst.type === "u32") return {
99
+ if (trueDst.type === "i32") return {
95
100
  rank: 2,
96
101
  action: "cast",
97
102
  targetType: trueDst
98
103
  };
99
- if (trueDst.type === "i32") return {
100
- rank: 1,
104
+ if (trueDst.type === "u32") return {
105
+ rank: 3,
101
106
  action: "cast",
102
107
  targetType: trueDst
103
108
  };
@@ -113,6 +118,10 @@ function getConversionRank(src, dest, allowImplicit) {
113
118
  function findBestType(types, uniqueTypes, allowImplicit) {
114
119
  let bestResult;
115
120
  for (const targetType of uniqueTypes) {
121
+ /**
122
+ * The type we end up converting to. Will be different than `targetType` if `targetType === abstractFloat`
123
+ */
124
+ let destType = targetType;
116
125
  const details = [];
117
126
  let sum = 0;
118
127
  for (const sourceType of types) {
@@ -120,9 +129,10 @@ function findBestType(types, uniqueTypes, allowImplicit) {
120
129
  sum += conversion.rank;
121
130
  if (conversion.rank === Number.POSITIVE_INFINITY) break;
122
131
  details.push(conversion);
132
+ if (conversion.action === "cast") destType = conversion.targetType;
123
133
  }
124
134
  if (sum < (bestResult?.sum ?? Number.POSITIVE_INFINITY)) bestResult = {
125
- type: targetType,
135
+ type: destType,
126
136
  details,
127
137
  sum
128
138
  };
@@ -168,7 +178,7 @@ function convertToCommonType(ctx, values, restrictTo, verbose = true) {
168
178
  if (DEV && Array.isArray(restrictTo) && restrictTo.length === 0) console.warn("convertToCommonType was called with an empty restrictTo array, which prevents any conversions from being made. If you intend to allow all conversions, pass undefined instead. If this was intended call the function conditionally since the result will always be undefined.");
169
179
  const conversion = getBestConversion(types, restrictTo);
170
180
  if (!conversion) return;
171
- if ((TEST || DEV) && verbose && conversion.hasImplicitConversions) console.warn(`Implicit conversions from [\n${values.map((v) => ` ${v.value}: ${safeStringify(v.dataType)}`).join(",\n")}\n] to ${conversion.targetType.type} are supported, but not recommended.
181
+ if ((TEST || DEV) && verbose && conversion.hasImplicitConversions) console.warn(`Implicit conversions from [\n${values.map((v) => ` ${ctx.resolveSnippet(v).value}: ${safeStringify(v.dataType)}`).join(",\n")}\n] to ${conversion.targetType.type} are supported, but not recommended.
172
182
  Consider using explicit conversions instead.`);
173
183
  return values.map((value, index) => {
174
184
  const action = conversion.actions[index];
@@ -33,12 +33,20 @@ function getElementType(elementSnippet, iterableSnippet) {
33
33
  }
34
34
  function getRangeSnippets(ctx, iterableSnippet, unroll = false) {
35
35
  const { value, dataType } = iterableSnippet;
36
- if (isTgpuRange(value)) return {
37
- start: snip(value.start, i32, "constant"),
38
- end: snip(value.end, i32, "constant"),
39
- step: snip(value.step, i32, "constant"),
40
- comparison: value.step < 0 ? ">" : "<"
41
- };
36
+ if (isTgpuRange(value)) {
37
+ const { start, end, step } = value;
38
+ const dataType$1 = [
39
+ start,
40
+ end,
41
+ step
42
+ ].every((v) => v >= 0) ? u32 : i32;
43
+ return {
44
+ start: snip(start, dataType$1, "constant"),
45
+ end: snip(end, dataType$1, "constant"),
46
+ step: snip(step, dataType$1, "constant"),
47
+ comparison: step < 0 ? ">" : "<"
48
+ };
49
+ }
42
50
  if (!unroll && isEphemeralSnippet(iterableSnippet)) throw new Error(`\`for ... of ...\` loops only support std.range or iterables stored in variables.
43
51
  -----
44
52
  You can wrap iterable with \`tgpu.unroll(...)\`. If iterable is known at comptime, the loop will be unrolled.
@@ -25,9 +25,6 @@ function concretize(type) {
25
25
  function concretizeSnippet(snippet) {
26
26
  return snip(snippet.value, concretize(snippet.dataType), snippet.origin);
27
27
  }
28
- function concretizeSnippets(args) {
29
- return args.map(concretizeSnippet);
30
- }
31
28
  function coerceToSnippet(value) {
32
29
  if (isSnippet(value)) return value;
33
30
  if (isRef(value)) throw new Error("Cannot use refs (d.ref(...)) from the outer scope.");
@@ -66,4 +63,4 @@ var ArrayExpression = class {
66
63
  };
67
64
 
68
65
  //#endregion
69
- export { ArrayExpression, coerceToSnippet, concretize, concretizeSnippets, numericLiteralToSnippet };
66
+ export { ArrayExpression, coerceToSnippet, concretize, concretizeSnippet, numericLiteralToSnippet };
@@ -1,8 +1,7 @@
1
1
  import { ResolvedSnippet, Snippet } from "../data/snippet.js";
2
2
  import { GenerationCtx } from "./generationHelpers.js";
3
- import "./shaderGenerator_members.js";
3
+ import { FunctionDefinitionOptions } from "./shaderGenerator_members.js";
4
4
  import { BaseData } from "../data/wgslTypes.js";
5
- import { Block } from "tinyest";
6
5
 
7
6
  //#region src/tgsl/shaderGenerator.d.ts
8
7
 
@@ -14,7 +13,7 @@ import { Block } from "tinyest";
14
13
  */
15
14
  interface ShaderGenerator {
16
15
  initGenerator(ctx: GenerationCtx): void;
17
- functionDefinition(body: Block): string;
16
+ functionDefinition(options: FunctionDefinitionOptions): string;
18
17
  typeInstantiation(schema: BaseData, args: readonly Snippet[]): ResolvedSnippet;
19
18
  typeAnnotation(schema: BaseData): string;
20
19
  }
@@ -1,2 +1,15 @@
1
- import { ResolutionCtx } from "../types.js";
2
- import { UnknownData } from "../data/dataTypes.js";
1
+ import { Origin, Snippet } from "../data/snippet.js";
2
+ import { FunctionArgument, ResolutionCtx, TgpuShaderStage } from "../types.js";
3
+ import { BaseData } from "../data/wgslTypes.js";
4
+ import { UnknownData } from "../data/dataTypes.js";
5
+ import { Block } from "tinyest";
6
+
7
+ //#region src/tgsl/shaderGenerator_members.d.ts
8
+ interface FunctionDefinitionOptions {
9
+ readonly functionType: 'normal' | TgpuShaderStage;
10
+ readonly args: readonly FunctionArgument[];
11
+ readonly body: Block;
12
+ determineReturnType(): BaseData;
13
+ }
14
+ //#endregion
15
+ export { FunctionDefinitionOptions };
@@ -1,5 +1,6 @@
1
1
  import { Origin, ResolvedSnippet, Snippet } from "../data/snippet.js";
2
2
  import { GenerationCtx } from "./generationHelpers.js";
3
+ import { FunctionDefinitionOptions } from "./shaderGenerator_members.js";
3
4
  import { ShaderGenerator } from "./shaderGenerator.js";
4
5
  import { BaseData, StorableData } from "../data/wgslTypes.js";
5
6
  import { UnknownData } from "../data/dataTypes.js";
@@ -22,7 +23,7 @@ declare class WgslGenerator implements ShaderGenerator {
22
23
  */
23
24
  _typedExpression(expression: tinyest.Expression, expectedType: BaseData | BaseData[]): Snippet;
24
25
  _expression(expression: tinyest.Expression): Snippet;
25
- functionDefinition(body: tinyest.Block): string;
26
+ functionDefinition(options: FunctionDefinitionOptions): string;
26
27
  /**
27
28
  * Generates a WGSL type string for the given data type, and adds necessary
28
29
  * definitions to the shader preamble. This shouldn't be called directly, only
@@ -30,6 +31,7 @@ declare class WgslGenerator implements ShaderGenerator {
30
31
  */
31
32
  typeAnnotation(data: BaseData): string;
32
33
  typeInstantiation(schema: BaseData, args: readonly Snippet[]): ResolvedSnippet;
34
+ _return(statement: tinyest.Return): string;
33
35
  _statement(statement: tinyest.Statement): string;
34
36
  }
35
37
  //#endregion
@@ -13,6 +13,7 @@ import { convertStructValues, convertToCommonType, tryConvertSnippet } from "./c
13
13
  import { bool, i32, u32 } from "../data/numeric.js";
14
14
  import { ArrayExpression, coerceToSnippet, concretize, numericLiteralToSnippet } from "./generationHelpers.js";
15
15
  import { vec2u, vec3u, vec4u } from "../data/vector.js";
16
+ import { getAttributesString } from "../data/attributes.js";
16
17
  import { AutoStruct } from "../data/autoStruct.js";
17
18
  import { add, div, mul, neg, sub } from "../std/operators.js";
18
19
  import { accessProp } from "./accessProp.js";
@@ -292,7 +293,7 @@ ${this.ctx.pre}}`;
292
293
  if (!accessed) {
293
294
  const targetStr = this.ctx.resolve(target.value, target.dataType).value;
294
295
  const propertyStr = this.ctx.resolve(property.value, property.dataType).value;
295
- throw new Error(`Unable to index value ${targetStr} of unknown type with index ${propertyStr}. If the value is an array, to address this, consider one of the following approaches: (1) declare the array using 'tgpu.const', (2) store the array in a buffer, or (3) define the array within the GPU function scope.`);
296
+ throw new Error(`Index access '${targetStr}[${propertyStr}]' is invalid. If the value is an array, to address this, consider one of the following approaches: (1) declare the array using 'tgpu.const', (2) store the array in a buffer, or (3) define the array within the GPU function scope.`);
296
297
  }
297
298
  return accessed;
298
299
  }
@@ -422,8 +423,13 @@ ${this.ctx.pre}}`;
422
423
  if (expression[0] === NODE.preUpdate) throw new Error("Cannot use pre-updates in TypeGPU functions.");
423
424
  assertExhaustive(expression);
424
425
  }
425
- functionDefinition(body) {
426
- return this._block(body);
426
+ functionDefinition(options) {
427
+ const body = this._block(options.body);
428
+ const returnType = options.determineReturnType();
429
+ const argList = options.args.filter((arg) => arg.used || options.functionType === "normal").map((arg) => {
430
+ return `${getAttributesString(arg.decoratedType)}${arg.name}: ${this.ctx.resolve(arg.decoratedType).value}`;
431
+ }).join(", ");
432
+ return `${returnType.type !== "void" ? `(${argList}) -> ${getAttributesString(returnType)}${this.ctx.resolve(returnType).value} ` : `(${argList}) `}${body}`;
427
433
  }
428
434
  /**
429
435
  * Generates a WGSL type string for the given data type, and adds necessary
@@ -437,6 +443,28 @@ ${this.ctx.pre}}`;
437
443
  if (args.length === 1 && args[0]?.dataType === schema) return snip(stitch`${args[0]}`, schema, fallthroughCopyOrigin(args[0].origin));
438
444
  return snip(stitch`${this.ctx.resolve(schema).value}(${args})`, schema, "runtime");
439
445
  }
446
+ _return(statement) {
447
+ const returnNode = statement[1];
448
+ if (returnNode !== void 0) {
449
+ const expectedReturnType = this.ctx.topFunctionReturnType;
450
+ let returnSnippet = expectedReturnType ? this._typedExpression(returnNode, expectedReturnType) : this._expression(returnNode);
451
+ if (returnSnippet.value instanceof RefOperator) throw new WgslTypeError(stitch`Cannot return references, returning '${returnSnippet.value.snippet}'`);
452
+ if (returnSnippet.origin === "argument" && !isNaturallyEphemeral(returnSnippet.dataType) && this.ctx.topFunctionScope?.functionType === "normal") throw new WgslTypeError(stitch`Cannot return references to arguments, returning '${returnSnippet}'. Copy the argument before returning it.`);
453
+ if (!expectedReturnType && !isEphemeralSnippet(returnSnippet) && returnSnippet.origin !== "this-function") {
454
+ const str = this.ctx.resolve(returnSnippet.value, returnSnippet.dataType).value;
455
+ const typeStr = this.ctx.resolve(unptr(returnSnippet.dataType)).value;
456
+ throw new WgslTypeError(`'return ${str};' is invalid, cannot return references.
457
+ -----
458
+ Try 'return ${typeStr}(${str});' instead.
459
+ -----`);
460
+ }
461
+ returnSnippet = tryConvertSnippet(this.ctx, returnSnippet, unptr(returnSnippet.dataType), false);
462
+ invariant(returnSnippet.dataType !== UnknownData, "Return type should be known");
463
+ this.ctx.reportReturnType(returnSnippet.dataType);
464
+ return stitch`${this.ctx.pre}return ${returnSnippet};`;
465
+ }
466
+ return `${this.ctx.pre}return;`;
467
+ }
440
468
  _statement(statement) {
441
469
  if (typeof statement === "string") {
442
470
  const id = this._identifier(statement);
@@ -444,28 +472,7 @@ ${this.ctx.pre}}`;
444
472
  return resolved$1 ? `${this.ctx.pre}${resolved$1};` : "";
445
473
  }
446
474
  if (typeof statement === "boolean") return `${this.ctx.pre}${statement ? "true" : "false"};`;
447
- if (statement[0] === NODE.return) {
448
- const returnNode = statement[1];
449
- if (returnNode !== void 0) {
450
- const expectedReturnType = this.ctx.topFunctionReturnType;
451
- let returnSnippet = expectedReturnType ? this._typedExpression(returnNode, expectedReturnType) : this._expression(returnNode);
452
- if (returnSnippet.value instanceof RefOperator) throw new WgslTypeError(stitch`Cannot return references, returning '${returnSnippet.value.snippet}'`);
453
- if (returnSnippet.origin === "argument" && !isNaturallyEphemeral(returnSnippet.dataType) && this.ctx.topFunctionScope?.functionType === "normal") throw new WgslTypeError(stitch`Cannot return references to arguments, returning '${returnSnippet}'. Copy the argument before returning it.`);
454
- if (!expectedReturnType && !isEphemeralSnippet(returnSnippet) && returnSnippet.origin !== "this-function") {
455
- const str = this.ctx.resolve(returnSnippet.value, returnSnippet.dataType).value;
456
- const typeStr = this.ctx.resolve(unptr(returnSnippet.dataType)).value;
457
- throw new WgslTypeError(`'return ${str};' is invalid, cannot return references.
458
- -----
459
- Try 'return ${typeStr}(${str});' instead.
460
- -----`);
461
- }
462
- returnSnippet = tryConvertSnippet(this.ctx, returnSnippet, unptr(returnSnippet.dataType), false);
463
- invariant(returnSnippet.dataType !== UnknownData, "Return type should be known");
464
- this.ctx.reportReturnType(returnSnippet.dataType);
465
- return stitch`${this.ctx.pre}return ${returnSnippet};`;
466
- }
467
- return `${this.ctx.pre}return;`;
468
- }
475
+ if (statement[0] === NODE.return) return this._return(statement);
469
476
  if (statement[0] === NODE.if) {
470
477
  const [_, condNode, consNode, altNode] = statement;
471
478
  const condition = this._typedExpression(condNode, bool);
@@ -600,7 +607,7 @@ ${this.ctx.pre}else ${alternate}`;
600
607
  const index = this.ctx.makeNameValid("i");
601
608
  const forHeaderStr = stitch`${this.ctx.pre}for (var ${index} = ${range.start}; ${index} ${range.comparison} ${range.end}; ${index} += ${range.step})`;
602
609
  let bodyStr = "";
603
- if (isTgpuRange(iterableSnippet.value)) bodyStr = this._block(blockified, { [originalLoopVarName]: snip(index, u32, "runtime") });
610
+ if (isTgpuRange(iterableSnippet.value)) bodyStr = this._block(blockified, { [originalLoopVarName]: snip(index, range.start.dataType, "runtime") });
604
611
  else {
605
612
  this.ctx.indent();
606
613
  ctxIndent = true;
package/types.d.ts CHANGED
@@ -49,11 +49,17 @@ type ItemLayer = {
49
49
  type: 'item';
50
50
  usedSlots: Set<TgpuSlot<unknown>>;
51
51
  };
52
+ type FunctionArgumentAccess = () => Snippet | undefined;
53
+ interface FunctionArgument {
54
+ name: string;
55
+ access: FunctionArgumentAccess;
56
+ decoratedType: BaseData;
57
+ used: boolean;
58
+ }
52
59
  type FunctionScopeLayer = {
53
60
  type: 'functionScope';
54
61
  functionType: 'normal' | 'compute' | 'vertex' | 'fragment';
55
- args: Snippet[];
56
- argAliases: Record<string, Snippet>;
62
+ argAccess: Record<string, FunctionArgumentAccess>;
57
63
  externalMap: Record<string, unknown>;
58
64
  /**
59
65
  * The return type of the function. If undefined, the type should be inferred
@@ -81,7 +87,7 @@ interface ItemStateStack {
81
87
  readonly topFunctionScope: FunctionScopeLayer | undefined;
82
88
  pushItem(): void;
83
89
  pushSlotBindings(pairs: SlotValuePair[]): void;
84
- pushFunctionScope(functionType: 'normal' | TgpuShaderStage, args: Snippet[], argAliases: Record<string, Snippet>,
90
+ pushFunctionScope(functionType: 'normal' | TgpuShaderStage, argAccess: Record<string, FunctionArgumentAccess>,
85
91
  /**
86
92
  * The return type of the function. If undefined, the type should be inferred
87
93
  * from the implementation (relevant for shellless functions).
@@ -217,8 +223,7 @@ interface ResolutionCtx {
217
223
  */
218
224
  resolveSnippet(snippet: Snippet): ResolvedSnippet;
219
225
  fnToWgsl(options: FnToWgslOptions): {
220
- head: Wgsl;
221
- body: Wgsl;
226
+ code: string;
222
227
  returnType: BaseData;
223
228
  };
224
229
  withVaryingLocations<T>(locations: Record<string, number>, callback: () => T): T;
@@ -261,4 +266,4 @@ type AnyFn = (...args: never[]) => unknown;
261
266
  type DualFn<T extends AnyFn> = T & GPUCallable<Parameters<T>>;
262
267
  type BindableBufferUsage = 'uniform' | 'readonly' | 'mutable';
263
268
  //#endregion
264
- export { BindableBufferUsage, DualFn, FunctionScopeLayer, GPUCallable, ResolutionCtx, ResolvableObject, SelfResolvable, TgpuShaderStage, Wgsl, WithCast };
269
+ export { BindableBufferUsage, DualFn, FunctionArgument, FunctionScopeLayer, GPUCallable, ResolutionCtx, ResolvableObject, SelfResolvable, TgpuShaderStage, Wgsl, WithCast };