@driftengine/core 3.63.0 → 4.1.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 (428) hide show
  1. package/CHANGELOG.json +122 -0
  2. package/NOTICE +20 -0
  3. package/README.md +1 -1
  4. package/dist/core/loop.js +18 -2
  5. package/dist/core/storage.js +5 -0
  6. package/dist/geometry/meshBuilder.d.ts +1 -1
  7. package/dist/geometry/meshBuilder.js +6 -2
  8. package/dist/index.d.ts +69 -4
  9. package/dist/index.js +112 -2
  10. package/dist/input/input.js +6 -1
  11. package/dist/math/exact.d.ts +13 -3
  12. package/dist/math/exact.js +68 -3
  13. package/dist/math/frustum.d.ts +17 -2
  14. package/dist/math/frustum.js +24 -0
  15. package/dist/render/backend/api.d.ts +34 -1
  16. package/dist/render/backend/api.js +22 -1
  17. package/dist/render/backend/budget.d.ts +7 -6
  18. package/dist/render/backend/budget.js +7 -6
  19. package/dist/render/backend/createRenderer.d.ts +57 -0
  20. package/dist/render/backend/createRenderer.js +51 -2
  21. package/dist/render/backend/materialChanges.d.ts +41 -0
  22. package/dist/render/backend/materialChanges.js +38 -0
  23. package/dist/render/backend/select.js +8 -0
  24. package/dist/render/backend/webgl2/renderer.d.ts +80 -1
  25. package/dist/render/backend/webgl2/renderer.js +208 -10
  26. package/dist/render/backend/webgpu/buffers.d.ts +20 -1
  27. package/dist/render/backend/webgpu/buffers.js +116 -58
  28. package/dist/render/backend/webgpu/fieldCompose.d.ts +156 -0
  29. package/dist/render/backend/webgpu/fieldCompose.js +396 -0
  30. package/dist/render/backend/webgpu/giFieldPass.d.ts +66 -0
  31. package/dist/render/backend/webgpu/giFieldPass.js +137 -0
  32. package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +728 -0
  33. package/dist/render/backend/webgpu/gpuDrivenPass.js +2473 -0
  34. package/dist/render/backend/webgpu/linePass.d.ts +4 -14
  35. package/dist/render/backend/webgpu/linePass.js +4 -33
  36. package/dist/render/backend/webgpu/probeBake.d.ts +148 -0
  37. package/dist/render/backend/webgpu/probeBake.js +493 -0
  38. package/dist/render/backend/webgpu/renderer.d.ts +379 -24
  39. package/dist/render/backend/webgpu/renderer.js +1369 -76
  40. package/dist/render/backend/webgpu/scatterPass.js +15 -1
  41. package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +19 -9
  42. package/dist/render/backend/webgpu/surfaceTexturePass.js +58 -32
  43. package/dist/render/causticsRenderer.d.ts +3 -1
  44. package/dist/render/causticsRenderer.js +4 -1
  45. package/dist/render/depthConvention.d.ts +12 -0
  46. package/dist/render/depthConvention.js +14 -0
  47. package/dist/render/deviceFeatures.d.ts +32 -0
  48. package/dist/render/deviceFeatures.js +41 -0
  49. package/dist/render/fog.d.ts +79 -0
  50. package/dist/render/fog.js +138 -0
  51. package/dist/render/frame/alias.d.ts +30 -0
  52. package/dist/render/frame/alias.js +61 -0
  53. package/dist/render/frame/deps.d.ts +37 -0
  54. package/dist/render/frame/deps.js +122 -0
  55. package/dist/render/frame/flushGraph.d.ts +43 -0
  56. package/dist/render/frame/flushGraph.js +84 -0
  57. package/dist/render/frame/graphSchedule.d.ts +49 -0
  58. package/dist/render/frame/graphSchedule.js +120 -0
  59. package/dist/render/frame/index.d.ts +15 -0
  60. package/dist/render/frame/index.js +8 -0
  61. package/dist/render/frame/lifetime.d.ts +24 -0
  62. package/dist/render/frame/lifetime.js +36 -0
  63. package/dist/render/frame/passTimings.d.ts +42 -0
  64. package/dist/render/frame/passTimings.js +38 -0
  65. package/dist/render/frame/validate.d.ts +15 -0
  66. package/dist/render/frame/validate.js +22 -0
  67. package/dist/render/frame/virtual.d.ts +44 -0
  68. package/dist/render/frame/virtual.js +61 -0
  69. package/dist/render/gi/chain.d.ts +82 -0
  70. package/dist/render/gi/chain.js +135 -0
  71. package/dist/render/gi/denoise.d.ts +114 -0
  72. package/dist/render/gi/denoise.js +169 -0
  73. package/dist/render/gi/fieldScene.d.ts +125 -0
  74. package/dist/render/gi/fieldScene.js +219 -0
  75. package/dist/render/gi/globalField.d.ts +157 -0
  76. package/dist/render/gi/globalField.js +373 -0
  77. package/dist/render/gi/probeGridFit.d.ts +24 -0
  78. package/dist/render/gi/probeGridFit.js +71 -0
  79. package/dist/render/gi/probeTrace.d.ts +82 -0
  80. package/dist/render/gi/probeTrace.js +128 -0
  81. package/dist/render/gi/probeVolume.d.ts +136 -0
  82. package/dist/render/gi/probeVolume.js +191 -0
  83. package/dist/render/gi/reflection.d.ts +73 -0
  84. package/dist/render/gi/reflection.js +109 -0
  85. package/dist/render/gi/traceField.d.ts +91 -0
  86. package/dist/render/gi/traceField.js +129 -0
  87. package/dist/render/gi/traceScreen.d.ts +68 -0
  88. package/dist/render/gi/traceScreen.js +82 -0
  89. package/dist/render/gpuScene.d.ts +38 -0
  90. package/dist/render/gpuScene.js +41 -0
  91. package/dist/render/gpudriven/alphaTest.d.ts +28 -0
  92. package/dist/render/gpudriven/alphaTest.js +32 -0
  93. package/dist/render/gpudriven/clusterUpload.d.ts +59 -0
  94. package/dist/render/gpudriven/clusterUpload.js +75 -0
  95. package/dist/render/gpudriven/clusterWorld.d.ts +57 -0
  96. package/dist/render/gpudriven/clusterWorld.js +155 -0
  97. package/dist/render/gpudriven/compact.d.ts +51 -0
  98. package/dist/render/gpudriven/compact.js +68 -0
  99. package/dist/render/gpudriven/cullClusters.d.ts +129 -0
  100. package/dist/render/gpudriven/cullClusters.js +237 -0
  101. package/dist/render/gpudriven/decodeTables.d.ts +64 -0
  102. package/dist/render/gpudriven/decodeTables.js +219 -0
  103. package/dist/render/gpudriven/frustum.d.ts +25 -0
  104. package/dist/render/gpudriven/frustum.js +59 -0
  105. package/dist/render/gpudriven/geometryHarness.d.ts +15 -0
  106. package/dist/render/gpudriven/geometryHarness.js +31 -0
  107. package/dist/render/gpudriven/hzb.d.ts +60 -0
  108. package/dist/render/gpudriven/hzb.js +97 -0
  109. package/dist/render/gpudriven/ibl.d.ts +85 -0
  110. package/dist/render/gpudriven/ibl.js +129 -0
  111. package/dist/render/gpudriven/indirect.d.ts +67 -0
  112. package/dist/render/gpudriven/indirect.js +77 -0
  113. package/dist/render/gpudriven/instances.d.ts +43 -0
  114. package/dist/render/gpudriven/instances.js +172 -0
  115. package/dist/render/gpudriven/lit.d.ts +165 -0
  116. package/dist/render/gpudriven/lit.js +165 -0
  117. package/dist/render/gpudriven/lodCut.d.ts +28 -0
  118. package/dist/render/gpudriven/lodCut.js +38 -0
  119. package/dist/render/gpudriven/materialBin.d.ts +60 -0
  120. package/dist/render/gpudriven/materialBin.js +108 -0
  121. package/dist/render/gpudriven/materialTable.d.ts +88 -0
  122. package/dist/render/gpudriven/materialTable.js +115 -0
  123. package/dist/render/gpudriven/pipeline.d.ts +135 -0
  124. package/dist/render/gpudriven/pipeline.js +237 -0
  125. package/dist/render/gpudriven/rangeAlloc.d.ts +50 -0
  126. package/dist/render/gpudriven/rangeAlloc.js +112 -0
  127. package/dist/render/gpudriven/sceneUpload.d.ts +96 -0
  128. package/dist/render/gpudriven/sceneUpload.js +115 -0
  129. package/dist/render/gpudriven/shadeBins.d.ts +92 -0
  130. package/dist/render/gpudriven/shadeBins.js +182 -0
  131. package/dist/render/gpudriven/shadow.d.ts +136 -0
  132. package/dist/render/gpudriven/shadow.js +224 -0
  133. package/dist/render/gpudriven/shadowCamera.d.ts +87 -0
  134. package/dist/render/gpudriven/shadowCamera.js +345 -0
  135. package/dist/render/gpudriven/streamScene.d.ts +194 -0
  136. package/dist/render/gpudriven/streamScene.js +459 -0
  137. package/dist/render/gpudriven/surfaceFrame.d.ts +25 -0
  138. package/dist/render/gpudriven/surfaceFrame.js +51 -0
  139. package/dist/render/gpudriven/twoPhase.d.ts +122 -0
  140. package/dist/render/gpudriven/twoPhase.js +160 -0
  141. package/dist/render/gpudriven/visbuffer.d.ts +25 -0
  142. package/dist/render/gpudriven/visbuffer.js +37 -0
  143. package/dist/render/halfFloat.d.ts +10 -0
  144. package/dist/render/halfFloat.js +23 -4
  145. package/dist/render/inference/attentionTiled.d.ts +27 -0
  146. package/dist/render/inference/attentionTiled.js +117 -0
  147. package/dist/render/inference/denseKernels.d.ts +29 -0
  148. package/dist/render/inference/denseKernels.js +312 -0
  149. package/dist/render/inference/device.d.ts +21 -0
  150. package/dist/render/inference/device.js +32 -0
  151. package/dist/render/inference/deviceGraph.d.ts +34 -0
  152. package/dist/render/inference/deviceGraph.js +17 -0
  153. package/dist/render/inference/fuse.d.ts +15 -0
  154. package/dist/render/inference/fuse.js +37 -0
  155. package/dist/render/inference/kernelKit.d.ts +52 -0
  156. package/dist/render/inference/kernelKit.js +70 -0
  157. package/dist/render/inference/kernels.d.ts +3 -0
  158. package/dist/render/inference/kernels.js +11 -0
  159. package/dist/render/inference/plan.d.ts +13 -0
  160. package/dist/render/inference/plan.js +18 -0
  161. package/dist/render/inference/reuse.d.ts +39 -0
  162. package/dist/render/inference/reuse.js +65 -0
  163. package/dist/render/inference/runner.d.ts +31 -0
  164. package/dist/render/inference/runner.js +175 -0
  165. package/dist/render/inference/schedule.d.ts +39 -0
  166. package/dist/render/inference/schedule.js +59 -0
  167. package/dist/render/inference/shapeKernels.d.ts +10 -0
  168. package/dist/render/inference/shapeKernels.js +80 -0
  169. package/dist/render/inference/spatialKernels.d.ts +21 -0
  170. package/dist/render/inference/spatialKernels.js +179 -0
  171. package/dist/render/inference/splatRaster.wgsl.d.ts +75 -0
  172. package/dist/render/inference/splatRaster.wgsl.js +337 -0
  173. package/dist/render/inference/splatTiles.d.ts +79 -0
  174. package/dist/render/inference/splatTiles.js +161 -0
  175. package/dist/render/lineBatch.d.ts +2 -5
  176. package/dist/render/lineBatch.js +4 -24
  177. package/dist/render/mesh.d.ts +4 -0
  178. package/dist/render/mesh.js +45 -1
  179. package/dist/render/pass.d.ts +145 -8
  180. package/dist/render/prefilterEnvMap.d.ts +22 -0
  181. package/dist/render/prefilterEnvMap.js +31 -0
  182. package/dist/render/readback.d.ts +30 -0
  183. package/dist/render/readback.js +47 -0
  184. package/dist/render/recon/clamp.d.ts +36 -0
  185. package/dist/render/recon/clamp.js +92 -0
  186. package/dist/render/recon/disocclusion.d.ts +60 -0
  187. package/dist/render/recon/disocclusion.js +109 -0
  188. package/dist/render/recon/frameGen.d.ts +81 -0
  189. package/dist/render/recon/frameGen.js +150 -0
  190. package/dist/render/recon/frameSizes.d.ts +34 -0
  191. package/dist/render/recon/frameSizes.js +58 -0
  192. package/dist/render/recon/jitter.d.ts +60 -0
  193. package/dist/render/recon/jitter.js +118 -0
  194. package/dist/render/recon/motionVectors.d.ts +55 -0
  195. package/dist/render/recon/motionVectors.js +107 -0
  196. package/dist/render/recon/reproject.d.ts +41 -0
  197. package/dist/render/recon/reproject.js +131 -0
  198. package/dist/render/recon/resolve.d.ts +90 -0
  199. package/dist/render/recon/resolve.js +313 -0
  200. package/dist/render/recon/tier.d.ts +24 -0
  201. package/dist/render/recon/tier.js +8 -0
  202. package/dist/render/reflectionProbe.d.ts +26 -0
  203. package/dist/render/reflectionProbe.js +33 -0
  204. package/dist/render/renderQuality.d.ts +69 -0
  205. package/dist/render/renderQuality.js +22 -0
  206. package/dist/render/screenSpaceReflection.d.ts +23 -0
  207. package/dist/render/screenSpaceReflection.js +22 -3
  208. package/dist/render/sdfFont.js +2 -0
  209. package/dist/render/segmentQuads.d.ts +13 -0
  210. package/dist/render/segmentQuads.js +32 -0
  211. package/dist/render/shaders/flat/lobes.d.ts +27 -0
  212. package/dist/render/shaders/flat/lobes.js +33 -3
  213. package/dist/render/shaders/flat/preamble.d.ts +7 -0
  214. package/dist/render/shaders/flat/preamble.js +24 -1
  215. package/dist/render/shaders/flat/probeGrid.d.ts +1 -1
  216. package/dist/render/shaders/flat/probeGrid.js +71 -2
  217. package/dist/render/shaders/generated/flat.wgsl.d.ts +48 -8
  218. package/dist/render/shaders/generated/flat.wgsl.js +64 -24
  219. package/dist/render/shaders/gi/composeField.wgsl.d.ts +56 -0
  220. package/dist/render/shaders/gi/composeField.wgsl.js +231 -0
  221. package/dist/render/shaders/gi/marchField.wgsl.d.ts +30 -0
  222. package/dist/render/shaders/gi/marchField.wgsl.js +141 -0
  223. package/dist/render/shaders/gi/probeBake.wgsl.d.ts +113 -0
  224. package/dist/render/shaders/gi/probeBake.wgsl.js +635 -0
  225. package/dist/render/shaders/gi/probeTrace.wgsl.d.ts +72 -0
  226. package/dist/render/shaders/gi/probeTrace.wgsl.js +261 -0
  227. package/dist/render/shaders/gi/probeVolume.wgsl.d.ts +49 -0
  228. package/dist/render/shaders/gi/probeVolume.wgsl.js +242 -0
  229. package/dist/render/shaders/gi/sampleField.wgsl.d.ts +32 -0
  230. package/dist/render/shaders/gi/sampleField.wgsl.js +134 -0
  231. package/dist/render/shaders/gpudriven/blendRaster.wgsl.d.ts +26 -0
  232. package/dist/render/shaders/gpudriven/blendRaster.wgsl.js +339 -0
  233. package/dist/render/shaders/gpudriven/compact.wgsl.d.ts +29 -0
  234. package/dist/render/shaders/gpudriven/compact.wgsl.js +58 -0
  235. package/dist/render/shaders/gpudriven/cull.wgsl.d.ts +90 -0
  236. package/dist/render/shaders/gpudriven/cull.wgsl.js +423 -0
  237. package/dist/render/shaders/gpudriven/decode.wgsl.d.ts +72 -0
  238. package/dist/render/shaders/gpudriven/decode.wgsl.js +349 -0
  239. package/dist/render/shaders/gpudriven/environment.wgsl.d.ts +44 -0
  240. package/dist/render/shaders/gpudriven/environment.wgsl.js +137 -0
  241. package/dist/render/shaders/gpudriven/fog.wgsl.d.ts +28 -0
  242. package/dist/render/shaders/gpudriven/fog.wgsl.js +107 -0
  243. package/dist/render/shaders/gpudriven/frameBlock.wgsl.d.ts +13 -0
  244. package/dist/render/shaders/gpudriven/frameBlock.wgsl.js +62 -0
  245. package/dist/render/shaders/gpudriven/materialBin.wgsl.d.ts +51 -0
  246. package/dist/render/shaders/gpudriven/materialBin.wgsl.js +112 -0
  247. package/dist/render/shaders/gpudriven/materialTable.wgsl.d.ts +25 -0
  248. package/dist/render/shaders/gpudriven/materialTable.wgsl.js +43 -0
  249. package/dist/render/shaders/gpudriven/meshTransform.wgsl.d.ts +18 -0
  250. package/dist/render/shaders/gpudriven/meshTransform.wgsl.js +37 -0
  251. package/dist/render/shaders/gpudriven/present.wgsl.d.ts +43 -0
  252. package/dist/render/shaders/gpudriven/present.wgsl.js +127 -0
  253. package/dist/render/shaders/gpudriven/shade.wgsl.d.ts +127 -0
  254. package/dist/render/shaders/gpudriven/shade.wgsl.js +874 -0
  255. package/dist/render/shaders/gpudriven/shadow.wgsl.d.ts +44 -0
  256. package/dist/render/shaders/gpudriven/shadow.wgsl.js +308 -0
  257. package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.d.ts +28 -0
  258. package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.js +245 -0
  259. package/dist/render/shaders/network.wgsl.d.ts +101 -0
  260. package/dist/render/shaders/network.wgsl.js +206 -0
  261. package/dist/render/shaders/recon/motion.wgsl.d.ts +44 -0
  262. package/dist/render/shaders/recon/motion.wgsl.js +96 -0
  263. package/dist/render/shaders/recon/resolve.wgsl.d.ts +51 -0
  264. package/dist/render/shaders/recon/resolve.wgsl.js +733 -0
  265. package/dist/render/temporalAa.js +8 -33
  266. package/dist/render/textLayout.js +12 -6
  267. package/dist/render/textRenderer.d.ts +3 -1
  268. package/dist/render/textRenderer.js +4 -1
  269. package/dist/render/translucentQueue.d.ts +6 -0
  270. package/dist/render/translucentQueue.js +11 -0
  271. package/dist/render/windStreakRenderer.d.ts +2 -1
  272. package/dist/render/windStreakRenderer.js +3 -1
  273. package/dist/world/cell.d.ts +63 -0
  274. package/dist/world/cell.js +181 -0
  275. package/dist/world/cellStream.d.ts +103 -0
  276. package/dist/world/cellStream.js +198 -0
  277. package/dist/world/freeze.d.ts +81 -0
  278. package/dist/world/freeze.js +114 -0
  279. package/dist/world/rebase.d.ts +29 -0
  280. package/dist/world/rebase.js +41 -0
  281. package/package.json +8 -3
  282. package/scripts/frames.mjs +92 -0
  283. package/scripts/gpuCompute.mjs +323 -0
  284. package/scripts/png.d.mts +16 -0
  285. package/scripts/png.mjs +25 -0
  286. package/src/core/loop.ts +19 -2
  287. package/src/core/storage.ts +5 -0
  288. package/src/geometry/meshBuilder.ts +5 -1
  289. package/src/index.ts +246 -4
  290. package/src/input/input.ts +6 -1
  291. package/src/math/exact.ts +69 -3
  292. package/src/math/frustum.ts +52 -3
  293. package/src/render/backend/api.ts +42 -1
  294. package/src/render/backend/budget.ts +7 -6
  295. package/src/render/backend/createRenderer.ts +92 -3
  296. package/src/render/backend/materialChanges.ts +54 -0
  297. package/src/render/backend/select.ts +8 -0
  298. package/src/render/backend/webgl2/renderer.ts +211 -9
  299. package/src/render/backend/webgpu/buffers.ts +182 -69
  300. package/src/render/backend/webgpu/fieldCompose.ts +482 -0
  301. package/src/render/backend/webgpu/giFieldPass.ts +200 -0
  302. package/src/render/backend/webgpu/gpuDrivenPass.ts +2993 -0
  303. package/src/render/backend/webgpu/linePass.ts +4 -39
  304. package/src/render/backend/webgpu/probeBake.ts +588 -0
  305. package/src/render/backend/webgpu/renderer.ts +1481 -76
  306. package/src/render/backend/webgpu/scatterPass.ts +15 -1
  307. package/src/render/backend/webgpu/surfaceTexturePass.ts +63 -36
  308. package/src/render/causticsRenderer.ts +5 -2
  309. package/src/render/depthConvention.ts +15 -0
  310. package/src/render/deviceFeatures.ts +77 -0
  311. package/src/render/fog.ts +185 -0
  312. package/src/render/frame/alias.ts +97 -0
  313. package/src/render/frame/deps.ts +155 -0
  314. package/src/render/frame/flushGraph.ts +135 -0
  315. package/src/render/frame/graphSchedule.ts +170 -0
  316. package/src/render/frame/index.ts +52 -0
  317. package/src/render/frame/lifetime.ts +61 -0
  318. package/src/render/frame/passTimings.ts +69 -0
  319. package/src/render/frame/validate.ts +40 -0
  320. package/src/render/frame/virtual.ts +91 -0
  321. package/src/render/gi/chain.ts +225 -0
  322. package/src/render/gi/denoise.ts +276 -0
  323. package/src/render/gi/fieldScene.ts +264 -0
  324. package/src/render/gi/globalField.ts +543 -0
  325. package/src/render/gi/probeGridFit.ts +89 -0
  326. package/src/render/gi/probeTrace.ts +143 -0
  327. package/src/render/gi/probeVolume.ts +288 -0
  328. package/src/render/gi/reflection.ts +163 -0
  329. package/src/render/gi/traceField.ts +223 -0
  330. package/src/render/gi/traceScreen.ts +106 -0
  331. package/src/render/gpuScene.ts +80 -0
  332. package/src/render/gpudriven/alphaTest.ts +33 -0
  333. package/src/render/gpudriven/clusterUpload.ts +123 -0
  334. package/src/render/gpudriven/clusterWorld.ts +239 -0
  335. package/src/render/gpudriven/compact.ts +80 -0
  336. package/src/render/gpudriven/cullClusters.ts +333 -0
  337. package/src/render/gpudriven/decodeTables.ts +332 -0
  338. package/src/render/gpudriven/frustum.ts +70 -0
  339. package/src/render/gpudriven/geometryHarness.ts +51 -0
  340. package/src/render/gpudriven/hzb.ts +113 -0
  341. package/src/render/gpudriven/ibl.ts +147 -0
  342. package/src/render/gpudriven/indirect.ts +89 -0
  343. package/src/render/gpudriven/instances.ts +234 -0
  344. package/src/render/gpudriven/lit.ts +329 -0
  345. package/src/render/gpudriven/lodCut.ts +62 -0
  346. package/src/render/gpudriven/materialBin.ts +131 -0
  347. package/src/render/gpudriven/materialTable.ts +164 -0
  348. package/src/render/gpudriven/pipeline.ts +336 -0
  349. package/src/render/gpudriven/rangeAlloc.ts +122 -0
  350. package/src/render/gpudriven/sceneUpload.ts +173 -0
  351. package/src/render/gpudriven/shadeBins.ts +222 -0
  352. package/src/render/gpudriven/shadow.ts +285 -0
  353. package/src/render/gpudriven/shadowCamera.ts +406 -0
  354. package/src/render/gpudriven/streamScene.ts +575 -0
  355. package/src/render/gpudriven/surfaceFrame.ts +68 -0
  356. package/src/render/gpudriven/twoPhase.ts +214 -0
  357. package/src/render/gpudriven/visbuffer.ts +41 -0
  358. package/src/render/halfFloat.ts +22 -4
  359. package/src/render/inference/attentionTiled.ts +132 -0
  360. package/src/render/inference/denseKernels.ts +369 -0
  361. package/src/render/inference/device.ts +44 -0
  362. package/src/render/inference/deviceGraph.ts +39 -0
  363. package/src/render/inference/fuse.ts +47 -0
  364. package/src/render/inference/kernelKit.ts +120 -0
  365. package/src/render/inference/kernels.ts +18 -0
  366. package/src/render/inference/plan.ts +26 -0
  367. package/src/render/inference/reuse.ts +79 -0
  368. package/src/render/inference/runner.ts +204 -0
  369. package/src/render/inference/schedule.ts +80 -0
  370. package/src/render/inference/shapeKernels.ts +112 -0
  371. package/src/render/inference/spatialKernels.ts +220 -0
  372. package/src/render/inference/splatRaster.wgsl.ts +348 -0
  373. package/src/render/inference/splatTiles.ts +186 -0
  374. package/src/render/lineBatch.ts +4 -24
  375. package/src/render/mesh.ts +46 -1
  376. package/src/render/pass.ts +155 -10
  377. package/src/render/prefilterEnvMap.ts +33 -0
  378. package/src/render/readback.ts +73 -0
  379. package/src/render/recon/clamp.ts +113 -0
  380. package/src/render/recon/disocclusion.ts +143 -0
  381. package/src/render/recon/frameGen.ts +191 -0
  382. package/src/render/recon/frameSizes.ts +64 -0
  383. package/src/render/recon/jitter.ts +126 -0
  384. package/src/render/recon/motionVectors.ts +138 -0
  385. package/src/render/recon/reproject.ts +179 -0
  386. package/src/render/recon/resolve.ts +444 -0
  387. package/src/render/recon/tier.ts +31 -0
  388. package/src/render/reflectionProbe.ts +34 -0
  389. package/src/render/renderQuality.ts +87 -0
  390. package/src/render/screenSpaceReflection.ts +37 -3
  391. package/src/render/sdfFont.ts +2 -0
  392. package/src/render/segmentQuads.ts +39 -0
  393. package/src/render/shaders/flat/lobes.ts +35 -3
  394. package/src/render/shaders/flat/preamble.ts +25 -1
  395. package/src/render/shaders/flat/probeGrid.ts +77 -2
  396. package/src/render/shaders/generated/flat.wgsl.ts +64 -24
  397. package/src/render/shaders/gi/composeField.wgsl.ts +239 -0
  398. package/src/render/shaders/gi/marchField.wgsl.ts +146 -0
  399. package/src/render/shaders/gi/probeBake.wgsl.ts +649 -0
  400. package/src/render/shaders/gi/probeTrace.wgsl.ts +269 -0
  401. package/src/render/shaders/gi/probeVolume.wgsl.ts +246 -0
  402. package/src/render/shaders/gi/sampleField.wgsl.ts +140 -0
  403. package/src/render/shaders/gpudriven/blendRaster.wgsl.ts +343 -0
  404. package/src/render/shaders/gpudriven/compact.wgsl.ts +59 -0
  405. package/src/render/shaders/gpudriven/cull.wgsl.ts +433 -0
  406. package/src/render/shaders/gpudriven/decode.wgsl.ts +373 -0
  407. package/src/render/shaders/gpudriven/environment.wgsl.ts +141 -0
  408. package/src/render/shaders/gpudriven/fog.wgsl.ts +110 -0
  409. package/src/render/shaders/gpudriven/frameBlock.wgsl.ts +62 -0
  410. package/src/render/shaders/gpudriven/materialBin.wgsl.ts +116 -0
  411. package/src/render/shaders/gpudriven/materialTable.wgsl.ts +46 -0
  412. package/src/render/shaders/gpudriven/meshTransform.wgsl.ts +37 -0
  413. package/src/render/shaders/gpudriven/present.wgsl.ts +129 -0
  414. package/src/render/shaders/gpudriven/shade.wgsl.ts +884 -0
  415. package/src/render/shaders/gpudriven/shadow.wgsl.ts +322 -0
  416. package/src/render/shaders/gpudriven/visbufferRaster.wgsl.ts +251 -0
  417. package/src/render/shaders/network.wgsl.ts +238 -0
  418. package/src/render/shaders/recon/motion.wgsl.ts +101 -0
  419. package/src/render/shaders/recon/resolve.wgsl.ts +741 -0
  420. package/src/render/temporalAa.ts +9 -33
  421. package/src/render/textLayout.ts +12 -6
  422. package/src/render/textRenderer.ts +5 -2
  423. package/src/render/translucentQueue.ts +11 -0
  424. package/src/render/windStreakRenderer.ts +4 -2
  425. package/src/world/cell.ts +231 -0
  426. package/src/world/cellStream.ts +278 -0
  427. package/src/world/freeze.ts +157 -0
  428. package/src/world/rebase.ts +56 -0
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Which values of a graph may share one buffer, as one rule both sides plan by: the device's
3
+ * runner beside this file, and `@driftengine/texture`'s reference evaluator.
4
+ *
5
+ * **It lives here rather than beside that evaluator because of the direction of the arrow.**
6
+ * `texture` peers on core and core does not peer on `texture` — `deviceGraph.ts` says so and is
7
+ * built around it — so a rule both need has to sit on this side or be written twice. It was on the
8
+ * other side for a day, where it made core's runtime import a devDependency and
9
+ * `scripts/boundaries.test.mjs` refused it.
10
+ *
11
+ * **A value's buffer is given back after the last node that reads it, and not before** — so a
12
+ * node's output never shares a buffer with any of its own inputs, since the inputs are read while
13
+ * the output is written. What is `held` keeps a buffer of its own for the life of the plan, and so
14
+ * does every output; a value that is neither written by a node nor held is not planned at all,
15
+ * which is how the evaluator leaves weights and inputs in the caller's own arrays.
16
+ *
17
+ * **Two implementations of this would drift**, and the failure is a network that runs, validates
18
+ * and answers wrongly — a value overwritten before its last reader reads it.
19
+ *
20
+ * What it gives up: a free buffer is taken first-come rather than by the size that fits best, so a
21
+ * small value may hold a large buffer while a larger one waits. The transformers this runs repeat a
22
+ * block of identically shaped values, where first-come and best-fit choose the same buffers.
23
+ */
24
+
25
+ export interface BufferReuse {
26
+ /** The buffer each planned value lives in. */
27
+ readonly slotOf: ReadonlyMap<string, number>;
28
+ /** Each buffer's size, in values: the largest value it ever holds. */
29
+ readonly sizes: readonly number[];
30
+ }
31
+
32
+ export function planReuse(
33
+ graph: {
34
+ readonly nodes: readonly { readonly inputs: readonly string[]; readonly output: string }[];
35
+ /** Values given a buffer each before any node runs, in this order. */
36
+ readonly held: readonly string[];
37
+ /** Values never given back, claimed where they are written. */
38
+ readonly outputs: readonly string[];
39
+ },
40
+ sizeOf: (name: string) => number,
41
+ ): BufferReuse {
42
+ const slotOf = new Map<string, number>();
43
+ const sizes: number[] = [];
44
+ const pinned = new Set<string>([...graph.held, ...graph.outputs]);
45
+ const claim = (name: string): number => {
46
+ sizes.push(sizeOf(name));
47
+ slotOf.set(name, sizes.length - 1);
48
+ return sizes.length - 1;
49
+ };
50
+ for (const name of graph.held) claim(name);
51
+
52
+ /* The last node reading each value; a value never read is last read where it is written. */
53
+ const lastRead = new Map<string, number>();
54
+ graph.nodes.forEach((node, at) => {
55
+ lastRead.set(node.output, at);
56
+ for (const input of node.inputs) lastRead.set(input, at);
57
+ });
58
+
59
+ const free: number[] = [];
60
+ graph.nodes.forEach((node, at) => {
61
+ if (pinned.has(node.output)) {
62
+ claim(node.output);
63
+ } else {
64
+ const reuse = free.shift();
65
+ if (reuse === undefined) claim(node.output);
66
+ else {
67
+ slotOf.set(node.output, reuse);
68
+ sizes[reuse] = Math.max(sizes[reuse] as number, sizeOf(node.output));
69
+ }
70
+ }
71
+ /* Only after the node has run: its inputs are read while its output is written. */
72
+ for (const value of new Set([...node.inputs, node.output])) {
73
+ const slot = slotOf.get(value);
74
+ if (slot === undefined || pinned.has(value) || lastRead.get(value) !== at) continue;
75
+ free.push(slot);
76
+ }
77
+ });
78
+ return { slotOf, sizes };
79
+ }
@@ -0,0 +1,204 @@
1
+ /**
2
+ * A graph on a device: its buffers, its pipelines, and one compute pass that runs it.
3
+ *
4
+ * **A binder over `schedule.ts`**, which decides everything and is tested without a device; what is
5
+ * left here is creating what the schedule names and recording its dispatches. One pass holds the
6
+ * whole graph, because WebGPU orders a pass's dispatches and makes each one's writes visible to the
7
+ * next — a network is a chain of dependent dispatches and needs nothing more.
8
+ *
9
+ * **Creation is asynchronous, and it is where anything wrong is reported**: a value larger than the
10
+ * device can bind is refused by name before a buffer exists, and every pipeline is built with
11
+ * `createComputePipelineAsync`, which rejects on a kernel that does not compile. A runner that was
12
+ * created runs. Identical kernels share one pipeline — a transformer repeats one block's shapes
13
+ * once per layer, so its pipelines number its distinct shapes rather than its nodes.
14
+ *
15
+ * `encode` records the graph into a caller's encoder, so a network can run inside a frame or under
16
+ * a timestamp query; `run` is the whole round trip, and one is in flight at a time, because its
17
+ * readback buffers are the runner's and a second run would map them while the first holds them.
18
+ * **A run the device refuses is refused too**: WebGPU reports a validation failure at `submit`,
19
+ * and a refused command buffer runs nothing, so without the scope around it the readback would
20
+ * map and return whatever the buffers last held — a plausible answer to a question never run.
21
+ */
22
+ import { shapeSize, type DeviceGraph } from './deviceGraph.ts';
23
+ import type { InferenceDevice } from './device.ts';
24
+ import { scheduleGraph } from './schedule.ts';
25
+
26
+ /* The usage and stage flags by value: a host with no browser has no `GPUBufferUsage` global. */
27
+ const MAP_READ = 0x0001;
28
+ const COPY_SRC = 0x0004;
29
+ const COPY_DST = 0x0008;
30
+ const STORAGE = 0x0080;
31
+ const COMPUTE = 0x4;
32
+ const MODE_READ = 0x0001;
33
+
34
+ export interface GraphRunner {
35
+ /** Records every dispatch of the graph into `encoder`, in one compute pass. */
36
+ encode(encoder: GPUCommandEncoder, timestampWrites?: GPUComputePassTimestampWrites): void;
37
+ /** Writes the inputs, runs the graph and reads its outputs back, each by name. */
38
+ run(inputs: ReadonlyMap<string, Float32Array>): Promise<Map<string, Float32Array>>;
39
+ dispose(): void;
40
+ }
41
+
42
+ export async function createGraphRunner(
43
+ inference: InferenceDevice,
44
+ graph: DeviceGraph,
45
+ ): Promise<GraphRunner> {
46
+ const { device } = inference;
47
+ const schedule = scheduleGraph(graph, { half: inference.half });
48
+ const namesOf = new Map<number, string[]>();
49
+ for (const [name, slot] of schedule.plan.slotOf) {
50
+ namesOf.set(slot, [...(namesOf.get(slot) ?? []), name]);
51
+ }
52
+ const limit = device.limits.maxStorageBufferBindingSize;
53
+ const oversized = schedule.bytes.flatMap((bytes, slot) =>
54
+ bytes > limit ? [`${(namesOf.get(slot) ?? []).join('/')} (${bytes} bytes)`] : [],
55
+ );
56
+ if (oversized.length > 0) {
57
+ throw new Error(
58
+ `${oversized.join(', ')} ${oversized.length === 1 ? 'is' : 'are'} larger than the ` +
59
+ `${limit} bytes this device can bind as one buffer`,
60
+ );
61
+ }
62
+
63
+ device.pushErrorScope('validation');
64
+ const buffers = schedule.bytes.map((size, slot) =>
65
+ device.createBuffer({
66
+ label: `inference ${(namesOf.get(slot) ?? []).join('/')}`,
67
+ size,
68
+ usage: STORAGE | COPY_DST | COPY_SRC,
69
+ }),
70
+ );
71
+ for (const upload of schedule.uploads) {
72
+ device.queue.writeBuffer(buffers[upload.slot] as GPUBuffer, 0, padded(upload.data));
73
+ }
74
+
75
+ const layouts = new Map<number, GPUBindGroupLayout>();
76
+ const layoutFor = (inputs: number): GPUBindGroupLayout => {
77
+ let layout = layouts.get(inputs);
78
+ if (layout === undefined) {
79
+ const entries: GPUBindGroupLayoutEntry[] = [];
80
+ for (let i = 0; i <= inputs; i += 1) {
81
+ entries.push({
82
+ binding: i,
83
+ visibility: COMPUTE,
84
+ buffer: { type: i < inputs ? 'read-only-storage' : 'storage' },
85
+ });
86
+ }
87
+ layout = device.createBindGroupLayout({ label: `inference ${inputs} in`, entries });
88
+ layouts.set(inputs, layout);
89
+ }
90
+ return layout;
91
+ };
92
+ const pipelines = new Map<string, Promise<GPUComputePipeline>>();
93
+ const steps = await Promise.all(
94
+ schedule.steps.map(async (step) => {
95
+ const layout = layoutFor(step.slots.length - 1);
96
+ let pipeline = pipelines.get(step.code);
97
+ if (pipeline === undefined) {
98
+ pipeline = device.createComputePipelineAsync({
99
+ label: `inference ${step.label}`,
100
+ layout: device.createPipelineLayout({ bindGroupLayouts: [layout] }),
101
+ compute: {
102
+ module: device.createShaderModule({ label: step.label, code: step.code }),
103
+ entryPoint: 'main',
104
+ },
105
+ });
106
+ pipelines.set(step.code, pipeline);
107
+ }
108
+ const group = device.createBindGroup({
109
+ label: `inference ${step.label}`,
110
+ layout,
111
+ entries: step.slots.map((slot, binding) => ({
112
+ binding,
113
+ resource: { buffer: buffers[slot] as GPUBuffer },
114
+ })),
115
+ });
116
+ return { pipeline: await pipeline, group, workgroups: step.workgroups };
117
+ }),
118
+ );
119
+ const staging = graph.outputs.map((name) => {
120
+ const bytes = Math.max(4, shapeSize(graph.shapes.get(name) ?? []) * 4);
121
+ return {
122
+ name,
123
+ source: buffers[schedule.plan.slotOf.get(name) as number] as GPUBuffer,
124
+ bytes,
125
+ buffer: device.createBuffer({
126
+ label: `inference readback ${name}`,
127
+ size: bytes,
128
+ usage: MAP_READ | COPY_DST,
129
+ }),
130
+ };
131
+ });
132
+ const invalid = await device.popErrorScope();
133
+ if (invalid !== null)
134
+ throw new Error(`the device refused a network's buffers: ${invalid.message}`);
135
+
136
+ const encode = (encoder: GPUCommandEncoder, timestampWrites?: GPUComputePassTimestampWrites) => {
137
+ const pass = encoder.beginComputePass(timestampWrites === undefined ? {} : { timestampWrites });
138
+ for (const step of steps) {
139
+ pass.setPipeline(step.pipeline);
140
+ pass.setBindGroup(0, step.group);
141
+ pass.dispatchWorkgroups(step.workgroups[0], step.workgroups[1], step.workgroups[2]);
142
+ }
143
+ pass.end();
144
+ };
145
+
146
+ let running = false;
147
+ const run = async (inputs: ReadonlyMap<string, Float32Array>) => {
148
+ if (running) throw new Error('a network runner runs one graph at a time; await the last run');
149
+ for (const input of graph.inputs) {
150
+ const values = inputs.get(input.name);
151
+ const expected = shapeSize(input.shape);
152
+ if (values === undefined || values.length !== expected) {
153
+ throw new RangeError(
154
+ `input "${input.name}" needs ${expected} values and was given ${values?.length ?? 'none'}`,
155
+ );
156
+ }
157
+ }
158
+ running = true;
159
+ try {
160
+ for (const input of graph.inputs) {
161
+ const slot = schedule.plan.slotOf.get(input.name) as number;
162
+ device.queue.writeBuffer(
163
+ buffers[slot] as GPUBuffer,
164
+ 0,
165
+ inputs.get(input.name) as Float32Array,
166
+ );
167
+ }
168
+ device.pushErrorScope('validation');
169
+ const encoder = device.createCommandEncoder({ label: 'inference run' });
170
+ encode(encoder);
171
+ for (const out of staging)
172
+ encoder.copyBufferToBuffer(out.source, 0, out.buffer, 0, out.bytes);
173
+ device.queue.submit([encoder.finish()]);
174
+ const refused = await device.popErrorScope();
175
+ if (refused !== null)
176
+ throw new Error(`the device refused a network's run: ${refused.message}`);
177
+ await Promise.all(staging.map((out) => out.buffer.mapAsync(MODE_READ)));
178
+ const results = new Map<string, Float32Array>();
179
+ for (const out of staging) {
180
+ const values = new Float32Array(out.buffer.getMappedRange().slice(0));
181
+ const count = shapeSize(graph.shapes.get(out.name) ?? []);
182
+ results.set(out.name, count === values.length ? values : values.subarray(0, count));
183
+ out.buffer.unmap();
184
+ }
185
+ return results;
186
+ } finally {
187
+ running = false;
188
+ }
189
+ };
190
+
191
+ const dispose = () => {
192
+ for (const buffer of buffers) buffer.destroy();
193
+ for (const out of staging) out.buffer.destroy();
194
+ };
195
+ return { encode, run, dispose };
196
+ }
197
+
198
+ /* A queue write is sized in fours, so an odd count of halves is written with one of padding. */
199
+ function padded(data: Float32Array | Uint16Array): Float32Array | Uint16Array {
200
+ if (data.byteLength % 4 === 0) return data;
201
+ const out = new Uint16Array(data.length + 1);
202
+ out.set(data);
203
+ return out;
204
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * What a graph becomes before a device sees it: its dispatches, its buffers, and its weights.
3
+ *
4
+ * **Everything a runner decides is decided here, with no device**, so the decisions have tests and
5
+ * the runner is a binder: GELUs folded into their multiplies, a buffer for every value from the
6
+ * planner, one kernel per node generated at the shapes the node has, and the weights narrowed to
7
+ * half precision when that was asked for. A dispatch binds its inputs' buffers in order and then
8
+ * its output's, which is the binding order every kernel declares.
9
+ *
10
+ * **Half precision narrows the weights and nothing else.** A weight is stored as the nearest half
11
+ * and widened as it is read; the values between nodes stay single precision, because they are what
12
+ * a network's error accumulates through and a weight is read-only and read many times. What it
13
+ * gives up is half the memory of the activations as well — the step to take if a model's
14
+ * activations turn out to be what does not fit.
15
+ */
16
+ import { shapeSize, type DeviceGraph } from './deviceGraph.ts';
17
+ import { fuseActivations } from './fuse.ts';
18
+ import { toHalfFloats } from '../halfFloat.ts';
19
+ import { DEVICE_KERNELS, type ElementType } from './kernels.ts';
20
+ import { planBuffers, type BufferPlan } from './plan.ts';
21
+
22
+ export interface ScheduledStep {
23
+ /** The operator and the value it writes, which is what a device error names. */
24
+ readonly label: string;
25
+ readonly code: string;
26
+ readonly workgroups: readonly [number, number, number];
27
+ /** The buffers bound, in binding order: each input's, then the output's. */
28
+ readonly slots: readonly number[];
29
+ }
30
+
31
+ export interface Schedule {
32
+ readonly steps: readonly ScheduledStep[];
33
+ readonly plan: BufferPlan;
34
+ /** Each buffer's size in bytes, rounded up to the four a storage binding is sized in. */
35
+ readonly bytes: readonly number[];
36
+ /** The weights, each into its buffer once, as the precision asked for stores them. */
37
+ readonly uploads: readonly { readonly slot: number; readonly data: Float32Array | Uint16Array }[];
38
+ }
39
+
40
+ export function scheduleGraph(graph: DeviceGraph, options: { readonly half: boolean }): Schedule {
41
+ const missing = graph.nodes.filter((node) => !DEVICE_KERNELS.has(node.op));
42
+ if (missing.length > 0) {
43
+ const names = [...new Set(missing.map((node) => node.op))].join(', ');
44
+ throw new Error(`the device has no kernel for ${names}; the graph cannot run here`);
45
+ }
46
+ const fused = fuseActivations(graph);
47
+ const plan = planBuffers(fused);
48
+ const narrow = new Set(options.half ? fused.tensors.map((tensor) => tensor.name) : []);
49
+ const typeOf = (name: string): ElementType => (narrow.has(name) ? 'f16' : 'f32');
50
+ const shapeOf = (name: string): readonly number[] => fused.shapes.get(name) ?? [];
51
+
52
+ const bytes = plan.sizes.map((size) => Math.max(4, size * 4));
53
+ for (const name of narrow) {
54
+ const slot = plan.slotOf.get(name) as number;
55
+ bytes[slot] = Math.max(4, Math.ceil((shapeSize(shapeOf(name)) * 2) / 4) * 4);
56
+ }
57
+
58
+ const steps = fused.nodes.map((node): ScheduledStep => {
59
+ const generate = DEVICE_KERNELS.get(node.op);
60
+ if (generate === undefined) throw new Error(`the device has no kernel for ${node.op}`);
61
+ const kernel = generate({
62
+ inputShapes: node.inputs.map(shapeOf),
63
+ outputShape: shapeOf(node.output),
64
+ attributes: node.attributes,
65
+ inputTypes: node.inputs.map(typeOf),
66
+ });
67
+ return {
68
+ label: `${node.op} ${node.output}`,
69
+ code: kernel.code,
70
+ workgroups: kernel.workgroups,
71
+ slots: [...node.inputs, node.output].map((name) => plan.slotOf.get(name) as number),
72
+ };
73
+ });
74
+
75
+ const uploads = fused.tensors.map((tensor) => ({
76
+ slot: plan.slotOf.get(tensor.name) as number,
77
+ data: narrow.has(tensor.name) ? toHalfFloats(tensor.data) : tensor.data,
78
+ }));
79
+ return { steps, plan, bytes, uploads };
80
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * The shape operators on the device: they move values and compute nothing, or write a zero.
3
+ *
4
+ * **Each is a copy, one invocation per output element**, with the index arithmetic baked from the
5
+ * shapes. `reshape` is a copy too rather than an alias of its input's buffer: aliasing would make
6
+ * two values share a buffer and the planner's rule — a buffer is reused once nothing reads what it
7
+ * holds — would have to follow aliases, which is a second rule for one saving the size of a copy.
8
+ */
9
+ import { type KernelGenerator, list, num, perElement, read, size } from './kernelKit.ts';
10
+
11
+ /* Strides of a row-major shape. */
12
+ function strides(shape: readonly number[]): number[] {
13
+ const out = shape.map(() => 1);
14
+ for (let d = shape.length - 2; d >= 0; d -= 1)
15
+ out[d] = (out[d + 1] as number) * (shape[d + 1] as number);
16
+ return out;
17
+ }
18
+
19
+ const permute: KernelGenerator = (request) => {
20
+ const input = request.inputShapes[0] as readonly number[];
21
+ const order = list(request.attributes, 'order');
22
+ const from = strides(input);
23
+ const outStrides = strides(request.outputShape);
24
+ /* Output axis d walks input axis order[d]: its index times that axis's input stride. */
25
+ const terms = order.map(
26
+ (axis, d) =>
27
+ `((i / ${outStrides[d]}u) % ${request.outputShape[d]}u) * ${from[axis as number]}u`,
28
+ );
29
+ return perElement(
30
+ request,
31
+ size(request.outputShape),
32
+ ` output[i] = ${read(request, 0, terms.join(' + ') || '0u')};`,
33
+ );
34
+ };
35
+
36
+ const reshape: KernelGenerator = (request) =>
37
+ perElement(request, size(request.outputShape), ` output[i] = ${read(request, 0, 'i')};`);
38
+
39
+ const concat: KernelGenerator = (request) => {
40
+ const axis = num(request.attributes, 'axis');
41
+ const out = request.outputShape;
42
+ const inner = size(out.slice(axis + 1));
43
+ const along = out[axis] as number;
44
+ /* Walk the inputs along the axis: each owns a run of it, starting where the one before ended. */
45
+ let start = 0;
46
+ const branches = request.inputShapes.map((shape, n) => {
47
+ const length = shape[axis] as number;
48
+ const branch = `if (a < ${start + length}u) { output[i] = ${read(request, n, `(outer * ${length}u + a - ${start}u) * ${inner}u + rest`)}; return; }`;
49
+ start += length;
50
+ return branch;
51
+ });
52
+ return perElement(
53
+ request,
54
+ size(out),
55
+ ` let rest = i % ${inner}u;
56
+ let a = (i / ${inner}u) % ${along}u;
57
+ let outer = i / ${inner * along}u;
58
+ ${branches.join('\n ')}`,
59
+ );
60
+ };
61
+
62
+ const slice: KernelGenerator = (request) => {
63
+ const axis = num(request.attributes, 'axis');
64
+ const begin = num(request.attributes, 'start');
65
+ const input = request.inputShapes[0] as readonly number[];
66
+ const inner = size(input.slice(axis + 1));
67
+ const length = input[axis] as number;
68
+ const taken = request.outputShape[axis] as number;
69
+ return perElement(
70
+ request,
71
+ size(request.outputShape),
72
+ ` let rest = i % ${inner}u;
73
+ let a = (i / ${inner}u) % ${taken}u;
74
+ let outer = i / ${inner * taken}u;
75
+ output[i] = ${read(request, 0, `(outer * ${length}u + a + ${begin}u) * ${inner}u + rest`)};`,
76
+ );
77
+ };
78
+
79
+ /* An output element past the input's end on any axis is a zero; the rest read their own index. */
80
+ const pad: KernelGenerator = (request) => {
81
+ const input = request.inputShapes[0] as readonly number[];
82
+ const from = strides(input);
83
+ const to = strides(request.outputShape);
84
+ const at = (axis: number): string => `((i / ${to[axis]}u) % ${request.outputShape[axis]}u)`;
85
+ const inside = input.map((d, axis) => `${at(axis)} < ${d}u`).join(' && ');
86
+ const index = input.map((_, axis) => `${at(axis)} * ${from[axis]}u`).join(' + ');
87
+ return perElement(
88
+ request,
89
+ size(request.outputShape),
90
+ ` if (${inside}) { output[i] = ${read(request, 0, index)}; } else { output[i] = 0.0; }`,
91
+ );
92
+ };
93
+
94
+ /* Row `indices[r]` of the table, clamped to the last row, since a device cannot refuse an index. */
95
+ const gather: KernelGenerator = (request) => {
96
+ const [rows, width] = request.inputShapes[0] as readonly number[] as [number, number];
97
+ return perElement(
98
+ request,
99
+ size(request.outputShape),
100
+ ` let row = min(u32(${read(request, 1, `i / ${width}u`)}), ${rows - 1}u);
101
+ output[i] = ${read(request, 0, `row * ${width}u + i % ${width}u`)};`,
102
+ );
103
+ };
104
+
105
+ export const SHAPE_KERNELS: readonly (readonly [string, KernelGenerator])[] = [
106
+ ['permute', permute],
107
+ ['reshape', reshape],
108
+ ['concat', concat],
109
+ ['slice', slice],
110
+ ['pad', pad],
111
+ ['gather', gather],
112
+ ];