typegpu 0.11.9 → 0.12.0

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 (362) hide show
  1. package/builtin.d.ts +51 -53
  2. package/builtin.js +30 -34
  3. package/common/fullScreenTriangle.d.ts +2 -10
  4. package/common/fullScreenTriangle.js +20 -28
  5. package/common/index.d.ts +2 -9
  6. package/common/index.js +3 -12
  7. package/common/writeSoA.d.ts +11 -12
  8. package/common/writeSoA.js +88 -76
  9. package/core/buffer/buffer.d.ts +79 -62
  10. package/core/buffer/buffer.js +279 -205
  11. package/core/buffer/bufferBinding.d.ts +71 -0
  12. package/core/buffer/bufferBinding.js +154 -0
  13. package/core/buffer/bufferUsage.d.ts +14 -45
  14. package/core/buffer/bufferUsage.js +1 -171
  15. package/core/buffer/laidOutBuffer.d.ts +25 -0
  16. package/core/buffer/laidOutBuffer.js +55 -0
  17. package/core/commandEncoder/attachments.d.ts +125 -0
  18. package/core/commandEncoder/attachments.js +29 -0
  19. package/core/commandEncoder/commandEncoder.d.ts +53 -0
  20. package/core/commandEncoder/commandEncoder.js +56 -0
  21. package/core/commandEncoder/computePass.d.ts +58 -0
  22. package/core/commandEncoder/computePass.js +63 -0
  23. package/core/commandEncoder/renderPass.d.ts +121 -0
  24. package/core/commandEncoder/renderPass.js +196 -0
  25. package/core/constant/tgpuConstant.d.ts +26 -26
  26. package/core/constant/tgpuConstant.js +76 -65
  27. package/core/declare/tgpuDeclare.d.ts +3 -6
  28. package/core/declare/tgpuDeclare.js +36 -36
  29. package/core/function/autoIO.d.ts +61 -33
  30. package/core/function/autoIO.js +68 -73
  31. package/core/function/comptime.d.ts +11 -13
  32. package/core/function/comptime.js +60 -52
  33. package/core/function/createCallableSchema.d.ts +16 -0
  34. package/core/function/createCallableSchema.js +50 -40
  35. package/core/function/dualImpl.d.ts +44 -0
  36. package/core/function/dualImpl.js +71 -50
  37. package/core/function/entryInputRouter.d.ts +26 -0
  38. package/core/function/entryInputRouter.js +31 -33
  39. package/core/function/extractArgs.d.ts +38 -0
  40. package/core/function/extractArgs.js +202 -200
  41. package/core/function/fnCore.d.ts +44 -5
  42. package/core/function/fnCore.js +148 -93
  43. package/core/function/fnTypes.d.ts +31 -29
  44. package/core/function/fnTypes.js +1 -0
  45. package/core/function/ioSchema.d.ts +12 -10
  46. package/core/function/ioSchema.js +65 -47
  47. package/core/function/shelllessImpl.d.ts +9 -12
  48. package/core/function/shelllessImpl.js +17 -22
  49. package/core/function/templateUtils.d.ts +2 -0
  50. package/core/function/templateUtils.js +9 -8
  51. package/core/function/tgpuComputeFn.d.ts +26 -28
  52. package/core/function/tgpuComputeFn.js +47 -48
  53. package/core/function/tgpuFn.d.ts +34 -37
  54. package/core/function/tgpuFn.js +179 -153
  55. package/core/function/tgpuFragmentFn.d.ts +52 -53
  56. package/core/function/tgpuFragmentFn.js +63 -56
  57. package/core/function/tgpuVertexFn.d.ts +36 -39
  58. package/core/function/tgpuVertexFn.js +56 -53
  59. package/core/pipeline/computePipeline.d.ts +141 -53
  60. package/core/pipeline/computePipeline.js +291 -225
  61. package/core/pipeline/connectAttachmentToShader.d.ts +4 -0
  62. package/core/pipeline/connectAttachmentToShader.js +25 -22
  63. package/core/pipeline/connectTargetsToShader.d.ts +3 -0
  64. package/core/pipeline/connectTargetsToShader.js +29 -27
  65. package/core/pipeline/drawState.d.ts +52 -0
  66. package/core/pipeline/drawState.js +225 -0
  67. package/core/pipeline/limitsOverflow.d.ts +2 -0
  68. package/core/pipeline/limitsOverflow.js +13 -10
  69. package/core/pipeline/performanceTracker.d.ts +14 -0
  70. package/core/pipeline/performanceTracker.js +34 -0
  71. package/core/pipeline/pipelineUtils.d.ts +18 -0
  72. package/core/pipeline/pipelineUtils.js +54 -25
  73. package/core/pipeline/priors.d.ts +1 -0
  74. package/core/pipeline/priors.js +12 -0
  75. package/core/pipeline/renderPipeline.d.ts +246 -261
  76. package/core/pipeline/renderPipeline.js +487 -480
  77. package/core/pipeline/timeable.d.ts +28 -18
  78. package/core/pipeline/timeable.js +90 -52
  79. package/core/pipeline/typeGuards.d.ts +17 -0
  80. package/core/pipeline/typeGuards.js +52 -22
  81. package/core/querySet/querySet.d.ts +26 -21
  82. package/core/querySet/querySet.js +127 -103
  83. package/core/rawCodeSnippet/tgpuRawCodeSnippet.d.ts +13 -18
  84. package/core/rawCodeSnippet/tgpuRawCodeSnippet.js +89 -90
  85. package/core/resolve/externals.d.ts +25 -8
  86. package/core/resolve/externals.js +78 -54
  87. package/core/resolve/namespace.d.ts +22 -25
  88. package/core/resolve/namespace.js +16 -21
  89. package/core/resolve/resolvableString.d.ts +7 -0
  90. package/core/resolve/resolvableString.js +13 -0
  91. package/core/resolve/resolveData.d.ts +10 -0
  92. package/core/resolve/resolveData.js +162 -121
  93. package/core/resolve/stitch.d.ts +8 -0
  94. package/core/resolve/stitch.js +23 -21
  95. package/core/resolve/tgpuResolve.d.ts +55 -53
  96. package/core/resolve/tgpuResolve.js +106 -53
  97. package/core/root/configurableImpl.d.ts +10 -0
  98. package/core/root/configurableImpl.js +17 -19
  99. package/core/root/init.d.ts +76 -38
  100. package/core/root/init.js +346 -455
  101. package/core/root/rootTypes.d.ts +461 -636
  102. package/core/root/rootTypes.js +1 -0
  103. package/core/sampler/sampler.d.ts +50 -31
  104. package/core/sampler/sampler.js +120 -113
  105. package/core/simulate/tgpuSimulate.d.ts +9 -12
  106. package/core/simulate/tgpuSimulate.js +68 -71
  107. package/core/slot/accessor.d.ts +36 -13
  108. package/core/slot/accessor.js +138 -91
  109. package/core/slot/internalSlots.d.ts +2 -0
  110. package/core/slot/internalSlots.js +1 -6
  111. package/core/slot/lazy.d.ts +2 -6
  112. package/core/slot/lazy.js +71 -39
  113. package/core/slot/slot.d.ts +2 -6
  114. package/core/slot/slot.js +45 -38
  115. package/core/slot/slotTypes.d.ts +78 -80
  116. package/core/slot/slotTypes.js +11 -16
  117. package/core/texture/externalTexture.d.ts +20 -11
  118. package/core/texture/externalTexture.js +46 -46
  119. package/core/texture/texture.d.ts +152 -97
  120. package/core/texture/texture.js +407 -314
  121. package/core/texture/textureFormats.d.ts +42 -23
  122. package/core/texture/textureFormats.js +104 -75
  123. package/core/texture/textureProps.d.ts +7 -10
  124. package/core/texture/textureProps.js +1 -0
  125. package/core/texture/textureUtils.d.ts +8 -0
  126. package/core/texture/textureUtils.js +185 -179
  127. package/core/texture/usageExtension.d.ts +21 -18
  128. package/core/texture/usageExtension.js +13 -17
  129. package/core/unroll/tgpuUnroll.d.ts +20 -19
  130. package/core/unroll/tgpuUnroll.js +82 -91
  131. package/core/valueProxyUtils.d.ts +3 -0
  132. package/core/valueProxyUtils.js +52 -41
  133. package/core/variable/tgpuVariable.d.ts +26 -27
  134. package/core/variable/tgpuVariable.js +93 -96
  135. package/core/vertexLayout/connectAttributesToShader.d.ts +9 -0
  136. package/core/vertexLayout/connectAttributesToShader.js +61 -56
  137. package/core/vertexLayout/vertexAttribute.d.ts +21 -17
  138. package/core/vertexLayout/vertexAttribute.js +1 -0
  139. package/core/vertexLayout/vertexLayout.d.ts +24 -18
  140. package/core/vertexLayout/vertexLayout.js +130 -99
  141. package/core/whitespaces.d.ts +2 -0
  142. package/core/whitespaces.js +16 -0
  143. package/data/alignIO.d.ts +7 -0
  144. package/data/alignIO.js +13 -13
  145. package/data/alignmentOf.d.ts +5 -8
  146. package/data/alignmentOf.js +90 -75
  147. package/data/array.d.ts +6 -9
  148. package/data/array.js +48 -40
  149. package/data/atomic.d.ts +2 -7
  150. package/data/atomic.js +26 -23
  151. package/data/attributes.d.ts +19 -21
  152. package/data/attributes.js +192 -132
  153. package/data/autoStruct.d.ts +36 -3
  154. package/data/autoStruct.js +84 -81
  155. package/data/compiledIO.d.ts +5 -0
  156. package/data/compiledIO.js +231 -215
  157. package/data/dataIO.d.ts +13 -11
  158. package/data/dataIO.js +643 -589
  159. package/data/dataTypes.d.ts +83 -65
  160. package/data/dataTypes.js +66 -68
  161. package/data/deepEqual.d.ts +2 -7
  162. package/data/deepEqual.js +80 -55
  163. package/data/disarray.d.ts +6 -10
  164. package/data/disarray.js +52 -46
  165. package/data/float16Conversion.d.ts +4 -0
  166. package/data/float16Conversion.js +7 -0
  167. package/data/getLongestContiguousPrefix.d.ts +4 -8
  168. package/data/getLongestContiguousPrefix.js +6 -11
  169. package/data/index.d.ts +30 -31
  170. package/data/index.js +39 -172
  171. package/data/instanceToSchema.d.ts +24 -27
  172. package/data/instanceToSchema.js +1 -0
  173. package/data/isContiguous.d.ts +4 -8
  174. package/data/isContiguous.js +6 -11
  175. package/data/matrix.d.ts +21 -21
  176. package/data/matrix.js +513 -505
  177. package/data/numberOps.d.ts +6 -0
  178. package/data/numberOps.js +26 -20
  179. package/data/numeric.d.ts +21 -12
  180. package/data/numeric.js +287 -197
  181. package/data/offsetUtils.d.ts +9 -13
  182. package/data/offsetUtils.js +204 -144
  183. package/data/offsets.d.ts +8 -0
  184. package/data/offsets.js +33 -33
  185. package/data/partialIO.d.ts +13 -8
  186. package/data/partialIO.js +124 -113
  187. package/data/ptr.d.ts +12 -12
  188. package/data/ptr.js +42 -44
  189. package/data/ref.d.ts +40 -27
  190. package/data/ref.js +125 -95
  191. package/data/sampler.d.ts +99 -101
  192. package/data/sampler.js +17 -21
  193. package/data/schemaCallWrapper.d.ts +19 -0
  194. package/data/schemaCallWrapper.js +31 -26
  195. package/data/schemaMemoryLayout.d.ts +8 -0
  196. package/data/schemaMemoryLayout.js +213 -185
  197. package/data/sizeOf.d.ts +4 -8
  198. package/data/sizeOf.js +6 -11
  199. package/data/snippet.d.ts +96 -20
  200. package/data/snippet.js +75 -86
  201. package/data/struct.d.ts +4 -7
  202. package/data/struct.js +51 -39
  203. package/data/texture.d.ts +253 -250
  204. package/data/texture.js +238 -200
  205. package/data/unstruct.d.ts +2 -7
  206. package/data/unstruct.js +43 -37
  207. package/data/vector.d.ts +33 -21
  208. package/data/vector.js +234 -221
  209. package/data/vectorImpl.d.ts +231 -0
  210. package/data/vectorImpl.js +563 -515
  211. package/data/vectorOps.d.ts +63 -0
  212. package/data/vectorOps.js +642 -630
  213. package/data/vertexFormatData.d.ts +181 -184
  214. package/data/vertexFormatData.js +104 -106
  215. package/data/wgslTypes.d.ts +665 -600
  216. package/data/wgslTypes.js +220 -198
  217. package/errors.d.ts +50 -24
  218. package/errors.js +146 -126
  219. package/execMode.d.ts +16 -0
  220. package/execMode.js +47 -40
  221. package/extension.d.ts +13 -8
  222. package/extension.js +10 -16
  223. package/getGPUValue.d.ts +1 -0
  224. package/getGPUValue.js +2 -7
  225. package/index.d.ts +28 -68
  226. package/index.js +8 -28
  227. package/indexNamedExports.d.ts +69 -42
  228. package/indexNamedExports.js +25 -0
  229. package/internal.d.ts +16 -0
  230. package/internal.js +12 -0
  231. package/mathUtils.d.ts +5 -0
  232. package/mathUtils.js +7 -11
  233. package/memo.d.ts +11 -0
  234. package/memo.js +20 -22
  235. package/minify.d.ts +5 -0
  236. package/minify.js +93 -0
  237. package/nameUtils.d.ts +29 -0
  238. package/nameUtils.js +427 -394
  239. package/package.json +5 -1
  240. package/resolutionCtx.d.ts +162 -22
  241. package/resolutionCtx.js +911 -629
  242. package/serial/registry.d.ts +15 -0
  243. package/serial/registry.js +106 -0
  244. package/serial/restore.d.ts +49 -0
  245. package/serial/restore.js +68 -0
  246. package/serial/schema.d.ts +58 -0
  247. package/serial/schema.js +209 -0
  248. package/serial/types.d.ts +5 -0
  249. package/serial/types.js +1 -0
  250. package/shared/env.d.ts +9 -0
  251. package/shared/env.js +9 -12
  252. package/shared/generators.d.ts +4 -0
  253. package/shared/generators.js +10 -12
  254. package/shared/meta.d.ts +29 -14
  255. package/shared/meta.js +71 -55
  256. package/shared/normalizeMetadata.d.ts +32 -27
  257. package/shared/normalizeMetadata.js +23 -36
  258. package/shared/repr.d.ts +73 -55
  259. package/shared/repr.js +1 -0
  260. package/shared/soul.d.ts +17 -0
  261. package/shared/soul.js +1 -0
  262. package/shared/stringify.d.ts +2 -0
  263. package/shared/stringify.js +29 -20
  264. package/shared/symbols.d.ts +26 -20
  265. package/shared/symbols.js +79 -79
  266. package/shared/tseynit.d.ts +2 -0
  267. package/shared/tseynit.js +160 -75
  268. package/shared/utilityTypes.d.ts +30 -14
  269. package/shared/utilityTypes.js +2 -6
  270. package/shared/vertexFormat.d.ts +41 -43
  271. package/shared/vertexFormat.js +59 -62
  272. package/std/array.d.ts +2 -7
  273. package/std/array.js +18 -23
  274. package/std/atomic.d.ts +14 -18
  275. package/std/atomic.js +96 -95
  276. package/std/bitcast.d.ts +193 -10
  277. package/std/bitcast.js +309 -39
  278. package/std/boolean.d.ts +19 -33
  279. package/std/boolean.js +296 -288
  280. package/std/copy.d.ts +2 -7
  281. package/std/copy.js +27 -24
  282. package/std/derivative.d.ts +11 -15
  283. package/std/derivative.js +56 -79
  284. package/std/discard.d.ts +1 -6
  285. package/std/discard.js +7 -14
  286. package/std/environment.d.ts +19 -14
  287. package/std/environment.js +71 -51
  288. package/std/extensions.d.ts +2 -8
  289. package/std/extensions.js +10 -11
  290. package/std/index.d.ts +20 -24
  291. package/std/index.js +32 -187
  292. package/std/matrix.d.ts +6 -12
  293. package/std/matrix.js +60 -69
  294. package/std/numeric.d.ts +143 -146
  295. package/std/numeric.js +858 -749
  296. package/std/operators.d.ts +19 -27
  297. package/std/operators.js +227 -193
  298. package/std/packing.d.ts +5 -11
  299. package/std/packing.js +67 -75
  300. package/std/range.d.ts +6 -11
  301. package/std/range.js +48 -36
  302. package/std/subgroup.d.ts +33 -37
  303. package/std/subgroup.js +180 -217
  304. package/std/texture.d.ts +70 -38
  305. package/std/texture.js +176 -172
  306. package/taskQueue.d.ts +6 -0
  307. package/taskQueue.js +30 -0
  308. package/tgpu.d.ts +16 -0
  309. package/tgpu.js +17 -44
  310. package/tgpuBindGroupLayout.d.ts +132 -152
  311. package/tgpuBindGroupLayout.js +346 -268
  312. package/tgpuLogger.d.ts +34 -0
  313. package/tgpuLogger.js +63 -0
  314. package/tgpuUnstable.d.ts +16 -22
  315. package/tgpuUnstable.js +13 -35
  316. package/tgsl/accessIndex.d.ts +2 -0
  317. package/tgsl/accessIndex.js +76 -33
  318. package/tgsl/accessProp.d.ts +2 -0
  319. package/tgsl/accessProp.js +142 -101
  320. package/tgsl/accessStructProp.d.ts +5 -0
  321. package/tgsl/accessStructProp.js +13 -15
  322. package/tgsl/consoleLog/deserializers.d.ts +13 -0
  323. package/tgsl/consoleLog/deserializers.js +119 -103
  324. package/tgsl/consoleLog/logGenerator.d.ts +21 -0
  325. package/tgsl/consoleLog/logGenerator.js +85 -80
  326. package/tgsl/consoleLog/serializers.d.ts +21 -0
  327. package/tgsl/consoleLog/serializers.js +119 -100
  328. package/tgsl/consoleLog/types.d.ts +40 -39
  329. package/tgsl/consoleLog/types.js +1 -0
  330. package/tgsl/conversion.d.ts +33 -0
  331. package/tgsl/conversion.js +271 -216
  332. package/tgsl/forOfUtils.d.ts +15 -0
  333. package/tgsl/forOfUtils.js +85 -70
  334. package/tgsl/generationHelpers.d.ts +22 -39
  335. package/tgsl/generationHelpers.js +85 -58
  336. package/tgsl/infixDispatch.d.ts +70 -0
  337. package/tgsl/infixDispatch.js +48 -46
  338. package/tgsl/jsPolyfills.d.ts +16 -19
  339. package/tgsl/jsPolyfills.js +44 -42
  340. package/tgsl/makeDereferenceable.d.ts +48 -0
  341. package/tgsl/makeDereferenceable.js +86 -0
  342. package/tgsl/makeResolvable.d.ts +22 -0
  343. package/tgsl/makeResolvable.js +33 -0
  344. package/tgsl/shaderGenerator.d.ts +77 -17
  345. package/tgsl/shaderGenerator.js +1 -0
  346. package/tgsl/shellless.d.ts +6 -9
  347. package/tgsl/shellless.js +73 -43
  348. package/tgsl/wgslGenerator.d.ts +66 -59
  349. package/tgsl/wgslGenerator.js +1344 -760
  350. package/types.d.ts +287 -222
  351. package/types.js +61 -44
  352. package/unwrapper.d.ts +31 -26
  353. package/unwrapper.js +1 -0
  354. package/wgslExtensions.d.ts +3 -5
  355. package/wgslExtensions.js +12 -16
  356. package/_virtual/rolldown_runtime.js +0 -13
  357. package/core/buffer/bufferShorthand.d.ts +0 -50
  358. package/core/buffer/bufferShorthand.js +0 -55
  359. package/core/pipeline/applyPipelineState.js +0 -37
  360. package/package.js +0 -5
  361. package/tgsl/shaderGenerator_members.d.ts +0 -33
  362. package/tgsl/shaderGenerator_members.js +0 -12
package/resolutionCtx.js CHANGED
@@ -1,643 +1,925 @@
1
- import { $internal, $providing, $resolve, isMarkedInternal } from "./shared/symbols.js";
2
- import { Void, isPtr, isWgslArray, isWgslStruct } from "./data/wgslTypes.js";
3
- import { safeStringify } from "./shared/stringify.js";
4
- import { getName, hasTinyestMetadata, isNamable, setName } from "./shared/meta.js";
5
- import { UnknownData, isData } from "./data/dataTypes.js";
6
- import { snip } from "./data/snippet.js";
7
- import { MissingSlotValueError, ResolutionError, WgslTypeError, invariant } from "./errors.js";
8
- import { isLazy, isProviding, isSlot } from "./core/slot/slotTypes.js";
9
- import { CodegenState, NormalState, isSelfResolvable } from "./types.js";
1
+ import { ConfigurableImpl } from "./core/root/configurableImpl.js";
2
+ import { isLazy, isProviding, isSlot, } from "./core/slot/slotTypes.js";
3
+ import { isData, UnknownData } from "./data/dataTypes.js";
4
+ import { bool } from "./data/numeric.js";
5
+ import { snip, withValue, } from "./data/snippet.js";
6
+ import { isPtr, isWgslArray, isWgslStruct, Void } from "./data/wgslTypes.js";
7
+ import { invariant, MissingSlotValueError, ResolutionError, WgslTypeError } from "./errors.js";
10
8
  import { provideCtx, topLevelState } from "./execMode.js";
9
+ import { naturalsExcept } from "./shared/generators.js";
10
+ import { isMarkedInternal } from "./shared/symbols.js";
11
+ import { safeStringify } from "./shared/stringify.js";
12
+ import { $internal, $providing, $resolve } from "./shared/symbols.js";
13
+ import { bindGroupLayout, TgpuBindGroupImpl, } from "./tgpuBindGroupLayout.js";
14
+ import { LogGeneratorImpl, LogGeneratorNullImpl } from "./tgsl/consoleLog/logGenerator.js";
11
15
  import { getBestConversion } from "./tgsl/conversion.js";
12
- import { bool } from "./data/numeric.js";
13
16
  import { coerceToSnippet, concretize, numericLiteralToSnippet } from "./tgsl/generationHelpers.js";
14
- import { bannedTokens, sanitizePrimer, validateIdentifier } from "./nameUtils.js";
17
+ import { WgslGenerator } from "./tgsl/wgslGenerator.js";
18
+ import { CodegenState, isSelfResolvable, NormalState } from "./types.js";
19
+ import { getName, hasTinyestMetadata, isNamable, setName } from "./shared/meta.js";
20
+ import { FuncParameterType } from 'tinyest';
21
+ import { accessProp } from "./tgsl/accessProp.js";
15
22
  import { createIoSchema } from "./core/function/ioSchema.js";
23
+ import { isShelllessImpl } from "./core/function/shelllessImpl.js";
24
+ import { isTgpuFn } from "./core/function/tgpuFn.js";
16
25
  import { AutoStruct } from "./data/autoStruct.js";
17
26
  import { EntryInputRouter } from "./core/function/entryInputRouter.js";
18
- import { accessProp } from "./tgsl/accessProp.js";
19
- import { isTgpuFn } from "./core/function/tgpuFn.js";
20
- import { ConfigurableImpl } from "./core/root/configurableImpl.js";
21
- import { naturalsExcept } from "./shared/generators.js";
22
- import { TgpuBindGroupImpl, bindGroupLayout } from "./tgpuBindGroupLayout.js";
23
- import { LogGeneratorImpl, LogGeneratorNullImpl } from "./tgsl/consoleLog/logGenerator.js";
24
- import wgslGenerator_default from "./tgsl/wgslGenerator.js";
25
- import { isShelllessImpl } from "./core/function/shelllessImpl.js";
26
- import { FuncParameterType } from "tinyest";
27
-
28
- //#region src/resolutionCtx.ts
27
+ import { validateIdentifier, sanitizePrimer, bannedTokens } from "./nameUtils.js";
28
+ import { minify } from "./minify.js";
29
29
  /**
30
- * Inserted into bind group entry definitions that belong
31
- * to the automatically generated catch-all bind group.
32
- *
33
- * A non-occupied group index can only be determined after
34
- * every resource has been resolved, so this acts as a placeholder
35
- * to be replaced with an actual numeric index at the very end
36
- * of the resolution process.
37
- */
38
- const CATCHALL_BIND_GROUP_IDX_MARKER = "#CATCHALL#";
39
- var ItemStateStackImpl = class {
40
- _stack = [];
41
- _itemDepth = 0;
42
- get itemDepth() {
43
- return this._itemDepth;
44
- }
45
- get topItem() {
46
- const state = this._stack[this._stack.length - 1];
47
- if (!state || state.type !== "item") throw new Error("Internal error, expected item layer to be on top.");
48
- return state;
49
- }
50
- get topFunctionScope() {
51
- return this._stack.findLast((e) => e.type === "functionScope");
52
- }
53
- get topBlockScope() {
54
- return this._stack.findLast((e) => e.type === "blockScope");
55
- }
56
- pushItem() {
57
- this._itemDepth++;
58
- this._stack.push({
59
- type: "item",
60
- usedSlots: /* @__PURE__ */ new Set()
61
- });
62
- }
63
- pushSlotBindings(pairs) {
64
- this._stack.push({
65
- type: "slotBinding",
66
- bindingMap: new WeakMap(pairs)
67
- });
68
- }
69
- pushFunctionScope(functionType, argAccess, returnType, externalMap) {
70
- const scope = {
71
- type: "functionScope",
72
- functionType,
73
- argAccess,
74
- returnType,
75
- externalMap,
76
- reportedReturnTypes: /* @__PURE__ */ new Set(),
77
- placeholderForVariable: /* @__PURE__ */ new Map(),
78
- modifiedVariables: /* @__PURE__ */ new Set()
79
- };
80
- this._stack.push(scope);
81
- return scope;
82
- }
83
- pushBlockScope() {
84
- this._stack.push({
85
- type: "blockScope",
86
- takenLocalIdentifiers: /* @__PURE__ */ new Set(),
87
- declarations: /* @__PURE__ */ new Map(),
88
- externals: /* @__PURE__ */ new Map()
89
- });
90
- }
91
- pop(type) {
92
- const layer = this._stack[this._stack.length - 1];
93
- if (!layer || type && layer.type !== type) throw new Error(`Internal error, expected a ${type} layer to be on top.`);
94
- const poppedValue = this._stack.pop();
95
- if (type === "item") this._itemDepth--;
96
- return poppedValue;
97
- }
98
- readSlot(slot) {
99
- for (let i = this._stack.length - 1; i >= 0; --i) {
100
- const layer = this._stack[i];
101
- if (layer?.type === "item") layer.usedSlots.add(slot);
102
- else if (layer?.type === "slotBinding") {
103
- const boundValue = layer.bindingMap.get(slot);
104
- if (boundValue !== void 0) return boundValue;
105
- } else if (layer?.type === "functionScope" || layer?.type === "blockScope") {} else throw new Error("Unknown layer type.");
106
- }
107
- return slot.defaultValue;
108
- }
109
- getSnippetById(id) {
110
- for (let i = this._stack.length - 1; i >= 0; --i) {
111
- const layer = this._stack[i];
112
- if (layer?.type === "functionScope") {
113
- const access = layer.argAccess[id];
114
- if (access) return access();
115
- const external = layer.externalMap[id];
116
- if (isNamable(external) && getName(external) === void 0) setName(external, id);
117
- if (external !== void 0 && external !== null) return coerceToSnippet(external);
118
- return;
119
- }
120
- if (layer?.type === "blockScope") {
121
- const snippet = layer.declarations.get(id) ?? layer.externals.get(id);
122
- if (snippet !== void 0) return snippet;
123
- }
124
- }
125
- }
126
- isIdentifierTakenLocally(id) {
127
- for (let i = this._stack.length - 1; i >= 0; --i) {
128
- const layer = this._stack[i];
129
- if (layer?.type === "functionScope") return false;
130
- if (layer?.type === "blockScope") {
131
- if (layer.takenLocalIdentifiers.has(id)) return true;
132
- }
133
- }
134
- return false;
135
- }
136
- defineBlockVariable(id, snippet) {
137
- if (snippet.dataType === UnknownData) throw Error(`Tried to define variable '${id}' of unknown type`);
138
- for (let i = this._stack.length - 1; i >= 0; --i) {
139
- const layer = this._stack[i];
140
- if (layer?.type === "blockScope") {
141
- layer.declarations.set(id, snippet);
142
- return;
143
- }
144
- }
145
- throw new Error("No block scope found to define a variable in.");
146
- }
147
- setBlockExternals(externals) {
148
- for (let i = this._stack.length - 1; i >= 0; --i) {
149
- const layer = this._stack[i];
150
- if (layer?.type === "blockScope") {
151
- Object.entries(externals).forEach(([id, snippet]) => {
152
- layer.externals.set(id, snippet);
153
- });
154
- return;
155
- }
156
- }
157
- throw new Error("No block scope found to set externals in.");
158
- }
159
- clearBlockExternals() {
160
- for (let i = this._stack.length - 1; i >= 0; --i) {
161
- const layer = this._stack[i];
162
- if (layer?.type === "blockScope") {
163
- layer.externals.clear();
164
- return;
165
- }
166
- }
167
- throw new Error("No block scope found to clear externals in.");
168
- }
169
- };
30
+ * Inserted into bind group entry definitions that belong
31
+ * to the automatically generated catch-all bind group.
32
+ *
33
+ * A non-occupied group index can only be determined after
34
+ * every resource has been resolved, so this acts as a placeholder
35
+ * to be replaced with an actual numeric index at the very end
36
+ * of the resolution process.
37
+ */
38
+ const CATCHALL_BIND_GROUP_IDX_MARKER = '#CATCHALL#';
39
+ class ItemStateStackImpl {
40
+ _stack = [];
41
+ _itemDepth = 0;
42
+ get itemDepth() {
43
+ return this._itemDepth;
44
+ }
45
+ get topItem() {
46
+ const state = this._stack[this._stack.length - 1];
47
+ if (!state || state.type !== 'item') {
48
+ throw new Error('Internal error, expected item layer to be on top.');
49
+ }
50
+ return state;
51
+ }
52
+ get topFunctionScope() {
53
+ return this._stack.findLast((e) => e.type === 'functionScope');
54
+ }
55
+ get topBlockScope() {
56
+ return this._stack.findLast((e) => e.type === 'blockScope');
57
+ }
58
+ get blockDepth() {
59
+ let depth = 0;
60
+ for (let i = this._stack.length - 1; i >= 0; --i) {
61
+ const layer = this._stack[i];
62
+ if (layer?.type === 'functionScope') {
63
+ break;
64
+ }
65
+ if (layer?.type === 'blockScope') {
66
+ depth++;
67
+ }
68
+ }
69
+ return depth;
70
+ }
71
+ pushItem() {
72
+ this._itemDepth++;
73
+ this._stack.push({
74
+ type: 'item',
75
+ usedSlots: new Set(),
76
+ });
77
+ }
78
+ pushSlotBindings(pairs) {
79
+ this._stack.push({
80
+ type: 'slotBinding',
81
+ bindingMap: new WeakMap(pairs),
82
+ });
83
+ }
84
+ pushFunctionScope(functionType, argAccess, returnType, externalMap) {
85
+ const scope = {
86
+ type: 'functionScope',
87
+ functionType,
88
+ argAccess,
89
+ returnType,
90
+ externalMap,
91
+ reportedReturnTypes: new Set(),
92
+ placeholderForVariable: new Map(),
93
+ modifiedVariables: new Set(),
94
+ };
95
+ this._stack.push(scope);
96
+ return scope;
97
+ }
98
+ pushBlockScope() {
99
+ this._stack.push({
100
+ type: 'blockScope',
101
+ takenLocalIdentifiers: new Set(),
102
+ declarations: new Map(),
103
+ externals: new Map(),
104
+ });
105
+ }
106
+ pop(type) {
107
+ const layer = this._stack[this._stack.length - 1];
108
+ if (!layer || (type && layer.type !== type)) {
109
+ throw new Error(`Internal error, expected a ${type} layer to be on top.`);
110
+ }
111
+ const poppedValue = this._stack.pop();
112
+ if (type === 'item') {
113
+ this._itemDepth--;
114
+ }
115
+ return poppedValue;
116
+ }
117
+ readSlot(slot) {
118
+ for (let i = this._stack.length - 1; i >= 0; --i) {
119
+ const layer = this._stack[i];
120
+ if (layer?.type === 'item') {
121
+ // Binding not available yet, so this layer is dependent on the slot's value.
122
+ layer.usedSlots.add(slot);
123
+ }
124
+ else if (layer?.type === 'slotBinding') {
125
+ const boundValue = layer.bindingMap.get(slot);
126
+ if (boundValue !== undefined) {
127
+ return boundValue;
128
+ }
129
+ }
130
+ else if (layer?.type === 'functionScope' || layer?.type === 'blockScope') {
131
+ // Skip
132
+ }
133
+ else {
134
+ throw new Error('Unknown layer type.');
135
+ }
136
+ }
137
+ return slot.defaultValue;
138
+ }
139
+ getSnippetById(id) {
140
+ for (let i = this._stack.length - 1; i >= 0; --i) {
141
+ const layer = this._stack[i];
142
+ if (layer?.type === 'functionScope') {
143
+ const access = layer.argAccess[id];
144
+ if (access) {
145
+ return access();
146
+ }
147
+ if (Object.hasOwn(layer.externalMap, id)) {
148
+ const external = layer.externalMap[id];
149
+ if (isNamable(external) && getName(external) === undefined) {
150
+ setName(external, id.replaceAll('.', '_'));
151
+ }
152
+ return coerceToSnippet(external);
153
+ }
154
+ return undefined;
155
+ }
156
+ if (layer?.type === 'blockScope') {
157
+ // the order matters
158
+ const snippet = layer.declarations.get(id) ?? layer.externals.get(id);
159
+ if (snippet !== undefined) {
160
+ return snippet;
161
+ }
162
+ }
163
+ else {
164
+ // Skip
165
+ }
166
+ }
167
+ return undefined;
168
+ }
169
+ /**
170
+ * Returns whether the given identifier is taken in any block scope up to the nearest function scope.
171
+ */
172
+ isIdentifierTakenLocally(id) {
173
+ for (let i = this._stack.length - 1; i >= 0; --i) {
174
+ const layer = this._stack[i];
175
+ if (layer?.type === 'functionScope') {
176
+ // Since functions cannot access resources from the calling scope, we
177
+ // return early here.
178
+ return false;
179
+ }
180
+ if (layer?.type === 'blockScope') {
181
+ if (layer.takenLocalIdentifiers.has(id)) {
182
+ return true;
183
+ }
184
+ }
185
+ }
186
+ return false;
187
+ }
188
+ /**
189
+ * Returns whether the given identifier is taken in any block scope on the stack.
190
+ *
191
+ * This is useful when resolving a global identifier for the first time within a nested function.
192
+ */
193
+ isIdentifierTakenInCallStack(id) {
194
+ for (let i = this._stack.length - 1; i >= 0; --i) {
195
+ const layer = this._stack[i];
196
+ if (layer?.type === 'blockScope') {
197
+ if (layer.takenLocalIdentifiers.has(id)) {
198
+ return true;
199
+ }
200
+ }
201
+ }
202
+ return false;
203
+ }
204
+ defineBlockVariable(id, snippet) {
205
+ if (snippet.dataType === UnknownData) {
206
+ throw Error(`Tried to define variable '${id}' of unknown type`);
207
+ }
208
+ for (let i = this._stack.length - 1; i >= 0; --i) {
209
+ const layer = this._stack[i];
210
+ if (layer?.type === 'blockScope') {
211
+ layer.declarations.set(id, snippet);
212
+ return;
213
+ }
214
+ }
215
+ throw new Error('No block scope found to define a variable in.');
216
+ }
217
+ setBlockExternals(externals) {
218
+ for (let i = this._stack.length - 1; i >= 0; --i) {
219
+ const layer = this._stack[i];
220
+ if (layer?.type === 'blockScope') {
221
+ Object.entries(externals).forEach(([id, snippet]) => {
222
+ layer.externals.set(id, snippet);
223
+ });
224
+ return;
225
+ }
226
+ }
227
+ throw new Error('No block scope found to set externals in.');
228
+ }
229
+ clearBlockExternals() {
230
+ for (let i = this._stack.length - 1; i >= 0; --i) {
231
+ const layer = this._stack[i];
232
+ if (layer?.type === 'blockScope') {
233
+ layer.externals.clear();
234
+ return;
235
+ }
236
+ }
237
+ throw new Error('No block scope found to clear externals in.');
238
+ }
239
+ }
170
240
  const INDENT = [
171
- "",
172
- " ",
173
- " ",
174
- " ",
175
- " ",
176
- " ",
177
- " ",
178
- " ",
179
- " "
241
+ '', // 0
242
+ ' ', // 1
243
+ ' ', // 2
244
+ ' ', // 3
245
+ ' ', // 4
246
+ ' ', // 5
247
+ ' ', // 6
248
+ ' ', // 7
249
+ ' ', // 8
180
250
  ];
181
251
  const N = INDENT.length - 1;
182
- var IndentController = class {
183
- identLevel = 0;
184
- get pre() {
185
- return INDENT[this.identLevel] ?? INDENT[N].repeat(this.identLevel / N) + INDENT[this.identLevel % N];
186
- }
187
- indent() {
188
- const str = this.pre;
189
- this.identLevel++;
190
- return str;
191
- }
192
- dedent() {
193
- this.identLevel--;
194
- return this.pre;
195
- }
196
- withResetLevel(callback) {
197
- const savedLevel = this.identLevel;
198
- this.identLevel = 0;
199
- try {
200
- return callback();
201
- } finally {
202
- this.identLevel = savedLevel;
203
- }
204
- }
205
- };
206
- function createArgument(name, type, origin = "argument") {
207
- let used = false;
208
- return {
209
- name,
210
- access: () => {
211
- used = true;
212
- return snip(name, type, origin);
213
- },
214
- decoratedType: type,
215
- get used() {
216
- return used;
217
- }
218
- };
252
+ export class IndentController {
253
+ identLevel = 0;
254
+ get pre() {
255
+ return (INDENT[this.identLevel] ??
256
+ INDENT[N].repeat(this.identLevel / N) + INDENT[this.identLevel % N]);
257
+ }
258
+ indent() {
259
+ const str = this.pre;
260
+ this.identLevel++;
261
+ return str;
262
+ }
263
+ dedent() {
264
+ this.identLevel--;
265
+ return this.pre;
266
+ }
267
+ withResetLevel(callback) {
268
+ const savedLevel = this.identLevel;
269
+ this.identLevel = 0;
270
+ try {
271
+ return callback();
272
+ }
273
+ finally {
274
+ this.identLevel = savedLevel;
275
+ }
276
+ }
277
+ }
278
+ function createArgument(name, type, origin = 'argument') {
279
+ let used = false;
280
+ return {
281
+ name,
282
+ access: () => {
283
+ used = true;
284
+ return snip(name, type, origin, /* possibleSideEffects */ false);
285
+ },
286
+ decoratedType: type,
287
+ get used() {
288
+ return used;
289
+ },
290
+ };
219
291
  }
220
292
  function createArgumentPropAccess(argAccess, prop) {
221
- return () => {
222
- const argSnippet = argAccess();
223
- if (!argSnippet) return;
224
- return accessProp(argSnippet, prop);
225
- };
293
+ return () => {
294
+ const argSnippet = argAccess();
295
+ if (!argSnippet) {
296
+ return undefined;
297
+ }
298
+ return accessProp(argSnippet, prop);
299
+ };
300
+ }
301
+ export class ResolutionCtxImpl {
302
+ #namespaceInternal;
303
+ _indentController = new IndentController();
304
+ _itemStateStack = new ItemStateStackImpl();
305
+ #modeStack = [];
306
+ _declarations = [];
307
+ _varyingLocations;
308
+ /**
309
+ * Holds a set of base (slot-less) functions that have started their resolution process.
310
+ * Used for recursion detection check - a function is recursive if:
311
+ * - it was passed to ctx.resolve while already present in this set,
312
+ * - it never finished resolution (<=> it does not appear in `memoizedResolves`).
313
+ * The set is NOT cleared after the resolution finishes.
314
+ */
315
+ #startedFunctionResolves = new WeakSet();
316
+ #logGenerator;
317
+ gen;
318
+ get varyingLocations() {
319
+ return this._varyingLocations;
320
+ }
321
+ [$internal] = {
322
+ itemStateStack: this._itemStateStack,
323
+ };
324
+ // -- Bindings
325
+ /**
326
+ * A map from registered bind group layouts to random strings put in
327
+ * place of their group index. The whole tree has to be traversed to
328
+ * collect every use of a typed bind group layout, since they can be
329
+ * explicitly imposed group indices, and they cannot collide.
330
+ */
331
+ bindGroupLayoutsToPlaceholderMap = new Map();
332
+ _nextFreeLayoutPlaceholderIdx = 0;
333
+ fixedBindings = [];
334
+ // --
335
+ enableExtensions;
336
+ expectedType;
337
+ /**
338
+ * A counter used to generate unique identifiers for globally-scoped definitions in the 'random' strategy.
339
+ */
340
+ #lastUniqueId = 0;
341
+ constructor(opts) {
342
+ this.enableExtensions = opts.enableExtensions;
343
+ this.#logGenerator = opts.root ? new LogGeneratorImpl(opts.root) : new LogGeneratorNullImpl();
344
+ this.#namespaceInternal = opts.namespace[$internal];
345
+ this.gen = opts.shaderGenerator ?? new WgslGenerator();
346
+ this.gen.initGenerator(this);
347
+ }
348
+ isIdentifierBanned(name) {
349
+ return bannedTokens.has(name);
350
+ }
351
+ isIdentifierTaken(name, scope) {
352
+ return (this.#namespaceInternal.takenGlobalIdentifiers.has(name) ||
353
+ (scope === 'block'
354
+ ? this._itemStateStack.isIdentifierTakenLocally(name)
355
+ : this._itemStateStack.isIdentifierTakenInCallStack(name)));
356
+ }
357
+ makeUniqueIdentifier(primer = 'item', scope) {
358
+ if (scope === 'block' &&
359
+ validateIdentifier(primer).success &&
360
+ !this.isIdentifierTaken(primer, scope)) {
361
+ // Preserving local definitions as they are, provided they are valid and not already taken.
362
+ this.reserveIdentifier(primer, 'block');
363
+ return primer;
364
+ }
365
+ const base = sanitizePrimer(primer);
366
+ let index = 0;
367
+ const random = this.#namespaceInternal.strategy === 'random';
368
+ let name = random ? `${base}_${this.#lastUniqueId++}` : base;
369
+ while (this.isIdentifierTaken(name, scope)) {
370
+ name = random ? `${base}_${this.#lastUniqueId++}` : `${base}_${++index}`;
371
+ }
372
+ this.reserveIdentifier(name, scope);
373
+ return name;
374
+ }
375
+ reserveIdentifier(name, scope) {
376
+ if (scope === 'block') {
377
+ const blockScope = this._itemStateStack.topBlockScope;
378
+ if (blockScope) {
379
+ blockScope.takenLocalIdentifiers.add(name);
380
+ return;
381
+ }
382
+ // Fall through if no block scope is present, treating as global.
383
+ }
384
+ this.#namespaceInternal.takenGlobalIdentifiers.add(name);
385
+ }
386
+ get pre() {
387
+ return this._indentController.pre;
388
+ }
389
+ get topFunctionScope() {
390
+ return this._itemStateStack.topFunctionScope;
391
+ }
392
+ get topFunctionReturnType() {
393
+ const scope = this._itemStateStack.topFunctionScope;
394
+ invariant(scope, 'Internal error, expected function scope to be present.');
395
+ return scope.returnType;
396
+ }
397
+ get shelllessRepo() {
398
+ return this.#namespaceInternal.shelllessRepo;
399
+ }
400
+ get blockDepth() {
401
+ return this._itemStateStack.blockDepth;
402
+ }
403
+ indent() {
404
+ return this._indentController.indent();
405
+ }
406
+ dedent() {
407
+ return this._indentController.dedent();
408
+ }
409
+ getDedented(code) {
410
+ return code.replaceAll(`\n${INDENT[1]}`, '\n');
411
+ }
412
+ withResetIndentLevel(callback) {
413
+ return this._indentController.withResetLevel(callback);
414
+ }
415
+ getById(id) {
416
+ const item = this._itemStateStack.getSnippetById(id);
417
+ if (item === undefined) {
418
+ return null;
419
+ }
420
+ return item;
421
+ }
422
+ defineVariable(id, snippet) {
423
+ this._itemStateStack.defineBlockVariable(id, snippet);
424
+ }
425
+ reportReturnType(dataType) {
426
+ const scope = this._itemStateStack.topFunctionScope;
427
+ invariant(scope, 'Internal error, expected function scope to be present.');
428
+ scope.reportedReturnTypes.add(dataType);
429
+ }
430
+ pushBlockScope() {
431
+ this._itemStateStack.pushBlockScope();
432
+ }
433
+ popBlockScope() {
434
+ this._itemStateStack.pop('blockScope');
435
+ }
436
+ setBlockExternals(externals) {
437
+ this._itemStateStack.setBlockExternals(externals);
438
+ }
439
+ clearBlockExternals() {
440
+ this._itemStateStack.clearBlockExternals();
441
+ }
442
+ generateLog(op, args) {
443
+ return this.#logGenerator.generateLog(this, op, args);
444
+ }
445
+ get logResources() {
446
+ return this.#logGenerator.logResources;
447
+ }
448
+ resolveFunction(options) {
449
+ try {
450
+ const scope = this._itemStateStack.pushFunctionScope(options.functionType, {}, options.returnType, options.externalMap);
451
+ // Pushing a block scope as well, so that any identifiers declared at this point will be scoped to the function body.
452
+ this._itemStateStack.pushBlockScope();
453
+ const args = [];
454
+ if (options.entryInput) {
455
+ const { dataSchema, positionalArgs } = options.entryInput;
456
+ const firstParam = options.params[0];
457
+ const structArg = dataSchema
458
+ ? createArgument(this.makeUniqueIdentifier('_arg_0', 'block'), dataSchema)
459
+ : undefined;
460
+ if (structArg) {
461
+ args.push(structArg);
462
+ }
463
+ if (firstParam?.type === FuncParameterType.destructuredObject) {
464
+ // Route each destructured prop to a positional arg or struct field.
465
+ for (const { name, alias } of firstParam.props) {
466
+ const argInfo = positionalArgs.find((a) => a.schemaKey === name);
467
+ if (argInfo) {
468
+ const arg = createArgument(this.makeUniqueIdentifier(alias, 'block'), argInfo.type);
469
+ args.push(arg);
470
+ scope.argAccess[alias] = arg.access;
471
+ }
472
+ else if (structArg) {
473
+ scope.argAccess[alias] = createArgumentPropAccess(structArg.access, name);
474
+ }
475
+ }
476
+ }
477
+ else if (firstParam?.type === FuncParameterType.identifier) {
478
+ // Create named arg snippets, then a proxy for property access routing.
479
+ const proxyEntries = [];
480
+ for (const a of positionalArgs) {
481
+ const argName = this.makeUniqueIdentifier(a.schemaKey, 'block');
482
+ const arg = createArgument(argName, a.type);
483
+ args.push(arg);
484
+ proxyEntries.push({ schemaKey: a.schemaKey, arg: arg.access });
485
+ }
486
+ const router = new EntryInputRouter(structArg?.access, proxyEntries);
487
+ scope.argAccess[firstParam.name] = () => snip('N/A', router, 'argument');
488
+ }
489
+ else {
490
+ // No first param: push positional args with schema key names.
491
+ for (const a of positionalArgs) {
492
+ const argName = this.makeUniqueIdentifier(`_arg_${a.schemaKey}`, 'block');
493
+ const arg = createArgument(argName, a.type);
494
+ args.push(arg);
495
+ scope.argAccess[argName] = arg.access;
496
+ }
497
+ }
498
+ }
499
+ else {
500
+ for (const [i, argType] of options.argTypes.entries()) {
501
+ const astParam = options.params[i];
502
+ // We know if arguments are passed by reference or by value, because we
503
+ // enforce that based on the whether the argument is a pointer or not.
504
+ //
505
+ // It still applies for shell-less functions, since we determine the type
506
+ // of the argument based on the argument's referentiality.
507
+ // In other words, if we pass a reference to a function, it's typed as a pointer,
508
+ // otherwise it's typed as a value.
509
+ const origin = isPtr(argType)
510
+ ? argType.addressSpace === 'storage'
511
+ ? argType.access === 'read'
512
+ ? 'readonly'
513
+ : 'mutable'
514
+ : argType.addressSpace
515
+ : 'argument';
516
+ switch (astParam?.type) {
517
+ case FuncParameterType.identifier: {
518
+ const arg = createArgument(this.makeUniqueIdentifier(astParam.name, 'block'), argType, origin);
519
+ args.push(arg);
520
+ scope.argAccess[astParam.name] = arg.access;
521
+ break;
522
+ }
523
+ case FuncParameterType.destructuredObject: {
524
+ const objArg = createArgument(this.makeUniqueIdentifier(`_arg_${i}`, 'block'), argType, origin);
525
+ args.push(objArg);
526
+ for (const { name, alias } of astParam.props) {
527
+ scope.argAccess[alias] = createArgumentPropAccess(objArg.access, name);
528
+ }
529
+ break;
530
+ }
531
+ case undefined: {
532
+ // Only push the argument if it's not an auto-struct.
533
+ // If we're not using an auto-struct, it's not going to
534
+ // have any properties anyway.
535
+ if (!(argType instanceof AutoStruct)) {
536
+ args.push({
537
+ name: this.makeUniqueIdentifier(`_arg_${i}`, 'block'),
538
+ access: () => {
539
+ throw new Error(`Unreachable: Accessing an argument that wasn't named in the function signature`);
540
+ },
541
+ decoratedType: argType,
542
+ used: false,
543
+ });
544
+ }
545
+ }
546
+ }
547
+ }
548
+ }
549
+ let returnType;
550
+ const code = this.gen.functionDefinition({
551
+ functionType: options.functionType,
552
+ name: options.name,
553
+ workgroupSize: options.workgroupSize,
554
+ args,
555
+ body: options.body,
556
+ determineReturnType: () => {
557
+ if (returnType) {
558
+ // Already determined
559
+ return returnType;
560
+ }
561
+ returnType = options.returnType;
562
+ if (returnType instanceof AutoStruct) {
563
+ // We're expecting an "auto" return type, so if there were structs returned,
564
+ // we accept the struct, otherwise we let the rest of the code unify on a
565
+ // primitive type.
566
+ if (isWgslStruct(scope.reportedReturnTypes.values().next().value)) {
567
+ returnType = returnType.completeStruct;
568
+ }
569
+ else {
570
+ returnType = undefined;
571
+ }
572
+ }
573
+ if (!returnType) {
574
+ const returnTypes = [...scope.reportedReturnTypes];
575
+ if (returnTypes.length === 0) {
576
+ returnType = Void;
577
+ }
578
+ else {
579
+ const conversion = getBestConversion(returnTypes);
580
+ if (conversion && !conversion.hasImplicitConversions) {
581
+ returnType = conversion.targetType;
582
+ }
583
+ }
584
+ if (!returnType) {
585
+ throw new Error(`Expected function to have a single return type, got [${returnTypes.join(', ')}]. Cast explicitly to the desired type.`);
586
+ }
587
+ returnType = concretize(returnType);
588
+ if (options.functionType === 'vertex' || options.functionType === 'fragment') {
589
+ returnType = createIoSchema(returnType);
590
+ }
591
+ }
592
+ return returnType;
593
+ },
594
+ });
595
+ if (!returnType) {
596
+ throw new Error(`Failed to determine return type`);
597
+ }
598
+ return {
599
+ code,
600
+ returnType,
601
+ };
602
+ }
603
+ finally {
604
+ this._itemStateStack.pop('blockScope');
605
+ this._itemStateStack.pop('functionScope');
606
+ }
607
+ }
608
+ addDeclaration(declaration, name) {
609
+ this._declarations.push({ name, code: declaration });
610
+ }
611
+ get declarations() {
612
+ return this._declarations;
613
+ }
614
+ allocateLayoutEntry(layout) {
615
+ const memoMap = this.bindGroupLayoutsToPlaceholderMap;
616
+ let placeholderKey = memoMap.get(layout);
617
+ if (!placeholderKey) {
618
+ placeholderKey = `#BIND_GROUP_LAYOUT_${this._nextFreeLayoutPlaceholderIdx++}#`;
619
+ memoMap.set(layout, placeholderKey);
620
+ }
621
+ return placeholderKey;
622
+ }
623
+ allocateFixedEntry(layoutEntry, resource) {
624
+ const binding = this.fixedBindings.length;
625
+ this.fixedBindings.push({ layoutEntry, resource });
626
+ return {
627
+ group: CATCHALL_BIND_GROUP_IDX_MARKER,
628
+ binding,
629
+ };
630
+ }
631
+ readSlot(slot) {
632
+ const value = this._itemStateStack.readSlot(slot);
633
+ if (value === undefined) {
634
+ throw new MissingSlotValueError(slot);
635
+ }
636
+ return value;
637
+ }
638
+ withSlots(pairs, callback) {
639
+ if (pairs.length === 0) {
640
+ return callback();
641
+ }
642
+ this._itemStateStack.pushSlotBindings(pairs);
643
+ try {
644
+ return callback();
645
+ }
646
+ finally {
647
+ this._itemStateStack.pop('slotBinding');
648
+ }
649
+ }
650
+ withVaryingLocations(locations, callback) {
651
+ this._varyingLocations = locations;
652
+ try {
653
+ return callback();
654
+ }
655
+ finally {
656
+ this._varyingLocations = undefined;
657
+ }
658
+ }
659
+ withRenamed(item, name, callback) {
660
+ if (!name) {
661
+ return callback();
662
+ }
663
+ const oldName = getName(item);
664
+ try {
665
+ setName(item, name);
666
+ return callback();
667
+ }
668
+ finally {
669
+ if (oldName) {
670
+ setName(item, oldName);
671
+ }
672
+ }
673
+ }
674
+ unwrap(eventual) {
675
+ if (isProviding(eventual)) {
676
+ return this.withRenamed(eventual[$providing].inner, getName(eventual), () => this.withSlots(eventual[$providing].pairs, () => this.unwrap(eventual[$providing].inner)));
677
+ }
678
+ let maybeEventual = eventual;
679
+ // Unwrapping all layers of slots.
680
+ while (true) {
681
+ if (isSlot(maybeEventual)) {
682
+ maybeEventual = this.readSlot(maybeEventual);
683
+ }
684
+ else if (isLazy(maybeEventual)) {
685
+ maybeEventual = this._getOrCompute(maybeEventual);
686
+ }
687
+ else {
688
+ break;
689
+ }
690
+ }
691
+ return maybeEventual;
692
+ }
693
+ _getOrCompute(lazy) {
694
+ // All memoized versions of `lazy`
695
+ const instances = this.#namespaceInternal.memoizedLazy.get(lazy) ?? [];
696
+ this._itemStateStack.pushItem();
697
+ try {
698
+ for (const instance of instances) {
699
+ const slotValuePairs = [...instance.slotToValueMap.entries()];
700
+ if (slotValuePairs.every(([slot, expectedValue]) => slot.areEqual(this._itemStateStack.readSlot(slot), expectedValue))) {
701
+ return instance.result;
702
+ }
703
+ }
704
+ // If we got here, no item with the given slot-to-value combo exists in cache yet
705
+ // Getting out of codegen or simulation mode so we can execute JS normally.
706
+ this.pushMode(new NormalState());
707
+ let result;
708
+ try {
709
+ result = lazy[$internal].compute();
710
+ }
711
+ finally {
712
+ this.popMode('normal');
713
+ }
714
+ // We know which slots the item used while resolving
715
+ const slotToValueMap = new Map();
716
+ for (const usedSlot of this._itemStateStack.topItem.usedSlots) {
717
+ slotToValueMap.set(usedSlot, this._itemStateStack.readSlot(usedSlot));
718
+ }
719
+ instances.push({ slotToValueMap, result });
720
+ this.#namespaceInternal.memoizedLazy.set(lazy, instances);
721
+ return result;
722
+ }
723
+ catch (err) {
724
+ if (err instanceof ResolutionError) {
725
+ throw err.appendToTrace(lazy);
726
+ }
727
+ throw new ResolutionError(err, [lazy]);
728
+ }
729
+ finally {
730
+ this._itemStateStack.pop('item');
731
+ }
732
+ }
733
+ /**
734
+ * @param item The item whose resolution should be either retrieved from the cache (if there is a cache hit), or resolved.
735
+ */
736
+ _getOrInstantiate(item) {
737
+ // All memoized versions of `item`
738
+ const instances = this.#namespaceInternal.memoizedResolves.get(item) ?? [];
739
+ this._itemStateStack.pushItem();
740
+ try {
741
+ for (const instance of instances) {
742
+ const slotValuePairs = [...instance.slotToValueMap.entries()];
743
+ if (slotValuePairs.every(([slot, expectedValue]) => slot.areEqual(this._itemStateStack.readSlot(slot), expectedValue))) {
744
+ return instance.result;
745
+ }
746
+ }
747
+ // If we got here, no item with the given slot-to-value combo exists in cache yet
748
+ let result;
749
+ if (isData(item)) {
750
+ // Ref is arbitrary, as we're resolving a schema
751
+ result = snip(this.gen.emitTypeAnnotation(item), Void, /* origin */ 'runtime');
752
+ }
753
+ else if (isLazy(item) || isSlot(item)) {
754
+ result = this.resolve(this.unwrap(item));
755
+ }
756
+ else if (isSelfResolvable(item)) {
757
+ result = item[$resolve](this);
758
+ }
759
+ else if (hasTinyestMetadata(item)) {
760
+ // Resolving a function with tinyest metadata directly means calling it with no arguments, since
761
+ // we cannot infer the types of the arguments from a WGSL string.
762
+ const shellless = this.#namespaceInternal.shelllessRepo.get(item,
763
+ /* no arguments */ undefined);
764
+ if (!shellless) {
765
+ throw new Error(`Couldn't resolve ${item.name}. Make sure it's a function that accepts no arguments, or call it from another TypeGPU function.`);
766
+ }
767
+ return this.withResetIndentLevel(() => this.resolve(shellless));
768
+ }
769
+ else {
770
+ throw new TypeError(`Unresolvable internal value: ${safeStringify(item)}`);
771
+ }
772
+ // We know which slots the item used while resolving
773
+ const slotToValueMap = new Map();
774
+ for (const usedSlot of this._itemStateStack.topItem.usedSlots) {
775
+ slotToValueMap.set(usedSlot, this._itemStateStack.readSlot(usedSlot));
776
+ }
777
+ instances.push({ slotToValueMap, result });
778
+ this.#namespaceInternal.memoizedResolves.set(item, instances);
779
+ return result;
780
+ }
781
+ catch (err) {
782
+ if (err instanceof ResolutionError) {
783
+ throw err.appendToTrace(item);
784
+ }
785
+ throw new ResolutionError(err, [item]);
786
+ }
787
+ finally {
788
+ this._itemStateStack.pop('item');
789
+ }
790
+ }
791
+ resolve(item, schema) {
792
+ if (typeof item === 'string') {
793
+ if (!schema || schema === UnknownData) {
794
+ throw new Error(`Strings cannot be injected into WGSL directly (tried to inject '${item}'). Look for TypeGPU APIs that cover your use-case, or resort to using tgpu['~unstable'].rawCodeSnippet for raw code injection.`);
795
+ }
796
+ // For example:
797
+ // () => { 'use gpu'; const color = d.vec3f(); return color; }
798
+ // snip('color', d.vec3f) ^^^^^
799
+ return snip(item, schema, /* origin */ 'runtime');
800
+ }
801
+ if ((isTgpuFn(item) || isShelllessImpl(item)) && !isProviding(item)) {
802
+ // We skip providing functions to only perform the checks on slot-less functions.
803
+ if (this.#startedFunctionResolves.has(item) &&
804
+ !this.#namespaceInternal.memoizedResolves.has(item)) {
805
+ throw new Error(`Recursive function ${item} detected. Recursion is not allowed on the GPU.`);
806
+ }
807
+ this.#startedFunctionResolves.add(item);
808
+ }
809
+ if (isProviding(item)) {
810
+ return this.withRenamed(item[$providing].inner, getName(item), () => this.withSlots(item[$providing].pairs, () => this.resolve(item[$providing].inner, schema)));
811
+ }
812
+ if (isMarkedInternal(item) || hasTinyestMetadata(item)) {
813
+ // Top-level resolve
814
+ if (this._itemStateStack.itemDepth === 0) {
815
+ try {
816
+ this.pushMode(new CodegenState());
817
+ const result = provideCtx(this, () => this._getOrInstantiate(item));
818
+ return snip(`${this._declarations.map((decl) => decl.code).join('\n\n')}${result.value}`, Void,
819
+ /* origin */ 'runtime');
820
+ }
821
+ finally {
822
+ this.popMode('codegen');
823
+ }
824
+ }
825
+ return this._getOrInstantiate(item);
826
+ }
827
+ // This is a value that comes from the outside, maybe we can coerce it
828
+ if (typeof item === 'number') {
829
+ const realSchema = schema ?? numericLiteralToSnippet(item).dataType;
830
+ invariant(realSchema !== UnknownData, 'Schema has to be known for resolving numbers');
831
+ return this.gen.numericLiteral(item, realSchema);
832
+ }
833
+ if (typeof item === 'boolean') {
834
+ return snip(item ? 'true' : 'false', bool, /* origin */ 'constant', false);
835
+ }
836
+ if (schema && isWgslArray(schema)) {
837
+ if (!Array.isArray(item)) {
838
+ throw new WgslTypeError(`Cannot coerce ${item} into value of type '${schema}'`);
839
+ }
840
+ if (schema.elementCount !== item.length) {
841
+ throw new WgslTypeError(`Cannot create value of type '${schema}' from an array of length: ${item.length}`);
842
+ }
843
+ return this.gen.typeInstantiation(schema, item.map((element) => snip(element, schema.elementType, /* origin */ 'runtime')));
844
+ }
845
+ if (schema && isWgslStruct(schema)) {
846
+ return this.gen.typeInstantiation(schema, Object.entries(schema.propTypes).map(([key, propType]) => snip(item[key], propType, /* origin */ 'runtime')));
847
+ }
848
+ throw new WgslTypeError(`Value ${safeStringify(item)} is not resolvable${schema && schema !== UnknownData ? ` to type ${safeStringify(schema)}` : ''}`);
849
+ }
850
+ resolveSnippet(snippet) {
851
+ return withValue(this.resolve(snippet.value, snippet.dataType).value, snippet);
852
+ }
853
+ pushMode(mode) {
854
+ this.#modeStack.push(mode);
855
+ }
856
+ popMode(expected) {
857
+ const mode = this.#modeStack.pop();
858
+ if (expected !== undefined) {
859
+ invariant(mode?.type === expected, 'Unexpected mode');
860
+ }
861
+ }
862
+ get mode() {
863
+ return this.#modeStack[this.#modeStack.length - 1] ?? topLevelState;
864
+ }
226
865
  }
227
- var ResolutionCtxImpl = class {
228
- #namespaceInternal;
229
- _indentController = new IndentController();
230
- _itemStateStack = new ItemStateStackImpl();
231
- #modeStack = [];
232
- _declarations = [];
233
- _varyingLocations;
234
- #currentlyResolvedItems = /* @__PURE__ */ new WeakSet();
235
- #logGenerator;
236
- gen;
237
- get varyingLocations() {
238
- return this._varyingLocations;
239
- }
240
- [$internal] = { itemStateStack: this._itemStateStack };
241
- /**
242
- * A map from registered bind group layouts to random strings put in
243
- * place of their group index. The whole tree has to be traversed to
244
- * collect every use of a typed bind group layout, since they can be
245
- * explicitly imposed group indices, and they cannot collide.
246
- */
247
- bindGroupLayoutsToPlaceholderMap = /* @__PURE__ */ new Map();
248
- _nextFreeLayoutPlaceholderIdx = 0;
249
- fixedBindings = [];
250
- enableExtensions;
251
- expectedType;
252
- /**
253
- * A counter used to generate unique identifiers for globally-scoped definitions in the 'random' strategy.
254
- */
255
- #lastUniqueId = 0;
256
- constructor(opts) {
257
- this.enableExtensions = opts.enableExtensions;
258
- this.gen = opts.shaderGenerator ?? wgslGenerator_default;
259
- this.#logGenerator = opts.root ? new LogGeneratorImpl(opts.root) : new LogGeneratorNullImpl();
260
- this.#namespaceInternal = opts.namespace[$internal];
261
- }
262
- isIdentifierBanned(name) {
263
- return bannedTokens.has(name);
264
- }
265
- isIdentifierTaken(name) {
266
- return this.#namespaceInternal.takenGlobalIdentifiers.has(name) || this._itemStateStack.isIdentifierTakenLocally(name);
267
- }
268
- makeUniqueIdentifier(primer = "item", scope) {
269
- if (scope === "block" && (/* @__PURE__ */ validateIdentifier(primer)).success && !this.isIdentifierTaken(primer)) {
270
- this.reserveIdentifier(primer, "block");
271
- return primer;
272
- }
273
- const base = /* @__PURE__ */ sanitizePrimer(primer);
274
- let index = 0;
275
- const random = this.#namespaceInternal.strategy === "random";
276
- let name = random ? `${base}_${this.#lastUniqueId++}` : base;
277
- while (this.isIdentifierTaken(name)) name = random ? `${base}_${this.#lastUniqueId++}` : `${base}_${++index}`;
278
- this.reserveIdentifier(name, scope);
279
- return name;
280
- }
281
- reserveIdentifier(name, scope) {
282
- if (scope === "block") {
283
- const blockScope = this._itemStateStack.topBlockScope;
284
- if (blockScope) {
285
- blockScope.takenLocalIdentifiers.add(name);
286
- return;
287
- }
288
- }
289
- this.#namespaceInternal.takenGlobalIdentifiers.add(name);
290
- }
291
- get pre() {
292
- return this._indentController.pre;
293
- }
294
- get topFunctionScope() {
295
- return this._itemStateStack.topFunctionScope;
296
- }
297
- get topFunctionReturnType() {
298
- const scope = this._itemStateStack.topFunctionScope;
299
- invariant(scope, "Internal error, expected function scope to be present.");
300
- return scope.returnType;
301
- }
302
- get shelllessRepo() {
303
- return this.#namespaceInternal.shelllessRepo;
304
- }
305
- indent() {
306
- return this._indentController.indent();
307
- }
308
- dedent() {
309
- return this._indentController.dedent();
310
- }
311
- withResetIndentLevel(callback) {
312
- return this._indentController.withResetLevel(callback);
313
- }
314
- getById(id) {
315
- const item = this._itemStateStack.getSnippetById(id);
316
- if (item === void 0) return null;
317
- return item;
318
- }
319
- defineVariable(id, snippet) {
320
- this._itemStateStack.defineBlockVariable(id, snippet);
321
- }
322
- reportReturnType(dataType) {
323
- const scope = this._itemStateStack.topFunctionScope;
324
- invariant(scope, "Internal error, expected function scope to be present.");
325
- scope.reportedReturnTypes.add(dataType);
326
- }
327
- pushBlockScope() {
328
- this._itemStateStack.pushBlockScope();
329
- }
330
- popBlockScope() {
331
- this._itemStateStack.pop("blockScope");
332
- }
333
- setBlockExternals(externals) {
334
- this._itemStateStack.setBlockExternals(externals);
335
- }
336
- clearBlockExternals() {
337
- this._itemStateStack.clearBlockExternals();
338
- }
339
- generateLog(op, args) {
340
- return this.#logGenerator.generateLog(this, op, args);
341
- }
342
- get logResources() {
343
- return this.#logGenerator.logResources;
344
- }
345
- resolveFunction(options) {
346
- try {
347
- const scope = this._itemStateStack.pushFunctionScope(options.functionType, {}, options.returnType, options.externalMap);
348
- this._itemStateStack.pushBlockScope();
349
- const args = [];
350
- if (options.entryInput) {
351
- const { dataSchema, positionalArgs } = options.entryInput;
352
- const firstParam = options.params[0];
353
- const structArg = dataSchema ? createArgument(this.makeUniqueIdentifier("_arg_0", "block"), dataSchema) : void 0;
354
- if (structArg) args.push(structArg);
355
- if (firstParam?.type === FuncParameterType.destructuredObject) for (const { name, alias } of firstParam.props) {
356
- const argInfo = positionalArgs.find((a) => a.schemaKey === name);
357
- if (argInfo) {
358
- const arg = createArgument(this.makeUniqueIdentifier(alias, "block"), argInfo.type);
359
- args.push(arg);
360
- scope.argAccess[alias] = arg.access;
361
- } else if (structArg) scope.argAccess[alias] = createArgumentPropAccess(structArg.access, name);
362
- }
363
- else if (firstParam?.type === FuncParameterType.identifier) {
364
- const proxyEntries = [];
365
- for (const a of positionalArgs) {
366
- const arg = createArgument(this.makeUniqueIdentifier(a.schemaKey, "block"), a.type);
367
- args.push(arg);
368
- proxyEntries.push({
369
- schemaKey: a.schemaKey,
370
- arg: arg.access
371
- });
372
- }
373
- const router = new EntryInputRouter(structArg?.access, proxyEntries);
374
- scope.argAccess[firstParam.name] = () => snip("N/A", router, "argument");
375
- } else for (const a of positionalArgs) {
376
- const argName = this.makeUniqueIdentifier(`_arg_${a.schemaKey}`, "block");
377
- const arg = createArgument(argName, a.type);
378
- args.push(arg);
379
- scope.argAccess[argName] = arg.access;
380
- }
381
- } else for (const [i, argType] of options.argTypes.entries()) {
382
- const astParam = options.params[i];
383
- const origin = isPtr(argType) ? argType.addressSpace === "storage" ? argType.access === "read" ? "readonly" : "mutable" : argType.addressSpace : "argument";
384
- switch (astParam?.type) {
385
- case FuncParameterType.identifier: {
386
- const arg = createArgument(this.makeUniqueIdentifier(astParam.name, "block"), argType, origin);
387
- args.push(arg);
388
- scope.argAccess[astParam.name] = arg.access;
389
- break;
390
- }
391
- case FuncParameterType.destructuredObject: {
392
- const objArg = createArgument(this.makeUniqueIdentifier(`_arg_${i}`, "block"), argType, origin);
393
- args.push(objArg);
394
- for (const { name, alias } of astParam.props) scope.argAccess[alias] = createArgumentPropAccess(objArg.access, name);
395
- break;
396
- }
397
- case void 0: if (!(argType instanceof AutoStruct)) args.push({
398
- name: this.makeUniqueIdentifier(`_arg_${i}`, "block"),
399
- access: () => {
400
- throw new Error(`Unreachable: Accessing an argument that wasn't named in the function signature`);
401
- },
402
- decoratedType: argType,
403
- used: false
404
- });
405
- }
406
- }
407
- let returnType;
408
- const code = this.gen.functionDefinition({
409
- functionType: options.functionType,
410
- name: options.name,
411
- workgroupSize: options.workgroupSize,
412
- args,
413
- body: options.body,
414
- determineReturnType: () => {
415
- if (returnType) return returnType;
416
- returnType = options.returnType;
417
- if (returnType instanceof AutoStruct) if (isWgslStruct(scope.reportedReturnTypes.values().next().value)) returnType = returnType.completeStruct;
418
- else returnType = void 0;
419
- if (!returnType) {
420
- const returnTypes = [...scope.reportedReturnTypes];
421
- if (returnTypes.length === 0) returnType = Void;
422
- else {
423
- const conversion = getBestConversion(returnTypes);
424
- if (conversion && !conversion.hasImplicitConversions) returnType = conversion.targetType;
425
- }
426
- if (!returnType) throw new Error(`Expected function to have a single return type, got [${returnTypes.join(", ")}]. Cast explicitly to the desired type.`);
427
- returnType = concretize(returnType);
428
- if (options.functionType === "vertex" || options.functionType === "fragment") returnType = createIoSchema(returnType);
429
- }
430
- return returnType;
431
- }
432
- });
433
- if (!returnType) throw new Error(`Failed to determine return type`);
434
- return {
435
- code,
436
- returnType
437
- };
438
- } finally {
439
- this._itemStateStack.pop("blockScope");
440
- this._itemStateStack.pop("functionScope");
441
- }
442
- }
443
- addDeclaration(declaration) {
444
- this._declarations.push(declaration);
445
- }
446
- allocateLayoutEntry(layout) {
447
- const memoMap = this.bindGroupLayoutsToPlaceholderMap;
448
- let placeholderKey = memoMap.get(layout);
449
- if (!placeholderKey) {
450
- placeholderKey = `#BIND_GROUP_LAYOUT_${this._nextFreeLayoutPlaceholderIdx++}#`;
451
- memoMap.set(layout, placeholderKey);
452
- }
453
- return placeholderKey;
454
- }
455
- allocateFixedEntry(layoutEntry, resource) {
456
- const binding = this.fixedBindings.length;
457
- this.fixedBindings.push({
458
- layoutEntry,
459
- resource
460
- });
461
- return {
462
- group: CATCHALL_BIND_GROUP_IDX_MARKER,
463
- binding
464
- };
465
- }
466
- readSlot(slot) {
467
- const value = this._itemStateStack.readSlot(slot);
468
- if (value === void 0) throw new MissingSlotValueError(slot);
469
- return value;
470
- }
471
- withSlots(pairs, callback) {
472
- if (pairs.length === 0) return callback();
473
- this._itemStateStack.pushSlotBindings(pairs);
474
- try {
475
- return callback();
476
- } finally {
477
- this._itemStateStack.pop("slotBinding");
478
- }
479
- }
480
- withVaryingLocations(locations, callback) {
481
- this._varyingLocations = locations;
482
- try {
483
- return callback();
484
- } finally {
485
- this._varyingLocations = void 0;
486
- }
487
- }
488
- withRenamed(item, name, callback) {
489
- if (!name) return callback();
490
- const oldName = getName(item);
491
- try {
492
- setName(item, name);
493
- return callback();
494
- } finally {
495
- if (oldName) setName(item, oldName);
496
- }
497
- }
498
- unwrap(eventual) {
499
- if (isProviding(eventual)) return this.withRenamed(eventual[$providing].inner, getName(eventual), () => this.withSlots(eventual[$providing].pairs, () => this.unwrap(eventual[$providing].inner)));
500
- let maybeEventual = eventual;
501
- while (true) if (isSlot(maybeEventual)) maybeEventual = this.readSlot(maybeEventual);
502
- else if (isLazy(maybeEventual)) maybeEventual = this._getOrCompute(maybeEventual);
503
- else break;
504
- return maybeEventual;
505
- }
506
- _getOrCompute(lazy) {
507
- const instances = this.#namespaceInternal.memoizedLazy.get(lazy) ?? [];
508
- this._itemStateStack.pushItem();
509
- try {
510
- for (const instance of instances) if ([...instance.slotToValueMap.entries()].every(([slot, expectedValue]) => slot.areEqual(this._itemStateStack.readSlot(slot), expectedValue))) return instance.result;
511
- this.pushMode(new NormalState());
512
- let result;
513
- try {
514
- result = lazy[$internal].compute();
515
- } finally {
516
- this.popMode("normal");
517
- }
518
- const slotToValueMap = /* @__PURE__ */ new Map();
519
- for (const usedSlot of this._itemStateStack.topItem.usedSlots) slotToValueMap.set(usedSlot, this._itemStateStack.readSlot(usedSlot));
520
- instances.push({
521
- slotToValueMap,
522
- result
523
- });
524
- this.#namespaceInternal.memoizedLazy.set(lazy, instances);
525
- return result;
526
- } catch (err) {
527
- if (err instanceof ResolutionError) throw err.appendToTrace(lazy);
528
- throw new ResolutionError(err, [lazy]);
529
- } finally {
530
- this._itemStateStack.pop("item");
531
- }
532
- }
533
- /**
534
- * @param item The item whose resolution should be either retrieved from the cache (if there is a cache hit), or resolved.
535
- */
536
- _getOrInstantiate(item) {
537
- const instances = this.#namespaceInternal.memoizedResolves.get(item) ?? [];
538
- this._itemStateStack.pushItem();
539
- try {
540
- for (const instance of instances) if ([...instance.slotToValueMap.entries()].every(([slot, expectedValue]) => slot.areEqual(this._itemStateStack.readSlot(slot), expectedValue))) return instance.result;
541
- let result;
542
- if (isData(item)) result = snip(this.gen.typeAnnotation(item), Void, "runtime");
543
- else if (isLazy(item) || isSlot(item)) result = this.resolve(this.unwrap(item));
544
- else if (isSelfResolvable(item)) result = item[$resolve](this);
545
- else if (hasTinyestMetadata(item)) {
546
- const shellless = this.#namespaceInternal.shelllessRepo.get(item, void 0);
547
- if (!shellless) throw new Error(`Couldn't resolve ${item.name}. Make sure it's a function that accepts no arguments, or call it from another TypeGPU function.`);
548
- return this.withResetIndentLevel(() => this.resolve(shellless));
549
- } else throw new TypeError(`Unresolvable internal value: ${safeStringify(item)}`);
550
- const slotToValueMap = /* @__PURE__ */ new Map();
551
- for (const usedSlot of this._itemStateStack.topItem.usedSlots) slotToValueMap.set(usedSlot, this._itemStateStack.readSlot(usedSlot));
552
- instances.push({
553
- slotToValueMap,
554
- result
555
- });
556
- this.#namespaceInternal.memoizedResolves.set(item, instances);
557
- return result;
558
- } catch (err) {
559
- if (err instanceof ResolutionError) throw err.appendToTrace(item);
560
- throw new ResolutionError(err, [item]);
561
- } finally {
562
- this._itemStateStack.pop("item");
563
- }
564
- }
565
- resolve(item, schema) {
566
- if (isTgpuFn(item) || isShelllessImpl(item)) {
567
- if (this.#currentlyResolvedItems.has(item) && !this.#namespaceInternal.memoizedResolves.has(item)) throw new Error(`Recursive function ${item} detected. Recursion is not allowed on the GPU.`);
568
- this.#currentlyResolvedItems.add(item);
569
- }
570
- if (isProviding(item)) return this.withRenamed(item[$providing].inner, getName(item), () => this.withSlots(item[$providing].pairs, () => this.resolve(item[$providing].inner, schema)));
571
- if (isMarkedInternal(item) || hasTinyestMetadata(item)) {
572
- if (this._itemStateStack.itemDepth === 0) {
573
- this.gen.initGenerator(this);
574
- try {
575
- this.pushMode(new CodegenState());
576
- const result = provideCtx(this, () => this._getOrInstantiate(item));
577
- return snip(`${[...this._declarations].join("\n\n")}${result.value}`, Void, "runtime");
578
- } finally {
579
- this.popMode("codegen");
580
- }
581
- }
582
- return this._getOrInstantiate(item);
583
- }
584
- if (typeof item === "number") {
585
- const realSchema = schema ?? numericLiteralToSnippet(item).dataType;
586
- invariant(realSchema !== UnknownData, "Schema has to be known for resolving numbers");
587
- return this.gen.numericLiteral(item, realSchema);
588
- }
589
- if (typeof item === "boolean") return snip(item ? "true" : "false", bool, "constant");
590
- if (typeof item === "string") return snip(item, Void, "runtime");
591
- if (schema && isWgslArray(schema)) {
592
- if (!Array.isArray(item)) throw new WgslTypeError(`Cannot coerce ${item} into value of type '${schema}'`);
593
- if (schema.elementCount !== item.length) throw new WgslTypeError(`Cannot create value of type '${schema}' from an array of length: ${item.length}`);
594
- return this.gen.typeInstantiation(schema, item.map((element) => snip(element, schema.elementType, "runtime")));
595
- }
596
- if (schema && isWgslStruct(schema)) return this.gen.typeInstantiation(schema, Object.entries(schema.propTypes).map(([key, propType]) => snip(item[key], propType, "runtime")));
597
- throw new WgslTypeError(`Value ${safeStringify(item)} is not resolvable${schema ? ` to type ${safeStringify(schema)}` : ""}`);
598
- }
599
- resolveSnippet(snippet) {
600
- return snip(this.resolve(snippet.value, snippet.dataType).value, snippet.dataType, snippet.origin);
601
- }
602
- pushMode(mode) {
603
- this.#modeStack.push(mode);
604
- }
605
- popMode(expected) {
606
- const mode = this.#modeStack.pop();
607
- if (expected !== void 0) invariant(mode?.type === expected, "Unexpected mode");
608
- }
609
- get mode() {
610
- return this.#modeStack[this.#modeStack.length - 1] ?? topLevelState;
611
- }
612
- };
613
- function resolve(item, options) {
614
- const ctx = new ResolutionCtxImpl(options);
615
- let code = (options.config ? ctx.withSlots(options.config(new ConfigurableImpl([])).bindings, () => ctx.resolve(item)) : ctx.resolve(item)).value;
616
- const memoMap = ctx.bindGroupLayoutsToPlaceholderMap;
617
- const usedBindGroupLayouts = [];
618
- const automaticIds = naturalsExcept(new Set([...memoMap.keys()].map((layout) => layout.index).filter((v) => v !== void 0)));
619
- const layoutEntries = ctx.fixedBindings.map((binding, idx) => [String(idx), binding.layoutEntry]);
620
- const createCatchallGroup = () => {
621
- const catchallIdx = automaticIds.next().value;
622
- const catchallLayout = bindGroupLayout(Object.fromEntries(layoutEntries));
623
- usedBindGroupLayouts[catchallIdx] = catchallLayout;
624
- code = code.replaceAll(CATCHALL_BIND_GROUP_IDX_MARKER, String(catchallIdx));
625
- return [catchallIdx, new TgpuBindGroupImpl(catchallLayout, Object.fromEntries(ctx.fixedBindings.map((binding, idx) => [String(idx), binding.resource])))];
626
- };
627
- const catchall = layoutEntries.length > 0 ? createCatchallGroup() : void 0;
628
- for (const [layout, placeholder] of memoMap.entries()) {
629
- const idx = layout.index ?? automaticIds.next().value;
630
- usedBindGroupLayouts[idx] = layout;
631
- code = code.replaceAll(placeholder, String(idx));
632
- }
633
- if (options.enableExtensions && options.enableExtensions.length > 0) code = `${options.enableExtensions.map((ext) => `enable ${ext};`).join("\n")}\n\n${code}`;
634
- return {
635
- code,
636
- usedBindGroupLayouts,
637
- catchall,
638
- logResources: ctx.logResources
639
- };
866
+ export function resolve(item, options) {
867
+ const ctx = new ResolutionCtxImpl(options);
868
+ const snippet = options.config
869
+ ? ctx.withSlots(options.config(new ConfigurableImpl([])).bindings, () => ctx.resolve(item))
870
+ : ctx.resolve(item);
871
+ let code = snippet.value;
872
+ const memoMap = ctx.bindGroupLayoutsToPlaceholderMap;
873
+ const usedBindGroupLayouts = [];
874
+ const takenIndices = new Set([...memoMap.keys()].map((layout) => layout.index).filter((v) => v !== undefined));
875
+ const automaticIds = naturalsExcept(takenIndices);
876
+ const layoutEntries = ctx.fixedBindings.map((binding, idx) => [String(idx), binding.layoutEntry]);
877
+ // Bind group indices are only known now, so the same placeholder
878
+ // replacements applied to `code` are recorded and re-applied to each
879
+ // declaration's code.
880
+ const bindingReplacements = [];
881
+ const createCatchallGroup = () => {
882
+ const catchallIdx = automaticIds.next().value;
883
+ const catchallLayout = bindGroupLayout(Object.fromEntries(layoutEntries));
884
+ usedBindGroupLayouts[catchallIdx] = catchallLayout;
885
+ code = code.replaceAll(CATCHALL_BIND_GROUP_IDX_MARKER, String(catchallIdx));
886
+ bindingReplacements.push([CATCHALL_BIND_GROUP_IDX_MARKER, String(catchallIdx)]);
887
+ return [
888
+ catchallIdx,
889
+ new TgpuBindGroupImpl(
890
+ // Undefined only in rootless `tgpu.resolve()`, where the group is never unwrapped
891
+ options.root, catchallLayout, Object.fromEntries(
892
+ // oxlint-disable-next-line typescript/no-explicit-any -- it's fine
893
+ ctx.fixedBindings.map((binding, idx) => [String(idx), binding.resource]))),
894
+ ];
895
+ };
896
+ // Retrieving the catch-all binding index first, because it's inherently
897
+ // the least swapped bind group (fixed and cannot be swapped).
898
+ const catchall = layoutEntries.length > 0 ? createCatchallGroup() : undefined;
899
+ for (const [layout, placeholder] of memoMap.entries()) {
900
+ const idx = layout.index ?? automaticIds.next().value;
901
+ usedBindGroupLayouts[idx] = layout;
902
+ code = code.replaceAll(placeholder, String(idx));
903
+ bindingReplacements.push([placeholder, String(idx)]);
904
+ }
905
+ if (options.enableExtensions && options.enableExtensions.length > 0) {
906
+ const extensions = options.enableExtensions.map((ext) => `enable ${ext};`);
907
+ code = `${extensions.join('\n')}\n\n${code}`;
908
+ }
909
+ let declarations = ctx.declarations.map(({ name, code: declarationCode }) => ({
910
+ name,
911
+ code: bindingReplacements.reduce((acc, [placeholder, idx]) => acc.replaceAll(placeholder, idx), declarationCode),
912
+ }));
913
+ if (options.minify) {
914
+ code = minify(code);
915
+ // TODO(#2804): remove this workaround
916
+ declarations = declarations.map((entry) => ({ ...entry, code: minify(entry.code) }));
917
+ }
918
+ return {
919
+ code,
920
+ declarations,
921
+ usedBindGroupLayouts,
922
+ catchall,
923
+ logResources: ctx.logResources,
924
+ };
640
925
  }
641
-
642
- //#endregion
643
- export { ResolutionCtxImpl, resolve };