typegpu 0.10.1 → 0.10.2

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 (263) hide show
  1. package/{chunk-BYypO7fO.js → _virtual/_rolldown/runtime.js} +1 -1
  2. package/builtin.d.ts +50 -0
  3. package/builtin.js +37 -0
  4. package/common/fullScreenTriangle.d.ts +26 -0
  5. package/common/fullScreenTriangle.js +36 -0
  6. package/common/index.d.ts +2 -3
  7. package/common/index.js +3 -4
  8. package/core/buffer/buffer.d.ts +74 -0
  9. package/core/buffer/buffer.js +197 -0
  10. package/core/buffer/bufferShorthand.d.ts +48 -0
  11. package/core/buffer/bufferShorthand.js +49 -0
  12. package/core/buffer/bufferUsage.d.ts +45 -0
  13. package/core/buffer/bufferUsage.js +163 -0
  14. package/core/constant/tgpuConstant.d.ts +28 -0
  15. package/core/constant/tgpuConstant.js +67 -0
  16. package/core/declare/tgpuDeclare.d.ts +18 -0
  17. package/core/declare/tgpuDeclare.js +40 -0
  18. package/core/function/autoIO.d.ts +37 -0
  19. package/core/function/autoIO.js +87 -0
  20. package/core/function/comptime.d.ts +39 -0
  21. package/core/function/comptime.js +51 -0
  22. package/core/function/createCallableSchema.js +42 -0
  23. package/core/function/dualImpl.js +54 -0
  24. package/core/function/extractArgs.js +204 -0
  25. package/core/function/fnCore.js +79 -0
  26. package/core/function/fnTypes.d.ts +34 -0
  27. package/core/function/ioSchema.d.ts +10 -0
  28. package/core/function/ioSchema.js +30 -0
  29. package/core/function/shelllessImpl.d.ts +28 -0
  30. package/core/function/shelllessImpl.js +23 -0
  31. package/core/function/templateUtils.js +13 -0
  32. package/core/function/tgpuComputeFn.d.ts +49 -0
  33. package/core/function/tgpuComputeFn.js +62 -0
  34. package/core/function/tgpuFn.d.ts +52 -0
  35. package/core/function/tgpuFn.js +170 -0
  36. package/core/function/tgpuFragmentFn.d.ts +68 -0
  37. package/core/function/tgpuFragmentFn.js +68 -0
  38. package/core/function/tgpuVertexFn.d.ts +55 -0
  39. package/core/function/tgpuVertexFn.js +65 -0
  40. package/core/pipeline/applyPipelineState.js +37 -0
  41. package/core/pipeline/computePipeline.d.ts +58 -0
  42. package/core/pipeline/computePipeline.js +226 -0
  43. package/core/pipeline/connectAttachmentToShader.js +26 -0
  44. package/core/pipeline/connectTargetsToShader.js +29 -0
  45. package/core/pipeline/limitsOverflow.js +13 -0
  46. package/core/pipeline/renderPipeline.d.ts +266 -0
  47. package/core/pipeline/renderPipeline.js +471 -0
  48. package/core/pipeline/timeable.d.ts +23 -0
  49. package/core/pipeline/timeable.js +61 -0
  50. package/core/pipeline/typeGuards.js +29 -0
  51. package/core/querySet/querySet.d.ts +22 -0
  52. package/core/querySet/querySet.js +103 -0
  53. package/core/rawCodeSnippet/tgpuRawCodeSnippet.d.ts +59 -0
  54. package/core/rawCodeSnippet/tgpuRawCodeSnippet.js +96 -0
  55. package/core/resolve/externals.d.ts +10 -0
  56. package/core/resolve/externals.js +58 -0
  57. package/core/resolve/namespace.d.ts +38 -0
  58. package/core/resolve/namespace.js +41 -0
  59. package/core/resolve/resolveData.js +146 -0
  60. package/core/resolve/stitch.js +25 -0
  61. package/core/resolve/tgpuResolve.d.ts +151 -0
  62. package/core/resolve/tgpuResolve.js +68 -0
  63. package/core/root/configurableImpl.js +18 -0
  64. package/core/root/init.d.ts +69 -0
  65. package/core/root/init.js +457 -0
  66. package/core/root/rootTypes.d.ts +622 -0
  67. package/core/sampler/sampler.d.ts +35 -0
  68. package/core/sampler/sampler.js +116 -0
  69. package/core/simulate/tgpuSimulate.d.ts +36 -0
  70. package/core/simulate/tgpuSimulate.js +76 -0
  71. package/core/slot/accessor.d.ts +13 -0
  72. package/core/slot/accessor.js +97 -0
  73. package/core/slot/internalSlots.js +7 -0
  74. package/core/slot/lazy.d.ts +6 -0
  75. package/core/slot/lazy.js +42 -0
  76. package/core/slot/slot.d.ts +6 -0
  77. package/core/slot/slot.js +40 -0
  78. package/core/slot/slotTypes.d.ts +92 -0
  79. package/core/slot/slotTypes.js +21 -0
  80. package/core/texture/externalTexture.d.ts +12 -0
  81. package/core/texture/externalTexture.js +48 -0
  82. package/core/texture/texture.d.ts +118 -0
  83. package/core/texture/texture.js +312 -0
  84. package/core/texture/textureFormats.d.ts +29 -0
  85. package/core/texture/textureFormats.js +99 -0
  86. package/core/texture/textureProps.d.ts +11 -0
  87. package/core/texture/textureUtils.js +224 -0
  88. package/core/texture/usageExtension.d.ts +21 -0
  89. package/core/texture/usageExtension.js +21 -0
  90. package/core/unroll/tgpuUnroll.d.ts +13 -0
  91. package/core/unroll/tgpuUnroll.js +36 -0
  92. package/core/valueProxyUtils.js +44 -0
  93. package/core/variable/tgpuVariable.d.ts +38 -0
  94. package/core/variable/tgpuVariable.js +101 -0
  95. package/core/vertexLayout/connectAttributesToShader.js +59 -0
  96. package/core/vertexLayout/vertexAttribute.d.ts +29 -0
  97. package/core/vertexLayout/vertexLayout.d.ts +19 -0
  98. package/core/vertexLayout/vertexLayout.js +103 -0
  99. package/data/alignIO.js +15 -0
  100. package/data/alignmentOf.d.ts +10 -0
  101. package/data/alignmentOf.js +88 -0
  102. package/data/array.d.ts +28 -0
  103. package/data/array.js +48 -0
  104. package/data/atomic.d.ts +15 -0
  105. package/data/atomic.js +25 -0
  106. package/data/attributes.d.ts +121 -0
  107. package/data/attributes.js +145 -0
  108. package/data/autoStruct.d.ts +3 -0
  109. package/data/autoStruct.js +83 -0
  110. package/data/compiledIO.js +231 -0
  111. package/data/dataIO.js +549 -0
  112. package/data/dataTypes.d.ts +115 -0
  113. package/data/dataTypes.js +97 -0
  114. package/data/deepEqual.d.ts +25 -0
  115. package/data/deepEqual.js +58 -0
  116. package/data/disarray.d.ts +34 -0
  117. package/data/disarray.js +52 -0
  118. package/data/getLongestContiguousPrefix.d.ts +10 -0
  119. package/data/getLongestContiguousPrefix.js +15 -0
  120. package/data/index.d.ts +26 -4
  121. package/data/index.js +27 -7
  122. package/data/instanceToSchema.d.ts +33 -0
  123. package/data/isContiguous.d.ts +10 -0
  124. package/data/isContiguous.js +15 -0
  125. package/data/matrix.d.ts +126 -0
  126. package/data/matrix.js +517 -0
  127. package/data/numberOps.js +24 -0
  128. package/data/numeric.d.ts +81 -0
  129. package/data/numeric.js +234 -0
  130. package/data/offsetUtils.d.ts +33 -0
  131. package/data/offsetUtils.js +167 -0
  132. package/data/offsets.js +36 -0
  133. package/data/partialIO.js +68 -0
  134. package/data/ptr.d.ts +12 -0
  135. package/data/ptr.js +46 -0
  136. package/data/ref.d.ts +37 -0
  137. package/data/ref.js +96 -0
  138. package/data/sampler.d.ts +107 -0
  139. package/data/sampler.js +26 -0
  140. package/data/schemaCallWrapper.js +32 -0
  141. package/data/schemaMemoryLayout.js +200 -0
  142. package/data/sizeOf.d.ts +10 -0
  143. package/data/sizeOf.js +15 -0
  144. package/data/snippet.d.ts +26 -0
  145. package/data/snippet.js +61 -0
  146. package/data/struct.d.ts +17 -0
  147. package/data/struct.js +46 -0
  148. package/data/texture.d.ts +292 -0
  149. package/{texture-BagDrrks.js → data/texture.js} +6 -3
  150. package/data/unstruct.d.ts +24 -0
  151. package/data/unstruct.js +43 -0
  152. package/data/vector.d.ts +191 -0
  153. package/data/vector.js +247 -0
  154. package/data/vectorImpl.js +516 -0
  155. package/data/vectorOps.js +664 -0
  156. package/data/vertexFormatData.d.ts +190 -0
  157. package/data/vertexFormatData.js +110 -0
  158. package/data/wgslTypes.d.ts +896 -0
  159. package/data/wgslTypes.js +215 -0
  160. package/errors.d.ts +44 -0
  161. package/errors.js +128 -0
  162. package/execMode.js +51 -0
  163. package/extension.d.ts +11 -0
  164. package/extension.js +18 -0
  165. package/getGPUValue.js +9 -0
  166. package/index.d.ts +40 -243
  167. package/index.js +19 -6318
  168. package/indexNamedExports.d.ts +38 -0
  169. package/mathUtils.js +13 -0
  170. package/memo.js +22 -0
  171. package/nameRegistry.d.ts +30 -0
  172. package/nameRegistry.js +449 -0
  173. package/package.js +5 -0
  174. package/package.json +23 -23
  175. package/resolutionCtx.d.ts +29 -0
  176. package/resolutionCtx.js +546 -0
  177. package/shared/env.js +13 -0
  178. package/shared/generators.js +14 -0
  179. package/shared/meta.d.ts +39 -0
  180. package/shared/meta.js +63 -0
  181. package/shared/repr.d.ts +108 -0
  182. package/shared/stringify.js +22 -0
  183. package/shared/symbols.d.ts +61 -0
  184. package/shared/symbols.js +71 -0
  185. package/shared/utilityTypes.d.ts +29 -0
  186. package/shared/utilityTypes.js +7 -0
  187. package/shared/vertexFormat.d.ts +70 -0
  188. package/shared/vertexFormat.js +64 -0
  189. package/std/array.d.ts +7 -0
  190. package/std/array.js +27 -0
  191. package/std/atomic.d.ts +19 -0
  192. package/std/atomic.js +113 -0
  193. package/std/bitcast.d.ts +10 -0
  194. package/std/bitcast.js +43 -0
  195. package/std/boolean.d.ts +127 -0
  196. package/std/boolean.js +274 -0
  197. package/std/derivative.d.ts +16 -0
  198. package/std/derivative.js +89 -0
  199. package/std/discard.d.ts +6 -0
  200. package/std/discard.js +16 -0
  201. package/std/extensions.d.ts +8 -0
  202. package/std/extensions.js +14 -0
  203. package/std/index.d.ts +15 -3
  204. package/std/index.js +16 -5
  205. package/std/matrix.d.ts +41 -0
  206. package/std/matrix.js +87 -0
  207. package/std/numeric.d.ts +254 -0
  208. package/std/numeric.js +847 -0
  209. package/std/operators.d.ts +48 -0
  210. package/std/operators.js +153 -0
  211. package/std/packing.d.ts +26 -0
  212. package/std/packing.js +86 -0
  213. package/std/subgroup.d.ts +47 -0
  214. package/std/subgroup.js +220 -0
  215. package/std/texture.d.ts +108 -0
  216. package/std/texture.js +197 -0
  217. package/tgpu.js +44 -0
  218. package/tgpuBindGroupLayout.d.ts +161 -0
  219. package/tgpuBindGroupLayout.js +271 -0
  220. package/tgpuUnstable.d.ts +48 -0
  221. package/tgpuUnstable.js +66 -0
  222. package/tgsl/accessIndex.js +45 -0
  223. package/tgsl/accessProp.js +113 -0
  224. package/tgsl/consoleLog/deserializers.js +117 -0
  225. package/tgsl/consoleLog/logGenerator.js +86 -0
  226. package/tgsl/consoleLog/serializers.js +225 -0
  227. package/tgsl/consoleLog/types.d.ts +54 -0
  228. package/tgsl/consoleLog/types.js +12 -0
  229. package/tgsl/conversion.js +200 -0
  230. package/tgsl/forOfUtils.js +45 -0
  231. package/tgsl/generationHelpers.d.ts +37 -0
  232. package/tgsl/generationHelpers.js +67 -0
  233. package/tgsl/math.js +45 -0
  234. package/tgsl/shaderGenerator.d.ts +18 -0
  235. package/tgsl/shellless.d.ts +11 -0
  236. package/tgsl/shellless.js +53 -0
  237. package/tgsl/wgslGenerator.js +585 -0
  238. package/types.d.ts +255 -0
  239. package/types.js +43 -0
  240. package/unwrapper.d.ts +27 -0
  241. package/wgslExtensions.d.ts +5 -0
  242. package/wgslExtensions.js +18 -0
  243. package/builtin-DdtWpk2t.js +0 -818
  244. package/builtin-DdtWpk2t.js.map +0 -1
  245. package/common/index.d.ts.map +0 -1
  246. package/common/index.js.map +0 -1
  247. package/data/index.d.ts.map +0 -1
  248. package/data/index.js.map +0 -1
  249. package/deepEqual-DQxK4vdp.js +0 -413
  250. package/deepEqual-DQxK4vdp.js.map +0 -1
  251. package/extensions-DIVuAfBM.js +0 -2032
  252. package/extensions-DIVuAfBM.js.map +0 -1
  253. package/fullScreenTriangle-CfFyQd_0.js +0 -543
  254. package/fullScreenTriangle-CfFyQd_0.js.map +0 -1
  255. package/index.d.ts.map +0 -1
  256. package/index.js.map +0 -1
  257. package/indexNamedExports-oL6tyaJ9.d.ts +0 -5697
  258. package/indexNamedExports-oL6tyaJ9.d.ts.map +0 -1
  259. package/operators-d-PMVTo7.js +0 -4158
  260. package/operators-d-PMVTo7.js.map +0 -1
  261. package/std/index.d.ts.map +0 -1
  262. package/std/index.js.map +0 -1
  263. package/texture-BagDrrks.js.map +0 -1
@@ -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
+ #parseStartPos;
115
+ #pos;
116
+ constructor(str) {
117
+ this.str = str;
118
+ this.#pos = 0;
119
+ }
120
+ get pos() {
121
+ return this.#pos;
122
+ }
123
+ /**
124
+ * This property is equivalent to the substring of `this.str`
125
+ * from the position of the last `parseUntil` call, to the current position.
126
+ */
127
+ get lastParsed() {
128
+ if (this.#parseStartPos === void 0) throw new Error("Parse was not called yet!");
129
+ return this.str.slice(this.#parseStartPos, this.pos);
130
+ }
131
+ isFinished() {
132
+ return this.#pos >= this.str.length;
133
+ }
134
+ isAt(substr) {
135
+ if (typeof substr === "string") {
136
+ for (let i = 0; i < substr.length; i++) if (this.str[this.#pos + i] !== substr[i]) return false;
137
+ return true;
138
+ }
139
+ for (const elem of substr) if (this.isAt(elem)) return true;
140
+ return false;
141
+ }
142
+ /**
143
+ * @param toFind a set of strings either of which satisfy the search.
144
+ * @param brackets a pair of brackets that has to be closed for result to be valid. This includes the found character(s).
145
+ * @example
146
+ * // internal state:
147
+ * // '(@attribute(0) identifier: type)'
148
+ * // ^
149
+ * this.parse(new Set(')'), ['(', ')']);
150
+ * // internal state:
151
+ * // '(@attribute(0) identifier: type)'
152
+ * // ^
153
+ */
154
+ parseUntil(toFind, brackets) {
155
+ this.#parseStartPos = this.#pos;
156
+ let openedBrackets = 0;
157
+ while (this.#pos < this.str.length) {
158
+ if (brackets && this.isAt(brackets[0])) openedBrackets += 1;
159
+ if (brackets && this.isAt(brackets[1])) openedBrackets -= 1;
160
+ if (openedBrackets === 0) {
161
+ if (this.isAt(toFind)) return this.#pos;
162
+ }
163
+ this.#pos += 1;
164
+ }
165
+ throw new Error("Reached the end of the string without finding a match!");
166
+ }
167
+ advanceBy(steps) {
168
+ this.#pos += steps;
169
+ }
170
+ consume(str) {
171
+ if (!this.isAt(str)) throw new Error(`Expected '${str}' at position ${this.#pos}, but found '${this.str.slice(this.#pos, this.#pos + str.length)}'`);
172
+ this.advanceBy(str.length);
173
+ }
174
+ };
175
+ const lineBreaks = new Set([
176
+ "\n",
177
+ "\v",
178
+ "\f",
179
+ "\r",
180
+ "…",
181
+ "\u2028",
182
+ "\u2029"
183
+ ]);
184
+ const blankSpaces = new Set([
185
+ ...lineBreaks,
186
+ " ",
187
+ " ",
188
+ "‎",
189
+ "‏"
190
+ ]);
191
+ const closingParenthesis = new Set([")"]);
192
+ const identifierEndSymbols = new Set([
193
+ ":",
194
+ ",",
195
+ ")"
196
+ ]);
197
+ const typeEndSymbols = new Set([",", ")"]);
198
+ const openingCommentBlock = new Set(["*/"]);
199
+ const parentheses = ["(", ")"];
200
+ const angleBrackets = ["<", ">"];
201
+ const commentBlocks = ["/*", "*/"];
202
+
203
+ //#endregion
204
+ export { extractArgs };
@@ -0,0 +1,79 @@
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
+
11
+ //#region src/core/function/fnCore.ts
12
+ function createFnCore(implementation, fnAttribute = "") {
13
+ /**
14
+ * External application has to be deferred until resolution because
15
+ * some externals can reference the owner function which has not been
16
+ * initialized yet (like when accessing the Output struct of a vertex
17
+ * entry fn).
18
+ */
19
+ const externalsToApply = [];
20
+ return {
21
+ [$getNameForward]: typeof implementation === "function" ? implementation : void 0,
22
+ applyExternals(newExternals) {
23
+ externalsToApply.push(newExternals);
24
+ },
25
+ resolve(ctx, argTypes, returnType) {
26
+ const externalMap = {};
27
+ for (const externals of externalsToApply) applyExternals(externalMap, externals);
28
+ const id = ctx.getUniqueName(this);
29
+ if (typeof implementation === "string") {
30
+ if (!returnType) throw new Error("Explicit return type is required for string implementation");
31
+ const replacedImpl = replaceExternalsInWgsl(ctx, externalMap, implementation);
32
+ let header = "";
33
+ let body = "";
34
+ if (fnAttribute !== "") {
35
+ const input = isWgslStruct(argTypes[0]) ? `(in: ${ctx.resolve(argTypes[0]).value})` : "()";
36
+ const attributes = isWgslData(returnType) ? getAttributesString(returnType) : "";
37
+ header = `${input} ${returnType !== Void ? isWgslStruct(returnType) ? `-> ${ctx.resolve(returnType).value}` : `-> ${attributes !== "" ? attributes : "@location(0)"} ${ctx.resolve(returnType).value}` : ""} `;
38
+ body = replacedImpl;
39
+ } else {
40
+ const providedArgs = extractArgs(replacedImpl);
41
+ if (providedArgs.args.length !== argTypes.length) throw new Error(`WGSL implementation has ${providedArgs.args.length} arguments, while the shell has ${argTypes.length} arguments.`);
42
+ 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)}`}`;
43
+ body = replacedImpl.slice(providedArgs.range.end);
44
+ }
45
+ ctx.addDeclaration(`${fnAttribute}fn ${id}${header}${body}`);
46
+ return snip(id, returnType, "runtime");
47
+ }
48
+ const pluginData = getMetaData(implementation);
49
+ const pluginExternals = typeof pluginData?.externals === "function" ? pluginData.externals() : pluginData?.externals;
50
+ if (pluginExternals) applyExternals(externalMap, Object.fromEntries(Object.entries(pluginExternals).filter(([name]) => !(name in externalMap))));
51
+ const ast = pluginData?.ast;
52
+ if (!ast) throw new Error("Missing metadata for tgpu.fn function body (either missing 'use gpu' directive, or misconfigured `unplugin-typegpu`)");
53
+ const missingExternals = ast.externalNames.filter((name) => !(name in externalMap));
54
+ if (missingExternals.length > 0) throw new MissingLinksError(getName(this), missingExternals);
55
+ const maybeSecondArg = ast.params[1];
56
+ if (maybeSecondArg && maybeSecondArg.type === "i" && fnAttribute !== "") applyExternals(externalMap, { [maybeSecondArg.name]: undecorate(returnType) });
57
+ const { head, body, returnType: actualReturnType } = ctx.fnToWgsl({
58
+ functionType: fnAttribute.includes("@compute") ? "compute" : fnAttribute.includes("@vertex") ? "vertex" : fnAttribute.includes("@fragment") ? "fragment" : "normal",
59
+ argTypes,
60
+ params: ast.params,
61
+ returnType,
62
+ body: ast.body,
63
+ externalMap
64
+ });
65
+ ctx.addDeclaration(`${fnAttribute}fn ${id}${ctx.resolve(head).value}${ctx.resolve(body).value}`);
66
+ return snip(id, actualReturnType, "runtime");
67
+ }
68
+ };
69
+ }
70
+ function checkAndReturnType(ctx, name, wgslType, jsType) {
71
+ const resolvedJsType = ctx.resolve(jsType).value.replace(/\s/g, "");
72
+ if (!wgslType) return resolvedJsType;
73
+ const resolvedWgslType = wgslType.replace(/\s/g, "");
74
+ if (resolvedWgslType !== resolvedJsType) throw new Error(`Type mismatch between TGPU shell and WGSL code string: ${name}, JS type "${resolvedJsType}", WGSL type "${resolvedWgslType}".`);
75
+ return wgslType;
76
+ }
77
+
78
+ //#endregion
79
+ export { createFnCore };
@@ -0,0 +1,34 @@
1
+ import { BuiltinClipDistances } from "../../builtin.js";
2
+ import { AnyAttribute } from "../../data/attributes.js";
3
+ import { 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 { Infer } from "../../shared/repr.js";
5
+ import "tinyest";
6
+
7
+ //#region src/core/function/fnTypes.d.ts
8
+ type AnyFn = (...args: never[]) => unknown;
9
+ type InferArgs<T extends unknown[]> = { [Idx in keyof T]: Infer<T[Idx]> };
10
+ type InheritTupleValues<T, From> = { [K in keyof T]: K extends keyof From ? From[K] : never };
11
+ /**
12
+ * Returns a type that has arg and return types of `T`, but argument
13
+ * names of `From`
14
+ *
15
+ * Wrapped in an object type with `result` prop just so that it's easier
16
+ * to remove InheritArgNames<...> from Intellisense with Prettify<T>['result']
17
+ */
18
+ type InheritArgNames<T extends AnyFn, From extends AnyFn> = {
19
+ result: (...args: Parameters<((...args: InheritTupleValues<Parameters<From>, Parameters<T>>) => ReturnType<T>) & T>) => ReturnType<T>;
20
+ };
21
+ type InferImplSchema<ImplSchema extends AnyFn> = (...args: InferArgs<Parameters<ImplSchema>>) => Infer<ReturnType<ImplSchema>>;
22
+ type Implementation<ImplSchema extends AnyFn = AnyFn> = string | InferImplSchema<ImplSchema>;
23
+ type BaseIOData = Bool | F32 | F16 | I32 | U32 | Vec2f | Vec3f | Vec4f | Vec2h | Vec3h | Vec4h | Vec2i | Vec3i | Vec4i | Vec2u | Vec3u | Vec4u;
24
+ type IOData = BaseIOData | Decorated<BaseIOData, AnyAttribute[]> | BuiltinClipDistances;
25
+ type IORecord<TElementType extends IOData = IOData> = Record<string, TElementType>;
26
+ /**
27
+ * Used for I/O definitions of entry functions.
28
+ */
29
+ type IOLayout<TElementType extends IOData = IOData> = TElementType | IORecord<TElementType> | Void;
30
+ type InferIO<T> = T extends {
31
+ type: string;
32
+ } ? Infer<T> : T extends Record<string, unknown> ? { [K in keyof T]: Infer<T[K]> } : T;
33
+ //#endregion
34
+ export { AnyFn, BaseIOData, IOLayout, IORecord, Implementation, InferArgs, InferIO, InferImplSchema, InheritArgNames };
@@ -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,30 @@
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
+
6
+ //#region src/core/function/ioSchema.ts
7
+ function withLocations(members, locations = {}) {
8
+ let nextLocation = 0;
9
+ const usedCustomLocations = /* @__PURE__ */ new Set();
10
+ return Object.fromEntries(Object.entries(members ?? {}).map(([key, member]) => {
11
+ const customLocation = getCustomLocation(member);
12
+ if (customLocation !== void 0) {
13
+ if (usedCustomLocations.has(customLocation)) throw new Error("Duplicate custom location attributes found");
14
+ usedCustomLocations.add(customLocation);
15
+ }
16
+ return [key, member];
17
+ }).map(([key, member]) => {
18
+ if (isBuiltin(member)) return [key, member];
19
+ if (getCustomLocation(member) !== void 0) return [key, member];
20
+ if (locations[key]) return [key, location(locations[key], member)];
21
+ while (usedCustomLocations.has(nextLocation)) nextLocation++;
22
+ return [key, location(nextLocation++, member)];
23
+ }));
24
+ }
25
+ function createIoSchema(layout, locations = {}) {
26
+ return isData(layout) ? isVoid(layout) ? layout : isBuiltin(layout) ? layout : getCustomLocation(layout) !== void 0 ? layout : location(0, layout) : INTERNAL_createStruct(withLocations(layout, locations), false);
27
+ }
28
+
29
+ //#endregion
30
+ export { createIoSchema };
@@ -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,23 @@
1
+ import { $getNameForward, $internal, $resolve } from "../../shared/symbols.js";
2
+ import { getName } from "../../shared/meta.js";
3
+ import { createFnCore } from "./fnCore.js";
4
+
5
+ //#region src/core/function/shelllessImpl.ts
6
+ function createShelllessImpl(argTypes, implementation) {
7
+ const core = createFnCore(implementation, "");
8
+ return {
9
+ [$internal]: true,
10
+ [$getNameForward]: core,
11
+ resourceType: "shellless-impl",
12
+ argTypes,
13
+ [$resolve](ctx) {
14
+ return core.resolve(ctx, argTypes, void 0);
15
+ },
16
+ toString() {
17
+ return `fn*:${getName(core) ?? "<unnamed>"}(${argTypes.map((t) => t.toString()).join(", ")})`;
18
+ }
19
+ };
20
+ }
21
+
22
+ //#endregion
23
+ export { createShelllessImpl };
@@ -0,0 +1,13 @@
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
+
12
+ //#endregion
13
+ export { stripTemplate };
@@ -0,0 +1,49 @@
1
+ import { TgpuNamable } from "../../shared/meta.js";
2
+ import { $internal } from "../../shared/symbols.js";
3
+ import { AnyComputeBuiltin } from "../../builtin.js";
4
+ import { IORecord, InferIO } from "./fnTypes.js";
5
+ import { IOLayoutToSchema } from "./ioSchema.js";
6
+ import { Void } from "../../data/wgslTypes.js";
7
+
8
+ //#region src/core/function/tgpuComputeFn.d.ts
9
+ /**
10
+ * Describes a compute entry function signature (its arguments, return type and workgroup size)
11
+ */
12
+ type TgpuComputeFnShellHeader<ComputeIn extends IORecord<AnyComputeBuiltin>> = {
13
+ readonly argTypes: [IOLayoutToSchema<ComputeIn>] | [];
14
+ readonly returnType: Void;
15
+ readonly workgroupSize: [number, number, number];
16
+ readonly entryPoint: 'compute';
17
+ };
18
+ /**
19
+ * Describes a compute entry function signature (its arguments, return type and workgroup size).
20
+ * Allows creating tgpu compute functions by calling this shell
21
+ * and passing the implementation (as WGSL string or JS function) as the argument.
22
+ */
23
+ type TgpuComputeFnShell<ComputeIn extends IORecord<AnyComputeBuiltin>> = TgpuComputeFnShellHeader<ComputeIn> &
24
+ /**
25
+ * Creates a type-safe implementation of this signature
26
+ */
27
+ ((implementation: (input: InferIO<ComputeIn>) => undefined) => TgpuComputeFn<ComputeIn>) &
28
+ /**
29
+ * @param implementation
30
+ * Raw WGSL function implementation with header and body
31
+ * without `fn` keyword and function name
32
+ * e.g. `"(x: f32) -> f32 { return x; }"`;
33
+ */
34
+ ((implementation: string) => TgpuComputeFn<ComputeIn>) & ((strings: TemplateStringsArray, ...values: unknown[]) => TgpuComputeFn<ComputeIn>);
35
+ interface TgpuComputeFn<ComputeIn extends IORecord<AnyComputeBuiltin> = any> extends TgpuNamable {
36
+ readonly [$internal]: true;
37
+ readonly shell: TgpuComputeFnShellHeader<ComputeIn>;
38
+ $uses(dependencyMap: Record<string, unknown>): this;
39
+ }
40
+ declare function computeFn(options: {
41
+ workgroupSize: number[];
42
+ }): TgpuComputeFnShell<{}>;
43
+ declare function computeFn<ComputeIn extends IORecord<AnyComputeBuiltin>>(options: {
44
+ in: ComputeIn;
45
+ workgroupSize: number[];
46
+ }): TgpuComputeFnShell<ComputeIn>;
47
+ declare function isTgpuComputeFn<ComputeIn extends IORecord<AnyComputeBuiltin>>(value: unknown): value is TgpuComputeFn<ComputeIn>;
48
+ //#endregion
49
+ export { TgpuComputeFn, TgpuComputeFnShell, computeFn, isTgpuComputeFn };
@@ -0,0 +1,62 @@
1
+ import { $getNameForward, $internal, $resolve } from "../../shared/symbols.js";
2
+ import { getName, isNamable, setName } from "../../shared/meta.js";
3
+ import { Void } from "../../data/wgslTypes.js";
4
+ import { createIoSchema } from "./ioSchema.js";
5
+ import { createFnCore } from "./fnCore.js";
6
+ import { stripTemplate } from "./templateUtils.js";
7
+ import { shaderStageSlot } from "../slot/internalSlots.js";
8
+
9
+ //#region src/core/function/tgpuComputeFn.ts
10
+ /**
11
+ * Creates a shell of a typed entry function for the compute shader stage. Any function
12
+ * that implements this shell can perform general-purpose computation.
13
+ *
14
+ * @param options.in
15
+ * Record with builtins used by the compute shader.
16
+ * @param options.workgroupSize
17
+ * Size of blocks that the thread grid will be divided into (up to 3 dimensions).
18
+ */
19
+ function computeFn(options) {
20
+ const shell = {
21
+ argTypes: options.in && Object.keys(options.in).length !== 0 ? [createIoSchema(options.in)] : [],
22
+ returnType: Void,
23
+ workgroupSize: [
24
+ options.workgroupSize[0] ?? 1,
25
+ options.workgroupSize[1] ?? 1,
26
+ options.workgroupSize[2] ?? 1
27
+ ],
28
+ entryPoint: "compute"
29
+ };
30
+ const call = (arg, ...values) => createComputeFn(shell, options.workgroupSize, stripTemplate(arg, ...values));
31
+ return Object.assign(call, shell);
32
+ }
33
+ function isTgpuComputeFn(value) {
34
+ return value?.shell?.entryPoint === "compute";
35
+ }
36
+ function createComputeFn(shell, workgroupSize, implementation) {
37
+ const core = createFnCore(implementation, `@compute @workgroup_size(${workgroupSize.join(", ")}) `);
38
+ const inputType = shell.argTypes[0];
39
+ return {
40
+ shell,
41
+ $uses(newExternals) {
42
+ core.applyExternals(newExternals);
43
+ return this;
44
+ },
45
+ [$internal]: true,
46
+ [$getNameForward]: core,
47
+ $name(newLabel) {
48
+ setName(this, newLabel);
49
+ if (isNamable(inputType)) inputType.$name(`${newLabel}_Input`);
50
+ return this;
51
+ },
52
+ [$resolve](ctx) {
53
+ return ctx.withSlots([[shaderStageSlot, "compute"]], () => core.resolve(ctx, shell.argTypes, shell.returnType));
54
+ },
55
+ toString() {
56
+ return `computeFn:${getName(core) ?? "<unnamed>"}`;
57
+ }
58
+ };
59
+ }
60
+
61
+ //#endregion
62
+ export { computeFn, isTgpuComputeFn };
@@ -0,0 +1,52 @@
1
+ import { TgpuNamable } from "../../shared/meta.js";
2
+ import { $internal, $providing } from "../../shared/symbols.js";
3
+ import { Prettify } from "../../shared/utilityTypes.js";
4
+ import { AnyFn, Implementation, InferArgs, InferImplSchema, InheritArgNames } from "./fnTypes.js";
5
+ import { Providing } from "../slot/slotTypes.js";
6
+ import { Withable } from "../root/rootTypes.js";
7
+ import { DualFn } from "../../types.js";
8
+ import { BaseData, Void } from "../../data/wgslTypes.js";
9
+ import { Infer } from "../../shared/repr.js";
10
+
11
+ //#region src/core/function/tgpuFn.d.ts
12
+ /**
13
+ * Describes a function signature (its arguments and return type)
14
+ */
15
+ type TgpuFnShellHeader<Args extends BaseData[], Return extends BaseData> = {
16
+ readonly [$internal]: true;
17
+ readonly argTypes: Args;
18
+ readonly returnType: Return;
19
+ };
20
+ /**
21
+ * Describes a function signature (its arguments and return type).
22
+ * Allows creating tgpu functions by calling this shell
23
+ * and passing the implementation (as WGSL string or JS function) as the argument.
24
+ */
25
+ type TgpuFnShell<Args extends BaseData[], Return extends BaseData> = TgpuFnShellHeader<Args, Return> & (<T extends (...args: InferArgs<Args>) => Infer<Return>>(implementation: T) => TgpuFn<Prettify<InheritArgNames<(...args: Args) => Return, T>>['result']>) & ((implementation: string) => TgpuFn<(...args: Args) => Return>) & ((strings: TemplateStringsArray, ...values: unknown[]) => TgpuFn<(...args: Args) => Return>);
26
+ interface TgpuFnBase<ImplSchema extends AnyFn> extends TgpuNamable, Withable<TgpuFn<ImplSchema>> {
27
+ [$internal]: {
28
+ implementation: Implementation<ImplSchema>;
29
+ };
30
+ readonly resourceType: 'function';
31
+ readonly shell: TgpuFnShellHeader<Parameters<ImplSchema>, Extract<ReturnType<ImplSchema>, BaseData>>;
32
+ readonly [$providing]?: Providing | undefined;
33
+ $uses(dependencyMap: Record<string, unknown>): this;
34
+ }
35
+ type TgpuFn<ImplSchema extends AnyFn = (...args: any[]) => any> = DualFn<InferImplSchema<ImplSchema>> & TgpuFnBase<ImplSchema>;
36
+ /**
37
+ * A function wrapper that allows providing slot and accessor overrides for shellless functions
38
+ */
39
+ interface TgpuGenericFn<T extends AnyFn> extends TgpuNamable, Withable<TgpuGenericFn<T>> {
40
+ readonly [$internal]: {
41
+ inner: T;
42
+ };
43
+ readonly [$providing]?: Providing | undefined;
44
+ readonly resourceType: 'generic-function';
45
+ (...args: Parameters<T>): ReturnType<T>;
46
+ }
47
+ declare function fn<Args extends BaseData[] | []>(argTypes: Args, returnType?: undefined): TgpuFnShell<Args, Void>;
48
+ declare function fn<Args extends BaseData[] | [], Return extends BaseData>(argTypes: Args, returnType: Return): TgpuFnShell<Args, Return>;
49
+ declare function fn<T extends AnyFn>(inner: T): TgpuGenericFn<T>;
50
+ declare function isTgpuFn<Args extends BaseData[] | [], Return extends BaseData>(value: unknown): value is TgpuFn<(...args: Args) => Return>;
51
+ //#endregion
52
+ export { TgpuFn, TgpuFnShell, TgpuGenericFn, fn, isTgpuFn };