typegpu 0.10.1 → 0.11.0-rc.1

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.
Files changed (273) hide show
  1. package/_virtual/_rolldown/runtime.js +13 -0
  2. package/builtin.d.ts +50 -0
  3. package/builtin.js +35 -0
  4. package/common/fullScreenTriangle.d.ts +22 -0
  5. package/common/fullScreenTriangle.js +34 -0
  6. package/common/index.d.ts +4 -4
  7. package/common/index.js +8 -7
  8. package/common/writeSoA.d.ts +16 -0
  9. package/common/writeSoA.js +90 -0
  10. package/core/buffer/buffer.d.ts +79 -0
  11. package/core/buffer/buffer.js +246 -0
  12. package/core/buffer/bufferShorthand.d.ts +48 -0
  13. package/core/buffer/bufferShorthand.js +53 -0
  14. package/core/buffer/bufferUsage.d.ts +43 -0
  15. package/core/buffer/bufferUsage.js +165 -0
  16. package/core/constant/tgpuConstant.d.ts +29 -0
  17. package/core/constant/tgpuConstant.js +68 -0
  18. package/core/declare/tgpuDeclare.d.ts +18 -0
  19. package/core/declare/tgpuDeclare.js +39 -0
  20. package/core/function/autoIO.d.ts +38 -0
  21. package/core/function/autoIO.js +85 -0
  22. package/core/function/comptime.d.ts +39 -0
  23. package/core/function/comptime.js +49 -0
  24. package/core/function/createCallableSchema.js +40 -0
  25. package/core/function/dualImpl.js +52 -0
  26. package/core/function/entryInputRouter.js +39 -0
  27. package/core/function/extractArgs.js +204 -0
  28. package/core/function/fnCore.js +90 -0
  29. package/core/function/fnTypes.d.ts +40 -0
  30. package/core/function/ioSchema.d.ts +10 -0
  31. package/core/function/ioSchema.js +51 -0
  32. package/core/function/shelllessImpl.d.ts +28 -0
  33. package/core/function/shelllessImpl.js +21 -0
  34. package/core/function/templateUtils.js +12 -0
  35. package/core/function/tgpuComputeFn.d.ts +48 -0
  36. package/core/function/tgpuComputeFn.js +55 -0
  37. package/core/function/tgpuFn.d.ts +52 -0
  38. package/core/function/tgpuFn.js +168 -0
  39. package/core/function/tgpuFragmentFn.d.ts +72 -0
  40. package/core/function/tgpuFragmentFn.js +63 -0
  41. package/core/function/tgpuVertexFn.d.ts +59 -0
  42. package/core/function/tgpuVertexFn.js +59 -0
  43. package/core/pipeline/applyPipelineState.js +35 -0
  44. package/core/pipeline/computePipeline.d.ts +54 -0
  45. package/core/pipeline/computePipeline.js +227 -0
  46. package/core/pipeline/connectAttachmentToShader.js +24 -0
  47. package/core/pipeline/connectTargetsToShader.js +27 -0
  48. package/core/pipeline/limitsOverflow.js +12 -0
  49. package/core/pipeline/pipelineUtils.js +29 -0
  50. package/core/pipeline/renderPipeline.d.ts +284 -0
  51. package/core/pipeline/renderPipeline.js +489 -0
  52. package/core/pipeline/timeable.d.ts +20 -0
  53. package/core/pipeline/timeable.js +55 -0
  54. package/core/pipeline/typeGuards.js +27 -0
  55. package/core/querySet/querySet.d.ts +20 -0
  56. package/core/querySet/querySet.js +104 -0
  57. package/core/rawCodeSnippet/tgpuRawCodeSnippet.d.ts +59 -0
  58. package/core/rawCodeSnippet/tgpuRawCodeSnippet.js +94 -0
  59. package/core/resolve/externals.d.ts +8 -0
  60. package/core/resolve/externals.js +56 -0
  61. package/core/resolve/namespace.d.ts +38 -0
  62. package/core/resolve/namespace.js +39 -0
  63. package/core/resolve/resolveData.js +144 -0
  64. package/core/resolve/stitch.js +23 -0
  65. package/core/resolve/tgpuResolve.d.ts +153 -0
  66. package/core/resolve/tgpuResolve.js +66 -0
  67. package/core/root/configurableImpl.js +17 -0
  68. package/core/root/init.d.ts +64 -0
  69. package/core/root/init.js +464 -0
  70. package/core/root/rootTypes.d.ts +642 -0
  71. package/core/sampler/sampler.d.ts +31 -0
  72. package/core/sampler/sampler.js +116 -0
  73. package/core/simulate/tgpuSimulate.d.ts +36 -0
  74. package/core/simulate/tgpuSimulate.js +74 -0
  75. package/core/slot/accessor.d.ts +9 -0
  76. package/core/slot/accessor.js +95 -0
  77. package/core/slot/internalSlots.js +5 -0
  78. package/core/slot/lazy.d.ts +6 -0
  79. package/core/slot/lazy.js +40 -0
  80. package/core/slot/slot.d.ts +6 -0
  81. package/core/slot/slot.js +39 -0
  82. package/core/slot/slotTypes.d.ts +92 -0
  83. package/core/slot/slotTypes.js +19 -0
  84. package/core/texture/externalTexture.d.ts +6 -0
  85. package/core/texture/externalTexture.js +47 -0
  86. package/core/texture/texture.d.ts +114 -0
  87. package/core/texture/texture.js +314 -0
  88. package/core/texture/textureFormats.d.ts +29 -0
  89. package/core/texture/textureFormats.js +97 -0
  90. package/core/texture/textureProps.d.ts +11 -0
  91. package/core/texture/textureUtils.js +222 -0
  92. package/core/texture/usageExtension.d.ts +21 -0
  93. package/core/texture/usageExtension.js +19 -0
  94. package/core/unroll/tgpuUnroll.d.ts +68 -0
  95. package/core/unroll/tgpuUnroll.js +94 -0
  96. package/core/valueProxyUtils.js +42 -0
  97. package/core/variable/tgpuVariable.d.ts +38 -0
  98. package/core/variable/tgpuVariable.js +99 -0
  99. package/core/vertexLayout/connectAttributesToShader.js +57 -0
  100. package/core/vertexLayout/vertexAttribute.d.ts +29 -0
  101. package/core/vertexLayout/vertexLayout.d.ts +19 -0
  102. package/core/vertexLayout/vertexLayout.js +103 -0
  103. package/data/alignIO.js +14 -0
  104. package/data/alignmentOf.d.ts +9 -0
  105. package/data/alignmentOf.js +86 -0
  106. package/data/array.d.ts +26 -0
  107. package/data/array.js +46 -0
  108. package/data/atomic.d.ts +15 -0
  109. package/data/atomic.js +24 -0
  110. package/data/attributes.d.ts +121 -0
  111. package/data/attributes.js +145 -0
  112. package/data/autoStruct.d.ts +1 -0
  113. package/data/autoStruct.js +81 -0
  114. package/data/compiledIO.js +228 -0
  115. package/data/dataIO.js +556 -0
  116. package/data/dataTypes.d.ts +115 -0
  117. package/data/dataTypes.js +100 -0
  118. package/data/deepEqual.d.ts +25 -0
  119. package/data/deepEqual.js +56 -0
  120. package/data/disarray.d.ts +32 -0
  121. package/data/disarray.js +50 -0
  122. package/data/getLongestContiguousPrefix.d.ts +9 -0
  123. package/data/getLongestContiguousPrefix.js +13 -0
  124. package/data/index.d.ts +26 -4
  125. package/data/index.js +36 -9
  126. package/data/instanceToSchema.d.ts +33 -0
  127. package/data/isContiguous.d.ts +9 -0
  128. package/data/isContiguous.js +13 -0
  129. package/data/matrix.d.ts +124 -0
  130. package/data/matrix.js +531 -0
  131. package/data/numberOps.js +23 -0
  132. package/data/numeric.d.ts +81 -0
  133. package/data/numeric.js +221 -0
  134. package/data/offsetUtils.d.ts +33 -0
  135. package/data/offsetUtils.js +165 -0
  136. package/data/offsets.js +34 -0
  137. package/data/partialIO.js +113 -0
  138. package/data/ptr.d.ts +11 -0
  139. package/data/ptr.js +44 -0
  140. package/data/ref.d.ts +34 -0
  141. package/data/ref.js +94 -0
  142. package/data/sampler.d.ts +107 -0
  143. package/data/sampler.js +24 -0
  144. package/data/schemaCallWrapper.js +30 -0
  145. package/data/schemaMemoryLayout.js +198 -0
  146. package/data/sizeOf.d.ts +9 -0
  147. package/data/sizeOf.js +13 -0
  148. package/data/snippet.d.ts +26 -0
  149. package/data/snippet.js +70 -0
  150. package/data/struct.d.ts +17 -0
  151. package/data/struct.js +44 -0
  152. package/data/texture.d.ts +292 -0
  153. package/{texture-BagDrrks.js → data/texture.js} +6 -5
  154. package/data/unstruct.d.ts +24 -0
  155. package/data/unstruct.js +41 -0
  156. package/data/vector.d.ts +191 -0
  157. package/data/vector.js +239 -0
  158. package/data/vectorImpl.js +515 -0
  159. package/data/vectorOps.js +681 -0
  160. package/data/vertexFormatData.d.ts +190 -0
  161. package/data/vertexFormatData.js +109 -0
  162. package/data/wgslTypes.d.ts +924 -0
  163. package/data/wgslTypes.js +222 -0
  164. package/errors.d.ts +44 -0
  165. package/errors.js +131 -0
  166. package/execMode.js +49 -0
  167. package/extension.d.ts +11 -0
  168. package/extension.js +16 -0
  169. package/getGPUValue.js +7 -0
  170. package/index.d.ts +42 -243
  171. package/index.js +21 -6320
  172. package/indexNamedExports.d.ts +40 -0
  173. package/mathUtils.js +12 -0
  174. package/memo.js +22 -0
  175. package/nameRegistry.d.ts +30 -0
  176. package/nameRegistry.js +447 -0
  177. package/package.js +4 -0
  178. package/package.json +26 -26
  179. package/resolutionCtx.d.ts +19 -0
  180. package/resolutionCtx.js +612 -0
  181. package/shared/env.js +12 -0
  182. package/shared/generators.js +13 -0
  183. package/shared/meta.d.ts +39 -0
  184. package/shared/meta.js +61 -0
  185. package/shared/repr.d.ts +138 -0
  186. package/shared/stringify.js +20 -0
  187. package/shared/symbols.d.ts +70 -0
  188. package/shared/symbols.js +48 -0
  189. package/shared/utilityTypes.d.ts +33 -0
  190. package/shared/utilityTypes.js +6 -0
  191. package/shared/vertexFormat.d.ts +70 -0
  192. package/shared/vertexFormat.js +63 -0
  193. package/std/array.d.ts +7 -0
  194. package/std/array.js +25 -0
  195. package/std/atomic.d.ts +19 -0
  196. package/std/atomic.js +111 -0
  197. package/std/bitcast.d.ts +10 -0
  198. package/std/bitcast.js +41 -0
  199. package/std/boolean.d.ts +141 -0
  200. package/std/boolean.js +299 -0
  201. package/std/derivative.d.ts +16 -0
  202. package/std/derivative.js +87 -0
  203. package/std/discard.d.ts +6 -0
  204. package/std/discard.js +14 -0
  205. package/std/extensions.d.ts +6 -0
  206. package/std/extensions.js +12 -0
  207. package/std/index.d.ts +17 -4
  208. package/std/index.js +21 -7
  209. package/std/matrix.d.ts +41 -0
  210. package/std/matrix.js +85 -0
  211. package/std/numeric.d.ts +200 -0
  212. package/std/numeric.js +845 -0
  213. package/std/operators.d.ts +56 -0
  214. package/std/operators.js +227 -0
  215. package/std/packing.d.ts +26 -0
  216. package/std/packing.js +84 -0
  217. package/std/range.d.ts +24 -0
  218. package/std/range.js +38 -0
  219. package/std/subgroup.d.ts +47 -0
  220. package/std/subgroup.js +218 -0
  221. package/std/texture.d.ts +117 -0
  222. package/std/texture.js +207 -0
  223. package/tgpu.js +42 -0
  224. package/tgpuBindGroupLayout.d.ts +161 -0
  225. package/tgpuBindGroupLayout.js +272 -0
  226. package/tgpuUnstable.d.ts +48 -0
  227. package/tgpuUnstable.js +64 -0
  228. package/tgsl/accessIndex.js +43 -0
  229. package/tgsl/accessProp.js +115 -0
  230. package/tgsl/consoleLog/deserializers.js +115 -0
  231. package/tgsl/consoleLog/logGenerator.js +84 -0
  232. package/tgsl/consoleLog/serializers.js +223 -0
  233. package/tgsl/consoleLog/types.d.ts +52 -0
  234. package/tgsl/consoleLog/types.js +11 -0
  235. package/tgsl/conversion.js +198 -0
  236. package/tgsl/forOfUtils.js +71 -0
  237. package/tgsl/generationHelpers.d.ts +37 -0
  238. package/tgsl/generationHelpers.js +67 -0
  239. package/tgsl/math.js +43 -0
  240. package/tgsl/shaderGenerator.d.ts +20 -0
  241. package/tgsl/shaderGenerator_members.d.ts +2 -0
  242. package/tgsl/shaderGenerator_members.js +6 -0
  243. package/tgsl/shellless.d.ts +11 -0
  244. package/tgsl/shellless.js +46 -0
  245. package/tgsl/wgslGenerator.d.ts +36 -0
  246. package/tgsl/wgslGenerator.js +639 -0
  247. package/types.d.ts +265 -0
  248. package/types.js +43 -0
  249. package/unwrapper.d.ts +27 -0
  250. package/wgslExtensions.d.ts +5 -0
  251. package/wgslExtensions.js +17 -0
  252. package/builtin-DdtWpk2t.js +0 -818
  253. package/builtin-DdtWpk2t.js.map +0 -1
  254. package/chunk-BYypO7fO.js +0 -18
  255. package/common/index.d.ts.map +0 -1
  256. package/common/index.js.map +0 -1
  257. package/data/index.d.ts.map +0 -1
  258. package/data/index.js.map +0 -1
  259. package/deepEqual-DQxK4vdp.js +0 -413
  260. package/deepEqual-DQxK4vdp.js.map +0 -1
  261. package/extensions-DIVuAfBM.js +0 -2032
  262. package/extensions-DIVuAfBM.js.map +0 -1
  263. package/fullScreenTriangle-CfFyQd_0.js +0 -543
  264. package/fullScreenTriangle-CfFyQd_0.js.map +0 -1
  265. package/index.d.ts.map +0 -1
  266. package/index.js.map +0 -1
  267. package/indexNamedExports-oL6tyaJ9.d.ts +0 -5697
  268. package/indexNamedExports-oL6tyaJ9.d.ts.map +0 -1
  269. package/operators-d-PMVTo7.js +0 -4158
  270. package/operators-d-PMVTo7.js.map +0 -1
  271. package/std/index.d.ts.map +0 -1
  272. package/std/index.js.map +0 -1
  273. package/texture-BagDrrks.js.map +0 -1
@@ -0,0 +1,49 @@
1
+ import { $getNameForward, $gpuCallable, $internal } from "../../shared/symbols.js";
2
+ import { setName } from "../../shared/meta.js";
3
+ import { WgslTypeError } from "../../errors.js";
4
+ import { isKnownAtComptime } from "../../types.js";
5
+ import { coerceToSnippet } from "../../tgsl/generationHelpers.js";
6
+ //#region src/core/function/comptime.ts
7
+ /**
8
+ * Creates a version of `func` that can called safely in a TypeGPU function to
9
+ * precompute and inject a value into the final shader code.
10
+ *
11
+ * Note how the function passed into `comptime` doesn't have to be marked with
12
+ * 'use gpu'. That's because the function doesn't execute on the GPU, it gets
13
+ * executed before the shader code gets sent to the GPU.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const color = tgpu.comptime((int: number) => {
18
+ * const r = (int >> 16) & 0xff;
19
+ * const g = (int >> 8) & 0xff;
20
+ * const b = int & 0xff;
21
+ * return d.vec3f(r / 255, g / 255, b / 255);
22
+ * });
23
+ *
24
+ * const material = (diffuse: d.v3f): d.v3f => {
25
+ * 'use gpu';
26
+ * const albedo = color(0xff00ff);
27
+ * return albedo.mul(diffuse);
28
+ * };
29
+ * ```
30
+ */
31
+ function comptime(func) {
32
+ const impl = ((...args) => {
33
+ return func(...args);
34
+ });
35
+ impl.toString = () => "comptime";
36
+ impl[$getNameForward] = func;
37
+ impl[$gpuCallable] = { call(_ctx, args) {
38
+ if (!args.every((s) => isKnownAtComptime(s))) throw new WgslTypeError(`Called comptime function with runtime-known values: ${args.filter((s) => !isKnownAtComptime(s)).map((s) => `'${s.value}'`).join(", ")}`);
39
+ return coerceToSnippet(func(...args.map((s) => s.value)));
40
+ } };
41
+ impl.$name = (label) => {
42
+ setName(func, label);
43
+ return impl;
44
+ };
45
+ Object.defineProperty(impl, $internal, { value: { isComptime: true } });
46
+ return impl;
47
+ }
48
+ //#endregion
49
+ export { comptime };
@@ -0,0 +1,40 @@
1
+ import { $gpuCallable } from "../../shared/symbols.js";
2
+ import { setName } from "../../shared/meta.js";
3
+ import { isPtr } from "../../data/wgslTypes.js";
4
+ import { snip } from "../../data/snippet.js";
5
+ import { NormalState, isKnownAtComptime } from "../../types.js";
6
+ import { tryConvertSnippet } from "../../tgsl/conversion.js";
7
+ //#region src/core/function/createCallableSchema.ts
8
+ function callableSchema(options) {
9
+ const impl = ((...args) => {
10
+ return options.normalImpl(...args);
11
+ });
12
+ setName(impl, options.name);
13
+ impl.toString = () => options.name;
14
+ impl[$gpuCallable] = {
15
+ get strictSignature() {},
16
+ call(ctx, args) {
17
+ const argTypes = options.argTypes(...args.map((s) => {
18
+ if (isPtr(s.dataType) && s.dataType.implicit) return s.dataType.inner;
19
+ return s.dataType;
20
+ }));
21
+ const converted = args.map((s, idx) => {
22
+ const argType = argTypes[idx];
23
+ if (!argType) throw new Error("Function called with invalid arguments");
24
+ return tryConvertSnippet(ctx, s, argType, false);
25
+ });
26
+ if (converted.every((s) => isKnownAtComptime(s))) {
27
+ ctx.pushMode(new NormalState());
28
+ try {
29
+ return snip(options.normalImpl(...converted.map((s) => s.value)), options.schema(), "constant");
30
+ } finally {
31
+ ctx.popMode("normal");
32
+ }
33
+ }
34
+ return options.codegenImpl(ctx, converted);
35
+ }
36
+ };
37
+ return impl;
38
+ }
39
+ //#endregion
40
+ export { callableSchema };
@@ -0,0 +1,52 @@
1
+ import { $gpuCallable } from "../../shared/symbols.js";
2
+ import { setName } from "../../shared/meta.js";
3
+ import { isPtr } from "../../data/wgslTypes.js";
4
+ import { snip } from "../../data/snippet.js";
5
+ import { NormalState, isKnownAtComptime } from "../../types.js";
6
+ import { tryConvertSnippet } from "../../tgsl/conversion.js";
7
+ import { concretize } from "../../tgsl/generationHelpers.js";
8
+ //#region src/core/function/dualImpl.ts
9
+ var MissingCpuImplError = class extends Error {
10
+ constructor(message) {
11
+ super(message);
12
+ this.name = this.constructor.name;
13
+ }
14
+ };
15
+ function dualImpl(options) {
16
+ const impl = ((...args) => {
17
+ if (typeof options.normalImpl === "string") throw new MissingCpuImplError(options.normalImpl);
18
+ return options.normalImpl(...args);
19
+ });
20
+ setName(impl, options.name);
21
+ impl.toString = () => options.name ?? "<unknown>";
22
+ impl[$gpuCallable] = {
23
+ get strictSignature() {
24
+ return typeof options.signature !== "function" ? options.signature : void 0;
25
+ },
26
+ call(ctx, args) {
27
+ const { argTypes, returnType } = typeof options.signature === "function" ? options.signature(...args.map((s) => {
28
+ if (isPtr(s.dataType) && s.dataType.implicit) return s.dataType.inner;
29
+ return s.dataType;
30
+ })) : options.signature;
31
+ const converted = args.map((s, idx) => {
32
+ const argType = argTypes[idx];
33
+ if (!argType) throw new Error("Function called with invalid arguments");
34
+ return tryConvertSnippet(ctx, s, argType, !options.ignoreImplicitCastWarning);
35
+ });
36
+ if (!options.noComptime && converted.every((s) => isKnownAtComptime(s)) && typeof options.normalImpl === "function") {
37
+ ctx.pushMode(new NormalState());
38
+ try {
39
+ return snip(options.normalImpl(...converted.map((s) => s.value)), returnType, "constant");
40
+ } catch (e) {
41
+ if (!(e instanceof MissingCpuImplError)) throw e;
42
+ } finally {
43
+ ctx.popMode("normal");
44
+ }
45
+ }
46
+ return snip(options.codegenImpl(ctx, converted), concretize(returnType), "runtime");
47
+ }
48
+ };
49
+ return impl;
50
+ }
51
+ //#endregion
52
+ export { MissingCpuImplError, dualImpl };
@@ -0,0 +1,39 @@
1
+ import { $internal } from "../../shared/symbols.js";
2
+ import { isWgslStruct } from "../../data/wgslTypes.js";
3
+ import { undecorate } from "../../data/dataTypes.js";
4
+ import { snip } from "../../data/snippet.js";
5
+ //#region src/core/function/entryInputRouter.ts
6
+ /**
7
+ * Routes `(input) => { input.x }` style property access to the correct WGSL
8
+ * expression: positional args get a direct snippet, struct fields get
9
+ * `structArgName.fieldName`.
10
+ */
11
+ var EntryInputRouter = class {
12
+ [$internal] = {};
13
+ type = "entry-input-router";
14
+ structArgName;
15
+ dataSchema;
16
+ /** Maps schemaKey → { WGSL arg name, type } */
17
+ positionalArgsMap;
18
+ constructor(structArgName, dataSchema, positionalArgs) {
19
+ this.structArgName = structArgName;
20
+ this.dataSchema = dataSchema;
21
+ this.positionalArgsMap = new Map(positionalArgs.map((a) => [a.schemaKey, {
22
+ argName: a.argName,
23
+ type: a.type
24
+ }]));
25
+ }
26
+ toString() {
27
+ return "entry-input-router";
28
+ }
29
+ accessProp(propName) {
30
+ const positionalEntry = this.positionalArgsMap.get(propName);
31
+ if (positionalEntry) return snip(positionalEntry.argName, positionalEntry.type, "argument");
32
+ if (this.dataSchema && isWgslStruct(this.dataSchema)) {
33
+ const propType = this.dataSchema.propTypes[propName];
34
+ if (propType) return snip(`${this.structArgName}.${propName}`, undecorate(propType), "argument");
35
+ }
36
+ }
37
+ };
38
+ //#endregion
39
+ export { EntryInputRouter };
@@ -0,0 +1,204 @@
1
+ //#region src/core/function/extractArgs.ts
2
+ /**
3
+ * Extracts info about arguments of a given WGSL function string.
4
+ * @example
5
+ * const code = `
6
+ * fn add(a: i32, @location(0) b: i32, c) -> i32 {
7
+ * return a + b + c;
8
+ * }`;
9
+ *
10
+ * extractArgs(code);
11
+ * // {
12
+ * // args: [
13
+ * // { identifier: 'a', attributes: [], type: 'i32' },
14
+ * // { identifier: 'b', attributes: ['@location(0)'], type: 'i32' },
15
+ * // { identifier: 'c', attributes: [], type: undefined }
16
+ * // ],
17
+ * // ret: { type: 'i32', attributes: [] },
18
+ * // range: { begin: 11, end: 51 }
19
+ * // }
20
+ */
21
+ function extractArgs(rawCode) {
22
+ const { strippedCode, argRange: range } = strip(rawCode);
23
+ const code = new ParsableString(strippedCode);
24
+ code.consume("(");
25
+ const args = [];
26
+ while (!code.isAt(")")) {
27
+ const attributes = [];
28
+ while (code.isAt("@")) {
29
+ code.parseUntil(closingParenthesis, parentheses);
30
+ code.consume(")");
31
+ attributes.push(code.lastParsed);
32
+ }
33
+ code.parseUntil(identifierEndSymbols);
34
+ const identifier = code.lastParsed;
35
+ let maybeType;
36
+ if (code.isAt(":")) {
37
+ code.consume(":");
38
+ code.parseUntil(typeEndSymbols, angleBrackets);
39
+ maybeType = code.lastParsed;
40
+ }
41
+ args.push({
42
+ identifier,
43
+ attributes,
44
+ type: maybeType
45
+ });
46
+ if (code.isAt(",")) code.consume(",");
47
+ }
48
+ code.consume(")");
49
+ let maybeRet;
50
+ if (code.isAt("->")) {
51
+ code.consume("->");
52
+ const attributes = [];
53
+ while (code.isAt("@")) {
54
+ code.parseUntil(closingParenthesis, parentheses);
55
+ code.consume(")");
56
+ attributes.push(code.lastParsed);
57
+ }
58
+ maybeRet = {
59
+ type: code.str.slice(code.pos),
60
+ attributes
61
+ };
62
+ }
63
+ return {
64
+ args,
65
+ ret: maybeRet,
66
+ range: {
67
+ begin: range[0],
68
+ end: range[1]
69
+ }
70
+ };
71
+ }
72
+ /**
73
+ * Strips comments, whitespaces, the name and the body of the function.
74
+ * @example
75
+ * const code = `
76
+ * fn add( a, // first argument
77
+ * @location(0) b : i32 ) -> i32 {
78
+ * return a + b; // returns the sum
79
+ * }`;
80
+ *
81
+ * strip(code); // "(a,@location(0)b:i32)->i32"
82
+ */
83
+ function strip(rawCode) {
84
+ const code = new ParsableString(rawCode);
85
+ let strippedCode = "";
86
+ let argsStart;
87
+ while (!code.isFinished()) {
88
+ if (code.isAt(blankSpaces)) {
89
+ code.advanceBy(1);
90
+ continue;
91
+ }
92
+ if (code.isAt("//")) {
93
+ code.consume("//");
94
+ code.parseUntil(lineBreaks);
95
+ code.advanceBy(1);
96
+ continue;
97
+ }
98
+ if (code.isAt("/*")) {
99
+ code.parseUntil(openingCommentBlock, commentBlocks);
100
+ code.consume("*/");
101
+ continue;
102
+ }
103
+ if (code.isAt("{")) return {
104
+ strippedCode,
105
+ argRange: [argsStart, code.pos]
106
+ };
107
+ if (code.isAt("(") && argsStart === void 0) argsStart = code.pos;
108
+ if (argsStart !== void 0) strippedCode += code.str[code.pos];
109
+ code.advanceBy(1);
110
+ }
111
+ throw new Error("Invalid wgsl code!");
112
+ }
113
+ var ParsableString = class {
114
+ str;
115
+ #parseStartPos;
116
+ #pos;
117
+ constructor(str) {
118
+ this.str = str;
119
+ this.#pos = 0;
120
+ }
121
+ get pos() {
122
+ return this.#pos;
123
+ }
124
+ /**
125
+ * This property is equivalent to the substring of `this.str`
126
+ * from the position of the last `parseUntil` call, to the current position.
127
+ */
128
+ get lastParsed() {
129
+ if (this.#parseStartPos === void 0) throw new Error("Parse was not called yet!");
130
+ return this.str.slice(this.#parseStartPos, this.pos);
131
+ }
132
+ isFinished() {
133
+ return this.#pos >= this.str.length;
134
+ }
135
+ isAt(substr) {
136
+ if (typeof substr === "string") {
137
+ for (let i = 0; i < substr.length; i++) if (this.str[this.#pos + i] !== substr[i]) return false;
138
+ return true;
139
+ }
140
+ for (const elem of substr) if (this.isAt(elem)) return true;
141
+ return false;
142
+ }
143
+ /**
144
+ * @param toFind a set of strings either of which satisfy the search.
145
+ * @param brackets a pair of brackets that has to be closed for result to be valid. This includes the found character(s).
146
+ * @example
147
+ * // internal state:
148
+ * // '(@attribute(0) identifier: type)'
149
+ * // ^
150
+ * this.parse(new Set(')'), ['(', ')']);
151
+ * // internal state:
152
+ * // '(@attribute(0) identifier: type)'
153
+ * // ^
154
+ */
155
+ parseUntil(toFind, brackets) {
156
+ this.#parseStartPos = this.#pos;
157
+ let openedBrackets = 0;
158
+ while (this.#pos < this.str.length) {
159
+ if (brackets && this.isAt(brackets[0])) openedBrackets += 1;
160
+ if (brackets && this.isAt(brackets[1])) openedBrackets -= 1;
161
+ if (openedBrackets === 0) {
162
+ if (this.isAt(toFind)) return this.#pos;
163
+ }
164
+ this.#pos += 1;
165
+ }
166
+ throw new Error("Reached the end of the string without finding a match!");
167
+ }
168
+ advanceBy(steps) {
169
+ this.#pos += steps;
170
+ }
171
+ consume(str) {
172
+ if (!this.isAt(str)) throw new Error(`Expected '${str}' at position ${this.#pos}, but found '${this.str.slice(this.#pos, this.#pos + str.length)}'`);
173
+ this.advanceBy(str.length);
174
+ }
175
+ };
176
+ const lineBreaks = new Set([
177
+ "\n",
178
+ "\v",
179
+ "\f",
180
+ "\r",
181
+ "…",
182
+ "\u2028",
183
+ "\u2029"
184
+ ]);
185
+ const blankSpaces = new Set([
186
+ ...lineBreaks,
187
+ " ",
188
+ " ",
189
+ "‎",
190
+ "‏"
191
+ ]);
192
+ const closingParenthesis = new Set([")"]);
193
+ const identifierEndSymbols = new Set([
194
+ ":",
195
+ ",",
196
+ ")"
197
+ ]);
198
+ const typeEndSymbols = new Set([",", ")"]);
199
+ const openingCommentBlock = new Set(["*/"]);
200
+ const parentheses = ["(", ")"];
201
+ const angleBrackets = ["<", ">"];
202
+ const commentBlocks = ["/*", "*/"];
203
+ //#endregion
204
+ export { extractArgs };
@@ -0,0 +1,90 @@
1
+ import { $getNameForward } from "../../shared/symbols.js";
2
+ import { getMetaData, getName } from "../../shared/meta.js";
3
+ import { Void, isWgslData, isWgslStruct } from "../../data/wgslTypes.js";
4
+ import { undecorate } from "../../data/dataTypes.js";
5
+ import { snip } from "../../data/snippet.js";
6
+ import { MissingLinksError } from "../../errors.js";
7
+ import { getAttributesString } from "../../data/attributes.js";
8
+ import { applyExternals, replaceExternalsInWgsl } from "../resolve/externals.js";
9
+ import { extractArgs } from "./extractArgs.js";
10
+ //#region src/core/function/fnCore.ts
11
+ function createFnCore(implementation, fnAttribute = "") {
12
+ /**
13
+ * External application has to be deferred until resolution because
14
+ * some externals can reference the owner function which has not been
15
+ * initialized yet (like when accessing the Output struct of a vertex
16
+ * entry fn).
17
+ */
18
+ const externalsToApply = [];
19
+ return {
20
+ [$getNameForward]: typeof implementation === "function" ? implementation : void 0,
21
+ applyExternals(newExternals) {
22
+ externalsToApply.push(newExternals);
23
+ },
24
+ resolve(ctx, argTypes, returnType, entryInput) {
25
+ const externalMap = {};
26
+ for (const externals of externalsToApply) applyExternals(externalMap, externals);
27
+ const id = ctx.getUniqueName(this);
28
+ if (typeof implementation === "string") {
29
+ if (!returnType) throw new Error("Explicit return type is required for string implementation");
30
+ const validArgNames = entryInput ? Object.fromEntries(entryInput.positionalArgs.map((a) => [a.schemaKey, ctx.makeNameValid(a.schemaKey)])) : void 0;
31
+ if (validArgNames && Object.keys(validArgNames).length > 0) applyExternals(externalMap, { in: validArgNames });
32
+ const replacedImpl = replaceExternalsInWgsl(ctx, externalMap, implementation);
33
+ let header = "";
34
+ let body = "";
35
+ if (fnAttribute !== "" && entryInput && validArgNames) {
36
+ const { dataSchema, positionalArgs } = entryInput;
37
+ const parts = [];
38
+ if (dataSchema && isArgUsedInBody("in", replacedImpl)) parts.push(`in: ${ctx.resolve(dataSchema).value}`);
39
+ for (const a of positionalArgs) {
40
+ const argName = validArgNames[a.schemaKey] ?? "";
41
+ if (argName !== "" && isArgUsedInBody(argName, replacedImpl)) parts.push(`${getAttributesString(a.type)}${argName}: ${ctx.resolve(a.type).value}`);
42
+ }
43
+ const input = `(${parts.join(", ")})`;
44
+ const attributes = isWgslData(returnType) ? getAttributesString(returnType) : "";
45
+ header = `${input}${returnType !== Void ? isWgslStruct(returnType) ? ` -> ${ctx.resolve(returnType).value} ` : ` -> ${attributes !== "" ? attributes : "@location(0)"} ${ctx.resolve(returnType).value} ` : " "}`;
46
+ body = replacedImpl;
47
+ } else {
48
+ const providedArgs = extractArgs(replacedImpl);
49
+ if (providedArgs.args.length !== argTypes.length) throw new Error(`WGSL implementation has ${providedArgs.args.length} arguments, while the shell has ${argTypes.length} arguments.`);
50
+ 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)} `}`;
51
+ body = replacedImpl.slice(providedArgs.range.end);
52
+ }
53
+ ctx.addDeclaration(`${fnAttribute}fn ${id}${header}${body}`);
54
+ return snip(id, returnType, "runtime");
55
+ }
56
+ const pluginData = getMetaData(implementation);
57
+ const pluginExternals = typeof pluginData?.externals === "function" ? pluginData.externals() : pluginData?.externals;
58
+ if (pluginExternals) applyExternals(externalMap, Object.fromEntries(Object.entries(pluginExternals).filter(([name]) => !(name in externalMap))));
59
+ const ast = pluginData?.ast;
60
+ if (!ast) throw new Error("Missing metadata for tgpu.fn function body (either missing 'use gpu' directive, or misconfigured `unplugin-typegpu`)");
61
+ const missingExternals = ast.externalNames.filter((name) => !(name in externalMap));
62
+ if (missingExternals.length > 0) throw new MissingLinksError(getName(this), missingExternals);
63
+ const maybeSecondArg = ast.params[1];
64
+ if (maybeSecondArg && maybeSecondArg.type === "i" && fnAttribute !== "") applyExternals(externalMap, { [maybeSecondArg.name]: undecorate(returnType) });
65
+ const { head, body, returnType: actualReturnType } = ctx.fnToWgsl({
66
+ functionType: fnAttribute.includes("@compute") ? "compute" : fnAttribute.includes("@vertex") ? "vertex" : fnAttribute.includes("@fragment") ? "fragment" : "normal",
67
+ argTypes,
68
+ entryInput,
69
+ params: ast.params,
70
+ returnType,
71
+ body: ast.body,
72
+ externalMap
73
+ });
74
+ ctx.addDeclaration(`${fnAttribute}fn ${id}${ctx.resolve(head).value}${ctx.resolve(body).value}`);
75
+ return snip(id, actualReturnType, "runtime");
76
+ }
77
+ };
78
+ }
79
+ function isArgUsedInBody(argName, body) {
80
+ return new RegExp(`\\b${argName}\\b`).test(body);
81
+ }
82
+ function checkAndReturnType(ctx, name, wgslType, jsType) {
83
+ const resolvedJsType = ctx.resolve(jsType).value.replace(/\s/g, "");
84
+ if (!wgslType) return resolvedJsType;
85
+ const resolvedWgslType = wgslType.replace(/\s/g, "");
86
+ if (resolvedWgslType !== resolvedJsType) throw new Error(`Type mismatch between TGPU shell and WGSL code string: ${name}, JS type "${resolvedJsType}", WGSL type "${resolvedWgslType}".`);
87
+ return wgslType;
88
+ }
89
+ //#endregion
90
+ export { createFnCore };
@@ -0,0 +1,40 @@
1
+ import { BuiltinClipDistances } from "../../builtin.js";
2
+ import { AnyAttribute } from "../../data/attributes.js";
3
+ import { BaseData, Bool, Decorated, F16, F32, I32, U32, Vec2f, Vec2h, Vec2i, Vec2u, Vec3f, Vec3h, Vec3i, Vec3u, Vec4f, Vec4h, Vec4i, Vec4u, Void } from "../../data/wgslTypes.js";
4
+ import { InferGPU } from "../../shared/repr.js";
5
+ //#region src/core/function/fnTypes.d.ts
6
+ type AnyFn = (...args: never[]) => unknown;
7
+ type InferArgs<T extends unknown[]> = { [Idx in keyof T]: InferGPU<T[Idx]> };
8
+ type InheritTupleValues<T, From> = { [K in keyof T]: K extends keyof From ? From[K] : never };
9
+ /**
10
+ * Returns a type that has arg and return types of `T`, but argument
11
+ * names of `From`
12
+ *
13
+ * Wrapped in an object type with `result` prop just so that it's easier
14
+ * to remove InheritArgNames<...> from Intellisense with Prettify<T>['result']
15
+ */
16
+ type InheritArgNames<T extends AnyFn, From extends AnyFn> = {
17
+ result: (...args: Parameters<((...args: InheritTupleValues<Parameters<From>, Parameters<T>>) => ReturnType<T>) & T>) => ReturnType<T>;
18
+ };
19
+ type InferImplSchema<ImplSchema extends AnyFn> = (...args: InferArgs<Parameters<ImplSchema>>) => InferGPU<ReturnType<ImplSchema>>;
20
+ type Implementation<ImplSchema extends AnyFn = AnyFn> = string | InferImplSchema<ImplSchema>;
21
+ type BaseIOData = Bool | F32 | F16 | I32 | U32 | Vec2f | Vec3f | Vec4f | Vec2h | Vec3h | Vec4h | Vec2i | Vec3i | Vec4i | Vec2u | Vec3u | Vec4u;
22
+ type IOData = BaseIOData | Decorated<BaseIOData, AnyAttribute[]> | BuiltinClipDistances;
23
+ type IORecord<TElementType extends IOData = IOData> = Record<string, TElementType>;
24
+ /**
25
+ * Used for I/O definitions of entry functions.
26
+ */
27
+ type IOLayout<TElementType extends IOData = IOData> = TElementType | IORecord<TElementType> | Void;
28
+ type InferIO<T> = T extends {
29
+ type: string;
30
+ } ? InferGPU<T> : T extends Record<string, unknown> ? { [K in keyof T]: InferGPU<T[K]> } : T;
31
+ interface PositionalArgInfo {
32
+ schemaKey: string;
33
+ type: BaseData;
34
+ }
35
+ interface SeparatedEntryArgs {
36
+ dataSchema: BaseData | undefined;
37
+ positionalArgs: PositionalArgInfo[];
38
+ }
39
+ //#endregion
40
+ export { AnyFn, BaseIOData, IOLayout, IORecord, Implementation, InferArgs, InferIO, InferImplSchema, InheritArgNames, SeparatedEntryArgs };
@@ -0,0 +1,10 @@
1
+ import { Decorate, HasCustomLocation, IsBuiltin } from "../../data/attributes.js";
2
+ import { BaseData, Location, WgslStruct } from "../../data/wgslTypes.js";
3
+
4
+ //#region src/core/function/ioSchema.d.ts
5
+ type WithLocations<T extends Record<string, BaseData>> = { [Key in keyof T]: IsBuiltin<T[Key]> extends true ? T[Key] : HasCustomLocation<T[Key]> extends true ? T[Key] : Decorate<T[Key], Location> };
6
+ type IOLayoutToSchema<T> = T extends BaseData ? HasCustomLocation<T> extends true ? T : Decorate<T, Location<0>> : T extends Record<string, BaseData> ? WgslStruct<WithLocations<T>> : T extends {
7
+ type: 'void';
8
+ } ? void : never;
9
+ //#endregion
10
+ export { IOLayoutToSchema };
@@ -0,0 +1,51 @@
1
+ import { isVoid } from "../../data/wgslTypes.js";
2
+ import { getCustomLocation, isData } from "../../data/dataTypes.js";
3
+ import { isBuiltin, location } from "../../data/attributes.js";
4
+ import { INTERNAL_createStruct } from "../../data/struct.js";
5
+ //#region src/core/function/ioSchema.ts
6
+ function withLocations(members, locations = {}) {
7
+ let nextLocation = 0;
8
+ const usedCustomLocations = /* @__PURE__ */ new Set();
9
+ return Object.fromEntries(Object.entries(members ?? {}).map(([key, member]) => {
10
+ const customLocation = getCustomLocation(member);
11
+ if (customLocation !== void 0) {
12
+ if (usedCustomLocations.has(customLocation)) throw new Error("Duplicate custom location attributes found");
13
+ usedCustomLocations.add(customLocation);
14
+ }
15
+ return [key, member];
16
+ }).map(([key, member]) => {
17
+ if (isBuiltin(member)) return [key, member];
18
+ if (getCustomLocation(member) !== void 0) return [key, member];
19
+ if (locations[key]) return [key, location(locations[key], member)];
20
+ while (usedCustomLocations.has(nextLocation)) nextLocation++;
21
+ return [key, location(nextLocation++, member)];
22
+ }));
23
+ }
24
+ function separateBuiltins(schema, locations = {}) {
25
+ const positionalArgs = [];
26
+ const dataFields = {};
27
+ for (const [key, type] of Object.entries(schema)) if (isBuiltin(type)) positionalArgs.push({
28
+ schemaKey: key,
29
+ type
30
+ });
31
+ else dataFields[key] = type;
32
+ return {
33
+ dataSchema: Object.keys(dataFields).length > 0 ? INTERNAL_createStruct(withLocations(dataFields, locations), false) : void 0,
34
+ positionalArgs
35
+ };
36
+ }
37
+ function separateAllAsPositional(schema) {
38
+ const withLocs = withLocations(schema);
39
+ return {
40
+ dataSchema: void 0,
41
+ positionalArgs: Object.entries(withLocs).map(([key, type]) => ({
42
+ schemaKey: key,
43
+ type
44
+ }))
45
+ };
46
+ }
47
+ function createIoSchema(layout, locations = {}) {
48
+ return isData(layout) ? isVoid(layout) ? layout : isBuiltin(layout) ? layout : getCustomLocation(layout) !== void 0 ? layout : location(0, layout) : INTERNAL_createStruct(withLocations(layout, locations), false);
49
+ }
50
+ //#endregion
51
+ export { createIoSchema, separateAllAsPositional, separateBuiltins };
@@ -0,0 +1,28 @@
1
+ import { $getNameForward } from "../../shared/symbols.js";
2
+ import { SelfResolvable } from "../../types.js";
3
+ import { BaseData } from "../../data/wgslTypes.js";
4
+
5
+ //#region src/core/function/shelllessImpl.d.ts
6
+ /**
7
+ * Shell-less functions are possible because we can infer the signature based solely on the context
8
+ * around the function.
9
+ *
10
+ * ## Arguments
11
+ * The snippets of the function's arguments are used to infer the types of the function's arguments.
12
+ * We only care that the arguments are of a concrete type (we concretize them if they're not). We
13
+ * cache these signatures based on the argument types, so that we can reuse them across calls.
14
+ *
15
+ * ## Return type
16
+ * In shelled functions, the return type is known when generating the body, but in the case of shell-less functions,
17
+ * we gather candidates for return types when visiting return statement nodes, and try to unify them into one type
18
+ * before generating the signature.
19
+ *
20
+ * TODO: This behavior can be refined by considering the "expected type" of the function call expression.
21
+ */
22
+ interface ShelllessImpl extends SelfResolvable {
23
+ readonly resourceType: 'shellless-impl';
24
+ readonly argTypes: BaseData[];
25
+ readonly [$getNameForward]: unknown;
26
+ }
27
+ //#endregion
28
+ export { ShelllessImpl };
@@ -0,0 +1,21 @@
1
+ import { $getNameForward, $internal, $resolve } from "../../shared/symbols.js";
2
+ import { getName } from "../../shared/meta.js";
3
+ import { createFnCore } from "./fnCore.js";
4
+ //#region src/core/function/shelllessImpl.ts
5
+ function createShelllessImpl(argTypes, implementation) {
6
+ const core = createFnCore(implementation, "");
7
+ return {
8
+ [$internal]: true,
9
+ [$getNameForward]: core,
10
+ resourceType: "shellless-impl",
11
+ argTypes,
12
+ [$resolve](ctx) {
13
+ return core.resolve(ctx, argTypes, void 0);
14
+ },
15
+ toString() {
16
+ return `fn*:${getName(core) ?? "<unnamed>"}(${argTypes.map((t) => t.toString()).join(", ")})`;
17
+ }
18
+ };
19
+ }
20
+ //#endregion
21
+ export { createShelllessImpl };
@@ -0,0 +1,12 @@
1
+ //#region src/core/function/templateUtils.ts
2
+ function stripTemplate(arg, ...values) {
3
+ return isTemplateStringsArray(arg) ? templateLiteralIdentity(arg, ...values) : arg;
4
+ }
5
+ function isTemplateStringsArray(value) {
6
+ return Array.isArray(value) && "raw" in value && Array.isArray(value.raw) && value.raw.every((item) => typeof item === "string");
7
+ }
8
+ function templateLiteralIdentity(strings, ...values) {
9
+ return strings.slice(1).reduce((acc, elem, index) => `${acc}${values[index]}${elem}`, strings[0]);
10
+ }
11
+ //#endregion
12
+ export { stripTemplate };