@driftengine/core 3.63.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 +111 -0
  2. package/NOTICE +20 -0
  3. package/README.md +1 -1
  4. package/dist/core/loop.js +18 -2
  5. package/dist/core/storage.js +5 -0
  6. package/dist/geometry/meshBuilder.d.ts +1 -1
  7. package/dist/geometry/meshBuilder.js +6 -2
  8. package/dist/index.d.ts +69 -4
  9. package/dist/index.js +112 -2
  10. package/dist/input/input.js +6 -1
  11. package/dist/math/exact.d.ts +13 -3
  12. package/dist/math/exact.js +68 -3
  13. package/dist/math/frustum.d.ts +17 -2
  14. package/dist/math/frustum.js +24 -0
  15. package/dist/render/backend/api.d.ts +34 -1
  16. package/dist/render/backend/api.js +22 -1
  17. package/dist/render/backend/budget.d.ts +7 -6
  18. package/dist/render/backend/budget.js +7 -6
  19. package/dist/render/backend/createRenderer.d.ts +57 -0
  20. package/dist/render/backend/createRenderer.js +51 -2
  21. package/dist/render/backend/materialChanges.d.ts +41 -0
  22. package/dist/render/backend/materialChanges.js +38 -0
  23. package/dist/render/backend/select.js +8 -0
  24. package/dist/render/backend/webgl2/renderer.d.ts +80 -1
  25. package/dist/render/backend/webgl2/renderer.js +208 -10
  26. package/dist/render/backend/webgpu/buffers.d.ts +20 -1
  27. package/dist/render/backend/webgpu/buffers.js +116 -58
  28. package/dist/render/backend/webgpu/fieldCompose.d.ts +156 -0
  29. package/dist/render/backend/webgpu/fieldCompose.js +396 -0
  30. package/dist/render/backend/webgpu/giFieldPass.d.ts +66 -0
  31. package/dist/render/backend/webgpu/giFieldPass.js +137 -0
  32. package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +728 -0
  33. package/dist/render/backend/webgpu/gpuDrivenPass.js +2473 -0
  34. package/dist/render/backend/webgpu/linePass.d.ts +4 -14
  35. package/dist/render/backend/webgpu/linePass.js +4 -33
  36. package/dist/render/backend/webgpu/probeBake.d.ts +148 -0
  37. package/dist/render/backend/webgpu/probeBake.js +493 -0
  38. package/dist/render/backend/webgpu/renderer.d.ts +379 -24
  39. package/dist/render/backend/webgpu/renderer.js +1369 -76
  40. package/dist/render/backend/webgpu/scatterPass.js +15 -1
  41. package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +19 -9
  42. package/dist/render/backend/webgpu/surfaceTexturePass.js +58 -32
  43. package/dist/render/causticsRenderer.d.ts +3 -1
  44. package/dist/render/causticsRenderer.js +4 -1
  45. package/dist/render/depthConvention.d.ts +12 -0
  46. package/dist/render/depthConvention.js +14 -0
  47. package/dist/render/deviceFeatures.d.ts +32 -0
  48. package/dist/render/deviceFeatures.js +41 -0
  49. package/dist/render/fog.d.ts +79 -0
  50. package/dist/render/fog.js +138 -0
  51. package/dist/render/frame/alias.d.ts +30 -0
  52. package/dist/render/frame/alias.js +61 -0
  53. package/dist/render/frame/deps.d.ts +37 -0
  54. package/dist/render/frame/deps.js +122 -0
  55. package/dist/render/frame/flushGraph.d.ts +43 -0
  56. package/dist/render/frame/flushGraph.js +84 -0
  57. package/dist/render/frame/graphSchedule.d.ts +49 -0
  58. package/dist/render/frame/graphSchedule.js +120 -0
  59. package/dist/render/frame/index.d.ts +15 -0
  60. package/dist/render/frame/index.js +8 -0
  61. package/dist/render/frame/lifetime.d.ts +24 -0
  62. package/dist/render/frame/lifetime.js +36 -0
  63. package/dist/render/frame/passTimings.d.ts +42 -0
  64. package/dist/render/frame/passTimings.js +38 -0
  65. package/dist/render/frame/validate.d.ts +15 -0
  66. package/dist/render/frame/validate.js +22 -0
  67. package/dist/render/frame/virtual.d.ts +44 -0
  68. package/dist/render/frame/virtual.js +61 -0
  69. package/dist/render/gi/chain.d.ts +82 -0
  70. package/dist/render/gi/chain.js +135 -0
  71. package/dist/render/gi/denoise.d.ts +114 -0
  72. package/dist/render/gi/denoise.js +169 -0
  73. package/dist/render/gi/fieldScene.d.ts +125 -0
  74. package/dist/render/gi/fieldScene.js +219 -0
  75. package/dist/render/gi/globalField.d.ts +157 -0
  76. package/dist/render/gi/globalField.js +373 -0
  77. package/dist/render/gi/probeGridFit.d.ts +24 -0
  78. package/dist/render/gi/probeGridFit.js +71 -0
  79. package/dist/render/gi/probeTrace.d.ts +82 -0
  80. package/dist/render/gi/probeTrace.js +128 -0
  81. package/dist/render/gi/probeVolume.d.ts +136 -0
  82. package/dist/render/gi/probeVolume.js +191 -0
  83. package/dist/render/gi/reflection.d.ts +73 -0
  84. package/dist/render/gi/reflection.js +109 -0
  85. package/dist/render/gi/traceField.d.ts +91 -0
  86. package/dist/render/gi/traceField.js +129 -0
  87. package/dist/render/gi/traceScreen.d.ts +68 -0
  88. package/dist/render/gi/traceScreen.js +82 -0
  89. package/dist/render/gpuScene.d.ts +38 -0
  90. package/dist/render/gpuScene.js +41 -0
  91. package/dist/render/gpudriven/alphaTest.d.ts +28 -0
  92. package/dist/render/gpudriven/alphaTest.js +32 -0
  93. package/dist/render/gpudriven/clusterUpload.d.ts +59 -0
  94. package/dist/render/gpudriven/clusterUpload.js +75 -0
  95. package/dist/render/gpudriven/clusterWorld.d.ts +57 -0
  96. package/dist/render/gpudriven/clusterWorld.js +155 -0
  97. package/dist/render/gpudriven/compact.d.ts +51 -0
  98. package/dist/render/gpudriven/compact.js +68 -0
  99. package/dist/render/gpudriven/cullClusters.d.ts +129 -0
  100. package/dist/render/gpudriven/cullClusters.js +237 -0
  101. package/dist/render/gpudriven/decodeTables.d.ts +64 -0
  102. package/dist/render/gpudriven/decodeTables.js +219 -0
  103. package/dist/render/gpudriven/frustum.d.ts +25 -0
  104. package/dist/render/gpudriven/frustum.js +59 -0
  105. package/dist/render/gpudriven/geometryHarness.d.ts +15 -0
  106. package/dist/render/gpudriven/geometryHarness.js +31 -0
  107. package/dist/render/gpudriven/hzb.d.ts +60 -0
  108. package/dist/render/gpudriven/hzb.js +97 -0
  109. package/dist/render/gpudriven/ibl.d.ts +85 -0
  110. package/dist/render/gpudriven/ibl.js +129 -0
  111. package/dist/render/gpudriven/indirect.d.ts +67 -0
  112. package/dist/render/gpudriven/indirect.js +77 -0
  113. package/dist/render/gpudriven/instances.d.ts +43 -0
  114. package/dist/render/gpudriven/instances.js +172 -0
  115. package/dist/render/gpudriven/lit.d.ts +165 -0
  116. package/dist/render/gpudriven/lit.js +165 -0
  117. package/dist/render/gpudriven/lodCut.d.ts +28 -0
  118. package/dist/render/gpudriven/lodCut.js +38 -0
  119. package/dist/render/gpudriven/materialBin.d.ts +60 -0
  120. package/dist/render/gpudriven/materialBin.js +108 -0
  121. package/dist/render/gpudriven/materialTable.d.ts +88 -0
  122. package/dist/render/gpudriven/materialTable.js +115 -0
  123. package/dist/render/gpudriven/pipeline.d.ts +135 -0
  124. package/dist/render/gpudriven/pipeline.js +237 -0
  125. package/dist/render/gpudriven/rangeAlloc.d.ts +50 -0
  126. package/dist/render/gpudriven/rangeAlloc.js +112 -0
  127. package/dist/render/gpudriven/sceneUpload.d.ts +96 -0
  128. package/dist/render/gpudriven/sceneUpload.js +115 -0
  129. package/dist/render/gpudriven/shadeBins.d.ts +92 -0
  130. package/dist/render/gpudriven/shadeBins.js +182 -0
  131. package/dist/render/gpudriven/shadow.d.ts +136 -0
  132. package/dist/render/gpudriven/shadow.js +224 -0
  133. package/dist/render/gpudriven/shadowCamera.d.ts +87 -0
  134. package/dist/render/gpudriven/shadowCamera.js +345 -0
  135. package/dist/render/gpudriven/streamScene.d.ts +194 -0
  136. package/dist/render/gpudriven/streamScene.js +459 -0
  137. package/dist/render/gpudriven/surfaceFrame.d.ts +25 -0
  138. package/dist/render/gpudriven/surfaceFrame.js +51 -0
  139. package/dist/render/gpudriven/twoPhase.d.ts +122 -0
  140. package/dist/render/gpudriven/twoPhase.js +160 -0
  141. package/dist/render/gpudriven/visbuffer.d.ts +25 -0
  142. package/dist/render/gpudriven/visbuffer.js +37 -0
  143. package/dist/render/halfFloat.d.ts +10 -0
  144. package/dist/render/halfFloat.js +23 -4
  145. package/dist/render/inference/attentionTiled.d.ts +27 -0
  146. package/dist/render/inference/attentionTiled.js +117 -0
  147. package/dist/render/inference/denseKernels.d.ts +29 -0
  148. package/dist/render/inference/denseKernels.js +312 -0
  149. package/dist/render/inference/device.d.ts +21 -0
  150. package/dist/render/inference/device.js +32 -0
  151. package/dist/render/inference/deviceGraph.d.ts +34 -0
  152. package/dist/render/inference/deviceGraph.js +17 -0
  153. package/dist/render/inference/fuse.d.ts +15 -0
  154. package/dist/render/inference/fuse.js +37 -0
  155. package/dist/render/inference/kernelKit.d.ts +52 -0
  156. package/dist/render/inference/kernelKit.js +70 -0
  157. package/dist/render/inference/kernels.d.ts +3 -0
  158. package/dist/render/inference/kernels.js +11 -0
  159. package/dist/render/inference/plan.d.ts +13 -0
  160. package/dist/render/inference/plan.js +18 -0
  161. package/dist/render/inference/reuse.d.ts +39 -0
  162. package/dist/render/inference/reuse.js +65 -0
  163. package/dist/render/inference/runner.d.ts +31 -0
  164. package/dist/render/inference/runner.js +175 -0
  165. package/dist/render/inference/schedule.d.ts +39 -0
  166. package/dist/render/inference/schedule.js +59 -0
  167. package/dist/render/inference/shapeKernels.d.ts +10 -0
  168. package/dist/render/inference/shapeKernels.js +80 -0
  169. package/dist/render/inference/spatialKernels.d.ts +21 -0
  170. package/dist/render/inference/spatialKernels.js +179 -0
  171. package/dist/render/inference/splatRaster.wgsl.d.ts +75 -0
  172. package/dist/render/inference/splatRaster.wgsl.js +337 -0
  173. package/dist/render/inference/splatTiles.d.ts +79 -0
  174. package/dist/render/inference/splatTiles.js +161 -0
  175. package/dist/render/lineBatch.d.ts +2 -5
  176. package/dist/render/lineBatch.js +4 -24
  177. package/dist/render/mesh.d.ts +4 -0
  178. package/dist/render/mesh.js +45 -1
  179. package/dist/render/pass.d.ts +145 -8
  180. package/dist/render/prefilterEnvMap.d.ts +22 -0
  181. package/dist/render/prefilterEnvMap.js +31 -0
  182. package/dist/render/readback.d.ts +30 -0
  183. package/dist/render/readback.js +47 -0
  184. package/dist/render/recon/clamp.d.ts +36 -0
  185. package/dist/render/recon/clamp.js +92 -0
  186. package/dist/render/recon/disocclusion.d.ts +60 -0
  187. package/dist/render/recon/disocclusion.js +109 -0
  188. package/dist/render/recon/frameGen.d.ts +81 -0
  189. package/dist/render/recon/frameGen.js +150 -0
  190. package/dist/render/recon/frameSizes.d.ts +34 -0
  191. package/dist/render/recon/frameSizes.js +58 -0
  192. package/dist/render/recon/jitter.d.ts +60 -0
  193. package/dist/render/recon/jitter.js +118 -0
  194. package/dist/render/recon/motionVectors.d.ts +55 -0
  195. package/dist/render/recon/motionVectors.js +107 -0
  196. package/dist/render/recon/reproject.d.ts +41 -0
  197. package/dist/render/recon/reproject.js +131 -0
  198. package/dist/render/recon/resolve.d.ts +90 -0
  199. package/dist/render/recon/resolve.js +313 -0
  200. package/dist/render/recon/tier.d.ts +24 -0
  201. package/dist/render/recon/tier.js +8 -0
  202. package/dist/render/reflectionProbe.d.ts +26 -0
  203. package/dist/render/reflectionProbe.js +33 -0
  204. package/dist/render/renderQuality.d.ts +69 -0
  205. package/dist/render/renderQuality.js +22 -0
  206. package/dist/render/screenSpaceReflection.d.ts +23 -0
  207. package/dist/render/screenSpaceReflection.js +22 -3
  208. package/dist/render/sdfFont.js +2 -0
  209. package/dist/render/segmentQuads.d.ts +13 -0
  210. package/dist/render/segmentQuads.js +32 -0
  211. package/dist/render/shaders/flat/lobes.d.ts +27 -0
  212. package/dist/render/shaders/flat/lobes.js +33 -3
  213. package/dist/render/shaders/flat/preamble.d.ts +7 -0
  214. package/dist/render/shaders/flat/preamble.js +24 -1
  215. package/dist/render/shaders/flat/probeGrid.d.ts +1 -1
  216. package/dist/render/shaders/flat/probeGrid.js +71 -2
  217. package/dist/render/shaders/generated/flat.wgsl.d.ts +48 -8
  218. package/dist/render/shaders/generated/flat.wgsl.js +64 -24
  219. package/dist/render/shaders/gi/composeField.wgsl.d.ts +56 -0
  220. package/dist/render/shaders/gi/composeField.wgsl.js +231 -0
  221. package/dist/render/shaders/gi/marchField.wgsl.d.ts +30 -0
  222. package/dist/render/shaders/gi/marchField.wgsl.js +141 -0
  223. package/dist/render/shaders/gi/probeBake.wgsl.d.ts +113 -0
  224. package/dist/render/shaders/gi/probeBake.wgsl.js +635 -0
  225. package/dist/render/shaders/gi/probeTrace.wgsl.d.ts +72 -0
  226. package/dist/render/shaders/gi/probeTrace.wgsl.js +261 -0
  227. package/dist/render/shaders/gi/probeVolume.wgsl.d.ts +49 -0
  228. package/dist/render/shaders/gi/probeVolume.wgsl.js +242 -0
  229. package/dist/render/shaders/gi/sampleField.wgsl.d.ts +32 -0
  230. package/dist/render/shaders/gi/sampleField.wgsl.js +134 -0
  231. package/dist/render/shaders/gpudriven/blendRaster.wgsl.d.ts +26 -0
  232. package/dist/render/shaders/gpudriven/blendRaster.wgsl.js +339 -0
  233. package/dist/render/shaders/gpudriven/compact.wgsl.d.ts +29 -0
  234. package/dist/render/shaders/gpudriven/compact.wgsl.js +58 -0
  235. package/dist/render/shaders/gpudriven/cull.wgsl.d.ts +90 -0
  236. package/dist/render/shaders/gpudriven/cull.wgsl.js +423 -0
  237. package/dist/render/shaders/gpudriven/decode.wgsl.d.ts +72 -0
  238. package/dist/render/shaders/gpudriven/decode.wgsl.js +349 -0
  239. package/dist/render/shaders/gpudriven/environment.wgsl.d.ts +44 -0
  240. package/dist/render/shaders/gpudriven/environment.wgsl.js +137 -0
  241. package/dist/render/shaders/gpudriven/fog.wgsl.d.ts +28 -0
  242. package/dist/render/shaders/gpudriven/fog.wgsl.js +107 -0
  243. package/dist/render/shaders/gpudriven/frameBlock.wgsl.d.ts +13 -0
  244. package/dist/render/shaders/gpudriven/frameBlock.wgsl.js +62 -0
  245. package/dist/render/shaders/gpudriven/materialBin.wgsl.d.ts +51 -0
  246. package/dist/render/shaders/gpudriven/materialBin.wgsl.js +112 -0
  247. package/dist/render/shaders/gpudriven/materialTable.wgsl.d.ts +25 -0
  248. package/dist/render/shaders/gpudriven/materialTable.wgsl.js +43 -0
  249. package/dist/render/shaders/gpudriven/meshTransform.wgsl.d.ts +18 -0
  250. package/dist/render/shaders/gpudriven/meshTransform.wgsl.js +37 -0
  251. package/dist/render/shaders/gpudriven/present.wgsl.d.ts +43 -0
  252. package/dist/render/shaders/gpudriven/present.wgsl.js +127 -0
  253. package/dist/render/shaders/gpudriven/shade.wgsl.d.ts +127 -0
  254. package/dist/render/shaders/gpudriven/shade.wgsl.js +874 -0
  255. package/dist/render/shaders/gpudriven/shadow.wgsl.d.ts +44 -0
  256. package/dist/render/shaders/gpudriven/shadow.wgsl.js +308 -0
  257. package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.d.ts +28 -0
  258. package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.js +245 -0
  259. package/dist/render/shaders/network.wgsl.d.ts +101 -0
  260. package/dist/render/shaders/network.wgsl.js +206 -0
  261. package/dist/render/shaders/recon/motion.wgsl.d.ts +44 -0
  262. package/dist/render/shaders/recon/motion.wgsl.js +96 -0
  263. package/dist/render/shaders/recon/resolve.wgsl.d.ts +51 -0
  264. package/dist/render/shaders/recon/resolve.wgsl.js +733 -0
  265. package/dist/render/temporalAa.js +8 -33
  266. package/dist/render/textLayout.js +12 -6
  267. package/dist/render/textRenderer.d.ts +3 -1
  268. package/dist/render/textRenderer.js +4 -1
  269. package/dist/render/translucentQueue.d.ts +6 -0
  270. package/dist/render/translucentQueue.js +11 -0
  271. package/dist/render/windStreakRenderer.d.ts +2 -1
  272. package/dist/render/windStreakRenderer.js +3 -1
  273. package/dist/world/cell.d.ts +63 -0
  274. package/dist/world/cell.js +181 -0
  275. package/dist/world/cellStream.d.ts +103 -0
  276. package/dist/world/cellStream.js +198 -0
  277. package/dist/world/freeze.d.ts +81 -0
  278. package/dist/world/freeze.js +114 -0
  279. package/dist/world/rebase.d.ts +29 -0
  280. package/dist/world/rebase.js +41 -0
  281. package/package.json +8 -3
  282. package/scripts/frames.mjs +92 -0
  283. package/scripts/gpuCompute.mjs +323 -0
  284. package/scripts/png.d.mts +16 -0
  285. package/scripts/png.mjs +25 -0
  286. package/src/core/loop.ts +19 -2
  287. package/src/core/storage.ts +5 -0
  288. package/src/geometry/meshBuilder.ts +5 -1
  289. package/src/index.ts +246 -4
  290. package/src/input/input.ts +6 -1
  291. package/src/math/exact.ts +69 -3
  292. package/src/math/frustum.ts +52 -3
  293. package/src/render/backend/api.ts +42 -1
  294. package/src/render/backend/budget.ts +7 -6
  295. package/src/render/backend/createRenderer.ts +92 -3
  296. package/src/render/backend/materialChanges.ts +54 -0
  297. package/src/render/backend/select.ts +8 -0
  298. package/src/render/backend/webgl2/renderer.ts +211 -9
  299. package/src/render/backend/webgpu/buffers.ts +182 -69
  300. package/src/render/backend/webgpu/fieldCompose.ts +482 -0
  301. package/src/render/backend/webgpu/giFieldPass.ts +200 -0
  302. package/src/render/backend/webgpu/gpuDrivenPass.ts +2993 -0
  303. package/src/render/backend/webgpu/linePass.ts +4 -39
  304. package/src/render/backend/webgpu/probeBake.ts +588 -0
  305. package/src/render/backend/webgpu/renderer.ts +1481 -76
  306. package/src/render/backend/webgpu/scatterPass.ts +15 -1
  307. package/src/render/backend/webgpu/surfaceTexturePass.ts +63 -36
  308. package/src/render/causticsRenderer.ts +5 -2
  309. package/src/render/depthConvention.ts +15 -0
  310. package/src/render/deviceFeatures.ts +77 -0
  311. package/src/render/fog.ts +185 -0
  312. package/src/render/frame/alias.ts +97 -0
  313. package/src/render/frame/deps.ts +155 -0
  314. package/src/render/frame/flushGraph.ts +135 -0
  315. package/src/render/frame/graphSchedule.ts +170 -0
  316. package/src/render/frame/index.ts +52 -0
  317. package/src/render/frame/lifetime.ts +61 -0
  318. package/src/render/frame/passTimings.ts +69 -0
  319. package/src/render/frame/validate.ts +40 -0
  320. package/src/render/frame/virtual.ts +91 -0
  321. package/src/render/gi/chain.ts +225 -0
  322. package/src/render/gi/denoise.ts +276 -0
  323. package/src/render/gi/fieldScene.ts +264 -0
  324. package/src/render/gi/globalField.ts +543 -0
  325. package/src/render/gi/probeGridFit.ts +89 -0
  326. package/src/render/gi/probeTrace.ts +143 -0
  327. package/src/render/gi/probeVolume.ts +288 -0
  328. package/src/render/gi/reflection.ts +163 -0
  329. package/src/render/gi/traceField.ts +223 -0
  330. package/src/render/gi/traceScreen.ts +106 -0
  331. package/src/render/gpuScene.ts +80 -0
  332. package/src/render/gpudriven/alphaTest.ts +33 -0
  333. package/src/render/gpudriven/clusterUpload.ts +123 -0
  334. package/src/render/gpudriven/clusterWorld.ts +239 -0
  335. package/src/render/gpudriven/compact.ts +80 -0
  336. package/src/render/gpudriven/cullClusters.ts +333 -0
  337. package/src/render/gpudriven/decodeTables.ts +332 -0
  338. package/src/render/gpudriven/frustum.ts +70 -0
  339. package/src/render/gpudriven/geometryHarness.ts +51 -0
  340. package/src/render/gpudriven/hzb.ts +113 -0
  341. package/src/render/gpudriven/ibl.ts +147 -0
  342. package/src/render/gpudriven/indirect.ts +89 -0
  343. package/src/render/gpudriven/instances.ts +234 -0
  344. package/src/render/gpudriven/lit.ts +329 -0
  345. package/src/render/gpudriven/lodCut.ts +62 -0
  346. package/src/render/gpudriven/materialBin.ts +131 -0
  347. package/src/render/gpudriven/materialTable.ts +164 -0
  348. package/src/render/gpudriven/pipeline.ts +336 -0
  349. package/src/render/gpudriven/rangeAlloc.ts +122 -0
  350. package/src/render/gpudriven/sceneUpload.ts +173 -0
  351. package/src/render/gpudriven/shadeBins.ts +222 -0
  352. package/src/render/gpudriven/shadow.ts +285 -0
  353. package/src/render/gpudriven/shadowCamera.ts +406 -0
  354. package/src/render/gpudriven/streamScene.ts +575 -0
  355. package/src/render/gpudriven/surfaceFrame.ts +68 -0
  356. package/src/render/gpudriven/twoPhase.ts +214 -0
  357. package/src/render/gpudriven/visbuffer.ts +41 -0
  358. package/src/render/halfFloat.ts +22 -4
  359. package/src/render/inference/attentionTiled.ts +132 -0
  360. package/src/render/inference/denseKernels.ts +369 -0
  361. package/src/render/inference/device.ts +44 -0
  362. package/src/render/inference/deviceGraph.ts +39 -0
  363. package/src/render/inference/fuse.ts +47 -0
  364. package/src/render/inference/kernelKit.ts +120 -0
  365. package/src/render/inference/kernels.ts +18 -0
  366. package/src/render/inference/plan.ts +26 -0
  367. package/src/render/inference/reuse.ts +79 -0
  368. package/src/render/inference/runner.ts +204 -0
  369. package/src/render/inference/schedule.ts +80 -0
  370. package/src/render/inference/shapeKernels.ts +112 -0
  371. package/src/render/inference/spatialKernels.ts +220 -0
  372. package/src/render/inference/splatRaster.wgsl.ts +348 -0
  373. package/src/render/inference/splatTiles.ts +186 -0
  374. package/src/render/lineBatch.ts +4 -24
  375. package/src/render/mesh.ts +46 -1
  376. package/src/render/pass.ts +155 -10
  377. package/src/render/prefilterEnvMap.ts +33 -0
  378. package/src/render/readback.ts +73 -0
  379. package/src/render/recon/clamp.ts +113 -0
  380. package/src/render/recon/disocclusion.ts +143 -0
  381. package/src/render/recon/frameGen.ts +191 -0
  382. package/src/render/recon/frameSizes.ts +64 -0
  383. package/src/render/recon/jitter.ts +126 -0
  384. package/src/render/recon/motionVectors.ts +138 -0
  385. package/src/render/recon/reproject.ts +179 -0
  386. package/src/render/recon/resolve.ts +444 -0
  387. package/src/render/recon/tier.ts +31 -0
  388. package/src/render/reflectionProbe.ts +34 -0
  389. package/src/render/renderQuality.ts +87 -0
  390. package/src/render/screenSpaceReflection.ts +37 -3
  391. package/src/render/sdfFont.ts +2 -0
  392. package/src/render/segmentQuads.ts +39 -0
  393. package/src/render/shaders/flat/lobes.ts +35 -3
  394. package/src/render/shaders/flat/preamble.ts +25 -1
  395. package/src/render/shaders/flat/probeGrid.ts +77 -2
  396. package/src/render/shaders/generated/flat.wgsl.ts +64 -24
  397. package/src/render/shaders/gi/composeField.wgsl.ts +239 -0
  398. package/src/render/shaders/gi/marchField.wgsl.ts +146 -0
  399. package/src/render/shaders/gi/probeBake.wgsl.ts +649 -0
  400. package/src/render/shaders/gi/probeTrace.wgsl.ts +269 -0
  401. package/src/render/shaders/gi/probeVolume.wgsl.ts +246 -0
  402. package/src/render/shaders/gi/sampleField.wgsl.ts +140 -0
  403. package/src/render/shaders/gpudriven/blendRaster.wgsl.ts +343 -0
  404. package/src/render/shaders/gpudriven/compact.wgsl.ts +59 -0
  405. package/src/render/shaders/gpudriven/cull.wgsl.ts +433 -0
  406. package/src/render/shaders/gpudriven/decode.wgsl.ts +373 -0
  407. package/src/render/shaders/gpudriven/environment.wgsl.ts +141 -0
  408. package/src/render/shaders/gpudriven/fog.wgsl.ts +110 -0
  409. package/src/render/shaders/gpudriven/frameBlock.wgsl.ts +62 -0
  410. package/src/render/shaders/gpudriven/materialBin.wgsl.ts +116 -0
  411. package/src/render/shaders/gpudriven/materialTable.wgsl.ts +46 -0
  412. package/src/render/shaders/gpudriven/meshTransform.wgsl.ts +37 -0
  413. package/src/render/shaders/gpudriven/present.wgsl.ts +129 -0
  414. package/src/render/shaders/gpudriven/shade.wgsl.ts +884 -0
  415. package/src/render/shaders/gpudriven/shadow.wgsl.ts +322 -0
  416. package/src/render/shaders/gpudriven/visbufferRaster.wgsl.ts +251 -0
  417. package/src/render/shaders/network.wgsl.ts +238 -0
  418. package/src/render/shaders/recon/motion.wgsl.ts +101 -0
  419. package/src/render/shaders/recon/resolve.wgsl.ts +741 -0
  420. package/src/render/temporalAa.ts +9 -33
  421. package/src/render/textLayout.ts +12 -6
  422. package/src/render/textRenderer.ts +5 -2
  423. package/src/render/translucentQueue.ts +11 -0
  424. package/src/render/windStreakRenderer.ts +4 -2
  425. package/src/world/cell.ts +231 -0
  426. package/src/world/cellStream.ts +278 -0
  427. package/src/world/freeze.ts +157 -0
  428. package/src/world/rebase.ts +56 -0
@@ -0,0 +1,164 @@
1
+ /** A GPU-driven material as the shading pass reads it: five blocks, one of them integers. */
2
+
3
+ import type { GpuDrivenMaterial } from '../backend/webgpu/gpuDrivenPass.ts';
4
+ import { DECODE_NO_PROGRAM } from '../shaders/gpudriven/decode.wgsl.ts';
5
+ import type { GpuDrivenProgram } from './decodeTables.ts';
6
+
7
+ /**
8
+ * **The forward path's maps, as decode programs.** `SurfaceMaterial` binds an albedo, a normal and
9
+ * an occlusion-roughness-metallic image, and its scales and strengths mean what they mean there —
10
+ * the ORM map *replaces* roughness and the scale gives the scaling back, and occlusion strength is
11
+ * a mix from one rather than a multiply. Defaults are `SurfaceMaterial`'s.
12
+ */
13
+ export interface GpuDrivenTextures {
14
+ readonly baseColour?: GpuDrivenProgram;
15
+ readonly normal?: GpuDrivenProgram;
16
+ /** Occlusion in R, roughness in G, metallic in B — glTF's packing, as `SurfaceMaterial.orm`. */
17
+ readonly orm?: GpuDrivenProgram;
18
+ /**
19
+ * Where the surface glows, in colour, as `SurfaceMaterial.emissive`'s map: the glow is the albedo
20
+ * times this times the material's `emissive`, so a black texel glows nowhere and the scalar
21
+ * still says how brightly the rest does. **glTF's rule and flat/main.ts's**, which the facade of
22
+ * a city at dusk needed — lit windows in a wall that does not glow — and the pipeline could not
23
+ * say until 2026-09-18.
24
+ */
25
+ readonly emissive?: GpuDrivenProgram;
26
+ readonly uScale?: number;
27
+ readonly vScale?: number;
28
+ /** Defaults to 1 when a `normal` program is given and 0 when it is not. */
29
+ readonly normalStrength?: number;
30
+ readonly roughnessScale?: number;
31
+ readonly metallicScale?: number;
32
+ readonly occlusionStrength?: number;
33
+ }
34
+
35
+ /**
36
+ * Words a material entry: tint and emissive, the surface scalars, four program indices, the UV
37
+ * scale and two strengths, the two ORM scales with the cutout and blend flags, and
38
+ * the opacity with three spare.
39
+ *
40
+ * **It was eight until 2026-09-17**, and metalness took its last spare lane the same day, so the
41
+ * programs and the scales needed three more blocks rather than squeezing into what was left. It
42
+ * became twenty-four on 2026-09-18, when transparency arrived and there was nowhere left to put an
43
+ * opacity: the cutout took lane 18 and the blend flag took 19, and lane 11 is a reserved program
44
+ * slot rather than a gap. A sixteen-byte block is 1 kB across the whole table, against the 64 kB a
45
+ * uniform buffer may hold.
46
+ */
47
+ export const GPU_DRIVEN_MATERIAL_FLOATS = 24;
48
+
49
+ /**
50
+ * Below this base-colour alpha the raster discards a fragment. Zero means no test.
51
+ *
52
+ * **Lane 18 rather than lane 11**, which looks spare and is not: the loop below initialises lanes
53
+ * 8 to 11 to `DECODE_NO_PROGRAM`, so eleven is a fourth program slot somebody reserved rather than
54
+ * a gap, and a scalar written there would be read back as a program index. Taking 18 leaves the
55
+ * reservation alone and leaves 19 after it.
56
+ */
57
+ export const MATERIAL_ALPHA_CUTOFF = 18;
58
+
59
+ /**
60
+ * Non-zero where this material's clusters are drawn blended rather than into the visibility buffer.
61
+ *
62
+ * **The last spare lane of twenty**, and a flag rather than an opacity because the opacity is the
63
+ * tint's fourth component. What this selects is which of the two halves of the frame a cluster
64
+ * belongs to, which the cut asks once per cluster.
65
+ */
66
+ export const MATERIAL_BLEND = 19;
67
+
68
+ /**
69
+ * How much of a blended surface is its own colour rather than what is behind it. One is opaque.
70
+ *
71
+ * **It is not the tint's fourth component**, which is the emissive gain and has been since the
72
+ * table was eight floats, and it is not `alphaCutoff`, which decides whether a fragment exists at
73
+ * all. A material that does not blend never reads this.
74
+ */
75
+ export const MATERIAL_OPACITY = 20;
76
+
77
+ /**
78
+ * Where a material's emissive program is: the fourth program lane, which the table reserved and
79
+ * initialised to none before anything used it.
80
+ */
81
+ export const MATERIAL_EMISSIVE_PROGRAM = 11;
82
+
83
+ /** Program lanes a material, and the stride `collectPrograms` writes its indices at. */
84
+ const PROGRAM_LANES = 4;
85
+
86
+ export interface MaterialPrograms {
87
+ readonly programs: readonly GpuDrivenProgram[];
88
+ /** Four a material — base colour, normal, ORM, emissive — each an index into `programs` or none. */
89
+ readonly indices: Uint32Array;
90
+ }
91
+
92
+ /** Every program the materials name, once each by identity, and where each material's are. */
93
+ export function collectPrograms(materials: readonly GpuDrivenMaterial[]): MaterialPrograms {
94
+ const programs: GpuDrivenProgram[] = [];
95
+ const known = new Map<GpuDrivenProgram, number>();
96
+ const indexOf = (program: GpuDrivenProgram | undefined): number => {
97
+ if (program === undefined) return DECODE_NO_PROGRAM;
98
+ const found = known.get(program);
99
+ if (found !== undefined) return found;
100
+ programs.push(program);
101
+ known.set(program, programs.length - 1);
102
+ return programs.length - 1;
103
+ };
104
+ const indices = new Uint32Array(materials.length * PROGRAM_LANES);
105
+ materials.forEach((material, m) => {
106
+ indices[m * PROGRAM_LANES] = indexOf(material.textures?.baseColour);
107
+ indices[m * PROGRAM_LANES + 1] = indexOf(material.textures?.normal);
108
+ indices[m * PROGRAM_LANES + 2] = indexOf(material.textures?.orm);
109
+ indices[m * PROGRAM_LANES + 3] = indexOf(material.textures?.emissive);
110
+ });
111
+ return { programs, indices };
112
+ }
113
+
114
+ /**
115
+ * The table, `slots` entries long.
116
+ *
117
+ * **Written through a `DataView` because one block is integers.** A program index written as a
118
+ * float would be read by `vec4<u32>` as the float's bits, which names a program four billion
119
+ * places away and draws nothing — or, clamped, the last program in the table.
120
+ */
121
+ export function writeMaterialTable(
122
+ materials: readonly GpuDrivenMaterial[],
123
+ indices: Uint32Array,
124
+ slots: number,
125
+ ): ArrayBuffer {
126
+ const buffer = new ArrayBuffer(slots * GPU_DRIVEN_MATERIAL_FLOATS * 4);
127
+ const view = new DataView(buffer);
128
+ const float = (m: number, lane: number, value: number): void =>
129
+ view.setFloat32((m * GPU_DRIVEN_MATERIAL_FLOATS + lane) * 4, value, true);
130
+ const word = (m: number, lane: number, value: number): void =>
131
+ view.setUint32((m * GPU_DRIVEN_MATERIAL_FLOATS + lane) * 4, value, true);
132
+
133
+ for (let m = 0; m < slots; m += 1) {
134
+ for (let lane = 8; lane < 12; lane += 1) word(m, lane, DECODE_NO_PROGRAM);
135
+ }
136
+ materials.forEach((material, m) => {
137
+ float(m, 0, material.tint[0]);
138
+ float(m, 1, material.tint[1]);
139
+ float(m, 2, material.tint[2]);
140
+ float(m, 3, material.emissive);
141
+ /* Roughness one and specular zero: the matte this pipeline drew before either existed. */
142
+ float(m, 4, material.roughness ?? 1);
143
+ float(m, 5, material.specular ?? 0);
144
+ float(m, 6, material.reflectivity ?? 0);
145
+ float(m, 7, material.metalness ?? 0);
146
+ for (let lane = 0; lane < PROGRAM_LANES; lane += 1) {
147
+ word(m, 8 + lane, indices[m * PROGRAM_LANES + lane] as number);
148
+ }
149
+ const textures = material.textures;
150
+ float(m, 12, textures?.uScale ?? 1);
151
+ float(m, 13, textures?.vScale ?? 1);
152
+ float(m, 14, textures?.normal === undefined ? 0 : (textures.normalStrength ?? 1));
153
+ float(m, 15, textures?.occlusionStrength ?? 1);
154
+ float(m, 16, textures?.roughnessScale ?? 1);
155
+ float(m, 17, textures?.metallicScale ?? 1);
156
+ /* Zero is off, so a material that says nothing about cutout writes the table it wrote before. */
157
+ float(m, MATERIAL_ALPHA_CUTOFF, material.alphaCutoff ?? 0);
158
+ /* Zero is opaque, so a material that says nothing about blending stays in the opaque half. */
159
+ float(m, MATERIAL_BLEND, material.blend === true ? 1 : 0);
160
+ /* One, so a material that asked to blend and said nothing else is as solid as an opaque one. */
161
+ float(m, MATERIAL_OPACITY, material.opacity ?? 1);
162
+ });
163
+ return buffer;
164
+ }
@@ -0,0 +1,336 @@
1
+ /**
2
+ * The GPU-driven frame, as an order and a set of dependencies.
3
+ *
4
+ * **Every stage of Wave 2A exists on its own and this is what says how they fit together.** The
5
+ * frame's colour is cleared, the directional map is drawn, the meshes wholly outside the view are
6
+ * flagged, the cut through the cluster graph is chosen without them and phase one culls what was
7
+ * visible last frame, phase one draws, the depth pyramid is reduced from that, phase two culls the
8
+ * rest against it and draws, the visibility is copied where a dispatch can read it, binned by
9
+ * material, and each bin is shaded. Twelve stages, and the edges between them are what stop a
10
+ * scheduler reordering the ones that must not move — see `twoPhase.ts` for the one that matters
11
+ * most.
12
+ *
13
+ * **The pipeline is opt-in and WebGPU only.** `gpuDrivenSupported` is `indirectSupport`, which is
14
+ * false on WebGL2 and not a thing a fallback can paper over: without an indirect draw the counts
15
+ * this frame produces would have to come back to the processor, and a readback is slower than the
16
+ * draw it would replace. Selecting it on a backend that cannot run it **fails at creation** rather
17
+ * than falling back, because a silent fallback means a consumer ships believing they have a
18
+ * pipeline they do not.
19
+ *
20
+ * **This is what `GpuDrivenPass` is scheduled by**, since 2026-09-17: the pass records these stages
21
+ * into a `Deps` table each frame, `scheduleGraph` decides which of them run, and the pass encodes
22
+ * the ones it kept in the order it kept them. Until then this was a description beside an encoder
23
+ * with its own fixed order — and the description had drifted, naming a separate instance cull the
24
+ * encoder never had and a colour both draws wrote when neither does. The instance cull is a stage
25
+ * of the encoder now, 2026-09-17, which is `wave2a`'s fifth task finally reaching the frame. Binding real buffers and
26
+ * issuing real dispatches stays the backend's; what moved here is the decision about what runs.
27
+ */
28
+
29
+ import { indirectSupport } from '../backend/api.ts';
30
+ import { recordDeps } from '../frame/deps.ts';
31
+ import type { Deps } from '../frame/deps.ts';
32
+
33
+ /** Whether a backend can run this pipeline at all. */
34
+ export function gpuDrivenSupported(backend: 'webgl2' | 'webgpu'): boolean {
35
+ return indirectSupport(backend);
36
+ }
37
+
38
+ /**
39
+ * Why a backend cannot, in the words a consumer sees.
40
+ *
41
+ * A sentence rather than a code, because the one thing the reader needs is that this is a property
42
+ * of the backend and not of their scene — and `''` where it can.
43
+ */
44
+ export function gpuDrivenRefusal(backend: 'webgl2' | 'webgpu'): string {
45
+ if (gpuDrivenSupported(backend)) return '';
46
+ return (
47
+ `the gpu-driven pipeline needs indirect draws and dispatches, which ${backend} does not have. ` +
48
+ 'Emulating them through a readback is slower than the draw it would replace, so this fails ' +
49
+ 'rather than falling back: a silent fallback ships a consumer a pipeline they do not have.'
50
+ );
51
+ }
52
+
53
+ /**
54
+ * Every resource a GPU-driven frame moves between its stages, as an identifier each.
55
+ *
56
+ * **Named for what the encoder actually binds**, which the first version of this table was not: it
57
+ * described both draws writing the colour, which neither does, and an instance cull the encoder did
58
+ * not then have. A description that is not the encoder is a comment, and this one is what the
59
+ * encoder is scheduled by.
60
+ */
61
+ export interface GpuDrivenResources {
62
+ /** Everything uploaded once: bounds, cones, errors, indices, vertices, transforms, materials. */
63
+ readonly clusters: number;
64
+ /** Which clusters last frame drew. Imported: this frame reads it and never writes it. */
65
+ readonly history: number;
66
+ readonly shadowMap: number;
67
+ /** Which meshes are wholly outside the view, one flag a mesh. */
68
+ readonly instances: number;
69
+ /** The cut through the cluster graph, one flag a cluster, with hidden meshes left out. */
70
+ readonly cut: number;
71
+ /** The cull's verdict, one flag a cluster, written by each phase for its own half. */
72
+ readonly keep: number;
73
+ /** Each phase's compacted list and the indirect draw that counts it. */
74
+ readonly listOne: number;
75
+ readonly listTwo: number;
76
+ /** Which clusters this frame drew, which is next frame's history. */
77
+ readonly drawn: number;
78
+ readonly depth: number;
79
+ /** The visibility attachment, and the buffer it is copied into so a dispatch can read it. */
80
+ readonly visibility: number;
81
+ readonly visibilityCopy: number;
82
+ readonly hzb: number;
83
+ readonly binCounts: number;
84
+ readonly binOffsets: number;
85
+ /** A copy of the offsets the scatter advances, because the offsets must survive it. */
86
+ readonly binCursors: number;
87
+ readonly binPixels: number;
88
+ readonly colour: number;
89
+ /** The compacted list of blended clusters and the indirect draw that counts it. */
90
+ readonly blendList: number;
91
+ /** The two weighted-transparency targets, and what resolving them writes. */
92
+ readonly oitAccum: number;
93
+ readonly oitReveal: number;
94
+ }
95
+
96
+ /** The identifiers one frame uses. A frame is its own graph, so they start at zero. */
97
+ export const GPU_DRIVEN_RESOURCES: GpuDrivenResources = {
98
+ clusters: 0,
99
+ history: 1,
100
+ shadowMap: 2,
101
+ cut: 3,
102
+ keep: 4,
103
+ listOne: 5,
104
+ listTwo: 6,
105
+ drawn: 7,
106
+ depth: 8,
107
+ visibility: 9,
108
+ visibilityCopy: 10,
109
+ hzb: 11,
110
+ binCounts: 12,
111
+ binOffsets: 13,
112
+ binCursors: 14,
113
+ binPixels: 15,
114
+ colour: 16,
115
+ instances: 17,
116
+ blendList: 18,
117
+ oitAccum: 19,
118
+ oitReveal: 20,
119
+ };
120
+
121
+ /**
122
+ * What each stage is called, in the order they are recorded — one render or compute pass each, or
123
+ * one copy between them.
124
+ */
125
+ export const GPU_DRIVEN_PASSES = [
126
+ 'clearColour',
127
+ 'shadow',
128
+ 'instanceCull',
129
+ 'cut',
130
+ 'phaseOneDraw',
131
+ 'pyramid',
132
+ 'phaseTwoCull',
133
+ 'phaseTwoDraw',
134
+ 'blendCull',
135
+ 'blendDraw',
136
+ 'visibilityCopy',
137
+ 'bin',
138
+ 'cursorCopy',
139
+ 'shade',
140
+ 'blendResolve',
141
+ ] as const;
142
+
143
+ export type GpuDrivenPassName = (typeof GPU_DRIVEN_PASSES)[number];
144
+
145
+ /**
146
+ * **Every stage is ordered, so none merges with a neighbour.** Two adjacent compute stages could
147
+ * share a pass as far as their results go; they do not, because each is bracketed by its own pair
148
+ * of timestamps and a pair brackets a pass. What the schedule decides here is which stages run,
149
+ * and it checks the order the names give against the edges the stages declare.
150
+ */
151
+ export const GPU_DRIVEN_ORDERED: Uint8Array = new Uint8Array(GPU_DRIVEN_PASSES.length).fill(1);
152
+
153
+ /** Where each pass landed in the dependency table, by name. */
154
+ export type GpuDrivenNodes = Readonly<Record<GpuDrivenPassName, number>>;
155
+
156
+ /** What about this frame changes which stages it needs. */
157
+ export interface GpuDrivenFrameShape {
158
+ /**
159
+ * Whether the shading reads the directional map. A frame whose shadow strength is zero does not:
160
+ * the lookup answers one before any arithmetic, so the map's contents cannot reach a pixel and
161
+ * the stage that renders it is culled rather than run for nothing.
162
+ */
163
+ readonly shadowed: boolean;
164
+ /**
165
+ * Whether any material in the table asks to be blended.
166
+ *
167
+ * A frame with none schedules the whole transparent half away — the second run of the cut, the
168
+ * blended draw and the resolve — so a scene that never mentions transparency encodes the frame it
169
+ * encoded before transparency existed, command for command. `gpuDrivenPass.test.ts` holds that
170
+ * against a fixed list rather than against a promise.
171
+ */
172
+ readonly blended: boolean;
173
+ }
174
+
175
+ /** One stage's reads and writes. */
176
+ type Edges = readonly [reads: readonly number[], writes: readonly number[]];
177
+
178
+ /**
179
+ * The frame's edges, stage by stage. The claim is here, and five parts of it are load-bearing
180
+ * enough to name:
181
+ *
182
+ * - `cut` reads the flags `instanceCull` wrote, so a mesh wholly outside the view has its clusters
183
+ * left out of the cut before the cluster cull or the compaction reads one of them.
184
+ * - `pyramid` reads the depth `phaseOneDraw` wrote, and `phaseTwoCull` reads the pyramid. Together
185
+ * those are "the occlusion is tested against depth from this frame", which is the whole reason
186
+ * the frame has two halves — and `cut` reads no pyramid at all, which is the other half of it.
187
+ * - `cut` and `phaseTwoCull` both read the history and both write the next one: the history
188
+ * decides which half judges a cluster, never whether one does.
189
+ * - `cursorCopy` reads the offsets `bin` wrote and `shade` reads the cursors. The scatter cannot
190
+ * start before the sum has, and neither ordering is a comment anybody has to obey.
191
+ * - `shade` reads the map only where the frame is shadowed — `unshadowedShade` — so an unshadowed
192
+ * frame's map is something nothing reads, and `scheduleGraph` culls the stage that draws it.
193
+ */
194
+ function edgesFor(res: GpuDrivenResources): {
195
+ readonly stages: readonly Edges[];
196
+ readonly unshadowedShade: readonly number[];
197
+ } {
198
+ const table: Record<GpuDrivenPassName, Edges> = {
199
+ clearColour: [[], [res.colour]],
200
+ shadow: [[res.clusters], [res.shadowMap]],
201
+ instanceCull: [[res.clusters], [res.instances]],
202
+ cut: [
203
+ [res.clusters, res.history, res.instances],
204
+ [res.cut, res.keep, res.listOne, res.drawn],
205
+ ],
206
+ phaseOneDraw: [
207
+ [res.listOne, res.clusters],
208
+ [res.depth, res.visibility],
209
+ ],
210
+ pyramid: [[res.depth], [res.hzb]],
211
+ phaseTwoCull: [
212
+ [res.hzb, res.cut, res.clusters, res.history],
213
+ [res.keep, res.listTwo, res.drawn],
214
+ ],
215
+ phaseTwoDraw: [
216
+ [res.listTwo, res.clusters, res.depth, res.visibility],
217
+ [res.depth, res.visibility],
218
+ ],
219
+ /*
220
+ * **The cut's second run, over the other half of the scene.** It reads what the first run read
221
+ * and writes the same working buffers, which is safe because it runs after both draws have
222
+ * taken what they needed from them — and it writes a list of its own, which is what the blended
223
+ * draw reads. It reads the pyramid too: a pane wholly behind a wall is occluded exactly as an
224
+ * opaque cluster there would be.
225
+ */
226
+ blendCull: [
227
+ [res.clusters, res.instances, res.hzb],
228
+ [res.cut, res.keep, res.blendList],
229
+ ],
230
+ /*
231
+ * **It reads the depth the opaque half wrote and does not write it.** A pane behind a wall is
232
+ * rejected at the wall; nothing here writes depth, so two panes do not hide each other and
233
+ * there is something left to blend.
234
+ */
235
+ blendDraw: [
236
+ [res.blendList, res.clusters, res.depth],
237
+ [res.oitAccum, res.oitReveal],
238
+ ],
239
+ visibilityCopy: [[res.visibility], [res.visibilityCopy]],
240
+ bin: [[res.visibilityCopy], [res.binCounts, res.binOffsets]],
241
+ cursorCopy: [[res.binOffsets], [res.binCursors]],
242
+ shade: [
243
+ [res.visibilityCopy, res.binOffsets, res.binCursors, res.clusters, res.colour, res.shadowMap],
244
+ [res.binPixels, res.colour],
245
+ ],
246
+ /*
247
+ * **After the shading, because it composites over what the shading wrote.** The opaque picture
248
+ * is the background a transparent layer is blended against, so this is the last thing the
249
+ * frame does to its own colour target.
250
+ */
251
+ blendResolve: [[res.oitAccum, res.oitReveal, res.colour], [res.colour]],
252
+ };
253
+ return {
254
+ stages: GPU_DRIVEN_PASSES.map((name) => table[name]),
255
+ unshadowedShade: table.shade[0].filter((id) => id !== res.shadowMap),
256
+ };
257
+ }
258
+
259
+ /* Built once a resource table, so a frame records without constructing an edge list. */
260
+ const EDGES = new WeakMap<GpuDrivenResources, ReturnType<typeof edgesFor>>();
261
+
262
+ const SHADE = GPU_DRIVEN_PASSES.indexOf('shade');
263
+
264
+ /**
265
+ * The three stages a frame with nothing transparent does not record at all.
266
+ *
267
+ * **Culled by giving them no edges rather than by filtering a read**, which is how the shadow map
268
+ * is culled one line above and does not work here: `blendResolve` writes the colour, the colour is
269
+ * what the frame is kept alive for, so a stage that writes it survives any amount of filtering. A
270
+ * stage with no writes is read by nothing and the scheduler drops it, which is the same answer
271
+ * reached the only way that is true for this one.
272
+ */
273
+ const BLEND_STAGES: readonly number[] = [
274
+ GPU_DRIVEN_PASSES.indexOf('blendCull'),
275
+ GPU_DRIVEN_PASSES.indexOf('blendDraw'),
276
+ GPU_DRIVEN_PASSES.indexOf('blendResolve'),
277
+ ];
278
+ const NOTHING: readonly number[] = [];
279
+
280
+ /**
281
+ * Record the whole frame, in order, and answer the index its first stage landed at.
282
+ *
283
+ * Allocates nothing once a resource table has been seen, which is what lets `GpuDrivenPass` call it
284
+ * every frame. Stage `i` of `GPU_DRIVEN_PASSES` is node `first + i`.
285
+ */
286
+ export function recordGpuDrivenStages(
287
+ deps: Deps,
288
+ res: GpuDrivenResources,
289
+ shape: GpuDrivenFrameShape,
290
+ ): number {
291
+ let edges = EDGES.get(res);
292
+ if (edges === undefined) {
293
+ edges = edgesFor(res);
294
+ EDGES.set(res, edges);
295
+ }
296
+ const first = deps.count;
297
+ for (let stage = 0; stage < edges.stages.length; stage += 1) {
298
+ if (!shape.blended && BLEND_STAGES.includes(stage)) {
299
+ recordDeps(deps, NOTHING, NOTHING);
300
+ continue;
301
+ }
302
+ const [reads, writes] = edges.stages[stage] as Edges;
303
+ recordDeps(deps, stage === SHADE && !shape.shadowed ? edges.unshadowedShade : reads, writes);
304
+ }
305
+ return first;
306
+ }
307
+
308
+ /** Record the whole frame and answer where each pass went, by name. For a reader, not a frame. */
309
+ export function recordGpuDrivenFrame(
310
+ deps: Deps,
311
+ res: GpuDrivenResources,
312
+ shape: GpuDrivenFrameShape,
313
+ ): GpuDrivenNodes {
314
+ const first = recordGpuDrivenStages(deps, res, shape);
315
+ return Object.fromEntries(
316
+ GPU_DRIVEN_PASSES.map((name, index) => [name, first + index]),
317
+ ) as unknown as GpuDrivenNodes;
318
+ }
319
+
320
+ /**
321
+ * What a frame leaves behind, which is what `scheduleGraph` is asked to keep alive.
322
+ *
323
+ * The colour, which the blit presents, and the history, which next frame's phase one reads. The
324
+ * depth, the pyramid, the visibility buffer and every bin are this frame's working set and nothing
325
+ * outside reads them. Naming more than is needed keeps resources alive that could have been
326
+ * aliased — which is `alias.ts`'s whole subject — and naming fewer culls a pass that was doing
327
+ * something.
328
+ */
329
+ export function gpuDrivenLive(res: GpuDrivenResources): readonly number[] {
330
+ return [res.colour, res.drawn];
331
+ }
332
+
333
+ /** What a frame reads without having written: the scene, and last frame's history. */
334
+ export function gpuDrivenImports(res: GpuDrivenResources): readonly number[] {
335
+ return [res.clusters, res.history];
336
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * A free list over one axis of units, and nothing else.
3
+ *
4
+ * **Four of these make a streaming scene** — vertices, indices, clusters and meshes — and none of
5
+ * them needs to know what a cluster is. Keeping it that way is what lets "a returned range is
6
+ * reusable" be a test that does not build a mesh.
7
+ *
8
+ * **Best fit rather than first fit**, because the workload that motivated this remeshes a chunk
9
+ * into a slightly different size on every block a player breaks. First fit hands the front of the
10
+ * largest hole to whatever asks next, so the large holes disappear first and the request that
11
+ * needed one is refused while the total says there is room.
12
+ *
13
+ * **Refusal is `-1` rather than an exception**, because a streaming consumer calls `claim` from a
14
+ * frame loop: an exception there is a crashed demo where a refusal is a chunk that arrives a frame
15
+ * later.
16
+ */
17
+
18
+ /** A free run: where it starts and how many units it holds. */
19
+ interface Hole {
20
+ at: number;
21
+ units: number;
22
+ }
23
+
24
+ export class RangeAlloc {
25
+ /**
26
+ * The free runs, kept sorted by `at` and never touching.
27
+ *
28
+ * **Sorted and coalesced is an invariant rather than a convenience**: it is what makes the
29
+ * layout independent of the order ranges were released in, which a capture would otherwise
30
+ * expose as an image that differs between runs with nothing failing.
31
+ */
32
+ private holes: Hole[];
33
+ private readonly total: number;
34
+ private usedUnits = 0;
35
+ private high = 0;
36
+
37
+ constructor(capacity: number) {
38
+ const units = Math.max(0, Math.floor(capacity));
39
+ this.total = units;
40
+ this.holes = units > 0 ? [{ at: 0, units }] : [];
41
+ }
42
+
43
+ get capacity(): number {
44
+ return this.total;
45
+ }
46
+
47
+ get used(): number {
48
+ return this.usedUnits;
49
+ }
50
+
51
+ /** The most units ever live at once. `scripts/stream-fragmentation.mjs` reads this. */
52
+ get highWater(): number {
53
+ return this.high;
54
+ }
55
+
56
+ /**
57
+ * The first unit of a run of `units`, or -1 where no single run is long enough.
58
+ *
59
+ * A request for nothing succeeds at 0 and occupies nothing: a mesh with no clusters is legal,
60
+ * and `buildGpuDrivenScene`'s header says what dropping one would do to every mesh after it.
61
+ */
62
+ claim(units: number): number {
63
+ const want = Math.max(0, Math.floor(units));
64
+ if (want === 0) return 0;
65
+
66
+ let best = -1;
67
+ for (let i = 0; i < this.holes.length; i += 1) {
68
+ const hole = this.holes[i] as Hole;
69
+ if (hole.units < want) continue;
70
+ if (best < 0 || hole.units < (this.holes[best] as Hole).units) best = i;
71
+ }
72
+ if (best < 0) return -1;
73
+
74
+ const hole = this.holes[best] as Hole;
75
+ const at = hole.at;
76
+ if (hole.units === want) this.holes.splice(best, 1);
77
+ else {
78
+ hole.at += want;
79
+ hole.units -= want;
80
+ }
81
+ this.usedUnits += want;
82
+ if (this.usedUnits > this.high) this.high = this.usedUnits;
83
+ return at;
84
+ }
85
+
86
+ /**
87
+ * Give a run back, merging it with whatever it now touches.
88
+ *
89
+ * **Merged on the way in rather than swept later**, which is what keeps the invariant true at
90
+ * every moment a caller could look and makes the order releases arrived in stop mattering.
91
+ */
92
+ release(at: number, units: number): void {
93
+ const count = Math.max(0, Math.floor(units));
94
+ if (count === 0) return;
95
+ const start = Math.max(0, Math.floor(at));
96
+
97
+ let index = 0;
98
+ while (index < this.holes.length && (this.holes[index] as Hole).at < start) index += 1;
99
+ this.holes.splice(index, 0, { at: start, units: count });
100
+ this.usedUnits = Math.max(0, this.usedUnits - count);
101
+
102
+ /* Merge with the one before and the one after, in that order, so three runs become one. */
103
+ const previous = index > 0 ? (this.holes[index - 1] as Hole) : null;
104
+ if (previous !== null && previous.at + previous.units === start) {
105
+ previous.units += count;
106
+ this.holes.splice(index, 1);
107
+ index -= 1;
108
+ }
109
+ const merged = this.holes[index] as Hole;
110
+ const next = index + 1 < this.holes.length ? (this.holes[index + 1] as Hole) : null;
111
+ if (next !== null && merged.at + merged.units === next.at) {
112
+ merged.units += next.units;
113
+ this.holes.splice(index + 1, 1);
114
+ }
115
+ }
116
+
117
+ /** Back to one free run, keeping the high-water mark, which is a record of the run so far. */
118
+ reset(): void {
119
+ this.holes = this.total > 0 ? [{ at: 0, units: this.total }] : [];
120
+ this.usedUnits = 0;
121
+ }
122
+ }