@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,138 @@
1
+ /**
2
+ * The medium between the camera and everything it can see, as arithmetic.
3
+ *
4
+ * **`shaders/fog.ts` was the only copy and it is GLSL**, which two things now make a problem. The
5
+ * GPU-driven pipeline is written in WGSL and cannot include it, so the second pipeline drew no fog
6
+ * at all; and a term that exists only as a shader is a term nothing can disagree with, which is the
7
+ * argument `gpudriven/lit.ts` and `gpudriven/alphaTest.ts` were both written under.
8
+ *
9
+ * So this is the expression in TypeScript, and both shaders are checked against it:
10
+ * `scripts/gpu-parity.mjs` runs the WGSL over generated cases, and `shaders/fog.ts` stays exactly
11
+ * as it is. **This is a second reader of one decision rather than a second decision** — every
12
+ * guard, every constant and the order of the two mixes are the GLSL's, and where a line looks odd
13
+ * that file's header is the long version of why.
14
+ *
15
+ * **What it does not carry** is the uniform block. `shaders/fog.ts` declares ten uniforms because a
16
+ * block that declares everything it uses can be pasted into any program; a function takes them as
17
+ * one argument instead, and the backends keep their own packing.
18
+ */
19
+ import { resolveAtmosphere } from './atmosphere.js';
20
+ /** Beer-Lambert through a haze layer that thins with height. `uFogMode` 0. */
21
+ export const MEDIUM_FOG = 0;
22
+ /** A ramp between two distances, which is a look rather than a medium. `uFogMode` 1. */
23
+ export const LINEAR_FOG = 1;
24
+ /**
25
+ * Linear interpolation **written the way `mix` is defined**, which is not the same arithmetic as
26
+ * the fused form.
27
+ *
28
+ * GLSL and WGSL both define `mix(x, y, a)` as `x * (1 - a) + y * a`. Written `x + (y - x) * a` the
29
+ * two agree to within rounding everywhere except the endpoints, where the fused form is off by an
30
+ * ulp — `0.82 + (0.2 - 0.82) * 1` is 0.20000000000000007 rather than 0.2. That is invisible in a
31
+ * picture and fatal in a parity check, and it is what the first run of this file's tests found: the
32
+ * reference and the device have to be the same *expression*, not the same function.
33
+ */
34
+ function mix(x, y, a) {
35
+ return x * (1 - a) + y * a;
36
+ }
37
+ /** What distance converges toward: the day's haze, or the water column. */
38
+ export function mediumColour(fog) {
39
+ const t = fog.underwaterFactor;
40
+ return [
41
+ mix(fog.colour[0], fog.underwaterColour[0], t),
42
+ mix(fog.colour[1], fog.underwaterColour[1], t),
43
+ mix(fog.colour[2], fog.underwaterColour[2], t),
44
+ ];
45
+ }
46
+ /**
47
+ * How much of a surface standing at `pointY`, `dist` metres away, is lost to the medium between.
48
+ * 0 is perfectly clear, 1 is the medium's own colour.
49
+ */
50
+ export function mediumFog(fog, dist, pointY) {
51
+ /*
52
+ * **A depth ramp rather than a medium, for worlds authored against one.** Before `near` the air
53
+ * is perfectly clear, which Beer-Lambert can never be, and height falloff has no meaning here
54
+ * because a ramp is defined on distance alone. `shaders/fog.ts` argues the whole of it.
55
+ */
56
+ if (fog.mode === LINEAR_FOG) {
57
+ /* A consumer asking for a hard cut writes `far === near`; the guard is why that is a cut. */
58
+ const span = Math.max(fog.far - fog.near, 1e-4);
59
+ const ramp = Math.min(1, Math.max(0, (dist - fog.near) / span));
60
+ if (fog.underwaterFactor <= 0)
61
+ return ramp;
62
+ const wetLinear = fog.underwaterDensity * dist;
63
+ return mix(ramp, 1 - Math.pow(2, -wetLinear * wetLinear * 1.442695), fog.underwaterFactor);
64
+ }
65
+ const t = (pointY - fog.eyeY) * fog.heightFalloff;
66
+ /*
67
+ * `(1 - e^-t)/t`, which tends to 1 as the ray levels out. **Guarded rather than branched**: at
68
+ * `t = 0` the quotient is 0/0, and 1e-4 of a scale height is 8 mm.
69
+ */
70
+ const denom = Math.abs(t) < 1e-4 ? 1e-4 : t;
71
+ const air = 1 - Math.exp((-fog.density * dist * (1 - Math.exp(-denom))) / denom);
72
+ if (fog.underwaterFactor <= 0)
73
+ return air;
74
+ /* Water is its own medium and keeps its own curve, so crossing the surface changes nothing
75
+ about how the water column reads. */
76
+ const wet = fog.underwaterDensity * dist;
77
+ return mix(air, 1 - Math.pow(2, -wet * wet * 1.442695), fog.underwaterFactor);
78
+ }
79
+ /** A target for `atmosphereFog`, allocated once, outside the frame loop. */
80
+ export function createFogTarget() {
81
+ return {
82
+ colour: [0, 0, 0],
83
+ density: 0,
84
+ heightFalloff: 0,
85
+ eyeY: 0,
86
+ underwaterColour: [0, 0, 0],
87
+ underwaterDensity: 0,
88
+ underwaterFactor: 0,
89
+ mode: MEDIUM_FOG,
90
+ near: 0,
91
+ far: 1,
92
+ };
93
+ }
94
+ /** `resolveAtmosphere`'s own target, reused, because this runs a frame at a time. */
95
+ const RESOLVED = {
96
+ fogColor: new Float32Array(3),
97
+ underwaterColor: new Float32Array(3),
98
+ fogDensity: 0,
99
+ fogHeightFalloff: 0,
100
+ fogEyeY: 0,
101
+ fogMode: 0,
102
+ fogNear: 0,
103
+ fogFar: 1,
104
+ underwaterFogDensity: 0,
105
+ underwaterFactor: 0,
106
+ };
107
+ /**
108
+ * The haze an `Environment` makes at a camera's height, as `GpuDrivenView.fog` takes it.
109
+ *
110
+ * **The forward path's own decision, handed over rather than made again.** A consumer drawing
111
+ * both pipelines in one frame has one environment and needs one haze from it, and
112
+ * `resolveAtmosphere` is where the forward path decides which medium the camera is in and what it
113
+ * looks like — the density at the eye, the linear ramp's two radii, how far under water the eye
114
+ * is. This calls it and copies the answer across field for field, so the two pipelines cannot
115
+ * disagree about where the fog begins or whether the camera is submerged. Both mode numbers are
116
+ * the shaders' `uFogMode`, which is why no mapping stands between them.
117
+ *
118
+ * @param underwater The renderer's `underwaterAtmosphere` quality, which gates the second medium
119
+ * on the forward path; pass the same.
120
+ */
121
+ export function atmosphereFog(atmosphere, eyeY, underwater, out) {
122
+ const medium = resolveAtmosphere(atmosphere, eyeY, underwater, RESOLVED);
123
+ out.colour[0] = medium.fogColor[0];
124
+ out.colour[1] = medium.fogColor[1];
125
+ out.colour[2] = medium.fogColor[2];
126
+ out.density = medium.fogDensity;
127
+ out.heightFalloff = medium.fogHeightFalloff;
128
+ out.eyeY = medium.fogEyeY;
129
+ out.underwaterColour[0] = medium.underwaterColor[0];
130
+ out.underwaterColour[1] = medium.underwaterColor[1];
131
+ out.underwaterColour[2] = medium.underwaterColor[2];
132
+ out.underwaterDensity = medium.underwaterFogDensity;
133
+ out.underwaterFactor = medium.underwaterFactor;
134
+ out.mode = medium.fogMode;
135
+ out.near = medium.fogNear;
136
+ out.far = medium.fogFar;
137
+ return out;
138
+ }
@@ -0,0 +1,30 @@
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 type { VirtualTable } from './virtual.ts';
16
+ export interface AliasPlan {
17
+ /** Byte offset into the arena per identifier, or -1 when nothing writes it. */
18
+ offsets: Int32Array;
19
+ /** Byte offset of each slot, parallel to `slotEnd` and `slotSize`. */
20
+ slotAt: Int32Array;
21
+ /** Node at which each slot's current occupant is last read. */
22
+ slotEnd: Int32Array;
23
+ /** Widest resource each slot has held. */
24
+ slotSize: Int32Array;
25
+ /** How many slots are in use. */
26
+ slots: number;
27
+ }
28
+ export declare function createAliasPlan(capacity: number): AliasPlan;
29
+ export declare function planAliases(table: VirtualTable, lifetimes: Lifetimes, out: AliasPlan): number;
30
+ export declare function offsetOf(plan: AliasPlan, id: number): number;
@@ -0,0 +1,61 @@
1
+ import { firstWrite, lastRead } from './lifetime.js';
2
+ import { virtualBytes } from './virtual.js';
3
+ export function createAliasPlan(capacity) {
4
+ return {
5
+ offsets: new Int32Array(capacity),
6
+ slotAt: new Int32Array(capacity),
7
+ slotEnd: new Int32Array(capacity),
8
+ slotSize: new Int32Array(capacity),
9
+ slots: 0,
10
+ };
11
+ }
12
+ /** Alignment every slot starts on. 256 is the widest uniform-buffer alignment WebGPU requires. */
13
+ const ALIGN = 256;
14
+ function aligned(bytes) {
15
+ return Math.ceil(bytes / ALIGN) * ALIGN;
16
+ }
17
+ export function planAliases(table, lifetimes, out) {
18
+ out.offsets.fill(-1);
19
+ out.slots = 0;
20
+ let total = 0;
21
+ for (let id = 0; id < table.count; id += 1) {
22
+ const born = firstWrite(lifetimes, id);
23
+ if (born === -1)
24
+ continue;
25
+ const dies = lastRead(lifetimes, id);
26
+ const size = aligned(virtualBytes(table, id));
27
+ let placed = -1;
28
+ for (let slot = 0; slot < out.slots; slot += 1) {
29
+ if ((out.slotEnd[slot] ?? 0) < born) {
30
+ placed = slot;
31
+ break;
32
+ }
33
+ }
34
+ if (placed === -1) {
35
+ placed = out.slots;
36
+ out.slotAt[placed] = total;
37
+ out.slotSize[placed] = size;
38
+ total += size;
39
+ out.slots = placed + 1;
40
+ }
41
+ else if (size > (out.slotSize[placed] ?? 0)) {
42
+ /*
43
+ * The slot has to widen, and widening in place would overlap whatever follows it. Retiring
44
+ * the slot and opening a new one is correct and costs one wasted slot; compacting would
45
+ * move every offset after it, which is the stability the header refuses to give up.
46
+ */
47
+ out.slotEnd[placed] = Number.MAX_SAFE_INTEGER;
48
+ placed = out.slots;
49
+ out.slotAt[placed] = total;
50
+ out.slotSize[placed] = size;
51
+ total += size;
52
+ out.slots = placed + 1;
53
+ }
54
+ out.offsets[id] = out.slotAt[placed] ?? 0;
55
+ out.slotEnd[placed] = dies;
56
+ }
57
+ return total;
58
+ }
59
+ export function offsetOf(plan, id) {
60
+ return plan.offsets[id] ?? -1;
61
+ }
@@ -0,0 +1,37 @@
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
+ export declare function createDeps(nodeCapacity: number, edgeCapacity: number): Deps;
23
+ export declare function resetDeps(deps: Deps): void;
24
+ export declare function depsNodeCount(deps: Deps): number;
25
+ export declare function recordDeps(deps: Deps, reads: readonly number[], writes: readonly number[]): number;
26
+ /**
27
+ * Record a node whose reads and writes are masks, one identifier per set bit, lowest first.
28
+ *
29
+ * **What lets a fixed-composition flush be scheduled by identifiers without building a list.** The
30
+ * forward renderer records masks, and `recordDeps` takes arrays; a flush converting one to the
31
+ * other through arrays would allocate per node, on the path `AGENTS.md` forbids it on. Bit `n`
32
+ * is identifier `n`, so `FRAME_RESOURCES` is the first `RESOURCE_COUNT` identifiers of any frame
33
+ * that mixes the two.
34
+ */
35
+ export declare function recordMaskDeps(deps: Deps, reads: number, writes: number): number;
36
+ export declare function readsOf(deps: Deps, node: number): Int32Array;
37
+ export declare function writesOf(deps: Deps, node: number): Int32Array;
@@ -0,0 +1,122 @@
1
+ const SPAN_STRIDE = 4;
2
+ export function createDeps(nodeCapacity, edgeCapacity) {
3
+ return {
4
+ edges: new Int32Array(edgeCapacity),
5
+ spans: new Int32Array(nodeCapacity * SPAN_STRIDE),
6
+ used: 0,
7
+ count: 0,
8
+ };
9
+ }
10
+ export function resetDeps(deps) {
11
+ deps.used = 0;
12
+ deps.count = 0;
13
+ }
14
+ export function depsNodeCount(deps) {
15
+ return deps.count;
16
+ }
17
+ function growEdges(deps, need) {
18
+ let size = deps.edges.length === 0 ? 16 : deps.edges.length;
19
+ while (size < need)
20
+ size *= 2;
21
+ const edges = new Int32Array(size);
22
+ edges.set(deps.edges);
23
+ deps.edges = edges;
24
+ }
25
+ function growSpans(deps) {
26
+ const size = deps.spans.length === 0 ? SPAN_STRIDE * 8 : deps.spans.length * 2;
27
+ const spans = new Int32Array(size);
28
+ spans.set(deps.spans);
29
+ deps.spans = spans;
30
+ }
31
+ /*
32
+ * Both stores are grown before either span is written. Growing between the read span and the
33
+ * write span would copy a half-written node and silently drop its writes, which is the defect
34
+ * the growth test in this module's suite exists to catch.
35
+ */
36
+ export function recordDeps(deps, reads, writes) {
37
+ const need = deps.used + reads.length + writes.length;
38
+ if (need > deps.edges.length)
39
+ growEdges(deps, need);
40
+ if ((deps.count + 1) * SPAN_STRIDE > deps.spans.length)
41
+ growSpans(deps);
42
+ const readAt = deps.used;
43
+ for (let i = 0; i < reads.length; i += 1)
44
+ deps.edges[deps.used + i] = reads[i] ?? 0;
45
+ deps.used += reads.length;
46
+ const writeAt = deps.used;
47
+ for (let i = 0; i < writes.length; i += 1)
48
+ deps.edges[deps.used + i] = writes[i] ?? 0;
49
+ deps.used += writes.length;
50
+ const node = deps.count;
51
+ const base = node * SPAN_STRIDE;
52
+ deps.spans[base] = readAt;
53
+ deps.spans[base + 1] = reads.length;
54
+ deps.spans[base + 2] = writeAt;
55
+ deps.spans[base + 3] = writes.length;
56
+ deps.count = node + 1;
57
+ return node;
58
+ }
59
+ /*
60
+ * Count the bits of a mask, which is how many identifiers it becomes.
61
+ *
62
+ * Kernighan's loop rather than a table: a mask here has at most `RESOURCE_COUNT` bits and usually
63
+ * two, so this runs once or twice.
64
+ */
65
+ function bitCount(mask) {
66
+ let count = 0;
67
+ for (let rest = mask >>> 0; rest !== 0; rest &= rest - 1)
68
+ count += 1;
69
+ return count;
70
+ }
71
+ function writeBits(deps, mask, at) {
72
+ let offset = at;
73
+ for (let bit = 0, rest = mask >>> 0; rest !== 0; bit += 1, rest >>>= 1) {
74
+ if ((rest & 1) === 0)
75
+ continue;
76
+ deps.edges[offset] = bit;
77
+ offset += 1;
78
+ }
79
+ }
80
+ /**
81
+ * Record a node whose reads and writes are masks, one identifier per set bit, lowest first.
82
+ *
83
+ * **What lets a fixed-composition flush be scheduled by identifiers without building a list.** The
84
+ * forward renderer records masks, and `recordDeps` takes arrays; a flush converting one to the
85
+ * other through arrays would allocate per node, on the path `AGENTS.md` forbids it on. Bit `n`
86
+ * is identifier `n`, so `FRAME_RESOURCES` is the first `RESOURCE_COUNT` identifiers of any frame
87
+ * that mixes the two.
88
+ */
89
+ export function recordMaskDeps(deps, reads, writes) {
90
+ const readCount = bitCount(reads);
91
+ const writeCount = bitCount(writes);
92
+ const need = deps.used + readCount + writeCount;
93
+ if (need > deps.edges.length)
94
+ growEdges(deps, need);
95
+ if ((deps.count + 1) * SPAN_STRIDE > deps.spans.length)
96
+ growSpans(deps);
97
+ const readAt = deps.used;
98
+ writeBits(deps, reads, readAt);
99
+ const writeAt = readAt + readCount;
100
+ writeBits(deps, writes, writeAt);
101
+ deps.used = writeAt + writeCount;
102
+ const node = deps.count;
103
+ const base = node * SPAN_STRIDE;
104
+ deps.spans[base] = readAt;
105
+ deps.spans[base + 1] = readCount;
106
+ deps.spans[base + 2] = writeAt;
107
+ deps.spans[base + 3] = writeCount;
108
+ deps.count = node + 1;
109
+ return node;
110
+ }
111
+ export function readsOf(deps, node) {
112
+ const base = node * SPAN_STRIDE;
113
+ const at = deps.spans[base] ?? 0;
114
+ const length = deps.spans[base + 1] ?? 0;
115
+ return deps.edges.subarray(at, at + length);
116
+ }
117
+ export function writesOf(deps, node) {
118
+ const base = node * SPAN_STRIDE;
119
+ const at = deps.spans[base + 2] ?? 0;
120
+ const length = deps.spans[base + 3] ?? 0;
121
+ return deps.edges.subarray(at, at + length);
122
+ }
@@ -0,0 +1,43 @@
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 type { Deps } from './deps.ts';
22
+ import type { GraphPass, GraphScratch } from './graphSchedule.ts';
23
+ import type { Lifetimes } from './lifetime.ts';
24
+ import type { ScheduledPass } from './schedule.ts';
25
+ export interface FlushSchedule {
26
+ deps: Deps;
27
+ scratch: GraphScratch;
28
+ passes: GraphPass[];
29
+ lifetimes: Lifetimes;
30
+ /** Every node ordered: a forward draw's position is its meaning. Grown with the arena. */
31
+ ordered: Uint8Array;
32
+ /** The live identifiers of this flush, and how many of them there are. */
33
+ live: Int32Array;
34
+ liveCount: number;
35
+ }
36
+ export declare function createFlushSchedule(capacity: number): FlushSchedule;
37
+ /**
38
+ * Schedule an arena's nodes through the identifier graph, into the mask scheduler's records.
39
+ *
40
+ * `clearMask` and `liveOut` mean what they mean to `schedule`: what this flush still owes a clear,
41
+ * and what must survive it. Returns how many of `out` were filled.
42
+ */
43
+ export declare function scheduleFlush(arena: Arena, clearMask: number, liveOut: number, state: FlushSchedule, out: ScheduledPass[]): number;
@@ -0,0 +1,84 @@
1
+ import { nodeCount, nodeReads, nodeWrites } from './arena.js';
2
+ import { createDeps, recordMaskDeps, resetDeps } from './deps.js';
3
+ import { createGraphPasses, createGraphScratch, scheduleGraph } from './graphSchedule.js';
4
+ import { computeLifetimes, createLifetimes, lastRead } from './lifetime.js';
5
+ import { RESOURCE_COUNT } from './resources.js';
6
+ export function createFlushSchedule(capacity) {
7
+ const nodes = Math.max(1, capacity);
8
+ return {
9
+ deps: createDeps(nodes, nodes * 4),
10
+ scratch: createGraphScratch(nodes, RESOURCE_COUNT),
11
+ passes: createGraphPasses(nodes),
12
+ lifetimes: createLifetimes(RESOURCE_COUNT),
13
+ ordered: new Uint8Array(nodes).fill(1),
14
+ live: new Int32Array(RESOURCE_COUNT),
15
+ liveCount: 0,
16
+ };
17
+ }
18
+ /* Grown where allocation is allowed: a flush larger than any before it, once. */
19
+ function fit(state, nodes) {
20
+ if (state.ordered.length < nodes) {
21
+ const size = Math.max(nodes, state.ordered.length * 2);
22
+ state.ordered = new Uint8Array(size).fill(1);
23
+ while (state.passes.length < size)
24
+ state.passes.push({ first: 0, count: 0, ordered: true });
25
+ }
26
+ }
27
+ /**
28
+ * Schedule an arena's nodes through the identifier graph, into the mask scheduler's records.
29
+ *
30
+ * `clearMask` and `liveOut` mean what they mean to `schedule`: what this flush still owes a clear,
31
+ * and what must survive it. Returns how many of `out` were filled.
32
+ */
33
+ export function scheduleFlush(arena, clearMask, liveOut, state, out) {
34
+ const total = nodeCount(arena);
35
+ if (total === 0)
36
+ return 0;
37
+ fit(state, total);
38
+ const deps = state.deps;
39
+ resetDeps(deps);
40
+ for (let node = 0; node < total; node += 1) {
41
+ recordMaskDeps(deps, nodeReads(arena, node), nodeWrites(arena, node));
42
+ }
43
+ state.liveCount = 0;
44
+ for (let bit = 0; bit < RESOURCE_COUNT; bit += 1) {
45
+ if ((liveOut & (1 << bit)) === 0)
46
+ continue;
47
+ state.live[state.liveCount] = bit;
48
+ state.liveCount += 1;
49
+ }
50
+ const scheduled = scheduleGraph(deps, total, state.live, state.ordered, state.passes, state.scratch, state.liveCount);
51
+ computeLifetimes(deps, total, state.lifetimes);
52
+ let filled = 0;
53
+ let cleared = 0;
54
+ for (let p = 0; p < scheduled; p += 1) {
55
+ const pass = state.passes[p];
56
+ const record = out[filled];
57
+ if (record === undefined)
58
+ return filled;
59
+ /* An ordered run shares one write set, so its first node's mask is the run's. */
60
+ const writes = nodeWrites(arena, pass.first);
61
+ const end = pass.first + pass.count;
62
+ /*
63
+ * Discardable where nothing at or after the run's end reads it and nothing outside the flush
64
+ * does either. `lastRead` is the last reader anywhere in the flush, culled or not, which is the
65
+ * mask scheduler's rule: a dropped pass's read still happened as far as a store op knows.
66
+ */
67
+ let discard = 0;
68
+ for (let bit = 0; bit < RESOURCE_COUNT; bit += 1) {
69
+ const mask = 1 << bit;
70
+ if ((writes & mask) === 0 || (liveOut & mask) !== 0)
71
+ continue;
72
+ if (lastRead(state.lifetimes, bit) < end)
73
+ discard |= mask;
74
+ }
75
+ record.writes = writes;
76
+ record.first = pass.first;
77
+ record.count = pass.count;
78
+ record.clear = clearMask & writes & ~cleared;
79
+ record.discard = discard;
80
+ cleared |= writes;
81
+ filled += 1;
82
+ }
83
+ return filled;
84
+ }
@@ -0,0 +1,49 @@
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
+ export interface GraphPass {
22
+ /** Index of the first node in the run. */
23
+ first: number;
24
+ /** How many nodes the run holds. */
25
+ count: number;
26
+ /** Whether this pass's position carries meaning. */
27
+ ordered: boolean;
28
+ }
29
+ export declare function createGraphPasses(capacity: number): GraphPass[];
30
+ /**
31
+ * What a schedule works in, owned by the caller so a flush allocates nothing.
32
+ *
33
+ * `keep` is a flag a node and `wanted` a flag an identifier. Both are cleared at the start of every
34
+ * call, so a scratch carried from one frame to the next answers exactly as a fresh one would.
35
+ */
36
+ export interface GraphScratch {
37
+ keep: Uint8Array;
38
+ wanted: Uint8Array;
39
+ }
40
+ export declare function createGraphScratch(nodes: number, identifiers: number): GraphScratch;
41
+ /**
42
+ * Group the live nodes of a frame into passes, and answer how many of `out` were filled.
43
+ *
44
+ * `live` is what must survive the frame, and only its first `liveCount` entries are read — so a
45
+ * caller can keep one typed array and a count rather than build a list. `scratch` is the working
46
+ * set; a caller that passes none gets one made for the call, which is what a test wants and what a
47
+ * frame must not do.
48
+ */
49
+ export declare function scheduleGraph(deps: Deps, count: number, live: ArrayLike<number>, ordered: Uint8Array, out: GraphPass[], scratch?: GraphScratch, liveCount?: number): number;