@forgeax/engine-render 0.1.19 → 0.1.21

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 (452) hide show
  1. package/README.md +215 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/assembly/device-feature-admission.d.ts +18 -0
  4. package/dist/assembly/device-feature-admission.d.ts.map +1 -0
  5. package/dist/assembly/directional-shadow-inspection.d.ts +38 -0
  6. package/dist/assembly/directional-shadow-inspection.d.ts.map +1 -0
  7. package/dist/assembly/factory.d.ts +34 -20
  8. package/dist/assembly/factory.d.ts.map +1 -1
  9. package/dist/assembly/host-contract.d.ts +9 -0
  10. package/dist/assembly/host-contract.d.ts.map +1 -1
  11. package/dist/assembly/render-target-host.d.ts +46 -0
  12. package/dist/assembly/render-target-host.d.ts.map +1 -0
  13. package/dist/assets/render-asset-port.d.ts.map +1 -1
  14. package/dist/authoring.mjs +3 -0
  15. package/dist/authoring.mjs.map +1 -1
  16. package/dist/capture/cube-views.d.ts +21 -0
  17. package/dist/capture/cube-views.d.ts.map +1 -0
  18. package/dist/capture/scheduler.d.ts +54 -0
  19. package/dist/capture/scheduler.d.ts.map +1 -0
  20. package/dist/{chunk-RJRUS55L.mjs → chunk-5YADUCA7.mjs} +1896 -1624
  21. package/dist/chunk-5YADUCA7.mjs.map +1 -0
  22. package/dist/{chunk-LOSO4CTV.mjs → chunk-6OPXDQ2E.mjs} +423 -46
  23. package/dist/chunk-6OPXDQ2E.mjs.map +1 -0
  24. package/dist/{chunk-IPXCABEP.mjs → chunk-BXBQQKFQ.mjs} +3 -9
  25. package/dist/chunk-BXBQQKFQ.mjs.map +1 -0
  26. package/dist/chunk-FS2KNUQH.mjs +1294 -0
  27. package/dist/chunk-FS2KNUQH.mjs.map +1 -0
  28. package/dist/components/camera.d.ts +1 -0
  29. package/dist/components/camera.d.ts.map +1 -1
  30. package/dist/components/cube-camera.d.ts +20 -0
  31. package/dist/components/cube-camera.d.ts.map +1 -0
  32. package/dist/components/directional-light.d.ts +11 -2
  33. package/dist/components/directional-light.d.ts.map +1 -1
  34. package/dist/components/directional-shadow-filter.d.ts +25 -0
  35. package/dist/components/directional-shadow-filter.d.ts.map +1 -0
  36. package/dist/components/index.d.ts +2 -0
  37. package/dist/components/index.d.ts.map +1 -1
  38. package/dist/components/light-helpers.d.ts.map +1 -1
  39. package/dist/components/reflection-probe.d.ts +17 -0
  40. package/dist/components/reflection-probe.d.ts.map +1 -0
  41. package/dist/components/spot-light.d.ts +12 -0
  42. package/dist/components/spot-light.d.ts.map +1 -1
  43. package/dist/construct-renderer.mjs +8552 -1612
  44. package/dist/construct-renderer.mjs.map +1 -1
  45. package/dist/device/gpu-residency.d.ts +19 -2
  46. package/dist/device/gpu-residency.d.ts.map +1 -1
  47. package/dist/environment/frame.d.ts.map +1 -1
  48. package/dist/environment/lifecycle.d.ts +5 -0
  49. package/dist/environment/lifecycle.d.ts.map +1 -1
  50. package/dist/errors/render.d.ts +209 -93
  51. package/dist/errors/render.d.ts.map +1 -1
  52. package/dist/extract/directional-shadow-projection.d.ts +23 -0
  53. package/dist/extract/directional-shadow-projection.d.ts.map +1 -0
  54. package/dist/extract/environment.d.ts +14 -0
  55. package/dist/extract/environment.d.ts.map +1 -1
  56. package/dist/extract/visibility.d.ts.map +1 -1
  57. package/dist/features/fullscreen.d.ts.map +1 -1
  58. package/dist/features/targets.d.ts.map +1 -1
  59. package/dist/features/types.d.ts +10 -0
  60. package/dist/features/types.d.ts.map +1 -1
  61. package/dist/fullscreen-post-process-pass.d.ts +13 -2
  62. package/dist/fullscreen-post-process-pass.d.ts.map +1 -1
  63. package/dist/gpu-driven/batch-topology.d.ts.map +1 -1
  64. package/dist/gpu-driven/production-raster.d.ts +0 -1
  65. package/dist/gpu-driven/production-raster.d.ts.map +1 -1
  66. package/dist/gpu-scene.d.ts.map +1 -1
  67. package/dist/gpu-usage.d.ts +2 -0
  68. package/dist/gpu-usage.d.ts.map +1 -1
  69. package/dist/hdrp-buffers.d.ts +19 -17
  70. package/dist/hdrp-buffers.d.ts.map +1 -1
  71. package/dist/ibl/IblPipelineCache.d.ts +4 -0
  72. package/dist/ibl/IblPipelineCache.d.ts.map +1 -1
  73. package/dist/ibl/kernel-cache.d.ts +36 -0
  74. package/dist/ibl/kernel-cache.d.ts.map +1 -0
  75. package/dist/index.d.ts +35 -4
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.mjs +4 -4
  78. package/dist/index.mjs.map +1 -1
  79. package/dist/inspection-types.d.ts +51 -0
  80. package/dist/inspection-types.d.ts.map +1 -1
  81. package/dist/instances-derived-bounds.d.ts +50 -0
  82. package/dist/instances-derived-bounds.d.ts.map +1 -0
  83. package/dist/internal.mjs +1 -1
  84. package/dist/light-buffer-layout.d.ts +30 -13
  85. package/dist/light-buffer-layout.d.ts.map +1 -1
  86. package/dist/mesh-material-bindings.d.ts +54 -0
  87. package/dist/mesh-material-bindings.d.ts.map +1 -1
  88. package/dist/pbr-pipeline.d.ts +20 -7
  89. package/dist/pbr-pipeline.d.ts.map +1 -1
  90. package/dist/pipeline/standard-forward-lane.d.ts +2 -1
  91. package/dist/pipeline/standard-forward-lane.d.ts.map +1 -1
  92. package/dist/pipeline/standard-lighting/errors.d.ts +4 -0
  93. package/dist/pipeline/standard-lighting/errors.d.ts.map +1 -0
  94. package/dist/pipeline/standard-lighting/graph.d.ts +24 -0
  95. package/dist/pipeline/standard-lighting/graph.d.ts.map +1 -0
  96. package/dist/pipeline/standard-lighting/inspection.d.ts +38 -0
  97. package/dist/pipeline/standard-lighting/inspection.d.ts.map +1 -0
  98. package/dist/pipeline/standard-lighting/layout.d.ts +28 -0
  99. package/dist/pipeline/standard-lighting/layout.d.ts.map +1 -0
  100. package/dist/pipeline/standard-lighting/light-frame.d.ts +33 -0
  101. package/dist/pipeline/standard-lighting/light-frame.d.ts.map +1 -0
  102. package/dist/pipeline/standard-lighting/membership.d.ts +14 -0
  103. package/dist/pipeline/standard-lighting/membership.d.ts.map +1 -0
  104. package/dist/pipeline/standard-lighting/prepare.d.ts +16 -0
  105. package/dist/pipeline/standard-lighting/prepare.d.ts.map +1 -0
  106. package/dist/pipeline/standard-lighting/topology.d.ts +45 -0
  107. package/dist/pipeline/standard-lighting/topology.d.ts.map +1 -0
  108. package/dist/pipeline/standard-lighting/transport.d.ts +36 -0
  109. package/dist/pipeline/standard-lighting/transport.d.ts.map +1 -0
  110. package/dist/pipeline/standard-pipeline.d.ts +4 -13
  111. package/dist/pipeline/standard-pipeline.d.ts.map +1 -1
  112. package/dist/pipeline/standard-post.d.ts.map +1 -1
  113. package/dist/pipeline/standard-profile.d.ts +12 -20
  114. package/dist/pipeline/standard-profile.d.ts.map +1 -1
  115. package/dist/pipeline-spec.d.ts +40 -7
  116. package/dist/pipeline-spec.d.ts.map +1 -1
  117. package/dist/point-shadow-inspection.d.ts +21 -0
  118. package/dist/point-shadow-inspection.d.ts.map +1 -0
  119. package/dist/record/frame-lighting.d.ts +29 -32
  120. package/dist/record/frame-lighting.d.ts.map +1 -1
  121. package/dist/record/frame-snapshot.d.ts +65 -15
  122. package/dist/record/frame-snapshot.d.ts.map +1 -1
  123. package/dist/record/frame-targets.d.ts +5 -0
  124. package/dist/record/frame-targets.d.ts.map +1 -1
  125. package/dist/record/frame.d.ts +12 -5
  126. package/dist/record/frame.d.ts.map +1 -1
  127. package/dist/record/gpu-pass-timing/contract.d.ts +96 -0
  128. package/dist/record/gpu-pass-timing/contract.d.ts.map +1 -0
  129. package/dist/record/gpu-pass-timing/errors.d.ts +18 -0
  130. package/dist/record/gpu-pass-timing/errors.d.ts.map +1 -0
  131. package/dist/record/gpu-pass-timing/index.d.ts +8 -0
  132. package/dist/record/gpu-pass-timing/index.d.ts.map +1 -0
  133. package/dist/record/gpu-pass-timing/parser.d.ts +11 -0
  134. package/dist/record/gpu-pass-timing/parser.d.ts.map +1 -0
  135. package/dist/record/gpu-pass-timing/session.d.ts +43 -0
  136. package/dist/record/gpu-pass-timing/session.d.ts.map +1 -0
  137. package/dist/record/gpu-timing.d.ts +37 -0
  138. package/dist/record/gpu-timing.d.ts.map +1 -0
  139. package/dist/record/main-pass-geometry.d.ts.map +1 -1
  140. package/dist/record/main-pass-material.d.ts +23 -2
  141. package/dist/record/main-pass-material.d.ts.map +1 -1
  142. package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
  143. package/dist/record/main-pass.d.ts +2 -0
  144. package/dist/record/main-pass.d.ts.map +1 -1
  145. package/dist/record/render-context.d.ts +48 -3
  146. package/dist/record/render-context.d.ts.map +1 -1
  147. package/dist/record/shadow-pass.d.ts.map +1 -1
  148. package/dist/record/skybox-post-pass.d.ts.map +1 -1
  149. package/dist/record/typed-frame-graph.d.ts +81 -5
  150. package/dist/record/typed-frame-graph.d.ts.map +1 -1
  151. package/dist/record/view-ubo.d.ts +7 -4
  152. package/dist/record/view-ubo.d.ts.map +1 -1
  153. package/dist/reflection/filter.d.ts +22 -0
  154. package/dist/reflection/filter.d.ts.map +1 -0
  155. package/dist/reflection/gpu-table.d.ts +25 -0
  156. package/dist/reflection/gpu-table.d.ts.map +1 -0
  157. package/dist/reflection/projection.d.ts +91 -0
  158. package/dist/reflection/projection.d.ts.map +1 -0
  159. package/dist/render-contract.d.ts +114 -7
  160. package/dist/render-contract.d.ts.map +1 -1
  161. package/dist/render-data.d.ts +10 -6
  162. package/dist/render-data.d.ts.map +1 -1
  163. package/dist/render-graph-primitives.d.ts +1 -0
  164. package/dist/render-graph-primitives.d.ts.map +1 -1
  165. package/dist/render-pipeline.d.ts +78 -2
  166. package/dist/render-pipeline.d.ts.map +1 -1
  167. package/dist/render-system-extract.d.ts +113 -20
  168. package/dist/render-system-extract.d.ts.map +1 -1
  169. package/dist/render-system.d.ts +24 -3
  170. package/dist/render-system.d.ts.map +1 -1
  171. package/dist/renderer-inspect.d.ts +29 -0
  172. package/dist/renderer-inspect.d.ts.map +1 -0
  173. package/dist/renderer.d.ts +43 -0
  174. package/dist/renderer.d.ts.map +1 -0
  175. package/dist/scene/render-scene.d.ts +14 -0
  176. package/dist/scene/render-scene.d.ts.map +1 -1
  177. package/dist/shadow-atlas.d.ts +3 -3
  178. package/dist/shadow-atlas.d.ts.map +1 -1
  179. package/dist/ssao-buffers.d.ts +3 -0
  180. package/dist/ssao-buffers.d.ts.map +1 -1
  181. package/dist/targets/contracts.d.ts +66 -0
  182. package/dist/targets/contracts.d.ts.map +1 -0
  183. package/dist/targets/graph-projection.d.ts +29 -0
  184. package/dist/targets/graph-projection.d.ts.map +1 -0
  185. package/dist/targets/material-source.d.ts +34 -0
  186. package/dist/targets/material-source.d.ts.map +1 -0
  187. package/dist/targets/owner.d.ts +32 -0
  188. package/dist/targets/owner.d.ts.map +1 -0
  189. package/dist/targets/physical.d.ts +18 -0
  190. package/dist/targets/physical.d.ts.map +1 -0
  191. package/dist/targets/readback.d.ts +39 -0
  192. package/dist/targets/readback.d.ts.map +1 -0
  193. package/dist/temporal/frame.d.ts +44 -0
  194. package/dist/temporal/frame.d.ts.map +1 -0
  195. package/dist/temporal/index.mjs +3 -3
  196. package/dist/typed-render-graph-primitives.d.ts +6 -1
  197. package/dist/typed-render-graph-primitives.d.ts.map +1 -1
  198. package/dist/typed-shadow-atlas.d.ts +10 -0
  199. package/dist/typed-shadow-atlas.d.ts.map +1 -0
  200. package/dist/typed-shadow-passes.d.ts +1 -1
  201. package/dist/typed-shadow-passes.d.ts.map +1 -1
  202. package/dist/volume/capability.d.ts +57 -0
  203. package/dist/volume/capability.d.ts.map +1 -0
  204. package/dist/volume/component.d.ts +61 -0
  205. package/dist/volume/component.d.ts.map +1 -0
  206. package/dist/volume/extract.d.ts +11 -0
  207. package/dist/volume/extract.d.ts.map +1 -0
  208. package/dist/volume/inspection.d.ts +38 -0
  209. package/dist/volume/inspection.d.ts.map +1 -0
  210. package/dist/volume/passes.d.ts +38 -0
  211. package/dist/volume/passes.d.ts.map +1 -0
  212. package/dist/volume/recovery.d.ts +38 -0
  213. package/dist/volume/recovery.d.ts.map +1 -0
  214. package/dist/volume/resources.d.ts +57 -0
  215. package/dist/volume/resources.d.ts.map +1 -0
  216. package/dist/volume/temporal.d.ts +35 -0
  217. package/dist/volume/temporal.d.ts.map +1 -0
  218. package/package.json +20 -20
  219. package/src/__tests__/bloom-exact-zero.unit.test.ts +48 -19
  220. package/src/__tests__/bloom-lifecycle.integration.test.ts +41 -13
  221. package/src/__tests__/camera-target-consumption.unit.test.ts +53 -0
  222. package/src/__tests__/cluster-binner.unit.test.ts +35 -0
  223. package/src/__tests__/cluster-grid-default-surface.unit.test.ts +7 -2
  224. package/src/__tests__/cube-camera-scheduler.unit.test.ts +70 -0
  225. package/src/__tests__/cube-camera-single-submit.perf.test.ts +75 -0
  226. package/src/__tests__/cube-camera-view-matrices.unit.test.ts +41 -0
  227. package/src/__tests__/cube-camera-vocabulary.unit.test.ts +47 -0
  228. package/src/__tests__/cube-camera.integration.test.ts +42 -0
  229. package/src/__tests__/device-feature-admission.unit.test.ts +73 -0
  230. package/src/__tests__/direct-light-snapshot.unit.test.ts +3 -3
  231. package/src/__tests__/docs-gate-green.unit.test.ts +38 -0
  232. package/src/__tests__/factory-contract.integration.test.ts +255 -29
  233. package/src/__tests__/fog-component.unit.test.ts +67 -0
  234. package/src/__tests__/fog.integration.test.ts +86 -0
  235. package/src/__tests__/fullscreen-feature-plan.unit.test.ts +37 -0
  236. package/src/__tests__/gpu-driven-indirect-raster-evidence.ts +10 -9
  237. package/src/__tests__/gpu-driven-indirect-raster.dawn.test.ts +17 -1
  238. package/src/__tests__/gpu-driven-production.integration.test.ts +16 -17
  239. package/src/__tests__/gpu-driven-view-graph.integration.test.ts +12 -4
  240. package/src/__tests__/gpu-pass-timing-browser-runner.ts +281 -0
  241. package/src/__tests__/gpu-pass-timing-coexistence.integration.test.ts +80 -0
  242. package/src/__tests__/gpu-pass-timing-contract.unit.test.ts +243 -0
  243. package/src/__tests__/gpu-pass-timing-exact-zero.unit.test.ts +131 -0
  244. package/src/__tests__/gpu-pass-timing-lifecycle.integration.test.ts +230 -0
  245. package/src/__tests__/gpu-pass-timing-observation.unit.test.ts +233 -0
  246. package/src/__tests__/gpu-pass-timing-session.unit.test.ts +438 -0
  247. package/src/__tests__/gpu-pass-timing.browser.test.ts +26 -0
  248. package/src/__tests__/gpu-pass-timing.rhi-null.unit.test.ts +125 -0
  249. package/src/__tests__/hdrp-group2-visibility.unit.test.ts +24 -0
  250. package/src/__tests__/instances-culling.integration.test.ts +94 -0
  251. package/src/__tests__/instances-derived-bounds.unit.test.ts +118 -0
  252. package/src/__tests__/ktx2-basis-gpu-consumer.dawn.test.ts +14 -14
  253. package/src/__tests__/material-observation.integration.test.ts +101 -0
  254. package/src/__tests__/mesh-buffer-usage-surface.unit.test.ts +1 -1
  255. package/src/__tests__/pbr-view-layout.unit.test.ts +16 -0
  256. package/src/__tests__/point-shadow-inspection.unit.test.ts +60 -0
  257. package/src/__tests__/public-surface.test-d.ts +10 -0
  258. package/src/__tests__/reflection-probe-authoring.unit.test.ts +71 -0
  259. package/src/__tests__/reflection-probe-filter.unit.test.ts +54 -0
  260. package/src/__tests__/reflection-probe-ibl-topology.unit.test.ts +45 -0
  261. package/src/__tests__/reflection-probe-pass-encode.integration.test.ts +101 -0
  262. package/src/__tests__/reflection-probe-performance.perf.test.ts +60 -0
  263. package/src/__tests__/reflection-probe-recovery.integration.test.ts +55 -0
  264. package/src/__tests__/reflection-probe-selection.unit.test.ts +46 -0
  265. package/src/__tests__/render-error-code-owner.test-d.ts +23 -3
  266. package/src/__tests__/render-feature-docs.unit.test.ts +1 -1
  267. package/src/__tests__/render-target-admission.unit.test.ts +80 -0
  268. package/src/__tests__/render-target-graph-projection.unit.test.ts +102 -0
  269. package/src/__tests__/render-target-inspection.unit.test.ts +52 -0
  270. package/src/__tests__/render-target-material-source.test-d.ts +30 -0
  271. package/src/__tests__/render-target-material-source.unit.test.ts +97 -0
  272. package/src/__tests__/render-target-owner-placement.unit.test.ts +203 -0
  273. package/src/__tests__/render-target-owner.unit.test.ts +122 -0
  274. package/src/__tests__/render-target-probe-soak.perf.test.ts +94 -0
  275. package/src/__tests__/render-target-public-schema.json +107 -0
  276. package/src/__tests__/render-target-public-schema.unit.test.ts +91 -0
  277. package/src/__tests__/render-target-public-surface.test-d.ts +83 -0
  278. package/src/__tests__/render-target-readback.integration.test.ts +90 -0
  279. package/src/__tests__/render-target-recovery.integration.test.ts +85 -0
  280. package/src/__tests__/renderer-factory-material-contract.unit.test.ts +76 -0
  281. package/src/__tests__/renderer-frame-transaction.integration.test.ts +1 -1
  282. package/src/__tests__/renderer-lifecycle.integration.test.ts +14 -0
  283. package/src/__tests__/shader-stage-surface.unit.test.ts +19 -4
  284. package/src/__tests__/skin-motion-regression.unit.test.ts +132 -0
  285. package/src/__tests__/skinned-shadow-caster.test.ts +32 -2
  286. package/src/__tests__/standard-cluster-capability.integration.test.ts +63 -0
  287. package/src/__tests__/standard-cluster-transport.unit.test.ts +121 -0
  288. package/src/__tests__/standard-cluster-variant-resolution.unit.test.ts +232 -0
  289. package/src/__tests__/standard-clustered-pipeline.unit.test.ts +8 -5
  290. package/src/__tests__/standard-lighting-inspection.integration.test.ts +138 -0
  291. package/src/__tests__/standard-lighting-ssot.unit.test.ts +18 -0
  292. package/src/__tests__/standard-lighting-write.unit.test.ts +377 -0
  293. package/src/__tests__/standard-lighting.integration.test.ts +67 -0
  294. package/src/__tests__/standard-pipeline.dawn.test.ts +206 -5
  295. package/src/__tests__/standard-pipeline.integration.test.ts +181 -150
  296. package/src/__tests__/standard-probe-binding.unit.test.ts +25 -0
  297. package/src/__tests__/standard-profile-oracle.unit.test.ts +23 -36
  298. package/src/__tests__/typed-pipeline-topology.unit.test.ts +395 -14
  299. package/src/__tests__/urp-pipeline-targets.unit.test.ts +2 -2
  300. package/src/__tests__/visibility-resolver.unit.test.ts +15 -0
  301. package/src/__tests__/volume-optics-oracle.unit.test.ts +85 -0
  302. package/src/__tests__/volumetric-fog-budget-recovery.integration.test.ts +655 -0
  303. package/src/__tests__/volumetric-fog-component.unit.test.ts +71 -0
  304. package/src/__tests__/volumetric-fog-composite-stage-readback.dawn.test.ts +376 -0
  305. package/src/__tests__/volumetric-fog-errors.unit.test.ts +51 -0
  306. package/src/__tests__/volumetric-fog-inspection.unit.test.ts +77 -0
  307. package/src/__tests__/volumetric-fog-light-capability.unit.test.ts +19 -0
  308. package/src/__tests__/volumetric-fog-light-consumers.integration.test.ts +18 -0
  309. package/src/__tests__/volumetric-fog-light-errors.unit.test.ts +17 -0
  310. package/src/__tests__/volumetric-fog-light-topology.unit.test.ts +21 -0
  311. package/src/__tests__/volumetric-fog-light-transaction.integration.test.ts +53 -0
  312. package/src/__tests__/volumetric-fog-m9-watcher.integration.test.ts +27 -0
  313. package/src/__tests__/volumetric-fog-point-light-owner.integration.test.ts +44 -0
  314. package/src/__tests__/volumetric-fog-point-spot-accumulation.integration.test.ts +49 -0
  315. package/src/__tests__/volumetric-fog-point-spot-contract.unit.test.ts +28 -0
  316. package/src/__tests__/volumetric-fog-point-spot-lkg.integration.test.ts +65 -0
  317. package/src/__tests__/volumetric-fog-point-spot-selection.integration.test.ts +49 -0
  318. package/src/__tests__/volumetric-fog-point-spot-temporal.unit.test.ts +55 -0
  319. package/src/__tests__/volumetric-fog-projector-contract.unit.test.ts +22 -0
  320. package/src/__tests__/volumetric-fog-projector-inspection.unit.test.ts +12 -0
  321. package/src/__tests__/volumetric-fog-projector-surface-volume.integration.test.ts +11 -0
  322. package/src/__tests__/volumetric-fog-projector-transaction.integration.test.ts +26 -0
  323. package/src/__tests__/volumetric-fog-recovery.integration.test.ts +47 -0
  324. package/src/__tests__/volumetric-fog-selected-light-resolution.integration.test.ts +63 -0
  325. package/src/__tests__/volumetric-fog-spot-closure.integration.test.ts +26 -0
  326. package/src/__tests__/volumetric-fog-spot-contract.test-d.ts +21 -0
  327. package/src/__tests__/volumetric-fog-spot-contract.unit.test.ts +27 -0
  328. package/src/__tests__/volumetric-fog-spot-frame-optics.integration.test.ts +14 -0
  329. package/src/__tests__/volumetric-fog-spot-optics.integration.test.ts +29 -0
  330. package/src/__tests__/volumetric-fog-stage-readback.dawn.test.ts +550 -0
  331. package/src/__tests__/volumetric-fog-temporal-selected-light.unit.test.ts +33 -0
  332. package/src/__tests__/volumetric-fog-temporal.unit.test.ts +45 -0
  333. package/src/__tests__/volumetric-fog-topology.unit.test.ts +237 -0
  334. package/src/__tests__/volumetric-fog-transparent.integration.test.ts +27 -0
  335. package/src/assembly/device-feature-admission.ts +73 -0
  336. package/src/assembly/directional-shadow-inspection.ts +122 -0
  337. package/src/assembly/factory.ts +1093 -246
  338. package/src/assembly/host-contract.ts +25 -0
  339. package/src/assembly/render-target-host.ts +847 -0
  340. package/src/assets/asset-decoders.ts +1 -1
  341. package/src/assets/render-asset-port.ts +7 -1
  342. package/src/capture/cube-views.ts +69 -0
  343. package/src/capture/scheduler.ts +265 -0
  344. package/src/components/__tests__/schema-contract.unit.test.ts +12 -0
  345. package/src/components/__tests__/schema-parity.unit.test.ts +9 -0
  346. package/src/components/camera.ts +4 -0
  347. package/src/components/cube-camera.ts +52 -0
  348. package/src/components/directional-light.ts +22 -2
  349. package/src/components/directional-shadow-filter.ts +57 -0
  350. package/src/components/index.ts +2 -0
  351. package/src/components/light-helpers.ts +85 -7
  352. package/src/components/reflection-probe.ts +49 -0
  353. package/src/components/spot-light.ts +22 -3
  354. package/src/device/gpu-residency.ts +168 -58
  355. package/src/environment/frame.ts +6 -24
  356. package/src/environment/lifecycle.ts +12 -0
  357. package/src/errors/render.ts +405 -143
  358. package/src/extract/directional-shadow-projection.ts +61 -0
  359. package/src/extract/environment.ts +57 -0
  360. package/src/extract/visibility.ts +25 -1
  361. package/src/features/fullscreen.ts +3 -0
  362. package/src/features/targets.ts +4 -1
  363. package/src/features/types.ts +10 -0
  364. package/src/fullscreen-post-process-pass.ts +43 -2
  365. package/src/gpu-driven/batch-topology.ts +1 -0
  366. package/src/gpu-driven/production-raster.ts +1 -3
  367. package/src/gpu-scene.ts +8 -1
  368. package/src/gpu-usage.ts +2 -0
  369. package/src/hdrp-buffers.ts +165 -59
  370. package/src/ibl/IblPipelineCache.ts +11 -0
  371. package/src/ibl/kernel-cache.ts +88 -0
  372. package/src/index.ts +186 -1
  373. package/src/inspection-types.ts +56 -0
  374. package/src/instances-derived-bounds.ts +171 -0
  375. package/src/light-buffer-layout.ts +74 -26
  376. package/src/mesh-material-bindings.ts +132 -0
  377. package/src/pbr-pipeline.ts +139 -27
  378. package/src/pipeline/standard-forward-lane.ts +65 -15
  379. package/src/pipeline/standard-lighting/errors.ts +6 -0
  380. package/src/pipeline/standard-lighting/graph.ts +157 -0
  381. package/src/pipeline/standard-lighting/inspection.ts +88 -0
  382. package/src/pipeline/standard-lighting/layout.ts +31 -0
  383. package/src/pipeline/standard-lighting/light-frame.ts +34 -0
  384. package/src/pipeline/standard-lighting/membership.ts +43 -0
  385. package/src/pipeline/standard-lighting/prepare.ts +37 -0
  386. package/src/pipeline/standard-lighting/topology.ts +120 -0
  387. package/src/pipeline/standard-lighting/transport.ts +77 -0
  388. package/src/pipeline/standard-pipeline.ts +141 -192
  389. package/src/pipeline/standard-post.ts +26 -7
  390. package/src/pipeline/standard-profile.ts +23 -30
  391. package/src/pipeline-spec.ts +84 -21
  392. package/src/point-shadow-inspection.ts +55 -0
  393. package/src/record/__tests__/temporal-payload.unit.test.ts +42 -1
  394. package/src/record/__tests__/transparent-group2-selection.unit.test.ts +73 -0
  395. package/src/record/__tests__/view-ubo-layout.unit.test.ts +40 -0
  396. package/src/record/frame-lighting.ts +470 -516
  397. package/src/record/frame-snapshot.ts +76 -28
  398. package/src/record/frame-targets.ts +23 -2
  399. package/src/record/frame.ts +1169 -79
  400. package/src/record/gpu-pass-timing/contract.ts +180 -0
  401. package/src/record/gpu-pass-timing/errors.ts +34 -0
  402. package/src/record/gpu-pass-timing/index.ts +37 -0
  403. package/src/record/gpu-pass-timing/parser.ts +97 -0
  404. package/src/record/gpu-pass-timing/session.ts +938 -0
  405. package/src/record/gpu-timing.ts +233 -0
  406. package/src/record/main-pass-geometry.ts +120 -80
  407. package/src/record/main-pass-material.ts +101 -11
  408. package/src/record/main-pass-sprite-draws.ts +54 -25
  409. package/src/record/main-pass.ts +71 -15
  410. package/src/record/render-context.ts +77 -0
  411. package/src/record/shadow-pass.ts +104 -66
  412. package/src/record/skybox-post-pass.ts +20 -4
  413. package/src/record/typed-frame-graph.ts +1016 -32
  414. package/src/record/view-ubo.ts +63 -28
  415. package/src/reflection/filter.ts +81 -0
  416. package/src/reflection/gpu-table.ts +44 -0
  417. package/src/reflection/projection.ts +281 -0
  418. package/src/render-contract.ts +147 -4
  419. package/src/render-data.ts +50 -22
  420. package/src/render-graph-primitives.ts +9 -4
  421. package/src/render-pipeline.ts +161 -2
  422. package/src/render-system-extract.ts +886 -103
  423. package/src/render-system.ts +1174 -66
  424. package/src/renderer-inspect.ts +66 -0
  425. package/src/renderer.ts +222 -0
  426. package/src/scene/render-scene.ts +117 -9
  427. package/src/shadow-atlas.ts +5 -5
  428. package/src/ssao-buffers.ts +9 -2
  429. package/src/targets/contracts.ts +182 -0
  430. package/src/targets/graph-projection.ts +169 -0
  431. package/src/targets/material-source.ts +143 -0
  432. package/src/targets/owner.ts +214 -0
  433. package/src/targets/physical.ts +18 -0
  434. package/src/targets/readback.ts +153 -0
  435. package/src/temporal/frame.ts +128 -0
  436. package/src/transmission/__tests__/standard-transmission.dawn.test.ts +61 -23
  437. package/src/typed-render-graph-primitives.ts +34 -2
  438. package/src/typed-shadow-atlas.ts +17 -0
  439. package/src/typed-shadow-passes.ts +47 -40
  440. package/src/volume/capability.ts +173 -0
  441. package/src/volume/component.ts +110 -0
  442. package/src/volume/extract.ts +21 -0
  443. package/src/volume/inspection.ts +78 -0
  444. package/src/volume/passes.ts +686 -0
  445. package/src/volume/recovery.ts +86 -0
  446. package/src/volume/resources.ts +236 -0
  447. package/src/volume/temporal.ts +89 -0
  448. package/dist/chunk-IPXCABEP.mjs.map +0 -1
  449. package/dist/chunk-LOSO4CTV.mjs.map +0 -1
  450. package/dist/chunk-RJRUS55L.mjs.map +0 -1
  451. package/dist/chunk-YTQ5C7YQ.mjs +0 -584
  452. package/dist/chunk-YTQ5C7YQ.mjs.map +0 -1
@@ -0,0 +1,120 @@
1
+ import { err, ok, type Result } from '@forgeax/engine-types';
2
+ import type { PreparedStandardLighting } from './prepare';
3
+ import type { StandardClusterTransport } from './transport';
4
+
5
+ /** A prepared frame with no local lights on a non-storage direct backend. */
6
+ export interface StandardNoLocalTopologyInput {
7
+ readonly kind: 'no-local-lights';
8
+ readonly prepared: PreparedStandardLighting;
9
+ }
10
+
11
+ /** A prepared frame whose Standard surface uses one proven Cluster transport. */
12
+ export interface StandardClusteredTopologyInput {
13
+ readonly kind: 'clustered';
14
+ readonly prepared: PreparedStandardLighting;
15
+ readonly transport: StandardClusterTransport;
16
+ }
17
+
18
+ /**
19
+ * The only lighting value accepted by a Standard topology adapter. It is a
20
+ * projection of one prepared frame, not a second light/config/capability
21
+ * input. Both Forward and Deferred keep the same object identity for a frame.
22
+ */
23
+ export type StandardTopologyInput = StandardNoLocalTopologyInput | StandardClusteredTopologyInput;
24
+
25
+ export type StandardTopologyInputValue = StandardTopologyInput;
26
+
27
+ /**
28
+ * Stable identity for the graph-facing Standard lighting declaration.
29
+ *
30
+ * The prepared light payload itself is frame-local and must never be retained
31
+ * by a compiled graph. These are the only facts that affect the Cluster graph
32
+ * shape and persistent buffer contract, so the record owner can reject an old
33
+ * graph before uploading a payload derived from a different declaration.
34
+ */
35
+ export function standardLightingTopologySignature(
36
+ input: StandardTopologyInputValue | undefined,
37
+ ): string {
38
+ if (input === undefined) return 'missing';
39
+ if (input.kind === 'no-local-lights') return 'no-local-lights';
40
+ return JSON.stringify({
41
+ kind: input.kind,
42
+ transport: input.transport.kind,
43
+ producer: input.transport.producer,
44
+ grid: input.prepared.layout.grid,
45
+ clusterGridU32Length: input.prepared.layout.clusterGridU32Length,
46
+ lightIndexListCapacity: input.prepared.layout.lightIndexListCapacity,
47
+ lightDataSlotCount: input.prepared.layout.lightDataSlotCount,
48
+ lightBoundsInt32Length: input.prepared.layout.lightBoundsInt32Length,
49
+ });
50
+ }
51
+
52
+ export interface StandardTopologyInputError {
53
+ readonly code: 'topology-input-invalid';
54
+ readonly expected: 'prepared Standard lighting topology input';
55
+ readonly hint: 'derive topology from prepared Standard lighting';
56
+ readonly detail: {
57
+ readonly field: 'kind' | 'prepared' | 'transport' | 'lights' | 'capabilities';
58
+ };
59
+ }
60
+
61
+ function invalid(
62
+ field: StandardTopologyInputError['detail']['field'],
63
+ ): Result<never, StandardTopologyInputError> {
64
+ return err({
65
+ code: 'topology-input-invalid',
66
+ expected: 'prepared Standard lighting topology input',
67
+ hint: 'derive topology from prepared Standard lighting',
68
+ detail: { field },
69
+ });
70
+ }
71
+
72
+ /**
73
+ * Validate that transport and prepared membership are the same derivation.
74
+ * The identity checks make it impossible for an adapter to silently combine
75
+ * one path's layout/counts with another path's prepared light corpus.
76
+ */
77
+ export function deriveStandardTopologyInput(
78
+ input: StandardTopologyInput,
79
+ ): Result<StandardTopologyInputValue, StandardTopologyInputError> {
80
+ const candidate = input as StandardTopologyInput & {
81
+ readonly kind?: unknown;
82
+ readonly lights?: unknown;
83
+ readonly capabilities?: unknown;
84
+ readonly transport?: unknown;
85
+ };
86
+ if ('lights' in candidate) return invalid('lights');
87
+ if ('capabilities' in candidate) return invalid('capabilities');
88
+ if (input === null || typeof input !== 'object') return invalid('kind');
89
+ if (input.prepared === null || typeof input.prepared !== 'object') {
90
+ return invalid('prepared');
91
+ }
92
+
93
+ const prepared = input.prepared;
94
+ if (input.kind === 'no-local-lights') {
95
+ if (prepared.local.length !== 0 || 'transport' in candidate) return invalid('transport');
96
+ return ok(input);
97
+ }
98
+ if (input.kind !== 'clustered') return invalid('kind');
99
+ if (
100
+ !('transport' in candidate) ||
101
+ candidate.transport === null ||
102
+ typeof candidate.transport !== 'object'
103
+ ) {
104
+ return invalid('transport');
105
+ }
106
+
107
+ const transport = input.transport;
108
+ const requested = prepared.local.length;
109
+ const transportMatchesPrepared =
110
+ transport.layout === prepared.layout &&
111
+ transport.requestedLightCount === requested &&
112
+ transport.admittedLightCount === requested &&
113
+ transport.membershipEntryCount === prepared.membershipEntryCount &&
114
+ transport.lightBoundsBytes === prepared.lightBounds.byteLength;
115
+ const producerMatchesKind =
116
+ (transport.producer === 'gpu' && transport.kind === 'compute-storage') ||
117
+ (transport.producer === 'cpu' && transport.kind === 'cpu-storage');
118
+ if (!transportMatchesPrepared || !producerMatchesKind) return invalid('transport');
119
+ return ok(input);
120
+ }
@@ -0,0 +1,77 @@
1
+ import { err, ok, type Result } from '@forgeax/engine-types';
2
+ import { type RenderError, StandardClusterTransportUnavailableError } from '../../errors/render';
3
+ import type { PreparedStandardLighting } from './prepare';
4
+
5
+ export interface StandardClusterCapabilities {
6
+ readonly compute: boolean;
7
+ readonly storageBuffer: boolean;
8
+ /**
9
+ * The graph producer is ready to encode the selected compute lane. The
10
+ * renderer supplies this from the actual pipeline + bind-group layout; it is
11
+ * required so capability admission cannot forge a GPU producer from
12
+ * `compute` alone.
13
+ */
14
+ readonly membershipPipelineReady: boolean;
15
+ }
16
+
17
+ /** Only transports with storage-backed membership representation exist. */
18
+ export type StandardClusterTransportKind = 'compute-storage' | 'cpu-storage';
19
+ export type StandardClusterMembershipProducer = 'cpu' | 'gpu';
20
+
21
+ export interface StandardClusterTransport {
22
+ readonly kind: StandardClusterTransportKind;
23
+ readonly producer: StandardClusterMembershipProducer;
24
+ readonly layout: PreparedStandardLighting['layout'];
25
+ readonly requestedLightCount: number;
26
+ readonly admittedLightCount: number;
27
+ readonly membershipEntryCount: number;
28
+ readonly occupiedClusterCount: number;
29
+ readonly clusterGridBytes: number;
30
+ readonly lightIndexListBytes: number;
31
+ readonly lightDataBytes: number;
32
+ readonly lightBoundsBytes: number;
33
+ }
34
+
35
+ function occupiedClusterCount(prepared: PreparedStandardLighting): number {
36
+ let occupied = 0;
37
+ for (let index = 1; index < prepared.clusterGrid.length; index += 2) {
38
+ if ((prepared.clusterGrid[index] ?? 0) > 0) occupied += 1;
39
+ }
40
+ return occupied;
41
+ }
42
+
43
+ /**
44
+ * Select a transport from one prepared frame. Capability facts choose only a
45
+ * producer/storage pair; all counts and byte sizes come from that frame.
46
+ */
47
+ export function selectStandardClusterTransport(
48
+ capabilities: StandardClusterCapabilities,
49
+ prepared: PreparedStandardLighting,
50
+ ): Result<StandardClusterTransport, RenderError> {
51
+ const requested = prepared.local.length;
52
+ if (!capabilities.storageBuffer) {
53
+ return err(
54
+ new StandardClusterTransportUnavailableError(
55
+ requested,
56
+ 'enable a proven storage-buffer Cluster transport; compute without storage is not a membership path',
57
+ ),
58
+ );
59
+ }
60
+
61
+ const producer: StandardClusterMembershipProducer =
62
+ capabilities.compute && capabilities.membershipPipelineReady ? 'gpu' : 'cpu';
63
+ const kind: StandardClusterTransportKind = producer === 'gpu' ? 'compute-storage' : 'cpu-storage';
64
+ return ok({
65
+ kind,
66
+ producer,
67
+ layout: prepared.layout,
68
+ requestedLightCount: requested,
69
+ admittedLightCount: requested,
70
+ membershipEntryCount: prepared.membershipEntryCount,
71
+ occupiedClusterCount: occupiedClusterCount(prepared),
72
+ clusterGridBytes: prepared.layout.clusterGridU32Length * Uint32Array.BYTES_PER_ELEMENT,
73
+ lightIndexListBytes: prepared.membershipEntryCount * Uint32Array.BYTES_PER_ELEMENT,
74
+ lightDataBytes: requested * 64,
75
+ lightBoundsBytes: prepared.lightBounds.byteLength,
76
+ });
77
+ }
@@ -1,21 +1,13 @@
1
- import type {
2
- GraphAccess,
3
- GraphBuffer,
4
- GraphTextureDescriptor,
5
- RenderGraphBuilder,
1
+ import {
2
+ type GraphAccess,
3
+ type GraphTextureDescriptor,
4
+ type RenderGraphBuilder,
6
5
  RenderGraphError,
7
6
  } from '@forgeax/engine-render-graph';
8
7
  import { err, ok, type Result } from '@forgeax/engine-types';
9
- import { HdrpDeferredCapsInsufficientError, SceneDataUnavailableError } from '../errors/render';
8
+ import { SceneDataUnavailableError, StandardProfileInvalidError } from '../errors/render';
10
9
  import type { FramePlan } from '../extract/environment';
11
- import {
12
- GPU_BUFFER_USAGE_COPY_DST,
13
- GPU_BUFFER_USAGE_STORAGE,
14
- GPU_BUFFER_USAGE_UNIFORM,
15
- } from '../gpu-usage';
16
- import { getOrCreateHdrpBuffers, type HdrpBuffers } from '../hdrp-buffers';
17
10
  import { DEFERRED_COLOR_FORMATS } from '../pipeline-spec';
18
- import type { _InternalRenderPipelineContext } from '../record/render-context';
19
11
  import type {
20
12
  RenderPipeline,
21
13
  RenderPipelineBuildContext,
@@ -47,16 +39,21 @@ import {
47
39
  typedFrameClearColor,
48
40
  } from '../typed-render-graph-primitives';
49
41
  import { addTypedShadowPasses } from '../typed-shadow-passes';
50
-
42
+ import { addAuthoredVolumetricFogPasses } from '../volume/passes';
51
43
  import { buildStandardForwardLane } from './standard-forward-lane';
44
+ import {
45
+ addStandardClusterMembershipPass,
46
+ importStandardClusterBuffers,
47
+ standardClusterReadAccesses,
48
+ } from './standard-lighting/graph';
49
+ import {
50
+ deriveStandardTopologyInput,
51
+ type StandardTopologyInputValue,
52
+ } from './standard-lighting/topology';
52
53
  import { addStandardPost } from './standard-post';
53
54
  import {
54
- CLUSTER_GRID_STRIDE_U32,
55
- DEFAULT_CLUSTER_GRID,
56
55
  DEFAULT_STANDARD_PROFILE,
57
- LIGHT_INDEX_LIST_CAPACITY,
58
- MAX_LIGHTS,
59
- resolveStandardLane,
56
+ STANDARD_LIGHT_COUNTS,
60
57
  STANDARD_PIPELINE_ID,
61
58
  type StandardProfile,
62
59
  } from './standard-profile';
@@ -124,26 +121,11 @@ fn cs_cluster_membership(@builtin(global_invocation_id) global_id : vec3<u32>) {
124
121
  }
125
122
  }
126
123
  `;
127
- export class HdrpInstallError extends Error {
128
- readonly code = 'hdrp-grid-invalid' as const;
129
- readonly expected = 'clusterGrid.{x,y,z} each integer in [1, 64]';
130
- readonly hint: string;
131
- readonly detail: { readonly x: number; readonly y: number; readonly z: number };
132
-
133
- constructor(x: number, y: number, z: number) {
134
- const hint = `clusterGrid {x:${x}, y:${y}, z:${z}} is invalid; set {x,y,z} to positive integers in [1, 64]`;
135
- super(`hdrp-grid-invalid: ${hint}`);
136
- this.name = 'HdrpInstallError';
137
- this.hint = hint;
138
- this.detail = { x, y, z };
139
- }
140
- }
141
-
142
124
  export function validateClusterGrid(grid: {
143
125
  x: number;
144
126
  y: number;
145
127
  z: number;
146
- }): Result<{ x: number; y: number; z: number }, HdrpInstallError> {
128
+ }): Result<{ x: number; y: number; z: number }, StandardProfileInvalidError> {
147
129
  const { x, y, z } = grid;
148
130
  return Number.isInteger(x) &&
149
131
  Number.isInteger(y) &&
@@ -155,7 +137,12 @@ export function validateClusterGrid(grid: {
155
137
  z >= 1 &&
156
138
  z <= 64
157
139
  ? ok({ x, y, z })
158
- : err(new HdrpInstallError(x, y, z));
140
+ : err(
141
+ new StandardProfileInvalidError(
142
+ `clusterGrid {x:${x}, y:${y}, z:${z}} is invalid; set x, y, and z to positive integers in [1, 64]`,
143
+ { field: 'clusterGrid', actual: { x, y, z } },
144
+ ),
145
+ );
159
146
  }
160
147
 
161
148
  function target(
@@ -166,114 +153,20 @@ function target(
166
153
  return createRenderPipelineTarget(graph, label, descriptor);
167
154
  }
168
155
 
169
- interface HdrpGraphBuffers {
170
- readonly lightData: GraphBuffer;
171
- readonly clusterGrid: GraphBuffer;
172
- readonly lightIndexList: GraphBuffer;
173
- readonly clusterUniform: GraphBuffer;
174
- readonly lightBounds: GraphBuffer;
175
- }
176
-
177
- function importBuffers(
178
- graph: RenderGraphBuilder<RenderPipelineFrame>,
179
- topology: RenderPipelineTopology,
180
- ): Result<HdrpGraphBuffers, RenderGraphError> {
181
- const grid = topology.config?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
182
- const cells = grid.x * grid.y * grid.z;
183
- const storage = topology.lane.storageBuffer;
184
- const usage =
185
- (storage ? GPU_BUFFER_USAGE_STORAGE : GPU_BUFFER_USAGE_UNIFORM) | GPU_BUFFER_USAGE_COPY_DST;
186
- const resolve = (frame: RenderPipelineFrame): HdrpBuffers => {
187
- const internal = frame as _InternalRenderPipelineContext;
188
- const buffers = getOrCreateHdrpBuffers(internal.runtime, grid);
189
- if (buffers === null) throw new Error('HDRP persistent buffer allocation failed');
190
- return buffers;
191
- };
192
- const lightData = graph.importBuffer(
193
- 'hdrp-light-data',
194
- { size: (storage ? MAX_LIGHTS : 128) * 64, usage },
195
- (frame) => resolve(frame).lightDataBuffer,
196
- );
197
- if (!lightData.ok) return lightData;
198
- const clusterGrid = graph.importBuffer(
199
- 'hdrp-cluster-grid',
200
- { size: storage ? cells * CLUSTER_GRID_STRIDE_U32 * 4 : 32, usage },
201
- (frame) => resolve(frame).clusterGridBuffer,
202
- );
203
- if (!clusterGrid.ok) return clusterGrid;
204
- const lightIndexList = graph.importBuffer(
205
- 'hdrp-light-index-list',
206
- { size: storage ? LIGHT_INDEX_LIST_CAPACITY * 4 : 32, usage },
207
- (frame) => resolve(frame).lightIndexListBuffer,
208
- );
209
- if (!lightIndexList.ok) return lightIndexList;
210
- const clusterUniform = graph.importBuffer(
211
- 'hdrp-cluster-uniform',
212
- { size: 32, usage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST },
213
- (frame) => resolve(frame).clusterUniformBuffer,
214
- );
215
- if (!clusterUniform.ok) return clusterUniform;
216
- const lightBounds = graph.importBuffer(
217
- 'hdrp-light-bounds',
218
- { size: MAX_LIGHTS * 6 * 4, usage },
219
- (frame) => resolve(frame).lightBoundsBuffer,
220
- );
221
- if (!lightBounds.ok) return lightBounds;
222
- return ok({
223
- lightData: lightData.value,
224
- clusterGrid: clusterGrid.value,
225
- lightIndexList: lightIndexList.value,
226
- clusterUniform: clusterUniform.value,
227
- lightBounds: lightBounds.value,
228
- });
229
- }
230
-
231
- function addMembershipPass(
232
- graph: RenderGraphBuilder<RenderPipelineFrame>,
233
- topology: RenderPipelineTopology,
234
- buffers: HdrpGraphBuffers,
235
- ): Result<void, RenderGraphError> {
236
- if (!topology.lane.compute || !topology.lane.storageBuffer) return ok(undefined);
237
- return graph.addComputePass('cluster-membership-producer', {
238
- accesses: [
239
- { resource: buffers.clusterGrid, usage: 'storage-read' },
240
- { resource: buffers.clusterUniform, usage: 'uniform-read' },
241
- { resource: buffers.lightBounds, usage: 'storage-read' },
242
- { resource: buffers.lightIndexList, usage: 'storage-write' },
243
- ],
244
- executeIf: (frame) => {
245
- const internal = frame as _InternalRenderPipelineContext;
246
- return (
247
- internal.pipelineState.hdrpClusterMembershipPipeline !== null &&
248
- internal.hdrpClusterMembershipBindGroup !== null
249
- );
250
- },
251
- encode: ({ pass, frame }) => {
252
- const internal = frame as _InternalRenderPipelineContext;
253
- const pipeline = internal.pipelineState.hdrpClusterMembershipPipeline;
254
- const bindings = internal.hdrpClusterMembershipBindGroup;
255
- if (pipeline === null || bindings === null) return;
256
- const grid = topology.config?.clusterGrid ?? DEFAULT_CLUSTER_GRID;
257
- pass.setPipeline(pipeline);
258
- pass.setBindGroup(0, bindings);
259
- pass.dispatchWorkgroups(Math.ceil((grid.x * grid.y * grid.z) / 64));
260
- },
261
- });
262
- }
263
-
264
- function buildHdrp(
156
+ function buildStandardDeferredLane(
265
157
  context: RenderPipelineBuildContext<RenderPipelineFrame>,
266
158
  topology: RenderPipelineTopology,
159
+ lighting: StandardTopologyInputValue,
267
160
  ): ReturnType<RenderPipeline['build']> {
268
- if (topology.lane.maxColorAttachments < 4) {
269
- return err(new HdrpDeferredCapsInsufficientError(topology.lane.maxColorAttachments));
270
- }
271
161
  const graph = context.graph;
272
162
  const surface = importRenderPipelineSurface(graph, topology);
273
163
  if (!surface.ok) return surface;
274
- const buffers = importBuffers(graph, topology);
164
+ const buffers = importStandardClusterBuffers(graph, lighting);
275
165
  if (!buffers.ok) return buffers;
276
- const membership = addMembershipPass(graph, topology, buffers.value);
166
+ const membership =
167
+ buffers.value === null
168
+ ? ok(undefined)
169
+ : addStandardClusterMembershipPass(graph, lighting, buffers.value);
277
170
  if (!membership.ok) return membership;
278
171
  const shadows = addTypedShadowPasses(graph, topology);
279
172
  if (!shadows.ok) return shadows;
@@ -304,9 +197,7 @@ function buildHdrp(
304
197
  taa: topology.camera.antialias === 'taa',
305
198
  motionBlur: topology.temporal?.motionBlur === true,
306
199
  });
307
- const temporalLane = topology.lane.compute
308
- ? (topology.standardProfile?.lighting ?? 'direct')
309
- : 'cpu-webgl2';
200
+ const temporalLane = topology.lane.compute ? 'clustered' : 'cpu-webgl2';
310
201
  const temporalAdmission = standardTemporalLaneAdmission({
311
202
  lane: temporalLane,
312
203
  demand: temporalDemand,
@@ -329,7 +220,11 @@ function buildHdrp(
329
220
  }),
330
221
  );
331
222
  }
332
-
223
+ const gpuDriven = context.projectGpuDriven({
224
+ format: scene.value.format,
225
+ sampleCount: scene.value.sampleCount,
226
+ });
227
+ if (!gpuDriven.ok) return gpuDriven;
333
228
  const gbuffer = addTypedScenePass(graph, {
334
229
  name: 'g-buffer',
335
230
  color: gbuffer0.value,
@@ -362,25 +257,13 @@ function buildHdrp(
362
257
  { resource: gbuffer1.value.view, usage: 'sampled-read' },
363
258
  { resource: gbuffer2.value.view, usage: 'sampled-read' },
364
259
  { resource: depth.value.view, usage: 'depth-stencil-read' },
365
- {
366
- resource: buffers.value.lightData,
367
- usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
368
- },
369
- {
370
- resource: buffers.value.clusterGrid,
371
- usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
372
- },
373
- {
374
- resource: buffers.value.lightIndexList,
375
- usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
376
- },
377
- { resource: buffers.value.clusterUniform, usage: 'uniform-read' },
260
+ ...(buffers.value === null ? [] : standardClusterReadAccesses(buffers.value)),
378
261
  ...(ssao === undefined
379
262
  ? []
380
263
  : ([{ resource: ssao.view, usage: 'sampled-read' }] satisfies GraphAccess[])),
381
264
  { resource: scene.value.view, usage: 'color-attachment' },
382
265
  ];
383
- const lighting = graph.addRasterPass('lighting', {
266
+ const lightingPass = graph.addRasterPass('lighting', {
384
267
  accesses: lightingAccesses,
385
268
  colorAttachments: [
386
269
  {
@@ -392,7 +275,7 @@ function buildHdrp(
392
275
  ],
393
276
  encode: () => undefined,
394
277
  });
395
- if (!lighting.ok) return lighting;
278
+ if (!lightingPass.ok) return lightingPass;
396
279
 
397
280
  const skybox = addTypedSkyboxPass(graph, scene.value);
398
281
  if (!skybox.ok) return skybox;
@@ -402,21 +285,8 @@ function buildHdrp(
402
285
  demand: transmissionDemand,
403
286
  sourceSampleCount: scene.value.sampleCount,
404
287
  }).active;
405
- const forwardExtraAccesses: GraphAccess[] = [
406
- {
407
- resource: buffers.value.lightData,
408
- usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
409
- },
410
- {
411
- resource: buffers.value.clusterGrid,
412
- usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
413
- },
414
- {
415
- resource: buffers.value.lightIndexList,
416
- usage: topology.lane.storageBuffer ? 'storage-read' : 'uniform-read',
417
- },
418
- { resource: buffers.value.clusterUniform, usage: 'uniform-read' },
419
- ];
288
+ const forwardExtraAccesses: GraphAccess[] =
289
+ buffers.value === null ? [] : [...standardClusterReadAccesses(buffers.value)];
420
290
 
421
291
  const forward = addTypedScenePass(graph, {
422
292
  name: 'forward',
@@ -429,14 +299,17 @@ function buildHdrp(
429
299
  gbuffer0.value,
430
300
  gbuffer1.value,
431
301
  gbuffer2.value,
432
- shadows.value.directional,
302
+ ...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
433
303
  shadows.value.spot,
434
304
  ...(shadows.value.point === undefined ? [] : [shadows.value.point]),
435
305
  ...(ssao === undefined ? [] : [ssao]),
436
306
  ],
437
- directionalShadow: shadows.value.directional,
307
+ ...(shadows.value.directional === undefined
308
+ ? {}
309
+ : { directionalShadow: shadows.value.directional }),
438
310
  spotShadow: shadows.value.spot,
439
311
  ...(ssao === undefined ? {} : { ssao }),
312
+ ...(gpuDriven.value === undefined ? {} : { gpuDriven: gpuDriven.value }),
440
313
  passKind: 'forward',
441
314
  ...(transmissionActive ? { recordMode: 'opaque' as const } : {}),
442
315
  extraAccesses: forwardExtraAccesses,
@@ -471,7 +344,7 @@ function buildHdrp(
471
344
  gbuffer0.value,
472
345
  gbuffer1.value,
473
346
  gbuffer2.value,
474
- shadows.value.directional,
347
+ ...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
475
348
  shadows.value.spot,
476
349
  ...(shadows.value.point === undefined ? [] : [shadows.value.point]),
477
350
  ...(ssao === undefined ? [] : [ssao]),
@@ -500,7 +373,7 @@ function buildHdrp(
500
373
  gbuffer0.value,
501
374
  gbuffer1.value,
502
375
  gbuffer2.value,
503
- shadows.value.directional,
376
+ ...(shadows.value.directional === undefined ? [] : [shadows.value.directional]),
504
377
  shadows.value.spot,
505
378
  ...(shadows.value.point === undefined ? [] : [shadows.value.point]),
506
379
  ...(ssao === undefined ? [] : [ssao]),
@@ -516,9 +389,28 @@ function buildHdrp(
516
389
  const temporal = addTransmissionBackdropTemporalPass(graph, scene.value);
517
390
  if (!temporal.ok) return temporal;
518
391
  }
392
+ if (topology.volumetricFog?.enabled === true) {
393
+ const depthSample = graph.view(depth.value.texture, {
394
+ label: 'scene-depth.sample',
395
+ dimension: '2d',
396
+ aspect: 'depth-only',
397
+ });
398
+ if (!depthSample.ok) return depthSample;
399
+ const volume = addAuthoredVolumetricFogPasses(
400
+ graph,
401
+ topology,
402
+ scene.value,
403
+ depthSample.value,
404
+ shadows.value.directional?.view,
405
+ shadows.value.spot.view,
406
+ );
407
+ if (!volume.ok) return volume;
408
+ }
409
+ // The volume-composite pass remains in linear HDR before tone mapping.
519
410
 
520
411
  const features = context.contributeFeatures([
521
412
  {
413
+ name: 'linear-hdr',
522
414
  kind: 'scene-color',
523
415
  texture: scene.value.texture,
524
416
  view: scene.value.view,
@@ -536,8 +428,7 @@ function buildHdrp(
536
428
  if (!features.ok) return features;
537
429
  const observation = addTypedFrameObservationPass(graph, scene.value, 'forgeax::standard');
538
430
  if (!observation.ok) return observation;
539
-
540
- return addStandardPost(
431
+ const post = addStandardPost(
541
432
  context,
542
433
  topology,
543
434
  scene.value,
@@ -545,13 +436,19 @@ function buildHdrp(
545
436
  surface.value,
546
437
  temporal.value?.temporal,
547
438
  );
439
+ if (!post.ok) return post;
440
+ const cubeCaptures = context.contributeCubeCaptures?.();
441
+ if (cubeCaptures !== undefined && !cubeCaptures.ok) return cubeCaptures;
442
+ return ok(undefined);
548
443
  }
549
- const buildStandardClusteredLane = buildHdrp;
550
-
551
444
  export interface StandardPipeline extends RenderPipeline {
552
445
  readonly identity: typeof STANDARD_PIPELINE_ID;
553
446
  }
554
447
 
448
+ export function standardProfileSupportsReflectionProbes(_profile: StandardProfile): boolean {
449
+ return true;
450
+ }
451
+
555
452
  /** Standard graph inputs are derived once from the immutable frame plan. */
556
453
  export type StandardFramePlan = FramePlan;
557
454
 
@@ -559,6 +456,43 @@ function profileFor(topology: RenderPipelineTopology): StandardProfile {
559
456
  return topology.standardProfile ?? DEFAULT_STANDARD_PROFILE;
560
457
  }
561
458
 
459
+ function resolveStandardTopologyInput(
460
+ context: RenderPipelineBuildContext<RenderPipelineFrame>,
461
+ ): Result<StandardTopologyInputValue, RenderGraphError> {
462
+ const supplied = context.standardLighting;
463
+ if (supplied !== undefined) {
464
+ const derived = deriveStandardTopologyInput(supplied);
465
+ if (derived.ok) return derived;
466
+ return err(
467
+ new RenderGraphError({
468
+ code: 'resource-descriptor-invalid',
469
+ expected: 'Forward/Deferred consume one prepared Standard topology input',
470
+ hint: derived.error.hint,
471
+ detail: {
472
+ resourceLabel: 'forgeax::standard',
473
+ field: `standardLighting.${derived.error.detail.field}`,
474
+ expected: derived.error.expected,
475
+ actual: 'invalid',
476
+ },
477
+ }),
478
+ );
479
+ }
480
+
481
+ return err(
482
+ new RenderGraphError({
483
+ code: 'resource-descriptor-invalid',
484
+ expected: 'RenderPipelineBuildContext.standardLighting from frame preparation',
485
+ hint: 'prepare Standard lighting once, select a proven Cluster transport, and pass it to both lanes',
486
+ detail: {
487
+ resourceLabel: 'forgeax::standard',
488
+ field: 'standardLighting',
489
+ expected: 'prepared Standard lighting topology input',
490
+ actual: 'invalid',
491
+ },
492
+ }),
493
+ );
494
+ }
495
+
562
496
  function standardTopology(
563
497
  topology: RenderPipelineTopology,
564
498
  profile: StandardProfile,
@@ -576,26 +510,41 @@ function standardTopology(
576
510
  }
577
511
 
578
512
  /**
579
- * The sole built-in pipeline entry point. Direct and clustered lighting are
580
- * execution lanes selected from the same profile and graph owner; callers do
581
- * not install a second topology or submit authority.
513
+ * The sole built-in pipeline entry point. All local lights use the same
514
+ * prepared Cluster topology; the profile chooses only Forward or Deferred
515
+ * graph shape and never a second lighting authority.
582
516
  */
583
517
  function buildStandard(
584
518
  context: RenderPipelineBuildContext<RenderPipelineFrame>,
585
519
  topology: RenderPipelineTopology,
586
520
  ): ReturnType<RenderPipeline['build']> {
587
521
  const profile = profileFor(topology);
588
- const lane = resolveStandardLane(profile, {
589
- compute: topology.lane.compute,
590
- storageBuffer: topology.lane.storageBuffer,
591
- });
522
+ if (!STANDARD_LIGHT_COUNTS.some((count) => count === profile.lightCount)) {
523
+ return err(
524
+ new RenderGraphError({
525
+ code: 'resource-descriptor-invalid',
526
+ expected: 'StandardProfile.lightCount is one of 1, 32, or 256',
527
+ hint: 'set StandardProfile.lightCount to 1, 32, or 256',
528
+ detail: {
529
+ resourceLabel: 'forgeax::standard',
530
+ field: 'lightCount',
531
+ expected: '1 | 32 | 256',
532
+ actual: profile.lightCount,
533
+ },
534
+ }),
535
+ );
536
+ }
592
537
  const effective = standardTopology(topology, profile);
593
- // A missing Camera is an intentional clear-only frame. Keep it on the
594
- // direct raster lane so clustered/HDRP resources cannot introduce work or
595
- // a post-process lookup into this minimal submit contract.
596
- if (effective.clearOnly === true) return buildStandardForwardLane(context, effective);
597
- if (lane === 'clustered') return buildStandardClusteredLane(context, effective);
598
- return buildStandardForwardLane(context, effective);
538
+ const lighting = resolveStandardTopologyInput(context);
539
+ if (!lighting.ok) return lighting;
540
+ // A missing Camera is an intentional clear-only frame. Keep it on the
541
+ // forward raster lane so clustered resources cannot introduce work.
542
+ if (effective.clearOnly === true) {
543
+ return buildStandardForwardLane(context, effective, lighting.value);
544
+ }
545
+ return profile.renderPath === 'forward'
546
+ ? buildStandardForwardLane(context, effective, lighting.value)
547
+ : buildStandardDeferredLane(context, effective, lighting.value);
599
548
  }
600
549
 
601
550
  export const standardPipeline: StandardPipeline = Object.freeze({