@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,38 @@
1
+ import type { TextureFormat } from '@forgeax/engine-rhi';
2
+ import type { VolumeRecoveryState, VolumeSelectedLightFacts } from './recovery';
3
+ import type { VolumetricFogResourceFacts } from './resources';
4
+ export type VolumetricFogInspectionStatus = 'off' | 'available' | 'unavailable' | 'degraded';
5
+ export type VolumetricFogResourceStage = 'none' | 'candidate' | 'accepted' | 'lkg' | 'recovering';
6
+ export interface VolumetricFogInspection {
7
+ readonly status: VolumetricFogInspectionStatus;
8
+ readonly resourceStage: VolumetricFogResourceStage;
9
+ readonly guid: string | undefined;
10
+ readonly generation: number | undefined;
11
+ readonly digest: string | undefined;
12
+ readonly candidateGeneration: number | undefined;
13
+ readonly candidateDigest: string | undefined;
14
+ readonly lkgGeneration: number | undefined;
15
+ readonly candidateFailure: VolumeRecoveryState['candidateFailure'];
16
+ readonly deviceEpoch: number;
17
+ readonly format: TextureFormat | undefined;
18
+ readonly passCount: number;
19
+ readonly sampleCount: number;
20
+ readonly memoryBytes: number;
21
+ readonly resourceFacts: VolumetricFogResourceFacts | undefined;
22
+ readonly selectedLight: VolumeSelectedLightFacts | undefined;
23
+ readonly candidateSelectedLight: VolumeSelectedLightFacts | undefined;
24
+ }
25
+ export interface VolumetricFogInspectionInput {
26
+ readonly authored: boolean;
27
+ readonly capability: 'available' | 'unavailable';
28
+ readonly degraded?: boolean;
29
+ readonly recovery?: VolumeRecoveryState;
30
+ readonly acceptedDigest?: string;
31
+ readonly format?: TextureFormat;
32
+ readonly passCount?: number;
33
+ readonly sampleCount?: number;
34
+ readonly memoryBytes?: number;
35
+ readonly resourceFacts?: VolumetricFogResourceFacts;
36
+ }
37
+ export declare function inspectVolumetricFog(input: VolumetricFogInspectionInput): VolumetricFogInspection;
38
+ //# sourceMappingURL=inspection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspection.d.ts","sourceRoot":"","sources":["../../src/volume/inspection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAE9D,MAAM,MAAM,6BAA6B,GAAG,KAAK,GAAG,WAAW,GAAG,aAAa,GAAG,UAAU,CAAC;AAE7F,MAAM,MAAM,0BAA0B,GAAG,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,KAAK,GAAG,YAAY,CAAC;AAElG,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,MAAM,EAAE,6BAA6B,CAAC;IAC/C,QAAQ,CAAC,aAAa,EAAE,0BAA0B,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,kBAAkB,CAAC,CAAC;IACnE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,0BAA0B,GAAG,SAAS,CAAC;IAC/D,QAAQ,CAAC,aAAa,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAC7D,QAAQ,CAAC,sBAAsB,EAAE,wBAAwB,GAAG,SAAS,CAAC;CACvE;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,WAAW,GAAG,aAAa,CAAC;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,mBAAmB,CAAC;IACxC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,CAAC,EAAE,0BAA0B,CAAC;CACrD;AAUD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,4BAA4B,GAAG,uBAAuB,CA4BjG"}
@@ -0,0 +1,38 @@
1
+ import type { GraphBuffer, GraphTextureView, RenderGraphBuilder, RenderGraphError } from '@forgeax/engine-render-graph';
2
+ import { type Result } from '@forgeax/engine-types';
3
+ import type { RenderPipelineFrame, RenderPipelineTarget, RenderPipelineTopology } from '../render-pipeline';
4
+ import type { VolumetricFogResources } from './resources';
5
+ import type { VolumeProjectorTuple } from './temporal';
6
+ export declare const VOLUMETRIC_FOG_PASS_ORDER: readonly ["volume-inject", "volume-integrate", "volume-temporal", "volume-composite"];
7
+ export interface VolumetricFogTopology {
8
+ readonly passes: readonly string[];
9
+ readonly resources: readonly string[];
10
+ readonly colorInput: 'linear-hdr';
11
+ readonly depthInput: 'scene-depth';
12
+ readonly lightKind?: 'directional' | 'point' | 'spot';
13
+ readonly lightEntity?: number;
14
+ readonly lightRevision?: number;
15
+ readonly projector?: Pick<VolumeProjectorTuple, 'guid' | 'generation' | 'revision'>;
16
+ }
17
+ export declare function volumetricFogTopology(enabled: boolean, selectedLight?: {
18
+ readonly lightKind: 'directional' | 'point' | 'spot';
19
+ readonly lightEntity: number;
20
+ readonly lightRevision: number;
21
+ }): VolumetricFogTopology;
22
+ export interface VolumetricFogPassInputs {
23
+ readonly resources: VolumetricFogResources;
24
+ readonly linearHdr: RenderPipelineTarget;
25
+ readonly sceneDepth: GraphTextureView;
26
+ readonly density: GraphTextureView;
27
+ readonly params: GraphBuffer;
28
+ readonly view: GraphBuffer;
29
+ readonly directionalShadow?: GraphTextureView;
30
+ readonly spotShadow: GraphTextureView;
31
+ readonly pointLights: GraphBuffer;
32
+ readonly spotLights: GraphBuffer;
33
+ readonly selectedLightKind: 'directional' | 'point' | 'spot';
34
+ readonly projector?: GraphTextureView;
35
+ }
36
+ export declare function addAuthoredVolumetricFogPasses(graph: RenderGraphBuilder<RenderPipelineFrame>, topology: RenderPipelineTopology, linearHdr: RenderPipelineTarget, sceneDepth: GraphTextureView, directionalShadow: GraphTextureView | undefined, spotShadow: GraphTextureView): Result<void, RenderGraphError>;
37
+ export declare function addVolumetricFogPasses(graph: RenderGraphBuilder<RenderPipelineFrame>, inputs: VolumetricFogPassInputs): Result<void, RenderGraphError>;
38
+ //# sourceMappingURL=passes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"passes.d.ts","sourceRoot":"","sources":["../../src/volume/passes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AAWtC,OAAO,EAAM,KAAK,MAAM,EAAE,MAAM,uBAAuB,CAAC;AAcxD,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAQ1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,eAAO,MAAM,yBAAyB,uFAK5B,CAAC;AACX,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,YAAY,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC;IACnC,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;IACtD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,MAAM,GAAG,YAAY,GAAG,UAAU,CAAC,CAAC;CACrF;AACD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,aAAa,CAAC,EAAE;IACd,QAAQ,CAAC,SAAS,EAAE,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;IACrD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC,GACA,qBAAqB,CAevB;AACD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,SAAS,EAAE,sBAAsB,CAAC;IAC3C,QAAQ,CAAC,SAAS,EAAE,oBAAoB,CAAC;IACzC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,gBAAgB,CAAC;IAC9C,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IACjC,QAAQ,CAAC,iBAAiB,EAAE,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;IAC7D,QAAQ,CAAC,SAAS,CAAC,EAAE,gBAAgB,CAAC;CACvC;AAqLD,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,kBAAkB,CAAC,mBAAmB,CAAC,EAC9C,QAAQ,EAAE,sBAAsB,EAChC,SAAS,EAAE,oBAAoB,EAC/B,UAAU,EAAE,gBAAgB,EAC5B,iBAAiB,EAAE,gBAAgB,GAAG,SAAS,EAC/C,UAAU,EAAE,gBAAgB,GAC3B,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAAC,CA2BhC;AACD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,kBAAkB,CAAC,mBAAmB,CAAC,EAC9C,MAAM,EAAE,uBAAuB,GAC9B,MAAM,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAiXhC"}
@@ -0,0 +1,38 @@
1
+ import type { VolumeProjectorTuple } from './temporal';
2
+ export interface VolumeSelectedLightFacts {
3
+ readonly entity: number;
4
+ readonly kind: 'directional' | 'point' | 'spot';
5
+ readonly revision: number;
6
+ readonly shadowTile: number;
7
+ readonly pointLightEntity?: number;
8
+ readonly spotLightEntity?: number;
9
+ readonly projector?: VolumeProjectorTuple;
10
+ }
11
+ export interface VolumeRecoveryState {
12
+ readonly guid: string;
13
+ readonly generation: number;
14
+ readonly deviceEpoch: number;
15
+ readonly status: 'accepted' | 'candidate' | 'degraded' | 'recovering';
16
+ readonly candidateGeneration?: number;
17
+ readonly candidateDigest?: string;
18
+ readonly lkgGeneration?: number;
19
+ readonly candidateFailure?: 'submit-failed' | 'stale-generation' | 'missing-selected-light' | 'missing-shadow';
20
+ readonly selectedLight?: VolumeSelectedLightFacts;
21
+ readonly candidateSelectedLight?: VolumeSelectedLightFacts;
22
+ }
23
+ export type VolumeRecoveryEvent = {
24
+ readonly kind: 'submit-failed';
25
+ } | {
26
+ readonly kind: 'device-lost';
27
+ readonly deviceEpoch: number;
28
+ } | {
29
+ readonly kind: 'accepted';
30
+ readonly generation: number;
31
+ };
32
+ export declare function stageVolumetricFog(state: VolumeRecoveryState, candidate: {
33
+ readonly generation: number;
34
+ readonly digest: string;
35
+ readonly selectedLight?: VolumeSelectedLightFacts;
36
+ }): VolumeRecoveryState;
37
+ export declare function recoverVolumetricFog(state: VolumeRecoveryState, event: VolumeRecoveryEvent): VolumeRecoveryState;
38
+ //# sourceMappingURL=recovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../../src/volume/recovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;IAChD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,SAAS,CAAC,EAAE,oBAAoB,CAAC;CAC3C;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,YAAY,CAAC;IACtE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,gBAAgB,CAAC,EACtB,eAAe,GACf,kBAAkB,GAClB,wBAAwB,GACxB,gBAAgB,CAAC;IACrB,QAAQ,CAAC,aAAa,CAAC,EAAE,wBAAwB,CAAC;IAClD,QAAQ,CAAC,sBAAsB,CAAC,EAAE,wBAAwB,CAAC;CAC5D;AAED,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAA;CAAE,GAClC;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAC9D;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/D,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,mBAAmB,EAC1B,SAAS,EAAE;IACT,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,aAAa,CAAC,EAAE,wBAAwB,CAAC;CACnD,GACA,mBAAmB,CAUrB;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,mBAAmB,EAC1B,KAAK,EAAE,mBAAmB,GACzB,mBAAmB,CA6BrB"}
@@ -0,0 +1,57 @@
1
+ import type { CompiledRenderGraphInfo, GraphTexture, GraphTextureView, RenderGraphBuilder, RenderGraphError } from '@forgeax/engine-render-graph';
2
+ import { type Result } from '@forgeax/engine-types';
3
+ import type { RenderPipelineFrame } from '../render-pipeline';
4
+ export declare const VOLUME_FROXEL_FORMAT: "rgba8unorm";
5
+ export declare const VOLUME_HISTORY_FORMAT: "rgba16float";
6
+ export declare const VOLUME_RESOLVED_FORMAT: "rgba16float";
7
+ export declare const VOLUME_DEPTH_FORMAT: "r32float";
8
+ export declare const VOLUME_PACKING_Z = 4;
9
+ /** Renderer-owned parameter allocation shared by staging and inspection. */
10
+ export declare const VOLUMETRIC_FOG_PARAMS_BYTES: number;
11
+ export interface VolumetricFogExtent {
12
+ readonly width: number;
13
+ readonly height: number;
14
+ readonly depth: number;
15
+ }
16
+ /** Derive the renderer's high profile grid from the actual surface descriptor. */
17
+ export declare function deriveVolumetricFogExtent(surface: {
18
+ readonly width: number;
19
+ readonly height: number;
20
+ }, depth?: number, tileSize?: number): VolumetricFogExtent;
21
+ /** Derive the 2D resolve extent from the same profile tile without a second profile. */
22
+ export declare function deriveVolumetricFogResolvedExtent(surface: {
23
+ readonly width: number;
24
+ readonly height: number;
25
+ }, froxelTileSize?: number): VolumetricFogExtent;
26
+ export interface VolumetricFogResources {
27
+ readonly extent: VolumetricFogExtent;
28
+ readonly resolvedExtent: VolumetricFogExtent;
29
+ readonly froxel: GraphTexture;
30
+ readonly froxelView: GraphTextureView;
31
+ readonly resolved: GraphTexture;
32
+ readonly resolvedView: GraphTextureView;
33
+ readonly history: GraphTexture;
34
+ readonly historyView: GraphTextureView;
35
+ readonly temporal: GraphTexture;
36
+ readonly temporalView: GraphTextureView;
37
+ }
38
+ export interface VolumetricFogResourceFacts {
39
+ readonly generation: number;
40
+ readonly liveResourceCount: number;
41
+ readonly currentBytes: number;
42
+ readonly historyBytes: number;
43
+ readonly scratchBytes: number;
44
+ readonly bufferBytes: number;
45
+ readonly totalBytes: number;
46
+ readonly physicalResourceCount: number;
47
+ readonly sampleCount: number;
48
+ readonly resolvedPixelCount: number;
49
+ }
50
+ /** Project graph descriptors into the volume inspection without a second ledger. */
51
+ export interface VolumetricFogResourceInspectionOptions {
52
+ /** Number of non-null parameter buffers retained by the frame owner. */
53
+ readonly parameterBufferCount?: number;
54
+ }
55
+ export declare function inspectVolumetricFogResources(graph: CompiledRenderGraphInfo, options?: VolumetricFogResourceInspectionOptions): VolumetricFogResourceFacts;
56
+ export declare function createVolumetricFogResources(graph: RenderGraphBuilder<RenderPipelineFrame>, extent?: VolumetricFogExtent, resolvedExtent?: VolumetricFogExtent): Result<VolumetricFogResources, RenderGraphError>;
57
+ //# sourceMappingURL=resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../../src/volume/resources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,YAAY,EAEZ,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAM,KAAK,MAAM,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,eAAO,MAAM,oBAAoB,EAAG,YAAqB,CAAC;AAC1D,eAAO,MAAM,qBAAqB,EAAG,aAAsB,CAAC;AAC5D,eAAO,MAAM,sBAAsB,EAAG,aAAsB,CAAC;AAC7D,eAAO,MAAM,mBAAmB,EAAG,UAAmB,CAAC;AACvD,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,4EAA4E;AAC5E,eAAO,MAAM,2BAA2B,QAAS,CAAC;AAElD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,kFAAkF;AAClF,wBAAgB,yBAAyB,CACvC,OAAO,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC5D,KAAK,SAAK,EACV,QAAQ,SAAI,GACX,mBAAmB,CASrB;AAED,wFAAwF;AACxF,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAC5D,cAAc,SAAI,GACjB,mBAAmB,CAOrB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,EAAE,mBAAmB,CAAC;IACrC,QAAQ,CAAC,cAAc,EAAE,mBAAmB,CAAC;IAC7C,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC;IACxC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC;CACzC;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;CACrC;AAED,oFAAoF;AACpF,MAAM,WAAW,sCAAsC;IACrD,wEAAwE;IACxE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CACxC;AAED,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,uBAAuB,EAC9B,OAAO,GAAE,sCAA2C,GACnD,0BAA0B,CA4D5B;AAyBD,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,kBAAkB,CAAC,mBAAmB,CAAC,EAC9C,MAAM,GAAE,mBAA0D,EAClE,cAAc,CAAC,EAAE,mBAAmB,GACnC,MAAM,CAAC,sBAAsB,EAAE,gBAAgB,CAAC,CAyDlD"}
@@ -0,0 +1,35 @@
1
+ export interface VolumeTemporalSignature {
2
+ readonly cameraRevision: number;
3
+ readonly fogRevision: number;
4
+ readonly lightRevision: number;
5
+ readonly densityGeneration: number;
6
+ readonly width: number;
7
+ readonly height: number;
8
+ readonly lightKind?: 'directional' | 'point' | 'spot';
9
+ readonly lightEntity?: number;
10
+ readonly pointLightEntity?: number;
11
+ readonly spotLightEntity?: number;
12
+ readonly projector?: VolumeProjectorTuple;
13
+ readonly lightShadowRevision?: number;
14
+ }
15
+ /** Accepted projector facts shared by surface and volume consumers. */
16
+ export interface VolumeProjectorTuple {
17
+ readonly guid: string;
18
+ readonly generation: number;
19
+ readonly view: string;
20
+ readonly sampler: string;
21
+ readonly projection: string;
22
+ readonly revision: number;
23
+ }
24
+ export type VolumeTemporalResetReason = 'camera-cut' | 'fog-revision' | 'light-revision' | 'density-generation' | 'resize' | 'reprojection-out-of-screen' | 'reprojection-depth-discontinuity';
25
+ export type VolumeTemporalReset = {
26
+ readonly reset: false;
27
+ } | {
28
+ readonly reset: true;
29
+ readonly reason: VolumeTemporalResetReason;
30
+ };
31
+ export declare function resolveVolumeTemporalReset(previous: VolumeTemporalSignature, next: VolumeTemporalSignature, options?: {
32
+ readonly taaEnabled?: boolean;
33
+ readonly reprojection?: 'out-of-screen' | 'depth-discontinuity';
34
+ }): VolumeTemporalReset;
35
+ //# sourceMappingURL=temporal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temporal.d.ts","sourceRoot":"","sources":["../../src/volume/temporal.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC;IACtD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,SAAS,CAAC,EAAE,oBAAoB,CAAC;IAC1C,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED,uEAAuE;AACvE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,yBAAyB,GACjC,YAAY,GACZ,cAAc,GACd,gBAAgB,GAChB,oBAAoB,GACpB,QAAQ,GACR,4BAA4B,GAC5B,kCAAkC,CAAC;AAEvC,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GACzB;IAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,yBAAyB,CAAA;CAAE,CAAC;AAEzE,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,uBAAuB,EACjC,IAAI,EAAE,uBAAuB,EAC7B,OAAO,GAAE;IACP,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,YAAY,CAAC,EAAE,eAAe,GAAG,qBAAqB,CAAC;CAC5D,GACL,mBAAmB,CA2CrB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgeax/engine-render",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "description": "Canonical ECS render schemas and renderer boundary.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -37,27 +37,27 @@
37
37
  "LICENSE"
38
38
  ],
39
39
  "dependencies": {
40
- "@forgeax/engine-assets-runtime": "0.1.19",
41
- "@forgeax/engine-audio-webaudio": "0.1.19",
42
- "@forgeax/engine-codec": "0.1.19",
43
- "@forgeax/engine-ecs": "0.1.19",
44
- "@forgeax/engine-geometry": "0.1.19",
45
- "@forgeax/engine-graphics-extras": "0.1.19",
46
- "@forgeax/engine-math": "0.1.19",
47
- "@forgeax/engine-pack": "0.1.19",
48
- "@forgeax/engine-plugin": "0.1.19",
49
- "@forgeax/engine-profiler": "0.1.19",
50
- "@forgeax/engine-render-graph": "0.1.19",
51
- "@forgeax/engine-rhi": "0.1.19",
52
- "@forgeax/engine-scene": "0.1.19",
53
- "@forgeax/engine-shader": "0.1.19",
54
- "@forgeax/engine-skinning": "0.1.19",
55
- "@forgeax/engine-types": "0.1.19"
40
+ "@forgeax/engine-assets-runtime": "0.1.21",
41
+ "@forgeax/engine-audio-webaudio": "0.1.21",
42
+ "@forgeax/engine-codec": "0.1.21",
43
+ "@forgeax/engine-ecs": "0.1.21",
44
+ "@forgeax/engine-geometry": "0.1.21",
45
+ "@forgeax/engine-graphics-extras": "0.1.21",
46
+ "@forgeax/engine-math": "0.1.21",
47
+ "@forgeax/engine-pack": "0.1.21",
48
+ "@forgeax/engine-plugin": "0.1.21",
49
+ "@forgeax/engine-profiler": "0.1.21",
50
+ "@forgeax/engine-render-graph": "0.1.21",
51
+ "@forgeax/engine-rhi": "0.1.21",
52
+ "@forgeax/engine-scene": "0.1.21",
53
+ "@forgeax/engine-shader": "0.1.21",
54
+ "@forgeax/engine-skinning": "0.1.21",
55
+ "@forgeax/engine-types": "0.1.21"
56
56
  },
57
57
  "devDependencies": {
58
- "@forgeax/engine-rhi-null": "0.1.19",
59
- "@forgeax/engine-rhi-webgpu": "0.1.19",
60
- "@forgeax/engine-vite-plugin-shader": "0.1.19"
58
+ "@forgeax/engine-rhi-null": "0.1.21",
59
+ "@forgeax/engine-rhi-webgpu": "0.1.21",
60
+ "@forgeax/engine-vite-plugin-shader": "0.1.21"
61
61
  },
62
62
  "forgeax": {
63
63
  "metrics": {
@@ -1,9 +1,13 @@
1
1
  import { readFileSync } from 'node:fs';
2
+ import { mat4, vec3 } from '@forgeax/engine-math';
2
3
  import { RenderGraphBuilder } from '@forgeax/engine-render-graph';
3
4
  import type { RhiDevice } from '@forgeax/engine-rhi';
4
5
  import { rhi } from '@forgeax/engine-rhi-null';
5
6
  import { ok } from '@forgeax/engine-types';
6
7
  import { beforeAll, describe, expect, it } from 'vitest';
8
+ import { prepareStandardLighting } from '../pipeline/standard-lighting/prepare';
9
+ import { deriveStandardTopologyInput } from '../pipeline/standard-lighting/topology';
10
+ import { selectStandardClusterTransport } from '../pipeline/standard-lighting/transport';
7
11
  import { standardPipeline } from '../pipeline/standard-pipeline';
8
12
  import { inspectStandardBloomGraph, STANDARD_BLOOM_TARGET_SPEC } from '../pipeline/standard-post';
9
13
  import { DEFAULT_STANDARD_PROFILE, STANDARD_PIPELINE_ID } from '../pipeline/standard-profile';
@@ -19,11 +23,11 @@ beforeAll(async () => {
19
23
  device = result.value;
20
24
  });
21
25
 
22
- function topology(lighting: 'direct' | 'clustered', bloom: 'off' | 'on'): RenderPipelineTopology {
26
+ function topology(bloom: 'off' | 'on'): RenderPipelineTopology {
23
27
  return {
24
28
  pipelineId: STANDARD_PIPELINE_ID,
25
- standardProfile: { ...DEFAULT_STANDARD_PROFILE, lighting },
26
- config: lighting === 'clustered' ? { ssao: { enabled: false } } : undefined,
29
+ standardProfile: DEFAULT_STANDARD_PROFILE,
30
+ config: { ssao: { enabled: false } },
27
31
  surface: {
28
32
  width: 640,
29
33
  height: 360,
@@ -32,15 +36,15 @@ function topology(lighting: 'direct' | 'clustered', bloom: 'off' | 'on'): Render
32
36
  },
33
37
  camera: { tonemap: 'aces-filmic', antialias: 'fxaa', bloom },
34
38
  shadow: {
35
- mapSize: 64,
36
- cascadeCount: 1,
39
+ directional: { mapSize: 64, cascadeCount: 1 },
40
+ spotMapSize: 64,
37
41
  pointCount: 0,
38
42
  pointFaceSize: 64,
39
43
  spotCount: 0,
40
44
  },
41
45
  lane: {
42
- compute: lighting === 'clustered',
43
- storageBuffer: lighting === 'clustered',
46
+ compute: true,
47
+ storageBuffer: true,
44
48
  multisample: false,
45
49
  maxColorAttachments: 8,
46
50
  },
@@ -49,15 +53,43 @@ function topology(lighting: 'direct' | 'clustered', bloom: 'off' | 'on'): Render
49
53
  };
50
54
  }
51
55
 
52
- function inspect(lighting: 'direct' | 'clustered', bloom: 'off' | 'on') {
56
+ function clusteredStandardLighting() {
57
+ const prepared = prepareStandardLighting({
58
+ directional: undefined,
59
+ local: [{ kind: 'point' as const, shadowed: false, position: vec3.create(0, 0, -4), range: 2 }],
60
+ view: mat4.lookAt(mat4.create(), [0, 0, 0], [0, 0, -1], [0, 1, 0]),
61
+ projection: mat4.perspective(mat4.create(), Math.PI / 3, 1, 0.1, 100),
62
+ near: 0.1,
63
+ far: 100,
64
+ grid: { x: 4, y: 3, z: 4 },
65
+ lightCount: DEFAULT_STANDARD_PROFILE.lightCount,
66
+ renderPath: 'forward',
67
+ });
68
+ if (!prepared.ok) throw prepared.error;
69
+ const transport = selectStandardClusterTransport(
70
+ { compute: true, storageBuffer: true, membershipPipelineReady: true },
71
+ prepared.value,
72
+ );
73
+ if (!transport.ok) throw transport.error;
74
+ const lighting = deriveStandardTopologyInput({
75
+ kind: 'clustered',
76
+ prepared: prepared.value,
77
+ transport: transport.value,
78
+ });
79
+ if (!lighting.ok) throw lighting.error;
80
+ return lighting.value;
81
+ }
82
+
83
+ function inspect(bloom: 'off' | 'on') {
53
84
  const graph = new RenderGraphBuilder<RenderPipelineFrame>();
54
85
  const built = standardPipeline.build(
55
86
  {
56
87
  graph,
88
+ standardLighting: clusteredStandardLighting(),
57
89
  projectGpuDriven: () => ok(undefined),
58
90
  contributeFeatures: () => ok(undefined),
59
91
  },
60
- topology(lighting, bloom),
92
+ topology(bloom),
61
93
  );
62
94
  if (!built.ok) throw built.error;
63
95
  const compiled = graph.compile({ device, surfaceSize: { width: 640, height: 360 } });
@@ -66,11 +98,8 @@ function inspect(lighting: 'direct' | 'clustered', bloom: 'off' | 'on') {
66
98
  }
67
99
 
68
100
  describe('Standard Bloom exact-zero topology', () => {
69
- it.each([
70
- 'direct',
71
- 'clustered',
72
- ] as const)('%s Bloom off declares no Bloom targets or passes', (lighting) => {
73
- const info = inspect(lighting, 'off');
101
+ it('Bloom off declares no Bloom targets or passes', () => {
102
+ const info = inspect('off');
74
103
  const bloomPasses = info.passes.filter((pass) => pass.name.startsWith('bloom-'));
75
104
  const bloomResources = info.resources.filter((resource) => resource.label.startsWith('bloom-'));
76
105
  expect(bloomPasses).toHaveLength(0);
@@ -120,8 +149,8 @@ describe('Standard Bloom exact-zero topology', () => {
120
149
  });
121
150
 
122
151
  it('keeps one shared Bloom chain when enabled', () => {
123
- for (const lighting of ['direct', 'clustered'] as const) {
124
- const info = inspect(lighting, 'on');
152
+ {
153
+ const info = inspect('on');
125
154
  expect(inspectStandardBloomGraph(info)).toEqual({
126
155
  status: 'valid',
127
156
  targetCount: 4,
@@ -147,7 +176,7 @@ describe('Standard Bloom exact-zero topology', () => {
147
176
  });
148
177
 
149
178
  it('fails closed when a canonical Bloom descriptor drifts', () => {
150
- const info = inspect('direct', 'on');
179
+ const info = inspect('on');
151
180
  const drifted = {
152
181
  ...info,
153
182
  resources: info.resources.map((resource) =>
@@ -171,7 +200,7 @@ describe('Standard Bloom exact-zero topology', () => {
171
200
  });
172
201
 
173
202
  it('rejects a graph with a missing canonical Bloom target', () => {
174
- const info = inspect('direct', 'on');
203
+ const info = inspect('on');
175
204
  const drifted = {
176
205
  ...info,
177
206
  resources: info.resources.filter(
@@ -187,7 +216,7 @@ describe('Standard Bloom exact-zero topology', () => {
187
216
  });
188
217
 
189
218
  it('rejects a graph with a missing canonical Bloom pass', () => {
190
- const info = inspect('direct', 'on');
219
+ const info = inspect('on');
191
220
  const drifted = {
192
221
  ...info,
193
222
  passes: info.passes.filter((pass) => pass.name !== 'bloom-blur-h'),
@@ -1,9 +1,13 @@
1
+ import { mat4, vec3 } from '@forgeax/engine-math';
1
2
  import { RenderGraphBuilder } from '@forgeax/engine-render-graph';
2
3
  import type { RhiDevice } from '@forgeax/engine-rhi';
3
4
  import { rhi } from '@forgeax/engine-rhi-null';
4
5
  import { ok } from '@forgeax/engine-types';
5
6
  import { beforeAll, describe, expect, it } from 'vitest';
6
7
  import { DeviceScope, LifecycleTransaction } from '../device/device-scope';
8
+ import { prepareStandardLighting } from '../pipeline/standard-lighting/prepare';
9
+ import { deriveStandardTopologyInput } from '../pipeline/standard-lighting/topology';
10
+ import { selectStandardClusterTransport } from '../pipeline/standard-lighting/transport';
7
11
  import { standardPipeline } from '../pipeline/standard-pipeline';
8
12
  import { DEFAULT_STANDARD_PROFILE, STANDARD_PIPELINE_ID } from '../pipeline/standard-profile';
9
13
  import type { RenderPipelineFrame, RenderPipelineTopology } from '../render-pipeline';
@@ -18,11 +22,11 @@ beforeAll(async () => {
18
22
  device = result.value;
19
23
  });
20
24
 
21
- function build(bloom: 'off' | 'on', lighting: 'direct' | 'clustered') {
25
+ function build(bloom: 'off' | 'on') {
22
26
  const topology: RenderPipelineTopology = {
23
27
  pipelineId: STANDARD_PIPELINE_ID,
24
- standardProfile: { ...DEFAULT_STANDARD_PROFILE, lighting },
25
- config: lighting === 'clustered' ? { ssao: { enabled: false } } : undefined,
28
+ standardProfile: DEFAULT_STANDARD_PROFILE,
29
+ config: { ssao: { enabled: false } },
26
30
  surface: {
27
31
  width: 320,
28
32
  height: 180,
@@ -31,15 +35,15 @@ function build(bloom: 'off' | 'on', lighting: 'direct' | 'clustered') {
31
35
  },
32
36
  camera: { tonemap: 'aces-filmic', antialias: 'fxaa', bloom },
33
37
  shadow: {
34
- mapSize: 64,
35
- cascadeCount: 1,
38
+ directional: { mapSize: 64, cascadeCount: 1 },
39
+ spotMapSize: 64,
36
40
  pointCount: 0,
37
41
  pointFaceSize: 64,
38
42
  spotCount: 0,
39
43
  },
40
44
  lane: {
41
- compute: lighting === 'clustered',
42
- storageBuffer: lighting === 'clustered',
45
+ compute: true,
46
+ storageBuffer: true,
43
47
  multisample: false,
44
48
  maxColorAttachments: 8,
45
49
  },
@@ -47,9 +51,33 @@ function build(bloom: 'off' | 'on', lighting: 'direct' | 'clustered') {
47
51
  gpuDrivenTopologySignature: '',
48
52
  };
49
53
  const graph = new RenderGraphBuilder<RenderPipelineFrame>();
54
+ const prepared = prepareStandardLighting({
55
+ directional: undefined,
56
+ local: [{ kind: 'point' as const, shadowed: false, position: vec3.create(0, 0, -4), range: 2 }],
57
+ view: mat4.lookAt(mat4.create(), [0, 0, 0], [0, 0, -1], [0, 1, 0]),
58
+ projection: mat4.perspective(mat4.create(), Math.PI / 3, 1, 0.1, 100),
59
+ near: 0.1,
60
+ far: 100,
61
+ grid: { x: 4, y: 3, z: 4 },
62
+ lightCount: DEFAULT_STANDARD_PROFILE.lightCount,
63
+ renderPath: 'forward',
64
+ });
65
+ if (!prepared.ok) throw prepared.error;
66
+ const transport = selectStandardClusterTransport(
67
+ { compute: true, storageBuffer: true, membershipPipelineReady: true },
68
+ prepared.value,
69
+ );
70
+ if (!transport.ok) throw transport.error;
71
+ const standardLighting = deriveStandardTopologyInput({
72
+ kind: 'clustered',
73
+ prepared: prepared.value,
74
+ transport: transport.value,
75
+ });
76
+ if (!standardLighting.ok) throw standardLighting.error;
50
77
  const built = standardPipeline.build(
51
78
  {
52
79
  graph,
80
+ standardLighting: standardLighting.value,
53
81
  projectGpuDriven: () => ok(undefined),
54
82
  contributeFeatures: () => ok(undefined),
55
83
  },
@@ -71,10 +99,10 @@ function bloomSummary(info: ReturnType<typeof build>) {
71
99
  }
72
100
 
73
101
  describe('Standard Bloom lifecycle contract', () => {
74
- it.each(['direct', 'clustered'] as const)('supports on -> off -> on for %s', (lighting) => {
75
- const on = bloomSummary(build('on', lighting));
76
- const off = bloomSummary(build('off', lighting));
77
- const recovered = bloomSummary(build('on', lighting));
102
+ it('supports on -> off -> on for the Standard clustered graph', () => {
103
+ const on = bloomSummary(build('on'));
104
+ const off = bloomSummary(build('off'));
105
+ const recovered = bloomSummary(build('on'));
78
106
  expect(on.passes).toHaveLength(4);
79
107
  expect(on.resources.length).toBeGreaterThan(0);
80
108
  expect(off).toEqual({ passes: [], resources: [] });
@@ -82,7 +110,7 @@ describe('Standard Bloom lifecycle contract', () => {
82
110
  });
83
111
 
84
112
  it('keeps post order scene -> Bloom -> output transform -> FXAA -> debug', () => {
85
- const names = build('on', 'clustered').passes.map((pass) => pass.name);
113
+ const names = build('on').passes.map((pass) => pass.name);
86
114
  const order = [
87
115
  'forward',
88
116
  'bloom-bright',
@@ -117,7 +145,7 @@ describe('Standard Bloom lifecycle contract', () => {
117
145
  });
118
146
 
119
147
  it('FALSIFY rejects an injected Bloom contribution on the off path', () => {
120
- const off = bloomSummary(build('off', 'direct'));
148
+ const off = bloomSummary(build('off'));
121
149
  const injected = { ...off, passes: ['bloom-falsified'] };
122
150
  expect(injected).not.toEqual({ passes: [], resources: [] });
123
151
  expect(off).toEqual({ passes: [], resources: [] });
@@ -0,0 +1,53 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { type CameraTargetCandidate, selectCameraTargetViews } from '../render-system-extract';
3
+ import type { RenderTargetDescriptor } from '../targets/contracts';
4
+ import { createRenderTargetOwner } from '../targets/owner';
5
+
6
+ const descriptor: RenderTargetDescriptor = {
7
+ shape: '2d',
8
+ width: 16,
9
+ height: 16,
10
+ format: 'rgba8unorm',
11
+ mipLevels: 1,
12
+ sampleCount: 1,
13
+ sampled: true,
14
+ readback: false,
15
+ };
16
+
17
+ function targets() {
18
+ const owner = createRenderTargetOwner({ rendererId: Symbol('renderer'), initialGeneration: 1 });
19
+ const first = owner.create(descriptor);
20
+ const second = owner.create(descriptor);
21
+ if (!first.ok) throw first.error;
22
+ if (!second.ok) throw second.error;
23
+ return [first.value, second.value] as const;
24
+ }
25
+
26
+ describe('Camera target consumption', () => {
27
+ it('keeps display authority separate and applies stable auxiliary ordering and budget', () => {
28
+ const [first, second] = targets();
29
+ const cameras: CameraTargetCandidate[] = [
30
+ { worldId: 2, entityKey: 20, target: first, requestVersion: 1, update: 'once' },
31
+ { worldId: 1, entityKey: 30, target: second, requestVersion: 1, update: 'continuous' },
32
+ { worldId: 1, entityKey: 10, requestVersion: 0, update: 'continuous' },
33
+ ];
34
+ const selected = selectCameraTargetViews(cameras, { displayEntityKey: 10, budget: 1 });
35
+ expect(selected.display?.entityKey).toBe(10);
36
+ expect(selected.auxiliary.map((camera) => camera.entityKey)).toEqual([30]);
37
+ expect(selected.rejected).toHaveLength(1);
38
+ expect(selected.rejected[0]?.reason).toBe('budget');
39
+ });
40
+
41
+ it('rejects a target camera selected as display and duplicate target producers', () => {
42
+ const [first] = targets();
43
+ const cameras: CameraTargetCandidate[] = [
44
+ { worldId: 1, entityKey: 3, target: first, requestVersion: 1, update: 'once' },
45
+ { worldId: 1, entityKey: 4, target: first, requestVersion: 2, update: 'once' },
46
+ ];
47
+ const selected = selectCameraTargetViews(cameras, { displayEntityKey: 3, budget: 2 });
48
+ expect(selected.display).toBeUndefined();
49
+ expect(selected.rejected.map((entry) => entry.reason)).toEqual(
50
+ expect.arrayContaining(['display-target', 'duplicate-target']),
51
+ );
52
+ });
53
+ });
@@ -0,0 +1,35 @@
1
+ import { mat4, vec3 } from '@forgeax/engine-math';
2
+ import { describe, expect, it } from 'vitest';
3
+ import { bin, createClusterBinScratch } from '../cluster-binner';
4
+
5
+ describe('cluster binner structured boundaries', () => {
6
+ it('returns a complete structured overflow without truncating output', () => {
7
+ const grid = { x: 4, y: 3, z: 4 };
8
+ const view = mat4.lookAt(mat4.create(), [0, 0, 0], [0, 0, -1], [0, 1, 0]);
9
+ const projection = mat4.perspective(mat4.create(), Math.PI / 3, 1, 0.1, 100);
10
+ const clusterGrid = new Uint32Array(grid.x * grid.y * grid.z * 2).fill(7);
11
+ const lightIndexList = new Uint32Array(1).fill(9);
12
+ const result = bin(
13
+ [{ position: vec3.create(0, 0, -4), range: 100 }],
14
+ view,
15
+ projection,
16
+ grid,
17
+ 0.1,
18
+ 100,
19
+ clusterGrid,
20
+ lightIndexList,
21
+ 0,
22
+ createClusterBinScratch(),
23
+ );
24
+
25
+ expect(result.ok).toBe(false);
26
+ if (result.ok) return;
27
+ expect(result.error.code).toBe('index-overflow');
28
+ expect(result.error.expected).toContain('writeCount <= 0');
29
+ expect(result.error.hint).toContain('reduce lights');
30
+ expect(result.error.detail.actual).toBeGreaterThan(0);
31
+ expect(result.error.detail.capacity).toBe(0);
32
+ expect(Array.from(clusterGrid)).toEqual(new Array(clusterGrid.length).fill(0));
33
+ expect(Array.from(lightIndexList)).toEqual([9]);
34
+ });
35
+ });