@driftengine/core 3.63.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (428) hide show
  1. package/CHANGELOG.json +122 -0
  2. package/NOTICE +20 -0
  3. package/README.md +1 -1
  4. package/dist/core/loop.js +18 -2
  5. package/dist/core/storage.js +5 -0
  6. package/dist/geometry/meshBuilder.d.ts +1 -1
  7. package/dist/geometry/meshBuilder.js +6 -2
  8. package/dist/index.d.ts +69 -4
  9. package/dist/index.js +112 -2
  10. package/dist/input/input.js +6 -1
  11. package/dist/math/exact.d.ts +13 -3
  12. package/dist/math/exact.js +68 -3
  13. package/dist/math/frustum.d.ts +17 -2
  14. package/dist/math/frustum.js +24 -0
  15. package/dist/render/backend/api.d.ts +34 -1
  16. package/dist/render/backend/api.js +22 -1
  17. package/dist/render/backend/budget.d.ts +7 -6
  18. package/dist/render/backend/budget.js +7 -6
  19. package/dist/render/backend/createRenderer.d.ts +57 -0
  20. package/dist/render/backend/createRenderer.js +51 -2
  21. package/dist/render/backend/materialChanges.d.ts +41 -0
  22. package/dist/render/backend/materialChanges.js +38 -0
  23. package/dist/render/backend/select.js +8 -0
  24. package/dist/render/backend/webgl2/renderer.d.ts +80 -1
  25. package/dist/render/backend/webgl2/renderer.js +208 -10
  26. package/dist/render/backend/webgpu/buffers.d.ts +20 -1
  27. package/dist/render/backend/webgpu/buffers.js +116 -58
  28. package/dist/render/backend/webgpu/fieldCompose.d.ts +156 -0
  29. package/dist/render/backend/webgpu/fieldCompose.js +396 -0
  30. package/dist/render/backend/webgpu/giFieldPass.d.ts +66 -0
  31. package/dist/render/backend/webgpu/giFieldPass.js +137 -0
  32. package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +728 -0
  33. package/dist/render/backend/webgpu/gpuDrivenPass.js +2473 -0
  34. package/dist/render/backend/webgpu/linePass.d.ts +4 -14
  35. package/dist/render/backend/webgpu/linePass.js +4 -33
  36. package/dist/render/backend/webgpu/probeBake.d.ts +148 -0
  37. package/dist/render/backend/webgpu/probeBake.js +493 -0
  38. package/dist/render/backend/webgpu/renderer.d.ts +379 -24
  39. package/dist/render/backend/webgpu/renderer.js +1369 -76
  40. package/dist/render/backend/webgpu/scatterPass.js +15 -1
  41. package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +19 -9
  42. package/dist/render/backend/webgpu/surfaceTexturePass.js +58 -32
  43. package/dist/render/causticsRenderer.d.ts +3 -1
  44. package/dist/render/causticsRenderer.js +4 -1
  45. package/dist/render/depthConvention.d.ts +12 -0
  46. package/dist/render/depthConvention.js +14 -0
  47. package/dist/render/deviceFeatures.d.ts +32 -0
  48. package/dist/render/deviceFeatures.js +41 -0
  49. package/dist/render/fog.d.ts +79 -0
  50. package/dist/render/fog.js +138 -0
  51. package/dist/render/frame/alias.d.ts +30 -0
  52. package/dist/render/frame/alias.js +61 -0
  53. package/dist/render/frame/deps.d.ts +37 -0
  54. package/dist/render/frame/deps.js +122 -0
  55. package/dist/render/frame/flushGraph.d.ts +43 -0
  56. package/dist/render/frame/flushGraph.js +84 -0
  57. package/dist/render/frame/graphSchedule.d.ts +49 -0
  58. package/dist/render/frame/graphSchedule.js +120 -0
  59. package/dist/render/frame/index.d.ts +15 -0
  60. package/dist/render/frame/index.js +8 -0
  61. package/dist/render/frame/lifetime.d.ts +24 -0
  62. package/dist/render/frame/lifetime.js +36 -0
  63. package/dist/render/frame/passTimings.d.ts +42 -0
  64. package/dist/render/frame/passTimings.js +38 -0
  65. package/dist/render/frame/validate.d.ts +15 -0
  66. package/dist/render/frame/validate.js +22 -0
  67. package/dist/render/frame/virtual.d.ts +44 -0
  68. package/dist/render/frame/virtual.js +61 -0
  69. package/dist/render/gi/chain.d.ts +82 -0
  70. package/dist/render/gi/chain.js +135 -0
  71. package/dist/render/gi/denoise.d.ts +114 -0
  72. package/dist/render/gi/denoise.js +169 -0
  73. package/dist/render/gi/fieldScene.d.ts +125 -0
  74. package/dist/render/gi/fieldScene.js +219 -0
  75. package/dist/render/gi/globalField.d.ts +157 -0
  76. package/dist/render/gi/globalField.js +373 -0
  77. package/dist/render/gi/probeGridFit.d.ts +24 -0
  78. package/dist/render/gi/probeGridFit.js +71 -0
  79. package/dist/render/gi/probeTrace.d.ts +82 -0
  80. package/dist/render/gi/probeTrace.js +128 -0
  81. package/dist/render/gi/probeVolume.d.ts +136 -0
  82. package/dist/render/gi/probeVolume.js +191 -0
  83. package/dist/render/gi/reflection.d.ts +73 -0
  84. package/dist/render/gi/reflection.js +109 -0
  85. package/dist/render/gi/traceField.d.ts +91 -0
  86. package/dist/render/gi/traceField.js +129 -0
  87. package/dist/render/gi/traceScreen.d.ts +68 -0
  88. package/dist/render/gi/traceScreen.js +82 -0
  89. package/dist/render/gpuScene.d.ts +38 -0
  90. package/dist/render/gpuScene.js +41 -0
  91. package/dist/render/gpudriven/alphaTest.d.ts +28 -0
  92. package/dist/render/gpudriven/alphaTest.js +32 -0
  93. package/dist/render/gpudriven/clusterUpload.d.ts +59 -0
  94. package/dist/render/gpudriven/clusterUpload.js +75 -0
  95. package/dist/render/gpudriven/clusterWorld.d.ts +57 -0
  96. package/dist/render/gpudriven/clusterWorld.js +155 -0
  97. package/dist/render/gpudriven/compact.d.ts +51 -0
  98. package/dist/render/gpudriven/compact.js +68 -0
  99. package/dist/render/gpudriven/cullClusters.d.ts +129 -0
  100. package/dist/render/gpudriven/cullClusters.js +237 -0
  101. package/dist/render/gpudriven/decodeTables.d.ts +64 -0
  102. package/dist/render/gpudriven/decodeTables.js +219 -0
  103. package/dist/render/gpudriven/frustum.d.ts +25 -0
  104. package/dist/render/gpudriven/frustum.js +59 -0
  105. package/dist/render/gpudriven/geometryHarness.d.ts +15 -0
  106. package/dist/render/gpudriven/geometryHarness.js +31 -0
  107. package/dist/render/gpudriven/hzb.d.ts +60 -0
  108. package/dist/render/gpudriven/hzb.js +97 -0
  109. package/dist/render/gpudriven/ibl.d.ts +85 -0
  110. package/dist/render/gpudriven/ibl.js +129 -0
  111. package/dist/render/gpudriven/indirect.d.ts +67 -0
  112. package/dist/render/gpudriven/indirect.js +77 -0
  113. package/dist/render/gpudriven/instances.d.ts +43 -0
  114. package/dist/render/gpudriven/instances.js +172 -0
  115. package/dist/render/gpudriven/lit.d.ts +165 -0
  116. package/dist/render/gpudriven/lit.js +165 -0
  117. package/dist/render/gpudriven/lodCut.d.ts +28 -0
  118. package/dist/render/gpudriven/lodCut.js +38 -0
  119. package/dist/render/gpudriven/materialBin.d.ts +60 -0
  120. package/dist/render/gpudriven/materialBin.js +108 -0
  121. package/dist/render/gpudriven/materialTable.d.ts +88 -0
  122. package/dist/render/gpudriven/materialTable.js +115 -0
  123. package/dist/render/gpudriven/pipeline.d.ts +135 -0
  124. package/dist/render/gpudriven/pipeline.js +237 -0
  125. package/dist/render/gpudriven/rangeAlloc.d.ts +50 -0
  126. package/dist/render/gpudriven/rangeAlloc.js +112 -0
  127. package/dist/render/gpudriven/sceneUpload.d.ts +96 -0
  128. package/dist/render/gpudriven/sceneUpload.js +115 -0
  129. package/dist/render/gpudriven/shadeBins.d.ts +92 -0
  130. package/dist/render/gpudriven/shadeBins.js +182 -0
  131. package/dist/render/gpudriven/shadow.d.ts +136 -0
  132. package/dist/render/gpudriven/shadow.js +224 -0
  133. package/dist/render/gpudriven/shadowCamera.d.ts +87 -0
  134. package/dist/render/gpudriven/shadowCamera.js +345 -0
  135. package/dist/render/gpudriven/streamScene.d.ts +194 -0
  136. package/dist/render/gpudriven/streamScene.js +459 -0
  137. package/dist/render/gpudriven/surfaceFrame.d.ts +25 -0
  138. package/dist/render/gpudriven/surfaceFrame.js +51 -0
  139. package/dist/render/gpudriven/twoPhase.d.ts +122 -0
  140. package/dist/render/gpudriven/twoPhase.js +160 -0
  141. package/dist/render/gpudriven/visbuffer.d.ts +25 -0
  142. package/dist/render/gpudriven/visbuffer.js +37 -0
  143. package/dist/render/halfFloat.d.ts +10 -0
  144. package/dist/render/halfFloat.js +23 -4
  145. package/dist/render/inference/attentionTiled.d.ts +27 -0
  146. package/dist/render/inference/attentionTiled.js +117 -0
  147. package/dist/render/inference/denseKernels.d.ts +29 -0
  148. package/dist/render/inference/denseKernels.js +312 -0
  149. package/dist/render/inference/device.d.ts +21 -0
  150. package/dist/render/inference/device.js +32 -0
  151. package/dist/render/inference/deviceGraph.d.ts +34 -0
  152. package/dist/render/inference/deviceGraph.js +17 -0
  153. package/dist/render/inference/fuse.d.ts +15 -0
  154. package/dist/render/inference/fuse.js +37 -0
  155. package/dist/render/inference/kernelKit.d.ts +52 -0
  156. package/dist/render/inference/kernelKit.js +70 -0
  157. package/dist/render/inference/kernels.d.ts +3 -0
  158. package/dist/render/inference/kernels.js +11 -0
  159. package/dist/render/inference/plan.d.ts +13 -0
  160. package/dist/render/inference/plan.js +18 -0
  161. package/dist/render/inference/reuse.d.ts +39 -0
  162. package/dist/render/inference/reuse.js +65 -0
  163. package/dist/render/inference/runner.d.ts +31 -0
  164. package/dist/render/inference/runner.js +175 -0
  165. package/dist/render/inference/schedule.d.ts +39 -0
  166. package/dist/render/inference/schedule.js +59 -0
  167. package/dist/render/inference/shapeKernels.d.ts +10 -0
  168. package/dist/render/inference/shapeKernels.js +80 -0
  169. package/dist/render/inference/spatialKernels.d.ts +21 -0
  170. package/dist/render/inference/spatialKernels.js +179 -0
  171. package/dist/render/inference/splatRaster.wgsl.d.ts +75 -0
  172. package/dist/render/inference/splatRaster.wgsl.js +337 -0
  173. package/dist/render/inference/splatTiles.d.ts +79 -0
  174. package/dist/render/inference/splatTiles.js +161 -0
  175. package/dist/render/lineBatch.d.ts +2 -5
  176. package/dist/render/lineBatch.js +4 -24
  177. package/dist/render/mesh.d.ts +4 -0
  178. package/dist/render/mesh.js +45 -1
  179. package/dist/render/pass.d.ts +145 -8
  180. package/dist/render/prefilterEnvMap.d.ts +22 -0
  181. package/dist/render/prefilterEnvMap.js +31 -0
  182. package/dist/render/readback.d.ts +30 -0
  183. package/dist/render/readback.js +47 -0
  184. package/dist/render/recon/clamp.d.ts +36 -0
  185. package/dist/render/recon/clamp.js +92 -0
  186. package/dist/render/recon/disocclusion.d.ts +60 -0
  187. package/dist/render/recon/disocclusion.js +109 -0
  188. package/dist/render/recon/frameGen.d.ts +81 -0
  189. package/dist/render/recon/frameGen.js +150 -0
  190. package/dist/render/recon/frameSizes.d.ts +34 -0
  191. package/dist/render/recon/frameSizes.js +58 -0
  192. package/dist/render/recon/jitter.d.ts +60 -0
  193. package/dist/render/recon/jitter.js +118 -0
  194. package/dist/render/recon/motionVectors.d.ts +55 -0
  195. package/dist/render/recon/motionVectors.js +107 -0
  196. package/dist/render/recon/reproject.d.ts +41 -0
  197. package/dist/render/recon/reproject.js +131 -0
  198. package/dist/render/recon/resolve.d.ts +90 -0
  199. package/dist/render/recon/resolve.js +313 -0
  200. package/dist/render/recon/tier.d.ts +24 -0
  201. package/dist/render/recon/tier.js +8 -0
  202. package/dist/render/reflectionProbe.d.ts +26 -0
  203. package/dist/render/reflectionProbe.js +33 -0
  204. package/dist/render/renderQuality.d.ts +69 -0
  205. package/dist/render/renderQuality.js +22 -0
  206. package/dist/render/screenSpaceReflection.d.ts +23 -0
  207. package/dist/render/screenSpaceReflection.js +22 -3
  208. package/dist/render/sdfFont.js +2 -0
  209. package/dist/render/segmentQuads.d.ts +13 -0
  210. package/dist/render/segmentQuads.js +32 -0
  211. package/dist/render/shaders/flat/lobes.d.ts +27 -0
  212. package/dist/render/shaders/flat/lobes.js +33 -3
  213. package/dist/render/shaders/flat/preamble.d.ts +7 -0
  214. package/dist/render/shaders/flat/preamble.js +24 -1
  215. package/dist/render/shaders/flat/probeGrid.d.ts +1 -1
  216. package/dist/render/shaders/flat/probeGrid.js +71 -2
  217. package/dist/render/shaders/generated/flat.wgsl.d.ts +48 -8
  218. package/dist/render/shaders/generated/flat.wgsl.js +64 -24
  219. package/dist/render/shaders/gi/composeField.wgsl.d.ts +56 -0
  220. package/dist/render/shaders/gi/composeField.wgsl.js +231 -0
  221. package/dist/render/shaders/gi/marchField.wgsl.d.ts +30 -0
  222. package/dist/render/shaders/gi/marchField.wgsl.js +141 -0
  223. package/dist/render/shaders/gi/probeBake.wgsl.d.ts +113 -0
  224. package/dist/render/shaders/gi/probeBake.wgsl.js +635 -0
  225. package/dist/render/shaders/gi/probeTrace.wgsl.d.ts +72 -0
  226. package/dist/render/shaders/gi/probeTrace.wgsl.js +261 -0
  227. package/dist/render/shaders/gi/probeVolume.wgsl.d.ts +49 -0
  228. package/dist/render/shaders/gi/probeVolume.wgsl.js +242 -0
  229. package/dist/render/shaders/gi/sampleField.wgsl.d.ts +32 -0
  230. package/dist/render/shaders/gi/sampleField.wgsl.js +134 -0
  231. package/dist/render/shaders/gpudriven/blendRaster.wgsl.d.ts +26 -0
  232. package/dist/render/shaders/gpudriven/blendRaster.wgsl.js +339 -0
  233. package/dist/render/shaders/gpudriven/compact.wgsl.d.ts +29 -0
  234. package/dist/render/shaders/gpudriven/compact.wgsl.js +58 -0
  235. package/dist/render/shaders/gpudriven/cull.wgsl.d.ts +90 -0
  236. package/dist/render/shaders/gpudriven/cull.wgsl.js +423 -0
  237. package/dist/render/shaders/gpudriven/decode.wgsl.d.ts +72 -0
  238. package/dist/render/shaders/gpudriven/decode.wgsl.js +349 -0
  239. package/dist/render/shaders/gpudriven/environment.wgsl.d.ts +44 -0
  240. package/dist/render/shaders/gpudriven/environment.wgsl.js +137 -0
  241. package/dist/render/shaders/gpudriven/fog.wgsl.d.ts +28 -0
  242. package/dist/render/shaders/gpudriven/fog.wgsl.js +107 -0
  243. package/dist/render/shaders/gpudriven/frameBlock.wgsl.d.ts +13 -0
  244. package/dist/render/shaders/gpudriven/frameBlock.wgsl.js +62 -0
  245. package/dist/render/shaders/gpudriven/materialBin.wgsl.d.ts +51 -0
  246. package/dist/render/shaders/gpudriven/materialBin.wgsl.js +112 -0
  247. package/dist/render/shaders/gpudriven/materialTable.wgsl.d.ts +25 -0
  248. package/dist/render/shaders/gpudriven/materialTable.wgsl.js +43 -0
  249. package/dist/render/shaders/gpudriven/meshTransform.wgsl.d.ts +18 -0
  250. package/dist/render/shaders/gpudriven/meshTransform.wgsl.js +37 -0
  251. package/dist/render/shaders/gpudriven/present.wgsl.d.ts +43 -0
  252. package/dist/render/shaders/gpudriven/present.wgsl.js +127 -0
  253. package/dist/render/shaders/gpudriven/shade.wgsl.d.ts +127 -0
  254. package/dist/render/shaders/gpudriven/shade.wgsl.js +874 -0
  255. package/dist/render/shaders/gpudriven/shadow.wgsl.d.ts +44 -0
  256. package/dist/render/shaders/gpudriven/shadow.wgsl.js +308 -0
  257. package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.d.ts +28 -0
  258. package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.js +245 -0
  259. package/dist/render/shaders/network.wgsl.d.ts +101 -0
  260. package/dist/render/shaders/network.wgsl.js +206 -0
  261. package/dist/render/shaders/recon/motion.wgsl.d.ts +44 -0
  262. package/dist/render/shaders/recon/motion.wgsl.js +96 -0
  263. package/dist/render/shaders/recon/resolve.wgsl.d.ts +51 -0
  264. package/dist/render/shaders/recon/resolve.wgsl.js +733 -0
  265. package/dist/render/temporalAa.js +8 -33
  266. package/dist/render/textLayout.js +12 -6
  267. package/dist/render/textRenderer.d.ts +3 -1
  268. package/dist/render/textRenderer.js +4 -1
  269. package/dist/render/translucentQueue.d.ts +6 -0
  270. package/dist/render/translucentQueue.js +11 -0
  271. package/dist/render/windStreakRenderer.d.ts +2 -1
  272. package/dist/render/windStreakRenderer.js +3 -1
  273. package/dist/world/cell.d.ts +63 -0
  274. package/dist/world/cell.js +181 -0
  275. package/dist/world/cellStream.d.ts +103 -0
  276. package/dist/world/cellStream.js +198 -0
  277. package/dist/world/freeze.d.ts +81 -0
  278. package/dist/world/freeze.js +114 -0
  279. package/dist/world/rebase.d.ts +29 -0
  280. package/dist/world/rebase.js +41 -0
  281. package/package.json +8 -3
  282. package/scripts/frames.mjs +92 -0
  283. package/scripts/gpuCompute.mjs +323 -0
  284. package/scripts/png.d.mts +16 -0
  285. package/scripts/png.mjs +25 -0
  286. package/src/core/loop.ts +19 -2
  287. package/src/core/storage.ts +5 -0
  288. package/src/geometry/meshBuilder.ts +5 -1
  289. package/src/index.ts +246 -4
  290. package/src/input/input.ts +6 -1
  291. package/src/math/exact.ts +69 -3
  292. package/src/math/frustum.ts +52 -3
  293. package/src/render/backend/api.ts +42 -1
  294. package/src/render/backend/budget.ts +7 -6
  295. package/src/render/backend/createRenderer.ts +92 -3
  296. package/src/render/backend/materialChanges.ts +54 -0
  297. package/src/render/backend/select.ts +8 -0
  298. package/src/render/backend/webgl2/renderer.ts +211 -9
  299. package/src/render/backend/webgpu/buffers.ts +182 -69
  300. package/src/render/backend/webgpu/fieldCompose.ts +482 -0
  301. package/src/render/backend/webgpu/giFieldPass.ts +200 -0
  302. package/src/render/backend/webgpu/gpuDrivenPass.ts +2993 -0
  303. package/src/render/backend/webgpu/linePass.ts +4 -39
  304. package/src/render/backend/webgpu/probeBake.ts +588 -0
  305. package/src/render/backend/webgpu/renderer.ts +1481 -76
  306. package/src/render/backend/webgpu/scatterPass.ts +15 -1
  307. package/src/render/backend/webgpu/surfaceTexturePass.ts +63 -36
  308. package/src/render/causticsRenderer.ts +5 -2
  309. package/src/render/depthConvention.ts +15 -0
  310. package/src/render/deviceFeatures.ts +77 -0
  311. package/src/render/fog.ts +185 -0
  312. package/src/render/frame/alias.ts +97 -0
  313. package/src/render/frame/deps.ts +155 -0
  314. package/src/render/frame/flushGraph.ts +135 -0
  315. package/src/render/frame/graphSchedule.ts +170 -0
  316. package/src/render/frame/index.ts +52 -0
  317. package/src/render/frame/lifetime.ts +61 -0
  318. package/src/render/frame/passTimings.ts +69 -0
  319. package/src/render/frame/validate.ts +40 -0
  320. package/src/render/frame/virtual.ts +91 -0
  321. package/src/render/gi/chain.ts +225 -0
  322. package/src/render/gi/denoise.ts +276 -0
  323. package/src/render/gi/fieldScene.ts +264 -0
  324. package/src/render/gi/globalField.ts +543 -0
  325. package/src/render/gi/probeGridFit.ts +89 -0
  326. package/src/render/gi/probeTrace.ts +143 -0
  327. package/src/render/gi/probeVolume.ts +288 -0
  328. package/src/render/gi/reflection.ts +163 -0
  329. package/src/render/gi/traceField.ts +223 -0
  330. package/src/render/gi/traceScreen.ts +106 -0
  331. package/src/render/gpuScene.ts +80 -0
  332. package/src/render/gpudriven/alphaTest.ts +33 -0
  333. package/src/render/gpudriven/clusterUpload.ts +123 -0
  334. package/src/render/gpudriven/clusterWorld.ts +239 -0
  335. package/src/render/gpudriven/compact.ts +80 -0
  336. package/src/render/gpudriven/cullClusters.ts +333 -0
  337. package/src/render/gpudriven/decodeTables.ts +332 -0
  338. package/src/render/gpudriven/frustum.ts +70 -0
  339. package/src/render/gpudriven/geometryHarness.ts +51 -0
  340. package/src/render/gpudriven/hzb.ts +113 -0
  341. package/src/render/gpudriven/ibl.ts +147 -0
  342. package/src/render/gpudriven/indirect.ts +89 -0
  343. package/src/render/gpudriven/instances.ts +234 -0
  344. package/src/render/gpudriven/lit.ts +329 -0
  345. package/src/render/gpudriven/lodCut.ts +62 -0
  346. package/src/render/gpudriven/materialBin.ts +131 -0
  347. package/src/render/gpudriven/materialTable.ts +164 -0
  348. package/src/render/gpudriven/pipeline.ts +336 -0
  349. package/src/render/gpudriven/rangeAlloc.ts +122 -0
  350. package/src/render/gpudriven/sceneUpload.ts +173 -0
  351. package/src/render/gpudriven/shadeBins.ts +222 -0
  352. package/src/render/gpudriven/shadow.ts +285 -0
  353. package/src/render/gpudriven/shadowCamera.ts +406 -0
  354. package/src/render/gpudriven/streamScene.ts +575 -0
  355. package/src/render/gpudriven/surfaceFrame.ts +68 -0
  356. package/src/render/gpudriven/twoPhase.ts +214 -0
  357. package/src/render/gpudriven/visbuffer.ts +41 -0
  358. package/src/render/halfFloat.ts +22 -4
  359. package/src/render/inference/attentionTiled.ts +132 -0
  360. package/src/render/inference/denseKernels.ts +369 -0
  361. package/src/render/inference/device.ts +44 -0
  362. package/src/render/inference/deviceGraph.ts +39 -0
  363. package/src/render/inference/fuse.ts +47 -0
  364. package/src/render/inference/kernelKit.ts +120 -0
  365. package/src/render/inference/kernels.ts +18 -0
  366. package/src/render/inference/plan.ts +26 -0
  367. package/src/render/inference/reuse.ts +79 -0
  368. package/src/render/inference/runner.ts +204 -0
  369. package/src/render/inference/schedule.ts +80 -0
  370. package/src/render/inference/shapeKernels.ts +112 -0
  371. package/src/render/inference/spatialKernels.ts +220 -0
  372. package/src/render/inference/splatRaster.wgsl.ts +348 -0
  373. package/src/render/inference/splatTiles.ts +186 -0
  374. package/src/render/lineBatch.ts +4 -24
  375. package/src/render/mesh.ts +46 -1
  376. package/src/render/pass.ts +155 -10
  377. package/src/render/prefilterEnvMap.ts +33 -0
  378. package/src/render/readback.ts +73 -0
  379. package/src/render/recon/clamp.ts +113 -0
  380. package/src/render/recon/disocclusion.ts +143 -0
  381. package/src/render/recon/frameGen.ts +191 -0
  382. package/src/render/recon/frameSizes.ts +64 -0
  383. package/src/render/recon/jitter.ts +126 -0
  384. package/src/render/recon/motionVectors.ts +138 -0
  385. package/src/render/recon/reproject.ts +179 -0
  386. package/src/render/recon/resolve.ts +444 -0
  387. package/src/render/recon/tier.ts +31 -0
  388. package/src/render/reflectionProbe.ts +34 -0
  389. package/src/render/renderQuality.ts +87 -0
  390. package/src/render/screenSpaceReflection.ts +37 -3
  391. package/src/render/sdfFont.ts +2 -0
  392. package/src/render/segmentQuads.ts +39 -0
  393. package/src/render/shaders/flat/lobes.ts +35 -3
  394. package/src/render/shaders/flat/preamble.ts +25 -1
  395. package/src/render/shaders/flat/probeGrid.ts +77 -2
  396. package/src/render/shaders/generated/flat.wgsl.ts +64 -24
  397. package/src/render/shaders/gi/composeField.wgsl.ts +239 -0
  398. package/src/render/shaders/gi/marchField.wgsl.ts +146 -0
  399. package/src/render/shaders/gi/probeBake.wgsl.ts +649 -0
  400. package/src/render/shaders/gi/probeTrace.wgsl.ts +269 -0
  401. package/src/render/shaders/gi/probeVolume.wgsl.ts +246 -0
  402. package/src/render/shaders/gi/sampleField.wgsl.ts +140 -0
  403. package/src/render/shaders/gpudriven/blendRaster.wgsl.ts +343 -0
  404. package/src/render/shaders/gpudriven/compact.wgsl.ts +59 -0
  405. package/src/render/shaders/gpudriven/cull.wgsl.ts +433 -0
  406. package/src/render/shaders/gpudriven/decode.wgsl.ts +373 -0
  407. package/src/render/shaders/gpudriven/environment.wgsl.ts +141 -0
  408. package/src/render/shaders/gpudriven/fog.wgsl.ts +110 -0
  409. package/src/render/shaders/gpudriven/frameBlock.wgsl.ts +62 -0
  410. package/src/render/shaders/gpudriven/materialBin.wgsl.ts +116 -0
  411. package/src/render/shaders/gpudriven/materialTable.wgsl.ts +46 -0
  412. package/src/render/shaders/gpudriven/meshTransform.wgsl.ts +37 -0
  413. package/src/render/shaders/gpudriven/present.wgsl.ts +129 -0
  414. package/src/render/shaders/gpudriven/shade.wgsl.ts +884 -0
  415. package/src/render/shaders/gpudriven/shadow.wgsl.ts +322 -0
  416. package/src/render/shaders/gpudriven/visbufferRaster.wgsl.ts +251 -0
  417. package/src/render/shaders/network.wgsl.ts +238 -0
  418. package/src/render/shaders/recon/motion.wgsl.ts +101 -0
  419. package/src/render/shaders/recon/resolve.wgsl.ts +741 -0
  420. package/src/render/temporalAa.ts +9 -33
  421. package/src/render/textLayout.ts +12 -6
  422. package/src/render/textRenderer.ts +5 -2
  423. package/src/render/translucentQueue.ts +11 -0
  424. package/src/render/windStreakRenderer.ts +4 -2
  425. package/src/world/cell.ts +231 -0
  426. package/src/world/cellStream.ts +278 -0
  427. package/src/world/freeze.ts +157 -0
  428. package/src/world/rebase.ts +56 -0
@@ -0,0 +1,155 @@
1
+ /**
2
+ * What each node reads and writes, when there are too many resources for a mask.
3
+ *
4
+ * One flat identifier store with a span per node, which is the same shape `nav/navGraph.ts` uses
5
+ * for adjacency and for the same reason: the spans are written once in order and read many
6
+ * times, so an offset and a length beat an array per node by every measure that matters here.
7
+ *
8
+ * `readsOf` and `writesOf` return **views into the store**, not copies. A caller that keeps one
9
+ * past the next `resetDeps` is reading somebody else's edges, which is why neither is exposed
10
+ * outside `render/`.
11
+ */
12
+ export interface Deps {
13
+ /** Every read identifier then every write identifier, node by node. */
14
+ edges: Int32Array;
15
+ /** Four entries per node: read offset, read length, write offset, write length. */
16
+ spans: Int32Array;
17
+ /** How many identifiers of `edges` are in use. */
18
+ used: number;
19
+ /** How many nodes have been recorded. */
20
+ count: number;
21
+ }
22
+
23
+ const SPAN_STRIDE = 4;
24
+
25
+ export function createDeps(nodeCapacity: number, edgeCapacity: number): Deps {
26
+ return {
27
+ edges: new Int32Array(edgeCapacity),
28
+ spans: new Int32Array(nodeCapacity * SPAN_STRIDE),
29
+ used: 0,
30
+ count: 0,
31
+ };
32
+ }
33
+
34
+ export function resetDeps(deps: Deps): void {
35
+ deps.used = 0;
36
+ deps.count = 0;
37
+ }
38
+
39
+ export function depsNodeCount(deps: Deps): number {
40
+ return deps.count;
41
+ }
42
+
43
+ function growEdges(deps: Deps, need: number): void {
44
+ let size = deps.edges.length === 0 ? 16 : deps.edges.length;
45
+ while (size < need) size *= 2;
46
+ const edges = new Int32Array(size);
47
+ edges.set(deps.edges);
48
+ deps.edges = edges;
49
+ }
50
+
51
+ function growSpans(deps: Deps): void {
52
+ const size = deps.spans.length === 0 ? SPAN_STRIDE * 8 : deps.spans.length * 2;
53
+ const spans = new Int32Array(size);
54
+ spans.set(deps.spans);
55
+ deps.spans = spans;
56
+ }
57
+
58
+ /*
59
+ * Both stores are grown before either span is written. Growing between the read span and the
60
+ * write span would copy a half-written node and silently drop its writes, which is the defect
61
+ * the growth test in this module's suite exists to catch.
62
+ */
63
+ export function recordDeps(
64
+ deps: Deps,
65
+ reads: readonly number[],
66
+ writes: readonly number[],
67
+ ): number {
68
+ const need = deps.used + reads.length + writes.length;
69
+ if (need > deps.edges.length) growEdges(deps, need);
70
+ if ((deps.count + 1) * SPAN_STRIDE > deps.spans.length) growSpans(deps);
71
+
72
+ const readAt = deps.used;
73
+ for (let i = 0; i < reads.length; i += 1) deps.edges[deps.used + i] = reads[i] ?? 0;
74
+ deps.used += reads.length;
75
+
76
+ const writeAt = deps.used;
77
+ for (let i = 0; i < writes.length; i += 1) deps.edges[deps.used + i] = writes[i] ?? 0;
78
+ deps.used += writes.length;
79
+
80
+ const node = deps.count;
81
+ const base = node * SPAN_STRIDE;
82
+ deps.spans[base] = readAt;
83
+ deps.spans[base + 1] = reads.length;
84
+ deps.spans[base + 2] = writeAt;
85
+ deps.spans[base + 3] = writes.length;
86
+ deps.count = node + 1;
87
+ return node;
88
+ }
89
+
90
+ /*
91
+ * Count the bits of a mask, which is how many identifiers it becomes.
92
+ *
93
+ * Kernighan's loop rather than a table: a mask here has at most `RESOURCE_COUNT` bits and usually
94
+ * two, so this runs once or twice.
95
+ */
96
+ function bitCount(mask: number): number {
97
+ let count = 0;
98
+ for (let rest = mask >>> 0; rest !== 0; rest &= rest - 1) count += 1;
99
+ return count;
100
+ }
101
+
102
+ function writeBits(deps: Deps, mask: number, at: number): void {
103
+ let offset = at;
104
+ for (let bit = 0, rest = mask >>> 0; rest !== 0; bit += 1, rest >>>= 1) {
105
+ if ((rest & 1) === 0) continue;
106
+ deps.edges[offset] = bit;
107
+ offset += 1;
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Record a node whose reads and writes are masks, one identifier per set bit, lowest first.
113
+ *
114
+ * **What lets a fixed-composition flush be scheduled by identifiers without building a list.** The
115
+ * forward renderer records masks, and `recordDeps` takes arrays; a flush converting one to the
116
+ * other through arrays would allocate per node, on the path `AGENTS.md` forbids it on. Bit `n`
117
+ * is identifier `n`, so `FRAME_RESOURCES` is the first `RESOURCE_COUNT` identifiers of any frame
118
+ * that mixes the two.
119
+ */
120
+ export function recordMaskDeps(deps: Deps, reads: number, writes: number): number {
121
+ const readCount = bitCount(reads);
122
+ const writeCount = bitCount(writes);
123
+ const need = deps.used + readCount + writeCount;
124
+ if (need > deps.edges.length) growEdges(deps, need);
125
+ if ((deps.count + 1) * SPAN_STRIDE > deps.spans.length) growSpans(deps);
126
+
127
+ const readAt = deps.used;
128
+ writeBits(deps, reads, readAt);
129
+ const writeAt = readAt + readCount;
130
+ writeBits(deps, writes, writeAt);
131
+ deps.used = writeAt + writeCount;
132
+
133
+ const node = deps.count;
134
+ const base = node * SPAN_STRIDE;
135
+ deps.spans[base] = readAt;
136
+ deps.spans[base + 1] = readCount;
137
+ deps.spans[base + 2] = writeAt;
138
+ deps.spans[base + 3] = writeCount;
139
+ deps.count = node + 1;
140
+ return node;
141
+ }
142
+
143
+ export function readsOf(deps: Deps, node: number): Int32Array {
144
+ const base = node * SPAN_STRIDE;
145
+ const at = deps.spans[base] ?? 0;
146
+ const length = deps.spans[base + 1] ?? 0;
147
+ return deps.edges.subarray(at, at + length);
148
+ }
149
+
150
+ export function writesOf(deps: Deps, node: number): Int32Array {
151
+ const base = node * SPAN_STRIDE;
152
+ const at = deps.spans[base + 2] ?? 0;
153
+ const length = deps.spans[base + 3] ?? 0;
154
+ return deps.edges.subarray(at, at + length);
155
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * A forward flush, scheduled by the identifier graph instead of by masks.
3
+ *
4
+ * **Wave 1A's exit criterion is that both pipelines are expressible in one graph and today's frames
5
+ * are pixel-identical through it.** The second pipeline records its stages into a `Deps` table
6
+ * (`gpudriven/pipeline.ts`); this is the forward renderer's half. A flush's arena is recorded as
7
+ * identifier nodes — bit `n` of a mask is identifier `n` — scheduled by `scheduleGraph`, and the
8
+ * load and store each attachment gets are derived from `lifetime.ts`. What comes out is the same
9
+ * `ScheduledPass` the mask scheduler writes, so the executor reading it does not know which ran.
10
+ *
11
+ * **One difference, and the renderer never reaches it.** Culling here is transitive: a pass whose
12
+ * only reader was dropped is dropped too, where `schedule.ts` keeps it. Every node the renderer
13
+ * records writes something its live set holds, so no flush it makes has a dropped reader —
14
+ * `flushGraph.test.ts` holds a random corpus of its own shapes to exact agreement and names the
15
+ * frame where the two part.
16
+ *
17
+ * Allocates nothing once warm. The state is the caller's and grows only when a flush outgrows it,
18
+ * the way the arena does.
19
+ */
20
+ import type { Arena } from './arena.ts';
21
+ import { nodeCount, nodeReads, nodeWrites } from './arena.ts';
22
+ import type { Deps } from './deps.ts';
23
+ import { createDeps, recordMaskDeps, resetDeps } from './deps.ts';
24
+ import type { GraphPass, GraphScratch } from './graphSchedule.ts';
25
+ import { createGraphPasses, createGraphScratch, scheduleGraph } from './graphSchedule.ts';
26
+ import type { Lifetimes } from './lifetime.ts';
27
+ import { computeLifetimes, createLifetimes, lastRead } from './lifetime.ts';
28
+ import { RESOURCE_COUNT } from './resources.ts';
29
+ import type { ScheduledPass } from './schedule.ts';
30
+
31
+ export interface FlushSchedule {
32
+ deps: Deps;
33
+ scratch: GraphScratch;
34
+ passes: GraphPass[];
35
+ lifetimes: Lifetimes;
36
+ /** Every node ordered: a forward draw's position is its meaning. Grown with the arena. */
37
+ ordered: Uint8Array;
38
+ /** The live identifiers of this flush, and how many of them there are. */
39
+ live: Int32Array;
40
+ liveCount: number;
41
+ }
42
+
43
+ export function createFlushSchedule(capacity: number): FlushSchedule {
44
+ const nodes = Math.max(1, capacity);
45
+ return {
46
+ deps: createDeps(nodes, nodes * 4),
47
+ scratch: createGraphScratch(nodes, RESOURCE_COUNT),
48
+ passes: createGraphPasses(nodes),
49
+ lifetimes: createLifetimes(RESOURCE_COUNT),
50
+ ordered: new Uint8Array(nodes).fill(1),
51
+ live: new Int32Array(RESOURCE_COUNT),
52
+ liveCount: 0,
53
+ };
54
+ }
55
+
56
+ /* Grown where allocation is allowed: a flush larger than any before it, once. */
57
+ function fit(state: FlushSchedule, nodes: number): void {
58
+ if (state.ordered.length < nodes) {
59
+ const size = Math.max(nodes, state.ordered.length * 2);
60
+ state.ordered = new Uint8Array(size).fill(1);
61
+ while (state.passes.length < size) state.passes.push({ first: 0, count: 0, ordered: true });
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Schedule an arena's nodes through the identifier graph, into the mask scheduler's records.
67
+ *
68
+ * `clearMask` and `liveOut` mean what they mean to `schedule`: what this flush still owes a clear,
69
+ * and what must survive it. Returns how many of `out` were filled.
70
+ */
71
+ export function scheduleFlush(
72
+ arena: Arena,
73
+ clearMask: number,
74
+ liveOut: number,
75
+ state: FlushSchedule,
76
+ out: ScheduledPass[],
77
+ ): number {
78
+ const total = nodeCount(arena);
79
+ if (total === 0) return 0;
80
+ fit(state, total);
81
+
82
+ const deps = state.deps;
83
+ resetDeps(deps);
84
+ for (let node = 0; node < total; node += 1) {
85
+ recordMaskDeps(deps, nodeReads(arena, node), nodeWrites(arena, node));
86
+ }
87
+
88
+ state.liveCount = 0;
89
+ for (let bit = 0; bit < RESOURCE_COUNT; bit += 1) {
90
+ if ((liveOut & (1 << bit)) === 0) continue;
91
+ state.live[state.liveCount] = bit;
92
+ state.liveCount += 1;
93
+ }
94
+
95
+ const scheduled = scheduleGraph(
96
+ deps,
97
+ total,
98
+ state.live,
99
+ state.ordered,
100
+ state.passes,
101
+ state.scratch,
102
+ state.liveCount,
103
+ );
104
+ computeLifetimes(deps, total, state.lifetimes);
105
+
106
+ let filled = 0;
107
+ let cleared = 0;
108
+ for (let p = 0; p < scheduled; p += 1) {
109
+ const pass = state.passes[p] as GraphPass;
110
+ const record = out[filled];
111
+ if (record === undefined) return filled;
112
+ /* An ordered run shares one write set, so its first node's mask is the run's. */
113
+ const writes = nodeWrites(arena, pass.first);
114
+ const end = pass.first + pass.count;
115
+ /*
116
+ * Discardable where nothing at or after the run's end reads it and nothing outside the flush
117
+ * does either. `lastRead` is the last reader anywhere in the flush, culled or not, which is the
118
+ * mask scheduler's rule: a dropped pass's read still happened as far as a store op knows.
119
+ */
120
+ let discard = 0;
121
+ for (let bit = 0; bit < RESOURCE_COUNT; bit += 1) {
122
+ const mask = 1 << bit;
123
+ if ((writes & mask) === 0 || (liveOut & mask) !== 0) continue;
124
+ if (lastRead(state.lifetimes, bit) < end) discard |= mask;
125
+ }
126
+ record.writes = writes;
127
+ record.first = pass.first;
128
+ record.count = pass.count;
129
+ record.clear = clearMask & writes & ~cleared;
130
+ record.discard = discard;
131
+ cleared |= writes;
132
+ filled += 1;
133
+ }
134
+ return filled;
135
+ }
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Grouping and culling for a frame whose composition is not fixed.
3
+ *
4
+ * **`schedule.ts` is not replaced.** It schedules the forward path, where the composition is
5
+ * fixed and a mask is exactly right, and it stays. This is its counterpart for the other path,
6
+ * and the two differences are the whole reason it exists.
7
+ *
8
+ * **Culling is transitive here and is not there.** The mask scheduler drops a pass whose writes
9
+ * nothing later reads. Once it has, the pass whose only reader was the dropped one has become
10
+ * dead too — and a single backward scan over masks never revisits it. A GPU-driven frame makes
11
+ * that ordinary rather than exotic, because turning off one quality flag kills a consumer
12
+ * several passes downstream. So liveness is propagated backwards to a fixed point first, and
13
+ * grouping runs over what survives.
14
+ *
15
+ * **Some nodes may be reordered and most may not.** A node marked ordered carries meaning in its
16
+ * position — blending and depth make *after* different from *before*, which is the rule
17
+ * `schedule.ts` states and this does not weaken. An unordered node is a compute dispatch whose
18
+ * result depends only on its declared reads, and two adjacent ones may merge whatever they write.
19
+ */
20
+ import type { Deps } from './deps.ts';
21
+ import { readsOf, writesOf } from './deps.ts';
22
+
23
+ export interface GraphPass {
24
+ /** Index of the first node in the run. */
25
+ first: number;
26
+ /** How many nodes the run holds. */
27
+ count: number;
28
+ /** Whether this pass's position carries meaning. */
29
+ ordered: boolean;
30
+ }
31
+
32
+ export function createGraphPasses(capacity: number): GraphPass[] {
33
+ return Array.from({ length: capacity }, () => ({ first: 0, count: 0, ordered: true }));
34
+ }
35
+
36
+ /**
37
+ * What a schedule works in, owned by the caller so a flush allocates nothing.
38
+ *
39
+ * `keep` is a flag a node and `wanted` a flag an identifier. Both are cleared at the start of every
40
+ * call, so a scratch carried from one frame to the next answers exactly as a fresh one would.
41
+ */
42
+ export interface GraphScratch {
43
+ keep: Uint8Array;
44
+ wanted: Uint8Array;
45
+ }
46
+
47
+ export function createGraphScratch(nodes: number, identifiers: number): GraphScratch {
48
+ return {
49
+ keep: new Uint8Array(Math.max(1, nodes)),
50
+ wanted: new Uint8Array(Math.max(1, identifiers)),
51
+ };
52
+ }
53
+
54
+ /*
55
+ * Make the scratch big enough for this frame, which is the one place it may allocate.
56
+ *
57
+ * A frame that outgrows it has to be scheduled somehow, and growing here once is what the arena
58
+ * does too; the scratch the caller keeps is then large enough for every frame like it. Doubled, so
59
+ * a frame that grows by one node at a time does not reallocate every frame.
60
+ */
61
+ function fitScratch(scratch: GraphScratch, deps: Deps, count: number): void {
62
+ if (scratch.keep.length < count) {
63
+ scratch.keep = new Uint8Array(Math.max(count, scratch.keep.length * 2));
64
+ }
65
+ let ceiling = 0;
66
+ for (let i = 0; i < deps.used; i += 1) ceiling = Math.max(ceiling, (deps.edges[i] ?? 0) + 1);
67
+ if (scratch.wanted.length < ceiling) {
68
+ scratch.wanted = new Uint8Array(Math.max(ceiling, scratch.wanted.length * 2));
69
+ }
70
+ }
71
+
72
+ /*
73
+ * Mark every node that contributes to something in `live`, to a fixed point.
74
+ *
75
+ * Backwards, because a node is needed exactly when something after it reads what it writes. One
76
+ * backward sweep suffices for a chain; the outer repeat covers a node that writes a resource
77
+ * read by an earlier-indexed node, which cannot happen in a well-formed frame but costs one
78
+ * comparison to be safe about rather than one silently wrong picture to discover.
79
+ *
80
+ * `fitScratch` sized both flags for everything recorded, and this relies on it: a keep flag past
81
+ * the end of `keep` would read 0 after being set, and the sweep would never settle.
82
+ */
83
+ function markLive(
84
+ deps: Deps,
85
+ count: number,
86
+ live: ArrayLike<number>,
87
+ liveCount: number,
88
+ scratch: GraphScratch,
89
+ ): void {
90
+ const { keep, wanted } = scratch;
91
+ keep.fill(0, 0, count);
92
+ wanted.fill(0);
93
+ /* A live identifier past the end is one no node writes, and a typed array ignores the write. */
94
+ for (let i = 0; i < liveCount; i += 1) wanted[live[i] ?? -1] = 1;
95
+ let changed = true;
96
+ while (changed) {
97
+ changed = false;
98
+ for (let node = count - 1; node >= 0; node -= 1) {
99
+ if (keep[node] === 1) continue;
100
+ const writes = writesOf(deps, node);
101
+ let needed = false;
102
+ for (let i = 0; i < writes.length; i += 1) {
103
+ if (wanted[writes[i] ?? 0] === 1) {
104
+ needed = true;
105
+ break;
106
+ }
107
+ }
108
+ if (!needed) continue;
109
+ keep[node] = 1;
110
+ changed = true;
111
+ const reads = readsOf(deps, node);
112
+ for (let i = 0; i < reads.length; i += 1) wanted[reads[i] ?? 0] = 1;
113
+ }
114
+ }
115
+ }
116
+
117
+ function sameWrites(deps: Deps, a: number, b: number): boolean {
118
+ const left = writesOf(deps, a);
119
+ const right = writesOf(deps, b);
120
+ if (left.length !== right.length) return false;
121
+ for (let i = 0; i < left.length; i += 1) if (left[i] !== right[i]) return false;
122
+ return true;
123
+ }
124
+
125
+ /**
126
+ * Group the live nodes of a frame into passes, and answer how many of `out` were filled.
127
+ *
128
+ * `live` is what must survive the frame, and only its first `liveCount` entries are read — so a
129
+ * caller can keep one typed array and a count rather than build a list. `scratch` is the working
130
+ * set; a caller that passes none gets one made for the call, which is what a test wants and what a
131
+ * frame must not do.
132
+ */
133
+ export function scheduleGraph(
134
+ deps: Deps,
135
+ count: number,
136
+ live: ArrayLike<number>,
137
+ ordered: Uint8Array,
138
+ out: GraphPass[],
139
+ scratch: GraphScratch = createGraphScratch(count, 1),
140
+ liveCount: number = live.length,
141
+ ): number {
142
+ fitScratch(scratch, deps, count);
143
+ markLive(deps, count, live, liveCount, scratch);
144
+ const keep = scratch.keep;
145
+
146
+ let passes = 0;
147
+ let at = 0;
148
+ while (at < count) {
149
+ if (keep[at] === 0) {
150
+ at += 1;
151
+ continue;
152
+ }
153
+ const isOrdered = ordered[at] === 1;
154
+ let end = at + 1;
155
+ while (end < count && keep[end] === 1) {
156
+ const nextOrdered = ordered[end] === 1;
157
+ if (isOrdered !== nextOrdered) break;
158
+ if (isOrdered && !sameWrites(deps, at, end)) break;
159
+ end += 1;
160
+ }
161
+ const pass = out[passes];
162
+ if (pass === undefined) return passes;
163
+ pass.first = at;
164
+ pass.count = end - at;
165
+ pass.ordered = isOrdered;
166
+ passes += 1;
167
+ at = end;
168
+ }
169
+ return passes;
170
+ }
@@ -27,3 +27,55 @@ export {
27
27
  export type { ScheduledPass } from './schedule.ts';
28
28
  export { schedule } from './schedule.ts';
29
29
  export { keptNodes, scratchFor } from './replay.ts';
30
+
31
+ /*
32
+ * The identifier-addressed half, for a frame whose composition is not fixed. See `virtual.ts`
33
+ * for why there are two representations and why neither converts into the other.
34
+ */
35
+ export type {
36
+ VirtualBufferDesc,
37
+ VirtualDesc,
38
+ VirtualTable,
39
+ VirtualTextureDesc,
40
+ } from './virtual.ts';
41
+ export {
42
+ createVirtualTable,
43
+ declareVirtual,
44
+ resetVirtualTable,
45
+ virtualBytes,
46
+ virtualCount,
47
+ virtualKind,
48
+ } from './virtual.ts';
49
+ export type { Deps } from './deps.ts';
50
+ export {
51
+ createDeps,
52
+ depsNodeCount,
53
+ readsOf,
54
+ recordDeps,
55
+ recordMaskDeps,
56
+ resetDeps,
57
+ writesOf,
58
+ } from './deps.ts';
59
+ export type { Lifetimes } from './lifetime.ts';
60
+ export { computeLifetimes, createLifetimes, firstWrite, lastRead } from './lifetime.ts';
61
+ export type { AliasPlan } from './alias.ts';
62
+ export { createAliasPlan, offsetOf, planAliases } from './alias.ts';
63
+ export type { GraphPass, GraphScratch } from './graphSchedule.ts';
64
+ export { createGraphPasses, createGraphScratch, scheduleGraph } from './graphSchedule.ts';
65
+ export type { FlushSchedule } from './flushGraph.ts';
66
+ export { createFlushSchedule, scheduleFlush } from './flushGraph.ts';
67
+ export { validateGraph } from './validate.ts';
68
+
69
+ /*
70
+ * Per-pass timings, which are the one thing here that *is* on the package barrel — see the note
71
+ * beside its export in `src/index.ts`. A readout is not the graph.
72
+ */
73
+ export type { PassTimings } from './passTimings.ts';
74
+ export {
75
+ createPassTimings,
76
+ passLabel,
77
+ passMs,
78
+ recordPassLabel,
79
+ recordPassSample,
80
+ resetPassTimings,
81
+ } from './passTimings.ts';
@@ -0,0 +1,61 @@
1
+ /**
2
+ * When each transient resource is first written and last read.
3
+ *
4
+ * Two numbers per identifier and one pass over the nodes, which is all the aliasing allocator
5
+ * needs and is deliberately less than a general dependency graph would compute. There is no
6
+ * topological sort here because there is no reordering here: the node order is the caller's,
7
+ * exactly as `schedule.ts` requires for the fixed path and for the same reason — blending and
8
+ * depth make *after* different from *before*.
9
+ *
10
+ * **A resource written and never read still has a lifetime**, ending at the node that writes
11
+ * it. It has to: memory it is being written into cannot be handed to something else at the same
12
+ * moment. Reporting an empty lifetime there is the bug this module's third test exists to catch.
13
+ */
14
+ import type { Deps } from './deps.ts';
15
+ import { readsOf, writesOf } from './deps.ts';
16
+
17
+ export interface Lifetimes {
18
+ /** Node index of the first write per identifier, or -1. */
19
+ first: Int32Array;
20
+ /** Node index of the last read per identifier, or the first write when nothing reads it. */
21
+ last: Int32Array;
22
+ }
23
+
24
+ export function createLifetimes(capacity: number): Lifetimes {
25
+ return { first: new Int32Array(capacity), last: new Int32Array(capacity) };
26
+ }
27
+
28
+ export function computeLifetimes(deps: Deps, count: number, out: Lifetimes): void {
29
+ out.first.fill(-1);
30
+ out.last.fill(-1);
31
+
32
+ for (let node = 0; node < count; node += 1) {
33
+ const writes = writesOf(deps, node);
34
+ for (let i = 0; i < writes.length; i += 1) {
35
+ const id = writes[i] ?? 0;
36
+ if (out.first[id] === -1) {
37
+ out.first[id] = node;
38
+ out.last[id] = node;
39
+ }
40
+ }
41
+ /*
42
+ * Reads are folded in after this node's writes, so a node that reads and writes the same
43
+ * identifier extends the lifetime rather than starting a second one. A read of something
44
+ * nothing has written is ignored here and refused by `validate.ts`, which is where a
45
+ * malformed frame belongs.
46
+ */
47
+ const reads = readsOf(deps, node);
48
+ for (let i = 0; i < reads.length; i += 1) {
49
+ const id = reads[i] ?? 0;
50
+ if (out.first[id] !== -1) out.last[id] = node;
51
+ }
52
+ }
53
+ }
54
+
55
+ export function firstWrite(out: Lifetimes, id: number): number {
56
+ return out.first[id] ?? -1;
57
+ }
58
+
59
+ export function lastRead(out: Lifetimes, id: number): number {
60
+ return out.last[id] ?? -1;
61
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Where a frame's milliseconds went, one row per graph pass.
3
+ *
4
+ * **Not a widening of `gpuTimer.ts`, and that is deliberate.** That class is a WebGL2 query pool
5
+ * over `TIME_ELAPSED_EXT`, partitioning a frame into three fixed brackets — shadows, reflection,
6
+ * rest — and it is right for what it measures. A graph pass is not one of three brackets: there
7
+ * are as many as the frame composes, they are named at record time, and on WebGPU the sample
8
+ * comes from a timestamp query rather than an elapsed-time extension. Two different measurements
9
+ * with two different shapes; widening one into the other would leave a class that does neither
10
+ * well.
11
+ *
12
+ * **What it does inherit from that class is its best rule: unmeasured is not zero.** A device
13
+ * without timestamp queries, or a pass that ran no work, must not read as "took no time" — a
14
+ * profiler that cannot distinguish those two is a profiler that sends somebody optimising a pass
15
+ * that never ran. `passMs` returns null for unmeasured and a number for measured, including zero.
16
+ *
17
+ * **Labels persist and timings reset.** A pass that did nothing this frame keeps its name and
18
+ * reports unmeasured, so the profiler's rows stop jumping about as quality settings toggle
19
+ * passes on and off — which is exactly when somebody is reading it.
20
+ */
21
+ export interface PassTimings {
22
+ /** Accumulated milliseconds per pass for the current frame. */
23
+ ms: Float64Array;
24
+ /** Whether each pass received a sample this frame. */
25
+ measured: Uint8Array;
26
+ /** Name per pass, kept across frames. */
27
+ labels: string[];
28
+ }
29
+
30
+ export function createPassTimings(capacity: number): PassTimings {
31
+ return {
32
+ ms: new Float64Array(capacity),
33
+ measured: new Uint8Array(capacity),
34
+ labels: Array.from({ length: capacity }, () => ''),
35
+ };
36
+ }
37
+
38
+ /** Start a frame: timings go, labels stay. See the header for why they are treated differently. */
39
+ export function resetPassTimings(timings: PassTimings): void {
40
+ timings.ms.fill(0);
41
+ timings.measured.fill(0);
42
+ }
43
+
44
+ /**
45
+ * Add one sample to a pass.
46
+ *
47
+ * Accumulates rather than replaces, because a pass may be sampled more than once in a frame — a
48
+ * shadow pass runs per cascade — and the row a reader wants is what that pass cost altogether.
49
+ */
50
+ export function recordPassSample(timings: PassTimings, pass: number, ms: number): void {
51
+ if (pass < 0 || pass >= timings.ms.length) return;
52
+ timings.ms[pass] = (timings.ms[pass] ?? 0) + ms;
53
+ timings.measured[pass] = 1;
54
+ }
55
+
56
+ export function recordPassLabel(timings: PassTimings, pass: number, label: string): void {
57
+ if (pass < 0 || pass >= timings.labels.length) return;
58
+ timings.labels[pass] = label;
59
+ }
60
+
61
+ /** Milliseconds this pass cost, or null where nothing measured it. Null is not zero. */
62
+ export function passMs(timings: PassTimings, pass: number): number | null {
63
+ if (pass < 0 || pass >= timings.ms.length) return null;
64
+ return timings.measured[pass] === 1 ? (timings.ms[pass] ?? 0) : null;
65
+ }
66
+
67
+ export function passLabel(timings: PassTimings, pass: number): string {
68
+ return timings.labels[pass] ?? '';
69
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Whether a recorded frame is one that can be executed.
3
+ *
4
+ * One rule: a node may read an identifier only if something wrote it earlier in this frame, or
5
+ * it was imported into the frame from outside. That catches the whole family of defects a fixed
6
+ * resource table caught by construction — a pass sampling an attachment the quality settings
7
+ * disabled, a pass reading a mip chain built only when a different feature is on — and which
8
+ * identifiers do not catch by construction, because any integer is a plausible identifier.
9
+ *
10
+ * Returns a message rather than throwing. The renderer decides whether a malformed frame is a
11
+ * developer-time assertion or a dropped frame, and a validator that throws has made that
12
+ * decision for it.
13
+ */
14
+ import type { Deps } from './deps.ts';
15
+ import { readsOf, writesOf } from './deps.ts';
16
+
17
+ export function validateGraph(
18
+ deps: Deps,
19
+ count: number,
20
+ imported: readonly number[],
21
+ ): string | null {
22
+ const written = new Set<number>(imported);
23
+ for (let node = 0; node < count; node += 1) {
24
+ /*
25
+ * Reads are checked before this node's writes join the set, which is what makes a read of
26
+ * something written only later a refusal and a read-modify-write legal — the latter is
27
+ * reading contents something earlier put there.
28
+ */
29
+ const reads = readsOf(deps, node);
30
+ for (let i = 0; i < reads.length; i += 1) {
31
+ const id = reads[i] ?? 0;
32
+ if (!written.has(id)) {
33
+ return `node ${node} reads resource ${id}, which nothing wrote and nothing imported`;
34
+ }
35
+ }
36
+ const writes = writesOf(deps, node);
37
+ for (let i = 0; i < writes.length; i += 1) written.add(writes[i] ?? 0);
38
+ }
39
+ return null;
40
+ }