@driftengine/core 3.62.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (428) hide show
  1. package/CHANGELOG.json +122 -0
  2. package/NOTICE +20 -0
  3. package/README.md +1 -1
  4. package/dist/core/loop.js +18 -2
  5. package/dist/core/storage.js +5 -0
  6. package/dist/geometry/meshBuilder.d.ts +1 -1
  7. package/dist/geometry/meshBuilder.js +6 -2
  8. package/dist/index.d.ts +70 -4
  9. package/dist/index.js +123 -2
  10. package/dist/input/input.js +6 -1
  11. package/dist/math/exact.d.ts +13 -3
  12. package/dist/math/exact.js +68 -3
  13. package/dist/math/frustum.d.ts +17 -2
  14. package/dist/math/frustum.js +24 -0
  15. package/dist/render/backend/api.d.ts +34 -1
  16. package/dist/render/backend/api.js +22 -1
  17. package/dist/render/backend/budget.d.ts +7 -6
  18. package/dist/render/backend/budget.js +7 -6
  19. package/dist/render/backend/createRenderer.d.ts +57 -0
  20. package/dist/render/backend/createRenderer.js +51 -2
  21. package/dist/render/backend/materialChanges.d.ts +41 -0
  22. package/dist/render/backend/materialChanges.js +38 -0
  23. package/dist/render/backend/select.js +8 -0
  24. package/dist/render/backend/webgl2/renderer.d.ts +80 -1
  25. package/dist/render/backend/webgl2/renderer.js +208 -10
  26. package/dist/render/backend/webgpu/buffers.d.ts +20 -1
  27. package/dist/render/backend/webgpu/buffers.js +116 -58
  28. package/dist/render/backend/webgpu/fieldCompose.d.ts +156 -0
  29. package/dist/render/backend/webgpu/fieldCompose.js +396 -0
  30. package/dist/render/backend/webgpu/giFieldPass.d.ts +66 -0
  31. package/dist/render/backend/webgpu/giFieldPass.js +137 -0
  32. package/dist/render/backend/webgpu/gpuDrivenPass.d.ts +728 -0
  33. package/dist/render/backend/webgpu/gpuDrivenPass.js +2473 -0
  34. package/dist/render/backend/webgpu/linePass.d.ts +4 -14
  35. package/dist/render/backend/webgpu/linePass.js +4 -33
  36. package/dist/render/backend/webgpu/probeBake.d.ts +148 -0
  37. package/dist/render/backend/webgpu/probeBake.js +493 -0
  38. package/dist/render/backend/webgpu/renderer.d.ts +379 -24
  39. package/dist/render/backend/webgpu/renderer.js +1369 -76
  40. package/dist/render/backend/webgpu/scatterPass.js +15 -1
  41. package/dist/render/backend/webgpu/surfaceTexturePass.d.ts +47 -14
  42. package/dist/render/backend/webgpu/surfaceTexturePass.js +128 -80
  43. package/dist/render/causticsRenderer.d.ts +3 -1
  44. package/dist/render/causticsRenderer.js +4 -1
  45. package/dist/render/depthConvention.d.ts +12 -0
  46. package/dist/render/depthConvention.js +14 -0
  47. package/dist/render/deviceFeatures.d.ts +32 -0
  48. package/dist/render/deviceFeatures.js +41 -0
  49. package/dist/render/fog.d.ts +79 -0
  50. package/dist/render/fog.js +138 -0
  51. package/dist/render/frame/alias.d.ts +30 -0
  52. package/dist/render/frame/alias.js +61 -0
  53. package/dist/render/frame/deps.d.ts +37 -0
  54. package/dist/render/frame/deps.js +122 -0
  55. package/dist/render/frame/flushGraph.d.ts +43 -0
  56. package/dist/render/frame/flushGraph.js +84 -0
  57. package/dist/render/frame/graphSchedule.d.ts +49 -0
  58. package/dist/render/frame/graphSchedule.js +120 -0
  59. package/dist/render/frame/index.d.ts +15 -0
  60. package/dist/render/frame/index.js +8 -0
  61. package/dist/render/frame/lifetime.d.ts +24 -0
  62. package/dist/render/frame/lifetime.js +36 -0
  63. package/dist/render/frame/passTimings.d.ts +42 -0
  64. package/dist/render/frame/passTimings.js +38 -0
  65. package/dist/render/frame/validate.d.ts +15 -0
  66. package/dist/render/frame/validate.js +22 -0
  67. package/dist/render/frame/virtual.d.ts +44 -0
  68. package/dist/render/frame/virtual.js +61 -0
  69. package/dist/render/gi/chain.d.ts +82 -0
  70. package/dist/render/gi/chain.js +135 -0
  71. package/dist/render/gi/denoise.d.ts +114 -0
  72. package/dist/render/gi/denoise.js +169 -0
  73. package/dist/render/gi/fieldScene.d.ts +125 -0
  74. package/dist/render/gi/fieldScene.js +219 -0
  75. package/dist/render/gi/globalField.d.ts +157 -0
  76. package/dist/render/gi/globalField.js +373 -0
  77. package/dist/render/gi/probeGridFit.d.ts +24 -0
  78. package/dist/render/gi/probeGridFit.js +71 -0
  79. package/dist/render/gi/probeTrace.d.ts +82 -0
  80. package/dist/render/gi/probeTrace.js +128 -0
  81. package/dist/render/gi/probeVolume.d.ts +136 -0
  82. package/dist/render/gi/probeVolume.js +191 -0
  83. package/dist/render/gi/reflection.d.ts +73 -0
  84. package/dist/render/gi/reflection.js +109 -0
  85. package/dist/render/gi/traceField.d.ts +91 -0
  86. package/dist/render/gi/traceField.js +129 -0
  87. package/dist/render/gi/traceScreen.d.ts +68 -0
  88. package/dist/render/gi/traceScreen.js +82 -0
  89. package/dist/render/gpuScene.d.ts +38 -0
  90. package/dist/render/gpuScene.js +41 -0
  91. package/dist/render/gpudriven/alphaTest.d.ts +28 -0
  92. package/dist/render/gpudriven/alphaTest.js +32 -0
  93. package/dist/render/gpudriven/clusterUpload.d.ts +59 -0
  94. package/dist/render/gpudriven/clusterUpload.js +75 -0
  95. package/dist/render/gpudriven/clusterWorld.d.ts +57 -0
  96. package/dist/render/gpudriven/clusterWorld.js +155 -0
  97. package/dist/render/gpudriven/compact.d.ts +51 -0
  98. package/dist/render/gpudriven/compact.js +68 -0
  99. package/dist/render/gpudriven/cullClusters.d.ts +129 -0
  100. package/dist/render/gpudriven/cullClusters.js +237 -0
  101. package/dist/render/gpudriven/decodeTables.d.ts +64 -0
  102. package/dist/render/gpudriven/decodeTables.js +219 -0
  103. package/dist/render/gpudriven/frustum.d.ts +25 -0
  104. package/dist/render/gpudriven/frustum.js +59 -0
  105. package/dist/render/gpudriven/geometryHarness.d.ts +15 -0
  106. package/dist/render/gpudriven/geometryHarness.js +31 -0
  107. package/dist/render/gpudriven/hzb.d.ts +60 -0
  108. package/dist/render/gpudriven/hzb.js +97 -0
  109. package/dist/render/gpudriven/ibl.d.ts +85 -0
  110. package/dist/render/gpudriven/ibl.js +129 -0
  111. package/dist/render/gpudriven/indirect.d.ts +67 -0
  112. package/dist/render/gpudriven/indirect.js +77 -0
  113. package/dist/render/gpudriven/instances.d.ts +43 -0
  114. package/dist/render/gpudriven/instances.js +172 -0
  115. package/dist/render/gpudriven/lit.d.ts +165 -0
  116. package/dist/render/gpudriven/lit.js +165 -0
  117. package/dist/render/gpudriven/lodCut.d.ts +28 -0
  118. package/dist/render/gpudriven/lodCut.js +38 -0
  119. package/dist/render/gpudriven/materialBin.d.ts +60 -0
  120. package/dist/render/gpudriven/materialBin.js +108 -0
  121. package/dist/render/gpudriven/materialTable.d.ts +88 -0
  122. package/dist/render/gpudriven/materialTable.js +115 -0
  123. package/dist/render/gpudriven/pipeline.d.ts +135 -0
  124. package/dist/render/gpudriven/pipeline.js +237 -0
  125. package/dist/render/gpudriven/rangeAlloc.d.ts +50 -0
  126. package/dist/render/gpudriven/rangeAlloc.js +112 -0
  127. package/dist/render/gpudriven/sceneUpload.d.ts +96 -0
  128. package/dist/render/gpudriven/sceneUpload.js +115 -0
  129. package/dist/render/gpudriven/shadeBins.d.ts +92 -0
  130. package/dist/render/gpudriven/shadeBins.js +182 -0
  131. package/dist/render/gpudriven/shadow.d.ts +136 -0
  132. package/dist/render/gpudriven/shadow.js +224 -0
  133. package/dist/render/gpudriven/shadowCamera.d.ts +87 -0
  134. package/dist/render/gpudriven/shadowCamera.js +345 -0
  135. package/dist/render/gpudriven/streamScene.d.ts +194 -0
  136. package/dist/render/gpudriven/streamScene.js +459 -0
  137. package/dist/render/gpudriven/surfaceFrame.d.ts +25 -0
  138. package/dist/render/gpudriven/surfaceFrame.js +51 -0
  139. package/dist/render/gpudriven/twoPhase.d.ts +122 -0
  140. package/dist/render/gpudriven/twoPhase.js +160 -0
  141. package/dist/render/gpudriven/visbuffer.d.ts +25 -0
  142. package/dist/render/gpudriven/visbuffer.js +37 -0
  143. package/dist/render/halfFloat.d.ts +10 -0
  144. package/dist/render/halfFloat.js +23 -4
  145. package/dist/render/inference/attentionTiled.d.ts +27 -0
  146. package/dist/render/inference/attentionTiled.js +117 -0
  147. package/dist/render/inference/denseKernels.d.ts +29 -0
  148. package/dist/render/inference/denseKernels.js +312 -0
  149. package/dist/render/inference/device.d.ts +21 -0
  150. package/dist/render/inference/device.js +32 -0
  151. package/dist/render/inference/deviceGraph.d.ts +34 -0
  152. package/dist/render/inference/deviceGraph.js +17 -0
  153. package/dist/render/inference/fuse.d.ts +15 -0
  154. package/dist/render/inference/fuse.js +37 -0
  155. package/dist/render/inference/kernelKit.d.ts +52 -0
  156. package/dist/render/inference/kernelKit.js +70 -0
  157. package/dist/render/inference/kernels.d.ts +3 -0
  158. package/dist/render/inference/kernels.js +11 -0
  159. package/dist/render/inference/plan.d.ts +13 -0
  160. package/dist/render/inference/plan.js +18 -0
  161. package/dist/render/inference/reuse.d.ts +39 -0
  162. package/dist/render/inference/reuse.js +65 -0
  163. package/dist/render/inference/runner.d.ts +31 -0
  164. package/dist/render/inference/runner.js +175 -0
  165. package/dist/render/inference/schedule.d.ts +39 -0
  166. package/dist/render/inference/schedule.js +59 -0
  167. package/dist/render/inference/shapeKernels.d.ts +10 -0
  168. package/dist/render/inference/shapeKernels.js +80 -0
  169. package/dist/render/inference/spatialKernels.d.ts +21 -0
  170. package/dist/render/inference/spatialKernels.js +179 -0
  171. package/dist/render/inference/splatRaster.wgsl.d.ts +75 -0
  172. package/dist/render/inference/splatRaster.wgsl.js +337 -0
  173. package/dist/render/inference/splatTiles.d.ts +79 -0
  174. package/dist/render/inference/splatTiles.js +161 -0
  175. package/dist/render/lineBatch.d.ts +2 -5
  176. package/dist/render/lineBatch.js +4 -24
  177. package/dist/render/mesh.d.ts +4 -0
  178. package/dist/render/mesh.js +45 -1
  179. package/dist/render/pass.d.ts +145 -8
  180. package/dist/render/prefilterEnvMap.d.ts +22 -0
  181. package/dist/render/prefilterEnvMap.js +31 -0
  182. package/dist/render/readback.d.ts +30 -0
  183. package/dist/render/readback.js +47 -0
  184. package/dist/render/recon/clamp.d.ts +36 -0
  185. package/dist/render/recon/clamp.js +92 -0
  186. package/dist/render/recon/disocclusion.d.ts +60 -0
  187. package/dist/render/recon/disocclusion.js +109 -0
  188. package/dist/render/recon/frameGen.d.ts +81 -0
  189. package/dist/render/recon/frameGen.js +150 -0
  190. package/dist/render/recon/frameSizes.d.ts +34 -0
  191. package/dist/render/recon/frameSizes.js +58 -0
  192. package/dist/render/recon/jitter.d.ts +60 -0
  193. package/dist/render/recon/jitter.js +118 -0
  194. package/dist/render/recon/motionVectors.d.ts +55 -0
  195. package/dist/render/recon/motionVectors.js +107 -0
  196. package/dist/render/recon/reproject.d.ts +41 -0
  197. package/dist/render/recon/reproject.js +131 -0
  198. package/dist/render/recon/resolve.d.ts +90 -0
  199. package/dist/render/recon/resolve.js +313 -0
  200. package/dist/render/recon/tier.d.ts +24 -0
  201. package/dist/render/recon/tier.js +8 -0
  202. package/dist/render/reflectionProbe.d.ts +26 -0
  203. package/dist/render/reflectionProbe.js +33 -0
  204. package/dist/render/renderQuality.d.ts +69 -0
  205. package/dist/render/renderQuality.js +22 -0
  206. package/dist/render/screenSpaceReflection.d.ts +23 -0
  207. package/dist/render/screenSpaceReflection.js +22 -3
  208. package/dist/render/sdfFont.js +2 -0
  209. package/dist/render/segmentQuads.d.ts +13 -0
  210. package/dist/render/segmentQuads.js +32 -0
  211. package/dist/render/shaders/flat/lobes.d.ts +27 -0
  212. package/dist/render/shaders/flat/lobes.js +33 -3
  213. package/dist/render/shaders/flat/preamble.d.ts +7 -0
  214. package/dist/render/shaders/flat/preamble.js +24 -1
  215. package/dist/render/shaders/flat/probeGrid.d.ts +1 -1
  216. package/dist/render/shaders/flat/probeGrid.js +71 -2
  217. package/dist/render/shaders/generated/flat.wgsl.d.ts +48 -8
  218. package/dist/render/shaders/generated/flat.wgsl.js +64 -24
  219. package/dist/render/shaders/gi/composeField.wgsl.d.ts +56 -0
  220. package/dist/render/shaders/gi/composeField.wgsl.js +231 -0
  221. package/dist/render/shaders/gi/marchField.wgsl.d.ts +30 -0
  222. package/dist/render/shaders/gi/marchField.wgsl.js +141 -0
  223. package/dist/render/shaders/gi/probeBake.wgsl.d.ts +113 -0
  224. package/dist/render/shaders/gi/probeBake.wgsl.js +635 -0
  225. package/dist/render/shaders/gi/probeTrace.wgsl.d.ts +72 -0
  226. package/dist/render/shaders/gi/probeTrace.wgsl.js +261 -0
  227. package/dist/render/shaders/gi/probeVolume.wgsl.d.ts +49 -0
  228. package/dist/render/shaders/gi/probeVolume.wgsl.js +242 -0
  229. package/dist/render/shaders/gi/sampleField.wgsl.d.ts +32 -0
  230. package/dist/render/shaders/gi/sampleField.wgsl.js +134 -0
  231. package/dist/render/shaders/gpudriven/blendRaster.wgsl.d.ts +26 -0
  232. package/dist/render/shaders/gpudriven/blendRaster.wgsl.js +339 -0
  233. package/dist/render/shaders/gpudriven/compact.wgsl.d.ts +29 -0
  234. package/dist/render/shaders/gpudriven/compact.wgsl.js +58 -0
  235. package/dist/render/shaders/gpudriven/cull.wgsl.d.ts +90 -0
  236. package/dist/render/shaders/gpudriven/cull.wgsl.js +423 -0
  237. package/dist/render/shaders/gpudriven/decode.wgsl.d.ts +72 -0
  238. package/dist/render/shaders/gpudriven/decode.wgsl.js +349 -0
  239. package/dist/render/shaders/gpudriven/environment.wgsl.d.ts +44 -0
  240. package/dist/render/shaders/gpudriven/environment.wgsl.js +137 -0
  241. package/dist/render/shaders/gpudriven/fog.wgsl.d.ts +28 -0
  242. package/dist/render/shaders/gpudriven/fog.wgsl.js +107 -0
  243. package/dist/render/shaders/gpudriven/frameBlock.wgsl.d.ts +13 -0
  244. package/dist/render/shaders/gpudriven/frameBlock.wgsl.js +62 -0
  245. package/dist/render/shaders/gpudriven/materialBin.wgsl.d.ts +51 -0
  246. package/dist/render/shaders/gpudriven/materialBin.wgsl.js +112 -0
  247. package/dist/render/shaders/gpudriven/materialTable.wgsl.d.ts +25 -0
  248. package/dist/render/shaders/gpudriven/materialTable.wgsl.js +43 -0
  249. package/dist/render/shaders/gpudriven/meshTransform.wgsl.d.ts +18 -0
  250. package/dist/render/shaders/gpudriven/meshTransform.wgsl.js +37 -0
  251. package/dist/render/shaders/gpudriven/present.wgsl.d.ts +43 -0
  252. package/dist/render/shaders/gpudriven/present.wgsl.js +127 -0
  253. package/dist/render/shaders/gpudriven/shade.wgsl.d.ts +127 -0
  254. package/dist/render/shaders/gpudriven/shade.wgsl.js +874 -0
  255. package/dist/render/shaders/gpudriven/shadow.wgsl.d.ts +44 -0
  256. package/dist/render/shaders/gpudriven/shadow.wgsl.js +308 -0
  257. package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.d.ts +28 -0
  258. package/dist/render/shaders/gpudriven/visbufferRaster.wgsl.js +245 -0
  259. package/dist/render/shaders/network.wgsl.d.ts +101 -0
  260. package/dist/render/shaders/network.wgsl.js +206 -0
  261. package/dist/render/shaders/recon/motion.wgsl.d.ts +44 -0
  262. package/dist/render/shaders/recon/motion.wgsl.js +96 -0
  263. package/dist/render/shaders/recon/resolve.wgsl.d.ts +51 -0
  264. package/dist/render/shaders/recon/resolve.wgsl.js +733 -0
  265. package/dist/render/temporalAa.js +8 -33
  266. package/dist/render/textLayout.js +12 -6
  267. package/dist/render/textRenderer.d.ts +3 -1
  268. package/dist/render/textRenderer.js +4 -1
  269. package/dist/render/translucentQueue.d.ts +6 -0
  270. package/dist/render/translucentQueue.js +11 -0
  271. package/dist/render/windStreakRenderer.d.ts +2 -1
  272. package/dist/render/windStreakRenderer.js +3 -1
  273. package/dist/world/cell.d.ts +63 -0
  274. package/dist/world/cell.js +181 -0
  275. package/dist/world/cellStream.d.ts +103 -0
  276. package/dist/world/cellStream.js +198 -0
  277. package/dist/world/freeze.d.ts +81 -0
  278. package/dist/world/freeze.js +114 -0
  279. package/dist/world/rebase.d.ts +29 -0
  280. package/dist/world/rebase.js +41 -0
  281. package/package.json +8 -3
  282. package/scripts/frames.mjs +92 -0
  283. package/scripts/gpuCompute.mjs +323 -0
  284. package/scripts/png.d.mts +16 -0
  285. package/scripts/png.mjs +25 -0
  286. package/src/core/loop.ts +19 -2
  287. package/src/core/storage.ts +5 -0
  288. package/src/geometry/meshBuilder.ts +5 -1
  289. package/src/index.ts +261 -4
  290. package/src/input/input.ts +6 -1
  291. package/src/math/exact.ts +69 -3
  292. package/src/math/frustum.ts +52 -3
  293. package/src/render/backend/api.ts +42 -1
  294. package/src/render/backend/budget.ts +7 -6
  295. package/src/render/backend/createRenderer.ts +92 -3
  296. package/src/render/backend/materialChanges.ts +54 -0
  297. package/src/render/backend/select.ts +8 -0
  298. package/src/render/backend/webgl2/renderer.ts +211 -9
  299. package/src/render/backend/webgpu/buffers.ts +182 -69
  300. package/src/render/backend/webgpu/fieldCompose.ts +482 -0
  301. package/src/render/backend/webgpu/giFieldPass.ts +200 -0
  302. package/src/render/backend/webgpu/gpuDrivenPass.ts +2993 -0
  303. package/src/render/backend/webgpu/linePass.ts +4 -39
  304. package/src/render/backend/webgpu/probeBake.ts +588 -0
  305. package/src/render/backend/webgpu/renderer.ts +1481 -76
  306. package/src/render/backend/webgpu/scatterPass.ts +15 -1
  307. package/src/render/backend/webgpu/surfaceTexturePass.ts +158 -88
  308. package/src/render/causticsRenderer.ts +5 -2
  309. package/src/render/depthConvention.ts +15 -0
  310. package/src/render/deviceFeatures.ts +77 -0
  311. package/src/render/fog.ts +185 -0
  312. package/src/render/frame/alias.ts +97 -0
  313. package/src/render/frame/deps.ts +155 -0
  314. package/src/render/frame/flushGraph.ts +135 -0
  315. package/src/render/frame/graphSchedule.ts +170 -0
  316. package/src/render/frame/index.ts +52 -0
  317. package/src/render/frame/lifetime.ts +61 -0
  318. package/src/render/frame/passTimings.ts +69 -0
  319. package/src/render/frame/validate.ts +40 -0
  320. package/src/render/frame/virtual.ts +91 -0
  321. package/src/render/gi/chain.ts +225 -0
  322. package/src/render/gi/denoise.ts +276 -0
  323. package/src/render/gi/fieldScene.ts +264 -0
  324. package/src/render/gi/globalField.ts +543 -0
  325. package/src/render/gi/probeGridFit.ts +89 -0
  326. package/src/render/gi/probeTrace.ts +143 -0
  327. package/src/render/gi/probeVolume.ts +288 -0
  328. package/src/render/gi/reflection.ts +163 -0
  329. package/src/render/gi/traceField.ts +223 -0
  330. package/src/render/gi/traceScreen.ts +106 -0
  331. package/src/render/gpuScene.ts +80 -0
  332. package/src/render/gpudriven/alphaTest.ts +33 -0
  333. package/src/render/gpudriven/clusterUpload.ts +123 -0
  334. package/src/render/gpudriven/clusterWorld.ts +239 -0
  335. package/src/render/gpudriven/compact.ts +80 -0
  336. package/src/render/gpudriven/cullClusters.ts +333 -0
  337. package/src/render/gpudriven/decodeTables.ts +332 -0
  338. package/src/render/gpudriven/frustum.ts +70 -0
  339. package/src/render/gpudriven/geometryHarness.ts +51 -0
  340. package/src/render/gpudriven/hzb.ts +113 -0
  341. package/src/render/gpudriven/ibl.ts +147 -0
  342. package/src/render/gpudriven/indirect.ts +89 -0
  343. package/src/render/gpudriven/instances.ts +234 -0
  344. package/src/render/gpudriven/lit.ts +329 -0
  345. package/src/render/gpudriven/lodCut.ts +62 -0
  346. package/src/render/gpudriven/materialBin.ts +131 -0
  347. package/src/render/gpudriven/materialTable.ts +164 -0
  348. package/src/render/gpudriven/pipeline.ts +336 -0
  349. package/src/render/gpudriven/rangeAlloc.ts +122 -0
  350. package/src/render/gpudriven/sceneUpload.ts +173 -0
  351. package/src/render/gpudriven/shadeBins.ts +222 -0
  352. package/src/render/gpudriven/shadow.ts +285 -0
  353. package/src/render/gpudriven/shadowCamera.ts +406 -0
  354. package/src/render/gpudriven/streamScene.ts +575 -0
  355. package/src/render/gpudriven/surfaceFrame.ts +68 -0
  356. package/src/render/gpudriven/twoPhase.ts +214 -0
  357. package/src/render/gpudriven/visbuffer.ts +41 -0
  358. package/src/render/halfFloat.ts +22 -4
  359. package/src/render/inference/attentionTiled.ts +132 -0
  360. package/src/render/inference/denseKernels.ts +369 -0
  361. package/src/render/inference/device.ts +44 -0
  362. package/src/render/inference/deviceGraph.ts +39 -0
  363. package/src/render/inference/fuse.ts +47 -0
  364. package/src/render/inference/kernelKit.ts +120 -0
  365. package/src/render/inference/kernels.ts +18 -0
  366. package/src/render/inference/plan.ts +26 -0
  367. package/src/render/inference/reuse.ts +79 -0
  368. package/src/render/inference/runner.ts +204 -0
  369. package/src/render/inference/schedule.ts +80 -0
  370. package/src/render/inference/shapeKernels.ts +112 -0
  371. package/src/render/inference/spatialKernels.ts +220 -0
  372. package/src/render/inference/splatRaster.wgsl.ts +348 -0
  373. package/src/render/inference/splatTiles.ts +186 -0
  374. package/src/render/lineBatch.ts +4 -24
  375. package/src/render/mesh.ts +46 -1
  376. package/src/render/pass.ts +155 -10
  377. package/src/render/prefilterEnvMap.ts +33 -0
  378. package/src/render/readback.ts +73 -0
  379. package/src/render/recon/clamp.ts +113 -0
  380. package/src/render/recon/disocclusion.ts +143 -0
  381. package/src/render/recon/frameGen.ts +191 -0
  382. package/src/render/recon/frameSizes.ts +64 -0
  383. package/src/render/recon/jitter.ts +126 -0
  384. package/src/render/recon/motionVectors.ts +138 -0
  385. package/src/render/recon/reproject.ts +179 -0
  386. package/src/render/recon/resolve.ts +444 -0
  387. package/src/render/recon/tier.ts +31 -0
  388. package/src/render/reflectionProbe.ts +34 -0
  389. package/src/render/renderQuality.ts +87 -0
  390. package/src/render/screenSpaceReflection.ts +37 -3
  391. package/src/render/sdfFont.ts +2 -0
  392. package/src/render/segmentQuads.ts +39 -0
  393. package/src/render/shaders/flat/lobes.ts +35 -3
  394. package/src/render/shaders/flat/preamble.ts +25 -1
  395. package/src/render/shaders/flat/probeGrid.ts +77 -2
  396. package/src/render/shaders/generated/flat.wgsl.ts +64 -24
  397. package/src/render/shaders/gi/composeField.wgsl.ts +239 -0
  398. package/src/render/shaders/gi/marchField.wgsl.ts +146 -0
  399. package/src/render/shaders/gi/probeBake.wgsl.ts +649 -0
  400. package/src/render/shaders/gi/probeTrace.wgsl.ts +269 -0
  401. package/src/render/shaders/gi/probeVolume.wgsl.ts +246 -0
  402. package/src/render/shaders/gi/sampleField.wgsl.ts +140 -0
  403. package/src/render/shaders/gpudriven/blendRaster.wgsl.ts +343 -0
  404. package/src/render/shaders/gpudriven/compact.wgsl.ts +59 -0
  405. package/src/render/shaders/gpudriven/cull.wgsl.ts +433 -0
  406. package/src/render/shaders/gpudriven/decode.wgsl.ts +373 -0
  407. package/src/render/shaders/gpudriven/environment.wgsl.ts +141 -0
  408. package/src/render/shaders/gpudriven/fog.wgsl.ts +110 -0
  409. package/src/render/shaders/gpudriven/frameBlock.wgsl.ts +62 -0
  410. package/src/render/shaders/gpudriven/materialBin.wgsl.ts +116 -0
  411. package/src/render/shaders/gpudriven/materialTable.wgsl.ts +46 -0
  412. package/src/render/shaders/gpudriven/meshTransform.wgsl.ts +37 -0
  413. package/src/render/shaders/gpudriven/present.wgsl.ts +129 -0
  414. package/src/render/shaders/gpudriven/shade.wgsl.ts +884 -0
  415. package/src/render/shaders/gpudriven/shadow.wgsl.ts +322 -0
  416. package/src/render/shaders/gpudriven/visbufferRaster.wgsl.ts +251 -0
  417. package/src/render/shaders/network.wgsl.ts +238 -0
  418. package/src/render/shaders/recon/motion.wgsl.ts +101 -0
  419. package/src/render/shaders/recon/resolve.wgsl.ts +741 -0
  420. package/src/render/temporalAa.ts +9 -33
  421. package/src/render/textLayout.ts +12 -6
  422. package/src/render/textRenderer.ts +5 -2
  423. package/src/render/translucentQueue.ts +11 -0
  424. package/src/render/windStreakRenderer.ts +4 -2
  425. package/src/world/cell.ts +231 -0
  426. package/src/world/cellStream.ts +278 -0
  427. package/src/world/freeze.ts +157 -0
  428. package/src/world/rebase.ts +56 -0
@@ -177,7 +177,21 @@ export function scatterDepthPipeline(cache, device, layout, shadowFormat, depthF
177
177
  targets: [],
178
178
  },
179
179
  primitive: { topology: 'triangle-list', cullMode: 'none' },
180
- depthStencil: { format: shadowFormat, depthWriteEnabled: true, depthCompare: DEPTH_COMPARE },
180
+ /*
181
+ * **`less`, not the frame's `DEPTH_COMPARE`, because a shadow map is not reversed.**
182
+ * `depthConvention.ts` says so in as many words: the cascades are orthographic, where depth
183
+ * is already linear and a float buffer gains nothing, so `SHADOW_DEPTH_CLEAR` is 1 and
184
+ * `beginShadowPass` clears to 1. This pipeline took the scene's compare, which under
185
+ * `REVERSED_DEPTH` is `greater` — and a fragment at depth 0.3 tested with `greater` against a
186
+ * map cleared to 1 fails. **Nothing was ever written**, so a scatter batch cast no shadow at
187
+ * all on this backend: no error, no warning, an ordinary-looking frame.
188
+ *
189
+ * `depthPass.ts` has had `'less'` for the mesh path all along, which is why meshes cast and
190
+ * scatter did not, and why it took a scene whose only caster is a scatter batch to show it.
191
+ * `demo/windField.ts` is that scene — turning directional shadows off there changed 2,628
192
+ * pixels on WebGL2 and 0 on WebGPU.
193
+ */
194
+ depthStencil: { format: shadowFormat, depthWriteEnabled: true, depthCompare: 'less' },
181
195
  }));
182
196
  }
183
197
  /**
@@ -2,27 +2,65 @@ import type { SurfaceTextureOptions } from '../../surfaceTexture.ts';
2
2
  import type { PipelineCache } from './pipelineCache.ts';
3
3
  /** How many levels an image of this size has, counting the one it arrives with. */
4
4
  export declare function mipLevelCount(width: number, height: number): number;
5
+ /**
6
+ * Somewhere to keep one pipeline per format. `PipelineCache` satisfies it; so does a `Map`.
7
+ *
8
+ * Taken as an interface rather than as the class, because the other caller of the chain below is
9
+ * `@driftengine/ui2d`, which builds its own pipeline from the device and has no cache of the
10
+ * renderer's to hand.
11
+ */
12
+ export interface MipPipelines {
13
+ get(key: string, describe: () => GPURenderPipelineDescriptor): GPURenderPipeline;
14
+ }
15
+ /**
16
+ * Fill every level of a texture from the one above it, which is what WebGPU asks for instead of a
17
+ * call.
18
+ *
19
+ * **`gl.generateMipmap` is one line and WebGPU has no equivalent at all**, so this is the whole of
20
+ * the difference between the two backends for any texture that wants a chain. One encoder, one
21
+ * render pass per level, submitted together, once, at upload.
22
+ *
23
+ * The source view is a **single level**, so the sample cannot read the level being written — that
24
+ * would be one texture bound as an attachment and as a resource at once, which is rejected, and
25
+ * rejected quietly enough to matter.
26
+ *
27
+ * **A free function because there are two callers now.** A surface texture on a mesh has wanted a
28
+ * chain since it existed; a sprite sheet wanted one the day a consumer baked type into an atlas and
29
+ * drew it at a seventh of its authored size. Writing the blit twice would be two statements of one
30
+ * thing, and the second copy is the one that would quietly disagree about the format.
31
+ */
32
+ export declare function generateMipChain(device: GPUDevice, pipelines: MipPipelines, texture: GPUTexture, format: GPUTextureFormat, levels: number): void;
5
33
  /** An image uploaded once and bound per material. */
6
34
  export declare class GpuSurfaceTexture {
7
35
  private readonly device;
8
36
  private readonly pipelines;
9
- readonly view: GPUTextureView;
10
37
  readonly sampler: GPUSampler;
11
38
  private texture;
39
+ private current;
12
40
  private readonly format;
13
41
  private readonly mipmapped;
14
- private readonly levels;
15
- private readonly width;
16
- private readonly height;
42
+ private levels;
43
+ private width;
44
+ private height;
17
45
  constructor(device: GPUDevice, pipelines: PipelineCache, source: TexImageSource, options?: SurfaceTextureOptions);
46
+ /** The view every binding of this image holds. A new one when `update` changes the size. */
47
+ get view(): GPUTextureView;
18
48
  /**
19
- * Replace the pixels, keeping the texture, its view and its sampler.
49
+ * Replace the pixels, keeping the handle and its sampler.
50
+ *
51
+ * **At the same size, the texture and its view are kept**, so a binding a draw loop already holds
52
+ * stays valid and the swap is a swap rather than a rebuild — the same argument `surfaceTexture.ts`
53
+ * makes. Not a hot path: it re-uploads the whole image and rebuilds the chain.
20
54
  *
21
- * The binding a draw loop already holds stays valid, so the swap is a swap rather than a
22
- * rebuild — the same argument `surfaceTexture.ts` makes. Not a hot path: it re-uploads the
23
- * whole image and rebuilds the chain.
55
+ * **At another size, a texture of that size replaces it**, which is what WebGL2's `texImage2D`
56
+ * does by itself. This used to keep the old size and copy that much of the new image — its
57
+ * top-left corner, stretched — and a model loader updating a small preview with the real image
58
+ * hit that whenever the preview's decode won the race. The view is new then, and the texture it
59
+ * replaced is handed back rather than destroyed: a draw recorded earlier in this frame may still
60
+ * read it, so the renderer destroys it once nothing can, and drops every binding of the old view.
24
61
  */
25
- update(source: TexImageSource): void;
62
+ update(source: TexImageSource): GPUTexture | null;
63
+ private allocate;
26
64
  dispose(): void;
27
65
  private upload;
28
66
  /**
@@ -33,9 +71,4 @@ export declare class GpuSurfaceTexture {
33
71
  * an attachment and a resource at once — rejected, and rejected silently enough to matter.
34
72
  */
35
73
  private generateMips;
36
- /**
37
- * Cached per format, because the two differ: an `-srgb` target encodes on write, and blitting
38
- * a linear chain through a pipeline declared for the other one is a gamma error per level.
39
- */
40
- private mipPipeline;
41
74
  }
@@ -48,6 +48,75 @@ fn fragmentMain(in: Varying) -> @location(0) vec4<f32> {
48
48
  export function mipLevelCount(width, height) {
49
49
  return Math.floor(Math.log2(Math.max(width, height))) + 1;
50
50
  }
51
+ /**
52
+ * Fill every level of a texture from the one above it, which is what WebGPU asks for instead of a
53
+ * call.
54
+ *
55
+ * **`gl.generateMipmap` is one line and WebGPU has no equivalent at all**, so this is the whole of
56
+ * the difference between the two backends for any texture that wants a chain. One encoder, one
57
+ * render pass per level, submitted together, once, at upload.
58
+ *
59
+ * The source view is a **single level**, so the sample cannot read the level being written — that
60
+ * would be one texture bound as an attachment and as a resource at once, which is rejected, and
61
+ * rejected quietly enough to matter.
62
+ *
63
+ * **A free function because there are two callers now.** A surface texture on a mesh has wanted a
64
+ * chain since it existed; a sprite sheet wanted one the day a consumer baked type into an atlas and
65
+ * drew it at a seventh of its authored size. Writing the blit twice would be two statements of one
66
+ * thing, and the second copy is the one that would quietly disagree about the format.
67
+ */
68
+ export function generateMipChain(device, pipelines, texture, format, levels) {
69
+ if (levels < 2)
70
+ return;
71
+ const pipeline = mipBlitPipeline(device, pipelines, format);
72
+ const sampler = device.createSampler({
73
+ label: 'mip.sampler',
74
+ magFilter: 'linear',
75
+ minFilter: 'linear',
76
+ });
77
+ const encoder = device.createCommandEncoder({ label: 'mip.chain' });
78
+ for (let level = 1; level < levels; level++) {
79
+ const source = texture.createView({ baseMipLevel: level - 1, mipLevelCount: 1 });
80
+ const target = texture.createView({ baseMipLevel: level, mipLevelCount: 1 });
81
+ const pass = encoder.beginRenderPass({
82
+ label: `mip.level${level}`,
83
+ colorAttachments: [
84
+ { view: target, loadOp: 'clear', storeOp: 'store', clearValue: [0, 0, 0, 0] },
85
+ ],
86
+ });
87
+ pass.setPipeline(pipeline);
88
+ pass.setBindGroup(0, device.createBindGroup({
89
+ layout: pipeline.getBindGroupLayout(0),
90
+ entries: [
91
+ { binding: 0, resource: source },
92
+ { binding: 1, resource: sampler },
93
+ ],
94
+ }));
95
+ pass.draw(3);
96
+ pass.end();
97
+ }
98
+ device.queue.submit([encoder.finish()]);
99
+ }
100
+ /**
101
+ * Cached per format, because the two differ: an `-srgb` target encodes on write, and blitting a
102
+ * linear chain through a pipeline declared for the other one is a gamma error per level.
103
+ */
104
+ function mipBlitPipeline(device, pipelines, format) {
105
+ return pipelines.get(`surface.mip:${format}`, () => ({
106
+ label: `surface.mip:${format}`,
107
+ layout: 'auto',
108
+ vertex: {
109
+ module: shaderModule(device, { label: 'surface.mip', code: MIP_WGSL }),
110
+ entryPoint: 'vertexMain',
111
+ },
112
+ fragment: {
113
+ module: shaderModule(device, { label: 'surface.mip', code: MIP_WGSL }),
114
+ entryPoint: 'fragmentMain',
115
+ targets: [{ format }],
116
+ },
117
+ primitive: { topology: 'triangle-list' },
118
+ }));
119
+ }
51
120
  function sourceSize(source) {
52
121
  const candidate = source;
53
122
  const width = candidate.videoWidth ?? candidate.width ?? 0;
@@ -58,9 +127,9 @@ function sourceSize(source) {
58
127
  export class GpuSurfaceTexture {
59
128
  device;
60
129
  pipelines;
61
- view;
62
130
  sampler;
63
131
  texture;
132
+ current;
64
133
  format;
65
134
  mipmapped;
66
135
  levels;
@@ -70,35 +139,15 @@ export class GpuSurfaceTexture {
70
139
  this.device = device;
71
140
  this.pipelines = pipelines;
72
141
  const { width, height } = sourceSize(source);
73
- this.width = width;
74
- this.height = height;
75
142
  this.mipmapped = options.mipmap ?? true;
76
- this.levels = this.mipmapped ? mipLevelCount(width, height) : 1;
77
143
  /* `SRGB8_ALPHA8`'s equivalent. Decoded in the sampler, before filtering, which is the only
78
144
  place it is correct — `surfaceTexture.ts` makes the argument in full. */
79
145
  this.format = (options.colorSpace ?? 'linear') === 'srgb' ? 'rgba8unorm-srgb' : 'rgba8unorm';
80
- this.texture = device.createTexture({
81
- label: 'surface.texture',
82
- size: [width, height],
83
- format: this.format,
84
- mipLevelCount: this.levels,
85
- /*
86
- * **`RENDER_ATTACHMENT` is required by `copyExternalImageToTexture`, not by the mip
87
- * chain**, and the difference matters enough to state.
88
- *
89
- * This used to say the flag was there "because building the chain renders into levels 1
90
- * and below", which is true and is not the reason. The upload itself demands it: Dawn
91
- * rejects a destination without `CopyDst | RenderAttachment` outright, whatever its mip
92
- * count. Gating it on `levels > 1` therefore breaks every unmipped texture, and the read
93
- * of the old comment that led there cost a broken build to disprove.
94
- *
95
- * So it cannot be dropped to make a sampled-only allocation, and anything that wants one
96
- * has to leave `copyExternalImageToTexture` behind and write raw pixels instead, which
97
- * trades a driver cost for a CPU readback.
98
- */
99
- usage: 0x2 | 0x4 | 0x10, // COPY_DST | TEXTURE_BINDING | RENDER_ATTACHMENT
100
- });
101
- this.view = this.texture.createView();
146
+ this.width = width;
147
+ this.height = height;
148
+ this.levels = this.mipmapped ? mipLevelCount(width, height) : 1;
149
+ this.texture = this.allocate();
150
+ this.current = this.texture.createView();
102
151
  const wrap = (options.wrap ?? 'repeat') === 'repeat' ? 'repeat' : 'clamp-to-edge';
103
152
  /*
104
153
  * Nearest where the caller said their pixels are the subject. `mipmapFilter` stays as it was:
@@ -131,17 +180,63 @@ export class GpuSurfaceTexture {
131
180
  });
132
181
  this.upload(source);
133
182
  }
183
+ /** The view every binding of this image holds. A new one when `update` changes the size. */
184
+ get view() {
185
+ return this.current;
186
+ }
134
187
  /**
135
- * Replace the pixels, keeping the texture, its view and its sampler.
188
+ * Replace the pixels, keeping the handle and its sampler.
189
+ *
190
+ * **At the same size, the texture and its view are kept**, so a binding a draw loop already holds
191
+ * stays valid and the swap is a swap rather than a rebuild — the same argument `surfaceTexture.ts`
192
+ * makes. Not a hot path: it re-uploads the whole image and rebuilds the chain.
136
193
  *
137
- * The binding a draw loop already holds stays valid, so the swap is a swap rather than a
138
- * rebuild — the same argument `surfaceTexture.ts` makes. Not a hot path: it re-uploads the
139
- * whole image and rebuilds the chain.
194
+ * **At another size, a texture of that size replaces it**, which is what WebGL2's `texImage2D`
195
+ * does by itself. This used to keep the old size and copy that much of the new image — its
196
+ * top-left corner, stretched — and a model loader updating a small preview with the real image
197
+ * hit that whenever the preview's decode won the race. The view is new then, and the texture it
198
+ * replaced is handed back rather than destroyed: a draw recorded earlier in this frame may still
199
+ * read it, so the renderer destroys it once nothing can, and drops every binding of the old view.
140
200
  */
141
201
  update(source) {
142
- if (this.texture === null)
143
- return;
202
+ const replaced = this.texture;
203
+ if (replaced === null)
204
+ return null;
205
+ const { width, height } = sourceSize(source);
206
+ if (width === this.width && height === this.height) {
207
+ this.upload(source);
208
+ return null;
209
+ }
210
+ this.width = width;
211
+ this.height = height;
212
+ this.levels = this.mipmapped ? mipLevelCount(width, height) : 1;
213
+ this.texture = this.allocate();
214
+ this.current = this.texture.createView();
144
215
  this.upload(source);
216
+ return replaced;
217
+ }
218
+ allocate() {
219
+ return this.device.createTexture({
220
+ label: 'surface.texture',
221
+ size: [this.width, this.height],
222
+ format: this.format,
223
+ mipLevelCount: this.levels,
224
+ /*
225
+ * **`RENDER_ATTACHMENT` is required by `copyExternalImageToTexture`, not by the mip
226
+ * chain**, and the difference matters enough to state.
227
+ *
228
+ * This used to say the flag was there "because building the chain renders into levels 1
229
+ * and below", which is true and is not the reason. The upload itself demands it: Dawn
230
+ * rejects a destination without `CopyDst | RenderAttachment` outright, whatever its mip
231
+ * count. Gating it on `levels > 1` therefore breaks every unmipped texture, and the read
232
+ * of the old comment that led there cost a broken build to disprove.
233
+ *
234
+ * So it cannot be dropped to make a sampled-only allocation, and anything that wants one
235
+ * has to leave `copyExternalImageToTexture` behind and write raw pixels instead, which
236
+ * trades a driver cost for a CPU readback.
237
+ */
238
+ usage: 0x2 | 0x4 | 0x10, // COPY_DST | TEXTURE_BINDING | RENDER_ATTACHMENT
239
+ });
145
240
  }
146
241
  dispose() {
147
242
  if (this.texture === null)
@@ -176,53 +271,6 @@ export class GpuSurfaceTexture {
176
271
  * an attachment and a resource at once — rejected, and rejected silently enough to matter.
177
272
  */
178
273
  generateMips(texture) {
179
- const pipeline = this.mipPipeline();
180
- const sampler = this.device.createSampler({
181
- label: 'surface.mipSampler',
182
- magFilter: 'linear',
183
- minFilter: 'linear',
184
- });
185
- const encoder = this.device.createCommandEncoder({ label: 'surface.mips' });
186
- for (let level = 1; level < this.levels; level++) {
187
- const source = texture.createView({ baseMipLevel: level - 1, mipLevelCount: 1 });
188
- const target = texture.createView({ baseMipLevel: level, mipLevelCount: 1 });
189
- const pass = encoder.beginRenderPass({
190
- label: `surface.mip${level}`,
191
- colorAttachments: [
192
- { view: target, loadOp: 'clear', storeOp: 'store', clearValue: [0, 0, 0, 0] },
193
- ],
194
- });
195
- pass.setPipeline(pipeline);
196
- pass.setBindGroup(0, this.device.createBindGroup({
197
- layout: pipeline.getBindGroupLayout(0),
198
- entries: [
199
- { binding: 0, resource: source },
200
- { binding: 1, resource: sampler },
201
- ],
202
- }));
203
- pass.draw(3);
204
- pass.end();
205
- }
206
- this.device.queue.submit([encoder.finish()]);
207
- }
208
- /**
209
- * Cached per format, because the two differ: an `-srgb` target encodes on write, and blitting
210
- * a linear chain through a pipeline declared for the other one is a gamma error per level.
211
- */
212
- mipPipeline() {
213
- return this.pipelines.get(`surface.mip:${this.format}`, () => ({
214
- label: `surface.mip:${this.format}`,
215
- layout: 'auto',
216
- vertex: {
217
- module: shaderModule(this.device, { label: 'surface.mip', code: MIP_WGSL }),
218
- entryPoint: 'vertexMain',
219
- },
220
- fragment: {
221
- module: shaderModule(this.device, { label: 'surface.mip', code: MIP_WGSL }),
222
- entryPoint: 'fragmentMain',
223
- targets: [{ format: this.format }],
224
- },
225
- primitive: { topology: 'triangle-list' },
226
- }));
274
+ generateMipChain(this.device, this.pipelines, texture, this.format, this.levels);
227
275
  }
228
276
  }
@@ -57,7 +57,9 @@ export declare class CausticsRenderer {
57
57
  * pass: this is light arriving at a surface, not the surface.
58
58
  *
59
59
  * @param strength scales the whole effect; 1 is the calibrated default.
60
+ *
61
+ * Answers whether it drew, which the renderer counts on its frame budget.
60
62
  */
61
- draw(gl: WebGL2RenderingContext, camera: FrameView, timeSeconds: number, directionalDir: Vec3, directionalColor: Vec3, ambient: Vec3, atmosphere: Atmosphere, underwaterEnabled: boolean, windX?: number, windZ?: number, strength?: number): void;
63
+ draw(gl: WebGL2RenderingContext, camera: FrameView, timeSeconds: number, directionalDir: Vec3, directionalColor: Vec3, ambient: Vec3, atmosphere: Atmosphere, underwaterEnabled: boolean, windX?: number, windZ?: number, strength?: number): boolean;
62
64
  dispose(gl: WebGL2RenderingContext): void;
63
65
  }
@@ -62,10 +62,12 @@ export class CausticsRenderer {
62
62
  * pass: this is light arriving at a surface, not the surface.
63
63
  *
64
64
  * @param strength scales the whole effect; 1 is the calibrated default.
65
+ *
66
+ * Answers whether it drew, which the renderer counts on its frame budget.
65
67
  */
66
68
  draw(gl, camera, timeSeconds, directionalDir, directionalColor, ambient, atmosphere, underwaterEnabled, windX = 0, windZ = 0, strength = 1) {
67
69
  if (this.vertexCount === 0)
68
- return;
70
+ return false;
69
71
  const u = this.uniforms;
70
72
  gl.useProgram(this.program);
71
73
  gl.uniformMatrix4fv(u['uViewProj'] ?? null, false, camera.viewProjection);
@@ -109,6 +111,7 @@ export class CausticsRenderer {
109
111
  gl.enable(gl.CULL_FACE);
110
112
  gl.depthMask(true);
111
113
  gl.disable(gl.BLEND);
114
+ return true;
112
115
  }
113
116
  dispose(gl) {
114
117
  for (const buffer of this.buffers)
@@ -139,6 +139,18 @@ export declare function conventionalDepth(stored: number): number;
139
139
  * `%s` is the name of the depth variable at the call site.
140
140
  */
141
141
  export declare function glslSceneDepthToNdc(depth: string): string;
142
+ /**
143
+ * The same conversion as WGSL, for the hand-written compute shaders that have no GLSL to generate
144
+ * from.
145
+ *
146
+ * **It is the same text, and that is the point of it being here.** The reconstruction resolve picks
147
+ * the *nearest* of nine depths and dilates that texel's motion, which is the rule every temporal
148
+ * upscaler uses because an edge's motion belongs to the nearer of the two surfaces meeting there.
149
+ * Under a reversed buffer the nearest is the largest number, so a shader reading the attachment
150
+ * without this conversion picks the furthest and drags the background's motion over every
151
+ * silhouette — a defect that draws a plausible picture and moves the wrong way.
152
+ */
153
+ export declare function wgslSceneDepthToNdc(depth: string): string;
142
154
  /**
143
155
  * The clip-space z of the far plane, as GLSL, for geometry that writes a fixed depth.
144
156
  *
@@ -145,6 +145,20 @@ export function conventionalDepth(stored) {
145
145
  export function glslSceneDepthToNdc(depth) {
146
146
  return REVERSED_DEPTH ? `(1.0 - ${depth} * 2.0)` : `(${depth} * 2.0 - 1.0)`;
147
147
  }
148
+ /**
149
+ * The same conversion as WGSL, for the hand-written compute shaders that have no GLSL to generate
150
+ * from.
151
+ *
152
+ * **It is the same text, and that is the point of it being here.** The reconstruction resolve picks
153
+ * the *nearest* of nine depths and dilates that texel's motion, which is the rule every temporal
154
+ * upscaler uses because an edge's motion belongs to the nearer of the two surfaces meeting there.
155
+ * Under a reversed buffer the nearest is the largest number, so a shader reading the attachment
156
+ * without this conversion picks the furthest and drags the background's motion over every
157
+ * silhouette — a defect that draws a plausible picture and moves the wrong way.
158
+ */
159
+ export function wgslSceneDepthToNdc(depth) {
160
+ return REVERSED_DEPTH ? `(1.0 - ${depth} * 2.0)` : `(${depth} * 2.0 - 1.0)`;
161
+ }
148
162
  /**
149
163
  * The clip-space z of the far plane, as GLSL, for geometry that writes a fixed depth.
150
164
  *
@@ -0,0 +1,32 @@
1
+ /** The subset of a device this needs. A real `GPUDevice` satisfies it. */
2
+ export interface DeviceShape {
3
+ readonly features: {
4
+ has(name: string): boolean;
5
+ };
6
+ readonly limits: Readonly<Record<string, number | undefined>>;
7
+ }
8
+ export interface GpuCapabilities {
9
+ /** Half-precision arithmetic in shaders. */
10
+ readonly shaderF16: boolean;
11
+ /** Subgroup operations, which make a compute reduction far cheaper where present. */
12
+ readonly subgroups: boolean;
13
+ /** Timestamp queries. Absent by default in more browsers than people expect. */
14
+ readonly timestampQuery: boolean;
15
+ /** Whether this backend can be driven from buffers the GPU wrote. See `indirectSupport`. */
16
+ readonly indirect: boolean;
17
+ /**
18
+ * The three compressed families, reported separately.
19
+ *
20
+ * **Separately, because a device may have exactly one.** Desktop parts carry block compression,
21
+ * mobile carries one of the other two, and a single `compressed: boolean` would be true on
22
+ * every device and useful on none.
23
+ */
24
+ readonly compressedBc: boolean;
25
+ readonly compressedEtc2: boolean;
26
+ readonly compressedAstc: boolean;
27
+ /** Limits, with an absent one reported as 0 so arithmetic on it is safe. */
28
+ readonly maxStorageBufferBytes: number;
29
+ readonly maxComputeWorkgroupStorageBytes: number;
30
+ readonly maxComputeInvocationsPerWorkgroup: number;
31
+ }
32
+ export declare function probeCapabilities(device: DeviceShape, backend: 'webgl2' | 'webgpu'): GpuCapabilities;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * What this device can do, asked once, in one place.
3
+ *
4
+ * **Not `gpuCapability.ts`, which answers a different question.** That module identifies the
5
+ * *part* — a renderer string, matched against families known to struggle — so that a consumer can
6
+ * choose a quality profile. This one reads the optional features and limits a device actually
7
+ * reports. A weak part may support half precision and a strong one may not; neither answer
8
+ * predicts the other.
9
+ *
10
+ * **One place, because the alternative is each subsystem asking the device itself.** Every
11
+ * capability below has more than one consumer waiting for it, and a feature string spelled two
12
+ * ways in two subsystems is a capability that is present in one and absent in the other on the
13
+ * same machine.
14
+ *
15
+ * **Takes the device's shape as a parameter rather than reaching for a global**, which is the
16
+ * rule `AGENTS.md` applies to persistence applied here — and is what lets every branch below be
17
+ * asserted without a graphics device.
18
+ */
19
+ import { indirectSupport } from './backend/api.js';
20
+ function limit(device, name) {
21
+ /*
22
+ * Zero rather than undefined for a limit the device does not report. A consumer sizing a buffer
23
+ * against `undefined` gets NaN and allocates nothing while believing it allocated something;
24
+ * against 0 it gets a refusal it can see.
25
+ */
26
+ return device.limits[name] ?? 0;
27
+ }
28
+ export function probeCapabilities(device, backend) {
29
+ return {
30
+ shaderF16: device.features.has('shader-f16'),
31
+ subgroups: device.features.has('subgroups'),
32
+ timestampQuery: device.features.has('timestamp-query'),
33
+ indirect: indirectSupport(backend),
34
+ compressedBc: device.features.has('texture-compression-bc'),
35
+ compressedEtc2: device.features.has('texture-compression-etc2'),
36
+ compressedAstc: device.features.has('texture-compression-astc'),
37
+ maxStorageBufferBytes: limit(device, 'maxStorageBufferBindingSize'),
38
+ maxComputeWorkgroupStorageBytes: limit(device, 'maxComputeWorkgroupStorageSize'),
39
+ maxComputeInvocationsPerWorkgroup: limit(device, 'maxComputeInvocationsPerWorkgroup'),
40
+ };
41
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * The medium between the camera and everything it can see, as arithmetic.
3
+ *
4
+ * **`shaders/fog.ts` was the only copy and it is GLSL**, which two things now make a problem. The
5
+ * GPU-driven pipeline is written in WGSL and cannot include it, so the second pipeline drew no fog
6
+ * at all; and a term that exists only as a shader is a term nothing can disagree with, which is the
7
+ * argument `gpudriven/lit.ts` and `gpudriven/alphaTest.ts` were both written under.
8
+ *
9
+ * So this is the expression in TypeScript, and both shaders are checked against it:
10
+ * `scripts/gpu-parity.mjs` runs the WGSL over generated cases, and `shaders/fog.ts` stays exactly
11
+ * as it is. **This is a second reader of one decision rather than a second decision** — every
12
+ * guard, every constant and the order of the two mixes are the GLSL's, and where a line looks odd
13
+ * that file's header is the long version of why.
14
+ *
15
+ * **What it does not carry** is the uniform block. `shaders/fog.ts` declares ten uniforms because a
16
+ * block that declares everything it uses can be pasted into any program; a function takes them as
17
+ * one argument instead, and the backends keep their own packing.
18
+ */
19
+ import { type Atmosphere } from './atmosphere.ts';
20
+ /** A colour as three numbers, matching `render/orderIndependent.ts`'s own `Rgb`. */
21
+ export type Rgb = readonly [number, number, number];
22
+ /** Beer-Lambert through a haze layer that thins with height. `uFogMode` 0. */
23
+ export declare const MEDIUM_FOG = 0;
24
+ /** A ramp between two distances, which is a look rather than a medium. `uFogMode` 1. */
25
+ export declare const LINEAR_FOG = 1;
26
+ export interface FogOptions {
27
+ readonly colour: Rgb;
28
+ /** Extinction per metre **at the camera's own height**, not at the base. */
29
+ readonly density: number;
30
+ /** Reciprocal scale height of the haze, per metre. 0 is a uniform medium. */
31
+ readonly heightFalloff: number;
32
+ /** The camera's height, so a fragment's own height is one subtraction away. */
33
+ readonly eyeY: number;
34
+ readonly underwaterColour: Rgb;
35
+ readonly underwaterDensity: number;
36
+ readonly underwaterFactor: number;
37
+ /** `MEDIUM_FOG` integrates a medium; `LINEAR_FOG` ramps between near and far. */
38
+ readonly mode: number;
39
+ /** Linear mode only: where haze begins, and where it is total. */
40
+ readonly near: number;
41
+ readonly far: number;
42
+ }
43
+ /** What distance converges toward: the day's haze, or the water column. */
44
+ export declare function mediumColour(fog: FogOptions): [number, number, number];
45
+ /**
46
+ * How much of a surface standing at `pointY`, `dist` metres away, is lost to the medium between.
47
+ * 0 is perfectly clear, 1 is the medium's own colour.
48
+ */
49
+ export declare function mediumFog(fog: FogOptions, dist: number, pointY: number): number;
50
+ /** `FogOptions` with its fields writable, which is what a caller holds and refills a frame at a time. */
51
+ export interface FogTarget {
52
+ colour: [number, number, number];
53
+ density: number;
54
+ heightFalloff: number;
55
+ eyeY: number;
56
+ underwaterColour: [number, number, number];
57
+ underwaterDensity: number;
58
+ underwaterFactor: number;
59
+ mode: number;
60
+ near: number;
61
+ far: number;
62
+ }
63
+ /** A target for `atmosphereFog`, allocated once, outside the frame loop. */
64
+ export declare function createFogTarget(): FogTarget;
65
+ /**
66
+ * The haze an `Environment` makes at a camera's height, as `GpuDrivenView.fog` takes it.
67
+ *
68
+ * **The forward path's own decision, handed over rather than made again.** A consumer drawing
69
+ * both pipelines in one frame has one environment and needs one haze from it, and
70
+ * `resolveAtmosphere` is where the forward path decides which medium the camera is in and what it
71
+ * looks like — the density at the eye, the linear ramp's two radii, how far under water the eye
72
+ * is. This calls it and copies the answer across field for field, so the two pipelines cannot
73
+ * disagree about where the fog begins or whether the camera is submerged. Both mode numbers are
74
+ * the shaders' `uFogMode`, which is why no mapping stands between them.
75
+ *
76
+ * @param underwater The renderer's `underwaterAtmosphere` quality, which gates the second medium
77
+ * on the forward path; pass the same.
78
+ */
79
+ export declare function atmosphereFog(atmosphere: Atmosphere, eyeY: number, underwater: boolean, out: FogTarget): FogTarget;