@driftengine/core 3.62.0 → 4.0.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 +70 -4
  9. package/dist/index.js +123 -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 +47 -14
  42. package/dist/render/backend/webgpu/surfaceTexturePass.js +128 -80
  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 +261 -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 +158 -88
  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,97 @@
1
+ /**
2
+ * Where each transient resource lives in the frame's arena, so that two which are never alive
3
+ * together share the memory.
4
+ *
5
+ * **First fit over slots, in declaration order.** Not best fit and not a bin-packing search:
6
+ * the input is tens of resources whose order is already meaningful, the packing runs once per
7
+ * frame composition rather than per frame, and a first-fit result is stable — which matters far
8
+ * more than a few saved bytes, because an allocator whose output moves between frames moves
9
+ * every binding with it.
10
+ *
11
+ * A slot records the widest resource it has held and the node at which its current occupant
12
+ * dies. A later resource may take the slot when it is born strictly after that node.
13
+ */
14
+ import type { Lifetimes } from './lifetime.ts';
15
+ import { firstWrite, lastRead } from './lifetime.ts';
16
+ import type { VirtualTable } from './virtual.ts';
17
+ import { virtualBytes } from './virtual.ts';
18
+
19
+ export interface AliasPlan {
20
+ /** Byte offset into the arena per identifier, or -1 when nothing writes it. */
21
+ offsets: Int32Array;
22
+ /** Byte offset of each slot, parallel to `slotEnd` and `slotSize`. */
23
+ slotAt: Int32Array;
24
+ /** Node at which each slot's current occupant is last read. */
25
+ slotEnd: Int32Array;
26
+ /** Widest resource each slot has held. */
27
+ slotSize: Int32Array;
28
+ /** How many slots are in use. */
29
+ slots: number;
30
+ }
31
+
32
+ export function createAliasPlan(capacity: number): AliasPlan {
33
+ return {
34
+ offsets: new Int32Array(capacity),
35
+ slotAt: new Int32Array(capacity),
36
+ slotEnd: new Int32Array(capacity),
37
+ slotSize: new Int32Array(capacity),
38
+ slots: 0,
39
+ };
40
+ }
41
+
42
+ /** Alignment every slot starts on. 256 is the widest uniform-buffer alignment WebGPU requires. */
43
+ const ALIGN = 256;
44
+
45
+ function aligned(bytes: number): number {
46
+ return Math.ceil(bytes / ALIGN) * ALIGN;
47
+ }
48
+
49
+ export function planAliases(table: VirtualTable, lifetimes: Lifetimes, out: AliasPlan): number {
50
+ out.offsets.fill(-1);
51
+ out.slots = 0;
52
+ let total = 0;
53
+
54
+ for (let id = 0; id < table.count; id += 1) {
55
+ const born = firstWrite(lifetimes, id);
56
+ if (born === -1) continue;
57
+ const dies = lastRead(lifetimes, id);
58
+ const size = aligned(virtualBytes(table, id));
59
+
60
+ let placed = -1;
61
+ for (let slot = 0; slot < out.slots; slot += 1) {
62
+ if ((out.slotEnd[slot] ?? 0) < born) {
63
+ placed = slot;
64
+ break;
65
+ }
66
+ }
67
+
68
+ if (placed === -1) {
69
+ placed = out.slots;
70
+ out.slotAt[placed] = total;
71
+ out.slotSize[placed] = size;
72
+ total += size;
73
+ out.slots = placed + 1;
74
+ } else if (size > (out.slotSize[placed] ?? 0)) {
75
+ /*
76
+ * The slot has to widen, and widening in place would overlap whatever follows it. Retiring
77
+ * the slot and opening a new one is correct and costs one wasted slot; compacting would
78
+ * move every offset after it, which is the stability the header refuses to give up.
79
+ */
80
+ out.slotEnd[placed] = Number.MAX_SAFE_INTEGER;
81
+ placed = out.slots;
82
+ out.slotAt[placed] = total;
83
+ out.slotSize[placed] = size;
84
+ total += size;
85
+ out.slots = placed + 1;
86
+ }
87
+
88
+ out.offsets[id] = out.slotAt[placed] ?? 0;
89
+ out.slotEnd[placed] = dies;
90
+ }
91
+
92
+ return total;
93
+ }
94
+
95
+ export function offsetOf(plan: AliasPlan, id: number): number {
96
+ return plan.offsets[id] ?? -1;
97
+ }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * What each node reads and writes, when there are too many resources for a mask.
3
+ *
4
+ * One flat identifier store with a span per node, which is the same shape `nav/navGraph.ts` uses
5
+ * for adjacency and for the same reason: the spans are written once in order and read many
6
+ * times, so an offset and a length beat an array per node by every measure that matters here.
7
+ *
8
+ * `readsOf` and `writesOf` return **views into the store**, not copies. A caller that keeps one
9
+ * past the next `resetDeps` is reading somebody else's edges, which is why neither is exposed
10
+ * outside `render/`.
11
+ */
12
+ export interface Deps {
13
+ /** Every read identifier then every write identifier, node by node. */
14
+ edges: Int32Array;
15
+ /** Four entries per node: read offset, read length, write offset, write length. */
16
+ spans: Int32Array;
17
+ /** How many identifiers of `edges` are in use. */
18
+ used: number;
19
+ /** How many nodes have been recorded. */
20
+ count: number;
21
+ }
22
+
23
+ const SPAN_STRIDE = 4;
24
+
25
+ export function createDeps(nodeCapacity: number, edgeCapacity: number): Deps {
26
+ return {
27
+ edges: new Int32Array(edgeCapacity),
28
+ spans: new Int32Array(nodeCapacity * SPAN_STRIDE),
29
+ used: 0,
30
+ count: 0,
31
+ };
32
+ }
33
+
34
+ export function resetDeps(deps: Deps): void {
35
+ deps.used = 0;
36
+ deps.count = 0;
37
+ }
38
+
39
+ export function depsNodeCount(deps: Deps): number {
40
+ return deps.count;
41
+ }
42
+
43
+ function growEdges(deps: Deps, need: number): void {
44
+ let size = deps.edges.length === 0 ? 16 : deps.edges.length;
45
+ while (size < need) size *= 2;
46
+ const edges = new Int32Array(size);
47
+ edges.set(deps.edges);
48
+ deps.edges = edges;
49
+ }
50
+
51
+ function growSpans(deps: Deps): void {
52
+ const size = deps.spans.length === 0 ? SPAN_STRIDE * 8 : deps.spans.length * 2;
53
+ const spans = new Int32Array(size);
54
+ spans.set(deps.spans);
55
+ deps.spans = spans;
56
+ }
57
+
58
+ /*
59
+ * Both stores are grown before either span is written. Growing between the read span and the
60
+ * write span would copy a half-written node and silently drop its writes, which is the defect
61
+ * the growth test in this module's suite exists to catch.
62
+ */
63
+ export function recordDeps(
64
+ deps: Deps,
65
+ reads: readonly number[],
66
+ writes: readonly number[],
67
+ ): number {
68
+ const need = deps.used + reads.length + writes.length;
69
+ if (need > deps.edges.length) growEdges(deps, need);
70
+ if ((deps.count + 1) * SPAN_STRIDE > deps.spans.length) growSpans(deps);
71
+
72
+ const readAt = deps.used;
73
+ for (let i = 0; i < reads.length; i += 1) deps.edges[deps.used + i] = reads[i] ?? 0;
74
+ deps.used += reads.length;
75
+
76
+ const writeAt = deps.used;
77
+ for (let i = 0; i < writes.length; i += 1) deps.edges[deps.used + i] = writes[i] ?? 0;
78
+ deps.used += writes.length;
79
+
80
+ const node = deps.count;
81
+ const base = node * SPAN_STRIDE;
82
+ deps.spans[base] = readAt;
83
+ deps.spans[base + 1] = reads.length;
84
+ deps.spans[base + 2] = writeAt;
85
+ deps.spans[base + 3] = writes.length;
86
+ deps.count = node + 1;
87
+ return node;
88
+ }
89
+
90
+ /*
91
+ * Count the bits of a mask, which is how many identifiers it becomes.
92
+ *
93
+ * Kernighan's loop rather than a table: a mask here has at most `RESOURCE_COUNT` bits and usually
94
+ * two, so this runs once or twice.
95
+ */
96
+ function bitCount(mask: number): number {
97
+ let count = 0;
98
+ for (let rest = mask >>> 0; rest !== 0; rest &= rest - 1) count += 1;
99
+ return count;
100
+ }
101
+
102
+ function writeBits(deps: Deps, mask: number, at: number): void {
103
+ let offset = at;
104
+ for (let bit = 0, rest = mask >>> 0; rest !== 0; bit += 1, rest >>>= 1) {
105
+ if ((rest & 1) === 0) continue;
106
+ deps.edges[offset] = bit;
107
+ offset += 1;
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Record a node whose reads and writes are masks, one identifier per set bit, lowest first.
113
+ *
114
+ * **What lets a fixed-composition flush be scheduled by identifiers without building a list.** The
115
+ * forward renderer records masks, and `recordDeps` takes arrays; a flush converting one to the
116
+ * other through arrays would allocate per node, on the path `AGENTS.md` forbids it on. Bit `n`
117
+ * is identifier `n`, so `FRAME_RESOURCES` is the first `RESOURCE_COUNT` identifiers of any frame
118
+ * that mixes the two.
119
+ */
120
+ export function recordMaskDeps(deps: Deps, reads: number, writes: number): number {
121
+ const readCount = bitCount(reads);
122
+ const writeCount = bitCount(writes);
123
+ const need = deps.used + readCount + writeCount;
124
+ if (need > deps.edges.length) growEdges(deps, need);
125
+ if ((deps.count + 1) * SPAN_STRIDE > deps.spans.length) growSpans(deps);
126
+
127
+ const readAt = deps.used;
128
+ writeBits(deps, reads, readAt);
129
+ const writeAt = readAt + readCount;
130
+ writeBits(deps, writes, writeAt);
131
+ deps.used = writeAt + writeCount;
132
+
133
+ const node = deps.count;
134
+ const base = node * SPAN_STRIDE;
135
+ deps.spans[base] = readAt;
136
+ deps.spans[base + 1] = readCount;
137
+ deps.spans[base + 2] = writeAt;
138
+ deps.spans[base + 3] = writeCount;
139
+ deps.count = node + 1;
140
+ return node;
141
+ }
142
+
143
+ export function readsOf(deps: Deps, node: number): Int32Array {
144
+ const base = node * SPAN_STRIDE;
145
+ const at = deps.spans[base] ?? 0;
146
+ const length = deps.spans[base + 1] ?? 0;
147
+ return deps.edges.subarray(at, at + length);
148
+ }
149
+
150
+ export function writesOf(deps: Deps, node: number): Int32Array {
151
+ const base = node * SPAN_STRIDE;
152
+ const at = deps.spans[base + 2] ?? 0;
153
+ const length = deps.spans[base + 3] ?? 0;
154
+ return deps.edges.subarray(at, at + length);
155
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * A forward flush, scheduled by the identifier graph instead of by masks.
3
+ *
4
+ * **Wave 1A's exit criterion is that both pipelines are expressible in one graph and today's frames
5
+ * are pixel-identical through it.** The second pipeline records its stages into a `Deps` table
6
+ * (`gpudriven/pipeline.ts`); this is the forward renderer's half. A flush's arena is recorded as
7
+ * identifier nodes — bit `n` of a mask is identifier `n` — scheduled by `scheduleGraph`, and the
8
+ * load and store each attachment gets are derived from `lifetime.ts`. What comes out is the same
9
+ * `ScheduledPass` the mask scheduler writes, so the executor reading it does not know which ran.
10
+ *
11
+ * **One difference, and the renderer never reaches it.** Culling here is transitive: a pass whose
12
+ * only reader was dropped is dropped too, where `schedule.ts` keeps it. Every node the renderer
13
+ * records writes something its live set holds, so no flush it makes has a dropped reader —
14
+ * `flushGraph.test.ts` holds a random corpus of its own shapes to exact agreement and names the
15
+ * frame where the two part.
16
+ *
17
+ * Allocates nothing once warm. The state is the caller's and grows only when a flush outgrows it,
18
+ * the way the arena does.
19
+ */
20
+ import type { Arena } from './arena.ts';
21
+ import { nodeCount, nodeReads, nodeWrites } from './arena.ts';
22
+ import type { Deps } from './deps.ts';
23
+ import { createDeps, recordMaskDeps, resetDeps } from './deps.ts';
24
+ import type { GraphPass, GraphScratch } from './graphSchedule.ts';
25
+ import { createGraphPasses, createGraphScratch, scheduleGraph } from './graphSchedule.ts';
26
+ import type { Lifetimes } from './lifetime.ts';
27
+ import { computeLifetimes, createLifetimes, lastRead } from './lifetime.ts';
28
+ import { RESOURCE_COUNT } from './resources.ts';
29
+ import type { ScheduledPass } from './schedule.ts';
30
+
31
+ export interface FlushSchedule {
32
+ deps: Deps;
33
+ scratch: GraphScratch;
34
+ passes: GraphPass[];
35
+ lifetimes: Lifetimes;
36
+ /** Every node ordered: a forward draw's position is its meaning. Grown with the arena. */
37
+ ordered: Uint8Array;
38
+ /** The live identifiers of this flush, and how many of them there are. */
39
+ live: Int32Array;
40
+ liveCount: number;
41
+ }
42
+
43
+ export function createFlushSchedule(capacity: number): FlushSchedule {
44
+ const nodes = Math.max(1, capacity);
45
+ return {
46
+ deps: createDeps(nodes, nodes * 4),
47
+ scratch: createGraphScratch(nodes, RESOURCE_COUNT),
48
+ passes: createGraphPasses(nodes),
49
+ lifetimes: createLifetimes(RESOURCE_COUNT),
50
+ ordered: new Uint8Array(nodes).fill(1),
51
+ live: new Int32Array(RESOURCE_COUNT),
52
+ liveCount: 0,
53
+ };
54
+ }
55
+
56
+ /* Grown where allocation is allowed: a flush larger than any before it, once. */
57
+ function fit(state: FlushSchedule, nodes: number): void {
58
+ if (state.ordered.length < nodes) {
59
+ const size = Math.max(nodes, state.ordered.length * 2);
60
+ state.ordered = new Uint8Array(size).fill(1);
61
+ while (state.passes.length < size) state.passes.push({ first: 0, count: 0, ordered: true });
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Schedule an arena's nodes through the identifier graph, into the mask scheduler's records.
67
+ *
68
+ * `clearMask` and `liveOut` mean what they mean to `schedule`: what this flush still owes a clear,
69
+ * and what must survive it. Returns how many of `out` were filled.
70
+ */
71
+ export function scheduleFlush(
72
+ arena: Arena,
73
+ clearMask: number,
74
+ liveOut: number,
75
+ state: FlushSchedule,
76
+ out: ScheduledPass[],
77
+ ): number {
78
+ const total = nodeCount(arena);
79
+ if (total === 0) return 0;
80
+ fit(state, total);
81
+
82
+ const deps = state.deps;
83
+ resetDeps(deps);
84
+ for (let node = 0; node < total; node += 1) {
85
+ recordMaskDeps(deps, nodeReads(arena, node), nodeWrites(arena, node));
86
+ }
87
+
88
+ state.liveCount = 0;
89
+ for (let bit = 0; bit < RESOURCE_COUNT; bit += 1) {
90
+ if ((liveOut & (1 << bit)) === 0) continue;
91
+ state.live[state.liveCount] = bit;
92
+ state.liveCount += 1;
93
+ }
94
+
95
+ const scheduled = scheduleGraph(
96
+ deps,
97
+ total,
98
+ state.live,
99
+ state.ordered,
100
+ state.passes,
101
+ state.scratch,
102
+ state.liveCount,
103
+ );
104
+ computeLifetimes(deps, total, state.lifetimes);
105
+
106
+ let filled = 0;
107
+ let cleared = 0;
108
+ for (let p = 0; p < scheduled; p += 1) {
109
+ const pass = state.passes[p] as GraphPass;
110
+ const record = out[filled];
111
+ if (record === undefined) return filled;
112
+ /* An ordered run shares one write set, so its first node's mask is the run's. */
113
+ const writes = nodeWrites(arena, pass.first);
114
+ const end = pass.first + pass.count;
115
+ /*
116
+ * Discardable where nothing at or after the run's end reads it and nothing outside the flush
117
+ * does either. `lastRead` is the last reader anywhere in the flush, culled or not, which is the
118
+ * mask scheduler's rule: a dropped pass's read still happened as far as a store op knows.
119
+ */
120
+ let discard = 0;
121
+ for (let bit = 0; bit < RESOURCE_COUNT; bit += 1) {
122
+ const mask = 1 << bit;
123
+ if ((writes & mask) === 0 || (liveOut & mask) !== 0) continue;
124
+ if (lastRead(state.lifetimes, bit) < end) discard |= mask;
125
+ }
126
+ record.writes = writes;
127
+ record.first = pass.first;
128
+ record.count = pass.count;
129
+ record.clear = clearMask & writes & ~cleared;
130
+ record.discard = discard;
131
+ cleared |= writes;
132
+ filled += 1;
133
+ }
134
+ return filled;
135
+ }
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Grouping and culling for a frame whose composition is not fixed.
3
+ *
4
+ * **`schedule.ts` is not replaced.** It schedules the forward path, where the composition is
5
+ * fixed and a mask is exactly right, and it stays. This is its counterpart for the other path,
6
+ * and the two differences are the whole reason it exists.
7
+ *
8
+ * **Culling is transitive here and is not there.** The mask scheduler drops a pass whose writes
9
+ * nothing later reads. Once it has, the pass whose only reader was the dropped one has become
10
+ * dead too — and a single backward scan over masks never revisits it. A GPU-driven frame makes
11
+ * that ordinary rather than exotic, because turning off one quality flag kills a consumer
12
+ * several passes downstream. So liveness is propagated backwards to a fixed point first, and
13
+ * grouping runs over what survives.
14
+ *
15
+ * **Some nodes may be reordered and most may not.** A node marked ordered carries meaning in its
16
+ * position — blending and depth make *after* different from *before*, which is the rule
17
+ * `schedule.ts` states and this does not weaken. An unordered node is a compute dispatch whose
18
+ * result depends only on its declared reads, and two adjacent ones may merge whatever they write.
19
+ */
20
+ import type { Deps } from './deps.ts';
21
+ import { readsOf, writesOf } from './deps.ts';
22
+
23
+ export interface GraphPass {
24
+ /** Index of the first node in the run. */
25
+ first: number;
26
+ /** How many nodes the run holds. */
27
+ count: number;
28
+ /** Whether this pass's position carries meaning. */
29
+ ordered: boolean;
30
+ }
31
+
32
+ export function createGraphPasses(capacity: number): GraphPass[] {
33
+ return Array.from({ length: capacity }, () => ({ first: 0, count: 0, ordered: true }));
34
+ }
35
+
36
+ /**
37
+ * What a schedule works in, owned by the caller so a flush allocates nothing.
38
+ *
39
+ * `keep` is a flag a node and `wanted` a flag an identifier. Both are cleared at the start of every
40
+ * call, so a scratch carried from one frame to the next answers exactly as a fresh one would.
41
+ */
42
+ export interface GraphScratch {
43
+ keep: Uint8Array;
44
+ wanted: Uint8Array;
45
+ }
46
+
47
+ export function createGraphScratch(nodes: number, identifiers: number): GraphScratch {
48
+ return {
49
+ keep: new Uint8Array(Math.max(1, nodes)),
50
+ wanted: new Uint8Array(Math.max(1, identifiers)),
51
+ };
52
+ }
53
+
54
+ /*
55
+ * Make the scratch big enough for this frame, which is the one place it may allocate.
56
+ *
57
+ * A frame that outgrows it has to be scheduled somehow, and growing here once is what the arena
58
+ * does too; the scratch the caller keeps is then large enough for every frame like it. Doubled, so
59
+ * a frame that grows by one node at a time does not reallocate every frame.
60
+ */
61
+ function fitScratch(scratch: GraphScratch, deps: Deps, count: number): void {
62
+ if (scratch.keep.length < count) {
63
+ scratch.keep = new Uint8Array(Math.max(count, scratch.keep.length * 2));
64
+ }
65
+ let ceiling = 0;
66
+ for (let i = 0; i < deps.used; i += 1) ceiling = Math.max(ceiling, (deps.edges[i] ?? 0) + 1);
67
+ if (scratch.wanted.length < ceiling) {
68
+ scratch.wanted = new Uint8Array(Math.max(ceiling, scratch.wanted.length * 2));
69
+ }
70
+ }
71
+
72
+ /*
73
+ * Mark every node that contributes to something in `live`, to a fixed point.
74
+ *
75
+ * Backwards, because a node is needed exactly when something after it reads what it writes. One
76
+ * backward sweep suffices for a chain; the outer repeat covers a node that writes a resource
77
+ * read by an earlier-indexed node, which cannot happen in a well-formed frame but costs one
78
+ * comparison to be safe about rather than one silently wrong picture to discover.
79
+ *
80
+ * `fitScratch` sized both flags for everything recorded, and this relies on it: a keep flag past
81
+ * the end of `keep` would read 0 after being set, and the sweep would never settle.
82
+ */
83
+ function markLive(
84
+ deps: Deps,
85
+ count: number,
86
+ live: ArrayLike<number>,
87
+ liveCount: number,
88
+ scratch: GraphScratch,
89
+ ): void {
90
+ const { keep, wanted } = scratch;
91
+ keep.fill(0, 0, count);
92
+ wanted.fill(0);
93
+ /* A live identifier past the end is one no node writes, and a typed array ignores the write. */
94
+ for (let i = 0; i < liveCount; i += 1) wanted[live[i] ?? -1] = 1;
95
+ let changed = true;
96
+ while (changed) {
97
+ changed = false;
98
+ for (let node = count - 1; node >= 0; node -= 1) {
99
+ if (keep[node] === 1) continue;
100
+ const writes = writesOf(deps, node);
101
+ let needed = false;
102
+ for (let i = 0; i < writes.length; i += 1) {
103
+ if (wanted[writes[i] ?? 0] === 1) {
104
+ needed = true;
105
+ break;
106
+ }
107
+ }
108
+ if (!needed) continue;
109
+ keep[node] = 1;
110
+ changed = true;
111
+ const reads = readsOf(deps, node);
112
+ for (let i = 0; i < reads.length; i += 1) wanted[reads[i] ?? 0] = 1;
113
+ }
114
+ }
115
+ }
116
+
117
+ function sameWrites(deps: Deps, a: number, b: number): boolean {
118
+ const left = writesOf(deps, a);
119
+ const right = writesOf(deps, b);
120
+ if (left.length !== right.length) return false;
121
+ for (let i = 0; i < left.length; i += 1) if (left[i] !== right[i]) return false;
122
+ return true;
123
+ }
124
+
125
+ /**
126
+ * Group the live nodes of a frame into passes, and answer how many of `out` were filled.
127
+ *
128
+ * `live` is what must survive the frame, and only its first `liveCount` entries are read — so a
129
+ * caller can keep one typed array and a count rather than build a list. `scratch` is the working
130
+ * set; a caller that passes none gets one made for the call, which is what a test wants and what a
131
+ * frame must not do.
132
+ */
133
+ export function scheduleGraph(
134
+ deps: Deps,
135
+ count: number,
136
+ live: ArrayLike<number>,
137
+ ordered: Uint8Array,
138
+ out: GraphPass[],
139
+ scratch: GraphScratch = createGraphScratch(count, 1),
140
+ liveCount: number = live.length,
141
+ ): number {
142
+ fitScratch(scratch, deps, count);
143
+ markLive(deps, count, live, liveCount, scratch);
144
+ const keep = scratch.keep;
145
+
146
+ let passes = 0;
147
+ let at = 0;
148
+ while (at < count) {
149
+ if (keep[at] === 0) {
150
+ at += 1;
151
+ continue;
152
+ }
153
+ const isOrdered = ordered[at] === 1;
154
+ let end = at + 1;
155
+ while (end < count && keep[end] === 1) {
156
+ const nextOrdered = ordered[end] === 1;
157
+ if (isOrdered !== nextOrdered) break;
158
+ if (isOrdered && !sameWrites(deps, at, end)) break;
159
+ end += 1;
160
+ }
161
+ const pass = out[passes];
162
+ if (pass === undefined) return passes;
163
+ pass.first = at;
164
+ pass.count = end - at;
165
+ pass.ordered = isOrdered;
166
+ passes += 1;
167
+ at = end;
168
+ }
169
+ return passes;
170
+ }
@@ -27,3 +27,55 @@ export {
27
27
  export type { ScheduledPass } from './schedule.ts';
28
28
  export { schedule } from './schedule.ts';
29
29
  export { keptNodes, scratchFor } from './replay.ts';
30
+
31
+ /*
32
+ * The identifier-addressed half, for a frame whose composition is not fixed. See `virtual.ts`
33
+ * for why there are two representations and why neither converts into the other.
34
+ */
35
+ export type {
36
+ VirtualBufferDesc,
37
+ VirtualDesc,
38
+ VirtualTable,
39
+ VirtualTextureDesc,
40
+ } from './virtual.ts';
41
+ export {
42
+ createVirtualTable,
43
+ declareVirtual,
44
+ resetVirtualTable,
45
+ virtualBytes,
46
+ virtualCount,
47
+ virtualKind,
48
+ } from './virtual.ts';
49
+ export type { Deps } from './deps.ts';
50
+ export {
51
+ createDeps,
52
+ depsNodeCount,
53
+ readsOf,
54
+ recordDeps,
55
+ recordMaskDeps,
56
+ resetDeps,
57
+ writesOf,
58
+ } from './deps.ts';
59
+ export type { Lifetimes } from './lifetime.ts';
60
+ export { computeLifetimes, createLifetimes, firstWrite, lastRead } from './lifetime.ts';
61
+ export type { AliasPlan } from './alias.ts';
62
+ export { createAliasPlan, offsetOf, planAliases } from './alias.ts';
63
+ export type { GraphPass, GraphScratch } from './graphSchedule.ts';
64
+ export { createGraphPasses, createGraphScratch, scheduleGraph } from './graphSchedule.ts';
65
+ export type { FlushSchedule } from './flushGraph.ts';
66
+ export { createFlushSchedule, scheduleFlush } from './flushGraph.ts';
67
+ export { validateGraph } from './validate.ts';
68
+
69
+ /*
70
+ * Per-pass timings, which are the one thing here that *is* on the package barrel — see the note
71
+ * beside its export in `src/index.ts`. A readout is not the graph.
72
+ */
73
+ export type { PassTimings } from './passTimings.ts';
74
+ export {
75
+ createPassTimings,
76
+ passLabel,
77
+ passMs,
78
+ recordPassLabel,
79
+ recordPassSample,
80
+ resetPassTimings,
81
+ } from './passTimings.ts';
@@ -0,0 +1,61 @@
1
+ /**
2
+ * When each transient resource is first written and last read.
3
+ *
4
+ * Two numbers per identifier and one pass over the nodes, which is all the aliasing allocator
5
+ * needs and is deliberately less than a general dependency graph would compute. There is no
6
+ * topological sort here because there is no reordering here: the node order is the caller's,
7
+ * exactly as `schedule.ts` requires for the fixed path and for the same reason — blending and
8
+ * depth make *after* different from *before*.
9
+ *
10
+ * **A resource written and never read still has a lifetime**, ending at the node that writes
11
+ * it. It has to: memory it is being written into cannot be handed to something else at the same
12
+ * moment. Reporting an empty lifetime there is the bug this module's third test exists to catch.
13
+ */
14
+ import type { Deps } from './deps.ts';
15
+ import { readsOf, writesOf } from './deps.ts';
16
+
17
+ export interface Lifetimes {
18
+ /** Node index of the first write per identifier, or -1. */
19
+ first: Int32Array;
20
+ /** Node index of the last read per identifier, or the first write when nothing reads it. */
21
+ last: Int32Array;
22
+ }
23
+
24
+ export function createLifetimes(capacity: number): Lifetimes {
25
+ return { first: new Int32Array(capacity), last: new Int32Array(capacity) };
26
+ }
27
+
28
+ export function computeLifetimes(deps: Deps, count: number, out: Lifetimes): void {
29
+ out.first.fill(-1);
30
+ out.last.fill(-1);
31
+
32
+ for (let node = 0; node < count; node += 1) {
33
+ const writes = writesOf(deps, node);
34
+ for (let i = 0; i < writes.length; i += 1) {
35
+ const id = writes[i] ?? 0;
36
+ if (out.first[id] === -1) {
37
+ out.first[id] = node;
38
+ out.last[id] = node;
39
+ }
40
+ }
41
+ /*
42
+ * Reads are folded in after this node's writes, so a node that reads and writes the same
43
+ * identifier extends the lifetime rather than starting a second one. A read of something
44
+ * nothing has written is ignored here and refused by `validate.ts`, which is where a
45
+ * malformed frame belongs.
46
+ */
47
+ const reads = readsOf(deps, node);
48
+ for (let i = 0; i < reads.length; i += 1) {
49
+ const id = reads[i] ?? 0;
50
+ if (out.first[id] !== -1) out.last[id] = node;
51
+ }
52
+ }
53
+ }
54
+
55
+ export function firstWrite(out: Lifetimes, id: number): number {
56
+ return out.first[id] ?? -1;
57
+ }
58
+
59
+ export function lastRead(out: Lifetimes, id: number): number {
60
+ return out.last[id] ?? -1;
61
+ }